did-you-mean-1.0.0/0000755000175000017500000000000012647462403014222 5ustar terceiroterceirodid-you-mean-1.0.0/metadata.yml0000644000175000017500000001017412647462403016530 0ustar terceiroterceiro--- !ruby/object:Gem::Specification name: did_you_mean version: !ruby/object:Gem::Version version: 1.0.0 platform: ruby authors: - Yuki Nishijima autorequire: bindir: bin cert_chain: [] date: 2015-12-22 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: bundler requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.5' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '1.5' - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: minitest requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' description: '"did you mean?" experience in Ruby: the error message will tell you the right one when you misspelled something.' email: - mail@yukinishijima.net executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".travis.yml" - CHANGELOG.md - Gemfile - LICENSE.txt - README.md - Rakefile - benchmark/jaro_winkler/memory_usage.rb - benchmark/jaro_winkler/speed.rb - benchmark/levenshtein/memory_usage.rb - benchmark/levenshtein/speed.rb - benchmark/memory_usage.rb - did_you_mean.gemspec - doc/CHANGELOG.md.erb - doc/changelog_generator.rb - doc/did_you_mean_example.png - evaluation/calculator.rb - evaluation/dictionary_generator.rb - evaluation/incorrect_words.yaml - lib/did_you_mean.rb - lib/did_you_mean/core_ext/name_error.rb - lib/did_you_mean/extra_features.rb - lib/did_you_mean/extra_features/initializer_name_correction.rb - lib/did_you_mean/extra_features/ivar_name_correction.rb - lib/did_you_mean/formatter.rb - lib/did_you_mean/jaro_winkler.rb - lib/did_you_mean/levenshtein.rb - lib/did_you_mean/spell_checkable.rb - lib/did_you_mean/spell_checkers/method_name_checker.rb - lib/did_you_mean/spell_checkers/name_error_checkers.rb - lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb - lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb - lib/did_you_mean/spell_checkers/null_checker.rb - lib/did_you_mean/verbose_formatter.rb - lib/did_you_mean/version.rb - test/core_ext/name_error_extension_test.rb - test/correctable/class_name_test.rb - test/correctable/method_name_test.rb - test/correctable/uncorrectable_name_test.rb - test/correctable/variable_name_test.rb - test/edit_distance/jaro_winkler_test.rb - test/extra_features/initializer_name_correction_test.rb - test/extra_features/method_name_checker_test.rb - test/spell_checker_test.rb - test/test_helper.rb - test/verbose_formatter_test.rb homepage: https://github.com/yuki24/did_you_mean licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 2.3.0dev required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: rubygems_version: 2.5.1 signing_key: specification_version: 4 summary: '"Did you mean?" experience in Ruby' test_files: - test/core_ext/name_error_extension_test.rb - test/correctable/class_name_test.rb - test/correctable/method_name_test.rb - test/correctable/uncorrectable_name_test.rb - test/correctable/variable_name_test.rb - test/edit_distance/jaro_winkler_test.rb - test/extra_features/initializer_name_correction_test.rb - test/extra_features/method_name_checker_test.rb - test/spell_checker_test.rb - test/test_helper.rb - test/verbose_formatter_test.rb did-you-mean-1.0.0/test/0000755000175000017500000000000012647462403015201 5ustar terceiroterceirodid-you-mean-1.0.0/test/extra_features/0000755000175000017500000000000012647462403020222 5ustar terceiroterceirodid-you-mean-1.0.0/test/extra_features/initializer_name_correction_test.rb0000644000175000017500000000063512647462403027364 0ustar terceiroterceirorequire 'test_helper' class InitializerNameCorrectionTest < Minitest::Test def test_corrects_wrong_initializer_name assert_output nil, "warning: intialize might be misspelled, perhaps you meant initialize?\n" do Class.new { def intialize; end } end end def test_does_not_correct_correct_initializer_name assert_output nil, "" do Class.new { def initialize; end } end end end did-you-mean-1.0.0/test/extra_features/method_name_checker_test.rb0000644000175000017500000000055412647462403025556 0ustar terceiroterceirorequire 'test_helper' class MethodNameWithExtraFeaturesTest < Minitest::Test def test_corrects_incorrect_ivar_name @number = 1 @nubmer = nil error = assert_raises(NoMethodError) { @nubmer.zero? } remove_instance_variable :@nubmer assert_correction :@number, error.corrections assert_match "Did you mean? @number", error.to_s end end did-you-mean-1.0.0/test/correctable/0000755000175000017500000000000012647462403017466 5ustar terceiroterceirodid-you-mean-1.0.0/test/correctable/uncorrectable_name_test.rb0000644000175000017500000000046612647462403024710 0ustar terceiroterceirorequire 'test_helper' class UncorrectableNameTest < Minitest::Test class FirstNameError < NameError; end def setup @error = assert_raises(FirstNameError) do raise FirstNameError, "Other name error" end end def test_message assert_equal "Other name error", @error.message end end did-you-mean-1.0.0/test/correctable/method_name_test.rb0000644000175000017500000000364012647462403023335 0ustar terceiroterceirorequire 'test_helper' class MethodNameTest < Minitest::Test class User def friends; end def first_name; end def descendants; end def call_incorrect_private_method raiae NoMethodError end protected def the_protected_method; end private def friend; end def the_private_method; end class << self def load; end end end module UserModule def from_module; end end def setup @user = User.new.extend(UserModule) end def test_corrections_include_instance_method error = assert_raises(NoMethodError){ @user.flrst_name } assert_correction :first_name, error.corrections assert_match "Did you mean? first_name", error.to_s end def test_corrections_include_private_method error = assert_raises(NoMethodError){ @user.friend } assert_correction :friends, error.corrections assert_match "Did you mean? friends", error.to_s end def test_corrections_include_method_from_module error = assert_raises(NoMethodError){ @user.fr0m_module } assert_correction :from_module, error.corrections assert_match "Did you mean? from_module", error.to_s end def test_corrections_include_class_method error = assert_raises(NoMethodError){ User.l0ad } assert_correction :load, error.corrections assert_match "Did you mean? load", error.to_s end def test_private_methods_should_not_be_suggested error = assert_raises(NoMethodError){ User.new.the_protected_method } refute_includes error.corrections, :the_protected_method error = assert_raises(NoMethodError){ User.new.the_private_method } refute_includes error.corrections, :the_private_method end def test_corrections_when_private_method_is_called_with_args error = assert_raises(NoMethodError){ @user.call_incorrect_private_method } assert_correction :raise, error.corrections assert_match "Did you mean? raise", error.to_s end end did-you-mean-1.0.0/test/correctable/class_name_test.rb0000644000175000017500000000314612647462403023163 0ustar terceiroterceirorequire 'test_helper' module ACRONYM end class Project def self.bo0k Bo0k end end class Book class TableOfContents; end def tableof_contents TableofContents end class Page def tableof_contents TableofContents end def self.tableof_contents TableofContents end end end class ClassNameTest < Minitest::Test def test_corrections error = assert_raises(NameError) { ::Bo0k } assert_correction "Book", error.corrections end def test_corrections_include_case_specific_class_name error = assert_raises(NameError) { ::Acronym } assert_correction "ACRONYM", error.corrections end def test_corrections_include_top_level_class_name error = assert_raises(NameError) { Project.bo0k } assert_correction "Book", error.corrections end def test_names_in_corrections_have_namespaces error = assert_raises(NameError) { ::Book::TableofContents } assert_correction "Book::TableOfContents", error.corrections end def test_corrections_candidates_for_names_in_upper_level_scopes error = assert_raises(NameError) { Book::Page.tableof_contents } assert_correction "Book::TableOfContents", error.corrections end def test_corrections_should_work_from_within_instance_method error = assert_raises(NameError) { ::Book.new.tableof_contents } assert_correction "Book::TableOfContents", error.corrections end def test_corrections_should_work_from_within_instance_method_on_nested_class error = assert_raises(NameError) { ::Book::Page.new.tableof_contents } assert_correction "Book::TableOfContents", error.corrections end end did-you-mean-1.0.0/test/correctable/variable_name_test.rb0000644000175000017500000000412512647462403023641 0ustar terceiroterceirorequire 'test_helper' class VariableNameTest < Minitest::Test class User def initialize @email_address = 'email_address@address.net' @first_name = nil @last_name = nil end def first_name; end def to_s "#{@first_name} #{@last_name} <#{email_address}>" end private def cia_codename; "Alexa" end end module UserModule def from_module; end end def setup @user = User.new.extend(UserModule) end def test_corrections_include_instance_method error = assert_raises(NameError) do @user.instance_eval { flrst_name } end @user.instance_eval do remove_instance_variable :@first_name remove_instance_variable :@last_name end assert_correction :first_name, error.corrections assert_match "Did you mean? first_name", error.to_s end def test_corrections_include_method_from_module error = assert_raises(NameError) do @user.instance_eval { fr0m_module } end assert_correction :from_module, error.corrections assert_match "Did you mean? from_module", error.to_s end def test_corrections_include_local_variable_name person = person = nil error = (eprson rescue $!) # Do not use @assert_raises here as it changes a scope. assert_correction :person, error.corrections assert_match "Did you mean? person", error.to_s end def test_corrections_include_instance_variable_name error = assert_raises(NameError){ @user.to_s } assert_correction :@email_address, error.corrections assert_match "Did you mean? @email_address", error.to_s end def test_corrections_include_private_method error = assert_raises(NameError) do @user.instance_eval { cia_code_name } end assert_correction :cia_codename, error.corrections assert_match "Did you mean? cia_codename", error.to_s end @@does_exist = true def test_corrections_include_class_variable_name error = assert_raises(NameError){ @@doesnt_exist } assert_correction :@@does_exist, error.corrections assert_match "Did you mean? @@does_exist", error.to_s end end did-you-mean-1.0.0/test/edit_distance/0000755000175000017500000000000012647462403020000 5ustar terceiroterceirodid-you-mean-1.0.0/test/edit_distance/jaro_winkler_test.rb0000644000175000017500000000217712647462403024061 0ustar terceiroterceiro# -*- coding: utf-8 -*- require 'test_helper' class JaroWinklerTest < Minitest::Test def test_jaro_winkler_distance assert_distance 0.9667, 'henka', 'henkan' assert_distance 1.0, 'al', 'al' assert_distance 0.9611, 'martha', 'marhta' assert_distance 0.8324, 'jones', 'johnson' assert_distance 0.9167, 'abcvwxyz', 'zabcvwxy' assert_distance 0.9583, 'abcvwxyz', 'cabvwxyz' assert_distance 0.84, 'dwayne', 'duane' assert_distance 0.8133, 'dixon', 'dicksonx' assert_distance 0.0, 'fvie', 'ten' assert_distance 0.9067, 'does_exist', 'doesnt_exist' assert_distance 1.0, 'x', 'x' end def test_jarowinkler_distance_with_utf8_strings assert_distance 0.9818, '變形金剛4:絕跡重生', '變形金剛4: 絕跡重生' assert_distance 0.8222, '連勝文', '連勝丼' assert_distance 0.8222, '馬英九', '馬英丸' assert_distance 0.6667, '良い', 'いい' end private def assert_distance(score, str1, str2) assert_equal score, DidYouMean::JaroWinkler.distance(str1, str2).round(4) end end did-you-mean-1.0.0/test/test_helper.rb0000644000175000017500000000046012647462403020044 0ustar terceiroterceirorequire 'minitest/autorun' require 'minitest/unit' require 'did_you_mean' module DidYouMean::TestHelper def assert_correction(expected, array) assert_equal [expected], array, "Expected #{array.inspect} to only include #{expected.inspect}" end end MiniTest::Test.include(DidYouMean::TestHelper) did-you-mean-1.0.0/test/core_ext/0000755000175000017500000000000012647462403017011 5ustar terceiroterceirodid-you-mean-1.0.0/test/core_ext/name_error_extension_test.rb0000644000175000017500000000316212647462403024624 0ustar terceiroterceirorequire 'test_helper' class NameErrorExtensionTest < Minitest::Test SPELL_CHECKERS = DidYouMean::SPELL_CHECKERS class TestSpellChecker def initialize(*); end def corrections; ["Y U SO SLOW?"]; end end def setup @org, SPELL_CHECKERS['NameError'] = SPELL_CHECKERS['NameError'], TestSpellChecker @error = assert_raises(NameError){ doesnt_exist } end def teardown SPELL_CHECKERS['NameError'] = @org end def test_message_provides_original_message assert_match "undefined local variable or method", @error.to_s end def test_message assert_match "Did you mean? Y U SO SLOW?", @error.to_s assert_match "Did you mean? Y U SO SLOW?", @error.message end def test_to_s_does_not_make_disruptive_changes_to_error_message error = assert_raises(NameError) do raise NameError, "uninitialized constant Object" end assert_equal 1, error.to_s.scan("Did you mean?").count end end class IgnoreCallersTest < Minitest::Test SPELL_CHECKERS = DidYouMean::SPELL_CHECKERS class Boomer def initialize(*) raise Exception, "spell checker was created when it shouldn't!" end end def setup @org, SPELL_CHECKERS['NameError'] = SPELL_CHECKERS['NameError'], Boomer DidYouMean::IGNORED_CALLERS << /( |`)do_not_correct_typo'/ @error = assert_raises(NameError){ doesnt_exist } end def teardown SPELL_CHECKERS['NameError'] = @org DidYouMean::IGNORED_CALLERS.clear end def test_ignore assert_nothing_raised { do_not_correct_typo } end private def do_not_correct_typo; @error.message end def assert_nothing_raised yield end end did-you-mean-1.0.0/test/verbose_formatter_test.rb0000644000175000017500000000062412647462403022317 0ustar terceiroterceirorequire 'test_helper' class VerboseFormatterTest < Minitest::Test def setup does_exist = does_exist = nil @error = assert_raises(NameError){ doesnt_exist } end def test_message assert_equal <<~MESSAGE.chomp, @error.message undefined local variable or method `doesnt_exist' for #{method(:to_s).super_method.call} Did you mean? does_exist MESSAGE end end did-you-mean-1.0.0/test/spell_checker_test.rb0000644000175000017500000000551712647462403021400 0ustar terceiroterceirorequire 'test_helper' class SpellCheckerTest < Minitest::Test SpellChecker = Struct.new(:input, :words) do include DidYouMean::SpellCheckable def candidates { input => words } end end def test_spell_checker_corrects_mistypes assert_spell 'foo', input: 'doo', dictionary: ['foo', 'fork'] assert_spell 'email', input: 'meail', dictionary: ['email', 'fail', 'eval'] assert_spell 'fail', input: 'fial', dictionary: ['email', 'fail', 'eval'] assert_spell 'fail', input: 'afil', dictionary: ['email', 'fail', 'eval'] assert_spell 'eval', input: 'eavl', dictionary: ['email', 'fail', 'eval'] assert_spell 'eval', input: 'veal', dictionary: ['email', 'fail', 'eval'] assert_spell 'sub!', input: 'suv!', dictionary: ['sub', 'gsub', 'sub!'] assert_spell 'sub', input: 'suv', dictionary: ['sub', 'gsub', 'sub!'] assert_spell %w(gsub! gsub), input: 'gsuv!', dictionary: %w(sub gsub gsub!) assert_spell %w(sub! sub gsub!), input: 'ssub!', dictionary: %w(sub sub! gsub gsub!) assert_spell %i(read rand), input: 'raed', dictionary: File.methods + File.private_methods group_methods = %w(groups group_url groups_url group_path) assert_spell 'groups', input: 'group', dictionary: group_methods group_classes = %w( GroupMembership GroupMembershipPolicy GroupMembershipDecorator GroupMembershipSerializer GroupHelper Group GroupMailer NullGroupMembership ) assert_spell 'GroupMembership', dictionary: group_classes, input: 'GroupMemberhip' assert_spell 'GroupMembershipDecorator', dictionary: group_classes, input: 'GroupMemberhipDecorator' names = %w(first_name_change first_name_changed? first_name_will_change!) assert_spell names, input: 'first_name_change!', dictionary: names assert_empty SpellChecker.new('product_path', ['proc']).corrections assert_empty SpellChecker.new('fooo', ['fork']).corrections end def test_spell_checker_corrects_misspells assert_spell 'descendants', input: 'dependents', dictionary: ['descendants'] assert_spell 'drag_to', input: 'drag', dictionary: ['drag_to'] assert_spell 'set_result_count', input: 'set_result', dictionary: ['set_result_count'] end def test_spell_checker_sorts_results_by_simiarity expected = %w( name123456 name12345 name1234 name123 ) actual = SpellChecker.new("name123456", %w( name12 name123 name1234 name12345 name123456 )).corrections assert_equal expected, actual end private def assert_spell(expected, input: , dictionary: ) corrections = SpellChecker.new(input, dictionary).corrections assert_equal Array(expected), corrections, "Expected to suggest #{expected}, but got #{corrections.inspect}" end end did-you-mean-1.0.0/.travis.yml0000644000175000017500000000027112647462403016333 0ustar terceiroterceirolanguage: ruby script: bundle exec rake cache: bundler sudo: false after_success: - bundle exec rake test:accuracy - bundle exec rake benchmark:memory rvm: - ruby-head did-you-mean-1.0.0/did_you_mean.gemspec0000644000175000017500000000202312647462403020220 0ustar terceiroterceiro# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'did_you_mean/version' Gem::Specification.new do |spec| spec.name = "did_you_mean" spec.version = DidYouMean::VERSION spec.authors = ["Yuki Nishijima"] spec.email = ["mail@yukinishijima.net"] spec.summary = '"Did you mean?" experience in Ruby' spec.description = '"did you mean?" experience in Ruby: the error message will tell you the right one when you misspelled something.' spec.homepage = "https://github.com/yuki24/did_you_mean" spec.license = "MIT" spec.files = `git ls-files`.split($/) spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } spec.test_files = spec.files.grep(%r{^(test)/}) spec.require_paths = ["lib"] spec.required_ruby_version = '>= 2.3.0dev' spec.add_development_dependency "bundler", "~> 1.5" spec.add_development_dependency "rake" spec.add_development_dependency "minitest" end did-you-mean-1.0.0/doc/0000755000175000017500000000000012647462403014767 5ustar terceiroterceirodid-you-mean-1.0.0/doc/changelog_generator.rb0000644000175000017500000000156212647462403021315 0ustar terceiroterceirorequire 'octokit' require 'reverse_markdown' require 'erb' class ChangeLogGenerator attr :repository, :template_path, :changelog_path def initialize(repository, template_path: "CHANGELOG.md.erb", changelog_path: "CHANGELOG.md") @repository = repository @template_path = template_path @changelog_path = changelog_path end def generate_and_save! changelog_in_md = ERB.new(template).result(binding) changelog_in_html = Octokit.markdown(changelog_in_md, context: repository, mode: "gfm") File.open(changelog_path, 'w') do |file| file.write ReverseMarkdown.convert(changelog_in_html, github_flavored: true) end end private def template open("#{__dir__}/#{template_path}").read end def releases @releases ||= Octokit.releases(repository) end end ChangeLogGenerator.new("yuki24/did_you_mean").generate_and_save! did-you-mean-1.0.0/doc/did_you_mean_example.png0000644000175000017500000044420012647462403021650 0ustar terceiroterceiroPNG  IHDR "A*MMiCCPICC ProfileX YgT.9%g9 *KQ"QDI*( b ׋}=yꞞZHpX0a`"D:8؀yXf?e~XpP.MSS!AWh8h!{ 8HPA0@p_X#C"D7S l }e'_BkB GDS6q0^lIT 'xeq+ a#}!f9zYBL1XCJjKRF!.5}442܎>tgpc bf 1+69bmqΘ0g`c|]D,ST3PCh>Fԏ~/n(W vr8c`b 1/# 7LptM?9:|}}Cps\x?cR]hr7`(Ŋ^!gXZLh| 0&@DP3smc( @-3}' |P'8ʃaC QWVZ믯(1\p$jHPp!܅-#6()@i:|sZ߫dpT7G"##6aiL@ HCTX{E`0YTV]6XTWӐ +߀۠!rC!y||kN4k )TRW WVz̪l|CJUn&/jrjj՞۪WoW_Ԡj4hLkkhiik9hк6ޭݬsQ糮nݩR6Voգ$gӉMc"J7b52g ?)Q-2n3d355 275W7afȳҴeiMv>fFֆjs-}i'aiw[؏8H9lwwtp,u|363.F../\]\ݘܼM<=vy< l"xyxm6\w-[l6mm|p>>g|V(JʜoײַzzSAzAA3!!BZV.ه[ wo FD\d JꏖΈۮh,՚Zlieqq^o/_LpKȒ؝$4l|jvߎ";|p$7}oSSk (M)-?^7S`̠f _ R:3?+G)8g߁K <ԓ{0p<|ۂ…مߋ=(V+8B$XMIQ񣇏 >Ԩ,lܿ| 'BN<;i~jdeq*][SZjxkrjVOGuӬ;&>}ɹ9/\h}֥ˮ]ɾ\M:{-XgSu7to\ptHs-[---kɭsmm3nokӱwv3z_~׻=xx[#GWz4zj6i2?pO,<|juِ3gSß^~2{yx̫1[M^wq~boDwwœBuS*Sf}7!LGe?]l{cꗵ|;]{|B"bҽ?&V+%27~Z|MRֿ0Ez'l}Wε?|@;1{8M'D`G #f4"V>)˕_-Mhp#1q'lܑ ] Jʩ*OQ e-ZWu^o$im2`Ҙhagvؼb 1 ˵qљE-GCכg,o>_y?CmA`琍aHXxkĉȽQ۵1Ęϱq- )Iɞ;,wLحj:}o@z}3/eew xupܯ cpl8j~̯twYIy֊'^9Q+[gtƻ>lṋ _.\T|9un4ݾq+[Zogw |Wcz>/x|20ί\_~9GhǝUCΣ.A#IK1:L~),-l̜Z\L˼ RO`RM+pA[aJ ,QK-V=GZ#7:76)73hF4P4rMK1)9k[{Gf}o-^[vP#=X)2v#.427*-ݛj#4\|FoiR<8RwwϧӕvaoQz¾-VM2m({rN{pЧܹ ys f ?:xvidYMyoO|^_}TKMڏgD규-;݅L{-]QiZ[ZjZZni?ܱ3N{:0|gb_Nc'O}➥??EKޑyC|ncw'SUӻ߇| )sloIB.-.>\Zo:>rF<&+%ӄS`:E%. RىQi9Kk[. N'.=n)*RbB\ x ԢtLlyT~ZaH 3*%j>x^"-m:UzI3of7--$ƬKlm v{-;88躒]Gι|U9 ښ؇O) O8=H+h%5$5 0Fމm uJ7Ə&& $JILQs.{Lʦscg>j>C9vppayw 6&,hD넉v_iF{'5(yAxNw ɛp@Ej}"99j0Ӵ^0sNY0< Z b  (F?fy aXl NJYSp(B '^#й?I`PK’|Id r c3tv O^V3[lZlWu;889\ܒME[Q[]iV,`u+ M5ڣ:]unc0l8e4oLp#Z-H6"jvvNo]Ȯjn2_5@Ј%C!bF$nI 6e#nYXK*SCj]5nkvi˸QIqS~0DTLbeI{6v|aV|ĥȵ{/ͩޏ n / 4y,-=+,6>tp"smrg$Sv9+#6?{ _nG^ZGݣ2'wkNߪ8;p|Ź+v^bFm霾gbrOY'_'O yM?V|bxFs?O? 6ɃM?wbpt "TiCޣ ֠%&ӆYd GD"1N & 7Iڤd;4&6foyì"F/9z/ 6 G؈*qŗ$H~&*('@G!U\I75^uK4my=Vm15*04m0d9f%f@Y]P(}+בSJujҞtt1yjfL֓Ӈ2+=/,-RRwlk} *Nt:=w9`x#Wv]]iʺ!yVZFt{Y]콛buO`<4wٗ#SVߤM`ަMS{c?sl_㾙|[~fn|BbR%_V,W*WW]Vyv Ys];C@UXB2ѵoX[[[\[[KCSOTdҮ>H pHYs  iTXtXML:com.adobe.xmp 1034 988 ]Ւ@IDATx eEu# HӀ$IƠFMbL41%!}GgbԘhb8b4 eYeW~}WoϹCwU5UWU>5T*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"PT*@E"P=t7?W^*f?W]+[T*@E"P 03PG ?ޟ:?jfTT*@E"PT~hY]4gp*U*@E"PT*5?s? GV>R _T*@E"PTj"PT*@E"PT̂}:61j3ѵn?LJw*9MG;kWU*@E"PT*O]On*f]4{*]L&}@E"PT*@E"A`Ed\évUN^Sm"x:yN2@kgێ7;c3*T*@E"PT*ݏ,ٴN&YOfoFt3S> 5mv@NGyjo?V*@E"PT*Յt:t.i'LuvK\NW';d2;d2WZT*@E"PT*?=:-)d2x2,qNL廅>ݩLN6 : bSL[o236@E"PT*@E"P;n4to˳M;}ˠSɳv*&5Aɺ9#Iމ1]]MW*@E"PT*LwI߹fy[m7tYt\N廓oyκ͸m~l;Y|g&Ye@E"PT*@E"~>\ ruLeig}Nv}$|τuԕnϼNq5z,"PT*@E"PT~[H㹤Y)z:;eM۩m)G N~o9mڥɚNo;g~W*@E"PT*#@E49e~xֳN6u,7t;^;y;],/rY6-;(MF厷Y]6rh}}}Euؘ茧O%mT*@E"PT*G`qM'N)7յ=>^-o54ݾ7/2d:dfS]]ȶo&K#r3]i,>3SΝ{6Bm<ѵMNityv֏DNOFk㦶'=::WdJ=f6(iB']Q|:?˧r;qɨuMukOc\wkݯt*'O#xE|IvŎ~o',wz2j]St7=:'1.Su3vuϞjeG|u5ş|my;ގ2:' Æ?LČYCk4i䶭B-ܗGv?lGѵ^s)κ:'21kbh moU %si+tu .yfڴish}_]y1쓥- d,kۥ;OZ):*[ed^N:YN<_Y|V\t7Xwe{/ӹ=ڥ=0ȁ |#M<'N~ȸ,}ΏCֱXjMHg߶'ﬗul5߾ͳ-?,qm,?fe+A`ge</X3~N~5Ǽ[`a|2| ]Xn^n#,CCfc?GFݟMdžzodddAm,3?OHik{ۙ6srJ@/?GqYZfjlO&Ngd~ѧ|Pt\vm ,&Eyj>ƩI-ch;'!}ܧءE!q;@<@ ;QbNxMH?yn )|I{}1-}ܲw¯u_WoL/<6umy_W)ωq_:+;SL3+3ŇljO#GAqͷ]o]Uu|ˆoQ>[Nw,XwT'Nm+ێmOlN2NQ NMf`ڵvI`T9Ni^QnCFO9<&Ou>ַeP.uH['o;ěrM]@E'y׮ ֵ/l9?!7?S}8us̳PB../4ѭ3c Fo3A0fWYq&#Ʊy}}~4fe&dg/ecʺ:}=+Y4!-ǠgַeP.u.iۇ>ěrM]@E'y׮ ֵ/l9?!7?S}8us̳PB../4ѭ3c F>V۟tAorּZ q6u2iB'eEimk͟ZnRvvMӦ8"L7Vm }AztqBYX;- ٙ3]},s<ߴq:sp'F7=2AJ|mĝ;E< sTv.]?cj3u{Nw7yfq뻬]]Bwں. |Nc8}/4qts^e92upfؾS9ڹtu:Yic _d}-|g ,k J|%d9q'4C7jOG7e_##@]`;KϘZ'~6̓:d1'|G.+icEĝ:E< sTv.]?cj3u{Nw7yfq뻬]]Bwں. |Nc8}/4qts^e92upfؾS9ڹtu:Yic _sq(!Δ8fhk!ho-|ǡ͸y“ų~3^z w;;`;pкCmٷ 9~Aݱkꢟr?rrP,U^lfl1Lf}Gp]]GSd|v>ց"il-qF.2s9lc2hS߲/JsY8hc;2]Yn;\Ƭgг}oѳma=>rgYa? b|1?q#l,2Fq˛馎16|>oևZ}ejvO_pprq?}}4Yj".1]Æ\'k-ïq|"sPm,/h̓:,ϔ<8#,s9Aq0~*Sd%N0USl/twZ)>,8ncl}'XrmJLY8.M>jy2/?nSƏ8Xe̺ ƕjݮnW3ŇfC6|e.'y_)ܦ$qu+me؀ߣ˛-Gr?s9St{.l2Ur*HJXɟvzwl(P`~g}󠭞ߢ}v\IN@Gqxmv0 $EAAlv؏_2>ٗ/d~m_GE^6D[WƇ8'nO`D+q5E%ؗvi>r>O&^ۿ?} }~gܯ>CB~#NiOI@;ׅ:(q^E%zξ\榟;B\&ƒB>zPے ġ2Gl7˲?YfM?.?6g7o7F__vӭ[g] qcu)/PO6:2@кYQNNu31k5@joRC,w,9'=0g9 |)8va-|IжͼmcomoL=ɗ<]@·,Gބ\/̃15h9vH?qd 9o#4oa n`e3ë_?!A<#N4y?c%xGLTNYI#dI>NFS*_ Q^E]]/4=@PҀx 2֍QKOI-TZLszؙO<f^3>6Tp&98mqh[fd -ogj;ߝM yPcx6VΛ[֮sa/:wrmءCa=/<]6;7q}w+b}J'&w\Ҕ׍^kcϏu^}iܵ~],$.Z^lz0 so,zNųJCZYkS@E֭uϣ ^ln#Zh{Hm,pB_YdEV:\Y o#, )}r6QsFÒIl卍>N(ht}]Hbv(UAe-"Vmo0͂޲2V7 K!{E\qŕ i;!At8-ԗ]Ӷ?t["vٯwqqYL(C:wqҶ!N!a!L\>&.4q샴u8 JYC^;|eo{teg9oyc6qd6鶳^q~PǑۆ8up>s޶Ew^::ib2A N>H[iˠ:eΧY6GYx󶿜a?`GF~lcjn;eumS3m[|Ec?ȭ&.4q샴u8 JYC^;|eo{teg9oyc6qd6鶳^q~PǑۆ8up>s޶Ew^::ib2A N>H[iˠ:eΧY6GYx󶿜a?`GF~lcjn;eumS3m[|E>Og.lC)71vRP)$Qve8hm ִ͟щԛ4= 8)q_87mƝAgNʣ8uGgwUr٥?N{V,~iO=Y]N ޴,hv!wwuEO+[ aM7,J.mH^,䁮,U 6+ |)ØҽڭF' 5jBeckA zU~-zU!.(l|+ MuQWІR}Hꋪ`AG6}8S HT>1TRmPƊ#ѰNt6lnGc8Iaa|^3P7ǿ-vÜcerJ@  /> %xOKd uO?p?\@v~GyE:PAC<_oZ~_Ȭ]Bom۶I']tQ9>?n֚L­IVE*+q [h&S2o} ;cS|FL +q˦.S@2hnr$ܩ! ߌ]<ٺvF6 |'FwF]Xx~kqGNI$r_zEq}W?&<иi䶸xc<(/Vj8 o/A߀i0s?3^;'\~Fst1cL.KӦM{lNYF'G(?EiO{Z|_ǧ1g6 ״eg>t-|Œ 5,/rqUgGȗ,c2ҷ=#ZdkSa@'ffG(:*Yi?c e{CUF6R!ȋF?g(_*c: h17ІHߠ>P?cT8Mշh#@/f@INH-D*F 8' @:O0Br=c>Ёeg}ڧ5/<.lGHX@>ekCc߾zaGJ0$E9 {|໾`>ЁNJs/tZmC71֣ϹX5P+UpxE:cNxOOm*x7-,9<'py._wf-<_2tw])4e?pOrihasW̬F"eq]ʬ̓rY=Oi!Yc*odH^YG>̗>{霪BxG[߮vR؞. 1m&ŗg)9WF'JZ-y,@_iaL؏o65>ՓM/\PoVC[>P%Q@TOM怑>ʭI% \_BFyWN2/E+Rr3bG#GQvy^ ;G˦[J'5"@K;*EKuxj~6Elz)<(RվsfǼuw+'ؤϒ/c?Lse"ҥGOSydu}.nzyzE`^+u|k>̶6.\Q"yIcC>x޺mm,/A\>۹>'ru;mȬ_ۿՖ3cZ1vOljO1:[s/Z\<<Ơy޲č%v/h:A86eX'XD(~ .(/>蠃}1:\W('t_': jlF=rImyPpz&ɕRB.tS2S94 i^u04hxwrgB / bўI0^ĂF,YX|t[ cNv.Y݋Fb.ZkK-OʒI'u$y칱`Xq,379ś΋{̋Y'n)G!NPB4Ǭ.]En^oC5k>$Vݶm@u73^u4Ze c,t*`X(Nk7e}˿-g>SdQE۰xlP>  A-/HTt !fi/g/}b_TPH]8Q^h7\w6oY!!nmŠʇ'ƄH&Z ɸ_v|lav#oԜi?7u$`x<̙3'~!}(MjLpEm7M)#)w<7x `3AAm3l{lK)c/-ę1Ki]w~\<_PmKY,wyW@| ns6.e;k=\.|}Lȳj+錫Ȉ_9nlϗbtmx_6!'@c9^Ĝ\џ:Oo&XN2VV\YctDskR̼Lkwd1uT hyP1oiSi6̧ UcnaA .d_D{EaOxGo ?ti] ?jCⁱ=k6ja|/ܧuCDe%M|EEFH?ωžcY+J|=+z6EA;l3#gxQGe>nߏjZ  3"c͇'hMJs,6=wt 2t?>ڂӣ*kzO/dsWzc!>-G.X=SG nj[<cg?~y \B.\'Mֱ-̓vݼ1A`'!׃ݜ:N;z'x7uّcپz9ʆ ~r=ks}<}C6\.}"wP -LغjۣV_XĹk<90.1'ⓐ1btsn399=ǽˎHS6la]ş! :rRfrBƍ2J~\'Mֱ-̓c|x*ոozj)}|ta1r@KXһ0/)"v͉{tö8l٪:O`LH3ziNg g,өXrK\֛-^/ӛ~\-՞Zo];'˗IJg9ޫrSoR{]'4^kˣ# mRp6^ZhSo,NZƩ<#xgb>0pSoW=XzP 񖷾5V>4c/|<@??}g<ҏԧY:%uw9׏},nswݳ>3cX hf;4V:S+KApɅiWӟ8՗5&5Y۷6ᥡC_ؼysr]|/~=ݧ 3}}q€ݛ>kH}f_͐ \}Uh#vGuΛSE:[1x9siϱWP-C^9חD>ybW_ɠ5q^\(%:P@FhӒ<]]u&uM>szn(wJAI,:i: Z.-y-qem7޻!yM=Ċt|ȅ/v=Kc#~%xp\_7u7]w{kC/Y:e%l9oQgż͋K-r|nIUt)P\zQ28'NKAۣoϻt[404xޟc6@y)rCofGxQ\pѧkb`_|}_xyn/>omQ;4$捇?v~'.{bxi]~1Ww o7 x#žV+/^+}s{Ʌ _8=ޠZaqg}ʸKO:ԋqs*?H2~ⶋύWņeƯһ ^cSW|ex);x,)ѡ-qyoԸsJT ksgx{q|c'xAOG Y-X%}Y]wxq]q6Xz__',ߍ I?3|߻n]Ʒ~4:+}W"yڳK+i:0w;='膰lCXG#?X]+*~zq/o5էVDOzP}'?< e fU ~w_ Tl\pʤ[oo*x9#zBo4FǏ͕{H3[ jgEy{ :S!J7}P2>u3'gJ99r{.jm\"/cX<<R.2E ;uy(C.#|E.O?3~!/zp]2 J:7Yߺw }S>6q4}c G8N):w/cx,|1\Q[|¯5(n߯͟(rUny5kN#עNτ%x 4ዷ] .X'ӕus ~7vjX;h܈hxd\s:(X_sMgW,|c Ɲ@'RvC'{`?zUpn+cS_6\^=ӎ~qܴ+ch8j q芣bv6@0HB/uL~Z|đ3)[NS+~ԕ1KN?#ޭg3xe|,_?ܸGħuC'ǝ_Hw`UAEOڇω.ձYo]T~!!x'~rj`m$lׄ{wZ`_F6/^8f|+~d-3_Xm~tFܟ*䶞*X*">Ǻ]e꠹mيe*XqX4K/Ӊ^7:tpC 4\8Ct({I+c 93M-髟$?x~|:Es⍯C߿/9jb>F.|t`WzԄS :?_ kży?/WߔiOȾ2gu]n7!GZ/md8/t4t.':#c yq ů}:_|XN@Բ\F?3ak`o܉#sJD_}xu50s+M=rҦs0=5)CɛwOOֆ;^`Q}3-6e ݕe%i_mӷ$PڗNof͎e<5{ֳ |:2v>rٟmIvw'&YCEK&/gm~3.[O ZZc:ҭZu.}sxzZ^Rt n|vXܷ߽?;~yz [Z<,ZMuP89xC<qĻ΍O5(Wx ϊMϏw,?XI~NQUnTmZЂtD-NZ7ε=|O,6oM86/1b*=؎ g8(#sNUoX U~ `{6mWk!>/  腍n>|%<]0#]~ߋgacOo}巇&؈ޟ1noUf^~x+% ,~gmԧGP0ؚ׻ xA`9=/:û(W.`ԣoɃoyY&wDfi Oq/^ lB-ygPQc4K{v\yN*\Llל: 81[~*M^V,ce8JX'P=S/;/=*mx =e~S u[a*H68eU?fSdWQ Gxq+ȋE<y>c3|CL8iS@t\>e@@˜)z?,P3Y4a&bG~.eu9 F][>nCM5'uM)yj \}#͌am֜T+EZx&0_G3~4A{nMfp}a7I֟,v=6%Mס+0]}lӤM4]ڡ1:o "EhdQx=S^G?ƷBCEq>ȇlƒ<|D|`Ci:;\lPO|zB[|N%cz_,X7|ʢhH|^?d:P|'XjIy%֬ }Љo94t֙*nSm4 Gya9ݔVlEo|SJM/AJvLMQ%,#ك1z!wڃ;)S9yዋ46!X¶-zv\VUaӛZU밎"E:Gx}*Ī䡼Qk*=\W?Wi>/.[S#;}os2mR\Jq{h&mrO}+;\x1gĊJyΓ_+[|ųTg ?8驱PxrHgGSWTC _FG Vy''n/+^mХxʳ{E~KUo?史yhDv=j!}=M1dcFeׇ#^?8'ƻO8kv|Gs󬚻n4>=vvuJ{?9Ϗ x ڄQ}@C΋5z/%/{i<>7✏~<^vYqWCiH}^x%W^YeG_ i\u%+ $ƈRf F:MG8ӑAҩcrN"EMhqX/Fjj};@GկwcڜcтR-[X{}ٿTMm?i qYOQMm:lHK# |P6+Füfal2מ<0Lƿu< ^(_\##OCseu=qtd|w;\Fo ϲs=Cr÷ |#'mf6:M=|7/,9yaEr}8牌Ŷ ߺ;SO%Iud`h["8"Nj:[Ae|i<CA]jҺS}x$E[2f^m?Y[F |:έkw`< jL{3u%k0 AMtGÅ5GQ,:yq4z\so(r? "#/`Lǟb߮O:Ĺnxⓞw'_ѷc:]H5(Qj5"sXᄊ,j\&|7׋7HyY+kԥocy!,9We1zxroӸcB^XjzwPSx`W7 &)lV sSVz5޾zʛ0ڴ{^Qq,(dUm1W =)0b᩺q{!ʬ!lUfձ~6&0}?|jEyc4֘=_Gq?Kbg^sb1x PG**«Q~%!c4ˊшl:yuk#j,#~ZrD `Ǔ~0ʫ(e0ޮzN9FCԎ|D/mܣe䅆:6- ѧ:-STW-s7mj<x΀"#_ԟ42[č@Mj`-D96صѷ/uoݬ7ڂxm/=@ox>f&:?_fpoFx Zxp<;^t;nrnϫu3J÷MjLw 5mAm,kevg_:W Z^f ':(>#2 2/}i[O ɖ8eJ35ZC~'>7uw}lK>>{W":QM }ۥEݨs-~=ux>]ڄu!| kѫ֐w '#L7AFskn1Geo: ڲ@ZdiiXr婩{cB//bѹ->$O_2k}Zws]eMnɛ_鉯]?;GdoL .e3l \(:Q{!Jst@?75Fl07<˯|[kT/kbmW_r,hQm9rfdGsz̑?^?xAH؍4M >FvVL&F充 #~]G+킑~~ۥ~4>F*7FS'o:}Sv[t!*@P],m`𓎴t`kH}N.Jڠ :x!'6C`bѵ[[]y_{1?PWCU 3,||˅.z9B{u\\M6@> P \Igy.vLYɇQ62>ؠ %m3ظ+vEdŞOS _>C}rS?>7Xqa~{,i8A*u`t~g92uzl9C|:2tvaM7(`RCYG>><my@灏`g. G?iOƉ3Үi aϻVZ7ު'&._jEqs|Z#V)Et\>UWބ_~MONf =ԙ䋕>x?اsaDƄ'U2Omtc*u̽Z(݆hqωM-|0~lP[.Zfr¼ٺލox p:9y1&(Xzu#K+)A߁`9x著D6x,Q) "/ND8MӧK~L]CٶI/.y_|Ig!9>s9>Pt|C9 {]2A#XYg[Ҩ KYy,,R+\<T8YNu+ӻV:Gbtrrno<'x `ioJ4;^5qFE #/wWT9Y;_HPU 20b,p XtH0ݐOJ!7Vu}gi}~s\ H8VbR-RWLHHٙDӿ2`1o<2x"V0a0Jdf.!ICaTɟ{0J5(X-[?insQiӦ+-&c)55sRsI86A-`>N["w[(>uK.gSm+W52?n9TyU5=+mҺg޶omѻTR0 OAV .J+g}A/Nkn{[i^x뿳z뿳i\hZG& ]˨̂"k,4qauaNeK{wE{V ڡax2;ȝ2jsh;T*\"8n(^m:4C%Nq:h&ضSyTNt쩙¬S)mmOym{.x<֫rt@ՐA#,12@H(x4 >Y3?H]EZeϜ d~ʦw]yϺ7d %<-oNC|/{ӄXVmxBD o5:#^@]a$+—lK\j/HEGyI?(h =u2BrJ`b ldfppfaSr+BFr87k՘W2d揮N\Y7p8|C#;9L|+^ع+?mRyH)X>ۨv퐯4ꓜ[v)Ne+Na6m{uؓ{׶Kerl.9[P~Joٶ*moSNm3yfƎs;l:+o{_@cîvq"ߎ)gvy뿃;hi^ӳ`_E oowp駹m"M8l {ehyz>m}[?=w?=>zzgӺ8G5H׻ۣ*\il^o˶ym,|TuQ9F[ewP o={߁`ai/Eԓ77?;{{' 1g`C+:H|8\8iӻ|!P6Nym$KEW)4%X% lcl}+̆;qQ0-/|&g 1a(6N~/d}|Ն/P|gS҆yW-g",2=lݶmk(XDEL[v)m[>rºuxACt Y$RO4,H6Da"ē=K ' xt,M6=N_N>w h0!u 3~sf\24yU\0I8Ѣ T1Qb/ 'XS/" q*x%a$Vg^_ޜki>oiZ.Xg(̮IZWzxNx[}W[ʒS(^u̼|S~ im]]uȺn ?gwxx|gn˰eɗi'wsğ^ٕ,'Zxd]ҊU_|yɖy! Pv-q4mjD HKW>|?ư\>ZYϏ#l1 qnH[$ ZI "Ik*i`TkY1,EKIKBW`PZIМnc0v ($ę>PH@~MR2Áx˱8c_ ]bN d\=JLhEey0߂Q_^Xv=VH A<x_ DRZKyrDz8yqټimr 12}wzv􊿻ItWz=˷?\gݳܾvx@T (bjgxmPC!Zu'VR=݈8ҽN@8)" u:EJ]=: Uj`Ud7*eH3K2ĺtҚ|5iTa!W8Ne_h. 9nvGWɠQD?^ > x!fifkLgR 7;BBP|PŚXc QVB]d?50m#ċ9|#]{Y`? 8? &<+\<֣#F0<i墭 oVd_Ƒ7~#oyY1Qmk}h\K2NI\^NIOaz Q`L҄]ճh]iwɷ?,g;oDAD~azv+md7$m|I(Yg',2A$&:)4Q4$x9juNj?Y"E'3JW_ģ+Q)t8Jg\uu{Y=HV;Fk \ĮFx'b(.}]?)W!2O̗}&!GW}G$Iɟ10bj˧:2 xJ[Y8T;'D*^<#oX;;Eihʗ?,6vFN gBGpc=NWU3DjO!bgL1sF0P e"ṈÜkzTz5ۃ#{G8\}5b"( AaL|9wR2Li"D"Sh ?f0Ww#mҒ" MzI x*Six-}E< i|iO$0 IS2OHqObZ!YYs<@s^w$ ]w= 0( oLG[m}#Ol)R;'&,997'l`,0X;uy"V`G\#[5}=Ï<ó=Z$#|HlXB^=|% w)LW>[WX OQ6+YG"ywINYaEO׳Xa~ W#1neGQaF5LRyu543HFo0=|^ &G F)T/(a1nը,yA_ T} l#mEm40b^HN|/Fh0& #v^0b\08F9?2 FL~'[a4i``⇗m@cbRS0RjK8H=8L#,ѬG'u YFR+Ѹ`#K\#ok[$|FxCzxϋg{Q_V~;Ha% l)~|6N 3TC׳ S)>˗~i&͕^,.-Ki쏃PaOM`D%./{ z=$hv$HH:I@BO '2HǛ6Sl!c)p\Gʒ+=D[_SΠ/|7\EP2Uu(OQw] ([`Lvɐ_ FמD0K:E? 5ӊ&b?AI<_wr1 aadeR DBj 3|"l8:ّ'8߃ez!')'YO~ O) /ƎnTUL,CC#º͛ '+} )ELĴ1QX0oJ`G\#o-kD5l;WJRy8gi<ۣE~=0E`p8˙aNז#()"(0*G KKg.Ɔgw ,J=Su=x3eOW/0K#i:Q6Lu!Haɨ\i 0X~,T%>6 WyeOuY˥2D\!VY"Kd`NN'ƒ? IȘyTM1W@šs.:[CtwP'L/k<'Vy@~1t-czK0v$ekݰ ](HA p2ĽPB\NR@̓xMFt9?B0T%5y΃<xC:~$T18BhyJd'DԆ.Ɂs?…xb“;Ə5% $5󧫯w-`#gXDM`<%8W7F y (>'y85z&-R"nC0i !`}dZdgŢ ׊:֛oB]D=ҹ4wF~.0Ϛ,'ds<ŸYцȟ'1.=}3!89I`~$tQ` h;@tC:~.O1ϧHYLT Lr AC.,n<d K }Ttc@I8` p1S2jh 8C4N+}$ (y-%t[qL05֫H A_0CV*,ԫ{@,9 0Z#P6t(<x AW ӧ˗#-- Ç_* bՉ#[dxy0M\*@qȦh.8UK4p'ٞpקO;Pn]\?j?_-)[2'G_,b93oHa,UL1ᛑ92vi1wݍ?=6f?Y~'7"` _h: ^vQxۨ(Ҧ֏XM+Ţ/GQIRyuΫgҸ)=Xey^D&eOeA_j B/P@Tu/DnGL0(*k! R b a b9,C< +ĉ#CQ72^@IDAT8P:@$> -9CƙپRPVZy+1Z*ڴnCY#5‹?^NQ "FPdX >btԩSc~ӳ: )))1<x Aƍxbx xcŊСC ݟѮ߃J0|plݺå_*ďd}9@&Џ %%y s86(|$V!5-W f>vڏ5;oG!-9q:D* g!/K^?t~HMMŁSOq1gt>xw|rGFpH ϯ8BKó{/.YMC<ة#=BxZBBBe˖&N˃g[[wħs_?ma?!'csrI-\øLU PoKBݏ\gGGe" : 's мٳލc?&n ۴1D}1 Xn>2̲hsMRAqr^e lJZ'͢Oګ 1x.dirkLeO?hy˓4*'366P,lq4 _r^?7|P8B 4oK=_ !UNur<؃pއvP 1*\$(w 1=g@,728rt7nc Pٖ#|I ,_R[l۾7BmI\6PO; l,5väP t+ z}`O`矣J*čYbژ^={kGo7ˮ000swy @v ,>p999#K?O̘6q1+? oOr;!' ]c#ϢO>eqk0!s%X],_q:|ҕۥ۷m3觨 N۷m%W!<[c2 ),811O JA3^īѠ_2xdIDtFi㐻y3|5*%7"n`.t-̼< "<;r5-&82ڶT5Lhիf醻Ǝ}c9q4[nG9}7{iZ Ia&jh5RТb x'7l0EDGanekŸh[J\攷 w:v)<2U?Ҍ5!1Cn)7en&"x8h7y|\⤽@3PG7ߠA!.d$o Щ<'.ҥ2Iĥb"M B15#Nc@u2f+/G N ܴxi\ ? Ӱw~,nuhSh}? \ZU Ґ~uM.>2!$1` vw,w5kf6$$''l\t)::aDd 8M5}jFs0j˓Q01&OTNfA=~-n=# mK0z 8jQn37cfWͩp_AfCSָԎCpU(Vʓf'1aLGniƇ¨GƢm ;o9ob]e(rY/n%]d)hZ Q >^ÅkpMc'mўϟ++ݹni'ܮjժe7&7\[6?~)$&Gb$Ə$)Qol5N ^MIDe0ۉ9<%N{KW:khR- ؅UA!cG-$zC~g1hѢ_D8NԴiS`-[0SѲuqH‚ $4E␎:,\y|֣4bXxi:u "tUxlW=bYqia3 ~RN<76tgo5pY`l8*wmdYfy8ҧ7lO~e7d)u6Z,w8b ќ}Ozh'9 b8bk5 9s }S$.5H|rk3 X?L?QD0p'0 ,n}s BדI.C5A󂩑`xn`yG|24ml'ĉ p-,O éŇerB0s;QA'iUePB%R'U`d-pv7MDI3rJ䤗G Tny?`.l&CM~|GL]Q}K\# <TÏ3bWusZO&A;bӦak 0NgˆI*VX{0k8<]S #F~J_-:O&Bg1wTyyUA`l7Ĵn:XMmbh!G))U0埓 aG]N ,!(bdP#DxH\Yď$jh_n'6>ԸC`j*;p&3~bz6k (N4', ?ɯ5c_,Zl$6(4pA"(Xr%֬Y?ˎCC*Cܼ |غs9=ۣUشi{O|,[xM&%8AqT 'Z>%^T~D S"U \}ls6N_թ̽R zŲ1 k/J)+7gq2#ٓ")}m6#*Gذa1d([M:;8~ { l ј(! ,z$Ze:6@oQ#R M&;3pꩧu]+~@&MzތST( >W?nn㵘 4<ێ'oVW_}18); ;w6*DLqe+yU³erlXz"Nn8A~NA܅Ȥɺb$YXd #Al8*a'#u,u>x\Eil,wyUfۿAC;b}]{A=yz ՜Qzaf"̵8εC/#"@ GdhJ:Q]$oɀ255L"g%#]d$ﶌ(QhQD19AsM'ZG@#?lڠ$;(O14QiFy rq$v3عq}qCAyt#G|Am_.֍Io⛕Zu,NjlM `x((`>t601 bWUA.cJJf:7^'kp?7q'2WqTq6d/M%H*++No x=8s NyaWpu#p哱 Q5v#u‡pU&y# "Ÿ7/`@eGRʑL,܀k?R1qz߉bcb`W.ה>,L= q=Z&s<8zC`׮pO {]2_;v!b5kVe~R;9|JJjIniQ-~ ~0 X$V@e ' 2)u8¿Pj3~t{xjʨ*@JH_#Y=yx(Kl۶61p$D['BY7?0~}\/_<8AG|I _OMnNϽ4Jk&ik<<($Ӊ8ekV7z o(sLG;*SuDxg;"[ <]t/h$%Aqe׉V,Hӆl1K >,X!'T,<й.Й7tBGHJ$܆G^ݍ$~; RrʕW">>rp瑁³8~H4h -_1p>bsdYB{jEp%1,&B2*A(&aӵnzsM RbDW‹^a5~8%p ľiȍ͐_GQZdc6tEaƪ|W/ bՖ((wX)m;N̲o4}ȥHۿSNcf̿oO$ \zc[,Źq=zmX+f<vdx$`aRL1:@xdӑС?Ftjm BƯ)s tmҎBRH_AѣY}T0s<=zUC@=N:VV2`|L 8~c.r%|rvy))Xs-N1(#XŹsH(rJ)[WfsW+4 FTJ9L#aF2G2CZ9Zɋ/N»瘺m|sD- 8EqmQ# w sU;7nOh\,*Ty\"ùo/X~F-+m:V N9҉q ݦ"|ĕ6H@s)"OfB >ض  ›-7|&s0}7K.LZfM.{x}! 1~ N:E%1)YNBY Y.Ȗ(6oV6]pPZ}b AFc8 >_l84?$Ā$$Mv'3Vĝ+t io)5'ZU:afҷ1=^Z5 C;S`- x+8Ͼɦw!DC3N{WPQe2s HɚrStFJۣ5hpPzy&8hX{>gpڙChF*CYi260S3(H<΁y%H]aMiQ2G*SW4{ϘZqN;x?'->=ɨNu}Nh^#>~c4 .0â:EUyO~С[oT7 j>G3D#Ki/OHHU 8V[5!I ),:~g&n$w2[Ăd@VsYwL!y\ڟ髶xro^ ضJ.hpٖݜ'Ul͂;ѿU^x~O[nlJ)QdWgeo[8pp?:`)܏C!C3JGvƳ8Jgy|7O5 k?7xˇt哚3q0{5 z^SLxe8/Z_I=oI WDxh.=LS]\N浝KCͺD a // E%!d/7mj$BvxD&7_g<3S --Δc L)Sqp1 F^!ꕳK>'c_)1nLgkѥˣu6{@m6>AintWr 'b2|Ra#>Hԍdiq0Xe n[nŪի rs-5S P+‡JÏaU qx ـ.Y*WW-Y?XDBxɐ 0Y.R":ѷb~,_\5Cpl$лN+To+JYqf*C()`]`Ts LUp/۰n!;s+ ߼q3G\6, V_WAɯ&M89"Dq!=g3"~9A/Ճ\G=?"%9PYC4oڶH`sAŰP7nbHbIwjTmPjE V e~G14 AfMRZ|)NӇ\!OI #I_Fԉ ]<sNqUu+,ɆcM.B W89$ R,ᗒ&bPhF0q8ュt&30ю]ǽo]u\GQd396: WZg|uс8!3/ђ!K)+/:HGvnɰHr(5Ĥxs)b f6oJn-Eb,gĖ鑻i&=~:Qmk.cUV'`[TX%„ rww]Qbe1* \2WA?>tP}[sj K?^םqQAFcvj*<kry]w7fg1sùx(xzM@@'^8 9N[o5xKO<M41Y72I@SvhJbHh5iI"QpkӦ5 1W#ںSuIPEX!>kN|uMJsAP2HՐݴWgi[+cpb4JUK=Nޟ_"LGILEK:\nyWZ=Op Qeَ9\oxڮ% QV-RKlšoW!@˖qFhFDܧG*ժ6GDʼVD1b;!;R ;IT|sع7"T! '`ڵ&+ƅ)/ =X$?oP1_e];Nώ Gixaw!ġA;ׯG8#ED-BwƌXq# !B".ƚib֬Y!hZ_ǻ>V>ZDl\ʜ /Dm!/yb#Uk$%K jKqm6}߿c(rn"{}ڸ(*'c|Ĥ$/p8:?\,3{=<9I:C1e`O#!r?I}j@&%>5yF/ 6DR#"fLj|ԑ`]YdYdNddӀa.+W$6Pݐbiyltmϣ |&#jPuLb~"JMMNf;ia$Xl۲eDžOMxUi!/&4Sŕը4Cϊ*FW=XE#{zz$\fEmlh(k=!}{&aBqX^l\&21|>^Ip^/ dt#XO2M]X,GDt{¯m &|Fcphqrv>_S.8͔If~'l w)gxu. ^ۏt]ΖFJ8]c\hWJe-63EB#>]p={ZX`}S_G[iuo6|v`0GNX K.ڢo +ܝ=Ne~H4R۱b'oh'L<_%,uܔ{WkKW{Ѷ`y!MerL;.F q(/²psc2 hSpnеape$f .c!'|?7 >Mj*6n&␂OM4W1*^p_UNyl FeX́h4<[5Hnd86<CGHM)S>sG d7 I0cLAE7X<ێ|6 <1,s_oIݳC1|bk dfeaK/iӦt#Y08=rz .^\XEA2d2iCtW&m:^+s( %=Iq2"{|wa9}2wbrrssȋ9ĕA.W_K1~8?W!\yI3- /Օ<\5B|sa$F<#U@)2_8t.B^6|Xٞ< tM%n$׮¾{P:hIY/a-#Q(KJQ\H2sEWɽLD:T]MoPMt?7>ݣS QR=Zv%$ Y q<>EH֎0mrַ~Y6Nj3O^;L kx pPo7 i<!-wjۃE x- yv;O]n[mf<ߖOGI:\yjuJA'46k /oGz0yjpE;T7?Sw9 -. !(qs, H$V.GxEۏz02zuq!lLxe8],:ٱ-@ D*褵BY]{L%hn4zs'ގ}If=(4\xbZ i1Lģ8g+mwMxyhsJ_EF#O@܌GRc`G̝}YWFcn .Rpe6f,Z5q'Kɪ+2G<\C,s d85_ uhi*-|\#%! }u[;jcqȲ#ypHIRxN>\2Jt%̙3 w^àQzWīwCMs`A 1Np-TIlF\:lJ)۞eJ#G@ф2;D1پJ`^S HOO7+Yk7Q[c:o~M6dԡY'Gz¾xU? \Lx?2.[cTN阽<[*s #B7;lIiڨ.֭ǎ7տ=$d5is(#ٍgQiЏ ;n ]r1Nj1ԲIhmB.ѼE<'4I5[瀑>63Ihjw0]tFUJݺhZyl_"{6$"314lЈ_.u$%ǝI':XmODf:|[ yD<9nr}Q:6j`5> HR!^bv 㢮4$7Yp<fx̣:Ŏ;*p?"&NM,uȜH8P:uO$ZeYF7 3# 䰻ȹc:ļtQ#]f] %WW9gve&dj%t:`ª\> ]Fދ3C'?E#xs:ڜ. RB#:w&)=Fz|8qxyGO'N"<~Ԥv .>Q/<څX+J!U4FѻCktnݘ!>‒t㐥G4j>AI I|łp1b (|ݗm?2syL.*I퓵X0J}]-'p$Cp12AبD[bP=Qxt8UV*EUD6R2.=r٧p3 +/"x{|Nse_鋹2l}xh1v*h: F߉b4VncR XKnFvGb͵qއqwiF0 ̂?ZO`n8[n؀BeדO~ >jsfqLklqzD~GǏA|I(j6DGʚk L09cTBS=0ɘ<%MXzX7buѝ>Gr wn W|g.컞M߾4 oaͦC$IQl-D-7$UzщD7.@IDAT+t }O_&HAʧ[<O%v'5"$y}14 H!+Gk?7mٶ4"VF54[WMeS&v$ {mκ]^I$ <~bQoN%Kz\ý % IS8sfJIRN*G.oRJz?Of0i?q Qxb.iDMPF`6M@uT&֞}{8.4"S,A6BՍ(z^ VB )]ΆU Nm,7nCD#SyQqFaҜOU"<49{vw0_WLM]޹٠(b=E!xTziڮ(*iCr BφUCJD(/wތY8 -ɗrOSX4Wd}c ǜ'E)u*{7 /NPcI.O)3'4E]z|,ږP7JNtC4zONADT8T <ИG e[SLyTj[^&/x( ہ:),܋h6mﬧ>-KPС3fyonFB"H٪D KIXN?+0\OqI$K%퓨5A7?%O*޲/^r6EMC&F92PX45jǀK/Xc+K2 XCƪWqeһTYF,;z~ڪN.s;2! (Jҋk2kˡ){M`9$QfB$tMja OAJV# bbJe൛oFzCR{.hBx|yߒ}_~âX)*x({ ?h-[`׸k1I'u%~=Y?~>jOD#\чQ89眅'"F ervlE#L~ti e߬U?noVᛏ! ٿG~ԬV-24:ܑ}ph/2![Xc횵+ىx Ѫ!4ӰoJ0sgJ2B(JQ R\ ([+6JRAiW Uť"Ve)f@eS* . hd&$,\˹]={n9Ld{7b809z=`]H[un6f00vl-w` vǣyx`lI'D7@ %$hV7vc\x lIi 6x(|M~.~vT]_{h8]XlJs%¬dzQ!J:2ۚ1HlP,W9WQ1`"?s q Zhc{\Asf5 H? (xz%f Q3ie.&lLL$c(]3qnCtdT)CNBhcbPbtBm<-ҠΉWfQ 2gBTco?Ŭ-A֗GF-~^egאE )? `" Ë\Gb{+I& GtypBE۽;qd=5zEGV~ 5ӛ.4;w$E nݺc_TMv?\kOaQ! eo.:T=G~ 8q#kDMKr9^! 7lDMύ΢I EM>ۃHKDA)"+c*ṣ<#)5g&ġ)$rǎ;|۠4,Q?3yE[n9~a<{ ѬYJm E`Úg05OcsY&A;| 0u5/ 7-y ^pѱ9/;6 N)!#̙y#ůLM s0}Ugq'P? \~<<h6,J8>b' Fq/y2KU؇D@eMY/g[NCd^x/H,IWQ1^1*EQ #L_ ĉ}/}4ƁV5L:[meA.  *urۋV|"("D 2eir/?g#cmwGʉL8 R]!OFj,B}w?@K=C,|DŽ.U!-ϓgA ь 挕d[.]Uj>ϖHy=dgLrC9 ?^lɀQ1bE4 ' {15$AN>QxczqeH^ XP, LbTT' ,D hhN&D(`T1jHh!%+oTQE@Pr~7Dr|͏ژq6(c^YRsÇi&&OC4MH@ .y8/ګa[,-hQ 6 52f9xI9m@<[`<ݘg-xq"s{.rS_Gw /c ^^D-ŨVj٪"ƢEޘ5LB|%]1h)[ikeMXFm5"PGl o"Z)}wm@kI+ )}RцD΂H4\XN_4DRi )Ӿ)H2 dk Q[pG&ؙ~X`hQFaF1(O BʨA4 )t!EzbYN@x#F&G?C=!ͣNXvbS#Rby;i.=/v0Nʨa"1CkȗL佴#ٟ(R#iGR'JIўޜvtE#DJ9ӑbľi;Ҿ㑎wM: XLUr>t~|uڝgsHE ~Sz~ T 73G O(|"n)- #lH,F g~#h'5rKl9CAD,ӏ!lm(!=r,GٖǘJJ')tc%qc\&E Qd]Nc%ðo F ((,ɧ4ESi2c!=P!` #Ff pbAh<_-J,J@''YD(G |[aF|Ib4 o!I5A46e/CIK2W#<8BM96HBR@3"PP86i;Ҿ㑎2߬u"W ~;H:Ϯy"Ɖkw? AA)1d g|qp_F@ %q@dܴ&SUo5h~ ƏqASpra!}fQ"PjD!c("3r=zN3L> ?BVch@H^ +FL*.U(`|wp(7Z5Y^q);M@KvP[2Zml B0r #Ik|D^^Lƍ DqWe)ъ"("("( ك~Q_Cwz:o?g}I.n8B^s% y=8\x]fx Zw6~'˂ŊσQ?o@׻q՗a4ɺ!hFQy- v`îUw!nko$LPMتS:o?.Lmx/`ױI_GC0o3qEjN@5 E@PE@PzIݕWȎi[OI ` @+(Νjt\qbO@K\yg7g'{Wf3xrojoqLE,[j SG̫UƀwNNH܏j6+pqij#`5؂{׽h/g9^hVN1)VZ},$U~OMi4yh\E@PE@PLNJؠeK<oUo@W%! 5d ^yJcCԚ-̹&=NJUbPlyK:3w6_aivO@(dI.uTkZOG\~UAz^Vo\j"}(ڐ_0Rxb*h?ZjE/]#[ ..5@!fD"("(O,O0Ǖgl Nolipo dh1gn:8pq֋"o~M&`9-ђBqS[`^d+0=y)Me?B M֧eWP[\_,u5<RZӲA"\tihP(MA֋)q PiqKI2.tQrk,׋Xs'Izccg7+|ZAaݡqhS^ `m7 'sR)-x^5|ylux&ýCk=f"lC+[St_nYg^^M!39|w{w9lH9X'qqş;Jj8q)K72p_=ڃ\#ETGUU ZsY{H0uQo`ʂ,}6h }op"iAϪ!DoE@PE@P!X:WɧᩆRɶytvHu׃MO]MGËvPg~NFh砥ZaFn\ '%{}1m1piڸz:")Z)~MLstlC\7wz_T3ҫ,_]y9Ǻ/:#N2?La0d>qjBGt)acںĔp߱ٛ`! ͞ 갲p vi;Nuú|1h٦Y5^ ^PnsK{}fPUm9Od9vʎ~"("(PAAS??'!%[0{Y0oO򰉋ț5pcG)܃o Oٌ֒[ N2Tɺ_7=o $t2S'PPϖbX`eMs`s'x] nYl.(H`: xp3|ؙ17زw4 P\qo ->=eÝ0ٝ&){Z3 rOF8 $Hj(Uz_2e?~̂7l>E#ZB WUxHn+![~2Ϳs:r m36B(ݲ=ė_G+d2ye`9̿? )H܋Z Z TMbx?5L[&8tk I2}(˝]TYui6we۝ $, sSH O,C(#dV&%<_w;%:E@PE@PE >"[@1rKܱaH%6#+̖p%e>nMVĆ֊=bθsp(/.r(tL*J/+!&jX:pMu'sL$Ǣ/yc @&\?`W } ?k_[ ï<_ i]ѯcMG[\o?dL+j{{N$܍Ḃb?W$ɺB~o[Gtyx#tq%:o3Ͻx|7CQc9xNG!)aQNc 0ôD_}n 8 <2xgn.'S(g:nEm%Q)#^.2ԫ 3iҒ |˽ b')*`~g[.wW^zeE{9g &X} /Q;> 4?|noHiy&νV!Z q#X͌!uS]&ĴԠ g—Ή qhF usgt թE{m4ȱÑѫx~` hۤVU٪ߟ}RE@PE@!b~jEzbOcN+Ҷزm,>58ty/_>BlKz}1/{ -gc³qFdPMZbEqOm5{ցXsxS\In~B4/m+ V Eۿ&$M S"Sڢϛ#^s#F\*F!K#N.5l'`Vl6/$ؑθ"?ܕNDb9Y(DHB)"k߆˛Vይ;>:rn_@5𛎦Ʃᗳ,6=oe=pK݋t R-ʞ滹N%. 3 &!͸(H@Ua "tݼXc( ^MN[TG! U m$Ju u)6rxm2h|~nZ^PE@PEেjDYN|VP-H?di _GC/k3~$KO{,ݴ x_?:ow>.0?+ovO,I |<|Ғ=zO+UqxΝqcf*j/ '϶\CD\56>{M,FWC-[}ϵxhh'ZwLYG$ޕfp/Py)>`1^7IE#0 Z&2rbbi@P.1 ﲃPQFhDaT›"sm5@(2nĚ[62/qW[.1R}E2~B3q[ k㖡'7dgٷ  p)(_ϭ>cȻ]sGûōК9`ReLf ,D"H9$|kqQyme0-+r5~w'˃Fe%%ƊΎ/P?;Ix޾+Wxuf>WWyzA0?A4GY<~.HzwX20 w%Gsx?")Xib%fK% +@ZTIoD*s "C㡟A><(u $ﰟB>LCv't&ޜ ه~7T_*D\,Y7-."tė0OM ]fzMHk-,gKP>'.cr{Ii? ]505B>J: cʼIq4iHɬrA]ָ_B; {kX|C?mtշ$ h1R$PE@PE@P2O"9;@-PjAE)(^|'2ꌎiPgbP*24gE@PE@PEE p!40}՞'϶\CdORNn(R7*!aU$z7%V.8Ҙ$"("(n=p#( z*eȶ.Q iVzJUwuIǑƴaҤE@PE@PcYW("("("( !("("("( (FPE@PE@PE@PTPm@PE@PE@PE@PTP@7"("("("m"("("(" #:P"]`H!.9"P놡]BJr2|>6m2CMG m ]ضnVm?)W E@P*(oun4ֿx_7tŃ07~ Ff\4 ׋Mqc&}9QLs%2c1TH/pǜc(G1Mjު'N07F!3(ݍ"2o<}1as܌ϿKjxl?v=#_jZtMo!|49j"F17^͏ŧ:ir9]cW!-!G1) ߷ yۍ6ɋ&?[ j݅!E#p1r-xUӒ`a֖^ ew4q{#6]FMyyE6jDMiA6E@ y7i&74'k͡i&8,=~tJQASƱ?Z;*3ʵEɻ,^Uת7zvt?HkΘY pcz+_R-!7n\7hӸ5HwÌe5H_KMmt#^|ЉX?x5HkԴ1h0x;6SfSrb9- W߇r(1F zR-@}S;spȜ88FNZM)Db-#j*ReLȩN_d)zq4?6k:^o+LX6hRyު+^s7a#$x:a4;=ڷӮY9^t= CC¿*PxUqnhnȝ ҷț`Vh!!IG#N~kB_-;^N;uxf/ {\vՓc'Sعa-/~gnEٿv.!AaNf]dJ {~7`K;rJIMI덷*ͭS;rF̩$p2  <1K&xY".qXA܊hYp\\qA"D87jYTm:[$z5rg53WtV,?0G\kw 8qtCE,lDBcNB bLk0ӛX;N0ڵm/n}'V,g >-ccKչV+^$ 0_bjV<1(GiXgGJ[14tTEƭyDU 2X.34]z0紧B<9wՖF@ޤe=E\l(/-Ÿ^Xjԛ`ЛQَ[zYZ7; .N ߔt?~rn5c}2D,:4oD@5 [ )q҉0pPޱ`br[LGL89G#0dp#*$|ذ[hjsk-[[)$v18ΪOzk)&ֶ\\ey>Zƒt]&`P cūI.}vYtio%kt-Ƭv 6#x$o QM~u VTpjJ+^p-w{Ohݟ^+TCnqaHjN?{H0o bbd Nl0kt o)xM7~4pS̨0rRћjDXO6 `dY=ĽK7c:7=x^ ];4=sv[T}ٟ_+ g܊^Ę/N4s=VlibiۚM̥a%|>SHw2"͘;c֬b9ۺ>7ǾM//[M D%L2l{z9 VF%DQ~[ 7#}:Ghm 6r3ꢽa>_[W[0+t\c+yy:~#8k6SmK ; #4SxP ̿ro[@%#xG:1^2l@IDAT#9+ru:9 8eYX媿` `IlBlYk #ZnElĪUoX7the}G.Èyq'F㝝p-,pa鲸QDcaR!޼9"rZ5nտs1_COF6治_O뿸!R)h0qpo%Թn:~%)(4 줒눙 p.]u1wc߄׮pnm٦PKðW7< <hQ⻳$>oَ)ey9ɰʗ~n8m\ 5k*OK6Ԏ)97Vz C46ss[lo2$O^4q#7ϮϴhǹX8eC#y&s\5ˁR];GJhںh!B( ZЪ)o0Uq[^CSU?>&RѵPzSP0G/o+{Q5˯B?xKƋiLx?VsOSR3|1kcq|?5HH͢JiEX'pcKw&0YzJ&7?EAAh .!,i܃=nqm)ܶ"<)RZ5n@8xsVtx'1mck/4wӦ\IxbT%9q.Yn{ W>APaևLH`|Ϋ1kD1bb8 #"L4oE7_XT\6rܩ}}D@jQ^V ҔJVv!oX[sɄ\I3nC$­'M46z7FPvy4~+\vHQ.!AΖ¿#B lTtxXM\Dmtc`$kw81сWr j\'"bwT(_Ix@Κz"o?6ѴC~Q;hN[xڔ}ܕ< %;h<{![ksE]uz(GUŖA(׎kyȜ] 4JAdpetfO~f$XI#ԷK;Z]dZOcx/RvB_ YNGGSdk8 )$@FC[gF_iո6^ʞv`Eݙ99f]JX_M( 4)~:. P s[>!Igo/?!ҾMaw@M[CB}D{.TCD\ۮ#$oDl &/lkoD\clP LT;r⽙aG&_0RVCg|y9 n"pϞD[S4P1oJqͳϸ֮]G#騺7n|F|fZ`g Y1pF DA.Ojj4TM½ ;oM׭s,-D7mF}9 ?Ÿ包#zX1 v]}߷OD>@.bdߦ? PM>!Aޖ r0ܵAV9fx,^xRߌao0o(kS.MUד&mYB-1ǝXϽTp_.?i3.l{c1}B čcdy\7We SG/+62MaՎѴMDWX.hNUx)hi+pۻCqr_8ja_ #pOPAICC&mH5\eC?85B^[9x0)A o弅xe  "+#cf(bH-j"ͮbTkbߗEoYZI;}*>Yb-5c&C]IF\zdr3Z8iոfMPbve]u粷p*5!SPD'|*A1\{-miiM Қ\]|6^PZ 0h#z^ |p 4zOH^L SҘv/F K%-oÛFpcWo)!-P8}=%XB2$bMZ xrb:x$w:.РӉiȊ52@vBH/l5#xFZibB,~>*;p}2);is?r €}#Oj~de5"^_]>>& j+{9KĸÐg搜Í#dr~g7dI'ړ)B ^uI'{.(XG=mGH /[゛hR3*wwAUVzOe'*GKH`FzPi[ݻ/3JosطoӽEGO_~#M1[H@1w$ESH юVқ;+QҚ[ ?Io~\J o2-"+#cfƫ/Ƕ͝tvfa.=C\\8<;'֙EƄOq SGⱝ\&4{w?2b3M},RÖIJo;e N]gmIk1WS5NMN |s8e(0 0۶FIF\n MoW={Y¤]-\Ye.@`  ;xmҎyd,<ԧ]oekyX9*`Z͘𙜳\w.Ǯ>MdkؔuN763XOgwq#P D7ʱ-,'00{)$> ]ѴqF[ogfN7h![N@І܏Ah5݈S?uG8UKpP;^et r0'a5mĴQc!T[4iG nМ4+Hr}- ߘ8=Z \1D wcAڛhBLpld7q8gv;e(-->VѶ~ _|pƁl)˚6Ou[?;TN$æysy9Ac$hc̈!w"{}fתz*?TB?"?g\sR6h'L1lo5$}"$: x͈w1M7'O:V hr%.Mu.آ-zr\/6'D2#{X[h狓>7{WcAlBab_[@.'D+ &w/ےiX7zYE[gn%h0n#FSod/ݶEj_!rJƕB\ {\m}K7 cRIᔵ&En*1l-Ɉ7W^=.oƀ_uEsSqM-i< p}5dE9%-Ћuqp="$mTaG{wuK^EKcߟ:W QM( z1װXtQbNoZzvͼn>FkqzTSWE55mfm~eڒ{ac6gKv`qc0Jc؈$_KW2:M=H2].nX|OH .g.zoC4-͍V_[~OUkMU| y,h Blɱ#Y_b1:⩏> ^ݲ;S!~h7;-CyGx[I_(GT0Q`:Fo*(D&li0 $_6> o R Cqo%NWRՋ}KRg_1Ttek%V{y[~;(E<Q*Ae>ץ ?8U>ú`+CYi1z4aضd1*7*6m 8!9g(3(^&fPpܱR4"SeAi>ց+$hαi psƚ^8m~B4FAA]Ujh 0|U&MV!=liS"Zͱ݀\14r MGVO)ԓԒ6w v{lH?=rI'Z"^xE~k/:(0"L>ⲆL1}i[$K21.s}y2(_`̩Mtb?66 X9m4 4k ho;S;\r='1g&n$y!'$M"[_TD'%50~.g}B#V>;c,k,KFZ|+ &>WVOAMhc}Ijo,<2eIf(FQhomN6 z cm'^}zQꓯynha} M}LCw׿1H%38sVK楖ToLZNǨ${ty>̵M]=jatoG~ 1|b(w'C8~0D2VFί稉5k f͠@4XbsgcN~ovc!=|۸ƇG l.Sдo0i'`3&?kׇnʝ:k2Q$ƊifD\3vBO"g* Z}^̣"80a퓋M3n~#T^#*khJ}X)ě.2z Š]iі)lb5 7spEiX<xJL?9f vwEg 7 0 &G6sJVSEI-Q?ɃϭzkZL?)2|"6OMP3=ny#sX﬜w1SFu ZZN|q[j2(e"5~l^& Ç߅ɳ`ݵE?>⸑b{ۛus۳ꌮ]fnO5RtOE(n>w&/ J"ǚ5Јob9?|=##rS]x掕2~p\ O͋x)71b6$&>sJnp%zv"dJXI^<>aPVݔf:Z^i<~Fed~͘Ձw©}qk t2Ѹ'.|G#иuVVřNZIMmP -kѝ߹)A4_EF w.Tߜ3HR[DxsTߩ ˧`"F#̹쵐09>zƲ͏*&E!JlZ?P;^<?+rvwǾ(6>!t<%6r5ʚ̼,݄iD؃<&5h);N^xOGS^ѲQ}1fӚF܊A_)g>XNm#/L+;HQM6ҲJyڨυ6?U[ ' G-1lW) 9HQyO턇xD6M0c;x Т1{>dSGBvy[ӂyEH=)l$7AZdu Ԋ_(ri?B$ғĬ- q-Bg{W aMY9PW܆Ebh96حr#̂.Y~!BiqE 癁t;]G/rq{>܇.0`Aqiq%}n0߁_x\e 5n&jjۛF4Dmq1ʧA|/ZPiMۋgE ѨD}>rArjgCh P?(SCx3/Ĵ3pwߘ϶E!|}s;,0:Y-$؛ɾi$vعEZO6NA\T}F}?b؛B󗗃 _ibW܋"nزsUUAZSPȱ6u=ǣvkX0hcQ I Jl1b^sV7SΠ/QTZnL]gE*.+Ge>(0q}|ro̳8[yeRIW4Hc MF㪎-̕2j{wngN/U@n=դQ*ӎ ]oҊ2Qr8_Xi Ӗg 7vy֎'m51I709y=bPw ~qO0lºp0Jo \Q^VN!ax}4vdNϾse:N7&:ӖfɒBt'y*&xe&LS6/Giя():\s XAn]s7ۻa K+dbi-漩$xeJy_`W&zb̷XF+o?7$qoo_™ϭ9t Ƴ;W:}9;ass3>!"~LmzÙ eFMq6wf3y9<#IYf!a~z1<"F%\R9 p'O`8QGFS?;+oߗ#Ύ/P?}o_e |cl߳;}xOm?I/w H**LIvݻrTMȣ;w\VI-$j3pZ4y[va=#΃ө9/'EށTyz;{ywS sYNwOݖ퓽]w%[wa+Ws-ΧDF}>#IE]*hӸP V-E1gwDž&RX|qo]8cBL򣣹Ǭ ]&X!KPIPIZD% *6URy T*Xh5ԶPDP+P@^D^b^$ &(\<3;]rwcffgκ/y EAgU_ׯn Aeoyu-ڶح|-3*.Ob!yCόo=]tHusㆻAd0H-ƿ ɫ]ۦ*s5]{?o1/q䵓vi7~\_{.n Zc)@V"Xpw׹Jw#<^]0eЃ8|NzF@jy ToNf4Z\K3oI PZ*YӨeϹk/[?r&>уv[$0W<>/Ũ[= M>(ڜkrJZ)i2B P|q0 (@hY]"q~ }A,;tH0zRɁ_B1Hj}#,sk͸L PZ=h5(2mAD#mHξL^_er;(@ P@K`%ցipw~l(@ P& P(@ P\0?l(@ P(@ P  bZ P(@ P@ 0P'ͣ(@ P(@ "@A ZLK P(@ Ps y(@ P(@@(Di)@ P(@ Pa.@A`6(@ P(h1-(@ P(@ P ¼}Ѽ1kMHKGeY1(9/SWm7܍ZR=Eڴ0*M8JVuvd{YJ P(lYDDDh;vht8ںgZ8qڵ.ijħ֘]NZ]-TWW[e9#ӫe5r\nܺMKBYc PsVZpuNJ;I 9n/-ArzZtEqA%C9H9sV, ʑyױ~Y 6 \ꇠa > *ͬ(@ P=)g A.zBL'-Fpd(H̸2>V%1&@ϩ%}i3h\N0ϝe^O5']ۆcEm3͏o`sq,0nQ cRozu\=yXO-āX1Ei͜0ٓh 595^-(@ P)`SMg8 StJ7 ]<1i,zfF/~d݉ *_՝ƞī6[1rrpr9$:,1Oerܭ{f?ςY,50e-标Dρcv4t5AxvB;!63/(@ PB%@MH1OLBߞ0f[/5 HLF8|`#wk<_^t+Xn}c ʰfg.FѻA({E/}r"krq#t  q̝`ǼcQz)z1 a1o1Qb5P\ )iW#k`%ʷi Su |>v0M Vhp)]~Ơ^jl 8mAw/?#7B;!f21(@ PI@3.̊o nsbpx\~1A16,7iA&MƤXR?]Ԗl}b䫺$#{`، olOy-M,c]V6<a-Sģ14_cm(((Dq=^{c\3;u/~mnޅQ~|~, IF>^"ppMF G똄(@ P.@AHE *ȁqX_l^~%zº9t{SBCC_k(<1x9^N|c|DxyB7flUywF8z)qe 3PT #;vC7`ѷwotxRBL1ala!@9QH7u3oQk[fF7sW[^…|]; V fչ@ P(@&O[[ځ#!_8q+䮪 %}0Nt\k ! 6oCq[n`Ǽnn+&+Kc5"6NecP~pW2qm- DF20ipo,U]BLjAbΊm ɠ\L6(Ÿ x"=ק1hH(yB^Np/k(@ PhV W>}UMڍꕇNv+ŲoXe\UrvCKn3sH93o" s.YΚzѣE=Td+~ZO|ng"pkΦUثmYbnヽ Sk% P(@ > +6C![#F;l^.oi ~Hfpm ` 6j6Ou?ywQR>j,v>#}d㞥F9^ 8q,jyyԾi 7$81#wX)L=`xn*"%JQ}Ty AFy(XyC0OfK,WAD rLql/9S~'m1Q(@ P aǰQ˞sq7Mr#{mr#l>96 j].kivmU/~ekܕGQRR.HLoΝ0jr͞Q, .'W!֝ğЋg+-5+sț1^hB;цs'(@ P@lYxKرC+phӧjkkq knH'Zc.kvmnl;ikv\S]]mͣG\#e5r.snݦ%Gps X F./܇9/FNz~ Cy?ӖT- KIKŪw` =Hdowa9AyG& b&2Axj3o&VRQ]MRKU 2o02#M_abM ŵ$> 6Рx] h y@IDATm75)83W<*Ic??u TE8Yw1#w F](@ P8Ug@cdzQ˞spۭs]ms_;@z "@=B|H{@i 2TUU-D!6.Vj'\8;Ƹ;l@LuPZT8"|ާP%c] -

