├── Gemfile ├── .gitignore ├── .travis.yml ├── Makefile ├── lib ├── lastpass │ ├── version.rb │ ├── http.rb │ ├── note.rb │ ├── chunk.rb │ ├── session.rb │ ├── blob.rb │ ├── account.rb │ ├── exceptions.rb │ ├── vault.rb │ ├── fetcher.rb │ └── parser.rb └── lastpass.rb ├── example ├── credentials.yaml.example └── example.rb ├── spec ├── chunk_spec.rb ├── session_spec.rb ├── account_spec.rb ├── http_spec.rb ├── blob_spec.rb ├── spec_helper.rb ├── vault_spec.rb ├── fetcher_spec.rb ├── parser_spec.rb └── test_data.rb ├── TODO ├── Rakefile ├── LICENSE ├── lastpass.gemspec ├── .github └── workflows │ └── ruby.yml ├── CHANGELOG.md └── README.md /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /pkg/ 2 | /Gemfile.lock 3 | /coverage 4 | /example/credentials.yaml 5 | /vendor/ 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.0.0-p648 4 | - 2.1.10 5 | - 2.2.9 6 | - 2.3.8 7 | - 2.4.9 8 | - 2.5.8 9 | - 2.6.6 10 | - 2.7.1 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @# TODO: This is a temporary hack for ST3. 3 | @# Figure out why ST3 doesn't use the environment of the launching process. 4 | @rbenv exec rake 5 | -------------------------------------------------------------------------------- /lib/lastpass/version.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | VERSION = "1.7.1" 6 | end 7 | -------------------------------------------------------------------------------- /example/credentials.yaml.example: -------------------------------------------------------------------------------- 1 | # Copy this file to credentials.yaml and put correct username/password. 2 | # There shouldn't be any real credentials in the repo. 3 | username: account@example.com 4 | password: correct horse battery staple 5 | -------------------------------------------------------------------------------- /lib/lastpass/http.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | class HTTP 6 | include HTTParty 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/lastpass/note.rb: -------------------------------------------------------------------------------- 1 | module LastPass 2 | class Note 3 | attr_reader :id, 4 | :name, 5 | :notes, 6 | :group 7 | 8 | def initialize id, name, notes, group 9 | @id = id 10 | @name = name 11 | @notes = notes 12 | @group = group 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/lastpass/chunk.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | class Chunk 6 | attr_reader :id, 7 | :payload 8 | 9 | def initialize id, payload 10 | @id = id 11 | @payload = payload 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/chunk_spec.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "spec_helper" 5 | 6 | describe LastPass::Chunk do 7 | let(:id) { "IDID" } 8 | let(:payload) { "Payload" } 9 | 10 | subject { LastPass::Chunk.new id, payload } 11 | 12 | its(:id) { should eq id } 13 | its(:payload) { should eq payload } 14 | end 15 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Make tests more consistent. Currently there's a lot of different binary blobs stored in the tests. 2 | It would be good to generate the test data from some meaningful pieces. Like construct chunks from 3 | items, construct items themselves. Build the whole blob out of chunks. This way the tests would be 4 | more readable and easier to update in case of format changes. This also fixes the problem of 5 | exposing real world usernames, passwords and encryption keys. 6 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "bundler/gem_tasks" 5 | require "rspec/core/rake_task" 6 | 7 | task :default => :spec 8 | 9 | # Spec 10 | RSpec::Core::RakeTask.new :spec do |task| 11 | task.rspec_opts = "--format documentation --color" 12 | end 13 | 14 | # Example 15 | task :example do 16 | ruby "-Ilib", "example/example.rb" 17 | end 18 | -------------------------------------------------------------------------------- /lib/lastpass.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "base64" 5 | require "httparty" 6 | require "openssl" 7 | require "stringio" 8 | 9 | require "lastpass/account" 10 | require "lastpass/blob" 11 | require "lastpass/chunk" 12 | require "lastpass/exceptions" 13 | require "lastpass/http" 14 | require "lastpass/fetcher" 15 | require "lastpass/note" 16 | require "lastpass/parser" 17 | require "lastpass/session" 18 | require "lastpass/vault" 19 | require "lastpass/version" 20 | -------------------------------------------------------------------------------- /lib/lastpass/session.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | class Session 6 | attr_reader :id, 7 | :key_iteration_count, 8 | :encrypted_private_key 9 | 10 | def initialize id, key_iteration_count, encrypted_private_key 11 | @id = id 12 | @key_iteration_count = key_iteration_count 13 | @encrypted_private_key = encrypted_private_key 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/session_spec.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "spec_helper" 5 | 6 | describe LastPass::Session do 7 | let(:id) { "53ru,Hb713QnEVM5zWZ16jMvxS0" } 8 | let(:key_iteration_count) { 5000 } 9 | let(:encrypted_private_key) { "DEADBEEF" } 10 | 11 | subject { LastPass::Session.new id, key_iteration_count, encrypted_private_key } 12 | 13 | its(:id) { should eq id } 14 | its(:key_iteration_count) { should eq key_iteration_count } 15 | its(:encrypted_private_key) { should eq encrypted_private_key } 16 | end 17 | -------------------------------------------------------------------------------- /lib/lastpass/blob.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | class Blob 6 | attr_reader :bytes, 7 | :key_iteration_count, 8 | :encrypted_private_key 9 | 10 | def initialize bytes, key_iteration_count, encrypted_private_key 11 | @bytes = bytes 12 | @key_iteration_count = key_iteration_count 13 | @encrypted_private_key = encrypted_private_key 14 | end 15 | 16 | def encryption_key username, password 17 | Fetcher.make_key username, password, key_iteration_count 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/lastpass/account.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | class Account 6 | attr_reader :id, 7 | :name, 8 | :username, 9 | :password, 10 | :url, 11 | :notes, 12 | :group 13 | 14 | def initialize id, name, username, password, url, notes, group 15 | @id = id 16 | @name = name 17 | @username = username 18 | @password = password 19 | @url = url 20 | @notes = notes 21 | @group = group 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/account_spec.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "spec_helper" 5 | 6 | describe LastPass::Account do 7 | let(:id) { "id" } 8 | let(:name) { "name" } 9 | let(:username) { "username" } 10 | let(:password) { "password" } 11 | let(:url) { "url" } 12 | let(:notes) { "notes" } 13 | let(:group) { "group" } 14 | 15 | subject { LastPass::Account.new id, name, username, password, url, notes, group } 16 | 17 | its(:id) { should eq id } 18 | its(:name) { should eq name } 19 | its(:username) { should eq username } 20 | its(:password) { should eq password } 21 | its(:url) { should eq url } 22 | its(:notes) { should eq notes } 23 | its(:group) { should eq group } 24 | end 25 | -------------------------------------------------------------------------------- /spec/http_spec.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "spec_helper" 5 | 6 | describe LastPass::HTTP do 7 | let(:http) { LastPass::HTTP } 8 | 9 | describe "#http_proxy" do 10 | let(:url) { "https://proxy.example.com" } 11 | let(:port) { 12345 } 12 | let(:username) { "username" } 13 | let(:password) { "password" } 14 | 15 | it "sets the proxy options" do 16 | http.http_proxy url, port, username, password 17 | 18 | options = http.instance_variable_get :@default_options 19 | expect(options[:http_proxyaddr]).to eq url 20 | expect(options[:http_proxyport]).to eq port 21 | expect(options[:http_proxyuser]).to eq username 22 | expect(options[:http_proxypass]).to eq password 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/blob_spec.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "spec_helper" 5 | 6 | describe LastPass::Blob do 7 | let(:bytes) { "TFBBVgAAAAMxMjJQUkVNAAAACjE0MTQ5".decode64 } 8 | let(:key_iteration_count) { 500 } 9 | let(:encrypted_private_key) { "DEADBEEF" } 10 | let(:username) { "postlass@gmail.com" } 11 | let(:password) { "pl1234567890" } 12 | let(:encryption_key) { "OfOUvVnQzB4v49sNh4+PdwIFb9Fr5+jVfWRTf+E2Ghg=".decode64 } 13 | 14 | subject { LastPass::Blob.new bytes, key_iteration_count, encrypted_private_key } 15 | 16 | its(:bytes) { should eq bytes } 17 | its(:key_iteration_count) { should eq key_iteration_count } 18 | its(:encrypted_private_key) { should eq encrypted_private_key } 19 | 20 | describe "#encryption_key" do 21 | it "returns encryption key" do 22 | expect(subject.encryption_key username, password).to eq encryption_key 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | # Only calculate test coverage on TravisCI 5 | if ENV["CI"] == "true" && ENV["TRAVIS"] == "true" 6 | require "coveralls" 7 | Coveralls.wear! 8 | end 9 | 10 | require "base64" 11 | require "lastpass" 12 | require "rspec/its" 13 | 14 | class String 15 | def decode64 16 | Base64.decode64 self 17 | end 18 | 19 | def decode_hex 20 | scan(/../).map { |i| i.to_i 16 }.pack "c*" 21 | end 22 | end 23 | 24 | module LastPass 25 | class Session 26 | def == other 27 | id == other.id && key_iteration_count == other.key_iteration_count 28 | end 29 | end 30 | 31 | class Blob 32 | def == other 33 | bytes == other.bytes && key_iteration_count == other.key_iteration_count 34 | end 35 | end 36 | 37 | class Chunk 38 | def == other 39 | id == other.id && payload == other.payload 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Dmitry Yakimenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /lastpass.gemspec: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | $:.push File.expand_path("../lib", __FILE__) 5 | require "lastpass/version" 6 | 7 | Gem::Specification.new do |s| 8 | s.name = "lastpass" 9 | s.version = LastPass::VERSION 10 | s.licenses = ["MIT"] 11 | s.authors = ["Dmitry Yakimenko"] 12 | s.email = "detunized@gmail.com" 13 | s.homepage = "https://github.com/detunized/lastpass-ruby" 14 | s.summary = "Unofficial LastPass API" 15 | s.description = "Read only access to the online LastPass vault" 16 | 17 | s.required_ruby_version = ">= 2.0.0" 18 | 19 | s.add_dependency "httparty", "~> 0.14" 20 | 21 | s.add_development_dependency "rake", "~> 12.0" 22 | s.add_development_dependency "rspec", "~> 3.5" 23 | s.add_development_dependency "rspec-its", "~> 1.2" 24 | s.add_development_dependency "coveralls", "~> 0.8.19" 25 | 26 | s.files = `git ls-files`.split "\n" 27 | s.test_files = `git ls-files spec`.split "\n" 28 | s.require_paths = ["lib"] 29 | end 30 | -------------------------------------------------------------------------------- /lib/lastpass/exceptions.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | # Base class for all errors, should not be raised 6 | class Error < StandardError; end 7 | 8 | # 9 | # Generic errors 10 | # 11 | 12 | # Something went wrong with the network 13 | class NetworkError < Error; end 14 | 15 | # Server responded with something we don't understand 16 | class InvalidResponseError < Error; end 17 | 18 | # Server responded with XML we don't understand 19 | class UnknownResponseSchemaError < Error; end 20 | 21 | # 22 | # LastPass returned errors 23 | # 24 | 25 | # LastPass error: unknown username 26 | class LastPassUnknownUsernameError < Error; end 27 | 28 | # LastPass error: invalid password 29 | class LastPassInvalidPasswordError < Error; end 30 | 31 | # LastPass error: missing or incorrect Google Authenticator code 32 | class LastPassIncorrectGoogleAuthenticatorCodeError < Error; end 33 | 34 | # LastPass error: missing or incorrect Yubikey password 35 | class LastPassIncorrectYubikeyPasswordError < Error; end 36 | 37 | # LastPass error we don't know about 38 | class LastPassUnknownError < Error; end 39 | end 40 | -------------------------------------------------------------------------------- /.github/workflows/ruby.yml: -------------------------------------------------------------------------------- 1 | name: Ruby 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | tags: 'v*' 7 | pull_request: 8 | branches: [ master ] 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | ruby: [2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7] 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: ruby/setup-ruby@v1 20 | with: 21 | ruby-version: ${{ matrix.ruby }} 22 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 23 | - run: bundle install 24 | - run: bundle exec rake 25 | 26 | build: 27 | if: github.event_name == 'push' && contains(github.ref, 'refs/tags/v') 28 | needs: test 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v3 32 | - uses: ruby/setup-ruby@v1 33 | with: 34 | ruby-version: 2.7 35 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 36 | - name: Install dependencies 37 | run: bundle install 38 | - name: Build the gem 39 | run: bundle exec gem build lastpass.gemspec 40 | - name: Push the gem to rubygems.org 41 | run: bundle exec gem push *.gem 42 | env: 43 | GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}" 44 | -------------------------------------------------------------------------------- /example/example.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | # Run via top level rake file: 5 | # $ rake example 6 | 7 | require "lastpass" 8 | require "yaml" 9 | 10 | DEVICE_ID = "example.rb" 11 | 12 | credentials = YAML.load_file File.join File.dirname(__FILE__), "credentials.yaml" 13 | 14 | username = credentials["username"] 15 | password = credentials["password"] 16 | 17 | begin 18 | # First try without a multifactor password 19 | vault = LastPass::Vault.open_remote username, password, nil, DEVICE_ID 20 | rescue LastPass::LastPassIncorrectGoogleAuthenticatorCodeError => e 21 | # Get the code 22 | puts "Enter Google Authenticator code:" 23 | multifactor_password = gets.chomp 24 | 25 | # And now retry with the code 26 | vault = LastPass::Vault.open_remote username, password, multifactor_password, DEVICE_ID 27 | rescue LastPass::LastPassIncorrectYubikeyPasswordError => e 28 | # Get the password 29 | puts "Enter Yubikey password:" 30 | multifactor_password = gets.chomp 31 | 32 | # And now retry with the Yubikey password 33 | vault = LastPass::Vault.open_remote username, password, multifactor_password, DEVICE_ID 34 | end 35 | 36 | vault.accounts.each_with_index do |i, index| 37 | puts "#{index + 1}: #{i.id} #{i.name} #{i.username} #{i.password} #{i.url} #{i.group}" 38 | end 39 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Version 1.7.1 2 | ------------- 3 | 4 | - Updated httparty gem (thanks to Hethe Berg @growthcode) 5 | 6 | Version 1.7.0 7 | ------------- 8 | 9 | - Parse generic secure notes (thanks to Michael Chui @saraid) 10 | - Parse and store secure notes for accounts (see `Account.note` property) 11 | 12 | Version 1.6.1 13 | ------------- 14 | 15 | - Obsolete URI.encode is replaced with URI.encode_www_form_component to 16 | inhibit the warning 17 | - Travic CI runs on all 2.* latest minor version releases (2.0.0 to 2.7.1) 18 | 19 | Version 1.6.0 20 | ------------- 21 | 22 | - Changed the way the private keys are parsed 23 | - OpenSSL 1.1.0 support 24 | - Bug fixes 25 | 26 | Version 1.5.0 27 | ------------- 28 | 29 | - Fixed failing `get_iteraction_count`. POST parameters are moved from the 30 | query (URL) to the body. 31 | - pbkdf2-ruby gem is no longer used as it was causing problems. Relying on 32 | built-in `OpenSSL::PKCS5.pbkdf2_hmac` 33 | - Minimum supported Ruby version is 2.0.0 34 | - Dependencies updated to their laters versions 35 | - Travis CI fixed 36 | 37 | Version 1.4.0 38 | ------------- 39 | 40 | - Added device id (IMEI/UUID) support 41 | - Log out after fetching the blob to close the newly open session on LP server 42 | to prevent triggering anti-hacking logic (hopefully) 43 | - Verify that the recieved blob is marked with ENDM chunk and hasn't been 44 | truncated in the process 45 | 46 | 47 | Version 1.3.0 48 | ------------- 49 | 50 | - Added proxy support 51 | 52 | 53 | Version 1.2.1 54 | ------------- 55 | 56 | - Fixed the decryption bug on long shared folder names. 57 | 58 | 59 | Version 1.2.0 60 | ------------- 61 | 62 | - Server secure note support 63 | 64 | 65 | Version 1.1.0 66 | ------------- 67 | 68 | - Shared folder support 69 | 70 | 71 | Version 1.0.1 72 | ------------- 73 | 74 | - Ruby 2.0 compatibility 75 | 76 | 77 | Version 1.0.0 78 | ------------- 79 | 80 | - First public gem release 81 | -------------------------------------------------------------------------------- /spec/vault_spec.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "spec_helper" 5 | require "test_data" 6 | 7 | describe LastPass::Vault do 8 | let(:vault) { 9 | LastPass::Vault.new LastPass::Blob.new(TEST_BLOB, TEST_KEY_ITERATION_COUNT, nil), 10 | TEST_ENCRYPTION_KEY 11 | } 12 | 13 | describe ".new" do 14 | it "raises an exception on trucated blob" do 15 | [1, 2, 3, 4, 5, 10, 100, 1000].each do |i| 16 | expect { 17 | blob = TEST_BLOB[0..(-1 - i)] 18 | LastPass::Vault.new LastPass::Blob.new(blob, TEST_KEY_ITERATION_COUNT, nil), 19 | TEST_ENCRYPTION_KEY 20 | }.to raise_error LastPass::InvalidResponseError, "Blob is truncated" 21 | end 22 | end 23 | end 24 | 25 | describe "#accounts" do 26 | context "returned accounts" do 27 | it { expect(vault.accounts).to be_instance_of Array } 28 | 29 | it "should have correct IDs" do 30 | expect(vault.accounts.map &:id).to eq TEST_ACCOUNTS.map &:id 31 | end 32 | 33 | it "should have correct names" do 34 | expect(vault.accounts.map &:name).to eq TEST_ACCOUNTS.map &:name 35 | end 36 | 37 | it "should have correct usernames" do 38 | expect(vault.accounts.map &:username).to eq TEST_ACCOUNTS.map &:username 39 | end 40 | 41 | it "should have correct passwords" do 42 | expect(vault.accounts.map &:password).to eq TEST_ACCOUNTS.map &:password 43 | end 44 | 45 | it "should have correct urls" do 46 | expect(vault.accounts.map &:url).to eq TEST_ACCOUNTS.map &:url 47 | end 48 | 49 | it "should have correct notes" do 50 | expect(vault.accounts.map &:notes).to eq TEST_ACCOUNTS.map &:notes 51 | end 52 | 53 | it "should have correct groups" do 54 | expect(vault.accounts.map &:group).to eq TEST_ACCOUNTS.map &:group 55 | end 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /lib/lastpass/vault.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | class Vault 6 | attr_reader :accounts, :notes 7 | 8 | # Fetches a blob from the server and creates a vault 9 | def self.open_remote username, password, multifactor_password = nil, client_id = nil 10 | blob = Vault.fetch_blob username, password, multifactor_password, client_id 11 | open blob, username, password 12 | end 13 | 14 | # Creates a vault from a blob object 15 | def self.open blob, username, password 16 | new blob, blob.encryption_key(username, password) 17 | end 18 | 19 | # Just fetches the blob, could be used to store it locally 20 | def self.fetch_blob username, password, multifactor_password = nil, client_id = nil 21 | session = Fetcher.login username, password, multifactor_password, client_id 22 | blob = Fetcher.fetch session 23 | Fetcher.logout session 24 | 25 | blob 26 | end 27 | 28 | # This more of an internal method, use one of the static constructors instead 29 | def initialize blob, encryption_key 30 | chunks = Parser.extract_chunks blob 31 | if !complete? chunks 32 | raise InvalidResponseError, "Blob is truncated" 33 | end 34 | 35 | private_key = nil 36 | if blob.encrypted_private_key 37 | private_key = Parser.parse_private_key blob.encrypted_private_key, encryption_key 38 | end 39 | 40 | @accounts, @notes = parse_accounts_and_notes chunks, encryption_key, private_key 41 | end 42 | 43 | def accounts_and_notes 44 | @accounts_and_notes ||= @accounts + @notes 45 | end 46 | 47 | def complete? chunks 48 | !chunks.empty? && chunks.last.id == "ENDM" && chunks.last.payload == "OK" 49 | end 50 | 51 | def parse_accounts_and_notes chunks, encryption_key, private_key 52 | accounts = [] 53 | notes = [] 54 | key = encryption_key 55 | 56 | chunks.each do |i| 57 | case i.id 58 | when "ACCT" 59 | # TODO: Put shared folder name as group in the account 60 | account = Parser.parse_ACCT i, key 61 | case account 62 | when Account 63 | accounts << account 64 | when Note 65 | notes << account 66 | end 67 | when "SHAR" 68 | raise "private_key must be provided" if !private_key 69 | 70 | # After SHAR chunk all the folliwing accounts are enrypted with a new key 71 | key = Parser.parse_SHAR(i, encryption_key, private_key)[:encryption_key] 72 | end 73 | end 74 | 75 | [accounts, notes] 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LastPass Ruby API 2 | ================= 3 | 4 | [![Build Status](https://travis-ci.org/detunized/lastpass-ruby.svg?branch=master)](https://travis-ci.org/detunized/lastpass-ruby) 5 | [![Coverage Status](https://coveralls.io/repos/detunized/lastpass-ruby/badge.svg?branch=master)](https://coveralls.io/r/detunized/lastpass-ruby?branch=master) 6 | [![Code Climate](https://codeclimate.com/github/detunized/lastpass-ruby.svg)](https://codeclimate.com/github/detunized/lastpass-ruby) 7 | [![Dependency Status](https://gemnasium.com/detunized/lastpass-ruby.svg)](https://gemnasium.com/detunized/lastpass-ruby) 8 | 9 | ## No longer supported 10 | 11 | This project is no longer supported. There's a fully supported and regularly 12 | updated C# library that implements access to a veriety of password managers, 13 | including LastPass. Please check out 14 | [Password Manager Access](https://github.com/detunized/password-manager-access). 15 | 16 | --- 17 | 18 | **This is unofficial LastPass API.** 19 | 20 | There are also [a C#/.NET port](https://github.com/detunized/lastpass-sharp) and [a Python port](https://github.com/konomae/lastpass-python) available. 21 | 22 | This library implements fetching and parsing of LastPass data. The library is 23 | still in the proof of concept stage and doesn't support all LastPass features 24 | yet. Only account information (logins, passwords, urls, etc.) is available so 25 | far. 26 | 27 | There is a low level API which is used to fetch the data from the LastPass 28 | server and parse it. Normally this is not the one you would want to use. What 29 | you want is the `Vault` class which hides all the complexity and exposes all 30 | the accounts already parsed, decrypted and ready to use. See the example 31 | program for detail. 32 | 33 | A quick example of accessing your account information: 34 | 35 | ```ruby 36 | require "lastpass.rb" 37 | 38 | vault = LastPass::Vault.open_remote "username", "password" 39 | vault.accounts.each do |i| 40 | puts "#{i.name}: #{i.username}, #{i.password} (#{i.url})" 41 | end 42 | ``` 43 | 44 | 45 | A multifactor password (YubiKey, Google Authenticator) can optionally be appended to 46 | the login credentials: 47 | 48 | ```ruby 49 | vault = LastPass::Vault.open_remote "username", "password", "multifactor_password" 50 | ``` 51 | 52 | The blob received from LastPass could be safely stored locally (it's well 53 | encrypted) and reused later on. 54 | 55 | LostPass iOS App 56 | ---------------- 57 | 58 | There's an iOS app called [LostPass](http://detunized.net/lostpass/) that is 59 | based on a totally incomplete C++ port of this library. If you are a LastPass 60 | user it would have made your life much easier if I didn't have to take it down 61 | from the App Store. Now it's open source and if you have a developer account 62 | or a jailbroken phone you could build it and install it on the phone. The 63 | source code is [here](https://github.com/detunized/LostPass). 64 | 65 | 66 | Contributing 67 | ------------ 68 | 69 | Contribution in any form and shape is very welcome. Have comments, 70 | suggestions, patches, pull requests? All of the above are welcome. 71 | 72 | 73 | Thanks 74 | ------ 75 | 76 | - [Chris D'Ambrosio](https://github.com/chrisdambrosio) for adding proxy support 77 | 78 | 79 | License 80 | ------- 81 | 82 | The library is released under [the MIT 83 | license](http://www.opensource.org/licenses/mit-license.php). 84 | -------------------------------------------------------------------------------- /lib/lastpass/fetcher.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | class Fetcher 6 | def self.login username, password, multifactor_password = nil, client_id = nil 7 | key_iteration_count = request_iteration_count username 8 | request_login username, password, key_iteration_count, multifactor_password, client_id 9 | end 10 | 11 | def self.logout session, web_client = http 12 | response = web_client.get "https://lastpass.com/logout.php?method=cli&noredirect=1", 13 | cookies: {"PHPSESSID" => URI.encode_www_form_component(session.id)} 14 | 15 | raise NetworkError unless response.response.is_a? Net::HTTPOK 16 | end 17 | 18 | def self.fetch session, web_client = http 19 | response = web_client.get "https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=cli", 20 | format: :plain, 21 | cookies: {"PHPSESSID" => URI.encode_www_form_component(session.id)} 22 | 23 | raise NetworkError unless response.response.is_a? Net::HTTPOK 24 | 25 | Blob.new decode_blob(response.parsed_response), 26 | session.key_iteration_count, 27 | session.encrypted_private_key 28 | end 29 | 30 | def self.request_iteration_count username, web_client = http 31 | response = web_client.post "https://lastpass.com/iterations.php", 32 | body: {email: username} 33 | 34 | raise NetworkError unless response.response.is_a? Net::HTTPOK 35 | 36 | begin 37 | count = Integer response.parsed_response 38 | rescue ArgumentError 39 | raise InvalidResponseError, "Key iteration count is invalid" 40 | end 41 | 42 | raise InvalidResponseError, "Key iteration count is not positive" unless count > 0 43 | 44 | count 45 | end 46 | 47 | def self.request_login username, 48 | password, 49 | key_iteration_count, 50 | multifactor_password = nil, 51 | client_id = nil, 52 | web_client = http 53 | 54 | body = { 55 | method: "cli", 56 | xml: 2, 57 | username: username, 58 | hash: make_hash(username, password, key_iteration_count), 59 | iterations: key_iteration_count, 60 | includeprivatekeyenc: 1 61 | } 62 | 63 | body[:otp] = multifactor_password if multifactor_password 64 | body[:imei] = client_id if client_id 65 | 66 | response = web_client.post "https://lastpass.com/login.php", 67 | format: :xml, 68 | body: body 69 | 70 | raise NetworkError unless response.response.is_a? Net::HTTPOK 71 | 72 | parsed_response = response.parsed_response 73 | raise InvalidResponseError unless parsed_response.is_a? Hash 74 | 75 | create_session parsed_response, key_iteration_count or 76 | raise login_error parsed_response 77 | end 78 | 79 | def self.create_session parsed_response, key_iteration_count 80 | ok = (parsed_response["response"] || {})["ok"] 81 | if ok.is_a? Hash 82 | session_id = ok["sessionid"] 83 | if session_id.is_a? String 84 | private_key = ok["privatekeyenc"] 85 | private_key = nil if private_key == "" 86 | 87 | return Session.new session_id, key_iteration_count, private_key 88 | end 89 | end 90 | 91 | nil 92 | end 93 | 94 | def self.login_error parsed_response 95 | error = (parsed_response["response"] || {})["error"] 96 | return UnknownResponseSchemaError unless error.is_a? Hash 97 | 98 | exceptions = { 99 | "unknownemail" => LastPassUnknownUsernameError, 100 | "unknownpassword" => LastPassInvalidPasswordError, 101 | "googleauthrequired" => LastPassIncorrectGoogleAuthenticatorCodeError, 102 | "googleauthfailed" => LastPassIncorrectGoogleAuthenticatorCodeError, 103 | "otprequired" => LastPassIncorrectYubikeyPasswordError, 104 | } 105 | 106 | cause = error["cause"] 107 | message = error["message"] 108 | 109 | if cause 110 | (exceptions[cause] || LastPassUnknownError).new message || cause 111 | else 112 | InvalidResponseError.new message 113 | end 114 | end 115 | 116 | def self.decode_blob blob 117 | # TODO: Check for invalid base64 118 | Base64.decode64 blob 119 | end 120 | 121 | def self.make_key username, password, key_iteration_count 122 | if key_iteration_count == 1 123 | Digest::SHA256.digest username + password 124 | else 125 | OpenSSL::PKCS5.pbkdf2_hmac password, username, key_iteration_count, 32, "sha256" 126 | end 127 | end 128 | 129 | def self.make_hash username, password, key_iteration_count 130 | if key_iteration_count == 1 131 | Digest::SHA256.hexdigest Digest.hexencode(make_key(username, password, 1)) + password 132 | else 133 | Digest.hexencode OpenSSL::PKCS5.pbkdf2_hmac make_key(username, password, key_iteration_count), 134 | password, 135 | 1, 136 | 32, 137 | "sha256" 138 | end 139 | end 140 | 141 | def self.http 142 | @http ||= HTTP 143 | end 144 | 145 | def self.http= client 146 | @http = client 147 | end 148 | 149 | # Can't instantiate Fetcher 150 | private_class_method :new 151 | end 152 | end 153 | -------------------------------------------------------------------------------- /lib/lastpass/parser.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | module LastPass 5 | class Parser 6 | # OpenSSL constant 7 | RSA_PKCS1_OAEP_PADDING = 4 8 | 9 | # Secure note types that contain account-like information 10 | ACCOUNT_LIKE_SECURE_NOTE_TYPES = { 11 | "Server" => true, 12 | "Email Account" => true, 13 | "Database" => true, 14 | "Instant Messenger" => true, 15 | } 16 | 17 | # Splits the blob into chucks grouped by kind. 18 | def self.extract_chunks blob 19 | chunks = [] 20 | 21 | StringIO.open blob.bytes do |stream| 22 | while !stream.eof? 23 | chunks.push read_chunk stream 24 | end 25 | end 26 | 27 | chunks 28 | end 29 | 30 | # Parses an account chunk, decrypts and creates an Account object. 31 | # Returns either an Account or a Note object, in case of a generic 32 | # note that doesn't represent an account. All secure notes are ACCTs 33 | # but not all of them store account information. 34 | # 35 | # TODO: Make a test case that covers secure note account 36 | def self.parse_ACCT chunk, encryption_key 37 | StringIO.open chunk.payload do |io| 38 | id = read_item io 39 | name = decode_aes256_plain_auto read_item(io), encryption_key 40 | group = decode_aes256_plain_auto read_item(io), encryption_key 41 | url = decode_hex read_item io 42 | notes = decode_aes256_plain_auto read_item(io), encryption_key 43 | 2.times { skip_item io } 44 | username = decode_aes256_plain_auto read_item(io), encryption_key 45 | password = decode_aes256_plain_auto read_item(io), encryption_key 46 | 2.times { skip_item io } 47 | secure_note = read_item io 48 | 49 | # Parse secure note 50 | if secure_note == "1" 51 | parsed = parse_secure_note_server notes 52 | if !ACCOUNT_LIKE_SECURE_NOTE_TYPES.key? parsed[:type] 53 | return Note.new id, name, notes, group 54 | end 55 | 56 | url = parsed[:url] if parsed.key? :url 57 | username = parsed[:username] if parsed.key? :username 58 | password = parsed[:password] if parsed.key? :password 59 | end 60 | 61 | Account.new id, name, username, password, url, notes, group 62 | end 63 | end 64 | 65 | # TODO: Fake some data and make a test 66 | def self.parse_SHAR chunk, encryption_key, rsa_key 67 | StringIO.open chunk.payload do |io| 68 | id = read_item io 69 | encrypted_key = decode_hex read_item io 70 | encrypted_name = read_item io 71 | 2.times { skip_item io } 72 | key = read_item io 73 | 74 | # Shared folder encryption key might come already in pre-decrypted form, 75 | # where it's only AES encrypted with the regular encryption key. 76 | # When the key is blank, then there's a RSA encrypted key, which has to 77 | # be decrypted first before use. 78 | key = if key.empty? 79 | decode_hex rsa_key.private_decrypt(encrypted_key, RSA_PKCS1_OAEP_PADDING) 80 | else 81 | decode_hex decode_aes256_plain_auto(key, encryption_key) 82 | end 83 | 84 | name = decode_aes256_base64_auto encrypted_name, key 85 | 86 | # TODO: Return an object, not a hash 87 | {id: id, name: name, encryption_key: key} 88 | end 89 | end 90 | 91 | # Parse and decrypt the encrypted private RSA key 92 | def self.parse_private_key encrypted_private_key, encryption_key 93 | decrypted = decode_aes256 "cbc", 94 | encryption_key[0, 16], 95 | decode_hex(encrypted_private_key), 96 | encryption_key 97 | 98 | /^LastPassPrivateKey<(?.*)>LastPassPrivateKey$/ =~ decrypted 99 | asn1_encoded_all = OpenSSL::ASN1.decode decode_hex hex_key 100 | asn1_encoded_key = OpenSSL::ASN1.decode asn1_encoded_all.value[2].value 101 | 102 | rsa_key = OpenSSL::PKey::RSA.new 103 | n = asn1_encoded_key.value[1].value 104 | e = asn1_encoded_key.value[2].value 105 | d = asn1_encoded_key.value[3].value 106 | p = asn1_encoded_key.value[4].value 107 | q = asn1_encoded_key.value[5].value 108 | dmp1 = asn1_encoded_key.value[6].value 109 | dmq1 = asn1_encoded_key.value[7].value 110 | iqmp = asn1_encoded_key.value[8].value 111 | 112 | if rsa_key.respond_to? :set_key 113 | rsa_key.set_key n, e, d 114 | rsa_key.set_factors p, q 115 | rsa_key.set_crt_params dmp1, dmq1, iqmp 116 | else 117 | rsa_key.n = n 118 | rsa_key.e = e 119 | rsa_key.d = d 120 | rsa_key.p = p 121 | rsa_key.q = q 122 | rsa_key.dmp1 = dmp1 123 | rsa_key.dmq1 = dmq1 124 | rsa_key.iqmp = iqmp 125 | end 126 | 127 | rsa_key 128 | end 129 | 130 | def self.parse_secure_note_server notes 131 | info = {} 132 | 133 | notes.split("\n").each do |i| 134 | key, value = i.split ":", 2 135 | case key 136 | when "NoteType" 137 | info[:type] = value 138 | when "Hostname" 139 | info[:url] = value 140 | when "Username" 141 | info[:username] = value 142 | when "Password" 143 | info[:password] = value 144 | end 145 | end 146 | 147 | info 148 | end 149 | 150 | # Reads one chunk from a stream and creates a Chunk object with the data read. 151 | def self.read_chunk stream 152 | # LastPass blob chunk is made up of 4-byte ID, 153 | # big endian 4-byte size and payload of that size. 154 | # 155 | # Example: 156 | # 0000: "IDID" 157 | # 0004: 4 158 | # 0008: 0xDE 0xAD 0xBE 0xEF 159 | # 000C: --- Next chunk --- 160 | Chunk.new read_id(stream), read_payload(stream, read_size(stream)) 161 | end 162 | 163 | # Reads an item from a stream and returns it as a string of bytes. 164 | def self.read_item stream 165 | # An item in an itemized chunk is made up of the 166 | # big endian size and the payload of that size. 167 | # 168 | # Example: 169 | # 0000: 4 170 | # 0004: 0xDE 0xAD 0xBE 0xEF 171 | # 0008: --- Next item --- 172 | read_payload stream, read_size(stream) 173 | end 174 | 175 | # Skips an item in a stream. 176 | def self.skip_item stream 177 | read_item stream 178 | end 179 | 180 | # Reads a chunk ID from a stream. 181 | def self.read_id stream 182 | stream.read 4 183 | end 184 | 185 | # Reads a chunk or an item ID. 186 | def self.read_size stream 187 | read_uint32 stream 188 | end 189 | 190 | # Reads a payload of a given size from a stream. 191 | def self.read_payload stream, size 192 | stream.read size 193 | end 194 | 195 | # Reads an unsigned 32 bit integer from a stream. 196 | def self.read_uint32 stream 197 | stream.read(4).unpack("N").first 198 | end 199 | 200 | # Decodes a hex encoded string into raw bytes. 201 | def self.decode_hex data 202 | raise ArgumentError, "Input length must be multple of 2" unless data.size % 2 == 0 203 | raise ArgumentError, "Input contains invalid characters" unless data =~ /^[0-9a-f]*$/i 204 | 205 | data.scan(/../).map { |i| i.to_i 16 }.pack "c*" 206 | end 207 | 208 | # Decodes a base64 encoded string into raw bytes. 209 | def self.decode_base64 data 210 | # TODO: Check for input validity! 211 | Base64.decode64 data 212 | end 213 | 214 | # Guesses AES cipher (EBC or CBD) from the length of the plain data. 215 | def self.decode_aes256_plain_auto data, encryption_key 216 | length = data.length 217 | 218 | if length == 0 219 | "" 220 | elsif data[0] == "!" && length % 16 == 1 && length > 32 221 | decode_aes256_cbc_plain data, encryption_key 222 | else 223 | decode_aes256_ecb_plain data, encryption_key 224 | end 225 | end 226 | 227 | # Guesses AES cipher (EBC or CBD) from the length of the base64 encoded data. 228 | def self.decode_aes256_base64_auto data, encryption_key 229 | length = data.length 230 | 231 | if length == 0 232 | "" 233 | elsif data[0] == "!" 234 | decode_aes256_cbc_base64 data, encryption_key 235 | else 236 | decode_aes256_ecb_base64 data, encryption_key 237 | end 238 | end 239 | 240 | # Decrypts AES-256 ECB bytes. 241 | def self.decode_aes256_ecb_plain data, encryption_key 242 | if data.empty? 243 | "" 244 | else 245 | decode_aes256 :ecb, "", data, encryption_key 246 | end 247 | end 248 | 249 | # Decrypts base64 encoded AES-256 ECB bytes. 250 | def self.decode_aes256_ecb_base64 data, encryption_key 251 | decode_aes256_ecb_plain decode_base64(data), encryption_key 252 | end 253 | 254 | # Decrypts AES-256 CBC bytes. 255 | def self.decode_aes256_cbc_plain data, encryption_key 256 | if data.empty? 257 | "" 258 | else 259 | # LastPass AES-256/CBC encryted string starts with an "!". 260 | # Next 16 bytes are the IV for the cipher. 261 | # And the rest is the encrypted payload. 262 | 263 | # TODO: Check for input validity! 264 | decode_aes256 :cbc, 265 | data[1, 16], 266 | data[17..-1], 267 | encryption_key 268 | end 269 | end 270 | 271 | # Decrypts base64 encoded AES-256 CBC bytes. 272 | def self.decode_aes256_cbc_base64 data, encryption_key 273 | if data.empty? 274 | "" 275 | else 276 | # LastPass AES-256/CBC/base64 encryted string starts with an "!". 277 | # Next 24 bytes are the base64 encoded IV for the cipher. 278 | # Then comes the "|". 279 | # And the rest is the base64 encoded encrypted payload. 280 | 281 | # TODO: Check for input validity! 282 | decode_aes256 :cbc, 283 | decode_base64(data[1, 24]), 284 | decode_base64(data[26..-1]), 285 | encryption_key 286 | end 287 | end 288 | 289 | # Decrypt AES-256 bytes. 290 | # Allowed ciphers are: :ecb, :cbc. 291 | # If for :ecb iv is not used and should be set to "". 292 | def self.decode_aes256 cipher, iv, data, encryption_key 293 | aes = OpenSSL::Cipher.new "aes-256-#{cipher}" 294 | aes.decrypt 295 | aes.key = encryption_key 296 | aes.iv = iv 297 | aes.update(data) + aes.final 298 | end 299 | end 300 | end 301 | -------------------------------------------------------------------------------- /spec/fetcher_spec.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "spec_helper" 5 | 6 | describe LastPass::Fetcher do 7 | let(:username) { "username" } 8 | let(:password) { "password" } 9 | let(:key_iteration_count) { 5000 } 10 | 11 | let(:hash) { "7880a04588cfab954aa1a2da98fd9c0d2c6eba4c53e36a94510e6dbf30759256" } 12 | let(:session_id) { "53ru,Hb713QnEVM5zWZ16jMvxS0" } 13 | let(:escaped_session_id) { "53ru%2CHb713QnEVM5zWZ16jMvxS0" } 14 | let(:session) { LastPass::Session.new session_id, key_iteration_count, "DEADBEEF" } 15 | 16 | let(:blob_response) { "TFBBVgAAAAMxMjJQUkVNAAAACjE0MTQ5" } 17 | let(:blob_bytes) { blob_response.decode64 } 18 | let(:blob) { LastPass::Blob.new blob_bytes, key_iteration_count, "DEADBEEF" } 19 | 20 | let(:login_post_data) { {method: "cli", 21 | xml: 2, 22 | username: username, 23 | hash: hash, 24 | iterations: key_iteration_count, 25 | includeprivatekeyenc: 1} } 26 | 27 | let(:device_id) { "492378378052455" } 28 | let(:login_post_data_with_device_id) { login_post_data.merge({imei: device_id}) } 29 | 30 | let(:google_authenticator_code) { "123456" } 31 | let(:yubikey_password) { "emdbwzemyisymdnevznyqhqnklaqheaxszzvtnxjrmkb" } 32 | 33 | let(:login_post_data_with_google_authenticator_code) { login_post_data.merge({otp: google_authenticator_code}) } 34 | let(:login_post_data_with_yubikey_password) { login_post_data.merge({otp: yubikey_password}) } 35 | 36 | describe ".logout" do 37 | it "makes a GET request" do 38 | web_client = double "web_client" 39 | expect(web_client).to receive(:get) 40 | .with("https://lastpass.com/logout.php?method=cli&noredirect=1", cookies: {"PHPSESSID" => escaped_session_id}) 41 | .and_return(http_ok "") 42 | LastPass::Fetcher.logout session, web_client 43 | end 44 | 45 | it "raises an exception on HTTP error" do 46 | expect { 47 | LastPass::Fetcher.logout session, double("web_client", get: http_error) 48 | }.to raise_error LastPass::NetworkError 49 | end 50 | end 51 | 52 | describe ".request_iteration_count" do 53 | it "makes a POST request" do 54 | expect(web_client = double("web_client")).to receive(:post) 55 | .with("https://lastpass.com/iterations.php", body: {email: username}) 56 | .and_return(http_ok(key_iteration_count.to_s)) 57 | 58 | LastPass::Fetcher.request_iteration_count username, web_client 59 | end 60 | 61 | it "returns key iteration count" do 62 | expect( 63 | LastPass::Fetcher.request_iteration_count username, 64 | double("web_client", post: http_ok(key_iteration_count.to_s)) 65 | ).to eq key_iteration_count 66 | end 67 | 68 | it "raises an exception on HTTP error" do 69 | expect { 70 | LastPass::Fetcher.request_iteration_count username, 71 | double("web_client", post: http_error) 72 | }.to raise_error LastPass::NetworkError 73 | end 74 | 75 | it "raises an exception on invalid key iteration count" do 76 | expect { 77 | LastPass::Fetcher.request_iteration_count username, 78 | double("web_client", post: http_ok("not a number")) 79 | }.to raise_error LastPass::InvalidResponseError, "Key iteration count is invalid" 80 | end 81 | 82 | it "raises an exception on zero key iteration count" do 83 | expect { 84 | LastPass::Fetcher.request_iteration_count username, 85 | double("web_client", post: http_ok("0")) 86 | }.to raise_error LastPass::InvalidResponseError, "Key iteration count is not positive" 87 | end 88 | 89 | it "raises an exception on negative key iteration count" do 90 | expect { 91 | LastPass::Fetcher.request_iteration_count username, 92 | double("web_client", post: http_ok("-1")) 93 | }.to raise_error LastPass::InvalidResponseError, "Key iteration count is not positive" 94 | end 95 | end 96 | 97 | describe ".request_login" do 98 | def verify_post_request multifactor_password, device_id, post_data 99 | web_client = double("web_client") 100 | expect(web_client).to receive(:post) 101 | .with("https://lastpass.com/login.php", format: :xml, body: post_data) 102 | .and_return(http_ok("response" => {"ok" => {"sessionid" => session_id, "privatekeyenc" => "DEADBEEF"}})) 103 | 104 | LastPass::Fetcher.request_login username, 105 | password, 106 | key_iteration_count, 107 | multifactor_password, 108 | device_id, 109 | web_client 110 | end 111 | 112 | it "makes a POST request" do 113 | verify_post_request nil, nil, login_post_data 114 | end 115 | 116 | it "makes a POST request with device id" do 117 | verify_post_request nil, device_id, login_post_data_with_device_id 118 | end 119 | 120 | it "makes a POST request with Google Authenticator code" do 121 | verify_post_request google_authenticator_code, nil, login_post_data_with_google_authenticator_code 122 | end 123 | 124 | it "makes a POST request with Yubikey password" do 125 | verify_post_request yubikey_password, nil, login_post_data_with_yubikey_password 126 | end 127 | 128 | it "returns a session" do 129 | expect(request_login_with_xml "").to eq session 130 | end 131 | 132 | it "raises an exception on HTTP error" do 133 | expect { request_login_with_error }.to raise_error LastPass::NetworkError 134 | end 135 | 136 | it "raises an exception when response is not a hash" do 137 | expect { request_login_with_ok "not a hash" }.to raise_error LastPass::InvalidResponseError 138 | end 139 | 140 | it "raises an exception on unknown response schema" do 141 | expect { request_login_with_xml "" }.to raise_error LastPass::UnknownResponseSchemaError 142 | end 143 | 144 | it "raises an exception on unknown response schema" do 145 | expect { request_login_with_xml "" }.to raise_error LastPass::UnknownResponseSchemaError 146 | end 147 | 148 | it "raises an exception on unknown response schema" do 149 | expect { request_login_with_xml "" } 150 | .to raise_error LastPass::UnknownResponseSchemaError 151 | end 152 | 153 | it "raises an exception on unknown username" do 154 | message = "Unknown email address." 155 | expect { request_login_with_lastpass_error "unknownemail", message } 156 | .to raise_error LastPass::LastPassUnknownUsernameError, message 157 | end 158 | 159 | it "raises an exception on invalid password" do 160 | message = "Invalid password!" 161 | expect { request_login_with_lastpass_error "unknownpassword", message } 162 | .to raise_error LastPass::LastPassInvalidPasswordError, message 163 | end 164 | 165 | it "raises an exception on missing Google Authenticator code" do 166 | message = "Google Authenticator authentication required! " + 167 | "Upgrade your browser extension so you can enter it." 168 | expect { request_login_with_lastpass_error "googleauthrequired", message } 169 | .to raise_error LastPass::LastPassIncorrectGoogleAuthenticatorCodeError, message 170 | end 171 | 172 | it "raises an exception on incorrect Google Authenticator code" do 173 | message = "Google Authenticator authentication failed!" 174 | expect { request_login_with_lastpass_error "googleauthfailed", message } 175 | .to raise_error LastPass::LastPassIncorrectGoogleAuthenticatorCodeError, message 176 | end 177 | 178 | it "raises an exception on missing/incorrect Yubikey password" do 179 | message = "Your account settings have restricted you from logging in " + 180 | "from mobile devices that do not support YubiKey authentication." 181 | expect { request_login_with_lastpass_error "otprequired", message } 182 | .to raise_error LastPass::LastPassIncorrectYubikeyPasswordError, message 183 | end 184 | 185 | it "raises an exception on unknown LastPass error with a message" do 186 | message = "Unknow error message" 187 | expect { request_login_with_lastpass_error "Unknown cause", message } 188 | .to raise_error LastPass::LastPassUnknownError, message 189 | end 190 | 191 | it "raises an exception on unknown LastPass error without a message" do 192 | cause = "Unknown casue" 193 | expect { request_login_with_lastpass_error cause } 194 | .to raise_error LastPass::LastPassUnknownError, cause 195 | end 196 | end 197 | 198 | describe ".fetch" do 199 | it "makes a GET request" do 200 | expect(web_client = double("web_client")).to receive(:get) 201 | .with("https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=cli", 202 | format: :plain, 203 | cookies: {"PHPSESSID" => escaped_session_id}) 204 | .and_return(http_ok(blob_response)) 205 | 206 | LastPass::Fetcher.fetch session, web_client 207 | end 208 | 209 | it "returns a blob" do 210 | expect(LastPass::Fetcher.fetch session, double("web_client", get: http_ok(blob_response))) 211 | .to eq blob 212 | end 213 | 214 | it "raises an exception on HTTP error" do 215 | expect { 216 | LastPass::Fetcher.fetch session, double("web_client", get: http_error) 217 | } .to raise_error LastPass::NetworkError 218 | end 219 | end 220 | 221 | describe ".make_key" do 222 | it "generates correct keys" do 223 | def key iterations 224 | LastPass::Fetcher.make_key "postlass@gmail.com", "pl1234567890", iterations 225 | end 226 | 227 | expect(key 1).to eq "C/Bh2SGWxI8JDu54DbbpV8J9wa6pKbesIb9MAXkeF3Y=".decode64 228 | expect(key 5).to eq "pE9goazSCRqnWwcixWM4NHJjWMvB5T15dMhe6ug1pZg=".decode64 229 | expect(key 10).to eq "n9S0SyJdrMegeBHtkxUx8Lzc7wI6aGl+y3/udGmVey8=".decode64 230 | expect(key 50).to eq "GwI8/kNy1NjIfe3Z0VAZfF78938UVuCi6xAL3MJBux0=".decode64 231 | expect(key 100).to eq "piGdSULeHMWiBS3QJNM46M5PIYwQXA6cNS10pLB3Xf8=".decode64 232 | expect(key 500).to eq "OfOUvVnQzB4v49sNh4+PdwIFb9Fr5+jVfWRTf+E2Ghg=".decode64 233 | expect(key 1000).to eq "z7CdwlIkbu0XvcB7oQIpnlqwNGemdrGTBmDKnL9taPg=".decode64 234 | end 235 | end 236 | 237 | describe ".make_hash" do 238 | it "generates correct hashes" do 239 | def hash iterations 240 | LastPass::Fetcher.make_hash "postlass@gmail.com", "pl1234567890", iterations 241 | end 242 | 243 | expect(hash 1).to eq "a1943cfbb75e37b129bbf78b9baeab4ae6dd08225776397f66b8e0c7a913a055" 244 | expect(hash 5).to eq "a95849e029a7791cfc4503eed9ec96ab8675c4a7c4e82b00553ddd179b3d8445" 245 | expect(hash 10).to eq "0da0b44f5e6b7306f14e92de6d629446370d05afeb1dc07cfcbe25f169170c16" 246 | expect(hash 50).to eq "1d5bc0d636da4ad469cefe56c42c2ff71589facb9c83f08fcf7711a7891cc159" 247 | expect(hash 100).to eq "82fc12024acb618878ba231a9948c49c6f46e30b5a09c11d87f6d3338babacb5" 248 | expect(hash 500).to eq "3139861ae962801b59fc41ff7eeb11f84ca56d810ab490f0d8c89d9d9ab07aa6" 249 | expect(hash 1000).to eq "03161354566c396fcd624a424164160e890e96b4b5fa6d942fc6377ab613513b" 250 | end 251 | end 252 | 253 | # 254 | # Helpers 255 | # 256 | 257 | private 258 | 259 | def mock_response type, code, body 260 | double response: type.new("1.1", code, ""), 261 | parsed_response: body 262 | end 263 | 264 | def http_ok body 265 | mock_response Net::HTTPOK, 200, body 266 | end 267 | 268 | def http_error body = "" 269 | mock_response Net::HTTPNotFound, 404, body 270 | end 271 | 272 | def xml text 273 | MultiXml.parse text 274 | end 275 | 276 | def lastpass_error cause, message 277 | if message 278 | %Q{} 279 | else 280 | %Q{} 281 | end 282 | end 283 | 284 | def request_login_with_lastpass_error cause, message = nil 285 | request_login_with_xml lastpass_error cause, message 286 | end 287 | 288 | def request_login_with_xml text 289 | request_login_with_ok xml text 290 | end 291 | 292 | def request_login_with_ok response 293 | request_login_with_response http_ok response 294 | end 295 | 296 | def request_login_with_error 297 | request_login_with_response http_error 298 | end 299 | 300 | def request_login_with_response response 301 | LastPass::Fetcher.request_login username, 302 | password, 303 | key_iteration_count, 304 | nil, 305 | nil, 306 | double("web_client", post: response) 307 | end 308 | end 309 | -------------------------------------------------------------------------------- /spec/parser_spec.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require "spec_helper" 5 | require_relative "test_data" 6 | 7 | describe LastPass::Parser do 8 | let(:key_iteration_count) { 5000 } 9 | let(:blob) { LastPass::Blob.new TEST_BLOB, key_iteration_count, "DEADBEEF" } 10 | let(:padding) { "BEEFFACE"} 11 | let(:encryption_key) { "OfOUvVnQzB4v49sNh4+PdwIFb9Fr5+jVfWRTf+E2Ghg=".decode64 } 12 | let(:encoded_rsa_key) { "98F3F5518AE7C03EBBF195A616361619033509FB1FFA0408E883B7C5E80381F8" + 13 | "C8A343925DDA78FB06A14324BEC77EAF63290D381F54763A2793FE25C3247FC0" + 14 | "29022687F453426DE96A9FB34CEB55C02764FB41E5E1619226FE47FA7EA40B41" + 15 | "0973132F7AB2DE2D7F08C181C7D56BBF92CD4D44BC7DEE4253DEC36C77D28E30" + 16 | "6F41B8BB26B0EDB97BADCEE912D3671C22339036FC064F5AF60D3545D47B8263" + 17 | "6BBA1896ECDCF5EBE99A1061EFB8FBBD6C3500EA06A28BB8863F413702D9C05B" + 18 | "9A54120F1BEFA0D98A48E82622A36DBD79772B5E4AD957045DC2B97311983592" + 19 | "A357037DDA172C284B4FEC7DF8962A11B42079D6F943C8F9C0FEDFEA0C43A362" + 20 | "B550E217715FD82D9F3BB168A006B0880B1F3660076158FE8CF6B706CF2FEAA1" + 21 | "A731D1F68B1BC20E7ADE15097D2CD84606B4B0756DFE25DAF110D62841F44265" + 22 | "73A676B904972B31AD7B02093C536341E1DA943F1AFF88DF2005BD04C6897FB6" + 23 | "F9E307DA1C2BD219AB39F911FF90C6B1EA658C72C67C1EADC36CD5202654B4E1" + 24 | "99A88F13DCE1148CC04F81485896627BB1DB5C73969520CC66652492383930E3" + 25 | "3AFD57BE171F4BA25016EC9C3662F5B054101E381565433E46CB9FD517B59AE8" + 26 | "A5CE7D11005282E551E9DCAA1996763E41B49677F906F122AAB76E852F35B31F" + 27 | "397B70949D5F6C8DAA244AF16E9D48E0801E5C6D3FCEAFD2C3E157968B3E796C" + 28 | "87E1F3FFF86B62FE5263D1A597E3906BF697C019F1F543D7BB1E11B08837B47F" + 29 | "4528E4B47EB77508CFC0581B2A005383D0A238EA5BDE2E2602E0D2408B139735" + 30 | "F4BAF8D6CF260BBC81833A85F14C5746AC6081B878486F5A4BD23B821F3F5F6B" + 31 | "DAC8A9B57E25E24EDB8D701F01AE142D63A8A7D0F1CC8FAFF5F0320551CEB29B" + 32 | "DB6907C57E38602927AD7240003FEB238AC5437FE4BAD11BB5038CA74D539523" + 33 | "A167B8EBB1210608EB7DA53B4155D05B87D21848E58905EFA550EA5A51E0A68D" + 34 | "5FF0F9E0CC0D5105DD98BE9E2C41362794A71A573CCA87B57147115B86FC8A6B" + 35 | "B1778CED1920787271C75D69C5D63CD798915BF8F9877808F841F9269B2EA809" + 36 | "0E11F6C89FDB537F341142CA29BAC761E1CF9D58FFB0C44A26E5EF7FA14142C8" + 37 | "A84BC9304A221D5F961DB41B5925B06823A12A6F8950E47325021A747A02A28F" + 38 | "DAE65997EBDF5D2BDBCA7C8D689AE186A9FE85A170B76EE92595C9E33639C993" + 39 | "07C377FA4DA975E191810E993CDC0A33EE494B0EE8A1B6A9408285012967C17A" + 40 | "8CB5EE8E7973CF9186A98000FE00F1CC76420089C6BDCE9E39D403C320DF1135" + 41 | "1597FF8B231689389CCE12844289FEFE468BFCAEE9A2CFB1A8DD066AEC974DA9" + 42 | "C8530C9A17593E25DC89934E056B178329C4BBF7113657677AB25EE66A1E1D92" + 43 | "F62154B2451B37727F05B3AC0F2501F7A95845C9BE210D411028C27A9AD4B0E8" + 44 | "31A6C46D26883A8AA2D1E2BD3E8E122A6FC21CECB7AE2B91C6FCFA793C5CAFF6" + 45 | "53C6670D914A29EAD81CD5C29FFB048C81CC80EDD693B4D8091B2D5DE88EA042" + 46 | "11AC551F406B713278BD14667E437C610953D6186C2986BA60361C2013395E8E" + 47 | "A9D14CD00EC5C61147BE03D8965B5376DF32E2C3740128398E0D47900C888FD0" + 48 | "D1F7D583808AFBC0712806E11462B37815C20692FB38E61CC0B1AAF66A854982" + 49 | "6A1F5FFFF2436B0B9F9EDFF4F5B59B362AA1D25A4E3C398EB18445483F8419BD" + 50 | "1511A5177E9C4B7034375A2D91B95153535E6CD5F023F4EED0E15B5415A3B7A7" + 51 | "7E390AA698DF00F4FD897B0454C00959AF0CB54B272DE63968815B971C44B273" + 52 | "6AC737FAE6A19F544907833F13C6F424D30E3B85054A4402EC94079C1473C20B" + 53 | "E4C1B33525486BB098EF960082DB4DF5FE9CAF71681B03CB2D4BE7382FF0C03F" + 54 | "18144DE554256591773DC3F381116955233FDA7223D71C402E558783F221E25A" + 55 | "94FECD350654A9CD8EE8C39E4B1CFBA0D5FD46891527F2D0FC9EA61584A76D59" + 56 | "99719811B2BAFC99769E6911733ED389A731C327CB5D7BB6D79CE030D3285586" + 57 | "C6681FC8C110EFE30CEE883FFEF5FB511B4421863E2A15F8CDCFA7B84B931121" + 58 | "5B23093DE3B5E7F4CFCCE60BE7857B7442B8FCC3E43C46C4BFA3E9ABD2F479F6" + 59 | "BD8D3F3D36C0FAC1F4D72FBE96C644AB56F73CAF956D5544B2EB9C589ED30FF3" + 60 | "0BB03D09DB455764EF4A33C24F93170A98A21455826390B13A8F338A820EC08D" + 61 | "6E9F562282C2F815BB57CE511AB6B0DE75EFA63F28C6D0B25298CDAAC76742D5" + 62 | "353B26B77C1533B4DFE2D95F3E89315C0D806A90FCDFDC31CE04A9E29937680D" + 63 | "32D8B503352388109C1F5F41E8496302E13A61917F70A9AA3C5ECDBD88163E3C" + 64 | "F0580C5EB1382BB66194AC0983BAA16B4D220756F4B7E3DDFFC5BF343FA7E31D" + 65 | "14FED4409AD0FE9BBE01AF79DA4852253CBF166FDCA90E894B5267A502F73347" + 66 | "06F8C767EC861324CC7734352D76DB007E25105E7994CF91D79532221316F4DE" + 67 | "56BAE4351D3E3C6549FBFEF13BBE2636071794AD9EC3787B4A71E5438B86C358" + 68 | "65ECF2EA5980318F82D8B113C0EC8FEE41C243E0A1A09F373A0CF546FA18E1EC" + 69 | "7DB4842A6B8B03D115654222B87DA6034EFDE2224DBD23AB104BF3723856C03D" + 70 | "B639BA073F2CC8E4AB05BAADDB5DEACC1874F4D6F86B95710019114DACBFE48F" + 71 | "EF2AE2DF27356B5C17948B26A41FD1A8F07E8068E176F995910C373886DB47D2" + 72 | "6C2FE5CD97AAF1829EBC1EEBA4D88343A322E810385138F51F0E5149183699C4" + 73 | "05E49ED13C2889A22742893A52567B0F7D4A3BC9F4DC6D29F713AA7FB4EF6B13" + 74 | "5F92F598404A80E7D6515CE234AFA68A4B562AF203162C60D578F0D00E302958" + 75 | "174E1A712FD449D257C6AA5F56E4DBD0363573931463BC910858AF1EC40C1F4A" + 76 | "7BE27DE8E170D4AACF6C34B0CDE15190FD81FA5676136A4D73E2AA4BBFBB8E7C" + 77 | "1178EF47362188D9288E822B10BBF2C8BE075A5BD1D3E1F08108BA8C4E6FB173" + 78 | "DCECB5771E9D8AE4CD776EA3409DF30FA2252D3C3769AF12177F4A1929DC8E74" + 79 | "D5AEAC94CF94EEBA0E9AC012C57B40A8BB57530C25846B841005767B9AABE436" + 80 | "D4590977FDDA519B9B284CF8B8922A0E8B659ECE3745A95800EE1B3DDD33E0FF" + 81 | "230C0528BC7A4CB80604411E59E08775A42C634E93BA9C77D015659AC912F436" + 82 | "94F774E94050E4B3BF84290368D5AFD7F043BDCA3BD0CC8C0E267069B6F1386A" + 83 | "E1D9C8B5512AAAA292FDA9CA07E27BAF983E1E25A11732797425F2BB396B302E" + 84 | "0782BA183D4BC1F682365774520EAC8A321C7A0BD08027021EA0063D471E0AD1" + 85 | "E1469AD803C311D3FBF50B5538265D4262B6716D90E89A8C906D08533D650000" + 86 | "6BF1B8ABAAFE1CA3AFDD1A19ACABE5B86A804D36AE27163CAF390FD266D5FFEF" + 87 | "FC7CE6FEF9458E4AF0C4108E32EFD11C19751B1D9883E803F7C2E1A5786F3385" + 88 | "1A7CA3772ECD7CB0E9782A7D30E0A9FD09EED361B774A277C618C995FD7F7634" + 89 | "E7DB3834690B58DDFF6B721157D0EC02" } 90 | let(:rsa_key_encryption_key) { "v4uHomAR0tAXC3fA5Nfq7DjyJxuvYErMSCcZIWZKjpM=".decode64 } 91 | 92 | describe ".extract_chunks" do 93 | context "returned chunks" do 94 | let(:chunks) { LastPass::Parser.extract_chunks blob } 95 | 96 | it { expect(chunks).to be_instance_of Array } 97 | 98 | it "all values are instances of Chunk" do 99 | expect(chunks.map(&:class).uniq).to eq [LastPass::Chunk] 100 | end 101 | end 102 | end 103 | 104 | describe ".parse_ACCT" do 105 | let(:accounts) { 106 | LastPass::Parser 107 | .extract_chunks(blob) 108 | .select { |i| i.id == "ACCT" } 109 | .map { |i| LastPass::Parser.parse_ACCT i, TEST_ENCRYPTION_KEY } 110 | } 111 | 112 | it "parses accounts" do 113 | expect(accounts.map &:id).to eq TEST_ACCOUNTS.map &:id 114 | end 115 | end 116 | 117 | describe ".parse_private_key" do 118 | let(:rsa_key) { 119 | LastPass::Parser.parse_private_key encoded_rsa_key, rsa_key_encryption_key 120 | } 121 | 122 | it "parses private key" do 123 | expect(rsa_key).to be_instance_of OpenSSL::PKey::RSA 124 | expect(rsa_key.n.to_s).to eq "26119467519435514320618523953258926539081857789201" + 125 | "11592360794055150234493177840791445076164320959092" + 126 | "33977645519805962686071307052774013402170389235283" + 127 | "48398581900094955608774421569689169697285847986479" + 128 | "82303230642077254435741682688235176460351551099267" + 129 | "22581481667367599195203736002065084704013295528661" + 130 | "76687143747593851140122182044652173598693510643390" + 131 | "47711449981712845835960707676646864765530616733341" + 132 | "58401920829305659156984748726238485655720031774127" + 133 | "01900577710668575227691993026576480667273922300137" + 134 | "80405264300989392980537603337301835174777026188388" + 135 | "93147718435999645840214854231168704372464234421315" + 136 | "01138217872658041" 137 | expect(rsa_key.e.to_s).to eq "65537" 138 | expect(rsa_key.d.to_s).to eq "20217010678828834626882766446083366137418639853408" + 139 | "07494174069610076841252047428625473158347002598408" + 140 | "18346644251082549844764624454370315666751565294997" + 141 | "10533208173186395672159239558808345075823110774221" + 142 | "61501075434955107584446470508660844962452555542861" + 143 | "72030926355197158923586674949673551608716945271868" + 144 | "18816984671497443384191412119383687600754285611808" + 145 | "23265620694961977962255376280640334543711420731809" + 146 | "16169692928898605559361322123131373948352054888316" + 147 | "99068010065680008419210277574874665723796199239285" + 148 | "78432149273871356528827780412288057677598714485872" + 149 | "23380715275000339748138416696881866569449168516354" + 150 | "08203050733598637" 151 | expect(rsa_key.p.to_s).to eq "17745924258106322606344019888040076543466707208121" + 152 | "93651272762195900747632457567234817364256394944312" + 153 | "33791510564351470780224344194760390006214095043405" + 154 | "42496712265086317539172843039592265661675784866722" + 155 | "91261262550895476526939878375016658686669778355984" + 156 | "43725100552628219407700007375820870959681331890216" + 157 | "873285999" 158 | expect(rsa_key.q.to_s).to eq "14718572636476888213359534581670909910031809536407" + 159 | "40164297606657861988206326322941728093846078102409" + 160 | "77115817405984843964689092056948880068086594283588" + 161 | "67786990898525462713620707076259988063113810297786" + 162 | "62342502396556461808879680749106840152602791951788" + 163 | "07295572399572445909627940220804206538364578785262" + 164 | "498615959" 165 | expect(rsa_key.dmp1.to_s).to eq "11323089471614997519408698592522878386531994069" + 166 | "33541387540978328974191124807026398192741826901" + 167 | "86286081197790519393403018396347119829946883285" + 168 | "08800265628051101161010033119239372833462468119" + 169 | "90625594353955836736745514688525978377008530625" + 170 | "69694172942783772849726563761756732407513441791" + 171 | "680438851248236159711158591" 172 | expect(rsa_key.dmq1.to_s).to eq "12614892732210916138126631634839174964470249502" + 173 | "72370951196981338360130575847987543477227082933" + 174 | "41184913630399067613236576233063778305668453307" + 175 | "65828324726545238243590265660986543730618177968" + 176 | "24851190055502445616363498122584261892788460430" + 177 | "15963041982287770355559480659540210015737708509" + 178 | "273864533597668007301940253" 179 | expect(rsa_key.iqmp.to_s).to eq "12662716333617943892704787530332782239196594580" + 180 | "72960727418453194230165281227127897455330083723" + 181 | "88895713617946267318745745224382578970891647971" + 182 | "94015463887039228876036602797561671319853126600" + 183 | "52663805817336717151173320411542486382434841161" + 184 | "62999647203566877832873138065626190040996517274" + 185 | "418161068665712298519808863" 186 | end 187 | end 188 | 189 | describe ".parse_secure_note_server" do 190 | let(:type) { "type"} 191 | let(:url) { "url" } 192 | let(:username) { "username" } 193 | let(:password) { "password" } 194 | let(:notes) { "NoteType:#{type}\nHostname:#{url}\nUsername:#{username}\nPassword:#{password}" } 195 | 196 | it "returns parsed values" do 197 | result = LastPass::Parser.parse_secure_note_server notes 198 | 199 | expect(result).to be_instance_of Hash 200 | expect(result).to eq(type: type, url: url, username: username, password: password) 201 | end 202 | end 203 | 204 | describe ".read_chunk" do 205 | it "returns a chunk" do 206 | with_chunk_hex "ABCD", "DEADBEEF", padding do |io| 207 | expect(LastPass::Parser.read_chunk io).to eq LastPass::Chunk.new("ABCD", "DEADBEEF".decode_hex) 208 | expect(io.pos).to eq 12 209 | end 210 | end 211 | end 212 | 213 | describe ".read_item" do 214 | it "returns an item" do 215 | with_item_hex "DEADBEEF", padding do |io| 216 | expect(LastPass::Parser.read_item io).to eq "DEADBEEF".decode_hex 217 | expect(io.pos).to eq 8 218 | end 219 | end 220 | end 221 | 222 | describe ".skip_item" do 223 | it "skips an empty item" do 224 | with_item_hex "", padding do |io| 225 | LastPass::Parser.skip_item io 226 | expect(io.pos).to eq 4 227 | end 228 | end 229 | 230 | it "skips a non-empty item" do 231 | with_item_hex "DEADBEEF", padding do |io| 232 | LastPass::Parser.skip_item io 233 | expect(io.pos).to eq 8 234 | end 235 | end 236 | end 237 | 238 | describe ".read_id" do 239 | it "returns an id" do 240 | with_bytes "ABCD" + padding do |io| 241 | expect(LastPass::Parser.read_id io).to eq "ABCD" 242 | expect(io.pos).to eq 4 243 | end 244 | end 245 | end 246 | 247 | describe ".read_size" do 248 | it "returns a size" do 249 | with_hex "DEADBEEF" + padding do |io| 250 | expect(LastPass::Parser.read_size io).to eq 0xDEADBEEF 251 | expect(io.pos).to eq 4 252 | end 253 | end 254 | end 255 | 256 | describe ".read_payload" do 257 | it "returns a payload" do 258 | with_hex "FEEDDEADBEEF" + padding do |io| 259 | expect(LastPass::Parser.read_payload io, 6).to eq "FEEDDEADBEEF".decode_hex 260 | expect(io.pos).to eq 6 261 | end 262 | end 263 | end 264 | 265 | describe ".read_uint32" do 266 | it "returns a number" do 267 | with_hex "DEADBEEF" + padding do |io| 268 | expect(LastPass::Parser.read_size io).to eq 0xDEADBEEF 269 | expect(io.pos).to eq 4 270 | end 271 | end 272 | end 273 | 274 | describe ".decode_hex" do 275 | it "decodes hex" do 276 | def hex s 277 | s.force_encoding "ASCII-8BIT" 278 | end 279 | 280 | expect(LastPass::Parser.decode_hex "") 281 | .to eq "" 282 | 283 | expect(LastPass::Parser.decode_hex "00ff") 284 | .to eq hex "\x00\xFF" 285 | 286 | expect(LastPass::Parser.decode_hex "00010203040506070809") 287 | .to eq hex "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09" 288 | 289 | expect(LastPass::Parser.decode_hex "000102030405060708090a0b0c0d0e0f") 290 | .to eq hex "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" 291 | 292 | expect(LastPass::Parser.decode_hex "8af633933e96a3c3550c2734bd814195") 293 | .to eq hex "\x8A\xF6\x33\x93\x3E\x96\xA3\xC3\x55\x0C\x27\x34\xBD\x81\x41\x95" 294 | end 295 | 296 | it "raises exception on odd length" do 297 | expect { LastPass::Parser.decode_hex "0" } 298 | .to raise_error ArgumentError, "Input length must be multple of 2" 299 | end 300 | 301 | it "raises exception on invalid characters" do 302 | expect { LastPass::Parser.decode_hex "xz" } 303 | .to raise_error ArgumentError, "Input contains invalid characters" 304 | end 305 | end 306 | 307 | describe ".decode_base64" do 308 | it "decodes base64" do 309 | def check base64, plain 310 | expect(LastPass::Parser.decode_base64 base64).to eq plain 311 | end 312 | 313 | check "", "" 314 | check "YQ==", "a" 315 | check "YWI=", "ab" 316 | check "YWJj", "abc" 317 | check "YWJjZA==", "abcd" 318 | end 319 | end 320 | 321 | describe ".decode_aes256_plain_auto" do 322 | def check encoded, decoded 323 | expect(LastPass::Parser.decode_aes256_plain_auto encoded, encryption_key) 324 | .to eq decoded 325 | end 326 | 327 | it "decodes a blank string" do 328 | check "", "" 329 | end 330 | 331 | it "decodes ECB/plain string" do 332 | check "BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM=".decode64, 333 | "All your base are belong to us" 334 | end 335 | 336 | it "decodes CBC/plain string" do 337 | check "IcokDWmjOkKtLpZehWKL6666Uj6fNXPpX6lLWlou+1Lrwb+D3ymP6BAwd6C0TB3hSA==".decode64, 338 | "All your base are belong to us" 339 | end 340 | end 341 | 342 | describe ".decode_aes256_base64_auto" do 343 | def check encoded, decoded 344 | expect(LastPass::Parser.decode_aes256_base64_auto encoded, encryption_key) 345 | .to eq decoded 346 | end 347 | 348 | it "decodes a blank string" do 349 | check "", "" 350 | end 351 | 352 | it "decodes ECB/base64 string" do 353 | check "BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM=", 354 | "All your base are belong to us" 355 | end 356 | 357 | it "decodes CBC/base64 string" do 358 | check "!YFuiAVZgOD2K+s6y8yaMOw==|TZ1+if9ofqRKTatyUaOnfudletslMJ/RZyUwJuR/+aI=", 359 | "All your base are belong to us" 360 | end 361 | end 362 | 363 | describe ".decode_aes256_ecb_plain" do 364 | def check encoded, decoded 365 | expect(LastPass::Parser.decode_aes256_ecb_plain encoded.decode64, encryption_key) 366 | .to eq decoded 367 | end 368 | 369 | it "decodes a blank string" do 370 | check "", "" 371 | end 372 | 373 | it "decodes a short string" do 374 | check "8mHxIA8rul6eq72a/Gq2iw==", "0123456789" 375 | end 376 | 377 | it "decodes a long string" do 378 | check "BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM=", "All your base are belong to us" 379 | end 380 | end 381 | 382 | describe ".decode_aes256_ecb_base64" do 383 | def check encoded, decoded 384 | expect(LastPass::Parser.decode_aes256_ecb_base64 encoded, encryption_key) 385 | .to eq decoded 386 | end 387 | 388 | it "decodes a blank string" do 389 | check "", "" 390 | end 391 | 392 | it "decodes a short string" do 393 | check "8mHxIA8rul6eq72a/Gq2iw==", "0123456789" 394 | end 395 | 396 | it "decodes a long string" do 397 | check "BNhd3Q3ZVODxk9c0C788NUPTIfYnZuxXfkghtMJ8jVM=", "All your base are belong to us" 398 | end 399 | end 400 | 401 | describe ".decode_aes256_cbc_plain" do 402 | def check encoded, decoded 403 | expect(LastPass::Parser.decode_aes256_cbc_plain encoded.decode64, encryption_key) 404 | .to eq decoded 405 | end 406 | 407 | it "decodes a blank string" do 408 | check "", "" 409 | end 410 | 411 | it "decodes a short string" do 412 | check "IQ+hiIy0vGG4srsHmXChe3ehWc/rYPnfiyqOG8h78DdX", "0123456789" 413 | end 414 | 415 | it "decodes a long string" do 416 | check "IcokDWmjOkKtLpZehWKL6666Uj6fNXPpX6lLWlou+1Lrwb+D3ymP6BAwd6C0TB3hSA==", 417 | "All your base are belong to us" 418 | end 419 | end 420 | 421 | describe ".decode_aes256_cbc_base64" do 422 | def check encoded, decoded 423 | expect(LastPass::Parser.decode_aes256_cbc_base64 encoded, encryption_key) 424 | .to eq decoded 425 | end 426 | 427 | it "decodes a blank string" do 428 | check "", "" 429 | end 430 | 431 | it "decodes a short string" do 432 | check "!6TZb9bbrqpocMaNgFjrhjw==|f7RcJ7UowesqGk+um+P5ug==", "0123456789" 433 | end 434 | 435 | it "decodes a long string" do 436 | check "!YFuiAVZgOD2K+s6y8yaMOw==|TZ1+if9ofqRKTatyUaOnfudletslMJ/RZyUwJuR/+aI=", 437 | "All your base are belong to us" 438 | end 439 | end 440 | 441 | # 442 | # Helpers 443 | # 444 | 445 | private 446 | 447 | def with_blob &block 448 | with_bytes TEST_BLOB, &block 449 | end 450 | 451 | def with_hex hex, &block 452 | with_bytes hex.decode_hex, &block 453 | end 454 | 455 | def with_bytes bytes, &block 456 | StringIO.open bytes do |io| 457 | yield io 458 | end 459 | end 460 | 461 | # 462 | # Chunks 463 | # 464 | 465 | def with_chunk id, payload, padding = "", &block 466 | with_bytes make_chunk(id, payload, padding), &block 467 | end 468 | 469 | def with_chunk_hex id, payload, padding = "", &block 470 | with_bytes make_chunk_hex(id, payload, padding), &block 471 | end 472 | 473 | def make_chunk id, payload, padding = "" 474 | [id, payload.size, payload, padding].pack "a4Na*a*" 475 | end 476 | 477 | def make_chunk_hex id, payload, padding = "" 478 | make_chunk id, payload.decode_hex, padding 479 | end 480 | 481 | # 482 | # Items 483 | # 484 | 485 | def with_item payload, padding = "", &block 486 | with_bytes make_item(payload, padding), &block 487 | end 488 | 489 | def with_item_hex payload, padding = "", &block 490 | with_bytes make_item_hex(payload, padding), &block 491 | end 492 | 493 | def make_item payload, padding = "" 494 | [payload.size, payload, padding].pack "Na*a*" 495 | end 496 | 497 | def make_item_hex payload, padding = "" 498 | make_item payload.decode_hex, padding 499 | end 500 | end 501 | -------------------------------------------------------------------------------- /spec/test_data.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). 2 | # Licensed under the terms of the MIT license. See LICENCE for details. 3 | 4 | require_relative "spec_helper" 5 | 6 | TEST_CHUNK_IDS = %w{LPAV ATVR ENCU CBCU BBTE IPTE WMTE ANTE DOTE FETE FUTE 7 | SYTE WOTE TATE WPTE SPMT NMAC ACCT EQDN URUL ENDM} 8 | 9 | TEST_BLOB = ("TFBBVgAAAAMxMThBVFZSAAAAAzEwMkVOQ1UAAABGITExVkVjWFVnelFramxranB2" + 10 | "VGZyR3c9PXxYUklhVVdQYlQzRXdRQlZCRUYxZUJTTDI3bWZ1cVViZmFCV3JCYnd5" + 11 | "WFdFPUNCQ1UAAAABMUJCVEUAAAAMLTYyMTY5OTY2MDAwSVBURQAAAAwtNjIxNjk5" + 12 | "NjYwMDBXTVRFAAAADC02MjE2OTk2NjAwMEFOVEUAAAAMLTYyMTY5OTY2MDAwRE9U" + 13 | "RQAAAAwtNjIxNjk5NjYwMDBGRVRFAAAADC02MjE2OTk2NjAwMEZVVEUAAAAMLTYy" + 14 | "MTY5OTY2MDAwU1lURQAAAAwtNjIxNjk5NjYwMDBXT1RFAAAADC02MjE2OTk2NjAw" + 15 | "MFRBVEUAAAAMLTYyMTY5OTY2MDAwV1BURQAAAAEwU1BNVAAAAC0AAAABMAAAAAEw" + 16 | "AAAAATAAAAABMAAAAAEwAAAAATEAAAABMQAAAAEwAAAAATBOTUFDAAAAAzEwMEFD" + 17 | "Q1QAAAGTAAAACjE4NzI3NDU1OTYAAAAxIaUvQYPzwlMtRTrZEYftBU9068UlQ6rL" + 18 | "OxmAxj8la1TXtePO6A6dOgmDalfC+dPq0gAAACEhP6C+06QXUEo+rzP1CV2Y8gRR" + 19 | "6lSnhVSaB3/FJPgnYLgAAABENjg3NDc0NzAzYTJmMmY2ZTY5NjU2ZTZmNzcyZTZl" + 20 | "NjU3NDJmNmQ2NTYxNjc2MTZlMmU2NzcyNjU2NTZlNjg2ZjZjNzQAAAAAAAAAATAA" + 21 | "AAAAAAAAISGrnmjbXckUV+TJvuuFaiAU055QL+iRpTOLUdEfvpR55gAAADEh02Ki" + 22 | "+p/VUgFlLbZKaV0AYtpeGsQ7Jmt+R+BRdoWkwGsXHm5blPx/YYVdf8Y9TwE7AAAA" + 23 | "ATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1NTk2AAAA" + 24 | "AAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAABMQAA" + 25 | "AAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGJAAAACjE4NzI3NDU2MDYA" + 26 | "AAAhIWzPDPU9FrsGRopvmOi6uvOYkcGqaqKCFprsL3G1f0FvAAAAISGG5zXlgJ5y" + 27 | "J8fZnAWd/SNb9l/aujeXOtTHTAvQ8RuCnQAAAEo2ODc0NzQ3MDNhMmYyZjYyNjU2" + 28 | "MzY4NzQ2NTZjNjE3MjJlNjI2OTdhMmY3NDcyNjk3Mzc0Njk2MTZlMmU2MjYxNzI3" + 29 | "MjZmNzc3MwAAAAAAAAABMAAAAAAAAAAxIRTPYYC8d7Rvc+NXYokX3soC70wrzjEa" + 30 | "xvytac7xJbd1K/dHU8ee7HU7u5bfNVWVuQAAACEhVq89o7tYpBLCvQO7dtjasGG7" + 31 | "Osin9SvtokRlhNmpDVoAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAA" + 32 | "AAAACjE4NzI3NDU2MDYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAB" + 33 | "MQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAA" + 34 | "AXUAAAAKMTg3Mjc0NTYxNgAAACEhO9e0HHKHemPXY7gLp1P722/WU9ZSQYjnTWU1" + 35 | "CEJgA3AAAAAhIQM9xNKiBFE1UVQVYaoW6IcvoVSjbGGtS7qj1PplR/2hAAAANjY4" + 36 | "NzQ3NDcwM2EyZjJmNzM2MzY4NzU3Mzc0NjU3MjJlNmU2MTZkNjUyZjYxNzM2ODc0" + 37 | "NmY2ZQAAAAAAAAABMAAAAAAAAAAhIZtIAgu1kRxJC7aqw4H8RXiOC2E4NuRse0fN" + 38 | "/IrFIYVUAAAAMSE9LwFmsD73HSRtgqo5wSX7aJposOOm2hqPIpzFvJwrJlNN1C+2" + 39 | "gbo3ml+YhjkN5pIAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAA" + 40 | "CjE4NzI3NDU2MTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAABMgAA" + 41 | "AAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAWsA" + 42 | "AAAKMTg3Mjc0NTYyNgAAACEhXQIttPj6P/25RK3pzV85x1XMTwsb1HMPjCr8RLnn" + 43 | "QOQAAAAhIQ14pX3pzuwOXfczG4+vhm1epPlgA2LtCJRV7Y/knBJ4AAAALDY4NzQ3" + 44 | "NDcwM2EyZjJmNzI3NTZlNmY2YzY2NmY2ZTJlNmY3MjY3MmY3NDY1AAAAAAAAAAEw" + 45 | "AAAAAAAAADEhbZ6cUQzOVkgsFB0d73mOTCJ9efy3VFBEsb0ekhyJcNcUjAPjh774" + 46 | "+BbjywxUsco1AAAAISGD3mOMS0xWcEKRLKimTZQwwpqoMUKCjU/a/brYZbGFhwAA" + 47 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTYyNgAA" + 48 | "AAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAEzAAAAATAAAAAAAAAAATEA" + 49 | "AAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABdwAAAAoxODcyNzQ1NjM2" + 50 | "AAAAISEb4m77GfIOvO6fYzktw4aSDOxy8gpxjuR2oD6imAeoiAAAACEh5kDr0YH/" + 51 | "YfHah6DgyCpwbVul9y9CBylEcXENkY8LUYoAAABINjg3NDc0NzAzYTJmMmY2ODY5" + 52 | "NmU3NDdhNzA3MjZmNjg2MTczNmI2MTJlNjI2OTdhMmY3NzYxNjQ2NTJlNjY2OTcz" + 53 | "Njg2NTcyAAAAAAAAAAEwAAAAAAAAACEh2LKP6v5jYlQ6/0yaS4D+u2fLAxJS1BYE" + 54 | "ebH/nwnm+NEAAAAhIbGahlE1a7dDksJcUScFfpGDWVbh6eA2FL5ZQiQJe3SOAAAA" + 55 | "ATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1NjM2AAAA" + 56 | "AAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAATQAAAABMAAAAAAAAAABMQAA" + 57 | "AAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFJAAAACjE4NzI3NDU2NDYA" + 58 | "AAAhIddUR3tvwQP0CiQGZ5nIN5AOu41QtVQQkiLlDXgC67C6AAAAAAAAADw2ODc0" + 59 | "NzQ3MDNhMmYyZjczNjM2ODc1NmM3NDdhNjg2NTYxNmU2NTc5MmU2ZjcyNjcyZjYx" + 60 | "NzI3NjY5NjQAAAAAAAAAATAAAAAAAAAAISEgjlPSKxJIaxzS4LtJ0h/WuXA+SzFk" + 61 | "+xq3PIoHE01ujQAAACEhLoYYeDLOwdf2vewKK49rZ9zDR2iTxjzB5ci5L7LdIewA" + 62 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDU2NDYA" + 63 | "AAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEA" + 64 | "AAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABcQAAAAoxODcyNzQ1NjU2" + 65 | "AAAAMSE6dpn4QFzEtGAOF0pnukMsy7MxHQkCHkPBc2WfDpPBNd+mqJoIUr4xn9Os" + 66 | "JLw6JHwAAAAhIa6Z2iLXCdY1FusJuahlVQ12V3AQ1xtx907dhrnLNb2RAAAAMjY4" + 67 | "NzQ3NDcwM2EyZjJmNzM3NDcyNjU2OTYzNjgyZTYzNmY2ZDJmNzI2MTZkNmY2ZTYx" + 68 | "AAAAAAAAAAEwAAAAAAAAACEhFjUkwX6BtmttaI8Xjeh7A4hfdzheEDvQl6ERKI/j" + 69 | "rFMAAAAhIY41/x6H8yJBXBKtRQWNLWdH1RhXe4tsalNPqFtVEFs2AAAAATAAAAAB" + 70 | "MAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1NjU2AAAAAAAAAAAA" + 71 | "AAAAAAAAATAAAAABMAAAAAAAAAAAAAAAATUAAAABMAAAAAAAAAABMQAAAAEwAAAA" + 72 | "AAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFnAAAACjE4NzI3NDU2NjYAAAAhIbaO" + 73 | "iTkfVFko62wOMqoFlk31KC/H4OafgmPG3Aq9Ovg1AAAAISEI9XR+O3ru13RyvgXP" + 74 | "IxvtUDWxbbN+9XewE/4vBxaSwQAAACg2ODc0NzQ3MDNhMmYyZjYzNmY2ZTZlMmU2" + 75 | "ZTY1NzQyZjZjNjU2NDYxAAAAAAAAAAEwAAAAAAAAADEhLVUiK630YW+SH5XRQHQ/" + 76 | "CTRgla8u9KY0uCtV9pw9jqppQaA8EEWIbUUxKdE9ZanFAAAAISGtYcBXZ53fKC4W" + 77 | "W7zFZ8OzVP8HE2SX0EBle6AWtVic4wAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 78 | "AAABMAAAAAAAAAAKMTg3Mjc0NTY2NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 79 | "AAAAAAAAAAE2AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcx" + 80 | "MDRBQ0NUAAABgQAAAAoxODcyNzQ1Njc2AAAAMSHLwsXqutzkzUtQO/qEkwAFxlzV" + 81 | "5P54THEqk12GeVRbGvasMv6m7w78Y5YKy7F0VUIAAAAhIZgyLh1/l1Zon+Sgd+3A" + 82 | "BJ6hc2K6KzI24AwxcC7/LCTyAAAAMjY4NzQ3NDcwM2EyZjJmNjM2ZjZlNzI2Zjc5" + 83 | "MmU2MjY5N2EyZjdhNjE2MzY4NjU3Mjc5AAAAAAAAAAEwAAAAAAAAACEhbhLO4orM" + 84 | "Ku6oUkegA3ItB77rckAc3sQwE5t0R7q8xHQAAAAxId+80ASeTkbv+0oDEV7dfe1n" + 85 | "oEKmVoutR6C50RUTR4s/s5fQdAt/NjqkKJ8GObagtQAAAAEwAAAAATAAAAABMAAA" + 86 | "AAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTY3NgAAAAAAAAAAAAAAAAAAAAEw" + 87 | "AAAAATAAAAAAAAAAAAAAAAE3AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAA" + 88 | "CjEzNzMwNzcxMDRBQ0NUAAABSwAAAAoxODcyNzQ1Njg2AAAAISGeWePdN9riofiB" + 89 | "vPXaNOxmNQTL7EkUxBTlR9ODSHHv+wAAAAAAAAAuNjg3NDc0NzAzYTJmMmY2YjY5" + 90 | "Njg2ZTJlNmY3MjY3MmY2MzYxNmU2NDY5NjM2NQAAAAAAAAABMAAAAAAAAAAxIZla" + 91 | "rXv+gtjIVVR/6cC9sytjKe+IjvJL2ezKP3oxEeCJOiJITo86/Furu374noD7rQAA" + 92 | "ACEhWuB+ckZ0FcvD2FXotyKjwHPIFI5a+Yy7Sct/whk+tccAAAABMAAAAAEwAAAA" + 93 | "ATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDU2ODYAAAAAAAAAAAAAAAAA" + 94 | "AAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAA" + 95 | "AAAACjEzNzMwNzcxMDRBQ0NUAAABbwAAAAoxODcyNzQ1Njk2AAAAISHFwj2xbX71" + 96 | "uPcF5SZ4bl5e0MIImDPxZqEE0t1T7j+sUQAAACEh+gZl1yfJkchbuZ3oaPGjwUNR" + 97 | "k/np5HlQaqidnepJnvkAAAAwNjg3NDc0NzAzYTJmMmY2NzZjNmY3NjY1NzIyZTZl" + 98 | "NjE2ZDY1MmY2YTY1NzI2MTY0AAAAAAAAAAEwAAAAAAAAACEhWejYIS8GCFp/GkGH" + 99 | "wGdTNj/WPIkshtOCZXUuRjcBDN4AAAAxIWYXzKArUH5hAhqE+bbZvOp9cz6/mUEt" + 100 | "Yw/n0eKACZQKC4RjdZEEXA4UllYuX3c0NwAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 101 | "ATAAAAABMAAAAAAAAAAKMTg3Mjc0NTY5NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAA" + 102 | "AAAAAAAAAAAAAAE4AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMw" + 103 | "NzcxMDRBQ0NUAAABcQAAAAoxODcyNzQ1NzA2AAAAISGorY0SSNF696WwYJcxsdFw" + 104 | "D6m2A6ZCkFFzx3v2MBnvEwAAACEhpa8+NWZoYBtoIXi7dUGa+JQbki+uG+vuHPpp" + 105 | "iYEcHxcAAAAyNjg3NDc0NzAzYTJmMmY2ZDYxNzk2NTcyNzQyZTZlNjE2ZDY1MmY2" + 106 | "YTY1NzI2ZjZkNzkAAAAAAAAAATAAAAAAAAAAMSF908guDN8hOUdYwC3tYSpo4PFf" + 107 | "yxNyzfmvW8k83zWY9Hd+QbbHHSjE5XTWAaxisfkAAAAhIdTFya25L9w4T6NH3aRm" + 108 | "P2aMRNqVXhk+91WWKPElSpseAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 109 | "AAAAAAAAAAoxODcyNzQ1NzA2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 110 | "AAAAATkAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFD" + 111 | "Q1QAAAFHAAAACjE4NzI3NDU3MTYAAAAhIXmUu59nSkkwpim5xZUX/B42qd4Z3H3l" + 112 | "8ZKDSxxZfqL5AAAAAAAAADo2ODc0NzQ3MDNhMmYyZjczNjE2ZTY2NmY3MjY0Nzc3" + 113 | "NTZlNzM2MzY4MmU2ZjcyNjcyZjYxNmM2NTZiAAAAAAAAAAEwAAAAAAAAACEhlYwT" + 114 | "HOBJy4TB4DjN4cgm/uH6ktEhYOEC33fQK/6Ew9cAAAAhIS2ehBFomoqThSf9tLV6" + 115 | "mlsBKPU9HimyVJ1apJAuBr8qAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 116 | "AAAAAAAAAAoxODcyNzQ1NzE2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 117 | "AAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUND" + 118 | "VAAAAYAAAAAKMTg3Mjc0NTcyNgAAACEhGMiPj9rwna8pqHwjeIpTwp+YcOs5ihke" + 119 | "WGiMXBl1edMAAAAhIQAztK0yhhOnVcnIDeqfN4VELzpZqrmq5u4XU7HCgvZXAAAA" + 120 | "QDY4NzQ3NDcwM2EyZjJmNmM2NTY4NmU2NTcyMmU2MjY5N2EyZjczNzQ2MTZlNmM2" + 121 | "NTc5MmU2NDZmNmY2YzY1NzkAAAAAAAAAATAAAAAAAAAAMSGlEEN0n+XAbvFb0tvd" + 122 | "UmIIsbeS1pGdnDEXHeH/d+0DZAJlNMgAYUWmVf39dp+1HTsAAAAhIemJWGnMPw2k" + 123 | "juEmHhbeEMtY67afvWj1PfccOzEPBQs8AAAAATAAAAABMAAAAAEwAAAAATAAAAAB" + 124 | "MAAAAAEwAAAAAAAAAAoxODcyNzQ1NzI2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAA" + 125 | "AAAAAAAAAAAAAjEwAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMw" + 126 | "NzcxMDRBQ0NUAAABcAAAAAoxODcyNzQ1NzM2AAAAISGs1uDBvUMCJm1J1x+5iNEE" + 127 | "i/i+XX0B9Yf2tadKy+U3+AAAACEhG1dTn17o1/ymRQgpn2oI+xZ36+3H3N6eXgRK" + 128 | "hcadeWQAAAAwNjg3NDc0NzAzYTJmMmY3MjZmNmM2NjczNmY2ZTJlNmU2NTc0MmY2" + 129 | "YTYxNjQ2NTZlAAAAAAAAAAEwAAAAAAAAACEhg9tVLX+90vps5qXkR0alKpJq7Obq" + 130 | "E/jOwi2q6vNmy90AAAAxIWSApHuog5j4KelzaTNUloHzZX/yl1csGWvDr94aN+TN" + 131 | "kIX0wbfFFD/3sLrIm3zo9wAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAA" + 132 | "AAAAAAAKMTg3Mjc0NTczNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAA" + 133 | "AAIxMQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUND" + 134 | "VAAAAX4AAAAKMTg3Mjc0NTc0NgAAACEhyxtMnSycw7Agyf8otQJ4l3+dBGGxmiwv" + 135 | "hPQBVbIZChUAAAAhIeCFWsm5ZAR1oSKwDvuq968uKEWrG8yeHg/z+DjB+LSJAAAA" + 136 | "PjY4NzQ3NDcwM2EyZjJmNjY2MTY4NjU3OTJlNmU2MTZkNjUyZjZhNmY2ZTVmNjE2" + 137 | "ZTZiNzU2ZTY0Njk2ZTY3AAAAAAAAAAEwAAAAAAAAADEhnoNgy2MYpZqChvAvuUK6" + 138 | "CBUyZW+13hF920UkRWeztghueq9SQpgflbmcJRZNHPH/AAAAISGSz84xg3A6AJQF" + 139 | "9IYAiRWm+6aAo+Elx7nHUnTOSJClvwAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 140 | "AAABMAAAAAAAAAAKMTg3Mjc0NTc0NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 141 | "AAAAAAAAAAIxMgAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 142 | "MTA0QUNDVAAAAYwAAAAKMTg3Mjc0NTc1NgAAADEhGIdprJWxd/VPfw+rLbbq2U9E" + 143 | "OJ8fmmafAUinE9mJh2Piw0Dt5wC1NRLcrpnUCPxtAAAAISG53FZfu7sXpOcq9n83" + 144 | "vL85SAKSnrEO1I12DwMNs/sV6gAAADw2ODc0NzQ3MDNhMmYyZjc0NzI2NTc1NzQ2" + 145 | "NTZjNmI2OTY1Njg2ZTJlNmY3MjY3MmY2ZDYxNzI2MzZmNzMAAAAAAAAAATAAAAAA" + 146 | "AAAAMSF67pO4h3QqKy9FFhKpxihsjI9MG0b4ANOsekIBuXdvBg0usIZqRskzySD9" + 147 | "m3sqM/cAAAAhIV16dEXwW0dpTkKFa2SMXToJBWjH6g6WcNdSUtOv6JUUAAAAATAA" + 148 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1NzU2AAAAAAAA" + 149 | "AAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjEzAAAAATAAAAAAAAAAATEAAAAB" + 150 | "MAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABYgAAAAoxODcyNzQ1NzY2AAAA" + 151 | "ISE2rzBtquT4KbKDNIgBZcTpY5Wqq0OFt+65lvoBOqTuCQAAACEhRMvVlJen73am" + 152 | "EgLBa3i4+mb7Er3+PWfNPVkXOBD46JAAAAAyNjg3NDc0NzAzYTJmMmY2YzY1NjY2" + 153 | "NjZjNjU3MjJlNjk2ZTY2NmYyZjYzNjg2MTc5NjEAAAAAAAAAATAAAAAAAAAAISFk" + 154 | "bW//Ga0ZSLaQuduBTr2wQg3994ZlVS23PLrmoTC/IQAAACEhmeVc7QeEZez1ql1p" + 155 | "gi8xykwV4BZKzF7E0onW2oAOvgwAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 156 | "ATAAAAAAAAAACjE4NzI3NDU3NjYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 157 | "AAAAAAACMTQAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEw" + 158 | "NEFDQ1QAAAFNAAAACjE4NzI3NDU3NzYAAAAhIZ/uatMIc0Y2ZF+LbZUuisLpWNE7" + 159 | "sEOLNUl14Yec8qqCAAAAAAAAAEA2ODc0NzQ3MDNhMmYyZjYyNzI2MTZiNzU3Mzc3" + 160 | "Njk2YzZjNjk2MTZkNzM2ZjZlMmU2MzZmNmQyZjYyNzI2NTc0AAAAAAAAAAEwAAAA" + 161 | "AAAAACEhiZ6UHPLcSrKVLRzKlOuAhhPGr5H39GJ17j2ZdmtBWkcAAAAhIYsZHdIB" + 162 | "gMIwDgqGpbmG2mrwHeHlnqCYo4d+ev8txvTiAAAAATAAAAABMAAAAAEwAAAAATAA" + 163 | "AAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1Nzc2AAAAAAAAAAAAAAAAAAAAATAAAAAB" + 164 | "MAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzcz" + 165 | "MDc3MTA0QUNDVAAAAZwAAAAKMTg3Mjc0NTc4NgAAADEhmciPQ/oX/XcoxHJBR5XZ" + 166 | "aSif1w2DU56kUZIjGmyYlank2qlK0S3IUcNQwAGo6W4FAAAAISHbIP/rAq2WzcM7" + 167 | "qfes+H2rd6xRVwiZfDsa4npC5QhAqgAAAEw2ODc0NzQ3MDNhMmYyZjZiNzU2ZTdh" + 168 | "NjU2ZjZiNzU2ZTY1NzY2MTJlNjk2ZTY2NmYyZjczNjg2MTc3NmU1ZjZjNjE2ZTY3" + 169 | "NmY3MzY4AAAAAAAAAAEwAAAAAAAAADEh1rZcvQLPDGfwFLS9m+xB8pkTT2s8R8hS" + 170 | "+KkGHNkBlUuvWijoE8o/d4SZjG4aeKMXAAAAISFBViTLvTjoM4/4f47d4Eazeh4i" + 171 | "qBE9UaeH/bEV2nbxnQAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAA" + 172 | "AAAKMTg3Mjc0NTc4NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAIx" + 173 | "NQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAA" + 174 | "AUEAAAAKMTg3Mjc0NTc5NgAAACEh9+j0st/9S+BQB2EEkgeDi2QaltidD5q7jC4D" + 175 | "kHPkQZMAAAAAAAAANDY4NzQ3NDcwM2EyZjJmNjM3MjZmNmY2YjczMmU2MzZmNmQy" + 176 | "ZjczNjE2ZTY0NzI2OTZlNjUAAAAAAAAAATAAAAAAAAAAISEw8Nau8j29pJuVu1Yn" + 177 | "+5rgPeNeRWEuQwmgf9vGzA6vmAAAACEhFBedhEe9UqyYRjmWZYflGqQvkTcxFcN/" + 178 | "QlM4e48oZ6AAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4" + 179 | "NzI3NDU3OTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAA" + 180 | "AAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABgAAAAAox" + 181 | "ODcyNzQ1ODA2AAAAISHgFLmEN8n3CujAwhp9Ovukvkz5V7+CmIjkOi+dkxKuNgAA" + 182 | "ACEh9OBhtr31mJFvWcbHNMCAd44KqzXIvgLiHPE+sbY6z/AAAAAwNjg3NDc0NzAz" + 183 | "YTJmMmY2YjY1NmQ2ZDY1NzIyZTZmNzI2NzJmNjg2OTZjNzQ2ZjZlAAAAAAAAAAEw" + 184 | "AAAAAAAAADEhrP3NRn7628agNyO/QQZxNF5s6kRH2lhndFMFxVX/8pkTkIcPGcTA" + 185 | "lYRjrVWDBu7JAAAAMSE32B39KTGTPxbh2PkQqhbi75qsIfRgD4zPw96Sq5ckf7ER" + 186 | "pv1ra7omvV0wVbeBV84AAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAA" + 187 | "AAAACjE4NzI3NDU4MDYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAC" + 188 | "MTYAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QA" + 189 | "AAGYAAAACjE4NzI3NDU4MTYAAAAxIaZRSACBHI6LWMPcUbL9BDPJBA6ezXxodjYX" + 190 | "eeQnS5jHd3JWW5yQ5juFLioSS+0vcgAAACEhTbCYIRlc8Vp5a6MnPhZwN61RXsZ1" + 191 | "RLLrB/lPKTSvlyoAAABINjg3NDc0NzAzYTJmMmY3NDcyNmY2ZDcwNjI2NTcyNmU2" + 192 | "ODYxNzI2NDJlNjM2ZjZkMmY3NDcyNjU2MTJlNjg2OTcyNzQ2ODY1AAAAAAAAAAEw" + 193 | "AAAAAAAAADEhM3Y9D0SUShS0/StfAeN5ZCCxs0NxNSnI5HkKJsrVy/Z3XpgPuBDJ" + 194 | "MTOCczoM5/qhAAAAISHrEm5JWCe27yo+OyGBv2YsDhh1XGM7OdB+wYRBmc2uaAAA" + 195 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTgxNgAA" + 196 | "AAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAIxNwAAAAEwAAAAAAAAAAEx" + 197 | "AAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAZQAAAAKMTg3Mjc0NTgy" + 198 | "NgAAADEhIimFHCGaaVBOe0mBxijAWbsc5rn5jkSsmIoJBV8i+zCrFKH/tC4ZCtly" + 199 | "gczOpZj9AAAAISFAbpg8zACxOEHkUeKFepaecFumI2KadyBznEhWmnlFIQAAADQ2" + 200 | "ODc0NzQ3MDNhMmYyZjc1NmM2YzcyNjk2MzY4MmU2OTZlNjY2ZjJmNjM2MTcyNmM2" + 201 | "NTY1AAAAAAAAAAEwAAAAAAAAADEhUIKf99JmmX098GrUfxHr6/NLv8WU9UEGlZ1W" + 202 | "KCd/08iqfS/2MqwUXoYCZ/3K+eEGAAAAMSGVA3zC9wpvKaAdTWTDyqVQiwQ35Ov8" + 203 | "em8JA1fpb1gZNLB3JKLRxt7WHl85Eb2KxqAAAAABMAAAAAEwAAAAATAAAAABMAAA" + 204 | "AAEwAAAAATAAAAAAAAAACjE4NzI3NDU4MjYAAAAAAAAAAAAAAAAAAAABMAAAAAEw" + 205 | "AAAAAAAAAAAAAAACMTgAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3" + 206 | "MzA3NzEwNEFDQ1QAAAFwAAAACjE4NzI3NDU4MzYAAAAhIcJw1qL5OWA5gHmfeSRP" + 207 | "a1u2OacvtgC0gN2nqh2lP2TYAAAAISHVhEe8XadXg2zF535/xOvaMJqaxuT/L7D1" + 208 | "10cxoVuVIgAAAEA2ODc0NzQ3MDNhMmYyZjcyNjk3MDcwNjk2ZTJlNmU2MTZkNjUy" + 209 | "ZjYyNmY2ZTY5NzQ2MTVmNjg2OTYzNmI2YzY1AAAAAAAAAAEwAAAAAAAAACEhvzjc" + 210 | "4db86CZmTzxTpe3n4EK7H2Gvg7PnKaxv8khTx+AAAAAhIUoEgdRme2H4ahRTxfzR" + 211 | "KTYV2+BySfdStWnvP2zsvUfvAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 212 | "AAAAAAAAAAoxODcyNzQ1ODM2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 213 | "AAAAAjE5AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRB" + 214 | "Q0NUAAABsgAAAAoxODcyNzQ1ODU2AAAAMSHIhRWCbYpBTEn7oVMBuJH8u78b40Z2" + 215 | "tw7qPSpOi/los3O+MN+ckeyBRQafSSmO49YAAAAhIdcAclA642w11ibw/3sVFWLi" + 216 | "brQ+UvzSwVlhBlYuDQdnAAAAYjY4NzQ3NDcwM2EyZjJmNjE3NTY2NjQ2NTcyNjg2" + 217 | "MTcyNzI3NTZlNmY2YzY2NzM2NDZmNzQ3NDY5NzIyZTY5NmU2NjZmMmY2NjY1NmM2" + 218 | "OTYzNjk2MTVmNzQ2ZjcyNzA2ODc5AAAAAAAAAAEwAAAAAAAAADEh9TfrO+Fwvhby" + 219 | "J/AXH2f1Lm+2FgRR8otkUz6ofiY8IZKuGzfcnpVgTxFtVha8Gki1AAAAISHKG4L5" + 220 | "CqgDQtGSNcLF+0wgd6ggfqryIT4aW4ZzbJOSXwAAAAEwAAAAATAAAAABMAAAAAEw" + 221 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTg1NgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 222 | "ATAAAAAAAAAAAAAAAAIyMAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAox" + 223 | "MzczMDc3MTA0QUNDVAAAAXgAAAAKMTg3Mjc0NTg2NgAAACEhQE1Ye79tC4KS/FAz" + 224 | "PyHjDV6xuCpJuqa7nNDJxmEc7k4AAAAhIQNekQjGv4ewrI6iEdRe63wx7oygqQVx" + 225 | "UsQ3A4+otWeXAAAAODY4NzQ3NDcwM2EyZjJmNmM2ZjYzNmI2ZDYxNmU2Yzc5NmU2" + 226 | "MzY4MmU2ZTY1NzQyZjYxNmM2MjYxAAAAAAAAAAEwAAAAAAAAADEhplJ5oQspBCJX" + 227 | "J96eppbg1dhBqk64ImC0Le9niB0AJRuhUWGuCwqQs7++dir4ogYkAAAAISEgTMF5" + 228 | "pv4GQ1KpVSr2rShvLkSaBHvzFvo/hVdjNqR6zQAAAAEwAAAAATAAAAABMAAAAAEw" + 229 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTg2NgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 230 | "ATAAAAAAAAAAAAAAAAIyMQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAox" + 231 | "MzczMDc3MTA0QUNDVAAAAZoAAAAKMTg3Mjc0NTg3NgAAADEhRMdg8/tq4PEVYWVK" + 232 | "wMo0WEN3Yur3AX7lun+Kn7eS5aFf3GzaAAJIOpniDbupf1oZAAAAISEvuWGKizfq" + 233 | "8zJybfTlt7GGaybp50DqxCCwIw4kC/GULwAAAEo2ODc0NzQ3MDNhMmYyZjYzNjE3" + 234 | "MjcyNmY2YzZjNzM2MzY4NmQ2OTc0NzQyZTYzNmY2ZDJmNzc2OTZjNmM3OTJlNjU2" + 235 | "ZDYxNzI2NAAAAAAAAAABMAAAAAAAAAAxIRGwGqXCb3tWMdTM0MevrA7izlSGq7R7" + 236 | "QdHxlBvyX+sTKwF8q/U4bgaBfGOjdYKnWwAAACEhgPjXbuVA+QuUToPd/VpkP+v/" + 237 | "B4yv4WrA1lbhDiQlYUYAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAA" + 238 | "AAAACjE4NzI3NDU4NzYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAC" + 239 | "MjIAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QA" + 240 | "AAGIAAAACjE4NzI3NDU4ODYAAAAxIVR6nvORUDTzLM2ccDbg4X5xWSwcd7lWUkpz" + 241 | "TQkzgdvtshGthLiBgr9KWDPGkk70qQAAACEhQV3F6awFZJ/iHgqhmCccSxPo87Lp" + 242 | "zYADyrvDzVm3iMoAAAA4Njg3NDc0NzAzYTJmMmY2NjY1Njk2YzJlNmU2NTc0MmY2" + 243 | "ZTYxNzQ2MTczNjg2MTVmNjg2Zjc3NjUAAAAAAAAAATAAAAAAAAAAMSGifN07AIi3" + 244 | "wSxPhnXERybIV55e1BewQMDTczO6f+UEM5JD3LHBg9x+i8rjjaWrOzEAAAAhIQdz" + 245 | "q3+v8HjcJKUc7xb9+6NSLWKo+w7sTAPbF8hMm3Y+AAAAATAAAAABMAAAAAEwAAAA" + 246 | "ATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1ODg2AAAAAAAAAAAAAAAAAAAAATAA" + 247 | "AAABMAAAAAAAAAAAAAAAAjIzAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAA" + 248 | "CjEzNzMwNzcxMDRBQ0NUAAABUwAAAAoxODcyNzQ1ODk2AAAAISHcbMpS37UtrNiw" + 249 | "y7aZoDB2jKY5VKeJbF73QFU4lJskdAAAAAAAAABGNjg3NDc0NzAzYTJmMmY2NzZj" + 250 | "NjU2MTczNmY2ZTZhNjE2Yjc1NjI2Zjc3NzM2YjY5MmU2MjY5N2EyZjYxNzU2Nzc1" + 251 | "NzM3NAAAAAAAAAABMAAAAAAAAAAhIeeo3o1u8KJySEwNzY1v008/rDUxNBMjjVdz" + 252 | "j7FSbCYfAAAAISH6pvRafbbMtp1AI7hJ0fjdVPajOsrRFVqhqo1diIgbHAAAAAEw" + 253 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTg5NgAAAAAA" + 254 | "AAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAABMQAAAAEw" + 255 | "AAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGeAAAACjE4NzI3NDU5MDYAAAAx" + 256 | "IW61eKunz6Xb4Arymj5hAv9f56jTEJlVZPSBinxGShzXBas3bTjIGRhbkTekskND" + 257 | "RwAAACEhz+hKrf51+vOL+g8fvuyJSPKCcx73WEAB1dUn8u+kBXsAAABONjg3NDc0" + 258 | "NzAzYTJmMmY3NzY5NmM2YjY5NmU3MzZmNmU2YzY1NjE2ZTZlNmY2ZTJlNmU2MTZk" + 259 | "NjUyZjYyNzU2NDJlNzc2OTZjNmM2ZDczAAAAAAAAAAEwAAAAAAAAADEhhnDGWano" + 260 | "GhnwVsEjnH5YvPW55hjLi+5m8VPp873jbrOMVe4eSgMOMdz6R81V2Y6lAAAAISGP" + 261 | "ckyidKNfVX0l6wB/sUr+zDonEkt8ph94HsaXXsHLLgAAAAEwAAAAATAAAAABMAAA" + 262 | "AAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTkwNgAAAAAAAAAAAAAAAAAAAAEw" + 263 | "AAAAATAAAAAAAAAAAAAAAAIyNAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAA" + 264 | "AAoxMzczMDc3MTA0QUNDVAAAAX4AAAAKMTg3Mjc0NTkxNgAAACEhIxXNy4pUbU8z" + 265 | "w0LfG59qS38wa8sY0Ho/iV07I/hdHZ0AAAAhIdKPEper6levT1HDFcjEeXaeY8sv" + 266 | "CTU43zixIgF49gXIAAAALjY4NzQ3NDcwM2EyZjJmNzA3MjY5NjM2NTJlNjk2ZTY2" + 267 | "NmYyZjc1NzI2MjYxNmUAAAAAAAAAATAAAAAAAAAAMSHZiSutgWI+cIm313+M9xet" + 268 | "6yzJPYpF8/h32rZnfM5qUO0bCsZXenRPqGSpX5pFAokAAAAxIah32aDNd/L41Lzh" + 269 | "lLgFmiKL36FNdW4J7QoODBtBEo+haSrtiEFNuJYTZfNdEDCSaQAAAAEwAAAAATAA" + 270 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTkxNgAAAAAAAAAAAAAA" + 271 | "AAAAAAEwAAAAATAAAAAAAAAAAAAAAAIyNQAAAAEwAAAAAAAAAAExAAAAATAAAAAA" + 272 | "AAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAVkAAAAKMTg3Mjc0NTkyNgAAACEhnHKG" + 273 | "ExBpHQpFwzERx1pvpUw9wGGmzdCy5I5JPO+LdhEAAAAAAAAATDY4NzQ3NDcwM2Ey" + 274 | "ZjJmNzA2MTc1NjM2NTZiNzQ3NTcyNjM2Zjc0NzQ2NTJlNmY3MjY3MmY2YjYxNjQ2" + 275 | "OTZlNWY2NzY5NjI3MzZmNmUAAAAAAAAAATAAAAAAAAAAISGAcKkcAZQQeQBS77Zg" + 276 | "d7KT4ox6vPScCpFCAqfGxyF0DQAAACEhF7CaZZbafKaUhk+fNE+xLweUfV16+9zP" + 277 | "HBSM2UBsWrcAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4" + 278 | "NzI3NDU5MjYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAA" + 279 | "AAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABeAAAAAox" + 280 | "ODcyNzQ1OTM2AAAAMSG9wsGHAKAy1+C0KCxALbmYvKff3uz/VwB612HaOw2F+alp" + 281 | "I80cRPAODmEmIru4GmwAAAAhIZWsd0ncx3rwoCcZ9NeSOyye3O6BLsNk4noPSdkf" + 282 | "bpaHAAAAODY4NzQ3NDcwM2EyZjJmNzI3NTZlNzQ2NTJlNjM2ZjZkMmY2MzYxNmQ3" + 283 | "Mjc5NmUyZTY4NjE2ZTY1AAAAAAAAAAEwAAAAAAAAACEhLMHRM5rsCrQu2F3GOVWA" + 284 | "Z2UFCixVGpdq83tnFrIk0h8AAAAhIe44XrrijvblrbT5iPzLMxWLud83cuXoy6mt" + 285 | "toZDlJF+AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcy" + 286 | "NzQ1OTM2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjI2AAAAATAA" + 287 | "AAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABigAAAAox" + 288 | "ODcyNzQ1OTQ2AAAAISF2yEkIfLl7Ajsf0YVp4pdwfLPebMHUjD5t1Z8zoxjeagAA" + 289 | "ACEhspchm7eXxpyy6CNinAtGNPThM5RFe/sVdNQ19pTXl0gAAAA6Njg3NDc0NzAz" + 290 | "YTJmMmY2Yjc1NmM2MTczNmI2YzY1Njk2ZTJlNjk2ZTY2NmYyZjZlNzk2MTczNjk2" + 291 | "MQAAAAAAAAABMAAAAAAAAAAxIS9HwLQWni0TBZMqQKmFdZ2oSvtDRFsTdqFe8P8c" + 292 | "Yk7NQJBt4lyYLnB63twUAeWEJwAAADEhvQVarcMhBEuu0ForhuAX8DIMl7CQfmDB" + 293 | "io/lvJPciLI6MJixWK9Tn6vOBMuLhSpJAAAAATAAAAABMAAAAAEwAAAAATAAAAAB" + 294 | "MAAAAAEwAAAAAAAAAAoxODcyNzQ1OTQ2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAA" + 295 | "AAAAAAAAAAAAAjI3AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMw" + 296 | "NzcxMDRBQ0NUAAABggAAAAoxODcyNzQ1OTU2AAAAISEsQ5H+p6k+/lE3UtzgktRL" + 297 | "NuBOZ78szV04ZQhWqaLAcAAAACEh+4RkoGkaAOREFTBbkr+7j2kcFXdoUX9epm6e" + 298 | "hbaHxjcAAABCNjg3NDc0NzAzYTJmMmY3MzYzNjg2MTY1NjY2NTcyMmU2OTZlNjY2" + 299 | "ZjJmNmM2NTczNmM2OTY1MmU2MjZmNjc2MTZlAAAAAAAAAAEwAAAAAAAAADEh2FnB" + 300 | "pIHlJoXCCjBDYMPnFTgD93rhg/45CQphpCA7aeErTY6zBvwn+rTo4lVGsrrdAAAA" + 301 | "ISGRjWDv3wjtjdP4P9Z5WO/HQ8XJ5oCPMXEn1raT5ls97gAAAAEwAAAAATAAAAAB" + 302 | "MAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NTk1NgAAAAAAAAAAAAAAAAAA" + 303 | "AAEwAAAAATAAAAAAAAAAAAAAAAIyOAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAA" + 304 | "AAAAAAoxMzczMDc3MTA0QUNDVAAAAXYAAAAKMTg3Mjc0NTk2NgAAACEhUYoAXo4M" + 305 | "zWu+MmrXMigKluN9UJtOrOA4WXbIWy/PbdIAAAAhIZxV+QFIyL1YG6PLx+ZnjL3p" + 306 | "tMq1wYU6g/7sr8or8Si7AAAARjY4NzQ3NDcwM2EyZjJmNmU2MTY0NjU3MjcyNjU2" + 307 | "ZDcwNjU2YzJlNmU2NTc0MmY2Nzc3NjU2ZTVmNzM2MzY4NmQ2OTY0NzQAAAAAAAAA" + 308 | "ATAAAAAAAAAAISHKTNAq4v2W12jAahJnG0LAIACiJA+7gyVNYN92upz3JAAAACEh" + 309 | "p5i1vp06RA/WhfZObM4wV3KcVliYGzHw/V4rlU0TosEAAAABMAAAAAEwAAAAATAA" + 310 | "AAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDU5NjYAAAAAAAAAAAAAAAAAAAAB" + 311 | "MAAAAAEwAAAAAAAAAAAAAAACMjkAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAA" + 312 | "AAAKMTM3MzA3NzEwNEFDQ1QAAAF8AAAACjE4NzI3NDU5NzYAAAAxId4VFZGCTWXr" + 313 | "j4xQXFpk8tcZsy3E6RGp9NbLrg9ZwQar9jrZv7ID1hwJsYXayPzdFAAAACEhF54x" + 314 | "UhH8yMXvFHi6ZCFmLAbB2lggCDQqIknhi8HM+1sAAAA8Njg3NDc0NzAzYTJmMmY2" + 315 | "NDZmNmY2YzY1NzkyZTY5NmU2NjZmMmY2MTZjNjU2YjVmNzA2MTcyNmI2NTcyAAAA" + 316 | "AAAAAAEwAAAAAAAAACEhAt8Mu6ecm7T+rGwHWfz68rIDJl24ac3ZH2QsNiYtcIEA" + 317 | "AAAhIQUx5F972yrpW+f9iPemLRfzZmEXTeddYh5FYgIIhoNqAAAAATAAAAABMAAA" + 318 | "AAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ1OTc2AAAAAAAAAAAAAAAA" + 319 | "AAAAATAAAAABMAAAAAAAAAAAAAAAAjMwAAAAATAAAAAAAAAAATEAAAABMAAAAAAA" + 320 | "AAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABkgAAAAoxODcyNzQ1OTg2AAAAMSFctg/x" + 321 | "qezfr1hwKzUCtxWN0TjN8ANA9ZbZUERX+/qLHJQup7o0Mj5XcpIpmAl0aWsAAAAh" + 322 | "IcGbzhx5ScC7b55/yvXtxwi/yG5gx4vg2bz6w9Q6G02qAAAAQjY4NzQ3NDcwM2Ey" + 323 | "ZjJmNmE2ZjY4NmU3MzJlNmU2MTZkNjUyZjYzNmY2Yzc1NmQ2Mjc1NzMyZTY0NmY2" + 324 | "ZjZjNjU3OQAAAAAAAAABMAAAAAAAAAAxIWLfo4j24vstNR/p8NYSrP+xHOy05DNx" + 325 | "vaB97a1r5gRApXnVDtAZzsOriidjgsXORwAAACEhzO+TfzZsgaSKkwVOPRk1m1WN" + 326 | "OzkviDjC0bj/je3cKg4AAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAA" + 327 | "AAAACjE4NzI3NDU5ODYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAC" + 328 | "MzEAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QA" + 329 | "AAF+AAAACjE4NzI3NDU5OTYAAAAxIUYf7M6iePmYVtOOdv0B9Mozb8cKmIFSbYwM" + 330 | "NOneeTpPEaP3TZIO2pkg0ga6SS2K4gAAACEhdi67SeZgy7Wr/mNaggGVaOnI0NcW" + 331 | "u6n/jJqMqL63lUQAAAAuNjg3NDc0NzAzYTJmMmY2MjYxNzU2MzY4MmU2ZjcyNjcy" + 332 | "ZjZkNjE3MjZjNjk2ZQAAAAAAAAABMAAAAAAAAAAhIWNxIegSHbcqsTw0CCV3gULh" + 333 | "V6Y2LRi6Vun+cbxazWq8AAAAMSEBSbLQTX2NKTwu+0TZNUwagKnHCMTHnw+Q3PCZ" + 334 | "t3CSOU9MPeEXl2a50drLEiRSIZAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 335 | "ATAAAAAAAAAACjE4NzI3NDU5OTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 336 | "AAAAAAACMzIAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEw" + 337 | "NEFDQ1QAAAFgAAAACjE4NzI3NDYwMDYAAAAhIUcBac23/F98Pwy/FSWJMGfEQVEr" + 338 | "Vmz8uJiW0ndhsHbVAAAAISGqxjmXDgHposEvOwIzXMM/wIPTaXmE6K2LMu+WvRBC" + 339 | "awAAADA2ODc0NzQ3MDNhMmYyZjY0NzU2Mjc1NzE3NTY1MmU2MzZmNmQyZjZhNjE2" + 340 | "MzY1NzkAAAAAAAAAATAAAAAAAAAAISEaL/HykudSEtIvCV4IZLmGVpRjO42P4prW" + 341 | "+BrhJwbCTwAAACEhGQIAi2dOCY+71CfKKLrelcbyGQX5X9LuaLYUMy9DihUAAAAB" + 342 | "MAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYwMDYAAAAA" + 343 | "AAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACMzMAAAABMAAAAAAAAAABMQAA" + 344 | "AAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFiAAAACjE4NzI3NDYwMTYA" + 345 | "AAAhId82S/9iRPDUriavRfqNVUhEGZOX08ECOnuaojPykIKAAAAAISHqqFJGu5eh" + 346 | "qOtr4bEHV5mficeDT2fVkf+LDCKWMCeZ9gAAADI2ODc0NzQ3MDNhMmYyZjczNjM2" + 347 | "ODY5NmU2ZTY1NzIyZTZmNzI2NzJmNzA3MjY5NjM2NQAAAAAAAAABMAAAAAAAAAAh" + 348 | "IS7XEzV9BA7EJEAwHlBxchTS64GqXT79huR1/o3vIMaCAAAAISH6Rh1DDkPHs0Sv" + 349 | "wmSkzoS/D23FFui7SeNffUnMuO4AIgAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 350 | "AAABMAAAAAAAAAAKMTg3Mjc0NjAxNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 351 | "AAAAAAAAAAIzNAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 352 | "MTA0QUNDVAAAAVsAAAAKMTg3Mjc0NjAyNgAAACEhKzg8FWTtLVnsx/q5hLxbOkcn" + 353 | "e/ypclJgm7BN3p/zsFYAAAAAAAAAPjY4NzQ3NDcwM2EyZjJmNzQ2ZjcyNzAyZTZl" + 354 | "NjU3NDJmNzM2ODc5NjE2ZTZlNjUyZTczNmQ2OTc0Njg2MTZkAAAAAAAAAAEwAAAA" + 355 | "AAAAADEhQX/IAe7mSCwFyHIFWT4ckp2VqD4KkkfvzvzEJFwXI7ZNmH1SvZqvFziL" + 356 | "U0Rkp7AGAAAAISFh6Ou1peyH/2balpLVMvjQNUPtJZo69s4hmcCl/S1m4AAAAAEw" + 357 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjAyNgAAAAAA" + 358 | "AAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAABMQAAAAEw" + 359 | "AAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFXAAAACjE4NzI3NDYwMzYAAAAh" + 360 | "Id0gI+Cr9oVISRJI+WSG5zK2nLbTZxYUnR66RF1Gh4JaAAAAAAAAADo2ODc0NzQ3" + 361 | "MDNhMmYyZjZkNjE2ZTc0NjUyZTYzNmY2ZDJmNjM2MTY5NjU1ZjczNzQ3MjY1Njk2" + 362 | "MzY4AAAAAAAAAAEwAAAAAAAAACEh/QMWW3D0w5CeocXshs+ucAWyxwmiNchiwYoB" + 363 | "6V2oOYwAAAAxIaPEUHR/4e325btZoD4F/PY9/iqT6+NTy1QlFn8sOJuO73XOru8a" + 364 | "NRxNP5JVdjNeKgAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAK" + 365 | "MTg3Mjc0NjAzNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAAB" + 366 | "MAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGaAAAA" + 367 | "CjE4NzI3NDYwNDYAAAAhIe3ccgsU8mUbkDYOwQv4NJ4OAyqU8VZJOTiUd+USdVtL" + 368 | "AAAAISHPfxoXKRXWeeBvuKovJYvHIZJFiD2AXNY1IZ5bbqZ7nAAAAEo2ODc0NzQ3" + 369 | "MDNhMmYyZjczNzc2MTZlNjk2MTc3NzM2YjY5MmU2ZjcyNjcyZjc3NjU2ZTY0NjU2" + 370 | "YzZjNWY2NzYxNzk2YzZmNzI2NAAAAAAAAAABMAAAAAAAAABBIfQUgwe7+CAYi4L3" + 371 | "v5Nqd3882yA1x4DsP9MHnoIuxZfMwL30DWyVMZgRdIyz+pzoUB3BuTmpyT27+iem" + 372 | "J9TCvw4AAAAhIUczUTh5lR8H7Ktgpuqs1gxES8B9t200WVcR7Qpp9PCnAAAAATAA" + 373 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2MDQ2AAAAAAAA" + 374 | "AAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjM1AAAAATAAAAAAAAAAATEAAAAB" + 375 | "MAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABTQAAAAoxODcyNzQ2MDU2AAAA" + 376 | "ISFois9KEuC2s4n6+S4iIfxoPyaICVq5eAnmVnRt+IjEVQAAAAAAAABANjg3NDc0" + 377 | "NzAzYTJmMmY3MjZmNmM2NjczNmY2ZTJlNjM2ZjZkMmY3NzY5NmM2Yzc5NWY2MjYx" + 378 | "NzI3NDY1NmM2YwAAAAAAAAABMAAAAAAAAAAhIUUANM5pwqxsxpSIR12nl8MIEH2d" + 379 | "gzPDjs3akFpSViFaAAAAISHnnvsbor3lJDmegn0727nV7i+T4xwr4mHPdpMD+AoS" + 380 | "qAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjA1" + 381 | "NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAAB" + 382 | "MQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAFyAAAACjE4NzI3NDYw" + 383 | "NjYAAAAhIT3aUadIp7a4npcPewKyUNmM571IfUBI3HonHGqhFvKDAAAAISEtgPTq" + 384 | "ASDU7nJMFiBIQgmLNLs2Rf73uAyvCojBZznxMQAAAEI2ODc0NzQ3MDNhMmYyZjYz" + 385 | "NmY2YzZjNjk2ZTczNzI2NTY5NjM2ODY1NmMyZTZlNjU3NDJmNzk2MTczNmQ2OTZl" + 386 | "NjUAAAAAAAAAATAAAAAAAAAAISHyXlSAi4MAqz/VfXdgBn05h52/TMidVmsXbiye" + 387 | "ePviSgAAACEhm1pnAzRXD1lZ7E5w8u4hWlA6ZfoAEn0OgnG4i0P7NZAAAAABMAAA" + 388 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYwNjYAAAAAAAAA" + 389 | "AAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACMzYAAAABMAAAAAAAAAABMQAAAAEw" + 390 | "AAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGIAAAACjE4NzI3NDYwNzYAAAAh" + 391 | "IS6Zh5Ri+NYQTzg3DUClYCs8WHCYJMcSRjqAbtxJpiFaAAAAISE/FW6hUIGfpHVy" + 392 | "OjQ5Y3oexM/pbESQXSzZSs7DEx45ZQAAAEg2ODc0NzQ3MDNhMmYyZjY0NjU2MzZi" + 393 | "NmY3NzJlNmU2NTc0MmY3MjZmNmY3MzY1NzY2NTZjNzQyZTZiNzM2ODZjNjU3MjY5" + 394 | "NmUAAAAAAAAAATAAAAAAAAAAMSGo7CEeh4bG90RwATzYPM3JH6U5RXJKMy6sZ5vL" + 395 | "AHjrnWjSX2AMDegxFFxZA2euXssAAAAhIRQ4hn15n/NJMhOAfXcwQfD838qSTiMW" + 396 | "3Jm9L8n03FEyAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAox" + 397 | "ODcyNzQ2MDc2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjM3AAAA" + 398 | "ATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABgQAA" + 399 | "AAoxODcyNzQ2MDg2AAAAISGzuJy2/x0bzTTo5NZNRwqUmrQuRlFd3dF4BICxsjwi" + 400 | "WgAAAAAAAABkNjg3NDc0NzAzYTJmMmY2MzZmNmU3MzY5NjQ2OTZlNjU2ODY1Njk2" + 401 | "NDY1NmU3MjY1Njk2MzY4MmU2ZTYxNmQ2NTJmNmU2MTZkNjUyZTYzNjg3MjY5NzM3" + 402 | "NDY5NjE2ZTczNjU2ZQAAAAAAAAABMAAAAAAAAAAxIRr+9XJWPmE4/AG7+Pb0Ks8N" + 403 | "D8/7aC18pUrAyp9kbODPMms0fFnL/yZA/ad2xfS50wAAACEhYu5vWJSOS+ui86sl" + 404 | "CfaoQ8oUxXGQGr6z+15FToZdk0AAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 405 | "ATAAAAAAAAAACjE4NzI3NDYwODYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 406 | "AAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRB" + 407 | "Q0NUAAABYAAAAAoxODcyNzQ2MDk2AAAAISHDPPYOG+t5Z2olWjktpv9ONj9GtSrB" + 408 | "zhEzPN4E3dORUAAAACEhNno60cEl6iYI5QvcGwalaVlou8ciQkyDcXScg6X5MtMA" + 409 | "AAAwNjg3NDc0NzAzYTJmMmY2MjZmNjc2OTczNjk2MzY4MmU2ZTY1NzQyZjZjNmY3" + 410 | "MjY5AAAAAAAAAAEwAAAAAAAAACEhA0cQrJycpr3/lFSJ8mRaVxxYFqaEq8SWeeGH" + 411 | "kL0zA7oAAAAhIcq2yHDSlHc9T8KKsjYWPpHNaR/F9Gix38FLEuNHnJ+gAAAAATAA" + 412 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2MDk2AAAAAAAA" + 413 | "AAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjM4AAAAATAAAAAAAAAAATEAAAAB" + 414 | "MAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABTQAAAAoxODcyNzQ2MTA2AAAA" + 415 | "ISERFSfjI3TjPMa0kTR1GR50OjZ/EiLvDiqW6CDzyuUuVQAAAAAAAAAwNjg3NDc0" + 416 | "NzAzYTJmMmY2ODY1NzI3YTZmNjcyZTZlNjE2ZDY1MmY2Yzc1Njk2NzY5AAAAAAAA" + 417 | "AAEwAAAAAAAAADEhJE3xkPvg7pMNLEHaUJwff5QT6ZLrXAqHIIOhJ+/xjI5ZMR3K" + 418 | "gWdPoqRKWTI1hTuOAAAAISHg5oGEGzA/npjXns+NvIuIx80syiLBG8+IVOjQkcaw" + 419 | "MwAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjEw" + 420 | "NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAAB" + 421 | "MQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAF8AAAACjE4NzI3NDYx" + 422 | "MTYAAAAxIR+rniCxFedvT5iPsV+wriz/eUGqUDjSUVvgWx++Ie8SpuixV2oLJek3" + 423 | "5QlsXpUpdAAAACEhA/oyqcYV/FLwZ/bwWmpw411m0Yw7xEIrSlTD84jBzdcAAAAs" + 424 | "Njg3NDc0NzAzYTJmMmY2ZDYxNmU2ZTJlNjM2ZjZkMmY2MzY1NjM2OTZjNjUAAAAA" + 425 | "AAAAATAAAAAAAAAAMSHTlqBR1p5KTloaXsqfkCtKXfnnkhBud6vb2lrKt9TgHbzz" + 426 | "FmisdDtXdPOayMyjIA8AAAAhIRa8RGSt4sHV3kBWgWtmzffe0eQY13rGXh+aTQqu" + 427 | "QlTbAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2" + 428 | "MTE2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjM5AAAAATAAAAAA" + 429 | "AAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABgAAAAAoxODcy" + 430 | "NzQ2MTI2AAAAMSF5MfDk4jYK0etH9leG6MO7EBSFlr5N29bfk2aH8WOf6PW1E82G" + 431 | "hVy6jyldOud6wakAAAAhIRs3CcQDvzx4kT89JGnOSoLaYkQOJ5wcH07foV8Zl8w7" + 432 | "AAAAMDY4NzQ3NDcwM2EyZjJmNjQ2ZjZmNmM2NTc5MmU2ZTYxNmQ2NTJmNjU3NzYx" + 433 | "NmM2NAAAAAAAAAABMAAAAAAAAAAxISBUh/zVQKwBdHsI1zLcz9/V686lIrsDg1Y4" + 434 | "oL21SljpYgGYgXUJomOI9PUnjj/F2QAAACEhWopo9RqMg0T6LeHA1ouIoR6s9uBn" + 435 | "T4GdUb+8LyOSuloAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAA" + 436 | "CjE4NzI3NDYxMjYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNDAA" + 437 | "AAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGq" + 438 | "AAAACjE4NzI3NDYxMzYAAAAxIbMZ3DBnzDDDh7eUUesvL3gFnLLJWDwDKJdWk4iL" + 439 | "2AcmCOXZEjAM6AOis0Dy0CZM5AAAACEhXk0HduCrtiALdG21CCdcDsw5WD09Vzlt" + 440 | "HgBKPVjPbFkAAABaNjg3NDc0NzAzYTJmMmY2MjYxNmM2OTczNzQ3MjY1NzI2OTZk" + 441 | "NjM2MzZjNzU3MjY1MmU2MzZmNmQyZjZhNjE3MTc1NjE2ZTVmNzc2OTZjNmI2OTZl" + 442 | "NzM2ZjZlAAAAAAAAAAEwAAAAAAAAACEhiUn0XC5CEOI/x/ZPf8pnfBwCHVDWN6MP" + 443 | "klIaKSK9+mYAAAAxIa1LGBP4wk8fbn9CjFbeYzwIZoX1Kgry55/SKi8vjhoSTBwK" + 444 | "jKasZIdygJMhODEVqQAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAA" + 445 | "AAAKMTg3Mjc0NjEzNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI0" + 446 | "MQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAA" + 447 | "AV8AAAAKMTg3Mjc0NjE0NgAAADEhK3mh+y52pwKRaNPCkf2itmwOWCf+ihpxwkYY" + 448 | "qRWmQUFJFaYVfWEqjf+rjkOLupx2AAAAAAAAADI2ODc0NzQ3MDNhMmYyZjcwNmY3" + 449 | "NTcyNmY3MzJlNmU2NTc0MmY2YTY1NzI2NTZkNjk2NQAAAAAAAAABMAAAAAAAAAAh" + 450 | "IQz4rm0x0oifUs7U79kkwk2KZZ7RWw76GLZfZM2jFDmoAAAAMSHuKArDA7E6S7MY" + 451 | "7YYjW5oENQti+8AhNRIRmvm3ZJoDH/8AzsjP7VwZCeCNXDi5+rkAAAABMAAAAAEw" + 452 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYxNDYAAAAAAAAAAAAA" + 453 | "AAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAA" + 454 | "AAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABogAAAAoxODcyNzQ2MTU2AAAAMSG7//UM" + 455 | "gswtSfMRaL+bnmoiL1VNggfiqWrW+ydbIPxULtrvGgel1i/fIsxZ+tKbGy0AAAAh" + 456 | "IcjhBXk5Y2nNSIor79shd7xmBDaO7Xdnuc7SWo0fv+3IAAAAQjY4NzQ3NDcwM2Ey" + 457 | "ZjJmNmI2NTZjNjU3MjJlNjk2ZTY2NmYyZjZlNjk2YjY5NzQ2MTJlNmM2OTZlNjQ2" + 458 | "NzcyNjU2ZQAAAAAAAAABMAAAAAAAAAAxIRQAwLVE2YVFMOZJftKR4ERR1jI111VM" + 459 | "xOHVfymc1Nb/VMfvKPcugRyFnToJ5FXt8gAAADEho+zPg8+KNDX5ZyozfI+foxnd" + 460 | "4M1wfV5XyqO+3iPgbMGSgB/EuAqVCf9vPY8fgDf5AAAAATAAAAABMAAAAAEwAAAA" + 461 | "ATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2MTU2AAAAAAAAAAAAAAAAAAAAATAA" + 462 | "AAABMAAAAAAAAAAAAAAAAjQyAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAA" + 463 | "CjEzNzMwNzcxMDRBQ0NUAAABggAAAAoxODcyNzQ2MTY2AAAAISGrWq0AxhTXoiug" + 464 | "tHw2J/31Ec04r0hpJUGvooLiOV5ghgAAACEhdEJ1EZw4nIA/bIaL5Fb/urcMoAf8" + 465 | "4uRmjnvkNZf61dMAAABCNjg3NDc0NzAzYTJmMmY2YTYxNzM2YjZmNmM3MzZiNjky" + 466 | "ZTYzNmY2ZDJmNjM2ZjZlNmU2NTcyNWY2ZjcyNzQ2OTdhAAAAAAAAAAEwAAAAAAAA" + 467 | "ADEhL1bEVgVPSRUz8DcNcIByBGss/2eixkW0Y/nqgKrSdYG0kMFd0Pfb9iNu5h4R" + 468 | "wSnmAAAAISEi4LXgtoJUiILwN9uVsPNumBtSrq8CrPXhhCPqY+LZpgAAAAEwAAAA" + 469 | "ATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjE2NgAAAAAAAAAA" + 470 | "AAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI0MwAAAAEwAAAAAAAAAAExAAAAATAA" + 471 | "AAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAYIAAAAKMTg3Mjc0NjE3NgAAADEh" + 472 | "qTunGI7LVuA6smQ5NUl/QAdp0BpFBZ86DxXcu9GIPjulrbfm7D8rbLlK+hyrrPUR" + 473 | "AAAAISF/eCndbZ7sty8Fk5GacdtCSAoe4UlUJmeA0+bfRhWb1QAAAEI2ODc0NzQ3" + 474 | "MDNhMmYyZjYzNjg2MTZkNzA2YzY5NmUyZTZmNzI2NzJmNmM3NTY1NWY3MzYzNjg3" + 475 | "MjZmNjU2NDY1NzIAAAAAAAAAATAAAAAAAAAAISHlHxpgVAUJAiECPC2RJ6/cJl8w" + 476 | "VbPqsL9MINg0d2HcvAAAACEhcNCDj79e3CRAemHtbExcOM0yS/eiXvyLs58RfTHV" + 477 | "4c8AAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYx" + 478 | "NzYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNDQAAAABMAAAAAAA" + 479 | "AAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGAAAAACjE4NzI3" + 480 | "NDYxODYAAAAhIQwGNLfZsRLpZCmV9LYbZUQipCsK0h/iwz/F0sdXGljHAAAAISEy" + 481 | "nfcjxV48zNP1YQL0G+fczKb9WYYKN/yvim5CoVQWgAAAAEA2ODc0NzQ3MDNhMmYy" + 482 | "ZjY0NmY2ZTZlNjU2YzZjNzk2MTY0NjE2ZDczMmU2MzZmNmQyZjczNjE2ZTc0Njk2" + 483 | "ZTZmAAAAAAAAAAEwAAAAAAAAACEhr5OqXVgwE4Cm5pJ7dBbJ/5MR+odlcYi68jT8" + 484 | "/d2ZqPwAAAAxIcqzbJKVdtdhP57PWMymBWVaLF/3OhGnBpRaGd3m9MtBhwbJDRuQ" + 485 | "znGbA3QzZTT6EwAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAK" + 486 | "MTg3Mjc0NjE4NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI0NQAA" + 487 | "AAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAZAA" + 488 | "AAAKMTg3Mjc0NjE5NgAAADEh11IPQ+cUTTBgD145Il6mGe6388poazsKm27r2rgQ" + 489 | "2I2rPR+vvH822BmmHqieiS77AAAAISFBRBjsh6QoJPEAikbmliMNGIJOiKXD0POg" + 490 | "XU28iLWtPgAAAEA2ODc0NzQ3MDNhMmYyZjZjNjE3MjZiNjk2ZTYzNmY2ZTczNjk2" + 491 | "NDY5NmU2NTJlNmY3MjY3MmY2YzY1NmY2YzYxAAAAAAAAAAEwAAAAAAAAADEhOp67" + 492 | "pjeKjn3jZvND4y6Spl+0Uf5sfT4uT/6XdU7EQjL1mIc4KFKITq9u8bZyMfbvAAAA" + 493 | "ISFDKO6UmiN55Vz/Z1nE9wgMIggkRFLSfoEWtOFxBxm4gQAAAAEwAAAAATAAAAAB" + 494 | "MAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjE5NgAAAAAAAAAAAAAAAAAA" + 495 | "AAEwAAAAATAAAAAAAAAAAAAAAAI0NgAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAA" + 496 | "AAAAAAoxMzczMDc3MTA0QUNDVAAAAWgAAAAKMTg3Mjc0NjIwNgAAACEhivEANkoW" + 497 | "2ebUjJQ1zqte5o5Lm+n7/0diEkqe0IF0gwoAAAAhIaBuyDnnjdcSg6CpOio1F0EY" + 498 | "hTlnREYYRBn23/oNcYWtAAAAODY4NzQ3NDcwM2EyZjJmNzI3NTZlNzQ2NTZkNmY2" + 499 | "NTZlMmU2ZTYxNmQ2NTJmNzA2OTY1NzI3MjY1AAAAAAAAAAEwAAAAAAAAACEhTp3L" + 500 | "/Io2JJhFs4xZauBDMM7CDOZN9aEWbzO20rKqcW8AAAAhIRazdF90kyS1RTrapUfd" + 501 | "ZCIG5h767SrwDO1O0cv+qh4HAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 502 | "AAAAAAAAAAoxODcyNzQ2MjA2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 503 | "AAAAAjQ3AAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRB" + 504 | "Q0NUAAABbgAAAAoxODcyNzQ2MjE2AAAAISFKhsuIHlq9ZK8qj7V6l34zT2Y4SaW7" + 505 | "e8vrBQg4wUmt2QAAACEhZP+ucMFHVfuqhnkbse0AdEl+gwiMAaFzNIQ7E2Azp4gA" + 506 | "AAAuNjg3NDc0NzAzYTJmMmY2ZDZmNmY3MjY1MmU2OTZlNjY2ZjJmNzA2NTYxNzI2" + 507 | "YwAAAAAAAAABMAAAAAAAAAAhIfSeNtDnxF+rrgC2lqoAp5fOEYzeZoWC22pGjnLR" + 508 | "jvflAAAAMSFGQQA1zXOD46JDl7KlJOOdNKqvf4zUEAAvCvSzYil4PoZEmpEhzORM" + 509 | "82wjFD8ycXcAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4" + 510 | "NzI3NDYyMTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNDgAAAAB" + 511 | "MAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGWAAAA" + 512 | "CjE4NzI3NDYyMjYAAAAhIfzsPBb9zw+znGr4dJ9oi+K9Kasa6HGl9KeaNzyjZnDz" + 513 | "AAAAISHOX7VYz7NdFBpwqA5SWOlwVYg9QsxgzCQ1Pg+rnoHQDQAAAEY2ODc0NzQ3" + 514 | "MDNhMmYyZjYxNzI2ZDczNzQ3MjZmNmU2NzY4NjE2MzZiNjU3NDc0MmU2ZTYxNmQ2" + 515 | "NTJmNmE2MTY1NjQ2NTZlAAAAAAAAAAEwAAAAAAAAADEhQ6EOU47TD4aNTeAqrKvn" + 516 | "0meY9qJPPxBR9Plfn/uN1Kp6ZWDuYWM0XNNG2U+suAY9AAAAMSGnFX55n8slGEuC" + 517 | "4VixBBjncWn4DCOckmOZlXbMJGojAdxm6ItEBUkXZRfoJqCrSg8AAAABMAAAAAEw" + 518 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYyMjYAAAAAAAAAAAAA" + 519 | "AAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNDkAAAABMAAAAAAAAAABMQAAAAEwAAAA" + 520 | "AAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAGYAAAACjE4NzI3NDYyMzYAAAAhIZ6M" + 521 | "UDsd3cxd81PLuLGbefM0evo6JDhjC3mFemUTexW4AAAAISF1SZY7/6ii9QquiGk3" + 522 | "ZSBSKy06zeI7hfepQ2HlEObtCwAAAFg2ODc0NzQ3MDNhMmYyZjczNjM2ODc1NmM2" + 523 | "OTczNzQ2ZDY1NzQ3YTJlNjk2ZTY2NmYyZjY1NzM3MDY1NzI2MTZlN2E2MTVmNjM3" + 524 | "NTZkNmQ2NTcyNjE3NDYxAAAAAAAAAAEwAAAAAAAAADEh3UA8lPeFoYOCGcoMqpad" + 525 | "cfn91UaHAZ84jzzrluB/tUsNlkOKGYEEnYogobIeyY2IAAAAISFvuhLWcLczKxUv" + 526 | "TPzCREpwVZhz5JnBiHgtFQXHzbE4bgAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 527 | "AAABMAAAAAAAAAAKMTg3Mjc0NjIzNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 528 | "AAAAAAAAAAI1MAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 529 | "MTA0QUNDVAAAAXoAAAAKMTg3Mjc0NjI0NgAAADEh+6+5E2dpwHAahj8HhghS7Tiz" + 530 | "atIe+K/38mBeat2wIGuLBl1QBuzlAz/HAM4wJs5RAAAAISFMXZCT5hUyeLF6c73d" + 531 | "GIBFhIv2JElNHRLU9FDwTiQ8UQAAADo2ODc0NzQ3MDNhMmYyZjYyNjU2NTcyNmQ2" + 532 | "OTZjNmM3MzJlNmU2NTc0MmY2NDYxNmU2OTY1NmM2YzY1AAAAAAAAAAEwAAAAAAAA" + 533 | "ACEh+k828kKLO01oMkW/DYji9UXLzE0LYCbqda1NZZmdmeEAAAAhIYBS4wjSMEDX" + 534 | "JoA5/5rvJe/qiAlVSCl3yvKpwgo23eFQAAAAATAAAAABMAAAAAEwAAAAATAAAAAB" + 535 | "MAAAAAEwAAAAAAAAAAoxODcyNzQ2MjQ2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAA" + 536 | "AAAAAAAAAAAAAjUxAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMw" + 537 | "NzcxMDRBQ0NUAAABUQAAAAoxODcyNzQ2MjU2AAAAISGW8+9kctjuPK6X5L9r6zOm" + 538 | "lgpvvX6j0/2UR5ve7qyW3gAAAAAAAAA0Njg3NDc0NzAzYTJmMmY2NDZmNzU2NzZj" + 539 | "NjE3MzJlNmU2MTZkNjUyZjcwNmY3Mjc0NjU3MgAAAAAAAAABMAAAAAAAAAAxIaiv" + 540 | "pvk7dppj/nPolImh7AFR2kx4cANrGRYyAvIbeHY/KwTYM5Ck0O8Gkm1jdNxSXAAA" + 541 | "ACEhiCOqIxGHXnB0Zoey+TP+gUovtRZQ3lU79xhLzCoOx8sAAAABMAAAAAEwAAAA" + 542 | "ATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDYyNTYAAAAAAAAAAAAAAAAA" + 543 | "AAABMAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAA" + 544 | "AAAACjEzNzMwNzcxMDRBQ0NUAAABdgAAAAoxODcyNzQ2MjY2AAAAISFv+mMv2B/U" + 545 | "Q2BdUUHBjU6866hJAgc67yKhuMoAJxXRuAAAACEhPaLJhgtFmmyF33KXEcUfCIxW" + 546 | "BEBAZqgl4Eerx0wE0JEAAABGNjg3NDc0NzAzYTJmMmY2NDZmNmU2ZTY1NmM2Yzc5" + 547 | "MmU2MzZmNmQyZjc0Nzk3MjY5NzE3NTY1NWY2YzYxNmU2NzZmNzM2OAAAAAAAAAAB" + 548 | "MAAAAAAAAAAhISydgPK/e1rJplm2wN1+4yTz56+EKDmsbiq+1uYcN027AAAAISFe" + 549 | "8CoPyaC3aS0wEwpXrZGKWIo4hlZb7bje85a6dzyf9AAAAAEwAAAAATAAAAABMAAA" + 550 | "AAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjI2NgAAAAAAAAAAAAAAAAAAAAEw" + 551 | "AAAAATAAAAAAAAAAAAAAAAI1MgAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAA" + 552 | "AAoxMzczMDc3MTA0QUNDVAAAAW4AAAAKMTg3Mjc0NjI3NgAAACEh3LwiezAkEUR+" + 553 | "j9usrYMiyyqeOYR+6PKzYRBlE22FfpoAAAAhIbBjmikiDf/gGMftxTr1uY4XR21R" + 554 | "8UObVLnnhgIC+EkYAAAALjY4NzQ3NDcwM2EyZjJmNzM2MzY4NmY2NTZlMmU2OTZl" + 555 | "NjY2ZjJmNmQ2MTYzNzkAAAAAAAAAATAAAAAAAAAAMSECrpe5ZtQ6RB3CYz5V5hE9" + 556 | "KVKEIRn1Fh4c3hW4CAXQ8n10k8lnIXisyEMn+PH+8M0AAAAhIX1mKNsOAMrhn7cl" + 557 | "E9XBmVfkUMzcrLY7PWyDTGi46Zy9AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAA" + 558 | "AAEwAAAAAAAAAAoxODcyNzQ2Mjc2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAA" + 559 | "AAAAAAAAAjUzAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcx" + 560 | "MDRBQ0NUAAABfQAAAAoxODcyNzQ2Mjg2AAAAMSH+Pt5lvMdF2sZltKJuzRxWW5+R" + 561 | "518B7+oeoX1pCk8Re1OAImuUvARJ06aoSsH2PQ8AAAAAAAAAQDY4NzQ3NDcwM2Ey" + 562 | "ZjJmNzM2MzY4NzU3MDcwNjUyZTYzNmY2ZDJmNzI2ZjczNjU3NDc0NjEyZTc5NzU2" + 563 | "ZTY0NzQAAAAAAAAAATAAAAAAAAAAMSF51wnU/8MQL0M2I1KRg/VRXoBm7EyuAPdz" + 564 | "gicb+jPMj5uCqLGkO6yw71F7EmHYF44AAAAxIfcdgP77/uyU/+FuliVhRDQVup3h" + 565 | "CwNBTKpcjksC8vg4nXW3n9PBJZ9csWw9ric9mAAAAAEwAAAAATAAAAABMAAAAAEw" + 566 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjI4NgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 567 | "ATAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3" + 568 | "MzA3NzEwNEFDQ1QAAAGAAAAACjE4NzI3NDYyOTYAAAAhIf9jc91gmE4zEOM45EtG" + 569 | "NTDZfJysY54eXl4Mm4gZ62F0AAAAISEThT3gw6D9nq7lbUehPOGZZScqeBBopIzr" + 570 | "N314io+HsQAAADA2ODc0NzQ3MDNhMmYyZjY2NjU2OTZjMmU2MzZmNmQyZjY5NzM2" + 571 | "MTYyNjU2YzZjNjUAAAAAAAAAATAAAAAAAAAAMSGTi2pOr8iisupbXnGcstLDjTmy" + 572 | "hL1dMh/GZfOwI1ROZNnm5739s4BimxGSa2YqNC0AAAAxIb7ncD0hULxm09sIMeZy" + 573 | "7OGBYtVHu3nRKdnhSO4ORH+g5ekRiuRrR5lZ6o6tCI2lkAAAAAEwAAAAATAAAAAB" + 574 | "MAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjI5NgAAAAAAAAAAAAAAAAAA" + 575 | "AAEwAAAAATAAAAAAAAAAAAAAAAI1NAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAA" + 576 | "AAAAAAoxMzczMDc3MTA0QUNDVAAAAV8AAAAKMTg3Mjc0NjMwNgAAADEhk8jUgvJn" + 577 | "090+fAf6MJBipK6AxFQ+ZDheQzDCeoivsc3jv0i/62miiB80RDF6UMoiAAAAAAAA" + 578 | "ADI2ODc0NzQ3MDNhMmYyZjZkNjM2YjY1NmU3YTY5NjUyZTZlNjU3NDJmN2E2MTcy" + 579 | "Njk2MQAAAAAAAAABMAAAAAAAAAAxIeRkk2vH0Asii+9greWOFnT9Yh7byhKdRIJH" + 580 | "7Nt60VYt5m0Gd/0f0g3WPmxMNUCw5wAAACEhOkJc3e9C9dwhnAu0zVVBeOo3gBwu" + 581 | "D0s9clIUYV9kvskAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAA" + 582 | "CjE4NzI3NDYzMDYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAAAAAAA" + 583 | "ATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABpAAA" + 584 | "AAoxODcyNzQ2MzE2AAAAMSHqrjdVh7SyJdm/i/QdveoHr0EmFm2dKysPmxUwIyz8" + 585 | "dStajfUR8UuecrJkDpcfE2gAAAAhIagNh8jpaaAgHvWQ6dIp/TinfIRiAtdNKzli" + 586 | "A2Qcjj8PAAAARDY4NzQ3NDcwM2EyZjJmNzc2ODY5NzQ2NTZiNmM2ZjYzNmI2ZjJl" + 587 | "NmU2MTZkNjUyZjZjNjE2MzY1NzkyZTY0NjE3MjY1AAAAAAAAAAEwAAAAAAAAADEh" + 588 | "+gQF+NEN0o11e4QQcvHmVAzzlAL8378JeJHYiLx5oys3Hux8rm8V5Wmefw29sAN0" + 589 | "AAAAMSFdcr3phRXBfJNB7mcqyGcxhq7Oa8Y0tBuseTXMXpDn+PEN2E2AxmmtG4Go" + 590 | "lkrOmqsAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3" + 591 | "NDYzMTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNTUAAAABMAAA" + 592 | "AAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNEFDQ1QAAAF2AAAACjE4" + 593 | "NzI3NDYzMjYAAAAxIVK90J3XMPZAFuRp6Osn5EkFu3jHT8XBpNzVESLLl2QuyGkx" + 594 | "H1eaoWtQu9znoH8d3AAAACEhDKRI7S5YTtlSsgQOM56/q4NWLlvLw0s+eCACoUqy" + 595 | "2HAAAAA2Njg3NDc0NzAzYTJmMmY2ZjZiNzU2ZTY1NzY2MTJlNjI2OTdhMmY2YzY5" + 596 | "NzM2MTZlNjQ3MjZmAAAAAAAAAAEwAAAAAAAAACEhoAKmn3YZpzOlVaWh7DH41IL7" + 597 | "Fscmahm5cou/nr1YDMEAAAAhIVsDiiobgbm4IusJeTIpJYqUGTXar5OsoExjFCHt" + 598 | "CVMqAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2" + 599 | "MzI2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAjU2AAAAATAAAAAA" + 600 | "AAAAATEAAAABMAAAAAAAAAAAAAAACjEzNzMwNzcxMDRBQ0NUAAABoAAAAAoxODcy" + 601 | "NzQ2MzM2AAAAMSFU6SKNW6QfLGsMUOh6SDiCJTkLkqgooMJjQnu67ggENVvCNJXY" + 602 | "/k4PLO0EVYe0F9sAAAAhISu0qI6/0edzHljLC2LY6IZyC+C5uih4/NzmxnMysCXU" + 603 | "AAAAQDY4NzQ3NDcwM2EyZjJmNzM2MTc1NjU3MjZiNzU3NjYxNmM2OTczMmU2OTZl" + 604 | "NjY2ZjJmNjI3MjYxNzg3NDZmNmUAAAAAAAAAATAAAAAAAAAAMSF90O1BZfKqUWt3" + 605 | "0H6m9sQGvHoaO21DvtTQ/DglAFnIXHltZ528s1EoRElwxNHj3pAAAAAxIRwmpCAn" + 606 | "PcbgJdgmONJ/3yan8wqRNxwva6eTfvfYJ6VyO/T1GR9ytQ/4YuKIRcFXWQAAAAEw" + 607 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjMzNgAAAAAA" + 608 | "AAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI1NwAAAAEwAAAAAAAAAAExAAAA" + 609 | "ATAAAAAAAAAAAAAAAAoxMzczMDc3MTA0QUNDVAAAAT8AAAAKMTg3Mjc0NjM0NgAA" + 610 | "ACEhWHIlbPdrg1cxYw12zp/pT4NXK1251UvT7sQAxZvDRJ4AAAAAAAAAMjY4NzQ3" + 611 | "NDcwM2EyZjJmNzM3MDY5NmU2YjYxMmU2OTZlNjY2ZjJmNmI2NTZlNjQ3MjYxAAAA" + 612 | "AAAAAAEwAAAAAAAAACEhopsZrJCftw32PVUKDFNPeDazeyR+x3g9tdOF4i8EtlgA" + 613 | "AAAhIW5MiA5bQIegxeMVVVvSIxIJMhw8jl2VOkFR5dMNk6moAAAAATAAAAABMAAA" + 614 | "AAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2MzQ2AAAAAAAAAAAAAAAA" + 615 | "AAAAATAAAAABMAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAA" + 616 | "AAAAAAoxMzczMDc3MTA0QUNDVAAAAWwAAAAKMTg3Mjc0NjM2NgAAACEhgaOpYMbJ" + 617 | "z03Hg74f+VxVhArquOV7s3SrsaPlKKKBzHQAAAAhIT8AG2KA6BljbGz6JB1c4W+Q" + 618 | "pevHAnl3Ry04T6OhydrRAAAAPDY4NzQ3NDcwM2EyZjJmNzA2Zjc1NzI2ZjZkNjk3" + 619 | "NDY4NjE2ZDJlNmU2MTZkNjUyZjY1NjY3MjYxNjk2ZQAAAAAAAAABMAAAAAAAAAAh" + 620 | "Ifjbyraq5+KMagWUJNytVJ90ZmAsh+s/Y68K4tgv6iTcAAAAISGCFBhinuNKk5m7" + 621 | "TWJ6ZQyYoPFljt89RKIGbm3FE6PkMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 622 | "AAABMAAAAAAAAAAKMTg3Mjc0NjM2NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 623 | "AAAAAAAAAAI1OAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 624 | "MTA1QUNDVAAAAVEAAAAKMTg3Mjc0NjM3NgAAACEhT0031xQ/fE7hclg1kZbaqDXV" + 625 | "+R82hh/wuo/aBkRlm0UAAAAAAAAARDY4NzQ3NDcwM2EyZjJmNjg2NTY5NjQ2NTZl" + 626 | "NzI2NTY5NjM2ODJlNmU2NTc0MmY3Mjc5NjE2ZTZlNWY2ODYxNzk2NTczAAAAAAAA" + 627 | "AAEwAAAAAAAAACEhPWUFEFPqutbf6MAvc7Fc8T77ELjBjqTS3fmYd3HDcAEAAAAh" + 628 | "IaoV06azgsaZ1IP71foi65sfmwkZyDultYjBzSZohFDnAAAAATAAAAABMAAAAAEw" + 629 | "AAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2Mzc2AAAAAAAAAAAAAAAAAAAA" + 630 | "ATAAAAABMAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAA" + 631 | "AAoxMzczMDc3MTA1QUNDVAAAAX4AAAAKMTg3Mjc0NjM4NgAAACEh6nj/Gqvp52rR" + 632 | "VczHT/rehNK9VjgvEUqxNY8IQO/4sV4AAAAhIbSNbyYuKDi8vFWoN+OBdCneJ4at" + 633 | "SJpmSP3p6ohJ94JZAAAAPjY4NzQ3NDcwM2EyZjJmNmY2YjY1NjU2NjY1NjQ2MTZk" + 634 | "NmY3MjY1MmU2MjY5N2EyZjY3Njk2Zjc2NjE2ZTY5AAAAAAAAAAEwAAAAAAAAADEh" + 635 | "lbQt9/ORxb2Nat6AYieI7rj2BrxlZhomVvMexifb73pKu5ZHHmBP9y2Ob/zIbq6L" + 636 | "AAAAISE5UbIwhatj9gc5xyOl54RdobqcmIg22iqS/zpI51KItQAAAAEwAAAAATAA" + 637 | "AAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjM4NgAAAAAAAAAAAAAA" + 638 | "AAAAAAEwAAAAATAAAAAAAAAAAAAAAAI1OQAAAAEwAAAAAAAAAAExAAAAATAAAAAA" + 639 | "AAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAX4AAAAKMTg3Mjc0NjM5NgAAADEh26zB" + 640 | "cIcYY7x6GqCqvOsF1DDLdYD0jt9NqwrScomHZ4byJtmyK1+DPlbhkhRiAEilAAAA" + 641 | "ISHx5jHsfYubswaeDNgl2qloJBpWGJf87m+TT5O3zRbBnAAAAD42ODc0NzQ3MDNh" + 642 | "MmYyZjY0Njk2MzZiNjk2MjZmNzM2MzZmMmU2MjY5N2EyZjdhNjE2MzY4NjE3MjY5" + 643 | "NjE2OAAAAAAAAAABMAAAAAAAAAAhIQuOoAGzVTssrRbtg4dyDiTcHUtsx1sWDTPc" + 644 | "IAXoRsT3AAAAISGHCH8TUm702itAbe82iWvFjdwCZj0HkPIfclWbW6417wAAAAEw" + 645 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjM5NgAAAAAA" + 646 | "AAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI2MAAAAAEwAAAAAAAAAAExAAAA" + 647 | "ATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAXYAAAAKMTg3Mjc0NjQwNgAA" + 648 | "ACEhN5YTsEv5p9MjV/B5nPNetm726M1lsqCX/graNnGXTPcAAAAhIdhvOYLMAhx0" + 649 | "DQGNdnyD5aPZxzJMrR0FMFvh4zMhiKyRAAAARjY4NzQ3NDcwM2EyZjJmNmI3NTZl" + 650 | "N2E2NTZkNzU3MjYxN2E2OTZiMmU2ZTY1NzQyZjZhNmY2ODZlNmU3OTJlNmI2ZjYz" + 651 | "NjgAAAAAAAAAATAAAAAAAAAAISFWU2xUQyWpi3pEUBjFSthhtWWORIsnZ4BadLkX" + 652 | "3baQnAAAACEhzQVeTO7cJfirtx5qIX393cLNYdYW1ytORG01QWfWcR0AAAABMAAA" + 653 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDY0MDYAAAAAAAAA" + 654 | "AAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNjEAAAABMAAAAAAAAAABMQAAAAEw" + 655 | "AAAAAAAAAAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAGKAAAACjE4NzI3NDY0MTYAAAAx" + 656 | "IY8zvMfWHSRx1+G5SwVzbgOlMZZk8MZHRyaddVbzwSt89lsGOij4defG9Rw1nNSP" + 657 | "SgAAACEhpnF0CCVu/s1ReU/UcClvoIRdm6ls8iiCPfTP/iq2Ta8AAABKNjg3NDc0" + 658 | "NzAzYTJmMmY2ODYxNzI3MjY5NzMyZTZlNjE2ZDY1MmY3MjZmNzM2MTZjNjk2ZTY0" + 659 | "NWY2ZDYxNzI3MTc1NjE3MjY0NzQAAAAAAAAAATAAAAAAAAAAISFcwR2UwzK5wXYW" + 660 | "nn5wBqvAxTkROjU1KEhRWXgZ8QPgGwAAACEhwt+Z3UwKxRVtjiBu2aV2B3rp4zQb" + 661 | "UkpRb9Xnolie6VYAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAA" + 662 | "CjE4NzI3NDY0MTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNjIA" + 663 | "AAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAGQ" + 664 | "AAAACjE4NzI3NDY0MjYAAAAxIcau1MQfKYFvcyd43jYAKADsjGg4JaIuQxxMOeUf" + 665 | "Pkk7ekC7rPOMgUcUmQeqOEAvmQAAACEhVnhVvy+q5BoBlgG28yZj00hgUrpwNk08" + 666 | "mezvGgs6P+AAAABQNjg3NDc0NzAzYTJmMmY3Mjc1NmU2ZjZjNjY3MzY0NmY3NDc0" + 667 | "Njk3MjJlNmU2MTZkNjUyZjZlNjk2MzZiNmM2MTc1NzM1ZjY4NjE3OTY1NzMAAAAA" + 668 | "AAAAATAAAAAAAAAAISE4S+TZaeEgkoSQJuGyZewfdFtZ7J0KUPB/P1CQ8GueegAA" + 669 | "ACEhwVO2MK+u2tRq3d6ZeCYfy8vtsw0SRpGTZPRbWXkeWIkAAAABMAAAAAEwAAAA" + 670 | "ATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDY0MjYAAAAAAAAAAAAAAAAA" + 671 | "AAABMAAAAAEwAAAAAAAAAAAAAAACNjMAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAA" + 672 | "AAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAFzAAAACjE4NzI3NDY0MzYAAAAxIV4H0EZb" + 673 | "dEL/QdJXHUFuOc36ZRh+VU5XmQGsLEtCHxX4x4wMloS0H3D8GYesBb2e9AAAAAAA" + 674 | "AABGNjg3NDc0NzAzYTJmMmY2ZjcyNjU2OTZjNmM3OTJlNjk2ZTY2NmYyZjY0NjE2" + 675 | "ODZjNjk2MTVmNjQ2ZjZlNmU2NTZjNmM3OQAAAAAAAAABMAAAAAAAAAAxIbLAZeQ0" + 676 | "4zfYy6ocJ3420t18WDcoQ/8v4mNJrUEt4AtzgF+rwA0JflHE9t6HwcurYwAAACEh" + 677 | "9lh/HLXHkvlHFXil5zSnsrpW6kX2fU9jiv1sX/Ue0OwAAAABMAAAAAEwAAAAATAA" + 678 | "AAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDY0MzYAAAAAAAAAAAAAAAAAAAAB" + 679 | "MAAAAAEwAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAATEAAAABMAAAAAAAAAAAAAAA" + 680 | "CjEzNzMwNzcxMDVBQ0NUAAABiAAAAAoxODcyNzQ2NDQ2AAAAMSGrKahsenlFqPnV" + 681 | "lmjW6pNI+96JYSUiHraJXyF4lQjs6di7u4n8AiUtFFhBSNakJNAAAAAhIadyuMaD" + 682 | "CSh17uwbG2oGp2HezHnQls4i4MDEaXtgrEbyAAAAODY4NzQ3NDcwM2EyZjJmNzI2" + 683 | "MTc0NjgyZTZlNjU3NDJmNmM2NTY5NjY1ZjY4NjU3MjZkNjE2ZTZlAAAAAAAAAAEw" + 684 | "AAAAAAAAADEhBIgUGgVVgTQHqOTicVtkCMPL0FOI4VPaZmQbpjcwF/iRn21B3fCz" + 685 | "Fsp357ehcwyaAAAAISGqE6XJGWnYtxkNfUOR6tNp+IvkccEdIGHgTJjHH0yOiQAA" + 686 | "AAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjQ0NgAA" + 687 | "AAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI2NAAAAAEwAAAAAAAAAAEx" + 688 | "AAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAYoAAAAKMTg3Mjc0NjQ1" + 689 | "NgAAACEhZkA4xoPDy4bgy7ZKfe9aIRdJqTNU8wxcgChdxW/d83sAAAAhISHBtvN1" + 690 | "YUsZY0IIE6gwJCCFgzY5CIEG4qeoYTO3y6cZAAAAOjY4NzQ3NDcwM2EyZjJmNzM2" + 691 | "MzY4NmQ2OTY0NzQ2ZDY1NzI3NDdhMmU2ZTYxNmQ2NTJmNmI2OTcyNjEAAAAAAAAA" + 692 | "ATAAAAAAAAAAMSEhCDNKrrqp9guf4Uiwgt7n2M+zBHHY18NCymJ5zy2S5jZ1B51J" + 693 | "GbxzrA2+dY3YgNQAAAAxIQDSGhz+Uj/7Q5AQqV3ZxpSYSwUWn6V1dtLHnjq2OIbj" + 694 | "WbuB+XvIhjCAPEjuJ4GWkAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAA" + 695 | "AAAAAAAKMTg3Mjc0NjQ1NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAA" + 696 | "AAI2NQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUND" + 697 | "VAAAAX4AAAAKMTg3Mjc0NjQ2NgAAACEhvQQWSEN4Q9F6DpAZmDYR7rGt6hdb5jAm" + 698 | "aNYuzrNJwJQAAAAhIescncg6gMVW7n9v/IR3uVnhg11QsWmjt13ZLWN3tk0iAAAA" + 699 | "LjY4NzQ3NDcwM2EyZjJmNmQ2ZjZmNzI2NTJlNjI2OTdhMmY2MTZlNjk2MjYxNmMA" + 700 | "AAAAAAAAATAAAAAAAAAAQSHEjDC/J8AM/5+IcD6QL8IYiUd2+zCWE/r4BygYvKt+" + 701 | "AvhWz0Mk/jtAk3MJKfkK2NTd5H0XiGeFKIaZ+R51HEPNAAAAISFQImWVvnLxb4ww" + 702 | "7plDgbfhWgWm000webb6iCd0ANjnqwAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 703 | "AAABMAAAAAAAAAAKMTg3Mjc0NjQ2NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAA" + 704 | "AAAAAAAAAAI2NgAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3" + 705 | "MTA1QUNDVAAAAWYAAAAKMTg3Mjc0NjQ3NgAAACEh1UMRSOR6rSnNpoBrQ8dcU6Id" + 706 | "ZvFAlwGyF776j2iIePEAAAAhIRJ+Is82ejxYBD89T1xLgFdLJdYkfmOFDw8kpn4h" + 707 | "SnM0AAAANjY4NzQ3NDcwM2EyZjJmNmM2NTc1NzM2MzY4NmI2NTJlNjM2ZjZkMmY2" + 708 | "NDYxNzA2ODZlNjU3OQAAAAAAAAABMAAAAAAAAAAhIRRhvc0h1K1Ia5XM2NL/2uv6" + 709 | "nJs9xzw4EgEdgPO/jqNHAAAAISF4UBbivLN4vGOEJNMoNp06C+tk7/r9qUQ3llPO" + 710 | "k6iyBQAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0" + 711 | "NjQ3NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI2NwAAAAEwAAAA" + 712 | "AAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAV4AAAAKMTg3" + 713 | "Mjc0NjQ4NgAAACEhNDsGOVJdXNVJJYTl5KraHxdsxIog6NQuymajYSXkeVgAAAAh" + 714 | "IU6tnMOtDTKlxZkrL4ocYAfFhgTDV3/UHNld+ie9LHeoAAAALjY4NzQ3NDcwM2Ey" + 715 | "ZjJmNjM3MjZmNmU2OTZlMmU2ZTY1NzQyZjYzNzk3MjY5NmMAAAAAAAAAATAAAAAA" + 716 | "AAAAISHB6qFDZ5CLTuSTEZkt2lKxSYkWwXiSFXBEUC92WRowHwAAACEhpMuL0lvS" + 717 | "xLjDtwYHXcluFCm6zxL+5lsRZAGKMyVtuDoAAAABMAAAAAEwAAAAATAAAAABMAAA" + 718 | "AAEwAAAAATAAAAAAAAAACjE4NzI3NDY0ODYAAAAAAAAAAAAAAAAAAAABMAAAAAEw" + 719 | "AAAAAAAAAAAAAAACNjgAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3" + 720 | "MzA3NzEwNUFDQ1QAAAF6AAAACjE4NzI3NDY0OTYAAAAxIQaQDPg3JmzYujNUhwdk" + 721 | "x8uKsB5E2YxKXSNVgX/j/T4kN+bsKxoE173N7N3UuW3vBwAAACEhmoKCnmzdmcBm" + 722 | "OwfLFHBQS51W+53P246QhgIUXrQUbnEAAAA6Njg3NDc0NzAzYTJmMmY3Mzc0NjU3" + 723 | "NTYyNjU3MjJlNjM2ZjZkMmY2MTZjNjk1ZjY3Njk2MjczNmY2ZQAAAAAAAAABMAAA" + 724 | "AAAAAAAhIdAikrlhzlhz8r33P2Stw/Zn4RXVv0sE5DnGbY2/Y7PEAAAAISHsr7jL" + 725 | "jaATZw6veoWRfmHiBNFbZjhKWRpc1qCMLI/djQAAAAEwAAAAATAAAAABMAAAAAEw" + 726 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjQ5NgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 727 | "ATAAAAAAAAAAAAAAAAI2OQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAox" + 728 | "MzczMDc3MTA1QUNDVAAAAYIAAAAKMTg3Mjc0NjUwNgAAADEhdj8sGtoiaRhR2ukP" + 729 | "VM2EqRlS8rw7vOnAN6HKek9LJEqzPlEPyzNlsQpwJF8Ruu17AAAAISG1AUGnPJRu" + 730 | "ZwhuOzelbQFTZl0ekVmENixE18fpdRWkYAAAAEI2ODc0NzQ3MDNhMmYyZjZiNjU3" + 731 | "Mjc0N2E2ZDYxNmU2ZTJlNjI2OTdhMmY2YTYxNzk2NDZmNmU1ZjZiNzU2ZTdhNjUA" + 732 | "AAAAAAAAATAAAAAAAAAAISHKnHE7GVST7ukUNNcWxUiMhlcljy/X31n5OCqVdODb" + 733 | "EwAAACEhcDIPTXpUMoxulC2fHPNr0eqUHvzEdpEYPi6IaJ/W4koAAAABMAAAAAEw" + 734 | "AAAAATAAAAABMAAAAAEwAAAAATAAAAAAAAAACjE4NzI3NDY1MDYAAAAAAAAAAAAA" + 735 | "AAAAAAABMAAAAAEwAAAAAAAAAAAAAAACNzAAAAABMAAAAAAAAAABMQAAAAEwAAAA" + 736 | "AAAAAAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAGeAAAACjE4NzI3NDY1MTYAAAAxISbs" + 737 | "q/LHUzxe9WZcGips3Wth3v8SZPEwH/MmwWCGTo7HXG7uexsrRHSkzHVWDNGWjQAA" + 738 | "ACEh1xU+wdTpc+Kv1M61y33JISYaZZOZQuFEhrXnkd3lknkAAABONjg3NDc0NzAz" + 739 | "YTJmMmY2Nzc1NzQ2YjZmNzc3MzZiNjk3MjYxNzUyZTZmNzI2NzJmNjQ2ZjcyNjEy" + 740 | "ZTc3Njk2YzZjNjk2MTZkNzM2ZjZlAAAAAAAAAAEwAAAAAAAAADEhdk7n/+SQFAL7" + 741 | "2dz2bep6hKa+1RxqVtMMOjNn0KVgFaWyEhY9F6+BzhRjqtApGET7AAAAISEJsfL0" + 742 | "LEAMyrJ+JDZQ8sMmZ3aQtZpUCSF2aZzIC/uiIAAAAAEwAAAAATAAAAABMAAAAAEw" + 743 | "AAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjUxNgAAAAAAAAAAAAAAAAAAAAEwAAAA" + 744 | "ATAAAAAAAAAAAAAAAAI3MQAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAox" + 745 | "MzczMDc3MTA1QUNDVAAAAYQAAAAKMTg3Mjc0NjUyNgAAACEhCH2dW2TvT05XAoqC" + 746 | "i5GtSXCKhtCLcIp2oEhtK6NaBAoAAAAhIZC18+hzJxeUCkBwWy75C1pYz2+OOLZ0" + 747 | "K2ctNl1Vo2GcAAAARDY4NzQ3NDcwM2EyZjJmNjI3NTYzNmI3MjY5NjQ2NzY1MmU2" + 748 | "ZTY1NzQyZjZjNjE3NTcyNjU3NDc0NjEyZTc2NjU3NTZkAAAAAAAAAAEwAAAAAAAA" + 749 | "ADEhMz3QU9XsQ9YRGZf5WndY4i6M65cZp/dXdPPfkYRjhECB8OwbPozZZr3GAlL0" + 750 | "mniTAAAAISH35JWqSpN0G/ryr8wN4cm8JQx39xSv/WwDd481RWMLZgAAAAEwAAAA" + 751 | "ATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjUyNgAAAAAAAAAA" + 752 | "AAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI3MgAAAAEwAAAAAAAAAAExAAAAATAA" + 753 | "AAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAVsAAAAKMTg3Mjc0NjUzNgAAACEh" + 754 | "rZAymsLlKg8EmVqRzZuf4n9Bc3Ag/O28MQFRuYjaZzUAAAAAAAAAPjY4NzQ3NDcw" + 755 | "M2EyZjJmNjM3NTZkNmQ2OTZlNjc3Mzc3NjU2ODZlNjU3MjJlNjI2OTdhMmY2MTcw" + 756 | "NzI2OTZjAAAAAAAAAAEwAAAAAAAAADEhywe4mNI06dhIJhx68RLj2Zzj3gYbi3cR" + 757 | "U+fBf9RkIRW5OTGWRxfC5rIepNfY5gXtAAAAISFwTCUl/eIsU0NqyrhI+E3HLMDP" + 758 | "GqBohKWb3ALCab+K4QAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAA" + 759 | "AAAKMTg3Mjc0NjUzNgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAAA" + 760 | "AAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNUFDQ1QAAAFN" + 761 | "AAAACjE4NzI3NDY1NDYAAAAhIZohkZeduize24bhEB34LGC5MKD8ZKivHChDMSnI" + 762 | "CbE7AAAAAAAAAEA2ODc0NzQ3MDNhMmYyZjY3NzI2MTY0NzkyZTYyNjk3YTJmNmQ2" + 763 | "ZjY4NjE2ZDZkNjU2NDVmNjI3MjYxNmI3NTczAAAAAAAAAAEwAAAAAAAAACEhUIgb" + 764 | "cpIZAQJxF9rxK6XtDWFiyR84IBR7vlpBHx7fmkoAAAAhIR9DUEY85kTttQlzgFgZ" + 765 | "qcnAKW1FNA76tVl2q/o0p+6DAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEw" + 766 | "AAAAAAAAAAoxODcyNzQ2NTQ2AAAAAAAAAAAAAAAAAAAAATAAAAABMAAAAAAAAAAA" + 767 | "AAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUND" + 768 | "VAAAAXwAAAAKMTg3Mjc0NjU1NgAAADEhruEMVK972nEfSiAWnnvmpgnBiONiM3JT" + 769 | "g29++iaGwyaR5x7D2C7/+0G/WrTGvV04AAAAISFEPu/XMRbV0DBbJiFUs3C0/nm2" + 770 | "pYJT8tu+Ho+QdOAtDgAAADw2ODc0NzQ3MDNhMmYyZjY3NmY3NDc0NmM2OTY1NjIy" + 771 | "ZTZlNjE2ZDY1MmY2NTZjNjk3MzYxNjI2NTc0NjgAAAAAAAAAATAAAAAAAAAAISF9" + 772 | "4WILdSHxrR6qzEEMy07FURJnAp770+ppyJM/KG4wqwAAACEhwEs7wyKYcIJ05lS8" + 773 | "+gIWX7uWA8yMhCFlBxrdl/LAWmAAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 774 | "ATAAAAAAAAAACjE4NzI3NDY1NTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 775 | "AAAAAAACNzMAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEw" + 776 | "NUFDQ1QAAAF4AAAACjE4NzI3NDY1NjYAAAAhISrRosN67ZDNH2xyB3d4ywdJaAD8" + 777 | "s34SagHcl2TGk150AAAAISF8S/LT9cg1/b0QErA5SPznZmnshsvfjePbLpTKHVRQ" + 778 | "aAAAADg2ODc0NzQ3MDNhMmYyZjY0NjE2MzY4Njc2OTczNmM2MTczNmY2ZTJlNmY3" + 779 | "MjY3MmY2MTZjNzY2MQAAAAAAAAABMAAAAAAAAAAxIakkKSxfhSFpGH0hU7sjoZJ/" + 780 | "JEk2XFuvU26H15BZYZC5K22lBRKNp2MROQkzTr5RHwAAACEhk1UjSMVmdD40Ilkw" + 781 | "TFe6iEXFZ0HFU/kV14EOVGGOko4AAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAA" + 782 | "ATAAAAAAAAAACjE4NzI3NDY1NjYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAA" + 783 | "AAAAAAACNzQAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEw" + 784 | "NUFDQ1QAAAGeAAAACjE4NzI3NDY1NzYAAAAhIWV5XeJcLDDr88ffAGB3fAMXUDTZ" + 785 | "H5VxZ9+jaKHbwOSLAAAAISFC0s+hSulEiuF//bbQ/+5tz+1k2aV2H2ZYLakrwvqN" + 786 | "gAAAAD42ODc0NzQ3MDNhMmYyZjcyNjk2MzY1MmU2OTZlNjY2ZjJmNjc2OTZmNzY2" + 787 | "MTZlNmU3OTVmNjU2MjY1NzI3NAAAAAAAAAABMAAAAAAAAABBISrH3GQCdKEtSu3j" + 788 | "8JGQAmt0bb3N5rMndYdPdpZ04dB3P0PjBqyAW6cGg/ycoNJlIRI6iykCa+aiJB1w" + 789 | "JiomzcwAAAAxIYi6OcqI1uilWb3yE6T/lSyJZfZGoZM2GTaPK2u7OvuCA4BbdZvh" + 790 | "XytlitWmRYsFigAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAK" + 791 | "MTg3Mjc0NjU3NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI3NQAA" + 792 | "AAEwAAAAAAAAAAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAWMA" + 793 | "AAAKMTg3Mjc0NjU4NgAAACEhPxthU1wxY1Vfg9FtdzPeaM16ul3vD9ewKUwi0LYx" + 794 | "P4YAAAAAAAAARjY4NzQ3NDcwM2EyZjJmNjc2YzZmNzY2NTcyNmQ2MzZiNjU2ZTdh" + 795 | "Njk2NTJlNjk2ZTY2NmYyZjZiNjE3NDY1NmM3OTZlNmUAAAAAAAAAATAAAAAAAAAA" + 796 | "MSG7r/Ki2TpMoKgYPY6hvy4pkYnySbIRetT2uKIOT0Y08ldKqJpFHpvtZ+jjw7RY" + 797 | "QWIAAAAhIS8zsOjIHPVGtEMzb496ThecPslNg9xnysv7txkZNvrWAAAAATAAAAAB" + 798 | "MAAAAAEwAAAAATAAAAABMAAAAAEwAAAAAAAAAAoxODcyNzQ2NTg2AAAAAAAAAAAA" + 799 | "AAAAAAAAATAAAAABMAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAExAAAAATAAAAAA" + 800 | "AAAAAAAAAAoxMzczMDc3MTA1QUNDVAAAAWQAAAAKMTg3Mjc0NjU5NgAAACEhEbPb" + 801 | "uJsF57lzoIq6F2FKQhgRRAHvN0KIcSuzs8n/jpYAAAAhIekaX0ey4afkTz5BHXGv" + 802 | "A2UOsZh8CYt56eKNR1hLPyJvAAAANDY4NzQ3NDcwM2EyZjJmNzM2OTcwNjU3MzJl" + 803 | "NjM2ZjZkMmY2YTZmNjU3OTJlNmQ2NTc0N2EAAAAAAAAAATAAAAAAAAAAISFFsZHh" + 804 | "NE2jfzflVu2rCoI9yYXShSD22+bIYCqX1bJn2AAAACEhmFKfi0Y4UQ4dVKQLnZWw" + 805 | "LfrmyXG44I9R2KD/547mCsoAAAABMAAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAA" + 806 | "AAAAAAAACjE4NzI3NDY1OTYAAAAAAAAAAAAAAAAAAAABMAAAAAEwAAAAAAAAAAAA" + 807 | "AAACNzYAAAABMAAAAAAAAAABMQAAAAEwAAAAAAAAAAAAAAAKMTM3MzA3NzEwNUFD" + 808 | "Q1QAAAFoAAAACjE4NzI3NDY2MDYAAAAhIUHNGYLU9wBDjFH4cQd5wpL8cvIG1uJF" + 809 | "Z47PcbT4zNJYAAAAISHUq0bIfBWiDXXoroCW6B3zQk0zfiBsrIi+A0CQZQ0HnAAA" + 810 | "ADg2ODc0NzQ3MDNhMmYyZjYyNjU3MjZlNjk2NTcyMmU2ZjcyNjcyZjY3NjE2NzY1" + 811 | "NWY2ODYxNjE2NwAAAAAAAAABMAAAAAAAAAAhIcqK9nXa9CORzJLL17L0HQCur+St" + 812 | "+FnhL4oQAfk9z5uiAAAAISGcPvE/fXdL9HU69fCNLk6kmu4L/Hb7N/K9584AVe+o" + 813 | "qQAAAAEwAAAAATAAAAABMAAAAAEwAAAAATAAAAABMAAAAAAAAAAKMTg3Mjc0NjYw" + 814 | "NgAAAAAAAAAAAAAAAAAAAAEwAAAAATAAAAAAAAAAAAAAAAI3NwAAAAEwAAAAAAAA" + 815 | "AAExAAAAATAAAAAAAAAAAAAAAAoxMzczMDc3MTA1RVFETgAAACUAAAABMQAAABw2" + 816 | "MTZkNjU3MjY5NzQ3MjYxNjQ2NTJlNjM2ZjZkRVFETgAAACkAAAABMQAAACA3NDY0" + 817 | "NjE2ZDY1NzI2OTc0NzI2MTY0NjUyZTYzNmY2ZEVRRE4AAAArAAAAATIAAAAiNjI2" + 818 | "MTZlNmI2ZjY2NjE2ZDY1NzI2OTYzNjEyZTYzNmY2ZEVRRE4AAAAZAAAAATIAAAAQ" + 819 | "NjI2ZjY2NjEyZTYzNmY2ZEVRRE4AAAAZAAAAATIAAAAQNmQ2MjZlNjEyZTYzNmY2" + 820 | "ZEVRRE4AAAAdAAAAATIAAAAUNzU3MzY1NjM2NjZmMmU2MzZmNmRFUUROAAAAHQAA" + 821 | "AAEzAAAAFDczNzA3MjY5NmU3NDJlNjM2ZjZkRVFETgAAACMAAAABMwAAABo3Mzcw" + 822 | "NzI2OTZlNzQ3MDYzNzMyZTYzNmY2ZEVRRE4AAAAdAAAAATMAAAAUNmU2NTc4NzQ2" + 823 | "NTZjMmU2MzZmNmRFUUROAAAAHwAAAAE0AAAAFjc5NmY3NTc0NzU2MjY1MmU2MzZm" + 824 | "NmRFUUROAAAAHQAAAAE0AAAAFDY3NmY2ZjY3NmM2NTJlNjM2ZjZkRVFETgAAABsA" + 825 | "AAABNQAAABI2MTcwNzA2YzY1MmU2MzZmNmRFUUROAAAAHQAAAAE1AAAAFDY5NjM2" + 826 | "YzZmNzU2NDJlNjM2ZjZkRVFETgAAACUAAAABNgAAABw3NzY1NmM2YzczNjY2MTcy" + 827 | "Njc2ZjJlNjM2ZjZkRVFETgAAABUAAAABNgAAAAw3NzY2MmU2MzZmNmRFUUROAAAA" + 828 | "LwAAAAE3AAAAJjczNmY3NTc0Njg2NTcyNmU2MzZmNmQ3MDYxNmU3OTJlNjM2ZjZk" + 829 | "RVFETgAAACUAAAABNwAAABw3MzZmNzU3NDY4NjU3MjZlNjM2ZjJlNjM2ZjZkRVFE" + 830 | "TgAAACwAAAACMTIAAAAiNjE2MzYzNmY3NTZlNzQ2ZjZlNmM2OTZlNjUyZTYzNmY2" + 831 | "ZEVRRE4AAAAaAAAAAjEyAAAAEDYzNjk3NDY5MmU2MzZmNmRFUUROAAAAIgAAAAIx" + 832 | "MgAAABg2MzY5NzQ2OTYyNjE2ZTZiMmU2MzZmNmRFUUROAAAAJAAAAAIxMgAAABo2" + 833 | "MzY5NzQ2OTYzNjE3MjY0NzMyZTYzNmY2ZEVRRE4AAAAaAAAAAjIyAAAAEDYzNmU2" + 834 | "NTc0MmU2MzZmNmRFUUROAAAAHgAAAAIyMgAAABQ2MzZlNjU3NDc0NzYyZTYzNmY2" + 835 | "ZEVRRE4AAAAYAAAAAjIyAAAADjYzNmY2ZDJlNjM2ZjZkRVFETgAAACIAAAACMjIA" + 836 | "AAAYNjQ2Zjc3NmU2YzZmNjE2NDJlNjM2ZjZkRVFETgAAABoAAAACMjIAAAAQNmU2" + 837 | "NTc3NzMyZTYzNmY2ZEVRRE4AAAAeAAAAAjIyAAAAFDczNjU2MTcyNjM2ODJlNjM2" + 838 | "ZjZkRVFETgAAAB4AAAACMjIAAAAUNzU3MDZjNmY2MTY0MmU2MzZmNmRFUUROAAAA" + 839 | "LgAAAAIzMgAAACQ2MjYxNmU2MTZlNjE3MjY1NzA3NTYyNmM2OTYzMmU2MzZmNmRF" + 840 | "UUROAAAAGAAAAAIzMgAAAA42NzYxNzAyZTYzNmY2ZEVRRE4AAAAgAAAAAjMyAAAA" + 841 | "FjZmNmM2NDZlNjE3Njc5MmU2MzZmNmRFUUROAAAAJAAAAAIzMgAAABo3MDY5NzA2" + 842 | "NTcyNmM2OTZkNjUyZTYzNmY2ZEVRRE4AAAAaAAAAAjQyAAAAEDYyNjk2ZTY3MmU2" + 843 | "MzZmNmRFUUROAAAAIAAAAAI0MgAAABY2ODZmNzQ2ZDYxNjk2YzJlNjM2ZjZkRVFE" + 844 | "TgAAABoAAAACNDIAAAAQNmM2OTc2NjUyZTYzNmY2ZEVRRE4AAAAkAAAAAjQyAAAA" + 845 | "GjZkNjk2MzcyNmY3MzZmNjY3NDJlNjM2ZjZkRVFETgAAABgAAAACNDIAAAAONmQ3" + 846 | "MzZlMmU2MzZmNmRFUUROAAAAIgAAAAI0MgAAABg3MDYxNzM3MzcwNmY3Mjc0MmU2" + 847 | "ZTY1NzRFUUROAAAAHAAAAAI1MgAAABI3NTYxMzI2NzZmMmU2MzZmNmRFUUROAAAA" + 848 | "GAAAAAI1MgAAAA43NTYxNmMyZTYzNmY2ZEVRRE4AAAAeAAAAAjUyAAAAFDc1NmU2" + 849 | "OTc0NjU2NDJlNjM2ZjZkRVFETgAAACIAAAACODIAAAAYNmY3NjY1NzI3NDc1NzI2" + 850 | "NTJlNjM2ZjZkRVFETgAAABwAAAACODIAAAASNzk2MTY4NmY2ZjJlNjM2ZjZkRVFE" + 851 | "TgAAACQAAAACOTIAAAAaN2E2ZjZlNjU2MTZjNjE3MjZkMmU2MzZmNmRFUUROAAAA" + 852 | "IgAAAAI5MgAAABg3YTZmNmU2NTZjNjE2MjczMmU2MzZmNmRFUUROAAAAGwAAAAM4" + 853 | "NDIAAAAQNjE3NjZmNmUyZTYzNmY2ZEVRRE4AAAAjAAAAAzg0MgAAABg3OTZmNzU3" + 854 | "MjYxNzY2ZjZlMmU2MzZmNmRFUUROAAAALAAAAAQxNDc0AAAAIDMxMzgzMDMwNjM2" + 855 | "ZjZlNzQ2MTYzNzQ3MzJlNjM2ZjZkRVFETgAAACoAAAAEMTQ3NAAAAB4zODMwMzA2" + 856 | "MzZmNmU3NDYxNjM3NDczMmU2MzZmNmRFUUROAAAAIAAAAAQyMDAwAAAAFDYxNmQ2" + 857 | "MTdhNmY2ZTJlNjM2ZjZkRVFETgAAACQAAAAEMjAwMAAAABg2MTZkNjE3YTZmNmUy" + 858 | "ZTYzNmYyZTc1NmJFUUROAAAAMgAAAAQyMDEwAAAAJjY1Nzg3MDcyNjU3MzczMmQ3" + 859 | "MzYzNzI2OTcwNzQ3MzJlNjM2ZjZkRVFETgAAACoAAAAEMjAxMAAAAB42ZDY1NjQ2" + 860 | "MzZmNjg2NTYxNmM3NDY4MmU2MzZmNmRFUUROAAAAGgAAAAQyMDEyAAAADjYzNmY3" + 861 | "ODJlNjM2ZjZkRVFETgAAABoAAAAEMjAxMgAAAA42MzZmNzgyZTZlNjU3NEVRRE4A" + 862 | "AAAqAAAABDIwMTIAAAAeNjM2Zjc4NjI3NTczNjk2ZTY1NzM3MzJlNjM2ZjZkRVFE" + 863 | "TgAAADIAAAAEMjAyMgAAACY2ZDc5NmU2ZjcyNzQ2ZjZlNjE2MzYzNmY3NTZlNzQy" + 864 | "ZTYzNmY2ZEVRRE4AAAAgAAAABDIwMjIAAAAUNmU2ZjcyNzQ2ZjZlMmU2MzZmNmRF" + 865 | "UUROAAAAIgAAAAQyMDMyAAAAFjc2NjU3MjY5N2E2ZjZlMmU2MzZmNmRFUUROAAAA" + 866 | "IgAAAAQyMDMyAAAAFjc2NjU3MjY5N2E2ZjZlMmU2ZTY1NzRFUUROAAAAIgAAAAQy" + 867 | "MDQyAAAAFjZjNmY2NzZkNjU2OTZlMmU2MzZmNmRFUUROAAAAHAAAAAQyMDQyAAAA" + 868 | "EDZjNmY2NzZkNjUyZTY5NmVFUUROAAAAIgAAAAQyMDUyAAAAFjcyNjE2Yjc1NzQ2" + 869 | "NTZlMmU2MzZmNmRFUUROAAAAGgAAAAQyMDUyAAAADjYyNzU3OTJlNjM2ZjZkRVFE" + 870 | "TgAAACQAAAAEMjA2MgAAABg3MzY5NzI2OTc1NzM3ODZkMmU2MzZmNmRFUUROAAAA" + 871 | "IAAAAAQyMDYyAAAAFDczNjk3MjY5NzU3MzJlNjM2ZjZkRVFETgAAABgAAAAEMjA3" + 872 | "MgAAAAw2NTYxMmU2MzZmNmRFUUROAAAAIAAAAAQyMDcyAAAAFDZmNzI2OTY3Njk2" + 873 | "ZTJlNjM2ZjZkRVFETgAAACYAAAAEMjA3MgAAABo3MDZjNjE3OTM0NjY3MjY1NjUy" + 874 | "ZTYzNmY2ZEVRRE4AAAA0AAAABDIwNzIAAAAoNzQ2OTYyNjU3MjY5NzU2ZDYxNmM2" + 875 | "YzY5NjE2ZTYzNjUyZTYzNmY2ZFVSVUwAAAAoAAAAGjY3NmY2ZjY3NmM2NTJlNjM2" + 876 | "ZjZkMmY2MTJmAAAAATAAAAABMFVSVUwAAAAkAAAAFjZjNmY2NzZkNjU2OTZlMmU2" + 877 | "MzZmNmQAAAABMQAAAAEwVVJVTAAAADoAAAAsNzM2OTc0NjU3MzJlNjc2ZjZmNjc2" + 878 | "YzY1MmU2MzZmNmQyZjczNjk3NDY1MmYAAAABMAAAAAEwVVJVTAAAACIAAAAUNzc2" + 879 | "NTY1NjI2Yzc5MmU2MzZmNmQAAAABMQAAAAEwVVJVTAAAABwAAAAONzc2OTc4MmU2" + 880 | "MzZmNmQAAAABMQAAAAEwVVJVTAAAAB4AAAAQNzc2NTYyNzMyZTYzNmY2ZAAAAAEx" + 881 | "AAAAATBVUlVMAAAAKAAAABo2ODZmNmQ2NTczNzQ2NTYxNjQyZTYzNmY2ZAAAAAEx" + 882 | "AAAAATBVUlVMAAAAKAAAABo3NzZmNzI2NDcwNzI2NTczNzMyZTYzNmY2ZAAAAAEx" + 883 | "AAAAATBVUlVMAAAAIAAAABI2YTY5NmQ2NDZmMmU2MzZmNmQAAAABMQAAAAEwVVJV" + 884 | "TAAAACgAAAAaNzc2NTYyNzM3NDYxNzI3NDczMmU2MzZmNmQAAAABMQAAAAEwVVJV" + 885 | "TAAAACgAAAAaNzM2ZTYxNzA3MDYxNjc2NTczMmU2MzZmNmQAAAABMQAAAAEwVVJV" + 886 | "TAAAACwAAAAeNjM2YzZmNzU2NDYxNjM2MzY1NzM3MzJlNmU2NTc0AAAAATEAAAAB" + 887 | "MFVSVUwAAAAkAAAAFjc3NjU2MjZlNmY2NDY1MmU2MzZmNmQAAAABMQAAAAEwVVJV" + 888 | "TAAAACwAAAAeNmY2ZTZkNjk2MzcyNmY3MzZmNjY3NDJlNjM2ZjZkAAAAATEAAAAB" + 889 | "MFVSVUwAAAAoAAAAGjY4NjU3MjZmNmI3NTYxNzA3MDJlNjM2ZjZkAAAAATEAAAAB" + 890 | "MFVSVUwAAAAaAAAADDZlNmY3NjJlNzI3NQAAAAExAAAAATBFTkRNAAAAAk9L").decode64 891 | 892 | TEST_ENCRYPTION_KEY = "p8utF7ZB8yD06SrtrD4hsdvEOiBU1Y19cr2dhG9DWZg=".decode64 893 | TEST_KEY_ITERATION_COUNT = 5000 894 | 895 | TEST_ACCOUNTS = [ 896 | LastPass::Account.new("1872745596", "Muller, Morar and Wisoky", "branson_cormier", "8jgLCzQSkB2rTZ1OtF9sNGpc", "http://nienow.net/meagan.greenholt", "", "three"), 897 | LastPass::Account.new("1872745606", "goyette.net", "kris_quigley@baileyjewe.biz", "S5@3^wPv!6JsFj", "http://bechtelar.biz/tristian.barrows", "", "four"), 898 | LastPass::Account.new("1872745616", "Ward Inc", "angela_emard", "zp8N@KoWyS0IYu7VR$dvBF!t", "http://schuster.name/ashton", "", "one"), 899 | LastPass::Account.new("1872745626", "stehr.com", "bailee_marvin@mohrlegros.net", "cupiditate", "http://runolfon.org/te", "", "three"), 900 | LastPass::Account.new("1872745636", "kiehn.biz", "freda", "et", "http://hintzprohaska.biz/wade.fisher", "", "one"), 901 | LastPass::Account.new("1872745646", "Jacobs and Sons", "johnnie.hand", "gzyl6714", "http://schultzheaney.org/arvid", "", ""), 902 | LastPass::Account.new("1872745656", "Larkin, Kautzer and Wiegand", "hilton", "zguovmdr8703", "http://streich.com/ramona", "", "one"), 903 | LastPass::Account.new("1872745666", "Conn Inc", "malvina_paucek@nikolausveum.net", "numquam", "http://conn.net/leda", "", "four"), 904 | LastPass::Account.new("1872745676", "Block, Sanford and Connelly", "marilie_wolff", "zKcy?U*aCGS^gf@Z", "http://conroy.biz/zachery", "", "two"), 905 | LastPass::Account.new("1872745686", "gradyrenner.org", "oswald@ryan.info", "ojgwad28", "http://kihn.org/candice", "", ""), 906 | LastPass::Account.new("1872745696", "lesch.net", "nicholas", "Pkc72Lmr1qwI%sNV^d4@GtX", "http://glover.name/jerad", "", "two"), 907 | LastPass::Account.new("1872745706", "sipes.biz", "kaitlyn.bernier@reichel.net", "in", "http://mayert.name/jeromy", "", "two"), 908 | LastPass::Account.new("1872745716", "Hintz-Herman", "prince.moriette", "0hebvIS@s^BwMc", "http://sanfordwunsch.org/alek", "", ""), 909 | LastPass::Account.new("1872745726", "Hammes-Kassulke", "brooke@gloverhintz.net", "paokcs08", "http://lehner.biz/stanley.dooley", "", "four"), 910 | LastPass::Account.new("1872745736", "hermann.com", "jasper_dickens", "Ppj2b!rIMLu*@ElTCZU", "http://rolfson.net/jaden", "", "one"), 911 | LastPass::Account.new("1872745746", "Veum and Sons", "marquise@quitzonbrown.com", "owsg728", "http://fahey.name/jon_ankunding", "", "one"), 912 | LastPass::Account.new("1872745756", "Balistreri, Emard and Mayert", "verona@willmswhite.info", "wnydas6714", "http://treutelkiehn.org/marcos", "", "two"), 913 | LastPass::Account.new("1872745766", "lindkeler.net", "ed", "quia", "http://leffler.info/chaya", "", "one"), 914 | LastPass::Account.new("1872745776", "nikolaus.biz", "leonard", "oW9fdvJLkp#%I", "http://brakuswilliamson.com/bret", "", ""), 915 | LastPass::Account.new("1872745786", "bartonherzog.net", "dock@vonrueden.net", "beatae", "http://kunzeokuneva.info/shawn_langosh", "", "three"), 916 | LastPass::Account.new("1872745796", "howe.org", "chad@walker.biz", "zexfir7951", "http://crooks.com/sandrine", "", ""), 917 | LastPass::Account.new("1872745806", "shields.info", "modesto@kunzenicolas.com", "*JDSdp@VyR8f5FOALW", "http://kemmer.org/hilton", "", "three"), 918 | LastPass::Account.new("1872745816", "kihnabernathy.com", "mafalda.treutel@gislason.name", "hwuoxizq18", "http://trompbernhard.com/trea.hirthe", "", "two"), 919 | LastPass::Account.new("1872745826", "Gislason and Sons", "torrey@kshlerin.info", "OfZrTFAIq?Uyl9X$", "http://ullrich.info/carlee", "", "four"), 920 | LastPass::Account.new("1872745836", "simonis.com", "marco.cronin", "upokmxct57", "http://rippin.name/bonita_hickle", "", "four"), 921 | LastPass::Account.new("1872745856", "Howell, Beer and Yundt", "raegan@cruickshankgreenholt.org", "dHPFrtOjieum4L", "http://aufderharrunolfsdottir.info/felicia_torphy", "", "two"), 922 | LastPass::Account.new("1872745866", "Gottlieb-Ernser", "ivory.moore@paucek.com", "fugit", "http://lockmanlynch.net/alba", "", "four"), 923 | LastPass::Account.new("1872745876", "Emmerich and Sons", "lacey.bernier@hansenboyer.com", "aqzkolu6021", "http://carrollschmitt.com/willy.emard", "", "three"), 924 | LastPass::Account.new("1872745886", "Gerlach, Kirlin and Roberts", "maiya@bayergusikowski.org", "nhit3214", "http://feil.net/natasha_howe", "", "one"), 925 | LastPass::Account.new("1872745896", "ryan.net", "rubie@fahey.org", "aihw^uFgXnC%R", "http://gleasonjakubowski.biz/august", "", ""), 926 | LastPass::Account.new("1872745906", "Jewess, Wolf and Volkman", "kristin_blanda@howekuhlman.biz", "nacro5213", "http://wilkinsonleannon.name/bud.willms", "", "two"), 927 | LastPass::Account.new("1872745916", "Ritchie Group", "nathen_ortiz@turner.biz", "XfmN@G%ebsK1Jc$q", "http://price.info/urban", "", "two"), 928 | LastPass::Account.new("1872745926", "wiegand.info", "lavon_greenholt", "fzedpuq30", "http://paucekturcotte.org/kadin_gibson", "", ""), 929 | LastPass::Account.new("1872745936", "Rohan, Schneider and Daniel", "zella.effertz", "wksei21", "http://runte.com/camryn.hane", "", "one"), 930 | LastPass::Account.new("1872745946", "boyle.name", "gennaro_goldner@kovacek.biz", "eaJD#Kb6UAis@M*8jhILk", "http://kulasklein.info/nyasia", "", "four"), 931 | LastPass::Account.new("1872745956", "Pouros-Funk", "maudie@fahey.org", "wahkvms6871", "http://schaefer.info/leslie.bogan", "", "three"), 932 | LastPass::Account.new("1872745966", "Parisian-Legros", "holly", "et", "http://naderrempel.net/gwen_schmidt", "", "four"), 933 | LastPass::Account.new("1872745976", "Rosenbaum-Schulist", "jordy.krajcik", "xqzflsy843", "http://dooley.info/alek_parker", "", "four"), 934 | LastPass::Account.new("1872745986", "christiansen.info", "phoebe@larson.info", "bilvs07", "http://johns.name/columbus.dooley", "", "two"), 935 | LastPass::Account.new("1872745996", "Hauck, Thiel and VonRueden", "leif", "QVx?JvZ46e1FBmsAi", "http://bauch.org/marlin", "", "one"), 936 | LastPass::Account.new("1872746006", "Sipes and Sons", "leland", "ecgs1758", "http://dubuque.com/jacey", "", "one"), 937 | LastPass::Account.new("1872746016", "Osinski LLC", "rhoda", "nhwo705", "http://schinner.org/price", "", "four"), 938 | LastPass::Account.new("1872746026", "daniel.name", "santina@wiegand.net", "dolorem", "http://torp.net/shyanne.smitham", "", ""), 939 | LastPass::Account.new("1872746036", "darekutch.name", "ali", "U*kgl8u1p#QO9xWNnEd0b3", "http://mante.com/caie_streich", "", ""), 940 | LastPass::Account.new("1872746046", "grimes.com", "eunice_satterfield@baileymante.net", "ipsam", "http://swaniawski.org/wendell_gaylord", "", "three"), 941 | LastPass::Account.new("1872746056", "conn.name", "sandrine", "rv%XVjo#2Id?@4L", "http://rolfson.com/willy_bartell", "", ""), 942 | LastPass::Account.new("1872746066", "Kozey-Spinka", "brando.kshlerin", "consequatur", "http://collinsreichel.net/yasmine", "", "three"), 943 | LastPass::Account.new("1872746076", "Daugherty LLC", "horacio_schulist@davis.net", "sbxzn64", "http://deckow.net/roosevelt.kshlerin", "", "four"), 944 | LastPass::Account.new("1872746086", "Lubowitz LLC", "maxine@ebertmckenzie.biz", "qrcl02", "http://considineheidenreich.name/name.christiansen", "", ""), 945 | LastPass::Account.new("1872746096", "mante.name", "jayne", "xnekizj90", "http://bogisich.net/lori", "", "four"), 946 | LastPass::Account.new("1872746106", "Mante LLC", "antonio.turner@sauertorphy.com", "ckomnf175", "http://herzog.name/luigi", "", ""), 947 | LastPass::Account.new("1872746116", "Greenholt-Hodkiewicz", "moriah@mccullough.org", "udaxo7451", "http://mann.com/cecile", "", "three"), 948 | LastPass::Account.new("1872746126", "Rosenbaum, Sipes and Leffler", "keshaun@schroeder.info", "recusandae", "http://dooley.name/ewald", "", "two"), 949 | LastPass::Account.new("1872746136", "Fadel, Ferry and Kohler", "sister", "sUxoLNhl8Kty*Ve76b45G", "http://balistrerimcclure.com/jaquan_wilkinson", "", "two"), 950 | LastPass::Account.new("1872746146", "Schaden-Rosenbaum", "godfrey", "oDVcsx*m!0Rb@NjSyqdGIl", "http://pouros.net/jeremie", "", ""), 951 | LastPass::Account.new("1872746156", "Monahan, Reinger and McKenzie", "christophe.kub@luettgen.name", "fLqj&e$TyNo8gd7!", "http://keler.info/nikita.lindgren", "", "four"), 952 | LastPass::Account.new("1872746166", "bednar.info", "roselyn@hickle.com", "*2tiEP&Ic7dT", "http://jaskolski.com/conner_ortiz", "", "two"), 953 | LastPass::Account.new("1872746176", "Jewess, Wolf and Feil", "hal", "doloribus", "http://champlin.org/lue_schroeder", "", "three"), 954 | LastPass::Account.new("1872746186", "Kunze-Hettinger", "camilla_pagac", "elpbzT08Dvo6NyQF3wPEr", "http://donnellyadams.com/santino", "", "one"), 955 | LastPass::Account.new("1872746196", "Jacobs, Toy and Schultz", "billy_boehm@will.biz", "g5X*hRwlmcL6ZM", "http://larkinconsidine.org/leola", "", "one"), 956 | LastPass::Account.new("1872746206", "sanford.com", "joy@abbott.org", "rfolun872", "http://runtemoen.name/pierre", "", "three"), 957 | LastPass::Account.new("1872746216", "upton.net", "susana.gaylord", "WR4KxbU^@$Vpi%QH9Mv#T", "http://moore.info/pearl", "", "three"), 958 | LastPass::Account.new("1872746226", "wiegand.biz", "ashleigh_gutmann", "t7C&j!Ox21oha5sX*f", "http://armstronghackett.name/jaeden", "", "three"), 959 | LastPass::Account.new("1872746236", "schneider.net", "eunice.sauer@ledner.org", "U%EFVGnxw2fQ^t*", "http://schulistmetz.info/esperanza_cummerata", "", "two"), 960 | LastPass::Account.new("1872746246", "Swift-Stoltenberg", "katelin_rempel", "labore", "http://beermills.net/danielle", "", "two"), 961 | LastPass::Account.new("1872746256", "Heathcote Group", "hope.waters@parisianbruen.info", "EhG7zBTb8OseI", "http://douglas.name/porter", "", ""), 962 | LastPass::Account.new("1872746266", "hilpert.com", "phyllis.lemke", "est", "http://donnelly.com/tyrique_langosh", "", "one"), 963 | LastPass::Account.new("1872746276", "daviswolff.name", "martine@ryan.com", "incidunt", "http://schoen.info/macy", "", "one"), 964 | LastPass::Account.new("1872746286", "Bahringer, Prohaska and Mills", "merritt_reilly@lynch.info", "dyX^xZ3HTKsqFIMeA", "http://schuppe.com/rosetta.yundt", "", ""), 965 | LastPass::Account.new("1872746296", "ledner.name", "billie.lueilwitz@kertzmann.org", "Zi5K6tXh91mJG3EnjBD4r", "http://feil.com/isabelle", "", "four"), 966 | LastPass::Account.new("1872746306", "jerdecormier.com", "renee.towne@ruecker.net", "vuzoskg85", "http://mckenzie.net/zaria", "", ""), 967 | LastPass::Account.new("1872746316", "harbervandervort.org", "elta_haag@okuneva.net", "2?GVri70HkKceU*m#CZ3x", "http://whiteklocko.name/lacey.dare", "", "one"), 968 | LastPass::Account.new("1872746326", "gulgowskimann.org", "chaz_brakus", "explicabo", "http://okuneva.biz/lisandro", "", "two"), 969 | LastPass::Account.new("1872746336", "padbergconn.info", "lenore@ullrich.net", "ORrNKnhuqd7xeULa^YDk", "http://sauerkuvalis.info/braxton", "", "one"), 970 | LastPass::Account.new("1872746346", "davis.com", "margarett", "debitis", "http://spinka.info/kendra", "", ""), 971 | LastPass::Account.new("1872746366", "Gerlach Inc", "krystel_boyer", "qui", "http://pouromitham.name/efrain", "", "three"), 972 | LastPass::Account.new("1872746376", "cummerata.net", "rudy.flatley", "mzqvakic527", "http://heidenreich.net/ryann_hayes", "", ""), 973 | LastPass::Account.new("1872746386", "schowalter.name", "hyman.satterfield", "pjts564", "http://okeefedamore.biz/giovani", "", "one"), 974 | LastPass::Account.new("1872746396", "McLaughlin-Fadel", "fanny_sporer", "kyti64", "http://dickibosco.biz/zachariah", "", "four"), 975 | LastPass::Account.new("1872746406", "Gerlach-Nienow", "treva.block", "csnxhldi893", "http://kunzemurazik.net/johnny.koch", "", "two"), 976 | LastPass::Account.new("1872746416", "O'Reilly-Trantow", "grayson", "non", "http://harris.name/rosalind_marquardt", "", "three"), 977 | LastPass::Account.new("1872746426", "Larkin-Konopelski", "josianne_walker", "bwms78", "http://runolfsdottir.name/nicklaus_hayes", "", "two"), 978 | LastPass::Account.new("1872746436", "Swaniawski, Will and Gaylord", "jeramie.ohara@nader.org", "quia", "http://oreilly.info/dahlia_donnelly", "", ""), 979 | LastPass::Account.new("1872746446", "emmerichgaylord.name", "diana@hansenbeahan.net", "omnis", "http://rath.net/leif_hermann", "", "three"), 980 | LastPass::Account.new("1872746456", "armstrong.org", "genesis@rosenbaumlueilwitz.biz", "zHeu%^kxj9Y0Qr4@m*3!ov", "http://schmidtmertz.name/kira", "", "one"), 981 | LastPass::Account.new("1872746466", "Waelchi Group", "trace.heaney@heidenreichbernier.com", "whljnru03", "http://moore.biz/anibal", "", "two"), 982 | LastPass::Account.new("1872746476", "fahey.org", "ward_okuneva", "qjnz18", "http://leuschke.com/daphney", "", "two"), 983 | LastPass::Account.new("1872746486", "koelpin.info", "dylan.klocko", "vdjlot364", "http://cronin.net/cyril", "", "three"), 984 | LastPass::Account.new("1872746496", "Murphy-Breitenberg", "marcia_kreiger", "dacyz723", "http://steuber.com/ali_gibson", "", "three"), 985 | LastPass::Account.new("1872746506", "andersondicki.org", "ceasar@lind.com", "nvymdsk14", "http://kertzmann.biz/jaydon_kunze", "", "four"), 986 | LastPass::Account.new("1872746516", "watersreichel.net", "adella_price@beahanblock.biz", "maiores", "http://gutkowskirau.org/dora.williamson", "", "four"), 987 | LastPass::Account.new("1872746526", "torphy.biz", "osborne_hackett@davis.org", "wkdcu1265", "http://buckridge.net/lauretta.veum", "", "four"), 988 | LastPass::Account.new("1872746536", "Moen-Hermiston", "hildegard@hahn.com", "zbag942", "http://cummingswehner.biz/april", "", ""), 989 | LastPass::Account.new("1872746546", "Gaylord-Lowe", "jerrell", "quasi", "http://grady.biz/mohammed_brakus", "", ""), 990 | LastPass::Account.new("1872746556", "Bechtelar, Wyman and Thompson", "shanie@batz.biz", "vel", "http://gottlieb.name/elisabeth", "", "four"), 991 | LastPass::Account.new("1872746566", "jacobs.info", "lon_champlin@cristlittel.name", "aut", "http://dachgislason.org/alva", "", "two"), 992 | LastPass::Account.new("1872746576", "ankunding.com", "reina_runolfon@altenwerthhilll.net", "@g&aWsoTeJEFhHK5wr#4", "http://rice.info/giovanny_ebert", "", "two"), 993 | LastPass::Account.new("1872746586", "Okuneva-Schmitt", "esperanza@kshlerin.com", "djwhba31", "http://glovermckenzie.info/katelynn", "", ""), 994 | LastPass::Account.new("1872746596", "jones.name", "elvera", "ewoqt49", "http://sipes.com/joey.metz", "", "two"), 995 | LastPass::Account.new("1872746606", "Tromp-Roob", "brisa.mcdermott", "vcnkg254", "http://bernier.org/gage_haag", "", "three"), 996 | ] 997 | --------------------------------------------------------------------------------