From b8aca8ce418dbea42afe7ab677efb825bf60b073 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 14 Feb 2024 10:34:29 +0100
Subject: [PATCH 01/37] proof of concept
---
Gemfile | 11 +--
Gemfile.lock | 9 +++
beepboop.txt | 13 ++++
config/application.rb | 10 +--
lib/ingestors/gpt_ingestor.rb | 77 +++++++++++++++++++++
lib/ingestors/ingestor_factory.rb | 11 ++-
lib/modules/chatgpt_service.rb | 109 ++++++++++++++++++++++++++++++
7 files changed, 225 insertions(+), 15 deletions(-)
create mode 100644 beepboop.txt
create mode 100644 lib/ingestors/gpt_ingestor.rb
create mode 100644 lib/modules/chatgpt_service.rb
diff --git a/Gemfile b/Gemfile
index 1c1c54a00..e832de59d 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,4 +1,5 @@
# frozen_string_literal: true
+
source 'https://rubygems.org'
gem 'rails', '7.0.7.2'
@@ -14,7 +15,6 @@ gem 'bootstrap-tab-history-rails'
gem 'country_select'
gem 'devise'
gem 'devise_invitable'
-gem 'sitemap_generator'
gem 'eventbrite_sdk'
gem 'font-awesome-sass', '~> 4.7.0' # Prefer V4 icon styles
gem 'friendly_id'
@@ -33,23 +33,23 @@ gem 'jquery-turbolinks'
gem 'kt-paperclip'
gem 'linkeddata'
gem 'money-rails'
-gem 'omniauth-rails_csrf_protection'
gem 'omniauth_openid_connect'
+gem 'omniauth-rails_csrf_protection'
gem 'pg'
gem 'private_address_check'
gem 'public_activity'
gem 'pundit'
gem 'rack-cors', require: 'rack/cors'
-gem 'rails-i18n'
gem 'rails_admin'
+gem 'rails-i18n'
gem 'recaptcha', require: 'recaptcha/rails'
gem 'redcarpet'
gem 'redis'
gem 'rest-client'
gem 'reverse_markdown'
gem 'rss'
-gem 'sass-rails'
gem 'sassc-rails'
+gem 'sass-rails'
gem 'sentry-rails'
gem 'sentry-ruby'
gem 'sentry-sidekiq'
@@ -58,6 +58,7 @@ gem 'sidekiq-status'
gem 'simple_calendar', '~> 2.4'
gem 'simple_form'
gem 'simple_token_authentication'
+gem 'sitemap_generator'
gem 'sitemap-parser'
gem 'slim'
gem 'sunspot_rails', github: 'sunspot/sunspot', branch: 'master' # Contains Ruby 3 fixes that are not released
@@ -103,3 +104,5 @@ group :test do
gem 'vcr'
gem 'webmock'
end
+
+gem 'ruby-openai'
diff --git a/Gemfile.lock b/Gemfile.lock
index 1d9fe413b..09276a9b4 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -195,6 +195,7 @@ GEM
erubi (1.12.0)
ethon (0.16.0)
ffi (>= 1.15.0)
+ event_stream_parser (1.0.0)
eventbrite_sdk (3.6.0)
rest-client (~> 2.0)
execjs (2.8.1)
@@ -203,6 +204,8 @@ GEM
ruby2_keywords (>= 0.0.4)
faraday-follow_redirects (0.3.0)
faraday (>= 1, < 3)
+ faraday-multipart (1.0.4)
+ multipart-post (~> 2)
faraday-net_http (3.0.2)
ffi (1.15.5)
font-awesome-sass (4.7.0)
@@ -365,6 +368,7 @@ GEM
msgpack (1.7.2)
multi_json (1.15.0)
multi_xml (0.6.0)
+ multipart-post (2.4.0)
nested_form (0.3.2)
net-http-persistent (4.0.2)
connection_pool (~> 2.2)
@@ -596,6 +600,10 @@ GEM
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.29.0)
parser (>= 3.2.1.0)
+ ruby-openai (6.3.1)
+ event_stream_parser (>= 0.3.0, < 2.0.0)
+ faraday (>= 1)
+ faraday-multipart (>= 1)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
safely_block (0.4.0)
@@ -826,6 +834,7 @@ DEPENDENCIES
reverse_markdown
rss
rubocop
+ ruby-openai
sass-rails
sassc-rails
sentry-rails
diff --git a/beepboop.txt b/beepboop.txt
new file mode 100644
index 000000000..735845b9e
--- /dev/null
+++ b/beepboop.txt
@@ -0,0 +1,13 @@
+Give me a json describing a research themed event with the following format:
+
+title (string): The title of the event
+url (string): The url where the event is described
+organizer (string): The organisation that hosts the event
+description (string): A description of what will happen at the event
+start (datetime): The local starting time of the event
+end (datetime): The local end time of the event
+timezone (string): The timezone for which the start and end are filled in
+venue (string): The venue where the event is hosted
+source (string): The organisation whose website this event is scraped from
+keywords (array of strings): A set of keywords based which the event can be filtered
+target_audience (array of strings): The target audience for this event
diff --git a/config/application.rb b/config/application.rb
index 9ab35a469..92478678b 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -10,6 +10,7 @@ module TeSS
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
+ config.autoload_paths << Rails.root.join('lib/modules')
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
@@ -21,7 +22,7 @@ class Application < Rails::Application
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
- resource '*', headers: :any, methods: [:get, :post, :options]
+ resource '*', headers: :any, methods: %i[get post options]
end
end
@@ -38,7 +39,7 @@ class Application < Rails::Application
ActiveSupport::HashWithIndifferentAccess, BigDecimal
]
- config.exceptions_app = self.routes
+ config.exceptions_app = routes
end
tess_config = Rails.configuration.tess.with_indifferent_access
@@ -64,9 +65,7 @@ def self.merge_config(default_config, config, current_path = '')
puts "Setting '#{current_path}#{key}' not configured, using defaults" if Rails.env.development?
config[key] = value
end
- if value.is_a?(Hash) && config[key].is_a?(Hash)
- merge_config(value, config[key], current_path + "#{key}: ")
- end
+ merge_config(value, config[key], current_path + "#{key}: ") if value.is_a?(Hash) && config[key].is_a?(Hash)
end
end
@@ -83,6 +82,7 @@ def redis_url
def ingestion
return @ingestion if @ingestion
+
config_file = File.join(Rails.root, 'config', 'ingestion.yml')
@ingestion = YAML.safe_load(File.read(config_file)).deep_symbolize_keys! if File.exist?(config_file)
end
diff --git a/lib/ingestors/gpt_ingestor.rb b/lib/ingestors/gpt_ingestor.rb
new file mode 100644
index 000000000..50c11374e
--- /dev/null
+++ b/lib/ingestors/gpt_ingestor.rb
@@ -0,0 +1,77 @@
+require 'open-uri'
+require 'csv'
+require 'nokogiri'
+
+module Ingestors
+ class GptIngestor < Ingestor
+ def self.config
+ {
+ key: 'gpt_event',
+ title: 'GPT Events API',
+ category: :events
+ }
+ end
+
+ def read(url)
+ begin
+ process_gpt(url)
+ rescue Exception => e
+ @messages << "#{self.class.name} failed with: #{e.message}"
+ end
+
+ # finished
+ nil
+ end
+
+ private
+
+ def process_gpt(_url)
+ # dans HTML
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
+ event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='nieuws_detail_row']")
+ beep_func(event_page)
+
+ # nwo HTML
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ url = 'https://www.nwo.nl/en/meetings'
+ event_page = Nokogiri::HTML5.parse(open_url("#{url}?page=0", raise: true)).css('.overviewContent > .listing-cards > li.list-item')[3]
+ beep_func(event_page)
+
+ # rug HTML
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ url = 'https://www.rug.nl/about-ug/latest-news/events/calendar/2023/phallus-tentoonstelling'
+ event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[class='rug-mb']")[0].css("div[itemtype='https://schema.org/Event']")
+ beep_func(event_page)
+
+ # tdcc HTML
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ url = 'https://tdcc.nl/evenementen/teaming-up-across-domains/'
+ event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css('article')[0]
+ beep_func(event_page)
+
+ # json not necessary (SURF, UvA)
+ # XML not necessary (wur)
+ end
+
+ def beep_func(event_page) # rubocop:disable Metrics
+ prompt = File.read('beepboop.txt')
+ event_page.css('script, link').each { |node| node.remove }
+ event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
+ response = ChatgptService.new.scrape(event_page, prompt).dig('choices', 0, 'message', 'content')
+ puts response
+ response_json = JSON.parse(response)
+ begin
+ event = OpenStruct.new
+ response_json.each_key do |key|
+ event[key] = response_json[key]
+ end
+ event.source = 'GPT'
+ event.timezone = 'Amsterdam'
+ add_event(event)
+ rescue Exception => e
+ @messages << "Extract event fields failed with: #{e.message}"
+ end
+ end
+ end
+end
diff --git a/lib/ingestors/ingestor_factory.rb b/lib/ingestors/ingestor_factory.rb
index 80982d116..790baa457 100644
--- a/lib/ingestors/ingestor_factory.rb
+++ b/lib/ingestors/ingestor_factory.rb
@@ -29,7 +29,8 @@ def self.ingestors
Ingestors::RstIngestor,
Ingestors::OsciIngestor,
Ingestors::DccIngestor,
- Ingestors::SenseIngestor
+ Ingestors::SenseIngestor,
+ Ingestors::GptIngestor
]
end
@@ -41,11 +42,9 @@ def self.ingestor_config
def self.get_ingestor(method)
config = ingestor_config[method]
- if config
- config[:ingestor].new
- else
- raise "Invalid method: [#{method}]"
- end
+ raise "Invalid method: [#{method}]" unless config
+
+ config[:ingestor].new
end
def self.valid_ingestor?(method)
diff --git a/lib/modules/chatgpt_service.rb b/lib/modules/chatgpt_service.rb
new file mode 100644
index 000000000..ae1a4842e
--- /dev/null
+++ b/lib/modules/chatgpt_service.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+class ChatgptService
+ # require 'open-uri'
+ # source = URI(url).open(&:read)
+ require 'openai'
+ def initialize
+ api_key = ENV.fetch('GPT_API_KEY', nil)
+ @client = OpenAI::Client.new(access_token: api_key)
+ @params = {
+ # max_tokens: 50,
+ model: 'gpt-3.5-turbo-1106',
+ temperature: 0.7
+ }
+ end
+
+ def call(prompt)
+ params = @params.merge(
+ {
+ messages: [{ role: 'user', content: prompt }]
+ }
+ )
+ @client.chat(parameters: params)
+ end
+
+ def scrape(event_page, prompt)
+ content = "Based on the following webpage describing a research event:\n\n#{event_page}\n\n #{prompt}"
+ params = @params.merge(
+ {
+ response_format: { type: 'json_object' },
+ messages: [{ role: 'user', content: }]
+ }
+ )
+ @client.chat(parameters: params)
+ end
+
+ def beep
+ file_name = 'beepboop.txt'
+ content = File.read(file_name)
+
+ params = @params.merge(
+ {
+ response_format: { type: 'json_object' },
+ messages: [{ role: 'user', content: }]
+ }
+ )
+ @client.chat(parameters: params)
+ end
+
+ class << self
+ def call(message)
+ new.call(message)
+ end
+
+ def scrape # rubocop:disable Metrics
+ url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
+ file_name = 'beepboop.txt'
+ require 'open-uri'
+ event_page = URI(url).open(&:read)
+ doc = Nokogiri::HTML5.parse(event_page).css('body').css("div[id='nieuws_detail_row']")
+ doc.css('script, link').each { |node| node.remove }
+ event_page = doc.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
+ prompt = File.read(file_name)
+ response = new.scrape(event_page, prompt).dig('choices', 0, 'message', 'content')
+ puts response
+ JSON.parse(response)
+ end
+
+ def beep
+ new.beep
+ end
+ end
+end
+
+# class ChatgptService
+# include HTTParty
+
+# attr_reader :api_url, :options, :body, :message
+
+# def initialize(message, model = 'gpt-3.5-turbo')
+# api_key = ENV.fetch('GPT_API_KEY', nil)
+# @options = {
+# headers: {
+# 'Content-Type' => 'application/json',
+# 'Authorization' => "Bearer #{api_key}"
+# }
+# }
+# @body = {
+# model:,
+# messages: [{ role: 'user', content: message }],
+# max_tokens: 50
+# }
+# @api_url = 'https://api.openai.com/v1/chat/completions'
+# @message = message
+# end
+
+# def call
+# response = HTTParty.post(api_url, body: body.to_json, headers: options[:headers], timeout: 10)
+# raise response['error']['message'] unless response.code == 200
+
+# response['choices'][0]['message']['content']
+# end
+
+# class << self
+# def call(message)
+# new(message).call
+# end
+# end
+# end
From 5e303b9e425097b69c2f52deb859465939a01ba4 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 21 Feb 2024 09:34:26 +0100
Subject: [PATCH 02/37] add post processing
---
db/migrate/20240220144246_add_llm_check.rb | 13 ++++
lib/ingestors/gpt_ingestor.rb | 2 +-
lib/modules/chatgpt_service.rb | 90 ++++++++--------------
llm_process_prompt.txt | 21 +++++
beepboop.txt => llm_scrape_prompt.txt | 5 +-
5 files changed, 69 insertions(+), 62 deletions(-)
create mode 100644 db/migrate/20240220144246_add_llm_check.rb
create mode 100644 llm_process_prompt.txt
rename beepboop.txt => llm_scrape_prompt.txt (83%)
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
new file mode 100644
index 000000000..4e0d737db
--- /dev/null
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -0,0 +1,13 @@
+class AddLlmCheck < ActiveRecord::Migration[7.0]
+ def up
+ add_column :events, :llm_processed, :bool, default: false
+ add_column :events, :curation, :bool, default: true
+ add_column :materials, :llm_processed, :bool, default: false
+ end
+
+ def down
+ remove_column :events, :llm_processed, :bool, default: false
+ remove_column :events, :curation, :bool, default: true
+ remove_column :materials, :llm_processed, :bool, default: false
+ end
+end
diff --git a/lib/ingestors/gpt_ingestor.rb b/lib/ingestors/gpt_ingestor.rb
index 50c11374e..3834410a4 100644
--- a/lib/ingestors/gpt_ingestor.rb
+++ b/lib/ingestors/gpt_ingestor.rb
@@ -55,7 +55,7 @@ def process_gpt(_url)
end
def beep_func(event_page) # rubocop:disable Metrics
- prompt = File.read('beepboop.txt')
+ prompt = File.read('llm_scrape_prompt.txt')
event_page.css('script, link').each { |node| node.remove }
event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
response = ChatgptService.new.scrape(event_page, prompt).dig('choices', 0, 'message', 'content')
diff --git a/lib/modules/chatgpt_service.rb b/lib/modules/chatgpt_service.rb
index ae1a4842e..827071cf1 100644
--- a/lib/modules/chatgpt_service.rb
+++ b/lib/modules/chatgpt_service.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
class ChatgptService
- # require 'open-uri'
- # source = URI(url).open(&:read)
require 'openai'
def initialize
api_key = ENV.fetch('GPT_API_KEY', nil)
@@ -14,37 +12,41 @@ def initialize
}
end
- def call(prompt)
+ def run(content)
+ beep = content
params = @params.merge(
{
- messages: [{ role: 'user', content: prompt }]
+ response_format: { type: 'json_object' },
+ messages: [{ role: 'user', content: beep }]
}
)
@client.chat(parameters: params)
end
- def scrape(event_page, prompt)
- content = "Based on the following webpage describing a research event:\n\n#{event_page}\n\n #{prompt}"
+ def call(prompt)
params = @params.merge(
{
- response_format: { type: 'json_object' },
- messages: [{ role: 'user', content: }]
+ messages: [{ role: 'user', content: prompt }]
}
)
@client.chat(parameters: params)
end
- def beep
- file_name = 'beepboop.txt'
- content = File.read(file_name)
+ def scrape(event_page)
+ content = File.read('llm_scrape_prompt.txt')
+ .gsub('*replace_with_event_page*', event_page)
+ run(content)
+ end
- params = @params.merge(
- {
- response_format: { type: 'json_object' },
- messages: [{ role: 'user', content: }]
- }
- )
- @client.chat(parameters: params)
+ def process(event, collections)
+ event_attrs = %i[title description venue start end keywords target_audience]
+ collection_attrs = %i[title description keywords]
+ event_json = JSON.generate(event.to_json(only: event_attrs))
+ collections_json = JSON.generate(collections.map { |col| [col.id, col.to_json(only: collection_attrs)] }.to_h)
+ content = File.read('llm_process_prompt.txt')
+ .gsub('*replace_with_event*', event_json)
+ .gsub('*replace_with_collections*', collections_json)
+ run(content)
end
class << self
@@ -54,56 +56,26 @@ def call(message)
def scrape # rubocop:disable Metrics
url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
- file_name = 'beepboop.txt'
require 'open-uri'
event_page = URI(url).open(&:read)
doc = Nokogiri::HTML5.parse(event_page).css('body').css("div[id='nieuws_detail_row']")
doc.css('script, link').each { |node| node.remove }
event_page = doc.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
- prompt = File.read(file_name)
- response = new.scrape(event_page, prompt).dig('choices', 0, 'message', 'content')
+ response = new.scrape(event_page).dig('choices', 0, 'message', 'content')
puts response
JSON.parse(response)
end
- def beep
- new.beep
+ def process
+ event_json = ChatgptService.scrape
+ event = Event.new(event_json)
+ collections = [
+ Collection.new(title: 'Python stuff', description: 'Anything concerning the python programming language', keywords: %w[python programming IT]),
+ Collection.new(title: 'Open hours on mondays', description: 'All open hours that happen on the first day of the week', keywords: %w[Monday questions])
+ ]
+ response = new.process(event, collections).dig('choices', 0, 'message', 'content')
+ puts response
+ JSON.parse(response)
end
end
end
-
-# class ChatgptService
-# include HTTParty
-
-# attr_reader :api_url, :options, :body, :message
-
-# def initialize(message, model = 'gpt-3.5-turbo')
-# api_key = ENV.fetch('GPT_API_KEY', nil)
-# @options = {
-# headers: {
-# 'Content-Type' => 'application/json',
-# 'Authorization' => "Bearer #{api_key}"
-# }
-# }
-# @body = {
-# model:,
-# messages: [{ role: 'user', content: message }],
-# max_tokens: 50
-# }
-# @api_url = 'https://api.openai.com/v1/chat/completions'
-# @message = message
-# end
-
-# def call
-# response = HTTParty.post(api_url, body: body.to_json, headers: options[:headers], timeout: 10)
-# raise response['error']['message'] unless response.code == 200
-
-# response['choices'][0]['message']['content']
-# end
-
-# class << self
-# def call(message)
-# new(message).call
-# end
-# end
-# end
diff --git a/llm_process_prompt.txt b/llm_process_prompt.txt
new file mode 100644
index 000000000..110c434cd
--- /dev/null
+++ b/llm_process_prompt.txt
@@ -0,0 +1,21 @@
+Based on the following event:
+*replace_with_event*
+
+and based on the following collections:
+*replace_with_collections*
+
+and the following curation criteria:
+Is this event useful for anyone rather than only people from a specific institution?
+Is this event centered around research?
+
+Give me a json describing a research themed event with the following format:
+
+title (string): The title of the event
+description (string): A description of what will happen at the event
+start (datetime): The local starting time of the event
+end (datetime): The local end time of the event
+venue (string): The venue where the event is hosted
+keywords (array of strings): A set of keywords based which the event can be filtered
+target_audience (array of strings): The target audience for this event
+collections (array of strings): Which collections from the given list the event should be added to
+curation (bool): Whether or not the event is relevant according to the curation criteria
diff --git a/beepboop.txt b/llm_scrape_prompt.txt
similarity index 83%
rename from beepboop.txt
rename to llm_scrape_prompt.txt
index 735845b9e..398c3aac1 100644
--- a/beepboop.txt
+++ b/llm_scrape_prompt.txt
@@ -1,13 +1,14 @@
+Based on the following webpage describing a research event:
+*replace_with_event_page*
+
Give me a json describing a research themed event with the following format:
title (string): The title of the event
-url (string): The url where the event is described
organizer (string): The organisation that hosts the event
description (string): A description of what will happen at the event
start (datetime): The local starting time of the event
end (datetime): The local end time of the event
timezone (string): The timezone for which the start and end are filled in
venue (string): The venue where the event is hosted
-source (string): The organisation whose website this event is scraped from
keywords (array of strings): A set of keywords based which the event can be filtered
target_audience (array of strings): The target audience for this event
From 03d7b4f84219b8d26acc2044fcab442a481865f2 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 21 Feb 2024 11:47:32 +0100
Subject: [PATCH 03/37] working start to finish gpt scraper
---
lib/ingestors/gpt_ingestor.rb | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/lib/ingestors/gpt_ingestor.rb b/lib/ingestors/gpt_ingestor.rb
index 3834410a4..a7a503c00 100644
--- a/lib/ingestors/gpt_ingestor.rb
+++ b/lib/ingestors/gpt_ingestor.rb
@@ -25,40 +25,39 @@ def read(url)
private
- def process_gpt(_url)
+ def process_gpt(_url) # rubocop:disable Metrics
# dans HTML
sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='nieuws_detail_row']")
- beep_func(event_page)
+ beep_func(url, event_page)
# nwo HTML
sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
url = 'https://www.nwo.nl/en/meetings'
event_page = Nokogiri::HTML5.parse(open_url("#{url}?page=0", raise: true)).css('.overviewContent > .listing-cards > li.list-item')[3]
- beep_func(event_page)
+ beep_func(url, event_page)
# rug HTML
sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
url = 'https://www.rug.nl/about-ug/latest-news/events/calendar/2023/phallus-tentoonstelling'
event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[class='rug-mb']")[0].css("div[itemtype='https://schema.org/Event']")
- beep_func(event_page)
+ beep_func(url, event_page)
# tdcc HTML
sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
url = 'https://tdcc.nl/evenementen/teaming-up-across-domains/'
event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css('article')[0]
- beep_func(event_page)
+ beep_func(url, event_page)
# json not necessary (SURF, UvA)
# XML not necessary (wur)
end
- def beep_func(event_page) # rubocop:disable Metrics
- prompt = File.read('llm_scrape_prompt.txt')
+ def beep_func(url, event_page) # rubocop:disable Metrics
event_page.css('script, link').each { |node| node.remove }
event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
- response = ChatgptService.new.scrape(event_page, prompt).dig('choices', 0, 'message', 'content')
+ response = ChatgptService.new.scrape(event_page).dig('choices', 0, 'message', 'content')
puts response
response_json = JSON.parse(response)
begin
@@ -66,6 +65,7 @@ def beep_func(event_page) # rubocop:disable Metrics
response_json.each_key do |key|
event[key] = response_json[key]
end
+ event.url = url
event.source = 'GPT'
event.timezone = 'Amsterdam'
add_event(event)
From 14132f0cff0dea3c1c8ebdc7c283f99dac941225 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 23 Feb 2024 13:03:46 +0100
Subject: [PATCH 04/37] working semi scraper
---
db/migrate/20240220144246_add_llm_check.rb | 2 +
db/schema.rb | 10 ++-
lib/ingestors/gpt_ingestor.rb | 81 +++++++++++++++++-----
lib/modules/chatgpt_service.rb | 19 ++---
llm_process_prompt.txt | 43 +++++++++---
llm_scrape_prompt.txt | 11 +--
6 files changed, 116 insertions(+), 50 deletions(-)
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
index 4e0d737db..efa92cfd3 100644
--- a/db/migrate/20240220144246_add_llm_check.rb
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -1,12 +1,14 @@
class AddLlmCheck < ActiveRecord::Migration[7.0]
def up
add_column :events, :llm_processed, :bool, default: false
+ add_column :events, :open_science, :string, array: true, default: []
add_column :events, :curation, :bool, default: true
add_column :materials, :llm_processed, :bool, default: false
end
def down
remove_column :events, :llm_processed, :bool, default: false
+ remove_column :events, :open_science, :string, array: true, default: []
remove_column :events, :curation, :bool, default: true
remove_column :materials, :llm_processed, :bool, default: false
end
diff --git a/db/schema.rb b/db/schema.rb
index cada47ae8..6e9617026 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2023_10_13_134117) do
+ActiveRecord::Schema[7.0].define(version: 2024_02_20_144246) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -104,8 +104,8 @@
t.bigint "resource_id"
t.text "comment"
t.integer "order"
- t.datetime "created_at", precision: 6, null: false
- t.datetime "updated_at", precision: 6, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.index ["collection_id"], name: "index_collection_items_on_collection_id"
t.index ["resource_type", "resource_id"], name: "index_collection_items_on_resource"
end
@@ -226,6 +226,9 @@
t.string "cost_basis"
t.string "cost_currency"
t.string "fields", default: [], array: true
+ t.boolean "llm_processed", default: false
+ t.string "open_science", default: [], array: true
+ t.boolean "curation", default: true
t.index ["presence"], name: "index_events_on_presence"
t.index ["slug"], name: "index_events_on_slug", unique: true
t.index ["user_id"], name: "index_events_on_user_id"
@@ -304,6 +307,7 @@
t.text "contact"
t.text "learning_objectives"
t.string "fields", default: [], array: true
+ t.boolean "llm_processed", default: false
t.index ["content_provider_id"], name: "index_materials_on_content_provider_id"
t.index ["slug"], name: "index_materials_on_slug", unique: true
t.index ["user_id"], name: "index_materials_on_user_id"
diff --git a/lib/ingestors/gpt_ingestor.rb b/lib/ingestors/gpt_ingestor.rb
index a7a503c00..a39e3a867 100644
--- a/lib/ingestors/gpt_ingestor.rb
+++ b/lib/ingestors/gpt_ingestor.rb
@@ -25,51 +25,96 @@ def read(url)
private
- def process_gpt(_url) # rubocop:disable Metrics
- # dans HTML
+ def scrape_dans
sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='nieuws_detail_row']")
beep_func(url, event_page)
+ end
- # nwo HTML
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ def scrape_nwo # rubocop:disable Metrics
+ # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ # url = 'https://www.nwo.nl/en/meetings/dualis-event-in-utrecht'
+ # event_page = Nokogiri::HTML5.parse(open_url(url, raise: true)).css('body').css('main')[0].css('article')
+ # beep_func(url, event_page)
url = 'https://www.nwo.nl/en/meetings'
- event_page = Nokogiri::HTML5.parse(open_url("#{url}?page=0", raise: true)).css('.overviewContent > .listing-cards > li.list-item')[3]
- beep_func(url, event_page)
+ 4.times.each do |i| # always check the first 4 pages, # of pages could be increased if needed
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ event_page = Nokogiri::HTML5.parse(open_url("#{url}?page=#{i}", raise: true)).css('.overviewContent')[0].css('li.list-item').css('a')
+ event_page.each do |event_data|
+ new_url = "https://www.nwo.nl#{event_data['href']}"
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ new_event_page = Nokogiri::HTML5.parse(open_url(new_url, raise: true)).css('body').css('main')[0].css('article')
+ beep_func(new_url, new_event_page)
+ end
+ end
+ end
- # rug HTML
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
- url = 'https://www.rug.nl/about-ug/latest-news/events/calendar/2023/phallus-tentoonstelling'
- event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[class='rug-mb']")[0].css("div[itemtype='https://schema.org/Event']")
- beep_func(url, event_page)
+ def scrape_rug # rubocop:disable Metrics
+ # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ # url = 'https://www.rug.nl/about-ug/latest-news/events/calendar/2023/phallus-tentoonstelling'
+ # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
+ # beep_func(url, event_page)
+ url = 'https://www.rug.nl/wubbo-ockels-school/calendar/2024/'
+ # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body')[0].css("div[class='rug-mb']")[0].css("div[itemtype='https://schema.org/Event']")
+ event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
+ event_page.each do |event_data|
+ new_url = event_data.css("meta[itemprop='url']")[0].get_attribute('content')
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ new_event_page = Nokogiri::HTML5.parse(open_url(new_url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
+ beep_func(new_url, new_event_page)
+ end
+ end
- # tdcc HTML
+ def scrape_tdcc
sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
url = 'https://tdcc.nl/evenementen/teaming-up-across-domains/'
event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css('article')[0]
beep_func(url, event_page)
+ end
+ def process_gpt(_url)
+ scrape_dans
+ scrape_nwo
+ scrape_rug
+ scrape_tdcc
# json not necessary (SURF, UvA)
# XML not necessary (wur)
end
+ def unload_json(event, response)
+ response_json = JSON.parse(response)
+ response_json.each_key do |key|
+ event[key] = response_json[key]
+ end
+ event
+ end
+
+ def scrape_func(event, event_page)
+ response = ChatgptService.new.scrape(event_page).dig('choices', 0, 'message', 'content')
+ puts response
+ unload_json(event, response)
+ end
+
+ def post_process_func(event)
+ response = ChatgptService.new.process(event).dig('choices', 0, 'message', 'content')
+ puts response
+ unload_json(event, response)
+ end
+
def beep_func(url, event_page) # rubocop:disable Metrics
event_page.css('script, link').each { |node| node.remove }
event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
- response = ChatgptService.new.scrape(event_page).dig('choices', 0, 'message', 'content')
- puts response
- response_json = JSON.parse(response)
begin
event = OpenStruct.new
- response_json.each_key do |key|
- event[key] = response_json[key]
- end
+ event = scrape_func(event, event_page)
+ event = post_process_func(event)
event.url = url
event.source = 'GPT'
event.timezone = 'Amsterdam'
add_event(event)
rescue Exception => e
+ puts e
@messages << "Extract event fields failed with: #{e.message}"
end
end
diff --git a/lib/modules/chatgpt_service.rb b/lib/modules/chatgpt_service.rb
index 827071cf1..c7be0d72c 100644
--- a/lib/modules/chatgpt_service.rb
+++ b/lib/modules/chatgpt_service.rb
@@ -7,7 +7,8 @@ def initialize
@client = OpenAI::Client.new(access_token: api_key)
@params = {
# max_tokens: 50,
- model: 'gpt-3.5-turbo-1106',
+ # model: 'gpt-3.5-turbo-1106',
+ model: 'gpt-4',
temperature: 0.7
}
end
@@ -16,7 +17,7 @@ def run(content)
beep = content
params = @params.merge(
{
- response_format: { type: 'json_object' },
+ # response_format: { type: 'json_object' },
messages: [{ role: 'user', content: beep }]
}
)
@@ -38,14 +39,10 @@ def scrape(event_page)
run(content)
end
- def process(event, collections)
- event_attrs = %i[title description venue start end keywords target_audience]
- collection_attrs = %i[title description keywords]
- event_json = JSON.generate(event.to_json(only: event_attrs))
- collections_json = JSON.generate(collections.map { |col| [col.id, col.to_json(only: collection_attrs)] }.to_h)
+ def process(event)
+ event_json = JSON.generate(event.to_json)
content = File.read('llm_process_prompt.txt')
.gsub('*replace_with_event*', event_json)
- .gsub('*replace_with_collections*', collections_json)
run(content)
end
@@ -69,11 +66,7 @@ def scrape # rubocop:disable Metrics
def process
event_json = ChatgptService.scrape
event = Event.new(event_json)
- collections = [
- Collection.new(title: 'Python stuff', description: 'Anything concerning the python programming language', keywords: %w[python programming IT]),
- Collection.new(title: 'Open hours on mondays', description: 'All open hours that happen on the first day of the week', keywords: %w[Monday questions])
- ]
- response = new.process(event, collections).dig('choices', 0, 'message', 'content')
+ response = new.process(event).dig('choices', 0, 'message', 'content')
puts response
JSON.parse(response)
end
diff --git a/llm_process_prompt.txt b/llm_process_prompt.txt
index 110c434cd..37a45d2e4 100644
--- a/llm_process_prompt.txt
+++ b/llm_process_prompt.txt
@@ -1,21 +1,42 @@
Based on the following event:
*replace_with_event*
-and based on the following collections:
-*replace_with_collections*
-
and the following curation criteria:
Is this event useful for anyone rather than only people from a specific institution?
Is this event centered around research?
-Give me a json describing a research themed event with the following format:
+Give me a json describing a research themed event with the following format.
+Strictly adhere to the provided options if applicable without introducing new categories or combinations of words.
+Fill the keywords attributes with with ['domain agnostic'] if all options are relevant.
+If a specified option is not applicable or missing, fill it with null.
+The options are defined below between quotation marks. Options are separated by commas.
title (string): The title of the event
-description (string): A description of what will happen at the event
-start (datetime): The local starting time of the event
-end (datetime): The local end time of the event
-venue (string): The venue where the event is hosted
-keywords (array of strings): A set of keywords based which the event can be filtered
-target_audience (array of strings): The target audience for this event
-collections (array of strings): Which collections from the given list the event should be added to
+keywords (array of strings): A set of keywords based which the event can be filtered.
+target_audience (array of strings): The target audience for this event.
+open_science (array of strings): The type of open science that this event advocates for, if any.
curation (bool): Whether or not the event is relevant according to the curation criteria
+
+keywords options:
+[
+ 'natural & engineering sciences',
+ 'humanities & social sciences',
+ 'life sciences',
+]
+target_audience options:
+[
+ 'researchers',
+ 'research support staff',
+ 'bachelor & master students',
+ 'PhD candidates',
+ 'teaching staff',
+ 'other'
+]
+
+open_science options:
+[
+ 'open software',
+ 'FAIR data',
+ 'Open Access,
+ 'citizen science',
+]
diff --git a/llm_scrape_prompt.txt b/llm_scrape_prompt.txt
index 398c3aac1..7321af8d3 100644
--- a/llm_scrape_prompt.txt
+++ b/llm_scrape_prompt.txt
@@ -1,3 +1,4 @@
+Prompt Scraper:
Based on the following webpage describing a research event:
*replace_with_event_page*
@@ -6,9 +7,9 @@ Give me a json describing a research themed event with the following format:
title (string): The title of the event
organizer (string): The organisation that hosts the event
description (string): A description of what will happen at the event
-start (datetime): The local starting time of the event
-end (datetime): The local end time of the event
-timezone (string): The timezone for which the start and end are filled in
+start (date or datetime): The local starting time of the event
+end (date or datetime): The local end time of the event
venue (string): The venue where the event is hosted
-keywords (array of strings): A set of keywords based which the event can be filtered
-target_audience (array of strings): The target audience for this event
+
+Instead of generating values for missing attributes, fill them with null.
+Do not change the wording of the description please.
From 18e889e54d13517ba14a1d3ddcb1d81c11063811 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 20 Mar 2024 10:26:58 +0100
Subject: [PATCH 05/37] update migration
---
db/migrate/20240220144246_add_llm_check.rb | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
index efa92cfd3..c80bc4201 100644
--- a/db/migrate/20240220144246_add_llm_check.rb
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -1,13 +1,25 @@
class AddLlmCheck < ActiveRecord::Migration[7.0]
def up
- add_column :events, :llm_processed, :bool, default: false
+ create_table :llm_object do |t|
+ t.references :events, foreign_key: true
+ t.datetime :created_at
+ t.datetime :updated_at
+ t.string :scrape_or_process
+ t.string :model
+ t.string :model_version
+ t.string :prompt
+ t.string :input
+ t.string :output
+ end
+ add_reference :events, :llm_object, foreign_key: true
add_column :events, :open_science, :string, array: true, default: []
add_column :events, :curation, :bool, default: true
add_column :materials, :llm_processed, :bool, default: false
end
def down
- remove_column :events, :llm_processed, :bool, default: false
+ drop_table :llm_object
+ remove_reference :events, :llm_object, foreign_key: true
remove_column :events, :open_science, :string, array: true, default: []
remove_column :events, :curation, :bool, default: true
remove_column :materials, :llm_processed, :bool, default: false
From 210920a82c8254da91b05b1134492bd3dac2d115 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 20 Mar 2024 10:44:51 +0100
Subject: [PATCH 06/37] fill llm object on scrape
---
db/migrate/20240220144246_add_llm_check.rb | 1 -
lib/ingestors/gpt_ingestor.rb | 14 +++-
lib/modules/chatgpt_service.rb | 28 +++++--
lib/tasks/tess.rake | 87 +++++++++++-----------
llm_scrape_prompt.txt | 1 -
5 files changed, 76 insertions(+), 55 deletions(-)
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
index c80bc4201..12af36213 100644
--- a/db/migrate/20240220144246_add_llm_check.rb
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -6,7 +6,6 @@ def up
t.datetime :updated_at
t.string :scrape_or_process
t.string :model
- t.string :model_version
t.string :prompt
t.string :input
t.string :output
diff --git a/lib/ingestors/gpt_ingestor.rb b/lib/ingestors/gpt_ingestor.rb
index a39e3a867..c07996ce0 100644
--- a/lib/ingestors/gpt_ingestor.rb
+++ b/lib/ingestors/gpt_ingestor.rb
@@ -91,15 +91,21 @@ def unload_json(event, response)
end
def scrape_func(event, event_page)
- response = ChatgptService.new.scrape(event_page).dig('choices', 0, 'message', 'content')
+ llm_service = ChatgptService.new
+ response = llm_service.scrape(event_page).dig('choices', 0, 'message', 'content')
puts response
- unload_json(event, response)
+ event = unload_json(event, response)
+ event.llm_object = llm_service.llm_object
+ event
end
def post_process_func(event)
- response = ChatgptService.new.process(event).dig('choices', 0, 'message', 'content')
+ llm_service = ChatgptService.new
+ response = llm_service.process(event).dig('choices', 0, 'message', 'content')
puts response
- unload_json(event, response)
+ event = unload_json(event, response)
+ event.llm_object = llm_service.llm_object
+ event
end
def beep_func(url, event_page) # rubocop:disable Metrics
diff --git a/lib/modules/chatgpt_service.rb b/lib/modules/chatgpt_service.rb
index c7be0d72c..e747cb2c1 100644
--- a/lib/modules/chatgpt_service.rb
+++ b/lib/modules/chatgpt_service.rb
@@ -13,6 +13,16 @@ def initialize
}
end
+ def llm_object
+ LlmObject.new(
+ scrape_or_process: @scrape_or_process,
+ model: @params[:model],
+ prompt: @prompt,
+ input: @input,
+ output: @output
+ )
+ end
+
def run(content)
beep = content
params = @params.merge(
@@ -34,16 +44,22 @@ def call(prompt)
end
def scrape(event_page)
- content = File.read('llm_scrape_prompt.txt')
- .gsub('*replace_with_event_page*', event_page)
- run(content)
+ @scrape_or_process = 'scrape'
+ @prompt = File.read('llm_scrape_prompt.txt')
+ @input = event_page
+ content = @prompt.gsub('*replace_with_event_page*', event_page)
+ @output = run(content)
+ @output
end
def process(event)
+ @scrape_or_process = 'process'
event_json = JSON.generate(event.to_json)
- content = File.read('llm_process_prompt.txt')
- .gsub('*replace_with_event*', event_json)
- run(content)
+ @prompt = File.read('llm_process_prompt.txt')
+ @input = event_json
+ content = @prompt.gsub('*replace_with_event*', event_json)
+ @output = run(content)
+ @output
end
class << self
diff --git a/lib/tasks/tess.rake b/lib/tasks/tess.rake
index cd6f6a4f8..c1e6195f6 100644
--- a/lib/tasks/tess.rake
+++ b/lib/tasks/tess.rake
@@ -1,9 +1,7 @@
require 'yaml'
-require 'set'
namespace :tess do
-
- task :remove_spam_activities, [:type] => [:environment] do |t, args|
+ task :remove_spam_activities, [:type] => [:environment] do |_t, args|
types = args[:type] ? [args[:type].constantize] : [Node, Workflow, ContentProvider, Material, Event]
total_deleted_count = 0
total_activity_count = PublicActivity::Activity.count
@@ -11,7 +9,7 @@ namespace :tess do
types.each do |type|
deleted_count = 0
- records = (type == Event) ? type.all.not_finished : type.all
+ records = type == Event ? type.all.not_finished : type.all
puts "Looking at #{records.count} #{type.name.pluralize}:"
records.each do |record|
##########
@@ -34,13 +32,11 @@ namespace :tess do
# are the same value (when sorted). If so, delete the newer one.
grouped.each_value do |activities|
activities.to_a.unshift(nil).reverse.each_cons(2) do |newer, older|
- if newer && older
- if newer.parameters[:new_val].length == older.parameters[:new_val].length &&
- newer.parameters[:new_val].sort == older.parameters[:new_val].sort
- newer.destroy
- deleted_count += 1
- end
- end
+ next unless newer && older && (newer.parameters[:new_val].length == older.parameters[:new_val].length &&
+ newer.parameters[:new_val].sort == older.parameters[:new_val].sort)
+
+ newer.destroy
+ deleted_count += 1
end
end
@@ -50,12 +46,12 @@ namespace :tess do
updates.each do |activity|
# Have to do this very awkward query due to `update_parameter` activities being created separately from
# `update` activities and not necessarily at the same time!
- if record.activities.where(key: "#{type.name.underscore}.update_parameter").
- where('id < ?', activity.id).
- where('created_at > ?', (activity.created_at - 2.seconds)).none?
- activity.destroy
- deleted_count += 1
- end
+ next unless record.activities.where(key: "#{type.name.underscore}.update_parameter")
+ .where('id < ?', activity.id)
+ .where('created_at > ?', (activity.created_at - 2.seconds)).none?
+
+ activity.destroy
+ deleted_count += 1
end
print '.'
end
@@ -66,10 +62,10 @@ namespace :tess do
puts
puts "Deleted #{total_deleted_count} activities in total"
- puts "Done"
+ puts 'Done'
end
- desc "Populates the database with Node information from a JSON document"
+ desc 'Populates the database with Node information from a JSON document'
task load_node_json: :environment do
path = File.join(Rails.root, 'config', 'data', 'elixir_nodes.json')
@@ -79,7 +75,7 @@ namespace :tess do
nodes = Node.load_from_hash(hash, verbose: true)
puts "#{nodes.select(&:valid?).count}/#{nodes.count} succeeded"
- puts "Done"
+ puts 'Done'
end
task download_images: :environment do
@@ -91,12 +87,10 @@ namespace :tess do
puts "Downloading #{downloadable.length} images for #{klass.name}s"
downloadable.each do |resource|
- begin
- resource.save!
- rescue Exception => e
- puts "Exception occurred fetching image for #{klass.name} ID: #{resource.id}"
- raise e
- end
+ resource.save!
+ rescue Exception => e
+ puts "Exception occurred fetching image for #{klass.name} ID: #{resource.id}"
+ raise e
end
puts
else
@@ -106,7 +100,7 @@ namespace :tess do
ensure
ActiveRecord::Base.record_timestamps = true
end
- puts "Done"
+ puts 'Done'
end
task expire_sessions: :environment do
@@ -123,7 +117,7 @@ namespace :tess do
sub.process
print '.'
end
- puts " Done"
+ puts ' Done'
end
task reset_subscriptions: :environment do
@@ -133,7 +127,7 @@ namespace :tess do
sub.reset_due
print '.'
end
- puts " Done"
+ puts ' Done'
end
desc 'run generic ingestion process'
@@ -145,9 +139,17 @@ namespace :tess do
puts "Finished successfully, output written to: #{log.path}"
end
+ desc 'run LLM post processing'
+ task llm_post_processing: :environment do
+ end
+
+ desc 'open all events to being llm processed again'
+ task reset_llm_status: :environment do
+ end
+
desc 'check and update time zones'
task check_timezones: :environment do
- puts "Task: check_timezones - start"
+ puts 'Task: check_timezones - start'
overrides = { 'AEDT' => 'Sydney',
'AEST' => 'Sydney' }
begin
@@ -162,11 +164,11 @@ namespace :tess do
event.check_timezone
event.timezone = overrides[event.timezone] if overrides.keys.include? event.timezone
if event.save
- unless event.timezone == pre_tz
+ if event.timezone == pre_tz
+ unchanged += 1
+ else
updated += 1
messages << "event[#{event.title}] updated to timezone[#{event.timezone}]"
- else
- unchanged += 1
end
else
failed += 1
@@ -179,7 +181,7 @@ namespace :tess do
end
messages.each { |m| puts m }
puts "Task: check_timezones - processed[#{processed}] unchanged[#{unchanged}] updated[#{updated}] failed[#{failed}]"
- puts "Task: check_timezones - finished."
+ puts 'Task: check_timezones - finished.'
end
desc 'Fetch and convert SPDX licenses from GitHub'
@@ -193,20 +195,20 @@ namespace :tess do
'title' => 'License Not Specified'
},
'other-at' => {
- 'title' => "Other (Attribution)"
+ 'title' => 'Other (Attribution)'
},
'other-closed' => {
- 'title' => "Other (Not Open)"
+ 'title' => 'Other (Not Open)'
},
'other-nc' => {
- 'title' => "Other (Non-Commercial)"
+ 'title' => 'Other (Non-Commercial)'
},
'other-open' => {
- 'title' => "Other (Open)"
+ 'title' => 'Other (Open)'
},
'other-pd' => {
- 'title' => "Other (Public Domain)"
- },
+ 'title' => 'Other (Public Domain)'
+ }
}
hash['licenses'].each do |license|
id = license.delete('licenseId')
@@ -214,9 +216,7 @@ namespace :tess do
transformed[id] = license.transform_keys(&:underscore)
# Supplement with URLs from old licences dictionary
old_url = old_licenses.dig(id, 'url')
- unless old_url.blank? || transformed[id]['see_also'].include?(old_url)
- transformed[id]['see_also'] << old_url
- end
+ transformed[id]['see_also'] << old_url unless old_url.blank? || transformed[id]['see_also'].include?(old_url)
end
File.write(File.join(Rails.root, 'config', 'dictionaries', 'licences.yml'), transformed.to_yaml)
@@ -234,6 +234,7 @@ namespace :tess do
suggestions.each do |field, values|
next unless values.any?
+
puts "Updating #{field} suggestions..."
count = AutocompleteSuggestion.refresh(field, *values)
puts " Deleted #{count} redundant suggestions" if count > 0
diff --git a/llm_scrape_prompt.txt b/llm_scrape_prompt.txt
index 7321af8d3..dfbe68ba3 100644
--- a/llm_scrape_prompt.txt
+++ b/llm_scrape_prompt.txt
@@ -1,4 +1,3 @@
-Prompt Scraper:
Based on the following webpage describing a research event:
*replace_with_event_page*
From 387ee354668d86446369118050b9747f3af75088 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 20 Mar 2024 11:35:33 +0100
Subject: [PATCH 07/37] post processing rake task
---
lib/tasks/tess.rake | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/lib/tasks/tess.rake b/lib/tasks/tess.rake
index c1e6195f6..d4de838ce 100644
--- a/lib/tasks/tess.rake
+++ b/lib/tasks/tess.rake
@@ -141,6 +141,13 @@ namespace :tess do
desc 'run LLM post processing'
task llm_post_processing: :environment do
+ prompt = File.read('llm_process_prompt.txt')
+ Events.each do |event|
+ unless event&.llm_object&.prompt == prompt
+ event = GptIngestor.new.post_process_func(event)
+ event.save!
+ end
+ end
end
desc 'open all events to being llm processed again'
From b005528061d3c5c87ced16ebba48c4eeb43be3f3 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 20 Mar 2024 12:02:51 +0100
Subject: [PATCH 08/37] llm_object model
---
app/models/event.rb | 40 ++++++++++++++++++----------------------
app/models/llm_object.rb | 8 ++++++++
2 files changed, 26 insertions(+), 22 deletions(-)
create mode 100644 app/models/llm_object.rb
diff --git a/app/models/event.rb b/app/models/event.rb
index 0fce3b6b8..d7f5bfaf1 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -108,6 +108,7 @@ class Event < ApplicationRecord
enum presence: { onsite: 0, online: 1, hybrid: 2 }
belongs_to :user
+ has_one :llm_object
has_one :edit_suggestion, as: :suggestible, dependent: :destroy
has_one :link_monitor, as: :lcheck, dependent: :destroy
has_many :collection_items, as: :resource
@@ -119,7 +120,7 @@ class Event < ApplicationRecord
has_ontology_terms(:scientific_topics, branch: OBO_EDAM.topics)
has_ontology_terms(:operations, branch: OBO_EDAM.operations)
- has_many :stars, as: :resource, dependent: :destroy
+ has_many :stars, as: :resource, dependent: :destroy
auto_strip_attributes :title, :description, :url, squish: false
@@ -260,14 +261,15 @@ def set_default_times
self.start = start + 9.hours if start.hour == 0 # hour set to 0 if not otherwise defined...
- unless self.end
- if online?
- self.end = start + 1.hour
- else
- diff = 17 - start.hour
- self.end = start + diff.hours
- end
+ return if self.end
+
+ if online?
+ self.end = start + 1.hour
+ else
+ diff = 17 - start.hour
+ self.end = start + diff.hours
end
+
# TODO: Set timezone for online events. Where to get it from, though?
# TODO: Check events form to add timezone autocomplete.
# Get timezones from: https://timezonedb.com/download
@@ -302,13 +304,9 @@ def self.check_exists(event_params)
scope = provider_id.present? ? where(content_provider_id: provider_id) : all
- if given_event.url.present?
- event = scope.where(url: given_event.url).last
- end
+ event = scope.where(url: given_event.url).last if given_event.url.present?
- if given_event.title.present? && given_event.start.present?
- event ||= where(content_provider_id: provider_id, title: given_event.title, start: given_event.start).last
- end
+ event ||= where(content_provider_id: provider_id, title: given_event.title, start: given_event.start).last if given_event.title.present? && given_event.start.present?
event
end
@@ -369,7 +367,7 @@ def geocoding_api_lookup
location = address
# result = Geocoder.search(location).first
- args = { postalcode: postcode, city: city, county: county, country: country, format: 'json' }
+ args = { postalcode: postcode, city:, county:, country:, format: 'json' }
result = nominatim_lookup(args)
if result
self.latitude = result[:lat]
@@ -435,14 +433,14 @@ def duplicate
external_resources.each do |er|
c.external_resources.build(url: er.url, title: er.title)
end
- [:materials, :scientific_topics, :operations, :nodes].each do |field|
+ %i[materials scientific_topics operations nodes].each do |field|
c.send("#{field}=", send(field))
end
c
end
- def online= value
+ def online=(value)
value = :online if value.is_a?(TrueClass) || value == '1' || value == 1 || value == 'true'
value = :onsite if value.is_a?(FalseClass) || value == '0' || value == 0 || value == 'false'
self.presence = value
@@ -489,17 +487,15 @@ def fix_keywords
[
[TargetAudienceDictionary, :target_audience],
[EventTypeDictionary, :event_types],
- [EligibilityDictionary, :eligibility],
+ [EligibilityDictionary, :eligibility]
].each do |dict, var|
- if self[var].blank?
- self[var] = []
- end
+ self[var] = [] if self[var].blank?
dic = dict.instance
self&.keywords&.dup&.each do |kw|
res = dic.best_match(kw)
if res
self[var].append(kw)
- self.keywords.delete(kw)
+ keywords.delete(kw)
end
end
end
diff --git a/app/models/llm_object.rb b/app/models/llm_object.rb
new file mode 100644
index 000000000..4584f633e
--- /dev/null
+++ b/app/models/llm_object.rb
@@ -0,0 +1,8 @@
+class LlmObject < ApplicationRecord
+ belongs_to :event
+ validates :scrape_or_process, presence: true
+ validates :model, presence: true
+ validates :prompt, presence: true
+ validates :input, presence: true
+ validates :output, presence: true
+end
From 5d02d71326977e73d75e58ac4e9296cefbb7289d Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Thu, 28 Mar 2024 11:50:31 +0100
Subject: [PATCH 09/37] fix curation visible name and build scalable class
system for llm service modules
---
config/tess.example.yml | 3 +
db/migrate/20240220144246_add_llm_check.rb | 4 +-
db/schema.rb | 970 +++++++++---------
lib/ingestors/ingestor_factory.rb | 2 +-
.../{gpt_ingestor.rb => llm_ingestor.rb} | 39 +-
lib/modules/chatgpt_service.rb | 35 +-
lib/modules/llm_service.rb | 68 ++
llm_process_prompt.txt | 2 +-
8 files changed, 573 insertions(+), 550 deletions(-)
rename lib/ingestors/{gpt_ingestor.rb => llm_ingestor.rb} (82%)
create mode 100644 lib/modules/llm_service.rb
diff --git a/config/tess.example.yml b/config/tess.example.yml
index 0a4ce0cc6..51451c741 100644
--- a/config/tess.example.yml
+++ b/config/tess.example.yml
@@ -115,6 +115,9 @@ default: &default
- CC-BY-NC-SA-4.0
- CC-BY-ND-4.0
- CC-BY-SA-4.0
+ llm_scraper:
+ model:
+ model_version:
development:
<<: *default
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
index 12af36213..4b942fa0d 100644
--- a/db/migrate/20240220144246_add_llm_check.rb
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -12,7 +12,7 @@ def up
end
add_reference :events, :llm_object, foreign_key: true
add_column :events, :open_science, :string, array: true, default: []
- add_column :events, :curation, :bool, default: true
+ add_column :events, :visible, :bool, default: true
add_column :materials, :llm_processed, :bool, default: false
end
@@ -20,7 +20,7 @@ def down
drop_table :llm_object
remove_reference :events, :llm_object, foreign_key: true
remove_column :events, :open_science, :string, array: true, default: []
- remove_column :events, :curation, :bool, default: true
+ remove_column :events, :visible, :bool, default: true
remove_column :materials, :llm_processed, :bool, default: false
end
end
diff --git a/db/schema.rb b/db/schema.rb
index 6e9617026..a33223047 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,552 +10,552 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2024_02_20_144246) do
+ActiveRecord::Schema[7.0].define(version: 20_240_220_144_246) do
# These are extensions that must be enabled in order to support this database
- enable_extension "plpgsql"
-
- create_table "activities", force: :cascade do |t|
- t.integer "trackable_id"
- t.string "trackable_type"
- t.integer "owner_id"
- t.string "owner_type"
- t.string "key"
- t.text "parameters"
- t.integer "recipient_id"
- t.string "recipient_type"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.index ["key"], name: "index_activities_on_key"
- t.index ["owner_id", "owner_type"], name: "index_activities_on_owner_id_and_owner_type"
- t.index ["recipient_id", "recipient_type"], name: "index_activities_on_recipient_id_and_recipient_type"
- t.index ["trackable_id", "trackable_type"], name: "index_activities_on_trackable_id_and_trackable_type"
+ enable_extension 'plpgsql'
+
+ create_table 'activities', force: :cascade do |t|
+ t.integer 'trackable_id'
+ t.string 'trackable_type'
+ t.integer 'owner_id'
+ t.string 'owner_type'
+ t.string 'key'
+ t.text 'parameters'
+ t.integer 'recipient_id'
+ t.string 'recipient_type'
+ t.datetime 'created_at'
+ t.datetime 'updated_at'
+ t.index ['key'], name: 'index_activities_on_key'
+ t.index %w[owner_id owner_type], name: 'index_activities_on_owner_id_and_owner_type'
+ t.index %w[recipient_id recipient_type], name: 'index_activities_on_recipient_id_and_recipient_type'
+ t.index %w[trackable_id trackable_type], name: 'index_activities_on_trackable_id_and_trackable_type'
end
- create_table "ahoy_events", force: :cascade do |t|
- t.bigint "visit_id"
- t.bigint "user_id"
- t.string "name"
- t.jsonb "properties"
- t.datetime "time"
- t.index ["name", "time"], name: "index_ahoy_events_on_name_and_time"
- t.index ["properties"], name: "index_ahoy_events_on_properties", opclass: :jsonb_path_ops, using: :gin
- t.index ["user_id"], name: "index_ahoy_events_on_user_id"
- t.index ["visit_id"], name: "index_ahoy_events_on_visit_id"
+ create_table 'ahoy_events', force: :cascade do |t|
+ t.bigint 'visit_id'
+ t.bigint 'user_id'
+ t.string 'name'
+ t.jsonb 'properties'
+ t.datetime 'time'
+ t.index %w[name time], name: 'index_ahoy_events_on_name_and_time'
+ t.index ['properties'], name: 'index_ahoy_events_on_properties', opclass: :jsonb_path_ops, using: :gin
+ t.index ['user_id'], name: 'index_ahoy_events_on_user_id'
+ t.index ['visit_id'], name: 'index_ahoy_events_on_visit_id'
end
- create_table "ahoy_visits", force: :cascade do |t|
- t.string "visit_token"
- t.string "visitor_token"
- t.bigint "user_id"
- t.string "ip"
- t.text "user_agent"
- t.text "referrer"
- t.string "referring_domain"
- t.text "landing_page"
- t.string "browser"
- t.string "os"
- t.string "device_type"
- t.string "country"
- t.string "region"
- t.string "city"
- t.float "latitude"
- t.float "longitude"
- t.string "utm_source"
- t.string "utm_medium"
- t.string "utm_term"
- t.string "utm_content"
- t.string "utm_campaign"
- t.string "app_version"
- t.string "os_version"
- t.string "platform"
- t.datetime "started_at"
- t.index ["user_id"], name: "index_ahoy_visits_on_user_id"
- t.index ["visit_token"], name: "index_ahoy_visits_on_visit_token", unique: true
+ create_table 'ahoy_visits', force: :cascade do |t|
+ t.string 'visit_token'
+ t.string 'visitor_token'
+ t.bigint 'user_id'
+ t.string 'ip'
+ t.text 'user_agent'
+ t.text 'referrer'
+ t.string 'referring_domain'
+ t.text 'landing_page'
+ t.string 'browser'
+ t.string 'os'
+ t.string 'device_type'
+ t.string 'country'
+ t.string 'region'
+ t.string 'city'
+ t.float 'latitude'
+ t.float 'longitude'
+ t.string 'utm_source'
+ t.string 'utm_medium'
+ t.string 'utm_term'
+ t.string 'utm_content'
+ t.string 'utm_campaign'
+ t.string 'app_version'
+ t.string 'os_version'
+ t.string 'platform'
+ t.datetime 'started_at'
+ t.index ['user_id'], name: 'index_ahoy_visits_on_user_id'
+ t.index ['visit_token'], name: 'index_ahoy_visits_on_visit_token', unique: true
end
- create_table "autocomplete_suggestions", force: :cascade do |t|
- t.string "field"
- t.string "value"
- t.index ["field", "value"], name: "index_autocomplete_suggestions_on_field_and_value", unique: true
+ create_table 'autocomplete_suggestions', force: :cascade do |t|
+ t.string 'field'
+ t.string 'value'
+ t.index %w[field value], name: 'index_autocomplete_suggestions_on_field_and_value', unique: true
end
- create_table "bans", force: :cascade do |t|
- t.integer "user_id"
- t.integer "banner_id"
- t.boolean "shadow"
- t.text "reason"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.index ["banner_id"], name: "index_bans_on_banner_id"
- t.index ["user_id"], name: "index_bans_on_user_id"
+ create_table 'bans', force: :cascade do |t|
+ t.integer 'user_id'
+ t.integer 'banner_id'
+ t.boolean 'shadow'
+ t.text 'reason'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.index ['banner_id'], name: 'index_bans_on_banner_id'
+ t.index ['user_id'], name: 'index_bans_on_user_id'
end
- create_table "collaborations", force: :cascade do |t|
- t.integer "user_id"
- t.integer "resource_id"
- t.string "resource_type"
- t.index ["resource_type", "resource_id"], name: "index_collaborations_on_resource_type_and_resource_id"
- t.index ["user_id"], name: "index_collaborations_on_user_id"
+ create_table 'collaborations', force: :cascade do |t|
+ t.integer 'user_id'
+ t.integer 'resource_id'
+ t.string 'resource_type'
+ t.index %w[resource_type resource_id], name: 'index_collaborations_on_resource_type_and_resource_id'
+ t.index ['user_id'], name: 'index_collaborations_on_user_id'
end
- create_table "collection_items", force: :cascade do |t|
- t.bigint "collection_id"
- t.string "resource_type"
- t.bigint "resource_id"
- t.text "comment"
- t.integer "order"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.index ["collection_id"], name: "index_collection_items_on_collection_id"
- t.index ["resource_type", "resource_id"], name: "index_collection_items_on_resource"
+ create_table 'collection_items', force: :cascade do |t|
+ t.bigint 'collection_id'
+ t.string 'resource_type'
+ t.bigint 'resource_id'
+ t.text 'comment'
+ t.integer 'order'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.index ['collection_id'], name: 'index_collection_items_on_collection_id'
+ t.index %w[resource_type resource_id], name: 'index_collection_items_on_resource'
end
- create_table "collections", force: :cascade do |t|
- t.string "title"
- t.text "description"
- t.text "image_url"
- t.boolean "public", default: true
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.integer "user_id"
- t.string "slug"
- t.string "keywords", default: [], array: true
- t.string "image_file_name"
- t.string "image_content_type"
- t.bigint "image_file_size"
- t.datetime "image_updated_at"
- t.index ["slug"], name: "index_collections_on_slug", unique: true
- t.index ["user_id"], name: "index_collections_on_user_id"
+ create_table 'collections', force: :cascade do |t|
+ t.string 'title'
+ t.text 'description'
+ t.text 'image_url'
+ t.boolean 'public', default: true
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.integer 'user_id'
+ t.string 'slug'
+ t.string 'keywords', default: [], array: true
+ t.string 'image_file_name'
+ t.string 'image_content_type'
+ t.bigint 'image_file_size'
+ t.datetime 'image_updated_at'
+ t.index ['slug'], name: 'index_collections_on_slug', unique: true
+ t.index ['user_id'], name: 'index_collections_on_user_id'
end
- create_table "content_providers", force: :cascade do |t|
- t.text "title"
- t.text "url"
- t.text "image_url"
- t.text "description"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "slug"
- t.string "keywords", default: [], array: true
- t.integer "user_id"
- t.integer "node_id"
- t.string "content_provider_type", default: "Organisation"
- t.string "image_file_name"
- t.string "image_content_type"
- t.bigint "image_file_size"
- t.datetime "image_updated_at"
- t.string "contact"
- t.index ["node_id"], name: "index_content_providers_on_node_id"
- t.index ["slug"], name: "index_content_providers_on_slug", unique: true
- t.index ["user_id"], name: "index_content_providers_on_user_id"
+ create_table 'content_providers', force: :cascade do |t|
+ t.text 'title'
+ t.text 'url'
+ t.text 'image_url'
+ t.text 'description'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'slug'
+ t.string 'keywords', default: [], array: true
+ t.integer 'user_id'
+ t.integer 'node_id'
+ t.string 'content_provider_type', default: 'Organisation'
+ t.string 'image_file_name'
+ t.string 'image_content_type'
+ t.bigint 'image_file_size'
+ t.datetime 'image_updated_at'
+ t.string 'contact'
+ t.index ['node_id'], name: 'index_content_providers_on_node_id'
+ t.index ['slug'], name: 'index_content_providers_on_slug', unique: true
+ t.index ['user_id'], name: 'index_content_providers_on_user_id'
end
- create_table "content_providers_users", id: false, force: :cascade do |t|
- t.bigint "content_provider_id"
- t.bigint "user_id"
- t.index ["content_provider_id", "user_id"], name: "provider_user_unique", unique: true
- t.index ["content_provider_id"], name: "index_content_providers_users_on_content_provider_id"
- t.index ["user_id"], name: "index_content_providers_users_on_user_id"
+ create_table 'content_providers_users', id: false, force: :cascade do |t|
+ t.bigint 'content_provider_id'
+ t.bigint 'user_id'
+ t.index %w[content_provider_id user_id], name: 'provider_user_unique', unique: true
+ t.index ['content_provider_id'], name: 'index_content_providers_users_on_content_provider_id'
+ t.index ['user_id'], name: 'index_content_providers_users_on_user_id'
end
- create_table "edit_suggestions", force: :cascade do |t|
- t.text "name"
- t.text "text"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.integer "suggestible_id"
- t.string "suggestible_type"
- t.json "data_fields", default: {}
- t.index ["suggestible_id", "suggestible_type"], name: "index_edit_suggestions_on_suggestible_id_and_suggestible_type"
+ create_table 'edit_suggestions', force: :cascade do |t|
+ t.text 'name'
+ t.text 'text'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.integer 'suggestible_id'
+ t.string 'suggestible_type'
+ t.json 'data_fields', default: {}
+ t.index %w[suggestible_id suggestible_type], name: 'index_edit_suggestions_on_suggestible_id_and_suggestible_type'
end
- create_table "event_materials", force: :cascade do |t|
- t.integer "event_id"
- t.integer "material_id"
- t.index ["event_id"], name: "index_event_materials_on_event_id"
- t.index ["material_id"], name: "index_event_materials_on_material_id"
+ create_table 'event_materials', force: :cascade do |t|
+ t.integer 'event_id'
+ t.integer 'material_id'
+ t.index ['event_id'], name: 'index_event_materials_on_event_id'
+ t.index ['material_id'], name: 'index_event_materials_on_material_id'
end
- create_table "events", force: :cascade do |t|
- t.string "external_id"
- t.string "title"
- t.string "subtitle"
- t.string "url"
- t.string "organizer"
- t.text "description"
- t.datetime "start"
- t.datetime "end"
- t.string "sponsors", default: [], array: true
- t.text "venue"
- t.string "city"
- t.string "county"
- t.string "country"
- t.string "postcode"
- t.decimal "latitude", precision: 10, scale: 6
- t.decimal "longitude", precision: 10, scale: 6
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.text "source", default: "tess"
- t.string "slug"
- t.integer "content_provider_id"
- t.integer "user_id"
- t.integer "presence", default: 0
- t.decimal "cost_value"
- t.date "last_scraped"
- t.boolean "scraper_record", default: false
- t.string "keywords", default: [], array: true
- t.string "event_types", default: [], array: true
- t.string "target_audience", default: [], array: true
- t.integer "capacity"
- t.string "eligibility", default: [], array: true
- t.text "contact"
- t.string "host_institutions", default: [], array: true
- t.string "timezone"
- t.string "funding"
- t.integer "attendee_count"
- t.integer "applicant_count"
- t.integer "trainer_count"
- t.string "feedback"
- t.text "notes"
- t.integer "nominatim_count", default: 0
- t.string "duration"
- t.text "recognition"
- t.text "learning_objectives"
- t.text "prerequisites"
- t.text "tech_requirements"
- t.string "cost_basis"
- t.string "cost_currency"
- t.string "fields", default: [], array: true
- t.boolean "llm_processed", default: false
- t.string "open_science", default: [], array: true
- t.boolean "curation", default: true
- t.index ["presence"], name: "index_events_on_presence"
- t.index ["slug"], name: "index_events_on_slug", unique: true
- t.index ["user_id"], name: "index_events_on_user_id"
+ create_table 'events', force: :cascade do |t|
+ t.string 'external_id'
+ t.string 'title'
+ t.string 'subtitle'
+ t.string 'url'
+ t.string 'organizer'
+ t.text 'description'
+ t.datetime 'start'
+ t.datetime 'end'
+ t.string 'sponsors', default: [], array: true
+ t.text 'venue'
+ t.string 'city'
+ t.string 'county'
+ t.string 'country'
+ t.string 'postcode'
+ t.decimal 'latitude', precision: 10, scale: 6
+ t.decimal 'longitude', precision: 10, scale: 6
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.text 'source', default: 'tess'
+ t.string 'slug'
+ t.integer 'content_provider_id'
+ t.integer 'user_id'
+ t.integer 'presence', default: 0
+ t.decimal 'cost_value'
+ t.date 'last_scraped'
+ t.boolean 'scraper_record', default: false
+ t.string 'keywords', default: [], array: true
+ t.string 'event_types', default: [], array: true
+ t.string 'target_audience', default: [], array: true
+ t.integer 'capacity'
+ t.string 'eligibility', default: [], array: true
+ t.text 'contact'
+ t.string 'host_institutions', default: [], array: true
+ t.string 'timezone'
+ t.string 'funding'
+ t.integer 'attendee_count'
+ t.integer 'applicant_count'
+ t.integer 'trainer_count'
+ t.string 'feedback'
+ t.text 'notes'
+ t.integer 'nominatim_count', default: 0
+ t.string 'duration'
+ t.text 'recognition'
+ t.text 'learning_objectives'
+ t.text 'prerequisites'
+ t.text 'tech_requirements'
+ t.string 'cost_basis'
+ t.string 'cost_currency'
+ t.string 'fields', default: [], array: true
+ t.boolean 'llm_processed', default: false
+ t.string 'open_science', default: [], array: true
+ t.boolean 'visible', default: true
+ t.index ['presence'], name: 'index_events_on_presence'
+ t.index ['slug'], name: 'index_events_on_slug', unique: true
+ t.index ['user_id'], name: 'index_events_on_user_id'
end
- create_table "external_resources", force: :cascade do |t|
- t.integer "source_id"
- t.text "url"
- t.string "title"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "source_type"
- t.index ["source_id", "source_type"], name: "index_external_resources_on_source_id_and_source_type"
+ create_table 'external_resources', force: :cascade do |t|
+ t.integer 'source_id'
+ t.text 'url'
+ t.string 'title'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'source_type'
+ t.index %w[source_id source_type], name: 'index_external_resources_on_source_id_and_source_type'
end
- create_table "field_locks", force: :cascade do |t|
- t.integer "resource_id"
- t.string "resource_type"
- t.string "field"
- t.index ["resource_type", "resource_id"], name: "index_field_locks_on_resource_type_and_resource_id"
+ create_table 'field_locks', force: :cascade do |t|
+ t.integer 'resource_id'
+ t.string 'resource_type'
+ t.string 'field'
+ t.index %w[resource_type resource_id], name: 'index_field_locks_on_resource_type_and_resource_id'
end
- create_table "friendly_id_slugs", force: :cascade do |t|
- t.string "slug", null: false
- t.integer "sluggable_id", null: false
- t.string "sluggable_type", limit: 50
- t.string "scope"
- t.datetime "created_at"
- t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true
- t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type"
- t.index ["sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_id"
- t.index ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type"
+ create_table 'friendly_id_slugs', force: :cascade do |t|
+ t.string 'slug', null: false
+ t.integer 'sluggable_id', null: false
+ t.string 'sluggable_type', limit: 50
+ t.string 'scope'
+ t.datetime 'created_at'
+ t.index %w[slug sluggable_type scope], name: 'index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope', unique: true
+ t.index %w[slug sluggable_type], name: 'index_friendly_id_slugs_on_slug_and_sluggable_type'
+ t.index ['sluggable_id'], name: 'index_friendly_id_slugs_on_sluggable_id'
+ t.index ['sluggable_type'], name: 'index_friendly_id_slugs_on_sluggable_type'
end
- create_table "link_monitors", force: :cascade do |t|
- t.string "url"
- t.integer "code"
- t.datetime "failed_at"
- t.datetime "last_failed_at"
- t.integer "fail_count"
- t.integer "lcheck_id"
- t.string "lcheck_type"
- t.index ["lcheck_type", "lcheck_id"], name: "index_link_monitors_on_lcheck_type_and_lcheck_id"
+ create_table 'link_monitors', force: :cascade do |t|
+ t.string 'url'
+ t.integer 'code'
+ t.datetime 'failed_at'
+ t.datetime 'last_failed_at'
+ t.integer 'fail_count'
+ t.integer 'lcheck_id'
+ t.string 'lcheck_type'
+ t.index %w[lcheck_type lcheck_id], name: 'index_link_monitors_on_lcheck_type_and_lcheck_id'
end
- create_table "materials", force: :cascade do |t|
- t.text "title"
- t.string "url"
- t.string "doi"
- t.date "remote_updated_date"
- t.date "remote_created_date"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.text "description"
- t.string "target_audience", default: [], array: true
- t.string "authors", default: [], array: true
- t.string "contributors", default: [], array: true
- t.string "licence", default: "notspecified"
- t.string "difficulty_level", default: "notspecified"
- t.integer "content_provider_id"
- t.string "slug"
- t.integer "user_id"
- t.date "last_scraped"
- t.boolean "scraper_record", default: false
- t.string "resource_type", default: [], array: true
- t.string "keywords", default: [], array: true
- t.string "other_types"
- t.date "date_created"
- t.date "date_modified"
- t.date "date_published"
- t.text "prerequisites"
- t.string "version"
- t.string "status"
- t.text "syllabus"
- t.string "subsets", default: [], array: true
- t.text "contact"
- t.text "learning_objectives"
- t.string "fields", default: [], array: true
- t.boolean "llm_processed", default: false
- t.index ["content_provider_id"], name: "index_materials_on_content_provider_id"
- t.index ["slug"], name: "index_materials_on_slug", unique: true
- t.index ["user_id"], name: "index_materials_on_user_id"
+ create_table 'materials', force: :cascade do |t|
+ t.text 'title'
+ t.string 'url'
+ t.string 'doi'
+ t.date 'remote_updated_date'
+ t.date 'remote_created_date'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.text 'description'
+ t.string 'target_audience', default: [], array: true
+ t.string 'authors', default: [], array: true
+ t.string 'contributors', default: [], array: true
+ t.string 'licence', default: 'notspecified'
+ t.string 'difficulty_level', default: 'notspecified'
+ t.integer 'content_provider_id'
+ t.string 'slug'
+ t.integer 'user_id'
+ t.date 'last_scraped'
+ t.boolean 'scraper_record', default: false
+ t.string 'resource_type', default: [], array: true
+ t.string 'keywords', default: [], array: true
+ t.string 'other_types'
+ t.date 'date_created'
+ t.date 'date_modified'
+ t.date 'date_published'
+ t.text 'prerequisites'
+ t.string 'version'
+ t.string 'status'
+ t.text 'syllabus'
+ t.string 'subsets', default: [], array: true
+ t.text 'contact'
+ t.text 'learning_objectives'
+ t.string 'fields', default: [], array: true
+ t.boolean 'llm_processed', default: false
+ t.index ['content_provider_id'], name: 'index_materials_on_content_provider_id'
+ t.index ['slug'], name: 'index_materials_on_slug', unique: true
+ t.index ['user_id'], name: 'index_materials_on_user_id'
end
- create_table "node_links", force: :cascade do |t|
- t.integer "node_id"
- t.integer "resource_id"
- t.string "resource_type"
- t.index ["node_id"], name: "index_node_links_on_node_id"
- t.index ["resource_type", "resource_id"], name: "index_node_links_on_resource_type_and_resource_id"
+ create_table 'node_links', force: :cascade do |t|
+ t.integer 'node_id'
+ t.integer 'resource_id'
+ t.string 'resource_type'
+ t.index ['node_id'], name: 'index_node_links_on_node_id'
+ t.index %w[resource_type resource_id], name: 'index_node_links_on_resource_type_and_resource_id'
end
- create_table "nodes", force: :cascade do |t|
- t.string "name"
- t.string "member_status"
- t.string "country_code"
- t.string "home_page"
- t.string "twitter"
- t.string "carousel_images", array: true
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "slug"
- t.integer "user_id"
- t.text "image_url"
- t.text "description"
- t.index ["slug"], name: "index_nodes_on_slug", unique: true
- t.index ["user_id"], name: "index_nodes_on_user_id"
+ create_table 'nodes', force: :cascade do |t|
+ t.string 'name'
+ t.string 'member_status'
+ t.string 'country_code'
+ t.string 'home_page'
+ t.string 'twitter'
+ t.string 'carousel_images', array: true
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'slug'
+ t.integer 'user_id'
+ t.text 'image_url'
+ t.text 'description'
+ t.index ['slug'], name: 'index_nodes_on_slug', unique: true
+ t.index ['user_id'], name: 'index_nodes_on_user_id'
end
- create_table "ontology_term_links", force: :cascade do |t|
- t.integer "resource_id"
- t.string "resource_type"
- t.string "term_uri"
- t.string "field"
- t.index ["field"], name: "index_ontology_term_links_on_field"
- t.index ["resource_type", "resource_id"], name: "index_ontology_term_links_on_resource_type_and_resource_id"
- t.index ["term_uri"], name: "index_ontology_term_links_on_term_uri"
+ create_table 'ontology_term_links', force: :cascade do |t|
+ t.integer 'resource_id'
+ t.string 'resource_type'
+ t.string 'term_uri'
+ t.string 'field'
+ t.index ['field'], name: 'index_ontology_term_links_on_field'
+ t.index %w[resource_type resource_id], name: 'index_ontology_term_links_on_resource_type_and_resource_id'
+ t.index ['term_uri'], name: 'index_ontology_term_links_on_term_uri'
end
- create_table "profiles", force: :cascade do |t|
- t.text "firstname"
- t.text "surname"
- t.text "image_url"
- t.text "email"
- t.text "website"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.integer "user_id"
- t.string "slug"
- t.boolean "public", default: false
- t.text "description"
- t.text "location"
- t.string "orcid"
- t.string "experience"
- t.string "expertise_academic", default: [], array: true
- t.string "expertise_technical", default: [], array: true
- t.string "interest", default: [], array: true
- t.string "activity", default: [], array: true
- t.string "language", default: [], array: true
- t.string "social_media", default: [], array: true
- t.string "type", default: "Profile"
- t.string "fields", default: [], array: true
- t.index ["slug"], name: "index_profiles_on_slug", unique: true
+ create_table 'profiles', force: :cascade do |t|
+ t.text 'firstname'
+ t.text 'surname'
+ t.text 'image_url'
+ t.text 'email'
+ t.text 'website'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.integer 'user_id'
+ t.string 'slug'
+ t.boolean 'public', default: false
+ t.text 'description'
+ t.text 'location'
+ t.string 'orcid'
+ t.string 'experience'
+ t.string 'expertise_academic', default: [], array: true
+ t.string 'expertise_technical', default: [], array: true
+ t.string 'interest', default: [], array: true
+ t.string 'activity', default: [], array: true
+ t.string 'language', default: [], array: true
+ t.string 'social_media', default: [], array: true
+ t.string 'type', default: 'Profile'
+ t.string 'fields', default: [], array: true
+ t.index ['slug'], name: 'index_profiles_on_slug', unique: true
end
- create_table "roles", force: :cascade do |t|
- t.string "name"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "title"
+ create_table 'roles', force: :cascade do |t|
+ t.string 'name'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'title'
end
- create_table "sessions", force: :cascade do |t|
- t.string "session_id", null: false
- t.text "data"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.index ["session_id"], name: "index_sessions_on_session_id", unique: true
- t.index ["updated_at"], name: "index_sessions_on_updated_at"
+ create_table 'sessions', force: :cascade do |t|
+ t.string 'session_id', null: false
+ t.text 'data'
+ t.datetime 'created_at'
+ t.datetime 'updated_at'
+ t.index ['session_id'], name: 'index_sessions_on_session_id', unique: true
+ t.index ['updated_at'], name: 'index_sessions_on_updated_at'
end
- create_table "sources", force: :cascade do |t|
- t.bigint "content_provider_id"
- t.bigint "user_id"
- t.datetime "created_at"
- t.datetime "finished_at"
- t.string "url"
- t.string "method"
- t.integer "records_read"
- t.integer "records_written"
- t.integer "resources_added"
- t.integer "resources_updated"
- t.integer "resources_rejected"
- t.text "log"
- t.boolean "enabled"
- t.string "token"
- t.integer "approval_status"
- t.datetime "updated_at"
- t.index ["content_provider_id"], name: "index_sources_on_content_provider_id"
- t.index ["user_id"], name: "index_sources_on_user_id"
+ create_table 'sources', force: :cascade do |t|
+ t.bigint 'content_provider_id'
+ t.bigint 'user_id'
+ t.datetime 'created_at'
+ t.datetime 'finished_at'
+ t.string 'url'
+ t.string 'method'
+ t.integer 'records_read'
+ t.integer 'records_written'
+ t.integer 'resources_added'
+ t.integer 'resources_updated'
+ t.integer 'resources_rejected'
+ t.text 'log'
+ t.boolean 'enabled'
+ t.string 'token'
+ t.integer 'approval_status'
+ t.datetime 'updated_at'
+ t.index ['content_provider_id'], name: 'index_sources_on_content_provider_id'
+ t.index ['user_id'], name: 'index_sources_on_user_id'
end
- create_table "staff_members", force: :cascade do |t|
- t.string "name"
- t.string "role"
- t.string "email"
- t.text "image_url"
- t.integer "node_id"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "image_file_name"
- t.string "image_content_type"
- t.bigint "image_file_size"
- t.datetime "image_updated_at"
- t.index ["node_id"], name: "index_staff_members_on_node_id"
+ create_table 'staff_members', force: :cascade do |t|
+ t.string 'name'
+ t.string 'role'
+ t.string 'email'
+ t.text 'image_url'
+ t.integer 'node_id'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'image_file_name'
+ t.string 'image_content_type'
+ t.bigint 'image_file_size'
+ t.datetime 'image_updated_at'
+ t.index ['node_id'], name: 'index_staff_members_on_node_id'
end
- create_table "stars", force: :cascade do |t|
- t.integer "user_id"
- t.integer "resource_id"
- t.string "resource_type"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.index ["resource_type", "resource_id"], name: "index_stars_on_resource_type_and_resource_id"
- t.index ["user_id"], name: "index_stars_on_user_id"
+ create_table 'stars', force: :cascade do |t|
+ t.integer 'user_id'
+ t.integer 'resource_id'
+ t.string 'resource_type'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.index %w[resource_type resource_id], name: 'index_stars_on_resource_type_and_resource_id'
+ t.index ['user_id'], name: 'index_stars_on_user_id'
end
- create_table "subscriptions", force: :cascade do |t|
- t.integer "user_id"
- t.datetime "last_sent_at"
- t.text "query"
- t.json "facets"
- t.integer "frequency"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "subscribable_type"
- t.datetime "last_checked_at"
- t.index ["user_id"], name: "index_subscriptions_on_user_id"
+ create_table 'subscriptions', force: :cascade do |t|
+ t.integer 'user_id'
+ t.datetime 'last_sent_at'
+ t.text 'query'
+ t.json 'facets'
+ t.integer 'frequency'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'subscribable_type'
+ t.datetime 'last_checked_at'
+ t.index ['user_id'], name: 'index_subscriptions_on_user_id'
end
- create_table "users", force: :cascade do |t|
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "username"
- t.integer "role_id"
- t.string "authentication_token"
- t.string "email", default: "", null: false
- t.string "encrypted_password", default: "", null: false
- t.string "reset_password_token"
- t.datetime "reset_password_sent_at"
- t.datetime "remember_created_at"
- t.integer "sign_in_count", default: 0, null: false
- t.datetime "current_sign_in_at"
- t.datetime "last_sign_in_at"
- t.inet "current_sign_in_ip"
- t.inet "last_sign_in_ip"
- t.string "confirmation_token"
- t.datetime "confirmed_at"
- t.datetime "confirmation_sent_at"
- t.string "unconfirmed_email"
- t.integer "failed_attempts", default: 0, null: false
- t.string "unlock_token"
- t.datetime "locked_at"
- t.string "slug"
- t.string "provider"
- t.string "uid"
- t.string "identity_url"
- t.string "invitation_token"
- t.datetime "invitation_created_at"
- t.datetime "invitation_sent_at"
- t.datetime "invitation_accepted_at"
- t.integer "invitation_limit"
- t.string "invited_by_type"
- t.bigint "invited_by_id"
- t.integer "invitations_count", default: 0
- t.text "image_url"
- t.string "image_file_name"
- t.string "image_content_type"
- t.bigint "image_file_size"
- t.datetime "image_updated_at"
- t.index ["authentication_token"], name: "index_users_on_authentication_token"
- t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
- t.index ["email"], name: "index_users_on_email", unique: true
- t.index ["identity_url"], name: "index_users_on_identity_url", unique: true
- t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
- t.index ["invited_by_id"], name: "index_users_on_invited_by_id"
- t.index ["invited_by_type", "invited_by_id"], name: "index_users_on_invited_by"
- t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
- t.index ["role_id"], name: "index_users_on_role_id"
- t.index ["slug"], name: "index_users_on_slug", unique: true
- t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true
- t.index ["username"], name: "index_users_on_username", unique: true
+ create_table 'users', force: :cascade do |t|
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'username'
+ t.integer 'role_id'
+ t.string 'authentication_token'
+ t.string 'email', default: '', null: false
+ t.string 'encrypted_password', default: '', null: false
+ t.string 'reset_password_token'
+ t.datetime 'reset_password_sent_at'
+ t.datetime 'remember_created_at'
+ t.integer 'sign_in_count', default: 0, null: false
+ t.datetime 'current_sign_in_at'
+ t.datetime 'last_sign_in_at'
+ t.inet 'current_sign_in_ip'
+ t.inet 'last_sign_in_ip'
+ t.string 'confirmation_token'
+ t.datetime 'confirmed_at'
+ t.datetime 'confirmation_sent_at'
+ t.string 'unconfirmed_email'
+ t.integer 'failed_attempts', default: 0, null: false
+ t.string 'unlock_token'
+ t.datetime 'locked_at'
+ t.string 'slug'
+ t.string 'provider'
+ t.string 'uid'
+ t.string 'identity_url'
+ t.string 'invitation_token'
+ t.datetime 'invitation_created_at'
+ t.datetime 'invitation_sent_at'
+ t.datetime 'invitation_accepted_at'
+ t.integer 'invitation_limit'
+ t.string 'invited_by_type'
+ t.bigint 'invited_by_id'
+ t.integer 'invitations_count', default: 0
+ t.text 'image_url'
+ t.string 'image_file_name'
+ t.string 'image_content_type'
+ t.bigint 'image_file_size'
+ t.datetime 'image_updated_at'
+ t.index ['authentication_token'], name: 'index_users_on_authentication_token'
+ t.index ['confirmation_token'], name: 'index_users_on_confirmation_token', unique: true
+ t.index ['email'], name: 'index_users_on_email', unique: true
+ t.index ['identity_url'], name: 'index_users_on_identity_url', unique: true
+ t.index ['invitation_token'], name: 'index_users_on_invitation_token', unique: true
+ t.index ['invited_by_id'], name: 'index_users_on_invited_by_id'
+ t.index %w[invited_by_type invited_by_id], name: 'index_users_on_invited_by'
+ t.index ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true
+ t.index ['role_id'], name: 'index_users_on_role_id'
+ t.index ['slug'], name: 'index_users_on_slug', unique: true
+ t.index ['unlock_token'], name: 'index_users_on_unlock_token', unique: true
+ t.index ['username'], name: 'index_users_on_username', unique: true
end
- create_table "widget_logs", force: :cascade do |t|
- t.string "widget_name"
- t.string "action"
- t.integer "resource_id"
- t.string "resource_type"
- t.text "data"
- t.json "params"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.index ["resource_type", "resource_id"], name: "index_widget_logs_on_resource_type_and_resource_id"
+ create_table 'widget_logs', force: :cascade do |t|
+ t.string 'widget_name'
+ t.string 'action'
+ t.integer 'resource_id'
+ t.string 'resource_type'
+ t.text 'data'
+ t.json 'params'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.index %w[resource_type resource_id], name: 'index_widget_logs_on_resource_type_and_resource_id'
end
- create_table "workflows", force: :cascade do |t|
- t.string "title"
- t.string "description"
- t.integer "user_id"
- t.json "workflow_content"
- t.datetime "created_at", null: false
- t.datetime "updated_at", null: false
- t.string "slug"
- t.string "target_audience", default: [], array: true
- t.string "keywords", default: [], array: true
- t.string "authors", default: [], array: true
- t.string "contributors", default: [], array: true
- t.string "licence", default: "notspecified"
- t.string "difficulty_level", default: "notspecified"
- t.string "doi"
- t.date "remote_created_date"
- t.date "remote_updated_date"
- t.boolean "hide_child_nodes", default: false
- t.boolean "public", default: true
- t.index ["slug"], name: "index_workflows_on_slug", unique: true
- t.index ["user_id"], name: "index_workflows_on_user_id"
+ create_table 'workflows', force: :cascade do |t|
+ t.string 'title'
+ t.string 'description'
+ t.integer 'user_id'
+ t.json 'workflow_content'
+ t.datetime 'created_at', null: false
+ t.datetime 'updated_at', null: false
+ t.string 'slug'
+ t.string 'target_audience', default: [], array: true
+ t.string 'keywords', default: [], array: true
+ t.string 'authors', default: [], array: true
+ t.string 'contributors', default: [], array: true
+ t.string 'licence', default: 'notspecified'
+ t.string 'difficulty_level', default: 'notspecified'
+ t.string 'doi'
+ t.date 'remote_created_date'
+ t.date 'remote_updated_date'
+ t.boolean 'hide_child_nodes', default: false
+ t.boolean 'public', default: true
+ t.index ['slug'], name: 'index_workflows_on_slug', unique: true
+ t.index ['user_id'], name: 'index_workflows_on_user_id'
end
- add_foreign_key "bans", "users"
- add_foreign_key "bans", "users", column: "banner_id"
- add_foreign_key "collaborations", "users"
- add_foreign_key "collections", "users"
- add_foreign_key "content_providers", "nodes"
- add_foreign_key "content_providers", "users"
- add_foreign_key "event_materials", "events"
- add_foreign_key "event_materials", "materials"
- add_foreign_key "events", "users"
- add_foreign_key "materials", "content_providers"
- add_foreign_key "materials", "users"
- add_foreign_key "node_links", "nodes"
- add_foreign_key "nodes", "users"
- add_foreign_key "sources", "content_providers"
- add_foreign_key "sources", "users"
- add_foreign_key "staff_members", "nodes"
- add_foreign_key "stars", "users"
- add_foreign_key "subscriptions", "users"
- add_foreign_key "users", "roles"
- add_foreign_key "workflows", "users"
+ add_foreign_key 'bans', 'users'
+ add_foreign_key 'bans', 'users', column: 'banner_id'
+ add_foreign_key 'collaborations', 'users'
+ add_foreign_key 'collections', 'users'
+ add_foreign_key 'content_providers', 'nodes'
+ add_foreign_key 'content_providers', 'users'
+ add_foreign_key 'event_materials', 'events'
+ add_foreign_key 'event_materials', 'materials'
+ add_foreign_key 'events', 'users'
+ add_foreign_key 'materials', 'content_providers'
+ add_foreign_key 'materials', 'users'
+ add_foreign_key 'node_links', 'nodes'
+ add_foreign_key 'nodes', 'users'
+ add_foreign_key 'sources', 'content_providers'
+ add_foreign_key 'sources', 'users'
+ add_foreign_key 'staff_members', 'nodes'
+ add_foreign_key 'stars', 'users'
+ add_foreign_key 'subscriptions', 'users'
+ add_foreign_key 'users', 'roles'
+ add_foreign_key 'workflows', 'users'
end
diff --git a/lib/ingestors/ingestor_factory.rb b/lib/ingestors/ingestor_factory.rb
index 790baa457..f01cbe971 100644
--- a/lib/ingestors/ingestor_factory.rb
+++ b/lib/ingestors/ingestor_factory.rb
@@ -30,7 +30,7 @@ def self.ingestors
Ingestors::OsciIngestor,
Ingestors::DccIngestor,
Ingestors::SenseIngestor,
- Ingestors::GptIngestor
+ Ingestors::LlmIngestor
]
end
diff --git a/lib/ingestors/gpt_ingestor.rb b/lib/ingestors/llm_ingestor.rb
similarity index 82%
rename from lib/ingestors/gpt_ingestor.rb
rename to lib/ingestors/llm_ingestor.rb
index c07996ce0..5f5fb2056 100644
--- a/lib/ingestors/gpt_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -3,7 +3,7 @@
require 'nokogiri'
module Ingestors
- class GptIngestor < Ingestor
+ class LlmIngestor < Ingestor
def self.config
{
key: 'gpt_event',
@@ -82,39 +82,20 @@ def process_gpt(_url)
# XML not necessary (wur)
end
- def unload_json(event, response)
- response_json = JSON.parse(response)
- response_json.each_key do |key|
- event[key] = response_json[key]
- end
- event
- end
-
- def scrape_func(event, event_page)
- llm_service = ChatgptService.new
- response = llm_service.scrape(event_page).dig('choices', 0, 'message', 'content')
- puts response
- event = unload_json(event, response)
- event.llm_object = llm_service.llm_object
- event
- end
-
- def post_process_func(event)
- llm_service = ChatgptService.new
- response = llm_service.process(event).dig('choices', 0, 'message', 'content')
- puts response
- event = unload_json(event, response)
- event.llm_object = llm_service.llm_object
- event
- end
-
def beep_func(url, event_page) # rubocop:disable Metrics
event_page.css('script, link').each { |node| node.remove }
event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
+ llm_service_hash = {
+ chatgpt: ChatgptService
+ }
+ llm_service_class = llm_service_hash.fetch(TeSS::Config.llm_scraper.model, nil)
+ return unless llm_service_class
+
begin
+ llm_service = llm_service_class.new
event = OpenStruct.new
- event = scrape_func(event, event_page)
- event = post_process_func(event)
+ event = llm_service.scrape_func(event, event_page)
+ event = llm_service.post_process_func(event)
event.url = url
event.source = 'GPT'
event.timezone = 'Amsterdam'
diff --git a/lib/modules/chatgpt_service.rb b/lib/modules/chatgpt_service.rb
index e747cb2c1..8529c6873 100644
--- a/lib/modules/chatgpt_service.rb
+++ b/lib/modules/chatgpt_service.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ChatgptService
+class ChatgptService < LlmService
require 'openai'
def initialize
api_key = ENV.fetch('GPT_API_KEY', nil)
@@ -8,21 +8,11 @@ def initialize
@params = {
# max_tokens: 50,
# model: 'gpt-3.5-turbo-1106',
- model: 'gpt-4',
+ model: TeSS::Config.llm_scraper.model_version,
temperature: 0.7
}
end
- def llm_object
- LlmObject.new(
- scrape_or_process: @scrape_or_process,
- model: @params[:model],
- prompt: @prompt,
- input: @input,
- output: @output
- )
- end
-
def run(content)
beep = content
params = @params.merge(
@@ -31,7 +21,7 @@ def run(content)
messages: [{ role: 'user', content: beep }]
}
)
- @client.chat(parameters: params)
+ @client.chat(parameters: params).dig('choices', 0, 'message', 'content')
end
def call(prompt)
@@ -43,25 +33,6 @@ def call(prompt)
@client.chat(parameters: params)
end
- def scrape(event_page)
- @scrape_or_process = 'scrape'
- @prompt = File.read('llm_scrape_prompt.txt')
- @input = event_page
- content = @prompt.gsub('*replace_with_event_page*', event_page)
- @output = run(content)
- @output
- end
-
- def process(event)
- @scrape_or_process = 'process'
- event_json = JSON.generate(event.to_json)
- @prompt = File.read('llm_process_prompt.txt')
- @input = event_json
- content = @prompt.gsub('*replace_with_event*', event_json)
- @output = run(content)
- @output
- end
-
class << self
def call(message)
new.call(message)
diff --git a/lib/modules/llm_service.rb b/lib/modules/llm_service.rb
new file mode 100644
index 000000000..76c73790f
--- /dev/null
+++ b/lib/modules/llm_service.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+class LlmService
+ def initialize
+ puts 'please provide child class'
+ end
+
+ def llm_object
+ LlmObject.new(
+ scrape_or_process: @scrape_or_process,
+ model: @params[:model],
+ prompt: @prompt,
+ input: @input,
+ output: @output
+ )
+ end
+
+ def unload_json(event, response)
+ response_json = JSON.parse(response)
+ response_json.each_key do |key|
+ event[key] = response_json[key]
+ end
+ event
+ end
+
+ def scrape(event_page)
+ @scrape_or_process = 'scrape'
+ @prompt = File.read('llm_scrape_prompt.txt')
+ @input = event_page
+ content = @prompt.gsub('*replace_with_event_page*', event_page)
+ @output = run(content)
+ @output
+ end
+
+ def process(event)
+ @scrape_or_process = 'process'
+ event_json = JSON.generate(event.to_json)
+ @prompt = File.read('llm_process_prompt.txt')
+ @input = event_json
+ content = @prompt.gsub('*replace_with_event*', event_json)
+ @output = run(content)
+ @output
+ end
+
+ def scrape_func(event, event_page)
+ response = scrape(event_page)
+ puts response
+ event = unload_json(event, response)
+ event.llm_object = llm_object
+ event
+ end
+
+ def post_process_func(event)
+ response = process(event)
+ puts response
+ event = unload_json(event, response)
+ event.llm_object = llm_object
+ event
+ end
+
+ def run(_content)
+ puts 'please provide child class'
+ end
+
+ def call(_prompt)
+ puts 'please provide child class'
+ end
+end
diff --git a/llm_process_prompt.txt b/llm_process_prompt.txt
index 37a45d2e4..d19be9b60 100644
--- a/llm_process_prompt.txt
+++ b/llm_process_prompt.txt
@@ -15,7 +15,7 @@ title (string): The title of the event
keywords (array of strings): A set of keywords based which the event can be filtered.
target_audience (array of strings): The target audience for this event.
open_science (array of strings): The type of open science that this event advocates for, if any.
-curation (bool): Whether or not the event is relevant according to the curation criteria
+visible (bool): Whether or not the event is relevant according to the curation criteria
keywords options:
[
From 722f7a84d291690c86222ce9837510c1b478bb89 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 15 May 2024 13:34:10 +0200
Subject: [PATCH 10/37] willma service
---
lib/ingestors/llm_ingestor.rb | 5 +--
lib/modules/chatgpt_service.rb | 35 +-------------------
lib/modules/llm_service.rb | 27 +++++++++++++++
lib/modules/willma_service.rb | 60 ++++++++++++++++++++++++++++++++++
llm_process_prompt.txt | 1 +
llm_scrape_prompt.txt | 2 +-
6 files changed, 93 insertions(+), 37 deletions(-)
create mode 100644 lib/modules/willma_service.rb
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index 5f5fb2056..3a667f09d 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -86,9 +86,10 @@ def beep_func(url, event_page) # rubocop:disable Metrics
event_page.css('script, link').each { |node| node.remove }
event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
llm_service_hash = {
- chatgpt: ChatgptService
+ chatgpt: ChatgptService,
+ willma: WillmaService
}
- llm_service_class = llm_service_hash.fetch(TeSS::Config.llm_scraper.model, nil)
+ llm_service_class = llm_service_hash.fetch(TeSS::Config.llm_scraper['model'].to_sym, nil)
return unless llm_service_class
begin
diff --git a/lib/modules/chatgpt_service.rb b/lib/modules/chatgpt_service.rb
index 8529c6873..b5311ced4 100644
--- a/lib/modules/chatgpt_service.rb
+++ b/lib/modules/chatgpt_service.rb
@@ -14,14 +14,7 @@ def initialize
end
def run(content)
- beep = content
- params = @params.merge(
- {
- # response_format: { type: 'json_object' },
- messages: [{ role: 'user', content: beep }]
- }
- )
- @client.chat(parameters: params).dig('choices', 0, 'message', 'content')
+ call(content).dig('choices', 0, 'message', 'content')
end
def call(prompt)
@@ -32,30 +25,4 @@ def call(prompt)
)
@client.chat(parameters: params)
end
-
- class << self
- def call(message)
- new.call(message)
- end
-
- def scrape # rubocop:disable Metrics
- url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
- require 'open-uri'
- event_page = URI(url).open(&:read)
- doc = Nokogiri::HTML5.parse(event_page).css('body').css("div[id='nieuws_detail_row']")
- doc.css('script, link').each { |node| node.remove }
- event_page = doc.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
- response = new.scrape(event_page).dig('choices', 0, 'message', 'content')
- puts response
- JSON.parse(response)
- end
-
- def process
- event_json = ChatgptService.scrape
- event = Event.new(event_json)
- response = new.process(event).dig('choices', 0, 'message', 'content')
- puts response
- JSON.parse(response)
- end
- end
end
diff --git a/lib/modules/llm_service.rb b/lib/modules/llm_service.rb
index 76c73790f..45ade0680 100644
--- a/lib/modules/llm_service.rb
+++ b/lib/modules/llm_service.rb
@@ -65,4 +65,31 @@ def run(_content)
def call(_prompt)
puts 'please provide child class'
end
+
+ class << self
+ def call(message)
+ new.call(message)
+ end
+
+ def scrape # rubocop:disable Metrics
+ url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
+ require 'open-uri'
+ event_page = URI(url).open(&:read)
+ doc = Nokogiri::HTML5.parse(event_page).css('body').css("div[id='nieuws_detail_row']")
+ doc.css('script, link').each { |node| node.remove }
+ event_page = doc.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
+ response = new.scrape(event_page)
+ puts response
+ JSON.parse(response)
+ end
+
+ def process
+ event_json = scrape
+ puts 'hi'
+ event = Event.new(event_json)
+ response = new.process(event)
+ puts response
+ JSON.parse(response)
+ end
+ end
end
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
new file mode 100644
index 000000000..efd4d1c2d
--- /dev/null
+++ b/lib/modules/willma_service.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+class WillmaService < LlmService
+ require 'openai'
+ def initialize
+ model_name = TeSS::Config.llm_scraper['model_version']
+ model_url = 'https://willma.soil.surf.nl/api/models'
+ parsed_response = JSON.parse(do_request(model_url, 'get', {}).body)
+ model_id = parsed_response.select { |i| i['name'] == model_name }.first['id']
+ @params = {
+ model: model_name,
+ sequence_id: model_id,
+ temperature: 0.7
+ }
+ end
+
+ def run(content)
+ call(content)['message']
+ end
+
+ def call(prompt)
+ data = {
+ 'sequence_id': @params[:sequence_id],
+ 'input': prompt
+ }
+ query_url = 'https://willma.soil.surf.nl/api/query'
+ response = do_request(query_url, 'post', data)
+ JSON.parse(response.body)
+ end
+end
+
+def do_request(url, mode, data = {})
+ header = {
+ 'Content-Type': 'application/json',
+ 'X-API-KEY': ENV.fetch('WILLMA_API_KEY')
+ }
+
+ parsed_url = URI.parse(url)
+ http = Net::HTTP.new(parsed_url.host, parsed_url.port)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
+
+ case mode
+ when 'post'
+ request = Net::HTTP::Post.new(parsed_url.path)
+ when 'get'
+ request = Net::HTTP::Get.new(parsed_url.path)
+ else
+ puts 'whoops'
+ request = Net::HTTP::Post.new(parsed_url.path)
+ end
+
+ header.each do |key, value|
+ request[key] = value
+ end
+ request.set_form_data(data)
+ request.body = data.to_json
+ request.content_type = 'application/json'
+ http.request(request)
+end
diff --git a/llm_process_prompt.txt b/llm_process_prompt.txt
index d19be9b60..c8aff1f10 100644
--- a/llm_process_prompt.txt
+++ b/llm_process_prompt.txt
@@ -10,6 +10,7 @@ Strictly adhere to the provided options if applicable without introducing new ca
Fill the keywords attributes with with ['domain agnostic'] if all options are relevant.
If a specified option is not applicable or missing, fill it with null.
The options are defined below between quotation marks. Options are separated by commas.
+Return the json string surrounded by |
title (string): The title of the event
keywords (array of strings): A set of keywords based which the event can be filtered.
diff --git a/llm_scrape_prompt.txt b/llm_scrape_prompt.txt
index dfbe68ba3..715c533c8 100644
--- a/llm_scrape_prompt.txt
+++ b/llm_scrape_prompt.txt
@@ -1,7 +1,7 @@
Based on the following webpage describing a research event:
*replace_with_event_page*
-Give me a json describing a research themed event with the following format:
+Give me a json string surrounded by || describing a research themed event with the following format:
title (string): The title of the event
organizer (string): The organisation that hosts the event
From beaeb7131b97be1f97d8699ad40f7cf0b6ae3504 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 17 May 2024 16:56:23 +0200
Subject: [PATCH 11/37] parse first json string from message
---
lib/modules/willma_service.rb | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
index efd4d1c2d..f51307294 100644
--- a/lib/modules/willma_service.rb
+++ b/lib/modules/willma_service.rb
@@ -15,7 +15,11 @@ def initialize
end
def run(content)
- call(content)['message']
+ msg = call(content)['message']
+ puts msg
+ res = get_first_json_from_string(msg)
+ puts res
+ res
end
def call(prompt)
@@ -58,3 +62,20 @@ def do_request(url, mode, data = {})
request.content_type = 'application/json'
http.request(request)
end
+
+def get_first_json_from_string(msg)
+ char_dict = {}
+ start_end = [0, 0]
+ res = msg
+ msg.split('').each_with_index do |char, idx|
+ char_dict[char] = char_dict.fetch(char, 0) + 1
+ if char == '{' && char_dict['{'] == 1
+ start_end[0] = idx
+ elsif char == '}' && char_dict['{'] == char_dict['}']
+ start_end[1] = idx
+ res = msg[start_end[0]..start_end[1]]
+ break
+ end
+ end
+ res
+end
From 3bb223d8a7e6c412410b4016adfbf7e25b0b23cf Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 31 May 2024 12:16:30 +0200
Subject: [PATCH 12/37] cleanup
---
app/models/llm_object.rb | 1 +
db/migrate/20240220144246_add_llm_check.rb | 3 +--
lib/modules/llm_service.rb | 3 ++-
lib/modules/willma_service.rb | 23 +++++++++++-----------
lib/tasks/tess.rake | 9 ++++++++-
llm_process_prompt.txt | 3 +--
llm_scrape_prompt.txt | 2 +-
7 files changed, 26 insertions(+), 18 deletions(-)
diff --git a/app/models/llm_object.rb b/app/models/llm_object.rb
index 4584f633e..b5f7788e6 100644
--- a/app/models/llm_object.rb
+++ b/app/models/llm_object.rb
@@ -5,4 +5,5 @@ class LlmObject < ApplicationRecord
validates :prompt, presence: true
validates :input, presence: true
validates :output, presence: true
+ validates :needs_processing, presence: true
end
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
index 4b942fa0d..a2021b314 100644
--- a/db/migrate/20240220144246_add_llm_check.rb
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -9,10 +9,10 @@ def up
t.string :prompt
t.string :input
t.string :output
+ t.boolean :needs_processing, default: false
end
add_reference :events, :llm_object, foreign_key: true
add_column :events, :open_science, :string, array: true, default: []
- add_column :events, :visible, :bool, default: true
add_column :materials, :llm_processed, :bool, default: false
end
@@ -20,7 +20,6 @@ def down
drop_table :llm_object
remove_reference :events, :llm_object, foreign_key: true
remove_column :events, :open_science, :string, array: true, default: []
- remove_column :events, :visible, :bool, default: true
remove_column :materials, :llm_processed, :bool, default: false
end
end
diff --git a/lib/modules/llm_service.rb b/lib/modules/llm_service.rb
index 45ade0680..2487dc0cb 100644
--- a/lib/modules/llm_service.rb
+++ b/lib/modules/llm_service.rb
@@ -11,7 +11,8 @@ def llm_object
model: @params[:model],
prompt: @prompt,
input: @input,
- output: @output
+ output: @output,
+ needs_processing: false
)
end
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
index f51307294..07215ca3e 100644
--- a/lib/modules/willma_service.rb
+++ b/lib/modules/willma_service.rb
@@ -44,15 +44,14 @@ def do_request(url, mode, data = {})
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
- case mode
- when 'post'
- request = Net::HTTP::Post.new(parsed_url.path)
- when 'get'
- request = Net::HTTP::Get.new(parsed_url.path)
- else
- puts 'whoops'
- request = Net::HTTP::Post.new(parsed_url.path)
- end
+ request = case mode
+ when 'post'
+ Net::HTTP::Post.new(parsed_url.path)
+ when 'get'
+ Net::HTTP::Get.new(parsed_url.path)
+ else
+ Net::HTTP::Post.new(parsed_url.path)
+ end
header.each do |key, value|
request[key] = value
@@ -64,11 +63,13 @@ def do_request(url, mode, data = {})
end
def get_first_json_from_string(msg)
- char_dict = {}
+ char_dict = { '{': 0, '}': 0 }
start_end = [0, 0]
res = msg
msg.split('').each_with_index do |char, idx|
- char_dict[char] = char_dict.fetch(char, 0) + 1
+ next unless char in '{}'
+
+ char_dict[char] += 1
if char == '{' && char_dict['{'] == 1
start_end[0] = idx
elsif char == '}' && char_dict['{'] == char_dict['}']
diff --git a/lib/tasks/tess.rake b/lib/tasks/tess.rake
index 1eb42a012..26e889157 100644
--- a/lib/tasks/tess.rake
+++ b/lib/tasks/tess.rake
@@ -143,7 +143,10 @@ namespace :tess do
task llm_post_processing: :environment do
prompt = File.read('llm_process_prompt.txt')
Events.each do |event|
- unless event&.llm_object&.prompt == prompt
+ needs_processing = event&.llm_object&.needs_processing
+ new_prompt = event&.llm_object&.prompt == prompt
+ future_event = event.end > Time.zone.now
+ unless (needs_processing || new_prompt) && future_event
event = GptIngestor.new.post_process_func(event)
event.save!
end
@@ -152,6 +155,10 @@ namespace :tess do
desc 'open all events to being llm processed again'
task reset_llm_status: :environment do
+ Events.where { |event| event.end > Time.zone.now }.each do |event|
+ event&.llm_object&.needs_processing = true
+ event.save!
+ end
end
desc 'mail content providers for curation of scraped events'
diff --git a/llm_process_prompt.txt b/llm_process_prompt.txt
index c8aff1f10..0f6de2ac3 100644
--- a/llm_process_prompt.txt
+++ b/llm_process_prompt.txt
@@ -5,12 +5,11 @@ and the following curation criteria:
Is this event useful for anyone rather than only people from a specific institution?
Is this event centered around research?
-Give me a json describing a research themed event with the following format.
+Give me a json string describing a research themed event with the following format.
Strictly adhere to the provided options if applicable without introducing new categories or combinations of words.
Fill the keywords attributes with with ['domain agnostic'] if all options are relevant.
If a specified option is not applicable or missing, fill it with null.
The options are defined below between quotation marks. Options are separated by commas.
-Return the json string surrounded by |
title (string): The title of the event
keywords (array of strings): A set of keywords based which the event can be filtered.
diff --git a/llm_scrape_prompt.txt b/llm_scrape_prompt.txt
index 715c533c8..4afa80318 100644
--- a/llm_scrape_prompt.txt
+++ b/llm_scrape_prompt.txt
@@ -1,7 +1,7 @@
Based on the following webpage describing a research event:
*replace_with_event_page*
-Give me a json string surrounded by || describing a research themed event with the following format:
+Give me a json string describing a research themed event with the following format:
title (string): The title of the event
organizer (string): The organisation that hosts the event
From f5ee2d48bae4b82d2e3245b1136ae9af00f812a5 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 31 May 2024 13:14:14 +0200
Subject: [PATCH 13/37] change gpt to llm in scraperee
---
lib/ingestors/llm_ingestor.rb | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index 3a667f09d..0772ab63d 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -6,15 +6,15 @@ module Ingestors
class LlmIngestor < Ingestor
def self.config
{
- key: 'gpt_event',
- title: 'GPT Events API',
+ key: 'llm_event',
+ title: 'LLM Events API',
category: :events
}
end
def read(url)
begin
- process_gpt(url)
+ process_llm(url)
rescue Exception => e
@messages << "#{self.class.name} failed with: #{e.message}"
end
@@ -26,24 +26,24 @@ def read(url)
private
def scrape_dans
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='nieuws_detail_row']")
beep_func(url, event_page)
end
def scrape_nwo # rubocop:disable Metrics
- # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
# url = 'https://www.nwo.nl/en/meetings/dualis-event-in-utrecht'
# event_page = Nokogiri::HTML5.parse(open_url(url, raise: true)).css('body').css('main')[0].css('article')
# beep_func(url, event_page)
url = 'https://www.nwo.nl/en/meetings'
4.times.each do |i| # always check the first 4 pages, # of pages could be increased if needed
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
event_page = Nokogiri::HTML5.parse(open_url("#{url}?page=#{i}", raise: true)).css('.overviewContent')[0].css('li.list-item').css('a')
event_page.each do |event_data|
new_url = "https://www.nwo.nl#{event_data['href']}"
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
new_event_page = Nokogiri::HTML5.parse(open_url(new_url, raise: true)).css('body').css('main')[0].css('article')
beep_func(new_url, new_event_page)
end
@@ -51,7 +51,7 @@ def scrape_nwo # rubocop:disable Metrics
end
def scrape_rug # rubocop:disable Metrics
- # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
# url = 'https://www.rug.nl/about-ug/latest-news/events/calendar/2023/phallus-tentoonstelling'
# event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
# beep_func(url, event_page)
@@ -60,20 +60,20 @@ def scrape_rug # rubocop:disable Metrics
event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
event_page.each do |event_data|
new_url = event_data.css("meta[itemprop='url']")[0].get_attribute('content')
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
new_event_page = Nokogiri::HTML5.parse(open_url(new_url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
beep_func(new_url, new_event_page)
end
end
def scrape_tdcc
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/gpt.yml')
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
url = 'https://tdcc.nl/evenementen/teaming-up-across-domains/'
event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css('article')[0]
beep_func(url, event_page)
end
- def process_gpt(_url)
+ def process_llm(_url)
scrape_dans
scrape_nwo
scrape_rug
@@ -98,7 +98,7 @@ def beep_func(url, event_page) # rubocop:disable Metrics
event = llm_service.scrape_func(event, event_page)
event = llm_service.post_process_func(event)
event.url = url
- event.source = 'GPT'
+ event.source = 'LLM'
event.timezone = 'Amsterdam'
add_event(event)
rescue Exception => e
From b4b6577b3feb4276f1d2a4008e2a4e228f7d41d7 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 31 May 2024 15:30:05 +0200
Subject: [PATCH 14/37] updated json extraction func
---
lib/modules/llm_service.rb | 5 -----
lib/modules/willma_service.rb | 8 ++++----
2 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/lib/modules/llm_service.rb b/lib/modules/llm_service.rb
index 2487dc0cb..f6c5718da 100644
--- a/lib/modules/llm_service.rb
+++ b/lib/modules/llm_service.rb
@@ -45,7 +45,6 @@ def process(event)
def scrape_func(event, event_page)
response = scrape(event_page)
- puts response
event = unload_json(event, response)
event.llm_object = llm_object
event
@@ -53,7 +52,6 @@ def scrape_func(event, event_page)
def post_process_func(event)
response = process(event)
- puts response
event = unload_json(event, response)
event.llm_object = llm_object
event
@@ -80,16 +78,13 @@ def scrape # rubocop:disable Metrics
doc.css('script, link').each { |node| node.remove }
event_page = doc.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
response = new.scrape(event_page)
- puts response
JSON.parse(response)
end
def process
event_json = scrape
- puts 'hi'
event = Event.new(event_json)
response = new.process(event)
- puts response
JSON.parse(response)
end
end
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
index 07215ca3e..fcd31d1af 100644
--- a/lib/modules/willma_service.rb
+++ b/lib/modules/willma_service.rb
@@ -16,9 +16,7 @@ def initialize
def run(content)
msg = call(content)['message']
- puts msg
res = get_first_json_from_string(msg)
- puts res
res
end
@@ -63,11 +61,13 @@ def do_request(url, mode, data = {})
end
def get_first_json_from_string(msg)
- char_dict = { '{': 0, '}': 0 }
+ char_dict = {}
+ char_dict['{'] = 0
+ char_dict['}'] = 0
start_end = [0, 0]
res = msg
msg.split('').each_with_index do |char, idx|
- next unless char in '{}'
+ next unless '{}'.include?(char)
char_dict[char] += 1
if char == '{' && char_dict['{'] == 1
From 63880fcc639e355755eba04a6d384d8b463a8898 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Mon, 3 Jun 2024 11:58:06 +0200
Subject: [PATCH 15/37] working scrape without llm_object
---
app/controllers/events_controller.rb | 1 +
app/models/event.rb | 3 +-
db/migrate/20240220144246_add_llm_check.rb | 36 +-
db/schema.rb | 1223 ++++++++++----------
lib/ingestors/llm_ingestor.rb | 7 +-
lib/modules/llm_service.rb | 10 +-
lib/modules/willma_service.rb | 19 +-
lib/tasks/seed_content_providers.rake | 25 +
8 files changed, 697 insertions(+), 627 deletions(-)
create mode 100644 lib/tasks/seed_content_providers.rake
diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb
index 8f7184cf6..e849461d0 100644
--- a/app/controllers/events_controller.rb
+++ b/app/controllers/events_controller.rb
@@ -235,6 +235,7 @@ def event_params
{ host_institutions: [] }, :capacity, :contact, :recognition, :learning_objectives,
:prerequisites, :tech_requirements, :cost_basis, :cost_value, :cost_currency,
external_resources_attributes: %i[id url title _destroy], material_ids: [],
+ llm_object_attributes: %i[scrape_or_process model prompt input output needs_processing],
locked_fields: [])
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 2e31de434..f09a7a1c4 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -109,7 +109,8 @@ class Event < ApplicationRecord
enum presence: { onsite: 0, online: 1, hybrid: 2 }
belongs_to :user
- has_one :llm_object
+ has_one :llm_object, inverse_of: :event
+ accepts_nested_attributes_for :llm_object, allow_destroy: true
has_one :edit_suggestion, as: :suggestible, dependent: :destroy
has_one :link_monitor, as: :lcheck, dependent: :destroy
has_many :collection_items, as: :resource
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
index a2021b314..5dd1edd55 100644
--- a/db/migrate/20240220144246_add_llm_check.rb
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -1,7 +1,31 @@
class AddLlmCheck < ActiveRecord::Migration[7.0]
- def up
+ # def up
+ # create_table :llm_object do |t|
+ # # t.references :event, foreign_key: true
+ # t.datetime :created_at
+ # t.datetime :updated_at
+ # t.string :scrape_or_process
+ # t.string :model
+ # t.string :prompt
+ # t.string :input
+ # t.string :output
+ # t.boolean :needs_processing, default: false
+ # end
+ # add_reference :events, :llm_object, foreign_key: true
+ # add_column :events, :open_science, :string, array: true, default: []
+ # add_column :materials, :llm_processed, :bool, default: false
+ # end
+
+ # def down
+ # drop_table :llm_object
+ # remove_reference :events, :llm_object, foreign_key: true
+ # remove_column :events, :open_science, :string, array: true, default: []
+ # remove_column :materials, :llm_processed, :bool, default: false
+ # end
+
+ def change
create_table :llm_object do |t|
- t.references :events, foreign_key: true
+ t.belongs_to :event, foreign_key: true
t.datetime :created_at
t.datetime :updated_at
t.string :scrape_or_process
@@ -11,15 +35,7 @@ def up
t.string :output
t.boolean :needs_processing, default: false
end
- add_reference :events, :llm_object, foreign_key: true
add_column :events, :open_science, :string, array: true, default: []
add_column :materials, :llm_processed, :bool, default: false
end
-
- def down
- drop_table :llm_object
- remove_reference :events, :llm_object, foreign_key: true
- remove_column :events, :open_science, :string, array: true, default: []
- remove_column :materials, :llm_processed, :bool, default: false
- end
end
diff --git a/db/schema.rb b/db/schema.rb
index 1a02a4fec..4f8bd93fe 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,614 +10,623 @@
#
# It's strongly recommended that you check this file into your version control system.
-<<<<<<< HEAD
-ActiveRecord::Schema[7.0].define(version: 20_240_426_090_005) do
-=======
ActiveRecord::Schema[7.0].define(version: 2024_05_30_064523) do
->>>>>>> origin/master
# These are extensions that must be enabled in order to support this database
- enable_extension 'plpgsql'
-
- create_table 'activities', force: :cascade do |t|
- t.integer 'trackable_id'
- t.string 'trackable_type'
- t.integer 'owner_id'
- t.string 'owner_type'
- t.string 'key'
- t.text 'parameters'
- t.integer 'recipient_id'
- t.string 'recipient_type'
- t.datetime 'created_at'
- t.datetime 'updated_at'
- t.index ['key'], name: 'index_activities_on_key'
- t.index %w[owner_id owner_type], name: 'index_activities_on_owner_id_and_owner_type'
- t.index %w[recipient_id recipient_type], name: 'index_activities_on_recipient_id_and_recipient_type'
- t.index %w[trackable_id trackable_type], name: 'index_activities_on_trackable_id_and_trackable_type'
- end
-
- create_table 'ahoy_events', force: :cascade do |t|
- t.bigint 'visit_id'
- t.bigint 'user_id'
- t.string 'name'
- t.jsonb 'properties'
- t.datetime 'time'
- t.index %w[name time], name: 'index_ahoy_events_on_name_and_time'
- t.index ['properties'], name: 'index_ahoy_events_on_properties', opclass: :jsonb_path_ops, using: :gin
- t.index ['user_id'], name: 'index_ahoy_events_on_user_id'
- t.index ['visit_id'], name: 'index_ahoy_events_on_visit_id'
- end
-
- create_table 'ahoy_visits', force: :cascade do |t|
- t.string 'visit_token'
- t.string 'visitor_token'
- t.bigint 'user_id'
- t.string 'ip'
- t.text 'user_agent'
- t.text 'referrer'
- t.string 'referring_domain'
- t.text 'landing_page'
- t.string 'browser'
- t.string 'os'
- t.string 'device_type'
- t.string 'country'
- t.string 'region'
- t.string 'city'
- t.float 'latitude'
- t.float 'longitude'
- t.string 'utm_source'
- t.string 'utm_medium'
- t.string 'utm_term'
- t.string 'utm_content'
- t.string 'utm_campaign'
- t.string 'app_version'
- t.string 'os_version'
- t.string 'platform'
- t.datetime 'started_at'
- t.index ['user_id'], name: 'index_ahoy_visits_on_user_id'
- t.index ['visit_token'], name: 'index_ahoy_visits_on_visit_token', unique: true
- end
-
- create_table 'autocomplete_suggestions', force: :cascade do |t|
- t.string 'field'
- t.string 'value'
- t.index %w[field value], name: 'index_autocomplete_suggestions_on_field_and_value', unique: true
- end
-
- create_table 'bans', force: :cascade do |t|
- t.integer 'user_id'
- t.integer 'banner_id'
- t.boolean 'shadow'
- t.text 'reason'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.index ['banner_id'], name: 'index_bans_on_banner_id'
- t.index ['user_id'], name: 'index_bans_on_user_id'
- end
-
- create_table 'collaborations', force: :cascade do |t|
- t.integer 'user_id'
- t.integer 'resource_id'
- t.string 'resource_type'
- t.index %w[resource_type resource_id], name: 'index_collaborations_on_resource_type_and_resource_id'
- t.index ['user_id'], name: 'index_collaborations_on_user_id'
- end
-
- create_table 'collection_items', force: :cascade do |t|
- t.bigint 'collection_id'
- t.string 'resource_type'
- t.bigint 'resource_id'
- t.text 'comment'
- t.integer 'order'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.index ['collection_id'], name: 'index_collection_items_on_collection_id'
- t.index %w[resource_type resource_id], name: 'index_collection_items_on_resource'
- end
-
- create_table 'collections', force: :cascade do |t|
- t.string 'title'
- t.text 'description'
- t.text 'image_url'
- t.boolean 'public', default: true
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.integer 'user_id'
- t.string 'slug'
- t.string 'keywords', default: [], array: true
- t.string 'image_file_name'
- t.string 'image_content_type'
- t.bigint 'image_file_size'
- t.datetime 'image_updated_at'
- t.index ['slug'], name: 'index_collections_on_slug', unique: true
- t.index ['user_id'], name: 'index_collections_on_user_id'
- end
-
- create_table 'content_providers', force: :cascade do |t|
- t.text 'title'
- t.text 'url'
- t.text 'image_url'
- t.text 'description'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.string 'slug'
- t.string 'keywords', default: [], array: true
- t.integer 'user_id'
- t.integer 'node_id'
- t.string 'content_provider_type', default: 'Organisation'
- t.string 'image_file_name'
- t.string 'image_content_type'
- t.bigint 'image_file_size'
- t.datetime 'image_updated_at'
- t.string 'contact'
+ enable_extension "plpgsql"
+
+ create_table "activities", id: :serial, force: :cascade do |t|
+ t.string "trackable_type"
+ t.integer "trackable_id"
+ t.string "owner_type"
+ t.integer "owner_id"
+ t.string "key"
+ t.text "parameters"
+ t.string "recipient_type"
+ t.integer "recipient_id"
+ t.datetime "created_at", precision: nil
+ t.datetime "updated_at", precision: nil
+ t.index ["key"], name: "index_activities_on_key"
+ t.index ["owner_id", "owner_type"], name: "index_activities_on_owner_id_and_owner_type"
+ t.index ["recipient_id", "recipient_type"], name: "index_activities_on_recipient_id_and_recipient_type"
+ t.index ["trackable_id", "trackable_type"], name: "index_activities_on_trackable_id_and_trackable_type"
+ end
+
+ create_table "ahoy_events", force: :cascade do |t|
+ t.bigint "visit_id"
+ t.bigint "user_id"
+ t.string "name"
+ t.jsonb "properties"
+ t.datetime "time", precision: nil
+ t.index ["name", "time"], name: "index_ahoy_events_on_name_and_time"
+ t.index ["properties"], name: "index_ahoy_events_on_properties", opclass: :jsonb_path_ops, using: :gin
+ t.index ["user_id"], name: "index_ahoy_events_on_user_id"
+ t.index ["visit_id"], name: "index_ahoy_events_on_visit_id"
+ end
+
+ create_table "ahoy_visits", force: :cascade do |t|
+ t.string "visit_token"
+ t.string "visitor_token"
+ t.bigint "user_id"
+ t.string "ip"
+ t.text "user_agent"
+ t.text "referrer"
+ t.string "referring_domain"
+ t.text "landing_page"
+ t.string "browser"
+ t.string "os"
+ t.string "device_type"
+ t.string "country"
+ t.string "region"
+ t.string "city"
+ t.float "latitude"
+ t.float "longitude"
+ t.string "utm_source"
+ t.string "utm_medium"
+ t.string "utm_term"
+ t.string "utm_content"
+ t.string "utm_campaign"
+ t.string "app_version"
+ t.string "os_version"
+ t.string "platform"
+ t.datetime "started_at", precision: nil
+ t.index ["user_id"], name: "index_ahoy_visits_on_user_id"
+ t.index ["visit_token"], name: "index_ahoy_visits_on_visit_token", unique: true
+ end
+
+ create_table "autocomplete_suggestions", force: :cascade do |t|
+ t.string "field"
+ t.string "value"
+ t.index ["field", "value"], name: "index_autocomplete_suggestions_on_field_and_value", unique: true
+ end
+
+ create_table "bans", id: :serial, force: :cascade do |t|
+ t.integer "user_id"
+ t.integer "banner_id"
+ t.boolean "shadow"
+ t.text "reason"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.index ["banner_id"], name: "index_bans_on_banner_id"
+ t.index ["user_id"], name: "index_bans_on_user_id"
+ end
+
+ create_table "collaborations", id: :serial, force: :cascade do |t|
+ t.integer "user_id"
+ t.string "resource_type"
+ t.integer "resource_id"
+ t.index ["resource_type", "resource_id"], name: "index_collaborations_on_resource_type_and_resource_id"
+ t.index ["user_id"], name: "index_collaborations_on_user_id"
+ end
+
+ create_table "collection_items", force: :cascade do |t|
+ t.bigint "collection_id"
+ t.string "resource_type"
+ t.bigint "resource_id"
+ t.text "comment"
+ t.integer "order"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["collection_id"], name: "index_collection_items_on_collection_id"
+ t.index ["resource_type", "resource_id"], name: "index_collection_items_on_resource"
+ end
+
+ create_table "collections", id: :serial, force: :cascade do |t|
+ t.string "title"
+ t.text "description"
+ t.text "image_url"
+ t.boolean "public", default: true
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.integer "user_id"
+ t.string "slug"
+ t.string "keywords", default: [], array: true
+ t.string "image_file_name"
+ t.string "image_content_type"
+ t.bigint "image_file_size"
+ t.datetime "image_updated_at"
+ t.index ["slug"], name: "index_collections_on_slug", unique: true
+ t.index ["user_id"], name: "index_collections_on_user_id"
+ end
+
+ create_table "content_providers", id: :serial, force: :cascade do |t|
+ t.text "title"
+ t.text "url"
+ t.text "image_url"
+ t.text "description"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.string "slug"
+ t.string "keywords", default: [], array: true
+ t.integer "user_id"
+ t.integer "node_id"
+ t.string "content_provider_type", default: "Organisation"
+ t.string "image_file_name"
+ t.string "image_content_type"
+ t.bigint "image_file_size"
+ t.datetime "image_updated_at"
+ t.string "contact"
t.string "event_curation_email"
- t.index ['node_id'], name: 'index_content_providers_on_node_id'
- t.index ['slug'], name: 'index_content_providers_on_slug', unique: true
- t.index ['user_id'], name: 'index_content_providers_on_user_id'
- end
-
- create_table 'content_providers_users', id: false, force: :cascade do |t|
- t.bigint 'content_provider_id'
- t.bigint 'user_id'
- t.index %w[content_provider_id user_id], name: 'provider_user_unique', unique: true
- t.index ['content_provider_id'], name: 'index_content_providers_users_on_content_provider_id'
- t.index ['user_id'], name: 'index_content_providers_users_on_user_id'
- end
-
- create_table 'edit_suggestions', force: :cascade do |t|
- t.text 'name'
- t.text 'text'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.integer 'suggestible_id'
- t.string 'suggestible_type'
- t.json 'data_fields', default: {}
- t.index %w[suggestible_id suggestible_type], name: 'index_edit_suggestions_on_suggestible_id_and_suggestible_type'
- end
-
- create_table 'event_materials', force: :cascade do |t|
- t.integer 'event_id'
- t.integer 'material_id'
- t.index ['event_id'], name: 'index_event_materials_on_event_id'
- t.index ['material_id'], name: 'index_event_materials_on_material_id'
- end
-
- create_table 'events', force: :cascade do |t|
- t.string 'external_id'
- t.string 'title'
- t.string 'subtitle'
- t.string 'url'
- t.string 'organizer'
- t.text 'description'
- t.datetime 'start'
- t.datetime 'end'
- t.string 'sponsors', default: [], array: true
- t.text 'venue'
- t.string 'city'
- t.string 'county'
- t.string 'country'
- t.string 'postcode'
- t.decimal 'latitude', precision: 10, scale: 6
- t.decimal 'longitude', precision: 10, scale: 6
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.text 'source', default: 'tess'
- t.string 'slug'
- t.integer 'content_provider_id'
- t.integer 'user_id'
- t.integer 'presence', default: 0
- t.decimal 'cost_value'
- t.date 'last_scraped'
- t.boolean 'scraper_record', default: false
- t.string 'keywords', default: [], array: true
- t.string 'event_types', default: [], array: true
- t.string 'target_audience', default: [], array: true
- t.integer 'capacity'
- t.string 'eligibility', default: [], array: true
- t.text 'contact'
- t.string 'host_institutions', default: [], array: true
- t.string 'timezone'
- t.string 'funding'
- t.integer 'attendee_count'
- t.integer 'applicant_count'
- t.integer 'trainer_count'
- t.string 'feedback'
- t.text 'notes'
- t.integer 'nominatim_count', default: 0
- t.string 'duration'
- t.text 'recognition'
- t.text 'learning_objectives'
- t.text 'prerequisites'
- t.text 'tech_requirements'
- t.string 'cost_basis'
- t.string 'cost_currency'
- t.string 'fields', default: [], array: true
- t.boolean 'llm_processed', default: false
- t.string 'open_science', default: [], array: true
- t.boolean 'visible', default: true
- t.index ['presence'], name: 'index_events_on_presence'
- t.index ['slug'], name: 'index_events_on_slug', unique: true
- t.index ['user_id'], name: 'index_events_on_user_id'
- end
-
- create_table 'external_resources', force: :cascade do |t|
- t.integer 'source_id'
- t.text 'url'
- t.string 'title'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.string 'source_type'
- t.index %w[source_id source_type], name: 'index_external_resources_on_source_id_and_source_type'
- end
-
- create_table 'field_locks', force: :cascade do |t|
- t.integer 'resource_id'
- t.string 'resource_type'
- t.string 'field'
- t.index %w[resource_type resource_id], name: 'index_field_locks_on_resource_type_and_resource_id'
- end
-
- create_table 'friendly_id_slugs', force: :cascade do |t|
- t.string 'slug', null: false
- t.integer 'sluggable_id', null: false
- t.string 'sluggable_type', limit: 50
- t.string 'scope'
- t.datetime 'created_at'
- t.index %w[slug sluggable_type scope], name: 'index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope', unique: true
- t.index %w[slug sluggable_type], name: 'index_friendly_id_slugs_on_slug_and_sluggable_type'
- t.index ['sluggable_id'], name: 'index_friendly_id_slugs_on_sluggable_id'
- t.index ['sluggable_type'], name: 'index_friendly_id_slugs_on_sluggable_type'
- end
-
- create_table 'learning_path_topic_items', force: :cascade do |t|
- t.bigint 'topic_id'
- t.string 'resource_type'
- t.bigint 'resource_id'
- t.text 'comment'
- t.integer 'order'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.index %w[resource_type resource_id], name: 'index_learning_path_topic_items_on_resource'
- t.index ['topic_id'], name: 'index_learning_path_topic_items_on_topic_id'
- end
-
- create_table 'learning_path_topic_links', force: :cascade do |t|
- t.bigint 'learning_path_id'
- t.bigint 'topic_id'
- t.integer 'order'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.index ['learning_path_id'], name: 'index_learning_path_topic_links_on_learning_path_id'
- t.index ['topic_id'], name: 'index_learning_path_topic_links_on_topic_id'
- end
-
- create_table 'learning_path_topics', force: :cascade do |t|
- t.string 'title'
- t.text 'description'
- t.integer 'user_id'
- t.string 'keywords', default: [], array: true
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.string 'difficulty_level', default: 'notspecified'
- end
-
- create_table 'learning_paths', force: :cascade do |t|
- t.text 'title'
- t.text 'description'
- t.string 'doi'
- t.string 'target_audience', default: [], array: true
- t.string 'authors', default: [], array: true
- t.string 'contributors', default: [], array: true
- t.string 'licence', default: 'notspecified'
- t.string 'difficulty_level', default: 'notspecified'
- t.string 'slug'
- t.bigint 'user_id'
- t.bigint 'content_provider_id'
- t.string 'keywords', default: [], array: true
- t.text 'prerequisites'
- t.text 'learning_objectives'
- t.string 'status'
- t.string 'learning_path_type'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.boolean 'public', default: true
- t.index ['content_provider_id'], name: 'index_learning_paths_on_content_provider_id'
- t.index ['slug'], name: 'index_learning_paths_on_slug', unique: true
- t.index ['user_id'], name: 'index_learning_paths_on_user_id'
- end
-
- create_table 'link_monitors', force: :cascade do |t|
- t.string 'url'
- t.integer 'code'
- t.datetime 'failed_at'
- t.datetime 'last_failed_at'
- t.integer 'fail_count'
- t.integer 'lcheck_id'
- t.string 'lcheck_type'
- t.index %w[lcheck_type lcheck_id], name: 'index_link_monitors_on_lcheck_type_and_lcheck_id'
- end
-
- create_table 'materials', force: :cascade do |t|
- t.text 'title'
- t.string 'url'
- t.string 'doi'
- t.date 'remote_updated_date'
- t.date 'remote_created_date'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.text 'description'
- t.string 'target_audience', default: [], array: true
- t.string 'authors', default: [], array: true
- t.string 'contributors', default: [], array: true
- t.string 'licence', default: 'notspecified'
- t.string 'difficulty_level', default: 'notspecified'
- t.integer 'content_provider_id'
- t.string 'slug'
- t.integer 'user_id'
- t.date 'last_scraped'
- t.boolean 'scraper_record', default: false
- t.string 'resource_type', default: [], array: true
- t.string 'keywords', default: [], array: true
- t.string 'other_types'
- t.date 'date_created'
- t.date 'date_modified'
- t.date 'date_published'
- t.text 'prerequisites'
- t.string 'version'
- t.string 'status'
- t.text 'syllabus'
- t.string 'subsets', default: [], array: true
- t.text 'contact'
- t.text 'learning_objectives'
- t.string 'fields', default: [], array: true
- t.boolean 'llm_processed', default: false
- t.index ['content_provider_id'], name: 'index_materials_on_content_provider_id'
- t.index ['slug'], name: 'index_materials_on_slug', unique: true
- t.index ['user_id'], name: 'index_materials_on_user_id'
- end
-
- create_table 'node_links', force: :cascade do |t|
- t.integer 'node_id'
- t.integer 'resource_id'
- t.string 'resource_type'
- t.index ['node_id'], name: 'index_node_links_on_node_id'
- t.index %w[resource_type resource_id], name: 'index_node_links_on_resource_type_and_resource_id'
- end
-
- create_table 'nodes', force: :cascade do |t|
- t.string 'name'
- t.string 'member_status'
- t.string 'country_code'
- t.string 'home_page'
- t.string 'twitter'
- t.string 'carousel_images', array: true
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.string 'slug'
- t.integer 'user_id'
- t.text 'image_url'
- t.text 'description'
- t.index ['slug'], name: 'index_nodes_on_slug', unique: true
- t.index ['user_id'], name: 'index_nodes_on_user_id'
- end
-
- create_table 'ontology_term_links', force: :cascade do |t|
- t.integer 'resource_id'
- t.string 'resource_type'
- t.string 'term_uri'
- t.string 'field'
- t.index ['field'], name: 'index_ontology_term_links_on_field'
- t.index %w[resource_type resource_id], name: 'index_ontology_term_links_on_resource_type_and_resource_id'
- t.index ['term_uri'], name: 'index_ontology_term_links_on_term_uri'
- end
-
- create_table 'profiles', force: :cascade do |t|
- t.text 'firstname'
- t.text 'surname'
- t.text 'image_url'
- t.text 'email'
- t.text 'website'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.integer 'user_id'
- t.string 'slug'
- t.boolean 'public', default: false
- t.text 'description'
- t.text 'location'
- t.string 'orcid'
- t.string 'experience'
- t.string 'expertise_academic', default: [], array: true
- t.string 'expertise_technical', default: [], array: true
- t.string 'interest', default: [], array: true
- t.string 'activity', default: [], array: true
- t.string 'language', default: [], array: true
- t.string 'social_media', default: [], array: true
- t.string 'type', default: 'Profile'
- t.string 'fields', default: [], array: true
- t.index ['slug'], name: 'index_profiles_on_slug', unique: true
- end
-
- create_table 'roles', force: :cascade do |t|
- t.string 'name'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.string 'title'
- end
-
- create_table 'sessions', force: :cascade do |t|
- t.string 'session_id', null: false
- t.text 'data'
- t.datetime 'created_at'
- t.datetime 'updated_at'
- t.index ['session_id'], name: 'index_sessions_on_session_id', unique: true
- t.index ['updated_at'], name: 'index_sessions_on_updated_at'
- end
-
- create_table 'sources', force: :cascade do |t|
- t.bigint 'content_provider_id'
- t.bigint 'user_id'
- t.datetime 'created_at'
- t.datetime 'finished_at'
- t.string 'url'
- t.string 'method'
- t.integer 'records_read'
- t.integer 'records_written'
- t.integer 'resources_added'
- t.integer 'resources_updated'
- t.integer 'resources_rejected'
- t.text 'log'
- t.boolean 'enabled'
- t.string 'token'
- t.integer 'approval_status'
- t.datetime 'updated_at'
- t.index ['content_provider_id'], name: 'index_sources_on_content_provider_id'
- t.index ['user_id'], name: 'index_sources_on_user_id'
- end
-
- create_table 'staff_members', force: :cascade do |t|
- t.string 'name'
- t.string 'role'
- t.string 'email'
- t.text 'image_url'
- t.integer 'node_id'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.string 'image_file_name'
- t.string 'image_content_type'
- t.bigint 'image_file_size'
- t.datetime 'image_updated_at'
- t.index ['node_id'], name: 'index_staff_members_on_node_id'
- end
-
- create_table 'stars', force: :cascade do |t|
- t.integer 'user_id'
- t.integer 'resource_id'
- t.string 'resource_type'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.index %w[resource_type resource_id], name: 'index_stars_on_resource_type_and_resource_id'
- t.index ['user_id'], name: 'index_stars_on_user_id'
- end
-
- create_table 'subscriptions', force: :cascade do |t|
- t.integer 'user_id'
- t.datetime 'last_sent_at'
- t.text 'query'
- t.json 'facets'
- t.integer 'frequency'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.string 'subscribable_type'
- t.datetime 'last_checked_at'
- t.index ['user_id'], name: 'index_subscriptions_on_user_id'
- end
-
- create_table 'users', force: :cascade do |t|
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.string 'username'
- t.integer 'role_id'
- t.string 'authentication_token'
- t.string 'email', default: '', null: false
- t.string 'encrypted_password', default: '', null: false
- t.string 'reset_password_token'
- t.datetime 'reset_password_sent_at'
- t.datetime 'remember_created_at'
- t.integer 'sign_in_count', default: 0, null: false
- t.datetime 'current_sign_in_at'
- t.datetime 'last_sign_in_at'
- t.inet 'current_sign_in_ip'
- t.inet 'last_sign_in_ip'
- t.string 'confirmation_token'
- t.datetime 'confirmed_at'
- t.datetime 'confirmation_sent_at'
- t.string 'unconfirmed_email'
- t.integer 'failed_attempts', default: 0, null: false
- t.string 'unlock_token'
- t.datetime 'locked_at'
- t.string 'slug'
- t.string 'provider'
- t.string 'uid'
- t.string 'identity_url'
- t.string 'invitation_token'
- t.datetime 'invitation_created_at'
- t.datetime 'invitation_sent_at'
- t.datetime 'invitation_accepted_at'
- t.integer 'invitation_limit'
- t.string 'invited_by_type'
- t.bigint 'invited_by_id'
- t.integer 'invitations_count', default: 0
- t.text 'image_url'
- t.string 'image_file_name'
- t.string 'image_content_type'
- t.bigint 'image_file_size'
- t.datetime 'image_updated_at'
- t.index ['authentication_token'], name: 'index_users_on_authentication_token'
- t.index ['confirmation_token'], name: 'index_users_on_confirmation_token', unique: true
- t.index ['email'], name: 'index_users_on_email', unique: true
- t.index ['identity_url'], name: 'index_users_on_identity_url', unique: true
- t.index ['invitation_token'], name: 'index_users_on_invitation_token', unique: true
- t.index ['invited_by_id'], name: 'index_users_on_invited_by_id'
- t.index %w[invited_by_type invited_by_id], name: 'index_users_on_invited_by'
- t.index ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true
- t.index ['role_id'], name: 'index_users_on_role_id'
- t.index ['slug'], name: 'index_users_on_slug', unique: true
- t.index ['unlock_token'], name: 'index_users_on_unlock_token', unique: true
- t.index ['username'], name: 'index_users_on_username', unique: true
- end
-
- create_table 'widget_logs', force: :cascade do |t|
- t.string 'widget_name'
- t.string 'action'
- t.integer 'resource_id'
- t.string 'resource_type'
- t.text 'data'
- t.json 'params'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.index %w[resource_type resource_id], name: 'index_widget_logs_on_resource_type_and_resource_id'
- end
-
- create_table 'workflows', force: :cascade do |t|
- t.string 'title'
- t.string 'description'
- t.integer 'user_id'
- t.json 'workflow_content'
- t.datetime 'created_at', null: false
- t.datetime 'updated_at', null: false
- t.string 'slug'
- t.string 'target_audience', default: [], array: true
- t.string 'keywords', default: [], array: true
- t.string 'authors', default: [], array: true
- t.string 'contributors', default: [], array: true
- t.string 'licence', default: 'notspecified'
- t.string 'difficulty_level', default: 'notspecified'
- t.string 'doi'
- t.date 'remote_created_date'
- t.date 'remote_updated_date'
- t.boolean 'hide_child_nodes', default: false
- t.boolean 'public', default: true
- t.index ['slug'], name: 'index_workflows_on_slug', unique: true
- t.index ['user_id'], name: 'index_workflows_on_user_id'
- end
-
- add_foreign_key 'bans', 'users'
- add_foreign_key 'bans', 'users', column: 'banner_id'
- add_foreign_key 'collaborations', 'users'
- add_foreign_key 'collections', 'users'
- add_foreign_key 'content_providers', 'nodes'
- add_foreign_key 'content_providers', 'users'
- add_foreign_key 'event_materials', 'events'
- add_foreign_key 'event_materials', 'materials'
- add_foreign_key 'events', 'users'
- add_foreign_key 'materials', 'content_providers'
- add_foreign_key 'materials', 'users'
- add_foreign_key 'node_links', 'nodes'
- add_foreign_key 'nodes', 'users'
- add_foreign_key 'sources', 'content_providers'
- add_foreign_key 'sources', 'users'
- add_foreign_key 'staff_members', 'nodes'
- add_foreign_key 'stars', 'users'
- add_foreign_key 'subscriptions', 'users'
- add_foreign_key 'users', 'roles'
- add_foreign_key 'workflows', 'users'
+ t.index ["node_id"], name: "index_content_providers_on_node_id"
+ t.index ["slug"], name: "index_content_providers_on_slug", unique: true
+ t.index ["user_id"], name: "index_content_providers_on_user_id"
+ end
+
+ create_table "content_providers_users", id: false, force: :cascade do |t|
+ t.bigint "content_provider_id"
+ t.bigint "user_id"
+ t.index ["content_provider_id", "user_id"], name: "provider_user_unique", unique: true
+ t.index ["content_provider_id"], name: "index_content_providers_users_on_content_provider_id"
+ t.index ["user_id"], name: "index_content_providers_users_on_user_id"
+ end
+
+ create_table "edit_suggestions", id: :serial, force: :cascade do |t|
+ t.text "name"
+ t.text "text"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.integer "suggestible_id"
+ t.string "suggestible_type"
+ t.json "data_fields", default: {}
+ t.index ["suggestible_id", "suggestible_type"], name: "index_edit_suggestions_on_suggestible_id_and_suggestible_type"
+ end
+
+ create_table "event_materials", id: :serial, force: :cascade do |t|
+ t.integer "event_id"
+ t.integer "material_id"
+ t.index ["event_id"], name: "index_event_materials_on_event_id"
+ t.index ["material_id"], name: "index_event_materials_on_material_id"
+ end
+
+ create_table "events", id: :serial, force: :cascade do |t|
+ t.string "external_id"
+ t.string "title"
+ t.string "subtitle"
+ t.string "url"
+ t.string "organizer"
+ t.text "description"
+ t.datetime "start", precision: nil
+ t.datetime "end", precision: nil
+ t.string "sponsors", default: [], array: true
+ t.text "venue"
+ t.string "city"
+ t.string "county"
+ t.string "country"
+ t.string "postcode"
+ t.decimal "latitude", precision: 10, scale: 6
+ t.decimal "longitude", precision: 10, scale: 6
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.text "source", default: "tess"
+ t.string "slug"
+ t.integer "content_provider_id"
+ t.integer "user_id"
+ t.integer "presence", default: 0
+ t.decimal "cost_value"
+ t.date "last_scraped"
+ t.boolean "scraper_record", default: false
+ t.string "keywords", default: [], array: true
+ t.string "event_types", default: [], array: true
+ t.string "target_audience", default: [], array: true
+ t.integer "capacity"
+ t.string "eligibility", default: [], array: true
+ t.text "contact"
+ t.string "host_institutions", default: [], array: true
+ t.string "timezone"
+ t.string "funding"
+ t.integer "attendee_count"
+ t.integer "applicant_count"
+ t.integer "trainer_count"
+ t.string "feedback"
+ t.text "notes"
+ t.integer "nominatim_count", default: 0
+ t.string "duration"
+ t.text "recognition"
+ t.text "learning_objectives"
+ t.text "prerequisites"
+ t.text "tech_requirements"
+ t.string "cost_basis"
+ t.string "cost_currency"
+ t.string "fields", default: [], array: true
+ t.string "open_science", default: [], array: true
+ t.boolean "visible", default: true
+ t.index ["presence"], name: "index_events_on_presence"
+ t.index ["slug"], name: "index_events_on_slug", unique: true
+ t.index ["user_id"], name: "index_events_on_user_id"
+ end
+
+ create_table "external_resources", id: :serial, force: :cascade do |t|
+ t.integer "source_id"
+ t.text "url"
+ t.string "title"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.string "source_type"
+ t.index ["source_id", "source_type"], name: "index_external_resources_on_source_id_and_source_type"
+ end
+
+ create_table "field_locks", id: :serial, force: :cascade do |t|
+ t.string "resource_type"
+ t.integer "resource_id"
+ t.string "field"
+ t.index ["resource_type", "resource_id"], name: "index_field_locks_on_resource_type_and_resource_id"
+ end
+
+ create_table "friendly_id_slugs", id: :serial, force: :cascade do |t|
+ t.string "slug", null: false
+ t.integer "sluggable_id", null: false
+ t.string "sluggable_type", limit: 50
+ t.string "scope"
+ t.datetime "created_at", precision: nil
+ t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true
+ t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type"
+ t.index ["sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_id"
+ t.index ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type"
+ end
+
+ create_table "learning_path_topic_items", force: :cascade do |t|
+ t.bigint "topic_id"
+ t.string "resource_type"
+ t.bigint "resource_id"
+ t.text "comment"
+ t.integer "order"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["resource_type", "resource_id"], name: "index_learning_path_topic_items_on_resource"
+ t.index ["topic_id"], name: "index_learning_path_topic_items_on_topic_id"
+ end
+
+ create_table "learning_path_topic_links", force: :cascade do |t|
+ t.bigint "learning_path_id"
+ t.bigint "topic_id"
+ t.integer "order"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["learning_path_id"], name: "index_learning_path_topic_links_on_learning_path_id"
+ t.index ["topic_id"], name: "index_learning_path_topic_links_on_topic_id"
+ end
+
+ create_table "learning_path_topics", force: :cascade do |t|
+ t.string "title"
+ t.text "description"
+ t.integer "user_id"
+ t.string "keywords", default: [], array: true
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.string "difficulty_level", default: "notspecified"
+ end
+
+ create_table "learning_paths", force: :cascade do |t|
+ t.text "title"
+ t.text "description"
+ t.string "doi"
+ t.string "target_audience", default: [], array: true
+ t.string "authors", default: [], array: true
+ t.string "contributors", default: [], array: true
+ t.string "licence", default: "notspecified"
+ t.string "difficulty_level", default: "notspecified"
+ t.string "slug"
+ t.bigint "user_id"
+ t.bigint "content_provider_id"
+ t.string "keywords", default: [], array: true
+ t.text "prerequisites"
+ t.text "learning_objectives"
+ t.string "status"
+ t.string "learning_path_type"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.boolean "public", default: true
+ t.index ["content_provider_id"], name: "index_learning_paths_on_content_provider_id"
+ t.index ["slug"], name: "index_learning_paths_on_slug", unique: true
+ t.index ["user_id"], name: "index_learning_paths_on_user_id"
+ end
+
+ create_table "link_monitors", id: :serial, force: :cascade do |t|
+ t.string "url"
+ t.integer "code"
+ t.datetime "failed_at", precision: nil
+ t.datetime "last_failed_at", precision: nil
+ t.integer "fail_count"
+ t.string "lcheck_type"
+ t.integer "lcheck_id"
+ t.index ["lcheck_type", "lcheck_id"], name: "index_link_monitors_on_lcheck_type_and_lcheck_id"
+ end
+
+ create_table "llm_object", force: :cascade do |t|
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "scrape_or_process"
+ t.string "model"
+ t.string "prompt"
+ t.string "input"
+ t.string "output"
+ t.boolean "needs_processing", default: false
+ end
+
+ create_table "materials", id: :serial, force: :cascade do |t|
+ t.text "title"
+ t.string "url"
+ t.string "doi"
+ t.date "remote_updated_date"
+ t.date "remote_created_date"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.text "description"
+ t.string "target_audience", default: [], array: true
+ t.string "keywords", default: [], array: true
+ t.string "authors", default: [], array: true
+ t.string "contributors", default: [], array: true
+ t.string "licence", default: "notspecified"
+ t.string "difficulty_level", default: "notspecified"
+ t.integer "content_provider_id"
+ t.string "slug"
+ t.integer "user_id"
+ t.date "last_scraped"
+ t.boolean "scraper_record", default: false
+ t.string "resource_type", default: [], array: true
+ t.string "other_types"
+ t.date "date_created"
+ t.date "date_modified"
+ t.date "date_published"
+ t.text "prerequisites"
+ t.string "version"
+ t.string "status"
+ t.text "syllabus"
+ t.string "subsets", default: [], array: true
+ t.text "contact"
+ t.text "learning_objectives"
+ t.string "fields", default: [], array: true
+ t.boolean "llm_processed", default: false
+ t.index ["content_provider_id"], name: "index_materials_on_content_provider_id"
+ t.index ["slug"], name: "index_materials_on_slug", unique: true
+ t.index ["user_id"], name: "index_materials_on_user_id"
+ end
+
+ create_table "node_links", id: :serial, force: :cascade do |t|
+ t.integer "node_id"
+ t.string "resource_type"
+ t.integer "resource_id"
+ t.index ["node_id"], name: "index_node_links_on_node_id"
+ t.index ["resource_type", "resource_id"], name: "index_node_links_on_resource_type_and_resource_id"
+ end
+
+ create_table "nodes", id: :serial, force: :cascade do |t|
+ t.string "name"
+ t.string "member_status"
+ t.string "country_code"
+ t.string "home_page"
+ t.string "twitter"
+ t.string "carousel_images", array: true
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.string "slug"
+ t.integer "user_id"
+ t.text "image_url"
+ t.text "description"
+ t.index ["slug"], name: "index_nodes_on_slug", unique: true
+ t.index ["user_id"], name: "index_nodes_on_user_id"
+ end
+
+ create_table "ontology_term_links", id: :serial, force: :cascade do |t|
+ t.string "resource_type"
+ t.integer "resource_id"
+ t.string "term_uri"
+ t.string "field"
+ t.index ["field"], name: "index_ontology_term_links_on_field"
+ t.index ["resource_type", "resource_id"], name: "index_ontology_term_links_on_resource_type_and_resource_id"
+ t.index ["term_uri"], name: "index_ontology_term_links_on_term_uri"
+ end
+
+ create_table "profiles", id: :serial, force: :cascade do |t|
+ t.text "firstname"
+ t.text "surname"
+ t.text "image_url"
+ t.text "email"
+ t.text "website"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.integer "user_id"
+ t.string "slug"
+ t.boolean "public", default: false
+ t.text "description"
+ t.text "location"
+ t.string "orcid"
+ t.string "experience"
+ t.string "expertise_academic", default: [], array: true
+ t.string "expertise_technical", default: [], array: true
+ t.string "interest", default: [], array: true
+ t.string "activity", default: [], array: true
+ t.string "language", default: [], array: true
+ t.string "social_media", default: [], array: true
+ t.string "type", default: "Profile"
+ t.string "fields", default: [], array: true
+ t.index ["slug"], name: "index_profiles_on_slug", unique: true
+ end
+
+ create_table "roles", id: :serial, force: :cascade do |t|
+ t.string "name"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.string "title"
+ end
+
+ create_table "sessions", id: :serial, force: :cascade do |t|
+ t.string "session_id", null: false
+ t.text "data"
+ t.datetime "created_at", precision: nil
+ t.datetime "updated_at", precision: nil
+ t.index ["session_id"], name: "index_sessions_on_session_id", unique: true
+ t.index ["updated_at"], name: "index_sessions_on_updated_at"
+ end
+
+ create_table "sources", force: :cascade do |t|
+ t.bigint "content_provider_id"
+ t.bigint "user_id"
+ t.datetime "created_at", precision: nil
+ t.datetime "finished_at", precision: nil
+ t.string "url"
+ t.string "method"
+ t.integer "records_read"
+ t.integer "records_written"
+ t.integer "resources_added"
+ t.integer "resources_updated"
+ t.integer "resources_rejected"
+ t.text "log"
+ t.boolean "enabled"
+ t.string "token"
+ t.integer "approval_status"
+ t.datetime "updated_at", precision: nil
+ t.index ["content_provider_id"], name: "index_sources_on_content_provider_id"
+ t.index ["user_id"], name: "index_sources_on_user_id"
+ end
+
+ create_table "staff_members", id: :serial, force: :cascade do |t|
+ t.string "name"
+ t.string "role"
+ t.string "email"
+ t.text "image_url"
+ t.integer "node_id"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.string "image_file_name"
+ t.string "image_content_type"
+ t.bigint "image_file_size"
+ t.datetime "image_updated_at"
+ t.index ["node_id"], name: "index_staff_members_on_node_id"
+ end
+
+ create_table "stars", id: :serial, force: :cascade do |t|
+ t.integer "user_id"
+ t.string "resource_type"
+ t.integer "resource_id"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.index ["resource_type", "resource_id"], name: "index_stars_on_resource_type_and_resource_id"
+ t.index ["user_id"], name: "index_stars_on_user_id"
+ end
+
+ create_table "subscriptions", id: :serial, force: :cascade do |t|
+ t.integer "user_id"
+ t.datetime "last_sent_at", precision: nil
+ t.text "query"
+ t.json "facets"
+ t.integer "frequency"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.string "subscribable_type"
+ t.datetime "last_checked_at", precision: nil
+ t.index ["user_id"], name: "index_subscriptions_on_user_id"
+ end
+
+ create_table "users", id: :serial, force: :cascade do |t|
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.string "username"
+ t.integer "role_id"
+ t.string "authentication_token"
+ t.string "email", default: "", null: false
+ t.string "encrypted_password", default: "", null: false
+ t.string "reset_password_token"
+ t.datetime "reset_password_sent_at", precision: nil
+ t.datetime "remember_created_at", precision: nil
+ t.integer "sign_in_count", default: 0, null: false
+ t.datetime "current_sign_in_at", precision: nil
+ t.datetime "last_sign_in_at", precision: nil
+ t.inet "current_sign_in_ip"
+ t.inet "last_sign_in_ip"
+ t.string "confirmation_token"
+ t.datetime "confirmed_at", precision: nil
+ t.datetime "confirmation_sent_at", precision: nil
+ t.string "unconfirmed_email"
+ t.integer "failed_attempts", default: 0, null: false
+ t.string "unlock_token"
+ t.datetime "locked_at", precision: nil
+ t.string "slug"
+ t.string "provider"
+ t.string "uid"
+ t.string "identity_url"
+ t.string "invitation_token"
+ t.datetime "invitation_created_at", precision: nil
+ t.datetime "invitation_sent_at", precision: nil
+ t.datetime "invitation_accepted_at", precision: nil
+ t.integer "invitation_limit"
+ t.string "invited_by_type"
+ t.bigint "invited_by_id"
+ t.integer "invitations_count", default: 0
+ t.text "image_url"
+ t.string "image_file_name"
+ t.string "image_content_type"
+ t.bigint "image_file_size"
+ t.datetime "image_updated_at", precision: nil
+ t.index ["authentication_token"], name: "index_users_on_authentication_token"
+ t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
+ t.index ["email"], name: "index_users_on_email", unique: true
+ t.index ["identity_url"], name: "index_users_on_identity_url", unique: true
+ t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
+ t.index ["invited_by_id"], name: "index_users_on_invited_by_id"
+ t.index ["invited_by_type", "invited_by_id"], name: "index_users_on_invited_by_type_and_invited_by_id"
+ t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
+ t.index ["role_id"], name: "index_users_on_role_id"
+ t.index ["slug"], name: "index_users_on_slug", unique: true
+ t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true
+ t.index ["username"], name: "index_users_on_username", unique: true
+ end
+
+ create_table "widget_logs", id: :serial, force: :cascade do |t|
+ t.string "widget_name"
+ t.string "action"
+ t.string "resource_type"
+ t.integer "resource_id"
+ t.text "data"
+ t.json "params"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.index ["resource_type", "resource_id"], name: "index_widget_logs_on_resource_type_and_resource_id"
+ end
+
+ create_table "workflows", id: :serial, force: :cascade do |t|
+ t.string "title"
+ t.string "description"
+ t.integer "user_id"
+ t.json "workflow_content"
+ t.datetime "created_at", precision: nil, null: false
+ t.datetime "updated_at", precision: nil, null: false
+ t.string "slug"
+ t.string "target_audience", default: [], array: true
+ t.string "keywords", default: [], array: true
+ t.string "authors", default: [], array: true
+ t.string "contributors", default: [], array: true
+ t.string "licence", default: "notspecified"
+ t.string "difficulty_level", default: "notspecified"
+ t.string "doi"
+ t.date "remote_created_date"
+ t.date "remote_updated_date"
+ t.boolean "hide_child_nodes", default: false
+ t.boolean "public", default: true
+ t.index ["slug"], name: "index_workflows_on_slug", unique: true
+ t.index ["user_id"], name: "index_workflows_on_user_id"
+ end
+
+ add_foreign_key "bans", "users"
+ add_foreign_key "bans", "users", column: "banner_id"
+ add_foreign_key "collaborations", "users"
+ add_foreign_key "collections", "users"
+ add_foreign_key "content_providers", "nodes"
+ add_foreign_key "content_providers", "users"
+ add_foreign_key "event_materials", "events"
+ add_foreign_key "event_materials", "materials"
+ add_foreign_key "events", "users"
+ add_foreign_key "learning_path_topic_links", "learning_paths"
+ add_foreign_key "learning_paths", "content_providers"
+ add_foreign_key "learning_paths", "users"
+ add_foreign_key "materials", "content_providers"
+ add_foreign_key "materials", "users"
+ add_foreign_key "node_links", "nodes"
+ add_foreign_key "nodes", "users"
+ add_foreign_key "sources", "content_providers"
+ add_foreign_key "sources", "users"
+ add_foreign_key "staff_members", "nodes"
+ add_foreign_key "stars", "users"
+ add_foreign_key "subscriptions", "users"
+ add_foreign_key "users", "roles"
+ add_foreign_key "workflows", "users"
end
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index 0772ab63d..edc24ec85 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -75,9 +75,9 @@ def scrape_tdcc
def process_llm(_url)
scrape_dans
- scrape_nwo
- scrape_rug
- scrape_tdcc
+ # scrape_nwo
+ # scrape_rug
+ # scrape_tdcc
# json not necessary (SURF, UvA)
# XML not necessary (wur)
end
@@ -101,6 +101,7 @@ def beep_func(url, event_page) # rubocop:disable Metrics
event.source = 'LLM'
event.timezone = 'Amsterdam'
add_event(event)
+ puts event
rescue Exception => e
puts e
@messages << "Extract event fields failed with: #{e.message}"
diff --git a/lib/modules/llm_service.rb b/lib/modules/llm_service.rb
index f6c5718da..6d662d3f6 100644
--- a/lib/modules/llm_service.rb
+++ b/lib/modules/llm_service.rb
@@ -6,14 +6,16 @@ def initialize
end
def llm_object
- LlmObject.new(
+ # LlmObject.new(
+ {
scrape_or_process: @scrape_or_process,
model: @params[:model],
prompt: @prompt,
input: @input,
output: @output,
needs_processing: false
- )
+ }
+ # )
end
def unload_json(event, response)
@@ -46,14 +48,14 @@ def process(event)
def scrape_func(event, event_page)
response = scrape(event_page)
event = unload_json(event, response)
- event.llm_object = llm_object
+ # event.llm_object = llm_object
event
end
def post_process_func(event)
response = process(event)
event = unload_json(event, response)
- event.llm_object = llm_object
+ # event.llm_object = llm_object
event
end
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
index fcd31d1af..26201d476 100644
--- a/lib/modules/willma_service.rb
+++ b/lib/modules/willma_service.rb
@@ -15,8 +15,23 @@ def initialize
end
def run(content)
- msg = call(content)['message']
- res = get_first_json_from_string(msg)
+ # msg = call(content)['message']
+ # res = get_first_json_from_string(msg)
+ res = {
+ title: "Open Hour SSH: Live Q&A on Monday",
+ organizer: "Data Archive Netherlands (DANS)",
+ description: "Get all your questions answered during Open Hour for the SSH community. A live Q&A every Monday morning. Meet us at the Open Hour every Monday from 10:00 to 11:00 CEST for the Social Sciences and Humanities (SSH) community. The Open Hour is a Q&A on Open Science, data storage and Research Data Management. Register here for the Open Hour and send in your question(s).",
+ start: "2024-06-03T10:00:00+02:00",
+ end: "2024-06-03T11:00:00+02:00",
+ venue: "Online",
+ keywords: ["natural & engineering sciences", "humanities & social sciences", "life sciences"],
+ target_audience: ["researchers", "research support staff", "bachelor & master students", "PhD candidates", "teaching staff", "other"],
+ open_science: ["open software", "FAIR data", "Open Access"],
+ visible: true,
+ url: "https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/",
+ source: "LLM",
+ timezone: "Amsterdam"
+ }.to_json
res
end
diff --git a/lib/tasks/seed_content_providers.rake b/lib/tasks/seed_content_providers.rake
new file mode 100644
index 000000000..4c81dac1e
--- /dev/null
+++ b/lib/tasks/seed_content_providers.rake
@@ -0,0 +1,25 @@
+require 'yaml'
+
+namespace :tess do
+ desc 'create ContentProviders objects for all scrapers'
+ task seed_content_providers: :environment do
+ if TeSS::Config.ingestion.nil?
+ config_file = File.join(Rails.root, 'config', 'ingestion.yml')
+ TeSS::Config.ingestion = YAML.safe_load(File.read(config_file)).deep_symbolize_keys!
+ end
+ config = TeSS::Config.ingestion
+
+ admin_user = User.all.select{|user| user.is_admin?}.first
+
+ config[:sources].each do |source|
+ if ContentProvider.find_by(title: source[:provider]).nil?
+ ContentProvider.create!(
+ title: source[:provider],
+ url: source[:url],
+ image_url: source[:image_url],
+ user_id: admin_user.id,
+ )
+ end
+ end
+ end
+end
\ No newline at end of file
From fa9235915fae1a7ea5a1974cc97fdf9b84d7d8a5 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Mon, 3 Jun 2024 15:38:42 +0200
Subject: [PATCH 16/37] working llm_object
---
app/controllers/events_controller.rb | 2 +-
app/models/event.rb | 2 +-
app/models/llm_object.rb | 2 +-
db/migrate/20240220144246_add_llm_check.rb | 3 ++-
db/schema.rb | 5 ++++-
lib/ingestors/ingestor.rb | 20 ++++++++++++++++++++
lib/ingestors/llm_ingestor.rb | 1 -
lib/modules/llm_service.rb | 4 ++--
8 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb
index e849461d0..7d4e55346 100644
--- a/app/controllers/events_controller.rb
+++ b/app/controllers/events_controller.rb
@@ -235,7 +235,7 @@ def event_params
{ host_institutions: [] }, :capacity, :contact, :recognition, :learning_objectives,
:prerequisites, :tech_requirements, :cost_basis, :cost_value, :cost_currency,
external_resources_attributes: %i[id url title _destroy], material_ids: [],
- llm_object_attributes: %i[scrape_or_process model prompt input output needs_processing],
+ llm_object_attributes: %i[id scrape_or_process model prompt input output needs_processing _destroy],
locked_fields: [])
end
diff --git a/app/models/event.rb b/app/models/event.rb
index f09a7a1c4..cdc6e15c8 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -109,7 +109,7 @@ class Event < ApplicationRecord
enum presence: { onsite: 0, online: 1, hybrid: 2 }
belongs_to :user
- has_one :llm_object, inverse_of: :event
+ has_one :llm_object, inverse_of: :event, dependent: :destroy
accepts_nested_attributes_for :llm_object, allow_destroy: true
has_one :edit_suggestion, as: :suggestible, dependent: :destroy
has_one :link_monitor, as: :lcheck, dependent: :destroy
diff --git a/app/models/llm_object.rb b/app/models/llm_object.rb
index b5f7788e6..a43bcfb8e 100644
--- a/app/models/llm_object.rb
+++ b/app/models/llm_object.rb
@@ -5,5 +5,5 @@ class LlmObject < ApplicationRecord
validates :prompt, presence: true
validates :input, presence: true
validates :output, presence: true
- validates :needs_processing, presence: true
+ # validates :needs_processing, presence: true
end
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
index 5dd1edd55..80cf2b6b9 100644
--- a/db/migrate/20240220144246_add_llm_check.rb
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -24,7 +24,7 @@ class AddLlmCheck < ActiveRecord::Migration[7.0]
# end
def change
- create_table :llm_object do |t|
+ create_table :llm_objects do |t|
t.belongs_to :event, foreign_key: true
t.datetime :created_at
t.datetime :updated_at
@@ -35,6 +35,7 @@ def change
t.string :output
t.boolean :needs_processing, default: false
end
+ add_reference :events, :llm_object, foreign_key: true
add_column :events, :open_science, :string, array: true, default: []
add_column :materials, :llm_processed, :bool, default: false
end
diff --git a/db/schema.rb b/db/schema.rb
index 4f8bd93fe..6538d677a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -331,7 +331,8 @@
t.index ["lcheck_type", "lcheck_id"], name: "index_link_monitors_on_lcheck_type_and_lcheck_id"
end
- create_table "llm_object", force: :cascade do |t|
+ create_table "llm_objects", force: :cascade do |t|
+ t.bigint "event_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "scrape_or_process"
@@ -340,6 +341,7 @@
t.string "input"
t.string "output"
t.boolean "needs_processing", default: false
+ t.index ["event_id"], name: "index_llm_objects_on_event_id"
end
create_table "materials", id: :serial, force: :cascade do |t|
@@ -618,6 +620,7 @@
add_foreign_key "learning_path_topic_links", "learning_paths"
add_foreign_key "learning_paths", "content_providers"
add_foreign_key "learning_paths", "users"
+ add_foreign_key "llm_objects", "events"
add_foreign_key "materials", "content_providers"
add_foreign_key "materials", "users"
add_foreign_key "node_links", "nodes"
diff --git a/lib/ingestors/ingestor.rb b/lib/ingestors/ingestor.rb
index 90f9dc2f3..711d7cb4e 100644
--- a/lib/ingestors/ingestor.rb
+++ b/lib/ingestors/ingestor.rb
@@ -136,6 +136,7 @@ def write_resources(type, resources, user, provider)
# check for matched events
resource.user_id ||= user.id
resource.content_provider_id ||= provider.id
+ llm_attr = resource.delete_field(:llm_object_attributes)
existing_resource = find_existing(type, resource)
update = existing_resource
@@ -146,9 +147,27 @@ def write_resources(type, resources, user, provider)
end
resource = set_resource_defaults(resource)
+ puts resource.valid?
if resource.valid?
resource.save!
@stats[key][update ? :updated : :added] += 1
+ if llm_attr
+ llm_object = LlmObject.new(llm_attr.to_h)
+ llm_object.event_id = resource.id
+ puts resource.attributes
+ puts llm_object.attributes
+ puts llm_object.needs_processing
+ puts llm_object.valid?
+ puts llm_object.errors.full_messages.map{|k| puts k}
+ llm_object.save!
+ resource.llm_object = llm_object
+ puts resource.llm_object.attributes
+ puts resource.attributes
+ puts resource.valid?
+ if resource.valid?
+ resource.save!
+ end
+ end
else
@stats[key][:rejected] += 1
title = resource.title
@@ -158,6 +177,7 @@ def write_resources(type, resources, user, provider)
@messages << " - #{m}"
end
end
+ puts resource
resources[i] = resource
end
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index edc24ec85..453d0828f 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -101,7 +101,6 @@ def beep_func(url, event_page) # rubocop:disable Metrics
event.source = 'LLM'
event.timezone = 'Amsterdam'
add_event(event)
- puts event
rescue Exception => e
puts e
@messages << "Extract event fields failed with: #{e.message}"
diff --git a/lib/modules/llm_service.rb b/lib/modules/llm_service.rb
index 6d662d3f6..c065024f7 100644
--- a/lib/modules/llm_service.rb
+++ b/lib/modules/llm_service.rb
@@ -48,14 +48,14 @@ def process(event)
def scrape_func(event, event_page)
response = scrape(event_page)
event = unload_json(event, response)
- # event.llm_object = llm_object
+ event.llm_object_attributes = llm_object
event
end
def post_process_func(event)
response = process(event)
event = unload_json(event, response)
- # event.llm_object = llm_object
+ # event.llm_object_attributes = llm_object
event
end
From 71a5d08e332da8eba7acbe341509e778353fceab Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Mon, 3 Jun 2024 17:04:54 +0200
Subject: [PATCH 17/37] cleanup, post process still stops halfway
---
lib/ingestors/ingestor.rb | 10 ----------
lib/modules/llm_service.rb | 8 +++-----
lib/modules/willma_service.rb | 27 +++++++++------------------
llm_process_prompt.txt | 3 ++-
llm_scrape_prompt.txt | 3 ++-
5 files changed, 16 insertions(+), 35 deletions(-)
diff --git a/lib/ingestors/ingestor.rb b/lib/ingestors/ingestor.rb
index 711d7cb4e..06c2ef1c5 100644
--- a/lib/ingestors/ingestor.rb
+++ b/lib/ingestors/ingestor.rb
@@ -147,23 +147,14 @@ def write_resources(type, resources, user, provider)
end
resource = set_resource_defaults(resource)
- puts resource.valid?
if resource.valid?
resource.save!
@stats[key][update ? :updated : :added] += 1
if llm_attr
llm_object = LlmObject.new(llm_attr.to_h)
llm_object.event_id = resource.id
- puts resource.attributes
- puts llm_object.attributes
- puts llm_object.needs_processing
- puts llm_object.valid?
- puts llm_object.errors.full_messages.map{|k| puts k}
llm_object.save!
resource.llm_object = llm_object
- puts resource.llm_object.attributes
- puts resource.attributes
- puts resource.valid?
if resource.valid?
resource.save!
end
@@ -177,7 +168,6 @@ def write_resources(type, resources, user, provider)
@messages << " - #{m}"
end
end
- puts resource
resources[i] = resource
end
diff --git a/lib/modules/llm_service.rb b/lib/modules/llm_service.rb
index c065024f7..9d3a4f488 100644
--- a/lib/modules/llm_service.rb
+++ b/lib/modules/llm_service.rb
@@ -5,8 +5,7 @@ def initialize
puts 'please provide child class'
end
- def llm_object
- # LlmObject.new(
+ def llm_object_attributes
{
scrape_or_process: @scrape_or_process,
model: @params[:model],
@@ -15,7 +14,6 @@ def llm_object
output: @output,
needs_processing: false
}
- # )
end
def unload_json(event, response)
@@ -48,14 +46,14 @@ def process(event)
def scrape_func(event, event_page)
response = scrape(event_page)
event = unload_json(event, response)
- event.llm_object_attributes = llm_object
+ event.llm_object_attributes = llm_object_attributes
event
end
def post_process_func(event)
response = process(event)
event = unload_json(event, response)
- # event.llm_object_attributes = llm_object
+ event.llm_object_attributes = llm_object_attributes
event
end
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
index 26201d476..01ce9ac80 100644
--- a/lib/modules/willma_service.rb
+++ b/lib/modules/willma_service.rb
@@ -10,28 +10,17 @@ def initialize
@params = {
model: model_name,
sequence_id: model_id,
- temperature: 0.7
+ temperature: 0
+ # temperature: 0.7
}
end
def run(content)
- # msg = call(content)['message']
- # res = get_first_json_from_string(msg)
- res = {
- title: "Open Hour SSH: Live Q&A on Monday",
- organizer: "Data Archive Netherlands (DANS)",
- description: "Get all your questions answered during Open Hour for the SSH community. A live Q&A every Monday morning. Meet us at the Open Hour every Monday from 10:00 to 11:00 CEST for the Social Sciences and Humanities (SSH) community. The Open Hour is a Q&A on Open Science, data storage and Research Data Management. Register here for the Open Hour and send in your question(s).",
- start: "2024-06-03T10:00:00+02:00",
- end: "2024-06-03T11:00:00+02:00",
- venue: "Online",
- keywords: ["natural & engineering sciences", "humanities & social sciences", "life sciences"],
- target_audience: ["researchers", "research support staff", "bachelor & master students", "PhD candidates", "teaching staff", "other"],
- open_science: ["open software", "FAIR data", "Open Access"],
- visible: true,
- url: "https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/",
- source: "LLM",
- timezone: "Amsterdam"
- }.to_json
+ msg = call(content)['message']
+ puts msg
+ res = get_first_json_from_string(msg)
+ puts '--------------------------------'
+ puts res
res
end
@@ -42,6 +31,7 @@ def call(prompt)
}
query_url = 'https://willma.soil.surf.nl/api/query'
response = do_request(query_url, 'post', data)
+ puts response.code
JSON.parse(response.body)
end
end
@@ -56,6 +46,7 @@ def do_request(url, mode, data = {})
http = Net::HTTP.new(parsed_url.host, parsed_url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ http.read_timeout = 120
request = case mode
when 'post'
diff --git a/llm_process_prompt.txt b/llm_process_prompt.txt
index 0f6de2ac3..7d5987ccb 100644
--- a/llm_process_prompt.txt
+++ b/llm_process_prompt.txt
@@ -5,7 +5,8 @@ and the following curation criteria:
Is this event useful for anyone rather than only people from a specific institution?
Is this event centered around research?
-Give me a json string describing a research themed event with the following format.
+Give me a valid json string describing a research themed event with the following format.
+Make sure the last json attribute is not followed by a comma.
Strictly adhere to the provided options if applicable without introducing new categories or combinations of words.
Fill the keywords attributes with with ['domain agnostic'] if all options are relevant.
If a specified option is not applicable or missing, fill it with null.
diff --git a/llm_scrape_prompt.txt b/llm_scrape_prompt.txt
index 4afa80318..c708d4e42 100644
--- a/llm_scrape_prompt.txt
+++ b/llm_scrape_prompt.txt
@@ -1,7 +1,7 @@
Based on the following webpage describing a research event:
*replace_with_event_page*
-Give me a json string describing a research themed event with the following format:
+Give me a valid json string describing a research themed event with the following format:
title (string): The title of the event
organizer (string): The organisation that hosts the event
@@ -12,3 +12,4 @@ venue (string): The venue where the event is hosted
Instead of generating values for missing attributes, fill them with null.
Do not change the wording of the description please.
+Make sure the last json attribute is not followed by a comma.
From 9dbbfbf36beedaf5a206c9eb82cbb5ca8f01b9e9 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Tue, 4 Jun 2024 13:28:42 +0200
Subject: [PATCH 18/37] updated prompts
---
lib/ingestors/ingestor.rb | 6 +++++-
lib/ingestors/llm_ingestor.rb | 2 +-
lib/modules/willma_service.rb | 2 +-
llm_process_prompt.txt | 17 ++++++++++-------
llm_scrape_prompt.txt | 3 ++-
5 files changed, 19 insertions(+), 11 deletions(-)
diff --git a/lib/ingestors/ingestor.rb b/lib/ingestors/ingestor.rb
index 06c2ef1c5..4ca107979 100644
--- a/lib/ingestors/ingestor.rb
+++ b/lib/ingestors/ingestor.rb
@@ -152,7 +152,11 @@ def write_resources(type, resources, user, provider)
@stats[key][update ? :updated : :added] += 1
if llm_attr
llm_object = LlmObject.new(llm_attr.to_h)
- llm_object.event_id = resource.id
+ if type == Event
+ llm_object.event_id = resource.id
+ elsif type == Material
+ llm_object.material_id = resource.id
+ end
llm_object.save!
resource.llm_object = llm_object
if resource.valid?
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index 453d0828f..f3d010265 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -77,7 +77,7 @@ def process_llm(_url)
scrape_dans
# scrape_nwo
# scrape_rug
- # scrape_tdcc
+ scrape_tdcc
# json not necessary (SURF, UvA)
# XML not necessary (wur)
end
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
index 01ce9ac80..d746d1b37 100644
--- a/lib/modules/willma_service.rb
+++ b/lib/modules/willma_service.rb
@@ -46,7 +46,7 @@ def do_request(url, mode, data = {})
http = Net::HTTP.new(parsed_url.host, parsed_url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
- http.read_timeout = 120
+ http.read_timeout = 180
request = case mode
when 'post'
diff --git a/llm_process_prompt.txt b/llm_process_prompt.txt
index 7d5987ccb..020a2100f 100644
--- a/llm_process_prompt.txt
+++ b/llm_process_prompt.txt
@@ -6,11 +6,6 @@ Is this event useful for anyone rather than only people from a specific institut
Is this event centered around research?
Give me a valid json string describing a research themed event with the following format.
-Make sure the last json attribute is not followed by a comma.
-Strictly adhere to the provided options if applicable without introducing new categories or combinations of words.
-Fill the keywords attributes with with ['domain agnostic'] if all options are relevant.
-If a specified option is not applicable or missing, fill it with null.
-The options are defined below between quotation marks. Options are separated by commas.
title (string): The title of the event
keywords (array of strings): A set of keywords based which the event can be filtered.
@@ -18,12 +13,20 @@ target_audience (array of strings): The target audience for this event.
open_science (array of strings): The type of open science that this event advocates for, if any.
visible (bool): Whether or not the event is relevant according to the curation criteria
+Make sure the last json attribute is not followed by a comma.
+Make sure the full json fits inside the response.
+Strictly adhere to the provided options if applicable without introducing new categories or combinations of words.
+Fill the keywords attributes with with ['domain agnostic'] if all options are relevant.
+If a specified option is not applicable or missing, fill it with null.
+The options are defined below between quotation marks. Options are separated by commas.
+
keywords options:
[
'natural & engineering sciences',
'humanities & social sciences',
- 'life sciences',
+ 'life sciences'
]
+
target_audience options:
[
'researchers',
@@ -39,5 +42,5 @@ open_science options:
'open software',
'FAIR data',
'Open Access,
- 'citizen science',
+ 'citizen science'
]
diff --git a/llm_scrape_prompt.txt b/llm_scrape_prompt.txt
index c708d4e42..12c67a15f 100644
--- a/llm_scrape_prompt.txt
+++ b/llm_scrape_prompt.txt
@@ -11,5 +11,6 @@ end (date or datetime): The local end time of the event
venue (string): The venue where the event is hosted
Instead of generating values for missing attributes, fill them with null.
-Do not change the wording of the description please.
+Summarize the description in less than 400 characters please.
Make sure the last json attribute is not followed by a comma.
+Make sure the full json fits inside the response.
From d5ad8dfd3479a48a112c225aeef38fd40738c7c3 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 5 Jun 2024 11:24:07 +0200
Subject: [PATCH 19/37] filter nonsense vars, add max_new_tokens
---
lib/ingestors/ingestor.rb | 1 +
lib/ingestors/llm_ingestor.rb | 7 ++++---
lib/modules/willma_service.rb | 5 +----
3 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/lib/ingestors/ingestor.rb b/lib/ingestors/ingestor.rb
index 4ca107979..9781fd748 100644
--- a/lib/ingestors/ingestor.rb
+++ b/lib/ingestors/ingestor.rb
@@ -137,6 +137,7 @@ def write_resources(type, resources, user, provider)
resource.user_id ||= user.id
resource.content_provider_id ||= provider.id
llm_attr = resource.delete_field(:llm_object_attributes)
+ resource = OpenStruct.new(resource.to_h.select { |key, _| type.attribute_names.map(&:to_sym).include?(key)})
existing_resource = find_existing(type, resource)
update = existing_resource
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index f3d010265..b718c3949 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -74,10 +74,10 @@ def scrape_tdcc
end
def process_llm(_url)
- scrape_dans
+ # scrape_dans
# scrape_nwo
- # scrape_rug
- scrape_tdcc
+ scrape_rug
+ # scrape_tdcc
# json not necessary (SURF, UvA)
# XML not necessary (wur)
end
@@ -100,6 +100,7 @@ def beep_func(url, event_page) # rubocop:disable Metrics
event.url = url
event.source = 'LLM'
event.timezone = 'Amsterdam'
+ event.nonsense_attr = 'beep'
add_event(event)
rescue Exception => e
puts e
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
index d746d1b37..558de5e0f 100644
--- a/lib/modules/willma_service.rb
+++ b/lib/modules/willma_service.rb
@@ -10,6 +10,7 @@ def initialize
@params = {
model: model_name,
sequence_id: model_id,
+ advanced_options: { "max_new_tokens": 4096 },
temperature: 0
# temperature: 0.7
}
@@ -17,10 +18,7 @@ def initialize
def run(content)
msg = call(content)['message']
- puts msg
res = get_first_json_from_string(msg)
- puts '--------------------------------'
- puts res
res
end
@@ -31,7 +29,6 @@ def call(prompt)
}
query_url = 'https://willma.soil.surf.nl/api/query'
response = do_request(query_url, 'post', data)
- puts response.code
JSON.parse(response.body)
end
end
From b87b3109d9593c6d3937a9748133e80eb5f32943 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 5 Jun 2024 11:26:20 +0200
Subject: [PATCH 20/37] migration fix
---
db/migrate/20240220144246_add_llm_check.rb | 24 ----------------------
1 file changed, 24 deletions(-)
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
index 80cf2b6b9..a3b57193e 100644
--- a/db/migrate/20240220144246_add_llm_check.rb
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -1,28 +1,4 @@
class AddLlmCheck < ActiveRecord::Migration[7.0]
- # def up
- # create_table :llm_object do |t|
- # # t.references :event, foreign_key: true
- # t.datetime :created_at
- # t.datetime :updated_at
- # t.string :scrape_or_process
- # t.string :model
- # t.string :prompt
- # t.string :input
- # t.string :output
- # t.boolean :needs_processing, default: false
- # end
- # add_reference :events, :llm_object, foreign_key: true
- # add_column :events, :open_science, :string, array: true, default: []
- # add_column :materials, :llm_processed, :bool, default: false
- # end
-
- # def down
- # drop_table :llm_object
- # remove_reference :events, :llm_object, foreign_key: true
- # remove_column :events, :open_science, :string, array: true, default: []
- # remove_column :materials, :llm_processed, :bool, default: false
- # end
-
def change
create_table :llm_objects do |t|
t.belongs_to :event, foreign_key: true
From 8c8d651fdfeca2e8cb6db014fd05fb7d9317ec1f Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 5 Jun 2024 14:40:06 +0200
Subject: [PATCH 21/37] working llm_ingestor subclass
---
lib/ingestors/fourtu_llm_ingestor.rb | 63 ++++++++++++++++++++++++++++
lib/ingestors/ingestor_factory.rb | 9 +++-
lib/ingestors/llm_ingestor.rb | 62 ++++-----------------------
llm_process_prompt.txt | 1 -
4 files changed, 77 insertions(+), 58 deletions(-)
create mode 100644 lib/ingestors/fourtu_llm_ingestor.rb
diff --git a/lib/ingestors/fourtu_llm_ingestor.rb b/lib/ingestors/fourtu_llm_ingestor.rb
new file mode 100644
index 000000000..38b12aec8
--- /dev/null
+++ b/lib/ingestors/fourtu_llm_ingestor.rb
@@ -0,0 +1,63 @@
+require 'open-uri'
+require 'csv'
+require 'nokogiri'
+
+module Ingestors
+ class FourtuLlmIngestor < LlmIngestor
+ def self.config
+ {
+ key: '4tu_llm_event',
+ title: '4TU LLM Events API',
+ category: :events
+ }
+ end
+
+ private
+
+ def process_llm(_url)
+ url = 'https://www.4tu.nl/en/agenda/'
+ event_page = Nokogiri::HTML5.parse(open_url(url, raise: true)).css('.searchresults')[0].css('a.searchresult')
+ event_page.each do |event_data|
+ new_url = event_data['href']
+ sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/4tu_llm.yml')
+ new_event_page = Nokogiri::HTML5.parse(open_url(new_url, raise: true)).css('body').css('main, .page-header__content')
+ get_event_from_css(new_url, new_event_page)
+ end
+ end
+ # def process_llm(_url) # rubocop:disable Metrics
+ # url = 'https://www.rug.nl/wubbo-ockels-school/calendar/2024/'
+ # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
+ # event_page.each do |event_data|
+ # new_url = event_data.css("meta[itemprop='url']")[0].get_attribute('content')
+ # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
+ # new_event_page = Nokogiri::HTML5.parse(open_url(new_url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
+ # get_event_from_css(new_url, new_event_page)
+ # end
+ # end
+ # def process_llm(_url) # rubocop:disable Metrics
+ # url = 'https://www.nwo.nl/en/meetings'
+ # 4.times.each do |i| # always check the first 4 pages, # of pages could be increased if needed
+ # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
+ # event_page = Nokogiri::HTML5.parse(open_url("#{url}?page=#{i}", raise: true)).css('.overviewContent')[0].css('li.list-item').css('a')
+ # event_page.each do |event_data|
+ # new_url = "https://www.nwo.nl#{event_data['href']}"
+ # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
+ # new_event_page = Nokogiri::HTML5.parse(open_url(new_url, raise: true)).css('body').css('main')[0].css('article')
+ # get_event_from_css(new_url, new_event_page)
+ # end
+ # end
+ # end
+ # def process_llm(_url)
+ # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
+ # url = 'https://tdcc.nl/evenementen/teaming-up-across-domains/'
+ # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css('article')[0]
+ # get_event_from_css(url, event_page)
+ # end
+ # def process_llm(_url)
+ # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
+ # url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
+ # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='nieuws_detail_row']")
+ # get_event_from_css(url, event_page)
+ # end
+ end
+end
diff --git a/lib/ingestors/ingestor_factory.rb b/lib/ingestors/ingestor_factory.rb
index f01cbe971..900bdbdd2 100644
--- a/lib/ingestors/ingestor_factory.rb
+++ b/lib/ingestors/ingestor_factory.rb
@@ -29,8 +29,13 @@ def self.ingestors
Ingestors::RstIngestor,
Ingestors::OsciIngestor,
Ingestors::DccIngestor,
- Ingestors::SenseIngestor,
- Ingestors::LlmIngestor
+ Ingestors::SenseIngestor
+ ] + llm_ingestors
+ end
+
+ def self.llm_ingestors
+ [
+ Ingestors::FourtuLlmIngestor
]
end
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index b718c3949..afcf81cfc 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -25,64 +25,11 @@ def read(url)
private
- def scrape_dans
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
- event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='nieuws_detail_row']")
- beep_func(url, event_page)
- end
-
- def scrape_nwo # rubocop:disable Metrics
- # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- # url = 'https://www.nwo.nl/en/meetings/dualis-event-in-utrecht'
- # event_page = Nokogiri::HTML5.parse(open_url(url, raise: true)).css('body').css('main')[0].css('article')
- # beep_func(url, event_page)
- url = 'https://www.nwo.nl/en/meetings'
- 4.times.each do |i| # always check the first 4 pages, # of pages could be increased if needed
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- event_page = Nokogiri::HTML5.parse(open_url("#{url}?page=#{i}", raise: true)).css('.overviewContent')[0].css('li.list-item').css('a')
- event_page.each do |event_data|
- new_url = "https://www.nwo.nl#{event_data['href']}"
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- new_event_page = Nokogiri::HTML5.parse(open_url(new_url, raise: true)).css('body').css('main')[0].css('article')
- beep_func(new_url, new_event_page)
- end
- end
- end
-
- def scrape_rug # rubocop:disable Metrics
- # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- # url = 'https://www.rug.nl/about-ug/latest-news/events/calendar/2023/phallus-tentoonstelling'
- # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
- # beep_func(url, event_page)
- url = 'https://www.rug.nl/wubbo-ockels-school/calendar/2024/'
- # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body')[0].css("div[class='rug-mb']")[0].css("div[itemtype='https://schema.org/Event']")
- event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
- event_page.each do |event_data|
- new_url = event_data.css("meta[itemprop='url']")[0].get_attribute('content')
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- new_event_page = Nokogiri::HTML5.parse(open_url(new_url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
- beep_func(new_url, new_event_page)
- end
- end
-
- def scrape_tdcc
- sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- url = 'https://tdcc.nl/evenementen/teaming-up-across-domains/'
- event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css('article')[0]
- beep_func(url, event_page)
- end
-
def process_llm(_url)
- # scrape_dans
- # scrape_nwo
- scrape_rug
- # scrape_tdcc
- # json not necessary (SURF, UvA)
- # XML not necessary (wur)
+ puts 'please provide child class'
end
- def beep_func(url, event_page) # rubocop:disable Metrics
+ def get_event_from_css(url, event_page) # rubocop:disable Metrics
event_page.css('script, link').each { |node| node.remove }
event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
llm_service_hash = {
@@ -100,6 +47,11 @@ def beep_func(url, event_page) # rubocop:disable Metrics
event.url = url
event.source = 'LLM'
event.timezone = 'Amsterdam'
+ a = Time.parse(event.start)
+ event.start = Time.local(a.year, a.month, a.day, a.hour, a.min, a.sec)
+ a = Time.parse(event.end)
+ event.end = Time.local(a.year, a.month, a.day, a.hour, a.min, a.sec)
+ event.set_default_times
event.nonsense_attr = 'beep'
add_event(event)
rescue Exception => e
diff --git a/llm_process_prompt.txt b/llm_process_prompt.txt
index 020a2100f..4bff9baab 100644
--- a/llm_process_prompt.txt
+++ b/llm_process_prompt.txt
@@ -7,7 +7,6 @@ Is this event centered around research?
Give me a valid json string describing a research themed event with the following format.
-title (string): The title of the event
keywords (array of strings): A set of keywords based which the event can be filtered.
target_audience (array of strings): The target audience for this event.
open_science (array of strings): The type of open science that this event advocates for, if any.
From c03978d82895897e5567f690e8cff900b9e70429 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 5 Jun 2024 17:00:14 +0200
Subject: [PATCH 22/37] test
---
lib/ingestors/ingestor.rb | 2 +-
lib/ingestors/llm_ingestor.rb | 4 +-
test/unit/ingestors/4tu_llm_ingestor_test.rb | 78 +++
test/vcr_cassettes/ingestors/4tu_llm.yml | 670 +++++++++++++++++++
4 files changed, 751 insertions(+), 3 deletions(-)
create mode 100644 test/unit/ingestors/4tu_llm_ingestor_test.rb
create mode 100644 test/vcr_cassettes/ingestors/4tu_llm.yml
diff --git a/lib/ingestors/ingestor.rb b/lib/ingestors/ingestor.rb
index 9781fd748..d7b0b4b14 100644
--- a/lib/ingestors/ingestor.rb
+++ b/lib/ingestors/ingestor.rb
@@ -136,7 +136,7 @@ def write_resources(type, resources, user, provider)
# check for matched events
resource.user_id ||= user.id
resource.content_provider_id ||= provider.id
- llm_attr = resource.delete_field(:llm_object_attributes)
+ llm_attr = resource.delete_field(:llm_object_attributes) if resource.respond_to?(:llm_object_attributes)
resource = OpenStruct.new(resource.to_h.select { |key, _| type.attribute_names.map(&:to_sym).include?(key)})
existing_resource = find_existing(type, resource)
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index afcf81cfc..7418af9be 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -48,9 +48,9 @@ def get_event_from_css(url, event_page) # rubocop:disable Metrics
event.source = 'LLM'
event.timezone = 'Amsterdam'
a = Time.parse(event.start)
- event.start = Time.local(a.year, a.month, a.day, a.hour, a.min, a.sec)
+ event.start = Time.new(a.year, a.month, a.day, a.hour, a.min, a.sec, "+00:00")
a = Time.parse(event.end)
- event.end = Time.local(a.year, a.month, a.day, a.hour, a.min, a.sec)
+ event.end = Time.new(a.year, a.month, a.day, a.hour, a.min, a.sec, "+00:00")
event.set_default_times
event.nonsense_attr = 'beep'
add_event(event)
diff --git a/test/unit/ingestors/4tu_llm_ingestor_test.rb b/test/unit/ingestors/4tu_llm_ingestor_test.rb
new file mode 100644
index 000000000..803be3e14
--- /dev/null
+++ b/test/unit/ingestors/4tu_llm_ingestor_test.rb
@@ -0,0 +1,78 @@
+require 'test_helper'
+
+class FourtuLlmIngestorTest < ActiveSupport::TestCase
+ setup do
+ @user = users(:regular_user)
+ @content_provider = content_providers(:another_portal_provider)
+ mock_ingestions
+ mock_timezone # System time zone should not affect test result
+ end
+
+ teardown do
+ reset_timezone
+ end
+
+ test 'can ingest events from 4tu' do
+ source = @content_provider.sources.build(
+ url: 'https://www.4tu.nl/en/agenda/',
+ method: '4tu',
+ enabled: true
+ )
+
+ ingestor = Ingestors::FourtuLlmIngestor.new
+
+ # check event doesn't
+ new_title = '4TU-meeting National Technology Strategy'
+ refute Event.where(title: new_title).any?
+
+ get_beep = '{
+ "boop": "{
+ \"name\": \"Zephyr 7B\",
+ \"id\": 0
+ }"
+ }'.gsub(/\n/, '')
+ post_beep = '{
+ "message": "Here is your JSON:
+ {
+ \"title\":\"4TU-meeting National Technology Strategy\",
+ \"start\":\"2024-07-03T12:30:00+02:00\",
+ \"end\":\"2024-07-03T19:00:00+02:00\",
+ \"venue\":\"Basecamp, Nijverheidsweg 16A, 3534 AM Utrecht (https://basecamputrecht.nl)\",
+ \"description\":\"My cool description\",
+ \"nonsense_attr\":\"My cool nonsense attribute\"
+ }
+ I am a dumb llm and I have to say something afterward even though I was specifically asked not to."
+ }'.gsub(/\n/, '')
+ # run task
+ assert_difference 'Event.count', 1 do
+ freeze_time(2019) do
+ VCR.use_cassette("ingestors/4tu_llm") do
+ WebMock.stub_request(:get, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: get_beep)
+ WebMock.stub_request(:post, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: post_beep)
+ with_settings({ llm_scraper: { model: 'willma', model_version: 'Zephyr 7B' } }) do
+ ingestor.read(source.url)
+ ingestor.write(@user, @content_provider)
+ end
+ end
+ end
+ end
+
+ assert_equal 4, ingestor.events.count
+ assert ingestor.materials.empty?
+ assert_equal 1, ingestor.stats[:events][:added]
+ assert_equal 3, ingestor.stats[:events][:updated]
+ assert_equal 0, ingestor.stats[:events][:rejected]
+
+ # check event does exist
+ event = Event.where(title: new_title).first
+ assert event
+ assert_equal new_title, event.title
+
+ # check other fields
+ assert_equal Time.zone.parse('Wed, 3 Jul 2024 12:30:00.000000000 UTC +00:00'), event.start
+ assert_equal Time.zone.parse('Wed, 3 Jul 2024 19:00:00.000000000 UTC +00:00'), event.end
+ assert_equal 'Amsterdam', event.timezone
+ assert_equal 'Basecamp, Nijverheidsweg 16A, 3534 AM Utrecht (https://basecamputrecht.nl)', event.venue
+ assert_equal 'LLM', event.source
+ end
+end
diff --git a/test/vcr_cassettes/ingestors/4tu_llm.yml b/test/vcr_cassettes/ingestors/4tu_llm.yml
new file mode 100644
index 000000000..94c89b80f
--- /dev/null
+++ b/test/vcr_cassettes/ingestors/4tu_llm.yml
@@ -0,0 +1,670 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Wed, 05 Jun 2024 14:16:15 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Transfer-Encoding:
+ - chunked
+ Connection:
+ - keep-alive
+ Vary:
+ - Accept-Encoding
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Cache-Control:
+ - no-cache
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnRzb3ZlcnZpZXcgcGFnZWhlYWRlci0tZmxhdHRlbiBzaXRlaGVhZGVyLS1tZW51YmFyLXRyYW5zbHVjZW50IiBkYXRhLXRyYWNraW5naWQ9IiI+PGhlYWQ+PG1ldGEgY2hhcnNldD0idXRmLTgiPjx0aXRsZT5BZ2VuZGE8L3RpdGxlPgo8IS0tClJlYWxpc2F0aWU6IPCfkrwgV2ViSGFyZSBidgogICAgICAgICAgICDwn4yQIGh0dHBzOi8vd3d3LndlYmhhcmUubmwvCi0tPgo8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEiIC8+PGxpbmsgcmVsPSJhcHBsZS10b3VjaC1pY29uIiBzaXplcz0iMTgweDE4MCIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2FwcGxlLXRvdWNoLWljb24tMTgweDE4MC5wbmciIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTMyeDMyLnBuZyIgc2l6ZXM9IjMyeDMyIiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi05Nng5Ni5wbmciIHNpemVzPSI5Nng5NiIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tMTk0eDE5NC5wbmciIHNpemVzPSIxOTR4MTk0IiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vYW5kcm9pZC1jaHJvbWUtMTkyeDE5Mi5wbmciIHNpemVzPSIxOTJ4MTkyIiAvPjxsaW5rIHJlbD0ibWFzay1pY29uIiAgICAgICAgICAgICBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vc2FmYXJpLXBpbm5lZC10YWIuc3ZnIiBjb2xvcj0iI2ZmOGIzOCIgLz48bWV0YSBuYW1lPSJ0aGVtZS1jb2xvciIgY29udGVudD0iI2ZmZmZmZiIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6dHlwZSIgY29udGVudD0id2Vic2l0ZSIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6c2l0ZV9uYW1lIiBjb250ZW50PSJGZWRlcmF0aW9uIiAvPjxtZXRhIHByb3BlcnR5PSJvZzp0aXRsZSIgY29udGVudD0iQWdlbmRhIiAvPjxzY3JpcHQgbm9tb2R1bGU+IGlmKCEhd2luZG93Lk1TSW5wdXRNZXRob2RDb250ZXh0ICYmICEhZG9jdW1lbnQuZG9jdW1lbnRNb2RlKWRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGFzc0xpc3QuYWRkKCJ1bnN1cHBvcnRlZC1icm93c2VyIik7PC9zY3JpcHQ+PHNjcmlwdCB0eXBlPSJhcHBsaWNhdGlvbi9qc29uIiBpZD0id2gtY29uZmlnIj57ImRlc2lnbmNkbnJvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS8iLCJkZXNpZ25yb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvIiwiZHRhcHN0YWdlIjoicHJvZHVjdGlvbiIsImltZ3Jvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvIiwiaXNsaXZlIjp0cnVlLCJsb2NhbGUiOiJlbi1VUyIsIm9iaiI6eyJuYXZwYXRoaXRlbSI6eyJsaW5rIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJ0aXRsZSI6IkFnZW5kYSJ9fSwic2VydmVyIjo1MDUwMCwic2l0ZSI6e30sInNpdGVyb290IjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsInNvY2lhbGl0ZTpndG0iOnsiYSI6IkdUTS1XVFo1RlJRIiwiaCI6dHJ1ZSwibSI6ZmFsc2V9fTwvc2NyaXB0PjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iLy5hcC80dHUuc2l0ZS9hcC5jc3MiPjxzY3JpcHQgc3JjPSIvLmFwLzR0dS5zaXRlL2FwLm1qcyIgdHlwZT0ibW9kdWxlIiBhc3luYz48L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2xkK2pzb24iPnsiQGNvbnRleHQiOiJodHRwczovL3NjaGVtYS5vcmciLCJAdHlwZSI6IkJyZWFkY3J1bWJMaXN0IiwiaXRlbUxpc3RFbGVtZW50IjpbeyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iLCJuYW1lIjoiRmVkZXJhdGlvbiIsInBvc2l0aW9uIjoxfSx7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJuYW1lIjoiQWdlbmRhIiwicG9zaXRpb24iOjJ9XX08L3NjcmlwdD48L2hlYWQ+PGJvZHk+PG5vc2NyaXB0PjxpZnJhbWUgc3JjPSIvL3d3dy5nb29nbGV0YWdtYW5hZ2VyLmNvbS9ucy5odG1sP2lkPUdUTS1XVFo1RlJRIiBoZWlnaHQ9IjAiIHdpZHRoPSIwIiBzdHlsZT0iZGlzcGxheTpub25lO3Zpc2liaWxpdHk6aGlkZGVuIj48L2lmcmFtZT48L25vc2NyaXB0PjxkaXYgY2xhc3M9InNwYy1tb2RhbGl0eWxheWVyIj48L2Rpdj48ZGl2IGlkPSJzbGlkZW1lbnUtY29udGFpbmVyIj48ZGl2IGlkPSJzbGlkZW1lbnUiIHRhYmluZGV4PSItMSIgICAgPjxkaXYgY2xhc3M9InNpZGViYXJfX2hlYWRlciI+IDxhIGNsYXNzPSJzaWRlYmFyX19oZWFkZXJfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJzaWRlYmFyX19pZGVudGl0eV9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJzaWRlYmFyX19pZGVudGl0eV9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PGJ1dHRvbiBpZD0ic2xpZGVtZW51LWNsb3NlIiBjbGFzcz0ic2lkZWJhci1hY3Rpb24tY2xvc2UiIHR5cGU9ImJ1dHRvbiIgYXJpYS1sYWJlbD0iQ2xvc2UiID48L2J1dHRvbj48L2Rpdj48dWwgY2xhc3M9InNpZGViYXJfX21lbnUgc2lkZWJhcl9fbWVudS0tbGV2ZWwxIiAgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIgPkhvbWU8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+UmVzZWFyY2g8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPkFib3V0IG91ciByZXNlYXJjaDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLzR0dS1jZW50cmVzLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPjRUVSBDZW50cmVzPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIiA+QU1JIChNYXRoZW1hdGljcyk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIiA+QnVpbHQgRW52aXJvbm1lbnQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyIgPkRlc2lnbiBVbml0ZWQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iID5FbmVyZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyIgPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIiA+SGVhbHRoPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIiA+SGlnaC1UZWNoIE1hdGVyaWFsczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyIgPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyIgPk5JUklDVCAoSUNUKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iID5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+SGlnaCBUZWNoIGZvciBhIFN1c3RhaW5hYmxlIEZ1dHVyZTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIiA+SFRTRiBJIFByb2dyYW1tZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyIgPkhUU0YgSUkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLXZpZGVvcy8iID5IVFNGIHZpZGVvczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyIgPjRUVS5SZXNlYXJjaERhdGE8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL0VFLU5MLyIgPkVsZWN0cmljYWwgRW5naW5lZXJpbmcgTmV0aGVybGFuZHM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5FZHVjYXRpb248L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5BYm91dCBvdXIgZWR1Y2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIiA+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyIgPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iID5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi9lZHVjYXRpb25wcm9ncmFtbWVzLyIgPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YnV0dG9uIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICI+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+VmFsb3Jpc2F0aW9uPC9idXR0b24+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0JTIwYWN0aXZpdGllcy8iID40VFUuSU1QQUNUPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iID5BYm91dCA0VFUuSW1wYWN0PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0YXJ0dXAlMjBtaXNzaW9ucy8iID5TdGFydHVwIG1pc3Npb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5NZWRpYTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9pbnNpZ2h0ZnVsLWlubm92YXRvcnMvIiA+SW5zaWdodGZ1bCBJbm5vdmF0b3JzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL1NwaW4tb2ZmJTIwc2VyaWUvIiA+U3Bpbi1PZmYgU3RvcmllczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3R1ZGVudCUyMGNoYWxsZW5nZXMvIiA+U3R1ZGVudCBjaGFsbGVuZ2VzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1R1c3NlbnBhZ2luYSUyMHZvb3JhZmdhYW5kJTIwYWFuJTIwU3RhcnR1cCUyMFN1cHBvcnQvIiA+QWJvdXQgU3RhcnR1cCBTdXBwb3J0PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+TmV3czwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gIHNpZGVtYWlubWVudV9faXRlbS0tZXhwYW5kICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19zZWxlY3RlZCAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5BYm91dCA0VFU8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS80dHUtaW4tMS1taW51dGUvIiA+NFRVIGluIG9ubHkgMSBtaW51dGU8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9mYWN0cy1maWd1cmVzLyIgPkZhY3RzIGFuZCBmaWd1cmVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvb3JnYW5pc2F0aW9uLyIgPk9yZ2FuaXNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L3B1YmxpY2F0aW9ucy8iID5QdWJsaWNhdGlvbnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9hbHVtbmkvIiA+QWx1bW5pPC9hPjwvbGk+PC91bD48L2xpPjwvdWw+PG5hdiBjbGFzcz0ic2lkZWJhcl9fbGFuZ3VhZ2VzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvIj5OTDwvYT4gfCA8c3BhbiBjbGFzcz0ic2VsZWN0ZWQiPkVOPC9zcGFuPjwvbmF2PjxuYXYgY2xhc3M9InNpZGViYXJfX3NlY29uZGFyeWxpbmtzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vY29udGFjdC8iPkNvbnRhY3Q8L2E+PC9uYXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcC1iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhci1iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wIj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19jb250ZW50Ij48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19pZGVudGl0eSI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fc2xvZ2FuIj5QYXJ0IG9mIHRoZSA8YnV0dG9uIGNsYXNzPSJoZWFkZXItdG9wX190b2dnbGVleHBsb3JlcGFuZWwiPjRUVS5GZWRlcmF0aW9uPC9idXR0b24+PC9kaXY+PGEgY2xhc3M9ImhlYWRlci10b3BfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX29yZ2FuaXphdGlvbnMiPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWRlbGZ0Lm5sL2VuLyIgdGl0bGU9IlRVIERlbGZ0IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWRlbGZ0LnN2ZyIgYWx0PSJUVSBEZWxmdCIgd2lkdGg9IjEwMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZS5ubC9lbi8iIHRpdGxlPSJUVSBFaW5kaG92ZW4iID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZWluZGhvdmVuLnN2ZyIgYWx0PSJUVSBFaW5kaG92ZW4iIHdpZHRoPSIxMzAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy51dHdlbnRlLm5sL2VuLyIgdGl0bGU9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci91bml2ZXJzaXR5LW9mLXR3ZW50ZS5zdmciIGFsdD0iVW5pdmVyc2l0eSBvZiBUd2VudGUiIHdpZHRoPSIxMDAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy53dXIubmwvIiB0aXRsZT0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXd1ci5zdmciIGFsdD0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiB3aWR0aD0iMTMyIiAvPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhciI+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX2NvbnRlbnQiPjxhIGNsYXNzPSJoZWFkZXItbWVudWJhcl9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc3BhY2VyIj48L2Rpdj48bmF2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fbWVudWJhciIgYXJpYS1sYWJlbD0iTWFpbiI+PHVsIGNsYXNzPSJzcGMtbWVudWJhciI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iID5Ib21lPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5SZXNlYXJjaDwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+QWJvdXQgb3VyIHJlc2VhcmNoPC9hPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC80dHUtY2VudHJlcy8iID40VFUgQ2VudHJlczwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyIgPkFNSSAoTWF0aGVtYXRpY3MpPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyIgPkJ1aWx0IEVudmlyb25tZW50PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iID5EZXNpZ24gVW5pdGVkPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIiA+RW5lcmd5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iID5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyIgPkhlYWx0aDwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyIgPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iID5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iID5OSVJJQ1QgKElDVCk8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIiA+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvIiA+SGlnaCBUZWNoIGZvciBhIFN1c3RhaW5hYmxlIEZ1dHVyZTwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIiA+SFRTRiBJIFByb2dyYW1tZXM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyIgPkhUU0YgSUkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLXZpZGVvcy8iID5IVFNGIHZpZGVvczwvYT48L2xpPjwvdWw+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iID40VFUuUmVzZWFyY2hEYXRhPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvRUUtTkwvIiA+RWxlY3RyaWNhbCBFbmdpbmVlcmluZyBOZXRoZXJsYW5kczwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5FZHVjYXRpb248L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5BYm91dCBvdXIgZWR1Y2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyIgPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIiA+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iID5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vZWR1Y2F0aW9ucHJvZ3JhbW1lcy8iID5FZHVjYXRpb24gcHJvZ3JhbW1lczwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iIiA+VmFsb3Jpc2F0aW9uPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdCUyMGFjdGl2aXRpZXMvIiA+NFRVLklNUEFDVDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyIgPkFib3V0IDRUVS5JbXBhY3Q8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0YXJ0dXAlMjBtaXNzaW9ucy8iID5TdGFydHVwIG1pc3Npb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhLyIgPk1lZGlhPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL2luc2lnaHRmdWwtaW5ub3ZhdG9ycy8iID5JbnNpZ2h0ZnVsIElubm92YXRvcnM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvU3Bpbi1vZmYlMjBzZXJpZS8iID5TcGluLU9mZiBTdG9yaWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3R1ZGVudCUyMGNoYWxsZW5nZXMvIiA+U3R1ZGVudCBjaGFsbGVuZ2VzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9UdXNzZW5wYWdpbmElMjB2b29yYWZnYWFuZCUyMGFhbiUyMFN0YXJ0dXAlMjBTdXBwb3J0LyIgPkFib3V0IFN0YXJ0dXAgU3VwcG9ydDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlbGVjdGVkIj5BZ2VuZGE8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iID5BYm91dCA0VFU8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS80dHUtaW4tMS1taW51dGUvIiA+NFRVIGluIG9ubHkgMSBtaW51dGU8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvZmFjdHMtZmlndXJlcy8iID5GYWN0cyBhbmQgZmlndXJlczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9vcmdhbmlzYXRpb24vIiA+T3JnYW5pc2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L3B1YmxpY2F0aW9ucy8iID5QdWJsaWNhdGlvbnM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2FsdW1uaS8iID5BbHVtbmk8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PC91bD48L25hdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc3BhY2VyIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fbGFuZ3VhZ2VzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvIj5OTDwvYT58PHNwYW4+RU48L3NwYW4+PC9kaXY+PGZvcm0gYWN0aW9uPSJodHRwczovL3d3dy40dHUubmwvZW4vc2VhcmNoLyIgbWV0aG9kPSJHRVQiIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNod3JhcHBlciIgYXV0b2NvbXBsZXRlPSJvZmYiID48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoLWlucHV0LWFuZC1zdWdnZXN0aW9ucy13cmFwcGVyIj48aW5wdXQgaWQ9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgbmFtZT0icXVlcnkiIGRhdGEtc3VnZ2VzdD0iNHR1OmNvcnBvcmF0ZV9lbiIgZGF0YS1zdWdnZXN0cGFyZW50PSJwYXJlbnQiIHBsYWNlaG9sZGVyPSJab2VrZW4iIGFyaWEtbGFiZWw9IlpvZWtlbiIgdHlwZT0ic2VhcmNoIiAvPjwvZGl2PjxsYWJlbCBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaCIgZm9yPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoaW5wdXQiIHRhYmluZGV4PSItMSIgPjxzcGFuIGNsYXNzPSJmYXIgZmEtc2VhcmNoIj48L3NwYW4+PC9sYWJlbD48L2Zvcm0+PGJ1dHRvbiBpZD0iaGVhZGVyLW1lbnViYXJfc2lkZWJhcnRvZ2dsZSIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zaG93c2lkZW1haW5tZW51IHNpZGViYXItYWN0aW9uLXRvZ2dsZSIgYXJpYS1sYWJlbD0iT3BlbiBtZW51IiBhcmlhLWV4cGFuZGVkPSJmYWxzZSIgYXJpYS1jb250cm9scz0ic2xpZGVtZW51IiA+PHNwYW4gY2xhc3M9ImZhciBmYS1iYXJzIj48L3NwYW4+PC9idXR0b24+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX3RvcGJhciI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jbG9zZSI+Q2xvc2U8L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbnMiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fYWRkcmVzcyBydGRjb250ZW50Ij48cCBjbGFzcz0iaGVhZGluZyI+NFRVLkZlZGVyYXRpb248L3A+PHAgY2xhc3M9Im5vcm1hbCI+KzMxKDApNiA0OCAyNyA1NSA2MTwvcD48cCBjbGFzcz0ibm9ybWFsIj48YSBocmVmPSJtYWlsdG86cHJvamVjdGxlaWRlckA0dHUubmwiPnNlY3JldGFyaXNANHR1Lm5sPC9hPjwvcD48cCBjbGFzcz0ibm9ybWFsIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48Yj5XZWJzaXRlOiA0VFUubmw8L2I+PC9hPjwvcD48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiBleHBsb3JlcGFuZWxfX2NvbHVtbi0tbWFueWl0ZW1zIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlJlc2VhcmNoPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyBleHBsb3JlcGFuZWxfX2l0ZW1zLS1tYW55aXRlbXMgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyI+PHNwYW4+QXBwbGllZCBNYXRoZW1hdGljcyBJbnN0aXR1dGU8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyI+PHNwYW4+QnVpbHQgRW52aXJvbm1lbnQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iPjxzcGFuPkRlc2lnbiBVbml0ZWQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIj48c3Bhbj5FbmVyZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iPjxzcGFuPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyI+PHNwYW4+SGVhbHRoPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyI+PHNwYW4+SGlnaC1UZWNoIE1hdGVyaWFsczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iPjxzcGFuPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iPjxzcGFuPk5JUklDVCAoSUNUKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIj48c3Bhbj5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIj48c3Bhbj5SZXNlYXJjaERhdGE8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIj48c3Bhbj5IVFNGIEkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIj48c3Bhbj5IVFNGIElJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiAiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuRWR1Y2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyAgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyI+PHNwYW4+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iPjxzcGFuPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIj48c3Bhbj5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcndpanMvb25kZXJ3aWpzcHJvZ3JhbW1hcy8iPjxzcGFuPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiAiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuVmFsb3Jpc2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyAgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIj48c3Bhbj40VFUuSU1QQUNUPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3RlY2gtdHJhbnNmZXIubmwvZW4vIj48c3Bhbj5UaGVtYXRpYyBUZWNobm9sb2d5IFRyYW5zZmVyPC9zcGFuPjwvYT48YSBocmVmPSIiPjxzcGFuPlNwaW4tb2ZmIFN0b3JpZXM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vNHR1aW1wYWN0Y2hhbGxlbmdlLm5sLyI+PHNwYW4+NFRVIEltcGFjdCBDaGFsbGVuZ2U8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fc2xpZGVzaG93IGNhcnJvdXNlbF9fdmlld3BvcnQgY2Fycm91c2VsX19kcmFnYXJlYSAiPjxzdHlsZT5AbWVkaWEgKG1heC13aWR0aDogNzY3cHgpey5oZWFkZXJzbGlkZTB7YmFja2dyb3VuZC1jb2xvcjogI0I5QjBBMztiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pMjRhODc2YzUwMTAyYWFlMTAyMDBjOTU1YTYwMTlmOTM1YmJkYmE4ZDM1MTkwODAxZTM0MDBiMDAwNzgxNDYvNHR1LWZhbGxiYWNrLWhlYWRlci5qcGcpO319QG1lZGlhIChtaW4td2lkdGg6IDc2OHB4KXsuaGVhZGVyc2xpZGUwe2JhY2tncm91bmQtY29sb3I6ICNCOUIwQTM7YmFja2dyb3VuZC1pbWFnZTogdXJsKC8udWMvaTQ5YTY4MGY4MDEwMmFhZTEwMjAwYzk1NWE2MDE5ZjkzNWJiZGJhOGQzNTE5MDgwMWUzNDAwYjYwMDQ4MTQ2LzR0dS1mYWxsYmFjay1oZWFkZXIuanBnKTt9fTwvc3R5bGU+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlIGNhcnJvdXNlbF9fY2VsbCBhY3RpdmVzbGlkZSBoZWFkZXJzbGlkZTAgIiBkYXRhLXNsaWRlc2hvdy1lbGVtZW50cz0icGFnZS1oZWFkZXJfX3NsaWRlMF9fY29udGVudCIgc3R5bGU9IiIgPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19jb250ZW50Ij48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fbWV0YSI+PGgxIGNsYXNzPSJwYWdlLWhlYWRlcl9fdGl0bGUiPkFnZW5kYTwvaDE+PC9kaXY+PC9kaXY+PG1haW4gY2xhc3M9InBhZ2VfX2JvZHkgICI+PGZvcm0gaWQ9IiIgIGNsYXNzPSJwYWdlX19oZWFkZXJmaWx0ZXJzICAgIj48L2Zvcm0+PGRpdiBjbGFzcz0icGFnZV9fY29udGVudGFyZWEgcGFnZV9fY29udGVudGFyZWEtLXJ0ZGRvYyAgIGhlYWRlcmlzb3BhcXVlICI+PGRpdiBjbGFzcz0icGFnZS1jb250ZW50c3RhcnQiPjwvZGl2PjwhLS13aF9jb25zaWxpb19jb250ZW50LS0+PGRpdiBjbGFzcz0ibmVvdGFicyI+PHNwYW4+VXBjb21pbmc8L3NwYW4+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS9hcmNoaXZlIj5BcmNoaXZlPC9hPjwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdHMiPjxhIGNsYXNzPSJzZWFyY2hyZXN1bHQiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvc3VtbWVyLWV2ZW50LTIwMjQvIj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2NvbnRlbnQiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9faW1hZ2Vjb2wiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9faW1hZ2UiIHN0eWxlPSIgYmFja2dyb3VuZC1jb2xvcjogIzU2NUEzOTsgYmFja2dyb3VuZC1pbWFnZTogdXJsKC8udWMvaTEwZWQzNDE3MDEwMjliMzMxMTAwYTU1ZDg4MDEyMWRhZGRjMmQzN2NhZTM4MDgwMWUzZWEwMGVhMDA4MTQxL3N1bW1lci0wMi5qcGcpOyAiPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fbWV0YWNvbCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19kYXRlIj5GcmkgNyBKdW4gMjAyNDwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fdGl0bGUiPjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQ8L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2Rlc2NyaXB0aW9uIj5Kb2luIHVzIGR1cmluZyBvdXIgYW5udWFsIHN1bW1lciBldmVudCBvbiBGcmlkYXkgNyBKdW5lIGF0IHRoZSBVbml2ZXJzaXR5IG9mIFR3ZW50ZS4gVGhlIG1haW4gcHVycG9zZSBvZiB0aGUgZXZlbnQgaXMgdG8gZ2V0IHRvIGtub3cgbmV3IGNvbGxlYWd1ZXMsIGV4cGxvcmUgY29tbW9uIHJlc2VhcmNoIG9yIHRlYWNoaW5nIGludGVyZXN0cywgaW52aXRlIGNvbGxhYm9yYXRpb24sIGFuZCBjYXRjaCB1cCB3aXRoIG9sZCBmcmllbmRzLjwvZGl2PjwvZGl2PjwvZGl2PjwvYT48YSBjbGFzcz0ic2VhcmNocmVzdWx0IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtNi0xOC13ZWJpbmFyLW1hdGhlbWF0aWNzLyI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19jb250ZW50Ij48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2ltYWdlY29sIj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2ltYWdlIiBzdHlsZT0iIGJhY2tncm91bmQtY29sb3I6ICMxRDFBMUQ7IGJhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2lhZjU3N2MzYzAxMDI1NGY4MTAwMDAzZGVhNjAxYzYwNDcyZTNhNmQyY2ZkNjA4MDFlM2VhMDBlYTAwODE0MS90aGUtY29uY2VwdC1vZi1yZWFkaW5nLWxvdmUtMjAyMy0xMS0yNy0wNS0xMi0wOS11dGMuanBnKTsgIj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX21ldGFjb2wiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fZGF0ZSI+VHVlIDE4IEp1biAyMDI0IC8gMTAuMDAgLSAxMS4zMDwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fdGl0bGUiPlVDTCdzIEV4cGVyaWVuY2Ugd2l0aCBDQkwgaW4gRW5naW5lZXJpbmcgZWR1Y2F0aW9uIHdpdGggQmlyZ2l0IFBlcGluIGFuZCBNYXRoZXVzIE8uIGRlIEFuZHJhZGU8L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2Rlc2NyaXB0aW9uIj5Mb2NhdGlvbjogb25saW5lPC9kaXY+PC9kaXY+PC9kaXY+PC9hPjxhIGNsYXNzPSJzZWFyY2hyZXN1bHQiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvNFRVLW1lZXRpbmclMjBOYXRpb25hbCUyMFRlY2hub2xvZ3klMjBTdHJhdGVneS8iPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fY29udGVudCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19pbWFnZWNvbCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19pbWFnZSIgc3R5bGU9ImJhY2tncm91bmQtcG9zaXRpb246IDU2LjgzNzYlIDgwLjM0MTklOyBiYWNrZ3JvdW5kLWNvbG9yOiAjRkRGRUZFOyBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pNDhhMDM3NzMwMTAyMGEzMTEzMDA3NzAxZDQwMWMxZTIxMmVlZjhmNGE3YzcwODAxZTNlYTAwZWEwMDgxNDEvZXprLW50cy5wbmcuanBnKTsgIj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX21ldGFjb2wiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fZGF0ZSI+V2VkIDMgSnVsIDIwMjQgLyAxMi4zMCAtIDE4LjAwPC9kaXY+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X190aXRsZSI+NFRVLW1lZXRpbmcgTmF0aW9uYWwgVGVjaG5vbG9neSBTdHJhdGVneTwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fZGVzY3JpcHRpb24iPjRUVS1tZWV0aW5nIG9uIHRoZSBOYXRpb25hbCBUZWNobm9sb2d5IFN0cmF0ZWd5IChOVFMpIC0gbG9jYXRpb24gVXRyZWNodDwvZGl2PjwvZGl2PjwvZGl2PjwvYT48YSBjbGFzcz0ic2VhcmNocmVzdWx0IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtMTAtMDktcm9vbS1mb3ItZXZlcnlvbmVzLWVkdWNhdGlvbmFsLXRhbGVudC8iPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fY29udGVudCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19pbWFnZWNvbCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19pbWFnZSIgc3R5bGU9IiBiYWNrZ3JvdW5kLWNvbG9yOiAjMzEyQTJGOyBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pMWFjMjkxMWYwMTAyNmFmODEwMDBiN2ZmYmIwMTMyYjA0OGNlZjRjYTVlOGQwODAxZTNlYTAwZWEwMDgxNDEvdGVhY2hpbmctbGVhcm5pbmcuanBnKTsgIj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX21ldGFjb2wiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fZGF0ZSI+V2VkIDkgT2N0IDIwMjQ8L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX3RpdGxlIj5Sb29tIGZvciBldmVyeW9uZSdzIGVkdWNhdGlvbmFsIHRhbGVudCAtIEV2ZW50PC9kaXY+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19kZXNjcmlwdGlvbiI+TG9jYXRpb246IFNvY2lhbCBJbXBhY3QgRmFjdG9yeSBWcmVkZW5idXJnIFV0cmVjaHQ8L2Rpdj48L2Rpdj48L2Rpdj48L2E+PC9kaXY+PCEtLS93aF9jb25zaWxpb19jb250ZW50LS0+PGRpdiBjbGFzcz0icGFnZV9fYmFsbG9vbiI+PC9kaXY+PGRpdiBjbGFzcz0icGFnZV9fZm9vdGVyIj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXJfX2NvbnRlbnQgbmF2cGF0aCI+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPkhvbWU8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19pdGVtIGNydW1icGF0aC0tY3VycmVudHBhZ2UiPkFnZW5kYTwvc3Bhbj48L2Rpdj48L2Rpdj48L2Rpdj48L21haW4+PGRpdiBjbGFzcz0iZm9vdGVyIj48ZGl2IGNsYXNzPSJmb290ZXJfX3BhbmVsIj48ZGl2IGNsYXNzPSJmb290ZXJfX2lkZW50aXR5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19zaXRldGl0bGUiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48IS0tIEZJWE1FOiB1c2UgYXJpYS1oaWRkZW49InRydWUiIGJlY2F1c2UgaXQncyBhIGR1cGxpY2F0ZSBvZiB0aGUgaXRlbXMgb24gdGhlIG1lbnUgYmFyID8gLS0+IDxuYXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMSBmb290ZXJfX21haW5tZW51IiBhcmlhLWxhYmVsPSJNYWluIj4gPHVsPiAgIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyI+UmVzZWFyY2g8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIj5FZHVjYXRpb248L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9IiI+VmFsb3Jpc2F0aW9uPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyI+TmV3czwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFnZW5kYTwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iPkFib3V0IDRUVTwvYT4gPC9saT4gICA8L3VsPiA8L25hdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMiI+IDxpbnB1dCB0eXBlPSJjaGVja2JveCIgbmFtZT0iZm9vdGVyY29sdW1uIiBpZD0iZm9vdGVyX19jb2x1bW4yX19leHBhbmQiIC8+IDxsYWJlbCBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciIGZvcj0iZm9vdGVyX19jb2x1bW4yX19leHBhbmQiPkNvbnRhY3Q8L2xhYmVsPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9fY29udGVudCBydGRjb250ZW50Ij4gPHAgY2xhc3M9Im5vcm1hbCI+KzMxKDApNiA4MyAyMiA1MCA1OTxiciAvPjxhIGhyZWY9Im1haWx0bzpwcm9qZWN0bGVpZGVyQDR0dS5ubCI+c2VjcmV0YXJpc0A0dHUubmw8L2E+PC9wPiA8L2Rpdj4gPC9kaXY+ICAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW4zIj4gPGlucHV0IHR5cGU9ImNoZWNrYm94IiBuYW1lPSJmb290ZXJjb2x1bW4iIGlkPSJmb290ZXJfX2NvbHVtbjNfX2V4cGFuZCIgLz4gPGxhYmVsIGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyIgZm9yPSJmb290ZXJfX2NvbHVtbjNfX2V4cGFuZCI+UG9zdGFkcmVzPC9sYWJlbD4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgcnRkY29udGVudCI+IDxwIGNsYXNzPSJub3JtYWwiPjRUVS5GZWRlcmF0aWU8YnIgLz5Qb3N0YnVzIDU8YnIgLz4yNjAwIEFBIERlbGZ0PC9wPiA8L2Rpdj4gPC9kaXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjQiPiAgPGRpdiBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtc19fZ3JvdXAiPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyI+Rm9sbG93IHVzPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgZm9vdGVyX19zb2NpYWxpdGVtcyAiPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vdHdpdHRlci5jb20vNFRVRmVkZXJhdGlvbiIgdGl0bGU9IlR3aXR0ZXIiID48c3BhbiBjbGFzcz0iZmFiIGZhLXR3aXR0ZXIiPjwvc3Bhbj48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbXBhbnkvNC10dS1mZWRlcmF0aW9uLyIgdGl0bGU9IkxpbmtlZEluIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS1saW5rZWRpbi1pbiI+PC9zcGFuPjwvYT48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS9jaGFubmVsL1VDTWtxaGp4MlcxaE5Sd3lzUnZXRVh3USIgdGl0bGU9IllvdXR1YmUiID48c3BhbiBjbGFzcz0iZmFiIGZhLXlvdXR1YmUiPjwvc3Bhbj48L2E+PC9kaXY+IDwvZGl2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyX19ncm91cCI+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyBmb290ZXJfX2NvbHVtbl9faGVhZGluZy0tbmV3c2xldHRlciAiPlN0YXkgdXAtdG8tZGF0ZTwvZGl2Pjxmb3JtIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXAgd2hwbHVnaW4tbmV3c2xldHRlci1zdWJzY3JpcHRpb24gICIgZGF0YS1uZXdzbGV0dGVyLWxpc3Q9IlNVQlNfNFRVX0NPUlBPUkFURV9OSUVVV1NCUklFRiIgPjxpbnB1dCBuYW1lPSJlbWFpbCIgcGxhY2Vob2xkZXI9IlNpZ24gdXAgZm9yIG91ciBuZXdzbGV0dGVyIiAvPjxidXR0b24gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VibWl0IiB0eXBlPSJzdWJtaXQiIG5hbWU9InN1Ym1pdGJ1dHRvbiIgYXJpYS1sYWJlbD0iU3Vic2NyaWJlIj48c3BhbiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwX19zdWJtaXRfX2ljb24gZmFyIGZhLWVudmVsb3BlIj48L3NwYW4+PC9idXR0b24+PC9mb3JtPjxkaXYgY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VjY2VzcyI+VGhhbmtzIGZvciBzdWJzY3JpYmluZyB0byBvdXIgbmV3c2xldHRlci48L2Rpdj4gIDwvZGl2PiA8L2Rpdj4gPGhyIGNsYXNzPSJmb290ZXJfX2RpdmlkZXIiIC8+IDxkZXRhaWxzIGNsYXNzPSJmb290ZXJfX2V4cGxvcmUiPjxzdW1tYXJ5PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fdG9nZ2xlX19jbG9zZWR0ZXh0Ij5QYXJ0IG9mIHRoZSA8c3BhbiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX19uYW1lIj40VFUuRmVkZXJhdGlvbjwvc3Bhbj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX3RvZ2dsZV9fb3BlbnRleHQiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jbG9zZSI+Q2xvc2U8L2Rpdj48L2Rpdj48L3N1bW1hcnk+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWwiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlJlc2VhcmNoPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyI+PHNwYW4+QXBwbGllZCBNYXRoZW1hdGljcyBJbnN0aXR1dGU8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyI+PHNwYW4+QnVpbHQgRW52aXJvbm1lbnQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iPjxzcGFuPkRlc2lnbiBVbml0ZWQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIj48c3Bhbj5FbmVyZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iPjxzcGFuPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyI+PHNwYW4+SGVhbHRoPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyI+PHNwYW4+SGlnaC1UZWNoIE1hdGVyaWFsczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iPjxzcGFuPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iPjxzcGFuPk5JUklDVCAoSUNUKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIj48c3Bhbj5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIj48c3Bhbj5SZXNlYXJjaERhdGE8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIj48c3Bhbj5IVFNGIEkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIj48c3Bhbj5IVFNGIElJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5FZHVjYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIj48c3Bhbj5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyI+PHNwYW4+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iPjxzcGFuPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyd2lqcy9vbmRlcndpanNwcm9ncmFtbWFzLyI+PHNwYW4+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlZhbG9yaXNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyI+PHNwYW4+NFRVLklNUEFDVDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly90ZWNoLXRyYW5zZmVyLm5sL2VuLyI+PHNwYW4+VGhlbWF0aWMgVGVjaG5vbG9neSBUcmFuc2Zlcjwvc3Bhbj48L2E+PGEgaHJlZj0iIj48c3Bhbj5TcGluLW9mZiBTdG9yaWVzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovLzR0dWltcGFjdGNoYWxsZW5nZS5ubC8iPjxzcGFuPjRUVSBJbXBhY3QgQ2hhbGxlbmdlPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48L2RldGFpbHM+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnMiPiA8ZGl2IGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtcyI+IDxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWRlbGZ0Lm5sL2VuLyIgdGl0bGU9IlRVIERlbGZ0IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWRlbGZ0LnN2ZyIgYWx0PSJUVSBEZWxmdCIgd2lkdGg9Ijg3IiBoZWlnaHQ9IjM0IiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuLyIgdGl0bGU9IlRVIEVpbmRob3ZlbiIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1laW5kaG92ZW4uc3ZnIiBhbHQ9IlRVIEVpbmRob3ZlbiIgd2lkdGg9IjEzMCIgaGVpZ2h0PSIyNyIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnV0d2VudGUubmwvZW4vIiB0aXRsZT0iVW5pdmVyc2l0eSBvZiBUd2VudGUiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL3VuaXZlcnNpdHktb2YtdHdlbnRlLnN2ZyIgYWx0PSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgd2lkdGg9Ijg1IiBoZWlnaHQ9IjMxIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cud3VyLm5sLyIgdGl0bGU9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby13dXIuc3ZnIiBhbHQ9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgd2lkdGg9IjE0NSIgaGVpZ2h0PSIyOSIgLz48L2E+IDwvZGl2PiA8L2Rpdj4gPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXIiPjxzcGFuIGNsYXNzPSJmb290ZXJfX2JvdHRvbWJhcl9fY29weXJpZ2h0Ij48c3BhbiBjbGFzcz0iZmJjcGFydCI+JmNvcHk7IDIwMjQgNFRVLkZlZGVyYXRpb248L3NwYW4+PC9zcGFuPjx1bCBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXJfX21lbnUiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vY29udGFjdC8iPkNvbnRhY3Q8L2E+PC9saT48L3VsPjwvZGl2PjwvZGl2PjwvYm9keT48L2h0bWw+
+ recorded_at: Wed, 02 Jan 2019 19:00:00 GMT
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/summer-event-2024/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Wed, 05 Jun 2024 14:16:16 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Content-Length:
+ - '34546'
+ Connection:
+ - keep-alive
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Last-Modified:
+ - Tue, 21 May 2024 20:39:53 GMT
+ Vary:
+ - Accept-Encoding
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnQgc2l0ZWhlYWRlci0tbWVudWJhci10cmFuc2x1Y2VudCBwYWdlLS13aXRoYmFja2xpbmsiIGRhdGEtdHJhY2tpbmdpZD0iIj48aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PHRpdGxlPjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQ8L3RpdGxlPjxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhL3N1bW1lci1ldmVudC0yMDI0LyI+CjwhLS0KUmVhbGlzYXRpZTog8J+SvCBXZWJIYXJlIGJ2CiAgICAgICAgICAgIPCfjJAgaHR0cHM6Ly93d3cud2ViaGFyZS5ubC8KLS0+CjxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSIgLz48bGluayByZWw9ImFwcGxlLXRvdWNoLWljb24iIHNpemVzPSIxODB4MTgwIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vYXBwbGUtdG91Y2gtaWNvbi0xODB4MTgwLnBuZyIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tMzJ4MzIucG5nIiBzaXplcz0iMzJ4MzIiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTk2eDk2LnBuZyIgc2l6ZXM9Ijk2eDk2IiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi0xOTR4MTk0LnBuZyIgc2l6ZXM9IjE5NHgxOTQiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9hbmRyb2lkLWNocm9tZS0xOTJ4MTkyLnBuZyIgc2l6ZXM9IjE5MngxOTIiIC8+PGxpbmsgcmVsPSJtYXNrLWljb24iICAgICAgICAgICAgIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9zYWZhcmktcGlubmVkLXRhYi5zdmciIGNvbG9yPSIjZmY4YjM4IiAvPjxtZXRhIG5hbWU9InRoZW1lLWNvbG9yIiBjb250ZW50PSIjZmZmZmZmIiAvPjxtZXRhIHByb3BlcnR5PSJvZzp0eXBlIiBjb250ZW50PSJ3ZWJzaXRlIiAvPjxtZXRhIHByb3BlcnR5PSJvZzpzaXRlX25hbWUiIGNvbnRlbnQ9IkZlZGVyYXRpb24iIC8+PG1ldGEgcHJvcGVydHk9Im9nOnRpdGxlIiBjb250ZW50PSI0VFUuQU1JIHN1bW1lciBldmVudCAyMDI0IiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZSIgY29udGVudD0iaHR0cHM6Ly93d3cuNHR1Lm5sLy51Yy9pN2IyODc5NzUwMTAyOWIzMzExMDBhNTVkODgwMTIxZGFkZGMyZDM3Y2FlMzgwNzAxYzNiMDA0NzYwMjgwL3N1bW1lci0wMi5qcGciIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlOndpZHRoIiBjb250ZW50PSIxMjAwIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTpoZWlnaHQiIGNvbnRlbnQ9IjYzMCIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2UiIGNvbnRlbnQ9Imh0dHBzOi8vd3d3LjR0dS5ubC8udWMvaWE0ZTQ3OWIzMDEwMjliMzMxMTAwYTU1ZDg4MDEyMWRhZGRjMmQzN2NhZTM4MDcwMWMzMmMwMTJjMDE4MC9zdW1tZXItMDIuanBnIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTp3aWR0aCIgY29udGVudD0iMzAwIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTpoZWlnaHQiIGNvbnRlbnQ9IjMwMCIgLz48c2NyaXB0IG5vbW9kdWxlPiBpZighIXdpbmRvdy5NU0lucHV0TWV0aG9kQ29udGV4dCAmJiAhIWRvY3VtZW50LmRvY3VtZW50TW9kZSlkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LmFkZCgidW5zdXBwb3J0ZWQtYnJvd3NlciIpOzwvc2NyaXB0PjxzY3JpcHQgdHlwZT0iYXBwbGljYXRpb24vanNvbiIgaWQ9IndoLWNvbmZpZyI+eyJkZXNpZ25jZG5yb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvIiwiZGVzaWducm9vdCI6Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlLyIsImR0YXBzdGFnZSI6InByb2R1Y3Rpb24iLCJpbWdyb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nLyIsImlzbGl2ZSI6dHJ1ZSwibG9jYWxlIjoiZW4tVVMiLCJvYmoiOnsibmF2cGF0aGl0ZW0iOnsibGluayI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvc3VtbWVyLWV2ZW50LTIwMjQvIiwidGl0bGUiOiI0VFUuQU1JIHN1bW1lciBldmVudCAyMDI0In19LCJzZXJ2ZXIiOjUwNTAwLCJzaXRlIjp7fSwic2l0ZXJvb3QiOiJodHRwczovL3d3dy40dHUubmwvZW4vIiwic29jaWFsaXRlOmd0bSI6eyJhIjoiR1RNLVdUWjVGUlEiLCJoIjp0cnVlLCJtIjpmYWxzZX19PC9zY3JpcHQ+PGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSIvLmFwLzR0dS5zaXRlL2FwLmNzcyI+PHNjcmlwdCBzcmM9Ii8uYXAvNHR1LnNpdGUvYXAubWpzIiB0eXBlPSJtb2R1bGUiIGFzeW5jPjwvc2NyaXB0PjxzY3JpcHQgdHlwZT0iYXBwbGljYXRpb24vbGQranNvbiI+eyJAY29udGV4dCI6Imh0dHBzOi8vc2NoZW1hLm9yZyIsIkB0eXBlIjoiQnJlYWRjcnVtYkxpc3QiLCJpdGVtTGlzdEVsZW1lbnQiOlt7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsIm5hbWUiOiJGZWRlcmF0aW9uIiwicG9zaXRpb24iOjF9LHsiQHR5cGUiOiJMaXN0SXRlbSIsIml0ZW0iOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyIsIm5hbWUiOiJBZ2VuZGEiLCJwb3NpdGlvbiI6Mn0seyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvc3VtbWVyLWV2ZW50LTIwMjQvIiwibmFtZSI6IjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQiLCJwb3NpdGlvbiI6M31dfTwvc2NyaXB0PjwvaGVhZD48Ym9keT48bm9zY3JpcHQ+PGlmcmFtZSBzcmM9Ii8vd3d3Lmdvb2dsZXRhZ21hbmFnZXIuY29tL25zLmh0bWw/aWQ9R1RNLVdUWjVGUlEiIGhlaWdodD0iMCIgd2lkdGg9IjAiIHN0eWxlPSJkaXNwbGF5Om5vbmU7dmlzaWJpbGl0eTpoaWRkZW4iPjwvaWZyYW1lPjwvbm9zY3JpcHQ+PGRpdiBjbGFzcz0ic3BjLW1vZGFsaXR5bGF5ZXIiPjwvZGl2PjxkaXYgaWQ9InNsaWRlbWVudS1jb250YWluZXIiPjxkaXYgaWQ9InNsaWRlbWVudSIgdGFiaW5kZXg9Ii0xIiAgICA+PGRpdiBjbGFzcz0ic2lkZWJhcl9faGVhZGVyIj4gPGEgY2xhc3M9InNpZGViYXJfX2hlYWRlcl9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9InNpZGViYXJfX2lkZW50aXR5X19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9InNpZGViYXJfX2lkZW50aXR5X19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48YnV0dG9uIGlkPSJzbGlkZW1lbnUtY2xvc2UiIGNsYXNzPSJzaWRlYmFyLWFjdGlvbi1jbG9zZSIgdHlwZT0iYnV0dG9uIiBhcmlhLWxhYmVsPSJDbG9zZSIgPjwvYnV0dG9uPjwvZGl2Pjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudSBzaWRlYmFyX19tZW51LS1sZXZlbDEiICA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIiA+SG9tZTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5SZXNlYXJjaDwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+QWJvdXQgb3VyIHJlc2VhcmNoPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvNHR1LWNlbnRyZXMvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+NFRVIENlbnRyZXM8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDMiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iID5BTUkgKE1hdGhlbWF0aWNzKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iID5CdWlsdCBFbnZpcm9ubWVudDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIiA+RGVzaWduIFVuaXRlZDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyIgPkVuZXJneTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIiA+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iID5IZWFsdGg8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iID5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIiA+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIiA+TklSSUNUIChJQ1QpPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyIgPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5IaWdoIFRlY2ggZm9yIGEgU3VzdGFpbmFibGUgRnV0dXJlPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iID5IVFNGIEkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIiA+SFRTRiBJSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtdmlkZW9zLyIgPkhUU0YgdmlkZW9zPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIiA+NFRVLlJlc2VhcmNoRGF0YTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvRUUtTkwvIiA+RWxlY3RyaWNhbCBFbmdpbmVlcmluZyBOZXRoZXJsYW5kczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkVkdWNhdGlvbjwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkFib3V0IG91ciBlZHVjYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iID5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIiA+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyIgPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uL2VkdWNhdGlvbnByb2dyYW1tZXMvIiA+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxidXR0b24gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIj48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5WYWxvcmlzYXRpb248L2J1dHRvbj48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QlMjBhY3Rpdml0aWVzLyIgPjRUVS5JTVBBQ1Q8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyIgPkFib3V0IDRUVS5JbXBhY3Q8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3RhcnR1cCUyMG1pc3Npb25zLyIgPlN0YXJ0dXAgbWlzc2lvbnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPk1lZGlhPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL2luc2lnaHRmdWwtaW5ub3ZhdG9ycy8iID5JbnNpZ2h0ZnVsIElubm92YXRvcnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvU3Bpbi1vZmYlMjBzZXJpZS8iID5TcGluLU9mZiBTdG9yaWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdHVkZW50JTIwY2hhbGxlbmdlcy8iID5TdHVkZW50IGNoYWxsZW5nZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vVHVzc2VucGFnaW5hJTIwdm9vcmFmZ2FhbmQlMjBhYW4lMjBTdGFydHVwJTIwU3VwcG9ydC8iID5BYm91dCBTdGFydHVwIFN1cHBvcnQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5OZXdzPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSAgc2lkZW1haW5tZW51X19pdGVtLS1leHBhbmQgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX3NlbGVjdGVkICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkFib3V0IDRUVTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LzR0dS1pbi0xLW1pbnV0ZS8iID40VFUgaW4gb25seSAxIG1pbnV0ZTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2ZhY3RzLWZpZ3VyZXMvIiA+RmFjdHMgYW5kIGZpZ3VyZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9vcmdhbmlzYXRpb24vIiA+T3JnYW5pc2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvcHVibGljYXRpb25zLyIgPlB1YmxpY2F0aW9uczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2FsdW1uaS8iID5BbHVtbmk8L2E+PC9saT48L3VsPjwvbGk+PC91bD48bmF2IGNsYXNzPSJzaWRlYmFyX19sYW5ndWFnZXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC8iPk5MPC9hPiB8IDxzcGFuIGNsYXNzPSJzZWxlY3RlZCI+RU48L3NwYW4+PC9uYXY+PG5hdiBjbGFzcz0ic2lkZWJhcl9fc2Vjb25kYXJ5bGlua3MiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9jb250YWN0LyI+Q29udGFjdDwvYT48L25hdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wLWJhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyLWJhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3AiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX2NvbnRlbnQiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX2lkZW50aXR5Ij48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19zbG9nYW4iPlBhcnQgb2YgdGhlIDxidXR0b24gY2xhc3M9ImhlYWRlci10b3BfX3RvZ2dsZWV4cGxvcmVwYW5lbCI+NFRVLkZlZGVyYXRpb248L2J1dHRvbj48L2Rpdj48YSBjbGFzcz0iaGVhZGVyLXRvcF9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fb3JnYW5pemF0aW9ucyI+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZGVsZnQubmwvZW4vIiB0aXRsZT0iVFUgRGVsZnQiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZGVsZnQuc3ZnIiBhbHQ9IlRVIERlbGZ0IiB3aWR0aD0iMTAwIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuLyIgdGl0bGU9IlRVIEVpbmRob3ZlbiIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1laW5kaG92ZW4uc3ZnIiBhbHQ9IlRVIEVpbmRob3ZlbiIgd2lkdGg9IjEzMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnV0d2VudGUubmwvZW4vIiB0aXRsZT0iVW5pdmVyc2l0eSBvZiBUd2VudGUiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL3VuaXZlcnNpdHktb2YtdHdlbnRlLnN2ZyIgYWx0PSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgd2lkdGg9IjEwMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3Lnd1ci5ubC8iIHRpdGxlPSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28td3VyLnN2ZyIgYWx0PSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiIHdpZHRoPSIxMzIiIC8+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyIj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fY29udGVudCI+PGEgY2xhc3M9ImhlYWRlci1tZW51YmFyX19pZGVudGl0eSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zcGFjZXIiPjwvZGl2PjxuYXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19tZW51YmFyIiBhcmlhLWxhYmVsPSJNYWluIj48dWwgY2xhc3M9InNwYy1tZW51YmFyIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIgPkhvbWU8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPlJlc2VhcmNoPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5BYm91dCBvdXIgcmVzZWFyY2g8L2E+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLzR0dS1jZW50cmVzLyIgPjRUVSBDZW50cmVzPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIiA+QU1JIChNYXRoZW1hdGljcyk8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIiA+QnVpbHQgRW52aXJvbm1lbnQ8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyIgPkRlc2lnbiBVbml0ZWQ8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iID5FbmVyZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyIgPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIiA+SGVhbHRoPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIiA+SGlnaC1UZWNoIE1hdGVyaWFsczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyIgPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyIgPk5JUklDVCAoSUNUKTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iID5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic3BjLW1lbnViYXItLWhhc3N1Yml0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS8iID5IaWdoIFRlY2ggZm9yIGEgU3VzdGFpbmFibGUgRnV0dXJlPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iID5IVFNGIEkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIiA+SFRTRiBJSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtdmlkZW9zLyIgPkhUU0YgdmlkZW9zPC9hPjwvbGk+PC91bD48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyIgPjRUVS5SZXNlYXJjaERhdGE8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9FRS1OTC8iID5FbGVjdHJpY2FsIEVuZ2luZWVyaW5nIE5ldGhlcmxhbmRzPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkVkdWNhdGlvbjwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkFib3V0IG91ciBlZHVjYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIiA+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iID40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyIgPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi9lZHVjYXRpb25wcm9ncmFtbWVzLyIgPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSIiID5WYWxvcmlzYXRpb248L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0JTIwYWN0aXZpdGllcy8iID40VFUuSU1QQUNUPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIiA+QWJvdXQgNFRVLkltcGFjdDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3RhcnR1cCUyMG1pc3Npb25zLyIgPlN0YXJ0dXAgbWlzc2lvbnM8L2E+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvIiA+TWVkaWE8L2E+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwzIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvaW5zaWdodGZ1bC1pbm5vdmF0b3JzLyIgPkluc2lnaHRmdWwgSW5ub3ZhdG9yczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9TcGluLW9mZiUyMHNlcmllLyIgPlNwaW4tT2ZmIFN0b3JpZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdHVkZW50JTIwY2hhbGxlbmdlcy8iID5TdHVkZW50IGNoYWxsZW5nZXM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1R1c3NlbnBhZ2luYSUyMHZvb3JhZmdhYW5kJTIwYWFuJTIwU3RhcnR1cCUyMFN1cHBvcnQvIiA+QWJvdXQgU3RhcnR1cCBTdXBwb3J0PC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VsZWN0ZWQiPkFnZW5kYTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyIgPkFib3V0IDRUVTwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LzR0dS1pbi0xLW1pbnV0ZS8iID40VFUgaW4gb25seSAxIG1pbnV0ZTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9mYWN0cy1maWd1cmVzLyIgPkZhY3RzIGFuZCBmaWd1cmVzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L29yZ2FuaXNhdGlvbi8iID5PcmdhbmlzYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvcHVibGljYXRpb25zLyIgPlB1YmxpY2F0aW9uczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvYWx1bW5pLyIgPkFsdW1uaTwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48L3VsPjwvbmF2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zcGFjZXIiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19sYW5ndWFnZXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC8iPk5MPC9hPnw8c3Bhbj5FTjwvc3Bhbj48L2Rpdj48Zm9ybSBhY3Rpb249Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9zZWFyY2gvIiBtZXRob2Q9IkdFVCIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2h3cmFwcGVyIiBhdXRvY29tcGxldGU9Im9mZiIgPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2gtaW5wdXQtYW5kLXN1Z2dlc3Rpb25zLXdyYXBwZXIiPjxpbnB1dCBpZD0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiBuYW1lPSJxdWVyeSIgZGF0YS1zdWdnZXN0PSI0dHU6Y29ycG9yYXRlX2VuIiBkYXRhLXN1Z2dlc3RwYXJlbnQ9InBhcmVudCIgcGxhY2Vob2xkZXI9IlpvZWtlbiIgYXJpYS1sYWJlbD0iWm9la2VuIiB0eXBlPSJzZWFyY2giIC8+PC9kaXY+PGxhYmVsIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoIiBmb3I9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgdGFiaW5kZXg9Ii0xIiA+PHNwYW4gY2xhc3M9ImZhciBmYS1zZWFyY2giPjwvc3Bhbj48L2xhYmVsPjwvZm9ybT48YnV0dG9uIGlkPSJoZWFkZXItbWVudWJhcl9zaWRlYmFydG9nZ2xlIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3Nob3dzaWRlbWFpbm1lbnUgc2lkZWJhci1hY3Rpb24tdG9nZ2xlIiBhcmlhLWxhYmVsPSJPcGVuIG1lbnUiIGFyaWEtZXhwYW5kZWQ9ImZhbHNlIiBhcmlhLWNvbnRyb2xzPSJzbGlkZW1lbnUiID48c3BhbiBjbGFzcz0iZmFyIGZhLWJhcnMiPjwvc3Bhbj48L2J1dHRvbj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWwiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fdG9wYmFyIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2Nsb3NlIj5DbG9zZTwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1ucyI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19hZGRyZXNzIHJ0ZGNvbnRlbnQiPjxwIGNsYXNzPSJoZWFkaW5nIj40VFUuRmVkZXJhdGlvbjwvcD48cCBjbGFzcz0ibm9ybWFsIj4rMzEoMCk2IDQ4IDI3IDU1IDYxPC9wPjxwIGNsYXNzPSJub3JtYWwiPjxhIGhyZWY9Im1haWx0bzpwcm9qZWN0bGVpZGVyQDR0dS5ubCI+c2VjcmV0YXJpc0A0dHUubmw8L2E+PC9wPjxwIGNsYXNzPSJub3JtYWwiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxiPldlYnNpdGU6IDRUVS5ubDwvYj48L2E+PC9wPjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uIGV4cGxvcmVwYW5lbF9fY29sdW1uLS1tYW55aXRlbXMiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuUmVzZWFyY2g8L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zIGV4cGxvcmVwYW5lbF9faXRlbXMtLW1hbnlpdGVtcyAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIj48c3Bhbj5BcHBsaWVkIE1hdGhlbWF0aWNzIEluc3RpdHV0ZTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIj48c3Bhbj5CdWlsdCBFbnZpcm9ubWVudDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyI+PHNwYW4+RGVzaWduIFVuaXRlZDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iPjxzcGFuPkVuZXJneTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyI+PHNwYW4+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIj48c3Bhbj5IZWFsdGg8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIj48c3Bhbj5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyI+PHNwYW4+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyI+PHNwYW4+TklSSUNUIChJQ1QpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iPjxzcGFuPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iPjxzcGFuPlJlc2VhcmNoRGF0YTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iPjxzcGFuPkhUU0YgSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iPjxzcGFuPkhUU0YgSUkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uICI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5FZHVjYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zICAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIj48c3Bhbj5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyI+PHNwYW4+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iPjxzcGFuPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyd2lqcy9vbmRlcndpanNwcm9ncmFtbWFzLyI+PHNwYW4+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uICI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5WYWxvcmlzYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zICAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iPjxzcGFuPjRUVS5JTVBBQ1Q8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vdGVjaC10cmFuc2Zlci5ubC9lbi8iPjxzcGFuPlRoZW1hdGljIFRlY2hub2xvZ3kgVHJhbnNmZXI8L3NwYW4+PC9hPjxhIGhyZWY9IiI+PHNwYW4+U3Bpbi1vZmYgU3Rvcmllczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly80dHVpbXBhY3RjaGFsbGVuZ2UubmwvIj48c3Bhbj40VFUgSW1wYWN0IENoYWxsZW5nZTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX2JhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19zbGlkZXNob3cgY2Fycm91c2VsX192aWV3cG9ydCBjYXJyb3VzZWxfX2RyYWdhcmVhICI+PHN0eWxlPkBtZWRpYSAobWF4LXdpZHRoOiA3NjdweCl7LmhlYWRlcnNsaWRlMHtiYWNrZ3JvdW5kLWNvbG9yOiAjNTY1QTM5O2JhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2kzZGZjYjE5YzAxMDI5YjMzMTEwMGE1NWQ4ODAxMjFkYWRkYzJkMzdjYWUzODA4MDFlMzQwMGIwMDA3ODE0Ni9zdW1tZXItMDIuanBnKTt9fUBtZWRpYSAobWluLXdpZHRoOiA3NjhweCl7LmhlYWRlcnNsaWRlMHtiYWNrZ3JvdW5kLWNvbG9yOiAjNTY1QTM5O2JhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2k0Y2I5YzEyOTAxMDI5YjMzMTEwMGE1NWQ4ODAxMjFkYWRkYzJkMzdjYWUzODA4MDFlMzQwMGI2MDA0ODE0Ni9zdW1tZXItMDIuanBnKTt9fTwvc3R5bGU+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlIGNhcnJvdXNlbF9fY2VsbCBhY3RpdmVzbGlkZSBoZWFkZXJzbGlkZTAgIiBkYXRhLXNsaWRlc2hvdy1lbGVtZW50cz0icGFnZS1oZWFkZXJfX3NsaWRlMF9fY29udGVudCIgc3R5bGU9IiIgPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19jb250ZW50Ij48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fbWV0YSI+PGgxIGNsYXNzPSJwYWdlLWhlYWRlcl9fdGl0bGUiPjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQ8L2gxPjxkaXYgY2xhc3M9InBhZ2VoZWFkZXJfX2RhdGUiPkZyaWRheSA3IEp1bmUgMjAyNDwvZGl2PjwvZGl2PjwvZGl2PjxtYWluIGNsYXNzPSJwYWdlX19ib2R5ICAiPjxmb3JtIGlkPSIiICBjbGFzcz0icGFnZV9faGVhZGVyZmlsdGVycyAgICI+PC9mb3JtPjxkaXYgY2xhc3M9InBhZ2VfX2NvbnRlbnRhcmVhIHBhZ2VfX2NvbnRlbnRhcmVhLS1ydGRkb2MgICBoZWFkZXJpc29wYXF1ZSAiPjxkaXYgY2xhc3M9ImRlZXBsaW5rcy13cmFwcGVyIj48ZGl2IGNsYXNzPSJkZWVwbGlua3MiPjxhIGNsYXNzPSJwYWdlLWJhY2tsaW5rIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyI+QWxsIGV2ZW50czwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWNvbnRlbnRzdGFydCI+PC9kaXY+PCEtLXdoX2NvbnNpbGlvX2NvbnRlbnQtLT48aDIgY2xhc3M9ImhlYWRpbmcyIj5OZXR3b3JraW5nIGV2ZW50IDRUVS5BTUk8L2gyPjxwIGNsYXNzPSJub3JtYWwiPjxiPkxvY2F0aW9uPC9iPjogQW1waGl0aGVhdGVyLCBWcmlqaG9mLMKgIERlIFZlbGRtYWF0IDUsIDc1MjIgTk0sIEVuc2NoZWRlIChjYW1wdXMgVVQpPGJyIC8+PGI+RGF0ZTwvYj46IDcgSnVuZSAyMDI0PC9wPjxwIGNsYXNzPSJub3JtYWwiPlRoZSBwdXJwb3NlIG9mIHRoaXMgZXZlbnQgaXMgdG8gYnJpbmcgdG9nZXRoZXIgbWVtYmVycyBvZiB0aGUgNFRVLkFNSSBjb21tdW5pdHkgaW4gb3JkZXIgdG8gZ2V0IHRvIGtub3cga25ldyBjb2xsZWFndWVzIGFuZCBjYXRjaCB1cCB3aXRoIG9sZCBvbmVzLCBleHBsb3JlIGNvbW1vbiByZXNlYXJjaCBvciB0ZWFjaGluZyBpbnRlcmVzdHMsIGludml0ZSBjb2xsYWJvcmF0aW9uLCBhbmQgcmVjZWl2ZcKgdXBkYXRlcyBvbiBjdXJyZW50IDRUVS5BTUkgZnVuZGVkIHByb2plY3RzIChzby1jYWxsZWQgU3RyYXRlZ2ljIFJlc2VhcmNoIEluaXRpYXRpdmVzIG9yIDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvUmVzZWFyY2gvIj5TUkk8L2E+cykuwqA8L3A+PHAgY2xhc3M9Im5vcm1hbCI+UmVnaXN0ZXIgZm9ywqB0aGlzIChmcmVlKSBldmVudCBoZXJlIGJlZm9yZSA8Yj5GcmlkYXkgMjQgTWF5PC9iPi48L3A+PHAgY2xhc3M9Im5vcm1hbCI+VGVudGF0aXZlIHNjaGVkdWxlOjwvcD48dWwgY2xhc3M9InVub3JkZXJlZCI+PGxpPjEwLjAwIC0gMTAuMzAgLSBXYWxrIGluIHdpdGggY29mZmVlIG9yIHRlYTwvbGk+PGxpPjEwLjMwIC0gMTAuNDUgLSBPcGVuaW5nIG9wIHRoZSBkYXk8L2xpPjxsaT4xMC40NSAtIDExLjE1IC0gSW52aXRlZCB0YWxrIGJ5wqA8YSBocmVmPSJodHRwczovL3d3d2hvbWUuZXdpLnV0d2VudGUubmwvfnNjaG1pZHRhai8iPkpvaGFubmVzIFNjaG1pZHQtSGllYmVyPC9hPsKgKFVUKSAtwqAnT24gYmlvbG9naWNhbGx5IGluc3BpcmVkIGxlYXJuaW5nJyAoYWJzdHJhY3QpPC9saT48bGk+MTEuMTUgLSAxMS40NSAtIENvZmZlZSBicmVhazwvbGk+PGxpPjExLjQ1IC0gMTIuMzAgLSBQaXRjaGVzIChpbmNsdWRpbmcgMSBTUkkpPC9saT48bGk+MTIuMzAgLSAxNC4wMCAtIEx1bmNoIGJyZWFrICsgZ3JvdXAgcGhvdG88L2xpPjxsaT4xNC4wMCAtIDE1LjAwIC0gU1JJICdSZXNlYXJjaCBvbiBFZHVjYXRpb24nICh0YWxrICsgcGFuZWwgZGlzY3Vzc2lvbik8L2xpPjxsaT4xNS4wMCAtIDE1LjMwIC0gQ29mZmVlIGJyZWFrPC9saT48bGk+MTUuMzAgLSAxNi4xNSAtIFBpdGNoZXPCoChpbmNsdWRpbmcgMcKgU1JJKTwvbGk+PGxpPjE2LjE1IC0gMTYuNDUgLSBJbnZpdGVkIHRhbGsgYnkgPGEgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuL3Jlc2VhcmNoL3Jlc2VhcmNoZXJzL21pcmVpbGxlLWJvdXRpbiI+TWlyZWlsbGUgQm91dGluPC9hPiAoVFUvZSk8L2xpPjxsaT4xNi40NSAtIDE4LjMwwqAtIERyaW5rcyBhbmQgZGlubmVyIChUaGVhdGVyY2Fmw6kpPC9saT48L3VsPjxwIGNsYXNzPSJub3JtYWwiPkNsaWNrIDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvTmV3cy9OZXdzL3N1bW1lci1ldmVudC0yMDIzLXJlcG9ydC8iPmhlcmU8L2E+IGZvciBhIHJlcG9ydCBvZiB0aGUgcHJldmlvdXMgNFRVLkFNSSBzdW1tZXIgZXZlbnQsIGhlbGQgaW4gRGVsZnQgb24gMjcgSnVuZSAyMDIzLjwvcD48IS0tL3doX2NvbnNpbGlvX2NvbnRlbnQtLT48ZGl2IGNsYXNzPSJwYWdlX19iYWxsb29uIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXIiPjxkaXYgY2xhc3M9InBhZ2VfX2Zvb3Rlcl9fY29udGVudCBuYXZwYXRoIj48YSBjbGFzcz0ibmF2cGF0aF9faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT48c3BhbiBjbGFzcz0ibmF2cGF0aF9fc2VwZXJhdG9yIj48L3NwYW4+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19pdGVtIGNydW1icGF0aC0tY3VycmVudHBhZ2UiPjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQ8L3NwYW4+PC9kaXY+PC9kaXY+PC9kaXY+PC9tYWluPjxkaXYgY2xhc3M9ImZvb3RlciI+PGRpdiBjbGFzcz0iZm9vdGVyX19wYW5lbCI+PGRpdiBjbGFzcz0iZm9vdGVyX19pZGVudGl0eSI+PGRpdiBjbGFzcz0iZm9vdGVyX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fc2l0ZXRpdGxlIj5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PCEtLSBGSVhNRTogdXNlIGFyaWEtaGlkZGVuPSJ0cnVlIiBiZWNhdXNlIGl0J3MgYSBkdXBsaWNhdGUgb2YgdGhlIGl0ZW1zIG9uIHRoZSBtZW51IGJhciA/IC0tPiA8bmF2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjEgZm9vdGVyX19tYWlubWVudSIgYXJpYS1sYWJlbD0iTWFpbiI+IDx1bD4gICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPkhvbWU8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iPlJlc2VhcmNoPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyI+RWR1Y2F0aW9uPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSIiPlZhbG9yaXNhdGlvbjwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iPk5ld3M8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvIj5BYm91dCA0VFU8L2E+IDwvbGk+ICAgPC91bD4gPC9uYXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjIiPiA8aW5wdXQgdHlwZT0iY2hlY2tib3giIG5hbWU9ImZvb3RlcmNvbHVtbiIgaWQ9ImZvb3Rlcl9fY29sdW1uMl9fZXhwYW5kIiAvPiA8bGFiZWwgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIiBmb3I9ImZvb3Rlcl9fY29sdW1uMl9fZXhwYW5kIj5Db250YWN0PC9sYWJlbD4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgcnRkY29udGVudCI+IDxwIGNsYXNzPSJub3JtYWwiPiszMSgwKTYgODMgMjIgNTAgNTk8YnIgLz48YSBocmVmPSJtYWlsdG86cHJvamVjdGxlaWRlckA0dHUubmwiPnNlY3JldGFyaXNANHR1Lm5sPC9hPjwvcD4gPC9kaXY+IDwvZGl2PiAgIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMyI+IDxpbnB1dCB0eXBlPSJjaGVja2JveCIgbmFtZT0iZm9vdGVyY29sdW1uIiBpZD0iZm9vdGVyX19jb2x1bW4zX19leHBhbmQiIC8+IDxsYWJlbCBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciIGZvcj0iZm9vdGVyX19jb2x1bW4zX19leHBhbmQiPlBvc3RhZHJlczwvbGFiZWw+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IHJ0ZGNvbnRlbnQiPiA8cCBjbGFzcz0ibm9ybWFsIj40VFUuRmVkZXJhdGllPGJyIC8+UG9zdGJ1cyA1PGJyIC8+MjYwMCBBQSBEZWxmdDwvcD4gPC9kaXY+IDwvZGl2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW40Ij4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbXNfX2dyb3VwIj4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciPkZvbGxvdyB1czwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IGZvb3Rlcl9fc29jaWFsaXRlbXMgIj48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3R3aXR0ZXIuY29tLzRUVUZlZGVyYXRpb24iIHRpdGxlPSJUd2l0dGVyIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS10d2l0dGVyIj48L3NwYW4+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21wYW55LzQtdHUtZmVkZXJhdGlvbi8iIHRpdGxlPSJMaW5rZWRJbiIgPjxzcGFuIGNsYXNzPSJmYWIgZmEtbGlua2VkaW4taW4iPjwvc3Bhbj48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vY2hhbm5lbC9VQ01rcWhqeDJXMWhOUnd5c1J2V0VYd1EiIHRpdGxlPSJZb3V0dWJlIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS15b3V0dWJlIj48L3NwYW4+PC9hPjwvZGl2PiA8L2Rpdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcl9fZ3JvdXAiPiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmcgZm9vdGVyX19jb2x1bW5fX2hlYWRpbmctLW5ld3NsZXR0ZXIgIj5TdGF5IHVwLXRvLWRhdGU8L2Rpdj48Zm9ybSBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwIHdocGx1Z2luLW5ld3NsZXR0ZXItc3Vic2NyaXB0aW9uICAiIGRhdGEtbmV3c2xldHRlci1saXN0PSJTVUJTXzRUVV9DT1JQT1JBVEVfTklFVVdTQlJJRUYiID48aW5wdXQgbmFtZT0iZW1haWwiIHBsYWNlaG9sZGVyPSJTaWduIHVwIGZvciBvdXIgbmV3c2xldHRlciIgLz48YnV0dG9uIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Ym1pdCIgdHlwZT0ic3VibWl0IiBuYW1lPSJzdWJtaXRidXR0b24iIGFyaWEtbGFiZWw9IlN1YnNjcmliZSI+PHNwYW4gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VibWl0X19pY29uIGZhciBmYS1lbnZlbG9wZSI+PC9zcGFuPjwvYnV0dG9uPjwvZm9ybT48ZGl2IGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Y2Nlc3MiPlRoYW5rcyBmb3Igc3Vic2NyaWJpbmcgdG8gb3VyIG5ld3NsZXR0ZXIuPC9kaXY+ICA8L2Rpdj4gPC9kaXY+IDxociBjbGFzcz0iZm9vdGVyX19kaXZpZGVyIiAvPiA8ZGV0YWlscyBjbGFzcz0iZm9vdGVyX19leHBsb3JlIj48c3VtbWFyeT48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX3RvZ2dsZV9fY2xvc2VkdGV4dCI+UGFydCBvZiB0aGUgPHNwYW4gY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fbmFtZSI+NFRVLkZlZGVyYXRpb248L3NwYW4+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX190b2dnbGVfX29wZW50ZXh0Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2xvc2UiPkNsb3NlPC9kaXY+PC9kaXY+PC9zdW1tYXJ5PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsIj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5SZXNlYXJjaDwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iPjxzcGFuPkFwcGxpZWQgTWF0aGVtYXRpY3MgSW5zdGl0dXRlPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iPjxzcGFuPkJ1aWx0IEVudmlyb25tZW50PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIj48c3Bhbj5EZXNpZ24gVW5pdGVkPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyI+PHNwYW4+RW5lcmd5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIj48c3Bhbj5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iPjxzcGFuPkhlYWx0aDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iPjxzcGFuPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIj48c3Bhbj5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIj48c3Bhbj5OSVJJQ1QgKElDVCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyI+PHNwYW4+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyI+PHNwYW4+UmVzZWFyY2hEYXRhPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyI+PHNwYW4+SFRTRiBJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyI+PHNwYW4+SFRTRiBJSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2NhdGVnb3J5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuRWR1Y2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyI+PHNwYW4+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iPjxzcGFuPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIj48c3Bhbj5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcndpanMvb25kZXJ3aWpzcHJvZ3JhbW1hcy8iPjxzcGFuPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5WYWxvcmlzYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iPjxzcGFuPjRUVS5JTVBBQ1Q8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vdGVjaC10cmFuc2Zlci5ubC9lbi8iPjxzcGFuPlRoZW1hdGljIFRlY2hub2xvZ3kgVHJhbnNmZXI8L3NwYW4+PC9hPjxhIGhyZWY9IiI+PHNwYW4+U3Bpbi1vZmYgU3Rvcmllczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly80dHVpbXBhY3RjaGFsbGVuZ2UubmwvIj48c3Bhbj40VFUgSW1wYWN0IENoYWxsZW5nZTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PC9kZXRhaWxzPiA8ZGl2IGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzIj4gPGRpdiBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbXMiPiA8YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVkZWxmdC5ubC9lbi8iIHRpdGxlPSJUVSBEZWxmdCIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1kZWxmdC5zdmciIGFsdD0iVFUgRGVsZnQiIHdpZHRoPSI4NyIgaGVpZ2h0PSIzNCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZS5ubC9lbi8iIHRpdGxlPSJUVSBFaW5kaG92ZW4iID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZWluZGhvdmVuLnN2ZyIgYWx0PSJUVSBFaW5kaG92ZW4iIHdpZHRoPSIxMzAiIGhlaWdodD0iMjciIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy51dHdlbnRlLm5sL2VuLyIgdGl0bGU9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci91bml2ZXJzaXR5LW9mLXR3ZW50ZS5zdmciIGFsdD0iVW5pdmVyc2l0eSBvZiBUd2VudGUiIHdpZHRoPSI4NSIgaGVpZ2h0PSIzMSIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3Lnd1ci5ubC8iIHRpdGxlPSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28td3VyLnN2ZyIgYWx0PSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiIHdpZHRoPSIxNDUiIGhlaWdodD0iMjkiIC8+PC9hPiA8L2Rpdj4gPC9kaXY+IDwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyIj48c3BhbiBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXJfX2NvcHlyaWdodCI+PHNwYW4gY2xhc3M9ImZiY3BhcnQiPiZjb3B5OyAyMDI0IDRUVS5GZWRlcmF0aW9uPC9zcGFuPjwvc3Bhbj48dWwgY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyX19tZW51Ij48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2NvbnRhY3QvIj5Db250YWN0PC9hPjwvbGk+PC91bD48L2Rpdj48L2Rpdj48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL3gtaHNvbiIgaWQ9IndoLWNvbnNpbGlvZmllbGRzIj5oc29uOnsid2hzZWFyY2h0aHVtYm5haWwiOiJodHRwczovL3d3dy40dHUubmwvLnVjL2kyZmRkMDQ2YzAxMDI5YjMzMTEwMGE1NWQ4ODAxMjFkYWRkYzJkMzdjYWUzODA4MDFlMzQwMDFmMDAwODE0MS9zdW1tZXItMDIuanBnIn08L3NjcmlwdD48L2JvZHk+PC9odG1sPg==
+ recorded_at: Wed, 02 Jan 2019 19:00:00 GMT
+- request:
+ method: get
+ uri: https://willma.soil.surf.nl/api/models
+ body:
+ encoding: UTF-8
+ string: "{}"
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ Content-Type:
+ - application/json
+ X-Api-Key:
+ - 77696c6c6d61-c5f9443d-e1eb-469a-a9ba-d7c9c733ebb3
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Wed, 05 Jun 2024 14:16:16 GMT
+ Server:
+ - gunicorn
+ Strict-Transport-Security:
+ - max-age=31556952
+ Content-Security-Policy:
+ - 'default-src ''self''; style-src ''self'' ''unsafe-inline'' *.bootstrapcdn.com
+ *.cloudflare.com fonts.googleapis.com estudybooks.surf.nl; script-src ''self''
+ ''unsafe-inline'' ''unsafe-eval'' webstats.surf.nl code.jquery.com *.bootstrapcdn.com
+ *.cloudflare.com *.aspnetcdn.com; img-src ''self'' data: blob: ''unsafe-inline''
+ https: data: webstats.surf.nl; font-src ''self'' data: *.bootstrapcdn.com
+ fonts.gstatic.com; connect-src ''self''; media-src ''self'' data: blob:'
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Xss-Protection:
+ - 1; mode=block;
+ X-Content-Type-Options:
+ - nosniff
+ Content-Type:
+ - application/json
+ Content-Length:
+ - '7139'
+ Vary:
+ - Cookie
+ Set-Cookie:
+ - session=.eJyNjcEKAjEMRP8lXnVhb5JfESkxjbqQdiVJvcj-u1XEiwh7GmZ4M_MAqTGFSunqgAdoVrEQC3qz81AV3aig0kn0HSVzRsp3qiw5t-CrakEPskjEPLcasP2zcrG53b4rK7GfsxW9XbebVzZ8ADj2koulKQOO4355AieiXTE.ZmBzMA.EVu_S4gNysljneNfzzp5ijcVjQs;
+ HttpOnly; Path=/
+ body:
+ encoding: UTF-8
+ string: '[{"description":"Based on the fluffy animal, Meta AI (from Facebook)
+ trained this model first on a huge unorganized public dataset from the web.\n Afterwards,
+ the model was further finetuned on natural conversations to accommodate: for
+ an improved chat interaction.\n Approximately 0.12% of the training
+ data is Dutch and raises questions on the performance on Dutch questions.\n \n Release
+ date: July 2023","id":1,"name":"LLaMa-2 13B Chat","sequence":[{"model_id":8,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Based
+ on the fluffy animal, Meta AI (from Facebook) trained this model first on
+ a huge unorganized public dataset from the web.\n Afterwards, the
+ model was further finetuned on natural conversations to accommodate: for an
+ improved chat interaction. \n Approximately 0.12% of the training
+ data is Dutch and raises questions on the performance on Dutch questions.}\n \n Release
+ date: July 2023","id":2,"name":"LLaMa-2 7B Chat","sequence":[{"model_id":9,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"OpenAI
+ first released ChatGPT and shock the world due to its impressive performance
+ on producing relevant answers in a natural conversation.\n However,
+ there have been some data and privacy concerns. Hence, we for now offer ChatGPT-3.5
+ through this interface via the OpenAI API.\n Hereby, we circumvent
+ any gathering of personal information via tracking cookies on the ChatGPT
+ website. Note: OpenAI could still store \n and process the messages
+ themselves.\n \n Release date: November 2022 (continuous
+ update)","id":3,"name":"ChatGPT-3.5","sequence":[{"model_id":10,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Zephyr
+ is a series of language models that are trained to act as helpful assistants.\n We
+ found that removing the in-built alignment of these datasets boosted performance
+ on MT Bench and made the model more helpful. \n However, this means
+ that model is likely to generate problematic text when prompted to do so and
+ should only be used for educational and research purposes.\n \n Release
+ Date: October 2023","id":4,"name":"Zephyr 7B","sequence":[{"model_id":11,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Stable
+ diffusion is for images","id":5,"name":"Stable Diffusion","sequence":[{"model_id":12,"type":"images"}],"sequence_type":"ImageGenerationSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":false},{"description":"This
+ is a text-to-speech model trained by facebook. It converts the input message
+ to output audio.\n The quality of the output is only guaranteed
+ by dutch speech, as this is the attempted output language.\n In
+ the future we may add different languages.\n\n Release
+ Date: December 2023","id":7,"name":"Massively Multilingual Speech Dutch","sequence":[{"model_id":14,"type":"tts"}],"sequence_type":"AudioGenerationSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":false},{"description":"Currently
+ only implemented for API access.","id":8,"name":"Whisper speech-to-text Dutch","sequence":[{"model_id":15,"type":"stt"}],"sequence_type":"SingleSessionSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"","id":17,"name":"BramVanroy/GEITje-7B-ultra","sequence":[{"model_id":29,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:label:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"Mixtral
+ GPT-Q quantization","id":22,"name":"casperhansen/mixtral-instruct-awq","sequence":[{"model_id":35,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"sasd","id":23,"name":"asd","sequence":[{"template_id":6},{"model_id":11,"type":"text"}],"sequence_type":"PromptTemplateSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":1,"web_visible":false},{"description":"","id":24,"name":"synthetic
+ data","sequence":[{"model_id":38,"type":"search"},{"template_id":7},{"model_id":11,"type":"text"}],"sequence_type":"RAGSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc","user_id":68,"web_visible":true},{"description":"bozo","id":28,"name":"Rijgersberg/GEITje-7B-chat-v2","sequence":[{"model_id":42,"type":"search"},{"template_id":32},{"model_id":46,"type":"text"}],"sequence_type":"RAGSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"","id":29,"name":"rhysjones/phi-2-orange-v2","sequence":[{"model_id":47,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"Fietje
+ van T.V.","id":30,"name":"BramVanroy/fietje-2b-chat","sequence":[{"model_id":49,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":62,"web_visible":true},{"description":"","id":33,"name":"ibm-granite/granite-8b-code-instruct","sequence":[{"model_id":62,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":null,"user_id":64,"web_visible":true},{"description":"","id":34,"name":"codellama/CodeLlama-7b-Instruct-hf","sequence":[{"model_id":63,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":null,"user_id":63,"web_visible":true},{"description":"\n This
+ is a text-to-speech model trained by facebook. It converts the input message
+ to output audio.\n The quality of the output is only
+ guaranteed by english speech, as this is the attempted output language.\n In
+ the future we may add different languages.\n\n Release
+ Date: December 2023\n ","id":36,"name":"Massively Multilingual
+ Speech English","sequence":[{"model_id":65,"type":"tts"}],"sequence_type":"AudioGenerationSequence","sram_owner_regex":null,"user_id":null,"web_visible":false},{"description":"SURF.nl
+ chat obv Sitemap en Dienstbrochure","id":40,"name":"SURF.nl chat ","sequence":[{"template_id":43},{"model_id":10,"type":"text"}],"sequence_type":"PromptTemplateSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":85,"web_visible":true}]
+
+ '
+ recorded_at: Wed, 02 Jan 2019 19:00:00 GMT
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/2024-6-18-webinar-mathematics/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Wed, 05 Jun 2024 14:16:18 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Transfer-Encoding:
+ - chunked
+ Connection:
+ - keep-alive
+ Vary:
+ - Accept-Encoding
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Cache-Control:
+ - no-cache
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnQgc2l0ZWhlYWRlci0tbWVudWJhci10cmFuc2x1Y2VudCBwYWdlLS1mb3Jtd2VidG9vbCBwYWdlLS13aXRoYmFja2xpbmsiIGRhdGEtdHJhY2tpbmdpZD0iIj48aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PHRpdGxlPlVDTCYjMzk7cyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlPC90aXRsZT48bWV0YSBuYW1lPSJkZXNjcmlwdGlvbiIgY29udGVudD0iTG9jYXRpb246IG9ubGluZSI+PGxpbmsgcmVsPSJjYW5vbmljYWwiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvMjAyNC02LTE4LXdlYmluYXItbWF0aGVtYXRpY3MvIj4KPCEtLQpSZWFsaXNhdGllOiDwn5K8IFdlYkhhcmUgYnYKICAgICAgICAgICAg8J+MkCBodHRwczovL3d3dy53ZWJoYXJlLm5sLwotLT4KPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xIiAvPjxtZXRhIG5hbWU9ImRlc2NyaXB0aW9uIiBjb250ZW50PSJMb2NhdGlvbjogb25saW5lIiAvPjxsaW5rIHJlbD0iYXBwbGUtdG91Y2gtaWNvbiIgc2l6ZXM9IjE4MHgxODAiIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9hcHBsZS10b3VjaC1pY29uLTE4MHgxODAucG5nIiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi0zMngzMi5wbmciIHNpemVzPSIzMngzMiIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tOTZ4OTYucG5nIiBzaXplcz0iOTZ4OTYiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTE5NHgxOTQucG5nIiBzaXplcz0iMTk0eDE5NCIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2FuZHJvaWQtY2hyb21lLTE5MngxOTIucG5nIiBzaXplcz0iMTkyeDE5MiIgLz48bGluayByZWw9Im1hc2staWNvbiIgICAgICAgICAgICAgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL3NhZmFyaS1waW5uZWQtdGFiLnN2ZyIgY29sb3I9IiNmZjhiMzgiIC8+PG1ldGEgbmFtZT0idGhlbWUtY29sb3IiIGNvbnRlbnQ9IiNmZmZmZmYiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnR5cGUiIGNvbnRlbnQ9IndlYnNpdGUiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnNpdGVfbmFtZSIgY29udGVudD0iRmVkZXJhdGlvbiIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6dGl0bGUiIGNvbnRlbnQ9IlVDTCYjMzk7cyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlIiAvPjxtZXRhIHByb3BlcnR5PSJvZzpkZXNjcmlwdGlvbiIgY29udGVudD0iTG9jYXRpb246IG9ubGluZSIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2UiIGNvbnRlbnQ9Imh0dHBzOi8vd3d3LjR0dS5ubC8udWMvaWMwOGRlNWEwMDEwMjUyZjgxMDAwMDNkZWE2MDFjNjA0NzJlM2E2ZDJjZmQ2MDcwMWMzYjAwNDc2MDI4MC90aGUtY29uY2VwdC1vZi1yZWFkaW5nLWxvdmUtMjAyMy0xMS0yNy0wNS0xMi0wOS11dGMuanBnIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTp3aWR0aCIgY29udGVudD0iMTIwMCIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6aGVpZ2h0IiBjb250ZW50PSI2MzAiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlIiBjb250ZW50PSJodHRwczovL3d3dy40dHUubmwvLnVjL2kyMDU3MjkzMzAxMDI1MmY4MTAwMDAzZGVhNjAxYzYwNDcyZTNhNmQyY2ZkNjA3MDFjMzJjMDEyYzAxODAvdGhlLWNvbmNlcHQtb2YtcmVhZGluZy1sb3ZlLTIwMjMtMTEtMjctMDUtMTItMDktdXRjLmpwZyIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6d2lkdGgiIGNvbnRlbnQ9IjMwMCIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6aGVpZ2h0IiBjb250ZW50PSIzMDAiIC8+PHNjcmlwdCBub21vZHVsZT4gaWYoISF3aW5kb3cuTVNJbnB1dE1ldGhvZENvbnRleHQgJiYgISFkb2N1bWVudC5kb2N1bWVudE1vZGUpZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsYXNzTGlzdC5hZGQoInVuc3VwcG9ydGVkLWJyb3dzZXIiKTs8L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2pzb24iIGlkPSJ3aC1jb25maWciPnsiZGVzaWduY2Rucm9vdCI6Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlLyIsImRlc2lnbnJvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS8iLCJkdGFwc3RhZ2UiOiJwcm9kdWN0aW9uIiwiaW1ncm9vdCI6Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy8iLCJpc2xpdmUiOnRydWUsImxvY2FsZSI6ImVuLVVTIiwib2JqIjp7Im5hdnBhdGhpdGVtIjp7ImxpbmsiOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtNi0xOC13ZWJpbmFyLW1hdGhlbWF0aWNzLyIsInRpdGxlIjoiVUNMJ3MgRXhwZXJpZW5jZSB3aXRoIENCTCBpbiBFbmdpbmVlcmluZyBlZHVjYXRpb24gd2l0aCBCaXJnaXQgUGVwaW4gYW5kIE1hdGhldXMgTy4gZGUgQW5kcmFkZSJ9fSwic2VydmVyIjo1MDUwMCwic2l0ZSI6e30sInNpdGVyb290IjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsInNvY2lhbGl0ZTpndG0iOnsiYSI6IkdUTS1XVFo1RlJRIiwiaCI6dHJ1ZSwibSI6ZmFsc2V9fTwvc2NyaXB0PjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iLy5hcC80dHUuc2l0ZS9hcC5jc3MiPjxzY3JpcHQgc3JjPSIvLmFwLzR0dS5zaXRlL2FwLm1qcyIgdHlwZT0ibW9kdWxlIiBhc3luYz48L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2xkK2pzb24iPnsiQGNvbnRleHQiOiJodHRwczovL3NjaGVtYS5vcmciLCJAdHlwZSI6IkJyZWFkY3J1bWJMaXN0IiwiaXRlbUxpc3RFbGVtZW50IjpbeyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iLCJuYW1lIjoiRmVkZXJhdGlvbiIsInBvc2l0aW9uIjoxfSx7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJuYW1lIjoiQWdlbmRhIiwicG9zaXRpb24iOjJ9LHsiQHR5cGUiOiJMaXN0SXRlbSIsIml0ZW0iOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtNi0xOC13ZWJpbmFyLW1hdGhlbWF0aWNzLyIsIm5hbWUiOiJVQ0wncyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlIiwicG9zaXRpb24iOjN9XX08L3NjcmlwdD48L2hlYWQ+PGJvZHk+PG5vc2NyaXB0PjxpZnJhbWUgc3JjPSIvL3d3dy5nb29nbGV0YWdtYW5hZ2VyLmNvbS9ucy5odG1sP2lkPUdUTS1XVFo1RlJRIiBoZWlnaHQ9IjAiIHdpZHRoPSIwIiBzdHlsZT0iZGlzcGxheTpub25lO3Zpc2liaWxpdHk6aGlkZGVuIj48L2lmcmFtZT48L25vc2NyaXB0PjxkaXYgY2xhc3M9InNwYy1tb2RhbGl0eWxheWVyIj48L2Rpdj48ZGl2IGlkPSJzbGlkZW1lbnUtY29udGFpbmVyIj48ZGl2IGlkPSJzbGlkZW1lbnUiIHRhYmluZGV4PSItMSIgICAgPjxkaXYgY2xhc3M9InNpZGViYXJfX2hlYWRlciI+IDxhIGNsYXNzPSJzaWRlYmFyX19oZWFkZXJfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJzaWRlYmFyX19pZGVudGl0eV9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJzaWRlYmFyX19pZGVudGl0eV9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PGJ1dHRvbiBpZD0ic2xpZGVtZW51LWNsb3NlIiBjbGFzcz0ic2lkZWJhci1hY3Rpb24tY2xvc2UiIHR5cGU9ImJ1dHRvbiIgYXJpYS1sYWJlbD0iQ2xvc2UiID48L2J1dHRvbj48L2Rpdj48dWwgY2xhc3M9InNpZGViYXJfX21lbnUgc2lkZWJhcl9fbWVudS0tbGV2ZWwxIiAgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIgPkhvbWU8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+UmVzZWFyY2g8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPkFib3V0IG91ciByZXNlYXJjaDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLzR0dS1jZW50cmVzLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPjRUVSBDZW50cmVzPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIiA+QU1JIChNYXRoZW1hdGljcyk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIiA+QnVpbHQgRW52aXJvbm1lbnQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyIgPkRlc2lnbiBVbml0ZWQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iID5FbmVyZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyIgPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIiA+SGVhbHRoPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIiA+SGlnaC1UZWNoIE1hdGVyaWFsczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyIgPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyIgPk5JUklDVCAoSUNUKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iID5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+SGlnaCBUZWNoIGZvciBhIFN1c3RhaW5hYmxlIEZ1dHVyZTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIiA+SFRTRiBJIFByb2dyYW1tZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyIgPkhUU0YgSUkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLXZpZGVvcy8iID5IVFNGIHZpZGVvczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyIgPjRUVS5SZXNlYXJjaERhdGE8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL0VFLU5MLyIgPkVsZWN0cmljYWwgRW5naW5lZXJpbmcgTmV0aGVybGFuZHM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5FZHVjYXRpb248L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5BYm91dCBvdXIgZWR1Y2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIiA+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyIgPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iID5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi9lZHVjYXRpb25wcm9ncmFtbWVzLyIgPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YnV0dG9uIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICI+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+VmFsb3Jpc2F0aW9uPC9idXR0b24+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0JTIwYWN0aXZpdGllcy8iID40VFUuSU1QQUNUPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iID5BYm91dCA0VFUuSW1wYWN0PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0YXJ0dXAlMjBtaXNzaW9ucy8iID5TdGFydHVwIG1pc3Npb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5NZWRpYTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9pbnNpZ2h0ZnVsLWlubm92YXRvcnMvIiA+SW5zaWdodGZ1bCBJbm5vdmF0b3JzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL1NwaW4tb2ZmJTIwc2VyaWUvIiA+U3Bpbi1PZmYgU3RvcmllczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3R1ZGVudCUyMGNoYWxsZW5nZXMvIiA+U3R1ZGVudCBjaGFsbGVuZ2VzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1R1c3NlbnBhZ2luYSUyMHZvb3JhZmdhYW5kJTIwYWFuJTIwU3RhcnR1cCUyMFN1cHBvcnQvIiA+QWJvdXQgU3RhcnR1cCBTdXBwb3J0PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+TmV3czwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gIHNpZGVtYWlubWVudV9faXRlbS0tZXhwYW5kICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19zZWxlY3RlZCAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5BYm91dCA0VFU8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS80dHUtaW4tMS1taW51dGUvIiA+NFRVIGluIG9ubHkgMSBtaW51dGU8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9mYWN0cy1maWd1cmVzLyIgPkZhY3RzIGFuZCBmaWd1cmVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvb3JnYW5pc2F0aW9uLyIgPk9yZ2FuaXNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L3B1YmxpY2F0aW9ucy8iID5QdWJsaWNhdGlvbnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9hbHVtbmkvIiA+QWx1bW5pPC9hPjwvbGk+PC91bD48L2xpPjwvdWw+PG5hdiBjbGFzcz0ic2lkZWJhcl9fbGFuZ3VhZ2VzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvIj5OTDwvYT4gfCA8c3BhbiBjbGFzcz0ic2VsZWN0ZWQiPkVOPC9zcGFuPjwvbmF2PjxuYXYgY2xhc3M9InNpZGViYXJfX3NlY29uZGFyeWxpbmtzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vY29udGFjdC8iPkNvbnRhY3Q8L2E+PC9uYXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcC1iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhci1iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wIj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19jb250ZW50Ij48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19pZGVudGl0eSI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fc2xvZ2FuIj5QYXJ0IG9mIHRoZSA8YnV0dG9uIGNsYXNzPSJoZWFkZXItdG9wX190b2dnbGVleHBsb3JlcGFuZWwiPjRUVS5GZWRlcmF0aW9uPC9idXR0b24+PC9kaXY+PGEgY2xhc3M9ImhlYWRlci10b3BfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX29yZ2FuaXphdGlvbnMiPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWRlbGZ0Lm5sL2VuLyIgdGl0bGU9IlRVIERlbGZ0IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWRlbGZ0LnN2ZyIgYWx0PSJUVSBEZWxmdCIgd2lkdGg9IjEwMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZS5ubC9lbi8iIHRpdGxlPSJUVSBFaW5kaG92ZW4iID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZWluZGhvdmVuLnN2ZyIgYWx0PSJUVSBFaW5kaG92ZW4iIHdpZHRoPSIxMzAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy51dHdlbnRlLm5sL2VuLyIgdGl0bGU9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci91bml2ZXJzaXR5LW9mLXR3ZW50ZS5zdmciIGFsdD0iVW5pdmVyc2l0eSBvZiBUd2VudGUiIHdpZHRoPSIxMDAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy53dXIubmwvIiB0aXRsZT0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXd1ci5zdmciIGFsdD0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiB3aWR0aD0iMTMyIiAvPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhciI+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX2NvbnRlbnQiPjxhIGNsYXNzPSJoZWFkZXItbWVudWJhcl9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc3BhY2VyIj48L2Rpdj48bmF2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fbWVudWJhciIgYXJpYS1sYWJlbD0iTWFpbiI+PHVsIGNsYXNzPSJzcGMtbWVudWJhciI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iID5Ib21lPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5SZXNlYXJjaDwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+QWJvdXQgb3VyIHJlc2VhcmNoPC9hPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC80dHUtY2VudHJlcy8iID40VFUgQ2VudHJlczwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyIgPkFNSSAoTWF0aGVtYXRpY3MpPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyIgPkJ1aWx0IEVudmlyb25tZW50PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iID5EZXNpZ24gVW5pdGVkPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIiA+RW5lcmd5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iID5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyIgPkhlYWx0aDwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyIgPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iID5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iID5OSVJJQ1QgKElDVCk8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIiA+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvIiA+SGlnaCBUZWNoIGZvciBhIFN1c3RhaW5hYmxlIEZ1dHVyZTwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIiA+SFRTRiBJIFByb2dyYW1tZXM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyIgPkhUU0YgSUkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLXZpZGVvcy8iID5IVFNGIHZpZGVvczwvYT48L2xpPjwvdWw+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iID40VFUuUmVzZWFyY2hEYXRhPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvRUUtTkwvIiA+RWxlY3RyaWNhbCBFbmdpbmVlcmluZyBOZXRoZXJsYW5kczwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5FZHVjYXRpb248L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5BYm91dCBvdXIgZWR1Y2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyIgPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIiA+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iID5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vZWR1Y2F0aW9ucHJvZ3JhbW1lcy8iID5FZHVjYXRpb24gcHJvZ3JhbW1lczwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iIiA+VmFsb3Jpc2F0aW9uPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdCUyMGFjdGl2aXRpZXMvIiA+NFRVLklNUEFDVDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyIgPkFib3V0IDRUVS5JbXBhY3Q8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0YXJ0dXAlMjBtaXNzaW9ucy8iID5TdGFydHVwIG1pc3Npb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhLyIgPk1lZGlhPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL2luc2lnaHRmdWwtaW5ub3ZhdG9ycy8iID5JbnNpZ2h0ZnVsIElubm92YXRvcnM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvU3Bpbi1vZmYlMjBzZXJpZS8iID5TcGluLU9mZiBTdG9yaWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3R1ZGVudCUyMGNoYWxsZW5nZXMvIiA+U3R1ZGVudCBjaGFsbGVuZ2VzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9UdXNzZW5wYWdpbmElMjB2b29yYWZnYWFuZCUyMGFhbiUyMFN0YXJ0dXAlMjBTdXBwb3J0LyIgPkFib3V0IFN0YXJ0dXAgU3VwcG9ydDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlbGVjdGVkIj5BZ2VuZGE8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iID5BYm91dCA0VFU8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS80dHUtaW4tMS1taW51dGUvIiA+NFRVIGluIG9ubHkgMSBtaW51dGU8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvZmFjdHMtZmlndXJlcy8iID5GYWN0cyBhbmQgZmlndXJlczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9vcmdhbmlzYXRpb24vIiA+T3JnYW5pc2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L3B1YmxpY2F0aW9ucy8iID5QdWJsaWNhdGlvbnM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2FsdW1uaS8iID5BbHVtbmk8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PC91bD48L25hdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc3BhY2VyIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fbGFuZ3VhZ2VzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvIj5OTDwvYT58PHNwYW4+RU48L3NwYW4+PC9kaXY+PGZvcm0gYWN0aW9uPSJodHRwczovL3d3dy40dHUubmwvZW4vc2VhcmNoLyIgbWV0aG9kPSJHRVQiIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNod3JhcHBlciIgYXV0b2NvbXBsZXRlPSJvZmYiID48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoLWlucHV0LWFuZC1zdWdnZXN0aW9ucy13cmFwcGVyIj48aW5wdXQgaWQ9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgbmFtZT0icXVlcnkiIGRhdGEtc3VnZ2VzdD0iNHR1OmNvcnBvcmF0ZV9lbiIgZGF0YS1zdWdnZXN0cGFyZW50PSJwYXJlbnQiIHBsYWNlaG9sZGVyPSJab2VrZW4iIGFyaWEtbGFiZWw9IlpvZWtlbiIgdHlwZT0ic2VhcmNoIiAvPjwvZGl2PjxsYWJlbCBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaCIgZm9yPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoaW5wdXQiIHRhYmluZGV4PSItMSIgPjxzcGFuIGNsYXNzPSJmYXIgZmEtc2VhcmNoIj48L3NwYW4+PC9sYWJlbD48L2Zvcm0+PGJ1dHRvbiBpZD0iaGVhZGVyLW1lbnViYXJfc2lkZWJhcnRvZ2dsZSIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zaG93c2lkZW1haW5tZW51IHNpZGViYXItYWN0aW9uLXRvZ2dsZSIgYXJpYS1sYWJlbD0iT3BlbiBtZW51IiBhcmlhLWV4cGFuZGVkPSJmYWxzZSIgYXJpYS1jb250cm9scz0ic2xpZGVtZW51IiA+PHNwYW4gY2xhc3M9ImZhciBmYS1iYXJzIj48L3NwYW4+PC9idXR0b24+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX3RvcGJhciI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jbG9zZSI+Q2xvc2U8L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbnMiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fYWRkcmVzcyBydGRjb250ZW50Ij48cCBjbGFzcz0iaGVhZGluZyI+NFRVLkZlZGVyYXRpb248L3A+PHAgY2xhc3M9Im5vcm1hbCI+KzMxKDApNiA0OCAyNyA1NSA2MTwvcD48cCBjbGFzcz0ibm9ybWFsIj48YSBocmVmPSJtYWlsdG86cHJvamVjdGxlaWRlckA0dHUubmwiPnNlY3JldGFyaXNANHR1Lm5sPC9hPjwvcD48cCBjbGFzcz0ibm9ybWFsIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48Yj5XZWJzaXRlOiA0VFUubmw8L2I+PC9hPjwvcD48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiBleHBsb3JlcGFuZWxfX2NvbHVtbi0tbWFueWl0ZW1zIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlJlc2VhcmNoPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyBleHBsb3JlcGFuZWxfX2l0ZW1zLS1tYW55aXRlbXMgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyI+PHNwYW4+QXBwbGllZCBNYXRoZW1hdGljcyBJbnN0aXR1dGU8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyI+PHNwYW4+QnVpbHQgRW52aXJvbm1lbnQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iPjxzcGFuPkRlc2lnbiBVbml0ZWQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIj48c3Bhbj5FbmVyZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iPjxzcGFuPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyI+PHNwYW4+SGVhbHRoPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyI+PHNwYW4+SGlnaC1UZWNoIE1hdGVyaWFsczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iPjxzcGFuPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iPjxzcGFuPk5JUklDVCAoSUNUKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIj48c3Bhbj5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIj48c3Bhbj5SZXNlYXJjaERhdGE8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIj48c3Bhbj5IVFNGIEkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIj48c3Bhbj5IVFNGIElJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiAiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuRWR1Y2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyAgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyI+PHNwYW4+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iPjxzcGFuPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIj48c3Bhbj5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcndpanMvb25kZXJ3aWpzcHJvZ3JhbW1hcy8iPjxzcGFuPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiAiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuVmFsb3Jpc2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyAgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIj48c3Bhbj40VFUuSU1QQUNUPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3RlY2gtdHJhbnNmZXIubmwvZW4vIj48c3Bhbj5UaGVtYXRpYyBUZWNobm9sb2d5IFRyYW5zZmVyPC9zcGFuPjwvYT48YSBocmVmPSIiPjxzcGFuPlNwaW4tb2ZmIFN0b3JpZXM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vNHR1aW1wYWN0Y2hhbGxlbmdlLm5sLyI+PHNwYW4+NFRVIEltcGFjdCBDaGFsbGVuZ2U8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fc2xpZGVzaG93IGNhcnJvdXNlbF9fdmlld3BvcnQgY2Fycm91c2VsX19kcmFnYXJlYSAiPjxzdHlsZT5AbWVkaWEgKG1heC13aWR0aDogNzY3cHgpey5oZWFkZXJzbGlkZTB7YmFja2dyb3VuZC1jb2xvcjogIzFEMUExRDtiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pYzgyYmJjMDUwMTAyNTJmODEwMDAwM2RlYTYwMWM2MDQ3MmUzYTZkMmNmZDYwODAxZTM0MDBiMDAwNzgxNDYvdGhlLWNvbmNlcHQtb2YtcmVhZGluZy1sb3ZlLTIwMjMtMTEtMjctMDUtMTItMDktdXRjLmpwZyk7fX1AbWVkaWEgKG1pbi13aWR0aDogNzY4cHgpey5oZWFkZXJzbGlkZTB7YmFja2dyb3VuZC1jb2xvcjogIzFEMUExRDtiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pYmU3ODUzNzgwMTAyNTJmODEwMDAwM2RlYTYwMWM2MDQ3MmUzYTZkMmNmZDYwODAxZTM0MDBiNjAwNDgxNDYvdGhlLWNvbmNlcHQtb2YtcmVhZGluZy1sb3ZlLTIwMjMtMTEtMjctMDUtMTItMDktdXRjLmpwZyk7fX08L3N0eWxlPjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19zbGlkZSBjYXJyb3VzZWxfX2NlbGwgYWN0aXZlc2xpZGUgaGVhZGVyc2xpZGUwICIgZGF0YS1zbGlkZXNob3ctZWxlbWVudHM9InBhZ2UtaGVhZGVyX19zbGlkZTBfX2NvbnRlbnQiIHN0eWxlPSIiID48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fY29udGVudCI+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX21ldGEiPjxoMSBjbGFzcz0icGFnZS1oZWFkZXJfX3RpdGxlIj5VQ0wncyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlPC9oMT48ZGl2IGNsYXNzPSJwYWdlaGVhZGVyX19kYXRlIj5UdWVzZGF5IDE4IEp1bmUgMjAyNCAvIDEwLjAwIC0gMTEuMzA8L2Rpdj48ZGl2IGNsYXNzPSJwYWdlaGVhZGVyX190ZXh0Ij5Mb2NhdGlvbjogb25saW5lPC9kaXY+PC9kaXY+PC9kaXY+PG1haW4gY2xhc3M9InBhZ2VfX2JvZHkgICI+PGZvcm0gaWQ9IiIgIGNsYXNzPSJwYWdlX19oZWFkZXJmaWx0ZXJzICAgIj48L2Zvcm0+PGRpdiBjbGFzcz0icGFnZV9fY29udGVudGFyZWEgIHBhZ2VfX2NvbnRlbnRhcmVhLS1mb3Jtd2VidG9vbCAgaGVhZGVyaXNvcGFxdWUgIj48ZGl2IGNsYXNzPSJkZWVwbGlua3Mtd3JhcHBlciI+PGRpdiBjbGFzcz0iZGVlcGxpbmtzIj48YSBjbGFzcz0icGFnZS1iYWNrbGluayIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFsbCBldmVudHM8L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1jb250ZW50c3RhcnQiPjwvZGl2PjwhLS13aF9jb25zaWxpb19jb250ZW50LS0+PGZvcm0gY2xhc3M9IndoLWZvcm0gd2gtc3R5bGVkaW5wdXQiICBtZXRob2Q9InBvc3QiIGFjdGlvbj0iamF2YXNjcmlwdDpjb25zb2xlLmVycm9yKCdObyBSUEMgaGFuZGxlciBpbnN0YWxsZWQnKTsiIGRhdGEtd2gtZm9ybS12YXItZm9ybXN1Ym1pdHR5cGU9Im5ldyIgZGF0YS13aC1mb3JtLWlkPSJ3ZWJ0b29sZm9ybSIgZGF0YS13aC1mb3JtLWhhbmRsZXI9InB1Ymxpc2hlcjpycGMiIGRhdGEtd2gtZm9ybS10YXJnZXQ9Ii15SllEQnM0UHJGNUxsX3F6cVNLcV9FbGhjUlF6Q2JHUENyM1hSd1NPaEVLVjExM19SR0FGQXJ5NmhLaGlZYUpSZUJ4WDYxbDVSYUYzdVVuVFdQNEdUSW1YaUY4Nmpfei44MVdVa2NEeFRnMHpST2g5Lk91Z1BOellzRDBtVFBQYnRyZU8tTVEiPjxhIGNsYXNzPSJ3aC1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19wcm9sb2d1ZSI+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fcGFnZSB3aC1mb3JtX19wYWdlLS12aXNpYmxlIj48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGdyb3VwIHdoLWZvcm1fX2ZpZWxkZ3JvdXAtLXJpY2h0ZXh0IiBkYXRhLXdoLWZvcm0tZ3JvdXAtZm9yPSJfX2Zvcm1maWVsZGF3WjZQX2lySnp5bVhTcHNJcFIxYVFfIj48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZHMiPjxhIGNsYXNzPSJ3aC1hbmNob3IiIGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZGF3WjZQX2lySnp5bVhTcHNJcFIxYVFfLWFuY2hvciI+PC9hPjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkbGluZSI+PGRpdiBjbGFzcz0id2gtZm9ybV9fcmljaHRleHQiPjxwIGNsYXNzPSJub3JtYWwiPkRhdGU6IDE4LzA2LzIwMjQ8L3A+PHAgY2xhc3M9Im5vcm1hbCI+VGltZTogMTAuMDAtMTEuMzA8L3A+PGgyIGNsYXNzPSJoZWFkaW5nMiI+Rmlyc3QgcHJlc2VudGF0aW9uOiBTdHVkZW50IExlYXJuaW5nIGV4cGVyaWVuY2VzIGluIENCTDogdGhlIGNhc2VzIG9mIE1hdGhlbWF0aWNzIGFuZCBQaHlzaWNzIGJ5IEJpcmdpdCBQZXBpbiBUVS9lPC9oMj48cCBjbGFzcz0ibm9ybWFsIj5DaGVjayBvdXQgdGhlIHByb2plY3TCoDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvaW5ub3ZhdGlvbi9wcm9qZWN0LzM3MzYvc3R1ZGVudC1sZWFybmluZy1leHBlcmllbmNlcy1pbi1jaGFsbGVuZ2UtYmFzZWQtZWR1Y2F0aW9uLXRoZS1jYXNlcy1vZi1hcHBsaWVkLW1hdGhlbWF0aWNzLWFuZC1waHlzaWNzIj5oZXJlPC9hPiE8L3A+PGgyIGNsYXNzPSJoZWFkaW5nMiI+U2Vjb25kIHByZXNlbnRhdGlvbjogVUNM4oCZcyBFeHBlcmllbmNlIGluIEVuZ2luZWVyaW5nIE1hdGhlbWF0aWNzIEN1cnJpY3VsYXIgUmVmb3JtOiBQcmVwYXJpbmcgc3R1ZGVudHMgZm9yIHRoZSB3b3JrcGxhY2UgYW5kIHNvY2lldHk8L2gyPjxwIGNsYXNzPSJub3JtYWwiPlNwZWFrZXI6wqBNYXRoZXVzIE8uIGRlIEFuZHJhZGU8L3A+PHAgY2xhc3M9Im5vcm1hbCI+RW5naW5lZXJzIG5lZWQgdG8gZHJhdyBmcm9tIGEgYmxlbmQgb2YgZm9ybXMgb2Yga25vd2xlZGdlIHRvIHJlYWxpc2UgdGVjaG5pY2FsbHksIHNvY2lhbGx5LCBlY29ub21pY2FsbHksIGFuZCBlbnZpcm9ubWVudGFsbHkgcmVzcG9uc2libGUgc29sdXRpb25zIHRvIGNvbXBsZXggcHJvYmxlbXMuIEludGVncmF0aW5nIHRoZXNlIHZhbHVlcyBpbiBtYXRoZW1hdGljcyBlZHVjYXRpb24gZm9yIGVuZ2luZWVyaW5nIHN0dWRlbnRzLCBob3dldmVyLCByZW1haW5zIGEgY2hhbGxlbmdlLCBlc3BlY2lhbGx5IGF0IHRoZSBwcm9ncmFtbWUgYW5kIGluc3RpdHV0aW9uYWwgbGV2ZWxzLiBPbiB0aGUgb25lIGhhbmQsIGl0IGlzIGltcGVyYXRpdmUgdGhhdCBtYXRoZW1hdGljcyBtb2R1bGVzIGVxdWlwIHN0dWRlbnRzIHdpdGggdGhlIHRlY2huaWNhbCBrbm93bGVkZ2UgYW5kIHNraWxscyB0aGF0IHdpbGwgYWxsb3cgdGhlbSB0byBlbmdhZ2Ugd2l0aCBhZHZhbmNlZCBlbmdpbmVlcmluZyBjb25jZXB0cyBsYXRlciBpbiB0aGVpciBjb3Vyc2UuIE9uIHRoZSBvdGhlciBoYW5kLCBpdCBpcyBhbHNvIGNsZWFyIHRoYXQgbWF0aGVtYXRpY3MgZWR1Y2F0aW9uIHNob3VsZCBhbHNvIHN1cHBvcnQgdGhlIGRldmVsb3BtZW50IG9mIHNvY2lhbCwgYWZmZWN0aXZlLCBhbmQgbWV0YS1jb2duaXRpdmUgc2tpbGxzIGZvciBlbmdpbmVlcmluZyBzdHVkZW50cy4gSW4gdGhpcyB3ZWJpbmFyLCBJIHdpbGwgZGlzY3VzcyBVQ0zigJlzIGV4cGVyaWVuY2VzIGluIHRoZSBkZXNpZ24gYW5kIGltcGxlbWVudGF0aW9uIG9mIGZhY3VsdHktd2lkZSBjdXJyaWN1bGEsIGFjdGl2aXRpZXMsIGFuZCBhc3Nlc3NtZW50IG9mIG1hdGhlbWF0aWNzIHRoYXQgaXMgcHJpbWFyaWx5IHRhdWdodCB0aHJvdWdoIGVuZ2luZWVyaW5nIGFwcGxpY2F0aW9ucyB3aXRoaW4gc29jaWV0YWwgY29udGV4dHMuPC9wPjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkZ3JvdXAgd2gtZm9ybV9fZmllbGRncm91cC0tdGV4dGVkaXQgd2gtZm9ybV9fZmllbGRncm91cC0tcmVxdWlyZWQiIGRhdGEtd2gtZm9ybS1ncm91cC1mb3I9Il9fZm9ybWZpZWxkS3QtRGM4OHZVUTV5aUNvQmx3SkZQQV8iPjxsYWJlbCBjbGFzcz0id2gtZm9ybV9fbGFiZWwiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRLdC1EYzg4dlVRNXlpQ29CbHdKRlBBXyI+Rmlyc3QgbmFtZTwvbGFiZWw+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRzIj48YSBjbGFzcz0id2gtYW5jaG9yIiBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRLdC1EYzg4dlVRNXlpQ29CbHdKRlBBXy1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUiPjxpbnB1dCBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRLdC1EYzg4dlVRNXlpQ29CbHdKRlBBXyIgdHlwZT0idGV4dCIgbmFtZT0iX19mb3JtZmllbGRLdC1EYzg4dlVRNXlpQ29CbHdKRlBBXyIgY2xhc3M9IndoLWZvcm1fX3RleHRpbnB1dCIgcGxhY2Vob2xkZXI9IiAiIHJlcXVpcmVkPjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkZ3JvdXAgd2gtZm9ybV9fZmllbGRncm91cC0tdGV4dGVkaXQgd2gtZm9ybV9fZmllbGRncm91cC0tcmVxdWlyZWQiIGRhdGEtd2gtZm9ybS1ncm91cC1mb3I9Il9fZm9ybWZpZWxkTEs4S0hSVnRFNkFPVVpwREt2VHRCZ18iPjxsYWJlbCBjbGFzcz0id2gtZm9ybV9fbGFiZWwiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRMSzhLSFJWdEU2QU9VWnBES3ZUdEJnXyI+TGFzdCBuYW1lPC9sYWJlbD48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZHMiPjxhIGNsYXNzPSJ3aC1hbmNob3IiIGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZExLOEtIUlZ0RTZBT1VacERLdlR0QmdfLWFuY2hvciI+PC9hPjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkbGluZSI+PGlucHV0IGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZExLOEtIUlZ0RTZBT1VacERLdlR0QmdfIiB0eXBlPSJ0ZXh0IiBuYW1lPSJfX2Zvcm1maWVsZExLOEtIUlZ0RTZBT1VacERLdlR0QmdfIiBjbGFzcz0id2gtZm9ybV9fdGV4dGlucHV0IiBwbGFjZWhvbGRlcj0iICIgcmVxdWlyZWQ+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRncm91cCB3aC1mb3JtX19maWVsZGdyb3VwLS10ZXh0ZWRpdCB3aC1mb3JtX19maWVsZGdyb3VwLS1yZXF1aXJlZCIgZGF0YS13aC1mb3JtLWdyb3VwLWZvcj0iX19mb3JtZmllbGRxaEtwRWVJZjhPbkRVVkh2bUVoR0VRXyI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19sYWJlbCIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZHFoS3BFZUlmOE9uRFVWSHZtRWhHRVFfIj5FLW1haWwgYWRkcmVzczwvbGFiZWw+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRzIj48YSBjbGFzcz0id2gtYW5jaG9yIiBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRxaEtwRWVJZjhPbkRVVkh2bUVoR0VRXy1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUiPjxpbnB1dCBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRxaEtwRWVJZjhPbkRVVkh2bUVoR0VRXyIgdHlwZT0iZW1haWwiIG5hbWU9Il9fZm9ybWZpZWxkcWhLcEVlSWY4T25EVVZIdm1FaEdFUV8iIGNsYXNzPSJ3aC1mb3JtX190ZXh0aW5wdXQiIHBsYWNlaG9sZGVyPSIgIiByZXF1aXJlZD48L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGdyb3VwIHdoLWZvcm1fX2ZpZWxkZ3JvdXAtLXJhZGlvZ3JvdXAgd2gtZm9ybV9fZmllbGRncm91cC0tcmVxdWlyZWQiIHJvbGU9Imdyb3VwIiBhcmlhLWxhYmVsbGVkYnk9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tbGFiZWwiIGRhdGEtd2gtZm9ybS1ncm91cC1mb3I9Il9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18gX19mb3JtZmllbGRrRUcyVF80dGpxMGlIUWxMS3ZIZm13XyI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19sYWJlbCIgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tbGFiZWwiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3XyI+VW5pdmVyc2l0eTwvbGFiZWw+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRzIj48YSBjbGFzcz0id2gtYW5jaG9yIiBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUgd2gtZm9ybV9fZmllbGRsaW5lLS1ub3dyYXAiPjxpbnB1dCBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy1xT01NS1pPT3lTRDRrVTc2X21JS1NBIiB0eXBlPSJyYWRpbyIgY2xhc3M9IndoLWZvcm1fX3JhZGlvIiBuYW1lPSJfX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfIiB2YWx1ZT0icU9NTUtaT095U0Q0a1U3Nl9tSUtTQSIgcmVxdWlyZWQ+PGxhYmVsIGFyaWEtaGlkZGVuPSJ0cnVlIiBmb3I9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tcU9NTUtaT095U0Q0a1U3Nl9tSUtTQSI+PC9sYWJlbD48c3BhbiBjbGFzcz0id2gtZm9ybV9fb3B0aW9uZGF0YSB3aC1mb3JtX19vcHRpb25kYXRhLS12ZXJ0aWNhbCI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25sYWJlbCIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLXFPTU1LWk9PeVNENGtVNzZfbUlLU0EiPkRlbGZ0IFVuaXZlcnNpdHkgb2YgVGVjaG5vbG9neTwvbGFiZWw+PC9zcGFuPjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkbGluZSB3aC1mb3JtX19maWVsZGxpbmUtLW5vd3JhcCI+PGlucHV0IGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLXhicVYwdVBUR2tMdk1qX3IxMlRabkEiIHR5cGU9InJhZGlvIiBjbGFzcz0id2gtZm9ybV9fcmFkaW8iIG5hbWU9Il9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18iIHZhbHVlPSJ4YnFWMHVQVEdrTHZNal9yMTJUWm5BIiByZXF1aXJlZD48bGFiZWwgYXJpYS1oaWRkZW49InRydWUiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy14YnFWMHVQVEdrTHZNal9yMTJUWm5BIj48L2xhYmVsPjxzcGFuIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25kYXRhIHdoLWZvcm1fX29wdGlvbmRhdGEtLXZlcnRpY2FsIj48bGFiZWwgY2xhc3M9IndoLWZvcm1fX29wdGlvbmxhYmVsIiBmb3I9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18teGJxVjB1UFRHa0x2TWpfcjEyVFpuQSI+RWluZGhvdmVuIFVuaXZlcnNpdHkgb2YgVGVjaG5vbG9neTwvbGFiZWw+PC9zcGFuPjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkbGluZSB3aC1mb3JtX19maWVsZGxpbmUtLW5vd3JhcCI+PGlucHV0IGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLTdvT080Z3JOUjZrbUotUzBoQnpMTEEiIHR5cGU9InJhZGlvIiBjbGFzcz0id2gtZm9ybV9fcmFkaW8iIG5hbWU9Il9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18iIHZhbHVlPSI3b09PNGdyTlI2a21KLVMwaEJ6TExBIiByZXF1aXJlZD48bGFiZWwgYXJpYS1oaWRkZW49InRydWUiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy03b09PNGdyTlI2a21KLVMwaEJ6TExBIj48L2xhYmVsPjxzcGFuIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25kYXRhIHdoLWZvcm1fX29wdGlvbmRhdGEtLXZlcnRpY2FsIj48bGFiZWwgY2xhc3M9IndoLWZvcm1fX29wdGlvbmxhYmVsIiBmb3I9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tN29PTzRnck5SNmttSi1TMGhCekxMQSI+VW5pdmVyc2l0eSBvZiBUd2VudGU8L2xhYmVsPjwvc3Bhbj48L2Rpdj48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUgd2gtZm9ybV9fZmllbGRsaW5lLS1ub3dyYXAiPjxpbnB1dCBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy1vWU01NVE5RFJhOEVmajFUZ3FVSkxBIiB0eXBlPSJyYWRpbyIgY2xhc3M9IndoLWZvcm1fX3JhZGlvIiBuYW1lPSJfX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfIiB2YWx1ZT0ib1lNNTVROURSYThFZmoxVGdxVUpMQSIgcmVxdWlyZWQ+PGxhYmVsIGFyaWEtaGlkZGVuPSJ0cnVlIiBmb3I9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tb1lNNTVROURSYThFZmoxVGdxVUpMQSI+PC9sYWJlbD48c3BhbiBjbGFzcz0id2gtZm9ybV9fb3B0aW9uZGF0YSB3aC1mb3JtX19vcHRpb25kYXRhLS12ZXJ0aWNhbCI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25sYWJlbCIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLW9ZTTU1UTlEUmE4RWZqMVRncVVKTEEiPldhZ2VuaW5nZW4gVW5pdmVyc2l0eSAgJiMzODsgIFJlc2VhcmNoPC9sYWJlbD48L3NwYW4+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRsaW5lIHdoLWZvcm1fX2ZpZWxkbGluZS0tbm93cmFwIHdoLWZvcm1fX2ZpZWxkbGluZS0tc3ViZmllbGRzIj48aW5wdXQgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tbFFSMUpZek8tZ2FUQWJpTU5mckVNQSIgdHlwZT0icmFkaW8iIGNsYXNzPSJ3aC1mb3JtX19yYWRpbyIgbmFtZT0iX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3XyIgdmFsdWU9ImxRUjFKWXpPLWdhVEFiaU1OZnJFTUEiIHJlcXVpcmVkIGRhdGEtd2gtZm9ybS1lbmFibGU9Il9fZm9ybWZpZWxka0VHMlRfNHRqcTBpSFFsTEt2SGZtd18iPjxsYWJlbCBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLWxRUjFKWXpPLWdhVEFiaU1OZnJFTUEiPjwvbGFiZWw+PHNwYW4gY2xhc3M9IndoLWZvcm1fX29wdGlvbmRhdGEgd2gtZm9ybV9fb3B0aW9uZGF0YS0tdmVydGljYWwiPjxsYWJlbCBjbGFzcz0id2gtZm9ybV9fb3B0aW9ubGFiZWwiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy1sUVIxSll6Ty1nYVRBYmlNTmZyRU1BIj5vdGhlcjwvbGFiZWw+PHNwYW4gY2xhc3M9IndoLWZvcm1fX3N1YmZpZWxkIj48aW5wdXQgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxka0VHMlRfNHRqcTBpSFFsTEt2SGZtd18iIHR5cGU9InRleHQiIG5hbWU9Il9fZm9ybWZpZWxka0VHMlRfNHRqcTBpSFFsTEt2SGZtd18iIGNsYXNzPSJ3aC1mb3JtX190ZXh0aW5wdXQiIHBsYWNlaG9sZGVyPSIgIiByZXF1aXJlZD48L3NwYW4+PC9zcGFuPjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkZ3JvdXAgd2gtZm9ybV9fZmllbGRncm91cC0tY2hlY2tib3giIGRhdGEtd2gtZm9ybS1ncm91cC1mb3I9Il9fZm9ybWZpZWxkNG1TQVFNSVRvaG9iVjduT0JTMUZVUV8iPjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkcyI+PGEgY2xhc3M9IndoLWFuY2hvciIgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkNG1TQVFNSVRvaG9iVjduT0JTMUZVUV8tYW5jaG9yIj48L2E+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRsaW5lIHdoLWZvcm1fX2ZpZWxkbGluZS0tbm93cmFwIj48aW5wdXQgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkNG1TQVFNSVRvaG9iVjduT0JTMUZVUV8iIHR5cGU9ImNoZWNrYm94IiBjbGFzcz0id2gtZm9ybV9fY2hlY2tib3giIG5hbWU9Il9fZm9ybWZpZWxkNG1TQVFNSVRvaG9iVjduT0JTMUZVUV8iIHZhbHVlPSIxIj48bGFiZWwgYXJpYS1oaWRkZW49InRydWUiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGQ0bVNBUU1JVG9ob2JWN25PQlMxRlVRXyI+PC9sYWJlbD48c3BhbiBjbGFzcz0id2gtZm9ybV9fb3B0aW9uZGF0YSB3aC1mb3JtX19vcHRpb25kYXRhLS12ZXJ0aWNhbCI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25sYWJlbCIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZDRtU0FRTUlUb2hvYlY3bk9CUzFGVVFfIj5zZW5kIG1lIHVwZGF0ZXMgb24gZnV0dXJlIDRUVS5DRUUgZXZlbnRzPC9sYWJlbD48L3NwYW4+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fcGFnZSB3aC1mb3JtX19wYWdlLS1oaWRkZW4iIGRhdGEtd2gtZm9ybS1wYWdlcm9sZT0idGhhbmt5b3UiIHJvbGU9InN0YXR1cyI+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRncm91cCB3aC1mb3JtX19maWVsZGdyb3VwLS1yaWNodGV4dCIgZGF0YS13aC1mb3JtLWdyb3VwLWZvcj0iX19mb3JtZmllbGRWNTVKSmYzWW5xcmV5SnlMN01FQll3XyI+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRzIj48YSBjbGFzcz0id2gtYW5jaG9yIiBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRWNTVKSmYzWW5xcmV5SnlMN01FQll3Xy1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUiPjxkaXYgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkVjU1SkpmM1lucXJleUp5TDdNRUJZd18iIGNsYXNzPSJ3aC1mb3JtX19yaWNodGV4dCI+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fYnV0dG9uZ3JvdXAgd2gtZm9ybV9fbmF2YnV0dG9ucyI+PGJ1dHRvbiB0eXBlPSJidXR0b24iIGRhdGEtd2gtZm9ybS1hY3Rpb249InByZXZpb3VzIiBjbGFzcz0id2gtZm9ybV9fYnV0dG9uIHdoLWZvcm1fX2J1dHRvbi0tcHJldmlvdXMiPjxzcGFuIGNsYXNzPSJ3aC1mb3JtX19idXR0b25sYWJlbCI+UHJldmlvdXM8L3NwYW4+PC9idXR0b24+PGJ1dHRvbiB0eXBlPSJidXR0b24iIGRhdGEtd2gtZm9ybS1hY3Rpb249Im5leHQiIGNsYXNzPSJ3aC1mb3JtX19idXR0b24gd2gtZm9ybV9fYnV0dG9uLS1uZXh0Ij48c3BhbiBjbGFzcz0id2gtZm9ybV9fYnV0dG9ubGFiZWwiPk5leHQ8L3NwYW4+PC9idXR0b24+PGJ1dHRvbiB0eXBlPSJzdWJtaXQiIGNsYXNzPSJ3aC1mb3JtX19idXR0b24gd2gtZm9ybV9fYnV0dG9uLS1zdWJtaXQiPjxzcGFuIGNsYXNzPSJ3aC1mb3JtX19idXR0b25sYWJlbCI+U3VibWl0PC9zcGFuPjwvYnV0dG9uPjwvZGl2PjwvZm9ybT48IS0tL3doX2NvbnNpbGlvX2NvbnRlbnQtLT48ZGl2IGNsYXNzPSJwYWdlX19iYWxsb29uIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXIiPjxkaXYgY2xhc3M9InBhZ2VfX2Zvb3Rlcl9fY29udGVudCBuYXZwYXRoIj48YSBjbGFzcz0ibmF2cGF0aF9faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT48c3BhbiBjbGFzcz0ibmF2cGF0aF9fc2VwZXJhdG9yIj48L3NwYW4+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19pdGVtIGNydW1icGF0aC0tY3VycmVudHBhZ2UiPlVDTCYjMzk7cyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlPC9zcGFuPjwvZGl2PjwvZGl2PjwvZGl2PjwvbWFpbj48ZGl2IGNsYXNzPSJmb290ZXIiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fcGFuZWwiPjxkaXYgY2xhc3M9ImZvb3Rlcl9faWRlbnRpdHkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX3NpdGV0aXRsZSI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwhLS0gRklYTUU6IHVzZSBhcmlhLWhpZGRlbj0idHJ1ZSIgYmVjYXVzZSBpdCdzIGEgZHVwbGljYXRlIG9mIHRoZSBpdGVtcyBvbiB0aGUgbWVudSBiYXIgPyAtLT4gPG5hdiBjbGFzcz0iZm9vdGVyX19jb2x1bW4xIGZvb3Rlcl9fbWFpbm1lbnUiIGFyaWEtbGFiZWw9Ik1haW4iPiA8dWw+ICAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj5Ib21lPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIj5SZXNlYXJjaDwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iPkVkdWNhdGlvbjwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iIj5WYWxvcmlzYXRpb248L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIj5OZXdzPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyI+QWdlbmRhPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyI+QWJvdXQgNFRVPC9hPiA8L2xpPiAgIDwvdWw+IDwvbmF2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW4yIj4gPGlucHV0IHR5cGU9ImNoZWNrYm94IiBuYW1lPSJmb290ZXJjb2x1bW4iIGlkPSJmb290ZXJfX2NvbHVtbjJfX2V4cGFuZCIgLz4gPGxhYmVsIGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyIgZm9yPSJmb290ZXJfX2NvbHVtbjJfX2V4cGFuZCI+Q29udGFjdDwvbGFiZWw+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IHJ0ZGNvbnRlbnQiPiA8cCBjbGFzcz0ibm9ybWFsIj4rMzEoMCk2IDgzIDIyIDUwIDU5PGJyIC8+PGEgaHJlZj0ibWFpbHRvOnByb2plY3RsZWlkZXJANHR1Lm5sIj5zZWNyZXRhcmlzQDR0dS5ubDwvYT48L3A+IDwvZGl2PiA8L2Rpdj4gICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjMiPiA8aW5wdXQgdHlwZT0iY2hlY2tib3giIG5hbWU9ImZvb3RlcmNvbHVtbiIgaWQ9ImZvb3Rlcl9fY29sdW1uM19fZXhwYW5kIiAvPiA8bGFiZWwgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIiBmb3I9ImZvb3Rlcl9fY29sdW1uM19fZXhwYW5kIj5Qb3N0YWRyZXM8L2xhYmVsPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9fY29udGVudCBydGRjb250ZW50Ij4gPHAgY2xhc3M9Im5vcm1hbCI+NFRVLkZlZGVyYXRpZTxiciAvPlBvc3RidXMgNTxiciAvPjI2MDAgQUEgRGVsZnQ8L3A+IDwvZGl2PiA8L2Rpdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uNCI+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW1zX19ncm91cCI+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIj5Gb2xsb3cgdXM8L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9fY29udGVudCBmb290ZXJfX3NvY2lhbGl0ZW1zICI+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly90d2l0dGVyLmNvbS80VFVGZWRlcmF0aW9uIiB0aXRsZT0iVHdpdHRlciIgPjxzcGFuIGNsYXNzPSJmYWIgZmEtdHdpdHRlciI+PC9zcGFuPjwvYT48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tcGFueS80LXR1LWZlZGVyYXRpb24vIiB0aXRsZT0iTGlua2VkSW4iID48c3BhbiBjbGFzcz0iZmFiIGZhLWxpbmtlZGluLWluIj48L3NwYW4+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2NoYW5uZWwvVUNNa3FoangyVzFoTlJ3eXNSdldFWHdRIiB0aXRsZT0iWW91dHViZSIgPjxzcGFuIGNsYXNzPSJmYWIgZmEteW91dHViZSI+PC9zcGFuPjwvYT48L2Rpdj4gPC9kaXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJfX2dyb3VwIj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIGZvb3Rlcl9fY29sdW1uX19oZWFkaW5nLS1uZXdzbGV0dGVyICI+U3RheSB1cC10by1kYXRlPC9kaXY+PGZvcm0gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cCB3aHBsdWdpbi1uZXdzbGV0dGVyLXN1YnNjcmlwdGlvbiAgIiBkYXRhLW5ld3NsZXR0ZXItbGlzdD0iU1VCU180VFVfQ09SUE9SQVRFX05JRVVXU0JSSUVGIiA+PGlucHV0IG5hbWU9ImVtYWlsIiBwbGFjZWhvbGRlcj0iU2lnbiB1cCBmb3Igb3VyIG5ld3NsZXR0ZXIiIC8+PGJ1dHRvbiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwX19zdWJtaXQiIHR5cGU9InN1Ym1pdCIgbmFtZT0ic3VibWl0YnV0dG9uIiBhcmlhLWxhYmVsPSJTdWJzY3JpYmUiPjxzcGFuIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Ym1pdF9faWNvbiBmYXIgZmEtZW52ZWxvcGUiPjwvc3Bhbj48L2J1dHRvbj48L2Zvcm0+PGRpdiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwX19zdWNjZXNzIj5UaGFua3MgZm9yIHN1YnNjcmliaW5nIHRvIG91ciBuZXdzbGV0dGVyLjwvZGl2PiAgPC9kaXY+IDwvZGl2PiA8aHIgY2xhc3M9ImZvb3Rlcl9fZGl2aWRlciIgLz4gPGRldGFpbHMgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZSI+PHN1bW1hcnk+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX190b2dnbGVfX2Nsb3NlZHRleHQiPlBhcnQgb2YgdGhlIDxzcGFuIGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX25hbWUiPjRUVS5GZWRlcmF0aW9uPC9zcGFuPjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fdG9nZ2xlX19vcGVudGV4dCI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2Nsb3NlIj5DbG9zZTwvZGl2PjwvZGl2Pjwvc3VtbWFyeT48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbCI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2NhdGVnb3J5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuUmVzZWFyY2g8L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIj48c3Bhbj5BcHBsaWVkIE1hdGhlbWF0aWNzIEluc3RpdHV0ZTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIj48c3Bhbj5CdWlsdCBFbnZpcm9ubWVudDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyI+PHNwYW4+RGVzaWduIFVuaXRlZDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iPjxzcGFuPkVuZXJneTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyI+PHNwYW4+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIj48c3Bhbj5IZWFsdGg8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIj48c3Bhbj5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyI+PHNwYW4+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyI+PHNwYW4+TklSSUNUIChJQ1QpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iPjxzcGFuPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iPjxzcGFuPlJlc2VhcmNoRGF0YTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iPjxzcGFuPkhUU0YgSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iPjxzcGFuPkhUU0YgSUkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLkVkdWNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iPjxzcGFuPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIj48c3Bhbj40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyI+PHNwYW4+U0FJIChFbmdpbmVlcmluZyBEb2N0b3JhdGUpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ3aWpzL29uZGVyd2lqc3Byb2dyYW1tYXMvIj48c3Bhbj5FZHVjYXRpb24gcHJvZ3JhbW1lczwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2NhdGVnb3J5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuVmFsb3Jpc2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIj48c3Bhbj40VFUuSU1QQUNUPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3RlY2gtdHJhbnNmZXIubmwvZW4vIj48c3Bhbj5UaGVtYXRpYyBUZWNobm9sb2d5IFRyYW5zZmVyPC9zcGFuPjwvYT48YSBocmVmPSIiPjxzcGFuPlNwaW4tb2ZmIFN0b3JpZXM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vNHR1aW1wYWN0Y2hhbGxlbmdlLm5sLyI+PHNwYW4+NFRVIEltcGFjdCBDaGFsbGVuZ2U8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjwvZGV0YWlscz4gPGRpdiBjbGFzcz0iZm9vdGVyX19wYXJ0bmVycyI+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW1zIj4gPGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZGVsZnQubmwvZW4vIiB0aXRsZT0iVFUgRGVsZnQiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZGVsZnQuc3ZnIiBhbHQ9IlRVIERlbGZ0IiB3aWR0aD0iODciIGhlaWdodD0iMzQiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWUubmwvZW4vIiB0aXRsZT0iVFUgRWluZGhvdmVuIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWVpbmRob3Zlbi5zdmciIGFsdD0iVFUgRWluZGhvdmVuIiB3aWR0aD0iMTMwIiBoZWlnaHQ9IjI3IiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudXR3ZW50ZS5ubC9lbi8iIHRpdGxlPSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvdW5pdmVyc2l0eS1vZi10d2VudGUuc3ZnIiBhbHQ9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiB3aWR0aD0iODUiIGhlaWdodD0iMzEiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy53dXIubmwvIiB0aXRsZT0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXd1ci5zdmciIGFsdD0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiB3aWR0aD0iMTQ1IiBoZWlnaHQ9IjI5IiAvPjwvYT4gPC9kaXY+IDwvZGl2PiA8L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2JvdHRvbWJhciI+PHNwYW4gY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyX19jb3B5cmlnaHQiPjxzcGFuIGNsYXNzPSJmYmNwYXJ0Ij4mY29weTsgMjAyNCA0VFUuRmVkZXJhdGlvbjwvc3Bhbj48L3NwYW4+PHVsIGNsYXNzPSJmb290ZXJfX2JvdHRvbWJhcl9fbWVudSI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9jb250YWN0LyI+Q29udGFjdDwvYT48L2xpPjwvdWw+PC9kaXY+PC9kaXY+PHNjcmlwdCB0eXBlPSJhcHBsaWNhdGlvbi94LWhzb24iIGlkPSJ3aC1jb25zaWxpb2ZpZWxkcyI+aHNvbjp7Indoc2VhcmNodGh1bWJuYWlsIjoiaHR0cHM6Ly93d3cuNHR1Lm5sLy51Yy9pYTc3MzQ1NWEwMTAyNTRmODEwMDAwM2RlYTYwMWM2MDQ3MmUzYTZkMmNmZDYwODAxZTM0MDAxZjAwMDgxNDEvdGhlLWNvbmNlcHQtb2YtcmVhZGluZy1sb3ZlLTIwMjMtMTEtMjctMDUtMTItMDktdXRjLmpwZyJ9PC9zY3JpcHQ+PC9ib2R5PjwvaHRtbD4=
+ recorded_at: Wed, 02 Jan 2019 19:00:00 GMT
+- request:
+ method: get
+ uri: https://willma.soil.surf.nl/api/models
+ body:
+ encoding: UTF-8
+ string: "{}"
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ Content-Type:
+ - application/json
+ X-Api-Key:
+ - 77696c6c6d61-c5f9443d-e1eb-469a-a9ba-d7c9c733ebb3
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Wed, 05 Jun 2024 14:16:18 GMT
+ Server:
+ - gunicorn
+ Strict-Transport-Security:
+ - max-age=31556952
+ Content-Security-Policy:
+ - 'default-src ''self''; style-src ''self'' ''unsafe-inline'' *.bootstrapcdn.com
+ *.cloudflare.com fonts.googleapis.com estudybooks.surf.nl; script-src ''self''
+ ''unsafe-inline'' ''unsafe-eval'' webstats.surf.nl code.jquery.com *.bootstrapcdn.com
+ *.cloudflare.com *.aspnetcdn.com; img-src ''self'' data: blob: ''unsafe-inline''
+ https: data: webstats.surf.nl; font-src ''self'' data: *.bootstrapcdn.com
+ fonts.gstatic.com; connect-src ''self''; media-src ''self'' data: blob:'
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Xss-Protection:
+ - 1; mode=block;
+ X-Content-Type-Options:
+ - nosniff
+ Content-Type:
+ - application/json
+ Content-Length:
+ - '7139'
+ Vary:
+ - Cookie
+ Set-Cookie:
+ - session=.eJyNjcEKAjEMRP8lXnVhb5JfESkxjbqQdiVJvcj-u1XEiwh7GmZ4M_MAqTGFSunqgAdoVrEQC3qz81AV3aig0kn0HSVzRsp3qiw5t-CrakEPskjEPLcasP2zcrG53b4rK7GfsxW9XbebVzZ8ADj2koulKQOO4355AieiXTE.ZmBzMg.u3eHyshxjBZTyRPagRrhTNgeZUc;
+ HttpOnly; Path=/
+ body:
+ encoding: UTF-8
+ string: '[{"description":"Based on the fluffy animal, Meta AI (from Facebook)
+ trained this model first on a huge unorganized public dataset from the web.\n Afterwards,
+ the model was further finetuned on natural conversations to accommodate: for
+ an improved chat interaction.\n Approximately 0.12% of the training
+ data is Dutch and raises questions on the performance on Dutch questions.\n \n Release
+ date: July 2023","id":1,"name":"LLaMa-2 13B Chat","sequence":[{"model_id":8,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Based
+ on the fluffy animal, Meta AI (from Facebook) trained this model first on
+ a huge unorganized public dataset from the web.\n Afterwards, the
+ model was further finetuned on natural conversations to accommodate: for an
+ improved chat interaction. \n Approximately 0.12% of the training
+ data is Dutch and raises questions on the performance on Dutch questions.}\n \n Release
+ date: July 2023","id":2,"name":"LLaMa-2 7B Chat","sequence":[{"model_id":9,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"OpenAI
+ first released ChatGPT and shock the world due to its impressive performance
+ on producing relevant answers in a natural conversation.\n However,
+ there have been some data and privacy concerns. Hence, we for now offer ChatGPT-3.5
+ through this interface via the OpenAI API.\n Hereby, we circumvent
+ any gathering of personal information via tracking cookies on the ChatGPT
+ website. Note: OpenAI could still store \n and process the messages
+ themselves.\n \n Release date: November 2022 (continuous
+ update)","id":3,"name":"ChatGPT-3.5","sequence":[{"model_id":10,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Zephyr
+ is a series of language models that are trained to act as helpful assistants.\n We
+ found that removing the in-built alignment of these datasets boosted performance
+ on MT Bench and made the model more helpful. \n However, this means
+ that model is likely to generate problematic text when prompted to do so and
+ should only be used for educational and research purposes.\n \n Release
+ Date: October 2023","id":4,"name":"Zephyr 7B","sequence":[{"model_id":11,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Stable
+ diffusion is for images","id":5,"name":"Stable Diffusion","sequence":[{"model_id":12,"type":"images"}],"sequence_type":"ImageGenerationSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":false},{"description":"This
+ is a text-to-speech model trained by facebook. It converts the input message
+ to output audio.\n The quality of the output is only guaranteed
+ by dutch speech, as this is the attempted output language.\n In
+ the future we may add different languages.\n\n Release
+ Date: December 2023","id":7,"name":"Massively Multilingual Speech Dutch","sequence":[{"model_id":14,"type":"tts"}],"sequence_type":"AudioGenerationSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":false},{"description":"Currently
+ only implemented for API access.","id":8,"name":"Whisper speech-to-text Dutch","sequence":[{"model_id":15,"type":"stt"}],"sequence_type":"SingleSessionSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"","id":17,"name":"BramVanroy/GEITje-7B-ultra","sequence":[{"model_id":29,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:label:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"Mixtral
+ GPT-Q quantization","id":22,"name":"casperhansen/mixtral-instruct-awq","sequence":[{"model_id":35,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"sasd","id":23,"name":"asd","sequence":[{"template_id":6},{"model_id":11,"type":"text"}],"sequence_type":"PromptTemplateSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":1,"web_visible":false},{"description":"","id":24,"name":"synthetic
+ data","sequence":[{"model_id":38,"type":"search"},{"template_id":7},{"model_id":11,"type":"text"}],"sequence_type":"RAGSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc","user_id":68,"web_visible":true},{"description":"bozo","id":28,"name":"Rijgersberg/GEITje-7B-chat-v2","sequence":[{"model_id":42,"type":"search"},{"template_id":32},{"model_id":46,"type":"text"}],"sequence_type":"RAGSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"","id":29,"name":"rhysjones/phi-2-orange-v2","sequence":[{"model_id":47,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"Fietje
+ van T.V.","id":30,"name":"BramVanroy/fietje-2b-chat","sequence":[{"model_id":49,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":62,"web_visible":true},{"description":"","id":33,"name":"ibm-granite/granite-8b-code-instruct","sequence":[{"model_id":62,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":null,"user_id":64,"web_visible":true},{"description":"","id":34,"name":"codellama/CodeLlama-7b-Instruct-hf","sequence":[{"model_id":63,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":null,"user_id":63,"web_visible":true},{"description":"\n This
+ is a text-to-speech model trained by facebook. It converts the input message
+ to output audio.\n The quality of the output is only
+ guaranteed by english speech, as this is the attempted output language.\n In
+ the future we may add different languages.\n\n Release
+ Date: December 2023\n ","id":36,"name":"Massively Multilingual
+ Speech English","sequence":[{"model_id":65,"type":"tts"}],"sequence_type":"AudioGenerationSequence","sram_owner_regex":null,"user_id":null,"web_visible":false},{"description":"SURF.nl
+ chat obv Sitemap en Dienstbrochure","id":40,"name":"SURF.nl chat ","sequence":[{"template_id":43},{"model_id":10,"type":"text"}],"sequence_type":"PromptTemplateSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":85,"web_visible":true}]
+
+ '
+ recorded_at: Wed, 02 Jan 2019 19:00:00 GMT
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/4TU-meeting%20National%20Technology%20Strategy/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Wed, 05 Jun 2024 14:16:19 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Content-Length:
+ - '35025'
+ Connection:
+ - keep-alive
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Last-Modified:
+ - Wed, 05 Jun 2024 08:57:55 GMT
+ Vary:
+ - Accept-Encoding
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnQgc2l0ZWhlYWRlci0tbWVudWJhci10cmFuc2x1Y2VudCBwYWdlLS13aXRoYmFja2xpbmsiIGRhdGEtdHJhY2tpbmdpZD0iIj48aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PHRpdGxlPjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3k8L3RpdGxlPjxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzRUVS1tZWV0aW5nJTIwTmF0aW9uYWwlMjBUZWNobm9sb2d5JTIwU3RyYXRlZ3kvIj4KPCEtLQpSZWFsaXNhdGllOiDwn5K8IFdlYkhhcmUgYnYKICAgICAgICAgICAg8J+MkCBodHRwczovL3d3dy53ZWJoYXJlLm5sLwotLT4KPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xIiAvPjxsaW5rIHJlbD0iYXBwbGUtdG91Y2gtaWNvbiIgc2l6ZXM9IjE4MHgxODAiIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9hcHBsZS10b3VjaC1pY29uLTE4MHgxODAucG5nIiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi0zMngzMi5wbmciIHNpemVzPSIzMngzMiIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tOTZ4OTYucG5nIiBzaXplcz0iOTZ4OTYiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTE5NHgxOTQucG5nIiBzaXplcz0iMTk0eDE5NCIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2FuZHJvaWQtY2hyb21lLTE5MngxOTIucG5nIiBzaXplcz0iMTkyeDE5MiIgLz48bGluayByZWw9Im1hc2staWNvbiIgICAgICAgICAgICAgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL3NhZmFyaS1waW5uZWQtdGFiLnN2ZyIgY29sb3I9IiNmZjhiMzgiIC8+PG1ldGEgbmFtZT0idGhlbWUtY29sb3IiIGNvbnRlbnQ9IiNmZmZmZmYiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnR5cGUiIGNvbnRlbnQ9IndlYnNpdGUiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnNpdGVfbmFtZSIgY29udGVudD0iRmVkZXJhdGlvbiIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6dGl0bGUiIGNvbnRlbnQ9IjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3kiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlIiBjb250ZW50PSJodHRwczovL3d3dy40dHUubmwvLnVjL2llMTdmODA1NzAxMDIwODMxMTMwMDc3MDFkNDAxMDNiZDg1ZWZiNzc0YjVkNDA3MDFjM2IwMDQ3NjAyODAvbmF0aW9uYWxlLXRlY2hub2xvZ2llc3RyYXRlZ2llLmpwZyIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6d2lkdGgiIGNvbnRlbnQ9IjEyMDAiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlOmhlaWdodCIgY29udGVudD0iNjMwIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZSIgY29udGVudD0iaHR0cHM6Ly93d3cuNHR1Lm5sLy51Yy9pNzYwNTgxYWIwMTAyMDgzMTEzMDA3NzAxZDQwMTAzYmQ4NWVmYjc3NGI1ZDQwNzAxYzMyYzAxMmMwMTgwL25hdGlvbmFsZS10ZWNobm9sb2dpZXN0cmF0ZWdpZS5qcGciIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlOndpZHRoIiBjb250ZW50PSIzMDAiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlOmhlaWdodCIgY29udGVudD0iMzAwIiAvPjxzY3JpcHQgbm9tb2R1bGU+IGlmKCEhd2luZG93Lk1TSW5wdXRNZXRob2RDb250ZXh0ICYmICEhZG9jdW1lbnQuZG9jdW1lbnRNb2RlKWRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGFzc0xpc3QuYWRkKCJ1bnN1cHBvcnRlZC1icm93c2VyIik7PC9zY3JpcHQ+PHNjcmlwdCB0eXBlPSJhcHBsaWNhdGlvbi9qc29uIiBpZD0id2gtY29uZmlnIj57ImRlc2lnbmNkbnJvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS8iLCJkZXNpZ25yb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvIiwiZHRhcHN0YWdlIjoicHJvZHVjdGlvbiIsImltZ3Jvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvIiwiaXNsaXZlIjp0cnVlLCJsb2NhbGUiOiJlbi1VUyIsIm9iaiI6eyJuYXZwYXRoaXRlbSI6eyJsaW5rIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS80VFUtbWVldGluZyUyME5hdGlvbmFsJTIwVGVjaG5vbG9neSUyMFN0cmF0ZWd5LyIsInRpdGxlIjoiNFRVLW1lZXRpbmcgTmF0aW9uYWwgVGVjaG5vbG9neSBTdHJhdGVneSJ9fSwic2VydmVyIjo1MDUwMCwic2l0ZSI6e30sInNpdGVyb290IjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsInNvY2lhbGl0ZTpndG0iOnsiYSI6IkdUTS1XVFo1RlJRIiwiaCI6dHJ1ZSwibSI6ZmFsc2V9fTwvc2NyaXB0PjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iLy5hcC80dHUuc2l0ZS9hcC5jc3MiPjxzY3JpcHQgc3JjPSIvLmFwLzR0dS5zaXRlL2FwLm1qcyIgdHlwZT0ibW9kdWxlIiBhc3luYz48L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2xkK2pzb24iPnsiQGNvbnRleHQiOiJodHRwczovL3NjaGVtYS5vcmciLCJAdHlwZSI6IkJyZWFkY3J1bWJMaXN0IiwiaXRlbUxpc3RFbGVtZW50IjpbeyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iLCJuYW1lIjoiRmVkZXJhdGlvbiIsInBvc2l0aW9uIjoxfSx7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJuYW1lIjoiQWdlbmRhIiwicG9zaXRpb24iOjJ9LHsiQHR5cGUiOiJMaXN0SXRlbSIsIml0ZW0iOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzRUVS1tZWV0aW5nJTIwTmF0aW9uYWwlMjBUZWNobm9sb2d5JTIwU3RyYXRlZ3kvIiwibmFtZSI6IjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3kiLCJwb3NpdGlvbiI6M31dfTwvc2NyaXB0PjwvaGVhZD48Ym9keT48bm9zY3JpcHQ+PGlmcmFtZSBzcmM9Ii8vd3d3Lmdvb2dsZXRhZ21hbmFnZXIuY29tL25zLmh0bWw/aWQ9R1RNLVdUWjVGUlEiIGhlaWdodD0iMCIgd2lkdGg9IjAiIHN0eWxlPSJkaXNwbGF5Om5vbmU7dmlzaWJpbGl0eTpoaWRkZW4iPjwvaWZyYW1lPjwvbm9zY3JpcHQ+PGRpdiBjbGFzcz0ic3BjLW1vZGFsaXR5bGF5ZXIiPjwvZGl2PjxkaXYgaWQ9InNsaWRlbWVudS1jb250YWluZXIiPjxkaXYgaWQ9InNsaWRlbWVudSIgdGFiaW5kZXg9Ii0xIiAgICA+PGRpdiBjbGFzcz0ic2lkZWJhcl9faGVhZGVyIj4gPGEgY2xhc3M9InNpZGViYXJfX2hlYWRlcl9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9InNpZGViYXJfX2lkZW50aXR5X19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9InNpZGViYXJfX2lkZW50aXR5X19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48YnV0dG9uIGlkPSJzbGlkZW1lbnUtY2xvc2UiIGNsYXNzPSJzaWRlYmFyLWFjdGlvbi1jbG9zZSIgdHlwZT0iYnV0dG9uIiBhcmlhLWxhYmVsPSJDbG9zZSIgPjwvYnV0dG9uPjwvZGl2Pjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudSBzaWRlYmFyX19tZW51LS1sZXZlbDEiICA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIiA+SG9tZTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5SZXNlYXJjaDwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+QWJvdXQgb3VyIHJlc2VhcmNoPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvNHR1LWNlbnRyZXMvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+NFRVIENlbnRyZXM8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDMiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iID5BTUkgKE1hdGhlbWF0aWNzKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iID5CdWlsdCBFbnZpcm9ubWVudDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIiA+RGVzaWduIFVuaXRlZDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyIgPkVuZXJneTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIiA+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iID5IZWFsdGg8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iID5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIiA+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIiA+TklSSUNUIChJQ1QpPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyIgPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5IaWdoIFRlY2ggZm9yIGEgU3VzdGFpbmFibGUgRnV0dXJlPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iID5IVFNGIEkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIiA+SFRTRiBJSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtdmlkZW9zLyIgPkhUU0YgdmlkZW9zPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIiA+NFRVLlJlc2VhcmNoRGF0YTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvRUUtTkwvIiA+RWxlY3RyaWNhbCBFbmdpbmVlcmluZyBOZXRoZXJsYW5kczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkVkdWNhdGlvbjwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkFib3V0IG91ciBlZHVjYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iID5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIiA+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyIgPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uL2VkdWNhdGlvbnByb2dyYW1tZXMvIiA+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxidXR0b24gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIj48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5WYWxvcmlzYXRpb248L2J1dHRvbj48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QlMjBhY3Rpdml0aWVzLyIgPjRUVS5JTVBBQ1Q8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyIgPkFib3V0IDRUVS5JbXBhY3Q8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3RhcnR1cCUyMG1pc3Npb25zLyIgPlN0YXJ0dXAgbWlzc2lvbnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPk1lZGlhPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL2luc2lnaHRmdWwtaW5ub3ZhdG9ycy8iID5JbnNpZ2h0ZnVsIElubm92YXRvcnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvU3Bpbi1vZmYlMjBzZXJpZS8iID5TcGluLU9mZiBTdG9yaWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdHVkZW50JTIwY2hhbGxlbmdlcy8iID5TdHVkZW50IGNoYWxsZW5nZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vVHVzc2VucGFnaW5hJTIwdm9vcmFmZ2FhbmQlMjBhYW4lMjBTdGFydHVwJTIwU3VwcG9ydC8iID5BYm91dCBTdGFydHVwIFN1cHBvcnQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5OZXdzPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSAgc2lkZW1haW5tZW51X19pdGVtLS1leHBhbmQgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX3NlbGVjdGVkICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkFib3V0IDRUVTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LzR0dS1pbi0xLW1pbnV0ZS8iID40VFUgaW4gb25seSAxIG1pbnV0ZTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2ZhY3RzLWZpZ3VyZXMvIiA+RmFjdHMgYW5kIGZpZ3VyZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9vcmdhbmlzYXRpb24vIiA+T3JnYW5pc2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvcHVibGljYXRpb25zLyIgPlB1YmxpY2F0aW9uczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2FsdW1uaS8iID5BbHVtbmk8L2E+PC9saT48L3VsPjwvbGk+PC91bD48bmF2IGNsYXNzPSJzaWRlYmFyX19sYW5ndWFnZXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC8iPk5MPC9hPiB8IDxzcGFuIGNsYXNzPSJzZWxlY3RlZCI+RU48L3NwYW4+PC9uYXY+PG5hdiBjbGFzcz0ic2lkZWJhcl9fc2Vjb25kYXJ5bGlua3MiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9jb250YWN0LyI+Q29udGFjdDwvYT48L25hdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wLWJhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyLWJhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3AiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX2NvbnRlbnQiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX2lkZW50aXR5Ij48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19zbG9nYW4iPlBhcnQgb2YgdGhlIDxidXR0b24gY2xhc3M9ImhlYWRlci10b3BfX3RvZ2dsZWV4cGxvcmVwYW5lbCI+NFRVLkZlZGVyYXRpb248L2J1dHRvbj48L2Rpdj48YSBjbGFzcz0iaGVhZGVyLXRvcF9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fb3JnYW5pemF0aW9ucyI+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZGVsZnQubmwvZW4vIiB0aXRsZT0iVFUgRGVsZnQiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZGVsZnQuc3ZnIiBhbHQ9IlRVIERlbGZ0IiB3aWR0aD0iMTAwIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuLyIgdGl0bGU9IlRVIEVpbmRob3ZlbiIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1laW5kaG92ZW4uc3ZnIiBhbHQ9IlRVIEVpbmRob3ZlbiIgd2lkdGg9IjEzMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnV0d2VudGUubmwvZW4vIiB0aXRsZT0iVW5pdmVyc2l0eSBvZiBUd2VudGUiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL3VuaXZlcnNpdHktb2YtdHdlbnRlLnN2ZyIgYWx0PSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgd2lkdGg9IjEwMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3Lnd1ci5ubC8iIHRpdGxlPSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28td3VyLnN2ZyIgYWx0PSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiIHdpZHRoPSIxMzIiIC8+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyIj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fY29udGVudCI+PGEgY2xhc3M9ImhlYWRlci1tZW51YmFyX19pZGVudGl0eSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zcGFjZXIiPjwvZGl2PjxuYXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19tZW51YmFyIiBhcmlhLWxhYmVsPSJNYWluIj48dWwgY2xhc3M9InNwYy1tZW51YmFyIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIgPkhvbWU8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPlJlc2VhcmNoPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5BYm91dCBvdXIgcmVzZWFyY2g8L2E+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLzR0dS1jZW50cmVzLyIgPjRUVSBDZW50cmVzPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIiA+QU1JIChNYXRoZW1hdGljcyk8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIiA+QnVpbHQgRW52aXJvbm1lbnQ8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyIgPkRlc2lnbiBVbml0ZWQ8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iID5FbmVyZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyIgPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIiA+SGVhbHRoPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIiA+SGlnaC1UZWNoIE1hdGVyaWFsczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyIgPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyIgPk5JUklDVCAoSUNUKTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iID5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic3BjLW1lbnViYXItLWhhc3N1Yml0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS8iID5IaWdoIFRlY2ggZm9yIGEgU3VzdGFpbmFibGUgRnV0dXJlPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iID5IVFNGIEkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIiA+SFRTRiBJSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtdmlkZW9zLyIgPkhUU0YgdmlkZW9zPC9hPjwvbGk+PC91bD48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyIgPjRUVS5SZXNlYXJjaERhdGE8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9FRS1OTC8iID5FbGVjdHJpY2FsIEVuZ2luZWVyaW5nIE5ldGhlcmxhbmRzPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkVkdWNhdGlvbjwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkFib3V0IG91ciBlZHVjYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIiA+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iID40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyIgPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi9lZHVjYXRpb25wcm9ncmFtbWVzLyIgPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSIiID5WYWxvcmlzYXRpb248L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0JTIwYWN0aXZpdGllcy8iID40VFUuSU1QQUNUPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIiA+QWJvdXQgNFRVLkltcGFjdDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3RhcnR1cCUyMG1pc3Npb25zLyIgPlN0YXJ0dXAgbWlzc2lvbnM8L2E+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvIiA+TWVkaWE8L2E+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwzIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvaW5zaWdodGZ1bC1pbm5vdmF0b3JzLyIgPkluc2lnaHRmdWwgSW5ub3ZhdG9yczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9TcGluLW9mZiUyMHNlcmllLyIgPlNwaW4tT2ZmIFN0b3JpZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdHVkZW50JTIwY2hhbGxlbmdlcy8iID5TdHVkZW50IGNoYWxsZW5nZXM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1R1c3NlbnBhZ2luYSUyMHZvb3JhZmdhYW5kJTIwYWFuJTIwU3RhcnR1cCUyMFN1cHBvcnQvIiA+QWJvdXQgU3RhcnR1cCBTdXBwb3J0PC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VsZWN0ZWQiPkFnZW5kYTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyIgPkFib3V0IDRUVTwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LzR0dS1pbi0xLW1pbnV0ZS8iID40VFUgaW4gb25seSAxIG1pbnV0ZTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9mYWN0cy1maWd1cmVzLyIgPkZhY3RzIGFuZCBmaWd1cmVzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L29yZ2FuaXNhdGlvbi8iID5PcmdhbmlzYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvcHVibGljYXRpb25zLyIgPlB1YmxpY2F0aW9uczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvYWx1bW5pLyIgPkFsdW1uaTwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48L3VsPjwvbmF2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zcGFjZXIiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19sYW5ndWFnZXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC8iPk5MPC9hPnw8c3Bhbj5FTjwvc3Bhbj48L2Rpdj48Zm9ybSBhY3Rpb249Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9zZWFyY2gvIiBtZXRob2Q9IkdFVCIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2h3cmFwcGVyIiBhdXRvY29tcGxldGU9Im9mZiIgPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2gtaW5wdXQtYW5kLXN1Z2dlc3Rpb25zLXdyYXBwZXIiPjxpbnB1dCBpZD0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiBuYW1lPSJxdWVyeSIgZGF0YS1zdWdnZXN0PSI0dHU6Y29ycG9yYXRlX2VuIiBkYXRhLXN1Z2dlc3RwYXJlbnQ9InBhcmVudCIgcGxhY2Vob2xkZXI9IlpvZWtlbiIgYXJpYS1sYWJlbD0iWm9la2VuIiB0eXBlPSJzZWFyY2giIC8+PC9kaXY+PGxhYmVsIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoIiBmb3I9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgdGFiaW5kZXg9Ii0xIiA+PHNwYW4gY2xhc3M9ImZhciBmYS1zZWFyY2giPjwvc3Bhbj48L2xhYmVsPjwvZm9ybT48YnV0dG9uIGlkPSJoZWFkZXItbWVudWJhcl9zaWRlYmFydG9nZ2xlIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3Nob3dzaWRlbWFpbm1lbnUgc2lkZWJhci1hY3Rpb24tdG9nZ2xlIiBhcmlhLWxhYmVsPSJPcGVuIG1lbnUiIGFyaWEtZXhwYW5kZWQ9ImZhbHNlIiBhcmlhLWNvbnRyb2xzPSJzbGlkZW1lbnUiID48c3BhbiBjbGFzcz0iZmFyIGZhLWJhcnMiPjwvc3Bhbj48L2J1dHRvbj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWwiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fdG9wYmFyIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2Nsb3NlIj5DbG9zZTwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1ucyI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19hZGRyZXNzIHJ0ZGNvbnRlbnQiPjxwIGNsYXNzPSJoZWFkaW5nIj40VFUuRmVkZXJhdGlvbjwvcD48cCBjbGFzcz0ibm9ybWFsIj4rMzEoMCk2IDQ4IDI3IDU1IDYxPC9wPjxwIGNsYXNzPSJub3JtYWwiPjxhIGhyZWY9Im1haWx0bzpwcm9qZWN0bGVpZGVyQDR0dS5ubCI+c2VjcmV0YXJpc0A0dHUubmw8L2E+PC9wPjxwIGNsYXNzPSJub3JtYWwiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxiPldlYnNpdGU6IDRUVS5ubDwvYj48L2E+PC9wPjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uIGV4cGxvcmVwYW5lbF9fY29sdW1uLS1tYW55aXRlbXMiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuUmVzZWFyY2g8L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zIGV4cGxvcmVwYW5lbF9faXRlbXMtLW1hbnlpdGVtcyAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIj48c3Bhbj5BcHBsaWVkIE1hdGhlbWF0aWNzIEluc3RpdHV0ZTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIj48c3Bhbj5CdWlsdCBFbnZpcm9ubWVudDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyI+PHNwYW4+RGVzaWduIFVuaXRlZDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iPjxzcGFuPkVuZXJneTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyI+PHNwYW4+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIj48c3Bhbj5IZWFsdGg8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIj48c3Bhbj5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyI+PHNwYW4+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyI+PHNwYW4+TklSSUNUIChJQ1QpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iPjxzcGFuPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iPjxzcGFuPlJlc2VhcmNoRGF0YTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iPjxzcGFuPkhUU0YgSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iPjxzcGFuPkhUU0YgSUkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uICI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5FZHVjYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zICAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIj48c3Bhbj5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyI+PHNwYW4+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iPjxzcGFuPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyd2lqcy9vbmRlcndpanNwcm9ncmFtbWFzLyI+PHNwYW4+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uICI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5WYWxvcmlzYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zICAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iPjxzcGFuPjRUVS5JTVBBQ1Q8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vdGVjaC10cmFuc2Zlci5ubC9lbi8iPjxzcGFuPlRoZW1hdGljIFRlY2hub2xvZ3kgVHJhbnNmZXI8L3NwYW4+PC9hPjxhIGhyZWY9IiI+PHNwYW4+U3Bpbi1vZmYgU3Rvcmllczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly80dHVpbXBhY3RjaGFsbGVuZ2UubmwvIj48c3Bhbj40VFUgSW1wYWN0IENoYWxsZW5nZTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX2JhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19zbGlkZXNob3cgY2Fycm91c2VsX192aWV3cG9ydCBjYXJyb3VzZWxfX2RyYWdhcmVhICI+PHN0eWxlPkBtZWRpYSAobWF4LXdpZHRoOiA3NjdweCl7LmhlYWRlcnNsaWRlMHtiYWNrZ3JvdW5kLXBvc2l0aW9uOiA1NC4xNjY3JSA2NS41MTM0JTtiYWNrZ3JvdW5kLWNvbG9yOiAjRkFGQ0ZEO2JhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2k0NDY2ZDNlMjAxMDIwODMxMTMwMDc3MDFkNDAxMDNiZDg1ZWZiNzc0YjVkNDA4MDFlMzQwMGIwMDA3ODE0Ni9uYXRpb25hbGUtdGVjaG5vbG9naWVzdHJhdGVnaWUuanBnKTt9fUBtZWRpYSAobWluLXdpZHRoOiA3NjhweCl7LmhlYWRlcnNsaWRlMHtiYWNrZ3JvdW5kLXBvc2l0aW9uOiA1NC4xNjY3JSA2NS41MzU3JTtiYWNrZ3JvdW5kLWNvbG9yOiAjRkFGQ0ZEO2JhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2kwYjBjZjg2YjAxMDIwODMxMTMwMDc3MDFkNDAxMDNiZDg1ZWZiNzc0YjVkNDA4MDFlMzQwMGI2MDA0ODE0Ni9uYXRpb25hbGUtdGVjaG5vbG9naWVzdHJhdGVnaWUuanBnKTt9fTwvc3R5bGU+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlIGNhcnJvdXNlbF9fY2VsbCBhY3RpdmVzbGlkZSBoZWFkZXJzbGlkZTAgIiBkYXRhLXNsaWRlc2hvdy1lbGVtZW50cz0icGFnZS1oZWFkZXJfX3NsaWRlMF9fY29udGVudCIgc3R5bGU9IiIgPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19jb250ZW50Ij48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fbWV0YSI+PGgxIGNsYXNzPSJwYWdlLWhlYWRlcl9fdGl0bGUiPjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3k8L2gxPjxkaXYgY2xhc3M9InBhZ2VoZWFkZXJfX2RhdGUiPldlZG5lc2RheSAzIEp1bHkgMjAyNCAvIDEyLjMwIC0gMTguMDA8L2Rpdj48L2Rpdj48L2Rpdj48bWFpbiBjbGFzcz0icGFnZV9fYm9keSAgIj48Zm9ybSBpZD0iIiAgY2xhc3M9InBhZ2VfX2hlYWRlcmZpbHRlcnMgICAiPjwvZm9ybT48ZGl2IGNsYXNzPSJwYWdlX19jb250ZW50YXJlYSBwYWdlX19jb250ZW50YXJlYS0tcnRkZG9jICAgaGVhZGVyaXNvcGFxdWUgIj48ZGl2IGNsYXNzPSJkZWVwbGlua3Mtd3JhcHBlciI+PGRpdiBjbGFzcz0iZGVlcGxpbmtzIj48YSBjbGFzcz0icGFnZS1iYWNrbGluayIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFsbCBldmVudHM8L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1jb250ZW50c3RhcnQiPjwvZGl2PjwhLS13aF9jb25zaWxpb19jb250ZW50LS0+PHAgY2xhc3M9Im5vcm1hbCI+PGI+NFRVLW1lZXRpbmcgb24gdGhlIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3kgKE5UUykgLSBsb2NhdGlvbiBVdHJlY2h0PC9iPjwvcD48cCBjbGFzcz0ibm9ybWFsIj7CoDwvcD48cCBjbGFzcz0ibm9ybWFsIj48Yj5XaGF0IGFuZCBmb3Igd2hvbTo8L2I+PC9wPjxwIGNsYXNzPSJub3JtYWwiPlRoZSBtZWV0aW5nIGlzIGludGVuZGVkIGZvciA8Yj5zY2llbnRpc3RzPC9iPiB3b3JraW5nIG9uIGkpIE9wdGljYWwgc3lzdGVtcyBhbmQgaW50ZWdyYXRlZCBwaG90b25pY3MsIGlpKSBJbWFnaW5nIHRlY2hub2xvZ2llcywgb3IgaWlpKSAoRW5lcmd5KSBtYXRlcmlhbHMgYW5kIGZvciA8Yj5tYW5hZ2VycyBhbmQgc3VwcG9ydCBvZmZpY2VyczwvYj4gb2YgcmVzZWFyY2ggb24ga2V5IHRlY2hub2xvZ2llcy48L3A+PHAgY2xhc3M9Im5vcm1hbCI+QWZ0ZXIgYSBzaG9ydCBwbGVuYXJ5IGluZm9ybWF0aW9uIHNlc3Npb24sIHdlIHNwbGl0IHVwIGFsb25nIHRoZXNlIHRocmVlIHRoZW1lcyBhbmQgd291bGQgbGlrZSB0byBnZXQgeW91ciBpbnB1dCBvbiBob3cgdG8gZ2V0IHRvIGNvbmNyZXRlIGFjdGlvbiBhZ2VuZGHigJlzIGZvciB0aGVzZSB0b3BpY3MuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgdGhlIGF0dGFjaGVkIGludml0YXRpb24uPC9wPjxwIGNsYXNzPSJub3JtYWwiPsKgPC9wPjxwIGNsYXNzPSJub3JtYWwiPjxiPlByYWN0aWNhbCBpbmZvcm1hdGlvbjo8L2I+PC9wPjxwIGNsYXNzPSJub3JtYWwiPkRhdGU6wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBXZWRuZXNkYXksIEp1bHkgMyAyMDI0LCAxMy4zMC0xNyBocnMgKGx1bmNoIGF0IDEyLjMwOyBkcmlua3MgYXQgMTcgaHJzKTwvcD48cCBjbGFzcz0ibm9ybWFsIj5Mb2NhdGlvbjogwqDCoMKgwqDCoMKgwqDCoCBCYXNlY2FtcCwgTmlqdmVyaGVpZHN3ZWcgMTZBLCAzNTM0IEFNIFV0cmVjaHQgKDxhIGhyZWY9Imh0dHBzOi8vYmFzZWNhbXB1dHJlY2h0Lm5sLyI+aHR0cHM6Ly9iYXNlY2FtcHV0cmVjaHQubmw8L2E+KTwvcD48cCBjbGFzcz0ibm9ybWFsIj7CoDwvcD48cCBjbGFzcz0ibm9ybWFsIj48Yj5SZWdpc3RyYXRpb246PC9iPjwvcD48cCBjbGFzcz0ibm9ybWFsIj5JZiB5b3Ugd2FudCB0byBqb2luIHRoaXMgbWVldGluZywgcGxlYXNlIHJlZ2lzdGVyIGJ5IGZpbGxpbmcgaW4gdGhpcyA8YSBocmVmPSJodHRwczovL2Zvcm1zLmdsZS9xTkxoYmJUNmh6dGN5VkNIQSI+PGI+R29vZ2xlIEZvcm08L2I+PC9hPjxiPiA8L2I+PGk+YmVmb3JlIFR1ZXNkYXkgSnVuZSAyNSE8L2k+PC9wPjxwIGNsYXNzPSJub3JtYWwiPsKgPC9wPjxwIGNsYXNzPSJub3JtYWwiPldlIGhhdmUgbWFkZSBhIG5pY2UgPGI+Y29ubmVjdGlvbjwvYj4gd2l0aCB0aGUgPGI+SG9sbGFuZCBIaWdoIFRlY2ggTmV0d29yayBFdmVudDwvYj4gYW5kIHdpbGwgPGI+am9pbiB0aGVtIGF0IDE3IGhycyBmb3IgZHJpbmtzLCBmb29kIChmb29kIHRydWNrcyEpIGFuZCBuZXR3b3JraW5nLjwvYj48L3A+PHAgY2xhc3M9Im5vcm1hbCI+SWYgeW91IHdhbnQgdG8gam9pbiB0aGUgZHJpbmtzICZhbXA7IGZvb2QgYXQgMTcgaHJzLCBwbGVhc2UgcmVnaXN0ZXIgPGI+YWxzbyA8L2I+PGEgaHJlZj0iaHR0cHM6Ly93d3cuYWFubWVsZGVyLm5sL2hodG5ldHdlcmtldmVudDIwMjQvYWFubWVsZGVuIj48Yj5oZXJlPC9iPjwvYT48Yj4uPC9iPjwvcD48cCBjbGFzcz0ibm9ybWFsIj48Yj7CoDwvYj48L3A+PHAgY2xhc3M9Im5vcm1hbCI+QmVzdCByZWdhcmRzLCBhbHNvIG9uIGJlaGFsZiBvZiBFWkssIEhIVCwgTldPLDwvcD48IS0tL3doX2NvbnNpbGlvX2NvbnRlbnQtLT48ZGl2IGNsYXNzPSJwYWdlX19iYWxsb29uIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXIiPjxkaXYgY2xhc3M9InBhZ2VfX2Zvb3Rlcl9fY29udGVudCBuYXZwYXRoIj48YSBjbGFzcz0ibmF2cGF0aF9faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT48c3BhbiBjbGFzcz0ibmF2cGF0aF9fc2VwZXJhdG9yIj48L3NwYW4+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19pdGVtIGNydW1icGF0aC0tY3VycmVudHBhZ2UiPjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3k8L3NwYW4+PC9kaXY+PC9kaXY+PC9kaXY+PC9tYWluPjxkaXYgY2xhc3M9ImZvb3RlciI+PGRpdiBjbGFzcz0iZm9vdGVyX19wYW5lbCI+PGRpdiBjbGFzcz0iZm9vdGVyX19pZGVudGl0eSI+PGRpdiBjbGFzcz0iZm9vdGVyX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fc2l0ZXRpdGxlIj5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PCEtLSBGSVhNRTogdXNlIGFyaWEtaGlkZGVuPSJ0cnVlIiBiZWNhdXNlIGl0J3MgYSBkdXBsaWNhdGUgb2YgdGhlIGl0ZW1zIG9uIHRoZSBtZW51IGJhciA/IC0tPiA8bmF2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjEgZm9vdGVyX19tYWlubWVudSIgYXJpYS1sYWJlbD0iTWFpbiI+IDx1bD4gICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPkhvbWU8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iPlJlc2VhcmNoPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyI+RWR1Y2F0aW9uPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSIiPlZhbG9yaXNhdGlvbjwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iPk5ld3M8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvIj5BYm91dCA0VFU8L2E+IDwvbGk+ICAgPC91bD4gPC9uYXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjIiPiA8aW5wdXQgdHlwZT0iY2hlY2tib3giIG5hbWU9ImZvb3RlcmNvbHVtbiIgaWQ9ImZvb3Rlcl9fY29sdW1uMl9fZXhwYW5kIiAvPiA8bGFiZWwgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIiBmb3I9ImZvb3Rlcl9fY29sdW1uMl9fZXhwYW5kIj5Db250YWN0PC9sYWJlbD4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgcnRkY29udGVudCI+IDxwIGNsYXNzPSJub3JtYWwiPiszMSgwKTYgODMgMjIgNTAgNTk8YnIgLz48YSBocmVmPSJtYWlsdG86cHJvamVjdGxlaWRlckA0dHUubmwiPnNlY3JldGFyaXNANHR1Lm5sPC9hPjwvcD4gPC9kaXY+IDwvZGl2PiAgIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMyI+IDxpbnB1dCB0eXBlPSJjaGVja2JveCIgbmFtZT0iZm9vdGVyY29sdW1uIiBpZD0iZm9vdGVyX19jb2x1bW4zX19leHBhbmQiIC8+IDxsYWJlbCBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciIGZvcj0iZm9vdGVyX19jb2x1bW4zX19leHBhbmQiPlBvc3RhZHJlczwvbGFiZWw+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IHJ0ZGNvbnRlbnQiPiA8cCBjbGFzcz0ibm9ybWFsIj40VFUuRmVkZXJhdGllPGJyIC8+UG9zdGJ1cyA1PGJyIC8+MjYwMCBBQSBEZWxmdDwvcD4gPC9kaXY+IDwvZGl2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW40Ij4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbXNfX2dyb3VwIj4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciPkZvbGxvdyB1czwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IGZvb3Rlcl9fc29jaWFsaXRlbXMgIj48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3R3aXR0ZXIuY29tLzRUVUZlZGVyYXRpb24iIHRpdGxlPSJUd2l0dGVyIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS10d2l0dGVyIj48L3NwYW4+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21wYW55LzQtdHUtZmVkZXJhdGlvbi8iIHRpdGxlPSJMaW5rZWRJbiIgPjxzcGFuIGNsYXNzPSJmYWIgZmEtbGlua2VkaW4taW4iPjwvc3Bhbj48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vY2hhbm5lbC9VQ01rcWhqeDJXMWhOUnd5c1J2V0VYd1EiIHRpdGxlPSJZb3V0dWJlIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS15b3V0dWJlIj48L3NwYW4+PC9hPjwvZGl2PiA8L2Rpdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcl9fZ3JvdXAiPiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmcgZm9vdGVyX19jb2x1bW5fX2hlYWRpbmctLW5ld3NsZXR0ZXIgIj5TdGF5IHVwLXRvLWRhdGU8L2Rpdj48Zm9ybSBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwIHdocGx1Z2luLW5ld3NsZXR0ZXItc3Vic2NyaXB0aW9uICAiIGRhdGEtbmV3c2xldHRlci1saXN0PSJTVUJTXzRUVV9DT1JQT1JBVEVfTklFVVdTQlJJRUYiID48aW5wdXQgbmFtZT0iZW1haWwiIHBsYWNlaG9sZGVyPSJTaWduIHVwIGZvciBvdXIgbmV3c2xldHRlciIgLz48YnV0dG9uIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Ym1pdCIgdHlwZT0ic3VibWl0IiBuYW1lPSJzdWJtaXRidXR0b24iIGFyaWEtbGFiZWw9IlN1YnNjcmliZSI+PHNwYW4gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VibWl0X19pY29uIGZhciBmYS1lbnZlbG9wZSI+PC9zcGFuPjwvYnV0dG9uPjwvZm9ybT48ZGl2IGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Y2Nlc3MiPlRoYW5rcyBmb3Igc3Vic2NyaWJpbmcgdG8gb3VyIG5ld3NsZXR0ZXIuPC9kaXY+ICA8L2Rpdj4gPC9kaXY+IDxociBjbGFzcz0iZm9vdGVyX19kaXZpZGVyIiAvPiA8ZGV0YWlscyBjbGFzcz0iZm9vdGVyX19leHBsb3JlIj48c3VtbWFyeT48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX3RvZ2dsZV9fY2xvc2VkdGV4dCI+UGFydCBvZiB0aGUgPHNwYW4gY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fbmFtZSI+NFRVLkZlZGVyYXRpb248L3NwYW4+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX190b2dnbGVfX29wZW50ZXh0Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2xvc2UiPkNsb3NlPC9kaXY+PC9kaXY+PC9zdW1tYXJ5PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsIj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5SZXNlYXJjaDwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iPjxzcGFuPkFwcGxpZWQgTWF0aGVtYXRpY3MgSW5zdGl0dXRlPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iPjxzcGFuPkJ1aWx0IEVudmlyb25tZW50PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIj48c3Bhbj5EZXNpZ24gVW5pdGVkPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyI+PHNwYW4+RW5lcmd5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIj48c3Bhbj5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iPjxzcGFuPkhlYWx0aDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iPjxzcGFuPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIj48c3Bhbj5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIj48c3Bhbj5OSVJJQ1QgKElDVCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyI+PHNwYW4+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyI+PHNwYW4+UmVzZWFyY2hEYXRhPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyI+PHNwYW4+SFRTRiBJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyI+PHNwYW4+SFRTRiBJSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2NhdGVnb3J5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuRWR1Y2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyI+PHNwYW4+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iPjxzcGFuPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIj48c3Bhbj5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcndpanMvb25kZXJ3aWpzcHJvZ3JhbW1hcy8iPjxzcGFuPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5WYWxvcmlzYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iPjxzcGFuPjRUVS5JTVBBQ1Q8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vdGVjaC10cmFuc2Zlci5ubC9lbi8iPjxzcGFuPlRoZW1hdGljIFRlY2hub2xvZ3kgVHJhbnNmZXI8L3NwYW4+PC9hPjxhIGhyZWY9IiI+PHNwYW4+U3Bpbi1vZmYgU3Rvcmllczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly80dHVpbXBhY3RjaGFsbGVuZ2UubmwvIj48c3Bhbj40VFUgSW1wYWN0IENoYWxsZW5nZTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PC9kZXRhaWxzPiA8ZGl2IGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzIj4gPGRpdiBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbXMiPiA8YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVkZWxmdC5ubC9lbi8iIHRpdGxlPSJUVSBEZWxmdCIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1kZWxmdC5zdmciIGFsdD0iVFUgRGVsZnQiIHdpZHRoPSI4NyIgaGVpZ2h0PSIzNCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZS5ubC9lbi8iIHRpdGxlPSJUVSBFaW5kaG92ZW4iID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZWluZGhvdmVuLnN2ZyIgYWx0PSJUVSBFaW5kaG92ZW4iIHdpZHRoPSIxMzAiIGhlaWdodD0iMjciIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy51dHdlbnRlLm5sL2VuLyIgdGl0bGU9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci91bml2ZXJzaXR5LW9mLXR3ZW50ZS5zdmciIGFsdD0iVW5pdmVyc2l0eSBvZiBUd2VudGUiIHdpZHRoPSI4NSIgaGVpZ2h0PSIzMSIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3Lnd1ci5ubC8iIHRpdGxlPSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28td3VyLnN2ZyIgYWx0PSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiIHdpZHRoPSIxNDUiIGhlaWdodD0iMjkiIC8+PC9hPiA8L2Rpdj4gPC9kaXY+IDwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyIj48c3BhbiBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXJfX2NvcHlyaWdodCI+PHNwYW4gY2xhc3M9ImZiY3BhcnQiPiZjb3B5OyAyMDI0IDRUVS5GZWRlcmF0aW9uPC9zcGFuPjwvc3Bhbj48dWwgY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyX19tZW51Ij48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2NvbnRhY3QvIj5Db250YWN0PC9hPjwvbGk+PC91bD48L2Rpdj48L2Rpdj48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL3gtaHNvbiIgaWQ9IndoLWNvbnNpbGlvZmllbGRzIj5oc29uOnsid2hzZWFyY2h0aHVtYm5haWwiOiJodHRwczovL3d3dy40dHUubmwvLnVjL2k2ZDYyMmJkZjAxMDIwYTMxMTMwMDc3MDFkNDAxYzFlMjEyZWVmOGY0YTdjNzA4MDFlMzQwMDFmMDAwODE0MS9lemstbnRzLnBuZy5qcGcifTwvc2NyaXB0PjwvYm9keT48L2h0bWw+
+ recorded_at: Wed, 02 Jan 2019 19:00:00 GMT
+- request:
+ method: get
+ uri: https://willma.soil.surf.nl/api/models
+ body:
+ encoding: UTF-8
+ string: "{}"
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ Content-Type:
+ - application/json
+ X-Api-Key:
+ - 77696c6c6d61-c5f9443d-e1eb-469a-a9ba-d7c9c733ebb3
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Wed, 05 Jun 2024 14:16:19 GMT
+ Server:
+ - gunicorn
+ Strict-Transport-Security:
+ - max-age=31556952
+ Content-Security-Policy:
+ - 'default-src ''self''; style-src ''self'' ''unsafe-inline'' *.bootstrapcdn.com
+ *.cloudflare.com fonts.googleapis.com estudybooks.surf.nl; script-src ''self''
+ ''unsafe-inline'' ''unsafe-eval'' webstats.surf.nl code.jquery.com *.bootstrapcdn.com
+ *.cloudflare.com *.aspnetcdn.com; img-src ''self'' data: blob: ''unsafe-inline''
+ https: data: webstats.surf.nl; font-src ''self'' data: *.bootstrapcdn.com
+ fonts.gstatic.com; connect-src ''self''; media-src ''self'' data: blob:'
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Xss-Protection:
+ - 1; mode=block;
+ X-Content-Type-Options:
+ - nosniff
+ Content-Type:
+ - application/json
+ Content-Length:
+ - '7139'
+ Vary:
+ - Cookie
+ Set-Cookie:
+ - session=.eJyNjcEKAjEMRP8lXnVhb5JfESkxjbqQdiVJvcj-u1XEiwh7GmZ4M_MAqTGFSunqgAdoVrEQC3qz81AV3aig0kn0HSVzRsp3qiw5t-CrakEPskjEPLcasP2zcrG53b4rK7GfsxW9XbebVzZ8ADj2koulKQOO4355AieiXTE.ZmBzMw.4GkyMCqKpiZo5501oc_GyauOmbs;
+ HttpOnly; Path=/
+ body:
+ encoding: UTF-8
+ string: '[{"description":"Based on the fluffy animal, Meta AI (from Facebook)
+ trained this model first on a huge unorganized public dataset from the web.\n Afterwards,
+ the model was further finetuned on natural conversations to accommodate: for
+ an improved chat interaction.\n Approximately 0.12% of the training
+ data is Dutch and raises questions on the performance on Dutch questions.\n \n Release
+ date: July 2023","id":1,"name":"LLaMa-2 13B Chat","sequence":[{"model_id":8,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Based
+ on the fluffy animal, Meta AI (from Facebook) trained this model first on
+ a huge unorganized public dataset from the web.\n Afterwards, the
+ model was further finetuned on natural conversations to accommodate: for an
+ improved chat interaction. \n Approximately 0.12% of the training
+ data is Dutch and raises questions on the performance on Dutch questions.}\n \n Release
+ date: July 2023","id":2,"name":"LLaMa-2 7B Chat","sequence":[{"model_id":9,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"OpenAI
+ first released ChatGPT and shock the world due to its impressive performance
+ on producing relevant answers in a natural conversation.\n However,
+ there have been some data and privacy concerns. Hence, we for now offer ChatGPT-3.5
+ through this interface via the OpenAI API.\n Hereby, we circumvent
+ any gathering of personal information via tracking cookies on the ChatGPT
+ website. Note: OpenAI could still store \n and process the messages
+ themselves.\n \n Release date: November 2022 (continuous
+ update)","id":3,"name":"ChatGPT-3.5","sequence":[{"model_id":10,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Zephyr
+ is a series of language models that are trained to act as helpful assistants.\n We
+ found that removing the in-built alignment of these datasets boosted performance
+ on MT Bench and made the model more helpful. \n However, this means
+ that model is likely to generate problematic text when prompted to do so and
+ should only be used for educational and research purposes.\n \n Release
+ Date: October 2023","id":4,"name":"Zephyr 7B","sequence":[{"model_id":11,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Stable
+ diffusion is for images","id":5,"name":"Stable Diffusion","sequence":[{"model_id":12,"type":"images"}],"sequence_type":"ImageGenerationSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":false},{"description":"This
+ is a text-to-speech model trained by facebook. It converts the input message
+ to output audio.\n The quality of the output is only guaranteed
+ by dutch speech, as this is the attempted output language.\n In
+ the future we may add different languages.\n\n Release
+ Date: December 2023","id":7,"name":"Massively Multilingual Speech Dutch","sequence":[{"model_id":14,"type":"tts"}],"sequence_type":"AudioGenerationSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":false},{"description":"Currently
+ only implemented for API access.","id":8,"name":"Whisper speech-to-text Dutch","sequence":[{"model_id":15,"type":"stt"}],"sequence_type":"SingleSessionSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"","id":17,"name":"BramVanroy/GEITje-7B-ultra","sequence":[{"model_id":29,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:label:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"Mixtral
+ GPT-Q quantization","id":22,"name":"casperhansen/mixtral-instruct-awq","sequence":[{"model_id":35,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"sasd","id":23,"name":"asd","sequence":[{"template_id":6},{"model_id":11,"type":"text"}],"sequence_type":"PromptTemplateSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":1,"web_visible":false},{"description":"","id":24,"name":"synthetic
+ data","sequence":[{"model_id":38,"type":"search"},{"template_id":7},{"model_id":11,"type":"text"}],"sequence_type":"RAGSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc","user_id":68,"web_visible":true},{"description":"bozo","id":28,"name":"Rijgersberg/GEITje-7B-chat-v2","sequence":[{"model_id":42,"type":"search"},{"template_id":32},{"model_id":46,"type":"text"}],"sequence_type":"RAGSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"","id":29,"name":"rhysjones/phi-2-orange-v2","sequence":[{"model_id":47,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"Fietje
+ van T.V.","id":30,"name":"BramVanroy/fietje-2b-chat","sequence":[{"model_id":49,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":62,"web_visible":true},{"description":"","id":33,"name":"ibm-granite/granite-8b-code-instruct","sequence":[{"model_id":62,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":null,"user_id":64,"web_visible":true},{"description":"","id":34,"name":"codellama/CodeLlama-7b-Instruct-hf","sequence":[{"model_id":63,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":null,"user_id":63,"web_visible":true},{"description":"\n This
+ is a text-to-speech model trained by facebook. It converts the input message
+ to output audio.\n The quality of the output is only
+ guaranteed by english speech, as this is the attempted output language.\n In
+ the future we may add different languages.\n\n Release
+ Date: December 2023\n ","id":36,"name":"Massively Multilingual
+ Speech English","sequence":[{"model_id":65,"type":"tts"}],"sequence_type":"AudioGenerationSequence","sram_owner_regex":null,"user_id":null,"web_visible":false},{"description":"SURF.nl
+ chat obv Sitemap en Dienstbrochure","id":40,"name":"SURF.nl chat ","sequence":[{"template_id":43},{"model_id":10,"type":"text"}],"sequence_type":"PromptTemplateSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":85,"web_visible":true}]
+
+ '
+ recorded_at: Wed, 02 Jan 2019 19:00:00 GMT
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/2024-10-09-room-for-everyones-educational-talent/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Wed, 05 Jun 2024 14:16:20 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Transfer-Encoding:
+ - chunked
+ Connection:
+ - keep-alive
+ Vary:
+ - Accept-Encoding
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Cache-Control:
+ - no-cache
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnQgc2l0ZWhlYWRlci0tbWVudWJhci10cmFuc2x1Y2VudCBwYWdlLS1mb3Jtd2VidG9vbCBwYWdlLS13aXRoYmFja2xpbmsiIGRhdGEtdHJhY2tpbmdpZD0iIj48aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PHRpdGxlPlJvb20gZm9yIGV2ZXJ5b25lJiMzOTtzIGVkdWNhdGlvbmFsIHRhbGVudCAtIEV2ZW50PC90aXRsZT48bWV0YSBuYW1lPSJkZXNjcmlwdGlvbiIgY29udGVudD0iTG9jYXRpb246IFNvY2lhbCBJbXBhY3QgRmFjdG9yeSBWcmVkZW5idXJnIFV0cmVjaHQiPjxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtMTAtMDktcm9vbS1mb3ItZXZlcnlvbmVzLWVkdWNhdGlvbmFsLXRhbGVudC8iPgo8IS0tClJlYWxpc2F0aWU6IPCfkrwgV2ViSGFyZSBidgogICAgICAgICAgICDwn4yQIGh0dHBzOi8vd3d3LndlYmhhcmUubmwvCi0tPgo8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEiIC8+PG1ldGEgbmFtZT0iZGVzY3JpcHRpb24iIGNvbnRlbnQ9IkxvY2F0aW9uOiBTb2NpYWwgSW1wYWN0IEZhY3RvcnkgVnJlZGVuYnVyZyBVdHJlY2h0IiAvPjxsaW5rIHJlbD0iYXBwbGUtdG91Y2gtaWNvbiIgc2l6ZXM9IjE4MHgxODAiIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9hcHBsZS10b3VjaC1pY29uLTE4MHgxODAucG5nIiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi0zMngzMi5wbmciIHNpemVzPSIzMngzMiIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tOTZ4OTYucG5nIiBzaXplcz0iOTZ4OTYiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTE5NHgxOTQucG5nIiBzaXplcz0iMTk0eDE5NCIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2FuZHJvaWQtY2hyb21lLTE5MngxOTIucG5nIiBzaXplcz0iMTkyeDE5MiIgLz48bGluayByZWw9Im1hc2staWNvbiIgICAgICAgICAgICAgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL3NhZmFyaS1waW5uZWQtdGFiLnN2ZyIgY29sb3I9IiNmZjhiMzgiIC8+PG1ldGEgbmFtZT0idGhlbWUtY29sb3IiIGNvbnRlbnQ9IiNmZmZmZmYiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnR5cGUiIGNvbnRlbnQ9IndlYnNpdGUiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnNpdGVfbmFtZSIgY29udGVudD0iRmVkZXJhdGlvbiIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6dGl0bGUiIGNvbnRlbnQ9IlJvb20gZm9yIGV2ZXJ5b25lJiMzOTtzIGVkdWNhdGlvbmFsIHRhbGVudCAtIEV2ZW50IiAvPjxtZXRhIHByb3BlcnR5PSJvZzpkZXNjcmlwdGlvbiIgY29udGVudD0iTG9jYXRpb246IFNvY2lhbCBJbXBhY3QgRmFjdG9yeSBWcmVkZW5idXJnIFV0cmVjaHQiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlIiBjb250ZW50PSJodHRwczovL3d3dy40dHUubmwvLnVjL2kxYWUzODVmODAxMDI2OGY4MTAwMGI3ZmZiYjAxMzJiMDQ4Y2VmNGNhNWU4ZDA3MDFjM2IwMDQ3NjAyODAvdGVhY2hpbmctbGVhcm5pbmcuanBnIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTp3aWR0aCIgY29udGVudD0iMTIwMCIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6aGVpZ2h0IiBjb250ZW50PSI2MzAiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlIiBjb250ZW50PSJodHRwczovL3d3dy40dHUubmwvLnVjL2ljOGJhZTFkOTAxMDI2OGY4MTAwMGI3ZmZiYjAxMzJiMDQ4Y2VmNGNhNWU4ZDA3MDFjMzJjMDEyYzAxODAvdGVhY2hpbmctbGVhcm5pbmcuanBnIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTp3aWR0aCIgY29udGVudD0iMzAwIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTpoZWlnaHQiIGNvbnRlbnQ9IjMwMCIgLz48c2NyaXB0IG5vbW9kdWxlPiBpZighIXdpbmRvdy5NU0lucHV0TWV0aG9kQ29udGV4dCAmJiAhIWRvY3VtZW50LmRvY3VtZW50TW9kZSlkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LmFkZCgidW5zdXBwb3J0ZWQtYnJvd3NlciIpOzwvc2NyaXB0PjxzY3JpcHQgdHlwZT0iYXBwbGljYXRpb24vanNvbiIgaWQ9IndoLWNvbmZpZyI+eyJkZXNpZ25jZG5yb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvIiwiZGVzaWducm9vdCI6Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlLyIsImR0YXBzdGFnZSI6InByb2R1Y3Rpb24iLCJpbWdyb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nLyIsImlzbGl2ZSI6dHJ1ZSwibG9jYWxlIjoiZW4tVVMiLCJvYmoiOnsibmF2cGF0aGl0ZW0iOnsibGluayI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvMjAyNC0xMC0wOS1yb29tLWZvci1ldmVyeW9uZXMtZWR1Y2F0aW9uYWwtdGFsZW50LyIsInRpdGxlIjoiUm9vbSBmb3IgZXZlcnlvbmUncyBlZHVjYXRpb25hbCB0YWxlbnQgLSBFdmVudCJ9fSwic2VydmVyIjo1MDUwMCwic2l0ZSI6e30sInNpdGVyb290IjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsInNvY2lhbGl0ZTpndG0iOnsiYSI6IkdUTS1XVFo1RlJRIiwiaCI6dHJ1ZSwibSI6ZmFsc2V9fTwvc2NyaXB0PjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iLy5hcC80dHUuc2l0ZS9hcC5jc3MiPjxzY3JpcHQgc3JjPSIvLmFwLzR0dS5zaXRlL2FwLm1qcyIgdHlwZT0ibW9kdWxlIiBhc3luYz48L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2xkK2pzb24iPnsiQGNvbnRleHQiOiJodHRwczovL3NjaGVtYS5vcmciLCJAdHlwZSI6IkJyZWFkY3J1bWJMaXN0IiwiaXRlbUxpc3RFbGVtZW50IjpbeyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iLCJuYW1lIjoiRmVkZXJhdGlvbiIsInBvc2l0aW9uIjoxfSx7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJuYW1lIjoiQWdlbmRhIiwicG9zaXRpb24iOjJ9LHsiQHR5cGUiOiJMaXN0SXRlbSIsIml0ZW0iOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtMTAtMDktcm9vbS1mb3ItZXZlcnlvbmVzLWVkdWNhdGlvbmFsLXRhbGVudC8iLCJuYW1lIjoiUm9vbSBmb3IgZXZlcnlvbmUncyBlZHVjYXRpb25hbCB0YWxlbnQgLSBFdmVudCIsInBvc2l0aW9uIjozfV19PC9zY3JpcHQ+PC9oZWFkPjxib2R5Pjxub3NjcmlwdD48aWZyYW1lIHNyYz0iLy93d3cuZ29vZ2xldGFnbWFuYWdlci5jb20vbnMuaHRtbD9pZD1HVE0tV1RaNUZSUSIgaGVpZ2h0PSIwIiB3aWR0aD0iMCIgc3R5bGU9ImRpc3BsYXk6bm9uZTt2aXNpYmlsaXR5OmhpZGRlbiI+PC9pZnJhbWU+PC9ub3NjcmlwdD48ZGl2IGNsYXNzPSJzcGMtbW9kYWxpdHlsYXllciI+PC9kaXY+PGRpdiBpZD0ic2xpZGVtZW51LWNvbnRhaW5lciI+PGRpdiBpZD0ic2xpZGVtZW51IiB0YWJpbmRleD0iLTEiICAgID48ZGl2IGNsYXNzPSJzaWRlYmFyX19oZWFkZXIiPiA8YSBjbGFzcz0ic2lkZWJhcl9faGVhZGVyX19pZGVudGl0eSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGRpdiBjbGFzcz0ic2lkZWJhcl9faWRlbnRpdHlfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0ic2lkZWJhcl9faWRlbnRpdHlfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjxidXR0b24gaWQ9InNsaWRlbWVudS1jbG9zZSIgY2xhc3M9InNpZGViYXItYWN0aW9uLWNsb3NlIiB0eXBlPSJidXR0b24iIGFyaWEtbGFiZWw9IkNsb3NlIiA+PC9idXR0b24+PC9kaXY+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51IHNpZGViYXJfX21lbnUtLWxldmVsMSIgID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iID5Ib21lPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPlJlc2VhcmNoPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5BYm91dCBvdXIgcmVzZWFyY2g8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC80dHUtY2VudHJlcy8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj40VFUgQ2VudHJlczwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyIgPkFNSSAoTWF0aGVtYXRpY3MpPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyIgPkJ1aWx0IEVudmlyb25tZW50PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iID5EZXNpZ24gVW5pdGVkPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIiA+RW5lcmd5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iID5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyIgPkhlYWx0aDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyIgPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iID5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iID5OSVJJQ1QgKElDVCk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIiA+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkhpZ2ggVGVjaCBmb3IgYSBTdXN0YWluYWJsZSBGdXR1cmU8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDMiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyIgPkhUU0YgSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iID5IVFNGIElJIFByb2dyYW1tZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi12aWRlb3MvIiA+SFRTRiB2aWRlb3M8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iID40VFUuUmVzZWFyY2hEYXRhPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9FRS1OTC8iID5FbGVjdHJpY2FsIEVuZ2luZWVyaW5nIE5ldGhlcmxhbmRzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+RWR1Y2F0aW9uPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIiA+QWJvdXQgb3VyIGVkdWNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyIgPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iID40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIiA+U0FJIChFbmdpbmVlcmluZyBEb2N0b3JhdGUpPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vZWR1Y2F0aW9ucHJvZ3JhbW1lcy8iID5FZHVjYXRpb24gcHJvZ3JhbW1lczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGJ1dHRvbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPlZhbG9yaXNhdGlvbjwvYnV0dG9uPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdCUyMGFjdGl2aXRpZXMvIiA+NFRVLklNUEFDVDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIiA+QWJvdXQgNFRVLkltcGFjdDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdGFydHVwJTIwbWlzc2lvbnMvIiA+U3RhcnR1cCBtaXNzaW9uczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+TWVkaWE8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDMiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvaW5zaWdodGZ1bC1pbm5vdmF0b3JzLyIgPkluc2lnaHRmdWwgSW5ub3ZhdG9yczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9TcGluLW9mZiUyMHNlcmllLyIgPlNwaW4tT2ZmIFN0b3JpZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0dWRlbnQlMjBjaGFsbGVuZ2VzLyIgPlN0dWRlbnQgY2hhbGxlbmdlczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9UdXNzZW5wYWdpbmElMjB2b29yYWZnYWFuZCUyMGFhbiUyMFN0YXJ0dXAlMjBTdXBwb3J0LyIgPkFib3V0IFN0YXJ0dXAgU3VwcG9ydDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vYWdlbmRhLyIgPkFnZW5kYTwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPk5ld3M8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtICBzaWRlbWFpbm1lbnVfX2l0ZW0tLWV4cGFuZCAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgc2lkZW1haW5tZW51LWxldmVsMV9fc2VsZWN0ZWQgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyIgPkFnZW5kYTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+QWJvdXQgNFRVPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvNHR1LWluLTEtbWludXRlLyIgPjRUVSBpbiBvbmx5IDEgbWludXRlPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvZmFjdHMtZmlndXJlcy8iID5GYWN0cyBhbmQgZmlndXJlczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L29yZ2FuaXNhdGlvbi8iID5PcmdhbmlzYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9wdWJsaWNhdGlvbnMvIiA+UHVibGljYXRpb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvYWx1bW5pLyIgPkFsdW1uaTwvYT48L2xpPjwvdWw+PC9saT48L3VsPjxuYXYgY2xhc3M9InNpZGViYXJfX2xhbmd1YWdlcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sLyI+Tkw8L2E+IHwgPHNwYW4gY2xhc3M9InNlbGVjdGVkIj5FTjwvc3Bhbj48L25hdj48bmF2IGNsYXNzPSJzaWRlYmFyX19zZWNvbmRhcnlsaW5rcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2NvbnRhY3QvIj5Db250YWN0PC9hPjwvbmF2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3AtYmFja2dyb3VuZCI+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXItYmFja2dyb3VuZCI+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcCI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fY29udGVudCI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9faWRlbnRpdHkiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX3Nsb2dhbiI+UGFydCBvZiB0aGUgPGJ1dHRvbiBjbGFzcz0iaGVhZGVyLXRvcF9fdG9nZ2xlZXhwbG9yZXBhbmVsIj40VFUuRmVkZXJhdGlvbjwvYnV0dG9uPjwvZGl2PjxhIGNsYXNzPSJoZWFkZXItdG9wX19pZGVudGl0eSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19vcmdhbml6YXRpb25zIj48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVkZWxmdC5ubC9lbi8iIHRpdGxlPSJUVSBEZWxmdCIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1kZWxmdC5zdmciIGFsdD0iVFUgRGVsZnQiIHdpZHRoPSIxMDAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWUubmwvZW4vIiB0aXRsZT0iVFUgRWluZGhvdmVuIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWVpbmRob3Zlbi5zdmciIGFsdD0iVFUgRWluZGhvdmVuIiB3aWR0aD0iMTMwIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudXR3ZW50ZS5ubC9lbi8iIHRpdGxlPSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvdW5pdmVyc2l0eS1vZi10d2VudGUuc3ZnIiBhbHQ9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiB3aWR0aD0iMTAwIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cud3VyLm5sLyIgdGl0bGU9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby13dXIuc3ZnIiBhbHQ9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgd2lkdGg9IjEzMiIgLz48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXIiPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19jb250ZW50Ij48YSBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NwYWNlciI+PC9kaXY+PG5hdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX21lbnViYXIiIGFyaWEtbGFiZWw9Ik1haW4iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXIiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIiA+SG9tZTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+UmVzZWFyY2g8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPkFib3V0IG91ciByZXNlYXJjaDwvYT48L2xpPjxsaSBjbGFzcz0ic3BjLW1lbnViYXItLWhhc3N1Yml0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvNHR1LWNlbnRyZXMvIiA+NFRVIENlbnRyZXM8L2E+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwzIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iID5BTUkgKE1hdGhlbWF0aWNzKTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iID5CdWlsdCBFbnZpcm9ubWVudDwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIiA+RGVzaWduIFVuaXRlZDwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyIgPkVuZXJneTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIiA+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iID5IZWFsdGg8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iID5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIiA+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIiA+TklSSUNUIChJQ1QpPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyIgPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlLyIgPkhpZ2ggVGVjaCBmb3IgYSBTdXN0YWluYWJsZSBGdXR1cmU8L2E+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwzIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyIgPkhUU0YgSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iID5IVFNGIElJIFByb2dyYW1tZXM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi12aWRlb3MvIiA+SFRTRiB2aWRlb3M8L2E+PC9saT48L3VsPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIiA+NFRVLlJlc2VhcmNoRGF0YTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL0VFLU5MLyIgPkVsZWN0cmljYWwgRW5naW5lZXJpbmcgTmV0aGVybGFuZHM8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIiA+RWR1Y2F0aW9uPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIiA+QWJvdXQgb3VyIGVkdWNhdGlvbjwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iID5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyIgPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIiA+U0FJIChFbmdpbmVlcmluZyBEb2N0b3JhdGUpPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uL2VkdWNhdGlvbnByb2dyYW1tZXMvIiA+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9IiIgPlZhbG9yaXNhdGlvbjwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QlMjBhY3Rpdml0aWVzLyIgPjRUVS5JTVBBQ1Q8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iID5BYm91dCA0VFUuSW1wYWN0PC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdGFydHVwJTIwbWlzc2lvbnMvIiA+U3RhcnR1cCBtaXNzaW9uczwvYT48L2xpPjxsaSBjbGFzcz0ic3BjLW1lbnViYXItLWhhc3N1Yml0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS8iID5NZWRpYTwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9pbnNpZ2h0ZnVsLWlubm92YXRvcnMvIiA+SW5zaWdodGZ1bCBJbm5vdmF0b3JzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL1NwaW4tb2ZmJTIwc2VyaWUvIiA+U3Bpbi1PZmYgU3RvcmllczwvYT48L2xpPjwvdWw+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0dWRlbnQlMjBjaGFsbGVuZ2VzLyIgPlN0dWRlbnQgY2hhbGxlbmdlczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vVHVzc2VucGFnaW5hJTIwdm9vcmFmZ2FhbmQlMjBhYW4lMjBTdGFydHVwJTIwU3VwcG9ydC8iID5BYm91dCBTdGFydHVwIFN1cHBvcnQ8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vYWdlbmRhLyIgPkFnZW5kYTwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID5OZXdzPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWxlY3RlZCI+QWdlbmRhPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvIiA+QWJvdXQgNFRVPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvNHR1LWluLTEtbWludXRlLyIgPjRUVSBpbiBvbmx5IDEgbWludXRlPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2ZhY3RzLWZpZ3VyZXMvIiA+RmFjdHMgYW5kIGZpZ3VyZXM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvb3JnYW5pc2F0aW9uLyIgPk9yZ2FuaXNhdGlvbjwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9wdWJsaWNhdGlvbnMvIiA+UHVibGljYXRpb25zPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9hbHVtbmkvIiA+QWx1bW5pPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjwvdWw+PC9uYXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NwYWNlciI+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX2xhbmd1YWdlcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sLyI+Tkw8L2E+fDxzcGFuPkVOPC9zcGFuPjwvZGl2Pjxmb3JtIGFjdGlvbj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3NlYXJjaC8iIG1ldGhvZD0iR0VUIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaHdyYXBwZXIiIGF1dG9jb21wbGV0ZT0ib2ZmIiA+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaC1pbnB1dC1hbmQtc3VnZ2VzdGlvbnMtd3JhcHBlciI+PGlucHV0IGlkPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoaW5wdXQiIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoaW5wdXQiIG5hbWU9InF1ZXJ5IiBkYXRhLXN1Z2dlc3Q9IjR0dTpjb3Jwb3JhdGVfZW4iIGRhdGEtc3VnZ2VzdHBhcmVudD0icGFyZW50IiBwbGFjZWhvbGRlcj0iWm9la2VuIiBhcmlhLWxhYmVsPSJab2VrZW4iIHR5cGU9InNlYXJjaCIgLz48L2Rpdj48bGFiZWwgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2giIGZvcj0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiB0YWJpbmRleD0iLTEiID48c3BhbiBjbGFzcz0iZmFyIGZhLXNlYXJjaCI+PC9zcGFuPjwvbGFiZWw+PC9mb3JtPjxidXR0b24gaWQ9ImhlYWRlci1tZW51YmFyX3NpZGViYXJ0b2dnbGUiIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2hvd3NpZGVtYWlubWVudSBzaWRlYmFyLWFjdGlvbi10b2dnbGUiIGFyaWEtbGFiZWw9Ik9wZW4gbWVudSIgYXJpYS1leHBhbmRlZD0iZmFsc2UiIGFyaWEtY29udHJvbHM9InNsaWRlbWVudSIgPjxzcGFuIGNsYXNzPSJmYXIgZmEtYmFycyI+PC9zcGFuPjwvYnV0dG9uPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbCI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX190b3BiYXIiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY2xvc2UiPkNsb3NlPC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jb2x1bW5zIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2FkZHJlc3MgcnRkY29udGVudCI+PHAgY2xhc3M9ImhlYWRpbmciPjRUVS5GZWRlcmF0aW9uPC9wPjxwIGNsYXNzPSJub3JtYWwiPiszMSgwKTYgNDggMjcgNTUgNjE8L3A+PHAgY2xhc3M9Im5vcm1hbCI+PGEgaHJlZj0ibWFpbHRvOnByb2plY3RsZWlkZXJANHR1Lm5sIj5zZWNyZXRhcmlzQDR0dS5ubDwvYT48L3A+PHAgY2xhc3M9Im5vcm1hbCI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGI+V2Vic2l0ZTogNFRVLm5sPC9iPjwvYT48L3A+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jb2x1bW4gZXhwbG9yZXBhbmVsX19jb2x1bW4tLW1hbnlpdGVtcyI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5SZXNlYXJjaDwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faXRlbXMgZXhwbG9yZXBhbmVsX19pdGVtcy0tbWFueWl0ZW1zICI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iPjxzcGFuPkFwcGxpZWQgTWF0aGVtYXRpY3MgSW5zdGl0dXRlPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iPjxzcGFuPkJ1aWx0IEVudmlyb25tZW50PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIj48c3Bhbj5EZXNpZ24gVW5pdGVkPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyI+PHNwYW4+RW5lcmd5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIj48c3Bhbj5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iPjxzcGFuPkhlYWx0aDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iPjxzcGFuPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIj48c3Bhbj5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIj48c3Bhbj5OSVJJQ1QgKElDVCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyI+PHNwYW4+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyI+PHNwYW4+UmVzZWFyY2hEYXRhPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyI+PHNwYW4+SFRTRiBJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyI+PHNwYW4+SFRTRiBJSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jb2x1bW4gIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLkVkdWNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faXRlbXMgICI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iPjxzcGFuPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIj48c3Bhbj40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyI+PHNwYW4+U0FJIChFbmdpbmVlcmluZyBEb2N0b3JhdGUpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ3aWpzL29uZGVyd2lqc3Byb2dyYW1tYXMvIj48c3Bhbj5FZHVjYXRpb24gcHJvZ3JhbW1lczwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jb2x1bW4gIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlZhbG9yaXNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faXRlbXMgICI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyI+PHNwYW4+NFRVLklNUEFDVDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly90ZWNoLXRyYW5zZmVyLm5sL2VuLyI+PHNwYW4+VGhlbWF0aWMgVGVjaG5vbG9neSBUcmFuc2Zlcjwvc3Bhbj48L2E+PGEgaHJlZj0iIj48c3Bhbj5TcGluLW9mZiBTdG9yaWVzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovLzR0dWltcGFjdGNoYWxsZW5nZS5ubC8iPjxzcGFuPjRUVSBJbXBhY3QgQ2hhbGxlbmdlPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fYmFja2dyb3VuZCI+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlc2hvdyBjYXJyb3VzZWxfX3ZpZXdwb3J0IGNhcnJvdXNlbF9fZHJhZ2FyZWEgIj48c3R5bGU+QG1lZGlhIChtYXgtd2lkdGg6IDc2N3B4KXsuaGVhZGVyc2xpZGUwe2JhY2tncm91bmQtY29sb3I6ICMzMTJBMkY7YmFja2dyb3VuZC1pbWFnZTogdXJsKC8udWMvaWQyODVhYmYxMDEwMjY4ZjgxMDAwYjdmZmJiMDEzMmIwNDhjZWY0Y2E1ZThkMDgwMWUzNDAwYjAwMDc4MTQ2L3RlYWNoaW5nLWxlYXJuaW5nLmpwZyk7fX1AbWVkaWEgKG1pbi13aWR0aDogNzY4cHgpey5oZWFkZXJzbGlkZTB7YmFja2dyb3VuZC1jb2xvcjogIzMxMkEyRjtiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pMzA3MGFjMWEwMTAyNjhmODEwMDBiN2ZmYmIwMTMyYjA0OGNlZjRjYTVlOGQwODAxZTM0MDBiNjAwNDgxNDYvdGVhY2hpbmctbGVhcm5pbmcuanBnKTt9fTwvc3R5bGU+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlIGNhcnJvdXNlbF9fY2VsbCBhY3RpdmVzbGlkZSBoZWFkZXJzbGlkZTAgIiBkYXRhLXNsaWRlc2hvdy1lbGVtZW50cz0icGFnZS1oZWFkZXJfX3NsaWRlMF9fY29udGVudCIgc3R5bGU9IiIgPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19jb250ZW50Ij48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fbWV0YSI+PGgxIGNsYXNzPSJwYWdlLWhlYWRlcl9fdGl0bGUiPlJvb20gZm9yIGV2ZXJ5b25lJ3MgZWR1Y2F0aW9uYWwgdGFsZW50IC0gRXZlbnQ8L2gxPjxkaXYgY2xhc3M9InBhZ2VoZWFkZXJfX2RhdGUiPldlZG5lc2RheSA5IE9jdG9iZXIgMjAyNDwvZGl2PjxkaXYgY2xhc3M9InBhZ2VoZWFkZXJfX3RleHQiPkxvY2F0aW9uOiBTb2NpYWwgSW1wYWN0IEZhY3RvcnkgVnJlZGVuYnVyZyBVdHJlY2h0PC9kaXY+PC9kaXY+PC9kaXY+PG1haW4gY2xhc3M9InBhZ2VfX2JvZHkgICI+PGZvcm0gaWQ9IiIgIGNsYXNzPSJwYWdlX19oZWFkZXJmaWx0ZXJzICAgIj48L2Zvcm0+PGRpdiBjbGFzcz0icGFnZV9fY29udGVudGFyZWEgIHBhZ2VfX2NvbnRlbnRhcmVhLS1mb3Jtd2VidG9vbCAgaGVhZGVyaXNvcGFxdWUgIj48ZGl2IGNsYXNzPSJkZWVwbGlua3Mtd3JhcHBlciI+PGRpdiBjbGFzcz0iZGVlcGxpbmtzIj48YSBjbGFzcz0icGFnZS1iYWNrbGluayIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFsbCBldmVudHM8L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1jb250ZW50c3RhcnQiPjwvZGl2PjwhLS13aF9jb25zaWxpb19jb250ZW50LS0+PHAgY2xhc3M9Im5vcm1hbCI+PGI+U3BhY2UgZm9yIGV2ZXJ5b25lJ3MgZWR1Y2F0aW9uIHRhbGVudDwvYj48L3A+PHAgY2xhc3M9Im5vcm1hbCI+OSBva3RvYmVyIDIwMjQ8L3A+PHAgY2xhc3M9Im5vcm1hbCI+U3RhcnQgMTAuMDAgdXVyIC0gZW5kIDE3LjAwIHV1cjwvcD48cCBjbGFzcz0ibm9ybWFsIj5Mb2NhdGlvbjogU29jaWFsIEltcGFjdCBGYWN0b3J5IFZyZWRlbmJ1cmcgVXRyZWNodDwvcD48cCBjbGFzcz0ibm9ybWFsIj40VFUuQ0VFIG9yZ2FuaXplcyBhIG5hdGlvbmFsIGV2ZW50IHRvIGNlbGVicmF0ZSB0aGUgcmVzdWx0cyBvZiB0aGUg4oCYU2VjdG9ycGxhbiBvbmRlcndpanMgYsOodGF0ZWNobmlla+KAmSAoc2VjdG9yIHBsYW4gZm9yIFNURU0gZWR1Y2F0aW9uIGluIHRoZSBOZXRoZXJsYW5kcyksIEFjdGlvbiAyYjog4oCcVG8gam9pbnRseSBvZmZlciBzY2llbnRpc3RzIG1vcmUgb3Bwb3J0dW5pdGllcyBmb3IgYW4gYWNhZGVtaWMgY2FyZWVyIHdpdGggZm9jdXMgb24gdGVhY2hpbmcgYW5kIGxlYXJuaW5nIGluIHRoZSBjb250ZXh0IG9mIFJlY29nbml0aW9uIGFuZCBSZXdhcmRzLuKAnSBUaGlzIGV2ZW50IHdpbGwgYmUgaW4gRHV0Y2guPC9wPjxwIGNsYXNzPSJub3JtYWwiPlRoZSBvcmdhbml6aW5nIGNvbW1pdHRlZTrCoDwvcD48cCBjbGFzcz0ibm9ybWFsIj5UVSBEZWxmdDogU3lsdmlhIFdhbHNhcmllIFdvbGZmIGVuIERhbmllbGxlIFJpZXRkaWprPC9wPjxwIGNsYXNzPSJub3JtYWwiPlRVIEVpbmRob3ZlbjogSnVsbWEgQnJhYXQgZW4gUmFjaGVsbGUgS2FtcDwvcD48cCBjbGFzcz0ibm9ybWFsIj5Vbml2ZXJzaXRlaXQgVHdlbnRlOiBDaW5keSBQb29ydG1hbjwvcD48cCBjbGFzcz0ibm9ybWFsIj5XYWdlbmluZ2VuIFVuaXZlcnNpdHkgJmFtcDsgUmVzZWFyY2g6IEZyaWtraWUgS29yZzwvcD48cCBjbGFzcz0ibm9ybWFsIj48Yj5TaWdudXAgbGluayB3aWxsIGZvbGxvdyBzb29uITwvYj48L3A+PCEtLS93aF9jb25zaWxpb19jb250ZW50LS0+PGRpdiBjbGFzcz0icGFnZV9fYmFsbG9vbiI+PC9kaXY+PGRpdiBjbGFzcz0icGFnZV9fZm9vdGVyIj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXJfX2NvbnRlbnQgbmF2cGF0aCI+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPkhvbWU8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxhIGNsYXNzPSJuYXZwYXRoX19pdGVtIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyI+QWdlbmRhPC9hPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19zZXBlcmF0b3IiPjwvc3Bhbj48c3BhbiBjbGFzcz0ibmF2cGF0aF9faXRlbSBjcnVtYnBhdGgtLWN1cnJlbnRwYWdlIj5Sb29tIGZvciBldmVyeW9uZSYjMzk7cyBlZHVjYXRpb25hbCB0YWxlbnQgLSBFdmVudDwvc3Bhbj48L2Rpdj48L2Rpdj48L2Rpdj48L21haW4+PGRpdiBjbGFzcz0iZm9vdGVyIj48ZGl2IGNsYXNzPSJmb290ZXJfX3BhbmVsIj48ZGl2IGNsYXNzPSJmb290ZXJfX2lkZW50aXR5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19zaXRldGl0bGUiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48IS0tIEZJWE1FOiB1c2UgYXJpYS1oaWRkZW49InRydWUiIGJlY2F1c2UgaXQncyBhIGR1cGxpY2F0ZSBvZiB0aGUgaXRlbXMgb24gdGhlIG1lbnUgYmFyID8gLS0+IDxuYXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMSBmb290ZXJfX21haW5tZW51IiBhcmlhLWxhYmVsPSJNYWluIj4gPHVsPiAgIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyI+UmVzZWFyY2g8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIj5FZHVjYXRpb248L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9IiI+VmFsb3Jpc2F0aW9uPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyI+TmV3czwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFnZW5kYTwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iPkFib3V0IDRUVTwvYT4gPC9saT4gICA8L3VsPiA8L25hdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMiI+IDxpbnB1dCB0eXBlPSJjaGVja2JveCIgbmFtZT0iZm9vdGVyY29sdW1uIiBpZD0iZm9vdGVyX19jb2x1bW4yX19leHBhbmQiIC8+IDxsYWJlbCBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciIGZvcj0iZm9vdGVyX19jb2x1bW4yX19leHBhbmQiPkNvbnRhY3Q8L2xhYmVsPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9fY29udGVudCBydGRjb250ZW50Ij4gPHAgY2xhc3M9Im5vcm1hbCI+KzMxKDApNiA4MyAyMiA1MCA1OTxiciAvPjxhIGhyZWY9Im1haWx0bzpwcm9qZWN0bGVpZGVyQDR0dS5ubCI+c2VjcmV0YXJpc0A0dHUubmw8L2E+PC9wPiA8L2Rpdj4gPC9kaXY+ICAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW4zIj4gPGlucHV0IHR5cGU9ImNoZWNrYm94IiBuYW1lPSJmb290ZXJjb2x1bW4iIGlkPSJmb290ZXJfX2NvbHVtbjNfX2V4cGFuZCIgLz4gPGxhYmVsIGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyIgZm9yPSJmb290ZXJfX2NvbHVtbjNfX2V4cGFuZCI+UG9zdGFkcmVzPC9sYWJlbD4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgcnRkY29udGVudCI+IDxwIGNsYXNzPSJub3JtYWwiPjRUVS5GZWRlcmF0aWU8YnIgLz5Qb3N0YnVzIDU8YnIgLz4yNjAwIEFBIERlbGZ0PC9wPiA8L2Rpdj4gPC9kaXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjQiPiAgPGRpdiBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtc19fZ3JvdXAiPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyI+Rm9sbG93IHVzPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgZm9vdGVyX19zb2NpYWxpdGVtcyAiPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vdHdpdHRlci5jb20vNFRVRmVkZXJhdGlvbiIgdGl0bGU9IlR3aXR0ZXIiID48c3BhbiBjbGFzcz0iZmFiIGZhLXR3aXR0ZXIiPjwvc3Bhbj48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbXBhbnkvNC10dS1mZWRlcmF0aW9uLyIgdGl0bGU9IkxpbmtlZEluIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS1saW5rZWRpbi1pbiI+PC9zcGFuPjwvYT48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS9jaGFubmVsL1VDTWtxaGp4MlcxaE5Sd3lzUnZXRVh3USIgdGl0bGU9IllvdXR1YmUiID48c3BhbiBjbGFzcz0iZmFiIGZhLXlvdXR1YmUiPjwvc3Bhbj48L2E+PC9kaXY+IDwvZGl2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyX19ncm91cCI+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyBmb290ZXJfX2NvbHVtbl9faGVhZGluZy0tbmV3c2xldHRlciAiPlN0YXkgdXAtdG8tZGF0ZTwvZGl2Pjxmb3JtIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXAgd2hwbHVnaW4tbmV3c2xldHRlci1zdWJzY3JpcHRpb24gICIgZGF0YS1uZXdzbGV0dGVyLWxpc3Q9IlNVQlNfNFRVX0NPUlBPUkFURV9OSUVVV1NCUklFRiIgPjxpbnB1dCBuYW1lPSJlbWFpbCIgcGxhY2Vob2xkZXI9IlNpZ24gdXAgZm9yIG91ciBuZXdzbGV0dGVyIiAvPjxidXR0b24gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VibWl0IiB0eXBlPSJzdWJtaXQiIG5hbWU9InN1Ym1pdGJ1dHRvbiIgYXJpYS1sYWJlbD0iU3Vic2NyaWJlIj48c3BhbiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwX19zdWJtaXRfX2ljb24gZmFyIGZhLWVudmVsb3BlIj48L3NwYW4+PC9idXR0b24+PC9mb3JtPjxkaXYgY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VjY2VzcyI+VGhhbmtzIGZvciBzdWJzY3JpYmluZyB0byBvdXIgbmV3c2xldHRlci48L2Rpdj4gIDwvZGl2PiA8L2Rpdj4gPGhyIGNsYXNzPSJmb290ZXJfX2RpdmlkZXIiIC8+IDxkZXRhaWxzIGNsYXNzPSJmb290ZXJfX2V4cGxvcmUiPjxzdW1tYXJ5PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fdG9nZ2xlX19jbG9zZWR0ZXh0Ij5QYXJ0IG9mIHRoZSA8c3BhbiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX19uYW1lIj40VFUuRmVkZXJhdGlvbjwvc3Bhbj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX3RvZ2dsZV9fb3BlbnRleHQiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jbG9zZSI+Q2xvc2U8L2Rpdj48L2Rpdj48L3N1bW1hcnk+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWwiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlJlc2VhcmNoPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyI+PHNwYW4+QXBwbGllZCBNYXRoZW1hdGljcyBJbnN0aXR1dGU8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyI+PHNwYW4+QnVpbHQgRW52aXJvbm1lbnQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iPjxzcGFuPkRlc2lnbiBVbml0ZWQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIj48c3Bhbj5FbmVyZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iPjxzcGFuPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyI+PHNwYW4+SGVhbHRoPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyI+PHNwYW4+SGlnaC1UZWNoIE1hdGVyaWFsczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iPjxzcGFuPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iPjxzcGFuPk5JUklDVCAoSUNUKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIj48c3Bhbj5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIj48c3Bhbj5SZXNlYXJjaERhdGE8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIj48c3Bhbj5IVFNGIEkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIj48c3Bhbj5IVFNGIElJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5FZHVjYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIj48c3Bhbj5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyI+PHNwYW4+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iPjxzcGFuPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyd2lqcy9vbmRlcndpanNwcm9ncmFtbWFzLyI+PHNwYW4+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlZhbG9yaXNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyI+PHNwYW4+NFRVLklNUEFDVDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly90ZWNoLXRyYW5zZmVyLm5sL2VuLyI+PHNwYW4+VGhlbWF0aWMgVGVjaG5vbG9neSBUcmFuc2Zlcjwvc3Bhbj48L2E+PGEgaHJlZj0iIj48c3Bhbj5TcGluLW9mZiBTdG9yaWVzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovLzR0dWltcGFjdGNoYWxsZW5nZS5ubC8iPjxzcGFuPjRUVSBJbXBhY3QgQ2hhbGxlbmdlPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48L2RldGFpbHM+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnMiPiA8ZGl2IGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtcyI+IDxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWRlbGZ0Lm5sL2VuLyIgdGl0bGU9IlRVIERlbGZ0IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWRlbGZ0LnN2ZyIgYWx0PSJUVSBEZWxmdCIgd2lkdGg9Ijg3IiBoZWlnaHQ9IjM0IiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuLyIgdGl0bGU9IlRVIEVpbmRob3ZlbiIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1laW5kaG92ZW4uc3ZnIiBhbHQ9IlRVIEVpbmRob3ZlbiIgd2lkdGg9IjEzMCIgaGVpZ2h0PSIyNyIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnV0d2VudGUubmwvZW4vIiB0aXRsZT0iVW5pdmVyc2l0eSBvZiBUd2VudGUiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL3VuaXZlcnNpdHktb2YtdHdlbnRlLnN2ZyIgYWx0PSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgd2lkdGg9Ijg1IiBoZWlnaHQ9IjMxIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cud3VyLm5sLyIgdGl0bGU9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby13dXIuc3ZnIiBhbHQ9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgd2lkdGg9IjE0NSIgaGVpZ2h0PSIyOSIgLz48L2E+IDwvZGl2PiA8L2Rpdj4gPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXIiPjxzcGFuIGNsYXNzPSJmb290ZXJfX2JvdHRvbWJhcl9fY29weXJpZ2h0Ij48c3BhbiBjbGFzcz0iZmJjcGFydCI+JmNvcHk7IDIwMjQgNFRVLkZlZGVyYXRpb248L3NwYW4+PC9zcGFuPjx1bCBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXJfX21lbnUiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vY29udGFjdC8iPkNvbnRhY3Q8L2E+PC9saT48L3VsPjwvZGl2PjwvZGl2PjxzY3JpcHQgdHlwZT0iYXBwbGljYXRpb24veC1oc29uIiBpZD0id2gtY29uc2lsaW9maWVsZHMiPmhzb246eyJ3aHNlYXJjaHRodW1ibmFpbCI6Imh0dHBzOi8vd3d3LjR0dS5ubC8udWMvaTA2MTljMjI0MDEwMjZhZjgxMDAwYjdmZmJiMDEzMmIwNDhjZWY0Y2E1ZThkMDgwMWUzNDAwMWYwMDA4MTQxL3RlYWNoaW5nLWxlYXJuaW5nLmpwZyJ9PC9zY3JpcHQ+PC9ib2R5PjwvaHRtbD4=
+ recorded_at: Wed, 02 Jan 2019 19:00:00 GMT
+- request:
+ method: get
+ uri: https://willma.soil.surf.nl/api/models
+ body:
+ encoding: UTF-8
+ string: "{}"
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ Content-Type:
+ - application/json
+ X-Api-Key:
+ - 77696c6c6d61-c5f9443d-e1eb-469a-a9ba-d7c9c733ebb3
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Date:
+ - Wed, 05 Jun 2024 14:16:21 GMT
+ Server:
+ - gunicorn
+ Strict-Transport-Security:
+ - max-age=31556952
+ Content-Security-Policy:
+ - 'default-src ''self''; style-src ''self'' ''unsafe-inline'' *.bootstrapcdn.com
+ *.cloudflare.com fonts.googleapis.com estudybooks.surf.nl; script-src ''self''
+ ''unsafe-inline'' ''unsafe-eval'' webstats.surf.nl code.jquery.com *.bootstrapcdn.com
+ *.cloudflare.com *.aspnetcdn.com; img-src ''self'' data: blob: ''unsafe-inline''
+ https: data: webstats.surf.nl; font-src ''self'' data: *.bootstrapcdn.com
+ fonts.gstatic.com; connect-src ''self''; media-src ''self'' data: blob:'
+ X-Frame-Options:
+ - SAMEORIGIN
+ X-Xss-Protection:
+ - 1; mode=block;
+ X-Content-Type-Options:
+ - nosniff
+ Content-Type:
+ - application/json
+ Content-Length:
+ - '7139'
+ Vary:
+ - Cookie
+ Set-Cookie:
+ - session=.eJyNjcEKAjEMRP8lXnVhb5JfESkxjbqQdiVJvcj-u1XEiwh7GmZ4M_MAqTGFSunqgAdoVrEQC3qz81AV3aig0kn0HSVzRsp3qiw5t-CrakEPskjEPLcasP2zcrG53b4rK7GfsxW9XbebVzZ8ADj2koulKQOO4355AieiXTE.ZmBzNQ.8TjdBvhlSWEUw_AxwSeQB6r-B_M;
+ HttpOnly; Path=/
+ body:
+ encoding: UTF-8
+ string: '[{"description":"Based on the fluffy animal, Meta AI (from Facebook)
+ trained this model first on a huge unorganized public dataset from the web.\n Afterwards,
+ the model was further finetuned on natural conversations to accommodate: for
+ an improved chat interaction.\n Approximately 0.12% of the training
+ data is Dutch and raises questions on the performance on Dutch questions.\n \n Release
+ date: July 2023","id":1,"name":"LLaMa-2 13B Chat","sequence":[{"model_id":8,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Based
+ on the fluffy animal, Meta AI (from Facebook) trained this model first on
+ a huge unorganized public dataset from the web.\n Afterwards, the
+ model was further finetuned on natural conversations to accommodate: for an
+ improved chat interaction. \n Approximately 0.12% of the training
+ data is Dutch and raises questions on the performance on Dutch questions.}\n \n Release
+ date: July 2023","id":2,"name":"LLaMa-2 7B Chat","sequence":[{"model_id":9,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"OpenAI
+ first released ChatGPT and shock the world due to its impressive performance
+ on producing relevant answers in a natural conversation.\n However,
+ there have been some data and privacy concerns. Hence, we for now offer ChatGPT-3.5
+ through this interface via the OpenAI API.\n Hereby, we circumvent
+ any gathering of personal information via tracking cookies on the ChatGPT
+ website. Note: OpenAI could still store \n and process the messages
+ themselves.\n \n Release date: November 2022 (continuous
+ update)","id":3,"name":"ChatGPT-3.5","sequence":[{"model_id":10,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Zephyr
+ is a series of language models that are trained to act as helpful assistants.\n We
+ found that removing the in-built alignment of these datasets boosted performance
+ on MT Bench and made the model more helpful. \n However, this means
+ that model is likely to generate problematic text when prompted to do so and
+ should only be used for educational and research purposes.\n \n Release
+ Date: October 2023","id":4,"name":"Zephyr 7B","sequence":[{"model_id":11,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"Stable
+ diffusion is for images","id":5,"name":"Stable Diffusion","sequence":[{"model_id":12,"type":"images"}],"sequence_type":"ImageGenerationSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":false},{"description":"This
+ is a text-to-speech model trained by facebook. It converts the input message
+ to output audio.\n The quality of the output is only guaranteed
+ by dutch speech, as this is the attempted output language.\n In
+ the future we may add different languages.\n\n Release
+ Date: December 2023","id":7,"name":"Massively Multilingual Speech Dutch","sequence":[{"model_id":14,"type":"tts"}],"sequence_type":"AudioGenerationSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":false},{"description":"Currently
+ only implemented for API access.","id":8,"name":"Whisper speech-to-text Dutch","sequence":[{"model_id":15,"type":"stt"}],"sequence_type":"SingleSessionSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":null,"web_visible":true},{"description":"","id":17,"name":"BramVanroy/GEITje-7B-ultra","sequence":[{"model_id":29,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:label:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"Mixtral
+ GPT-Q quantization","id":22,"name":"casperhansen/mixtral-instruct-awq","sequence":[{"model_id":35,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"sasd","id":23,"name":"asd","sequence":[{"template_id":6},{"model_id":11,"type":"text"}],"sequence_type":"PromptTemplateSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":1,"web_visible":false},{"description":"","id":24,"name":"synthetic
+ data","sequence":[{"model_id":38,"type":"search"},{"template_id":7},{"model_id":11,"type":"text"}],"sequence_type":"RAGSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc","user_id":68,"web_visible":true},{"description":"bozo","id":28,"name":"Rijgersberg/GEITje-7B-chat-v2","sequence":[{"model_id":42,"type":"search"},{"template_id":32},{"model_id":46,"type":"text"}],"sequence_type":"RAGSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"","id":29,"name":"rhysjones/phi-2-orange-v2","sequence":[{"model_id":47,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":66,"web_visible":true},{"description":"Fietje
+ van T.V.","id":30,"name":"BramVanroy/fietje-2b-chat","sequence":[{"model_id":49,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":62,"web_visible":true},{"description":"","id":33,"name":"ibm-granite/granite-8b-code-instruct","sequence":[{"model_id":62,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":null,"user_id":64,"web_visible":true},{"description":"","id":34,"name":"codellama/CodeLlama-7b-Instruct-hf","sequence":[{"model_id":63,"type":"text"}],"sequence_type":"LLMSequence","sram_owner_regex":null,"user_id":63,"web_visible":true},{"description":"\n This
+ is a text-to-speech model trained by facebook. It converts the input message
+ to output audio.\n The quality of the output is only
+ guaranteed by english speech, as this is the attempted output language.\n In
+ the future we may add different languages.\n\n Release
+ Date: December 2023\n ","id":36,"name":"Massively Multilingual
+ Speech English","sequence":[{"model_id":65,"type":"tts"}],"sequence_type":"AudioGenerationSequence","sram_owner_regex":null,"user_id":null,"web_visible":false},{"description":"SURF.nl
+ chat obv Sitemap en Dienstbrochure","id":40,"name":"SURF.nl chat ","sequence":[{"template_id":43},{"model_id":10,"type":"text"}],"sequence_type":"PromptTemplateSequence","sram_owner_regex":"urn:mace:surf.nl:sram:group:surf_rsc:advanceddutchllm","user_id":85,"web_visible":true}]
+
+ '
+ recorded_at: Wed, 02 Jan 2019 19:00:00 GMT
+recorded_with: VCR 6.2.0
From fcb4cd59aff5680f4fb746b91476fa73dff1057c Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Thu, 6 Jun 2024 10:13:41 +0200
Subject: [PATCH 23/37] working test gpt
---
lib/ingestors/llm_ingestor.rb | 2 +-
lib/ingestors/osci_ingestor.rb | 4 +-
lib/modules/chatgpt_service.rb | 2 +-
.../llm_prompts/llm_process_prompt.txt | 0
.../modules/llm_prompts/llm_scrape_prompt.txt | 0
lib/modules/llm_service.rb | 4 +-
.../ingestors/4tu_gpt_llm_ingestor_test.rb | 73 +++++
...est.rb => 4tu_willma_llm_ingestor_test.rb} | 10 +-
test/vcr_cassettes/ingestors/4tu_gpt_llm.yml | 278 ++++++++++++++++++
9 files changed, 362 insertions(+), 11 deletions(-)
rename llm_process_prompt.txt => lib/modules/llm_prompts/llm_process_prompt.txt (100%)
rename llm_scrape_prompt.txt => lib/modules/llm_prompts/llm_scrape_prompt.txt (100%)
create mode 100644 test/unit/ingestors/4tu_gpt_llm_ingestor_test.rb
rename test/unit/ingestors/{4tu_llm_ingestor_test.rb => 4tu_willma_llm_ingestor_test.rb} (92%)
create mode 100644 test/vcr_cassettes/ingestors/4tu_gpt_llm.yml
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index 7418af9be..8231b3d9e 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -52,7 +52,7 @@ def get_event_from_css(url, event_page) # rubocop:disable Metrics
a = Time.parse(event.end)
event.end = Time.new(a.year, a.month, a.day, a.hour, a.min, a.sec, "+00:00")
event.set_default_times
- event.nonsense_attr = 'beep'
+ event.nonsense_attr = 'nonsense'
add_event(event)
rescue Exception => e
puts e
diff --git a/lib/ingestors/osci_ingestor.rb b/lib/ingestors/osci_ingestor.rb
index dc65830d5..c9e2cd076 100644
--- a/lib/ingestors/osci_ingestor.rb
+++ b/lib/ingestors/osci_ingestor.rb
@@ -37,8 +37,8 @@ def process_osci(url)
event_page.each do |event_data|
next if event_data.get_attribute('class').include?('no-events')
- beep = event_data.css("div[id*=calendar-my-calendar]")
- beep.each do |boop|
+ event_cal = event_data.css("div[id*=calendar-my-calendar]")
+ event_cal.each do |boop|
event = OpenStruct.new
el = boop.css("h3[class='event-title summary']")[0]
url_str = el.css("a")[0].get_attribute('href')
diff --git a/lib/modules/chatgpt_service.rb b/lib/modules/chatgpt_service.rb
index b5311ced4..8df16fb10 100644
--- a/lib/modules/chatgpt_service.rb
+++ b/lib/modules/chatgpt_service.rb
@@ -8,7 +8,7 @@ def initialize
@params = {
# max_tokens: 50,
# model: 'gpt-3.5-turbo-1106',
- model: TeSS::Config.llm_scraper.model_version,
+ model: TeSS::Config.llm_scraper['model_version'],
temperature: 0.7
}
end
diff --git a/llm_process_prompt.txt b/lib/modules/llm_prompts/llm_process_prompt.txt
similarity index 100%
rename from llm_process_prompt.txt
rename to lib/modules/llm_prompts/llm_process_prompt.txt
diff --git a/llm_scrape_prompt.txt b/lib/modules/llm_prompts/llm_scrape_prompt.txt
similarity index 100%
rename from llm_scrape_prompt.txt
rename to lib/modules/llm_prompts/llm_scrape_prompt.txt
diff --git a/lib/modules/llm_service.rb b/lib/modules/llm_service.rb
index 9d3a4f488..0923b7d36 100644
--- a/lib/modules/llm_service.rb
+++ b/lib/modules/llm_service.rb
@@ -26,7 +26,7 @@ def unload_json(event, response)
def scrape(event_page)
@scrape_or_process = 'scrape'
- @prompt = File.read('llm_scrape_prompt.txt')
+ @prompt = File.read('lib/modules/llm_prompts/llm_scrape_prompt.txt')
@input = event_page
content = @prompt.gsub('*replace_with_event_page*', event_page)
@output = run(content)
@@ -36,7 +36,7 @@ def scrape(event_page)
def process(event)
@scrape_or_process = 'process'
event_json = JSON.generate(event.to_json)
- @prompt = File.read('llm_process_prompt.txt')
+ @prompt = File.read('lib/modules/llm_prompts/llm_process_prompt.txt')
@input = event_json
content = @prompt.gsub('*replace_with_event*', event_json)
@output = run(content)
diff --git a/test/unit/ingestors/4tu_gpt_llm_ingestor_test.rb b/test/unit/ingestors/4tu_gpt_llm_ingestor_test.rb
new file mode 100644
index 000000000..1e12e564e
--- /dev/null
+++ b/test/unit/ingestors/4tu_gpt_llm_ingestor_test.rb
@@ -0,0 +1,73 @@
+require 'test_helper'
+require 'minitest/autorun'
+
+class FourtuGptLlmIngestorTest < ActiveSupport::TestCase
+ setup do
+ @user = users(:regular_user)
+ @content_provider = content_providers(:another_portal_provider)
+ mock_ingestions
+ mock_timezone # System time zone should not affect test result
+ end
+
+ teardown do
+ reset_timezone
+ end
+
+ test 'can ingest events from 4tu' do
+ source = @content_provider.sources.build(
+ url: 'https://www.4tu.nl/en/agenda/',
+ method: '4tu',
+ enabled: true
+ )
+
+ ingestor = Ingestors::FourtuLlmIngestor.new
+
+ # check event doesn't
+ new_title = '4TU-meeting National Technology Strategy'
+ refute Event.where(title: new_title).any?
+
+ run_res = '{
+ "title":"4TU-meeting National Technology Strategy",
+ "start":"2024-07-03T12:30:00+02:00",
+ "end":"2024-07-03T19:00:00+02:00",
+ "venue":"Basecamp, Nijverheidsweg 16A, 3534 AM Utrecht (https://basecamputrecht.nl)",
+ "description":"My cool description",
+ "nonsense_attr":"My cool nonsense attribute"
+ }'.gsub(/\n/, '')
+ mock_client = Minitest::Mock.new
+ 8.times do
+ mock_client.expect(:chat, {'choices'=> {0=> {'message'=> {'content'=> run_res}}}}, parameters: Object)
+ end
+ # run task
+ assert_difference 'Event.count', 1 do
+ freeze_time(2019) do
+ VCR.use_cassette("ingestors/4tu_gpt_llm") do
+ OpenAI::Client.stub(:new, mock_client) do
+ with_settings({ llm_scraper: { model: 'chatgpt', model_version: 'GPT-3.5' } }) do
+ ingestor.read(source.url)
+ ingestor.write(@user, @content_provider)
+ end
+ end
+ end
+ end
+ end
+
+ assert_equal 4, ingestor.events.count
+ assert ingestor.materials.empty?
+ assert_equal 1, ingestor.stats[:events][:added]
+ assert_equal 3, ingestor.stats[:events][:updated]
+ assert_equal 0, ingestor.stats[:events][:rejected]
+
+ # check event does exist
+ event = Event.where(title: new_title).first
+ assert event
+ assert_equal new_title, event.title
+
+ # check other fields
+ assert_equal Time.zone.parse('Wed, 3 Jul 2024 12:30:00.000000000 UTC +00:00'), event.start
+ assert_equal Time.zone.parse('Wed, 3 Jul 2024 19:00:00.000000000 UTC +00:00'), event.end
+ assert_equal 'Amsterdam', event.timezone
+ assert_equal 'Basecamp, Nijverheidsweg 16A, 3534 AM Utrecht (https://basecamputrecht.nl)', event.venue
+ assert_equal 'LLM', event.source
+ end
+end
diff --git a/test/unit/ingestors/4tu_llm_ingestor_test.rb b/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb
similarity index 92%
rename from test/unit/ingestors/4tu_llm_ingestor_test.rb
rename to test/unit/ingestors/4tu_willma_llm_ingestor_test.rb
index 803be3e14..a1c1e43b4 100644
--- a/test/unit/ingestors/4tu_llm_ingestor_test.rb
+++ b/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb
@@ -1,6 +1,6 @@
require 'test_helper'
-class FourtuLlmIngestorTest < ActiveSupport::TestCase
+class FourtuWillmaLlmIngestorTest < ActiveSupport::TestCase
setup do
@user = users(:regular_user)
@content_provider = content_providers(:another_portal_provider)
@@ -25,13 +25,13 @@ class FourtuLlmIngestorTest < ActiveSupport::TestCase
new_title = '4TU-meeting National Technology Strategy'
refute Event.where(title: new_title).any?
- get_beep = '{
+ get_body = '{
"boop": "{
\"name\": \"Zephyr 7B\",
\"id\": 0
}"
}'.gsub(/\n/, '')
- post_beep = '{
+ post_body = '{
"message": "Here is your JSON:
{
\"title\":\"4TU-meeting National Technology Strategy\",
@@ -47,8 +47,8 @@ class FourtuLlmIngestorTest < ActiveSupport::TestCase
assert_difference 'Event.count', 1 do
freeze_time(2019) do
VCR.use_cassette("ingestors/4tu_llm") do
- WebMock.stub_request(:get, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: get_beep)
- WebMock.stub_request(:post, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: post_beep)
+ WebMock.stub_request(:get, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: get_body)
+ WebMock.stub_request(:post, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: post_body)
with_settings({ llm_scraper: { model: 'willma', model_version: 'Zephyr 7B' } }) do
ingestor.read(source.url)
ingestor.write(@user, @content_provider)
diff --git a/test/vcr_cassettes/ingestors/4tu_gpt_llm.yml b/test/vcr_cassettes/ingestors/4tu_gpt_llm.yml
new file mode 100644
index 000000000..828e53abd
--- /dev/null
+++ b/test/vcr_cassettes/ingestors/4tu_gpt_llm.yml
@@ -0,0 +1,278 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Thu, 06 Jun 2024 07:51:56 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Transfer-Encoding:
+ - chunked
+ Connection:
+ - keep-alive
+ Vary:
+ - Accept-Encoding
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Cache-Control:
+ - no-cache
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnRzb3ZlcnZpZXcgcGFnZWhlYWRlci0tZmxhdHRlbiBzaXRlaGVhZGVyLS1tZW51YmFyLXRyYW5zbHVjZW50IiBkYXRhLXRyYWNraW5naWQ9IiI+PGhlYWQ+PG1ldGEgY2hhcnNldD0idXRmLTgiPjx0aXRsZT5BZ2VuZGE8L3RpdGxlPgo8IS0tClJlYWxpc2F0aWU6IPCfkrwgV2ViSGFyZSBidgogICAgICAgICAgICDwn4yQIGh0dHBzOi8vd3d3LndlYmhhcmUubmwvCi0tPgo8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEiIC8+PGxpbmsgcmVsPSJhcHBsZS10b3VjaC1pY29uIiBzaXplcz0iMTgweDE4MCIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2FwcGxlLXRvdWNoLWljb24tMTgweDE4MC5wbmciIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTMyeDMyLnBuZyIgc2l6ZXM9IjMyeDMyIiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi05Nng5Ni5wbmciIHNpemVzPSI5Nng5NiIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tMTk0eDE5NC5wbmciIHNpemVzPSIxOTR4MTk0IiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vYW5kcm9pZC1jaHJvbWUtMTkyeDE5Mi5wbmciIHNpemVzPSIxOTJ4MTkyIiAvPjxsaW5rIHJlbD0ibWFzay1pY29uIiAgICAgICAgICAgICBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vc2FmYXJpLXBpbm5lZC10YWIuc3ZnIiBjb2xvcj0iI2ZmOGIzOCIgLz48bWV0YSBuYW1lPSJ0aGVtZS1jb2xvciIgY29udGVudD0iI2ZmZmZmZiIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6dHlwZSIgY29udGVudD0id2Vic2l0ZSIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6c2l0ZV9uYW1lIiBjb250ZW50PSJGZWRlcmF0aW9uIiAvPjxtZXRhIHByb3BlcnR5PSJvZzp0aXRsZSIgY29udGVudD0iQWdlbmRhIiAvPjxzY3JpcHQgbm9tb2R1bGU+IGlmKCEhd2luZG93Lk1TSW5wdXRNZXRob2RDb250ZXh0ICYmICEhZG9jdW1lbnQuZG9jdW1lbnRNb2RlKWRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGFzc0xpc3QuYWRkKCJ1bnN1cHBvcnRlZC1icm93c2VyIik7PC9zY3JpcHQ+PHNjcmlwdCB0eXBlPSJhcHBsaWNhdGlvbi9qc29uIiBpZD0id2gtY29uZmlnIj57ImRlc2lnbmNkbnJvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS8iLCJkZXNpZ25yb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvIiwiZHRhcHN0YWdlIjoicHJvZHVjdGlvbiIsImltZ3Jvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvIiwiaXNsaXZlIjp0cnVlLCJsb2NhbGUiOiJlbi1VUyIsIm9iaiI6eyJuYXZwYXRoaXRlbSI6eyJsaW5rIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJ0aXRsZSI6IkFnZW5kYSJ9fSwic2VydmVyIjo1MDUwMCwic2l0ZSI6e30sInNpdGVyb290IjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsInNvY2lhbGl0ZTpndG0iOnsiYSI6IkdUTS1XVFo1RlJRIiwiaCI6dHJ1ZSwibSI6ZmFsc2V9fTwvc2NyaXB0PjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iLy5hcC80dHUuc2l0ZS9hcC5jc3MiPjxzY3JpcHQgc3JjPSIvLmFwLzR0dS5zaXRlL2FwLm1qcyIgdHlwZT0ibW9kdWxlIiBhc3luYz48L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2xkK2pzb24iPnsiQGNvbnRleHQiOiJodHRwczovL3NjaGVtYS5vcmciLCJAdHlwZSI6IkJyZWFkY3J1bWJMaXN0IiwiaXRlbUxpc3RFbGVtZW50IjpbeyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iLCJuYW1lIjoiRmVkZXJhdGlvbiIsInBvc2l0aW9uIjoxfSx7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJuYW1lIjoiQWdlbmRhIiwicG9zaXRpb24iOjJ9XX08L3NjcmlwdD48L2hlYWQ+PGJvZHk+PG5vc2NyaXB0PjxpZnJhbWUgc3JjPSIvL3d3dy5nb29nbGV0YWdtYW5hZ2VyLmNvbS9ucy5odG1sP2lkPUdUTS1XVFo1RlJRIiBoZWlnaHQ9IjAiIHdpZHRoPSIwIiBzdHlsZT0iZGlzcGxheTpub25lO3Zpc2liaWxpdHk6aGlkZGVuIj48L2lmcmFtZT48L25vc2NyaXB0PjxkaXYgY2xhc3M9InNwYy1tb2RhbGl0eWxheWVyIj48L2Rpdj48ZGl2IGlkPSJzbGlkZW1lbnUtY29udGFpbmVyIj48ZGl2IGlkPSJzbGlkZW1lbnUiIHRhYmluZGV4PSItMSIgICAgPjxkaXYgY2xhc3M9InNpZGViYXJfX2hlYWRlciI+IDxhIGNsYXNzPSJzaWRlYmFyX19oZWFkZXJfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJzaWRlYmFyX19pZGVudGl0eV9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJzaWRlYmFyX19pZGVudGl0eV9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PGJ1dHRvbiBpZD0ic2xpZGVtZW51LWNsb3NlIiBjbGFzcz0ic2lkZWJhci1hY3Rpb24tY2xvc2UiIHR5cGU9ImJ1dHRvbiIgYXJpYS1sYWJlbD0iQ2xvc2UiID48L2J1dHRvbj48L2Rpdj48dWwgY2xhc3M9InNpZGViYXJfX21lbnUgc2lkZWJhcl9fbWVudS0tbGV2ZWwxIiAgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIgPkhvbWU8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+UmVzZWFyY2g8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPkFib3V0IG91ciByZXNlYXJjaDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLzR0dS1jZW50cmVzLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPjRUVSBDZW50cmVzPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIiA+QU1JIChNYXRoZW1hdGljcyk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIiA+QnVpbHQgRW52aXJvbm1lbnQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyIgPkRlc2lnbiBVbml0ZWQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iID5FbmVyZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyIgPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIiA+SGVhbHRoPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIiA+SGlnaC1UZWNoIE1hdGVyaWFsczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyIgPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyIgPk5JUklDVCAoSUNUKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iID5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+SGlnaCBUZWNoIGZvciBhIFN1c3RhaW5hYmxlIEZ1dHVyZTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIiA+SFRTRiBJIFByb2dyYW1tZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyIgPkhUU0YgSUkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLXZpZGVvcy8iID5IVFNGIHZpZGVvczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyIgPjRUVS5SZXNlYXJjaERhdGE8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL0VFLU5MLyIgPkVsZWN0cmljYWwgRW5naW5lZXJpbmcgTmV0aGVybGFuZHM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5FZHVjYXRpb248L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5BYm91dCBvdXIgZWR1Y2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIiA+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyIgPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iID5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi9lZHVjYXRpb25wcm9ncmFtbWVzLyIgPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YnV0dG9uIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICI+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+VmFsb3Jpc2F0aW9uPC9idXR0b24+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0JTIwYWN0aXZpdGllcy8iID40VFUuSU1QQUNUPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iID5BYm91dCA0VFUuSW1wYWN0PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0YXJ0dXAlMjBtaXNzaW9ucy8iID5TdGFydHVwIG1pc3Npb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5NZWRpYTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9pbnNpZ2h0ZnVsLWlubm92YXRvcnMvIiA+SW5zaWdodGZ1bCBJbm5vdmF0b3JzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL1NwaW4tb2ZmJTIwc2VyaWUvIiA+U3Bpbi1PZmYgU3RvcmllczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3R1ZGVudCUyMGNoYWxsZW5nZXMvIiA+U3R1ZGVudCBjaGFsbGVuZ2VzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1R1c3NlbnBhZ2luYSUyMHZvb3JhZmdhYW5kJTIwYWFuJTIwU3RhcnR1cCUyMFN1cHBvcnQvIiA+QWJvdXQgU3RhcnR1cCBTdXBwb3J0PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+TmV3czwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gIHNpZGVtYWlubWVudV9faXRlbS0tZXhwYW5kICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19zZWxlY3RlZCAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5BYm91dCA0VFU8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS80dHUtaW4tMS1taW51dGUvIiA+NFRVIGluIG9ubHkgMSBtaW51dGU8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9mYWN0cy1maWd1cmVzLyIgPkZhY3RzIGFuZCBmaWd1cmVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvb3JnYW5pc2F0aW9uLyIgPk9yZ2FuaXNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L3B1YmxpY2F0aW9ucy8iID5QdWJsaWNhdGlvbnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9hbHVtbmkvIiA+QWx1bW5pPC9hPjwvbGk+PC91bD48L2xpPjwvdWw+PG5hdiBjbGFzcz0ic2lkZWJhcl9fbGFuZ3VhZ2VzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvIj5OTDwvYT4gfCA8c3BhbiBjbGFzcz0ic2VsZWN0ZWQiPkVOPC9zcGFuPjwvbmF2PjxuYXYgY2xhc3M9InNpZGViYXJfX3NlY29uZGFyeWxpbmtzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vY29udGFjdC8iPkNvbnRhY3Q8L2E+PC9uYXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcC1iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhci1iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wIj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19jb250ZW50Ij48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19pZGVudGl0eSI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fc2xvZ2FuIj5QYXJ0IG9mIHRoZSA8YnV0dG9uIGNsYXNzPSJoZWFkZXItdG9wX190b2dnbGVleHBsb3JlcGFuZWwiPjRUVS5GZWRlcmF0aW9uPC9idXR0b24+PC9kaXY+PGEgY2xhc3M9ImhlYWRlci10b3BfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX29yZ2FuaXphdGlvbnMiPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWRlbGZ0Lm5sL2VuLyIgdGl0bGU9IlRVIERlbGZ0IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWRlbGZ0LnN2ZyIgYWx0PSJUVSBEZWxmdCIgd2lkdGg9IjEwMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZS5ubC9lbi8iIHRpdGxlPSJUVSBFaW5kaG92ZW4iID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZWluZGhvdmVuLnN2ZyIgYWx0PSJUVSBFaW5kaG92ZW4iIHdpZHRoPSIxMzAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy51dHdlbnRlLm5sL2VuLyIgdGl0bGU9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci91bml2ZXJzaXR5LW9mLXR3ZW50ZS5zdmciIGFsdD0iVW5pdmVyc2l0eSBvZiBUd2VudGUiIHdpZHRoPSIxMDAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy53dXIubmwvIiB0aXRsZT0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXd1ci5zdmciIGFsdD0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiB3aWR0aD0iMTMyIiAvPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhciI+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX2NvbnRlbnQiPjxhIGNsYXNzPSJoZWFkZXItbWVudWJhcl9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc3BhY2VyIj48L2Rpdj48bmF2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fbWVudWJhciIgYXJpYS1sYWJlbD0iTWFpbiI+PHVsIGNsYXNzPSJzcGMtbWVudWJhciI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iID5Ib21lPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5SZXNlYXJjaDwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+QWJvdXQgb3VyIHJlc2VhcmNoPC9hPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC80dHUtY2VudHJlcy8iID40VFUgQ2VudHJlczwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyIgPkFNSSAoTWF0aGVtYXRpY3MpPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyIgPkJ1aWx0IEVudmlyb25tZW50PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iID5EZXNpZ24gVW5pdGVkPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIiA+RW5lcmd5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iID5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyIgPkhlYWx0aDwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyIgPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iID5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iID5OSVJJQ1QgKElDVCk8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIiA+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvIiA+SGlnaCBUZWNoIGZvciBhIFN1c3RhaW5hYmxlIEZ1dHVyZTwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIiA+SFRTRiBJIFByb2dyYW1tZXM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyIgPkhUU0YgSUkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLXZpZGVvcy8iID5IVFNGIHZpZGVvczwvYT48L2xpPjwvdWw+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iID40VFUuUmVzZWFyY2hEYXRhPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvRUUtTkwvIiA+RWxlY3RyaWNhbCBFbmdpbmVlcmluZyBOZXRoZXJsYW5kczwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5FZHVjYXRpb248L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5BYm91dCBvdXIgZWR1Y2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyIgPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIiA+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iID5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vZWR1Y2F0aW9ucHJvZ3JhbW1lcy8iID5FZHVjYXRpb24gcHJvZ3JhbW1lczwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iIiA+VmFsb3Jpc2F0aW9uPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdCUyMGFjdGl2aXRpZXMvIiA+NFRVLklNUEFDVDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyIgPkFib3V0IDRUVS5JbXBhY3Q8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0YXJ0dXAlMjBtaXNzaW9ucy8iID5TdGFydHVwIG1pc3Npb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhLyIgPk1lZGlhPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL2luc2lnaHRmdWwtaW5ub3ZhdG9ycy8iID5JbnNpZ2h0ZnVsIElubm92YXRvcnM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvU3Bpbi1vZmYlMjBzZXJpZS8iID5TcGluLU9mZiBTdG9yaWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3R1ZGVudCUyMGNoYWxsZW5nZXMvIiA+U3R1ZGVudCBjaGFsbGVuZ2VzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9UdXNzZW5wYWdpbmElMjB2b29yYWZnYWFuZCUyMGFhbiUyMFN0YXJ0dXAlMjBTdXBwb3J0LyIgPkFib3V0IFN0YXJ0dXAgU3VwcG9ydDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlbGVjdGVkIj5BZ2VuZGE8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iID5BYm91dCA0VFU8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS80dHUtaW4tMS1taW51dGUvIiA+NFRVIGluIG9ubHkgMSBtaW51dGU8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvZmFjdHMtZmlndXJlcy8iID5GYWN0cyBhbmQgZmlndXJlczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9vcmdhbmlzYXRpb24vIiA+T3JnYW5pc2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L3B1YmxpY2F0aW9ucy8iID5QdWJsaWNhdGlvbnM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2FsdW1uaS8iID5BbHVtbmk8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PC91bD48L25hdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc3BhY2VyIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fbGFuZ3VhZ2VzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvIj5OTDwvYT58PHNwYW4+RU48L3NwYW4+PC9kaXY+PGZvcm0gYWN0aW9uPSJodHRwczovL3d3dy40dHUubmwvZW4vc2VhcmNoLyIgbWV0aG9kPSJHRVQiIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNod3JhcHBlciIgYXV0b2NvbXBsZXRlPSJvZmYiID48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoLWlucHV0LWFuZC1zdWdnZXN0aW9ucy13cmFwcGVyIj48aW5wdXQgaWQ9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgbmFtZT0icXVlcnkiIGRhdGEtc3VnZ2VzdD0iNHR1OmNvcnBvcmF0ZV9lbiIgZGF0YS1zdWdnZXN0cGFyZW50PSJwYXJlbnQiIHBsYWNlaG9sZGVyPSJab2VrZW4iIGFyaWEtbGFiZWw9IlpvZWtlbiIgdHlwZT0ic2VhcmNoIiAvPjwvZGl2PjxsYWJlbCBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaCIgZm9yPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoaW5wdXQiIHRhYmluZGV4PSItMSIgPjxzcGFuIGNsYXNzPSJmYXIgZmEtc2VhcmNoIj48L3NwYW4+PC9sYWJlbD48L2Zvcm0+PGJ1dHRvbiBpZD0iaGVhZGVyLW1lbnViYXJfc2lkZWJhcnRvZ2dsZSIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zaG93c2lkZW1haW5tZW51IHNpZGViYXItYWN0aW9uLXRvZ2dsZSIgYXJpYS1sYWJlbD0iT3BlbiBtZW51IiBhcmlhLWV4cGFuZGVkPSJmYWxzZSIgYXJpYS1jb250cm9scz0ic2xpZGVtZW51IiA+PHNwYW4gY2xhc3M9ImZhciBmYS1iYXJzIj48L3NwYW4+PC9idXR0b24+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX3RvcGJhciI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jbG9zZSI+Q2xvc2U8L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbnMiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fYWRkcmVzcyBydGRjb250ZW50Ij48cCBjbGFzcz0iaGVhZGluZyI+NFRVLkZlZGVyYXRpb248L3A+PHAgY2xhc3M9Im5vcm1hbCI+KzMxKDApNiA0OCAyNyA1NSA2MTwvcD48cCBjbGFzcz0ibm9ybWFsIj48YSBocmVmPSJtYWlsdG86cHJvamVjdGxlaWRlckA0dHUubmwiPnNlY3JldGFyaXNANHR1Lm5sPC9hPjwvcD48cCBjbGFzcz0ibm9ybWFsIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48Yj5XZWJzaXRlOiA0VFUubmw8L2I+PC9hPjwvcD48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiBleHBsb3JlcGFuZWxfX2NvbHVtbi0tbWFueWl0ZW1zIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlJlc2VhcmNoPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyBleHBsb3JlcGFuZWxfX2l0ZW1zLS1tYW55aXRlbXMgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyI+PHNwYW4+QXBwbGllZCBNYXRoZW1hdGljcyBJbnN0aXR1dGU8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyI+PHNwYW4+QnVpbHQgRW52aXJvbm1lbnQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iPjxzcGFuPkRlc2lnbiBVbml0ZWQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIj48c3Bhbj5FbmVyZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iPjxzcGFuPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyI+PHNwYW4+SGVhbHRoPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyI+PHNwYW4+SGlnaC1UZWNoIE1hdGVyaWFsczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iPjxzcGFuPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iPjxzcGFuPk5JUklDVCAoSUNUKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIj48c3Bhbj5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIj48c3Bhbj5SZXNlYXJjaERhdGE8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIj48c3Bhbj5IVFNGIEkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIj48c3Bhbj5IVFNGIElJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiAiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuRWR1Y2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyAgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyI+PHNwYW4+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iPjxzcGFuPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIj48c3Bhbj5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcndpanMvb25kZXJ3aWpzcHJvZ3JhbW1hcy8iPjxzcGFuPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiAiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuVmFsb3Jpc2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyAgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIj48c3Bhbj40VFUuSU1QQUNUPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3RlY2gtdHJhbnNmZXIubmwvZW4vIj48c3Bhbj5UaGVtYXRpYyBUZWNobm9sb2d5IFRyYW5zZmVyPC9zcGFuPjwvYT48YSBocmVmPSIiPjxzcGFuPlNwaW4tb2ZmIFN0b3JpZXM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vNHR1aW1wYWN0Y2hhbGxlbmdlLm5sLyI+PHNwYW4+NFRVIEltcGFjdCBDaGFsbGVuZ2U8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fc2xpZGVzaG93IGNhcnJvdXNlbF9fdmlld3BvcnQgY2Fycm91c2VsX19kcmFnYXJlYSAiPjxzdHlsZT5AbWVkaWEgKG1heC13aWR0aDogNzY3cHgpey5oZWFkZXJzbGlkZTB7YmFja2dyb3VuZC1jb2xvcjogI0I5QjBBMztiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pMjRhODc2YzUwMTAyYWFlMTAyMDBjOTU1YTYwMTlmOTM1YmJkYmE4ZDM1MTkwODAxZTM0MDBiMDAwNzgxNDYvNHR1LWZhbGxiYWNrLWhlYWRlci5qcGcpO319QG1lZGlhIChtaW4td2lkdGg6IDc2OHB4KXsuaGVhZGVyc2xpZGUwe2JhY2tncm91bmQtY29sb3I6ICNCOUIwQTM7YmFja2dyb3VuZC1pbWFnZTogdXJsKC8udWMvaTQ5YTY4MGY4MDEwMmFhZTEwMjAwYzk1NWE2MDE5ZjkzNWJiZGJhOGQzNTE5MDgwMWUzNDAwYjYwMDQ4MTQ2LzR0dS1mYWxsYmFjay1oZWFkZXIuanBnKTt9fTwvc3R5bGU+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlIGNhcnJvdXNlbF9fY2VsbCBhY3RpdmVzbGlkZSBoZWFkZXJzbGlkZTAgIiBkYXRhLXNsaWRlc2hvdy1lbGVtZW50cz0icGFnZS1oZWFkZXJfX3NsaWRlMF9fY29udGVudCIgc3R5bGU9IiIgPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19jb250ZW50Ij48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fbWV0YSI+PGgxIGNsYXNzPSJwYWdlLWhlYWRlcl9fdGl0bGUiPkFnZW5kYTwvaDE+PC9kaXY+PC9kaXY+PG1haW4gY2xhc3M9InBhZ2VfX2JvZHkgICI+PGZvcm0gaWQ9IiIgIGNsYXNzPSJwYWdlX19oZWFkZXJmaWx0ZXJzICAgIj48L2Zvcm0+PGRpdiBjbGFzcz0icGFnZV9fY29udGVudGFyZWEgcGFnZV9fY29udGVudGFyZWEtLXJ0ZGRvYyAgIGhlYWRlcmlzb3BhcXVlICI+PGRpdiBjbGFzcz0icGFnZS1jb250ZW50c3RhcnQiPjwvZGl2PjwhLS13aF9jb25zaWxpb19jb250ZW50LS0+PGRpdiBjbGFzcz0ibmVvdGFicyI+PHNwYW4+VXBjb21pbmc8L3NwYW4+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS9hcmNoaXZlIj5BcmNoaXZlPC9hPjwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdHMiPjxhIGNsYXNzPSJzZWFyY2hyZXN1bHQiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvc3VtbWVyLWV2ZW50LTIwMjQvIj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2NvbnRlbnQiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9faW1hZ2Vjb2wiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9faW1hZ2UiIHN0eWxlPSIgYmFja2dyb3VuZC1jb2xvcjogIzU2NUEzOTsgYmFja2dyb3VuZC1pbWFnZTogdXJsKC8udWMvaTEwZWQzNDE3MDEwMjliMzMxMTAwYTU1ZDg4MDEyMWRhZGRjMmQzN2NhZTM4MDgwMWUzZWEwMGVhMDA4MTQxL3N1bW1lci0wMi5qcGcpOyAiPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fbWV0YWNvbCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19kYXRlIj5GcmkgNyBKdW4gMjAyNDwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fdGl0bGUiPjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQ8L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2Rlc2NyaXB0aW9uIj5Kb2luIHVzIGR1cmluZyBvdXIgYW5udWFsIHN1bW1lciBldmVudCBvbiBGcmlkYXkgNyBKdW5lIGF0IHRoZSBVbml2ZXJzaXR5IG9mIFR3ZW50ZS4gVGhlIG1haW4gcHVycG9zZSBvZiB0aGUgZXZlbnQgaXMgdG8gZ2V0IHRvIGtub3cgbmV3IGNvbGxlYWd1ZXMsIGV4cGxvcmUgY29tbW9uIHJlc2VhcmNoIG9yIHRlYWNoaW5nIGludGVyZXN0cywgaW52aXRlIGNvbGxhYm9yYXRpb24sIGFuZCBjYXRjaCB1cCB3aXRoIG9sZCBmcmllbmRzLjwvZGl2PjwvZGl2PjwvZGl2PjwvYT48YSBjbGFzcz0ic2VhcmNocmVzdWx0IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtNi0xOC13ZWJpbmFyLW1hdGhlbWF0aWNzLyI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19jb250ZW50Ij48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2ltYWdlY29sIj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2ltYWdlIiBzdHlsZT0iIGJhY2tncm91bmQtY29sb3I6ICMxRDFBMUQ7IGJhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2lhZjU3N2MzYzAxMDI1NGY4MTAwMDAzZGVhNjAxYzYwNDcyZTNhNmQyY2ZkNjA4MDFlM2VhMDBlYTAwODE0MS90aGUtY29uY2VwdC1vZi1yZWFkaW5nLWxvdmUtMjAyMy0xMS0yNy0wNS0xMi0wOS11dGMuanBnKTsgIj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX21ldGFjb2wiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fZGF0ZSI+VHVlIDE4IEp1biAyMDI0IC8gMTAuMDAgLSAxMS4zMDwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fdGl0bGUiPlVDTCdzIEV4cGVyaWVuY2Ugd2l0aCBDQkwgaW4gRW5naW5lZXJpbmcgZWR1Y2F0aW9uIHdpdGggQmlyZ2l0IFBlcGluIGFuZCBNYXRoZXVzIE8uIGRlIEFuZHJhZGU8L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX2Rlc2NyaXB0aW9uIj5Mb2NhdGlvbjogb25saW5lPC9kaXY+PC9kaXY+PC9kaXY+PC9hPjxhIGNsYXNzPSJzZWFyY2hyZXN1bHQiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvNFRVLW1lZXRpbmclMjBOYXRpb25hbCUyMFRlY2hub2xvZ3klMjBTdHJhdGVneS8iPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fY29udGVudCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19pbWFnZWNvbCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19pbWFnZSIgc3R5bGU9ImJhY2tncm91bmQtcG9zaXRpb246IDU2LjgzNzYlIDgwLjM0MTklOyBiYWNrZ3JvdW5kLWNvbG9yOiAjRkRGRUZFOyBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pNDhhMDM3NzMwMTAyMGEzMTEzMDA3NzAxZDQwMWMxZTIxMmVlZjhmNGE3YzcwODAxZTNlYTAwZWEwMDgxNDEvZXprLW50cy5wbmcuanBnKTsgIj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX21ldGFjb2wiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fZGF0ZSI+V2VkIDMgSnVsIDIwMjQgLyAxMi4zMCAtIDE4LjAwPC9kaXY+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X190aXRsZSI+NFRVLW1lZXRpbmcgTmF0aW9uYWwgVGVjaG5vbG9neSBTdHJhdGVneTwvZGl2PjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fZGVzY3JpcHRpb24iPjRUVS1tZWV0aW5nIG9uIHRoZSBOYXRpb25hbCBUZWNobm9sb2d5IFN0cmF0ZWd5IChOVFMpIC0gbG9jYXRpb24gVXRyZWNodDwvZGl2PjwvZGl2PjwvZGl2PjwvYT48YSBjbGFzcz0ic2VhcmNocmVzdWx0IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtMTAtMDktcm9vbS1mb3ItZXZlcnlvbmVzLWVkdWNhdGlvbmFsLXRhbGVudC8iPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fY29udGVudCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19pbWFnZWNvbCI+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19pbWFnZSIgc3R5bGU9IiBiYWNrZ3JvdW5kLWNvbG9yOiAjMzEyQTJGOyBiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pMWFjMjkxMWYwMTAyNmFmODEwMDBiN2ZmYmIwMTMyYjA0OGNlZjRjYTVlOGQwODAxZTNlYTAwZWEwMDgxNDEvdGVhY2hpbmctbGVhcm5pbmcuanBnKTsgIj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX21ldGFjb2wiPjxkaXYgY2xhc3M9InNlYXJjaHJlc3VsdF9fZGF0ZSI+V2VkIDkgT2N0IDIwMjQ8L2Rpdj48ZGl2IGNsYXNzPSJzZWFyY2hyZXN1bHRfX3RpdGxlIj5Sb29tIGZvciBldmVyeW9uZSdzIGVkdWNhdGlvbmFsIHRhbGVudCAtIEV2ZW50PC9kaXY+PGRpdiBjbGFzcz0ic2VhcmNocmVzdWx0X19kZXNjcmlwdGlvbiI+TG9jYXRpb246IFNvY2lhbCBJbXBhY3QgRmFjdG9yeSBWcmVkZW5idXJnIFV0cmVjaHQ8L2Rpdj48L2Rpdj48L2Rpdj48L2E+PC9kaXY+PCEtLS93aF9jb25zaWxpb19jb250ZW50LS0+PGRpdiBjbGFzcz0icGFnZV9fYmFsbG9vbiI+PC9kaXY+PGRpdiBjbGFzcz0icGFnZV9fZm9vdGVyIj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXJfX2NvbnRlbnQgbmF2cGF0aCI+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPkhvbWU8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19pdGVtIGNydW1icGF0aC0tY3VycmVudHBhZ2UiPkFnZW5kYTwvc3Bhbj48L2Rpdj48L2Rpdj48L2Rpdj48L21haW4+PGRpdiBjbGFzcz0iZm9vdGVyIj48ZGl2IGNsYXNzPSJmb290ZXJfX3BhbmVsIj48ZGl2IGNsYXNzPSJmb290ZXJfX2lkZW50aXR5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19zaXRldGl0bGUiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48IS0tIEZJWE1FOiB1c2UgYXJpYS1oaWRkZW49InRydWUiIGJlY2F1c2UgaXQncyBhIGR1cGxpY2F0ZSBvZiB0aGUgaXRlbXMgb24gdGhlIG1lbnUgYmFyID8gLS0+IDxuYXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMSBmb290ZXJfX21haW5tZW51IiBhcmlhLWxhYmVsPSJNYWluIj4gPHVsPiAgIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyI+UmVzZWFyY2g8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIj5FZHVjYXRpb248L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9IiI+VmFsb3Jpc2F0aW9uPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyI+TmV3czwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFnZW5kYTwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iPkFib3V0IDRUVTwvYT4gPC9saT4gICA8L3VsPiA8L25hdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMiI+IDxpbnB1dCB0eXBlPSJjaGVja2JveCIgbmFtZT0iZm9vdGVyY29sdW1uIiBpZD0iZm9vdGVyX19jb2x1bW4yX19leHBhbmQiIC8+IDxsYWJlbCBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciIGZvcj0iZm9vdGVyX19jb2x1bW4yX19leHBhbmQiPkNvbnRhY3Q8L2xhYmVsPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9fY29udGVudCBydGRjb250ZW50Ij4gPHAgY2xhc3M9Im5vcm1hbCI+KzMxKDApNiA4MyAyMiA1MCA1OTxiciAvPjxhIGhyZWY9Im1haWx0bzpwcm9qZWN0bGVpZGVyQDR0dS5ubCI+c2VjcmV0YXJpc0A0dHUubmw8L2E+PC9wPiA8L2Rpdj4gPC9kaXY+ICAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW4zIj4gPGlucHV0IHR5cGU9ImNoZWNrYm94IiBuYW1lPSJmb290ZXJjb2x1bW4iIGlkPSJmb290ZXJfX2NvbHVtbjNfX2V4cGFuZCIgLz4gPGxhYmVsIGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyIgZm9yPSJmb290ZXJfX2NvbHVtbjNfX2V4cGFuZCI+UG9zdGFkcmVzPC9sYWJlbD4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgcnRkY29udGVudCI+IDxwIGNsYXNzPSJub3JtYWwiPjRUVS5GZWRlcmF0aWU8YnIgLz5Qb3N0YnVzIDU8YnIgLz4yNjAwIEFBIERlbGZ0PC9wPiA8L2Rpdj4gPC9kaXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjQiPiAgPGRpdiBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtc19fZ3JvdXAiPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyI+Rm9sbG93IHVzPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgZm9vdGVyX19zb2NpYWxpdGVtcyAiPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vdHdpdHRlci5jb20vNFRVRmVkZXJhdGlvbiIgdGl0bGU9IlR3aXR0ZXIiID48c3BhbiBjbGFzcz0iZmFiIGZhLXR3aXR0ZXIiPjwvc3Bhbj48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbXBhbnkvNC10dS1mZWRlcmF0aW9uLyIgdGl0bGU9IkxpbmtlZEluIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS1saW5rZWRpbi1pbiI+PC9zcGFuPjwvYT48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS9jaGFubmVsL1VDTWtxaGp4MlcxaE5Sd3lzUnZXRVh3USIgdGl0bGU9IllvdXR1YmUiID48c3BhbiBjbGFzcz0iZmFiIGZhLXlvdXR1YmUiPjwvc3Bhbj48L2E+PC9kaXY+IDwvZGl2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyX19ncm91cCI+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyBmb290ZXJfX2NvbHVtbl9faGVhZGluZy0tbmV3c2xldHRlciAiPlN0YXkgdXAtdG8tZGF0ZTwvZGl2Pjxmb3JtIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXAgd2hwbHVnaW4tbmV3c2xldHRlci1zdWJzY3JpcHRpb24gICIgZGF0YS1uZXdzbGV0dGVyLWxpc3Q9IlNVQlNfNFRVX0NPUlBPUkFURV9OSUVVV1NCUklFRiIgPjxpbnB1dCBuYW1lPSJlbWFpbCIgcGxhY2Vob2xkZXI9IlNpZ24gdXAgZm9yIG91ciBuZXdzbGV0dGVyIiAvPjxidXR0b24gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VibWl0IiB0eXBlPSJzdWJtaXQiIG5hbWU9InN1Ym1pdGJ1dHRvbiIgYXJpYS1sYWJlbD0iU3Vic2NyaWJlIj48c3BhbiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwX19zdWJtaXRfX2ljb24gZmFyIGZhLWVudmVsb3BlIj48L3NwYW4+PC9idXR0b24+PC9mb3JtPjxkaXYgY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VjY2VzcyI+VGhhbmtzIGZvciBzdWJzY3JpYmluZyB0byBvdXIgbmV3c2xldHRlci48L2Rpdj4gIDwvZGl2PiA8L2Rpdj4gPGhyIGNsYXNzPSJmb290ZXJfX2RpdmlkZXIiIC8+IDxkZXRhaWxzIGNsYXNzPSJmb290ZXJfX2V4cGxvcmUiPjxzdW1tYXJ5PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fdG9nZ2xlX19jbG9zZWR0ZXh0Ij5QYXJ0IG9mIHRoZSA8c3BhbiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX19uYW1lIj40VFUuRmVkZXJhdGlvbjwvc3Bhbj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX3RvZ2dsZV9fb3BlbnRleHQiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jbG9zZSI+Q2xvc2U8L2Rpdj48L2Rpdj48L3N1bW1hcnk+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWwiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlJlc2VhcmNoPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyI+PHNwYW4+QXBwbGllZCBNYXRoZW1hdGljcyBJbnN0aXR1dGU8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyI+PHNwYW4+QnVpbHQgRW52aXJvbm1lbnQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iPjxzcGFuPkRlc2lnbiBVbml0ZWQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIj48c3Bhbj5FbmVyZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iPjxzcGFuPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyI+PHNwYW4+SGVhbHRoPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyI+PHNwYW4+SGlnaC1UZWNoIE1hdGVyaWFsczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iPjxzcGFuPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iPjxzcGFuPk5JUklDVCAoSUNUKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIj48c3Bhbj5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIj48c3Bhbj5SZXNlYXJjaERhdGE8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIj48c3Bhbj5IVFNGIEkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIj48c3Bhbj5IVFNGIElJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5FZHVjYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIj48c3Bhbj5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyI+PHNwYW4+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iPjxzcGFuPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyd2lqcy9vbmRlcndpanNwcm9ncmFtbWFzLyI+PHNwYW4+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlZhbG9yaXNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyI+PHNwYW4+NFRVLklNUEFDVDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly90ZWNoLXRyYW5zZmVyLm5sL2VuLyI+PHNwYW4+VGhlbWF0aWMgVGVjaG5vbG9neSBUcmFuc2Zlcjwvc3Bhbj48L2E+PGEgaHJlZj0iIj48c3Bhbj5TcGluLW9mZiBTdG9yaWVzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovLzR0dWltcGFjdGNoYWxsZW5nZS5ubC8iPjxzcGFuPjRUVSBJbXBhY3QgQ2hhbGxlbmdlPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48L2RldGFpbHM+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnMiPiA8ZGl2IGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtcyI+IDxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWRlbGZ0Lm5sL2VuLyIgdGl0bGU9IlRVIERlbGZ0IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWRlbGZ0LnN2ZyIgYWx0PSJUVSBEZWxmdCIgd2lkdGg9Ijg3IiBoZWlnaHQ9IjM0IiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuLyIgdGl0bGU9IlRVIEVpbmRob3ZlbiIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1laW5kaG92ZW4uc3ZnIiBhbHQ9IlRVIEVpbmRob3ZlbiIgd2lkdGg9IjEzMCIgaGVpZ2h0PSIyNyIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnV0d2VudGUubmwvZW4vIiB0aXRsZT0iVW5pdmVyc2l0eSBvZiBUd2VudGUiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL3VuaXZlcnNpdHktb2YtdHdlbnRlLnN2ZyIgYWx0PSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgd2lkdGg9Ijg1IiBoZWlnaHQ9IjMxIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cud3VyLm5sLyIgdGl0bGU9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby13dXIuc3ZnIiBhbHQ9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgd2lkdGg9IjE0NSIgaGVpZ2h0PSIyOSIgLz48L2E+IDwvZGl2PiA8L2Rpdj4gPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXIiPjxzcGFuIGNsYXNzPSJmb290ZXJfX2JvdHRvbWJhcl9fY29weXJpZ2h0Ij48c3BhbiBjbGFzcz0iZmJjcGFydCI+JmNvcHk7IDIwMjQgNFRVLkZlZGVyYXRpb248L3NwYW4+PC9zcGFuPjx1bCBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXJfX21lbnUiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vY29udGFjdC8iPkNvbnRhY3Q8L2E+PC9saT48L3VsPjwvZGl2PjwvZGl2PjwvYm9keT48L2h0bWw+
+ recorded_at: Wed, 02 Jan 2019 16:00:00 GMT
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/summer-event-2024/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Thu, 06 Jun 2024 07:51:56 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Content-Length:
+ - '34546'
+ Connection:
+ - keep-alive
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Last-Modified:
+ - Tue, 21 May 2024 20:39:53 GMT
+ Vary:
+ - Accept-Encoding
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnQgc2l0ZWhlYWRlci0tbWVudWJhci10cmFuc2x1Y2VudCBwYWdlLS13aXRoYmFja2xpbmsiIGRhdGEtdHJhY2tpbmdpZD0iIj48aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PHRpdGxlPjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQ8L3RpdGxlPjxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhL3N1bW1lci1ldmVudC0yMDI0LyI+CjwhLS0KUmVhbGlzYXRpZTog8J+SvCBXZWJIYXJlIGJ2CiAgICAgICAgICAgIPCfjJAgaHR0cHM6Ly93d3cud2ViaGFyZS5ubC8KLS0+CjxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSIgLz48bGluayByZWw9ImFwcGxlLXRvdWNoLWljb24iIHNpemVzPSIxODB4MTgwIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vYXBwbGUtdG91Y2gtaWNvbi0xODB4MTgwLnBuZyIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tMzJ4MzIucG5nIiBzaXplcz0iMzJ4MzIiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTk2eDk2LnBuZyIgc2l6ZXM9Ijk2eDk2IiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi0xOTR4MTk0LnBuZyIgc2l6ZXM9IjE5NHgxOTQiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9hbmRyb2lkLWNocm9tZS0xOTJ4MTkyLnBuZyIgc2l6ZXM9IjE5MngxOTIiIC8+PGxpbmsgcmVsPSJtYXNrLWljb24iICAgICAgICAgICAgIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9zYWZhcmktcGlubmVkLXRhYi5zdmciIGNvbG9yPSIjZmY4YjM4IiAvPjxtZXRhIG5hbWU9InRoZW1lLWNvbG9yIiBjb250ZW50PSIjZmZmZmZmIiAvPjxtZXRhIHByb3BlcnR5PSJvZzp0eXBlIiBjb250ZW50PSJ3ZWJzaXRlIiAvPjxtZXRhIHByb3BlcnR5PSJvZzpzaXRlX25hbWUiIGNvbnRlbnQ9IkZlZGVyYXRpb24iIC8+PG1ldGEgcHJvcGVydHk9Im9nOnRpdGxlIiBjb250ZW50PSI0VFUuQU1JIHN1bW1lciBldmVudCAyMDI0IiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZSIgY29udGVudD0iaHR0cHM6Ly93d3cuNHR1Lm5sLy51Yy9pN2IyODc5NzUwMTAyOWIzMzExMDBhNTVkODgwMTIxZGFkZGMyZDM3Y2FlMzgwNzAxYzNiMDA0NzYwMjgwL3N1bW1lci0wMi5qcGciIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlOndpZHRoIiBjb250ZW50PSIxMjAwIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTpoZWlnaHQiIGNvbnRlbnQ9IjYzMCIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2UiIGNvbnRlbnQ9Imh0dHBzOi8vd3d3LjR0dS5ubC8udWMvaWE0ZTQ3OWIzMDEwMjliMzMxMTAwYTU1ZDg4MDEyMWRhZGRjMmQzN2NhZTM4MDcwMWMzMmMwMTJjMDE4MC9zdW1tZXItMDIuanBnIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTp3aWR0aCIgY29udGVudD0iMzAwIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTpoZWlnaHQiIGNvbnRlbnQ9IjMwMCIgLz48c2NyaXB0IG5vbW9kdWxlPiBpZighIXdpbmRvdy5NU0lucHV0TWV0aG9kQ29udGV4dCAmJiAhIWRvY3VtZW50LmRvY3VtZW50TW9kZSlkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LmFkZCgidW5zdXBwb3J0ZWQtYnJvd3NlciIpOzwvc2NyaXB0PjxzY3JpcHQgdHlwZT0iYXBwbGljYXRpb24vanNvbiIgaWQ9IndoLWNvbmZpZyI+eyJkZXNpZ25jZG5yb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvIiwiZGVzaWducm9vdCI6Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlLyIsImR0YXBzdGFnZSI6InByb2R1Y3Rpb24iLCJpbWdyb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nLyIsImlzbGl2ZSI6dHJ1ZSwibG9jYWxlIjoiZW4tVVMiLCJvYmoiOnsibmF2cGF0aGl0ZW0iOnsibGluayI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvc3VtbWVyLWV2ZW50LTIwMjQvIiwidGl0bGUiOiI0VFUuQU1JIHN1bW1lciBldmVudCAyMDI0In19LCJzZXJ2ZXIiOjUwNTAwLCJzaXRlIjp7fSwic2l0ZXJvb3QiOiJodHRwczovL3d3dy40dHUubmwvZW4vIiwic29jaWFsaXRlOmd0bSI6eyJhIjoiR1RNLVdUWjVGUlEiLCJoIjp0cnVlLCJtIjpmYWxzZX19PC9zY3JpcHQ+PGxpbmsgcmVsPSJzdHlsZXNoZWV0IiBocmVmPSIvLmFwLzR0dS5zaXRlL2FwLmNzcyI+PHNjcmlwdCBzcmM9Ii8uYXAvNHR1LnNpdGUvYXAubWpzIiB0eXBlPSJtb2R1bGUiIGFzeW5jPjwvc2NyaXB0PjxzY3JpcHQgdHlwZT0iYXBwbGljYXRpb24vbGQranNvbiI+eyJAY29udGV4dCI6Imh0dHBzOi8vc2NoZW1hLm9yZyIsIkB0eXBlIjoiQnJlYWRjcnVtYkxpc3QiLCJpdGVtTGlzdEVsZW1lbnQiOlt7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsIm5hbWUiOiJGZWRlcmF0aW9uIiwicG9zaXRpb24iOjF9LHsiQHR5cGUiOiJMaXN0SXRlbSIsIml0ZW0iOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyIsIm5hbWUiOiJBZ2VuZGEiLCJwb3NpdGlvbiI6Mn0seyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvc3VtbWVyLWV2ZW50LTIwMjQvIiwibmFtZSI6IjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQiLCJwb3NpdGlvbiI6M31dfTwvc2NyaXB0PjwvaGVhZD48Ym9keT48bm9zY3JpcHQ+PGlmcmFtZSBzcmM9Ii8vd3d3Lmdvb2dsZXRhZ21hbmFnZXIuY29tL25zLmh0bWw/aWQ9R1RNLVdUWjVGUlEiIGhlaWdodD0iMCIgd2lkdGg9IjAiIHN0eWxlPSJkaXNwbGF5Om5vbmU7dmlzaWJpbGl0eTpoaWRkZW4iPjwvaWZyYW1lPjwvbm9zY3JpcHQ+PGRpdiBjbGFzcz0ic3BjLW1vZGFsaXR5bGF5ZXIiPjwvZGl2PjxkaXYgaWQ9InNsaWRlbWVudS1jb250YWluZXIiPjxkaXYgaWQ9InNsaWRlbWVudSIgdGFiaW5kZXg9Ii0xIiAgICA+PGRpdiBjbGFzcz0ic2lkZWJhcl9faGVhZGVyIj4gPGEgY2xhc3M9InNpZGViYXJfX2hlYWRlcl9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9InNpZGViYXJfX2lkZW50aXR5X19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9InNpZGViYXJfX2lkZW50aXR5X19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48YnV0dG9uIGlkPSJzbGlkZW1lbnUtY2xvc2UiIGNsYXNzPSJzaWRlYmFyLWFjdGlvbi1jbG9zZSIgdHlwZT0iYnV0dG9uIiBhcmlhLWxhYmVsPSJDbG9zZSIgPjwvYnV0dG9uPjwvZGl2Pjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudSBzaWRlYmFyX19tZW51LS1sZXZlbDEiICA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIiA+SG9tZTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5SZXNlYXJjaDwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+QWJvdXQgb3VyIHJlc2VhcmNoPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvNHR1LWNlbnRyZXMvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+NFRVIENlbnRyZXM8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDMiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iID5BTUkgKE1hdGhlbWF0aWNzKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iID5CdWlsdCBFbnZpcm9ubWVudDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIiA+RGVzaWduIFVuaXRlZDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyIgPkVuZXJneTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIiA+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iID5IZWFsdGg8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iID5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIiA+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIiA+TklSSUNUIChJQ1QpPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyIgPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5IaWdoIFRlY2ggZm9yIGEgU3VzdGFpbmFibGUgRnV0dXJlPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iID5IVFNGIEkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIiA+SFRTRiBJSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtdmlkZW9zLyIgPkhUU0YgdmlkZW9zPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIiA+NFRVLlJlc2VhcmNoRGF0YTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvRUUtTkwvIiA+RWxlY3RyaWNhbCBFbmdpbmVlcmluZyBOZXRoZXJsYW5kczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkVkdWNhdGlvbjwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkFib3V0IG91ciBlZHVjYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iID5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIiA+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyIgPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uL2VkdWNhdGlvbnByb2dyYW1tZXMvIiA+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxidXR0b24gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIj48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5WYWxvcmlzYXRpb248L2J1dHRvbj48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QlMjBhY3Rpdml0aWVzLyIgPjRUVS5JTVBBQ1Q8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyIgPkFib3V0IDRUVS5JbXBhY3Q8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3RhcnR1cCUyMG1pc3Npb25zLyIgPlN0YXJ0dXAgbWlzc2lvbnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPk1lZGlhPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL2luc2lnaHRmdWwtaW5ub3ZhdG9ycy8iID5JbnNpZ2h0ZnVsIElubm92YXRvcnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvU3Bpbi1vZmYlMjBzZXJpZS8iID5TcGluLU9mZiBTdG9yaWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdHVkZW50JTIwY2hhbGxlbmdlcy8iID5TdHVkZW50IGNoYWxsZW5nZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vVHVzc2VucGFnaW5hJTIwdm9vcmFmZ2FhbmQlMjBhYW4lMjBTdGFydHVwJTIwU3VwcG9ydC8iID5BYm91dCBTdGFydHVwIFN1cHBvcnQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5OZXdzPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSAgc2lkZW1haW5tZW51X19pdGVtLS1leHBhbmQgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX3NlbGVjdGVkICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkFib3V0IDRUVTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LzR0dS1pbi0xLW1pbnV0ZS8iID40VFUgaW4gb25seSAxIG1pbnV0ZTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2ZhY3RzLWZpZ3VyZXMvIiA+RmFjdHMgYW5kIGZpZ3VyZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9vcmdhbmlzYXRpb24vIiA+T3JnYW5pc2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvcHVibGljYXRpb25zLyIgPlB1YmxpY2F0aW9uczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2FsdW1uaS8iID5BbHVtbmk8L2E+PC9saT48L3VsPjwvbGk+PC91bD48bmF2IGNsYXNzPSJzaWRlYmFyX19sYW5ndWFnZXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC8iPk5MPC9hPiB8IDxzcGFuIGNsYXNzPSJzZWxlY3RlZCI+RU48L3NwYW4+PC9uYXY+PG5hdiBjbGFzcz0ic2lkZWJhcl9fc2Vjb25kYXJ5bGlua3MiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9jb250YWN0LyI+Q29udGFjdDwvYT48L25hdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wLWJhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyLWJhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3AiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX2NvbnRlbnQiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX2lkZW50aXR5Ij48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19zbG9nYW4iPlBhcnQgb2YgdGhlIDxidXR0b24gY2xhc3M9ImhlYWRlci10b3BfX3RvZ2dsZWV4cGxvcmVwYW5lbCI+NFRVLkZlZGVyYXRpb248L2J1dHRvbj48L2Rpdj48YSBjbGFzcz0iaGVhZGVyLXRvcF9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fb3JnYW5pemF0aW9ucyI+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZGVsZnQubmwvZW4vIiB0aXRsZT0iVFUgRGVsZnQiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZGVsZnQuc3ZnIiBhbHQ9IlRVIERlbGZ0IiB3aWR0aD0iMTAwIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuLyIgdGl0bGU9IlRVIEVpbmRob3ZlbiIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1laW5kaG92ZW4uc3ZnIiBhbHQ9IlRVIEVpbmRob3ZlbiIgd2lkdGg9IjEzMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnV0d2VudGUubmwvZW4vIiB0aXRsZT0iVW5pdmVyc2l0eSBvZiBUd2VudGUiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL3VuaXZlcnNpdHktb2YtdHdlbnRlLnN2ZyIgYWx0PSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgd2lkdGg9IjEwMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3Lnd1ci5ubC8iIHRpdGxlPSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28td3VyLnN2ZyIgYWx0PSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiIHdpZHRoPSIxMzIiIC8+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyIj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fY29udGVudCI+PGEgY2xhc3M9ImhlYWRlci1tZW51YmFyX19pZGVudGl0eSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zcGFjZXIiPjwvZGl2PjxuYXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19tZW51YmFyIiBhcmlhLWxhYmVsPSJNYWluIj48dWwgY2xhc3M9InNwYy1tZW51YmFyIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIgPkhvbWU8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPlJlc2VhcmNoPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5BYm91dCBvdXIgcmVzZWFyY2g8L2E+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLzR0dS1jZW50cmVzLyIgPjRUVSBDZW50cmVzPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIiA+QU1JIChNYXRoZW1hdGljcyk8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIiA+QnVpbHQgRW52aXJvbm1lbnQ8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyIgPkRlc2lnbiBVbml0ZWQ8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iID5FbmVyZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyIgPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIiA+SGVhbHRoPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIiA+SGlnaC1UZWNoIE1hdGVyaWFsczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyIgPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyIgPk5JUklDVCAoSUNUKTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iID5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic3BjLW1lbnViYXItLWhhc3N1Yml0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS8iID5IaWdoIFRlY2ggZm9yIGEgU3VzdGFpbmFibGUgRnV0dXJlPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iID5IVFNGIEkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIiA+SFRTRiBJSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtdmlkZW9zLyIgPkhUU0YgdmlkZW9zPC9hPjwvbGk+PC91bD48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyIgPjRUVS5SZXNlYXJjaERhdGE8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9FRS1OTC8iID5FbGVjdHJpY2FsIEVuZ2luZWVyaW5nIE5ldGhlcmxhbmRzPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkVkdWNhdGlvbjwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkFib3V0IG91ciBlZHVjYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIiA+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iID40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyIgPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi9lZHVjYXRpb25wcm9ncmFtbWVzLyIgPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSIiID5WYWxvcmlzYXRpb248L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0JTIwYWN0aXZpdGllcy8iID40VFUuSU1QQUNUPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIiA+QWJvdXQgNFRVLkltcGFjdDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3RhcnR1cCUyMG1pc3Npb25zLyIgPlN0YXJ0dXAgbWlzc2lvbnM8L2E+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvIiA+TWVkaWE8L2E+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwzIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvaW5zaWdodGZ1bC1pbm5vdmF0b3JzLyIgPkluc2lnaHRmdWwgSW5ub3ZhdG9yczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9TcGluLW9mZiUyMHNlcmllLyIgPlNwaW4tT2ZmIFN0b3JpZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdHVkZW50JTIwY2hhbGxlbmdlcy8iID5TdHVkZW50IGNoYWxsZW5nZXM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1R1c3NlbnBhZ2luYSUyMHZvb3JhZmdhYW5kJTIwYWFuJTIwU3RhcnR1cCUyMFN1cHBvcnQvIiA+QWJvdXQgU3RhcnR1cCBTdXBwb3J0PC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VsZWN0ZWQiPkFnZW5kYTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyIgPkFib3V0IDRUVTwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LzR0dS1pbi0xLW1pbnV0ZS8iID40VFUgaW4gb25seSAxIG1pbnV0ZTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9mYWN0cy1maWd1cmVzLyIgPkZhY3RzIGFuZCBmaWd1cmVzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L29yZ2FuaXNhdGlvbi8iID5PcmdhbmlzYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvcHVibGljYXRpb25zLyIgPlB1YmxpY2F0aW9uczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvYWx1bW5pLyIgPkFsdW1uaTwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48L3VsPjwvbmF2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zcGFjZXIiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19sYW5ndWFnZXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC8iPk5MPC9hPnw8c3Bhbj5FTjwvc3Bhbj48L2Rpdj48Zm9ybSBhY3Rpb249Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9zZWFyY2gvIiBtZXRob2Q9IkdFVCIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2h3cmFwcGVyIiBhdXRvY29tcGxldGU9Im9mZiIgPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2gtaW5wdXQtYW5kLXN1Z2dlc3Rpb25zLXdyYXBwZXIiPjxpbnB1dCBpZD0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiBuYW1lPSJxdWVyeSIgZGF0YS1zdWdnZXN0PSI0dHU6Y29ycG9yYXRlX2VuIiBkYXRhLXN1Z2dlc3RwYXJlbnQ9InBhcmVudCIgcGxhY2Vob2xkZXI9IlpvZWtlbiIgYXJpYS1sYWJlbD0iWm9la2VuIiB0eXBlPSJzZWFyY2giIC8+PC9kaXY+PGxhYmVsIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoIiBmb3I9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgdGFiaW5kZXg9Ii0xIiA+PHNwYW4gY2xhc3M9ImZhciBmYS1zZWFyY2giPjwvc3Bhbj48L2xhYmVsPjwvZm9ybT48YnV0dG9uIGlkPSJoZWFkZXItbWVudWJhcl9zaWRlYmFydG9nZ2xlIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3Nob3dzaWRlbWFpbm1lbnUgc2lkZWJhci1hY3Rpb24tdG9nZ2xlIiBhcmlhLWxhYmVsPSJPcGVuIG1lbnUiIGFyaWEtZXhwYW5kZWQ9ImZhbHNlIiBhcmlhLWNvbnRyb2xzPSJzbGlkZW1lbnUiID48c3BhbiBjbGFzcz0iZmFyIGZhLWJhcnMiPjwvc3Bhbj48L2J1dHRvbj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWwiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fdG9wYmFyIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2Nsb3NlIj5DbG9zZTwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1ucyI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19hZGRyZXNzIHJ0ZGNvbnRlbnQiPjxwIGNsYXNzPSJoZWFkaW5nIj40VFUuRmVkZXJhdGlvbjwvcD48cCBjbGFzcz0ibm9ybWFsIj4rMzEoMCk2IDQ4IDI3IDU1IDYxPC9wPjxwIGNsYXNzPSJub3JtYWwiPjxhIGhyZWY9Im1haWx0bzpwcm9qZWN0bGVpZGVyQDR0dS5ubCI+c2VjcmV0YXJpc0A0dHUubmw8L2E+PC9wPjxwIGNsYXNzPSJub3JtYWwiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxiPldlYnNpdGU6IDRUVS5ubDwvYj48L2E+PC9wPjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uIGV4cGxvcmVwYW5lbF9fY29sdW1uLS1tYW55aXRlbXMiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuUmVzZWFyY2g8L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zIGV4cGxvcmVwYW5lbF9faXRlbXMtLW1hbnlpdGVtcyAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIj48c3Bhbj5BcHBsaWVkIE1hdGhlbWF0aWNzIEluc3RpdHV0ZTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIj48c3Bhbj5CdWlsdCBFbnZpcm9ubWVudDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyI+PHNwYW4+RGVzaWduIFVuaXRlZDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iPjxzcGFuPkVuZXJneTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyI+PHNwYW4+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIj48c3Bhbj5IZWFsdGg8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIj48c3Bhbj5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyI+PHNwYW4+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyI+PHNwYW4+TklSSUNUIChJQ1QpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iPjxzcGFuPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iPjxzcGFuPlJlc2VhcmNoRGF0YTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iPjxzcGFuPkhUU0YgSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iPjxzcGFuPkhUU0YgSUkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uICI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5FZHVjYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zICAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIj48c3Bhbj5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyI+PHNwYW4+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iPjxzcGFuPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyd2lqcy9vbmRlcndpanNwcm9ncmFtbWFzLyI+PHNwYW4+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uICI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5WYWxvcmlzYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zICAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iPjxzcGFuPjRUVS5JTVBBQ1Q8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vdGVjaC10cmFuc2Zlci5ubC9lbi8iPjxzcGFuPlRoZW1hdGljIFRlY2hub2xvZ3kgVHJhbnNmZXI8L3NwYW4+PC9hPjxhIGhyZWY9IiI+PHNwYW4+U3Bpbi1vZmYgU3Rvcmllczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly80dHVpbXBhY3RjaGFsbGVuZ2UubmwvIj48c3Bhbj40VFUgSW1wYWN0IENoYWxsZW5nZTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX2JhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19zbGlkZXNob3cgY2Fycm91c2VsX192aWV3cG9ydCBjYXJyb3VzZWxfX2RyYWdhcmVhICI+PHN0eWxlPkBtZWRpYSAobWF4LXdpZHRoOiA3NjdweCl7LmhlYWRlcnNsaWRlMHtiYWNrZ3JvdW5kLWNvbG9yOiAjNTY1QTM5O2JhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2kzZGZjYjE5YzAxMDI5YjMzMTEwMGE1NWQ4ODAxMjFkYWRkYzJkMzdjYWUzODA4MDFlMzQwMGIwMDA3ODE0Ni9zdW1tZXItMDIuanBnKTt9fUBtZWRpYSAobWluLXdpZHRoOiA3NjhweCl7LmhlYWRlcnNsaWRlMHtiYWNrZ3JvdW5kLWNvbG9yOiAjNTY1QTM5O2JhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2k0Y2I5YzEyOTAxMDI5YjMzMTEwMGE1NWQ4ODAxMjFkYWRkYzJkMzdjYWUzODA4MDFlMzQwMGI2MDA0ODE0Ni9zdW1tZXItMDIuanBnKTt9fTwvc3R5bGU+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlIGNhcnJvdXNlbF9fY2VsbCBhY3RpdmVzbGlkZSBoZWFkZXJzbGlkZTAgIiBkYXRhLXNsaWRlc2hvdy1lbGVtZW50cz0icGFnZS1oZWFkZXJfX3NsaWRlMF9fY29udGVudCIgc3R5bGU9IiIgPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19jb250ZW50Ij48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fbWV0YSI+PGgxIGNsYXNzPSJwYWdlLWhlYWRlcl9fdGl0bGUiPjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQ8L2gxPjxkaXYgY2xhc3M9InBhZ2VoZWFkZXJfX2RhdGUiPkZyaWRheSA3IEp1bmUgMjAyNDwvZGl2PjwvZGl2PjwvZGl2PjxtYWluIGNsYXNzPSJwYWdlX19ib2R5ICAiPjxmb3JtIGlkPSIiICBjbGFzcz0icGFnZV9faGVhZGVyZmlsdGVycyAgICI+PC9mb3JtPjxkaXYgY2xhc3M9InBhZ2VfX2NvbnRlbnRhcmVhIHBhZ2VfX2NvbnRlbnRhcmVhLS1ydGRkb2MgICBoZWFkZXJpc29wYXF1ZSAiPjxkaXYgY2xhc3M9ImRlZXBsaW5rcy13cmFwcGVyIj48ZGl2IGNsYXNzPSJkZWVwbGlua3MiPjxhIGNsYXNzPSJwYWdlLWJhY2tsaW5rIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyI+QWxsIGV2ZW50czwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWNvbnRlbnRzdGFydCI+PC9kaXY+PCEtLXdoX2NvbnNpbGlvX2NvbnRlbnQtLT48aDIgY2xhc3M9ImhlYWRpbmcyIj5OZXR3b3JraW5nIGV2ZW50IDRUVS5BTUk8L2gyPjxwIGNsYXNzPSJub3JtYWwiPjxiPkxvY2F0aW9uPC9iPjogQW1waGl0aGVhdGVyLCBWcmlqaG9mLMKgIERlIFZlbGRtYWF0IDUsIDc1MjIgTk0sIEVuc2NoZWRlIChjYW1wdXMgVVQpPGJyIC8+PGI+RGF0ZTwvYj46IDcgSnVuZSAyMDI0PC9wPjxwIGNsYXNzPSJub3JtYWwiPlRoZSBwdXJwb3NlIG9mIHRoaXMgZXZlbnQgaXMgdG8gYnJpbmcgdG9nZXRoZXIgbWVtYmVycyBvZiB0aGUgNFRVLkFNSSBjb21tdW5pdHkgaW4gb3JkZXIgdG8gZ2V0IHRvIGtub3cga25ldyBjb2xsZWFndWVzIGFuZCBjYXRjaCB1cCB3aXRoIG9sZCBvbmVzLCBleHBsb3JlIGNvbW1vbiByZXNlYXJjaCBvciB0ZWFjaGluZyBpbnRlcmVzdHMsIGludml0ZSBjb2xsYWJvcmF0aW9uLCBhbmQgcmVjZWl2ZcKgdXBkYXRlcyBvbiBjdXJyZW50IDRUVS5BTUkgZnVuZGVkIHByb2plY3RzIChzby1jYWxsZWQgU3RyYXRlZ2ljIFJlc2VhcmNoIEluaXRpYXRpdmVzIG9yIDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvUmVzZWFyY2gvIj5TUkk8L2E+cykuwqA8L3A+PHAgY2xhc3M9Im5vcm1hbCI+UmVnaXN0ZXIgZm9ywqB0aGlzIChmcmVlKSBldmVudCBoZXJlIGJlZm9yZSA8Yj5GcmlkYXkgMjQgTWF5PC9iPi48L3A+PHAgY2xhc3M9Im5vcm1hbCI+VGVudGF0aXZlIHNjaGVkdWxlOjwvcD48dWwgY2xhc3M9InVub3JkZXJlZCI+PGxpPjEwLjAwIC0gMTAuMzAgLSBXYWxrIGluIHdpdGggY29mZmVlIG9yIHRlYTwvbGk+PGxpPjEwLjMwIC0gMTAuNDUgLSBPcGVuaW5nIG9wIHRoZSBkYXk8L2xpPjxsaT4xMC40NSAtIDExLjE1IC0gSW52aXRlZCB0YWxrIGJ5wqA8YSBocmVmPSJodHRwczovL3d3d2hvbWUuZXdpLnV0d2VudGUubmwvfnNjaG1pZHRhai8iPkpvaGFubmVzIFNjaG1pZHQtSGllYmVyPC9hPsKgKFVUKSAtwqAnT24gYmlvbG9naWNhbGx5IGluc3BpcmVkIGxlYXJuaW5nJyAoYWJzdHJhY3QpPC9saT48bGk+MTEuMTUgLSAxMS40NSAtIENvZmZlZSBicmVhazwvbGk+PGxpPjExLjQ1IC0gMTIuMzAgLSBQaXRjaGVzIChpbmNsdWRpbmcgMSBTUkkpPC9saT48bGk+MTIuMzAgLSAxNC4wMCAtIEx1bmNoIGJyZWFrICsgZ3JvdXAgcGhvdG88L2xpPjxsaT4xNC4wMCAtIDE1LjAwIC0gU1JJICdSZXNlYXJjaCBvbiBFZHVjYXRpb24nICh0YWxrICsgcGFuZWwgZGlzY3Vzc2lvbik8L2xpPjxsaT4xNS4wMCAtIDE1LjMwIC0gQ29mZmVlIGJyZWFrPC9saT48bGk+MTUuMzAgLSAxNi4xNSAtIFBpdGNoZXPCoChpbmNsdWRpbmcgMcKgU1JJKTwvbGk+PGxpPjE2LjE1IC0gMTYuNDUgLSBJbnZpdGVkIHRhbGsgYnkgPGEgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuL3Jlc2VhcmNoL3Jlc2VhcmNoZXJzL21pcmVpbGxlLWJvdXRpbiI+TWlyZWlsbGUgQm91dGluPC9hPiAoVFUvZSk8L2xpPjxsaT4xNi40NSAtIDE4LjMwwqAtIERyaW5rcyBhbmQgZGlubmVyIChUaGVhdGVyY2Fmw6kpPC9saT48L3VsPjxwIGNsYXNzPSJub3JtYWwiPkNsaWNrIDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvTmV3cy9OZXdzL3N1bW1lci1ldmVudC0yMDIzLXJlcG9ydC8iPmhlcmU8L2E+IGZvciBhIHJlcG9ydCBvZiB0aGUgcHJldmlvdXMgNFRVLkFNSSBzdW1tZXIgZXZlbnQsIGhlbGQgaW4gRGVsZnQgb24gMjcgSnVuZSAyMDIzLjwvcD48IS0tL3doX2NvbnNpbGlvX2NvbnRlbnQtLT48ZGl2IGNsYXNzPSJwYWdlX19iYWxsb29uIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXIiPjxkaXYgY2xhc3M9InBhZ2VfX2Zvb3Rlcl9fY29udGVudCBuYXZwYXRoIj48YSBjbGFzcz0ibmF2cGF0aF9faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT48c3BhbiBjbGFzcz0ibmF2cGF0aF9fc2VwZXJhdG9yIj48L3NwYW4+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19pdGVtIGNydW1icGF0aC0tY3VycmVudHBhZ2UiPjRUVS5BTUkgc3VtbWVyIGV2ZW50IDIwMjQ8L3NwYW4+PC9kaXY+PC9kaXY+PC9kaXY+PC9tYWluPjxkaXYgY2xhc3M9ImZvb3RlciI+PGRpdiBjbGFzcz0iZm9vdGVyX19wYW5lbCI+PGRpdiBjbGFzcz0iZm9vdGVyX19pZGVudGl0eSI+PGRpdiBjbGFzcz0iZm9vdGVyX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fc2l0ZXRpdGxlIj5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PCEtLSBGSVhNRTogdXNlIGFyaWEtaGlkZGVuPSJ0cnVlIiBiZWNhdXNlIGl0J3MgYSBkdXBsaWNhdGUgb2YgdGhlIGl0ZW1zIG9uIHRoZSBtZW51IGJhciA/IC0tPiA8bmF2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjEgZm9vdGVyX19tYWlubWVudSIgYXJpYS1sYWJlbD0iTWFpbiI+IDx1bD4gICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPkhvbWU8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iPlJlc2VhcmNoPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyI+RWR1Y2F0aW9uPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSIiPlZhbG9yaXNhdGlvbjwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iPk5ld3M8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvIj5BYm91dCA0VFU8L2E+IDwvbGk+ICAgPC91bD4gPC9uYXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjIiPiA8aW5wdXQgdHlwZT0iY2hlY2tib3giIG5hbWU9ImZvb3RlcmNvbHVtbiIgaWQ9ImZvb3Rlcl9fY29sdW1uMl9fZXhwYW5kIiAvPiA8bGFiZWwgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIiBmb3I9ImZvb3Rlcl9fY29sdW1uMl9fZXhwYW5kIj5Db250YWN0PC9sYWJlbD4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgcnRkY29udGVudCI+IDxwIGNsYXNzPSJub3JtYWwiPiszMSgwKTYgODMgMjIgNTAgNTk8YnIgLz48YSBocmVmPSJtYWlsdG86cHJvamVjdGxlaWRlckA0dHUubmwiPnNlY3JldGFyaXNANHR1Lm5sPC9hPjwvcD4gPC9kaXY+IDwvZGl2PiAgIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMyI+IDxpbnB1dCB0eXBlPSJjaGVja2JveCIgbmFtZT0iZm9vdGVyY29sdW1uIiBpZD0iZm9vdGVyX19jb2x1bW4zX19leHBhbmQiIC8+IDxsYWJlbCBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciIGZvcj0iZm9vdGVyX19jb2x1bW4zX19leHBhbmQiPlBvc3RhZHJlczwvbGFiZWw+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IHJ0ZGNvbnRlbnQiPiA8cCBjbGFzcz0ibm9ybWFsIj40VFUuRmVkZXJhdGllPGJyIC8+UG9zdGJ1cyA1PGJyIC8+MjYwMCBBQSBEZWxmdDwvcD4gPC9kaXY+IDwvZGl2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW40Ij4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbXNfX2dyb3VwIj4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciPkZvbGxvdyB1czwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IGZvb3Rlcl9fc29jaWFsaXRlbXMgIj48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3R3aXR0ZXIuY29tLzRUVUZlZGVyYXRpb24iIHRpdGxlPSJUd2l0dGVyIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS10d2l0dGVyIj48L3NwYW4+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21wYW55LzQtdHUtZmVkZXJhdGlvbi8iIHRpdGxlPSJMaW5rZWRJbiIgPjxzcGFuIGNsYXNzPSJmYWIgZmEtbGlua2VkaW4taW4iPjwvc3Bhbj48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vY2hhbm5lbC9VQ01rcWhqeDJXMWhOUnd5c1J2V0VYd1EiIHRpdGxlPSJZb3V0dWJlIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS15b3V0dWJlIj48L3NwYW4+PC9hPjwvZGl2PiA8L2Rpdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcl9fZ3JvdXAiPiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmcgZm9vdGVyX19jb2x1bW5fX2hlYWRpbmctLW5ld3NsZXR0ZXIgIj5TdGF5IHVwLXRvLWRhdGU8L2Rpdj48Zm9ybSBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwIHdocGx1Z2luLW5ld3NsZXR0ZXItc3Vic2NyaXB0aW9uICAiIGRhdGEtbmV3c2xldHRlci1saXN0PSJTVUJTXzRUVV9DT1JQT1JBVEVfTklFVVdTQlJJRUYiID48aW5wdXQgbmFtZT0iZW1haWwiIHBsYWNlaG9sZGVyPSJTaWduIHVwIGZvciBvdXIgbmV3c2xldHRlciIgLz48YnV0dG9uIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Ym1pdCIgdHlwZT0ic3VibWl0IiBuYW1lPSJzdWJtaXRidXR0b24iIGFyaWEtbGFiZWw9IlN1YnNjcmliZSI+PHNwYW4gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VibWl0X19pY29uIGZhciBmYS1lbnZlbG9wZSI+PC9zcGFuPjwvYnV0dG9uPjwvZm9ybT48ZGl2IGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Y2Nlc3MiPlRoYW5rcyBmb3Igc3Vic2NyaWJpbmcgdG8gb3VyIG5ld3NsZXR0ZXIuPC9kaXY+ICA8L2Rpdj4gPC9kaXY+IDxociBjbGFzcz0iZm9vdGVyX19kaXZpZGVyIiAvPiA8ZGV0YWlscyBjbGFzcz0iZm9vdGVyX19leHBsb3JlIj48c3VtbWFyeT48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX3RvZ2dsZV9fY2xvc2VkdGV4dCI+UGFydCBvZiB0aGUgPHNwYW4gY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fbmFtZSI+NFRVLkZlZGVyYXRpb248L3NwYW4+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX190b2dnbGVfX29wZW50ZXh0Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2xvc2UiPkNsb3NlPC9kaXY+PC9kaXY+PC9zdW1tYXJ5PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsIj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5SZXNlYXJjaDwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iPjxzcGFuPkFwcGxpZWQgTWF0aGVtYXRpY3MgSW5zdGl0dXRlPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iPjxzcGFuPkJ1aWx0IEVudmlyb25tZW50PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIj48c3Bhbj5EZXNpZ24gVW5pdGVkPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyI+PHNwYW4+RW5lcmd5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIj48c3Bhbj5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iPjxzcGFuPkhlYWx0aDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iPjxzcGFuPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIj48c3Bhbj5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIj48c3Bhbj5OSVJJQ1QgKElDVCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyI+PHNwYW4+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyI+PHNwYW4+UmVzZWFyY2hEYXRhPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyI+PHNwYW4+SFRTRiBJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyI+PHNwYW4+SFRTRiBJSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2NhdGVnb3J5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuRWR1Y2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyI+PHNwYW4+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iPjxzcGFuPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIj48c3Bhbj5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcndpanMvb25kZXJ3aWpzcHJvZ3JhbW1hcy8iPjxzcGFuPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5WYWxvcmlzYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iPjxzcGFuPjRUVS5JTVBBQ1Q8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vdGVjaC10cmFuc2Zlci5ubC9lbi8iPjxzcGFuPlRoZW1hdGljIFRlY2hub2xvZ3kgVHJhbnNmZXI8L3NwYW4+PC9hPjxhIGhyZWY9IiI+PHNwYW4+U3Bpbi1vZmYgU3Rvcmllczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly80dHVpbXBhY3RjaGFsbGVuZ2UubmwvIj48c3Bhbj40VFUgSW1wYWN0IENoYWxsZW5nZTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PC9kZXRhaWxzPiA8ZGl2IGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzIj4gPGRpdiBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbXMiPiA8YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVkZWxmdC5ubC9lbi8iIHRpdGxlPSJUVSBEZWxmdCIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1kZWxmdC5zdmciIGFsdD0iVFUgRGVsZnQiIHdpZHRoPSI4NyIgaGVpZ2h0PSIzNCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZS5ubC9lbi8iIHRpdGxlPSJUVSBFaW5kaG92ZW4iID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZWluZGhvdmVuLnN2ZyIgYWx0PSJUVSBFaW5kaG92ZW4iIHdpZHRoPSIxMzAiIGhlaWdodD0iMjciIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy51dHdlbnRlLm5sL2VuLyIgdGl0bGU9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci91bml2ZXJzaXR5LW9mLXR3ZW50ZS5zdmciIGFsdD0iVW5pdmVyc2l0eSBvZiBUd2VudGUiIHdpZHRoPSI4NSIgaGVpZ2h0PSIzMSIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3Lnd1ci5ubC8iIHRpdGxlPSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28td3VyLnN2ZyIgYWx0PSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiIHdpZHRoPSIxNDUiIGhlaWdodD0iMjkiIC8+PC9hPiA8L2Rpdj4gPC9kaXY+IDwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyIj48c3BhbiBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXJfX2NvcHlyaWdodCI+PHNwYW4gY2xhc3M9ImZiY3BhcnQiPiZjb3B5OyAyMDI0IDRUVS5GZWRlcmF0aW9uPC9zcGFuPjwvc3Bhbj48dWwgY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyX19tZW51Ij48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2NvbnRhY3QvIj5Db250YWN0PC9hPjwvbGk+PC91bD48L2Rpdj48L2Rpdj48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL3gtaHNvbiIgaWQ9IndoLWNvbnNpbGlvZmllbGRzIj5oc29uOnsid2hzZWFyY2h0aHVtYm5haWwiOiJodHRwczovL3d3dy40dHUubmwvLnVjL2kyZmRkMDQ2YzAxMDI5YjMzMTEwMGE1NWQ4ODAxMjFkYWRkYzJkMzdjYWUzODA4MDFlMzQwMDFmMDAwODE0MS9zdW1tZXItMDIuanBnIn08L3NjcmlwdD48L2JvZHk+PC9odG1sPg==
+ recorded_at: Wed, 02 Jan 2019 16:00:00 GMT
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/2024-6-18-webinar-mathematics/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Thu, 06 Jun 2024 07:51:56 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Transfer-Encoding:
+ - chunked
+ Connection:
+ - keep-alive
+ Vary:
+ - Accept-Encoding
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Cache-Control:
+ - no-cache
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnQgc2l0ZWhlYWRlci0tbWVudWJhci10cmFuc2x1Y2VudCBwYWdlLS1mb3Jtd2VidG9vbCBwYWdlLS13aXRoYmFja2xpbmsiIGRhdGEtdHJhY2tpbmdpZD0iIj48aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PHRpdGxlPlVDTCYjMzk7cyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlPC90aXRsZT48bWV0YSBuYW1lPSJkZXNjcmlwdGlvbiIgY29udGVudD0iTG9jYXRpb246IG9ubGluZSI+PGxpbmsgcmVsPSJjYW5vbmljYWwiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvMjAyNC02LTE4LXdlYmluYXItbWF0aGVtYXRpY3MvIj4KPCEtLQpSZWFsaXNhdGllOiDwn5K8IFdlYkhhcmUgYnYKICAgICAgICAgICAg8J+MkCBodHRwczovL3d3dy53ZWJoYXJlLm5sLwotLT4KPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xIiAvPjxtZXRhIG5hbWU9ImRlc2NyaXB0aW9uIiBjb250ZW50PSJMb2NhdGlvbjogb25saW5lIiAvPjxsaW5rIHJlbD0iYXBwbGUtdG91Y2gtaWNvbiIgc2l6ZXM9IjE4MHgxODAiIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9hcHBsZS10b3VjaC1pY29uLTE4MHgxODAucG5nIiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi0zMngzMi5wbmciIHNpemVzPSIzMngzMiIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tOTZ4OTYucG5nIiBzaXplcz0iOTZ4OTYiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTE5NHgxOTQucG5nIiBzaXplcz0iMTk0eDE5NCIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2FuZHJvaWQtY2hyb21lLTE5MngxOTIucG5nIiBzaXplcz0iMTkyeDE5MiIgLz48bGluayByZWw9Im1hc2staWNvbiIgICAgICAgICAgICAgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL3NhZmFyaS1waW5uZWQtdGFiLnN2ZyIgY29sb3I9IiNmZjhiMzgiIC8+PG1ldGEgbmFtZT0idGhlbWUtY29sb3IiIGNvbnRlbnQ9IiNmZmZmZmYiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnR5cGUiIGNvbnRlbnQ9IndlYnNpdGUiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnNpdGVfbmFtZSIgY29udGVudD0iRmVkZXJhdGlvbiIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6dGl0bGUiIGNvbnRlbnQ9IlVDTCYjMzk7cyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlIiAvPjxtZXRhIHByb3BlcnR5PSJvZzpkZXNjcmlwdGlvbiIgY29udGVudD0iTG9jYXRpb246IG9ubGluZSIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2UiIGNvbnRlbnQ9Imh0dHBzOi8vd3d3LjR0dS5ubC8udWMvaWMwOGRlNWEwMDEwMjUyZjgxMDAwMDNkZWE2MDFjNjA0NzJlM2E2ZDJjZmQ2MDcwMWMzYjAwNDc2MDI4MC90aGUtY29uY2VwdC1vZi1yZWFkaW5nLWxvdmUtMjAyMy0xMS0yNy0wNS0xMi0wOS11dGMuanBnIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTp3aWR0aCIgY29udGVudD0iMTIwMCIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6aGVpZ2h0IiBjb250ZW50PSI2MzAiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlIiBjb250ZW50PSJodHRwczovL3d3dy40dHUubmwvLnVjL2kyMDU3MjkzMzAxMDI1MmY4MTAwMDAzZGVhNjAxYzYwNDcyZTNhNmQyY2ZkNjA3MDFjMzJjMDEyYzAxODAvdGhlLWNvbmNlcHQtb2YtcmVhZGluZy1sb3ZlLTIwMjMtMTEtMjctMDUtMTItMDktdXRjLmpwZyIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6d2lkdGgiIGNvbnRlbnQ9IjMwMCIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6aGVpZ2h0IiBjb250ZW50PSIzMDAiIC8+PHNjcmlwdCBub21vZHVsZT4gaWYoISF3aW5kb3cuTVNJbnB1dE1ldGhvZENvbnRleHQgJiYgISFkb2N1bWVudC5kb2N1bWVudE1vZGUpZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsYXNzTGlzdC5hZGQoInVuc3VwcG9ydGVkLWJyb3dzZXIiKTs8L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2pzb24iIGlkPSJ3aC1jb25maWciPnsiZGVzaWduY2Rucm9vdCI6Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlLyIsImRlc2lnbnJvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS8iLCJkdGFwc3RhZ2UiOiJwcm9kdWN0aW9uIiwiaW1ncm9vdCI6Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy8iLCJpc2xpdmUiOnRydWUsImxvY2FsZSI6ImVuLVVTIiwib2JqIjp7Im5hdnBhdGhpdGVtIjp7ImxpbmsiOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtNi0xOC13ZWJpbmFyLW1hdGhlbWF0aWNzLyIsInRpdGxlIjoiVUNMJ3MgRXhwZXJpZW5jZSB3aXRoIENCTCBpbiBFbmdpbmVlcmluZyBlZHVjYXRpb24gd2l0aCBCaXJnaXQgUGVwaW4gYW5kIE1hdGhldXMgTy4gZGUgQW5kcmFkZSJ9fSwic2VydmVyIjo1MDUwMCwic2l0ZSI6e30sInNpdGVyb290IjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsInNvY2lhbGl0ZTpndG0iOnsiYSI6IkdUTS1XVFo1RlJRIiwiaCI6dHJ1ZSwibSI6ZmFsc2V9fTwvc2NyaXB0PjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iLy5hcC80dHUuc2l0ZS9hcC5jc3MiPjxzY3JpcHQgc3JjPSIvLmFwLzR0dS5zaXRlL2FwLm1qcyIgdHlwZT0ibW9kdWxlIiBhc3luYz48L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2xkK2pzb24iPnsiQGNvbnRleHQiOiJodHRwczovL3NjaGVtYS5vcmciLCJAdHlwZSI6IkJyZWFkY3J1bWJMaXN0IiwiaXRlbUxpc3RFbGVtZW50IjpbeyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iLCJuYW1lIjoiRmVkZXJhdGlvbiIsInBvc2l0aW9uIjoxfSx7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJuYW1lIjoiQWdlbmRhIiwicG9zaXRpb24iOjJ9LHsiQHR5cGUiOiJMaXN0SXRlbSIsIml0ZW0iOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtNi0xOC13ZWJpbmFyLW1hdGhlbWF0aWNzLyIsIm5hbWUiOiJVQ0wncyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlIiwicG9zaXRpb24iOjN9XX08L3NjcmlwdD48L2hlYWQ+PGJvZHk+PG5vc2NyaXB0PjxpZnJhbWUgc3JjPSIvL3d3dy5nb29nbGV0YWdtYW5hZ2VyLmNvbS9ucy5odG1sP2lkPUdUTS1XVFo1RlJRIiBoZWlnaHQ9IjAiIHdpZHRoPSIwIiBzdHlsZT0iZGlzcGxheTpub25lO3Zpc2liaWxpdHk6aGlkZGVuIj48L2lmcmFtZT48L25vc2NyaXB0PjxkaXYgY2xhc3M9InNwYy1tb2RhbGl0eWxheWVyIj48L2Rpdj48ZGl2IGlkPSJzbGlkZW1lbnUtY29udGFpbmVyIj48ZGl2IGlkPSJzbGlkZW1lbnUiIHRhYmluZGV4PSItMSIgICAgPjxkaXYgY2xhc3M9InNpZGViYXJfX2hlYWRlciI+IDxhIGNsYXNzPSJzaWRlYmFyX19oZWFkZXJfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJzaWRlYmFyX19pZGVudGl0eV9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJzaWRlYmFyX19pZGVudGl0eV9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PGJ1dHRvbiBpZD0ic2xpZGVtZW51LWNsb3NlIiBjbGFzcz0ic2lkZWJhci1hY3Rpb24tY2xvc2UiIHR5cGU9ImJ1dHRvbiIgYXJpYS1sYWJlbD0iQ2xvc2UiID48L2J1dHRvbj48L2Rpdj48dWwgY2xhc3M9InNpZGViYXJfX21lbnUgc2lkZWJhcl9fbWVudS0tbGV2ZWwxIiAgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIgPkhvbWU8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+UmVzZWFyY2g8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPkFib3V0IG91ciByZXNlYXJjaDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLzR0dS1jZW50cmVzLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPjRUVSBDZW50cmVzPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIiA+QU1JIChNYXRoZW1hdGljcyk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIiA+QnVpbHQgRW52aXJvbm1lbnQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyIgPkRlc2lnbiBVbml0ZWQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iID5FbmVyZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyIgPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIiA+SGVhbHRoPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIiA+SGlnaC1UZWNoIE1hdGVyaWFsczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyIgPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyIgPk5JUklDVCAoSUNUKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iID5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+SGlnaCBUZWNoIGZvciBhIFN1c3RhaW5hYmxlIEZ1dHVyZTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIiA+SFRTRiBJIFByb2dyYW1tZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyIgPkhUU0YgSUkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLXZpZGVvcy8iID5IVFNGIHZpZGVvczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyIgPjRUVS5SZXNlYXJjaERhdGE8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL0VFLU5MLyIgPkVsZWN0cmljYWwgRW5naW5lZXJpbmcgTmV0aGVybGFuZHM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5FZHVjYXRpb248L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5BYm91dCBvdXIgZWR1Y2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIiA+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyIgPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iID5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi9lZHVjYXRpb25wcm9ncmFtbWVzLyIgPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YnV0dG9uIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICI+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+VmFsb3Jpc2F0aW9uPC9idXR0b24+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0JTIwYWN0aXZpdGllcy8iID40VFUuSU1QQUNUPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iID5BYm91dCA0VFUuSW1wYWN0PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0YXJ0dXAlMjBtaXNzaW9ucy8iID5TdGFydHVwIG1pc3Npb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5NZWRpYTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9pbnNpZ2h0ZnVsLWlubm92YXRvcnMvIiA+SW5zaWdodGZ1bCBJbm5vdmF0b3JzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL1NwaW4tb2ZmJTIwc2VyaWUvIiA+U3Bpbi1PZmYgU3RvcmllczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3R1ZGVudCUyMGNoYWxsZW5nZXMvIiA+U3R1ZGVudCBjaGFsbGVuZ2VzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1R1c3NlbnBhZ2luYSUyMHZvb3JhZmdhYW5kJTIwYWFuJTIwU3RhcnR1cCUyMFN1cHBvcnQvIiA+QWJvdXQgU3RhcnR1cCBTdXBwb3J0PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+TmV3czwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gIHNpZGVtYWlubWVudV9faXRlbS0tZXhwYW5kICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19zZWxlY3RlZCAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5BYm91dCA0VFU8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS80dHUtaW4tMS1taW51dGUvIiA+NFRVIGluIG9ubHkgMSBtaW51dGU8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9mYWN0cy1maWd1cmVzLyIgPkZhY3RzIGFuZCBmaWd1cmVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvb3JnYW5pc2F0aW9uLyIgPk9yZ2FuaXNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L3B1YmxpY2F0aW9ucy8iID5QdWJsaWNhdGlvbnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9hbHVtbmkvIiA+QWx1bW5pPC9hPjwvbGk+PC91bD48L2xpPjwvdWw+PG5hdiBjbGFzcz0ic2lkZWJhcl9fbGFuZ3VhZ2VzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvIj5OTDwvYT4gfCA8c3BhbiBjbGFzcz0ic2VsZWN0ZWQiPkVOPC9zcGFuPjwvbmF2PjxuYXYgY2xhc3M9InNpZGViYXJfX3NlY29uZGFyeWxpbmtzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vY29udGFjdC8iPkNvbnRhY3Q8L2E+PC9uYXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcC1iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhci1iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wIj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19jb250ZW50Ij48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19pZGVudGl0eSI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fc2xvZ2FuIj5QYXJ0IG9mIHRoZSA8YnV0dG9uIGNsYXNzPSJoZWFkZXItdG9wX190b2dnbGVleHBsb3JlcGFuZWwiPjRUVS5GZWRlcmF0aW9uPC9idXR0b24+PC9kaXY+PGEgY2xhc3M9ImhlYWRlci10b3BfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX29yZ2FuaXphdGlvbnMiPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWRlbGZ0Lm5sL2VuLyIgdGl0bGU9IlRVIERlbGZ0IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWRlbGZ0LnN2ZyIgYWx0PSJUVSBEZWxmdCIgd2lkdGg9IjEwMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZS5ubC9lbi8iIHRpdGxlPSJUVSBFaW5kaG92ZW4iID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZWluZGhvdmVuLnN2ZyIgYWx0PSJUVSBFaW5kaG92ZW4iIHdpZHRoPSIxMzAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy51dHdlbnRlLm5sL2VuLyIgdGl0bGU9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci91bml2ZXJzaXR5LW9mLXR3ZW50ZS5zdmciIGFsdD0iVW5pdmVyc2l0eSBvZiBUd2VudGUiIHdpZHRoPSIxMDAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy53dXIubmwvIiB0aXRsZT0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXd1ci5zdmciIGFsdD0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiB3aWR0aD0iMTMyIiAvPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhciI+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX2NvbnRlbnQiPjxhIGNsYXNzPSJoZWFkZXItbWVudWJhcl9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc3BhY2VyIj48L2Rpdj48bmF2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fbWVudWJhciIgYXJpYS1sYWJlbD0iTWFpbiI+PHVsIGNsYXNzPSJzcGMtbWVudWJhciI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iID5Ib21lPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5SZXNlYXJjaDwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+QWJvdXQgb3VyIHJlc2VhcmNoPC9hPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC80dHUtY2VudHJlcy8iID40VFUgQ2VudHJlczwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyIgPkFNSSAoTWF0aGVtYXRpY3MpPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyIgPkJ1aWx0IEVudmlyb25tZW50PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iID5EZXNpZ24gVW5pdGVkPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIiA+RW5lcmd5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iID5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyIgPkhlYWx0aDwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyIgPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iID5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iID5OSVJJQ1QgKElDVCk8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIiA+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvIiA+SGlnaCBUZWNoIGZvciBhIFN1c3RhaW5hYmxlIEZ1dHVyZTwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIiA+SFRTRiBJIFByb2dyYW1tZXM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyIgPkhUU0YgSUkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLXZpZGVvcy8iID5IVFNGIHZpZGVvczwvYT48L2xpPjwvdWw+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iID40VFUuUmVzZWFyY2hEYXRhPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvRUUtTkwvIiA+RWxlY3RyaWNhbCBFbmdpbmVlcmluZyBOZXRoZXJsYW5kczwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5FZHVjYXRpb248L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iID5BYm91dCBvdXIgZWR1Y2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyIgPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIiA+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iID5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vZWR1Y2F0aW9ucHJvZ3JhbW1lcy8iID5FZHVjYXRpb24gcHJvZ3JhbW1lczwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iIiA+VmFsb3Jpc2F0aW9uPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdCUyMGFjdGl2aXRpZXMvIiA+NFRVLklNUEFDVDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyIgPkFib3V0IDRUVS5JbXBhY3Q8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0YXJ0dXAlMjBtaXNzaW9ucy8iID5TdGFydHVwIG1pc3Npb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhLyIgPk1lZGlhPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL2luc2lnaHRmdWwtaW5ub3ZhdG9ycy8iID5JbnNpZ2h0ZnVsIElubm92YXRvcnM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvU3Bpbi1vZmYlMjBzZXJpZS8iID5TcGluLU9mZiBTdG9yaWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3R1ZGVudCUyMGNoYWxsZW5nZXMvIiA+U3R1ZGVudCBjaGFsbGVuZ2VzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9UdXNzZW5wYWdpbmElMjB2b29yYWZnYWFuZCUyMGFhbiUyMFN0YXJ0dXAlMjBTdXBwb3J0LyIgPkFib3V0IFN0YXJ0dXAgU3VwcG9ydDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9hZ2VuZGEvIiA+QWdlbmRhPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlbGVjdGVkIj5BZ2VuZGE8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iID5BYm91dCA0VFU8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS80dHUtaW4tMS1taW51dGUvIiA+NFRVIGluIG9ubHkgMSBtaW51dGU8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvZmFjdHMtZmlndXJlcy8iID5GYWN0cyBhbmQgZmlndXJlczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9vcmdhbmlzYXRpb24vIiA+T3JnYW5pc2F0aW9uPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L3B1YmxpY2F0aW9ucy8iID5QdWJsaWNhdGlvbnM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2FsdW1uaS8iID5BbHVtbmk8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PC91bD48L25hdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc3BhY2VyIj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fbGFuZ3VhZ2VzIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvIj5OTDwvYT58PHNwYW4+RU48L3NwYW4+PC9kaXY+PGZvcm0gYWN0aW9uPSJodHRwczovL3d3dy40dHUubmwvZW4vc2VhcmNoLyIgbWV0aG9kPSJHRVQiIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNod3JhcHBlciIgYXV0b2NvbXBsZXRlPSJvZmYiID48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoLWlucHV0LWFuZC1zdWdnZXN0aW9ucy13cmFwcGVyIj48aW5wdXQgaWQ9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgbmFtZT0icXVlcnkiIGRhdGEtc3VnZ2VzdD0iNHR1OmNvcnBvcmF0ZV9lbiIgZGF0YS1zdWdnZXN0cGFyZW50PSJwYXJlbnQiIHBsYWNlaG9sZGVyPSJab2VrZW4iIGFyaWEtbGFiZWw9IlpvZWtlbiIgdHlwZT0ic2VhcmNoIiAvPjwvZGl2PjxsYWJlbCBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaCIgZm9yPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoaW5wdXQiIHRhYmluZGV4PSItMSIgPjxzcGFuIGNsYXNzPSJmYXIgZmEtc2VhcmNoIj48L3NwYW4+PC9sYWJlbD48L2Zvcm0+PGJ1dHRvbiBpZD0iaGVhZGVyLW1lbnViYXJfc2lkZWJhcnRvZ2dsZSIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zaG93c2lkZW1haW5tZW51IHNpZGViYXItYWN0aW9uLXRvZ2dsZSIgYXJpYS1sYWJlbD0iT3BlbiBtZW51IiBhcmlhLWV4cGFuZGVkPSJmYWxzZSIgYXJpYS1jb250cm9scz0ic2xpZGVtZW51IiA+PHNwYW4gY2xhc3M9ImZhciBmYS1iYXJzIj48L3NwYW4+PC9idXR0b24+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX3RvcGJhciI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jbG9zZSI+Q2xvc2U8L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbnMiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fYWRkcmVzcyBydGRjb250ZW50Ij48cCBjbGFzcz0iaGVhZGluZyI+NFRVLkZlZGVyYXRpb248L3A+PHAgY2xhc3M9Im5vcm1hbCI+KzMxKDApNiA0OCAyNyA1NSA2MTwvcD48cCBjbGFzcz0ibm9ybWFsIj48YSBocmVmPSJtYWlsdG86cHJvamVjdGxlaWRlckA0dHUubmwiPnNlY3JldGFyaXNANHR1Lm5sPC9hPjwvcD48cCBjbGFzcz0ibm9ybWFsIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48Yj5XZWJzaXRlOiA0VFUubmw8L2I+PC9hPjwvcD48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiBleHBsb3JlcGFuZWxfX2NvbHVtbi0tbWFueWl0ZW1zIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlJlc2VhcmNoPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyBleHBsb3JlcGFuZWxfX2l0ZW1zLS1tYW55aXRlbXMgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyI+PHNwYW4+QXBwbGllZCBNYXRoZW1hdGljcyBJbnN0aXR1dGU8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyI+PHNwYW4+QnVpbHQgRW52aXJvbm1lbnQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iPjxzcGFuPkRlc2lnbiBVbml0ZWQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIj48c3Bhbj5FbmVyZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iPjxzcGFuPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyI+PHNwYW4+SGVhbHRoPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyI+PHNwYW4+SGlnaC1UZWNoIE1hdGVyaWFsczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iPjxzcGFuPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iPjxzcGFuPk5JUklDVCAoSUNUKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIj48c3Bhbj5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIj48c3Bhbj5SZXNlYXJjaERhdGE8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIj48c3Bhbj5IVFNGIEkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIj48c3Bhbj5IVFNGIElJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiAiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuRWR1Y2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyAgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyI+PHNwYW4+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iPjxzcGFuPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIj48c3Bhbj5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcndpanMvb25kZXJ3aWpzcHJvZ3JhbW1hcy8iPjxzcGFuPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2NvbHVtbiAiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuVmFsb3Jpc2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19pdGVtcyAgIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIj48c3Bhbj40VFUuSU1QQUNUPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3RlY2gtdHJhbnNmZXIubmwvZW4vIj48c3Bhbj5UaGVtYXRpYyBUZWNobm9sb2d5IFRyYW5zZmVyPC9zcGFuPjwvYT48YSBocmVmPSIiPjxzcGFuPlNwaW4tb2ZmIFN0b3JpZXM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vNHR1aW1wYWN0Y2hhbGxlbmdlLm5sLyI+PHNwYW4+NFRVIEltcGFjdCBDaGFsbGVuZ2U8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19iYWNrZ3JvdW5kIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fc2xpZGVzaG93IGNhcnJvdXNlbF9fdmlld3BvcnQgY2Fycm91c2VsX19kcmFnYXJlYSAiPjxzdHlsZT5AbWVkaWEgKG1heC13aWR0aDogNzY3cHgpey5oZWFkZXJzbGlkZTB7YmFja2dyb3VuZC1jb2xvcjogIzFEMUExRDtiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pYzgyYmJjMDUwMTAyNTJmODEwMDAwM2RlYTYwMWM2MDQ3MmUzYTZkMmNmZDYwODAxZTM0MDBiMDAwNzgxNDYvdGhlLWNvbmNlcHQtb2YtcmVhZGluZy1sb3ZlLTIwMjMtMTEtMjctMDUtMTItMDktdXRjLmpwZyk7fX1AbWVkaWEgKG1pbi13aWR0aDogNzY4cHgpey5oZWFkZXJzbGlkZTB7YmFja2dyb3VuZC1jb2xvcjogIzFEMUExRDtiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pYmU3ODUzNzgwMTAyNTJmODEwMDAwM2RlYTYwMWM2MDQ3MmUzYTZkMmNmZDYwODAxZTM0MDBiNjAwNDgxNDYvdGhlLWNvbmNlcHQtb2YtcmVhZGluZy1sb3ZlLTIwMjMtMTEtMjctMDUtMTItMDktdXRjLmpwZyk7fX08L3N0eWxlPjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19zbGlkZSBjYXJyb3VzZWxfX2NlbGwgYWN0aXZlc2xpZGUgaGVhZGVyc2xpZGUwICIgZGF0YS1zbGlkZXNob3ctZWxlbWVudHM9InBhZ2UtaGVhZGVyX19zbGlkZTBfX2NvbnRlbnQiIHN0eWxlPSIiID48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fY29udGVudCI+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX21ldGEiPjxoMSBjbGFzcz0icGFnZS1oZWFkZXJfX3RpdGxlIj5VQ0wncyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlPC9oMT48ZGl2IGNsYXNzPSJwYWdlaGVhZGVyX19kYXRlIj5UdWVzZGF5IDE4IEp1bmUgMjAyNCAvIDEwLjAwIC0gMTEuMzA8L2Rpdj48ZGl2IGNsYXNzPSJwYWdlaGVhZGVyX190ZXh0Ij5Mb2NhdGlvbjogb25saW5lPC9kaXY+PC9kaXY+PC9kaXY+PG1haW4gY2xhc3M9InBhZ2VfX2JvZHkgICI+PGZvcm0gaWQ9IiIgIGNsYXNzPSJwYWdlX19oZWFkZXJmaWx0ZXJzICAgIj48L2Zvcm0+PGRpdiBjbGFzcz0icGFnZV9fY29udGVudGFyZWEgIHBhZ2VfX2NvbnRlbnRhcmVhLS1mb3Jtd2VidG9vbCAgaGVhZGVyaXNvcGFxdWUgIj48ZGl2IGNsYXNzPSJkZWVwbGlua3Mtd3JhcHBlciI+PGRpdiBjbGFzcz0iZGVlcGxpbmtzIj48YSBjbGFzcz0icGFnZS1iYWNrbGluayIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFsbCBldmVudHM8L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1jb250ZW50c3RhcnQiPjwvZGl2PjwhLS13aF9jb25zaWxpb19jb250ZW50LS0+PGZvcm0gY2xhc3M9IndoLWZvcm0gd2gtc3R5bGVkaW5wdXQiICBtZXRob2Q9InBvc3QiIGFjdGlvbj0iamF2YXNjcmlwdDpjb25zb2xlLmVycm9yKCdObyBSUEMgaGFuZGxlciBpbnN0YWxsZWQnKTsiIGRhdGEtd2gtZm9ybS12YXItZm9ybXN1Ym1pdHR5cGU9Im5ldyIgZGF0YS13aC1mb3JtLWlkPSJ3ZWJ0b29sZm9ybSIgZGF0YS13aC1mb3JtLWhhbmRsZXI9InB1Ymxpc2hlcjpycGMiIGRhdGEtd2gtZm9ybS10YXJnZXQ9IjRGMzJ0VHJyUjVLYnROSHlaYmxZcWJVRGZHZ3R3WXQyR3RPT3VsNFFzTktNaF8xQWFrOFRjaGRYeVA0SXpyRW5GbFgwMmJPMUJPWnRQNUZUS3dnV2FvajVaa0ppelZ2RS5yeUZqYlcxcllfQ1E0QnN0LnBjUUM0N0VGMFpjQjF5UjdGNHdZdmciPjxhIGNsYXNzPSJ3aC1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19wcm9sb2d1ZSI+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fcGFnZSB3aC1mb3JtX19wYWdlLS12aXNpYmxlIj48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGdyb3VwIHdoLWZvcm1fX2ZpZWxkZ3JvdXAtLXJpY2h0ZXh0IiBkYXRhLXdoLWZvcm0tZ3JvdXAtZm9yPSJfX2Zvcm1maWVsZGF3WjZQX2lySnp5bVhTcHNJcFIxYVFfIj48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZHMiPjxhIGNsYXNzPSJ3aC1hbmNob3IiIGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZGF3WjZQX2lySnp5bVhTcHNJcFIxYVFfLWFuY2hvciI+PC9hPjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkbGluZSI+PGRpdiBjbGFzcz0id2gtZm9ybV9fcmljaHRleHQiPjxwIGNsYXNzPSJub3JtYWwiPkRhdGU6IDE4LzA2LzIwMjQ8L3A+PHAgY2xhc3M9Im5vcm1hbCI+VGltZTogMTAuMDAtMTEuMzA8L3A+PGgyIGNsYXNzPSJoZWFkaW5nMiI+Rmlyc3QgcHJlc2VudGF0aW9uOiBTdHVkZW50IExlYXJuaW5nIGV4cGVyaWVuY2VzIGluIENCTDogdGhlIGNhc2VzIG9mIE1hdGhlbWF0aWNzIGFuZCBQaHlzaWNzIGJ5IEJpcmdpdCBQZXBpbiBUVS9lPC9oMj48cCBjbGFzcz0ibm9ybWFsIj5DaGVjayBvdXQgdGhlIHByb2plY3TCoDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvaW5ub3ZhdGlvbi9wcm9qZWN0LzM3MzYvc3R1ZGVudC1sZWFybmluZy1leHBlcmllbmNlcy1pbi1jaGFsbGVuZ2UtYmFzZWQtZWR1Y2F0aW9uLXRoZS1jYXNlcy1vZi1hcHBsaWVkLW1hdGhlbWF0aWNzLWFuZC1waHlzaWNzIj5oZXJlPC9hPiE8L3A+PGgyIGNsYXNzPSJoZWFkaW5nMiI+U2Vjb25kIHByZXNlbnRhdGlvbjogVUNM4oCZcyBFeHBlcmllbmNlIGluIEVuZ2luZWVyaW5nIE1hdGhlbWF0aWNzIEN1cnJpY3VsYXIgUmVmb3JtOiBQcmVwYXJpbmcgc3R1ZGVudHMgZm9yIHRoZSB3b3JrcGxhY2UgYW5kIHNvY2lldHk8L2gyPjxwIGNsYXNzPSJub3JtYWwiPlNwZWFrZXI6wqBNYXRoZXVzIE8uIGRlIEFuZHJhZGU8L3A+PHAgY2xhc3M9Im5vcm1hbCI+RW5naW5lZXJzIG5lZWQgdG8gZHJhdyBmcm9tIGEgYmxlbmQgb2YgZm9ybXMgb2Yga25vd2xlZGdlIHRvIHJlYWxpc2UgdGVjaG5pY2FsbHksIHNvY2lhbGx5LCBlY29ub21pY2FsbHksIGFuZCBlbnZpcm9ubWVudGFsbHkgcmVzcG9uc2libGUgc29sdXRpb25zIHRvIGNvbXBsZXggcHJvYmxlbXMuIEludGVncmF0aW5nIHRoZXNlIHZhbHVlcyBpbiBtYXRoZW1hdGljcyBlZHVjYXRpb24gZm9yIGVuZ2luZWVyaW5nIHN0dWRlbnRzLCBob3dldmVyLCByZW1haW5zIGEgY2hhbGxlbmdlLCBlc3BlY2lhbGx5IGF0IHRoZSBwcm9ncmFtbWUgYW5kIGluc3RpdHV0aW9uYWwgbGV2ZWxzLiBPbiB0aGUgb25lIGhhbmQsIGl0IGlzIGltcGVyYXRpdmUgdGhhdCBtYXRoZW1hdGljcyBtb2R1bGVzIGVxdWlwIHN0dWRlbnRzIHdpdGggdGhlIHRlY2huaWNhbCBrbm93bGVkZ2UgYW5kIHNraWxscyB0aGF0IHdpbGwgYWxsb3cgdGhlbSB0byBlbmdhZ2Ugd2l0aCBhZHZhbmNlZCBlbmdpbmVlcmluZyBjb25jZXB0cyBsYXRlciBpbiB0aGVpciBjb3Vyc2UuIE9uIHRoZSBvdGhlciBoYW5kLCBpdCBpcyBhbHNvIGNsZWFyIHRoYXQgbWF0aGVtYXRpY3MgZWR1Y2F0aW9uIHNob3VsZCBhbHNvIHN1cHBvcnQgdGhlIGRldmVsb3BtZW50IG9mIHNvY2lhbCwgYWZmZWN0aXZlLCBhbmQgbWV0YS1jb2duaXRpdmUgc2tpbGxzIGZvciBlbmdpbmVlcmluZyBzdHVkZW50cy4gSW4gdGhpcyB3ZWJpbmFyLCBJIHdpbGwgZGlzY3VzcyBVQ0zigJlzIGV4cGVyaWVuY2VzIGluIHRoZSBkZXNpZ24gYW5kIGltcGxlbWVudGF0aW9uIG9mIGZhY3VsdHktd2lkZSBjdXJyaWN1bGEsIGFjdGl2aXRpZXMsIGFuZCBhc3Nlc3NtZW50IG9mIG1hdGhlbWF0aWNzIHRoYXQgaXMgcHJpbWFyaWx5IHRhdWdodCB0aHJvdWdoIGVuZ2luZWVyaW5nIGFwcGxpY2F0aW9ucyB3aXRoaW4gc29jaWV0YWwgY29udGV4dHMuPC9wPjwvZGl2PjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkZ3JvdXAgd2gtZm9ybV9fZmllbGRncm91cC0tdGV4dGVkaXQgd2gtZm9ybV9fZmllbGRncm91cC0tcmVxdWlyZWQiIGRhdGEtd2gtZm9ybS1ncm91cC1mb3I9Il9fZm9ybWZpZWxkS3QtRGM4OHZVUTV5aUNvQmx3SkZQQV8iPjxsYWJlbCBjbGFzcz0id2gtZm9ybV9fbGFiZWwiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRLdC1EYzg4dlVRNXlpQ29CbHdKRlBBXyI+Rmlyc3QgbmFtZTwvbGFiZWw+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRzIj48YSBjbGFzcz0id2gtYW5jaG9yIiBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRLdC1EYzg4dlVRNXlpQ29CbHdKRlBBXy1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUiPjxpbnB1dCBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRLdC1EYzg4dlVRNXlpQ29CbHdKRlBBXyIgdHlwZT0idGV4dCIgbmFtZT0iX19mb3JtZmllbGRLdC1EYzg4dlVRNXlpQ29CbHdKRlBBXyIgY2xhc3M9IndoLWZvcm1fX3RleHRpbnB1dCIgcGxhY2Vob2xkZXI9IiAiIHJlcXVpcmVkPjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkZ3JvdXAgd2gtZm9ybV9fZmllbGRncm91cC0tdGV4dGVkaXQgd2gtZm9ybV9fZmllbGRncm91cC0tcmVxdWlyZWQiIGRhdGEtd2gtZm9ybS1ncm91cC1mb3I9Il9fZm9ybWZpZWxkTEs4S0hSVnRFNkFPVVpwREt2VHRCZ18iPjxsYWJlbCBjbGFzcz0id2gtZm9ybV9fbGFiZWwiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRMSzhLSFJWdEU2QU9VWnBES3ZUdEJnXyI+TGFzdCBuYW1lPC9sYWJlbD48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZHMiPjxhIGNsYXNzPSJ3aC1hbmNob3IiIGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZExLOEtIUlZ0RTZBT1VacERLdlR0QmdfLWFuY2hvciI+PC9hPjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkbGluZSI+PGlucHV0IGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZExLOEtIUlZ0RTZBT1VacERLdlR0QmdfIiB0eXBlPSJ0ZXh0IiBuYW1lPSJfX2Zvcm1maWVsZExLOEtIUlZ0RTZBT1VacERLdlR0QmdfIiBjbGFzcz0id2gtZm9ybV9fdGV4dGlucHV0IiBwbGFjZWhvbGRlcj0iICIgcmVxdWlyZWQ+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRncm91cCB3aC1mb3JtX19maWVsZGdyb3VwLS10ZXh0ZWRpdCB3aC1mb3JtX19maWVsZGdyb3VwLS1yZXF1aXJlZCIgZGF0YS13aC1mb3JtLWdyb3VwLWZvcj0iX19mb3JtZmllbGRxaEtwRWVJZjhPbkRVVkh2bUVoR0VRXyI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19sYWJlbCIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZHFoS3BFZUlmOE9uRFVWSHZtRWhHRVFfIj5FLW1haWwgYWRkcmVzczwvbGFiZWw+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRzIj48YSBjbGFzcz0id2gtYW5jaG9yIiBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRxaEtwRWVJZjhPbkRVVkh2bUVoR0VRXy1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUiPjxpbnB1dCBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRxaEtwRWVJZjhPbkRVVkh2bUVoR0VRXyIgdHlwZT0iZW1haWwiIG5hbWU9Il9fZm9ybWZpZWxkcWhLcEVlSWY4T25EVVZIdm1FaEdFUV8iIGNsYXNzPSJ3aC1mb3JtX190ZXh0aW5wdXQiIHBsYWNlaG9sZGVyPSIgIiByZXF1aXJlZD48L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGdyb3VwIHdoLWZvcm1fX2ZpZWxkZ3JvdXAtLXJhZGlvZ3JvdXAgd2gtZm9ybV9fZmllbGRncm91cC0tcmVxdWlyZWQiIHJvbGU9Imdyb3VwIiBhcmlhLWxhYmVsbGVkYnk9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tbGFiZWwiIGRhdGEtd2gtZm9ybS1ncm91cC1mb3I9Il9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18gX19mb3JtZmllbGRrRUcyVF80dGpxMGlIUWxMS3ZIZm13XyI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19sYWJlbCIgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tbGFiZWwiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3XyI+VW5pdmVyc2l0eTwvbGFiZWw+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRzIj48YSBjbGFzcz0id2gtYW5jaG9yIiBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUgd2gtZm9ybV9fZmllbGRsaW5lLS1ub3dyYXAiPjxpbnB1dCBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy1xT01NS1pPT3lTRDRrVTc2X21JS1NBIiB0eXBlPSJyYWRpbyIgY2xhc3M9IndoLWZvcm1fX3JhZGlvIiBuYW1lPSJfX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfIiB2YWx1ZT0icU9NTUtaT095U0Q0a1U3Nl9tSUtTQSIgcmVxdWlyZWQ+PGxhYmVsIGFyaWEtaGlkZGVuPSJ0cnVlIiBmb3I9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tcU9NTUtaT095U0Q0a1U3Nl9tSUtTQSI+PC9sYWJlbD48c3BhbiBjbGFzcz0id2gtZm9ybV9fb3B0aW9uZGF0YSB3aC1mb3JtX19vcHRpb25kYXRhLS12ZXJ0aWNhbCI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25sYWJlbCIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLXFPTU1LWk9PeVNENGtVNzZfbUlLU0EiPkRlbGZ0IFVuaXZlcnNpdHkgb2YgVGVjaG5vbG9neTwvbGFiZWw+PC9zcGFuPjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkbGluZSB3aC1mb3JtX19maWVsZGxpbmUtLW5vd3JhcCI+PGlucHV0IGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLXhicVYwdVBUR2tMdk1qX3IxMlRabkEiIHR5cGU9InJhZGlvIiBjbGFzcz0id2gtZm9ybV9fcmFkaW8iIG5hbWU9Il9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18iIHZhbHVlPSJ4YnFWMHVQVEdrTHZNal9yMTJUWm5BIiByZXF1aXJlZD48bGFiZWwgYXJpYS1oaWRkZW49InRydWUiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy14YnFWMHVQVEdrTHZNal9yMTJUWm5BIj48L2xhYmVsPjxzcGFuIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25kYXRhIHdoLWZvcm1fX29wdGlvbmRhdGEtLXZlcnRpY2FsIj48bGFiZWwgY2xhc3M9IndoLWZvcm1fX29wdGlvbmxhYmVsIiBmb3I9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18teGJxVjB1UFRHa0x2TWpfcjEyVFpuQSI+RWluZGhvdmVuIFVuaXZlcnNpdHkgb2YgVGVjaG5vbG9neTwvbGFiZWw+PC9zcGFuPjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkbGluZSB3aC1mb3JtX19maWVsZGxpbmUtLW5vd3JhcCI+PGlucHV0IGlkPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLTdvT080Z3JOUjZrbUotUzBoQnpMTEEiIHR5cGU9InJhZGlvIiBjbGFzcz0id2gtZm9ybV9fcmFkaW8iIG5hbWU9Il9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18iIHZhbHVlPSI3b09PNGdyTlI2a21KLVMwaEJ6TExBIiByZXF1aXJlZD48bGFiZWwgYXJpYS1oaWRkZW49InRydWUiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy03b09PNGdyTlI2a21KLVMwaEJ6TExBIj48L2xhYmVsPjxzcGFuIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25kYXRhIHdoLWZvcm1fX29wdGlvbmRhdGEtLXZlcnRpY2FsIj48bGFiZWwgY2xhc3M9IndoLWZvcm1fX29wdGlvbmxhYmVsIiBmb3I9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tN29PTzRnck5SNmttSi1TMGhCekxMQSI+VW5pdmVyc2l0eSBvZiBUd2VudGU8L2xhYmVsPjwvc3Bhbj48L2Rpdj48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUgd2gtZm9ybV9fZmllbGRsaW5lLS1ub3dyYXAiPjxpbnB1dCBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy1vWU01NVE5RFJhOEVmajFUZ3FVSkxBIiB0eXBlPSJyYWRpbyIgY2xhc3M9IndoLWZvcm1fX3JhZGlvIiBuYW1lPSJfX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfIiB2YWx1ZT0ib1lNNTVROURSYThFZmoxVGdxVUpMQSIgcmVxdWlyZWQ+PGxhYmVsIGFyaWEtaGlkZGVuPSJ0cnVlIiBmb3I9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tb1lNNTVROURSYThFZmoxVGdxVUpMQSI+PC9sYWJlbD48c3BhbiBjbGFzcz0id2gtZm9ybV9fb3B0aW9uZGF0YSB3aC1mb3JtX19vcHRpb25kYXRhLS12ZXJ0aWNhbCI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25sYWJlbCIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLW9ZTTU1UTlEUmE4RWZqMVRncVVKTEEiPldhZ2VuaW5nZW4gVW5pdmVyc2l0eSAgJiMzODsgIFJlc2VhcmNoPC9sYWJlbD48L3NwYW4+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRsaW5lIHdoLWZvcm1fX2ZpZWxkbGluZS0tbm93cmFwIHdoLWZvcm1fX2ZpZWxkbGluZS0tc3ViZmllbGRzIj48aW5wdXQgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkQ0RGeWJxTzVUZUwwQ3dpQVYyRnI5d18tbFFSMUpZek8tZ2FUQWJpTU5mckVNQSIgdHlwZT0icmFkaW8iIGNsYXNzPSJ3aC1mb3JtX19yYWRpbyIgbmFtZT0iX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3XyIgdmFsdWU9ImxRUjFKWXpPLWdhVEFiaU1OZnJFTUEiIHJlcXVpcmVkIGRhdGEtd2gtZm9ybS1lbmFibGU9Il9fZm9ybWZpZWxka0VHMlRfNHRqcTBpSFFsTEt2SGZtd18iPjxsYWJlbCBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZENERnlicU81VGVMMEN3aUFWMkZyOXdfLWxRUjFKWXpPLWdhVEFiaU1OZnJFTUEiPjwvbGFiZWw+PHNwYW4gY2xhc3M9IndoLWZvcm1fX29wdGlvbmRhdGEgd2gtZm9ybV9fb3B0aW9uZGF0YS0tdmVydGljYWwiPjxsYWJlbCBjbGFzcz0id2gtZm9ybV9fb3B0aW9ubGFiZWwiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGRDREZ5YnFPNVRlTDBDd2lBVjJGcjl3Xy1sUVIxSll6Ty1nYVRBYmlNTmZyRU1BIj5vdGhlcjwvbGFiZWw+PHNwYW4gY2xhc3M9IndoLWZvcm1fX3N1YmZpZWxkIj48aW5wdXQgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxka0VHMlRfNHRqcTBpSFFsTEt2SGZtd18iIHR5cGU9InRleHQiIG5hbWU9Il9fZm9ybWZpZWxka0VHMlRfNHRqcTBpSFFsTEt2SGZtd18iIGNsYXNzPSJ3aC1mb3JtX190ZXh0aW5wdXQiIHBsYWNlaG9sZGVyPSIgIiByZXF1aXJlZD48L3NwYW4+PC9zcGFuPjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkZ3JvdXAgd2gtZm9ybV9fZmllbGRncm91cC0tY2hlY2tib3giIGRhdGEtd2gtZm9ybS1ncm91cC1mb3I9Il9fZm9ybWZpZWxkNG1TQVFNSVRvaG9iVjduT0JTMUZVUV8iPjxkaXYgY2xhc3M9IndoLWZvcm1fX2ZpZWxkcyI+PGEgY2xhc3M9IndoLWFuY2hvciIgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkNG1TQVFNSVRvaG9iVjduT0JTMUZVUV8tYW5jaG9yIj48L2E+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRsaW5lIHdoLWZvcm1fX2ZpZWxkbGluZS0tbm93cmFwIj48aW5wdXQgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkNG1TQVFNSVRvaG9iVjduT0JTMUZVUV8iIHR5cGU9ImNoZWNrYm94IiBjbGFzcz0id2gtZm9ybV9fY2hlY2tib3giIG5hbWU9Il9fZm9ybWZpZWxkNG1TQVFNSVRvaG9iVjduT0JTMUZVUV8iIHZhbHVlPSIxIj48bGFiZWwgYXJpYS1oaWRkZW49InRydWUiIGZvcj0id2VidG9vbGZvcm0tX19mb3JtZmllbGQ0bVNBUU1JVG9ob2JWN25PQlMxRlVRXyI+PC9sYWJlbD48c3BhbiBjbGFzcz0id2gtZm9ybV9fb3B0aW9uZGF0YSB3aC1mb3JtX19vcHRpb25kYXRhLS12ZXJ0aWNhbCI+PGxhYmVsIGNsYXNzPSJ3aC1mb3JtX19vcHRpb25sYWJlbCIgZm9yPSJ3ZWJ0b29sZm9ybS1fX2Zvcm1maWVsZDRtU0FRTUlUb2hvYlY3bk9CUzFGVVFfIj5zZW5kIG1lIHVwZGF0ZXMgb24gZnV0dXJlIDRUVS5DRUUgZXZlbnRzPC9sYWJlbD48L3NwYW4+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fcGFnZSB3aC1mb3JtX19wYWdlLS1oaWRkZW4iIGRhdGEtd2gtZm9ybS1wYWdlcm9sZT0idGhhbmt5b3UiIHJvbGU9InN0YXR1cyI+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRncm91cCB3aC1mb3JtX19maWVsZGdyb3VwLS1yaWNodGV4dCIgZGF0YS13aC1mb3JtLWdyb3VwLWZvcj0iX19mb3JtZmllbGRWNTVKSmYzWW5xcmV5SnlMN01FQll3XyI+PGRpdiBjbGFzcz0id2gtZm9ybV9fZmllbGRzIj48YSBjbGFzcz0id2gtYW5jaG9yIiBpZD0id2VidG9vbGZvcm0tX19mb3JtZmllbGRWNTVKSmYzWW5xcmV5SnlMN01FQll3Xy1hbmNob3IiPjwvYT48ZGl2IGNsYXNzPSJ3aC1mb3JtX19maWVsZGxpbmUiPjxkaXYgaWQ9IndlYnRvb2xmb3JtLV9fZm9ybWZpZWxkVjU1SkpmM1lucXJleUp5TDdNRUJZd18iIGNsYXNzPSJ3aC1mb3JtX19yaWNodGV4dCI+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0id2gtZm9ybV9fYnV0dG9uZ3JvdXAgd2gtZm9ybV9fbmF2YnV0dG9ucyI+PGJ1dHRvbiB0eXBlPSJidXR0b24iIGRhdGEtd2gtZm9ybS1hY3Rpb249InByZXZpb3VzIiBjbGFzcz0id2gtZm9ybV9fYnV0dG9uIHdoLWZvcm1fX2J1dHRvbi0tcHJldmlvdXMiPjxzcGFuIGNsYXNzPSJ3aC1mb3JtX19idXR0b25sYWJlbCI+UHJldmlvdXM8L3NwYW4+PC9idXR0b24+PGJ1dHRvbiB0eXBlPSJidXR0b24iIGRhdGEtd2gtZm9ybS1hY3Rpb249Im5leHQiIGNsYXNzPSJ3aC1mb3JtX19idXR0b24gd2gtZm9ybV9fYnV0dG9uLS1uZXh0Ij48c3BhbiBjbGFzcz0id2gtZm9ybV9fYnV0dG9ubGFiZWwiPk5leHQ8L3NwYW4+PC9idXR0b24+PGJ1dHRvbiB0eXBlPSJzdWJtaXQiIGNsYXNzPSJ3aC1mb3JtX19idXR0b24gd2gtZm9ybV9fYnV0dG9uLS1zdWJtaXQiPjxzcGFuIGNsYXNzPSJ3aC1mb3JtX19idXR0b25sYWJlbCI+U3VibWl0PC9zcGFuPjwvYnV0dG9uPjwvZGl2PjwvZm9ybT48IS0tL3doX2NvbnNpbGlvX2NvbnRlbnQtLT48ZGl2IGNsYXNzPSJwYWdlX19iYWxsb29uIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXIiPjxkaXYgY2xhc3M9InBhZ2VfX2Zvb3Rlcl9fY29udGVudCBuYXZwYXRoIj48YSBjbGFzcz0ibmF2cGF0aF9faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT48c3BhbiBjbGFzcz0ibmF2cGF0aF9fc2VwZXJhdG9yIj48L3NwYW4+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19pdGVtIGNydW1icGF0aC0tY3VycmVudHBhZ2UiPlVDTCYjMzk7cyBFeHBlcmllbmNlIHdpdGggQ0JMIGluIEVuZ2luZWVyaW5nIGVkdWNhdGlvbiB3aXRoIEJpcmdpdCBQZXBpbiBhbmQgTWF0aGV1cyBPLiBkZSBBbmRyYWRlPC9zcGFuPjwvZGl2PjwvZGl2PjwvZGl2PjwvbWFpbj48ZGl2IGNsYXNzPSJmb290ZXIiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fcGFuZWwiPjxkaXYgY2xhc3M9ImZvb3Rlcl9faWRlbnRpdHkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX3NpdGV0aXRsZSI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwhLS0gRklYTUU6IHVzZSBhcmlhLWhpZGRlbj0idHJ1ZSIgYmVjYXVzZSBpdCdzIGEgZHVwbGljYXRlIG9mIHRoZSBpdGVtcyBvbiB0aGUgbWVudSBiYXIgPyAtLT4gPG5hdiBjbGFzcz0iZm9vdGVyX19jb2x1bW4xIGZvb3Rlcl9fbWFpbm1lbnUiIGFyaWEtbGFiZWw9Ik1haW4iPiA8dWw+ICAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj5Ib21lPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIj5SZXNlYXJjaDwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi8iPkVkdWNhdGlvbjwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iIj5WYWxvcmlzYXRpb248L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIj5OZXdzPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyI+QWdlbmRhPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyI+QWJvdXQgNFRVPC9hPiA8L2xpPiAgIDwvdWw+IDwvbmF2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW4yIj4gPGlucHV0IHR5cGU9ImNoZWNrYm94IiBuYW1lPSJmb290ZXJjb2x1bW4iIGlkPSJmb290ZXJfX2NvbHVtbjJfX2V4cGFuZCIgLz4gPGxhYmVsIGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyIgZm9yPSJmb290ZXJfX2NvbHVtbjJfX2V4cGFuZCI+Q29udGFjdDwvbGFiZWw+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IHJ0ZGNvbnRlbnQiPiA8cCBjbGFzcz0ibm9ybWFsIj4rMzEoMCk2IDgzIDIyIDUwIDU5PGJyIC8+PGEgaHJlZj0ibWFpbHRvOnByb2plY3RsZWlkZXJANHR1Lm5sIj5zZWNyZXRhcmlzQDR0dS5ubDwvYT48L3A+IDwvZGl2PiA8L2Rpdj4gICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjMiPiA8aW5wdXQgdHlwZT0iY2hlY2tib3giIG5hbWU9ImZvb3RlcmNvbHVtbiIgaWQ9ImZvb3Rlcl9fY29sdW1uM19fZXhwYW5kIiAvPiA8bGFiZWwgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIiBmb3I9ImZvb3Rlcl9fY29sdW1uM19fZXhwYW5kIj5Qb3N0YWRyZXM8L2xhYmVsPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9fY29udGVudCBydGRjb250ZW50Ij4gPHAgY2xhc3M9Im5vcm1hbCI+NFRVLkZlZGVyYXRpZTxiciAvPlBvc3RidXMgNTxiciAvPjI2MDAgQUEgRGVsZnQ8L3A+IDwvZGl2PiA8L2Rpdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uNCI+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW1zX19ncm91cCI+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIj5Gb2xsb3cgdXM8L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9fY29udGVudCBmb290ZXJfX3NvY2lhbGl0ZW1zICI+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly90d2l0dGVyLmNvbS80VFVGZWRlcmF0aW9uIiB0aXRsZT0iVHdpdHRlciIgPjxzcGFuIGNsYXNzPSJmYWIgZmEtdHdpdHRlciI+PC9zcGFuPjwvYT48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3d3dy5saW5rZWRpbi5jb20vY29tcGFueS80LXR1LWZlZGVyYXRpb24vIiB0aXRsZT0iTGlua2VkSW4iID48c3BhbiBjbGFzcz0iZmFiIGZhLWxpbmtlZGluLWluIj48L3NwYW4+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2NoYW5uZWwvVUNNa3FoangyVzFoTlJ3eXNSdldFWHdRIiB0aXRsZT0iWW91dHViZSIgPjxzcGFuIGNsYXNzPSJmYWIgZmEteW91dHViZSI+PC9zcGFuPjwvYT48L2Rpdj4gPC9kaXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJfX2dyb3VwIj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIGZvb3Rlcl9fY29sdW1uX19oZWFkaW5nLS1uZXdzbGV0dGVyICI+U3RheSB1cC10by1kYXRlPC9kaXY+PGZvcm0gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cCB3aHBsdWdpbi1uZXdzbGV0dGVyLXN1YnNjcmlwdGlvbiAgIiBkYXRhLW5ld3NsZXR0ZXItbGlzdD0iU1VCU180VFVfQ09SUE9SQVRFX05JRVVXU0JSSUVGIiA+PGlucHV0IG5hbWU9ImVtYWlsIiBwbGFjZWhvbGRlcj0iU2lnbiB1cCBmb3Igb3VyIG5ld3NsZXR0ZXIiIC8+PGJ1dHRvbiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwX19zdWJtaXQiIHR5cGU9InN1Ym1pdCIgbmFtZT0ic3VibWl0YnV0dG9uIiBhcmlhLWxhYmVsPSJTdWJzY3JpYmUiPjxzcGFuIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Ym1pdF9faWNvbiBmYXIgZmEtZW52ZWxvcGUiPjwvc3Bhbj48L2J1dHRvbj48L2Zvcm0+PGRpdiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwX19zdWNjZXNzIj5UaGFua3MgZm9yIHN1YnNjcmliaW5nIHRvIG91ciBuZXdzbGV0dGVyLjwvZGl2PiAgPC9kaXY+IDwvZGl2PiA8aHIgY2xhc3M9ImZvb3Rlcl9fZGl2aWRlciIgLz4gPGRldGFpbHMgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZSI+PHN1bW1hcnk+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX190b2dnbGVfX2Nsb3NlZHRleHQiPlBhcnQgb2YgdGhlIDxzcGFuIGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX25hbWUiPjRUVS5GZWRlcmF0aW9uPC9zcGFuPjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fdG9nZ2xlX19vcGVudGV4dCI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2Nsb3NlIj5DbG9zZTwvZGl2PjwvZGl2Pjwvc3VtbWFyeT48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbCI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2NhdGVnb3J5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuUmVzZWFyY2g8L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIj48c3Bhbj5BcHBsaWVkIE1hdGhlbWF0aWNzIEluc3RpdHV0ZTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIj48c3Bhbj5CdWlsdCBFbnZpcm9ubWVudDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyI+PHNwYW4+RGVzaWduIFVuaXRlZDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iPjxzcGFuPkVuZXJneTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyI+PHNwYW4+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIj48c3Bhbj5IZWFsdGg8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIj48c3Bhbj5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyI+PHNwYW4+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyI+PHNwYW4+TklSSUNUIChJQ1QpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iPjxzcGFuPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iPjxzcGFuPlJlc2VhcmNoRGF0YTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iPjxzcGFuPkhUU0YgSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iPjxzcGFuPkhUU0YgSUkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLkVkdWNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iPjxzcGFuPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIj48c3Bhbj40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyI+PHNwYW4+U0FJIChFbmdpbmVlcmluZyBEb2N0b3JhdGUpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ3aWpzL29uZGVyd2lqc3Byb2dyYW1tYXMvIj48c3Bhbj5FZHVjYXRpb24gcHJvZ3JhbW1lczwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2NhdGVnb3J5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuVmFsb3Jpc2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIj48c3Bhbj40VFUuSU1QQUNUPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3RlY2gtdHJhbnNmZXIubmwvZW4vIj48c3Bhbj5UaGVtYXRpYyBUZWNobm9sb2d5IFRyYW5zZmVyPC9zcGFuPjwvYT48YSBocmVmPSIiPjxzcGFuPlNwaW4tb2ZmIFN0b3JpZXM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vNHR1aW1wYWN0Y2hhbGxlbmdlLm5sLyI+PHNwYW4+NFRVIEltcGFjdCBDaGFsbGVuZ2U8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjwvZGV0YWlscz4gPGRpdiBjbGFzcz0iZm9vdGVyX19wYXJ0bmVycyI+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW1zIj4gPGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZGVsZnQubmwvZW4vIiB0aXRsZT0iVFUgRGVsZnQiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZGVsZnQuc3ZnIiBhbHQ9IlRVIERlbGZ0IiB3aWR0aD0iODciIGhlaWdodD0iMzQiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWUubmwvZW4vIiB0aXRsZT0iVFUgRWluZGhvdmVuIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWVpbmRob3Zlbi5zdmciIGFsdD0iVFUgRWluZGhvdmVuIiB3aWR0aD0iMTMwIiBoZWlnaHQ9IjI3IiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudXR3ZW50ZS5ubC9lbi8iIHRpdGxlPSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvdW5pdmVyc2l0eS1vZi10d2VudGUuc3ZnIiBhbHQ9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiB3aWR0aD0iODUiIGhlaWdodD0iMzEiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy53dXIubmwvIiB0aXRsZT0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXd1ci5zdmciIGFsdD0iV2FnZW5pbmdlbiBVbml2ZXJzaXR5IiB3aWR0aD0iMTQ1IiBoZWlnaHQ9IjI5IiAvPjwvYT4gPC9kaXY+IDwvZGl2PiA8L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2JvdHRvbWJhciI+PHNwYW4gY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyX19jb3B5cmlnaHQiPjxzcGFuIGNsYXNzPSJmYmNwYXJ0Ij4mY29weTsgMjAyNCA0VFUuRmVkZXJhdGlvbjwvc3Bhbj48L3NwYW4+PHVsIGNsYXNzPSJmb290ZXJfX2JvdHRvbWJhcl9fbWVudSI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9jb250YWN0LyI+Q29udGFjdDwvYT48L2xpPjwvdWw+PC9kaXY+PC9kaXY+PHNjcmlwdCB0eXBlPSJhcHBsaWNhdGlvbi94LWhzb24iIGlkPSJ3aC1jb25zaWxpb2ZpZWxkcyI+aHNvbjp7Indoc2VhcmNodGh1bWJuYWlsIjoiaHR0cHM6Ly93d3cuNHR1Lm5sLy51Yy9pYTc3MzQ1NWEwMTAyNTRmODEwMDAwM2RlYTYwMWM2MDQ3MmUzYTZkMmNmZDYwODAxZTM0MDAxZjAwMDgxNDEvdGhlLWNvbmNlcHQtb2YtcmVhZGluZy1sb3ZlLTIwMjMtMTEtMjctMDUtMTItMDktdXRjLmpwZyJ9PC9zY3JpcHQ+PC9ib2R5PjwvaHRtbD4=
+ recorded_at: Wed, 02 Jan 2019 16:00:00 GMT
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/4TU-meeting%20National%20Technology%20Strategy/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Thu, 06 Jun 2024 07:51:56 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Content-Length:
+ - '35025'
+ Connection:
+ - keep-alive
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Last-Modified:
+ - Wed, 05 Jun 2024 08:57:55 GMT
+ Vary:
+ - Accept-Encoding
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnQgc2l0ZWhlYWRlci0tbWVudWJhci10cmFuc2x1Y2VudCBwYWdlLS13aXRoYmFja2xpbmsiIGRhdGEtdHJhY2tpbmdpZD0iIj48aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PHRpdGxlPjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3k8L3RpdGxlPjxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzRUVS1tZWV0aW5nJTIwTmF0aW9uYWwlMjBUZWNobm9sb2d5JTIwU3RyYXRlZ3kvIj4KPCEtLQpSZWFsaXNhdGllOiDwn5K8IFdlYkhhcmUgYnYKICAgICAgICAgICAg8J+MkCBodHRwczovL3d3dy53ZWJoYXJlLm5sLwotLT4KPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgaW5pdGlhbC1zY2FsZT0xIiAvPjxsaW5rIHJlbD0iYXBwbGUtdG91Y2gtaWNvbiIgc2l6ZXM9IjE4MHgxODAiIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9hcHBsZS10b3VjaC1pY29uLTE4MHgxODAucG5nIiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi0zMngzMi5wbmciIHNpemVzPSIzMngzMiIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tOTZ4OTYucG5nIiBzaXplcz0iOTZ4OTYiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTE5NHgxOTQucG5nIiBzaXplcz0iMTk0eDE5NCIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2FuZHJvaWQtY2hyb21lLTE5MngxOTIucG5nIiBzaXplcz0iMTkyeDE5MiIgLz48bGluayByZWw9Im1hc2staWNvbiIgICAgICAgICAgICAgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL3NhZmFyaS1waW5uZWQtdGFiLnN2ZyIgY29sb3I9IiNmZjhiMzgiIC8+PG1ldGEgbmFtZT0idGhlbWUtY29sb3IiIGNvbnRlbnQ9IiNmZmZmZmYiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnR5cGUiIGNvbnRlbnQ9IndlYnNpdGUiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnNpdGVfbmFtZSIgY29udGVudD0iRmVkZXJhdGlvbiIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6dGl0bGUiIGNvbnRlbnQ9IjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3kiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlIiBjb250ZW50PSJodHRwczovL3d3dy40dHUubmwvLnVjL2llMTdmODA1NzAxMDIwODMxMTMwMDc3MDFkNDAxMDNiZDg1ZWZiNzc0YjVkNDA3MDFjM2IwMDQ3NjAyODAvbmF0aW9uYWxlLXRlY2hub2xvZ2llc3RyYXRlZ2llLmpwZyIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6d2lkdGgiIGNvbnRlbnQ9IjEyMDAiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlOmhlaWdodCIgY29udGVudD0iNjMwIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZSIgY29udGVudD0iaHR0cHM6Ly93d3cuNHR1Lm5sLy51Yy9pNzYwNTgxYWIwMTAyMDgzMTEzMDA3NzAxZDQwMTAzYmQ4NWVmYjc3NGI1ZDQwNzAxYzMyYzAxMmMwMTgwL25hdGlvbmFsZS10ZWNobm9sb2dpZXN0cmF0ZWdpZS5qcGciIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlOndpZHRoIiBjb250ZW50PSIzMDAiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlOmhlaWdodCIgY29udGVudD0iMzAwIiAvPjxzY3JpcHQgbm9tb2R1bGU+IGlmKCEhd2luZG93Lk1TSW5wdXRNZXRob2RDb250ZXh0ICYmICEhZG9jdW1lbnQuZG9jdW1lbnRNb2RlKWRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGFzc0xpc3QuYWRkKCJ1bnN1cHBvcnRlZC1icm93c2VyIik7PC9zY3JpcHQ+PHNjcmlwdCB0eXBlPSJhcHBsaWNhdGlvbi9qc29uIiBpZD0id2gtY29uZmlnIj57ImRlc2lnbmNkbnJvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS8iLCJkZXNpZ25yb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvIiwiZHRhcHN0YWdlIjoicHJvZHVjdGlvbiIsImltZ3Jvb3QiOiIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvIiwiaXNsaXZlIjp0cnVlLCJsb2NhbGUiOiJlbi1VUyIsIm9iaiI6eyJuYXZwYXRoaXRlbSI6eyJsaW5rIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS80VFUtbWVldGluZyUyME5hdGlvbmFsJTIwVGVjaG5vbG9neSUyMFN0cmF0ZWd5LyIsInRpdGxlIjoiNFRVLW1lZXRpbmcgTmF0aW9uYWwgVGVjaG5vbG9neSBTdHJhdGVneSJ9fSwic2VydmVyIjo1MDUwMCwic2l0ZSI6e30sInNpdGVyb290IjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsInNvY2lhbGl0ZTpndG0iOnsiYSI6IkdUTS1XVFo1RlJRIiwiaCI6dHJ1ZSwibSI6ZmFsc2V9fTwvc2NyaXB0PjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iLy5hcC80dHUuc2l0ZS9hcC5jc3MiPjxzY3JpcHQgc3JjPSIvLmFwLzR0dS5zaXRlL2FwLm1qcyIgdHlwZT0ibW9kdWxlIiBhc3luYz48L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2xkK2pzb24iPnsiQGNvbnRleHQiOiJodHRwczovL3NjaGVtYS5vcmciLCJAdHlwZSI6IkJyZWFkY3J1bWJMaXN0IiwiaXRlbUxpc3RFbGVtZW50IjpbeyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iLCJuYW1lIjoiRmVkZXJhdGlvbiIsInBvc2l0aW9uIjoxfSx7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJuYW1lIjoiQWdlbmRhIiwicG9zaXRpb24iOjJ9LHsiQHR5cGUiOiJMaXN0SXRlbSIsIml0ZW0iOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzRUVS1tZWV0aW5nJTIwTmF0aW9uYWwlMjBUZWNobm9sb2d5JTIwU3RyYXRlZ3kvIiwibmFtZSI6IjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3kiLCJwb3NpdGlvbiI6M31dfTwvc2NyaXB0PjwvaGVhZD48Ym9keT48bm9zY3JpcHQ+PGlmcmFtZSBzcmM9Ii8vd3d3Lmdvb2dsZXRhZ21hbmFnZXIuY29tL25zLmh0bWw/aWQ9R1RNLVdUWjVGUlEiIGhlaWdodD0iMCIgd2lkdGg9IjAiIHN0eWxlPSJkaXNwbGF5Om5vbmU7dmlzaWJpbGl0eTpoaWRkZW4iPjwvaWZyYW1lPjwvbm9zY3JpcHQ+PGRpdiBjbGFzcz0ic3BjLW1vZGFsaXR5bGF5ZXIiPjwvZGl2PjxkaXYgaWQ9InNsaWRlbWVudS1jb250YWluZXIiPjxkaXYgaWQ9InNsaWRlbWVudSIgdGFiaW5kZXg9Ii0xIiAgICA+PGRpdiBjbGFzcz0ic2lkZWJhcl9faGVhZGVyIj4gPGEgY2xhc3M9InNpZGViYXJfX2hlYWRlcl9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9InNpZGViYXJfX2lkZW50aXR5X19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9InNpZGViYXJfX2lkZW50aXR5X19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48YnV0dG9uIGlkPSJzbGlkZW1lbnUtY2xvc2UiIGNsYXNzPSJzaWRlYmFyLWFjdGlvbi1jbG9zZSIgdHlwZT0iYnV0dG9uIiBhcmlhLWxhYmVsPSJDbG9zZSIgPjwvYnV0dG9uPjwvZGl2Pjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudSBzaWRlYmFyX19tZW51LS1sZXZlbDEiICA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIiA+SG9tZTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5SZXNlYXJjaDwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+QWJvdXQgb3VyIHJlc2VhcmNoPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvNHR1LWNlbnRyZXMvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+NFRVIENlbnRyZXM8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDMiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iID5BTUkgKE1hdGhlbWF0aWNzKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iID5CdWlsdCBFbnZpcm9ubWVudDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIiA+RGVzaWduIFVuaXRlZDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyIgPkVuZXJneTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIiA+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iID5IZWFsdGg8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iID5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIiA+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIiA+TklSSUNUIChJQ1QpPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyIgPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5IaWdoIFRlY2ggZm9yIGEgU3VzdGFpbmFibGUgRnV0dXJlPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iID5IVFNGIEkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIiA+SFRTRiBJSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtdmlkZW9zLyIgPkhUU0YgdmlkZW9zPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIiA+NFRVLlJlc2VhcmNoRGF0YTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvRUUtTkwvIiA+RWxlY3RyaWNhbCBFbmdpbmVlcmluZyBOZXRoZXJsYW5kczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkVkdWNhdGlvbjwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkFib3V0IG91ciBlZHVjYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iID5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIiA+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyIgPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uL2VkdWNhdGlvbnByb2dyYW1tZXMvIiA+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxidXR0b24gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIj48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5WYWxvcmlzYXRpb248L2J1dHRvbj48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QlMjBhY3Rpdml0aWVzLyIgPjRUVS5JTVBBQ1Q8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyIgPkFib3V0IDRUVS5JbXBhY3Q8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3RhcnR1cCUyMG1pc3Npb25zLyIgPlN0YXJ0dXAgbWlzc2lvbnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPk1lZGlhPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwzIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL2luc2lnaHRmdWwtaW5ub3ZhdG9ycy8iID5JbnNpZ2h0ZnVsIElubm92YXRvcnM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvU3Bpbi1vZmYlMjBzZXJpZS8iID5TcGluLU9mZiBTdG9yaWVzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdHVkZW50JTIwY2hhbGxlbmdlcy8iID5TdHVkZW50IGNoYWxsZW5nZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vVHVzc2VucGFnaW5hJTIwdm9vcmFmZ2FhbmQlMjBhYW4lMjBTdGFydHVwJTIwU3VwcG9ydC8iID5BYm91dCBTdGFydHVwIFN1cHBvcnQ8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj5OZXdzPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSAgc2lkZW1haW5tZW51X19pdGVtLS1leHBhbmQgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX3NlbGVjdGVkICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkFib3V0IDRUVTwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMiIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LzR0dS1pbi0xLW1pbnV0ZS8iID40VFUgaW4gb25seSAxIG1pbnV0ZTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2ZhY3RzLWZpZ3VyZXMvIiA+RmFjdHMgYW5kIGZpZ3VyZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9vcmdhbmlzYXRpb24vIiA+T3JnYW5pc2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvcHVibGljYXRpb25zLyIgPlB1YmxpY2F0aW9uczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2FsdW1uaS8iID5BbHVtbmk8L2E+PC9saT48L3VsPjwvbGk+PC91bD48bmF2IGNsYXNzPSJzaWRlYmFyX19sYW5ndWFnZXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC8iPk5MPC9hPiB8IDxzcGFuIGNsYXNzPSJzZWxlY3RlZCI+RU48L3NwYW4+PC9uYXY+PG5hdiBjbGFzcz0ic2lkZWJhcl9fc2Vjb25kYXJ5bGlua3MiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9jb250YWN0LyI+Q29udGFjdDwvYT48L25hdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wLWJhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyLWJhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3AiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX2NvbnRlbnQiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX2lkZW50aXR5Ij48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19zbG9nYW4iPlBhcnQgb2YgdGhlIDxidXR0b24gY2xhc3M9ImhlYWRlci10b3BfX3RvZ2dsZWV4cGxvcmVwYW5lbCI+NFRVLkZlZGVyYXRpb248L2J1dHRvbj48L2Rpdj48YSBjbGFzcz0iaGVhZGVyLXRvcF9faWRlbnRpdHkiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fb3JnYW5pemF0aW9ucyI+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZGVsZnQubmwvZW4vIiB0aXRsZT0iVFUgRGVsZnQiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZGVsZnQuc3ZnIiBhbHQ9IlRVIERlbGZ0IiB3aWR0aD0iMTAwIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuLyIgdGl0bGU9IlRVIEVpbmRob3ZlbiIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1laW5kaG92ZW4uc3ZnIiBhbHQ9IlRVIEVpbmRob3ZlbiIgd2lkdGg9IjEzMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnV0d2VudGUubmwvZW4vIiB0aXRsZT0iVW5pdmVyc2l0eSBvZiBUd2VudGUiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL3VuaXZlcnNpdHktb2YtdHdlbnRlLnN2ZyIgYWx0PSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgd2lkdGg9IjEwMCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3Lnd1ci5ubC8iIHRpdGxlPSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28td3VyLnN2ZyIgYWx0PSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiIHdpZHRoPSIxMzIiIC8+PC9hPjwvZGl2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyIj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fY29udGVudCI+PGEgY2xhc3M9ImhlYWRlci1tZW51YmFyX19pZGVudGl0eSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zcGFjZXIiPjwvZGl2PjxuYXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19tZW51YmFyIiBhcmlhLWxhYmVsPSJNYWluIj48dWwgY2xhc3M9InNwYy1tZW51YmFyIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIgPkhvbWU8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPlJlc2VhcmNoPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5BYm91dCBvdXIgcmVzZWFyY2g8L2E+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLzR0dS1jZW50cmVzLyIgPjRUVSBDZW50cmVzPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIiA+QU1JIChNYXRoZW1hdGljcyk8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIiA+QnVpbHQgRW52aXJvbm1lbnQ8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyIgPkRlc2lnbiBVbml0ZWQ8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iID5FbmVyZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyIgPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIiA+SGVhbHRoPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIiA+SGlnaC1UZWNoIE1hdGVyaWFsczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyIgPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyIgPk5JUklDVCAoSUNUKTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iID5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic3BjLW1lbnViYXItLWhhc3N1Yml0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS8iID5IaWdoIFRlY2ggZm9yIGEgU3VzdGFpbmFibGUgRnV0dXJlPC9hPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMyI+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iID5IVFNGIEkgUHJvZ3JhbW1lczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIiA+SFRTRiBJSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtdmlkZW9zLyIgPkhUU0YgdmlkZW9zPC9hPjwvbGk+PC91bD48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyIgPjRUVS5SZXNlYXJjaERhdGE8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9FRS1OTC8iID5FbGVjdHJpY2FsIEVuZ2luZWVyaW5nIE5ldGhlcmxhbmRzPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkVkdWNhdGlvbjwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyIgPkFib3V0IG91ciBlZHVjYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIiA+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iID40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyIgPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2VkdWNhdGlvbi9lZHVjYXRpb25wcm9ncmFtbWVzLyIgPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSIiID5WYWxvcmlzYXRpb248L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0JTIwYWN0aXZpdGllcy8iID40VFUuSU1QQUNUPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIiA+QWJvdXQgNFRVLkltcGFjdDwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vU3RhcnR1cCUyMG1pc3Npb25zLyIgPlN0YXJ0dXAgbWlzc2lvbnM8L2E+PC9saT48bGkgY2xhc3M9InNwYy1tZW51YmFyLS1oYXNzdWJpdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvIiA+TWVkaWE8L2E+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwzIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvaW5zaWdodGZ1bC1pbm5vdmF0b3JzLyIgPkluc2lnaHRmdWwgSW5ub3ZhdG9yczwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9TcGluLW9mZiUyMHNlcmllLyIgPlNwaW4tT2ZmIFN0b3JpZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdHVkZW50JTIwY2hhbGxlbmdlcy8iID5TdHVkZW50IGNoYWxsZW5nZXM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1R1c3NlbnBhZ2luYSUyMHZvb3JhZmdhYW5kJTIwYWFuJTIwU3RhcnR1cCUyMFN1cHBvcnQvIiA+QWJvdXQgU3RhcnR1cCBTdXBwb3J0PC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL2FnZW5kYS8iID5BZ2VuZGE8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VsZWN0ZWQiPkFnZW5kYTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LyIgPkFib3V0IDRUVTwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1LzR0dS1pbi0xLW1pbnV0ZS8iID40VFUgaW4gb25seSAxIG1pbnV0ZTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9mYWN0cy1maWd1cmVzLyIgPkZhY3RzIGFuZCBmaWd1cmVzPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L29yZ2FuaXNhdGlvbi8iID5PcmdhbmlzYXRpb248L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvcHVibGljYXRpb25zLyIgPlB1YmxpY2F0aW9uczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9uZXdzbGV0dGVyLyIgPk5ld3NsZXR0ZXI8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvYWx1bW5pLyIgPkFsdW1uaTwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48L3VsPjwvbmF2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zcGFjZXIiPjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19sYW5ndWFnZXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC8iPk5MPC9hPnw8c3Bhbj5FTjwvc3Bhbj48L2Rpdj48Zm9ybSBhY3Rpb249Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9zZWFyY2gvIiBtZXRob2Q9IkdFVCIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2h3cmFwcGVyIiBhdXRvY29tcGxldGU9Im9mZiIgPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2gtaW5wdXQtYW5kLXN1Z2dlc3Rpb25zLXdyYXBwZXIiPjxpbnB1dCBpZD0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiBuYW1lPSJxdWVyeSIgZGF0YS1zdWdnZXN0PSI0dHU6Y29ycG9yYXRlX2VuIiBkYXRhLXN1Z2dlc3RwYXJlbnQ9InBhcmVudCIgcGxhY2Vob2xkZXI9IlpvZWtlbiIgYXJpYS1sYWJlbD0iWm9la2VuIiB0eXBlPSJzZWFyY2giIC8+PC9kaXY+PGxhYmVsIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoIiBmb3I9ImhlYWRlci1tZW51YmFyX19zZWFyY2hpbnB1dCIgdGFiaW5kZXg9Ii0xIiA+PHNwYW4gY2xhc3M9ImZhciBmYS1zZWFyY2giPjwvc3Bhbj48L2xhYmVsPjwvZm9ybT48YnV0dG9uIGlkPSJoZWFkZXItbWVudWJhcl9zaWRlYmFydG9nZ2xlIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3Nob3dzaWRlbWFpbm1lbnUgc2lkZWJhci1hY3Rpb24tdG9nZ2xlIiBhcmlhLWxhYmVsPSJPcGVuIG1lbnUiIGFyaWEtZXhwYW5kZWQ9ImZhbHNlIiBhcmlhLWNvbnRyb2xzPSJzbGlkZW1lbnUiID48c3BhbiBjbGFzcz0iZmFyIGZhLWJhcnMiPjwvc3Bhbj48L2J1dHRvbj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWwiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fdG9wYmFyIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2Nsb3NlIj5DbG9zZTwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1ucyI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19hZGRyZXNzIHJ0ZGNvbnRlbnQiPjxwIGNsYXNzPSJoZWFkaW5nIj40VFUuRmVkZXJhdGlvbjwvcD48cCBjbGFzcz0ibm9ybWFsIj4rMzEoMCk2IDQ4IDI3IDU1IDYxPC9wPjxwIGNsYXNzPSJub3JtYWwiPjxhIGhyZWY9Im1haWx0bzpwcm9qZWN0bGVpZGVyQDR0dS5ubCI+c2VjcmV0YXJpc0A0dHUubmw8L2E+PC9wPjxwIGNsYXNzPSJub3JtYWwiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPjxiPldlYnNpdGU6IDRUVS5ubDwvYj48L2E+PC9wPjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uIGV4cGxvcmVwYW5lbF9fY29sdW1uLS1tYW55aXRlbXMiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuUmVzZWFyY2g8L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zIGV4cGxvcmVwYW5lbF9faXRlbXMtLW1hbnlpdGVtcyAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9hbWkvIj48c3Bhbj5BcHBsaWVkIE1hdGhlbWF0aWNzIEluc3RpdHV0ZTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2JvdXcvIj48c3Bhbj5CdWlsdCBFbnZpcm9ubWVudDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2R1LyI+PHNwYW4+RGVzaWduIFVuaXRlZDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuZXJneS8iPjxzcGFuPkVuZXJneTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9ldGhpY3NhbmR0ZWNobm9sb2d5LmV1LyI+PHNwYW4+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oZWFsdGgvIj48c3Bhbj5IZWFsdGg8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9odG0vIj48c3Bhbj5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGlzdG9yeS1vZi10ZWNobm9sb2d5LyI+PHNwYW4+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvbmlyaWN0LyI+PHNwYW4+TklSSUNUIChJQ1QpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvcmVzaWxpZW5jZS8iPjxzcGFuPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iPjxzcGFuPlJlc2VhcmNoRGF0YTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMS8iPjxzcGFuPkhUU0YgSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyem9lay9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iPjxzcGFuPkhUU0YgSUkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uICI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5FZHVjYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zICAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIj48c3Bhbj5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyI+PHNwYW4+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iPjxzcGFuPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyd2lqcy9vbmRlcndpanNwcm9ncmFtbWFzLyI+PHNwYW4+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY29sdW1uICI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5WYWxvcmlzYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2l0ZW1zICAiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iPjxzcGFuPjRUVS5JTVBBQ1Q8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vdGVjaC10cmFuc2Zlci5ubC9lbi8iPjxzcGFuPlRoZW1hdGljIFRlY2hub2xvZ3kgVHJhbnNmZXI8L3NwYW4+PC9hPjxhIGhyZWY9IiI+PHNwYW4+U3Bpbi1vZmYgU3Rvcmllczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly80dHVpbXBhY3RjaGFsbGVuZ2UubmwvIj48c3Bhbj40VFUgSW1wYWN0IENoYWxsZW5nZTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX2JhY2tncm91bmQiPjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19zbGlkZXNob3cgY2Fycm91c2VsX192aWV3cG9ydCBjYXJyb3VzZWxfX2RyYWdhcmVhICI+PHN0eWxlPkBtZWRpYSAobWF4LXdpZHRoOiA3NjdweCl7LmhlYWRlcnNsaWRlMHtiYWNrZ3JvdW5kLXBvc2l0aW9uOiA1NC4xNjY3JSA2NS41MTM0JTtiYWNrZ3JvdW5kLWNvbG9yOiAjRkFGQ0ZEO2JhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2k0NDY2ZDNlMjAxMDIwODMxMTMwMDc3MDFkNDAxMDNiZDg1ZWZiNzc0YjVkNDA4MDFlMzQwMGIwMDA3ODE0Ni9uYXRpb25hbGUtdGVjaG5vbG9naWVzdHJhdGVnaWUuanBnKTt9fUBtZWRpYSAobWluLXdpZHRoOiA3NjhweCl7LmhlYWRlcnNsaWRlMHtiYWNrZ3JvdW5kLXBvc2l0aW9uOiA1NC4xNjY3JSA2NS41MzU3JTtiYWNrZ3JvdW5kLWNvbG9yOiAjRkFGQ0ZEO2JhY2tncm91bmQtaW1hZ2U6IHVybCgvLnVjL2kwYjBjZjg2YjAxMDIwODMxMTMwMDc3MDFkNDAxMDNiZDg1ZWZiNzc0YjVkNDA4MDFlMzQwMGI2MDA0ODE0Ni9uYXRpb25hbGUtdGVjaG5vbG9naWVzdHJhdGVnaWUuanBnKTt9fTwvc3R5bGU+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlIGNhcnJvdXNlbF9fY2VsbCBhY3RpdmVzbGlkZSBoZWFkZXJzbGlkZTAgIiBkYXRhLXNsaWRlc2hvdy1lbGVtZW50cz0icGFnZS1oZWFkZXJfX3NsaWRlMF9fY29udGVudCIgc3R5bGU9IiIgPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19jb250ZW50Ij48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fbWV0YSI+PGgxIGNsYXNzPSJwYWdlLWhlYWRlcl9fdGl0bGUiPjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3k8L2gxPjxkaXYgY2xhc3M9InBhZ2VoZWFkZXJfX2RhdGUiPldlZG5lc2RheSAzIEp1bHkgMjAyNCAvIDEyLjMwIC0gMTguMDA8L2Rpdj48L2Rpdj48L2Rpdj48bWFpbiBjbGFzcz0icGFnZV9fYm9keSAgIj48Zm9ybSBpZD0iIiAgY2xhc3M9InBhZ2VfX2hlYWRlcmZpbHRlcnMgICAiPjwvZm9ybT48ZGl2IGNsYXNzPSJwYWdlX19jb250ZW50YXJlYSBwYWdlX19jb250ZW50YXJlYS0tcnRkZG9jICAgaGVhZGVyaXNvcGFxdWUgIj48ZGl2IGNsYXNzPSJkZWVwbGlua3Mtd3JhcHBlciI+PGRpdiBjbGFzcz0iZGVlcGxpbmtzIj48YSBjbGFzcz0icGFnZS1iYWNrbGluayIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFsbCBldmVudHM8L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1jb250ZW50c3RhcnQiPjwvZGl2PjwhLS13aF9jb25zaWxpb19jb250ZW50LS0+PHAgY2xhc3M9Im5vcm1hbCI+PGI+NFRVLW1lZXRpbmcgb24gdGhlIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3kgKE5UUykgLSBsb2NhdGlvbiBVdHJlY2h0PC9iPjwvcD48cCBjbGFzcz0ibm9ybWFsIj7CoDwvcD48cCBjbGFzcz0ibm9ybWFsIj48Yj5XaGF0IGFuZCBmb3Igd2hvbTo8L2I+PC9wPjxwIGNsYXNzPSJub3JtYWwiPlRoZSBtZWV0aW5nIGlzIGludGVuZGVkIGZvciA8Yj5zY2llbnRpc3RzPC9iPiB3b3JraW5nIG9uIGkpIE9wdGljYWwgc3lzdGVtcyBhbmQgaW50ZWdyYXRlZCBwaG90b25pY3MsIGlpKSBJbWFnaW5nIHRlY2hub2xvZ2llcywgb3IgaWlpKSAoRW5lcmd5KSBtYXRlcmlhbHMgYW5kIGZvciA8Yj5tYW5hZ2VycyBhbmQgc3VwcG9ydCBvZmZpY2VyczwvYj4gb2YgcmVzZWFyY2ggb24ga2V5IHRlY2hub2xvZ2llcy48L3A+PHAgY2xhc3M9Im5vcm1hbCI+QWZ0ZXIgYSBzaG9ydCBwbGVuYXJ5IGluZm9ybWF0aW9uIHNlc3Npb24sIHdlIHNwbGl0IHVwIGFsb25nIHRoZXNlIHRocmVlIHRoZW1lcyBhbmQgd291bGQgbGlrZSB0byBnZXQgeW91ciBpbnB1dCBvbiBob3cgdG8gZ2V0IHRvIGNvbmNyZXRlIGFjdGlvbiBhZ2VuZGHigJlzIGZvciB0aGVzZSB0b3BpY3MuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWUgdGhlIGF0dGFjaGVkIGludml0YXRpb24uPC9wPjxwIGNsYXNzPSJub3JtYWwiPsKgPC9wPjxwIGNsYXNzPSJub3JtYWwiPjxiPlByYWN0aWNhbCBpbmZvcm1hdGlvbjo8L2I+PC9wPjxwIGNsYXNzPSJub3JtYWwiPkRhdGU6wqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoMKgwqDCoCBXZWRuZXNkYXksIEp1bHkgMyAyMDI0LCAxMy4zMC0xNyBocnMgKGx1bmNoIGF0IDEyLjMwOyBkcmlua3MgYXQgMTcgaHJzKTwvcD48cCBjbGFzcz0ibm9ybWFsIj5Mb2NhdGlvbjogwqDCoMKgwqDCoMKgwqDCoCBCYXNlY2FtcCwgTmlqdmVyaGVpZHN3ZWcgMTZBLCAzNTM0IEFNIFV0cmVjaHQgKDxhIGhyZWY9Imh0dHBzOi8vYmFzZWNhbXB1dHJlY2h0Lm5sLyI+aHR0cHM6Ly9iYXNlY2FtcHV0cmVjaHQubmw8L2E+KTwvcD48cCBjbGFzcz0ibm9ybWFsIj7CoDwvcD48cCBjbGFzcz0ibm9ybWFsIj48Yj5SZWdpc3RyYXRpb246PC9iPjwvcD48cCBjbGFzcz0ibm9ybWFsIj5JZiB5b3Ugd2FudCB0byBqb2luIHRoaXMgbWVldGluZywgcGxlYXNlIHJlZ2lzdGVyIGJ5IGZpbGxpbmcgaW4gdGhpcyA8YSBocmVmPSJodHRwczovL2Zvcm1zLmdsZS9xTkxoYmJUNmh6dGN5VkNIQSI+PGI+R29vZ2xlIEZvcm08L2I+PC9hPjxiPiA8L2I+PGk+YmVmb3JlIFR1ZXNkYXkgSnVuZSAyNSE8L2k+PC9wPjxwIGNsYXNzPSJub3JtYWwiPsKgPC9wPjxwIGNsYXNzPSJub3JtYWwiPldlIGhhdmUgbWFkZSBhIG5pY2UgPGI+Y29ubmVjdGlvbjwvYj4gd2l0aCB0aGUgPGI+SG9sbGFuZCBIaWdoIFRlY2ggTmV0d29yayBFdmVudDwvYj4gYW5kIHdpbGwgPGI+am9pbiB0aGVtIGF0IDE3IGhycyBmb3IgZHJpbmtzLCBmb29kIChmb29kIHRydWNrcyEpIGFuZCBuZXR3b3JraW5nLjwvYj48L3A+PHAgY2xhc3M9Im5vcm1hbCI+SWYgeW91IHdhbnQgdG8gam9pbiB0aGUgZHJpbmtzICZhbXA7IGZvb2QgYXQgMTcgaHJzLCBwbGVhc2UgcmVnaXN0ZXIgPGI+YWxzbyA8L2I+PGEgaHJlZj0iaHR0cHM6Ly93d3cuYWFubWVsZGVyLm5sL2hodG5ldHdlcmtldmVudDIwMjQvYWFubWVsZGVuIj48Yj5oZXJlPC9iPjwvYT48Yj4uPC9iPjwvcD48cCBjbGFzcz0ibm9ybWFsIj48Yj7CoDwvYj48L3A+PHAgY2xhc3M9Im5vcm1hbCI+QmVzdCByZWdhcmRzLCBhbHNvIG9uIGJlaGFsZiBvZiBFWkssIEhIVCwgTldPLDwvcD48IS0tL3doX2NvbnNpbGlvX2NvbnRlbnQtLT48ZGl2IGNsYXNzPSJwYWdlX19iYWxsb29uIj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXIiPjxkaXYgY2xhc3M9InBhZ2VfX2Zvb3Rlcl9fY29udGVudCBuYXZwYXRoIj48YSBjbGFzcz0ibmF2cGF0aF9faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT48c3BhbiBjbGFzcz0ibmF2cGF0aF9fc2VwZXJhdG9yIj48L3NwYW4+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19pdGVtIGNydW1icGF0aC0tY3VycmVudHBhZ2UiPjRUVS1tZWV0aW5nIE5hdGlvbmFsIFRlY2hub2xvZ3kgU3RyYXRlZ3k8L3NwYW4+PC9kaXY+PC9kaXY+PC9kaXY+PC9tYWluPjxkaXYgY2xhc3M9ImZvb3RlciI+PGRpdiBjbGFzcz0iZm9vdGVyX19wYW5lbCI+PGRpdiBjbGFzcz0iZm9vdGVyX19pZGVudGl0eSI+PGRpdiBjbGFzcz0iZm9vdGVyX19vcmdhbml6YXRpb250aXRsZSI+NFRVLjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fc2l0ZXRpdGxlIj5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PCEtLSBGSVhNRTogdXNlIGFyaWEtaGlkZGVuPSJ0cnVlIiBiZWNhdXNlIGl0J3MgYSBkdXBsaWNhdGUgb2YgdGhlIGl0ZW1zIG9uIHRoZSBtZW51IGJhciA/IC0tPiA8bmF2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjEgZm9vdGVyX19tYWlubWVudSIgYXJpYS1sYWJlbD0iTWFpbiI+IDx1bD4gICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPkhvbWU8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iPlJlc2VhcmNoPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uLyI+RWR1Y2F0aW9uPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSIiPlZhbG9yaXNhdGlvbjwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iPk5ld3M8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvIj5BZ2VuZGE8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvIj5BYm91dCA0VFU8L2E+IDwvbGk+ICAgPC91bD4gPC9uYXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjIiPiA8aW5wdXQgdHlwZT0iY2hlY2tib3giIG5hbWU9ImZvb3RlcmNvbHVtbiIgaWQ9ImZvb3Rlcl9fY29sdW1uMl9fZXhwYW5kIiAvPiA8bGFiZWwgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19oZWFkaW5nIiBmb3I9ImZvb3Rlcl9fY29sdW1uMl9fZXhwYW5kIj5Db250YWN0PC9sYWJlbD4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgcnRkY29udGVudCI+IDxwIGNsYXNzPSJub3JtYWwiPiszMSgwKTYgODMgMjIgNTAgNTk8YnIgLz48YSBocmVmPSJtYWlsdG86cHJvamVjdGxlaWRlckA0dHUubmwiPnNlY3JldGFyaXNANHR1Lm5sPC9hPjwvcD4gPC9kaXY+IDwvZGl2PiAgIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMyI+IDxpbnB1dCB0eXBlPSJjaGVja2JveCIgbmFtZT0iZm9vdGVyY29sdW1uIiBpZD0iZm9vdGVyX19jb2x1bW4zX19leHBhbmQiIC8+IDxsYWJlbCBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciIGZvcj0iZm9vdGVyX19jb2x1bW4zX19leHBhbmQiPlBvc3RhZHJlczwvbGFiZWw+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IHJ0ZGNvbnRlbnQiPiA8cCBjbGFzcz0ibm9ybWFsIj40VFUuRmVkZXJhdGllPGJyIC8+UG9zdGJ1cyA1PGJyIC8+MjYwMCBBQSBEZWxmdDwvcD4gPC9kaXY+IDwvZGl2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW40Ij4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbXNfX2dyb3VwIj4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciPkZvbGxvdyB1czwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uX19jb250ZW50IGZvb3Rlcl9fc29jaWFsaXRlbXMgIj48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3R3aXR0ZXIuY29tLzRUVUZlZGVyYXRpb24iIHRpdGxlPSJUd2l0dGVyIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS10d2l0dGVyIj48L3NwYW4+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9jb21wYW55LzQtdHUtZmVkZXJhdGlvbi8iIHRpdGxlPSJMaW5rZWRJbiIgPjxzcGFuIGNsYXNzPSJmYWIgZmEtbGlua2VkaW4taW4iPjwvc3Bhbj48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vY2hhbm5lbC9VQ01rcWhqeDJXMWhOUnd5c1J2V0VYd1EiIHRpdGxlPSJZb3V0dWJlIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS15b3V0dWJlIj48L3NwYW4+PC9hPjwvZGl2PiA8L2Rpdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcl9fZ3JvdXAiPiAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmcgZm9vdGVyX19jb2x1bW5fX2hlYWRpbmctLW5ld3NsZXR0ZXIgIj5TdGF5IHVwLXRvLWRhdGU8L2Rpdj48Zm9ybSBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwIHdocGx1Z2luLW5ld3NsZXR0ZXItc3Vic2NyaXB0aW9uICAiIGRhdGEtbmV3c2xldHRlci1saXN0PSJTVUJTXzRUVV9DT1JQT1JBVEVfTklFVVdTQlJJRUYiID48aW5wdXQgbmFtZT0iZW1haWwiIHBsYWNlaG9sZGVyPSJTaWduIHVwIGZvciBvdXIgbmV3c2xldHRlciIgLz48YnV0dG9uIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Ym1pdCIgdHlwZT0ic3VibWl0IiBuYW1lPSJzdWJtaXRidXR0b24iIGFyaWEtbGFiZWw9IlN1YnNjcmliZSI+PHNwYW4gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VibWl0X19pY29uIGZhciBmYS1lbnZlbG9wZSI+PC9zcGFuPjwvYnV0dG9uPjwvZm9ybT48ZGl2IGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXBfX3N1Y2Nlc3MiPlRoYW5rcyBmb3Igc3Vic2NyaWJpbmcgdG8gb3VyIG5ld3NsZXR0ZXIuPC9kaXY+ICA8L2Rpdj4gPC9kaXY+IDxociBjbGFzcz0iZm9vdGVyX19kaXZpZGVyIiAvPiA8ZGV0YWlscyBjbGFzcz0iZm9vdGVyX19leHBsb3JlIj48c3VtbWFyeT48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX3RvZ2dsZV9fY2xvc2VkdGV4dCI+UGFydCBvZiB0aGUgPHNwYW4gY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fbmFtZSI+NFRVLkZlZGVyYXRpb248L3NwYW4+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX190b2dnbGVfX29wZW50ZXh0Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2xvc2UiPkNsb3NlPC9kaXY+PC9kaXY+PC9zdW1tYXJ5PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsIj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5SZXNlYXJjaDwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iPjxzcGFuPkFwcGxpZWQgTWF0aGVtYXRpY3MgSW5zdGl0dXRlPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iPjxzcGFuPkJ1aWx0IEVudmlyb25tZW50PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIj48c3Bhbj5EZXNpZ24gVW5pdGVkPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyI+PHNwYW4+RW5lcmd5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIj48c3Bhbj5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iPjxzcGFuPkhlYWx0aDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iPjxzcGFuPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIj48c3Bhbj5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIj48c3Bhbj5OSVJJQ1QgKElDVCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyI+PHNwYW4+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyI+PHNwYW4+UmVzZWFyY2hEYXRhPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyI+PHNwYW4+SFRTRiBJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyI+PHNwYW4+SFRTRiBJSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2NhdGVnb3J5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faGVhZGVyIj40VFUuRWR1Y2F0aW9uPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyI+PHNwYW4+Q2VudHJlIGZvciBFbmdpbmVlcmluZyBFZHVjYXRpb248L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iPjxzcGFuPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIj48c3Bhbj5TQUkgKEVuZ2luZWVyaW5nIERvY3RvcmF0ZSk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcndpanMvb25kZXJ3aWpzcHJvZ3JhbW1hcy8iPjxzcGFuPkVkdWNhdGlvbiBwcm9ncmFtbWVzPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5WYWxvcmlzYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iPjxzcGFuPjRUVS5JTVBBQ1Q8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vdGVjaC10cmFuc2Zlci5ubC9lbi8iPjxzcGFuPlRoZW1hdGljIFRlY2hub2xvZ3kgVHJhbnNmZXI8L3NwYW4+PC9hPjxhIGhyZWY9IiI+PHNwYW4+U3Bpbi1vZmYgU3Rvcmllczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly80dHVpbXBhY3RjaGFsbGVuZ2UubmwvIj48c3Bhbj40VFUgSW1wYWN0IENoYWxsZW5nZTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PC9kZXRhaWxzPiA8ZGl2IGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzIj4gPGRpdiBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbXMiPiA8YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVkZWxmdC5ubC9lbi8iIHRpdGxlPSJUVSBEZWxmdCIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1kZWxmdC5zdmciIGFsdD0iVFUgRGVsZnQiIHdpZHRoPSI4NyIgaGVpZ2h0PSIzNCIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnR1ZS5ubC9lbi8iIHRpdGxlPSJUVSBFaW5kaG92ZW4iID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28tdHUtZWluZGhvdmVuLnN2ZyIgYWx0PSJUVSBFaW5kaG92ZW4iIHdpZHRoPSIxMzAiIGhlaWdodD0iMjciIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy51dHdlbnRlLm5sL2VuLyIgdGl0bGU9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci91bml2ZXJzaXR5LW9mLXR3ZW50ZS5zdmciIGFsdD0iVW5pdmVyc2l0eSBvZiBUd2VudGUiIHdpZHRoPSI4NSIgaGVpZ2h0PSIzMSIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3Lnd1ci5ubC8iIHRpdGxlPSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL2xvZ28td3VyLnN2ZyIgYWx0PSJXYWdlbmluZ2VuIFVuaXZlcnNpdHkiIHdpZHRoPSIxNDUiIGhlaWdodD0iMjkiIC8+PC9hPiA8L2Rpdj4gPC9kaXY+IDwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyIj48c3BhbiBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXJfX2NvcHlyaWdodCI+PHNwYW4gY2xhc3M9ImZiY3BhcnQiPiZjb3B5OyAyMDI0IDRUVS5GZWRlcmF0aW9uPC9zcGFuPjwvc3Bhbj48dWwgY2xhc3M9ImZvb3Rlcl9fYm90dG9tYmFyX19tZW51Ij48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2NvbnRhY3QvIj5Db250YWN0PC9hPjwvbGk+PC91bD48L2Rpdj48L2Rpdj48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL3gtaHNvbiIgaWQ9IndoLWNvbnNpbGlvZmllbGRzIj5oc29uOnsid2hzZWFyY2h0aHVtYm5haWwiOiJodHRwczovL3d3dy40dHUubmwvLnVjL2k2ZDYyMmJkZjAxMDIwYTMxMTMwMDc3MDFkNDAxYzFlMjEyZWVmOGY0YTdjNzA4MDFlMzQwMDFmMDAwODE0MS9lemstbnRzLnBuZy5qcGcifTwvc2NyaXB0PjwvYm9keT48L2h0bWw+
+ recorded_at: Wed, 02 Jan 2019 16:00:00 GMT
+- request:
+ method: get
+ uri: https://www.4tu.nl/en/agenda/2024-10-09-room-for-everyones-educational-talent/
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Server:
+ - nginx
+ Date:
+ - Thu, 06 Jun 2024 07:51:57 GMT
+ Content-Type:
+ - text/html; charset=UTF-8
+ Transfer-Encoding:
+ - chunked
+ Connection:
+ - keep-alive
+ Vary:
+ - Accept-Encoding
+ Strict-Transport-Security:
+ - max-age=31536000
+ X-Frame-Options:
+ - DENY
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ Referrer-Policy:
+ - strict-origin-when-cross-origin
+ Feature-Policy:
+ - geolocation 'none'; camera 'none'; payment 'none'; microphone 'none';
+ Content-Security-Policy:
+ - script-src 'self' https://platform.twitter.com https://cdn.syndication.twimg.com
+ https://www.youtube.com https://player.vimeo.com 'sha256-B34d9UvaEWVUEqLK1XO7bmIC0GTuglVf9avDg11NcSc='
+ 'sha256-P8GHTBinuD+aYtH+iNVPhJcdl3xVDaG/Y3fcqecF83w=' https://www.google-analytics.com
+ https://www.googletagmanager.com https://embed.podcasts.apple.com 'sha256-zN1rNu6bv+5uQuqzW39H8OOBooeKevi2fT089esapTo=';
+ frame-ancestors 'self' https://4tu.webhare.net
+ Cache-Control:
+ - no-cache
+ body:
+ encoding: ASCII-8BIT
+ string: !binary |-
+ PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iIGNsYXNzPSJwYWdlaGVhZGVyLS0yMDIxIHNpdGVoZWFkZXIyMDIxIHBhZ2V3aWR0aC0td2lkdGgtZnVsbHdpZHRoIGlkZW50aXR5LS00dHUgcGFnZS0tZXZlbnQgc2l0ZWhlYWRlci0tbWVudWJhci10cmFuc2x1Y2VudCBwYWdlLS1mb3Jtd2VidG9vbCBwYWdlLS13aXRoYmFja2xpbmsiIGRhdGEtdHJhY2tpbmdpZD0iIj48aGVhZD48bWV0YSBjaGFyc2V0PSJ1dGYtOCI+PHRpdGxlPlJvb20gZm9yIGV2ZXJ5b25lJiMzOTtzIGVkdWNhdGlvbmFsIHRhbGVudCAtIEV2ZW50PC90aXRsZT48bWV0YSBuYW1lPSJkZXNjcmlwdGlvbiIgY29udGVudD0iTG9jYXRpb246IFNvY2lhbCBJbXBhY3QgRmFjdG9yeSBWcmVkZW5idXJnIFV0cmVjaHQiPjxsaW5rIHJlbD0iY2Fub25pY2FsIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtMTAtMDktcm9vbS1mb3ItZXZlcnlvbmVzLWVkdWNhdGlvbmFsLXRhbGVudC8iPgo8IS0tClJlYWxpc2F0aWU6IPCfkrwgV2ViSGFyZSBidgogICAgICAgICAgICDwn4yQIGh0dHBzOi8vd3d3LndlYmhhcmUubmwvCi0tPgo8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEiIC8+PG1ldGEgbmFtZT0iZGVzY3JpcHRpb24iIGNvbnRlbnQ9IkxvY2F0aW9uOiBTb2NpYWwgSW1wYWN0IEZhY3RvcnkgVnJlZGVuYnVyZyBVdHJlY2h0IiAvPjxsaW5rIHJlbD0iYXBwbGUtdG91Y2gtaWNvbiIgc2l6ZXM9IjE4MHgxODAiIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9hcHBsZS10b3VjaC1pY29uLTE4MHgxODAucG5nIiAvPjxsaW5rIHJlbD0iaWNvbiIgdHlwZT0iaW1hZ2UvcG5nIiBocmVmPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvc2l0ZWljb24vZmF2aWNvbi0zMngzMi5wbmciIHNpemVzPSIzMngzMiIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2Zhdmljb24tOTZ4OTYucG5nIiBzaXplcz0iOTZ4OTYiIC8+PGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS9wbmciIGhyZWY9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9zaXRlaWNvbi9mYXZpY29uLTE5NHgxOTQucG5nIiBzaXplcz0iMTk0eDE5NCIgLz48bGluayByZWw9Imljb24iIHR5cGU9ImltYWdlL3BuZyIgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL2FuZHJvaWQtY2hyb21lLTE5MngxOTIucG5nIiBzaXplcz0iMTkyeDE5MiIgLz48bGluayByZWw9Im1hc2staWNvbiIgICAgICAgICAgICAgaHJlZj0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL3NpdGVpY29uL3NhZmFyaS1waW5uZWQtdGFiLnN2ZyIgY29sb3I9IiNmZjhiMzgiIC8+PG1ldGEgbmFtZT0idGhlbWUtY29sb3IiIGNvbnRlbnQ9IiNmZmZmZmYiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnR5cGUiIGNvbnRlbnQ9IndlYnNpdGUiIC8+PG1ldGEgcHJvcGVydHk9Im9nOnNpdGVfbmFtZSIgY29udGVudD0iRmVkZXJhdGlvbiIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6dGl0bGUiIGNvbnRlbnQ9IlJvb20gZm9yIGV2ZXJ5b25lJiMzOTtzIGVkdWNhdGlvbmFsIHRhbGVudCAtIEV2ZW50IiAvPjxtZXRhIHByb3BlcnR5PSJvZzpkZXNjcmlwdGlvbiIgY29udGVudD0iTG9jYXRpb246IFNvY2lhbCBJbXBhY3QgRmFjdG9yeSBWcmVkZW5idXJnIFV0cmVjaHQiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlIiBjb250ZW50PSJodHRwczovL3d3dy40dHUubmwvLnVjL2kxYWUzODVmODAxMDI2OGY4MTAwMGI3ZmZiYjAxMzJiMDQ4Y2VmNGNhNWU4ZDA3MDFjM2IwMDQ3NjAyODAvdGVhY2hpbmctbGVhcm5pbmcuanBnIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTp3aWR0aCIgY29udGVudD0iMTIwMCIgLz48bWV0YSBwcm9wZXJ0eT0ib2c6aW1hZ2U6aGVpZ2h0IiBjb250ZW50PSI2MzAiIC8+PG1ldGEgcHJvcGVydHk9Im9nOmltYWdlIiBjb250ZW50PSJodHRwczovL3d3dy40dHUubmwvLnVjL2ljOGJhZTFkOTAxMDI2OGY4MTAwMGI3ZmZiYjAxMzJiMDQ4Y2VmNGNhNWU4ZDA3MDFjMzJjMDEyYzAxODAvdGVhY2hpbmctbGVhcm5pbmcuanBnIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTp3aWR0aCIgY29udGVudD0iMzAwIiAvPjxtZXRhIHByb3BlcnR5PSJvZzppbWFnZTpoZWlnaHQiIGNvbnRlbnQ9IjMwMCIgLz48c2NyaXB0IG5vbW9kdWxlPiBpZighIXdpbmRvdy5NU0lucHV0TWV0aG9kQ29udGV4dCAmJiAhIWRvY3VtZW50LmRvY3VtZW50TW9kZSlkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xhc3NMaXN0LmFkZCgidW5zdXBwb3J0ZWQtYnJvd3NlciIpOzwvc2NyaXB0PjxzY3JpcHQgdHlwZT0iYXBwbGljYXRpb24vanNvbiIgaWQ9IndoLWNvbmZpZyI+eyJkZXNpZ25jZG5yb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvIiwiZGVzaWducm9vdCI6Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlLyIsImR0YXBzdGFnZSI6InByb2R1Y3Rpb24iLCJpbWdyb290IjoiLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nLyIsImlzbGl2ZSI6dHJ1ZSwibG9jYWxlIjoiZW4tVVMiLCJvYmoiOnsibmF2cGF0aGl0ZW0iOnsibGluayI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hZ2VuZGEvMjAyNC0xMC0wOS1yb29tLWZvci1ldmVyeW9uZXMtZWR1Y2F0aW9uYWwtdGFsZW50LyIsInRpdGxlIjoiUm9vbSBmb3IgZXZlcnlvbmUncyBlZHVjYXRpb25hbCB0YWxlbnQgLSBFdmVudCJ9fSwic2VydmVyIjo1MDUwMCwic2l0ZSI6e30sInNpdGVyb290IjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyIsInNvY2lhbGl0ZTpndG0iOnsiYSI6IkdUTS1XVFo1RlJRIiwiaCI6dHJ1ZSwibSI6ZmFsc2V9fTwvc2NyaXB0PjxsaW5rIHJlbD0ic3R5bGVzaGVldCIgaHJlZj0iLy5hcC80dHUuc2l0ZS9hcC5jc3MiPjxzY3JpcHQgc3JjPSIvLmFwLzR0dS5zaXRlL2FwLm1qcyIgdHlwZT0ibW9kdWxlIiBhc3luYz48L3NjcmlwdD48c2NyaXB0IHR5cGU9ImFwcGxpY2F0aW9uL2xkK2pzb24iPnsiQGNvbnRleHQiOiJodHRwczovL3NjaGVtYS5vcmciLCJAdHlwZSI6IkJyZWFkY3J1bWJMaXN0IiwiaXRlbUxpc3RFbGVtZW50IjpbeyJAdHlwZSI6Ikxpc3RJdGVtIiwiaXRlbSI6Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iLCJuYW1lIjoiRmVkZXJhdGlvbiIsInBvc2l0aW9uIjoxfSx7IkB0eXBlIjoiTGlzdEl0ZW0iLCJpdGVtIjoiaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iLCJuYW1lIjoiQWdlbmRhIiwicG9zaXRpb24iOjJ9LHsiQHR5cGUiOiJMaXN0SXRlbSIsIml0ZW0iOiJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLzIwMjQtMTAtMDktcm9vbS1mb3ItZXZlcnlvbmVzLWVkdWNhdGlvbmFsLXRhbGVudC8iLCJuYW1lIjoiUm9vbSBmb3IgZXZlcnlvbmUncyBlZHVjYXRpb25hbCB0YWxlbnQgLSBFdmVudCIsInBvc2l0aW9uIjozfV19PC9zY3JpcHQ+PC9oZWFkPjxib2R5Pjxub3NjcmlwdD48aWZyYW1lIHNyYz0iLy93d3cuZ29vZ2xldGFnbWFuYWdlci5jb20vbnMuaHRtbD9pZD1HVE0tV1RaNUZSUSIgaGVpZ2h0PSIwIiB3aWR0aD0iMCIgc3R5bGU9ImRpc3BsYXk6bm9uZTt2aXNpYmlsaXR5OmhpZGRlbiI+PC9pZnJhbWU+PC9ub3NjcmlwdD48ZGl2IGNsYXNzPSJzcGMtbW9kYWxpdHlsYXllciI+PC9kaXY+PGRpdiBpZD0ic2xpZGVtZW51LWNvbnRhaW5lciI+PGRpdiBpZD0ic2xpZGVtZW51IiB0YWJpbmRleD0iLTEiICAgID48ZGl2IGNsYXNzPSJzaWRlYmFyX19oZWFkZXIiPiA8YSBjbGFzcz0ic2lkZWJhcl9faGVhZGVyX19pZGVudGl0eSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGRpdiBjbGFzcz0ic2lkZWJhcl9faWRlbnRpdHlfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0ic2lkZWJhcl9faWRlbnRpdHlfX3NpdGV0aXRsZSI+PGRpdiBzdHlsZT0iZGlzcGxheTppbmxpbmUtYmxvY2s7Ij5GZWRlcmF0aW9uPC9kaXY+PC9kaXY+PC9hPjxidXR0b24gaWQ9InNsaWRlbWVudS1jbG9zZSIgY2xhc3M9InNpZGViYXItYWN0aW9uLWNsb3NlIiB0eXBlPSJidXR0b24iIGFyaWEtbGFiZWw9IkNsb3NlIiA+PC9idXR0b24+PC9kaXY+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51IHNpZGViYXJfX21lbnUtLWxldmVsMSIgID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iID5Ib21lPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMV9faXRlbSBzaWRlbWFpbm1lbnVfX2l0ZW0tLWhhc3N1Yml0ZW1zICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPlJlc2VhcmNoPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC8iID5BYm91dCBvdXIgcmVzZWFyY2g8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC80dHUtY2VudHJlcy8iID48c3BhbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX190b2dnbGUiPjwvc3Bhbj40VFUgQ2VudHJlczwvYT48dWwgY2xhc3M9InNpZGViYXJfX21lbnUtLWxldmVsMyIgPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyIgPkFNSSAoTWF0aGVtYXRpY3MpPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyIgPkJ1aWx0IEVudmlyb25tZW50PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iID5EZXNpZ24gVW5pdGVkPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIiA+RW5lcmd5PC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iID5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyIgPkhlYWx0aDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyIgPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iID5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iID5OSVJJQ1QgKElDVCk8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIiA+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPkhpZ2ggVGVjaCBmb3IgYSBTdXN0YWluYWJsZSBGdXR1cmU8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDMiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyIgPkhUU0YgSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsM19faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iID5IVFNGIElJIFByb2dyYW1tZXM8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi12aWRlb3MvIiA+SFRTRiB2aWRlb3M8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vZGF0YS40dHUubmwvaW5mby9lbi8iID40VFUuUmVzZWFyY2hEYXRhPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9FRS1OTC8iID5FbGVjdHJpY2FsIEVuZ2luZWVyaW5nIE5ldGhlcmxhbmRzPC9hPjwvbGk+PC91bD48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+RWR1Y2F0aW9uPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIiA+QWJvdXQgb3VyIGVkdWNhdGlvbjwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvY2VlLyIgPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC92by8iID40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIiA+U0FJIChFbmdpbmVlcmluZyBEb2N0b3JhdGUpPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vZWR1Y2F0aW9ucHJvZ3JhbW1lcy8iID5FZHVjYXRpb24gcHJvZ3JhbW1lczwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGJ1dHRvbiBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPlZhbG9yaXNhdGlvbjwvYnV0dG9uPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdCUyMGFjdGl2aXRpZXMvIiA+NFRVLklNUEFDVDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QvIiA+QWJvdXQgNFRVLkltcGFjdDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdGFydHVwJTIwbWlzc2lvbnMvIiA+U3RhcnR1cCBtaXNzaW9uczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+TWVkaWE8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDMiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwzX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vTWVkaWEvaW5zaWdodGZ1bC1pbm5vdmF0b3JzLyIgPkluc2lnaHRmdWwgSW5ub3ZhdG9yczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDNfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsM19faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9TcGluLW9mZiUyMHNlcmllLyIgPlNwaW4tT2ZmIFN0b3JpZXM8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0dWRlbnQlMjBjaGFsbGVuZ2VzLyIgPlN0dWRlbnQgY2hhbGxlbmdlczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9UdXNzZW5wYWdpbmElMjB2b29yYWZnYWFuZCUyMGFhbiUyMFN0YXJ0dXAlMjBTdXBwb3J0LyIgPkFib3V0IFN0YXJ0dXAgU3VwcG9ydDwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9uZXdzLyIgPk5ld3M8L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vYWdlbmRhLyIgPkFnZW5kYTwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtIHNpZGVtYWlubWVudV9faXRlbS0taGFzc3ViaXRlbXMgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtbGluayAgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyIgPjxzcGFuIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX3RvZ2dsZSI+PC9zcGFuPk5ld3M8L2E+PHVsIGNsYXNzPSJzaWRlYmFyX19tZW51LS1sZXZlbDIiID48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID5OZXdzPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjwvdWw+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwxX19pdGVtICBzaWRlbWFpbm1lbnVfX2l0ZW0tLWV4cGFuZCAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMV9faXRlbWxpbmsgc2lkZW1haW5tZW51LWxldmVsMV9fc2VsZWN0ZWQgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyIgPkFnZW5kYTwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW0gc2lkZW1haW5tZW51X19pdGVtLS1oYXNzdWJpdGVtcyAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDFfX2l0ZW1saW5rICAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvIiA+PHNwYW4gY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fdG9nZ2xlIj48L3NwYW4+QWJvdXQgNFRVPC9hPjx1bCBjbGFzcz0ic2lkZWJhcl9fbWVudS0tbGV2ZWwyIiA+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvNHR1LWluLTEtbWludXRlLyIgPjRUVSBpbiBvbmx5IDEgbWludXRlPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvZmFjdHMtZmlndXJlcy8iID5GYWN0cyBhbmQgZmlndXJlczwvYT48L2xpPjxsaSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW0gICAiPjxhIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW1fX2xpbmsgc2lkZW1haW5tZW51LWxldmVsMl9faXRlbWxpbmsgIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L29yZ2FuaXNhdGlvbi8iID5PcmdhbmlzYXRpb248L2E+PC9saT48bGkgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbSBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtICAgIj48YSBjbGFzcz0ic2lkZW1haW5tZW51X19pdGVtX19saW5rIHNpZGVtYWlubWVudS1sZXZlbDJfX2l0ZW1saW5rICIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9wdWJsaWNhdGlvbnMvIiA+UHVibGljYXRpb25zPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PGxpIGNsYXNzPSJzaWRlbWFpbm1lbnVfX2l0ZW0gc2lkZW1haW5tZW51LWxldmVsMl9faXRlbSAgICI+PGEgY2xhc3M9InNpZGVtYWlubWVudV9faXRlbV9fbGluayBzaWRlbWFpbm1lbnUtbGV2ZWwyX19pdGVtbGluayAiIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvYWx1bW5pLyIgPkFsdW1uaTwvYT48L2xpPjwvdWw+PC9saT48L3VsPjxuYXYgY2xhc3M9InNpZGViYXJfX2xhbmd1YWdlcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sLyI+Tkw8L2E+IHwgPHNwYW4gY2xhc3M9InNlbGVjdGVkIj5FTjwvc3Bhbj48L25hdj48bmF2IGNsYXNzPSJzaWRlYmFyX19zZWNvbmRhcnlsaW5rcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2NvbnRhY3QvIj5Db250YWN0PC9hPjwvbmF2PjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImhlYWRlci10b3AtYmFja2dyb3VuZCI+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXItYmFja2dyb3VuZCI+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcCI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fY29udGVudCI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9faWRlbnRpdHkiPjxkaXYgY2xhc3M9ImhlYWRlci10b3BfX3Nsb2dhbiI+UGFydCBvZiB0aGUgPGJ1dHRvbiBjbGFzcz0iaGVhZGVyLXRvcF9fdG9nZ2xlZXhwbG9yZXBhbmVsIj40VFUuRmVkZXJhdGlvbjwvYnV0dG9uPjwvZGl2PjxhIGNsYXNzPSJoZWFkZXItdG9wX19pZGVudGl0eSIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGRpdiBjbGFzcz0iaGVhZGVyLXRvcF9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19zaXRldGl0bGUiPjxkaXYgc3R5bGU9ImRpc3BsYXk6aW5saW5lLWJsb2NrOyI+RmVkZXJhdGlvbjwvZGl2PjwvZGl2PjwvYT48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItdG9wX19vcmdhbml6YXRpb25zIj48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVkZWxmdC5ubC9lbi8iIHRpdGxlPSJUVSBEZWxmdCIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1kZWxmdC5zdmciIGFsdD0iVFUgRGVsZnQiIHdpZHRoPSIxMDAiIC8+PC9hPjxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWUubmwvZW4vIiB0aXRsZT0iVFUgRWluZGhvdmVuIiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWVpbmRob3Zlbi5zdmciIGFsdD0iVFUgRWluZGhvdmVuIiB3aWR0aD0iMTMwIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudXR3ZW50ZS5ubC9lbi8iIHRpdGxlPSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvdW5pdmVyc2l0eS1vZi10d2VudGUuc3ZnIiBhbHQ9IlVuaXZlcnNpdHkgb2YgVHdlbnRlIiB3aWR0aD0iMTAwIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cud3VyLm5sLyIgdGl0bGU9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby13dXIuc3ZnIiBhbHQ9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgd2lkdGg9IjEzMiIgLz48L2E+PC9kaXY+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXIiPjxkaXYgY2xhc3M9ImhlYWRlci1tZW51YmFyX19jb250ZW50Ij48YSBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX2lkZW50aXR5IiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fb3JnYW5pemF0aW9udGl0bGUiPjRUVS48L2Rpdj48ZGl2IGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2l0ZXRpdGxlIj48ZGl2IHN0eWxlPSJkaXNwbGF5OmlubGluZS1ibG9jazsiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48L2E+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NwYWNlciI+PC9kaXY+PG5hdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX21lbnViYXIiIGFyaWEtbGFiZWw9Ik1haW4iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXIiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vIiA+SG9tZTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvIiA+UmVzZWFyY2g8L2E+PGRpdiBjbGFzcz0ic3BjLW1lbnViYXJfX3B1bGxkb3duIj48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDIiPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyIgPkFib3V0IG91ciByZXNlYXJjaDwvYT48L2xpPjxsaSBjbGFzcz0ic3BjLW1lbnViYXItLWhhc3N1Yml0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vcmVzZWFyY2gvNHR1LWNlbnRyZXMvIiA+NFRVIENlbnRyZXM8L2E+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwzIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iID5BTUkgKE1hdGhlbWF0aWNzKTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iID5CdWlsdCBFbnZpcm9ubWVudDwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIiA+RGVzaWduIFVuaXRlZDwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyIgPkVuZXJneTwvYT48L2xpPjxsaT48YSBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIiA+RXRoaWNzICYjMzg7IFRlY2hub2xvZ3k8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iID5IZWFsdGg8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iID5IaWdoLVRlY2ggTWF0ZXJpYWxzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIiA+SGlzdG9yeSBvZiBUZWNobm9sb2d5PC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIiA+TklSSUNUIChJQ1QpPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyIgPlJlc2lsaWVuY2UgRW5naW5lZXJpbmc8L2E+PC9saT48L3VsPjwvbGk+PGxpIGNsYXNzPSJzcGMtbWVudWJhci0taGFzc3ViaXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlLyIgPkhpZ2ggVGVjaCBmb3IgYSBTdXN0YWluYWJsZSBGdXR1cmU8L2E+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwzIj48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyIgPkhUU0YgSSBQcm9ncmFtbWVzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9yZXNlYXJjaC9oaWdoLXRlY2gtZm9yLWEtc3VzdGFpbmFibGUtZnV0dXJlL2h0c2YtMi8iID5IVFNGIElJIFByb2dyYW1tZXM8L2E+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi12aWRlb3MvIiA+SFRTRiB2aWRlb3M8L2E+PC9saT48L3VsPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIiA+NFRVLlJlc2VhcmNoRGF0YTwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoL0VFLU5MLyIgPkVsZWN0cmljYWwgRW5naW5lZXJpbmcgTmV0aGVybGFuZHM8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIiA+RWR1Y2F0aW9uPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIiA+QWJvdXQgb3VyIGVkdWNhdGlvbjwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iID5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyIgPjRUVS5WTyAoc2Vjb25kYXJ5IGVkdWNhdGlvbik8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9zYWkvIiA+U0FJIChFbmdpbmVlcmluZyBEb2N0b3JhdGUpPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vZWR1Y2F0aW9uL2VkdWNhdGlvbnByb2dyYW1tZXMvIiA+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L2E+PC9saT48L3VsPjwvZGl2PjwvbGk+PGxpPjxhIGhyZWY9IiIgPlZhbG9yaXNhdGlvbjwvYT48ZGl2IGNsYXNzPSJzcGMtbWVudWJhcl9fcHVsbGRvd24iPjx1bCBjbGFzcz0ic3BjLW1lbnViYXJfX2xldmVsMiI+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9BYm91dCUyMDRUVS5JbXBhY3QlMjBhY3Rpdml0aWVzLyIgPjRUVS5JTVBBQ1Q8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL0Fib3V0JTIwNFRVLkltcGFjdC8iID5BYm91dCA0VFUuSW1wYWN0PC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9TdGFydHVwJTIwbWlzc2lvbnMvIiA+U3RhcnR1cCBtaXNzaW9uczwvYT48L2xpPjxsaSBjbGFzcz0ic3BjLW1lbnViYXItLWhhc3N1Yml0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS8iID5NZWRpYTwvYT48dWwgY2xhc3M9InNwYy1tZW51YmFyX19sZXZlbDMiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4va25vd2xlZGdlLXZhbG9yaXNhdGlvbi9NZWRpYS9pbnNpZ2h0ZnVsLWlubm92YXRvcnMvIiA+SW5zaWdodGZ1bCBJbm5vdmF0b3JzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL01lZGlhL1NwaW4tb2ZmJTIwc2VyaWUvIiA+U3Bpbi1PZmYgU3RvcmllczwvYT48L2xpPjwvdWw+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL1N0dWRlbnQlMjBjaGFsbGVuZ2VzLyIgPlN0dWRlbnQgY2hhbGxlbmdlczwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vVHVzc2VucGFnaW5hJTIwdm9vcmFmZ2FhbmQlMjBhYW4lMjBTdGFydHVwJTIwU3VwcG9ydC8iID5BYm91dCBTdGFydHVwIFN1cHBvcnQ8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9rbm93bGVkZ2UtdmFsb3Jpc2F0aW9uL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vYWdlbmRhLyIgPkFnZW5kYTwvYT48L2xpPjwvdWw+PC9kaXY+PC9saT48bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3cy8iID5OZXdzPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9uZXdzL25ld3MvIiA+TmV3czwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL25ld3MvbmV3c2xldHRlci8iID5OZXdzbGV0dGVyPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyIgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWxlY3RlZCI+QWdlbmRhPC9hPjwvbGk+PGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvIiA+QWJvdXQgNFRVPC9hPjxkaXYgY2xhc3M9InNwYy1tZW51YmFyX19wdWxsZG93biI+PHVsIGNsYXNzPSJzcGMtbWVudWJhcl9fbGV2ZWwyIj48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvNHR1LWluLTEtbWludXRlLyIgPjRUVSBpbiBvbmx5IDEgbWludXRlPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L2ZhY3RzLWZpZ3VyZXMvIiA+RmFjdHMgYW5kIGZpZ3VyZXM8L2E+PC9saT48bGkgPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9hYm91dF80dHUvb3JnYW5pc2F0aW9uLyIgPk9yZ2FuaXNhdGlvbjwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9wdWJsaWNhdGlvbnMvIiA+UHVibGljYXRpb25zPC9hPjwvbGk+PGxpID48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWJvdXRfNHR1L25ld3NsZXR0ZXIvIiA+TmV3c2xldHRlcjwvYT48L2xpPjxsaSA+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS9hbHVtbmkvIiA+QWx1bW5pPC9hPjwvbGk+PC91bD48L2Rpdj48L2xpPjwvdWw+PC9uYXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NwYWNlciI+PC9kaXY+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX2xhbmd1YWdlcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sLyI+Tkw8L2E+fDxzcGFuPkVOPC9zcGFuPjwvZGl2Pjxmb3JtIGFjdGlvbj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3NlYXJjaC8iIG1ldGhvZD0iR0VUIiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaHdyYXBwZXIiIGF1dG9jb21wbGV0ZT0ib2ZmIiA+PGRpdiBjbGFzcz0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaC1pbnB1dC1hbmQtc3VnZ2VzdGlvbnMtd3JhcHBlciI+PGlucHV0IGlkPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoaW5wdXQiIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2VhcmNoaW5wdXQiIG5hbWU9InF1ZXJ5IiBkYXRhLXN1Z2dlc3Q9IjR0dTpjb3Jwb3JhdGVfZW4iIGRhdGEtc3VnZ2VzdHBhcmVudD0icGFyZW50IiBwbGFjZWhvbGRlcj0iWm9la2VuIiBhcmlhLWxhYmVsPSJab2VrZW4iIHR5cGU9InNlYXJjaCIgLz48L2Rpdj48bGFiZWwgY2xhc3M9ImhlYWRlci1tZW51YmFyX19zZWFyY2giIGZvcj0iaGVhZGVyLW1lbnViYXJfX3NlYXJjaGlucHV0IiB0YWJpbmRleD0iLTEiID48c3BhbiBjbGFzcz0iZmFyIGZhLXNlYXJjaCI+PC9zcGFuPjwvbGFiZWw+PC9mb3JtPjxidXR0b24gaWQ9ImhlYWRlci1tZW51YmFyX3NpZGViYXJ0b2dnbGUiIGNsYXNzPSJoZWFkZXItbWVudWJhcl9fc2hvd3NpZGVtYWlubWVudSBzaWRlYmFyLWFjdGlvbi10b2dnbGUiIGFyaWEtbGFiZWw9Ik9wZW4gbWVudSIgYXJpYS1leHBhbmRlZD0iZmFsc2UiIGFyaWEtY29udHJvbHM9InNsaWRlbWVudSIgPjxzcGFuIGNsYXNzPSJmYXIgZmEtYmFycyI+PC9zcGFuPjwvYnV0dG9uPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbCI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX190b3BiYXIiPjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9fY2xvc2UiPkNsb3NlPC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jb2x1bW5zIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2FkZHJlc3MgcnRkY29udGVudCI+PHAgY2xhc3M9ImhlYWRpbmciPjRUVS5GZWRlcmF0aW9uPC9wPjxwIGNsYXNzPSJub3JtYWwiPiszMSgwKTYgNDggMjcgNTUgNjE8L3A+PHAgY2xhc3M9Im5vcm1hbCI+PGEgaHJlZj0ibWFpbHRvOnByb2plY3RsZWlkZXJANHR1Lm5sIj5zZWNyZXRhcmlzQDR0dS5ubDwvYT48L3A+PHAgY2xhc3M9Im5vcm1hbCI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+PGI+V2Vic2l0ZTogNFRVLm5sPC9iPjwvYT48L3A+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jb2x1bW4gZXhwbG9yZXBhbmVsX19jb2x1bW4tLW1hbnlpdGVtcyI+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5SZXNlYXJjaDwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faXRlbXMgZXhwbG9yZXBhbmVsX19pdGVtcy0tbWFueWl0ZW1zICI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2FtaS8iPjxzcGFuPkFwcGxpZWQgTWF0aGVtYXRpY3MgSW5zdGl0dXRlPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYm91dy8iPjxzcGFuPkJ1aWx0IEVudmlyb25tZW50PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZHUvIj48c3Bhbj5EZXNpZ24gVW5pdGVkPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW5lcmd5LyI+PHNwYW4+RW5lcmd5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2V0aGljc2FuZHRlY2hub2xvZ3kuZXUvIj48c3Bhbj5FdGhpY3MgJiMzODsgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hlYWx0aC8iPjxzcGFuPkhlYWx0aDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2h0bS8iPjxzcGFuPkhpZ2gtVGVjaCBNYXRlcmlhbHM8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9oaXN0b3J5LW9mLXRlY2hub2xvZ3kvIj48c3Bhbj5IaXN0b3J5IG9mIFRlY2hub2xvZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9uaXJpY3QvIj48c3Bhbj5OSVJJQ1QgKElDVCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9yZXNpbGllbmNlLyI+PHNwYW4+UmVzaWxpZW5jZSBFbmdpbmVlcmluZzwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly9kYXRhLjR0dS5ubC9pbmZvL2VuLyI+PHNwYW4+UmVzZWFyY2hEYXRhPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0xLyI+PHNwYW4+SFRTRiBJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ6b2VrL2hpZ2gtdGVjaC1mb3ItYS1zdXN0YWluYWJsZS1mdXR1cmUvaHRzZi0yLyI+PHNwYW4+SFRTRiBJSSAoaGlnaCB0ZWNoIHJlc2VhcmNoKTwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jb2x1bW4gIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLkVkdWNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faXRlbXMgICI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2NlZS8iPjxzcGFuPkNlbnRyZSBmb3IgRW5naW5lZXJpbmcgRWR1Y2F0aW9uPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvdm8vIj48c3Bhbj40VFUuVk8gKHNlY29uZGFyeSBlZHVjYXRpb24pPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvc2FpLyI+PHNwYW4+U0FJIChFbmdpbmVlcmluZyBEb2N0b3JhdGUpPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvb25kZXJ3aWpzL29uZGVyd2lqc3Byb2dyYW1tYXMvIj48c3Bhbj5FZHVjYXRpb24gcHJvZ3JhbW1lczwvc3Bhbj48L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0iZXhwbG9yZXBhbmVsX19jb2x1bW4gIj48ZGl2IGNsYXNzPSJleHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlZhbG9yaXNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImV4cGxvcmVwYW5lbF9faXRlbXMgICI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyI+PHNwYW4+NFRVLklNUEFDVDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly90ZWNoLXRyYW5zZmVyLm5sL2VuLyI+PHNwYW4+VGhlbWF0aWMgVGVjaG5vbG9neSBUcmFuc2Zlcjwvc3Bhbj48L2E+PGEgaHJlZj0iIj48c3Bhbj5TcGluLW9mZiBTdG9yaWVzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovLzR0dWltcGFjdGNoYWxsZW5nZS5ubC8iPjxzcGFuPjRUVSBJbXBhY3QgQ2hhbGxlbmdlPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fYmFja2dyb3VuZCI+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlc2hvdyBjYXJyb3VzZWxfX3ZpZXdwb3J0IGNhcnJvdXNlbF9fZHJhZ2FyZWEgIj48c3R5bGU+QG1lZGlhIChtYXgtd2lkdGg6IDc2N3B4KXsuaGVhZGVyc2xpZGUwe2JhY2tncm91bmQtY29sb3I6ICMzMTJBMkY7YmFja2dyb3VuZC1pbWFnZTogdXJsKC8udWMvaWQyODVhYmYxMDEwMjY4ZjgxMDAwYjdmZmJiMDEzMmIwNDhjZWY0Y2E1ZThkMDgwMWUzNDAwYjAwMDc4MTQ2L3RlYWNoaW5nLWxlYXJuaW5nLmpwZyk7fX1AbWVkaWEgKG1pbi13aWR0aDogNzY4cHgpey5oZWFkZXJzbGlkZTB7YmFja2dyb3VuZC1jb2xvcjogIzMxMkEyRjtiYWNrZ3JvdW5kLWltYWdlOiB1cmwoLy51Yy9pMzA3MGFjMWEwMTAyNjhmODEwMDBiN2ZmYmIwMTMyYjA0OGNlZjRjYTVlOGQwODAxZTM0MDBiNjAwNDgxNDYvdGVhY2hpbmctbGVhcm5pbmcuanBnKTt9fTwvc3R5bGU+PGRpdiBjbGFzcz0icGFnZS1oZWFkZXJfX3NsaWRlIGNhcnJvdXNlbF9fY2VsbCBhY3RpdmVzbGlkZSBoZWFkZXJzbGlkZTAgIiBkYXRhLXNsaWRlc2hvdy1lbGVtZW50cz0icGFnZS1oZWFkZXJfX3NsaWRlMF9fY29udGVudCIgc3R5bGU9IiIgPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9InBhZ2UtaGVhZGVyX19jb250ZW50Ij48ZGl2IGNsYXNzPSJwYWdlLWhlYWRlcl9fbWV0YSI+PGgxIGNsYXNzPSJwYWdlLWhlYWRlcl9fdGl0bGUiPlJvb20gZm9yIGV2ZXJ5b25lJ3MgZWR1Y2F0aW9uYWwgdGFsZW50IC0gRXZlbnQ8L2gxPjxkaXYgY2xhc3M9InBhZ2VoZWFkZXJfX2RhdGUiPldlZG5lc2RheSA5IE9jdG9iZXIgMjAyNDwvZGl2PjxkaXYgY2xhc3M9InBhZ2VoZWFkZXJfX3RleHQiPkxvY2F0aW9uOiBTb2NpYWwgSW1wYWN0IEZhY3RvcnkgVnJlZGVuYnVyZyBVdHJlY2h0PC9kaXY+PC9kaXY+PC9kaXY+PG1haW4gY2xhc3M9InBhZ2VfX2JvZHkgICI+PGZvcm0gaWQ9IiIgIGNsYXNzPSJwYWdlX19oZWFkZXJmaWx0ZXJzICAgIj48L2Zvcm0+PGRpdiBjbGFzcz0icGFnZV9fY29udGVudGFyZWEgIHBhZ2VfX2NvbnRlbnRhcmVhLS1mb3Jtd2VidG9vbCAgaGVhZGVyaXNvcGFxdWUgIj48ZGl2IGNsYXNzPSJkZWVwbGlua3Mtd3JhcHBlciI+PGRpdiBjbGFzcz0iZGVlcGxpbmtzIj48YSBjbGFzcz0icGFnZS1iYWNrbGluayIgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFsbCBldmVudHM8L2E+PC9kaXY+PC9kaXY+PGRpdiBjbGFzcz0icGFnZS1jb250ZW50c3RhcnQiPjwvZGl2PjwhLS13aF9jb25zaWxpb19jb250ZW50LS0+PHAgY2xhc3M9Im5vcm1hbCI+PGI+U3BhY2UgZm9yIGV2ZXJ5b25lJ3MgZWR1Y2F0aW9uIHRhbGVudDwvYj48L3A+PHAgY2xhc3M9Im5vcm1hbCI+OSBva3RvYmVyIDIwMjQ8L3A+PHAgY2xhc3M9Im5vcm1hbCI+U3RhcnQgMTAuMDAgdXVyIC0gZW5kIDE3LjAwIHV1cjwvcD48cCBjbGFzcz0ibm9ybWFsIj5Mb2NhdGlvbjogU29jaWFsIEltcGFjdCBGYWN0b3J5IFZyZWRlbmJ1cmcgVXRyZWNodDwvcD48cCBjbGFzcz0ibm9ybWFsIj40VFUuQ0VFIG9yZ2FuaXplcyBhIG5hdGlvbmFsIGV2ZW50IHRvIGNlbGVicmF0ZSB0aGUgcmVzdWx0cyBvZiB0aGUg4oCYU2VjdG9ycGxhbiBvbmRlcndpanMgYsOodGF0ZWNobmlla+KAmSAoc2VjdG9yIHBsYW4gZm9yIFNURU0gZWR1Y2F0aW9uIGluIHRoZSBOZXRoZXJsYW5kcyksIEFjdGlvbiAyYjog4oCcVG8gam9pbnRseSBvZmZlciBzY2llbnRpc3RzIG1vcmUgb3Bwb3J0dW5pdGllcyBmb3IgYW4gYWNhZGVtaWMgY2FyZWVyIHdpdGggZm9jdXMgb24gdGVhY2hpbmcgYW5kIGxlYXJuaW5nIGluIHRoZSBjb250ZXh0IG9mIFJlY29nbml0aW9uIGFuZCBSZXdhcmRzLuKAnSBUaGlzIGV2ZW50IHdpbGwgYmUgaW4gRHV0Y2guPC9wPjxwIGNsYXNzPSJub3JtYWwiPlRoZSBvcmdhbml6aW5nIGNvbW1pdHRlZTrCoDwvcD48cCBjbGFzcz0ibm9ybWFsIj5UVSBEZWxmdDogU3lsdmlhIFdhbHNhcmllIFdvbGZmIGVuIERhbmllbGxlIFJpZXRkaWprPC9wPjxwIGNsYXNzPSJub3JtYWwiPlRVIEVpbmRob3ZlbjogSnVsbWEgQnJhYXQgZW4gUmFjaGVsbGUgS2FtcDwvcD48cCBjbGFzcz0ibm9ybWFsIj5Vbml2ZXJzaXRlaXQgVHdlbnRlOiBDaW5keSBQb29ydG1hbjwvcD48cCBjbGFzcz0ibm9ybWFsIj5XYWdlbmluZ2VuIFVuaXZlcnNpdHkgJmFtcDsgUmVzZWFyY2g6IEZyaWtraWUgS29yZzwvcD48cCBjbGFzcz0ibm9ybWFsIj48Yj5TaWdudXAgbGluayB3aWxsIGZvbGxvdyBzb29uITwvYj48L3A+PCEtLS93aF9jb25zaWxpb19jb250ZW50LS0+PGRpdiBjbGFzcz0icGFnZV9fYmFsbG9vbiI+PC9kaXY+PGRpdiBjbGFzcz0icGFnZV9fZm9vdGVyIj48ZGl2IGNsYXNzPSJwYWdlX19mb290ZXJfX2NvbnRlbnQgbmF2cGF0aCI+PGEgY2xhc3M9Im5hdnBhdGhfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi8iPkhvbWU8L2E+PHNwYW4gY2xhc3M9Im5hdnBhdGhfX3NlcGVyYXRvciI+PC9zcGFuPjxhIGNsYXNzPSJuYXZwYXRoX19pdGVtIiBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vYWdlbmRhLyI+QWdlbmRhPC9hPjxzcGFuIGNsYXNzPSJuYXZwYXRoX19zZXBlcmF0b3IiPjwvc3Bhbj48c3BhbiBjbGFzcz0ibmF2cGF0aF9faXRlbSBjcnVtYnBhdGgtLWN1cnJlbnRwYWdlIj5Sb29tIGZvciBldmVyeW9uZSYjMzk7cyBlZHVjYXRpb25hbCB0YWxlbnQgLSBFdmVudDwvc3Bhbj48L2Rpdj48L2Rpdj48L2Rpdj48L21haW4+PGRpdiBjbGFzcz0iZm9vdGVyIj48ZGl2IGNsYXNzPSJmb290ZXJfX3BhbmVsIj48ZGl2IGNsYXNzPSJmb290ZXJfX2lkZW50aXR5Ij48ZGl2IGNsYXNzPSJmb290ZXJfX29yZ2FuaXphdGlvbnRpdGxlIj40VFUuPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19zaXRldGl0bGUiPkZlZGVyYXRpb248L2Rpdj48L2Rpdj48IS0tIEZJWE1FOiB1c2UgYXJpYS1oaWRkZW49InRydWUiIGJlY2F1c2UgaXQncyBhIGR1cGxpY2F0ZSBvZiB0aGUgaXRlbXMgb24gdGhlIG1lbnUgYmFyID8gLS0+IDxuYXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMSBmb290ZXJfX21haW5tZW51IiBhcmlhLWxhYmVsPSJNYWluIj4gPHVsPiAgIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuLyI+SG9tZTwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL3Jlc2VhcmNoLyI+UmVzZWFyY2g8L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbi9lZHVjYXRpb24vIj5FZHVjYXRpb248L2E+IDwvbGk+ICA8bGk+IDxhIGhyZWY9IiI+VmFsb3Jpc2F0aW9uPC9hPiA8L2xpPiAgPGxpPiA8YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vbmV3cy9uZXdzLyI+TmV3czwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2FnZW5kYS8iPkFnZW5kYTwvYT4gPC9saT4gIDxsaT4gPGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2Fib3V0XzR0dS8iPkFib3V0IDRUVTwvYT4gPC9saT4gICA8L3VsPiA8L25hdj4gIDxkaXYgY2xhc3M9ImZvb3Rlcl9fY29sdW1uMiI+IDxpbnB1dCB0eXBlPSJjaGVja2JveCIgbmFtZT0iZm9vdGVyY29sdW1uIiBpZD0iZm9vdGVyX19jb2x1bW4yX19leHBhbmQiIC8+IDxsYWJlbCBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2hlYWRpbmciIGZvcj0iZm9vdGVyX19jb2x1bW4yX19leHBhbmQiPkNvbnRhY3Q8L2xhYmVsPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9fY29udGVudCBydGRjb250ZW50Ij4gPHAgY2xhc3M9Im5vcm1hbCI+KzMxKDApNiA4MyAyMiA1MCA1OTxiciAvPjxhIGhyZWY9Im1haWx0bzpwcm9qZWN0bGVpZGVyQDR0dS5ubCI+c2VjcmV0YXJpc0A0dHUubmw8L2E+PC9wPiA8L2Rpdj4gPC9kaXY+ICAgPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW4zIj4gPGlucHV0IHR5cGU9ImNoZWNrYm94IiBuYW1lPSJmb290ZXJjb2x1bW4iIGlkPSJmb290ZXJfX2NvbHVtbjNfX2V4cGFuZCIgLz4gPGxhYmVsIGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyIgZm9yPSJmb290ZXJfX2NvbHVtbjNfX2V4cGFuZCI+UG9zdGFkcmVzPC9sYWJlbD4gPGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgcnRkY29udGVudCI+IDxwIGNsYXNzPSJub3JtYWwiPjRUVS5GZWRlcmF0aWU8YnIgLz5Qb3N0YnVzIDU8YnIgLz4yNjAwIEFBIERlbGZ0PC9wPiA8L2Rpdj4gPC9kaXY+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbjQiPiAgPGRpdiBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtc19fZ3JvdXAiPiA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyI+Rm9sbG93IHVzPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19jb2x1bW5fX2NvbnRlbnQgZm9vdGVyX19zb2NpYWxpdGVtcyAiPjxhIGNsYXNzPSJmb290ZXJfX3NvY2lhbGl0ZW0iIGhyZWY9Imh0dHBzOi8vdHdpdHRlci5jb20vNFRVRmVkZXJhdGlvbiIgdGl0bGU9IlR3aXR0ZXIiID48c3BhbiBjbGFzcz0iZmFiIGZhLXR3aXR0ZXIiPjwvc3Bhbj48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fc29jaWFsaXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2NvbXBhbnkvNC10dS1mZWRlcmF0aW9uLyIgdGl0bGU9IkxpbmtlZEluIiA+PHNwYW4gY2xhc3M9ImZhYiBmYS1saW5rZWRpbi1pbiI+PC9zcGFuPjwvYT48YSBjbGFzcz0iZm9vdGVyX19zb2NpYWxpdGVtIiBocmVmPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS9jaGFubmVsL1VDTWtxaGp4MlcxaE5Sd3lzUnZXRVh3USIgdGl0bGU9IllvdXR1YmUiID48c3BhbiBjbGFzcz0iZmFiIGZhLXlvdXR1YmUiPjwvc3Bhbj48L2E+PC9kaXY+IDwvZGl2PiAgPGRpdiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyX19ncm91cCI+ICA8ZGl2IGNsYXNzPSJmb290ZXJfX2NvbHVtbl9faGVhZGluZyBmb290ZXJfX2NvbHVtbl9faGVhZGluZy0tbmV3c2xldHRlciAiPlN0YXkgdXAtdG8tZGF0ZTwvZGl2Pjxmb3JtIGNsYXNzPSJmb290ZXJfX25ld3NsZXR0ZXJzaWdudXAgd2hwbHVnaW4tbmV3c2xldHRlci1zdWJzY3JpcHRpb24gICIgZGF0YS1uZXdzbGV0dGVyLWxpc3Q9IlNVQlNfNFRVX0NPUlBPUkFURV9OSUVVV1NCUklFRiIgPjxpbnB1dCBuYW1lPSJlbWFpbCIgcGxhY2Vob2xkZXI9IlNpZ24gdXAgZm9yIG91ciBuZXdzbGV0dGVyIiAvPjxidXR0b24gY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VibWl0IiB0eXBlPSJzdWJtaXQiIG5hbWU9InN1Ym1pdGJ1dHRvbiIgYXJpYS1sYWJlbD0iU3Vic2NyaWJlIj48c3BhbiBjbGFzcz0iZm9vdGVyX19uZXdzbGV0dGVyc2lnbnVwX19zdWJtaXRfX2ljb24gZmFyIGZhLWVudmVsb3BlIj48L3NwYW4+PC9idXR0b24+PC9mb3JtPjxkaXYgY2xhc3M9ImZvb3Rlcl9fbmV3c2xldHRlcnNpZ251cF9fc3VjY2VzcyI+VGhhbmtzIGZvciBzdWJzY3JpYmluZyB0byBvdXIgbmV3c2xldHRlci48L2Rpdj4gIDwvZGl2PiA8L2Rpdj4gPGhyIGNsYXNzPSJmb290ZXJfX2RpdmlkZXIiIC8+IDxkZXRhaWxzIGNsYXNzPSJmb290ZXJfX2V4cGxvcmUiPjxzdW1tYXJ5PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZV9fdG9nZ2xlX19jbG9zZWR0ZXh0Ij5QYXJ0IG9mIHRoZSA8c3BhbiBjbGFzcz0iZm9vdGVyX19leHBsb3JlX19uYW1lIj40VFUuRmVkZXJhdGlvbjwvc3Bhbj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVfX3RvZ2dsZV9fb3BlbnRleHQiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jbG9zZSI+Q2xvc2U8L2Rpdj48L2Rpdj48L3N1bW1hcnk+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWwiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlJlc2VhcmNoPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2l0ZW1zIj48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvYW1pLyI+PHNwYW4+QXBwbGllZCBNYXRoZW1hdGljcyBJbnN0aXR1dGU8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9ib3V3LyI+PHNwYW4+QnVpbHQgRW52aXJvbm1lbnQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9kdS8iPjxzcGFuPkRlc2lnbiBVbml0ZWQ8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9lbmVyZ3kvIj48c3Bhbj5FbmVyZ3k8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vZXRoaWNzYW5kdGVjaG5vbG9neS5ldS8iPjxzcGFuPkV0aGljcyAmIzM4OyBUZWNobm9sb2d5PC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaGVhbHRoLyI+PHNwYW4+SGVhbHRoPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvaHRtLyI+PHNwYW4+SGlnaC1UZWNoIE1hdGVyaWFsczwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2hpc3Rvcnktb2YtdGVjaG5vbG9neS8iPjxzcGFuPkhpc3Rvcnkgb2YgVGVjaG5vbG9neTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL25pcmljdC8iPjxzcGFuPk5JUklDVCAoSUNUKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3Jlc2lsaWVuY2UvIj48c3Bhbj5SZXNpbGllbmNlIEVuZ2luZWVyaW5nPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovL2RhdGEuNHR1Lm5sL2luZm8vZW4vIj48c3Bhbj5SZXNlYXJjaERhdGE8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTEvIj48c3Bhbj5IVFNGIEkgKGhpZ2ggdGVjaCByZXNlYXJjaCk8L3NwYW4+PC9hPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9vbmRlcnpvZWsvaGlnaC10ZWNoLWZvci1hLXN1c3RhaW5hYmxlLWZ1dHVyZS9odHNmLTIvIj48c3Bhbj5IVFNGIElJIChoaWdoIHRlY2ggcmVzZWFyY2gpPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9fY2F0ZWdvcnkiPjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19oZWFkZXIiPjRUVS5FZHVjYXRpb248L2Rpdj48ZGl2IGNsYXNzPSJmb290ZXJfX2V4cGxvcmVwYW5lbF9faXRlbXMiPjxhIGhyZWY9Imh0dHBzOi8vd3d3LjR0dS5ubC9jZWUvIj48c3Bhbj5DZW50cmUgZm9yIEVuZ2luZWVyaW5nIEVkdWNhdGlvbjwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3ZvLyI+PHNwYW4+NFRVLlZPIChzZWNvbmRhcnkgZWR1Y2F0aW9uKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL3NhaS8iPjxzcGFuPlNBSSAoRW5naW5lZXJpbmcgRG9jdG9yYXRlKTwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL29uZGVyd2lqcy9vbmRlcndpanNwcm9ncmFtbWFzLyI+PHNwYW4+RWR1Y2F0aW9uIHByb2dyYW1tZXM8L3NwYW4+PC9hPjwvZGl2PjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19jYXRlZ29yeSI+PGRpdiBjbGFzcz0iZm9vdGVyX19leHBsb3JlcGFuZWxfX2hlYWRlciI+NFRVLlZhbG9yaXNhdGlvbjwvZGl2PjxkaXYgY2xhc3M9ImZvb3Rlcl9fZXhwbG9yZXBhbmVsX19pdGVtcyI+PGEgaHJlZj0iaHR0cHM6Ly93d3cuNHR1Lm5sL2VuL2tub3dsZWRnZS12YWxvcmlzYXRpb24vQWJvdXQlMjA0VFUuSW1wYWN0LyI+PHNwYW4+NFRVLklNUEFDVDwvc3Bhbj48L2E+PGEgaHJlZj0iaHR0cHM6Ly90ZWNoLXRyYW5zZmVyLm5sL2VuLyI+PHNwYW4+VGhlbWF0aWMgVGVjaG5vbG9neSBUcmFuc2Zlcjwvc3Bhbj48L2E+PGEgaHJlZj0iIj48c3Bhbj5TcGluLW9mZiBTdG9yaWVzPC9zcGFuPjwvYT48YSBocmVmPSJodHRwczovLzR0dWltcGFjdGNoYWxsZW5nZS5ubC8iPjxzcGFuPjRUVSBJbXBhY3QgQ2hhbGxlbmdlPC9zcGFuPjwvYT48L2Rpdj48L2Rpdj48L2Rpdj48L2RldGFpbHM+IDxkaXYgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnMiPiA8ZGl2IGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtcyI+IDxhIGNsYXNzPSJmb290ZXJfX3BhcnRuZXJzX19pdGVtIiBocmVmPSJodHRwczovL3d3dy50dWRlbGZ0Lm5sL2VuLyIgdGl0bGU9IlRVIERlbGZ0IiA+PGltZyBzcmM9Ii8ucHVibGlzaGVyL3NkLzR0dS9zaXRlL2ltZy9sb2dvcy1jb2xvci9sb2dvLXR1LWRlbGZ0LnN2ZyIgYWx0PSJUVSBEZWxmdCIgd2lkdGg9Ijg3IiBoZWlnaHQ9IjM0IiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cudHVlLm5sL2VuLyIgdGl0bGU9IlRVIEVpbmRob3ZlbiIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby10dS1laW5kaG92ZW4uc3ZnIiBhbHQ9IlRVIEVpbmRob3ZlbiIgd2lkdGg9IjEzMCIgaGVpZ2h0PSIyNyIgLz48L2E+PGEgY2xhc3M9ImZvb3Rlcl9fcGFydG5lcnNfX2l0ZW0iIGhyZWY9Imh0dHBzOi8vd3d3LnV0d2VudGUubmwvZW4vIiB0aXRsZT0iVW5pdmVyc2l0eSBvZiBUd2VudGUiID48aW1nIHNyYz0iLy5wdWJsaXNoZXIvc2QvNHR1L3NpdGUvaW1nL2xvZ29zLWNvbG9yL3VuaXZlcnNpdHktb2YtdHdlbnRlLnN2ZyIgYWx0PSJVbml2ZXJzaXR5IG9mIFR3ZW50ZSIgd2lkdGg9Ijg1IiBoZWlnaHQ9IjMxIiAvPjwvYT48YSBjbGFzcz0iZm9vdGVyX19wYXJ0bmVyc19faXRlbSIgaHJlZj0iaHR0cHM6Ly93d3cud3VyLm5sLyIgdGl0bGU9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgPjxpbWcgc3JjPSIvLnB1Ymxpc2hlci9zZC80dHUvc2l0ZS9pbWcvbG9nb3MtY29sb3IvbG9nby13dXIuc3ZnIiBhbHQ9IldhZ2VuaW5nZW4gVW5pdmVyc2l0eSIgd2lkdGg9IjE0NSIgaGVpZ2h0PSIyOSIgLz48L2E+IDwvZGl2PiA8L2Rpdj4gPC9kaXY+PGRpdiBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXIiPjxzcGFuIGNsYXNzPSJmb290ZXJfX2JvdHRvbWJhcl9fY29weXJpZ2h0Ij48c3BhbiBjbGFzcz0iZmJjcGFydCI+JmNvcHk7IDIwMjQgNFRVLkZlZGVyYXRpb248L3NwYW4+PC9zcGFuPjx1bCBjbGFzcz0iZm9vdGVyX19ib3R0b21iYXJfX21lbnUiPjxsaT48YSBocmVmPSJodHRwczovL3d3dy40dHUubmwvZW4vY29udGFjdC8iPkNvbnRhY3Q8L2E+PC9saT48L3VsPjwvZGl2PjwvZGl2PjxzY3JpcHQgdHlwZT0iYXBwbGljYXRpb24veC1oc29uIiBpZD0id2gtY29uc2lsaW9maWVsZHMiPmhzb246eyJ3aHNlYXJjaHRodW1ibmFpbCI6Imh0dHBzOi8vd3d3LjR0dS5ubC8udWMvaTA2MTljMjI0MDEwMjZhZjgxMDAwYjdmZmJiMDEzMmIwNDhjZWY0Y2E1ZThkMDgwMWUzNDAwMWYwMDA4MTQxL3RlYWNoaW5nLWxlYXJuaW5nLmpwZyJ9PC9zY3JpcHQ+PC9ib2R5PjwvaHRtbD4=
+ recorded_at: Wed, 02 Jan 2019 16:00:00 GMT
+recorded_with: VCR 6.2.0
From 4b4ca67e0edc320f3f2be0eb7759362b3a25ab41 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Thu, 6 Jun 2024 10:24:36 +0200
Subject: [PATCH 24/37] nil as default for fetch willma api key
---
lib/modules/willma_service.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
index 558de5e0f..e5d752f2d 100644
--- a/lib/modules/willma_service.rb
+++ b/lib/modules/willma_service.rb
@@ -36,7 +36,7 @@ def call(prompt)
def do_request(url, mode, data = {})
header = {
'Content-Type': 'application/json',
- 'X-API-KEY': ENV.fetch('WILLMA_API_KEY')
+ 'X-API-KEY': ENV.fetch('WILLMA_API_KEY', nil)
}
parsed_url = URI.parse(url)
From 7eae18cf046285a37337682828d09c8d2fe549e9 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Thu, 6 Jun 2024 10:33:47 +0200
Subject: [PATCH 25/37] model test for llm_objects on events
---
config/secrets.example.yml | 2 ++
test/fixtures/llm_objects.yml | 9 +++++++++
test/models/event_test.rb | 19 +++++++++++++++++++
3 files changed, 30 insertions(+)
create mode 100644 test/fixtures/llm_objects.yml
diff --git a/config/secrets.example.yml b/config/secrets.example.yml
index 4c3c3e258..40fbff566 100644
--- a/config/secrets.example.yml
+++ b/config/secrets.example.yml
@@ -38,6 +38,8 @@ external_api_keys: &external_api_keys
fairsharing:
username:
password:
+ gpt_api_key:
+ willma_api_key:
#Internal config
development:
diff --git a/test/fixtures/llm_objects.yml b/test/fixtures/llm_objects.yml
new file mode 100644
index 000000000..646b60b0c
--- /dev/null
+++ b/test/fixtures/llm_objects.yml
@@ -0,0 +1,9 @@
+# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
+
+scrape:
+ scrape_or_process: 'scrape'
+ model: 'Zephyr 7B'
+ prompt: 'Give JSON please'
+ input: 'Give JSON please'
+ output: 'Give JSON please'
+ needs_processing: false
diff --git a/test/models/event_test.rb b/test/models/event_test.rb
index ea55e3515..f04d08a84 100644
--- a/test/models/event_test.rb
+++ b/test/models/event_test.rb
@@ -671,4 +671,23 @@ class EventTest < ActiveSupport::TestCase
assert_equal ['Fold recognition', 'Domain prediction', 'Fold prediction', 'Protein domain prediction',
'Protein fold prediction', 'Protein fold recognition'], @event.reload.operations_and_synonyms
end
+
+ test 'can add an llm_object to an event' do
+ e = events(:scraper_user_event)
+ l = llm_objects(:scrape)
+ e.llm_object = l
+ e.save!
+ assert_equal e.llm_object.id, l.id
+ assert_equal l.event_id, e.id
+ end
+
+ test 'can destroy an llm_object with an event' do
+ e = events(:scraper_user_event)
+ l = llm_objects(:scrape)
+ e.llm_object = l
+ e.save!
+ assert_difference 'LlmObject.count', -1 do
+ e.destroy!
+ end
+ end
end
From c32993af3e1f5d3f083db2d862da062954e4c19a Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Thu, 6 Jun 2024 10:41:58 +0200
Subject: [PATCH 26/37] remove accidental file
---
lib/tasks/seed_content_providers.rake | 25 -------------------------
1 file changed, 25 deletions(-)
delete mode 100644 lib/tasks/seed_content_providers.rake
diff --git a/lib/tasks/seed_content_providers.rake b/lib/tasks/seed_content_providers.rake
deleted file mode 100644
index 4c81dac1e..000000000
--- a/lib/tasks/seed_content_providers.rake
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'yaml'
-
-namespace :tess do
- desc 'create ContentProviders objects for all scrapers'
- task seed_content_providers: :environment do
- if TeSS::Config.ingestion.nil?
- config_file = File.join(Rails.root, 'config', 'ingestion.yml')
- TeSS::Config.ingestion = YAML.safe_load(File.read(config_file)).deep_symbolize_keys!
- end
- config = TeSS::Config.ingestion
-
- admin_user = User.all.select{|user| user.is_admin?}.first
-
- config[:sources].each do |source|
- if ContentProvider.find_by(title: source[:provider]).nil?
- ContentProvider.create!(
- title: source[:provider],
- url: source[:url],
- image_url: source[:image_url],
- user_id: admin_user.id,
- )
- end
- end
- end
-end
\ No newline at end of file
From 88ed51af704db7a97fab02320880d159af1cec9d Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Thu, 6 Jun 2024 11:59:54 +0200
Subject: [PATCH 27/37] fix tests
---
lib/ingestors/ingestor.rb | 27 ++++++++++++---------------
lib/ingestors/llm_ingestor.rb | 5 +++--
2 files changed, 15 insertions(+), 17 deletions(-)
diff --git a/lib/ingestors/ingestor.rb b/lib/ingestors/ingestor.rb
index d7b0b4b14..bb7440b8c 100644
--- a/lib/ingestors/ingestor.rb
+++ b/lib/ingestors/ingestor.rb
@@ -43,7 +43,7 @@ def write(user, provider)
def stats_summary(type)
summary = "\n### #{type.to_s.titleize}\n\n"
- [:processed, :added, :updated, :rejected].each do |key|
+ %i[processed added updated rejected].each do |key|
summary += " - #{key.to_s.titleize}: #{stats[type][key]}\n"
end
@@ -64,19 +64,17 @@ def open_url(url, raise: false)
retry if (redirect_attempts -= 1) > 0
raise e
rescue OpenURI::HTTPError => e
- if raise
- raise e
- else
- @messages << "Couldn't open URL #{url}: #{e}"
- nil
- end
+ raise e if raise
+
+ @messages << "Couldn't open URL #{url}: #{e}"
+ nil
end
end
def convert_description(input)
return input if input.nil?
- if input.match?(/<(li|p|b|i|ul|div|br|strong|em|h1)\/?>/)
+ if input.match?(%r{<(li|p|b|i|ul|div|br|strong|em|h1)/?>})
ReverseMarkdown.convert(input, tag_border: '').strip
else
input
@@ -85,14 +83,15 @@ def convert_description(input)
def convert_title(input)
return input if input.nil?
+
CGI.unescapeHTML(input)
end
def get_json_response(url, accept_params = 'application/json', **kwargs)
response = RestClient::Request.new({ method: :get,
- url: CGI.unescape_html(url),
- verify_ssl: false,
- headers: { accept: accept_params } }.merge(kwargs)).execute
+ url: CGI.unescape_html(url),
+ verify_ssl: false,
+ headers: { accept: accept_params } }.merge(kwargs)).execute
# check response
raise "invalid response code: #{response.code}" unless response.code == 200
@@ -137,7 +136,7 @@ def write_resources(type, resources, user, provider)
resource.user_id ||= user.id
resource.content_provider_id ||= provider.id
llm_attr = resource.delete_field(:llm_object_attributes) if resource.respond_to?(:llm_object_attributes)
- resource = OpenStruct.new(resource.to_h.select { |key, _| type.attribute_names.map(&:to_sym).include?(key)})
+ # resource = OpenStruct.new(resource.to_h.select { |key, _| (type.attribute_names + [:online]).map(&:to_sym).include?(key) })
existing_resource = find_existing(type, resource)
update = existing_resource
@@ -160,9 +159,7 @@ def write_resources(type, resources, user, provider)
end
llm_object.save!
resource.llm_object = llm_object
- if resource.valid?
- resource.save!
- end
+ resource.save! if resource.valid?
end
else
@stats[key][:rejected] += 1
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index 8231b3d9e..e1f0b2ebb 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -48,11 +48,12 @@ def get_event_from_css(url, event_page) # rubocop:disable Metrics
event.source = 'LLM'
event.timezone = 'Amsterdam'
a = Time.parse(event.start)
- event.start = Time.new(a.year, a.month, a.day, a.hour, a.min, a.sec, "+00:00")
+ event.start = Time.new(a.year, a.month, a.day, a.hour, a.min, a.sec, '+00:00')
a = Time.parse(event.end)
- event.end = Time.new(a.year, a.month, a.day, a.hour, a.min, a.sec, "+00:00")
+ event.end = Time.new(a.year, a.month, a.day, a.hour, a.min, a.sec, '+00:00')
event.set_default_times
event.nonsense_attr = 'nonsense'
+ event = OpenStruct.new(event.to_h.select { |key, _| (Event.attribute_names + [:online]).map(&:to_sym).include?(key) })
add_event(event)
rescue Exception => e
puts e
From d6d0bccf87f04a8739d3d753312f5f1c18260332 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Tue, 18 Jun 2024 13:09:39 +0200
Subject: [PATCH 28/37] handled most feedback
---
app/controllers/events_controller.rb | 2 +-
app/models/event.rb | 4 +-
.../{llm_object.rb => llm_interaction.rb} | 2 +-
config/application.rb | 1 -
db/migrate/20240220144246_add_llm_check.rb | 5 +-
lib/ingestors/ingestor.rb | 21 ++---
lib/ingestors/llm_ingestor.rb | 4 +-
lib/llm/chatgpt_service.rb | 32 +++++++
.../llm_prompts/llm_process_prompt.txt | 0
.../llm_prompts/llm_scrape_prompt.txt | 0
lib/llm/llm_service.rb | 71 +++++++++++++++
lib/llm/willma_service.rb | 88 ++++++++++++++++++
lib/modules/chatgpt_service.rb | 28 ------
lib/modules/llm_service.rb | 91 -------------------
lib/modules/willma_service.rb | 85 -----------------
lib/tasks/tess.rake | 22 +++--
test/models/event_test.rb | 22 ++---
17 files changed, 233 insertions(+), 245 deletions(-)
rename app/models/{llm_object.rb => llm_interaction.rb} (86%)
create mode 100644 lib/llm/chatgpt_service.rb
rename lib/{modules => llm}/llm_prompts/llm_process_prompt.txt (100%)
rename lib/{modules => llm}/llm_prompts/llm_scrape_prompt.txt (100%)
create mode 100644 lib/llm/llm_service.rb
create mode 100644 lib/llm/willma_service.rb
delete mode 100644 lib/modules/chatgpt_service.rb
delete mode 100644 lib/modules/llm_service.rb
delete mode 100644 lib/modules/willma_service.rb
diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb
index 7d4e55346..db07ef598 100644
--- a/app/controllers/events_controller.rb
+++ b/app/controllers/events_controller.rb
@@ -235,7 +235,7 @@ def event_params
{ host_institutions: [] }, :capacity, :contact, :recognition, :learning_objectives,
:prerequisites, :tech_requirements, :cost_basis, :cost_value, :cost_currency,
external_resources_attributes: %i[id url title _destroy], material_ids: [],
- llm_object_attributes: %i[id scrape_or_process model prompt input output needs_processing _destroy],
+ llm_interaction_attributes: %i[id scrape_or_process model prompt input output needs_processing _destroy],
locked_fields: [])
end
diff --git a/app/models/event.rb b/app/models/event.rb
index cdc6e15c8..264d50b0c 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -109,8 +109,8 @@ class Event < ApplicationRecord
enum presence: { onsite: 0, online: 1, hybrid: 2 }
belongs_to :user
- has_one :llm_object, inverse_of: :event, dependent: :destroy
- accepts_nested_attributes_for :llm_object, allow_destroy: true
+ has_one :llm_interaction, inverse_of: :event, dependent: :destroy
+ accepts_nested_attributes_for :llm_interaction, allow_destroy: true
has_one :edit_suggestion, as: :suggestible, dependent: :destroy
has_one :link_monitor, as: :lcheck, dependent: :destroy
has_many :collection_items, as: :resource
diff --git a/app/models/llm_object.rb b/app/models/llm_interaction.rb
similarity index 86%
rename from app/models/llm_object.rb
rename to app/models/llm_interaction.rb
index a43bcfb8e..f101580f1 100644
--- a/app/models/llm_object.rb
+++ b/app/models/llm_interaction.rb
@@ -1,4 +1,4 @@
-class LlmObject < ApplicationRecord
+class LlmInteraction < ApplicationRecord
belongs_to :event
validates :scrape_or_process, presence: true
validates :model, presence: true
diff --git a/config/application.rb b/config/application.rb
index 92478678b..a172940d8 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -10,7 +10,6 @@ module TeSS
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
- config.autoload_paths << Rails.root.join('lib/modules')
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
diff --git a/db/migrate/20240220144246_add_llm_check.rb b/db/migrate/20240220144246_add_llm_check.rb
index a3b57193e..28a08facb 100644
--- a/db/migrate/20240220144246_add_llm_check.rb
+++ b/db/migrate/20240220144246_add_llm_check.rb
@@ -1,6 +1,6 @@
class AddLlmCheck < ActiveRecord::Migration[7.0]
def change
- create_table :llm_objects do |t|
+ create_table :llm_interactions do |t|
t.belongs_to :event, foreign_key: true
t.datetime :created_at
t.datetime :updated_at
@@ -11,8 +11,7 @@ def change
t.string :output
t.boolean :needs_processing, default: false
end
- add_reference :events, :llm_object, foreign_key: true
+ add_reference :events, :llm_interaction, foreign_key: true
add_column :events, :open_science, :string, array: true, default: []
- add_column :materials, :llm_processed, :bool, default: false
end
end
diff --git a/lib/ingestors/ingestor.rb b/lib/ingestors/ingestor.rb
index bb7440b8c..2a774c168 100644
--- a/lib/ingestors/ingestor.rb
+++ b/lib/ingestors/ingestor.rb
@@ -135,8 +135,7 @@ def write_resources(type, resources, user, provider)
# check for matched events
resource.user_id ||= user.id
resource.content_provider_id ||= provider.id
- llm_attr = resource.delete_field(:llm_object_attributes) if resource.respond_to?(:llm_object_attributes)
- # resource = OpenStruct.new(resource.to_h.select { |key, _| (type.attribute_names + [:online]).map(&:to_sym).include?(key) })
+ # llm_attr = resource.delete_field(:llm_interaction_attributes) if resource.respond_to?(:llm_interaction_attributes)
existing_resource = find_existing(type, resource)
update = existing_resource
@@ -150,17 +149,13 @@ def write_resources(type, resources, user, provider)
if resource.valid?
resource.save!
@stats[key][update ? :updated : :added] += 1
- if llm_attr
- llm_object = LlmObject.new(llm_attr.to_h)
- if type == Event
- llm_object.event_id = resource.id
- elsif type == Material
- llm_object.material_id = resource.id
- end
- llm_object.save!
- resource.llm_object = llm_object
- resource.save! if resource.valid?
- end
+ # if llm_attr
+ # llm_interaction = LlmInteraction.new(llm_attr.to_h)
+ # llm_interaction.event_id = resource.id if type == Event
+ # llm_interaction.save!
+ # resource.llm_interaction = llm_interaction
+ # resource.save! if resource.valid?
+ # end
else
@stats[key][:rejected] += 1
title = resource.title
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index e1f0b2ebb..b7231c511 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -33,8 +33,8 @@ def get_event_from_css(url, event_page) # rubocop:disable Metrics
event_page.css('script, link').each { |node| node.remove }
event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
llm_service_hash = {
- chatgpt: ChatgptService,
- willma: WillmaService
+ chatgpt: Llm::ChatgptService,
+ willma: Llm::WillmaService
}
llm_service_class = llm_service_hash.fetch(TeSS::Config.llm_scraper['model'].to_sym, nil)
return unless llm_service_class
diff --git a/lib/llm/chatgpt_service.rb b/lib/llm/chatgpt_service.rb
new file mode 100644
index 000000000..88fdc2ff9
--- /dev/null
+++ b/lib/llm/chatgpt_service.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+# Module for LLM based scraping and post processing
+module Llm
+ # ChatGPT based LLM scraping and post processing
+ class ChatgptService < Service
+ require 'openai'
+ def initialize
+ api_key = Rails.application.secrets&.gpt_api_key
+ @client = OpenAI::Client.new(access_token: api_key)
+ @params = {
+ # max_tokens: 50,
+ # model: 'gpt-3.5-turbo-1106',
+ model: TeSS::Config.llm_scraper['model_version'],
+ temperature: 0.7
+ }
+ end
+
+ def run(content)
+ call(content).dig('choices', 0, 'message', 'content')
+ end
+
+ def call(prompt)
+ params = @params.merge(
+ {
+ messages: [{ role: 'user', content: prompt }]
+ }
+ )
+ @client.chat(parameters: params)
+ end
+ end
+end
diff --git a/lib/modules/llm_prompts/llm_process_prompt.txt b/lib/llm/llm_prompts/llm_process_prompt.txt
similarity index 100%
rename from lib/modules/llm_prompts/llm_process_prompt.txt
rename to lib/llm/llm_prompts/llm_process_prompt.txt
diff --git a/lib/modules/llm_prompts/llm_scrape_prompt.txt b/lib/llm/llm_prompts/llm_scrape_prompt.txt
similarity index 100%
rename from lib/modules/llm_prompts/llm_scrape_prompt.txt
rename to lib/llm/llm_prompts/llm_scrape_prompt.txt
diff --git a/lib/llm/llm_service.rb b/lib/llm/llm_service.rb
new file mode 100644
index 000000000..dd4af750f
--- /dev/null
+++ b/lib/llm/llm_service.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+# Module for LLM based scraping and post processing
+module Llm
+ # Base class for LLM scraping and post processing
+ class Service
+ def initialize
+ raise NotImplementedError
+ end
+
+ def llm_interaction_attributes
+ {
+ scrape_or_process: @scrape_or_process,
+ model: @params[:model],
+ prompt: @prompt,
+ input: @input,
+ output: @output,
+ needs_processing: false
+ }
+ end
+
+ def unload_json(event, response)
+ response_json = JSON.parse(response)
+ response_json.each_key do |key|
+ event[key] = response_json[key]
+ end
+ event
+ end
+
+ def scrape(event_page)
+ @scrape_or_process = 'scrape'
+ @prompt = File.read('lib/modules/llm_prompts/llm_scrape_prompt.txt')
+ @input = event_page
+ content = @prompt.gsub('*replace_with_event_page*', event_page)
+ @output = run(content)
+ @output
+ end
+
+ def process(event)
+ @scrape_or_process = 'process'
+ event_json = JSON.generate(event.to_json)
+ @prompt = File.read('lib/modules/llm_prompts/llm_process_prompt.txt')
+ @input = event_json
+ content = @prompt.gsub('*replace_with_event*', event_json)
+ @output = run(content)
+ @output
+ end
+
+ def scrape_func(event, event_page)
+ response = scrape(event_page)
+ event = unload_json(event, response)
+ event.llm_interaction_attributes = llm_interaction_attributes
+ event
+ end
+
+ def post_process_func(event)
+ response = process(event)
+ event = unload_json(event, response)
+ event.llm_interaction_attributes = llm_interaction_attributes
+ event
+ end
+
+ def run(_content)
+ raise NotImplementedError
+ end
+
+ def call(_prompt)
+ raise NotImplementedError
+ end
+ end
+end
diff --git a/lib/llm/willma_service.rb b/lib/llm/willma_service.rb
new file mode 100644
index 000000000..91f262355
--- /dev/null
+++ b/lib/llm/willma_service.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+# Module for LLM based scraping and post processing
+module Llm
+ # Willma based LLM scraping and post processing
+ class WillmaService < Service
+ require 'openai'
+ def initialize
+ model_name = TeSS::Config.llm_scraper['model_version']
+ model_url = 'https://willma.soil.surf.nl/api/models'
+ parsed_response = JSON.parse(do_request(model_url, 'get', {}).body)
+ model_id = parsed_response.select { |i| i['name'] == model_name }.first['id']
+ @params = {
+ model: model_name,
+ sequence_id: model_id,
+ advanced_options: { "max_new_tokens": 4096 },
+ temperature: 0
+ # temperature: 0.7
+ }
+ end
+
+ def run(content)
+ msg = call(content)['message']
+ get_first_json_from_string(msg)
+ end
+
+ def call(prompt)
+ data = {
+ 'sequence_id': @params[:sequence_id],
+ 'input': prompt
+ }
+ query_url = 'https://willma.soil.surf.nl/api/query'
+ response = do_request(query_url, 'post', data)
+ JSON.parse(response.body)
+ end
+ end
+
+ def do_request(url, mode, data = {})
+ header = {
+ 'Content-Type': 'application/json',
+ 'X-API-KEY': Rails.application.secrets&.willma_api_key
+ }
+
+ parsed_url = URI.parse(url)
+ http = Net::HTTP.new(parsed_url.host, parsed_url.port)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ http.read_timeout = 180
+
+ request = case mode
+ when 'post'
+ Net::HTTP::Post.new(parsed_url.path)
+ when 'get'
+ Net::HTTP::Get.new(parsed_url.path)
+ else
+ Net::HTTP::Post.new(parsed_url.path)
+ end
+
+ header.each do |key, value|
+ request[key] = value
+ end
+ request.set_form_data(data)
+ request.body = data.to_json
+ request.content_type = 'application/json'
+ http.request(request)
+ end
+
+ def get_first_json_from_string(msg)
+ char_dict = {}
+ char_dict['{'] = 0
+ char_dict['}'] = 0
+ start_end = [0, 0]
+ res = msg
+ msg.split('').each_with_index do |char, idx|
+ next unless '{}'.include?(char)
+
+ char_dict[char] += 1
+ if char == '{' && char_dict['{'] == 1
+ start_end[0] = idx
+ elsif char == '}' && char_dict['{'] == char_dict['}']
+ start_end[1] = idx
+ res = msg[start_end[0]..start_end[1]]
+ break
+ end
+ end
+ res
+ end
+end
diff --git a/lib/modules/chatgpt_service.rb b/lib/modules/chatgpt_service.rb
deleted file mode 100644
index 8df16fb10..000000000
--- a/lib/modules/chatgpt_service.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-
-class ChatgptService < LlmService
- require 'openai'
- def initialize
- api_key = ENV.fetch('GPT_API_KEY', nil)
- @client = OpenAI::Client.new(access_token: api_key)
- @params = {
- # max_tokens: 50,
- # model: 'gpt-3.5-turbo-1106',
- model: TeSS::Config.llm_scraper['model_version'],
- temperature: 0.7
- }
- end
-
- def run(content)
- call(content).dig('choices', 0, 'message', 'content')
- end
-
- def call(prompt)
- params = @params.merge(
- {
- messages: [{ role: 'user', content: prompt }]
- }
- )
- @client.chat(parameters: params)
- end
-end
diff --git a/lib/modules/llm_service.rb b/lib/modules/llm_service.rb
deleted file mode 100644
index 0923b7d36..000000000
--- a/lib/modules/llm_service.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-
-class LlmService
- def initialize
- puts 'please provide child class'
- end
-
- def llm_object_attributes
- {
- scrape_or_process: @scrape_or_process,
- model: @params[:model],
- prompt: @prompt,
- input: @input,
- output: @output,
- needs_processing: false
- }
- end
-
- def unload_json(event, response)
- response_json = JSON.parse(response)
- response_json.each_key do |key|
- event[key] = response_json[key]
- end
- event
- end
-
- def scrape(event_page)
- @scrape_or_process = 'scrape'
- @prompt = File.read('lib/modules/llm_prompts/llm_scrape_prompt.txt')
- @input = event_page
- content = @prompt.gsub('*replace_with_event_page*', event_page)
- @output = run(content)
- @output
- end
-
- def process(event)
- @scrape_or_process = 'process'
- event_json = JSON.generate(event.to_json)
- @prompt = File.read('lib/modules/llm_prompts/llm_process_prompt.txt')
- @input = event_json
- content = @prompt.gsub('*replace_with_event*', event_json)
- @output = run(content)
- @output
- end
-
- def scrape_func(event, event_page)
- response = scrape(event_page)
- event = unload_json(event, response)
- event.llm_object_attributes = llm_object_attributes
- event
- end
-
- def post_process_func(event)
- response = process(event)
- event = unload_json(event, response)
- event.llm_object_attributes = llm_object_attributes
- event
- end
-
- def run(_content)
- puts 'please provide child class'
- end
-
- def call(_prompt)
- puts 'please provide child class'
- end
-
- class << self
- def call(message)
- new.call(message)
- end
-
- def scrape # rubocop:disable Metrics
- url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
- require 'open-uri'
- event_page = URI(url).open(&:read)
- doc = Nokogiri::HTML5.parse(event_page).css('body').css("div[id='nieuws_detail_row']")
- doc.css('script, link').each { |node| node.remove }
- event_page = doc.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
- response = new.scrape(event_page)
- JSON.parse(response)
- end
-
- def process
- event_json = scrape
- event = Event.new(event_json)
- response = new.process(event)
- JSON.parse(response)
- end
- end
-end
diff --git a/lib/modules/willma_service.rb b/lib/modules/willma_service.rb
deleted file mode 100644
index e5d752f2d..000000000
--- a/lib/modules/willma_service.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-# frozen_string_literal: true
-
-class WillmaService < LlmService
- require 'openai'
- def initialize
- model_name = TeSS::Config.llm_scraper['model_version']
- model_url = 'https://willma.soil.surf.nl/api/models'
- parsed_response = JSON.parse(do_request(model_url, 'get', {}).body)
- model_id = parsed_response.select { |i| i['name'] == model_name }.first['id']
- @params = {
- model: model_name,
- sequence_id: model_id,
- advanced_options: { "max_new_tokens": 4096 },
- temperature: 0
- # temperature: 0.7
- }
- end
-
- def run(content)
- msg = call(content)['message']
- res = get_first_json_from_string(msg)
- res
- end
-
- def call(prompt)
- data = {
- 'sequence_id': @params[:sequence_id],
- 'input': prompt
- }
- query_url = 'https://willma.soil.surf.nl/api/query'
- response = do_request(query_url, 'post', data)
- JSON.parse(response.body)
- end
-end
-
-def do_request(url, mode, data = {})
- header = {
- 'Content-Type': 'application/json',
- 'X-API-KEY': ENV.fetch('WILLMA_API_KEY', nil)
- }
-
- parsed_url = URI.parse(url)
- http = Net::HTTP.new(parsed_url.host, parsed_url.port)
- http.use_ssl = true
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
- http.read_timeout = 180
-
- request = case mode
- when 'post'
- Net::HTTP::Post.new(parsed_url.path)
- when 'get'
- Net::HTTP::Get.new(parsed_url.path)
- else
- Net::HTTP::Post.new(parsed_url.path)
- end
-
- header.each do |key, value|
- request[key] = value
- end
- request.set_form_data(data)
- request.body = data.to_json
- request.content_type = 'application/json'
- http.request(request)
-end
-
-def get_first_json_from_string(msg)
- char_dict = {}
- char_dict['{'] = 0
- char_dict['}'] = 0
- start_end = [0, 0]
- res = msg
- msg.split('').each_with_index do |char, idx|
- next unless '{}'.include?(char)
-
- char_dict[char] += 1
- if char == '{' && char_dict['{'] == 1
- start_end[0] = idx
- elsif char == '}' && char_dict['{'] == char_dict['}']
- start_end[1] = idx
- res = msg[start_end[0]..start_end[1]]
- break
- end
- end
- res
-end
diff --git a/lib/tasks/tess.rake b/lib/tasks/tess.rake
index 4d4c65526..1e7b3663a 100644
--- a/lib/tasks/tess.rake
+++ b/lib/tasks/tess.rake
@@ -141,22 +141,30 @@ namespace :tess do
desc 'run LLM post processing'
task llm_post_processing: :environment do
+ llm_service_hash = {
+ chatgpt: Llm::ChatgptService,
+ willma: Llm::WillmaService
+ }
+ llm_service_class = llm_service_hash.fetch(TeSS::Config.llm_scraper['model'].to_sym, nil)
+ return unless llm_service_class
+
prompt = File.read('llm_process_prompt.txt')
Events.each do |event|
- needs_processing = event&.llm_object&.needs_processing
- new_prompt = event&.llm_object&.prompt == prompt
+ needs_processing = event&.llm_interaction&.needs_processing
+ new_prompt = event&.llm_interaction&.prompt == prompt
future_event = event.end > Time.zone.now
- unless (needs_processing || new_prompt) && future_event
- event = GptIngestor.new.post_process_func(event)
- event.save!
- end
+ next if (needs_processing || new_prompt) && future_event
+
+ llm_service = llm_service_class.new
+ event = llm_service.post_process_func(event)
+ event.save!
end
end
desc 'open all events to being llm processed again'
task reset_llm_status: :environment do
Events.where { |event| event.end > Time.zone.now }.each do |event|
- event&.llm_object&.needs_processing = true
+ event&.llm_interaction&.needs_processing = true
event.save!
end
end
diff --git a/test/models/event_test.rb b/test/models/event_test.rb
index f04d08a84..536c65870 100644
--- a/test/models/event_test.rb
+++ b/test/models/event_test.rb
@@ -495,13 +495,13 @@ class EventTest < ActiveSupport::TestCase
event = Event.new(
title: 'An event',
timezone: 'UTC',
- user: user,
+ user:,
url: 'https://events.com/1',
keywords: ['fun times'],
nodes: [node],
external_resources_attributes: { '0' => { title: 'test', url: 'https://external-resource.com' } },
materials: [material],
- scientific_topic_names: ['Proteins', 'DNA'],
+ scientific_topic_names: %w[Proteins DNA],
operation_names: ['Variant calling']
)
@@ -524,7 +524,7 @@ class EventTest < ActiveSupport::TestCase
assert_nil dup.url
assert_equal [material], dup.materials
assert_equal [node], dup.nodes
- assert_equal ['Proteins', 'DNA'], dup.scientific_topic_names
+ assert_equal %w[Proteins DNA], dup.scientific_topic_names
assert_equal ['Variant calling'], dup.operation_names
assert_equal 1, dup.external_resources.length
assert_equal 'test', dup.external_resources.first.title
@@ -672,21 +672,21 @@ class EventTest < ActiveSupport::TestCase
'Protein fold prediction', 'Protein fold recognition'], @event.reload.operations_and_synonyms
end
- test 'can add an llm_object to an event' do
+ test 'can add an llm_interaction to an event' do
e = events(:scraper_user_event)
- l = llm_objects(:scrape)
- e.llm_object = l
+ l = llm_interactions(:scrape)
+ e.llm_interaction = l
e.save!
- assert_equal e.llm_object.id, l.id
+ assert_equal e.llm_interaction.id, l.id
assert_equal l.event_id, e.id
end
- test 'can destroy an llm_object with an event' do
+ test 'can destroy an llm_interaction with an event' do
e = events(:scraper_user_event)
- l = llm_objects(:scrape)
- e.llm_object = l
+ l = llm_interactions(:scrape)
+ e.llm_interaction = l
e.save!
- assert_difference 'LlmObject.count', -1 do
+ assert_difference 'LlmInteraction.count', -1 do
e.destroy!
end
end
From 79047ab63761cedbc1314cddff21e267ce10ba8b Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Wed, 19 Jun 2024 10:00:16 +0200
Subject: [PATCH 29/37] rescue standarderror instead of exception
---
lib/ingestors/llm_ingestor.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index b7231c511..a603ff385 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -15,7 +15,7 @@ def self.config
def read(url)
begin
process_llm(url)
- rescue Exception => e
+ rescue StandardError => e
@messages << "#{self.class.name} failed with: #{e.message}"
end
@@ -55,7 +55,7 @@ def get_event_from_css(url, event_page) # rubocop:disable Metrics
event.nonsense_attr = 'nonsense'
event = OpenStruct.new(event.to_h.select { |key, _| (Event.attribute_names + [:online]).map(&:to_sym).include?(key) })
add_event(event)
- rescue Exception => e
+ rescue StandardError => e
puts e
@messages << "Extract event fields failed with: #{e.message}"
end
From d99575deca037d9142543369946483ca54c3abb8 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Thu, 20 Jun 2024 16:57:10 +0200
Subject: [PATCH 30/37] fix schema and reload llm module
---
config/application.rb | 1 +
db/schema.rb | 10 ++++++----
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/config/application.rb b/config/application.rb
index a172940d8..1ede76e30 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -10,6 +10,7 @@ module TeSS
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
+ config.autoload_paths << Rails.root.join('lib/llm')
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
diff --git a/db/schema.rb b/db/schema.rb
index 6538d677a..aab36f20a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -227,8 +227,10 @@
t.string "cost_basis"
t.string "cost_currency"
t.string "fields", default: [], array: true
+ t.bigint "llm_interaction_id"
t.string "open_science", default: [], array: true
t.boolean "visible", default: true
+ t.index ["llm_interaction_id"], name: "index_events_on_llm_interaction_id"
t.index ["presence"], name: "index_events_on_presence"
t.index ["slug"], name: "index_events_on_slug", unique: true
t.index ["user_id"], name: "index_events_on_user_id"
@@ -331,7 +333,7 @@
t.index ["lcheck_type", "lcheck_id"], name: "index_link_monitors_on_lcheck_type_and_lcheck_id"
end
- create_table "llm_objects", force: :cascade do |t|
+ create_table "llm_interactions", force: :cascade do |t|
t.bigint "event_id"
t.datetime "created_at"
t.datetime "updated_at"
@@ -341,7 +343,7 @@
t.string "input"
t.string "output"
t.boolean "needs_processing", default: false
- t.index ["event_id"], name: "index_llm_objects_on_event_id"
+ t.index ["event_id"], name: "index_llm_interactions_on_event_id"
end
create_table "materials", id: :serial, force: :cascade do |t|
@@ -377,7 +379,6 @@
t.text "contact"
t.text "learning_objectives"
t.string "fields", default: [], array: true
- t.boolean "llm_processed", default: false
t.index ["content_provider_id"], name: "index_materials_on_content_provider_id"
t.index ["slug"], name: "index_materials_on_slug", unique: true
t.index ["user_id"], name: "index_materials_on_user_id"
@@ -616,11 +617,12 @@
add_foreign_key "content_providers", "users"
add_foreign_key "event_materials", "events"
add_foreign_key "event_materials", "materials"
+ add_foreign_key "events", "llm_interactions"
add_foreign_key "events", "users"
add_foreign_key "learning_path_topic_links", "learning_paths"
add_foreign_key "learning_paths", "content_providers"
add_foreign_key "learning_paths", "users"
- add_foreign_key "llm_objects", "events"
+ add_foreign_key "llm_interactions", "events"
add_foreign_key "materials", "content_providers"
add_foreign_key "materials", "users"
add_foreign_key "node_links", "nodes"
From b381ffd09a3fc630618fb3fd379f3e2c2e6c327d Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 21 Jun 2024 10:43:17 +0200
Subject: [PATCH 31/37] changed llm_objects fixture file name to
llm_interactions
---
test/fixtures/{llm_objects.yml => llm_interactions.yml} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename test/fixtures/{llm_objects.yml => llm_interactions.yml} (100%)
diff --git a/test/fixtures/llm_objects.yml b/test/fixtures/llm_interactions.yml
similarity index 100%
rename from test/fixtures/llm_objects.yml
rename to test/fixtures/llm_interactions.yml
From 096100fd486cf4100f3d205c956961df65651857 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 21 Jun 2024 13:46:19 +0200
Subject: [PATCH 32/37] fix broken tests
---
config/application.rb | 1 -
lib/ingestors/fourtu_llm_ingestor.rb | 35 -----------
lib/ingestors/ingestor.rb | 8 ---
lib/ingestors/llm_ingestor.rb | 2 +
lib/llm/{llm_service.rb => service.rb} | 4 +-
lib/llm/willma_service.rb | 84 +++++++++++++-------------
6 files changed, 46 insertions(+), 88 deletions(-)
rename lib/llm/{llm_service.rb => service.rb} (91%)
diff --git a/config/application.rb b/config/application.rb
index 1ede76e30..a172940d8 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -10,7 +10,6 @@ module TeSS
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.0
- config.autoload_paths << Rails.root.join('lib/llm')
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
diff --git a/lib/ingestors/fourtu_llm_ingestor.rb b/lib/ingestors/fourtu_llm_ingestor.rb
index 38b12aec8..a1e4dca44 100644
--- a/lib/ingestors/fourtu_llm_ingestor.rb
+++ b/lib/ingestors/fourtu_llm_ingestor.rb
@@ -24,40 +24,5 @@ def process_llm(_url)
get_event_from_css(new_url, new_event_page)
end
end
- # def process_llm(_url) # rubocop:disable Metrics
- # url = 'https://www.rug.nl/wubbo-ockels-school/calendar/2024/'
- # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
- # event_page.each do |event_data|
- # new_url = event_data.css("meta[itemprop='url']")[0].get_attribute('content')
- # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- # new_event_page = Nokogiri::HTML5.parse(open_url(new_url.to_s, raise: true)).css('body').css("div[id='main']")[0].css("div[itemtype='https://schema.org/Event']")
- # get_event_from_css(new_url, new_event_page)
- # end
- # end
- # def process_llm(_url) # rubocop:disable Metrics
- # url = 'https://www.nwo.nl/en/meetings'
- # 4.times.each do |i| # always check the first 4 pages, # of pages could be increased if needed
- # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- # event_page = Nokogiri::HTML5.parse(open_url("#{url}?page=#{i}", raise: true)).css('.overviewContent')[0].css('li.list-item').css('a')
- # event_page.each do |event_data|
- # new_url = "https://www.nwo.nl#{event_data['href']}"
- # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- # new_event_page = Nokogiri::HTML5.parse(open_url(new_url, raise: true)).css('body').css('main')[0].css('article')
- # get_event_from_css(new_url, new_event_page)
- # end
- # end
- # end
- # def process_llm(_url)
- # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- # url = 'https://tdcc.nl/evenementen/teaming-up-across-domains/'
- # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css('article')[0]
- # get_event_from_css(url, event_page)
- # end
- # def process_llm(_url)
- # sleep(1) unless Rails.env.test? and File.exist?('test/vcr_cassettes/ingestors/llm.yml')
- # url = 'https://dans.knaw.nl/en/agenda/open-hour-ssh-live-qa-on-monday-2/'
- # event_page = Nokogiri::HTML5.parse(open_url(url.to_s, raise: true)).css('body').css("div[id='nieuws_detail_row']")
- # get_event_from_css(url, event_page)
- # end
end
end
diff --git a/lib/ingestors/ingestor.rb b/lib/ingestors/ingestor.rb
index 2a774c168..5cf4d7554 100644
--- a/lib/ingestors/ingestor.rb
+++ b/lib/ingestors/ingestor.rb
@@ -135,7 +135,6 @@ def write_resources(type, resources, user, provider)
# check for matched events
resource.user_id ||= user.id
resource.content_provider_id ||= provider.id
- # llm_attr = resource.delete_field(:llm_interaction_attributes) if resource.respond_to?(:llm_interaction_attributes)
existing_resource = find_existing(type, resource)
update = existing_resource
@@ -149,13 +148,6 @@ def write_resources(type, resources, user, provider)
if resource.valid?
resource.save!
@stats[key][update ? :updated : :added] += 1
- # if llm_attr
- # llm_interaction = LlmInteraction.new(llm_attr.to_h)
- # llm_interaction.event_id = resource.id if type == Event
- # llm_interaction.save!
- # resource.llm_interaction = llm_interaction
- # resource.save! if resource.valid?
- # end
else
@stats[key][:rejected] += 1
title = resource.title
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index a603ff385..4b6201828 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -25,6 +25,8 @@ def read(url)
private
+ include Llm
+
def process_llm(_url)
puts 'please provide child class'
end
diff --git a/lib/llm/llm_service.rb b/lib/llm/service.rb
similarity index 91%
rename from lib/llm/llm_service.rb
rename to lib/llm/service.rb
index dd4af750f..05cf8f4bb 100644
--- a/lib/llm/llm_service.rb
+++ b/lib/llm/service.rb
@@ -29,7 +29,7 @@ def unload_json(event, response)
def scrape(event_page)
@scrape_or_process = 'scrape'
- @prompt = File.read('lib/modules/llm_prompts/llm_scrape_prompt.txt')
+ @prompt = File.read('lib/llm/llm_prompts/llm_scrape_prompt.txt')
@input = event_page
content = @prompt.gsub('*replace_with_event_page*', event_page)
@output = run(content)
@@ -39,7 +39,7 @@ def scrape(event_page)
def process(event)
@scrape_or_process = 'process'
event_json = JSON.generate(event.to_json)
- @prompt = File.read('lib/modules/llm_prompts/llm_process_prompt.txt')
+ @prompt = File.read('lib/llm/llm_prompts/llm_process_prompt.txt')
@input = event_json
content = @prompt.gsub('*replace_with_event*', event_json)
@output = run(content)
diff --git a/lib/llm/willma_service.rb b/lib/llm/willma_service.rb
index 91f262355..9334ed452 100644
--- a/lib/llm/willma_service.rb
+++ b/lib/llm/willma_service.rb
@@ -33,56 +33,56 @@ def call(prompt)
response = do_request(query_url, 'post', data)
JSON.parse(response.body)
end
- end
- def do_request(url, mode, data = {})
- header = {
- 'Content-Type': 'application/json',
- 'X-API-KEY': Rails.application.secrets&.willma_api_key
- }
+ def do_request(url, mode, data = {})
+ header = {
+ 'Content-Type': 'application/json',
+ 'X-API-KEY': Rails.application.secrets&.willma_api_key
+ }
- parsed_url = URI.parse(url)
- http = Net::HTTP.new(parsed_url.host, parsed_url.port)
- http.use_ssl = true
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
- http.read_timeout = 180
+ parsed_url = URI.parse(url)
+ http = Net::HTTP.new(parsed_url.host, parsed_url.port)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ http.read_timeout = 180
- request = case mode
- when 'post'
- Net::HTTP::Post.new(parsed_url.path)
- when 'get'
- Net::HTTP::Get.new(parsed_url.path)
- else
- Net::HTTP::Post.new(parsed_url.path)
- end
+ request = case mode
+ when 'post'
+ Net::HTTP::Post.new(parsed_url.path)
+ when 'get'
+ Net::HTTP::Get.new(parsed_url.path)
+ else
+ Net::HTTP::Post.new(parsed_url.path)
+ end
- header.each do |key, value|
- request[key] = value
+ header.each do |key, value|
+ request[key] = value
+ end
+ request.set_form_data(data)
+ request.body = data.to_json
+ request.content_type = 'application/json'
+ http.request(request)
end
- request.set_form_data(data)
- request.body = data.to_json
- request.content_type = 'application/json'
- http.request(request)
- end
- def get_first_json_from_string(msg)
- char_dict = {}
- char_dict['{'] = 0
- char_dict['}'] = 0
- start_end = [0, 0]
- res = msg
- msg.split('').each_with_index do |char, idx|
- next unless '{}'.include?(char)
+ def get_first_json_from_string(msg)
+ char_dict = {}
+ char_dict['{'] = 0
+ char_dict['}'] = 0
+ start_end = [0, 0]
+ res = msg
+ msg.split('').each_with_index do |char, idx|
+ next unless '{}'.include?(char)
- char_dict[char] += 1
- if char == '{' && char_dict['{'] == 1
- start_end[0] = idx
- elsif char == '}' && char_dict['{'] == char_dict['}']
- start_end[1] = idx
- res = msg[start_end[0]..start_end[1]]
- break
+ char_dict[char] += 1
+ if char == '{' && char_dict['{'] == 1
+ start_end[0] = idx
+ elsif char == '}' && char_dict['{'] == char_dict['}']
+ start_end[1] = idx
+ res = msg[start_end[0]..start_end[1]]
+ break
+ end
end
+ res
end
- res
end
end
From 12725f4f45c75d37bd3332bc8a7253fb730ddb33 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Thu, 11 Jul 2024 17:33:40 +0200
Subject: [PATCH 33/37] test cases for llm module
---
app/models/event.rb | 7 +-
.../events_require_approval.html.erb | 3 +
config/schedule.rb | 26 ++---
lib/ingestors/llm_ingestor.rb | 10 +-
lib/llm.rb | 34 +++++++
lib/llm/service.rb | 4 +-
lib/llm/willma_service.rb | 2 +-
lib/tasks/tess.rake | 24 +----
test/fixtures/llm_interactions.yml | 14 +++
test/test_helper.rb | 81 +++++++--------
.../ingestors/4tu_willma_llm_ingestor_test.rb | 6 +-
test/unit/llm_service_test.rb | 99 +++++++++++++++++++
12 files changed, 222 insertions(+), 88 deletions(-)
create mode 100644 lib/llm.rb
create mode 100644 test/unit/llm_service_test.rb
diff --git a/app/models/event.rb b/app/models/event.rb
index 264d50b0c..7c8cc202f 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -286,13 +286,18 @@ def self.disabled
end
def self.not_finished
- where('events.end > ? OR events.end IS NULL', Time.now)
+ where('events.end >= ?', Time.now).where.not(end: nil)
end
def self.finished
where('events.end < ?', Time.now).where.not(end: nil)
end
+ def self.needs_processing(llm_prompt)
+ joins('LEFT OUTER JOIN llm_interactions ON llm_interactions.event_id = events.id')
+ .where('llm_interactions.needs_processing = ? OR llm_interactions.prompt != ?', true, llm_prompt)
+ end
+
# Ticket #423
def check_country_name
if country and country.respond_to?(:parameterize)
diff --git a/app/views/curation_mailer/events_require_approval.html.erb b/app/views/curation_mailer/events_require_approval.html.erb
index 11287c730..d069969e2 100644
--- a/app/views/curation_mailer/events_require_approval.html.erb
+++ b/app/views/curation_mailer/events_require_approval.html.erb
@@ -16,6 +16,9 @@
end: <%= event.end %>
venue: <%= event.venue %>
show: <%= event.visible %>
+ keywords: <%= event.keywords %>
+ audience: <%= event.audience %>
+ open_science: <%= event.open_science %>
<% end %>
diff --git a/config/schedule.rb b/config/schedule.rb
index cfbebca85..585419d5b 100644
--- a/config/schedule.rb
+++ b/config/schedule.rb
@@ -7,7 +7,7 @@
require 'yaml'
begin
schedules = YAML.load_file("#{path}/config/schedule.yml")
-rescue Exception => exception
+rescue Exception => e
# ignore failure
ensure
# set to empty hash if not exists
@@ -17,58 +17,60 @@
# Generate a new sitemap...
every schedules.dig('sitemap', 'every')&.to_sym || :day,
at: schedules.dig('sitemap', 'at') || '1am' do
- rake "sitemap:refresh"
+ rake 'sitemap:refresh'
end
# Process subscriptions...
if !schedules['subscriptions'].nil?
every :"#{schedules['subscriptions']['every']}", at: "#{schedules['subscriptions']['at']}" do
- rake "tess:process_subscriptions"
+ rake 'tess:process_subscriptions'
end
else
every :day, at: '2am' do
- rake "tess:process_subscriptions"
+ rake 'tess:process_subscriptions'
end
end
# Process ingestions
if !schedules['ingestions'].nil?
every :"#{schedules['ingestions']['every']}", at: "#{schedules['ingestions']['at']}" do
- rake "tess:automated_ingestion"
+ rake 'tess:automated_ingestion'
+ rake 'tess:llm_post_processing' if TeSS::Config.llm_scraper['model_version'].present?
end
else
every :day, at: '3am' do
- rake "tess:automated_ingestion"
+ rake 'tess:automated_ingestion'
+ rake 'tess:llm_post_processing' if TeSS::Config.llm_scraper['model_version'].present?
end
end
# Curation mail
if !schedules['curation_mail'].nil?
every :"#{schedules['curation_mail']['every']}", at: "#{schedules['curation_mail']['at']}" do
- rake "tess:event_curation_mails"
+ rake 'tess:event_curation_mails'
end
else
every :monday, at: '9am' do
- rake "tess:event_curation_mails"
+ rake 'tess:event_curation_mails'
end
end
if !schedules['autocomplete_suggestions'].nil?
every :"#{schedules['autocomplete_suggestions']['every']}", at: "#{schedules['autocomplete_suggestions']['at']}" do
- rake "tess:rebuild_autocomplete_suggestions"
+ rake 'tess:rebuild_autocomplete_suggestions'
end
else
every :tuesday, at: '5am' do
- rake "tess:rebuild_autocomplete_suggestions"
+ rake 'tess:rebuild_autocomplete_suggestions'
end
end
if !schedules['dead_link_check'].nil?
every :"#{schedules['dead_link_check']['every']}", at: "#{schedules['dead_link_check']['at']}" do
- rake "tess:check_resource_urls"
+ rake 'tess:check_resource_urls'
end
else
every :day, at: '6am' do
- rake "tess:check_resource_urls"
+ rake 'tess:check_resource_urls'
end
end
diff --git a/lib/ingestors/llm_ingestor.rb b/lib/ingestors/llm_ingestor.rb
index 4b6201828..5f7ebaae5 100644
--- a/lib/ingestors/llm_ingestor.rb
+++ b/lib/ingestors/llm_ingestor.rb
@@ -32,15 +32,11 @@ def process_llm(_url)
end
def get_event_from_css(url, event_page) # rubocop:disable Metrics
- event_page.css('script, link').each { |node| node.remove }
- event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
- llm_service_hash = {
- chatgpt: Llm::ChatgptService,
- willma: Llm::WillmaService
- }
- llm_service_class = llm_service_hash.fetch(TeSS::Config.llm_scraper['model'].to_sym, nil)
+ llm_service_class = Llm.service_hash.fetch(TeSS::Config.llm_scraper['model'].to_sym, nil)
return unless llm_service_class
+ event_page.css('script, link').each { |node| node.remove }
+ event_page = event_page.text.squeeze(" \n").squeeze("\n").squeeze("\t").squeeze(' ')
begin
llm_service = llm_service_class.new
event = OpenStruct.new
diff --git a/lib/llm.rb b/lib/llm.rb
new file mode 100644
index 000000000..260cf47bb
--- /dev/null
+++ b/lib/llm.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+# Module for LLM based scraping and post processing
+module Llm
+ def self.service_hash
+ {
+ chatgpt: Llm::ChatgptService,
+ willma: Llm::WillmaService
+ }
+ end
+
+ def self.post_processing_task
+ llm_service_class = Llm.service_hash.fetch(TeSS::Config.llm_scraper['model']&.to_sym, nil)
+ return unless llm_service_class
+
+ prompt = File.read(File.join(Rails.root, 'lib', 'llm', 'llm_prompts', 'llm_process_prompt.txt'))
+ filtered_event_list(prompt).each do |event|
+ llm_service = llm_service_class.new
+ event = llm_service.post_process_func(event)
+ event.save!
+ end
+ end
+
+ def self.filtered_event_list(prompt)
+ Event.not_finished.needs_processing(prompt)
+ end
+
+ def self.reset_llm_status_task
+ Event.not_finished.each do |event|
+ event&.llm_interaction&.needs_processing = true
+ event.save!
+ end
+ end
+end
diff --git a/lib/llm/service.rb b/lib/llm/service.rb
index 05cf8f4bb..ed8f52793 100644
--- a/lib/llm/service.rb
+++ b/lib/llm/service.rb
@@ -29,7 +29,7 @@ def unload_json(event, response)
def scrape(event_page)
@scrape_or_process = 'scrape'
- @prompt = File.read('lib/llm/llm_prompts/llm_scrape_prompt.txt')
+ @prompt = File.read(File.join(Rails.root, 'lib', 'llm', 'llm_prompts', 'llm_scrape_prompt.txt'))
@input = event_page
content = @prompt.gsub('*replace_with_event_page*', event_page)
@output = run(content)
@@ -39,7 +39,7 @@ def scrape(event_page)
def process(event)
@scrape_or_process = 'process'
event_json = JSON.generate(event.to_json)
- @prompt = File.read('lib/llm/llm_prompts/llm_process_prompt.txt')
+ @prompt = File.read(File.join(Rails.root, 'lib', 'llm', 'llm_prompts', 'llm_process_prompt.txt'))
@input = event_json
content = @prompt.gsub('*replace_with_event*', event_json)
@output = run(content)
diff --git a/lib/llm/willma_service.rb b/lib/llm/willma_service.rb
index 9334ed452..02b6c30c3 100644
--- a/lib/llm/willma_service.rb
+++ b/lib/llm/willma_service.rb
@@ -9,7 +9,7 @@ def initialize
model_name = TeSS::Config.llm_scraper['model_version']
model_url = 'https://willma.soil.surf.nl/api/models'
parsed_response = JSON.parse(do_request(model_url, 'get', {}).body)
- model_id = parsed_response.select { |i| i['name'] == model_name }.first['id']
+ model_id = parsed_response.values.select { |i| i['name'] == model_name }.first['id']
@params = {
model: model_name,
sequence_id: model_id,
diff --git a/lib/tasks/tess.rake b/lib/tasks/tess.rake
index 1e7b3663a..a4d88fbbf 100644
--- a/lib/tasks/tess.rake
+++ b/lib/tasks/tess.rake
@@ -141,32 +141,12 @@ namespace :tess do
desc 'run LLM post processing'
task llm_post_processing: :environment do
- llm_service_hash = {
- chatgpt: Llm::ChatgptService,
- willma: Llm::WillmaService
- }
- llm_service_class = llm_service_hash.fetch(TeSS::Config.llm_scraper['model'].to_sym, nil)
- return unless llm_service_class
-
- prompt = File.read('llm_process_prompt.txt')
- Events.each do |event|
- needs_processing = event&.llm_interaction&.needs_processing
- new_prompt = event&.llm_interaction&.prompt == prompt
- future_event = event.end > Time.zone.now
- next if (needs_processing || new_prompt) && future_event
-
- llm_service = llm_service_class.new
- event = llm_service.post_process_func(event)
- event.save!
- end
+ Llm.post_processing_task
end
desc 'open all events to being llm processed again'
task reset_llm_status: :environment do
- Events.where { |event| event.end > Time.zone.now }.each do |event|
- event&.llm_interaction&.needs_processing = true
- event.save!
- end
+ Llm.reset_llm_status_task
end
desc 'mail content providers for curation of scraped events'
diff --git a/test/fixtures/llm_interactions.yml b/test/fixtures/llm_interactions.yml
index 646b60b0c..532759293 100644
--- a/test/fixtures/llm_interactions.yml
+++ b/test/fixtures/llm_interactions.yml
@@ -7,3 +7,17 @@ scrape:
input: 'Give JSON please'
output: 'Give JSON please'
needs_processing: false
+different_prompt:
+ scrape_or_process: 'scrape'
+ model: 'Zephyr 7B'
+ prompt: 'different_prompt'
+ input: 'Give JSON please'
+ output: 'Give JSON please'
+ needs_processing: false
+needs_processing:
+ scrape_or_process: 'scrape'
+ model: 'Zephyr 7B'
+ prompt: 'Give JSON please'
+ input: 'Give JSON please'
+ output: 'Give JSON please'
+ needs_processing: true
\ No newline at end of file
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 8f4ff49a1..2740f41b4 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -5,9 +5,9 @@
SimpleCov::Formatter::LcovFormatter.config.report_with_single_file = true
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new([
- SimpleCov::Formatter::HTMLFormatter,
- SimpleCov::Formatter::LcovFormatter
-])
+ SimpleCov::Formatter::HTMLFormatter,
+ SimpleCov::Formatter::LcovFormatter
+ ])
SimpleCov.start do
add_filter '.gems'
@@ -17,7 +17,7 @@
end
ENV['RAILS_ENV'] ||= 'test'
-require File.expand_path('../../config/environment', __FILE__)
+require File.expand_path('../config/environment', __dir__)
require 'rails/test_help'
require 'webmock/minitest'
require 'minitest/mock'
@@ -26,8 +26,11 @@
require_relative './schema_helper'
WebMock.disable_net_connect!(allow_localhost: true, allow: 'api.codacy.com')
-Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(
- fast_fail: true, color: true, detailed_skip: false, slow_count: 10)] unless ENV['RM_INFO']
+unless ENV['RM_INFO']
+ Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(
+ fast_fail: true, color: true, detailed_skip: false, slow_count: 10
+ )]
+end
VCR.configure do |config|
config.cassette_library_dir = 'test/vcr_cassettes'
@@ -60,11 +63,11 @@ def with_settings(settings, overwrite = false, &block)
orig_config = {}
settings.each do |k, v|
orig_config[k] = TeSS::Config[k]
- if !overwrite && TeSS::Config[k].is_a?(Hash) && v.is_a?(Hash)
- TeSS::Config[k] = v.with_indifferent_access.reverse_merge!(TeSS::Config[k])
- else
- TeSS::Config[k] = v
- end
+ TeSS::Config[k] = if !overwrite && TeSS::Config[k].is_a?(Hash) && v.is_a?(Hash)
+ v.with_indifferent_access.reverse_merge!(TeSS::Config[k])
+ else
+ v
+ end
end
block.call
ensure
@@ -144,34 +147,33 @@ def freeze_time(time_or_year = Time.now, &block)
# Mock remote images so paperclip doesn't break:
def mock_images
- WebMock.stub_request(:any, /http\:\/\/example\.com\/(.+)\.png/).to_return(
+ WebMock.stub_request(:any, %r{http://example\.com/(.+)\.png}).to_return(
status: 200, body: File.read(File.join(Rails.root, 'test/fixtures/files/image.png')),
headers: { content_type: 'image/png' }
)
- WebMock.stub_request(:any, "http://image.host/another_image.png").to_return(
+ WebMock.stub_request(:any, 'http://image.host/another_image.png').to_return(
status: 200, body: File.read(File.join(Rails.root, 'test/fixtures/files/another_image.png')),
headers: { content_type: 'image/png' }
)
- WebMock.stub_request(:any, "http://malicious.host/image.png").to_return(
+ WebMock.stub_request(:any, 'http://malicious.host/image.png').to_return(
status: 200, body: File.read(File.join(Rails.root, 'test/fixtures/files/bad.js')), headers: { content_type: 'image/png' }
)
- WebMock.stub_request(:any, "http://text.host/text.txt").to_return(
+ WebMock.stub_request(:any, 'http://text.host/text.txt').to_return(
status: 200, body: File.read(File.join(Rails.root, 'test/fixtures/files/text.txt')), headers: { content_type: 'text/plain' }
)
- WebMock.stub_request(:any, "http://404.host/image.png").to_return(status: 404)
+ WebMock.stub_request(:any, 'http://404.host/image.png').to_return(status: 404)
- WebMock.stub_request(:get, "https://bio.tools/api/tool?q=Training%20Material%20Example").
- with(:headers => { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => 'Ruby' }).
- to_return(:status => 200, :body => "", :headers => {})
-
- WebMock.stub_request(:get, "https://bio.tools/api/tool?q=Material%20with%20suggestions").
- with(:headers => { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => 'Ruby' }).
- to_return(:status => 200, :body => "", :headers => {})
+ WebMock.stub_request(:get, 'https://bio.tools/api/tool?q=Training%20Material%20Example')
+ .with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => 'Ruby' })
+ .to_return(status: 200, body: '', headers: {})
+ WebMock.stub_request(:get, 'https://bio.tools/api/tool?q=Material%20with%20suggestions')
+ .with(headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => 'Ruby' })
+ .to_return(status: 200, body: '', headers: {})
end
def mock_orcids
@@ -223,7 +225,7 @@ def mock_ingestions
{ url: 'https://www.eventbriteapi.com/v3/organizations/34338661734', status: 404 }].each do |opts|
url = opts.delete(:url)
method = opts.delete(:method) || :get
- opts[:body] = File.open(Rails.root.join( 'test', 'fixtures', 'files', 'ingestion', opts.delete(:filename))) if opts.key?(:filename)
+ opts[:body] = File.open(Rails.root.join('test', 'fixtures', 'files', 'ingestion', opts.delete(:filename))) if opts.key?(:filename)
opts[:status] ||= 200
opts[:headers] ||= {}
@@ -233,22 +235,22 @@ def mock_ingestions
def mock_biotools
biotools_file = File.read("#{Rails.root}/test/fixtures/files/annotation.json")
- WebMock.stub_request(:get, /data.bioontology.org/).
- to_return(:status => 200, :headers => {}, :body => biotools_file)
+ WebMock.stub_request(:get, /data.bioontology.org/)
+ .to_return(status: 200, headers: {}, body: biotools_file)
end
def mock_nominatim
- nominatim_file = File.read(File.join(Rails.root, ['test', 'fixtures','files', 'nominatim.json'] ))
- kensington_file = File.read(File.join(Rails.root,['test', 'fixtures', 'files', 'geocode_kensington.json'] ))
+ nominatim_file = File.read(File.join(Rails.root, ['test', 'fixtures', 'files', 'nominatim.json']))
+ kensington_file = File.read(File.join(Rails.root, ['test', 'fixtures', 'files', 'geocode_kensington.json']))
- WebMock.stub_request(:get, /nominatim.openstreetmap.org/).
- to_return(:status => 200, :headers => {}, :body => nominatim_file)
+ WebMock.stub_request(:get, /nominatim.openstreetmap.org/)
+ .to_return(status: 200, headers: {}, body: nominatim_file)
# geocoder overrides
Geocoder.configure(lookup: :test, ip_lookup: :test)
- Geocoder::Lookup::Test.add_stub( "1 Bryce Avenue, Kensington, Western Australia, 6151, Australia", JSON.parse(kensington_file) )
- Geocoder::Lookup::Test.add_stub( "Pawsey Supercomputing Centre, 1 Bryce Avenue, Kensington, Western Australia, 6151, Australia", [] )
- Geocoder::Lookup::Test.add_stub( "Australia", [{ "address"=>{ "country"=>"Australia", "country_code"=>"au"} }] )
+ Geocoder::Lookup::Test.add_stub('1 Bryce Avenue, Kensington, Western Australia, 6151, Australia', JSON.parse(kensington_file))
+ Geocoder::Lookup::Test.add_stub('Pawsey Supercomputing Centre, 1 Bryce Avenue, Kensington, Western Australia, 6151, Australia', [])
+ Geocoder::Lookup::Test.add_stub('Australia', [{ 'address' => { 'country' => 'Australia', 'country_code' => 'au' } }])
end
def assert_permitted(policy, user, action, *opts)
@@ -260,7 +262,7 @@ def refute_permitted(*args)
end
def mock_timezone(tz = ActiveSupport::TimeZone.all.sample.tzinfo.identifier)
- @_prev_tz = ENV['TZ'] # Time zone should not affect test result
+ @_prev_tz = ENV['TZ'] # Time zone should not affect test result
ENV['TZ'] = tz
end
@@ -322,7 +324,7 @@ def mock_facets
if @collection.any?
c = @collection.first.class
f = c.facet_fields.map do |ff|
- { field_name: ff.to_sym, rows: (1 + rand(4)).times.map { { value: 'Fish', count: (1 + rand(4)) } } }
+ { field_name: ff.to_sym, rows: rand(1..4).times.map { { value: 'Fish', count: rand(1..4) } } }
end
JSON.parse(f.to_json, object_class: OpenStruct)
else
@@ -334,17 +336,16 @@ def mock_facets
# Minitest's `stub` method but ignores any blocks
class Object
-
- def blockless_stub name, val_or_callable, *block_args
+ def blockless_stub name, val_or_callable, *_block_args
new_name = "__minitest_stub__#{name}"
metaclass =
class << self
- self;
+ self
end
- if respond_to? name and not methods.map(&:to_s).include? name.to_s then
+ if respond_to? name and !methods.map(&:to_s).include? name.to_s
metaclass.send :define_method, name do |*args|
super(*args)
end
@@ -353,7 +354,7 @@ class << self
metaclass.send :alias_method, new_name, name
metaclass.send :define_method, name do |*args|
- ret = if val_or_callable.respond_to? :call then
+ ret = if val_or_callable.respond_to? :call
val_or_callable.call(*args)
else
val_or_callable
diff --git a/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb b/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb
index a1c1e43b4..7745a6f90 100644
--- a/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb
+++ b/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb
@@ -25,8 +25,8 @@ class FourtuWillmaLlmIngestorTest < ActiveSupport::TestCase
new_title = '4TU-meeting National Technology Strategy'
refute Event.where(title: new_title).any?
- get_body = '{
- "boop": "{
+ get_body = '{
+ "my_option": "{
\"name\": \"Zephyr 7B\",
\"id\": 0
}"
@@ -46,7 +46,7 @@ class FourtuWillmaLlmIngestorTest < ActiveSupport::TestCase
# run task
assert_difference 'Event.count', 1 do
freeze_time(2019) do
- VCR.use_cassette("ingestors/4tu_llm") do
+ VCR.use_cassette('ingestors/4tu_llm') do
WebMock.stub_request(:get, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: get_body)
WebMock.stub_request(:post, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: post_body)
with_settings({ llm_scraper: { model: 'willma', model_version: 'Zephyr 7B' } }) do
diff --git a/test/unit/llm_service_test.rb b/test/unit/llm_service_test.rb
new file mode 100644
index 000000000..ab99e862c
--- /dev/null
+++ b/test/unit/llm_service_test.rb
@@ -0,0 +1,99 @@
+require 'test_helper'
+require 'minitest/autorun'
+
+class LlmServiceTest < ActiveSupport::TestCase
+ test 'service_hash_contains_all_subclasses' do
+ hash_set = (Llm.service_hash.values + [Llm::Service]).map { |c| c.name.split('::').last.to_sym }.to_set
+ classes_set = Llm.constants.filter { |c| Llm.const_get(c).is_a?(Class) }.to_set
+ assert hash_set == classes_set
+ end
+
+ test 'no_post_processing unless model provided' do
+ with_settings({ llm_scraper: { model: 'willma' } }) do
+ mock = Minitest::Mock.new
+ Event.stub :not_finished, mock do
+ mock.expect :needs_processing, [], [String]
+ Llm.post_processing_task
+ end
+ mock.verify
+ end
+
+ with_settings({ llm_scraper: { model: nil } }) do
+ mock = Minitest::Mock.new
+ Event.stub :not_finished, mock do
+ mock.expect :needs_processing, []
+ Llm.post_processing_task
+ end
+ assert_raises(MockExpectationError) { mock.verify }
+ end
+ end
+
+ test 'NotImplementedError on parent class initialization' do
+ assert_raises(NotImplementedError) { Llm::Service.new }
+ end
+
+ test 'check event filtering in post_processing' do
+ u = users(:scraper_user)
+ event1 = Event.create!(title: 'needs_processing', start: Time.zone.now - 5.hours, end: Time.zone.now + 5.hours, url: 'https://www.google.com#1', user_id: u.id)
+ event1.llm_interaction = llm_interactions(:needs_processing)
+ event1.save!
+ event2 = Event.create!(title: 'different_prompt', start: Time.zone.now - 5.hours, end: Time.zone.now + 5.hours, url: 'https://www.google.com#2', user_id: u.id)
+ event2.llm_interaction = llm_interactions(:different_prompt)
+ event2.save!
+ event3 = Event.create!(title: 'finished', start: Time.zone.now - 5.hours, end: Time.zone.now - 4.hours, url: 'https://www.google.com#3', user_id: u.id)
+ event3.llm_interaction = llm_interactions(:scrape)
+ event3.save!
+ result = Llm.filtered_event_list(event1.llm_interaction.prompt)
+ assert result.map(&:title) == %w[needs_processing different_prompt]
+ end
+
+ test 'test willma scrape' do
+ get_body = {
+ "my_option": {
+ "name": 'Zephyr 7B',
+ "id": 0
+ }
+ }.to_json
+ post_body = '{
+ "message": "Here is your JSON:
+ {
+ \"title\":\"my_title\",
+ \"start\":\"2024-07-03T12:30:00+02:00\",
+ \"end\":\"2024-07-03T19:00:00+02:00\",
+ \"venue\":\"my_venue\",
+ \"description\":\"my_description\",
+ }
+ I am a dumb llm and I have to say something afterward even though I was specifically asked not to."
+ }'.gsub(/\n/, '')
+ # run task
+ WebMock.stub_request(:get, 'https://willma.soil.surf.nl/api/models').to_return(status: 200, body: get_body)
+ WebMock.stub_request(:post, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: post_body)
+ with_settings({ llm_scraper: { model: 'willma', model_version: 'Zephyr 7B' } }) do
+ result = Llm::WillmaService.new.scrape('my_html')
+ assert result['title'] = 'my_title'
+ assert result['venue'] = 'my_venue'
+ assert result['description'] = 'my_description'
+ end
+ end
+
+ test 'test gpt scrape' do
+ run_res = '{
+ "title":"my_title",
+ "start":"2024-07-03T12:30:00+02:00",
+ "end":"2024-07-03T19:00:00+02:00",
+ "venue":"my_venue",
+ "description":"my_description",
+ }'.gsub(/\n/, '')
+ mock_client = Minitest::Mock.new
+ mock_client.expect(:chat, { 'choices' => { 0 => { 'message' => { 'content' => run_res } } } }, parameters: Object)
+ # run task
+ OpenAI::Client.stub(:new, mock_client) do
+ with_settings({ llm_scraper: { model: 'chatgpt', model_version: 'GPT-3.5' } }) do
+ result = Llm::ChatgptService.new.scrape('my_html')
+ assert result['title'] = 'my_title'
+ assert result['venue'] = 'my_venue'
+ assert result['description'] = 'my_description'
+ end
+ end
+ end
+end
From a3a94e0c1a296f117c5e57145f02cb731a271479 Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 12 Jul 2024 08:42:55 +0200
Subject: [PATCH 34/37] updated schema
---
db/schema.rb | 197 +++++++++++++++++++++++++--------------------------
1 file changed, 96 insertions(+), 101 deletions(-)
diff --git a/db/schema.rb b/db/schema.rb
index aab36f20a..3878e06bd 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -14,17 +14,17 @@
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
- create_table "activities", id: :serial, force: :cascade do |t|
- t.string "trackable_type"
+ create_table "activities", force: :cascade do |t|
t.integer "trackable_id"
- t.string "owner_type"
+ t.string "trackable_type"
t.integer "owner_id"
+ t.string "owner_type"
t.string "key"
t.text "parameters"
- t.string "recipient_type"
t.integer "recipient_id"
- t.datetime "created_at", precision: nil
- t.datetime "updated_at", precision: nil
+ t.string "recipient_type"
+ t.datetime "created_at"
+ t.datetime "updated_at"
t.index ["key"], name: "index_activities_on_key"
t.index ["owner_id", "owner_type"], name: "index_activities_on_owner_id_and_owner_type"
t.index ["recipient_id", "recipient_type"], name: "index_activities_on_recipient_id_and_recipient_type"
@@ -36,7 +36,7 @@
t.bigint "user_id"
t.string "name"
t.jsonb "properties"
- t.datetime "time", precision: nil
+ t.datetime "time"
t.index ["name", "time"], name: "index_ahoy_events_on_name_and_time"
t.index ["properties"], name: "index_ahoy_events_on_properties", opclass: :jsonb_path_ops, using: :gin
t.index ["user_id"], name: "index_ahoy_events_on_user_id"
@@ -68,7 +68,7 @@
t.string "app_version"
t.string "os_version"
t.string "platform"
- t.datetime "started_at", precision: nil
+ t.datetime "started_at"
t.index ["user_id"], name: "index_ahoy_visits_on_user_id"
t.index ["visit_token"], name: "index_ahoy_visits_on_visit_token", unique: true
end
@@ -79,21 +79,21 @@
t.index ["field", "value"], name: "index_autocomplete_suggestions_on_field_and_value", unique: true
end
- create_table "bans", id: :serial, force: :cascade do |t|
+ create_table "bans", force: :cascade do |t|
t.integer "user_id"
t.integer "banner_id"
t.boolean "shadow"
t.text "reason"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.index ["banner_id"], name: "index_bans_on_banner_id"
t.index ["user_id"], name: "index_bans_on_user_id"
end
- create_table "collaborations", id: :serial, force: :cascade do |t|
+ create_table "collaborations", force: :cascade do |t|
t.integer "user_id"
- t.string "resource_type"
t.integer "resource_id"
+ t.string "resource_type"
t.index ["resource_type", "resource_id"], name: "index_collaborations_on_resource_type_and_resource_id"
t.index ["user_id"], name: "index_collaborations_on_user_id"
end
@@ -110,13 +110,13 @@
t.index ["resource_type", "resource_id"], name: "index_collection_items_on_resource"
end
- create_table "collections", id: :serial, force: :cascade do |t|
+ create_table "collections", force: :cascade do |t|
t.string "title"
t.text "description"
t.text "image_url"
t.boolean "public", default: true
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "user_id"
t.string "slug"
t.string "keywords", default: [], array: true
@@ -128,13 +128,13 @@
t.index ["user_id"], name: "index_collections_on_user_id"
end
- create_table "content_providers", id: :serial, force: :cascade do |t|
+ create_table "content_providers", force: :cascade do |t|
t.text "title"
t.text "url"
t.text "image_url"
t.text "description"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "slug"
t.string "keywords", default: [], array: true
t.integer "user_id"
@@ -159,33 +159,33 @@
t.index ["user_id"], name: "index_content_providers_users_on_user_id"
end
- create_table "edit_suggestions", id: :serial, force: :cascade do |t|
+ create_table "edit_suggestions", force: :cascade do |t|
t.text "name"
t.text "text"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "suggestible_id"
t.string "suggestible_type"
t.json "data_fields", default: {}
t.index ["suggestible_id", "suggestible_type"], name: "index_edit_suggestions_on_suggestible_id_and_suggestible_type"
end
- create_table "event_materials", id: :serial, force: :cascade do |t|
+ create_table "event_materials", force: :cascade do |t|
t.integer "event_id"
t.integer "material_id"
t.index ["event_id"], name: "index_event_materials_on_event_id"
t.index ["material_id"], name: "index_event_materials_on_material_id"
end
- create_table "events", id: :serial, force: :cascade do |t|
+ create_table "events", force: :cascade do |t|
t.string "external_id"
t.string "title"
t.string "subtitle"
t.string "url"
t.string "organizer"
t.text "description"
- t.datetime "start", precision: nil
- t.datetime "end", precision: nil
+ t.datetime "start"
+ t.datetime "end"
t.string "sponsors", default: [], array: true
t.text "venue"
t.string "city"
@@ -194,8 +194,8 @@
t.string "postcode"
t.decimal "latitude", precision: 10, scale: 6
t.decimal "longitude", precision: 10, scale: 6
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.text "source", default: "tess"
t.string "slug"
t.integer "content_provider_id"
@@ -227,38 +227,35 @@
t.string "cost_basis"
t.string "cost_currency"
t.string "fields", default: [], array: true
- t.bigint "llm_interaction_id"
- t.string "open_science", default: [], array: true
t.boolean "visible", default: true
- t.index ["llm_interaction_id"], name: "index_events_on_llm_interaction_id"
t.index ["presence"], name: "index_events_on_presence"
t.index ["slug"], name: "index_events_on_slug", unique: true
t.index ["user_id"], name: "index_events_on_user_id"
end
- create_table "external_resources", id: :serial, force: :cascade do |t|
+ create_table "external_resources", force: :cascade do |t|
t.integer "source_id"
t.text "url"
t.string "title"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "source_type"
t.index ["source_id", "source_type"], name: "index_external_resources_on_source_id_and_source_type"
end
- create_table "field_locks", id: :serial, force: :cascade do |t|
- t.string "resource_type"
+ create_table "field_locks", force: :cascade do |t|
t.integer "resource_id"
+ t.string "resource_type"
t.string "field"
t.index ["resource_type", "resource_id"], name: "index_field_locks_on_resource_type_and_resource_id"
end
- create_table "friendly_id_slugs", id: :serial, force: :cascade do |t|
+ create_table "friendly_id_slugs", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
t.string "scope"
- t.datetime "created_at", precision: nil
+ t.datetime "created_at"
t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true
t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type"
t.index ["sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_id"
@@ -322,14 +319,14 @@
t.index ["user_id"], name: "index_learning_paths_on_user_id"
end
- create_table "link_monitors", id: :serial, force: :cascade do |t|
+ create_table "link_monitors", force: :cascade do |t|
t.string "url"
t.integer "code"
- t.datetime "failed_at", precision: nil
- t.datetime "last_failed_at", precision: nil
+ t.datetime "failed_at"
+ t.datetime "last_failed_at"
t.integer "fail_count"
- t.string "lcheck_type"
t.integer "lcheck_id"
+ t.string "lcheck_type"
t.index ["lcheck_type", "lcheck_id"], name: "index_link_monitors_on_lcheck_type_and_lcheck_id"
end
@@ -346,17 +343,16 @@
t.index ["event_id"], name: "index_llm_interactions_on_event_id"
end
- create_table "materials", id: :serial, force: :cascade do |t|
+ create_table "materials", force: :cascade do |t|
t.text "title"
t.string "url"
t.string "doi"
t.date "remote_updated_date"
t.date "remote_created_date"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.text "description"
t.string "target_audience", default: [], array: true
- t.string "keywords", default: [], array: true
t.string "authors", default: [], array: true
t.string "contributors", default: [], array: true
t.string "licence", default: "notspecified"
@@ -367,6 +363,7 @@
t.date "last_scraped"
t.boolean "scraper_record", default: false
t.string "resource_type", default: [], array: true
+ t.string "keywords", default: [], array: true
t.string "other_types"
t.date "date_created"
t.date "date_modified"
@@ -384,23 +381,23 @@
t.index ["user_id"], name: "index_materials_on_user_id"
end
- create_table "node_links", id: :serial, force: :cascade do |t|
+ create_table "node_links", force: :cascade do |t|
t.integer "node_id"
- t.string "resource_type"
t.integer "resource_id"
+ t.string "resource_type"
t.index ["node_id"], name: "index_node_links_on_node_id"
t.index ["resource_type", "resource_id"], name: "index_node_links_on_resource_type_and_resource_id"
end
- create_table "nodes", id: :serial, force: :cascade do |t|
+ create_table "nodes", force: :cascade do |t|
t.string "name"
t.string "member_status"
t.string "country_code"
t.string "home_page"
t.string "twitter"
t.string "carousel_images", array: true
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "slug"
t.integer "user_id"
t.text "image_url"
@@ -409,9 +406,9 @@
t.index ["user_id"], name: "index_nodes_on_user_id"
end
- create_table "ontology_term_links", id: :serial, force: :cascade do |t|
- t.string "resource_type"
+ create_table "ontology_term_links", force: :cascade do |t|
t.integer "resource_id"
+ t.string "resource_type"
t.string "term_uri"
t.string "field"
t.index ["field"], name: "index_ontology_term_links_on_field"
@@ -419,14 +416,14 @@
t.index ["term_uri"], name: "index_ontology_term_links_on_term_uri"
end
- create_table "profiles", id: :serial, force: :cascade do |t|
+ create_table "profiles", force: :cascade do |t|
t.text "firstname"
t.text "surname"
t.text "image_url"
t.text "email"
t.text "website"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.integer "user_id"
t.string "slug"
t.boolean "public", default: false
@@ -445,18 +442,18 @@
t.index ["slug"], name: "index_profiles_on_slug", unique: true
end
- create_table "roles", id: :serial, force: :cascade do |t|
+ create_table "roles", force: :cascade do |t|
t.string "name"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "title"
end
- create_table "sessions", id: :serial, force: :cascade do |t|
+ create_table "sessions", force: :cascade do |t|
t.string "session_id", null: false
t.text "data"
- t.datetime "created_at", precision: nil
- t.datetime "updated_at", precision: nil
+ t.datetime "created_at"
+ t.datetime "updated_at"
t.index ["session_id"], name: "index_sessions_on_session_id", unique: true
t.index ["updated_at"], name: "index_sessions_on_updated_at"
end
@@ -464,8 +461,8 @@
create_table "sources", force: :cascade do |t|
t.bigint "content_provider_id"
t.bigint "user_id"
- t.datetime "created_at", precision: nil
- t.datetime "finished_at", precision: nil
+ t.datetime "created_at"
+ t.datetime "finished_at"
t.string "url"
t.string "method"
t.integer "records_read"
@@ -477,19 +474,19 @@
t.boolean "enabled"
t.string "token"
t.integer "approval_status"
- t.datetime "updated_at", precision: nil
+ t.datetime "updated_at"
t.index ["content_provider_id"], name: "index_sources_on_content_provider_id"
t.index ["user_id"], name: "index_sources_on_user_id"
end
- create_table "staff_members", id: :serial, force: :cascade do |t|
+ create_table "staff_members", force: :cascade do |t|
t.string "name"
t.string "role"
t.string "email"
t.text "image_url"
t.integer "node_id"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.bigint "image_file_size"
@@ -497,60 +494,60 @@
t.index ["node_id"], name: "index_staff_members_on_node_id"
end
- create_table "stars", id: :serial, force: :cascade do |t|
+ create_table "stars", force: :cascade do |t|
t.integer "user_id"
- t.string "resource_type"
t.integer "resource_id"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.string "resource_type"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.index ["resource_type", "resource_id"], name: "index_stars_on_resource_type_and_resource_id"
t.index ["user_id"], name: "index_stars_on_user_id"
end
- create_table "subscriptions", id: :serial, force: :cascade do |t|
+ create_table "subscriptions", force: :cascade do |t|
t.integer "user_id"
- t.datetime "last_sent_at", precision: nil
+ t.datetime "last_sent_at"
t.text "query"
t.json "facets"
t.integer "frequency"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "subscribable_type"
- t.datetime "last_checked_at", precision: nil
+ t.datetime "last_checked_at"
t.index ["user_id"], name: "index_subscriptions_on_user_id"
end
- create_table "users", id: :serial, force: :cascade do |t|
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ create_table "users", force: :cascade do |t|
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "username"
t.integer "role_id"
t.string "authentication_token"
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
- t.datetime "reset_password_sent_at", precision: nil
- t.datetime "remember_created_at", precision: nil
+ t.datetime "reset_password_sent_at"
+ t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
- t.datetime "current_sign_in_at", precision: nil
- t.datetime "last_sign_in_at", precision: nil
+ t.datetime "current_sign_in_at"
+ t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.string "confirmation_token"
- t.datetime "confirmed_at", precision: nil
- t.datetime "confirmation_sent_at", precision: nil
+ t.datetime "confirmed_at"
+ t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "failed_attempts", default: 0, null: false
t.string "unlock_token"
- t.datetime "locked_at", precision: nil
+ t.datetime "locked_at"
t.string "slug"
t.string "provider"
t.string "uid"
t.string "identity_url"
t.string "invitation_token"
- t.datetime "invitation_created_at", precision: nil
- t.datetime "invitation_sent_at", precision: nil
- t.datetime "invitation_accepted_at", precision: nil
+ t.datetime "invitation_created_at"
+ t.datetime "invitation_sent_at"
+ t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.string "invited_by_type"
t.bigint "invited_by_id"
@@ -559,14 +556,14 @@
t.string "image_file_name"
t.string "image_content_type"
t.bigint "image_file_size"
- t.datetime "image_updated_at", precision: nil
+ t.datetime "image_updated_at"
t.index ["authentication_token"], name: "index_users_on_authentication_token"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["identity_url"], name: "index_users_on_identity_url", unique: true
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
t.index ["invited_by_id"], name: "index_users_on_invited_by_id"
- t.index ["invited_by_type", "invited_by_id"], name: "index_users_on_invited_by_type_and_invited_by_id"
+ t.index ["invited_by_type", "invited_by_id"], name: "index_users_on_invited_by"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["role_id"], name: "index_users_on_role_id"
t.index ["slug"], name: "index_users_on_slug", unique: true
@@ -574,25 +571,25 @@
t.index ["username"], name: "index_users_on_username", unique: true
end
- create_table "widget_logs", id: :serial, force: :cascade do |t|
+ create_table "widget_logs", force: :cascade do |t|
t.string "widget_name"
t.string "action"
- t.string "resource_type"
t.integer "resource_id"
+ t.string "resource_type"
t.text "data"
t.json "params"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.index ["resource_type", "resource_id"], name: "index_widget_logs_on_resource_type_and_resource_id"
end
- create_table "workflows", id: :serial, force: :cascade do |t|
+ create_table "workflows", force: :cascade do |t|
t.string "title"
t.string "description"
t.integer "user_id"
t.json "workflow_content"
- t.datetime "created_at", precision: nil, null: false
- t.datetime "updated_at", precision: nil, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
t.string "slug"
t.string "target_audience", default: [], array: true
t.string "keywords", default: [], array: true
@@ -617,12 +614,10 @@
add_foreign_key "content_providers", "users"
add_foreign_key "event_materials", "events"
add_foreign_key "event_materials", "materials"
- add_foreign_key "events", "llm_interactions"
add_foreign_key "events", "users"
add_foreign_key "learning_path_topic_links", "learning_paths"
add_foreign_key "learning_paths", "content_providers"
add_foreign_key "learning_paths", "users"
- add_foreign_key "llm_interactions", "events"
add_foreign_key "materials", "content_providers"
add_foreign_key "materials", "users"
add_foreign_key "node_links", "nodes"
From 3a460a8e59a77d524bcf5db59aa05e05361a88ac Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 12 Jul 2024 09:02:38 +0200
Subject: [PATCH 35/37] undo changes wrt incomplete regular expression for
hostnames
---
test/test_helper.rb | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 1e4a7655a..f7852cd47 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -235,16 +235,14 @@ def mock_ingestions
def mock_biotools
biotools_file = File.read("#{Rails.root}/test/fixtures/files/annotation.json")
- WebMock.stub_request(:get, /data.bioontology.org/)
- .to_return(status: 200, headers: {}, body: biotools_file)
+ WebMock.stub_request(:get, /data.bioontology.org/).to_return(status: 200, headers: {}, body: biotools_file)
end
def mock_nominatim
nominatim_file = File.read(File.join(Rails.root, ['test', 'fixtures', 'files', 'nominatim.json']))
kensington_file = File.read(File.join(Rails.root, ['test', 'fixtures', 'files', 'geocode_kensington.json']))
- WebMock.stub_request(:get, /nominatim.openstreetmap.org/)
- .to_return(status: 200, headers: {}, body: nominatim_file)
+ WebMock.stub_request(:get, /nominatim.openstreetmap.org/).to_return(status: 200, headers: {}, body: nominatim_file)
# geocoder overrides
Geocoder.configure(lookup: :test, ip_lookup: :test)
From 8badfff67e444180fb55814278c6bf621d70cc8e Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 12 Jul 2024 09:22:17 +0200
Subject: [PATCH 36/37] fix language merge issue
---
app/controllers/events_controller.rb | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb
index cd1bfd697..11f7fb116 100644
--- a/app/controllers/events_controller.rb
+++ b/app/controllers/events_controller.rb
@@ -233,8 +233,8 @@ def event_params
:timezone, :content_provider_id, { collection_ids: [] }, { node_ids: [] },
{ node_names: [] }, { target_audience: [] }, { eligibility: [] }, :visible,
{ host_institutions: [] }, :capacity, :contact, :recognition, :learning_objectives,
- :prerequisites, :tech_requirements, :cost_basis, :cost_value, :cost_currency,
- external_resources_attributes: %i[id url title _destroy], material_ids: [], :language,
+ :prerequisites, :tech_requirements, :cost_basis, :cost_value, :cost_currency, :language,
+ external_resources_attributes: %i[id url title _destroy], material_ids: [],
llm_interaction_attributes: %i[id scrape_or_process model prompt input output needs_processing _destroy],
locked_fields: [])
end
From 464cc8d5061cb972d352219af2f6cfbb0e13631e Mon Sep 17 00:00:00 2001
From: Mike Sanders
Date: Fri, 12 Jul 2024 11:09:30 +0200
Subject: [PATCH 37/37] fix tests + add web request mocks in test helper
---
app/models/event.rb | 2 +-
.../events_require_approval.html.erb | 3 ---
lib/llm/willma_service.rb | 2 +-
test/test_helper.rb | 24 +++++++++++++++++++
.../ingestors/4tu_gpt_llm_ingestor_test.rb | 6 ++---
.../ingestors/4tu_willma_llm_ingestor_test.rb | 21 +---------------
test/unit/llm_service_test.rb | 24 ++++---------------
7 files changed, 34 insertions(+), 48 deletions(-)
diff --git a/app/models/event.rb b/app/models/event.rb
index af8d53c03..ec4ca68a6 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -288,7 +288,7 @@ def self.disabled
end
def self.not_finished
- where('events.end >= ?', Time.now).where.not(end: nil)
+ where('events.end >= ? OR events.end IS NULL', Time.now)
end
def self.finished
diff --git a/app/views/curation_mailer/events_require_approval.html.erb b/app/views/curation_mailer/events_require_approval.html.erb
index d069969e2..11287c730 100644
--- a/app/views/curation_mailer/events_require_approval.html.erb
+++ b/app/views/curation_mailer/events_require_approval.html.erb
@@ -16,9 +16,6 @@
end: <%= event.end %>
venue: <%= event.venue %>
show: <%= event.visible %>
- keywords: <%= event.keywords %>
- audience: <%= event.audience %>
- open_science: <%= event.open_science %>
<% end %>
diff --git a/lib/llm/willma_service.rb b/lib/llm/willma_service.rb
index 02b6c30c3..9334ed452 100644
--- a/lib/llm/willma_service.rb
+++ b/lib/llm/willma_service.rb
@@ -9,7 +9,7 @@ def initialize
model_name = TeSS::Config.llm_scraper['model_version']
model_url = 'https://willma.soil.surf.nl/api/models'
parsed_response = JSON.parse(do_request(model_url, 'get', {}).body)
- model_id = parsed_response.values.select { |i| i['name'] == model_name }.first['id']
+ model_id = parsed_response.select { |i| i['name'] == model_name }.first['id']
@params = {
model: model_name,
sequence_id: model_id,
diff --git a/test/test_helper.rb b/test/test_helper.rb
index f7852cd47..cc5ccc7f2 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -145,6 +145,30 @@ def freeze_time(time_or_year = Time.now, &block)
end
end
+ def mock_llm_requests
+ get_body = [
+ {
+ "name": 'Zephyr 7B',
+ "id": 0
+ }
+ ].to_json
+ post_body = '{
+ "message": "Here is your JSON:
+ {
+ \"title\":\"4TU-meeting National Technology Strategy\",
+ \"start\":\"2024-07-03T12:30:00+02:00\",
+ \"end\":\"2024-07-03T19:00:00+02:00\",
+ \"venue\":\"Basecamp, Nijverheidsweg 16A, 3534 AM Utrecht (https://basecamputrecht.nl)\",
+ \"description\":\"My cool description\",
+ \"nonsense_attr\":\"My cool nonsense attribute\"
+ }
+ I am a dumb llm and I have to say something afterward even though I was specifically asked not to."
+ }'.gsub(/\n/, '')
+ # run task
+ WebMock.stub_request(:get, 'https://willma.soil.surf.nl/api/models').to_return(status: 200, body: get_body)
+ WebMock.stub_request(:post, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: post_body)
+ end
+
# Mock remote images so paperclip doesn't break:
def mock_images
WebMock.stub_request(:any, %r{http://example\.com/(.+)\.png}).to_return(
diff --git a/test/unit/ingestors/4tu_gpt_llm_ingestor_test.rb b/test/unit/ingestors/4tu_gpt_llm_ingestor_test.rb
index 1e12e564e..1659771e3 100644
--- a/test/unit/ingestors/4tu_gpt_llm_ingestor_test.rb
+++ b/test/unit/ingestors/4tu_gpt_llm_ingestor_test.rb
@@ -35,13 +35,13 @@ class FourtuGptLlmIngestorTest < ActiveSupport::TestCase
"nonsense_attr":"My cool nonsense attribute"
}'.gsub(/\n/, '')
mock_client = Minitest::Mock.new
- 8.times do
- mock_client.expect(:chat, {'choices'=> {0=> {'message'=> {'content'=> run_res}}}}, parameters: Object)
+ 8.times do
+ mock_client.expect(:chat, { 'choices' => { 0 => { 'message' => { 'content' => run_res } } } }, parameters: Object)
end
# run task
assert_difference 'Event.count', 1 do
freeze_time(2019) do
- VCR.use_cassette("ingestors/4tu_gpt_llm") do
+ VCR.use_cassette('ingestors/4tu_gpt_llm') do
OpenAI::Client.stub(:new, mock_client) do
with_settings({ llm_scraper: { model: 'chatgpt', model_version: 'GPT-3.5' } }) do
ingestor.read(source.url)
diff --git a/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb b/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb
index 7745a6f90..5395d89f6 100644
--- a/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb
+++ b/test/unit/ingestors/4tu_willma_llm_ingestor_test.rb
@@ -25,30 +25,11 @@ class FourtuWillmaLlmIngestorTest < ActiveSupport::TestCase
new_title = '4TU-meeting National Technology Strategy'
refute Event.where(title: new_title).any?
- get_body = '{
- "my_option": "{
- \"name\": \"Zephyr 7B\",
- \"id\": 0
- }"
- }'.gsub(/\n/, '')
- post_body = '{
- "message": "Here is your JSON:
- {
- \"title\":\"4TU-meeting National Technology Strategy\",
- \"start\":\"2024-07-03T12:30:00+02:00\",
- \"end\":\"2024-07-03T19:00:00+02:00\",
- \"venue\":\"Basecamp, Nijverheidsweg 16A, 3534 AM Utrecht (https://basecamputrecht.nl)\",
- \"description\":\"My cool description\",
- \"nonsense_attr\":\"My cool nonsense attribute\"
- }
- I am a dumb llm and I have to say something afterward even though I was specifically asked not to."
- }'.gsub(/\n/, '')
+ mock_llm_requests
# run task
assert_difference 'Event.count', 1 do
freeze_time(2019) do
VCR.use_cassette('ingestors/4tu_llm') do
- WebMock.stub_request(:get, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: get_body)
- WebMock.stub_request(:post, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: post_body)
with_settings({ llm_scraper: { model: 'willma', model_version: 'Zephyr 7B' } }) do
ingestor.read(source.url)
ingestor.write(@user, @content_provider)
diff --git a/test/unit/llm_service_test.rb b/test/unit/llm_service_test.rb
index ab99e862c..e2adc263e 100644
--- a/test/unit/llm_service_test.rb
+++ b/test/unit/llm_service_test.rb
@@ -2,6 +2,10 @@
require 'minitest/autorun'
class LlmServiceTest < ActiveSupport::TestCase
+ def setup
+ mock_llm_requests
+ end
+
test 'service_hash_contains_all_subclasses' do
hash_set = (Llm.service_hash.values + [Llm::Service]).map { |c| c.name.split('::').last.to_sym }.to_set
classes_set = Llm.constants.filter { |c| Llm.const_get(c).is_a?(Class) }.to_set
@@ -48,26 +52,6 @@ class LlmServiceTest < ActiveSupport::TestCase
end
test 'test willma scrape' do
- get_body = {
- "my_option": {
- "name": 'Zephyr 7B',
- "id": 0
- }
- }.to_json
- post_body = '{
- "message": "Here is your JSON:
- {
- \"title\":\"my_title\",
- \"start\":\"2024-07-03T12:30:00+02:00\",
- \"end\":\"2024-07-03T19:00:00+02:00\",
- \"venue\":\"my_venue\",
- \"description\":\"my_description\",
- }
- I am a dumb llm and I have to say something afterward even though I was specifically asked not to."
- }'.gsub(/\n/, '')
- # run task
- WebMock.stub_request(:get, 'https://willma.soil.surf.nl/api/models').to_return(status: 200, body: get_body)
- WebMock.stub_request(:post, 'https://willma.soil.surf.nl/api/query').to_return(status: 200, body: post_body)
with_settings({ llm_scraper: { model: 'willma', model_version: 'Zephyr 7B' } }) do
result = Llm::WillmaService.new.scrape('my_html')
assert result['title'] = 'my_title'