P(@ P@ 0P'M(@ P(@ `Q(@ PP0 P(@ P@ 0P'M(@ P(@ `Q(@ PP0 P(@ P@ 0P'M(@ P(@ `Q(@ PP0ˣ@ (O0G P Z?er] TVz*PQr7~k)K6b\(۽W{kS_!y#'U>벇"%QYvo{ `55s4R/uy(Z.(Iߠ!ŬZa(@ Pha_mgb{[3NgSz k >^%!>^o$hlCR{kHOl,@px歖 ps&&c]?u/@G11QdOkf7u'>۸`O {<=B*f(@ -Z:/iܹ-> ^U_Pl޴YS`ݜn-am=΍nr Emr!oѓع'z썔7!w}ωk6.Z˅[ͬsᘹ wӓ+Bkv*~N9J P@x у~+q蝙)uupiuCmmjNܕM=)[0Ok]i{~R[?G`BȉpgDqXc1f-܌Ǯ %cU0E|-MUHЊ1FoҴ\ط|E1w{wilk(NQc> P(`Sp2éwp8qH 2l<7q9kFۓ> >{;ks&c(8"" C@ !0qKHj?x\ "d29"VD[}ZoxQLeظI[\x#xPe>?Ѓ!]JSst:yl PVp8(EC?ƭ1U|;R|;|`]PU瀇}1mԫ^K[ 0p;Zh̙z_3#Qo<[ɳ!+PYQ WEط}FgreY`%n:C0kxy  Oۣ1-HOIBUۗ1'J<ϯTE{ndzMWwӽHOoPVּ Mw ӑ=U +Q5/78Ǫ%۟>Nq!()7E|]/U%x V8E; u(ҿ\+ ~ T #`~f7|3 2F=͉1XxVX*n$JHBS#1F4StڠLHyF\p}s,raB 6IR ,8h _>3jGZ1*Yr]ڂ<)i0u6zܧ`=6"^ {ZjV֛@n*m,i< ͧAOJ1z-81ahHDҮ ;w- XwA( Yh3,GY,h"P3A =ܤt`:-+Bϡ[nĘ㌢׿^Z|<<C{`E꼱ڣ nAiꫯ&[G֡Whd=%e0i}T A9.FҍD'h ~%ƨXjQHpcբXv{~QV3YsDn5ODExde<a3%5nSTdLu$aGmeIGwm9;ڵ.e"(3ü֑x5fǨg<K QsyݪC_J$(߀E/y!Aqm'$CžyUy^Ov{~W5v7QMn P(AFjyc,ާ4]-͛+nA@0߾m r>Ce)s!]0b{`tKtË d0>HPnz J,xQѿ~ʒ[o V=^h9؄m[֎n{z"P t(bfL7@ <_K}."'Fzˬ|FĶhq" QīxdĘQҋoش379jW֠ۏG%DڞZ}efo^+ۊŶReQ@6{/9=^ݕZ'VB>g021W{TMAep#0ϙJ^;?MRVh?25--ɮg2[`o!v7ϑ3(@ P_筀E0eX}%s/LN3UyߨM32 & אinmtJlRǨ >wTĘA@'*O yz C1A_<wD$Ы䈈l}yxDtN_3H w;Dх31z!'ƚgu1[nsY "_TF^twׅގ1F@'n\#cl\o6x36|mx1x0 ;A>vM i\@%mi>`ۏi*(ro_VccR'JDЫllkΙ{R?K7AuU 'g dju >q z)Bd׳~WlV;iw#sHE PB"@AH[N!Ux۳jy. 67_G ,+ncyo3ogyD*2sdcDz##F%Y5bѢ04H2+b %hGzex` j}yنUD߱6x#Ju.QQ@V_Hmzw](pXzeZꭎ]<rx0F~n@Ty=%<=^+?-x}9ϭ ^>795xA1TLrܿ/-vRA1WOE!+:yb2WHy2#DBvL }zKos݅i,ɶg3jتn_A(@ )@A--4&[yf1Eue~f%yI/7x  j>g}x0: o\_Eiq6Xc};捏]Cd.7 w_4#YvWL]2HP+b@܉bAQlelr! 'F Ybb"\=)hQS9sBR2Gؘ8uxUJ<|#CPIXkWp;&^?7wr .iY1J }ڮ6j(@ P  BB eZDlMJb?&cK`쨫X>eޝ@[B/] _{b6,gȽZ_bHT W_}ؕoqb͡AK՚b*MI|Bꜫ b`MUr[|GhT^(=u#ƭ7f)ڵqM +w`Dy 0bk9vxQRбI$~6yMW@%U;\lq]e QU`~ P(~ $' F-ھ{ĠhbOC%o|&Cp\vKtC#+]oUCey3(.fܸ`GƔxSR}OÍu$4(Y S6puc B/c N瀐ɢ? &G<̩ozl(:>uVҼah n|}A.7ڶȘ6 /شl_;59Y{f^8myڎudy˒?o H?}F ؽqY.SO?G<(@ Pg@kvfƩ^q1?ʺQtyCag jtƷ?VGψnOMWGARֽ>_8|-{~|_>Vihŝcرw`̝wyA7>^oͲm;l1ky|h<Ӷ=O [z?bzF`5a*6sDrvHP =kd~_5ܟ|;0exMnLʿŤc ~ނ0pf@K(>QyfUSR&*jGyjhBTWnlx.ӟ4'yd0jB,0FdqlsQ`< _( JtJOwq,]޸J6y#\OD@\U夊kOBc3xQsWŵ5e6gk$({I8i<ɼYUyA NBώwa](.-?=P^.ڧίv=qj~WYnPyu P(B}D Q˞spۭs]ms_ 'r]]岖Flj]{~zNI<_(yj*᪪jPUu#k/M+Ka9"T}(ŚӱP[&37D? MC[FW>@tSLmYtaqv^ybOhGeh8nĞH>q'Я$*1n/?X!b z jUofP՗% PزeaILMlǎZ!1Z\#nʼn'Ю]"|F|_r}vsYl;ilrMuJ˹cM#e5r.snݦ%G"k9Wr#{mr@IhZԩKG;%0QHF,PWk^> jun7Sl?,~yD:yjӱbepVVh}S*G>͡1+{k)E>aKo G {\ @s }C;tH0xx|5 ŀ^ um-c(@ P0PpjϘDF~qb$yN@KoLn?mX3DOXo։(@ PT0Pp*y P-T@ ʱZ(@ PEv(@ P(2(h煵(@ P(@  N ;J P(@ Ph ZQ(@ PN(@ P(@ L Zya(@ P(@ PE΃R(@ P@KYs_` \,E P(@ PM ?ts}ẃp=l(@ P(@ %>AZM;Ӧ3l/(@ P(@ P* ݺuѣGQ^^풽 T֚<(SR(@ P@S2XвGδig(@ P(@ 4"@A#8E P(@ P8(88K P(@ PhDFp(@ P(p Oi2K P(@ P`8 P(@ P@X= 3uaqu(@ P(pΈ@AMM))@ P(@ PQ L P(@ P wiRçHQ>-(@ P(@ -@AЄ,(@ P(> ϹdK(@ P(@ PA 0P4! (@ P(@ s. P(@ P@ M(@ P(@ P#@AK(@ P(A P(@ P@0P>-(@ P(@ -@AЄ,(@ P(> ϹdK(@ P(@ PA 0P4! (@ P(@ s. P(@ P@ M(@ P(@ P#>M9-;)@ P(@ ! iij&58&(@ P(@ ȹﲮ[q(W^><H&(@ P(@C֏Ly( cgqLF P(@ P@DD%|s UAƏ☄(@ P@ 8t, (3P৫ ɓ'|\&(@ P(@۷G܅ɸpx9IK.z6~ TA٣@ d P{(@ P_Oå 3(D3g9rȋPNr}A32`k)@ P(@ P{VޏYNCuΘCGZ^*P $3$(@ P( f@ޛGA(T}mXn;B P(@ P*z2N/@*H~da P(@ PSb|0Pf^T(@ P@ ^y}=KgS(@ P(@3X3(@ P(@OS(Ь'k QPPr6X}:m۶袋н{w/9)@ Ph5 SŊRh2@sN_BeeenR{đq:+ѻwo ΐfR+@{r PL@ |M8e? lݺm݆6mڄ ,(@!1 Zi`%(@ ̙3A09eee<~x͠(@ PSOS@TO>j2QPUUCq:X P@AIY (@ (9&AS"jp ""BmUy}˲l9dl9ojRet\RgTyj]S_[eٳ@~-^(@ P GA,r¦&y|ITWWC~S-?rF9o*[YeuS-m2ʯh-GfR6\.H39Wu>-uW֙(@ P%u> P-F@#ꆾᎫ:c=J$o7|-}Ml.˼ն~t׻?l{AesyL-(9LG7Ÿ^z< >ʲAY7k//moqwl0cGZ]Ud U?Um.'O}-0o'Y˶U|C:xkjMXk\db :\os,Nsf*X8YN P $(ljR'/F4u o a߰H-xnj1~Oj '>+ݪšoETT^Q7jYGNڷг[W!eɶȺec#$՜T*qX=&&*i= TyL@-K\Ci\'&VvUGUk!(?UOd@NߣqonQ3 qY1Z$E/(@ P 0P03P?M&7MU?FN=A<7x bm+U׷q3qCr}{qVٯAsAsk/$n-eq x_NkcBez;:_y;K~HYqp|}7ny(GۗGѩS[i okzV\'8Nm9:acAh8?h3*zW*&Ϗ;X@yCX>0{Dk>%6y ~#SHj_+sc9<|'raM,Ewןo=Y>Z͟Vギ(>t:;czx\cًۿBbh9"[':_t>/*@DMƏ9oGeHW\_`j6&@(@ Pu pyXk P-^A 卲 MkՋIX<+?a8qGF jq0 *}Koăc#7vѾeWHq &,$_OC$wȻ@w'nn\7~3ʮ8^̱/{~m۰oD=/']Ui֭S'Q<1u왎Zp@"6k8/+Wҥ+d_7ʁX}2Hcu9 )XF$"٧߈q})FӂU_] No1 7b/FiF}-.A _twM)򉂊x[XxsʫETg"HP}iAtܐ.z}l݅1.Fq$C׮?LbWu|6C$9/W]5ǎ`ڝ(ܵ] OMGzy8!*F0(@ P0PBNA PL 5uޝ8}+#1tm~=}~QvjqK:8jjѳm੧ڵ[?|Fuǀk.ң;,{1_6[SϽ2/emy4~{1w~$fVĤI3Q( A\z#@?7վWcop_Q?b=3Vxj̽ϴN;-R7ĵݜ,? ׈ȶ{NF֝1\у"} :]аZqQXb,9AL49' qoCeuPc%Hqva'\s_$&M{íggzbb~mЊ^>Xcp!{EGG)k?BABנ@8. g?꧚bU#D Lsv bbFJ׳]M .}99D/9о̜SZtZ@۶m Ȗ8I|~3Ktf; .Տphr~waJB.L68I`_:!Urq $>I}>=DG}۷a!>j;i2wCt;$]oXV 3yqx˂[|ݴE8"EA}g- { U" .i_Dܹb{oh:/ŵI?Vx^Nq3c BGD vCrj˱1_7j14>.>_!ҼDV?`AG T6i?;K@C(z柅/CKeuBzz [a_"Z&Ji m44[ (Pwiʷhr9NV~{Y:EcEbAOn1h3$K0{Mƻ |U \tEZ>R;mv .;TrXD. 19&fp[WZ$%^nxwIĘ{b)zm$^"HP- H"6ЂүLRn(@ IcQ˞sp=69{#wgGW116@ZIh8+*ABR ԫJcEtZc#NjuL+$%G j GW\ܱ "~ .C/gEUѭW_1:D ݓEEYFo hL0-m1$ԡ 31c]ITՊQjC-mO#Uthe'd9G`DP8,\Ԣ uX}"_ 1qrC$Vh5/"ʎ*${@~[!HX@IDATNAp?{5vx7Oڗ#rYt_hiv\S]]mͣGE#e5r.snݦ%G{n[ӨeϹ Bn~vuM}}(.Sh[l֭[^׺?dy,G#[iok /&?_p>?w5WxrM2J˺r.u_%ɏԲ#smiAs.ùgEisYO҄Ǝ}ֺe5ڮ[ȑ#1۹L P@x0P瑭(bڴi;W +}-"L*&{q dHB¤l(@ P`@ Pd@,ϴo9>yS= $h}5(@ +1 b: PJ@ 9nAaa! P^^u!ڶm DQ$1 (@ H Zia(@ .?, ŚR` =?)i(@ ?skL P% 4AS[rZs(?$Y}O_y(@ P( ^JDf T8=]j?(@ PDuy{Ss0PY>ek4\(@ P(p& X.彔*5?ݚ ),/F_YDckc< ɯ7|cL/{ۦsN P(@ PLP~eo]=5gݵHl P^؊[êS(@ Ph]or[UW[ lsfm.s-f]yr-:/#Qs{k d& A(3(Ni|֏O}CjETA!2H%@B ! do_k{nν9$ѽ朳(WM 1=^9*dœX+5u%1?ޭ->gcFu=ͭV ]-<~>SDFOx\>3-W_˷hv xÊ*) ܚ!>@c=˰kYC pcc٣;cX'DӖ̄OdP3uE * ՞cpZt͋ -!vAD@" H$RQpo7`Kv 7\+f3/PVV("\!* !|D؊BLxg W->Sf2McG 4 u#/T:hq3&&˓"* % :l3}蹩 İ#*) mXB VxXAu+$ 0 =pt3Gx$39!}1HZ~ţcLz I}1θ"]G aqL pScS1Ӽ}VFK#>z)tĠ.`g\1!Z5/2n+?]\Բ2ZG.D@" >";>q1d݀- :mhkkGx?R771|ȋA3Op@A?I~]eV4q흷\N;e(stAߊ&e˱;œ1kZdS3*<5cPm}?Zw=>f ë!BIt:^8btPx\w/ǫ)!>xER"C!슉nr 03&D͘"'7|x+%SRџ&0GxbyBIP~։ u[G%P: @<5ZQ4)IvV>f%AuL}cnfFa1(h1sF5+w] Řdɣo!.gu-]:1kL`8^ZʰlF!.L0b:BDPQero&̛2L" \MHEgfu"A鵵 /2᥏au Ex؛_ mcli}w70{^.5UVRlZ2~Ƽ]2u*6u&%řjc^/6*ܳό"ĄiҏO JPk~Z* /?2M%GX$26b423k&>8'"Vgk[EsN|rA(فٳI>@+ϊժ(Vckiʠw lxb\gK s'',(;Vf3~Pq|pk?_hX)]VlUd(MmWdt 310*Q\e;a$e\0b CZje$R$nC< xkGe-2s %ȯVu*oF&'; axDncaDd .'):r(cm>bUzR=I)zE5|\3+IIџI|t0W\Ad5M-ؒ} GK鑕~W!\q~9 &bS gJݠ .3 kA Y L6]~B%<&%AMVmiMƲ 7),BIqҋo[epcފq!xJmec#$1?X%Zed%AC6:L"6~(֐EG94 ܀d@+t5BI/>9)38]1N8Jˬ}"" ,&Eլct'uؑuCr)$'HN:.ư}hRh1P&sqce0uu|9nGb &C#bchlPB*:\D Go16i釱{S=^9uB<_n/HIЎVR s=+2zgK:~.s6QT'W( +ʐWCJ:me^=P^'7`s9w8EUh3TQ4af0zP'D߻N7b' %(t=eI:-3μs{*^lʑ7=_q<%O+7MċwǁGa夞ĉa~I,R{ާhBL 6GSg&@֬Sj2.07@)a4^X6_G Mpq%ʅլNLDvڌOS^Ld0+?03|$7&'9LF2Db85&s)`DRdRySJZRU#l2F3k,lhLe"3d=QK"KFb>)M,P-$ڟvkY܂~~޸uL<QXRıx{Ƒ1Z^" )L7Rɨ=B-0c( Ϩ)2S'?{UTPA)ּ m@&FxMv٦s4'ߖyxV͎[wQoJ ",a&O|֟x aɞIkCE-,E"9" -5[/ӲuB'$ Uw+ 27N,7̍%eq՟+5F|\1:Zw=[DހZ|k5'Q- &GAG/pv"#әN.|0|W.ʧEyr4iq5OZ%Zʱ!ؓMA؝-*Ċ'Mpr?x 3IX^rv"v=+ O ǭҺM7CqٚH D3MU: |;II ^Mx hG,lWp!bs }, 8ζv ~8rwxTNE_.7U/_݅tf#:x K+v#yA>5#DXm˷mTt,&K4&OZ%~bBø"/ίaoHg(KLsQ2j(vS30!zZzXT\XxqApgY4XwۥLO2icG`*Mi2ɫ5؝9IC^yiD9>qHjE-H|=FvesC!m l)UZs%.duذi/QK̛vz!Ҏ|졭13?%8SG9rSEGɜ/FР^)GGshpO>XHseiAGxc|Y@>5^qm~2Y*?W665Ef?qBwvh<\):nfrQyQQxRzp59vj~Yؓ乳1&< :(L雚P\˘y(*40 3}Ϟ{v!]G\/xLUXb;i<?ށDa@/IOZvAi/,ut_u.R٬&% ,/(4`v,0ٮ:+ ,WMIEg?:Gmo/mW2OD\>f|i΋Yea μ"I0dM+Ÿ}w9մO:@L~yR(Ȥm2Ίd󤯾ϊΓ:vb2<^܇Efg&q,}EmP,; >r(G( OR]9ٟ##~ O M6IIj#H'kWY vmdUx>Uez{aVecil[_aDZB嫕W&ݝq`9*Gy me)2q2ho :_*ݧ!S P7|NAEE1Z7i}YLBtQwqA&fAqd:V!@ŰqrkXq$Xq 8JD0 W]49 #|oxk|xK"Gpj@<0/JEs)Tc4YZgF/(c (bD=ڕLFAS'JiC1~6N̦ P<,JD;w?6+<6?YQLfHAnH=f(cjZH@02}k+юɔrAh~ Z,@;)nε+7WdQ_38M޹u_ˋ.fu{O.u\Oۚ *yp .y̜81Vo4^2{=MlJ˕%U⢂BMkgql‹Q/Qp($HRvkL+,{bdPijLǻKXJ[n~iZʳ!"rL}2 0mB♯s<3g8ӈ_d$NպĶ]AOe DW`_{c.漘_zG=Iu;gD0.QZᰍЍpkn_ulq¦O6b'/k}q$,բ2۟P<1g8T$L|xR<6P3/|h}rɲ&S?2/j4jVdŒEN2Ghg}0f:9O(cB#&}d"jP]]mm~ MmQ/c;A(m9OܔDuჴ n3sS}uD mi\ ^:ѝc:% CIn̘DM{wSIA3jSK)GW5_c|挵^?}+Q G - fgߩ>&fԧm|ͨ_0q;WG$tL%_:AI&v>΋l/3b}Z_.=M[{]ĝMM&rvE Q0Jp-Iw>ӯsf3X}BЖ⩄Ϝ&?'%B)6O.>67GcՁl$D95/9giCՔ?Y-x3IQKgM'E傕 Uᄒ]歷WeU o ǙtV00W+J,@pnT&j< bTNW|:E-(*m.z >ҚծÆˈg%=y+ӹI$=C3m*_cgՏF?q_-{zT}{U}VʚгKՈF/57>F444`15Ek@E I_ m׏jLޖPVVzɨ7@ v}%g Ӡ uh2oBjC1#йn^O_}Da6Fg 7WF_3h;͕yWO4v{b6W:޵D5oԞyԞ:O_#^rOvp Ǻ/s>˨N`͜ R8` j`R3eVcjd;F_3b%>cːN61X7 lܿBc"'caFʮ`" V|~(Ye5F18PP)+O Xa"!9LK3H ry]-ihh[xUk"صt^H`[pZuX<)y! y>GǓBDG{Sm[i~M8՟3cvU&":qD9TyQVV5!H02}t~373}w8;K.@ *K&dt\@I/Uf4&,E! `Vd}1d׍TAȦ=-nt_cD[ J!l~#6Fn8B] } ؝/e63 VZ zI1-Օӏ-hÍi pXk]8&~W Еdm8?KMvu1_<aۖ w}RS_KX:+(X%%W9RQ`W"JJEZ\Uj{t7,Ĺ?\gvvUt5+Vz:>V&lٴҙ iF\ qxfL lm)W UŐiF^O*|hd/0A0g>Ox4 L|>0g:*\/$J pF8&l Sy0q)FsF~ݥaRɦs<>sLdсz3m.$M" RQVהEܚIK6| !j\r\_yI$Հ@IQS,LjO؛O ^ _+V mj]{u" VQ}o"%^Ka5]kb^~YOsD>K$DkHEApQ,n좣зoooo+?@ƎBYYPp|ފp-oCh.Di^:[i.f>2.H}p*!@eϴ_-u,gV) .s_ U^.S;oZoץIk}.|e5ζG) Vִ]YSI 3 Sԧف3/[W#}_eG7qI {;*R=kLhDh7(OXkpj.@ފcWRRSS:h9Š/,DR9'YmJ3Mtfa*E͖,| Up|}:S4ӷ HMN@N¬NLȸSYiD@" &RQMv$Pv8J܈;c(n,tv[w!CplMyjV/%+^pM\<ԻR>ŋvtXﺼΘ_ yu样 ]/54v<)|& . r$Y<%)cxmm-@paCn7i˅.y0~W_X^,_ ? Wa=%;۬h8V( >[gr'ەɬyBI;aܽn?Y|O-μXOoJқcZ߯D&bH`aTð!&4 ׭&d<0򩗑Bf ܋Xd\8MBYCVQ'')_!;1X z~q-1 6(հƍ0,%i[+jk`L^Ļy3[I$28ZvA7o7P[ /2᥏al aaQ&,Jf'!24Sk^F0pm⑁<۰G3 Y@_F (NW琹X%b(9jc;0h F<,rm,խ_G:t#W0]` @qG_KU\Y̷^FjRt.Olb蘲 "w-֬kęv!l͘hj^DjvuN=K NDpk^ E1ICfLQt"l&bc|DzlCI9#+0xE/mV+:;֦SX\p++a RhD=Dsc#*)U0,-¬zUx"i y Ee`JTfaf4Z1[؋2ѤOmMz+ ^1vR_%nƩ%YUfO߹uЬX+ڜ ~;7}ջ@7_jodžo-싒Ok%291a]{Fmk 5oX^"T_s/]][V"GOҪiOmƆjWǰfm"g-ŴUZq웍{?bnamWZPEG@~"B\XX(g+o&hJlE1W.JJIK1W#iR$Z -5$(C}`(JǶF%e*ܘ7 tjTJSO ''ZTڗHI1 #}qjK&Fc7JFQl@[v ɮ_@) *q,xdj]v8b ȄF &C8b'VDJdLxa$MK@uj~{yNS2s|.0ICiehkAKC) 0/)ջ!}W+=?Y h\]0ZS^?)KВVCv}T~Tp$*eX·qӉ̀N{w6tiBW>rtF"4&HK( !!H@U~<HDb=S?˗cBR M:-> &M6mpB4`Bґ5W* a H_O?O}t뙿Y_O ~} 坦_Ὗ+~(<}DnFTY#eM|?Y7ɏ4,̌&o*lo;f+e猧M#~rמ3_Ee$WfgVFfafuЬ\9ΊC4aY;2e S0/,9|9962uL]1rF5~WV]- C@53z]YkQx o؋:R6(qeEI zmԕfcNuȏ|:N:% XY0chjgL׎i!' ()e1?}Ȓ9wv"6[60nGM }GȦfLr rإN;bj /VQ >+Nf`-)-( @pYlT7߄kQhfo,2-)-\̘4\<ҳL]~0!9I Q KqMHo# @IDATnVQF9-7>BRٸK  Z(n CCm òf]۸tN|gō1u9rFKSgWA"v c#,R=Q/ܨ1?s3Y.mz/ɴ'yrS[ QsCyQ..KNg̎;U0XiVc^lW#s-}Hf  eLNnv|q G ,`5*"@ )&a毦93vقO ǽ1ˏ{ښt0C0M3ԟWy (\Ph.SJjJӤT]hbr(iF?K6)i\FIubI %Z}٥"gXd2 wbն|xyDq 7!1 &aH1d5bX>jG߄)߬ZLJ8bprΊQdYD%]IzlwF?܉Yqr׷8+vn0ACa_QDg9aχ[4cϚUѡq/wl|5i^Xt߬AZ[,EE{VIP^L:PQc $ J/#ZzLߓa߉Y:%' CEOd-ȫiWMH(h"nN83oK;ͺӶJ-tqqˁ V qu81g&6Nwo5cT q: fYÃeTUqZӫ<(~TC.l+4p0 iTr۝WO 0-FZho,U;F,BGãa-oB C_<2E.HB~h?)>~}':j^M+Y$sOnw޴m^k~G Qؼ1(6@pdS[8AV<$XNdSGu'Sb<4;z&%Y`A2x˖?H+ ͤmocLF%/?)Ysk%} nJmALb r2 @eC fuDϷ3".1R,vGޮa:O%베 ʄ\L6{tx_y$(F΁q,$DtR̸: l}Xl<^favN7]p>1nZ4) 7q~eh̊!7'Ҏo6lC9M\7WK?d%&%6SqtE@c؝=Κ@3*o+\a~! iz ḮXx/܉7! A+O縜dI\ c&u)4,~~|+`/_AqYQ]qXm{  S~#k輅R?,Xv"؛?ZD=[A ؿi+h+e60~wvĸa~(͉SESnmE hF+ 1e2[Ncç;9sBܰ=8)QdwkCR%^Ci(v;ؑ?/V(NWqa2 Ե!ePP$L_q!vvlސcRGUD'W-mu֣>s1fo@~Wx##$e! )ç["nw NӡvǰZ;{ }', 敛rݫRs*) 0rH=O7Cs61kuΖ֙q(,QOKX^zY*N'Za]y;_U]Z\8uDX}9+uܮ,ЫѬSXFaþ"/ Dc}@ cՓ-\8 na4cbbӇ궂e<_30nz8]o_ıl_<F N}D^-jo yAkI˳{ D便{ֆP_$ISɯD,ۣP 9 N{G?`C"Ċ8't3iitx1??+Nȧo"cHxڷv ޜnEqI440].ePuZI4M-4Wub>U TCUD2`ٙ#N=Iu=Dˤls6v:z|wd`//;Sy/A]0aSyꆝeڂf>Bpտʰ;4P=yE쁶Z=^듄inSea3sWx)AM(?[ IJv+)[Vg mj= ,JnPZ*$47eMqR"= q:gYQ%&1;GDc㸣KWFCiF>441[_!W( @d\SaMw4WWK_hDQz@JKfP~e07:h\~H~#>cڎN)[;XNu t2q 2 |T{aa8T،,%ag#H akCX-8-No1i8S/PZ/2unF~A%Kh32GQC\`,emW5:'b6+'A#vy͓|@H SdICL j\sf[QH3NJ;w:'h#*eTAJKh5ieHz o]Q FXܠ_l9)46lkOt/ƺT=*hV:Mk;JK n u m!CP~':QU}#%kh &+ãtaa~R:rK 1s"r@\9t>eS\"UHm:r2ÉC_7ZX*/nVEe\,EUJDNZ-Z)BSkkֽT𭲠ވټyy҂˵Q@WEEtMxXi;xbB)Kg\șaC_e-'U.Qfs3rg9q=(@*٫٘XK@@ۀfYܕVyw# p,Xa }Ϛ9zG~dz-uDڋ$bct*P(w@5_z"E'eGӋƄQxGetioK ` FAL%YB> ^וuW|xG<=ѾkQImN2X^?Gy%x0!@{xaS!-I9U, vYbo&sjl~oy2`jmnCӶ@oC3Ac9N|R=>({ mA0-Eavf2gyK*F|:TOpí6l}6dFo j=HZ6#:t7k+DY;zm$sv,S#;Ah^\;>7Ф*aп?2Zi/5ڔhP'+գ8[ѷ^iH|70 F4]\+&^< 5@DM]帑:2{jlby%‡֧sQ F'L3sV2m^sguc>O0WR:ϥRU=6qJL4=Xu)r#H}>\6(-&-Ţ[bIh\~m0*#{ ¿kT?‚Q9̾!;Gvpn+Z;J0es(vWb%xT^^BHKgjaQa`Z/EG?V1^؞WaK|M x텽E_2[<,3jq6)! IM{2 2KbtX-)n dr Ve" 5b_[Հo6u/|633ӐUEIJ 2+wߨ j0' b(E(/x ܨ,XKO;= DTNTV^l:O3l N޴;~Eꂐ3~rؕL3MāVVذJ+*3I),Us;agP7ʿLOwd([Y*~rU eW$|cTG:Y:;2o'WN]w9.pc1?y;땕Yw~GTEƆ>(pTK(mWl} SjJbA$lmߑ̋ړ([+-b/~K')72ܮtj࢔63i4f.5U,;Y)NODŽPG3z4x>hsrSH?LyWA됡wu'a͎B[6'"`4`}Ls`V=n8ޅ '昙k m,J4Oa)7;K`xx, &E5`k}sVq~y%h}Cj>[AG;?P3w"w&ܴ7Eq ~^''13lvYB# ?țw? >hĶV:.LO ]%ӬT>jZYJ֖[<9& 6>Rʰ ]3zد鯨|Tݵ|n9y]'fuV\4!zh٥[(2-%3|~Ut#Ӟ7]_cqXp(FEm8V-aoǂ6Nd[@!}٩|L[YMg? GYKƎW:U"\cǎ aooxyyb| Qε @; 1n󸜝JKܐ!!!#[? W#=*C꽕4=_~a|OW%9_~"sUt8 IXRTU?0^͊,Xb2fǖ?я$ B-hxt#fMJ%yQE!=z&Kϛ)DL.+u#]L 2GGףNy1k6WcZ70|i:: h:y8Ȩ)vz鬥xkJIEm.ů)4QcZշy]>In MN98~f\pss#Vqov-0[:JՕvAB#7NXxNsW9g)h᨞|)4brI:N/(۸*DWy+1iDUۇ, y^e=V^$Бp/R aQyLښ; /"tƟ#;:cx[Z=IkO8{EF M9KZ^rME3vީ澖.ˍ2۔TUu:l [@ѩ,6KpC}Q񳗟s76kl(JZ6kkNzQ* DWp~V+yW.OZdQTcU?)E#SWG/6y'>Pu|p!I ^%/Fjz.u/^x[1/{GN51 |x(~cKnl(}'߄Sc+Xgg$3^{|ѩe%tg`$FB_/iT^˸z Nj^znRocХיay! `Zd}1AQ=-.m&eI])Oi)T)Q*m"g=zW1 ond (是=ÍcmѺMmGz YF)7/<4'C{Z'ؒ?Qڱqg9.fy\k7:Pq}ƻC'1s(9EyLATgT?/ۗ:[7R V)^.5_WJ~nTOx{x%JRUօ^QHJ賾i ,j֭e[ُM.c1)0Stu\^O7IbbvʺpG" *>fa]kGD[_/z $"Jm$.\+2ޔ!5"%=E@* zL'H$D{ٹfaW@d=x&̗+*7|RWMldt"`ۈtTdrD@" H$D@" H (F)D@" H$D@" HzFfW+0_/$8?xqŸ|SXBjྂOO^5āz ہd? ~@TV'}C|ZS) #񮹹"=q8i| +(\?>'4=z_/(Ѕŵz*H$jd=@d? ~@Ӕ!~WGw Y<D@" H$D@"w&UTgl01A6p!nJBĪ(6.,JEl-ڗb oVm( YhHr{;νYHHs>99gN֭;ѪU+YDcu ^}? B+ +4_uV^@ `+++CFFo$3M-Cz4~:@see=uGunˈGS}_=&Rkk)U2 RGA-eY{mHe x4 T@zc>s>sρ~:t{W(^ufC3<犂x>@_      8 PЀ l߾}R1 @Cv vZܹ3k׮K0x`n:      h4|^x?~Fij4ПFqA$@$@$@$@$@$@' MLZf2Ji&gʁR;}vAV  nj@Pu:}.^ \7$)# GA֮~n+ u YY #Auu5/%% s234{ı2n[PYLA$@$@$@$@$@$p +U?' t%Av퍒@٭4T},È5]}\J9s&O{*0jb.AHIO~r6DY`     &O-5kWt5A p>9UL}e;j  nz^ xw?92{榉 =pOnFTqޞUWt-'CeXEc ]`s_ kU)zAQ0{zI U E;m_=VQ܎W\:ZTʶy{q~,cȁ"K|(2awO5]mʳ>JsU>,҆x.݄+1 K}x{ Ѫ:[W3$   ;(;z,**2X{ ֋Qu+*\*PCB{*PTEEen1ExW~*,Ƈk],|Viʇezkn %h/:SHar~}/m]bUN|8eJ|ekRV}evqZQK}h#@X4Gi j/bxڠ=h5_h;K1Fև%GY ʋt"p(ڴ ~cr_WbϱJT'ʫ6HIIBR|}<HHHH{dnd_j,8z9ξWfWcjPO qf5'>1 9e/O/|(t'x[2I Q$ 7en_~{nDVt=ػާnyZ̝KVᦇEf]^{ʍ goۑ KCnDDbmƲVL w4<7YYǖe\Z\w@ݽ o]د&7-3}s98xe[.+jg'e~$en6l}% .+86!߰=@.>fF6*>peTg9"!-Ml{t!Avov,royrԬx"9:t:ogH=Vܿ?ؙk0+gZr>:cՐ*]}FX®N|㷊00ùm7G-!~\\ ߞr7 [xM턳2)A$@$@$@$p2pEɠ*CԽcj *pU nBzk?B_azᑁ3NOB@ R J|/0_4-(Grq~g)qBF|aR1`]°+9o/*e1஻nBߌ#XbY,1Tꑙjba$8a%E zEk..\)ו8.w Ff\wf fpdV| RS^ыj0bX.^OK8TH Ɲѣ1ص}ff-= 5Ki>iC0^Y_B?_|$ţiɸ!9z n7wLYsnH T#+ߗc)ژaȇ!f.ϔU!P} |R g] _5tN³/}xg\)=~̳3`31\ɗk ׼T}^\>vʙZuOu Mz:P% D=0xXO-1uC &pn2n~Xrs%E857<2}Y6euAvpno6KNd=fHvֻ"\o{E=N\/7Zr hc:&:\(̃Z>!O uO0I ݻ  W`7ҎbҤ#   h.\QЄ/R#2p%av==Z |cķ5hYs$X}vxK QuZJJՊPgޘ9F2-1f*7D`wiν2c`yQ-ˏup+l 0YwY{ex#(l9$Ctc_3 )*_wIm[嗣@j&Ur]K^ZZe"] m۶EЫS;;`dwN+PWY6tM wd:\XRSG]dubxt`pm7Qz뭣XN2RѲehcmXa.%"a:)vTV^,aoJuHB|FEJpP< @Oӵ\)8z#˺e<>Λ+~n' 0 K;?≏cWU,*х4}Gs!gb WgGŨP);(3ah^tu9ߨƲM|S9tw 6ƌ鲉aBpb5(^M%27ཌྷd`V"kiFݏD76nA+=l^~56"KY)_/4:.cSZC7wAu2g[o#m)Hm]d_(kupSq{dsKwHh gU׶myͲPTjel/QBĭ}$՚ރ6aӧ`r,uȂ ջ[DZ@$@$@$@$P?=ɤ|Zn]YP\}gZ~wo?b{}Ia@DIuFϼsO\g#3U2hpս)^1J$ʠZ7Ryu>Z!d ~@f{JX ]o23 xc/VK^J 0޽ϭ2ϳroA'Tvh=ޒM sKϺ*~/|k*1 Ig}bm<5rKGwo\e3c,Y2t<^Z"$ob WdygLo&vƈ.2xm5okx!f̍--jp2T!Uxcs:K{{L; ۣe.mo|a n;Փ(\H[ ޺\r1Z]ɵ2{ft:P otK/Dֹc:í}ȓ5'3Dr x],EK5߻ q,#   h>ƊZDZΣ}mH ӣL'e7k=7∿q8߷E/k>(i;Gy#|x=v+ Hp,oz+/<, !2z;%[;UULmlJI1fߋVRcJ2II1T{DiYDCD1T(3G@&Rb[.3 1!85X W!& +KnrSnA'}l8@]VQ7>ZvѨG_1V|0֖5$;]+"zr֟CIN7YKCo֍{[*0kdjm'^Nq{05TDSsF7F75۰ut?j.t7%ʨx=i ޣxA$@$@$@شi+Zjd$&&BƈJms}<+-=(+-G5t:+/k\cCfddFd7YۉG=q ׾F2NOs(^F\=ψWDi\\r%(,,Ě5k btBݓ@?7J+k7DM_F)tP%=IlUr.+ʌ{ɏrKj9e: ~#",:QF{t]Qa:s\76#Ŕ|$ui ԞԙeeiIeDjTEqI#i3#cfdf,cvgp UA$Vȹ1ЌI+ jN: :-AYok]c;Spj7jt|m\"SEl;U]qa|=UCלk'UR+DXm:jΑfgV:ixj[QÎ{4'$@$@$@$@@@ks8y4D8GזutфN]=x2^%+ebE<zه2:"Y bQTˬذ窫vkޔ-Q%oiZ5j!#   J+ ڦ.Y?w8űK~പ!V؉|(xdLuipז(M/ f$@$@$@*8,<6h5M3MÕXF ;BOčAQbsb). |+~:       0PPφK[%<@z>s>sρz%{ u`m}bjmţ9llls>s):6XGG_[~zt5_=V\-?瓿^^^.2t$@$@$@$@$@$@MD`۶"$'_2ω_Պkf:k5.ԱaYY222~#aIjңй7㈿uӥ*V[?έxq~ꢏv?#B0H-X%UDe0 @#q#39{X籎vUbaֹ񿼺6%c(B6Ft`i"r|9|4sR$$+ t߾@˪ʑ@O'MOWO2 'Q#~o\Ɩ8u9Wqxzn9srnNqtPMBj֒h"SÁ:Ɂ|9|9MxB D]u䩍Qj:tPS1 q5&;Ѽv4( ņpdj!d9  @X+5~GNi\޿xܘPP bm~>E(;n Z{%k D Z/xo9]l1jCEj.7߱ %%e5eDCQB$@$@$@$@$@Q p$#5_,cA( O u@ 2hU֥+z?p`E5 XDgat$@$@$@$@$@$@֪@`Yd.jl4ԁe$՚U?KPCsʎ'*#    бE``Y4~@KLHHHHHH!x azxHJCA=* j$PǨ$@$@$@$@$@$Px˚ձ 9G%:ӆYQQh qb4      Ś: M uk$Gw28HHHHHH&hư鵎h(PMh(_'#AZZkj,[HHHHHH>8v Ǎd֤ϸgA}H?. u`XRn6mZ!%Qv-IDAT 4Nʶm*c ʍ,t\3%?X_7Ш4ԁ @cHIieì3ˏ%@CA=yꦆ9HHHHHH@bb"jXB !'gzc3HHHHHH1 dI9/ ЗHHHHHHa==ȑ#غu+L=2: @\\z聴o5< Xj$޽;g#2eV$@$@$@$@$@? c5;;QX yBh(8!|s\xE$@$@$@$@$@x*V<ܣ9{( 4+ ? '      EUHHHHHH ͊ @"@CA˪JC$@$@$@$@$@$@JfIHHHHHHee!      f%@CAo}X6c"{Yxq _=RۺdRO~sa=bq_5c~^3f=|m|D^!4%{DhV^1u$&8go|{dC(m!lp4<w 5cD]3=?n[[B%?|8qGJ`Ƹ6bRr>ƏIdMlK.Oe &NW,EHOt7yl7NѲ!&MI3iIn +ۂ%i }E+<iK-:YX'I+ѭ=9uM~+(uy P++ 6߹ ݓs+$ 0Oq=Zn0sɕ!B+?C܏ϝ^Hqm6=bqhi\YF6e[䟻EDtʘ]^W1@j݇c'A\|ğ2#O`[I*b,=R.!c|CȲ"8zY:;IzdR%E[~ɋZB)J,;gҥs ?¨PŘ|9K/f⑻CμX}q}RG[N n,bRF&=Š~>6yT= Kpqw&Kḋ%O܏ fb.=1\3i6^]ZhbKΒqLSt{w߿(dpj Is,kUXLj s.N[+b䓱& ~j&|ފ1,,iI8 $&%&!xv$.")|F;_ŹFjz ŋO 3Jk:o!EX!u>Zy7F;U:Kň$p l\0٘ԙȑdL$ ݌a$srqXŜދ,|tN+Y"&/*BMt~#΂  9&/B 揟-t#&g:i鄗bɌAc2]eu,]?ߐUs,Y#2mK 9qwϢÃGg/kMO~tQO]2y|3R'fC"NQM̰ڞ/Z|GNZ-ƌنɌmB:苚m/xz/mkigϰHW_m |ODJھ!K3sW? 'xc<%KV=¼ 2݃9cV T )ѥKt[o/-tJ4LXb\?A=Ln}9x}w OgDgѧKvf@V& qxgD,݋ޝ#deiX-ǒrZ>c'dwdiqYlC,αd- 9Z_^|44cIXcuE9~8Y%KKxGtb*9i>r{Ǐqb.1Cq#G85&㭎pLRҹ{o!kR,ϬS4L}9hj+3;/s`YS_|cvht';2X1LQkhOW0Y)u/L~qA^lzX˴pnfQ IЪ> S =S{S9κO? eP+Q?Ow\W?wVOnePslxL%Kpcs1ДI<+t+:W=,P5_2<'W]Bsi$,}bYE9 dz:%DȺ|LCV)"RLnyI~^.-z0z gaK3q,#+26BX:)w黫pC ڡ]ŃQǁ‚l?؊G,7a`DxM ǟEP%Byh<~R,_Z [meNz=0hGN4 ]w˻wk)tr"P_q۾*܎wkչwH9JDUq5a,f **bL4DXbɒvϱU=8W ڋE`HոN\~Uf .C_aKa5(eI :&K k/TYBn~>?| 6|.^ ߱z&Ȓm Yy֪=KrIXm!@CA3U~7J:'vy0fD] co+]sTƒbhؠ2:tQ%Px5$CѾl8svmXw_>vBE=\y+ׯǒE{Q%˗څpc5cv-?6U4y=e.~x{#{ L91@9"{pklyiJ]U{'bNMkR 3Vd]]C֭"c֣/(,L6g $LtL@4xe:INwѝuj&.J8!=o*ip#H5:/?lwT'MLe!}̯/̓rO&rRB;Pb)Ǡ[ѣ}+T˾8.DN$JcRTDeձow>l\k̓8HN=>'f9 ߆#ŧG™“ޭP3bk,bp,U 5eIliqf}nY! cg݂y+xi꧀NԭC_˩Ն!D'^ }i2+"VU[wP-3QA,9*ʥ-V·w5<fzj-DԹsCHX9p?Xa.-x5OMAIe1X8w"&L}tT,Kߛc䑟C^ҡzک+F+:`°+:=_6fR'џ܋~=Fi׍1X oJI&3#@:':#{"3 qe,T(?kQ^xy׫(:`BF_].X\'qx\:=?N;Uo=^U:u6"6FP_deE[;;Cꤦ64oyJ;,;Se.Av7!ϙH|c_&Qhz\L;C1Dy-O]myl ɫ: 7='ɺ_~4E?haSRp5bm?~Y]>dE2fh|h+Ij92Oʲ[о2O)u .^] d$&7?'x1>|# ߅r%g]=S75W9$LMwo\ -/dTaʚodƾg3鯐YF~ue0\sW!3WV7cAǮ1A.`qbڳ5*dv#Jl:搚@Q.: AG~'3#m"agA̾WQzc_*_=yCPgYzİV MiTYA#VKr6{jl.uIgYY!,Hr:sEg ?N s /F 5${+^zԅ HiXI߈ݢ^тG1O F.~_jp?Ye( U8HLꦻ%< J6N>zx5,/o~3 WQnc .u9u ȼ8;ѯe8Y;l ]lk޴w"Mފ2gPXUP\bhk/13$o-[KJA~hN%XsR¦#yV= @^>:Wph6t 7t| 5];7"눱]1X*FtCQy_ fZO|۞,%vLqhKdu1vԧ~uڍ!.xFŦ$ %&'u_#^D.upm{I8P֬گ.|OX>Mw,۳2|$yɻ3koV"f oT*1쵖A**^㞱2)`רMm%b;gYdWknr!".MD0Ȳ/fM{K/Zvpס vtWj'αeve. uisJ{: _F1SeWsƚ2xg>^n v /#)()heaꓺ GCuC.=s)udaХ.+&NR`e@cSzȄILVm_sZ9uv8RZc9T4w&bqvP^-W4SyKp`|b,LIuOI;pgz fԌ{ˀ;[.^[.o/`ǭ =reP̯| knaQ:aӕwᬽb(/ ]}p3FY9=Ѿ*+:9=Ië&b1^mX5Qݰ_Y|tXlD>zaXPW@֡d0#\1MfaĀ2&?Db6;Hf?;4nMYzݱQz_\fw1EV!ǹwX0|]yV(﫷0ӥ%m[04z Znt$2 䌝} {F䏕i?<YyX̪/Gބ92t /\]U+0V5 0 CZ{O=lț' &cGg{#Ÿpt\"v.8C>I8(8W,E2s9뾨|ݭ7ƈ-|xňԭߛqllʘ s^4V5z ţn_@Ay%9߃Kv',M縌TwuND' CqEELsh8-2\å49~$Kl3C_eϊ G׶wx^tx'ZGڽz 裦HјwWĮ0g |w$m gIۦb|#FC9#wS-,#+Nn/{Z,ૂ}\#1kd[Lx?n8=N<:s}yp=0c~D"bdW C ^|L;cy|b!y?cl>i%UDټҖ0 bM91dǪzwll*O) jcG oG7GoBB3Ϋu`]ok+[Rrt\7ؕn GE=Zflp kw g78Vv6o}1!=;]w.ƺl9ɵxk~KepD<?Gb, OQ^F~ow _}!dlH8멱8/Afst~J= Z\?1}٠N}gdY?!]%:.l_ ~ƈA"JQ_CWc~6`_c2{6d -ΉW4Y?+>]hz6\ZOoC Sn@`}Mﬡ!;3<1įwڂo ev*,oXyvlW?[O ;oT^3ޭL;`ĄDpiy3,hc2I!x"Krt$pbY.@ . t%Gk 7/~"9.KL?*0~UO /;-~"8KHBB\@ ~$&%G!v HN/|dxbηG%'rdַS%|m5]6&s=r+?oIÃ+7Jȩ薔_Q@dcxC/Q;'z'kO%,ޕ (RP%u,Vg6b|Kz2.XeV IcXXGM'2~+ᵱ m +&LN^I[c;~.AG#ȶWt3S=5yO{ q0'&#m"4”#mROyD'0FT5f|BejagtFzbrA1Z*Ȧ}n'ANAttXlU~X )9sCY 3CzyT79-i,zgX?KC1Juk#Y-fq䰞AͶ@׵^>ug_~%.RHx;M]j?3,-=4qx^*Kǁ@!##7D;VoC=?6∿u\bOc'P[?o[G =O]gDϤymcGMFz~zmYNG1? NL+ug4j.1s^^ ecr? B-BX8CgTlTQax? /=dR6ôRFg@n"ɭZ:SKzKIXU2-]Jv6=ma bvԦb: qfRKW7]:}/dduNmnTY]/=^#ogT=#:8׎a \XVɋ/{>h&֒ӒZ8?I3ՎX-JLFGBhe4hyV ЗcS4ޥmd"eӦhZt9vV 8YP. ղy`ͧkXʩHz$Gf۠ յDXa )5@)kʼOHi&> mUmRfBגv@v(=W N#6g#=E#q[m᧎IPZ>dUjb""TMH %V kajP  Ӄ Tud0N}j_ ]mV[xK֍ »zPz       F @CA#@d$@$@$@$@$@$@$ptIA$@$@$@$@$@$@@F,HHHHHHHt!@CRԃHHHHHH Y Bӥ& 4 "       Ӆ KMR      h8 ;v %%%|&HHHHHT%yRw4hF9Hx<C،bh     oo-[U Zvt%e$zPKh,8)Y HLL$BR-Hoh(ha$@$@$@$@$"t- -ZjPCZh-Z( |+$%%}+<T OH?:     8Yt ## [<%= release.name %>](https://github.com/<%= repository %>/tree/<%= release.tag_name %>) _released on <%= release.published_at %>_ <%= release.body.gsub(/\r\n/, "\n") %> <% end %> did-you-mean-1.0.0/benchmark/0000755000175000017500000000000012647462403016154 5ustar terceiroterceirodid-you-mean-1.0.0/benchmark/memory_usage.rb0000644000175000017500000000132412647462403021175 0ustar terceiroterceiro# -*- frozen-string-literal: true -*- require 'memory_profiler' require 'did_you_mean' # public def foo; end # error = (self.fooo rescue $!) # executable = -> { error.to_s } class DidYouMean::WordCollection include DidYouMean::SpellCheckable def initialize(words) @words = words end def similar_to(input, filter = '') @corrections, @input = nil, input corrections end def candidates { @input => @words } end end if !defined?(DidYouMean::WordCollection) METHODS = ''.methods INPUT = 'start_with?' collection = DidYouMean::WordCollection.new(METHODS) executable = proc { collection.similar_to(INPUT) } GC.disable MemoryProfiler.report { 100.times(&executable) }.pretty_print did-you-mean-1.0.0/benchmark/levenshtein/0000755000175000017500000000000012647462403020500 5ustar terceiroterceirodid-you-mean-1.0.0/benchmark/levenshtein/memory_usage.rb0000644000175000017500000000036012647462403023520 0ustar terceiroterceirorequire 'memory_profiler' require 'did_you_mean/levenshtein' str1, str2 = "user_signed_in?", "user_logged_in?" report = MemoryProfiler.report do 80.times do DidYouMean::Levenshtein.distance str1, str2 end end report.pretty_print did-you-mean-1.0.0/benchmark/levenshtein/speed.rb0000644000175000017500000000053012647462403022123 0ustar terceiroterceirorequire 'benchmark/ips' require 'did_you_mean' require 'did_you_mean/levenshtein' STR1, STR2 = "user_signed_in?", "user_logged_in?" Benchmark.ips do |x| x.report "enumerable" do DidYouMean::Levenshtein.before_distance STR1, STR2 end x.report "while" do DidYouMean::Levenshtein.after_distance STR1, STR2 end x.compare! end did-you-mean-1.0.0/benchmark/jaro_winkler/0000755000175000017500000000000012647462403020642 5ustar terceiroterceirodid-you-mean-1.0.0/benchmark/jaro_winkler/memory_usage.rb0000644000175000017500000000035212647462403023663 0ustar terceiroterceirorequire 'memory_profiler' require 'did_you_mean/jaro_winkler' str1, str2 = "user_signed_in?", "user_logged_in?" report = MemoryProfiler.report do 80.times do DidYouMean::Jaro.distance str1, str2 end end report.pretty_print did-you-mean-1.0.0/benchmark/jaro_winkler/speed.rb0000644000175000017500000000044412647462403022271 0ustar terceiroterceirorequire 'benchmark/ips' require 'did_you_mean' Benchmark.ips do |x| x.report "before" do DidYouMean::Jaro.before_distance "user_signed_in?", "user_logged_in?" end x.report "after" do DidYouMean::Jaro.after_distance "user_signed_in?", "user_logged_in?" end x.compare! end did-you-mean-1.0.0/lib/0000755000175000017500000000000012647462403014770 5ustar terceiroterceirodid-you-mean-1.0.0/lib/did_you_mean/0000755000175000017500000000000012647462403017424 5ustar terceiroterceirodid-you-mean-1.0.0/lib/did_you_mean/extra_features/0000755000175000017500000000000012647462403022445 5ustar terceiroterceirodid-you-mean-1.0.0/lib/did_you_mean/extra_features/ivar_name_correction.rb0000644000175000017500000000177512647462403027174 0ustar terceiroterceiromodule DidYouMean module ExtraFeatures module IvarNameCorrectable REPLS = { "(irb)" => -> { Readline::HISTORY.to_a.last } } def initialize(no_method_error) super @location = no_method_error.backtrace_locations.first @ivar_names = no_method_error.frame_binding.receiver.instance_variables end def candidates super.merge(receiver_name.to_s => @ivar_names) end private def receiver_name return unless receiver.nil? abs_path = @location.absolute_path lineno = @location.lineno /@(\w+)*\.#{method_name}/ =~ line(abs_path, lineno).to_s && $1 end def line(abs_path, lineno) if REPLS[abs_path] REPLS[abs_path].call elsif File.exist?(abs_path) File.open(abs_path) do |file| file.detect { file.lineno == lineno } end end end end SPELL_CHECKERS['NoMethodError'].prepend(IvarNameCorrectable) end end did-you-mean-1.0.0/lib/did_you_mean/extra_features/initializer_name_correction.rb0000644000175000017500000000067112647462403030550 0ustar terceiroterceiro# -*- frozen-string-literal: true -*- module DidYouMean module ExtraFeatures module InitializerNameCorrection def method_added(name) super distance = Levenshtein.distance(name.to_s, 'initialize') if distance != 0 && distance <= 2 warn "warning: #{name} might be misspelled, perhaps you meant initialize?" end end end ::Class.prepend(InitializerNameCorrection) end end did-you-mean-1.0.0/lib/did_you_mean/spell_checkable.rb0000644000175000017500000000267212647462403023060 0ustar terceiroterceiro# -*- frozen-string-literal: true -*- require "did_you_mean/levenshtein" require "did_you_mean/jaro_winkler" module DidYouMean module SpellCheckable def corrections @corrections ||= candidates.flat_map do |input, candidates| input = normalize(input) threshold = input.length > 3 ? 0.834 : 0.77 seed = candidates.select {|candidate| JaroWinkler.distance(normalize(candidate), input) >= threshold } .sort_by! {|candidate| JaroWinkler.distance(candidate.to_s, input) } .reverse! # Correct mistypes threshold = (input.length * 0.25).ceil has_mistype = seed.rindex {|c| Levenshtein.distance(normalize(c), input) <= threshold } corrections = if has_mistype seed.take(has_mistype + 1) else # Correct misspells seed.select do |candidate| candidate = normalize(candidate) length = input.length < candidate.length ? input.length : candidate.length Levenshtein.distance(candidate, input) < length end.first(1) end corrections end end def candidates raise NotImplementedError end private def normalize(str_or_symbol) #:nodoc: str = if str_or_symbol.is_a?(String) str_or_symbol.dup else str_or_symbol.to_s end str.downcase! str.tr!("@", "") str end end end did-you-mean-1.0.0/lib/did_you_mean/core_ext/0000755000175000017500000000000012647462403021234 5ustar terceiroterceirodid-you-mean-1.0.0/lib/did_you_mean/core_ext/name_error.rb0000644000175000017500000000101012647462403023702 0ustar terceiroterceiromodule DidYouMean module Correctable prepend_features NameError def original_message method(:to_s).super_method.call end def to_s msg = super.dup bt = caller(1, 6) msg << Formatter.new(corrections).to_s if IGNORED_CALLERS.all? {|ignored| bt.grep(ignored).empty? } msg rescue super end def corrections spell_checker.corrections end def spell_checker @spell_checker ||= SPELL_CHECKERS[self.class.to_s].new(self) end end end did-you-mean-1.0.0/lib/did_you_mean/version.rb0000644000175000017500000000005212647462403021433 0ustar terceiroterceiromodule DidYouMean VERSION = "1.0.0" end did-you-mean-1.0.0/lib/did_you_mean/extra_features.rb0000644000175000017500000000070512647462403022774 0ustar terceiroterceirorequire 'did_you_mean' module DidYouMean TRACE = TracePoint.trace(:raise) do |tp| e = tp.raised_exception if SPELL_CHECKERS.include?(e.class.to_s) && !e.instance_variable_defined?(:@frame_binding) e.instance_variable_set(:@frame_binding, tp.binding) end end NameError.send(:attr, :frame_binding) end require 'did_you_mean/extra_features/initializer_name_correction' require 'did_you_mean/extra_features/ivar_name_correction' did-you-mean-1.0.0/lib/did_you_mean/formatter.rb0000644000175000017500000000047712647462403021764 0ustar terceiroterceiro# -*- frozen-string-literal: true -*- module DidYouMean class Formatter def initialize(corrections = []) @corrections = corrections end def to_s return "" if @corrections.empty? output = "\nDid you mean? ".dup output << @corrections.join("\n ") end end end did-you-mean-1.0.0/lib/did_you_mean/verbose_formatter.rb0000644000175000017500000000054312647462403023503 0ustar terceiroterceiro# -*- frozen-string-literal: true -*- require 'did_you_mean/formatter' module DidYouMean module VerboseFormatter prepend_features DidYouMean::Formatter def to_s return "" if @corrections.empty? output = "\n\n Did you mean? ".dup output << @corrections.join("\n ") output << "\n " end end end did-you-mean-1.0.0/lib/did_you_mean/spell_checkers/0000755000175000017500000000000012647462403022412 5ustar terceiroterceirodid-you-mean-1.0.0/lib/did_you_mean/spell_checkers/null_checker.rb0000644000175000017500000000015012647462403025371 0ustar terceiroterceiromodule DidYouMean class NullChecker def initialize(*); end def corrections; [] end end end did-you-mean-1.0.0/lib/did_you_mean/spell_checkers/method_name_checker.rb0000644000175000017500000000111312647462403026677 0ustar terceiroterceiromodule DidYouMean class MethodNameChecker include SpellCheckable attr_reader :method_name, :receiver def initialize(exception) @method_name = exception.name @receiver = exception.receiver @has_args = !exception.args&.empty? end def candidates { method_name => method_names } end def method_names method_names = receiver.methods + receiver.singleton_methods method_names += receiver.private_methods if @has_args method_names.delete(method_name) method_names.uniq! method_names end end end did-you-mean-1.0.0/lib/did_you_mean/spell_checkers/name_error_checkers/0000755000175000017500000000000012647462403026412 5ustar terceiroterceirodid-you-mean-1.0.0/lib/did_you_mean/spell_checkers/name_error_checkers/class_name_checker.rb0000644000175000017500000000201212647462403032523 0ustar terceiroterceiro# -*- frozen-string-literal: true -*- require 'delegate' module DidYouMean class ClassNameChecker include SpellCheckable attr_reader :class_name def initialize(exception) @class_name, @receiver = exception.name, exception.receiver end def candidates {class_name => class_names} end def class_names scopes.flat_map do |scope| scope.constants.map do |c| ClassName.new(c, scope == Object ? "" : "#{scope}::") end end end def corrections super.map(&:full_name) end def scopes @scopes ||= @receiver.to_s.split("::").inject([Object]) do |_scopes, scope| _scopes << _scopes.last.const_get(scope) end.uniq end class ClassName < SimpleDelegator attr :namespace def initialize(name, namespace = '') super(name) @namespace = namespace end def full_name self.class.new("#{namespace}#{__getobj__}") end end private_constant :ClassName end end did-you-mean-1.0.0/lib/did_you_mean/spell_checkers/name_error_checkers/variable_name_checker.rb0000644000175000017500000000132012647462403033204 0ustar terceiroterceiro# -*- frozen-string-literal: true -*- module DidYouMean class VariableNameChecker include SpellCheckable attr_reader :name, :method_names, :lvar_names, :ivar_names, :cvar_names def initialize(exception) @name = exception.name.to_s.tr("@", "") @lvar_names = exception.local_variables receiver = exception.receiver @method_names = receiver.methods + receiver.private_methods @ivar_names = receiver.instance_variables @cvar_names = receiver.class.class_variables @cvar_names += receiver.class_variables if receiver.kind_of?(Module) end def candidates { name => (lvar_names + method_names + ivar_names + cvar_names) } end end end did-you-mean-1.0.0/lib/did_you_mean/spell_checkers/name_error_checkers.rb0000644000175000017500000000120412647462403026734 0ustar terceiroterceirorequire 'did_you_mean/spell_checkers/name_error_checkers/class_name_checker' require 'did_you_mean/spell_checkers/name_error_checkers/variable_name_checker' module DidYouMean module NameErrorCheckers def self.included(*) raise "Do not include this module since it overrides Class.new method." end def self.new(exception) case exception.original_message when /uninitialized constant/ ClassNameChecker when /undefined local variable or method/, /undefined method/, /uninitialized class variable/ VariableNameChecker else NullChecker end.new(exception) end end end did-you-mean-1.0.0/lib/did_you_mean/levenshtein.rb0000644000175000017500000000242012647462403022273 0ustar terceiroterceiromodule DidYouMean module Levenshtein # :nodoc: # This code is based directly on the Text gem implementation # Returns a value representing the "cost" of transforming str1 into str2 def distance(str1, str2) n = str1.length m = str2.length return m if n.zero? return n if m.zero? d = (0..m).to_a x = nil # to avoid duplicating an enumerable object, create it outside of the loop str2_codepoints = str2.codepoints str1.each_codepoint.with_index(1) do |char1, i| j = 0 while j < m cost = (char1 == str2_codepoints[j]) ? 0 : 1 x = min3( d[j+1] + 1, # insertion i + 1, # deletion d[j] + cost # substitution ) d[j] = i i = x j += 1 end d[m] = x end x end module_function :distance private # detects the minimum value out of three arguments. This method is # faster than `[a, b, c].min` and puts less GC pressure. # See https://github.com/yuki24/did_you_mean/pull/1 for a performance # benchmark. def min3(a, b, c) if a < b && a < c a elsif b < c b else c end end module_function :min3 end end did-you-mean-1.0.0/lib/did_you_mean/jaro_winkler.rb0000644000175000017500000000345112647462403022442 0ustar terceiroterceiromodule DidYouMean module Jaro module_function def distance(str1, str2) str1, str2 = str2, str1 if str1.length > str2.length length1, length2 = str1.length, str2.length m = 0.0 t = 0.0 range = (length2 / 2).floor - 1 range = 0 if range < 0 flags1 = 0 flags2 = 0 # Avoid duplicating enumerable objects str1_codepoints = str1.codepoints str2_codepoints = str2.codepoints i = 0 while i < length1 last = i + range j = (i >= range) ? i - range : 0 while j <= last if flags2[j] == 0 && str1_codepoints[i] == str2_codepoints[j] flags2 |= (1 << j) flags1 |= (1 << i) m += 1 break end j += 1 end i += 1 end k = i = 0 while i < length1 if flags1[i] != 0 j = index = k k = while j < length2 index = j break(j + 1) if flags2[j] != 0 j += 1 end t += 1 if str1_codepoints[i] != str2_codepoints[index] end i += 1 end t = (t / 2).floor m == 0 ? 0 : (m / length1 + m / length2 + (m - t) / m) / 3 end end module JaroWinkler WEIGHT = 0.1 THRESHOLD = 0.7 module_function def distance(str1, str2) jaro_distance = Jaro.distance(str1, str2) if jaro_distance > THRESHOLD codepoints2 = str2.codepoints prefix_bonus = 0 i = 0 str1.each_codepoint do |char1| char1 == codepoints2[i] && i < 4 ? prefix_bonus += 1 : break i += 1 end jaro_distance + (prefix_bonus * WEIGHT * (1 - jaro_distance)) else jaro_distance end end end end did-you-mean-1.0.0/lib/did_you_mean.rb0000644000175000017500000000100512647462403017745 0ustar terceiroterceirorequire "did_you_mean/version" require "did_you_mean/core_ext/name_error" require "did_you_mean/spell_checkable" require 'did_you_mean/spell_checkers/name_error_checkers' require 'did_you_mean/spell_checkers/method_name_checker' require 'did_you_mean/spell_checkers/null_checker' require "did_you_mean/formatter" module DidYouMean IGNORED_CALLERS = [] SPELL_CHECKERS = Hash.new(NullChecker) SPELL_CHECKERS.merge!({ "NameError" => NameErrorCheckers, "NoMethodError" => MethodNameChecker }) end did-you-mean-1.0.0/CHANGELOG.md0000644000175000017500000002221312647462403016033 0ustar terceiroterceiro## [v0.10.0](https://github.com/yuki24/did_you_mean/tree/v0.10.0) _released on 2015-08-21 06:44:11 UTC_ #### New Features - Now it corrects an instance variable name if the ivar name is mistyped and `NoMethodError` is raised: ```ruby @number = 1 @nubmer.zero? # => NoMethodError: undefined method `zero?' for nil:NilClass # # Did you mean? @number # ``` - Support for JRuby 9.0.0.0 - Prefix-based correction ( [@tjohn](https://github.com/tjohn), [#50](https://github.com/yuki24/did_you_mean/issues/50 "Match start of method name"), [#49](https://github.com/yuki24/did_you_mean/issues/49 "Use Jaro distance instead of Jaro-Winkler distance")) - Correction search is about 75% faster than 0.9.10 #### Breaking Changes - The ActiveRecord integration has been removed ## [v0.9.10](https://github.com/yuki24/did_you_mean/tree/v0.9.10) _released on 2015-05-14 03:04:47 UTC_ #### Bug Fixes - Fixed a bug where a duplicate "did you mean?" message was appended each time `#to_s` is called ( [@danfinnie](https://github.com/danfinnie), [#51](https://github.com/yuki24/did_you_mean/issues/51 "Duplicate output for constants in separate gem")) ## [v0.9.9](https://github.com/yuki24/did_you_mean/tree/v0.9.9) _released on 2015-05-13 03:48:19 UTC_ #### Small/Internal Changes - Order word corrections based on Levenshtein distance ( [@tleish](https://github.com/tleish), [#31](https://github.com/yuki24/did_you_mean/pull/31 "Order word corrections based on Levenshtein.distance.")) - Reduce memory allocation by about 40% - Speed up Levenshtein distance calculation by about 40% - The Java extension has been replaced with a pure JRuby implementation ## [v0.9.8](https://github.com/yuki24/did_you_mean/tree/v0.9.8) _released on 2015-04-12 01:55:27 UTC_ #### Internal Changes - Speed up Levenshtein by 50% and reduce 97% of memory usage ## [v0.9.7](https://github.com/yuki24/did_you_mean/tree/v0.9.7) _released on 2015-04-02 04:20:26 UTC_ #### Bug Fixes - Fixed an issue where _did\_you\_mean_ doesn't install on JRuby properly. ## [v0.9.6](https://github.com/yuki24/did_you_mean/tree/v0.9.6) _released on 2015-01-24 23:19:27 UTC_ #### Bug Fixes - Fixed a bug where did\_you\_mean incorrectly suggests protected methods when it just isn't callable ( [@glittershark](https://github.com/glittershark), [#34](https://github.com/yuki24/did_you_mean/issues/34 "Did\_you\_mean incorrectly called when attempting to call protected/private method")) ## [v0.9.5](https://github.com/yuki24/did_you_mean/tree/v0.9.5) _released on 2015-01-07 12:41:23 UTC_ #### Bug Fixes - Whitelist `#safe_constantize` method from `ActiveSupport::Inflector` to avoid significant performance slowdown ( [@tleish](https://github.com/tleish), [#19](https://github.com/yuki24/did_you_mean/issues/19 "Significant Slowdown when Using Debugger"), [#20](https://github.com/yuki24/did_you_mean/pull/20 "Whitelisting safe\_constantize (ActiveSupport::Inflector) method")) ## [v0.9.4](https://github.com/yuki24/did_you_mean/tree/v0.9.4) _released on 2014-11-19 20:00:00 UTC_ #### Bug Fixes - Fixed a bug where no corrections will be made on JRuby ## [v0.9.3](https://github.com/yuki24/did_you_mean/tree/v0.9.3) _released on 2014-11-18 03:50:11 UTC_ **This version has been yanked from rubygems.org as it doesn't work with jRuby at all. Please upgrade to 0.9.4 or higher as soon as possible.** #### Internal Changes - Replaced the crazy C extension with a so much better one (thanks to [@nobu](https://github.com/nobu)!) ## [v0.9.2](https://github.com/yuki24/did_you_mean/tree/v0.9.2) _released on 2014-11-17 15:32:33 UTC_ #### Bug Fixes - Fixed a bug where did\_you\_mean doesn't compile on Ruby 2.1.2/2.1.5 ( [#16](https://github.com/yuki24/did_you_mean/issues/16 "Gem building failed on Debian 6.0.10 x86\_64")) ## [v0.9.1](https://github.com/yuki24/did_you_mean/tree/v0.9.1) _released on 2014-11-16 18:54:24 UTC_ **This version has been yanked from rubygems.org as it doesn't compile on Ruby 2.1.2 and 2.1.5. Please upgrade to 0.9.4 or higher as soon as possible.** #### Internal Changes - Shrink the gem size by removing unneeded ruby header files. - Now it forces everyone to upgrade the gem when they upgrade Ruby to a new version. This avoids introducing a bug like [#14](https://github.com/yuki24/did_you_mean/issues/14 "Compatibility with `letter\_opener` gem"). ## [v0.9.0](https://github.com/yuki24/did_you_mean/tree/v0.9.0) _released on 2014-11-09 01:26:31 UTC_ #### New Features - did\_you\_mean now suggests instance variable names if `@` is missing ( [#12](https://github.com/yuki24/did_you_mean/issues/12 "Suggest instance- and class-vars"), [39d1e2b](https://github.com/yuki24/did_you_mean/commit/39d1e2bd66d6ff8acbc4dd5da922fc7e5fcefb20)) ```ruby @full_name = "Yuki Nishijima" first_name, last_name = full_name.split(" ") # => NameError: undefined local variable or method `full_name' for main:Object # # Did you mean? @full_name # ``` #### Bug Fixes - Fixed a bug where did\_you\_mean changes some behaviours of Ruby 2.1.3/2.1.4 installed on Max OS X ( [#14](https://github.com/yuki24/did_you_mean/issues/14 "Compatibility with `letter\_opener` gem"), [44c451f](https://github.com/yuki24/did_you_mean/commit/44c451f8c38b11763ba28ddf1ceb9696707ccea0), [9ebde21](https://github.com/yuki24/did_you_mean/commit/9ebde211e92eac8494e704f627c62fea7fdbee16)) - Fixed a bug where sometimes `NoMethodError` suggests duplicate method names ( [9865cc5](https://github.com/yuki24/did_you_mean/commit/9865cc5a9ce926dd9ad4c20d575b710e5f257a4b)) ## [v0.8.0](https://github.com/yuki24/did_you_mean/tree/v0.8.0) _released on 2014-10-27 02:03:13 UTC_ **This version has been yanked from rubygems.org as it has a serious bug with Ruby 2.1.3 and 2.1.4 installed on Max OS X. Please upgrade to 0.9.4 or higher as soon as possible.** #### New Features - JRuby support! #### Bug Fixes - Fixed a bug where did\_you\_mean unexpectedly disables [better\_errors](https://github.com/charliesome/better_errors)'s REPL - Replaced [binding\_of\_caller](https://github.com/banister/binding_of_caller) dependency with [interception](https://github.com/ConradIrwin/interception) - Fixed the wrong implementation of Levenshtein algorithm ( [#2](https://github.com/yuki24/did_you_mean/pull/2 "Fix bug of DidYouMean::Levenshtein#min3."), [@fortissimo1997](https://github.com/fortissimo1997)) ## [v0.7.0](https://github.com/yuki24/did_you_mean/tree/v0.7.0) _released on 2014-09-26 03:37:18 UTC_ **This version has been yanked from rubygems.org as it has a serious bug with Ruby 2.1.3 and 2.1.4 installed on Max OS X. Please upgrade to 0.9.4 or higher as soon as possible.** #### New Features - Added support for Ruby 2.1.3, 2.2.0-preview1 and ruby-head - Added support for ActiveRecord 4.2.0.beta1 - Word searching is now about 40% faster than v0.6.0 - Removed `text` gem dependency - Better output on pry and Rspec #### Small/Internal Changes - A lot of internal refactoring ## [v0.6.0](https://github.com/yuki24/did_you_mean/tree/v0.6.0) _released on 2014-05-18 00:23:24 UTC_ **This version has been yanked from rubygems.org as it has a serious bug with Ruby 2.1.3 and 2.1.4 installed on Max OS X. Please upgrade to 0.9.0 as soon as possible.** #### New Features - Added basic support for constants. Now you'll see class name corrections when you misspelled a class names/module names: ```ruby > Ocject # => NameError: uninitialized constant Ocject # # Did you mean? Object # ``` #### Bug Fixes - Fixed a bug where did\_you\_mean segfaults on Ruby head(2.2.0dev) ## [v0.5.0](https://github.com/yuki24/did_you_mean/tree/v0.5.0) _released on 2014-05-10 17:59:54 UTC_ #### New Features - Added support for Ruby 2.1.2 ## [v0.4.0](https://github.com/yuki24/did_you_mean/tree/v0.4.0) _released on 2014-04-20 02:10:31 UTC_ #### New Features - did\_you\_mean now suggests a similar attribute name when you misspelled it. ```ruby User.new(flrst_name: "wrong flrst name") # => ActiveRecord::UnknownAttributeError: unknown attribute: flrst_name # # Did you mean? first_name: string # ``` #### Bug Fixes - Fixed a bug where did\_you\_mean doesn't work with `ActiveRecord::UnknownAttributeError` ## [v0.3.1](https://github.com/yuki24/did_you_mean/tree/v0.3.1) _released on 2014-03-20 23:16:20 UTC_ #### Small/Internal Changes - Changed output for readability. - Better algorithm to find the correct method. ## [v0.3.0](https://github.com/yuki24/did_you_mean/tree/v0.3.0) _released on 2014-03-20 23:13:13 UTC_ #### New Features - Added support for Ruby 2.1.1 and 2.2.0(head). ## [v0.2.0](https://github.com/yuki24/did_you_mean/tree/v0.2.0) _released on 2014-03-20 23:12:13 UTC_ #### Incompatible Changes - dropped support for JRuby and Rubbinious. #### New Features - did\_you\_mean no longer makes Ruby slow. ## [v0.1.0: First Release](https://github.com/yuki24/did_you_mean/tree/v0.1.0) _released on 2014-03-20 23:11:14 UTC_ - Now you will have "did you mean?" experience in Ruby! - but still very experimental since this gem makes Ruby a lot slower. did-you-mean-1.0.0/evaluation/0000755000175000017500000000000012647462403016371 5ustar terceiroterceirodid-you-mean-1.0.0/evaluation/incorrect_words.yaml0000644000175000017500000005522512647462403022474 0ustar terceiroterceiro# This data is based on Birkbeck Spelling Error Corpus: http://ota.ox.ac.uk/headers/0643.xml # More specifically, this is a yaml version of the data in FAWTHROP1DAT.643 and FAWTHROP1DAT.643. --- abattoir: abbatoir abhorrence: abhorence absence: absense absorbent: absorbant absorption: absorbtion accede: acceed accelerate: acellerate accessible: accesible accidentally: accidently accommodate: accomodate accommodation: accomodation accommodations: accomodations accompaniment: accompanimen accompanying: acompaning accomplice: acomplice accrued: acrued accumulated: acumulated accustom: acustom achievement: acheivement acknowledgment: acknowledgement acquaintance: acquantance acquiesce: aquiese acquiescence: acquiesence acquire: aquire actually: actualy adaptability: adaptibility addition: additon address: adress adequately: adequattly adjacent: ajacent adjourned: adjorned administration: adminstration admissible: admissable admitting: admiting advantageous: advantageos advice: advise affidavit: afidavit aggravated: agravated aghast: agast agreeable: agreable allotted: alloted also: allso alumnae: alumni alumni: alumnae amateur: amatuer amiable: aimiable ammonia: amonia analogous: analagous analysis: analsis analyze: analize angel: angell anniversary: anniversery announcement: anouncement annoyance: anoyance answer: anwser antarctic: antartic any: anye anything: anythin apollo: appolo apology: appology apparent: apparant appearance: appearence appearing: appearin appetite: appitite appetites: appatites appropriate: apropriate appropriation: apropriation approximate: aproximate approximately: aproximatly archaeological: archeological ascertain: assertain asinine: assinine asking: askin asleep: asleeep assassinate: assasinate assessment: assesment assiduous: assidious assistance: assistence attorneys: attornies authoritative: authorative auxiliary: auxillary available: availble awkward: aukward bachelor: batchelor balloon: baloon banana: bananna bankruptcy: bankrupcy bargaining: baragining battalion: batallion beam: beame before: befor beginning: begining believe: belive belligerent: beligerant beneficent: beneficient beneficial: benificial bitch: bich brake: brakke brethren: bretheren brief: brif britain: britian britannia: britania brown: broun bungalow: bungalo buoyancy: bouyancy buoyant: bouyant buried: burried bushel: bushell business: busness buying: buyin cancellation: cancelation calling: callin cantaloupe: cantaloube caribbean: carribean catalogues: catologues category: catagorey cemetery: cemetary chauffeur: chauffuer chemistry: chemestry chimneys: chimnies cincinnati: cincinatti clever: cleva coalesced: coalesed coherent: coherant coliseum: colosium collateral: calateral colossal: collosal colossus: collosus commanded: commaunded commission: commision commitment: committment committee: committe communicate: comunicate comparative: comparitive comparatively: comparitively compendium: conpendium competent: compitent concede: consede conceive: concieve conceived: concieved conditions: condicions confectionery: confectionary confirmation: confermation confusing: confusin connoisseurs: connoiseurs conscience: concience conscientious: conscientous consensus: concensus considering: consderin consistent: consistant conspired: conpired consumer: comsumer contemptible: contempible continuous: continous controllable: controlable controversy: controversey conveniently: conviently coolly: cooly corduroy: corderoy correspondence: correspondanc corrugated: corrigated could: coud counting: countin countryman: countriman craftsman: craftman curiosity: curiousity curriculum: curicculum customary: customery cynical: synical darling: darlin decidedly: dicidely deem: deam definitely: definatly delinquent: delinquint delirious: dilirious delving: delvin denying: denyin dependant: dependent depreciation: depeciation descendant: descendent description: desacription despair: dispair deuce: duece develop: develope development: developement dictionary: dictionery dignitary: dignatary dilapidated: dilapadated diminish: diminsh dining: dinning diphtheria: diptheria disappoint: dissappoint disappointment: dissappointment disastrous: disasterous discipline: disiplin discrete: discite dispel: dispell dissipate: disippate divine: devine doctor: docter doctors: docters dormitory: dormatory doubt: doupt drastically: drasticly drawing: drawin dreaming: dreamin drew: drewe dropped: droped drunkenness: drunkeness duchess: dutchess duly: duely during: durin earnest: ernest ecstasy: ecstacy effecting: effectinge effeminate: affeminate effervescent: effervesent efficiency: effeciency eisenhower: eisenhhower eligible: elegable eliminate: illiminate embarrass: embarass embarrassment: embarrasment encyclopedia: encylopedia endorsement: endorsment enemy: emeny engineers: egnineers enlarged: enlargd entertained: enterteyned equipped: equipt equivalent: equivelant esteemed: estimed every: evrey exaggerate: exagerate exaggeration: exageration examination: eximination examining: examinin excellence: excelence exercises: excercises exhilarating: exhilirating exhorted: exorted existence: existance exorbitant: exhorbitant experience: experiance explicitly: explisitly exquisite: exqusite eyeing: eying facilitate: facilatate fascinating: facinating fatiguing: fatiging fear: feare february: febuary fictitious: fictitous fielder: fiedler fiery: firey fighting: fieghting filipinos: philipinoes filthiness: filthness finally: finaly flammable: flamable flourished: florished foreign: forien forthright: fortright forty: fourty fox: foxx frescos: frescoes friend: freind fulfill: fullfil fundamental: fundemental fundamentally: fundementally gardener: gardner gauge: guage generosity: generousity genius: genious ghastly: gastly gnawing: knawing gone: gonne government: goverment grabbing: grabbin grammar: grammer gramophone: grammophon grandeur: granduer grateful: greatful grievous: grievious grill: grille guarantee: gaurantee guaranteed: guarenteed guardian: guardien guttural: gutteral hammarskjold: hammerskjold hand: hande handkerchief: hankerchief handsome: hansome harass: harrass having: haveing heartrending: heartrendering height: heighth heinous: hienous hemorrhage: hemorrage heyday: heydey himself: himselfe hindrance: hinderence humbly: humly hurricane: huricane hygiene: hygeine identified: indentified idiosyncrasy: idiocyncracy imagination: imagnation imitation: immitation immediately: imidatly immensely: immensly impedance: impedence impresario: impressario incense: insense incessant: incesant incidentally: incidently incompatibility: incompatability inconvenience: inconvience incorrigible: incorigible incredible: incredable indefinite: indefinate independence: independance indictment: inditement indispensable: indispensible inevitable: inevitible infallible: infalable infinite: infinate ingratitude: ingratitoode innocuous: inocuous inoculate: innoculate insistence: insistance instantaneous: instantanous instead: insted intercede: intersede interfered: interferred interference: intereference interrupted: interupted invariably: invarably irrelevant: irrelavent irreparable: irrepairable irresistible: irristible itemized: itimized jackknife: jacknife jaguar: jagaur japanese: japaneze jaundice: jaundise jealousy: jelousy jeopardize: jeprodise judgment: judgement kaleidoscope: kaliedoscope kapok: kapock khaki: kahki kimono: kimona kindergarten: kindergarden kitchen: kitchin knickknacks: knicknacks labeled: labelled laboratory: labratory language: langauge leeway: leaway leisure: liesure leveled: levelled library: libray license: lisence lieutenant: leutenant linoleum: linolium liquefied: liquified liquefy: liquify livelihood: livelyhood lodestone: loadstone lodgment: lodgement lonely: lonley magnificent: magnigicient maintenance: maintainance mammoth: mamoth management: managment maneuver: manuveur manufactories: manufacturies masterpiece: masterpice material: materiel mathematics: mathmatics mattress: mattres maudlin: mauldin meant: ment medicine: medecine meeting: meetin mercenary: mercanery merchandise: merchandize merchantmen: merchantment meteorological: meterological metropolitan: metropolitian millionaire: millionnaire miniature: minature miscellaneous: miscelaneous mischievous: mischievious moccasins: mocassins momentous: momentus mortgage: morgage mortgaged: mortgauged murmurs: murmers mustnt: musnt mutilate: mutalate mythical: mithical nadir: nadar naphtha: naptha narrative: narative naturally: naturaly navigating: navagating necessarily: necessarilly necessary: nessisary niagara: niagra nickel: nickle niggardly: nigardly ninetieth: nintieth ninetyninth: nintynineth nocturnal: nocternal nonsense: nonsence notwithstanding: nothwithstanding nowadays: nowdays obbligato: obliggato obdurate: obdirate occasion: ocassion occasionally: occasionaly occurred: occureed occurrence: occurence octopus: octapus odyssey: oddysey ominous: omenous omission: ommision onerous: onirous opportunities: oppotunities opposition: oposition oppressor: oppresser optician: optitian oratorio: orotario orchestra: ochestra ordinarily: ordinarilly origin: origen originally: origionally own: owne pain: paine pamphlet: phamplet pamphlets: phamplets parallel: parellel paralysis: parallysis paraphernalia: parephernalia parenthesis: parenthasis participle: participal pastime: pasttime pastor: paster paternity: paternaty pavilion: pavillion peasant: peasent peculiar: pecular penance: pennance pendulum: pendelum penguins: pengiuns peninsula: peninsular penitentiary: penitentary perceive: percieve perforation: preforation permissible: permissable perseverance: perseverence personalty: personality perspiration: persperation persuade: pursuade persuaded: pursuaded persuasion: persausion pertaining: pertaning pervaded: prevaded pharaohs: pharoahs phase: faze phenomenal: phenominal phenomenon: phenonenon philippines: phillipines physician: physican pickerel: pickeral picnicking: picnicing pittsburgh: pittsburg plagiarism: plaigarism plaque: placque playwright: playwrite pleasant: plesent poetry: poetrie poisonous: poisenous ponderous: pondorous possess: posess possession: possesion possibilities: possablities prairie: prarie preceding: preceeding precipice: presipice preferable: preferrable preference: preferance preferred: prefered prejudice: prejedice preparation: preperation preserved: perserved presumptuous: presumptous prevalent: prevelant preventive: preventative prisoner: prisner privilege: priviledge probably: probabley procedure: proceduer professor: proffesor proffer: profer prominent: prominant promontory: promonotory pronunciation: pronounciation propeller: propellor prophecy: prophesy provisions: provisons pseudonym: pseudynom psychological: psycological public: publick publicly: publically pumpkin: pumkin pursue: persue pursuer: persuer pursuit: persuit qualified: qualafied quandary: quandry quantities: quanties quarantine: quarrantine quarreled: quarelled quarter: quater questionnaire: questionare quiescent: quiscent quorum: quorem radiant: radient radiator: radiater raise: raize rating: rateing really: realy rebuttal: rebutal receded: receeded receipt: reciept receipts: reciepts receive: recieve receiver: reciever receptacle: receptacel recipient: resipient reciprocal: reciprocel reckon: recon reclamation: reclaimation recommend: recomend recommendation: recomendation recommendations: reccomendations recommended: recommend recommending: recomending recompense: recompence redundant: redundent reference: refference referred: refered referring: refering refrigerator: refrigerater regretted: regreted rehabilitate: rehabilatate relevant: relevaant religious: religous remembrance: rememberance rendezvous: rendevous renegade: renagade renown: renoun reparation: repairation repel: repell repetition: repitition representatives: representitives rescinded: resinded reservoir: resevoir responsibility: responsiblity restaurant: restuarant restaurateur: restauranteur rhapsody: raphsody rheumatism: rhuematism rhododendron: rhododrendon rhubarb: ruhbarb rhythm: rythm ridiculous: rediculous romantic: romantick rummage: rumage running: runing sabbath: sabath sacrament: sacrement sacrilegious: sacreligious safety: safty sagacious: sagatious sailor: sailer sandwich: sanwich sanitary: sanatary satisfactory: satisfactary scarcity: scarsity scissors: sissers seize: sieze seized: siezed self: selfe sell: selle semesters: semisters seminary: seminery separate: seporate sergeant: sergant sheep: sheepe shepherd: sheperd silhouette: silhuette shipping: shippin shoulder: shouldda shoulders: sholders showing: showin shrubbery: shrubery siege: seige significant: significent silk: silke similar: similiar simultaneous: similtanous sincerity: sincerety slimmest: slimest smiling: smilin sociable: socable social: socal solemn: solomn sophomore: sophmore sorority: sororiety sought: saught source: sorce souvenir: souviner sovereignty: sovreignty sparsely: sparcely spear: speer specifically: specificly specimen: speciment specimens: specimans spirituous: spiritous sprinkle: sprinkel starting: startin stationary: stationery statue: statu stirring: stirrin stirrups: stirups stomach: stomack straining: strainin straitjacket: straightjacket stratagem: strategem strategy: stratagy strenuous: strenous stretched: streched stubbornness: stubborness suburban: sububan success: sucess sufficient: suficient suffrage: sufferage sugar: suger suing: sueing superficial: superfical superintendent: supertendent supersede: supercede supplement: suplement suppress: supress surprise: suprise surreptitious: sureptitous surrounded: surounded swearing: swearinge syllables: sylables symmetry: symetry synonymous: synonomous systematically: systemetically tacit: tasit taking: takin technically: technecally television: televison temperament: temperment temporarily: temporarly temporary: tempory tendency: tendancy terrestrial: terestial terrors: terrours that: thatt therefore: therefor thief: theaf think: thinke thinking: thinkin thorough: thourough thoroughly: throughly tobacco: tobbaco tobogganing: tobboganing tonnage: tonage tragedy: tradgedy tranquility: tranquillity tranquillity: tranquility transferable: transferrable transferred: transfred truculent: trucculent truly: truley tying: tieing tyrannical: tyranical undoubtedly: undoubtly unequaled: unequalled unfortunately: unfortunatly university: unversity unmistakable: unmistakeable unparalleled: unparalelled until: untill usage: useage usually: usualy usurious: usurous utterance: utterence vacancy: vancancy vaccination: vacinnation vacillate: vaccilate various: vairious vegetable: vegatable vengeance: vengance vertical: verticle vice: vise victuals: vituals vilify: villify villain: villian violence: violance violin: vioiln visible: visable vitamins: vitamines voucher: vouture wagging: waggin waggish: wagish wednesday: wensday weed: weede weight: weigth weird: wierd whether: wether which: whitch who: whoe withhold: withold worshiping: worshipping yacht: yaht yearned: yerned yeoman: yoman yield: yeild zealous: zelous zenith: zeenith ability: ablity academically: academicly accept: acept accepted: acepted access: acess accessibility: accessability accessing: accesing according: acording account: acount accounts: acounts acquaintances: aquantences adaptable: adabtable addressable: addresable adequate: adiquate adjournment: adjurnment advise: advice again: agiin agencies: agences aggravating: agravating allow: alow although: athough analyse: analiss analysed: analised analysing: aalysing and: anf announcing: anouncing annoying: anoying annual: anual anomalies: anomolies apologies: appologies apologised: appologised appeal: apeal appendix: apendix applicable: aplicable applied: upplied applying: applieing appointment: appoitment appointments: apointments appreciated: apreciated appreciation: apreciation approach: aproach approached: aproached are: arte arguing: aurguing arranged: arrainged arrangeing: aranging arrangement: arrangment arrangements: araingements articles: articals assessing: accesing associated: assosiated atmosphere: atmospher auguments: aurgument availability: avaiblity base: basse benefit: benifit benefits: benifits between: beetween bicycle: bicycal bingley: bingly bonus: bonas build: biuld building: biulding busy: buisy career: carrer careers: currers categories: catagoris centrally: centraly certain: cirtain challenges: chalenges challenge: chalange choice: choise choices: choises choose: chose choosing: chosing clerical: clearical clerk: clerck collate: colate combine: comibine commercial: comersial comments: coments commit: comit committees: commitees compare: compair compared: comppared comparison: comparrison completely: completly component: componant composed: compossed conditioning: conditining conference: conferance consider: concider considerable: conciderable consist: consisit consisting: consisiting consists: consisits contained: contasined containing: contasining continually: contually continued: contuned controlled: controled conversely: conversly corporate: corparate credit: creadit criticism: citisum currently: curruntly data: dsata dealt: delt decide: descide decided: descided decides: descides decision: descisions decisions: descisions declarations: declaratrions definition: defenition definitions: defenitions demands: diemands dependence: dependance described: discribed desirable: disiable desperately: despratly diagrammatically: diagrammatica different: diffrent difficult: dificult difficulty: dificulty disaggregate: disaggreagte disappointing: dissapoiting discretion: discresion dissension: desention dragged: draged earlier: earlyer earliest: earlyest easier: easer easily: easyly econometric: economtric edition: ediition eliminated: elimiated embellishing: embelishing employed: emploied employees: emploies employment: empolyment encompassing: encompasing encourage: encorage enormously: enomosly entirely: entierly equalled: equaled erroneous: errounous especially: especaily essential: esential eventually: eventully evident: evedent exact: exsact exactly: exsactly examine: examin excellent: exerlant except: excxept excessively: exessively executed: executted expansion: expanion expense: expence expensive: expencive experiences: experances explaining: explaning exponentially: exponentualy extremely: extreemly facilities: facilitys fails: failes 'false': faulse familiar: familer families: familys favourable: faverable favourably: favorably feeling: fealing female: femail figure: figuar figures: figuars financial: finatical financially: financialy flexible: flexable forbidden: forbiden forecast: forcast fourth: forth functionally: functionaly functions: functuions further: futher gaining: ganing generated: generataed geneva: geniva geographically: goegraphicaly graphically: graphicaly guidelines: guidlines handle: handel hierarchal: hierachial hierarchy: hierchy however: howeverr humour: humor ideally: idealy immediate: imediate inconceivable: inconcievable indeed: indead independent: independant inefficient: ineffiect initial: intital input: inut inquiries: equiries insight: insite intelligence: inteligence interest: intrest interesting: intresting interpretation: interpritatio interrogating: interogationg investigated: investegated journalism: journaism knowledge: knowlege largely: largly later: latter length: lengh level: leval levels: levals lieu: liew literature: litriture loans: lones locally: localy luckily: luckeley majority: majorty manually: manualy many: mony mathematically: mathematicaly matrix: matriiix mean: meen means: meens minutes: muiuets misleading: missleading monitoring: monitering months: monthes moving: moveing nationally: nationaly nature: natior necessitates: nessisitates necessity: nessesity negligible: negligable neither: niether night: nite normally: normaly now: noe numbers: numbuers obtaining: optaning occur: occure operations: operatins operator: opertor operators: oprators opinion: oppinion opportunity: oppotunity ordinary: ordenary organization: oranisation organized: oranised orientated: orentated output: oputput overall: overal paid: payed parameters: perametres partially: partialy particular: particulaur particularly: particulary patterns: pattarns per: pere perhaps: perhapse permanent: perminant permanently: perminantly personnel: personel pivoting: pivting politics: polatics position: possition possible: possable prepared: prepaired primarily: pimarily prior: piror proceeding: proceding profession: preffeson profit: proffit profits: proffits progresses: progressess progression: progresion projects: projeccts proportions: proprtions provide: provid provisionally: provisionaly proviso: provisoe qualities: quaties queries: quies reaching: reching readjusted: reajusted received: recived receives: recives receiving: reciving recently: reciently refered: reffered regained: regined register: rgister relatively: relitivly repetitive: repetative representative: representitiv requested: rquested required: reequired research: reserch resolved: resoved responsibilities: responsibliti responsible: responcible resulting: reulting retirement: retirment routine: rouint safeguard: safegaurd salaries: salarys scheme: scheem scrutinized: scrutiniesed search: serch searching: serching secretaries: secutaries security: seurity seen: seeen segment: segemnt senior: sienior sense: sence sensible: sensable separated: seperated separation: seperation session: sesion set: et sheets: sheertes shortened: shortend shown: hown sign: eign simular: similar singular: singulaur someone: somone sources: sorces speaking: speeking standardizing: stanerdizing stopped: stoped students: studens studying: studing subsequent: subsiquent subtract: subtrcat successful: sucssuful successive: sucsesive such: shuch suffering: suufering suggested: sugested suggestion: sugestion suggests: sugests suited: suted summarys: sumarys supervision: supervison supplementary: suplementary supplements: suplements supposedly: supposidly surrounding: serounding surroundings: suroundings surveys: servays surveying: servaying system: sysem table: tasble technique: tecnique techniques: tecniques the: thw their: thier there: thear thermawear: thermawhere these: thess they: thay thoughts: thorts through: throut throughout: throuout timing: timeing titles: tittles to: ro together: togehter totally: totaly traditionally: traditionaly transactions: trasactions transportability: transportibil triangular: triangulaur umbrella: umberalla unavailable: unavailble understandable: understadable unequalled: unequaled unequivocally: unequivocaly union: unioun unique: uneque universally: universaly unnecessarily: unessasarily unnecessary: unessessay unresolved: unresloved used: usedf useful: usful user: uers utilized: utalised valuable: valuble variable: varible variant: vairiant variety: variatry virtually: vertually visitor: vistor visitors: vistors voluntary: volantry voting: voteing weapons: wepons weighted: wagted were: where when: whn whereas: wheras widely: widly will: wil within: withing would: whould written: writen years: yesars did-you-mean-1.0.0/evaluation/calculator.rb0000644000175000017500000000523412647462403021053 0ustar terceiroterceiro# -*- frozen-string-literal: true -*- require 'benchmark' def report(message, &block) time = 1000 * Benchmark.realtime(&block) if (time / 1000 / 60) >= 1 minutes = (time / 1000 / 60).floor seconds = (time % (60 * 1000)) / 1000 puts " \e[36m%2dm%.3fs:\e[0m %s" % [minutes, seconds, message] elsif (time / 1000) >= 1 seconds = (time % (60 * 1000)) / 1000 puts " \e[36m%9.3fs:\e[0m %s" % [seconds, message] else puts " \e[36m%8.1fms:\e[0m %s" % [time, message] end time end puts "\n" report "loading program" do require 'yaml' require 'set' require 'did_you_mean' begin require 'jaro_winkler' DidYouMean::JaroWinkler.module_eval do module_function def distance(str1, str2) ::JaroWinkler.distance(str1, str2) end if RUBY_ENGINE != 'jruby' end rescue LoadError, NameError end class DidYouMean::WordCollection include DidYouMean::SpellCheckable def initialize(words) @words = words end def similar_to(input, filter = '') @corrections, @input = nil, input corrections end def candidates { @input => @words } end private def normalize(str); str; end end if !defined?(DidYouMean::WordCollection) end report "loading dictionary" do yaml = open("evaluation/dictionary.yml").read yaml = YAML.load(yaml).map{|word| word.downcase.tr(" ", "_") } DICTIONARY = Set.new(yaml) end report "loading corrent/incorrect words" do COLLECTION = DidYouMean::WordCollection.new(DICTIONARY) INCORRECT_WORDS = YAML.load(open("evaluation/incorrect_words.yaml").read) end total_count = 0 correct_count = 0 words_not_corrected = [] filename = "log/words_not_corrected_#{Time.now.to_i}.yml" puts " Total number of test data: #{INCORRECT_WORDS.size} did_you_mean version: #{DidYouMean::VERSION} " report "calculating accuracy" do index = 0 INCORRECT_WORDS.each do |correct, incorrect| if DICTIONARY.include?(correct) total_count += 1 corrections = COLLECTION.similar_to(incorrect) if corrections.first == correct correct_count += 1 else words_not_corrected << { correct => incorrect, 'result' => corrections } end end index += 1 puts "processed #{index} items" if index % 100 == 0 end puts "\n" end puts " Evaulation result Total count : #{total_count} Correct count: #{correct_count} Accuracy : #{correct_count.to_f / total_count} " Dir.mkdir('log') unless File.exist?('log') File.open(filename, 'w') do |file| file.write(words_not_corrected.to_yaml) end puts "Incorrect corrections were logged to #{filename}." did-you-mean-1.0.0/evaluation/dictionary_generator.rb0000644000175000017500000000145312647462403023134 0ustar terceiroterceirorequire 'open-uri' require 'cgi' require 'json' per_page = 500 base_url = "https://simple.wiktionary.org/w/api.php?action=query&aplimit=#{per_page}&list=allpages&format=json" filename = "evaluation/dictionary.yml" count = nil apfrom = "" num = 0 titles = [] begin url = base_url + "&apfrom=#{apfrom}" puts "downloading page %2d: #{url}" % num body = open(url).read json = JSON.load(body) count = json["query"]["allpages"].size apfrom = CGI.escape(json["query"]["allpages"].last['title']) if count > 0 titles += json["query"]["allpages"].map {|hash| hash["title"] } num += 1 end while count == per_page require 'yaml' File.open(filename, 'w') do |file| file.write(titles.uniq.to_yaml) end puts " Number of titles: #{titles.uniq.size} Dictionary saved: #{filename} " did-you-mean-1.0.0/LICENSE.txt0000644000175000017500000000205712647462403016051 0ustar terceiroterceiroCopyright (c) 2014 Yuki Nishijima MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. did-you-mean-1.0.0/Rakefile0000644000175000017500000000270712647462403015675 0ustar terceiroterceirorequire 'bundler/gem_tasks' require 'rake/testtask' Rake::TestTask.new do |task| task.libs << "test" task.test_files = Dir['test/**/*_test.rb'].reject do |path| /(verbose_formatter|extra_features)/ =~ path end task.verbose = true task.warning = true end Rake::TestTask.new("test:verbose_formatter") do |task| task.libs << "test" task.pattern = 'test/verbose_formatter_test.rb' task.verbose = true task.warning = true task.ruby_opts << "-rdid_you_mean/verbose_formatter" end Rake::TestTask.new("test:extra_features") do |task| task.libs << "test" task.pattern = 'test/extra_features/**/*_test.rb' task.verbose = true task.warning = true task.ruby_opts << "-rdid_you_mean/extra_features" end task default: %i(test test:verbose_formatter test:extra_features) namespace :test do namespace :accuracy do desc "Download Wiktionary's Simple English data and save it as a dictionary" task :prepare do sh 'ruby evaluation/dictionary_generator.rb' end end desc "Calculate accuracy of the gems' spell checker" task :accuracy do if !File.exist?("evaluation/dictionary.yml") puts 'Generating dictionary for evaluation:' Rake::Task["test:accuracy:prepare"].execute puts "\n" end sh 'bundle exec ruby evaluation/calculator.rb' end end namespace :benchmark do desc "Measure memory usage by the did_you_mean gem" task :memory do sh 'bundle exec ruby benchmark/memory_usage.rb' end end did-you-mean-1.0.0/README.md0000644000175000017500000000416512647462403015507 0ustar terceiroterceiro# did_you_mean [![Gem Version](https://badge.fury.io/rb/did_you_mean.svg)](https://rubygems.org/gems/did_you_mean) [![Build Status](https://travis-ci.org/yuki24/did_you_mean.svg?branch=master)](https://travis-ci.org/yuki24/did_you_mean) 'Did you mean?' experience in Ruby. No, Really. ## Installation This gem will automatically be activated when a Ruby process starts up. No special setup is required. ## Examples ### NameError #### Correcting a Misspelled Method Name ```ruby class User attr_accessor :first_name, :last_name def to_s "#{f1rst_name} #{last_name}" # f1rst_name ??? end end user.to_s # => NameError: undefined local variable or method `f1rst_name' for # # # Did you mean? #first_name # ``` #### Correcting a Misspelled Class Name ```ruby class Book class TableOfContents # ... end end Book::TableofContents # TableofContents ??? # => NameError: uninitialized constant Book::TableofContents # # Did you mean? Book::TableOfContents # ``` #### Suggesting an instance variable name ```ruby @full_name = "Yuki Nishijima" first_name, last_name = full_name.split(" ") # => NameError: undefined local variable or method `full_name' for main:Object # # Did you mean? @full_name # ``` ### NoMethodError ```ruby # In a Rails controller: params.with_inddiferent_access # => NoMethodError: undefined method `with_inddiferent_access' for {}:Hash # # Did you mean? #with_indifferent_access # ``` ## 'Did You Mean' Experience is Everywhere _did\_you\_mean_ gem automagically puts method corrections into the error message. This means you'll have the "Did you mean?" experience almost everywhere: ![Did you mean? on BetterErrors](https://raw.githubusercontent.com/yuki24/did_you_mean/master/doc/did_you_mean_example.png) ## Contributing 1. Fork it (http://github.com/yuki24/did_you_mean/fork) 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Add some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request ## License Copyright (c) 2015 Yuki Nishijima. See MIT-LICENSE for further details. did-you-mean-1.0.0/.gitignore0000644000175000017500000000045312647462403016214 0ustar terceiroterceiro*.gem *.rbc .bundle .config .yardoc .DS_Store Gemfile.lock gemfiles/*.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp log evaluation/dictionary.yml benchmark/results ext/**/*.o ext/**/*.so ext/**/Makefile lib/**/*.so .travis.yml.osx did-you-mean-1.0.0/Gemfile0000644000175000017500000000025312647462403015515 0ustar terceiroterceirosource 'https://rubygems.org' # Specify your gem's dependencies in did_you_mean.gemspec gemspec gem 'benchmark-ips' gem 'memory_profiler' gem 'jaro_winkler', '~> 1.3.6'