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'