elisp-refs-1.4/0000775000175000017500000000000014175024547013274 5ustar dogslegdogslegelisp-refs-1.4/test/0000775000175000017500000000000014175024547014253 5ustar dogslegdogslegelisp-refs-1.4/test/test-helper.el0000664000175000017500000000071014175024547017027 0ustar dogslegdogsleg;;; test-helper.el --- Helper for tests -*- lexical-binding: t; -*- ;; Copyright (C) 2016 Wilfred Hughes ;; Author: ;;; Code: (require 'ert) (require 'f) (let ((elisp-refs-dir (f-parent (f-dirname (f-this-file))))) (add-to-list 'load-path elisp-refs-dir)) (require 'undercover) (undercover "elisp-refs.el" (:exclude "*-test.el") (:report-file "/tmp/undercover-report.json")) ;;; test-helper.el ends here elisp-refs-1.4/test/elisp-refs-unit-test.el0000664000175000017500000004607714175024547020616 0ustar dogslegdogsleg(require 'ert) (require 'elisp-refs) ;; For Travis CI is recursing more deeply, meaning we hit recursion ;; limits. I suspect this is due to undercover collecting coverage ;; metrics. (when (getenv "TRAVIS") (message "Updating recursion limits from: max-specpdl-size: %s max-lisp-eval-depth: %s " max-specpdl-size max-lisp-eval-depth) (setq max-specpdl-size 2500) (setq max-lisp-eval-depth 1000)) (defmacro with-temp-backed-buffer (contents &rest body) "Create a temporary file with CONTENTS, and evaluate BODY whilst visiting that file." (let ((filename-sym (make-symbol "filename")) (buf-sym (make-symbol "buf"))) `(let* ((,filename-sym (make-temp-file "with-temp-buffer-and-file")) (,buf-sym (find-file-noselect ,filename-sym))) (unwind-protect (with-current-buffer ,buf-sym (insert ,contents) (set-syntax-table emacs-lisp-mode-syntax-table) (cl-letf (((symbol-function #'message) (lambda (_format-string) &rest _args))) (save-buffer)) ,@body ) (kill-buffer ,buf-sym) (delete-file ,filename-sym))))) (ert-deftest elisp-refs--format-int () "Ensure we format thousands correctly in numbers." (should (equal (elisp-refs--format-int 123) "123")) (should (equal (elisp-refs--format-int -123) "-123")) (should (equal (elisp-refs--format-int 1234) "1,234")) (should (equal (elisp-refs--format-int -1234) "-1,234")) (should (equal (elisp-refs--format-int 1234567) "1,234,567"))) (ert-deftest elisp-refs--pluralize () (should (equal (elisp-refs--pluralize 0 "thing") "0 things")) (should (equal (elisp-refs--pluralize 1 "thing") "1 thing")) (should (equal (elisp-refs--pluralize 2 "thing") "2 things")) (should (equal (elisp-refs--pluralize 1001 "thing") "1,001 things"))) (ert-deftest elisp-refs--unindent-split-properties () "Ensure we can still unindent when properties are split into separate region. Regression test for a very subtle bug." (let ((s #("e.\n" 0 2 (elisp-refs-start-pos 0) 2 3 (elisp-refs-start-pos 0)))) (elisp-refs--unindent-rigidly s))) (ert-deftest elisp-refs--sexp-positions () "Ensure we calculate positions correctly when we're considering the whole buffer." (with-temp-backed-buffer "(while list (setq len 1))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (sexp-positions (elisp-refs--sexp-positions elisp-refs-buf (point-min) (point-max)))) (should (equal sexp-positions (list '(1 26))))))) (ert-deftest elisp-refs--sexp-positions-comments () "Ensure we handle comments correctly when calculating sexp positions." (with-temp-backed-buffer "(while list ;; take the head of LIST (setq len 1))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (sexp-positions (elisp-refs--sexp-positions elisp-refs-buf (1+ (point-min)) (1- (point-max))))) ;; The position of the setq should take into account the comment. (should (equal (nth 2 sexp-positions) '(42 54)))))) (ert-deftest elisp-refs--find-calls-basic () "Find simple function calls." (with-temp-backed-buffer "(foo)" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (equal calls (list (list '(foo) 1 6))))))) (ert-deftest elisp-refs--find-calls-sharp-quote () "Find function references using sharp quotes." (with-temp-backed-buffer "(bar #'foo)" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (equal calls (list (list '(bar #'foo) 1 12))))))) (ert-deftest elisp-refs--find-calls-in-lambda () "Find function calls in lambda expressions." (with-temp-backed-buffer "(lambda (foo) (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (equal calls (list (list '(foo) 15 20))))))) (ert-deftest elisp-refs--find-calls-in-backquote () "Find function calls in backquotes. Useful for finding references in macros, but this is primarily a regression test for bugs where we miscalculated position with backquote forms." (with-temp-backed-buffer "(baz `(biz (foo 1)))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (equal calls (list (list '(foo 1) 12 19))))))) (ert-deftest elisp-refs--find-macros-improper-list () "We shouldn't crash if the source code contains improper lists." (with-temp-backed-buffer "(destructuring-bind (start . end) region\n (when foo\n (bar)))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'when #'elisp-refs--macro-p))) (should (equal calls (list (list '(when foo (bar)) 44 64))))))) (ert-deftest elisp-refs--find-calls-nested () "Find nested function calls." (with-temp-backed-buffer "(baz (bar (foo)))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (equal calls (list (list '(foo) 11 16))))))) (ert-deftest elisp-refs--find-calls-funcall () "Find calls that use funcall." (with-temp-backed-buffer "(funcall 'foo)" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (equal calls (list (list '(funcall 'foo) 1 15))))))) (ert-deftest elisp-refs--find-calls-apply () "Find calls that use apply." (with-temp-backed-buffer "(apply 'foo '(1 2))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (equal calls (list (list '(apply 'foo '(1 2)) 1 20))))))) (ert-deftest elisp-refs--find-calls-params () "Function or macro parameters should not be considered function calls." (with-temp-backed-buffer "(defun bar (foo)) (defsubst bar (foo)) (defmacro bar (foo)) (cl-defun bar (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (null calls))))) (ert-deftest elisp-refs--find-calls-declare-function () "Don't confuse `declare-function' arguments with function calls." (with-temp-backed-buffer "(declare-function bbdb-record-field \"ext:bbdb\" (record field))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'record #'elisp-refs--function-p))) (should (null calls))))) (ert-deftest elisp-refs--find-calls-let-without-assignment () "We shouldn't confuse let declarations with function calls." (with-temp-backed-buffer "(let (foo)) (let* (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (null calls))))) (ert-deftest elisp-refs--find-calls-let-with-assignment () "We shouldn't confuse let assignments with function calls." (with-temp-backed-buffer "(let ((foo nil))) (let* ((foo nil)))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (null calls))))) (ert-deftest elisp-refs--find-calls-let-with-assignment-call () "We should find function calls in let assignments." ;; TODO: actually check positions, this is error-prone. (with-temp-backed-buffer "(let ((bar (foo)))) (let* ((bar (foo))))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (equal (length calls) 2))))) (ert-deftest elisp-refs--find-calls-let-body () "We should find function calls in let body." (with-temp-backed-buffer "(let (bar) (foo)) (let* (bar) (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--function-p))) (should (equal (length calls) 2))))) (ert-deftest elisp-refs--find-macros-basic () "Find simple function calls." (with-temp-backed-buffer "(foo)" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--macro-p))) (should (equal calls (list (list '(foo) 1 6))))))) (ert-deftest elisp-refs--find-macros-in-lambda () "Find macros calls in lambda expressions." (with-temp-backed-buffer "(lambda (foo) (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--macro-p))) (should (equal calls (list (list '(foo) 15 20))))))) (ert-deftest elisp-refs--find-macros-params () "Find simple function calls." (with-temp-backed-buffer "(defun bar (foo)) (defsubst bar (foo)) (defmacro bar (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--macro-p))) (should (null calls))))) (ert-deftest elisp-refs--find-macros-let-without-assignment () "We shouldn't confuse let declarations with macro calls." (with-temp-backed-buffer "(let (foo)) (let* (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--macro-p))) (should (null calls))))) (ert-deftest elisp-refs--find-macros-let-with-assignment () "We shouldn't confuse let assignments with macro calls." (with-temp-backed-buffer "(let ((foo nil) (foo nil))) (let* ((foo nil) (foo nil)))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--macro-p))) (should (null calls))))) (ert-deftest elisp-refs--find-macros-let-with-assignment-call () "We should find macro calls in let assignments." (with-temp-backed-buffer "(let ((bar (foo)))) (let* ((bar (foo))))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--macro-p))) (should (equal (length calls) 2))))) (ert-deftest elisp-refs--find-calls-let-body () "We should find macro calls in let body." (with-temp-backed-buffer "(let (bar) (foo)) (let* (bar) (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (calls (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--macro-p))) (should (equal (length calls) 2))))) (ert-deftest elisp-refs--find-symbols () "We should find symbols, not their containing forms." (with-temp-backed-buffer "(foo foo)" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (matches (elisp-refs--read-and-find-symbol elisp-refs-buf 'foo))) (should (equal matches (list '(foo 2 5) '(foo 6 9))))))) (ert-deftest elisp-refs--find-var-basic () "Test the base case of finding variables" (with-temp-backed-buffer "foo" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (matches (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--variable-p))) (should (equal matches (list '(foo 1 4))))))) (ert-deftest elisp-refs--find-var-in-lambda () "Find variable references in lambda expressions." (with-temp-backed-buffer "(lambda (foo) (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (matches (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--variable-p))) (should (equal matches (list (list 'foo 10 13))))))) (ert-deftest elisp-refs--find-var-ignores-calls () "Function calls are not variable references." (with-temp-backed-buffer "(baz (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (matches (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--variable-p))) (should (null matches))))) (ert-deftest elisp-refs--find-var-ignores-defs () "Function definitions and macro definitions are not variable references." (with-temp-backed-buffer "(defun foo ()) (defmacro foo ())" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (matches (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--variable-p))) (should (null matches))))) (ert-deftest elisp-refs--find-var-let-without-assignments () "We should recognise let variables as variable references." (with-temp-backed-buffer "(let (foo)) (let* (foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (matches (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--variable-p))) (should (equal matches (list '(foo 7 10) '(foo 20 23))))))) (ert-deftest elisp-refs--find-var-let-with-assignments () "We should recognise let variables as variable references." (with-temp-backed-buffer "(let ((foo 1))) (let* ((foo 2)))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (matches (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--variable-p))) (should (equal matches (list '(foo 8 11) '(foo 25 28))))))) (ert-deftest elisp-refs--find-var-let-body () "We should recognise let variables as variable references." (with-temp-backed-buffer "(let ((x (1+ foo))) (+ x foo))" (let* ((elisp-refs-buf (elisp-refs--contents-buffer (buffer-file-name))) (matches (elisp-refs--read-and-find elisp-refs-buf 'foo #'elisp-refs--variable-p))) (should (equal (length matches) 2))))) (ert-deftest elisp-refs--unindent-rigidly () "Ensure we unindent by the right amount." ;; Take the smallest amount of indentation, (2 in this case), and ;; unindent by that amount. (should (equal (elisp-refs--unindent-rigidly " foo\n bar\n baz") " foo\nbar\n baz")) ;; If one of the lines has no indent, do nothing. (should (equal (elisp-refs--unindent-rigidly "foo\n bar") "foo\n bar")) ;; We should have set elisp-refs-unindented correctly. (should (equal (get-text-property 0 'elisp-refs-unindented (elisp-refs--unindent-rigidly " foo")) 2)) ;; We should still have elisp-refs-path properties in the entire string. (let ((result (elisp-refs--unindent-rigidly (propertize " foo\n bar" 'elisp-refs-path "/foo")))) (cl-loop for i from 0 below (length result) do (should (get-text-property i 'elisp-refs-path result))))) (ert-deftest elisp-refs--replace-tabs () "Ensure we replace all tabs in STRING." (let ((tab-width 4)) ;; zero tabs (should (equal (elisp-refs--replace-tabs " a ") " a ")) ;; many tabs (should (equal (elisp-refs--replace-tabs "a\t\tb") "a b")))) (ert-deftest elisp-refs--file-name-handler () "Ensure overriding `file-name-handler-alist' doesn't break our functionality." (let ((file-name-handler-alist nil) (jka-compr-verbose nil) (elisp-refs-verbose nil)) (elisp-refs-function 'buffer-substring-no-properties))) (ert-deftest elisp-refs-function () "Smoke test for `elisp-refs-function'." (let ((jka-compr-verbose nil) (elisp-refs-verbose nil)) (elisp-refs-function 'format)) (should (equal (buffer-name) "*refs: format*"))) (ert-deftest elisp-refs-macro () "Smoke test for `elisp-refs-macro'." (let ((jka-compr-verbose nil) (elisp-refs-verbose nil)) (elisp-refs-macro 'when)) (should (equal (buffer-name) "*refs: when*"))) (ert-deftest elisp-refs-variable () "Smoke test for `elisp-refs-variable'." (let ((jka-compr-verbose nil) (elisp-refs-verbose nil)) (elisp-refs-variable 'case-fold-search)) (should (equal (buffer-name) "*refs: case-fold-search*"))) (ert-deftest elisp-refs-special () "Smoke test for `elisp-refs-special'." (let ((jka-compr-verbose nil) (elisp-refs-verbose nil)) (elisp-refs-special 'prog2)) (should (equal (buffer-name) "*refs: prog2*"))) (ert-deftest elisp-refs-symbol () "Smoke test for `elisp-refs-symbol'." (let ((jka-compr-verbose nil) (elisp-refs-verbose nil)) (elisp-refs-symbol 'format-message)) (should (equal (buffer-name) "*refs: format-message*"))) (ert-deftest elisp-refs-function-prefix () "Smoke test for searching with a path prefix." (let ((jka-compr-verbose nil) (elisp-refs-verbose nil)) (elisp-refs-function 'format-message "/usr/share/emacs")) (should (equal (buffer-name) "*refs: format-message*"))) (ert-deftest elisp-refs-next-match () "Ensure movement commands move between results." (let ((jka-compr-verbose nil) (elisp-refs-verbose nil)) ;; First, get a results buffer. (elisp-refs-function 'ash)) ;; After moving to the first result, we should have a property that ;; tells us where the result came from. (elisp-refs-next-match) (should (not (null (get-text-property (point) 'elisp-refs-start-pos))))) (ert-deftest elisp-refs--start-pos () "Ensure `elisp-refs--start-pos' isn't confused by parentheses in comments." (with-temp-backed-buffer "(defun foo () ;; ( )" (should (equal (point-min) (elisp-refs--start-pos (point-max)))))) elisp-refs-1.4/README.md0000664000175000017500000001041414175024547014553 0ustar dogslegdogsleg# elisp-refs [![Build Status](https://travis-ci.org/Wilfred/elisp-refs.svg?branch=master)](https://travis-ci.org/Wilfred/elisp-refs) [![Coverage Status](https://coveralls.io/repos/github/Wilfred/elisp-refs/badge.svg?branch=master)](https://coveralls.io/github/Wilfred/elisp-refs?branch=master) [![MELPA](http://melpa.org/packages/elisp-refs-badge.svg)](http://melpa.org/#/elisp-refs) elisp-refs is an intelligent code search for Emacs lisp. It can find references to functions, macros or variables. Unlike a dumb text search, elisp-refs actually parses the code, so it's never confused by comments or variables with the same name as functions. ![screenshot](refs_screenshot.png) This is particularly useful for finding all the places a function is used, or finding examples of usage. Interested readers may enjoy my blog post: [Searching A Million Lines Of Lisp](http://www.wilfred.me.uk/blog/2016/09/30/searching-a-million-lines-of-lisp/). ## Installation Install from MELPA (recommended) or just add elisp-refs to your `load-path`. ## Commands available * `elisp-refs-function` (find function calls) * `elisp-refs-macro` (find macro calls) * `elisp-refs-variable` (find variable references) * `elisp-refs-special` (find special form calls) * `elisp-refs-symbol` (find all references to a symbol) These command search all the files currently loaded in your Emacs instance. If called with a prefix, you can limit search results to specific directories. For example: `C-u M-x elisp-refs-macro RET pcase RET ~/.emacs.d/elpa/magit-20160927.510 RET` will search for uses of `pcase` in magit: ![filtering screenshot](refs_filtered.png) ## Semantic analysis elisp-refs has *street smarts*: given `(defun foo (bar) (baz))`, it understands that `bar` is a variable and `baz` is a function. elisp-refs understands the following forms: * `defun` `defsubst` `defmacro` `cl-defun` * `lambda` * `let` `let*` * `funcall` `apply` * sharp quoted expressions (e.g. `#'some-func`) ## Limitations elisp-refs understands elisp special forms, and a few common macros. However, it **cannot understand arbitrary macros**. Therefore elisp-refs will assume that `(other-macro (foo bar))` is a function call to `foo`. If this is incorrect, you may wish to use the command `elisp-refs-symbol` to find all references to the `foo` symbol. If `other-macro` is a common macro, please consider submitting a patch to `elisp-refs--function-p` to make elisp-refs smarter. elisp-refs also does not support **indirect calls**. ``` emacs-lisp ;; Since we do a simple syntax tree walk, this isn't treated as a ;; call to foo. (let ((x (symbol-function 'foo))) (funcall x)) ;; Similarly, indirect function calls are not treated as ;; function calls. (defun call-func (x) (funcall x)) (call-func 'foo) ;; However, if you use sharp quoting, elisp-refs knows it's a function reference! (call-func #'foo) ``` ## Running tests You can run the tests with: ``` $ cask install $ cask exec ert-runner ``` ## Performance elisp-refs is CPU-intensive elisp and has been carefully optimised. You can run the benchmark script with: ``` $ cask install $ ./bench.sh ``` New features are carefully measured to ensure performance does not get worse. See elisp-refs-bench.el for more details. ## Alternative Projects **xref-find-references**: This command is included in Emacs 25.1, but it's based on a text search. It is confused by comments and strings, and cannot distinguish between functions and variables. xrefs-find-references is also line oriented, so it does not show the whole sexp that matched your search. Since it requires text files, it doesn't search built-in .el.gz files. **TAGS**: It is possible to record function references in TAGS files. Whilst [universal-ctags](https://github.com/universal-ctags/ctags) (formerly known as exuberant-ctags) does provide the ability to find references, it is not supported in its lisp parser. etags, the TAGS implementation shipped with Emacs, cannot find references (to my knowledge). **[el-search](https://elpa.gnu.org/packages/el-search.html)** allows you to search for arbitrary forms in elisp files. It's slower, but a much more general tool. Its design greatly influenced elisp-refs. **[elisp-slime-nav](https://github.com/purcell/elisp-slime-nav)** finds definitions, not references. It's a great complementary tool. elisp-refs-1.4/refs_screenshot.png0000664000175000017500000025647314175024547017217 0ustar dogslegdogslegPNG  IHDR;LL;sBIT|dtEXtSoftwaregnome-screenshot> IDATxwxUߖJЋ hRDE&ME(@",TEj@~,,);lB>Oؙ;wνSr2sgVEPLE!BV$p ݝ~6mB!e_FF^ 111wr# L2^``0<B!?ZFVhxY`A`gt: FE,B!FO>Irr2!!!*NLL z*B!ɴZ-+V$)) 5ڵk6B!(6^ڵk7oF%B!RSSɹB!9<#B!l%7T?8B!Ŀ$B!DH)B!J$B!DH)XVV/ȋM+-[<|=]{؉Ů"aZwVT_ !DY}! )SiҸ1dZg2Ū`Hsͧ}_Mff&Ul?OIBeh `dʯqpPȟ4nؐD<=<\ki&d_ !DqБF 0w <==֔w U%?ݝWª5khaCpw'++0|N:řӶu+OJJj*Xh֔1o'oMx?`߱io'^ٙի1k{xzz2zx#-Z2U3qT_HJJ *Tsҋ}tt܅ݺrr$BCpw';3dd[V mOn?t~ݟ{RO?P ߪ.sy<=y""RRiHKLC}Rbw߳sw0QѸˑ^)pz{yBUZ5N>è||T*o@hXXdQii錟4s.RNmo!.>TnW+Q4iWWWF#&Oa<չ3;g`f͝ @h!ѝ8},s?OjjϠVpwGEhX;nQNc1xyzdrSqoi٭+*߬f,ηԞ\;w֨٭+F/^ϣysxy&T܎+R_[Ki;vɉ;vFL ?_3gi׶ +TdǮ]m~|<@<8n_!DٶpއTLx%FǨ / >kBM!\\DjT|t NA51hF#'OѝÇp92C&1)G۴ĩS=vvmТY36n@:h4|78::{SW7ƌS<Ң9yth׎WFBWZh{_./'3g&5%QxGn؉.GF~fiClm{zpLbbnr0|=qpž={hҸ>Yhv幰+(*VOƘ܉lT-Vݒh ֶua4)cۛڙR|~]O7+{ƍ`h '''g~{!',4m;v~&IKO 9%%߲jhq#|KQZݙH4oڴu11fz>OYثVB'_ʀy_סa<֮] lڙvvv8DS{). @оټ~U \/߭/^Ů={XWlݶ/+*fC!2}l׫Q>/Y_ܛci9QZH$%} /Z9Fr-*B <ᘘrG`ؐ<ӥ M5,t=a`q~qP- g'OX֊{~ ځ `0Y+(ƽ=ٔd.d>Y@?W * )J5hۺ{gҴwiP\qY+p!VBFF_Ӄ,xsBX5/^@HH/тTP4^ -/j{rկWmNvUf΢ ō=?u5yc^{s m۴&55w77}ePkbGsMW/}'V%BXw쫕?x5k`4+--cO F*21b0Q:!Nhx8{ڵkmݚp2DF^aێT˜ߧIF o=T*>3~QTiՊ;cKZqbϏ2q"իUUcQ|loN9ooryVƔ !DYuVBQ2\]]eB!(h !B!B!(2FS!B؜B!%FM!BQ"$B!%BM!BQ"$B!%B tB!_F B!2ZB!B!6*xB!$O !B!B!(h !B!B!(h !B!B!(h !BUZ𭉓8<|+_~c(M^}>m M4iƶh|ksCn*<==b/)Fo".]Ưre=Ԅ^޾XFpv';3hKT*Eu$%'3w|}J>|6YYy988T36h(pWKSJbKsE>?l7}߸f+=#o~˾OHˋzu0hKTTb oMD떏лg<<_6U\!PJq 0__>47WWYi3j>~~8X\WYkQ3mŦ>k17cEj֨εh~Y1'외)B[#w;z.GSz5?V6mFL _~7WW_L+K>_07q)giR? YTt4[neLIh?< Чq2z*~~ܼ˞}SGi%q^BMGG!aC?ƫ͒Cf<8'P|1;v`Ԭ^*~Lxl\>};,+"\oWs(Rm,m7KW񙧞doߩȑXlYI<ڦ5KbhMz5ʔhҾz~_q[Wa _ :JPKBbUEJjFrs>b,y#VZ?̛3֎]1{|j5W]c)6+==114_?ujpZ1III~}$˕c5L}}V.[(ϿXFhh3ߛ'߬ޞꯖH^qyu|*VEKXd/x~qGѦu+RSRIHLI?N:cOpi}QѲcFh`o7>%KycpT##=^K{vh46fϝGJ}˕3+s0$L?s>gq11u8_;>>< A+m1p ;p7_IZ:w s36rGVFLicS^]||*2jnpYJLLdێHpwj4g*צu+jcrd$)96h >>ͮBBve>ߊlܫÆҨAJݔn\і7^:|nfHZ4k͛PYga狉OHȳX:n _Z7)j|E=!-YuEsؐA>!Y7r3`i^reOZآYMקT;Wzp綕h$>! 综+>+uF kQh4ji֩͵F @*~za3.gyTWv2 ܎cӖ?y+.VZsh{A,m7kki%VM CB닻)ԯWW^ÿݧbGs9~߯GɼT w}X:n;Q)!jyD!lIhեN!痈B8B#"ƿ EI6kLR)]R>m !~fxG 'r+j*/ϐP'N3vϕfgiY]d[7nгO?!!W'֦MPF;c?g&k8,79[ŧ<"Trg;Fа[UaTh4qI2r!+كʕ f}9"bUTza>=WW߬V\QF zh9uv,>Wmei)ޮ1sٶy'STT#==&qw4_bRBBQRJ$ttt 4<+Otȧy*: :sƦT^ۋV<̒e+Iff&G//OO.EFB[6ˋoO#q36'Oެ9\q/_9z8i$$$Khz|ayyzұC{>]hRSXrjmX3;[ϾIIM%1)hT*w;%%'y*-fl,6Յʱ+x;~ NN R}4^KMv{m ^^ԭmG۴Bh(n&--IǮ=\zlؼ[~㝊Ž+_J⼠+Dn_~ I :7F૯aʻIJNBr<߽M };Yٴo;z3|ȀMV8|V-ٸ7 FbǦj`t~W[#/GRR%j܈%*:_EZz6b;SMH-7X*&LFVfesOBbƧI?ft{yT 1o/ضs5WE\-`|iaJ텱,Ϳٽkm:-&ʁ4 ~@jL4V<\uvXoi)5,w9WI!DiP7?8JEzzGe|ֳt׎Z{eoY$S!?h !B#B!(1B!th !B#B!(h !Byq!B`\roa:m($!BQ֥:?::Zn !B8 >L6gr-$cT>ޱz޽{c߾=ׯ|JŐ!ټy#coh޼Y///ƏǷ߮!$ K~Qȑsp+W~y4kִWk4SտWZ>Ei=ʧ~ΝYd+|j8t!CspHgcL1̛QcBZ}do6By)3~)&LϪUp6}1cF/ @>|_3gңGw.O~z*tԑO d~z >3gR=G6gĈa<x{+][l*Đ!CZ :u3gh8;;yذW6~a ,4ͳ+d{)RJlp6lQ'>%WIǸY#;׫hP{$xu9&9֮ۯ*ntl M?lذlzϞ=HKK'88Dׇ{',, ?ȑ#V_ɱ,)&V'_dӣn,/ٿ8p@^|ՉhdéShѢ ٽ;Wp96m*̝!sBb0;C@vv6T^lڵpv.ٱ[O5D IDAT?M_}uL49'NvIII$%%ׯ>{%*M4iB۶myI C!fn:|+5;vXh4,;;|VeMgm\~یJRJ={v*:~^IpE]\yo5+|( ܈Z,apxFx*w]ϏKжy*5;}WCg?,Fu2X.۔ḋ\tz4M+ns.%l>|z4WWWƤI \,]0? .O*p)9v%u͜TՋ~ 1ͫ[YÇSN&= ۔+ <^F =j{Ky걤e˖;+G| ƏONLe~wz <  +Vz] ޓg7bǎFcǎROq)l4k֔}/oŠRuj?rbΘ9{N,r֗ndTUm-^=J^3s,L_ye(}cǎoe58pM63bHt,񔤲x+ 80rtttDX,##`D Vg] 5v[۷/yƑ#GR G27S)_.]X>k潍FWG0|pt*'/_.J=ōm A\\I(p"ӦC߾}Ysz=[%;;bXÖmIiX>y'f hggԻc^Q̬i|(Nu1ݭCN[ZB1Z bƌX%{5MTɗ^z믛^UhPr>gdd;&4>>3gRF<ʂxgTͦaQipt)t:][...VգV g֭f/]ij>#1z*V3W\aڴDDPmw2NMME׳lr{ݼySQE$ぜJodͺmζmqqqg᭷pI6nܤ8%bc,-VV4%Ud~WjU(}_; Ee$)j_1'$qb KR Xp>꫕f*W+V,ϳ\pn&Lx;@Q?7vtL6fsy?MnըT*jִdm4 '((4ɉ1 $$$PfM5k 999_7ox{{LJN{5|92ϏҿZ=GڛMWUunݏPBű_GAqbc, k? v#=CM쒈'ڦh+Qʜp #S]M= dJ=#T(M;?RE', 22YEa~bcc>|ǏNJj _>Ν+v$)) CJSzuu!MlzE3'3y$K6mhܸـ:ȑ3pAzzooo.]n|uc„q޽/kΆ 8pQQ#9y$קK.YT~ztܙ0xܸq>eR13}Į]mzhe,Z9:{snYծ]:u0nl=ǏC޻Uz 'OU={P^= !!!֭[gR1۷ILL">>Pۊ%{yyݹ~網'*& 9l 2bx8~5}VQ\NYގp >gEiO'DžQ-leƌZ*ۙsqRRR8q2> Yf׭`"#Ac4l/X?'N[t}?-Z4gq||c!)lh߿3f2x {Yn܈aΜ̞.=}4_~o91c_׳KlBʕ5k&ر /_Azz:> }͛,[,LIIqFك,8ȧ~FV݇j5|`}V6c5j4#F cYt:ٸѺZ=o=#ӧ xyyul[(YWhh:g 8;;qU}=Nܢ9۶ݪKz!BUZwѶ{i-ѱCޝ2`0бJC(5}.{&E(O~BQXhzץL?9::mѳ{w*H}|k223TFt5,݆N}thpi.q2VthcO|hdSjIk; =I{d2 Petd^$x Sd4y 3|0{p 18xIo[o^}[5 ^Aq8XϖїKSq8YpaF;j>}ƜY.ƞF#UMU^}fvݛd2QR)oԠւ>c̢;VqB%J$uh\ЭsK}r4dx :.eVli]JeȹY/ar(9 cͱS\ _!NPkq?θt?ͦ2Ba MF` ;;[㮮T (rPCegy**ҫGw*Wb;7g6-7}x2G}v{T'lݑ1:z)ߤ$wܫѨ82Iywꩁ:-L@]Fqkǜ]!R:}ս8^=&#Qe>|sz jzTY8\ߌOI{d2F]i]D&:֦Dmt1ڻcpAlŗaأB7ZWqgW}}WPiHkeavƨ⾡'z R:Qa1[ *5·fNF㑨Scp.OY%rA=v#z2*4NY?ruP_e*cM.>tX&McBwXhח>ߛy9-l믐8:8п__F#~xzxz嗴zjTFĥEPj;j`[޻N>3]Mc@fU}Dsd=3=.PDN1}%5`X.x%;ţBh6,D&!%2EY!N4WY˪5%׭;vZ--73dua엿54qp?̺Hy|1_ڊsiQ.]F!MǐUI~&ud4yW1TJzwgT Sy)w_}UPs/f=yPBI٦JWimgxjvWX@%vJ(C}J * F{wT b,~6:xJi6ұ\k0ڻUf_vd4|}n!iױJBRagLSrJSxgR'ۧ9zZ-`Qcbay۝T#[ho>|c]!*@V8YeL>*,末zO.jp{~).%< mO.%Re&btTl*g%\>nO﹒kKJbΡ|aA|`4%B69.F{|>QߓޝY};wVT@θf :+}Hk;EZ+w*#_ V?5$۬ˈa{>Ho1>gLO.%b0Lu{%xv)V<]AZMMB8z7+6ed@Y?+iWZܪta*MUhc܏] F̠`4pk6o9hPsO_ l.]L#mpA2Cw ??8ol ڻmU'bځu6պB> d8m@ߪz1p9I{tthðİ~VP-g"_%΋osi~V.w]ZGZN;_9.qˁ1͓8_Ԥk6)-Ws./_f1ڻp8VM鹶|_:6iAo̞8qXr^BZwpiAzu(_{{RRS9w!˦2h+ T𿓸Ep9X`oOO\bƳ]gg>bn*"ۼicjN~/\};?vʔ2}hӪvZ-zh4\rOa4-WӇP|y?g^5xKԯWwww_κ~f[Me&} *UeafV~ڪ2M4aؐAԬQd~Y} 7^NP ҧ888c.>b)4?ݻ>Vˆ;_Yj-%mءNDC;z#55O/aϾ}@ΕwGM v|s7Xv ʕIKKpRRRPmՆ ;8ȄмYS+]#ק"oVeBV'>HNI!#33۶^:##y1ԪYYI~I^tn2 IDAT5k{Eis;emE_,CNDǎ yy O ŞMIz>[/OOڶnUfY͍ +y:{~?~GiÃJu22ؖw' +9vW^fǮ,_iyJ׷gm^1 aUC-I45_ n遛ۥ<QWjO @s֪(\MM-u )g{-4&\]-Gne_`^" RW^ZBA8ؐ )II(dڊt;~0Μ=ke羽hKOڳ]'??$:RIV?nl먬ķSn o g{r<ݨT{ 7U'9){%+ыҲ $@~-Ns-9qo/%=9p1窈 #2 ]Hm~:Kϴɓ>Ãg~ 좱wX~9+uu 0]|-uVH$X6scm_QhApY\RMn53/3 cGDsf-JO5:-c09qSk0=͇8sT>%_RZFJRO;|59'HIJ %/NRZZLf}@{ٵ{sf>EbBY]}f6+? FT ;lG׳4w7ڊvwslt4r9Zy49S-Gsȷ{7)n# 8$1(( +q .\д8hΖ;)ё$&ı :PGxTUUwdU88UH$Zgͺ:;tDγxPR>jLx)=پ>A:FUi^\rr i)NP@RPtWdXQ#a;XpH@MDRb_bcbxzxuNU5ZXYFdx9=FA\ck8͎~$%LyE%Y9uq"$K?Fӑ$wsSsܷse_nnndfpg pcK  Bv.  -AA*4]r֤}ERbn>MdlJ/v>SXmooV  cS: k,H}AwUM?J7w "ɘ;{V3:*S.t[ABS"0~둏ݪΛ3//ZE E uy{m]/&55z|{>О!̘67m6NxQO~H^]̬,2vfe}]LWd^?'#ؾg  ]ÅfLL4 Zܶu{[g>BX bQHt:#j5$}f&oQHc͛yEtCu>t(nh4Fee%yr& q}:y=Od&_h4lȰn=>3Mt~>/*Fzhh_nz)d^A  \λtm...Ly,#6[?rmcW\RZ6/+,DP-JJwק7AA=ظymhu:N>'99gpiN:>2 qdiQP&gO/MZZVF1/WW0ݏ+,#USXt> u95Ǟ_i#VㄇqY/NgWF"#\]] Ӯ е9\hfeuhБÌ=n|ޭ 3^Yg0s!^0wׇwE\X7o&>E޽;G8yݻsH&yLgv:| r{v.o[1m$^yC_FN~)(==yꯏ!jCAKva̧HLH 3AK.>3Fa}FTzXĝhv6 SYuŻ$ӓ}bcy`?Xٷ'ls/4}߿3>y|2fL:E i/(d}1lKpqqf AAHcy}KS%$(9S)ǣӦ2hjjn68>  *-ms{iiVZŨ:JP 8I?Ħ[n"SAK'rOOGpS7<:!Cd  BrUAA]:AA[D)  \t\ΚHJ٩ܐZ:>73bO}t]scFQvFߋ3?fc^??ƍ%9)q}opS(:0+AF MM?J2fZ:> ԖBuL'fvc#L7 c9)(*:0+AF MH$Ə7nTnH-m21t域M?fL3a \Wz_J2~ܵb}lL .߮^ͽpwsQ#ٰq{)Lq}P*3ΛKhH5b8:u?g_,ا ӧLf!t񡸤o'}f0lP-\37iġVyΝr|#^/ WM?sjIB!(u=Ié?…s%6~]=sJmiǶ~Ntܼ> X):b]Qm{{{~<4"#"WXvҾ11gLzD-c>pr-[1 ( n9~IL< ֬ZsR>Mˁ_>v (4?9Rjjk[РfͺxIߴysf7PUu^a⃥Q[_GLTsEMM-{3GqI *"@EE7c^ϓ/W_XHxXd.4E.`CF_!! v?>toX_.UQSo=b$}q6#vZM G#\s\#sqE$[8Fkҭg~Uc/[yos?x{|W aƴTԐigŋ"cN4 M &{զ³*Μr(4AQh: &&n_Ï(<ЃaO̧ <[gu{9#e!N?BVsA7mf#1![d˯ѱ_T*5a.ڸy k «9<6-5%Gc]% /?Oz$$K\ ~]hIJI]Kȿ(4եKOB3Ƕ~NE/OPCa:uNgL|^|UF#{ÃEȻ,EPy99KI!cNF#z˭9_@ޱ " MtFiYyh5R1h4m]\\x6t8dHRdhZm^c܋D"h4HSS3;w^7o.aRWO`BG"K'3ή8] S_uM/ svhZ*OI] :Mh4RݪдOCu|l82 q| KGC8;;j(-+GјckP/WW_OlL@ACpqK%Fo/7 'ʇܼ{{S7w7R)N)/Do&g F2Zinn?/ B* wwہ>tNcKZVq^J/eR`@j0c麖}]d08v%Sf?5o 1u9۾$'k)X,y^ *zӈLf|l[=i^gWsUU6q<=O[罽ΩVㄇqY/NpFvG` gKn_A#[g9ȡ#3z4@3lZ<+҈Ջ;w.efeΧG3$ĄCjOOscyrĿ.h4rp?PUAQNSPUW)n }]2ΟA(~I;xFZ|zcq~ Z{ELt -v¢"~{狀JedD"!::e+t}AKh:`=$&$\]Xg|X<0qNzW⢗_ǟsqb{/~}'{+? H4C=Bo&$a(YwMܕFCU1\oN?IH]qVxk^|l[罽i,R{`-\¿?%G-[%eK,cy!>cw Of]k/-ui?u\B3?]{w[f=8a.|SAIUiiKKKňVZŨTnH+w77kWTA& M=ҏ?߿S!Ӷx|ddeTA&.  AAN# MAApCrYI};;.m¸$'%vv (4($hVgҥM7DQh WG G"0~qSg" 5SP 7~): ӧLf!t񡸤o'}fs#G@ee%Ҿegάf[|>r9[n㽥sL  QMvqZ6 v'u\BCB8Ϩiu'>LELq}P*V3B :E 0i y>qjs%'أӈ^buJ+ n9~IL< ֬wAkp韜LIi|')1_$0 \h2p R > @gP54c.s;gŋ"c` =֬oonV q0i ""xy TTT>}#B9WUK?(>=Zgޢ ؐ~HHp0iĄk޻+"gw> IDAT3MM hxhT7ٳo?߭6[AD)pbb9_Ąn8E/b"J1O\]p0ޢhh|bmFc^y'''V˹yy E"ƆjKeT*1 T{=ª,ڕ[AՍz>[]-xr(gAAVҹp).)%00mG2"p[-_~ɓy$[l_ ':'uc#߯]Gee%|Hp~~唤$ `0H$ ( 9NDZ  ٳV_Ս( ?'  F4PvN:Q̬,8уzW_Ly㕗x޳AϢW^u(wX~9+uu 0tOZ<+҈Ջ;wL+F9̘ѣ$̞$NN/XhuZv @tT1Q,\ rmݿT*UoA+BSڽ93"1!,뙁 N}MIi_yy0ᇸg(*+zs;.(yY(\o}}:lG׳4wd.׻nT26,ne0x5>k^*)!g9Qw&&hڙ(4M?J2Z3tT>Ǎ%9k]TF¢"ju1w{(rSPT'tv*(4H$Ə7nT/A0 L{q~=tho1cjV2AhH:Hd|}ٹkwC4 Wnh9{t+gnmʛzvxƗD;(Nˉ(?]ȟoxd2)k~hT?\j#9FdD*׮cU7i[c6y&Opxys T~>F GձȈNz>(JH{ ʢ 4}nWXh(|f-x{sۭpu*4(:sɢڍ(4Ds:jTFMc5gn%$a(|bݯP;s09,>ijjjC;O[K"+,#USXtܯ@aQNNNy$%~ӭz &bDS:3Zj;Fh gg.X핏;2*zeݐJ<:u ӧL$ Hޝkr+.9766"JQ*=ɿ>;>!7/VˌiSj:j#jjX|`4 ʯsR߯ZφJ\T*(mk}ƼfͺJji|#kg^o/Sy7y ,y [nc;܌K(t]Rp.('')F|ߥW8vC4hu:}zzxPQY @^gWsUUמ^JJe*ªذq9F.o}%.~]ɹV6<=45Yg~w=eU*>>H$VMGi Nb[+ڣ_m`[Fnn=j$3|cA}VKAKJ ZpF̙!ݎEs|F#$'%)Jz:ǎ'<,3gZ}]9RV7Ag^NIJ D\jq+Bo|Cp_hzܖ'HIIXwSN9VMM Y_竫-<\oX푏h:WWWB{t;q6kQYYoczr!W#AsrxV3F?{C0!FR nzzu<:i'},&O}7@Ӳ{^bEE 6Ouu *ŧܬe ϳ2-^s~hБÌ= AO^=ڣs[[7^yg={4p ,zv@fV`A|zA~A=CBHLH`񫯵k>YOcnNӐ-oF.$5\y{{`cʇ~:^{hzR[WǠБLXDBttV|>-k|Ą2,g9{t+F(u2.DӒ_Pt1-[%/BqUq N}MIi_m瓾y3,z9\\پc3-?;A>=Qw[Ķuiu晧gpUP\R«oEcV}zujHcs}ܺ.^{i1UUU;;|$ _-_Fw[C-7оB{ P:ANal]x|^w>\vEYTԟc@~a˼^x|<=?dƍ%9)q}opkBSQ^YI,].2*T,(}P96eA9$@Qu6N1 RIdCmXÒq]\ ;RA֬[&Krb汜q 7DLW$ MA$ ǎ7uv*7Ocy}zO?Ӗ@?* Fs-ۗFVNAH:^U *lYJe3wM7_hkލ7mf1m֑1]x tQRmuzVJM6ZэO_tG tma_CO 8ƦnvL9a6Qq3|{"{iJ? FU tEAEBsΰ.==bH?TQvY:,vC?Wow;2a17.Rg֔>{35uD@1ZIO_ ٵ/{8K} q=btuGȱ\6s[@AXn.nNN_uz6doaYu`Cg`x?ף Lu1R{* r "Fz>ahhZ~]RkS꼹p*?Q#XO|ťd"#":T*)++#-f6t(.`̛4}PռyN%'أӈ^buJƜY3Ͷ<}rl{K?`0P(5i'1m$gڹ{s-jD)]TdJJK[w{rr.FkPv%ȵC+Qh$*~vYt ntb=?{k1VLYtRBܚ r/ j_m*=s<&%O?󈦋/ =zVbtp;ҢhIR')&ү_2ۑH$<|4{=8IZ=YђsǘhШW⣰LKO0$Lg3S A#?͟5zǎsO 2QXTQ0..>\P*}#B9WUK?(>=Zgޢ ؐ~HHp0Ąk޻+"g3MM͟'f?CTd$.^DfV;vhxhT7ٳo?߭6V444Pt [-:2 tQ11ќ/Z*50- #}8Q[WGN7X^Р`X.pv2/ojg'#F&#O?M'ՖG%Οjh4krbyde>H$F"sIKŧ{VQԮG=;qL{\uH$s=8PENKRH9e'h5 /{H$Fh:٥'(8*V“mMOW  #'z,vwqcd!V ]B3;<hC@DeTTJ$:~A>[MZךsKlBX bqh:/3Mt~>/*Fzhhk[?POuc-Zi4@GNˉS/WO5*sۓ‹v.(2mg`x*E&8œĉ0p_%eGbvF Z F3mރkq^)-1Uq٭,ث=bqYD"jA^ԨkAhjaC*x@p\)Py-F#47@8hRAE\6)KJP/15...< :e2R)G2{9d$/,~fe3pvvF5'j1m ^-UߴT*ѩS>e  )+7&g F2Q܌KvtdLW" MAT*RGeՖ=b-LyI$F|\Lho8bE振Gw]6Q@Eկk} F̮ilV;r7$N_Q4ޓ5hZzӱ莻٥'p+ Й^eu-ή ;o!-WzUӥ~e.{Z&9? OuXV* T*9>tNcƍܵ QFu#zϖ`W #^׫nD</]TqI)VsUnhNx:r@vhD)wZ^+Cd`o\LZ'%OnŇj.A ܊ut/_VPzSX]hd_!F#o؟v4]"|7oFK Mjzȑc(VCo jtYgS8_*TB9,Fmޠ%S\rN IDATdvRIMoR }r֙B?Lsng:DHp~&HIJ D\J]+ qCqq8s՗Ns8o/Hْڑ1].*;'oa HNʊ@,o}x, Y}Gc( ƞgx<\.+a V\[hބd#o,sB.SyYkq`.0W {Amf3%9 :I{;g-^ ̺t}CDy͍vl'G9:܍ۣQZ[Noθ@AMc- h^yu *Mco`4ݽCo`4GɹR')A9Yq1 X  F}P7_`SV_iGE{-QCM!Hpϛ,zA=߮,~yVѫw =t0cFfH0{WO}7@Ӳ{^bWXTĐocTWנRޤ!Hbي/[m#cQh Bk|Ą2,~,?fgYIH~=U^֗7g$<VN r97gگW5G60$V&$C:vc_Asb_Π͋]^-1W?v<&]3JsٚǁΠh4r(&5N'KgGōzy<ϜaVO|3% z?1}GM8uce' 4~\x ?atp'a$Wp;Y\ z6do厨AL F}~@=We~ 2GL35 {[-'rs9zV}f%zg?CѰ>}#*U=CBO,R{S'hBt:-OO,[%/B{4ãwwtLW#AAAm.k/-~g"ta'ƱrR%$(9S;;bJo?6{4+[jF v ^C+` fb(]pg&q]Xj IŞm.Shl@MMB;A OuVg܂AA]7DMU*t.  8N\:AA:(4AABB6aX[ׇ6^lO  tEƒzy,8EE?q5 BW$ MA!}fƏ, BW#:Y꼹p*?Q#XO|rsLdDS'=B|\J%eee}ÆeL>ys&Ojw>7? @d{tԫT^Uiߘۘ3k&cٖ\Ζxo  }\qMIۗ|,)ef^hs5߾cLDh ), *ݐ:Nשxx}swvnZe]zB`M~/ߏsRbAQ"s J$:Jf&cɇî=p'/?Vp6^^NLA =Zi}sg;rK-ǭys+ֱCtqGvOpclH0 תU+Zed0qtZ$$&{RF}lRxT*Kqq1._IAAx܈DS0 Z͒+PT"K4a]hL4Dƶ?6$hZǣP(jYtt,]:w&&Wsrh4릫s15m}# h &q%3[=SR"jXXX0x޿M6 \ΩU`J۞VANL"p)++ +* prtu iӦ1 8`{N9 ˱ oOo2U'׮Ugck\.ьtgLL&qFd_ ͛z-זc&unݺycAq"M$7ԛ>ذ{b,-]_yyyy%4 ߯]ǡ*x׶5S((*2NW)1 8`n]iڤ yytԉK#ɰHommp1U6jΜ;G+"6l4IU%a<df't&&*gz*UDEҫgJV\ALT$1Q,~mߎ7a#  <jh x$N4uy@ՒJl칌 &18si4lh}SAMLFwOT}Gx 7'NTZWsr(-Yz" ^r]\HP Ccnf_w$Uߟ}T,--!/Qխݝ5ezۜJ8-iR̆ukty8xu>wFr$>BW^K4jYtt,]:w%[{(֮ | ֯3Ytr9ͥQFL5KG)eG'z>Zq99Z^ShdA(,*rG+ؽ}+ѻvܳ=prtԋ%L&)̌퉉=|NL½E u󲲯(\^PqiKN%$_Fz%cE',t:=?â%K),NR8EJ%}{о][\]'7b'Gz݆  FѴ0eG,v))16d4 UItII r{{;]rf(*<1dd27jDիܼYrm9frKlmm133Hԋ),*Urqq&y|u&M ]ick#j_y͟|e1Tr-,,kAgtT*QV/"6ld;--*5o7mooOyy9Jeyh4_Cq+?/?_R]T*ej566zmmlD?қ7n7x%ݍ>%eKChA^ϱ6ZtS((*R( #SW2pqPrLiukkkm_)֭+M4MwԉKzw)S9s<oT}lA}xKg8,-~zM?qI )h|۷]iJ8;8;WvӉIoǠh߮m12 oo/Μ bCq6i";t !Qq; ZSY+rJe1-LNtRsfhذQYRbN'6gc;ԴtvEꯧ&Ѹ8>g쏍]7ՖF_bb^}i8?m٨2>τ7۾::̜ݺCLۿ@ؽchÄS(غc',ՋiBQ3VAAx,_|K`،P\]6+N1/zH0^͛tq$x< ;AEAzepyVVVu."}`PԪ`B\5n] 96I / ڈ]AAF:3a<dfi'lWT"}OvLLTdϲ|V\ALT$1Q,.ƪ1eDEҫg:eCԱN1!lݴ6#^jÚoǎ͛S `J4\N',KFQ!m2>zT=W23 3/OO> vEӱCtqGvOpclH0 ֭UV`xnIHL$&nЀbΧ0Wn6 ͚5_^+jIk#Lnݻ[qv%,t:bbs7sssK K-)dzC۳Gw.\HVv6 OMAjJehJψ`*cxo:vdIMO]>EdtzIiCc^Jɸt'M" ugt٦7SӪ\w {OFr$>BW^OJZ/]Fii)yy$=KΝu?N{(֮ | ֯3YeG (qҭ?%'/V44@*%6\ysiԨf2Cq2|_.V =sn]>5}**FjNrmx{ە6 V\r5'GbݴJJ J Ex[7?q][H67xIB+]ֿ__B\h7lݾC7TzNҙ3ѝK/%Rllm$Tƪ\ȇ|ÇOє},\Z]ۮ C=7 "uTݺu 9# ԍщRDak[>ذ{|}Ci{{{Q*%4@u T\&JLFoM5J<;;;JoJ-(yÈ_tLqyYYٕ{(ەѝڧOJ4 u*qy[$}z7Cc'Rbb c҄HL:fKM,RLVɦ1c^*;"ecA1,\\*?(\&aiiwښ'|WukJ&Mtӝ;u"=9C1ej5gΝ._'HV%-- ֞yVVVh!:>Ν=ե3SRHˬq=cFĤ3kׯWZǁpm zw1}z_hi/?i,EBb"ǎ1;lxI{sfW5T/)mX1oL&ۋ3g# ԝѧfڤtЁD,j13OeSZZʮ=(ŴpsӋ39II F!bJe)&t"as1&8sQHMKgWqwř9s0gl,'*' p$>#xrsWs/F dŒżp~Q:p#G-ISCƏN`뎝,Zx˚֛o0q8v/Gc}3 U)e~g U:ep1-=z0}dǟ}Nҙ3l* IDATzݏ$O>kk)v*Ïx}hYl2T/)mX1oH>( O# ԝ к j|'??| Օi#Re O;as)FA0,?+򬬬ڽ|]DNU~cbkc 6"N1 i*3w6c2c|۵GRh7zu<wmHި#eljph>GfV7nTZÝ|.[Bxy:e278|.o{df8f,^|.999#9c|epoؐ`[OVhĩjݚ燓HLlŏˠOIa䫯ڋmݝfm,x{w(..#GyDߩ6غ}FJdT4˾]ɌiSi&Mr>_%-Ln^[U3nݘ6w(OwJXtŵ~_U39=Hѝ / H? uB^~>#i o@il2"(/3gR}>w6#drܚ7\KxϯNK/tPzj0#eljphiԴ*1'OLJ{8j,_JͰD!\LM>Fr$>BW^jYtt,]:w%{(֮ | ֯3Y$Oo/}RwTqX=|~8NN\^@;uN5Uv͹?2i"n͛Ms sܼ<^%/ \r2 Z lKCLhr׺z<ۣ;;wH? yFjNrژƆVjNn}źicG_m; 5-^LMm[Z6C[_jJ]OM^MH? F_DaQQ,,,=5V\[޵큓^ܕLSRhL&cnfF/N'&ޢyYW)--M_^PqWKN%$_Fz%cEPgdРAޙ9Ν:aeeU)&qJ}6cOozq%%%U*U ZRܙEn^nTibaaThiaaNYYY&9>Y*SR(++clh9}RRR\.ގ¢c$f;A22ƍ}*7oꭧ\[[[[(R*b 4E Oʅ|g<|( ?My9EQ@ő_y͟|޺Z-1-/;R,. ֶRݕJ%Vr4zח;D.Z [Mgees15=t ={tzISW66"elH "ڵu-,,ڿLŔ}aơf{Ø^ )cGDSTrY^Dl=wN[ZV>о޴=(Œb h~:Uq$%/?_R]T*ej566zmmlD .ğ4-ٞh^@Kzz?ժ,v =vhZnV$* {;;;;Joެ"bLq٣YYٕbb1__}=sROMh4pqxm%Jؐz7UNHYc!5_0qXu޾c:RƆ)Ə ѧίdf\iL&Jﴖ5OܕM;wDz%+C1ej5gΝ._'V%-- ֞yVVVh!U}*)mͥqFzR.\$5-ٱ/&VequoÎ;peSO3OuJ*R* XtFwJ1µY3뉇ޝƌs S2V-[M5~XT6R5sqr敚 =L}a㰺zj<~!} SA?h&=cdzhZN:A?v 2NPsn*cXq#-[ۿ_.ZlTwװO)Sw^^bn|ٲmS'O$6. 1&Kڟ}sm(,]qnڔ*gOt4Ǒx* =د_}D|m|̜>Gx[7:Ǖu:1ȠHF+W:q"Wsr8n1㧦LH1! ׏cxqptt$Sæ?R% uqphsEt;ƘAr$> P*F߅mʾB&u?z`xƌCC2x6~!} SA?Cq6i";t !Q ZSY+rJe1-LNtRsfhذjI8H؜y "|\2Ri3#qqq&|,,Ʉ?(RjiiуS&cme͕L>sΜG8W벤\H'=k&Z6-?g^Hп?yEUqw ||0~v [wdђFC_TZ&uT3gϱL?ˑXuSƏ3sOw몋 2You?vP>lkF0]_HѮ Ͽuߩ/elBJH? 2@j0=|0|s1fʴYauyե}n"3ܼy˄o[pw'l:26L9~A0,˳juۧ&Bkf<ݭ+#GH2=[^П&YytH? _r`=w׮,./ `gÈ<>Ӧ$9^RrՕW+^[uٿa#( ? BTԹ  xS  Ph  V%[7DO</>Y찙5V>Rg oqƘn@LT$U\NLT$zo:uW\ALT$1Q, K&M]eS;1C|۷cMxA}F?G`X\%tϱ{gU̍ ,kn?n8r_.)_jgdRG>8!éӵs133#t䚃Q1fșHaCY3:єd ̏?mw\rWΡpj#6'nnQuWb 7>Xi̿v қ4qI͸1c վ^J 6.hҸqohhIp(|۷ޞl6nE>a3BqwsBj*A]fFtc!Hd˶Dlܤ[>m$ڶf_L,<KKK~ۻ- $``nur%ߐz׶ig 7/p|qNnH; '(FV Iѫ(+-6,-M}o̭\GQW>o6V~/\3t`򘨊mOĸ8;a]-i\β_}5zI)3҆Q1< 339[wۛk싅wa`߱۷bC [jRSKn]VSˏ;SJo;w=NnkK"HUS_<ӭfsnV] XZLwwޛ3[optpݱChkֲz'o !hXJgDP0 XCh4>/XRg_L =ۃ=֔iF'`x{y^ 9s46^8t5; Gټ",))15R[L/?cLw1u/..&%6#£DMo.UlM8y>>}G{W]5 UTSˏil/Ѷv#£Ν(,*rG+ؽ}+ѻvܳ=prtԋwA{rJ -=ܑdb۞؃/CӉIhn^VUJKKuׯTnkHϸdljcWQ_g J;V׾vM<*]Xn#hk=:rSu;GʤHe/":yg8IootzF 43ܩVVVFAش2.]f kƘL&ukO8qR7Fa!iic)P(?s3/5}/TGqIwc^XTScAxt`aa^k'9>Y*SR(++clh:ũ9VRR\.ގ¢c⺤׃G3ftН LFFȾz7KS-Ln -fff ¢B)MQ%CcrM? w'51HJh[iyE؍c3y*srP\#/J%Vr4 ).',S4w -F]Ve<}ƈƘ*ƳS66)KX-wQi^w1rMe~ǘ~7nN2:T*(lm\ǿ6{ϝSGо޴=(Œb h~:|IuQTXͷ53>Q&Pp(HpV:J9",4jKc׸BbԷcLERaog7Ύқ7hþlmlؿ&Ebݸh4pObneiɃԸQ#Ǝ !t"!=t\q1V\  ݶJT%&wn;|4)3<2++Hm5{M-R1cN𻎥2,\\+͗dXZZҳ bݚҴItNHϸ?pC1ej5gΝ._'V%-- ֞yVVVh!U}]Vv:vJo_V CѨ޲KhԷ0C/|s+eŏ7V nuWldsS9>Ν=ե3SRW˶Ҹq#7n]!hղkgAp>%a3:J}ƘV%55Ntiᡛ6vQJ6킂]^e\R}jw)-R wfuu[3.g^1X.)1 <>t,W\w>ZN2x C&РA\֭2;7ٲ%{F|z ?2uqEo/ϗ\-v0uDbHIcBÑՋ86ytѵ*)Ul\xjۨgjchJ8g!gіk8x9q?>qFqnKŏt;7H1[G0sTnK]lAmǎsvŹiSNsmɄ~?v GGG2pmub;84Ź" }cNjE_÷>4@w71 _mgN,BI:sW_͛7bw32YszJVOT8?dЀ_]R[L/?cLJKm2 oo/VڲKfty(0&Mc$$꿕dW9}*RvEA,^ܟɜNJbn,4 6Vz^M1  31AϝZ]FjZ:"Sh\\ 3 sr2T=7vǡy-m8wĮ; oߕvrOm\KODSVqdDhEr>RsS9g^Hп?yE;.ѳGO5W23I:sFs9|DZs9r4z㝙3x[Wt;o?WfL~X͕L"9X;&ߏFmm/͚1!%Fo0lF(nLVY]G:d2?]Ϳ} 2x6w^bA2<++k4EDпo8#ԷX3B |ڴa[S(ػo*(YQ;̥3wYrM6{tPAPߪcjyih rR. B9 IDAT\ 4JhҤ V!1)ucbAxԹ  xS  Ph  B$&z b"ddfX7Ƅub"YJr91QٳҲ]GMM}!%Po۱c&l z[7fdĭ8]:equ{-=g(*S&SPpG0hGv}SR+xbÚly3cB32]L^~>#i o@j]:ŧ ;r½cC^P@dTt>w6#drܚ7\kԶ:Jf&cɇî={sfy6 <۽;VV-C)K}o?bbxѝL%RИqOUh*+HsjDS H4p.9_-hxy⥡Ds}Sy^DsXbu$OauFHHZTQh4\A^ScC}VH|< \DsOol+iFoKVd T*Ȩhh`ٷ+ui5.RTqU0}DRR 25?ŋ)mhl/ѶvQXH#'# ?q}Ԧ7'OқwIx{-,,=5V\[޵큓cŏL&tɿvKgnfB=;q۞؃z̝NL½E b`:mJf2))pG&I.OzF 43ܩVVV[ڴ2.]f uˤu/,*`͛a=A8yVzR\Fa›۟߮"9%2ƆơnfffSXTXi{%,u~;f y=x4cFY !hܨWƕMHݖD%%%r(,,T xyP~)r~ۻi臑Ve<}ݠ# [04nM9 kAD䪿URaog7Ύқ7h4EĆs:jlmck? phGx[7:hZN:A?v 2N@l#%o 9:8`ii; ggJ7wװO)Sw^^bn|Yn*cXq#-[ۿ_.ZlԶsm(,]qnڔ\C{2!7Ƅ0_?ѱ^M)ѩcGƾ5r>r `󖭀6Rd2^^;9:p*FA"4chÄS(غc',H|<{!#GB8XbfN]{P*i榋ř9s0gl,'*;3gt)w'N$l<>w.jui>)H֟ɜNJbn,4 6Vz^iM.ѳGO5W23I:sFs9|DZs9r4^nV\]1aa5W23t4M~?vK/KjC)u][ U[ƍ077ʕzAuuu5Ըw6#7WW {Ey,L~k<͝WmL'hhoׅ:FA,7~€=fnAzAh P4iªkHL|J6ϒ_UAq\AA08u.  <0"AAEM+KKk8 BX*C[ZqWuun[kv뵷Q{[uֽ-Ū(2T@ hd$VOosyNȗg-Pe85ϊˈA2R)Q{#ѽ{0x@ ᯣmhYyz0Ͼ}&-asSfNʢ.0kNϖ _9~oז7`+K N6Ğ;o<jwfҒS';Z-ii(ˠ?sUxrtmMNxӨ(W)毨m@_W %RnݪS9\O %-aCruw |7z۵ёLoܤ7Jxzxp99~}z.WmN~yI1yx{SPy6֬ߠ[?m$q 0#E&o]T1 8+KKFmc 7WW֭Y9tH=e/ݝ%q |+m.vь3sђ&ٍFf%̿.ٗql֊Baai͍K'td=Zme?;4iIN#7dv*ٽWͱY+:hם`im{nd$%ȝţ >O*%'i336 -Zȯ7 /y6lmy__v˷gh}q['gP2r&Zme_1??u2V򉞺}&-0+E>cbO{ߧM18.+d_ä;e  =,oM{șﹺGkŋ^̝3&2sڷmR};N<٩#ǜ2OANgd_PPe]+/Orrsn2 eƔpI]\ 棹"++]{ Ё/?ϱ'Yz--=8~yDԕӺukZɼĞ?O_{qGr.%%҈u;:S[#'7ca!`͊f㖭,\g'' ŨT*FW9OF.))S\<K$^[mrc߸ʼtb6~C$.W~!978KGS~1"rRL.ŵsh2sد MJ82`9gI9;'7|chl;lٶQ#G7%/g洩ݰܛFUs Ǧ^H$X;>]*ڹFo#m\=fO%BmRCɈ?ʥmuB 'Ǐ#;'[]O?dlw^01&P^^nR}â%KhFŤ]J`h arǕj?Qg& ^=j5.CTDdHX^i(fq\IN惏?Ar":{{{^p_Z- [J";'x:蒉!a9|?\@$6^ej?ƨFVZN#5֭jҕW\\[7Z-GQQ^8+x%7~F 86kSzZhթ?SB@:R,K8R@K.簔yMCcerFݻIȔIoѢ7f"Zr~2Ty䤜ɕMJ4Uʟ[ n)>ݘSW\fڊy';'cOÃaLJ4  ϒ1=غc')Jr mADمOY[[3r0zYfXYZ"J܈r==]&Ĥ$E$.q-R*CvoϺxsHtG22oRݹ9!//g'zV^^zso$5ݢS[KjZ;k&{"p9QUKEynknBjWs=  K$O.ź uR+RK|EPD'c!;fHmc%%%8T*KjT*6r,-2/ sPqo  Ӷu?겿r6322-=bmmMYY}m# TXTD+P_LN4kb|3@bRL?FNzq{Nߖ Jqtt` T>qc0v̝ DBƍɼQ앖'`K ;;;,--)R(b j?t }9ÇfQѰo|D˜*|kH:*m8n~I:ENr|a%w$]_ "AbaO0;}dvN*5ε 0~7NԻ*g0cb aꤷ˖3_zz[ghfI1[3 >ru9ǎ?_̝gt{6oos1.GMssxs^M#//_w32 ie995͵2q3i1((,Νqm֌gcl+5-ݟDt4yy(:Ң͝;2L| h,iqHg_B"1}b+[8h&Z84¡'\^56a<bz}Psoz7윛ӼMW.D|L6]v'zbm2jXC}ws&6W'}aЀL}\]swD/+Vb ͣǎ3mv@yo|YӧQT؃BQLKcN;TTTfzr=wg¸1̝3TvE<ňH\{X[[qaVM،U[ܶ`mxpg|;ޝ5tΘrg~p%%ݺ1}d6r_wBmX l:O?[Ѽ_ Qh:nSQ^JzQKKu3.qzt@QS|3_ƎgC5VUF޵xZ-i#Hp76 M=N7HD,Z-k7ʎݿ_O_Vco8ƴK"a޶Mu~F ƒ mr#77~k3pwg;0A7ӓ9? Q ӯXf rPI dgk c1Ϲ -uJ4/&^bh֬H#95mڔV Qٶs'?R/Wh(sf̜6mۡT*:R9{}2ꥑ͚4v Rʖ;f~mx{3n(ڷk#߸I-Zȯ7 /y6lmy__v˷?  ?hY`32OVbR#ґZɰoKk9 s(-)өq==&GsEVV"T;g6#hR},mC/ܲ}r F`$\LdʤhB$ 8yAW(JrbR"V{jc]z:}T^͞HBRRSkWM۲fa AfͰD*r6^\II YVJBn#q  4cOt.thߞٴu1ψC)--5i;Zg0cb aꤷ _H4L6:{^fFn>Hde N}(ȼl\LL\\sߡ5Wy!'? H^׏7;ۏ{ 4CyvR\Ղ2kTV#*]{P(iaR9  <$ݽg:zA瑛]>sL{'-HXr7nb˶ }AA_nFF3225a՚5{]͍cFLz   8u^.&^bh֬YyTj68 ˗nG xAAS  #MAA^D1`#eZ{}eD jo}PkR2x@ ᎐i{B_k߮-7nV.(b4vah؋XY|{11E$!aM9z3{#nj#:&`ZԴ4JӞY.(͇EMcCB|)ii 2ɽGaa#<^DH$ o{VY{&7P h:}>)< A{# 0Y2&9*H$#<>ıG\ǐ`6i‘~7WW֭Y9tH=e/ݝ%q |+m.vь3rђ&ٍFf%̿Qe q댵#%YK㺘mҺSl*#tmsl֊jl$-uXZަ GI<Ψ&-ii惕̎[E\=W-g_ƱY+b 釅57.ґhw<XH-{RCcښ c+.\OOg<߷/^+٬YAoi'ߏQ1|(2}풥h4wU1Vxzxp99~}z.WmN~y^\PΙ 9m ۶CTwucPƎzaaXZJٲ}~~/-ooƍEvmqtt$337ϲE uf^|6o݆-={v?fC2icȱϘΓ:{̩jސ1ׯg\y#1C$Ngd_PP2r8,YS1^lܲ3]"J1>h6nL&-IIt]iAh6iHHpXz=R^$ʝ[\;w֝^ #8JѤ0*TYssJtt=巊qhI(+)"'5VW}(҉MZm 2Ⱥ\ ߽3x?wcvIUphIe×>T_VJk//:w~RhKfb[v;w&|tzSnݚii=u:>>|2o.uK1E 棹"++]{Ν3{Xd)-ZhnW^xeXV[υF /ڶ˓\[B}}1e2?yRb%[mgDd˙9m*k7l 732Tgcnʘ/..&U:ט5dLYy9E \֘D#<>DJrJ_QQ,Rigj+8ѤU ~[BvrexjNy(+U䦝þ}k"ѪS/0+#ur`LIs#w]ypl WMZUqWphK4["ֳ(;g}Q~mlvߺtaGs#ǜȂp2w|[3lp^VR!.>!!D1Zfe(Jb 6;vjR,6[ScjQ?[>},mC/ٲ}r F`$\Ldʤh¤DSO͌ݖ:vSڴ SPXHc"|Ĺ8Y9aaaf'r Tzv@ШN>SͼH9z^!齦.h_.Cj%%@i|p{ $H,,OO֭\]%X\`N]K(2k#CjAqq+**tc]zO> {-#xIls==]Ĥ$E$ {fl$ >>BRRSkWM۲fa AfͰD*r6^\II YVJBnSynT\6y[ض: q}Cǔع$Ҙ GW>t0 }EPl)U:rUwЗH-|/?jXH67$߈"' ME9>]°;mB]_IɟG-er$j\i>kWI>fggWeQBLT*%_KLlRR)˽Y.C˱Siѻg(KĤ$˙8~,NZ-?}hj=PǹCo[̖mMVmu32ǃ`!^bcbǃH4q {;;Q5':Ł(݅zqؽ).U"; ǔF_lP47H= wN'[XZT 5Rkץ֦Ѻ[mcCP\푮۔J%ɲR#0iHoFBQ5԰ X\coOVvveִޡ=Xn^;e2jcq'2sn9#Cl۪Φݔ1`oOQQT6dee#<ğSPXk%%lںl4i\uy-6;-uŽʺD,,hG*ihţ-> RK;_R+NM}Ɯt+ɭ5ml=LfMn]^ѥKIc\'C4kTDjjV%99 zGGGZyyTWDLfCaѝ#r'ڷ3S< yyfV]n̘oƵn!cl)2p11A$x|}k}ٹqoז=Gmps|8;9ꊫk33s BNpP o*͚qllmѣ3ٲ%N՟2ĥE[%Yϸʹ8Ws4lO^t.}8mx=ApjsTiɻ@vbmm#DbGڹ4xmïpV[mc#ycb#';1$l~o.f㖭 `<)OLٸeI0eRVVμOc/3m3 cڵi6}njɎ{RZjywj>{Lcf3g/?-cnʘH$w!m6d 9y#<ĩGcǙ6m;t |?Eۀz5ٲ},wg.u3L?\II{nL2|]Pe[+V?ӏ>V.s4 XOA 셵ܑ[٤sJ*7Uqo "+87U C(/%=(%:~^#wh^BjE'~c }+c24lNNgd_uODG0Я9o87)ǐcN;TTTf*A4Ęvݷ2h Ç fH-6sւ2kTV#*]{P(iaR9S2mY Ӥ VVV\q_1Chݫ~[녇瑛]"sL{'-HXr7nһa"߶O~ <= C1 9:ppO 06Fx4fDFF8u8Xf AWExȈQ7?f4AOϤ7ޞ>=1glmy~\S3H2^|&Ř"N?.&^bh֬Y?blԍZ&80aðJI|VyqsiӦg|IC{>ZoLxAAS  #MAA^)Ѵز~-AO>/?Yk`HpP`MĒ_TJzt^纚SCgeD jo}PoytBg>h۵e ؚaA:%Cq#;s?qg Hp`)Z-ii(=4D}ޙ=cSos@JZÆ ~UAx LN4% a۞QFi?d.>7or#+ ʴYFAI؀: u i&͸ѣh߮-dff~&'gÃum;w+Mkۛ"[fi'ߏQ1|(2}풥zs3d]vQ#mm3qūckk[n[.sȑ*uYƼ2-))Q *ǘ/ƎzaaXZJٲ}~~/TgCcXL;^=pqvzz:DDd.}H\f 1ϲE uf^|6o݆-={vbWC^̝3&2sڷmRsu޸v5׭A 4u SHJjlZ//{ו?|r6`ȱϘΓ:{̩:EDSp0TY˓\[B}}1e2?yRס};3zD|hbWc;tsIV^gK&G^~>{$[uZoƠKDL?Fb5\JJǗ5Jbq|sd47W&%%%z͛7_`x3꜓1㰐ZfOӓ7[pbxkW66&%ƔcL}۫uaCQӦ44vlOP` +YMrj*I].]>wslIܙQMW\d˶9,~93Me F4c`â%KhF p1?j%!n}bY˘O]ihlqd4}{K4I]Ø*..&U:DSǎɉWS]`FO9Kz"T,Z RI7!aazq%9>Vˉhy -ARC\|<CBt_Cr1~Z KIlXn1?ZYYTTTP\\[>O~AK\QQ,Ri`j+:lz{(ǘa=~?V& lZW,51zlء҅}?PsJȂp2w|[3lp^erFݻIȔIoѢn 4c`O> @rJuCuNHLOϞ@Mt=Бܺu?_6.RyϡqL{k{"#8@P"}L|]INM"WgEC..Uښ^fe޶];xn8;]OO埘D+/O$Q1VthߎGtΝóeKted gccuso$5ݢS[+#:+5- ޝ5 lll^ceiYrah_x3 SƆRZZƑcVTTǙ3g֟:}{ҕpJe ZJFnt/syCs{6CuNHgKd2k,BĻuk#'|tu,"36cNQP;2n׶ OS?EE8#(2ծ{3@bRL?FIS%%%HRt_ @QWƍe1w$$ M7& JKUzh,2ȡe j?ƺTzFZfRIѧ3|`| `7 Qպ~}>cn]/gl9ƨm_aU;0uZD[;[dž;::_ήj ld2#Z͟.Oјc\cP-fKXXڛ@.\ $8xNil}\It_}IfM5vlj8H>ufK\~]S?eeeX[[Uy]QgrP(v]Y{ɪȱ޲#بrG9kT[J%j5r[lmkxaOC;Ł(ݍ%zqLyu*~/^w'+;wT(KڮP(pvrF"Ԙl*ʪuvp@UZw|Ɣ1oظL[z*~xLi\OOK?FUZ.fa}L{"#68V^^,+׬oޞGoA{|zznnU,HlNrh߮JG w5m[ "5ޗUm1j5hkת{MՒ5<[4թT o8+KJشu4iXo]~~>.~nթjINN&8(H#/R(ptt)cPƞC&{z}ҥ$BB?1KII7|jcʘ7elO/^$8({{;aiiENdl} ^Ͽf1xyzWHNI%|t8Uc;\4wsZj ]'V9ʣj9} ':& NzgǕ3_zz[ghfI1[3 >ru9ǎ?_̝gt{6oos1.d[MsԴ4ztP(&NNd2,}H7؟6m=<ݹ3͚qllVǘr16m{0~h.3bPJK^q9RۖFD0;7oNrJ -=<Ёy*M2kT?]С}{~1)/C= L2I3g2/ݲkk7JݙL&MF1il쉌_Dt޵`K"ˊUW{ALN4;δIoءgYBfM~DR+b E1-=<.&&r..9PQQuhLL>ƍa9$+BC""#qsse{ammÇ9kZ2v~MgGb+Wڼ;k&Ow[1eJJ ݻucm\OOϿ cL9{ǽys !ټm;R )Ug0k8۳eV IDATY`0yeX ɉLnh>F4#;;|bssŋHR8Sy#ةӧ_m`oo_Au@^kP{pE&o0| <ݙN}<;$ kW`M5ބ"eh ^?!#FRZZVr&^yߌAxr32j]QWYC>qSuꦹnj&( 8۳]51޼9OwF7r}%v\?V1y O\LĒ?ЬY3?8S7j@ B*%ef[QR%vâ%Khr;q҃ǑOĮ'9|dE2cd 8~${qGr.%%҈ÇLnׇ~@VTZ{yѹDo]0;|;vز<ݹ33(.֛Xɖm5r{#YrfN ͽiTۍC+'7tU/Qޭ+\%wCRT3sfijDW'~o6le8;9L׮ml$Ť]JͲr 61kAaDi,n *Rm'r[w 9%U㸒VDt4Ẅc(ҽ Wh]5$l 㧕HĆիLnR`K~1SHR]̰a$$&_ hnپ܆Q#Gcn.&2exh[*17j;`p__C7ߢVALصۤr Kr#2X|7k|\W+)iPk?AꟸFed@Rqqv6ȱU^Cvsl+++TQ/b2voBf^ɬޭwt)`Ov RRR:ƴcmŽysB펗'GrT A뺸6mFvv6M46үZ-EH cA'həX^0%:&A3i\wg|r?/~̙;Vgп?11H0u[UsyvN~ǎtW'GVwh޼9)) C}2|tgȬS9vOwB'!w10W_qu67tr1VjZ=?ÉhQ(0i1((,Νqm֌gc#HeŪ_jݞ.\|hbA'M3Ͽ_7^c8q2^nH=wg¸1̝3TvEyN䂯2kTV#*]{P(iᡋ͕gLlDs?WƎeh Hdݯ֟,`K#y_?sqn.ƴcmeK#ٰi}c~MgGb+=GJJ ݻucm\OOϿ …*m{5i삕ׯg<1 BÐZwwZX/koIk8x"FAA!lmy~\++K|Z{P  G sn{X/㩅;7n!/{\TvC Qi# B:AAL'N  H4AAzQDF&c>a<t>gA}S\efF}{ƏT*%jo=ws!AAob"weKyc*1۵e tcwXD`j5HpPY203MeGy_(ݘu2.s|ƴ?uJ4 Fv6Λ>[d^Fc7ihZRP*uz{|Gܸſ}ĵי<2h hk[;61ƣ/ yn:cjg>L cWMDBgo}/'z6}?Ka?ӧPVVǟ}NtL ?T*C 74KsoFV*UÇ֮Ӑ}ѐƴ\3i_LcH0M4vooƍEvmqtt$337;3Ϝק7r5vǟW18^7E nc &O3bPd2%Kh4cF6pVl۹.1҇عbrަ+zO 26QA3qhKʩ]xIK 2ris7|'-{#wlB-YTˀ?cj u-9i$YKIA10Ov܇-]\lʺU??x>1=92!+++tR%ȱϘΓ:{)ۦ>YƼ2-))QyXT0, .fP572,u-f;n(+K 3 0 GG`8.|_0|w=wʧ>'wKݾS^:::MϣG g&o!\,ɫ{׮̝3c2}$Z4kZoC Plmlں@nef3OOWoye3'#ޛkW^6)?`ף5̱dk}fyc}C)uwJUxx$߉|F~͒ddI"1c\͹1c ùrMҲ%}#Gbo6aQddfk1ƍ81Ф ͛ ?XbӇQ_aŪ\'IimKCVJ"=}[צn|} xj(Ez8z۪NpfW4l'R!j Nx4CR8c s#O|q&M9y4m6ZTt^1  lq=nk_'N&/42977Ĥ$oݺR;sm{g~f-nn<ݱ# ɎU6XPQ| 8;ZFcQ˫WE;g;viЀ"zV޾W:j$֬%:&JP`W쵫w)iѣHMKc-z&ݒ}9{+ϔ]HKTvi!Nj4P꼽ٻ?34 {.&MN-EVsIvfHhI3v(.0 DTLV VKjZQ11mƸ GyJ.\cݪ6K'# N3/Dr[{?10pbBrwtᩗ(eJ;r)\jc(Ӓc s#Omwi6)4eܸy\^zؠP(h4t?|Z{{.'дipmw,'e,Oymh0q1677Rի"yܽ >zݕ}`O_1lz5] ;{;}Դ4DCC54kr_ԺWd_WKgJ.%*ϬȺ!Njp ;'y|e/[ʎ-ؽ}< wwk&_/2LR--[4'!_QG۰!vvvi)oj322pwO 7ٳnq%7ژkK܌ /' ;Ge]!SPӤ` JcRǯ8ⴃ;H.B:|#&Rb,QVH&9s׍]XVEG^<=*uJb"666=c:mZBP'eNv(J㟝o`ġ#{zy&M9yq~Vv6 WT8?k)))?9{[=uMZ*,,K܏}[;Y|DގR֕ qq2vHjĩ9Lh帺Sn ?Q#3rĝ Lg\q|I:E"l8;;ckkK=Pɖ2>(+%+xPj#ompr]i*:K>NNͭĩ@Un.nnT"Z-NNNg)Nj4U*JgRڅkֲcC%reՕ"T\I1rz=?XR~ KZPdSK\+r{*iuk8Ô2(r/qPSa tų!O%XѨ54;+讋R^kKNI~}i III)%-u `_x8qvro^L&磢MK)`1i]UVıH&Mڔ%bw,am[\]\L(Lf|zD:nO.J Yw~侨ut_g-g/;`>z)USגSWbL&AarjёZ4/u?iՊ+I&BXtj?,  47NS(6l(iҔ>qKaZU8BC2Mc^W>-)?9[⁴w v %RDF;:HDY#Oy:ѼY N9C֭_<Ѷ-N)5WU*Os 6o!55O&l9**/Z̃3339mQvZf%%`0uVi4p,˘d25*ҒWK=ZSj^-Y5PzY2ϔT놔[}G4bbxw N9<~2&OW ;ZFֵ آ¢P+HQ `yqV&O#GkcFPʯ|jqoAkw/-dɺO _'7}PK0 i{CW;#^MFAZ^Hҧ6oƿ9u w77nnW%n +lc7g6 o^( 6sd2,_彛64?Mdegӡ];խ˩3gMlP|Ҁ}ߧW4%mx%1.hd$T* ^ZƆ[=-FNTt / J&JS~?},M^<~g www&uחzW_[mZ_[3ǒzUv)%3nHSЇD0exBZyӷS,b13Nf?j*>>&q_(| ^5kM)%̜cF`9t'\a{i: ۽/z̝={{;<%wRk;qŭAv$s.l)ͺӗZJ,zmkiX7ܼ0H֕ IO:e(=R}u8)10>R4q^/>?Ak^eC=c:ڷ3~6iJN'u>|{kɼ<%'m4RYs2׆ܩS'MQȵd>Z)Q&qRA(~D`ƽ:.J%n˯,k+?uhs4yYkصg/3A 2["[7TߣcbUl'GEx q8~ޚ`umǟuۣ5̱^gJ/c L)Rn& f<y~J5s4|J<*>5gco/3S鴪zO&ۊ]F'K}uX/VSݭϬϔR}SROIIػW^M=M2>qvr_ެX](ޭ&æG Uc17pQ*ٻo^1Ug>Laj/np%~nݺz\ǣJy5}ԩ|TSlQahsCˉti3.K~苇Zwk3&R0ON  5[:AA򈁦  P%@ (ش7Z^3,Cuau Z t:r]at j+Oغ~5< IDATNf^mA1ЬCBFj*gy]a^.Y/JK2tr;OɁlN2W$<͂ҋb%oL'-pZRXn2A``0p%1bϫպWXyn2ӰV hZL&#t@ܹdzƵXNl=?ݧ2[#Ot:[΅IzRc2?h FEEE~ N:uRK)Oخ݄X[#B9WD6Y'7| CzIANrF\<&]4:J\^L];gnjeIhZ͗|ˁC2q 4Ƈ*~B3n;u #^~h4jbbtVQ.-3@֭y4'Gb-^ΘFF ͛Y~C7F1Ae- ԫo^ҋxy#55kүƍ ׏D޽رs_}ĢrSGGGܲɤFPm˫^=݆֬M~ ={ՒLY<M[ȭ Zx]Jyn;t$Ӧm*=޺5))n%੡u3o8ժÙ_/'%llk w`0YeeZsf#l'_/ (**~'Ͽ`Lg^3cPXXh\חfb,[xcG 4+[搖-9z~÷cG"#3]hKZz:,YJVN6AL4,"> +Vb\/Bmy O<F!(k7 V2'6~S-_Nm*-zܽ >qzJEJEvv6 ܸyd,~CVe;zyG FFT*yaƁn\34 {.ƁA<|W8֭Ziq}z=78 XbEEcj2ܴu ^yA4a<> Hhקͭpz=7nD./e,AՒFTL m۴1pD~* Ʋaoߨu\\OijzY݃윜 -R"&fTZL&+_ϚE5Rf:t$帒 oϘNVP(N *Wf;[[ZhNCAQ6l|e/[ʎ-ؽ}< ww:F~~9{֘F[\I,yS-Jgg[߁eEPP O1viMi44y ZGŝ;{+\J~VkP_Msil\8\wKeQ-1 T/qDx!Æfѧ/*b},r1:*Sf'g'r9ɘ#̐ɐdx֮7ѭ+}(,,d葸*vvvֶ޲sKٻWOfNs|˦-[VWRnT*&G E o EE&1}j^RkM>o[JggJ鯊&RUK K 4LRtv.s/⣔22 0*i2KLn*} 7|2aܛfΝU2kz=?XR"УkVYkR>;Gj5:NN&;;~8ɤwrܲSV_j\]\LG[2[O9WQ*jqz5pQ*1mkPĩs+W2jo?ONvy9iIu98ӲqBu38)9Rgh`2K&FÆ[HMMӳvҨL u:cciGի%t:2 yGGGk`0@@4BoÆ%|TVFF^hӦɴ'ڶb\iYRTxm0uVi4e+5Rjjz#Vھ 4hnC:#M/Ԓx* vhe8P45hU(\>Ƙݻٳc>[5d1׻7i/M8Kt_Oi|89:xdyޞ1?O4}%k^gȳ6d0lEn#'7ײ[RfMQ*fkA 0x{{ ,g`jHOO_}}"2?sd2X*usè:>7ewd2](Vǧ:lŋ$]Ztv&toA8jۦ5u<=|˅=cF{.xs-9o lncL^xGjj*׮cwj3e/ / {%QTTdF2 hDͭz5gWhѼ\~7 {׮̝3c2}$Z4kZoC[^:S&N`]oMj. `洩J]V:9*9*`0pZچh4eAAvNNZ !?CG"LzAA>}dS 4rZ9##w7+i BQ:AeooW^fز۷ӝpw/5{ӪʤcifQAA!h>LNՕ̬Lѱ8;;sϫT* rq𖟯5)2a+w0~t?^ȰY'苊سw\Nz֕ qq2vHj~ev:aAAv)  <@RP:;9LVLVz;]\\!b_x8qvro^L&磢ٱsE.{eգkVYkCGᄅ2*%mTc 0PגSW3g`ONM}-ŋqidmp1.eRk4lؼT<=kW(K&09c-W,6k\2AA>qDǖztD?άoQ~}hCH˖h7m0cdDClт?i`:~l:kGu9ul`0piOȐ1y¸L�+%A#L0-9{t~8WGdh賸r5n42]^_ޤ/4\ tԉ&pZr2-RE_,fɬ'Z-vRǧBa(23* `6Y|j,`﫯wQQ5L| |}9]AA0+=%ql~ŪzUfjsA swʙ/T[P䑙yc5j*7o7 QBJAAˉS  }#  BM)ش7Z={+Ա?ë^=֬ 8p񳣣#ndm[WGߟz SeSua;YÏ&NM;3fw킇;גYv6i嵏T3ehUɶRuۡ#̜6'o_OZ&)1UM 4jx$Ub/͞MYtǎ8*&X͹1c ùrM\t^1  \bVq,wƢ:W5w,v%ӠEEIq4NLd4iGryT{uΫFjZcbyṡpelKZz:,YJVN6AL4,"\}0j+Xqq6 `G3y8oS8m۴!&&֢|jߞY3gm,=Fv9m*\:,yiْ>YX7|0v(223 ۵Լͱv*E`@ 66r>]9|};ziilܼER^S~ޡUH+~]E+4]'MKeJ_Vty3͈1c(,,4.kKbRn] RJLUMZr9>y,~Kt:n)j'Ok7CBC-hznܼS7ocsss-U^*{ؼH]%hZR҈m6/C9tbbcٰ7ϧNip0ݻv1hW!8x?X q[HV^m`hd$JV5S)R8q>> }8ЬNMmÐ-y}{~8 :X(},UV:9*9*pWr|M-$n99λ oϘNVP(]KN6XB\|dURڢT*vߤDTj7jxE5iS󳲳IrD:ޞeKٱeo㙧;nQyqY[dqy2W&9s mq>AA>}dډS --[4'!SG۰!vvv۩)))?9{[=m<5[[ !?Dz7ΜaЀs=o'?`8Ji٢sT"OsƏaO(r$(0g< [۩v.k[o^|%}xuzxy"g~UIDAT̷_> 4!eK}~:Y2T51#L0-9{MܩS'MQȵd>Z)Q&q_(| ^5kMx4 fTi6ޞ1cMhk&,_+3?'GG)^˒zk^gȳ6d0lEn#'7ײ7,b13Nf?j*>>{7^^;{6v?xgKx/7^gێ?9z,G o<~|NjcЀڳCG"q{)yd1׻7i/9x`̭gϝgw3jsA+$> JnRTv;q8~ޚ`umǟ%}xж\̭s?ϫ#G24YHNΚ7η~:Y͚T*|ΨԘ& f<˙/X<]G.9}>LykfL(L&Y~Cn f͜A]:?* wmua&~̜Nb*#=%qPV^M=J <8{y1zpZYJԹPp%~nݺzPut:CBxnp(6r9q.1m%")uKb8u.  XL:AA1AAh Eغ~Nf6^1=:;۲o_V r`=S9ARiithw7RX1<BPV;#M97zT*qDSAv&t@oΘ+I4Fvϻګ"Fj1Auy~m[ٴ7?=0lۺ5K?U&gNW/b l߼-Q#KБjm,Su\^Vy b) {gq)~]WGlg, -_62zpeVQ880|X>Z)Æ f@>%%1)[.\SPXHv zu}NrWGdwɐdx֮7Pk4&ik4r9.dg+((s3F/Fn8bQ' ѾpD޽0MGEcN4j zV˦yO-Z&\]])**B*jI{{; %Fu⧖ PZa-YBXtj?Ng\ާ7uܹMV\ILD^|ly3FDNnqU£NA4?Mdegӡ];խ˩3g1?.E ?PWȑq{V]FtڅϿ\\"OLF``WZf3ݍsWK <@SArB;ub꤉8*G ?%*:syf~1F0wtB=,$/\\Tsf^gl3,i4RɡG,WuxΎkR-믿O-˞={8y%4t0deeVkyխ[w22n l<<ݻw/A׮]y?@ZZΝرc|bZ-<ӹByիW^HLLƍJ& tUzD MvPMسg7l߾R… ԭ[&,\ UYRՕ^t _zL5$$xw'}[yOKN<gL~x-Ӿ62-Usѣʷ!:Ł-; ?-ov΢w>NEhm8xɑ;jv"J=n'T-d6F)ru:M;OѬ~>L>>jΝa/]v3~^{Οx @ݺuˬX $_PUf͚1jh53HMMBdmdLZŧ,cǾFll /f5t^>QKjrۙ8q|-|ӹsgbdggӧORSSY~=|O?M~ذaCYnIegT?&\yqN9j)Nn~-v&t`&*g=\{z\i'a;G&+?k tʂc 6iHbFR_BOJϦ6=,ڙ\9@w-)ٶdjX_sx_-n/WO7),X?+Y>:VOݻʕ~WΟ?OÆ>tރS[BVE֢};wVO~~~Q&j5PTT(tU}Rj>pvv6LAAq T*MbJgJܨ!Zɱb(-zob8/BNXՆq8\>l-1Y5AcD,e&fYc8JHtH'S.Vh W~>{OoϽ@=s >臬RD__h D0\,ݾ7;aFXVTUUep8SĹݡMU[[Z!;;yyKЀ'NHFj"]ȃܒ/Dmgxz=rrrL0DKK ~٦Ӄ֭[ÿi\lSM= |``OJ9hxv*>|s4ikgoO?N^/c ܏Bf򟿍/gB;e^/WgLPeF\錁 $ŋHO뢴a5>455b1KKKNol6/ 9s&-+Bf<1 { &&&iist:KբC:@l %W\ QQQE. hooDv]]]PTDj"]-NDAG}e"3s~bo.ž}?[Zjڎ\z5j}F5/+X t0gk^87ɗmL1C%+/?b}7 l}+`y|2oǹM~Х^Ӡ{>s2qnNO%r-wv١@fXnªU9ddd 5Մ;+'"VX ̘1YYwoiXr0w8#::=;W^b…pݒyaZ{qx  JRA`0pСg<*TV?DVVΜ92Y8[`0`0$zXV̚eĥKqv/22Z)>EBnѬ=a2PXXłR;v,J#F#6oނ l*ٮXzPߡ5*>$.+q9O' v9QoOV-Xы=6gl9ť6N5J[_*3ZDpMS l9 Ο?ݻlAqq1QZ߈s`5t9``8( LA``ِ^D` m:;oKh4l+F(J8ua]x6T,Gcc#-zٷ}6t:,_EEbIC]]hڵkPTX-^sc׮]p$e#9^DNl8zXׅƹ/&7I[U-C#WXXD]kR\ {/?G1TlɈ꒗رc3^F,HQ$jnn(c%?GƂ ^0ALt pH䮛=XIENDB`elisp-refs-1.4/Makefile0000664000175000017500000000020214175024547014726 0ustar dogslegdogslegCASK ?= cask EMACS ?= emacs all: test test: unit unit: ${CASK} exec ert-runner install: ${CASK} install bench: ./bench.sh elisp-refs-1.4/.travis.yml0000664000175000017500000000100214175024547015376 0ustar dogslegdogsleglanguage: generic sudo: false before_install: - curl -fsSkL https://gist.github.com/rejeep/ebcd57c3af83b049833b/raw > x.sh && source ./x.sh - evm install $EVM_EMACS --use --skip - cask env: - EVM_EMACS=emacs-24.4-travis - EVM_EMACS=emacs-24.5-travis - EVM_EMACS=emacs-25.1-travis - EVM_EMACS=emacs-git-snapshot-travis script: - emacs --version - make test - ./bench.sh notifications: email: false matrix: fast_finish: true allow_failures: - env: EVM_EMACS=emacs-git-snapshot-travis elisp-refs-1.4/.ert-runner0000664000175000017500000000001714175024547015374 0ustar dogslegdogsleg--reporter ert elisp-refs-1.4/refs_filtered.png0000664000175000017500000022674314175024547016635 0ustar dogslegdogslegPNG  IHDRQ{sBIT|dtEXtSoftwaregnome-screenshot> IDATxwxUlfF5T)J&M vĊRDOA@B!@z}?6ٴ yGwfvNSVMj1!Bql(*;~J.ͼyh۶-& EQ-R!BUUZ_>}pҥ+{p`Ĉ?ӉrSB!t::^ȑ#&OpU^aGJҥ3V>{QlE_ 3BQ\0wB‘˥_b2a&6nLbR^]x٧iצM@f—ФuL&4رsW./eO(UU 7pc˖ Пz11v:usnm11㣏Yq#o`ȳɋGi*/Ϗߙ#6mBZzmnl藇lt% dBcԮULFQ:CTV.zeO `Az8.?3ao(uV4k҄0TUe?p>#-=_Fjj*ߙHq8l۾Aj1ٳo'M\ٲ}V+ODx8vC\*6`S1/\;74kJXj_|5rex XsۭJdDzpzsʗgO^y䫞W::@+._A6mK~[;S?Aоvd\߬)v'Ԯm˯̈́k{9|(Ͻ4EQ=|*0݉W /Sn &?d=r6Wg_KOˋh$8DPpLfa&^6!==??Ԓ֭Zi 2"R]^%䗻@"p.^s/TV 'NKC1mJo=yϟ"G/\fͼ1fןҩ#O`=)dq>BZZ:իU^L Vry-e6{nfMkjy5 r_ 6B#Fy:~3Maƴ)TV'N#j2'RV-ڷmê5k9UkԐ$Ξ;_{6l` TRf࣏R]`AJ)S)W~Mڵ[sR~~۵%--R([ }%6nSAy r_Ug~CS)N͘6^ɡثZt9X>kׯg-T\ڵjR\w%KpT*VP7&RfM\ c+?_KQb~ 5m_fd 9Rҹ3O xCz:N:Em=|gLg WnAwohfq#YaaarϟB!DI"?!BD:B!%'BQB=B!%tB!J !B B!(A'BQNgq!B! ##B!ETq!B"`ߊ;!BQ@=wlq!B! Y i_!BD:B!%tB!J !B B!(A'BQHO!1h]ŗG9=3ʕ+?͝;Q::nЬi@7S'S7Nqqy=H ˯۰#GQR%_ߌGzSPU(u(u$0{?+gl9Lªę?TR(}ŗGҶyoy=ޏvm5B!<ЃtNiSvu@r-4$>o8y4؜N'<ԮUS/2d˼8KҴ] Ǖvr9<˄w'Qf :^m d2ǟrL|0e2. cݼP۩B(~uMD_,+6_tp: ?,̜6*U ͚17 ueZȽ?SV-};_s/E5lHev-)U*` zCU!"[>3Mԯc^jj*3?w`ҩ#O<CWFF-۶cMryٲuw7\[zG`C2lh!BBBޫwy[m'..ucxgTc^3f1oY~ԫ[g JtՇpi*V!Q/&+W#:*nwIr^ Jh_˗௥˘Ï|L`&K/`ԮY*+6i[>{<ȸW_gqI|; 7iݳngW!Wf1N"44?AFF1RukMl60;{o`0|\2kN:cG$ q]Fί_.'O^T 99Lҥb׌y CM}':˸W_ˋ#F1g֧q8\x!>Cr6Cf| LDBB'Ma ѮmRHLJ HNv;vsyM3T3=i9?R2B{~|Ye;fwmZ B?:_}3|c{|s..wӼo #"<;ʺ [L̜6$֬[όU&wtttDGEs..zuݣo;uQ<7x~=-+)).c{^OȆMYj wv+ڶ,ML>)y#,4P\doz11u{j@ONO<nڶn](vMAnB!7_\s<3tRREK^>sڵjrA|^r4uTu~yLQMEٸy ,\DAO̠v- Nl2{1nݻs܋YP抲j7۵8U}ۿBm 7vU|yTUPB+*?U*UFUU9;.B~^[V5G9s;oJXXXMLL||<5k_Jp:]^v:8իW(&O}Y_RUӅb`0pūZgAMsf꒕vܶ!WP:&>T0n 'Nb9x hWn@tE['wʶ;\OTd$G'%% =wAtT/Ŧ-[9]ymۜ=w~kmwNbb|1x^V_|Qtԑg~3gHKK/fؾ8'k֭'5-dN9Z]i8O>||0II Ĭ/bB2GÓ W~chDGEѮmxJ],\;@1ձW``¸Y̝cǎSbEoڄ1/3gsgӴq|e<4}9bh԰y "ſZԬYaC^gL&5WWPr% yg~_˖SfMZyܯ{~|Y=k]ُ/)z⎣Hdddx^r%lBQ*TX]B!Da+Q?!BN:B!%HO!$+q !BtB!(A'BQ;!BQ@TR B!DA;̙3rW!$[.)[aƨxW 5ja:~7oη~ڵk;[nՄ0?ş͛7;M7wټy#7ܥʈbذ|lܸ?(}uȯel޼{(Jwy'~5Wdߘ0mbbb;< >Ў9Wvp??˖-gаab[-mj^Oa0)OA^ʖ{5פ!C^urL:M63st֍I㡇ɓ[F y≾L.'##^S޽%l۶CUU9rVF .ر9$e}rȯ=<#^ҭ[7FɼyY-[N:Ҹu:tW߿)|g8zGGlVؿ߽6-h\֭[SR%VZMfͼ +bam,Z>}gҤ1TV O?Tl1_rx rwQ Se}rȯX,z/>؇E1mi |Op\VXƌ˩S=W^oFݘ1c&m߸|'bŊ;ǜ9sׅÇA3bz-tR~aM0eT\.{ո܉ӨQl(cX6 əTiP2Q,Iv}~~իbŊkdԨў]uE˲:h9nhVE/kUB.]cjY~eԲ/q ncZse֎@BB"ϟB i `۷^a5kז1cF+Zeԩ͑#Gׯ?u{cN-sݺÓOg֬/8p=eҥV=%==+WR 7!!!s)t錢(wo5 cʔTZ˽f͚zKWOq%-r>S[n ?E^`=ײ@ `ķ5 bccUm۶촔UF ƏǼy΢E>}:#G`ΜV?SD1e.]Ě5k504R+6GM<[QqL޳pUj~ UCf/J9tk߂r qtzCtG'J56ۦq`.֭˝?R ݾDwt-3Qjl"Jt?EzZ@GqCk})}Yѝ]v}\;Zbֺ^>ʕ+ӣGw:1116%@+ |r믞iq̋㘖ҒsaG>|S)fNa߾0a"֭#&&IEULA:t#G*k׺w{Գ%''Lbb" gmf- T<໽5kF1b$+V`Æ^CZjР>ӧ9}~TUpk=q~С/QZUϿϿu_ e$$$lrڶm뵍i9P@FF? Pxʼh9ii/-)<_2nd%̨7d`yϼ uV7oL3dddx>_xҥPZjm6 9r4z|y~osٌ HGQjU9F6mҥ˼Bھ}իW'(ȨiYƓ_{4o~V5G9Nӯ9Nc14o٬)'9--4bD7o.+W.g5tܙh9.6 tc`QFŀ>* Kބ3U+\CqtJk0fkwbst2ԨZ~H-|mOaz3z֬YC6OVbֲf>u_>}4 ^lcZb2 6 IDATnW7n<9Ŷ8櫽8\9>BCCsl\. CAZbNII ȹ2uogjj؊r[r^Zŕ#UZZ^ñX,񗀿O\b ~5Bhh_TAAF>, +W`ZSNQrUT!{Np:|ɧZ/kZwAS{%wŋ/a׮],\xв=J׮Ws}z 2g;G|ÒR?&*1w1ȜhyLZ" ٠'cp=\N;$wsRǟ@ȫkq_.##%K0lPt:昵Y/FKN3 +ʖ-ԩYrf}c~8櫽%#E!Zh5UV8p9!!҈(Ԯ]˯rTUԭ[3l6Szus? 8ڵkgAeVZhhVl޼ů|ٳZjq5|`۶L&:u5WAJKKcQlYͱd_G -s (Bpp0%iڴrrU F@ RNoC0ڷzsϟ`K[CpUlwT栤E |ۉӎrnjt J‘p~$_DDD^r͚5޽5k,P+V1f͚\p˥)fؗs%6m Ǐgs]&j^>ii/-)<_1QFzjڵkGӦMغu?]w>9zԿkCYb駟*Ν}]X6={_1̟ *Œ`Y=^^=ׯСٱco^rZ\}3F=aÆlذڶmK rՑ#Gҥ3k׮ŋ$%%{Ѳ=lٲ{PC_B>hɡÊ}Z.;1|3[9U8n~}x5Q#kVjݩ 8=r|5(UP\嚢;2.V^ ݩe bQvjFeaXj.t<+<KQ5 52sGpjuu0$K(g3yf MAY^;ū]vYeU~NDŽ ޣ(W>iYѨQ#^xyJ*{Mg__ѭ=<3fΜ9Ì3=xT@ZbԹA3v1<` 1-1-%?E碢jJ]/hn_BB8Qw(B!.gj:sLCg{P- S!!5A:B͈?!Ο@ G^H!5GSN\&$2B!?{B!ĵ@}|/wq;Q?pYż6-VY5ogP׭(`聕_-w(פ.Y.>m 9L{>H ȍVR{ hwEO ]=e.bw? Z{]tF`1ſsoAFpWGrinW48#kc8%92ڸK8DȆ7%\(X)}ۧc82[-J|xwҥ'4Ҹ?O1##ݯ{NĶ*_zx2sͯPUcǏcް1 sqr^-aiIV.{2Z,v>=5%'_Y?bK&xg(.ֺHcJ-~]`ʤu&wV;i&Sjу˄^fw̹`&'Rqn+(sDKYX $x/s/iz-^kFLz}vr˸y{^gkɏgwlBURE\rw@ /`X1T)/p~GqU2.(ÒȊ5RjkGK9l<{aFڱ( $\~[/}_:H`eއM3"ee Ɠ+;sIkޘN\/ k;#kGtOstGKs|ZVi3uٷB+2Ws fЯ/k"9%~~"s8]7/Zi\QuQlIǴ]Wg1tp>1[ ]ydrQ1XY1.SӘ_cai2{ѧ7e9ګ߂q\= CnB6bK^&z#A0hz,au')9/@XqDt Hr̷gBHz G-M`i2ӁyxAP, ϣfBK 綢8#Yӆ&ZeI}^K2;~YY*AY~iCaI^9qc(:i9OC~49*%(;_~5@7}yGp}^_8&]{b݆;UBs)!?Z@jxeH~!Qosp_?1׬YǏCS6_]{ruhŚL%~QzRoWxu,X.t8CR0\庾^y8 sХ㌨.=KP8j"SuO0G]b,+t5Ika2 58 {N_?[nXxj s/xuNABˣ?W*lp7.$j]CE패:M(4L#OgYeZ גr7[:LSG-;WhXBp~w"Gs/9%@U9cɹ8Wy99|lش0W7}> X4ǬLonz;T'+[ޘ_S!twYנJamWwg.%0\Kw_~r pn L8]M~92֙ ̜:`>sb3_w`G·u S^w.̡v,^D/Z}JQ1^KÚ7YÒc {X"t(G=G i!d0ۂ3.}ܝ?ek>OrwQCYzk܎.=CntԻn-ycX]sz='{4s( eJs=̛oO}2 8]..[p8ݱt. 0G(DB֎A5bq}(RNrwy "jP8zK;u?zӾ9)"OD|noPUL+?Z϶z}fӼ?C?sy!DhoЗh}c^|.W<:ufي4WP*,3Oڽ8v=?2/>zڵcsb6siO|ZE!z eai:}B,AzD'z)S(\Y2Oa.SetpUDz˗.!k__g="\aIk0_VeПgFd45(1oy3_a}\N}yWkZ :;X!L惢w_V,++|h5+D~ҫ= iC~ϟ3!c{~~LzЕ/En}^#Oqs䷭AuO:Jʗȸ9:LDgI$x'^,ŞlSl1=ixz=ۧykjgT 㱿4,;C6o\T0}]C~=P۪(ZR(c 5(䞋1oz;{Baz뱸JU7R*vWH+ W*™X ]shiKӧrLőW~|=CSY\ǟ쮵xĿG%$$nn5=1)q(pa[d5Wni_9 ],txf}!EkUGPy.aw? \񓨊ݟa>5([?UgWXe:OEvU% deBcv3RsQ5I 2m~"*K^Hϓy2Zf$)K>;[e\̹.ůh{v%i[8?Gzw|=;ivÌy=;پc'5kO?kn IDAT/p~GqU2㰀N_iwEE} еѥ|6ZEҽy }"e#dXCV{.Z-_:H`eއM3"ee Ɠ+;sIkޘN\/^e;#kGtOs GKs|mOy͵t:lλ뭌6̙<vo{٣+'1)_bZ @QMk݅y}Q%͞UŖ|LY)w.:=0j Vnbb:ٽ\T pm>4%(XAX ^+h)'1 AYN`i=`O oR@u{H??l~9/?Z+:Cj .;~t @{9ei$}@gt{.*cg엥TCI\_X t`'-vK=Zb8R6g7*K\>˲WY.|pJPlf~p_5ң^9q{/c(:qSC~49*KضePsMMoL5+f |v\8ܗu¨Qzz 'XAJk^˾[lќ;v҈y1p1X ::]O`<=_ `Egv[ \חË0o{Ga{xХu 5gt}[@\xjg=&(ל=KQ{嶞Ο3⁢[&Ga ` e K' 3 X=3e@~t@zF% l4rSQ>4ǿe3AQrMތMCU/wؔt2E1yOnBECPʼݘ0uACzaj?MW3T34` w6U֯.׫8Tk(ͩ,,&<T2wS?Qy#C9y>dySv/Άl*rAjhxfOu5Ǘǟ̕hҖOHnI)r0kH&=)5Fܰ}2eN7<903I],ۖ[e!VNś:cSzʯW-!=zCu Cn9xSJLŭo]y?n qz鶚,溯6P _K&Osw${zlSWT\LNN.EE.۲zRwv+Q-P)r0ujGñP]n*!=ؿLe>IAQӛ*QοtlC2W:b6)a 7 6s H*TSu\@P䆡 FQ|\b$,1NBnAO}f Нqza[qU|ؤ 9 K-81MM^clkvS-TߋצC..+L0D]#_en,TugdR8Tg~wy4hz:͐URg8D쭔ߵIxzzC6.UKh@R*scYYNo%2A*ssT^:Nn3x<픿Dԧ~jA6H *{I$@tQz!m>BTwFqXL{ƿ/R9h7Sq.-Qu"6 x| fyR{'RUi44>$"UaSk_^{>পKɥ:N s{'%uY12?Au)lV{РB ՄdnjPtiXUY|S{/"˖XP1]P\Nuu1nJoC}Ga7d<0N/rg,f i?$IHVscU`{[T5={_zc(tzCoצK{:R'PE[z0ß(GKUe<h+uZԙkϿ=f,\v#HUCk6WPial9VRr|ؔf4eKցՄMY K^8=ַC>;'H,ه@kdzC-dkL!T^(ʳ0EsTS)|6m Erj.r|?j*ۻ$ItvcU>ތC͂ZNzooo \sseR=n(J]0Utg-ۑ1X|;:'XM( bAQYG ݩgͦ)2wl Z>dң9-n| 5X/l(JObHVm:e4C#Uj#z:a7ڇclVIͲcˆ$kh|\M{{T ϡ,qt~m¦D۸g⹣wy1)ԘsyB`N +Q8r3()6[GV~Ź4>"XPknmzJsPjSdknsK6P MphZPP >~ ;W™g"#+ l6f>=Ce%,^)yjL2BP˽|J'МUqxZma}3DQ~C*VcK@RƆ2oqwHTyΎʂ}ra0w(JOa:n,DT9ۑ%Vzi/lTg6(>#N<e> wQi4ne^,ny͑/R= ϝCWڽaҤ~y? ƄIN)5۾DI":r$9٪ _GbL祪{k^BuX 7j^Jd+÷#TwN]BU:',A"/j/y,TwEI6uzUN$#nAsda~j{Q>j 3)(ʳi|l64Ǿv?r~=V{0|?FU?u_m@Pf pwyj8xSyʬ)W_s\ cF"*2LFf&;v`puBSu"sNKAc' ^ EIԧZf~*OO\ңN w;7 5_Qq#LJGKP"7T.f M鎡N{ۏUd7B? ߓuyS6 Soy7c)>rj/9$STǍKm}˩_NLbShPe(}`3(8Ǿ-eGNݯϪ>L*oxM2[@Yw1[hn\ [xx`5~-cSk)3;_3{O +CCDֻG\Z%Ǭ@s6rU@p1E9OɹIb@ m=9_[J"&wz`}⌤@QǞ8w NϪ@ps] @ \Kk^@ K_9|nn"f@ q)w0&n]Ѱl7]պW33=ʂwjr[֬P(HY5[@ .6-v!*U;. 8pe ~bB7Y Vپƪ*V^$1f(F]\uZL{],Ywy:iLS˱HpJsOrdgTU8=n(T %y>+kKFSG8e1&}yIg:@凹]aPZ1vd[>mՕ:OΩK{9ug0i zq&ymf{={ЃCN+XfN11L ]jNMĘѣP)8ޥV>e2Cl׭s7l8}~.f9RF JAA/qʷ_~8˯֫S] Ez$;'t4,,&#]Hu V Bƻg('"FeY% ])Z=n#(LUΝ9SK@DW}_#pV}I. z 7?"uV^{ >$}{Vݓ믲u~ Q̘6s%%^k:DGQXT >Xf=%%l۱;n`׋8Ƅq)~sN/=wgW_Ih)pi׮c$| b 2A؞f;u|Ogd:Ϙ6SWll߹ooo&#X1Sݷ.;3$y#;f4l  DKҥ=(Яs_zM{3wރBpż_6o_>H,?WRwXj*z;wӑ{, yuvUv9h/?ܼFl* Qw9|{ U]#hpZY^:a}9 I]qSP{Q]΃ڑC9|BQܱZtlI.ry:TJ%I /jz:̤ QTL&j5ﻗ!Ƀ ATP(Chɢb2NkS^zшlvѝ:z-qN\Mi+9>>kP[}4Gn @HV72UU:6[ ok%ɍ^f߾%g$Z˿щD$%Qw}+$aM$0*N9J:ԇ=' NaUHB$?=[OIMKd21c|큋JrΩ:6ٳt,[XRRZԇ`p:Xh5kJsmϕULJ:wBQ'lmw@  t:^^qw'j2};('w#In$?S>}?۟D"'(>9c혪 PӺȩ;4g dK==_E`xh`}Ukjf]k45=azٌ^vjɭS?$Ij2j4צ>\iz9UU?9z䶻@ Alq6;FD$ M"4jO-`Pj(I MhC:r"PjKQ09vќ>sΏlF$4wyxx-1ql SO݉cC8~ϝsJ Aor:;nf'իӹ{DZK4GN @\HGM3y ևEr?O?ijn%P<|{s (5$tE1ܽ<]:QFx܏TW Ceyd]MLtp-.=¦[IK;OCq}Cܽ9]vgdA$2jn.C3˖/3ٺm;#)1/FMa/a?/?_] E-[ģ=)"u7DuwP$iݸБf1ٳKBPQ|>U>'4a8k NuQt RǙCHU~XTʈv+~aجf*eSy"uo1o1}d>,fL~^]3yc[3a4yt "#"yV[GXX(s7j7mb߁.<8e ??sr\*C94o߹75I3rp [o;f߯x9N^ISz䴻@ ́Dz}<ϻ9oR{r@ AKRhzNNN˼E m(>-er=] AF56MGQq1 JJJjmu; c[1Vk.@Вj-QVNrþ@ +K @ "@ _+Ѱl7ޭ4w5=6@ "k%Ǝt}-ػFӳnBG m$1f(~Y@ }[z_q()-V>e2Cl׭s1lLOXX(,Z K|R61{h4~.*VNzĄhZrssY[bY~r[aETD'~P&3+~ϾXoHr2sä3xI욀^?͛ax>z[;Gdxyz2b0VY˻,JG 7rfnƹgOsr ^|9zt¯&=3{# Яsf?UYOpzcǎt⑙O۩̛ˁCHٴYQ(-/#>6Y?FII)vh42~}[ K`h%%&p6;IgKs'??WwsXz -Zm.Bϲ?q^SO%K(**nROkG _+ǩzӺ'%1_?2l`=( G{ñT;v"6#=)pf`4)(,ѣɱ~c 78OΝ>>zh,v1 j4mZ_cVjE-\>tU@ mfZoh x{NHWN7ʼn4t4eK$4w!j%&[^oã4WϜOsMhNHpWdfn0Ы+z?@ \"k=J\ll8tw3g3^xc tܙI}xHJLe]є-ugͭMfVL݉҆BC1lqWWs i'N,]%CW4@ İo+e6x'%qP>2N=cϏ\;G;y_4a<#L_4ek[3a4yt "#"_xuBC8xpSS9x0~¢o;q(\=@ .s+(**?R;AAuf?5pxfv+(K[#9tbVl6ソe@p"}@ İ@   @ \GOpѰl7ޭ4w5=7KYע$a]M+?_{96/'v5)kW꼿.08& CZVbBW~~ byyD'j;. 8pZW+cM]4g[\o<3YOݻ[[8rYY;֖"h#OpU"IcF5k[[JDGКXRYvcFjp&XEpUһWOؼekjS&3$y0fw?z:GÆ񄅅RPPKvxGdžM4 >tڷ)[bb:je?8lyxxˊeMĴɓ.y9>{.Α#Y|^>Uk diQLOgmC1̬'>bh \k3z*?\!}v''kz6on6rS '>7<=\ǹ[ic9T\V=yit\c,ZIrV6oYOr ٵ{Ok2"\г'99֛ ѣ{w~5陙to1gӬ\߾̞$ -:vHǬ,$:ʼ8tMeEaQ/2cccmF#'Oxm;vR{b0Z?zƏcu,zb&,YBQQq/l&MAlL /}|~^FyJx78WRRojۙ:~iiLw?qbٸzm}vVѾ=Vͥ:5Yr?cM ˖7݄#h랔?_wo`ƴ+)auˑˡc*`TZT N憞=E'$>>SuOJb@~}e6ڵ{ ‘޻p,5oȽwqf`4)(,ѣpȱ~c 78OΝw?ljw/CJDPAu{?z6 шKfgǩiiÝHfm͡Y$:DG; uA5f94W[dfe_~5~XjDT?erͅ$Id9ըժ֖!hOpUj0Tz9UU.`ȱ54y0]̪55i4m\ Gr5j}Z-V¡zohzٌu^s$\Crb$9sh͆68&/=_8t֬7`XlldzHV9>ޔ(sm̙4<ѽZڴ L+fOv=6GXh(# Bym=ʟoQoÁCع{7sf?CvH 2"II{Ul/Od׏DKZeػw#!1ч\k+3+nfΝ;WNkpnc4柦pEsuy?׋ӡ&oHmqe4/]#3{M[v?N+b:̝#Fpy:sJϗ]}1l;wQߟg}tҙ]PZVF} a< :&۶K|\,Ν'$˟(8}-bb$I"..Ͽm > `O!x6.4' 7բoͭ7OQQ/(yV<n3gdi8`?x?=8]:,.OR3TTT7r>ء|@S/LJqػFP*ٹkz!I&g]9NYY*Js~;>޼G;:|n1c8?aCr wdݱ(׿ Psе cFf[o_E}N›s2 I)yu Ϗl<ߋ(**?w]]f?5pxfv/\Hcgp$~"6˟b]{֣('Οm!IݒoE m(>W@Շ@6 APˑ Mgn<=yp.ZtE >bWfw>¨E**0*)i`뙖.S/aGXx'7/.^4]p"}@ #İ@   @ \GO FqhXztvEiC:pۣ;Mgn%zb&g~kpۺ´^F$ ieEg0krtBŭofx< ԷEáeB/^݈ i:c ӿ <}WfcuyNLʏ/2ZoNsinz]."QƎvѫG78uc={ЃCN+XxSyC&MSOsyp }YRbng_|DZZ>s>xyzOf **8v<1gٴe _|5nnn̘:LNx_7n raڇsAYr5A_m 42ʌ:KsһT$I>9{v Ⱦ35xi<wZw ֧n`Q6+gK_f6Qto)fc7bnQ)TЛ vfet #.#>蒞]NA繺[aZٳwmክ*GWcYO  qJϨ7$;m;0 fIrf:Ñ_Kd!te~ax#?mF?,锦Rʫuv"#"g],]{ñTec.bc:rct~X|C69qUsc\YVq _*!1t b)(@0H4J#H dak|CeM:i1AdRWd7|ܽy7忎bXA @W,JJw/ =p#r~ө-LCk9Yh'yrG=5YLr}OgХKin͗[H ޴t2?Dl)Tܽ{*T/ۛ nj1sF.߶lߟ{09>`6oYJHٴa|a"#QTuܼu[sɡFAڇV{o~kG|\83+ 777Swww-Я ;?<5C|ڬhr ;B$'&P)qWi?n_^<{)4 Ն\PyP* ԗ?<G⎤W3LB,&U hr4vDϟ@p V0%In5]NR8.0$Pj}#Xqi[r*=Ao# xϜ!3>BS>eŕA$siEُ=?Z-EExyyQ^kDѠP(X,Ç/2롭B}쳏/I dgf!=WܔGTVKڬtƚx6,k6| Aob/RO^aQQsVι x{:?JCTzm}||0VUaź!% ))xyz2b0}/:|Uk\K㉛F98əGo@6ⳗmS$+ mtk1N魽KnoK]UM4J5}CJsI=.MYo+~n"y7応R*VP &0ed;9X/oo!GskK  gs s^M݆ToKlh  8%m۵#ADGE9R69vќ>sΏDpBݻ'qGOi{DZ)WPPP@PP`h􉾴vΝJ8Gװ8vdH$`@GpaVm}KTT2W1(鼛@?W_CU34#"%L ȿg'FDt7jO4{׎n~) Lq%%zkGf IӃPWtQ݋SC._m(( {{,*{~2ȥřg#sI~xm%>.gsɖļŋbİa{-_'guvGRb"s_~őgwХKgvCiY%4$f9x?؝&NNÁC:ϯiO?T U d1Qb 鿓wL<|ٍO~%{oaY `p6SB!JA%,V gsSpSޅHhBۄcxqhA?C-U$I"..Ͽ꒮o hn @p e6x'%qPЖ_'~7v ֩.8W(jPy[&Onm&Mϒw!f9Ogl6ϫWSR㤝Lc{l6Y+W,M}N|&M)((_o p*#Al^yM9"X wPeHN*S'a \%TB~#j7܁MADwG̨nØpݜ,H aZk0Ndr, GTs0v}H,>oi۸#q(HFjIvd-}GM^7 IDAT3vsgmXmV=ʆ-Ne5g7UwWڥ3WV-Klf j"] =^}qEEE^-$I<6xgJY~@mSXQO\[r$oƑN@6Փ&7KPTTL( xGˬm;v8IJLlv6 6&>O~~>?^ ѣ{w~5陙to\[V^{ >$}{VjmMsSz憈ⅿeynuOJ⟯;X7DEF0cTΕz:\ӧg;9y@8"kF#RR.8Ng4Ǖxxq\cSyGhߞboLa{K I(f#z=k1vG=)1tr=( Grm]`ͺ_Y'32/=iGjnX|cݍmr3cTN_f}Np}ON9s*=.]:7MN@ 4bk0`0^ofa4pϖTՌ^$&$$RB`fgǩiiÝHfgTUUy6,Mں@Y9!2pssO?Śur,5HW)$%&ϿpڕL0Jdjڔ9>QmraDwV aٰ0_x@۬VGoz&ǟdbƴ)97  ևrZ-%o$ve4#W57DSwu,V+l6BS>erͅ$Id9FV5MN@ 4bt:^^|,v1ԼѸu:jXVt ?GOغju.4SCr4[,$sM6!%1Yч¡GXf g dK==EEʩ7庆.3@ FFϜOss6;K*_$4w<<<薘P'oDpBǽz 3# AorB+mMsSz.\C9/Wsii)NuСAmz@Lf3Gct4ϜS_^}Ԧ]Xg6En@wxTUwzI$Ҁ@(RTi,k/좮,uu]DE!(RC=$@Hd2}?& iwB 9'=yϝs9U L9}=|}W-;ylIKCBq4?˗ סCͷq_O߽-ii̜mڴ!+;IMIaKsJblϞsٵ{7]=7^wGPTTSdۼ#={Ç%-GuˌFؚRKdDwe;3 V 7ObB<̚-[Y$I"!!yQnDL\/Xa#>RSRHsO>_SL&,]PNtr22صgx ΂V[n /rה)}3AAo:Is>{βr:'%}Y'~=6ݷϾg7~M࣫>̀yp<7^}={ewfrzl6+YGeRsrzںn$ٶO.Q[sfP{葺垟MAAo&cӾm[}jFÌg @ hy=//OkHD|~`#^,?__nn, @ ԏm8NFr,Opގ AK!<%bcbj;fN瓾Z*v/ڡC9NOK8lS} a:Lݷn; ,?.V>5&Lʖ&MRX~.(,0S hS\G>=p:y7xj3dW_O$I5ߖ-D^:KJ0y*Up،6g9Iw--QE5ٮSp&n?<Nl^_Zes:8ޕb./n?h49e2C"$8㹹,{X@8N]:'Xv:x0ɤ;Gk.TTT{ǺulmQ[m:b`E}쫐-}|G,0znu62 me743__YL<ѣFVX/5#R˫1TCч$91y}nֳOas i׶-Fc{絹oR~2QW).2~\̂x$G4=S}'jEAְ`7(J.:gy`z 7/⒒&]k[-ITRID\O$PAHtbQYZ@qQ&aiReyJ0V!2d ;~zIn,ԧ瞥{j*#GK߾/1.(>x!Kظys5}ɯKҾ];ut)DAծW:ܰl)?ʬ|q {t9z^=z4I|}equ1ur33}m$tg?:ȜKK+(,osOE?5W_NRSRx9lش_~ELt{6b._![Y2Q"ݛ?֯p0qx9NhhO>(k֮OLLpVvەNɃ&qdR% ps3(`cf˄w$)p:n]g'ColBcd(jt?uIMI+d /Lkִm(JkXzx$'%1t_rVΏ? @Vl;!@YK/u v6gerig^NY=7q0oCsiu!e*r{Q 1scNW@iS9?^| ɦ-[~ۭOsi,?\@ G ۵cpÈ|< @Νyȇwd:T6[M8䵌Rawo6bZTj='JKLᨴHkBFRip?'兹T' ߠ& Oc=º =v @RT*ٙFԔ$󙯯,$IClGbAa!GrȜOK, )S9ϼ^Ƒ { L&uJEJ.wg`=L}jZi,?BE'4-2h ,4c׎=JRg%Ѹ*Hx;㊢<6}ejCH#!]ͳn%gQX͕mgfz(.)xNgؐ|Ojr)VWќX,h42󙯯,PT KJ9X^Rry9xCyWu vWb`ETr)9erՍ$IrzOcnwP9AE&Pq8+ jEIB[!I O[t_Z?W%o15޽基 $֗XB~]}N( pݭw)+3/󙯯,***lzJ|Zby]Hy櫨nfž?`՚5Z?__1{e+v>9kh=]P K455N@ f3*)13d5=#cGIO (0Nq9GTTdl%~oSSPiξ؈j&02V)PD&A81\xlM,ٙ VÀW{?;I$Zeek>>>tEn6 _ߔ6QQ=~Ai]gp:dggߩtDG\*.L T;/{QRRB9]$ѱCZm0 fctc>5դ|z?_ʛ@h_Td$NB[Ӷ1x _-xeKZZ=I׈2j$:Bt0 VoPCn#&S[YՓ{7[Ҙ9)z }zby陀+ؾs#o`BCBMZJA[j׋8챦zzLv [VI$I$$ijg b<?.auEO˽ўג$Gue*gٵ{]t뮣Kd"]Ŏt"#"~p:7듏3xztOn!'UU?M/J7> N4M(6uoTdeLkSȼϿޯU yBKہl$H }ᭋ2dj"&uhJNdo&Mj+ ozE2qo&8(ܼ|sO>_SL&,]PNtǀ-žmI{M(w:㧐j\7srzJX|}et "h4jV]ˎtϗRWci}~>k蜔M_gђxyߋ_rӯi|tUÇп?=>:ҫg^LxY:Y:JC ]sMAAo݋az9^6)?u7z.W>bcb̳5>9Xeښi,?_ѣ^ۼf ͑$5n_Ic7s9??V._/b5`#if̶tO}e!W功/7\7 \_WcikV1=2LUҬ[V l2SRZR&%T-xi ~nL:ҳGw-^rҼezX~ 2<3,ANe @ Zx@ @ A+B@  @ "D'@Њ@ A+B@  @ "D'@Њ@ A+B@  @ "D'@Њ@ A+B@  @ "D'@Њ@ A+B@ & ͚KY0M^ @@Tr pMvyy:x0>v8 F&4+* VqMi}ߍ*o!8oSl74rܱ3Q]Y96%QAIXĒx $PQgǻ( y"{S ( G_Nlq_wB0uOAPDj9|1zk۫\gyeGenwaIC4 :UJR c>?$ۇnwc~_BOyNkyV/l¥W&i+..fMl۾|Ii {%Ha耵h/ԦXC(yȲi>DYd-Uœt^ NݮNM?qQ1-y1EQ*3 EY :U>[X7Wz[_GYCUZјREsx ~k˜OŐޔ/iۃpBY#mu񏜼W=͖KY . ^vRG gSON0qڝ 2l̨=6Qf:>k,@q7oCeND=vp|`6c!NN|u'`6{x7@h}Џ*5Ra]J1@s΋{-nwZNw HW2ދ9PNٺ|Xbw(3+ڃ߹úln2usxPf|-$٣ܡoC%n󻓜*_J'Q/u:h|GH1_9[TT'!\-Y݂lQ}q޴уQ笨z@iI hUen9f_\-t{ 5ԛ2#le*ȫ-uՙrm/g;q۠8n|?W+hrV`2 R&{+͹4F*:S*h4fP\tmQƽw߅f#1ڴ1i׶ O?7^C޽ؾc'Omf-s8$s^kI>Oqb᪀Lf|)e?|(ơ0Bm{H2ƾC2>έ8UlE!Eg IDAT;RqBO`уq| ,FaJ,܏T!I(jQm>9"0#`XT z EI4ɻ<g34NyY:^}CY sICQ]NGQO@RRvv*]ׁk?@}| Xǩ Qmr]W"Y( ǰ $)K=0uT | kH ~DK޴$셐^ K t:J L|| [?gUN=&nΔks}y\ϵY$Ks^;$R1蟨w]^\>xMx;'>>7ڒƖ4s2j4vN'>833 dpՕWױYGV$8R$݊{(orc2K=-N\`>OAa<~: Ju2 [hF+h[DOUXyJUMd|~ySŜ<Ѫ6e~RC݊϶7NlFsgIʱ\]k|%Sqy&䴣(?Rm2Nu b:@LCUuBR^ у~AVBSuTՉǜ|;[Яz[hWX6cqvPo I©򕟯Etǡo]<|?DQr.sɔ?݆iDU0Bu:kTFW ^MMbB>>Xm69}^!I _Aa!yy'8]PuZP*֦@}t5E(X!JYꖷtS&_suPc87Tځ)NPVJ֊3(g ;lSe 8p*TPyc29ufcaMCub+.=)s="UԅOU߼Ͽ`_4-Vӻl*kslpZ>H|?S퇵u_1 0o͓E]8~ )~?V]$@v9sk1,ϷQSqjTh*LeQy"׾N;쥮_|iP!=}"Kj͇rSlȚՏ%%NMD볹 +/>ls&KM=>I{m7yݮQ ~Nl%p`LaEt&1VU3zJKwdʇea4~z: Kh/Anv]H"{u~nj}ܺENX8}T\?J^$$I g3r-Mj*4U-{p,=2Eچ+tⶣK5ծ+صoK;R:3(̥8}Bor4G=^驻$KWڳkͩ&[Ǔ+h6SZzyIa}6˥$Vڀl N.ע_~}|Do8CI q=Fi87/PWy-Y Őd58~(r0{egT}:U8 [9rUɭ[֙d-чԨ-] ..neW'Iq;x\ǡH FQq G ]e 'ʒC؃ϱG@j:e8|#Ƕޮ!>fYIˉUgr[0p;ODYrhSѯ|S{1xVŇm p`3=b!_1us3kvU%8cWP(;PNM8mf(5s~Gurz͑eúRQ`/;1^=vt{?s*w9ii~šo9i<Xխ~UamWbe߿qg+n0=G7q}^;J=ΫNmwo?(oTz<3N֣IRP1UgN;lkT |]G%'-Z-;`7݈n;թ?^E Nt|vm)?rޚU9ܺ:Sr]1܅H'<缙Cc֫ pm[:Xa\qj( >[^6{O CcqT\r(/j!E<\ ē׺I \_ V捜٭w1Ic]l8#)QgME.iYZ>O rBN%YE @pi@ A+AJd_"}Ew6>7]7amcؿK#2qjY+vk}-wRɚK4`@2cnEѪ Gr~1i~42ڥ3K_/,\j%&th$t+_L=́Uk7e8(:(Ǝ(Z)N#99TTT*3QHmYAb|1iNew~sre&MG hJ$I"1>윦k=ͅJF'1$ѣF۲/Rinyw8L~۶_-֜˕YK`ȑ(b䔠elߨd6WCIRad߁:!Ӟӯ+ۻa!XVm^e>{.1#o` ʪv->ݻuſq0ݻuARs1ܱ jȈpztJPP;p}c霔RQ\\}%$veJⶱ#k/#0=?_yo; `/hu ~!m)9q+?\^8bTk1h@Px:X4:=V£{9~!VkIg$mBRtXRyt!D' KS۪ м'%&ѻ?p 7Ïurtc;ڥ38q}/-Hg7z4*EK~")!"^}õATd$_[/u>>>xQynя^{ȠL8vmb4Vg~^&U;B\ѣF8 ~q1 z.hsdDHp0ssY,]B,O **|,Ϗ> ɉ ZCUq8Մ[,}zlL }WvbӾ=q0lVO?ܝBT׳o,m;?)$EEc(/1j6~}{q(w]H±ՍUg]eOcPPTDHHpB(,ڃR%>;v!((.I.1W@A9{=OjJgL&YGXk d`~zl,e_CnI<jKuуܼj߹$ OY~vt2? RE`TC_HtbQYZ@qQ&aiReZj6RtlBwF:\q=WaQQ|0b70^^^Kcx._'}B:p>Ry(..afWp?|P:/^}8czw: 0y* WĄSxWٸy z FsOE?5W_NRSRx9lش_~ELt{6b._s=5_|I֑#to,]B+d'_fˌP^uU~ر#sr#ߩ/͞EݬY[= 96i];t>ҵ sst¬s)~Y+?ׇ(S(//'Qz!?A/$8%%tvw$AA$%e9JҚu^=Aaa1bĒv=f#$8y'ݲjb29zAڎ~f&Cm;7( KޢT6;p_ƌK]AO`8'LxHApD_ȉtɕ* {8AU_$C*vzW}ђqDŽ?QPPkXz[~$'%1t w7nhoǟ^xc9yJF;N''Or˖%1!?z=m*Nj/t:ٴe zo(pՕW2Y~[Ӷ p˘``u1=NyL&Og>Sv'e+V?fLQ|Xf??d=D8Mrr,  ,t:̵s*ǹNTܺ&/BFvjQLaQ1(J""׷a( ),,/h,@ӹ . # lz&ɭǛ|Յ74&!!\*N/ۿS@Ri w_U\z2 $Ӊ7RZ@e9M0AwsU?"ZnS1]I\c=FJk #NɄ5P0厉#~]kj$NsΒRVU*zVyAݫ=j]XvG kbQ螊la݆7Řvqn$&$x;q>.**&$س?rؒ2aХs2m۶aي=zLv̤Cl $Z{FU x]) 쵌iQU͞c, *IuVVPc}m{z{uɜ tA!( PӉB j$ҙԔQ~Un8Q($UӘh4jVk2Vsۙ5:=3MgvK#!]rוG>_ nChlWڧ }`L"v'(*BcVӣRkCMԗwӉwwp[4w:Æ |BFf&VM!(rV(3<،~-3}{hqü:n s_{+W1wlT*k2J$!Ia8yK44[`@բT*Y9TJ>f v(;~C.yшR$ @,F~,4',f+Z~%Z6Z9Fn _;UU_%c(+3LdD;wӫgwJK0cop:ڳ']7zG ƶG._2:}K+a5^}X{wog:$)<9?VLhtWSM\Q^lgұɣ iu. ĂesZmUKyEVzNlܼx}WYZf ֬qObyٽg/.[̌OZ5 \  GdcSQQQ݇f[GV1ːAj28 r ,?˥5~2CA3=Cy9~~5^+*.&2s-pjedtASi'SPTLdxӅ( "(,,6  `;CЛ|X,jyCZT<"i2JMdB4cU$/WΏ]@9,89L`d\4&1=6~LYv(v֗)uzD׆$Ih:ncu>v:deeѣ{w:zE} #>u,f[\\={ݟs'@Ue4',[m6OX;VcZwB0:kUq`&={8Z\gsdeaϪ5kɴoc-Ξݻs$(C5YDEq,xA3떿R㯵 *\lP.{"3k ?MBӻzwA;im "$8?ojt5SX:u@䞴=ebڷ#I*+X,Ͱ޳o]}wŐFR^Gb2^6m>Ylf#*/%'o=XMu~t<C1:\q}4&]MTҕRi 0 < j"gR"y$ތawD۽I^N;w0ْ#>Pml?.O1m$[UVEtHT+(=@ M[PTT`sFؚRKdDwe;3 V ]]B|< <3k6w%-3M6degݾ=))~ilE?ʋca&]y%)]2ŗd[yيh^E֪XYi?a6mAQ86ʋr)<nq9yz'{/)&_.`('}{WҶM<[ǎKP*r?xg/K=/‹5e FLpPy'oYri^\&>F ?4۞B9~޸y ;Qǁ v33ns}2Iz֝,4^`54Z47{u3ֿ8vm?FɉCȺ7$y,{'F]Ӧ2vjf<8۶ѧf\"Z11xKm@P 9<7h=2lf:57{uvz6yoŴɓڍD>zVZ, Z,cG|wU_3n39\;t]:׼ϯtnE\N4?ݷn;R"^!?AD$Fo˖*S\R„SٷELКX|Gӊ@ 4gĀ(A䊞=  i׶-Fc{絹oR^^-^䖝6yt!@8N]:'X;+Lc"FFRhO$%$PX\īo̭SLk(3,Xi'1zH*yGzx1Y>·Yf-oVz }9y݆x1ziۼu@ \D'hуܼ<=ؘ{z&-w j|t:1LL_e-|+H1n=bc8]P{|DIY)0LZ^:q:y0L>͞}gOw|8+$>K"hPZVP(ۓOг{wt:]h41yį◟xMBNs=%d9>VTtš{FV#Ibcٙ^PXȑ ;q>.**&$8}\ZVFHpH%'hh4jVk@Xfctc>6 Ivv6t:b/85QRRR=׎:\m8{\##Z-=qw#I-FؚRKdDwW=àװi1 t:پs#o-iiHH<|<=)MĞ8f}W_ja&ILY%<_XaihW;ӹi\?|8[ҸyLc /w?KDBB<>+D ?||.\l 86vrwyJ~t0:z#lM&{p))n7Jme=w択=x{ض}'N$0 ={pV6$1Q fl6zr˘(J2¸~y{&/M@ L+z?{wU?p3 (*(Fu4˥ u55׼kKVnfijZX(i*,.,@2rtf~z9{{ [G^A>>^^}u&yWċ!6'&11x{q1m;~|rbN[qoז)!վ홡C [ ǻԨFyb%ss+-{T*IrGO&C &Ǜ)uߑFOPTdfeHݵ?o/>_F{Vp->DR/pvtԉAh7cFrq5IInN;SBC[Kh8=/hO];,,,dl\vyvNiWj!̹YK!3BdiiAiiiS\ҙ.הc.N'_;+V2v(V.r~>^MYY~^<@~)--eJ$haan^Ue\΋!<)nLL&åysJ%U_/9WcSRRmAhhb'4I {;VA&әgmeUM~8-Æ f+ӈO8$ln:VVwϒ) )-+Ag={{nefPTXZ櫍8sRY٨jJʰYfgk[)T8SP ,B!. MҵyyyKPqг}ZTXT=dffҼ"lx L&Z2 w몝h4ﯝH{tiY瓒ի+++CѐWqo׮V.ŃZ֮\~Mz!A8'4I L;LsTgxir(&IF?I7޷>CΝ)ݳ'ZٸJi 'bc};BAn^g0g=y2fxҳv DDƍCqqN̗aw)-+% b%ڳY3Cr%^U z#bæoMP-A!8w~ B}f¸9wN{YYYd2&g\JI!?? ss~>|={Ҽγ< s m9z٧8uvR.˸ј۩ǃĝGfL' ʩgq&9:jz9%L#4pGccffƭ,m;nepcL` چ唊X4  H6B иx'K-)uaKiTL&c l۱{:F>3sTZ2tSC*fpC:FcgkCh#Tdq"a뿠e˖_YY~~<7*3KJ%hт/6|C|:i_˾  )}ţ^AAFOx ͜6/~AA%Bemem[{Ҳ_TՍ3g:iY`~umՊ4C6_GTdQ,_Vcj:wڅ;c[A M$\|ej%˖Ԡ'ڥsd'4F-\bOV~Π11t>1t=^A?IdO"c|pIcfBc[Pkcj >[KAꂸ!Jhzt Gh3gǛWf[Zhv'PT4Ǝʊ9'ak)//`m˥<$ee_}Ѩ8&͍BxoՇ({'Plmm+# _ c(Ζmu "pp, PXgS1eg9~|rsxkr߹ yfPB&V~p&+[6Φb:+Jү\ᑀAę?IrJjwѰ0T*YY$$&ң{wjCXvw""2:0#H ףh8|$RK.'7/#Gҫ?tZ FÉXywA޸ پyST*EEx}l*uQ)tܩ^Mf/(~2nDRioΥN̵),,N_HN;2Lr?i阙yt3~|;y m>vJTQ\|aaaL&g˳srHK"9׺P_u6s~A͜i  MuOqJg\SJg^aQtQQrGG P/]+;f{uy9?rUL{˱\΋!<)nLL&åysJ%^y_/)ϺR_u6sII u  MBήjU5=δ#(J:š(lm6d03^F|yvYZW7q,xY٨jJʰYfgk[)c+ho8`oOAxO uO\k3pumUh쬝dxo_ڶqe_~Sؾ ع'L\\KΣIIxzxpJhHMMūczָkgKX\P訷bέ]]zޜALA &)!1o/u&.V-[2l` =coүo'+<ܨF< ?'ߏi/D-9}6r7<1q5._ބ%ژ]{2'yGwϗ8C[8@]xfPvkH1ue2^$OQmA!888 5\[vv6=ٸs4zld2A3z.9?> @=qiޜЮ7X[hcCII gϝ/NKNؽm;v՗9z٧8uv-Ru+ cק766|0.p)% >ǕkWQ*q kٔ|GZz:{9F\ֆbL]]:8b>} (R}DP 4n),{ 5 Âysi4XzgN; Щegd]!. Mצ-[ԓ87t*Pcv<=tliTA?EA˖-:A-ZņoO8Щ7!.  < e_AAA Ӧϰ01A{dY[Y{V,l(5@f۰~QDEF|[5V,g5Z׵U+"#h2{ VT'mWUn]wvlml]OJ Tb'4YGr33s񕖩j,[Sk q^[!ĞDT>A49[[Ji|48 GzS5AB )4Ip=#ܼ:OOϚûۭ+VVM²1v(6N󪎟/Zw"48aCkc:þ=\IygJnָ;yc!N՟QRRN\֭guٳwFuV*_#.%FA qOh||Zi44 JEfV ޝڐ2֬]Gaa!'ȃ Lju}p9%.Cp"6{{{^x~,8c1|q.&}R8U>^}F#ѕm IDATXt9yy9z^=O]rJ*;wқACę?Ij܌:'MT*v\9;\~Bd{#<{Yۭ+QGs k2.!-JzsZz:fff>6*߸qCO]9f/%FqOh,--(--~U:rV: t8::_;ll2ɓ.ɐd4oBܜBgz˳*UKygJƎŪE]^Ͽbǫ)++i^r,+:`ii7)1 $) jZY[YUCL;::R^^BA_j)*,BVM9^iyVv6jҲ2lmluV7XCQQ֖aC3i'gi(].5FqWh]յUˣvZ&پ}jƍ-Zh~EPc*P(ptt_u1eeOJÃ+WV FCjj*^;h׳ƽ];c6YZg8sO84G]չ+W_۷ACOh}ughղ%ɉ83p0FII)K&!x <1pk׹u3CҵKg\[Ur7<1q5._ބ%ژ]{2'yGwϗ8C[G< ?'ߏi/D-9}62ue2^$OO)1 R˾Bt,8gLחo0|b|i|S_f8klG~HDž KH`тPln?Q~9ENxe8۳{>>^䘸s,xM&x"JIIMLjDKRbA}AAⲯ  C AAFj4b=l|V,gr"#пdU٨#rAh7:p$733;gtt7#GrAgLF|ȧ+//' Qb΂  ԌуhRS K[GmDZkFލK+8K[GaVJܸp^iZx`imOiq9Ws6JU/qdxc8;Ή?QdsV2}{ = %*uw. uYQDXÏjwNt9G7h@/ZH)̛*ݺt?L# _ c(Ζmuڱd` @3gg]ζwq 666[' vÚFf1XYY/$l  4F zFyyt?tԥ*L'&qf-xtl\(+v׬]W\<lro'Җ֝zc&7':?E WuY.X;4W1(̽ ObP m~fPB&q.&'¸#ژl`&7cˆ xBG`MZڶiCy?__>xw91'~e歸k˔nyPy??6~4<=8__cٱb0XTTdT}zbۿuһgO̝B$1m'L5Yd1qDEWL pxs9%UoL$m=~ ݻa 6n]aJYɟ? nbi@ /p¯W ljAG&3C)ǶqX;4GS@nnN\IAV:6~7o2纤m8c1|q.&}&Z[caaAii)~TjCV*xܧNacueܸJN߾K3g'# B=SZeҺ_Ȯr]̌gܦs);4F[߁Jq3GaMm?frswԎmsss  ֯NvNNyvr^ Iwdd2\7͛8::3@+vvv]P`me\.8U:1rj, B1zP(cm]ٟQxC*׵wi%[N"1:q*%g~+{gF;A8?F9eSZ\đ/fZakc3ֶ5EEjڸcUʮ0+ du>,,,Ag:9( B29׮gJoL[[X:*.e\s_[`nygPƅKyUJ}8ycamO2c\:YWP`aeK[,[Ii4RSSx7kkk۵1J8W^_YYgaeeI~}u֯޽"llljŋt3ݹ\6AAh8FKHLdj)z::˟ 3\9Jq1{IljAϱoRV\-y7.x EJUXXe$WicX>:ŵS/(SCPH?A#< =G)WkD^?,ywˬӉ!9/MJVVV+NNڪb\՗-oX]JJ9^go//|Xx qĞ<ѺukRRSi׶-~,Y\tܾB~S[J;vݥo3,bw^v$o  уc1Ǚ=c:~W G$.ȻLeRvs|[̹F__(+."O~['W4e(o_''-u=jDէj9?FAF!-=z0qԽ.b|p'Oy_t>1t=QBCjL&#pp~:YmLn^CHL3kԧi9TN>Щ/99ܼu 2ȃY3FJ=ŅbjysU̞9"2Rܠm6|Jˮ\@ꏈa/;nf¸ZpOǣ:v'*2֭k!ciiԗۍq_aĄm{'bHOmsCTd3yir(gLݼ:6 c4q{w~ޝ3嗐d2u}8_[ˁ}{ٽm+KZ}ɔncc׮m[B3_mõU+|} ̦ؼ+}ZM5g lG=[7ofϘ^_v,0~P_R;"/Ϥ~;?KC}EJ!}Gg 46#\оg&|uMWܺu#T]h!#&l-m۴~|rbN[qoז)!%" Yq巓חK/qFP}ϛͤAϞq JHD6nd^<8})sV* y3o,nNvv}!o/o伷Cڻ3%4̬,v  wSݝpvrⱾ}FTR\__cٱk7EEE6܌-2>zp|O̺_ݳ' ATtϚWǎ,[xJR&gTdž)!RgG }:~ċ!6'&11x{qcPʶߡT*IrGt`?o.֪2֬]Gaa!'ȃ rw)iSBC[Kh8=/c!4ef/(U׮_׹Br2=ܫDq4xyvJTQ s kGٙn][hј]B_}(..Mjwg˲srHKRmUǔ9C٧?FJF0dfeiƝFuGmꓖϟGwuK~7%oΜ933x{˸qJ};fN5Sτ,0~P_15}ǏL&c~vy^~>ii:m4snhb!4ؙ?KK JKKkF=bP qtt ?_HvNNml2ɓ.ɐd4o΍7ȸKח+WLՖ8:: ^vvvSP/ȯc,CTPWwrה#% )ܡrBYQ))-U$_;+V2v(V.r~>^MYY~7%;;JǏB \ptb5˭jԧԟ uYڎ|t] C}Cg'+;ۨ waQϱ3vKJJ?Ah 6S(ժҙvttBY)Ҽ"j5_mı*z]~ӿ__{諏BLV@Ҳ2lmluV6Tʾpttܞ}7{;;hF~9š(lm6d03^F|y8 84MGyL#H?~lL;]*}}CgGGʿ~U:3Ϙmw@Qi~CBCh˾׮gڪVmmF-IK"uiY瓒ի#Gֺ5{,;%ՙ_xu]fmm{vu0ۧ )t ??_\Jii2FaQ;KL:aS^L:ѝ5nӐ:~}ب~7E_ٹWBadh4ﯝH{jב]]z޾3FBKHLdj):QRRʒmо=O 6/7|êRZVJx{yŢKqi\vYӧs-.^TWxbOdhݺ5)k?__,[={5s:11$'_ɡXYr)rB꾐cݝa'k/CF< ;wⷓϧwϞjْgޓ)%)tܾB~ +++99=kAם/ؽw99~޽zۭ.3imU_Ǐϲ SwS%exv0:+ܾmGj_ ^#48;b J;d2^lm}g 49%.fO%$hkj|0s,xM&x"JIIMLj9zƳ}k CYR^41#qvrz {qum7҂ќð>s6Ę}aHdN~GѰuSeTǜWgbcmõY=Ο7:C _-❷a= [ ѻWOmWgj=pHųNƲza˦:6LMї?;wr8.:ԗqg}|S2$_pkݚ#G0v(vEn&GE?)~GΝ{>c kjKUUiȂysiAfCmPbB!AL֍ضc'iSpwg7E ԅ 322ݾlaSOVXsqjJhp~LJӦ`o/ݖ-O-[E 4$9oSATRT'FۯOzjSS4xG5ϏѣxzXIGܫ7nR sBѰ}AAi}AAh3M˵aa`_HAAx4ʊ۶pea@,$$82ڨ#է&>X 曤:皘7{ko r_OY՞ ATd˗U[]ػc;zmA| :8ĝL/Z͒eyjtҹlO_}HʱhHKOPo\cRۜ_[!Ğ >3l*F[Pף{-\\j3gǛCQь;+++~yo^~1:PPkO8[m*.넭7o=zEx3uL-,)|vYhp] f>L̠h̵N"}Mhp#canN?VΠYh!A0otҕB>3=j;njߵg~]{µ/` O> ۆeL;&NОqu_|0}}>O x hFQQ! ICJQ666UVn7ڸ.r[ ڊLlۮAٳ+ IDATSGj`x"/>ibn.g}t&'6+?{yZʱp48 GzSUnAl 6{$ ք'L5Yd1qDEWwsW6nފ{L vn.Qլx)PT?֏2ٔQV3>8__cٱlQQQ Q Cy?oo7={>=3t(!Aٸy yaxwp*[h!#&l-m۴wY,dw^&GDA>_ϼٳغ};9v13ުiΔ2ص'0|l>獅ؽ՟}틍|wJ%Xf|pfr3lʜٷ?1~wϞ,;R7CASGJ`xK!/C>x ^ q>1qύۋ#OʶߡT*IrG*F[ ||ZF4VJ"3+Dzt;%4))tcPүņo3s:))}u&|K/ՅF"rZR45>~Ջ,%l<\.ƌA޸ پyS83{@Jjsؽw66L?}^1mڐ#iIi҂%˖Ekۖ1#}>>^}^{h)RUZ[t=7* Xj~ <7*P>~Bj_}̨@?*IINR^SRܹ޴L#ƒnh܌Zq&*J;}v.͜07Ƿ[W\9{vXXXhm߱+WYnffm'ߏיV{{xp6.N,;'+w[*>Y'Eh4T*66F/}ܑAfVvl9ڸaiiiT_wԦ>i阙ytZg| wS̙:N><}A vLFǎ|Rt0v hܬ^bAxp5ؙ?KK JKKkFqJg\S [;[r9/LbA22 ͹+4 >þ8t+}qtt$7/077WW_vNN͓}h(+;kˑvPwLCH>6M}/]+;f{uy9?rULjh]GP`me\.8}2TcYFemâ%%%XZV.bAxp5OP`ogWgVj&Uq_.͛3er(q Dc̬ܤWB32ʁ@aa!ee̷{)٧Rv@ѐcPT_P4γǪnJ8NoTurQ_}w) V}-l=iA\ v \][YeeOJÃ+WV޿5o.\LNfdJmaSOGWq簲:+55ˬqo׮vԘ%-[NrUJKKMޗ1 ع'L\\*fJ~駖ŋt3ݹ\6>зUPDŽ4 )))k9::ãul{kWW^oSj3 L;Nb|V|ҲRb o/-^SByy9C|-cFj)yGZz:?ƉXnEPO\|<'OpknݚTڵm/K-`מ̚9/Pgʜ*-)eɿdmx3l`>dMeȈgsNvyٓV-[r{2#eߡXuvr 3y~NNڪb~ ";vݥo3,bw^v{T3wOaxfPҮsv}sO8o,x '2nu/(edx{{aӷiAl 6;s3K\|ݼ "\< x!,^RRR1Yenny \~/1vW^նaӷ\V666u?CYR^41#qvrz {qum7҂ќ >s62FdN~GѰuSeTǜWgbcmõY=Ο7:C}ѻWOmWgj=p0NƲza>^Q}/n#;z"7T}cmKN}6bAx kjKUe.44Ŝ>d2n;gN; Y1 4]zgdd4}7mtP)֧),u+A=L'fL=:lt[v<=tlA|r`}H5BOrss뤏)֧),uښnjfQ<=tKW$I͍7orDewSд)_P4e_AAte_AA~  Hؽm+~7dO9?1r_OY՞͞Śһ눊 *2Kުq_[.ݱ[=6UKf | ꟆeA֠с#Iܹy_S'S;G OOѐNaa޸Ƥ9pC=y2IQus:xy B}kL&#pp~:P)4j>ЗrNE朝[P 6DD$pp̪e+xyVGS ԧѣ{-\\Sa>dM¼ٯҭKW 8rhEb(;t@`מpl@'֭YvOkODgaھFdcooǁ?ckkKf͘B¬鯰c~?}>MILL2j{< ٱ{? g''kk/x97c㷛IIKÃ=%AT*C5V梢"mYٌLnƖ _Ws^X`>'fݯٓsP*u^sgz:gcG-YL\|:2nDRioΥQ}1222N;G77,--kf}vۻߙJ:IDPB&\"WD+Vt*ewp-.@iH$'mJ~ N&e&d=vys(#1' KJHNI1:u/)-ӫMTWDyZ*BvCVW_P`;ysf_١PP(6lE{u9 #>&SoexzX$&]`̘>UoV#j^VFcV/egNQqEךŅ:_SVV666(VEy5>(3/}:oѹX]]\5m:峴555ۙlo4ZM㟑[*Bv puqi;>9T>MS*pjAMIHH$<ѶAIHLl9Q_X"00?__~n2\ZVf樭ŋ6wwwnnsOzfFyTWgJTV!h+6w&>עmVZhzɍzfg󖭼N+2ol^_Fpq>cf͜;'S:W 뺐yE89:_W͙g-.9s>n<=<̺}goEgY|NNF{isD lH쓋 pGUMo7-%??3*!:nb||-~ȳ |oٴnE- 8(iAm4BRվ0~\o Ik]?~[z,|lnٻs8;9q_~s&[*-=s&|Bf,us7^]Mo˩Uu1|..슊jёӧ1cT"'N+ζ\]/LT77WU72URi%U5/,n2;xg !B\̙pB!hO!B- B!B!VD?!B+"B!O!ŠH'BaE$B!" !BX B!B!VD?!B+"B!O!ŠH'BaEl|:p`{E!B\F'CdmV.!BѶB!*ȑ#|7mӦMc1<ԓ-Z?Z|9z]=48VQlqZUrS@5NvU) -!gР[T,~aȘ=oO?v777OՋ.]ȪU4+Pfμrrr8w.(MHH=ɒ%PUUuUuV5WJ.]ď? ..yM2#FFrr2+Wu寏R䣏>fݺuĜh<@!.vvv{,d6nHyyI~IAAaAAA:ۖE%tNafB >;ԩU|td1(TU ֚=!QQQ8@~L2dffP\\Ԧk̘^^^ 8DC>>,Z$e,\˗kHwE7n۷oov~ײ &8;;3r(xb!. -97BuuuKAYYYTVVjrav$&Nk֬3fԛN ;v, nEQ[kT ֿQ/]Į'3RM+dWO5k~d槁ҿu2δW5$99ĜyuRRaŋ۶@P(3f46ٗ /~bYj̘1j>3Μ9?9Ռ;$Ç=z4J}i/򈋋ȑ#Y*F٬:wVe_HMM%;;j(NDzeKMFz[5_?BUG ŋFXBBzLo΋/TgϞ҃+BVfWkտ )L_wfygCk|fWQQ?-CJQB7O J~<;TG5z^ZdEM*"/j%gXݛїRq6TF/N9f_K\F>Z^PȘ+pבo?}xld17V嬣J$'MqEj -鯎fСDFNۛBv ̙Cdd1F/¶m[_޽}ͮG<Ο?OMM jsݻI̞ؓ=>}pZX_UUUENN6>&2e*]vERw^vi}1zu>04h&݉\p/ ͊WYwӓZɚ5:44[̫JeeYK9bHҥXjȧ5_?BU?ӇsO𹹹CP0`ŅNSrNNNL://oJKKqsscڴ8;ϛX<\m-<7!XrGa՜r@U`b)p塡%7plB=')wQZ'9hH3oX O)Q Nd2,.k%.q.]UeRU%CC*ykJa}-srѢ*)n-3ޣ7VPVr<R򻮜ǜzӆWGЯ_?zh ㏈g9 0(]=/y?3|fٻw(++k:q3BaK;KhDW^<3'눊]wŰa imƒ%y&4 K’%GW֜??¹s^oFmQQKkÍN~~*ӧ2$(C(,,$1xzܚ!.kv΢EOvp㍡96mDII 'N$77M6l2V~#F͛۴6Jx{Z.λoa~́e=5q3kσ FM-48ղbjkO9倗O365ϱ筝wa!|z_w7:`OGֺxh9n IDATγ.<ɏ5XȞvҐUb=J QSVdWF $;% /5Mg| l֦eN&[_رHIIfÆ >}nݺ2v8bbiZ[*++Ì;C6tbuKT@UU%ҟO?Jlmm3^I[LUS}acc9 {{{~qawκu .L0ÇS* JeXg5՗i&y~W(((ht Ə7߿?0ݝRnV=R贵^?BU}o>X&w <2t~g lbr.𺦦tjhu0nT(TYe۽nzܩSkqkp.:Zo/4U>qs`5sMOVB}ߝZ;g$9*LڒVhGNuxؓ^dG7O5!>jJl6tT~Pe7' Ǧ;rWr<wGJm-lWjٿѶs1aDm9FRP(Oպw"//-o.0N/+//'88Mԑ4 n 3'ٓ-[] DFFbkkkŬ,J%sȑhRRZMNHH.\H"88OO/3gΠRK.EVRfF) <<<7/OOO>e<̳t:;ʆ jWUǺ << ';;K,Qj;v!C"bSM*za.?SPZtFUU;w$55y5k0eT"#',^o.8^_^[Zʫ|zGƕV’J%VpU(kٳ9%Pcx[:wC:]ycs^N߰ѥSo^ Jz-(]S m...?WWW4.t:_Rpvvj^͔_G~~u}ptvvF,4Eّ|^~FŞ={BӱmVbcMUTdㄎ?qttdذa̜y/III:tȲJʦMѿˢ7n 8;~^?B> LԻn$ #F`tޝ~L쉢W$OIIEǷ3T+[K =}^2 ҥKFrssLm`zhLogѧMoLJz],dN>T*h4\p@M~;bWUU޽{),,ãYhJLL >> 8zvNOO#33ٳ<^?B⑿ό+BU]l8^ݷ[=*C hUC W7eݧS`$gJw1n̍(%K͖2)RD#ߞp#ŕJHl)ѣ'}lN裏sNt Aqfyn !sww֖_~dQzooJQQɛ}5j<20l0ػwIy AAAͪϵO?b4hǎc۶<̳h4Zà bڵfcԨQpCwΞ=CYY9aa},{aɂ+s0"''YfQPP`Ѻs=3kpy5_?Bt:ƏODP ذao|w<Ìv>Ol=DwZ !ǞQ՘?K3<5عj(PQwje_݇%4G^reBUdg8ѽ*q[=ᣴJcYYaw彽5xޜzTv4qqq|ſİa),,dÆ&`$%%1oOB!B!VD?!B+"B!O!ŠH'BaE$B!" !BX B!B!VD?!B+"B!O!ŠH'BaE$B!" !BX B!mB!B'a IENDB`elisp-refs-1.4/CHANGELOG.md0000664000175000017500000000231014175024547015101 0ustar dogslegdogsleg## v1.4 Fixed an issue where elisp-refs would kill its own results buffer if no results were found. Fixed an issue when running elisp-refs on Emacs master, which renamed `format-proper-list-p` to `proper-list-p` (and moved it to subr.el). Fixed an issue where the results buffer showed the wrong lines if comments contained parentheses. Fixed an issue where arguments in `declare-function` were confused with a function call. Fixed an error when pressing RET on a line that didn't have a search result. ## v1.3 * Refs buffers now have names of the form `*refs: foo*`. * Fixed an issue with a dependency on a loop.el version that doesn't exist. ## v1.2 * You can now filter search results to a directory. This is useful when working on large elisp codebases, and it's faster too. * Results buffers now include a link to describe the thing being searched for. ## v1.1 * Rebranded to elisp-refs. * Commands are now autoloaded. * Added examples to the readme of cases that we can't detect. * Sharp-quoted function references are now highlighted with context. * Give more feedback on first run, when we're decompressing .el.gz files. * Searches now default to the symbol at point. ## v1.0 Initial release. elisp-refs-1.4/Cask0000664000175000017500000000024014175024547014074 0ustar dogslegdogsleg(source melpa) (package-file "elisp-refs.el") (development (depends-on "shut-up") (depends-on "ert-runner") (depends-on "undercover") (depends-on "f")) elisp-refs-1.4/elisp-refs-bench.el0000664000175000017500000000471614175024547016754 0ustar dogslegdogsleg;;; elisp-refs-bench.el --- measure elisp-refs.el performance ;;; Code: (require 'elisp-refs) (require 'dash) (defmacro elisp-refs--print-time (form) "Evaluate FORM, and print the time taken." `(progn (message "Timing %s" ',form) (-let [(total-time gc-runs gc-time) (cl-letf (((symbol-function #'message) (lambda (_format-string &rest _args)))) (benchmark-run 1 ,form))] (message "Elapsed time: %fs (%fs in %d GCs)" total-time gc-time gc-runs)))) ;; TODO: benchmark elisp-refs-variable (and add a smoke test) ;; TODO: make this more representative by loading more elisp files ;; before searching. Running this in a GUI is also conspicuously ;; slower, which bench.sh doesn't reflect. (defun elisp-refs-bench () "Measure runtime of searching." (interactive) (elisp-refs--report-loc) ;; Measure a fairly uncommon function. (elisp-refs--print-time (elisp-refs-function 'mod)) ;; Measure a common macro (elisp-refs--print-time (elisp-refs-macro 'when)) ;; Compare with searching for the same symbol without walking (elisp-refs--print-time (elisp-refs-symbol 'when)) ;; Synthetic test of a large number of results. (message "Formatting 10,000 results") (let ((forms (-repeat 10000 (list '(ignored) 1 64))) (buf (generate-new-buffer " *dummy-elisp-refs-buf*"))) (with-current-buffer buf (insert "(defun foo (bar) (if bar nil (with-current-buffer bar))) ;; blah") (setq-local elisp-refs--path "/tmp/foo.el")) (elisp-refs--print-time (elisp-refs--show-results 'foo "foo bar" (list (cons forms buf)) 20 nil)) (kill-buffer buf))) (defun elisp-refs--report-loc () "Report the total number of lines of code searched." (interactive) (let* ((loaded-paths (elisp-refs--loaded-paths)) (loaded-src-bufs (cl-letf (((symbol-function #'message) (lambda (_format-string &rest _args)))) (-map #'elisp-refs--contents-buffer loaded-paths))) (total-lines (-sum (--map (with-current-buffer it (line-number-at-pos (point-max))) loaded-src-bufs)))) ;; Clean up temporary buffers. (--each loaded-src-bufs (kill-buffer it)) (message "Total LOC: %s" (elisp-refs--format-int total-lines)))) (provide 'elisp-refs-bench) ;;; elisp-refs-bench.el ends here elisp-refs-1.4/bench.sh0000775000175000017500000000013114175024547014705 0ustar dogslegdogsleg#!/bin/bash set -ex cask eval "(progn (require 'elisp-refs-bench) (elisp-refs-bench))" elisp-refs-1.4/elisp-refs.el0000664000175000017500000010031714175024547015671 0ustar dogslegdogsleg;;; elisp-refs.el --- find callers of elisp functions or macros -*- lexical-binding: t; -*- ;; Copyright (C) 2016-2020 Wilfred Hughes ;; Author: Wilfred Hughes ;; Version: 1.4 ;; Keywords: lisp ;; Package-Requires: ((dash "2.12.0") (s "1.11.0")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; elisp-refs.el is an Emacs package for finding references to ;; functions, macros or variables. Unlike a dumb text search, ;; elisp-refs.el actually parses the code, so it's never confused by ;; comments or `foo-bar' matching `foo'. ;; ;; See https://github.com/Wilfred/refs.el/blob/master/README.md for ;; more information. ;;; Code: (require 'dash) (require 's) (require 'format) (eval-when-compile (require 'cl-lib)) ;;; Internal (defvar elisp-refs-verbose t) (defun elisp-refs--format-int (integer) "Format INTEGER as a string, with , separating thousands." (let ((number (abs integer)) (parts nil)) (while (> number 999) (push (format "%03d" (mod number 1000)) parts) (setq number (/ number 1000))) (push (format "%d" number) parts) (concat (if (< integer 0) "-" "") (s-join "," parts)))) (defsubst elisp-refs--start-pos (end-pos) "Find the start position of form ending at END-POS in the current buffer." (let ((parse-sexp-ignore-comments t)) (scan-sexps end-pos -1))) (defun elisp-refs--sexp-positions (buffer start-pos end-pos) "Return a list of start and end positions of all the sexps between START-POS and END-POS (inclusive) in BUFFER. Positions exclude quote characters, so given 'foo or `foo, we report the position of the f. Not recursive, so we don't consider subelements of nested sexps." (let ((positions nil)) (with-current-buffer buffer (condition-case _err (catch 'done (while t (let* ((sexp-end-pos (let ((parse-sexp-ignore-comments t)) (scan-sexps start-pos 1)))) ;; If we've reached a sexp beyond the range requested, ;; or if there are no sexps left, we're done. (when (or (null sexp-end-pos) (> sexp-end-pos end-pos)) (throw 'done nil)) ;; Otherwise, this sexp is in the range requested. (push (list (elisp-refs--start-pos sexp-end-pos) sexp-end-pos) positions) (setq start-pos sexp-end-pos)))) ;; Terminate when we see "Containing expression ends prematurely" (scan-error nil))) (nreverse positions))) (defun elisp-refs--read-buffer-form () "Read a form from the current buffer, starting at point. Returns a list: \(form form-start-pos form-end-pos symbol-positions read-start-pos) SYMBOL-POSITIONS are 0-indexed, relative to READ-START-POS." (let* ((read-with-symbol-positions t) (read-start-pos (point)) (form (read (current-buffer))) (end-pos (point)) (start-pos (elisp-refs--start-pos end-pos))) (list form start-pos end-pos read-symbol-positions-list read-start-pos))) (defvar elisp-refs--path nil "A buffer-local variable used by `elisp-refs--contents-buffer'. Internal implementation detail.") (defun elisp-refs--read-all-buffer-forms (buffer) "Read all the forms in BUFFER, along with their positions." (with-current-buffer buffer (goto-char (point-min)) (let ((forms nil)) (condition-case err (while t (push (elisp-refs--read-buffer-form) forms)) (error (if (or (equal (car err) 'end-of-file) ;; TODO: this shouldn't occur in valid elisp files, ;; but it's happening in helm-utils.el. (equal (car err) 'scan-error)) ;; Reached end of file, we're done. (nreverse forms) ;; Some unexpected error, propagate. (error "Unexpected error whilst reading %s position %s: %s" (abbreviate-file-name elisp-refs--path) (point) err))))))) (defun elisp-refs--proper-list-p (val) "Is VAL a proper list?" (if (fboundp 'format-proper-list-p) ;; Emacs stable. (with-no-warnings (format-proper-list-p val)) ;; Function was renamed in Emacs master: ;; http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=2fde6275b69fd113e78243790bf112bbdd2fe2bf (with-no-warnings (proper-list-p val)))) (defun elisp-refs--walk (buffer form start-pos end-pos symbol match-p &optional path) "Walk FORM, a nested list, and return a list of sublists (with their positions) where MATCH-P returns t. FORM is traversed depth-first (pre-order traversal, left-to-right). MATCH-P is called with three arguments: \(SYMBOL CURRENT-FORM PATH). PATH is the first element of all the enclosing forms of CURRENT-FORM, innermost first, along with the index of the current form. For example if we are looking at h in (e f (g h)), PATH takes the value ((g . 1) (e . 2)). START-POS and END-POS should be the position of FORM within BUFFER." (cond ((funcall match-p symbol form path) ;; If this form matches, just return it, along with the position. (list (list form start-pos end-pos))) ;; Otherwise, recurse on the subforms. ((consp form) (let ((matches nil) ;; Find the positions of the subforms. (subforms-positions (if (eq (car-safe form) '\`) ;; Kludge: `elisp-refs--sexp-positions' excludes the ` when ;; calculating positions. So, to find the inner ;; positions when walking from `(...) to (...), we ;; don't need to increment the start position. (cons nil (elisp-refs--sexp-positions buffer start-pos end-pos)) ;; Calculate the positions after the opening paren. (elisp-refs--sexp-positions buffer (1+ start-pos) end-pos)))) ;; For each subform, recurse if it's a list, or a matching symbol. (--each (-zip form subforms-positions) (-let [(subform subform-start subform-end) it] (when (or (and (consp subform) (elisp-refs--proper-list-p subform)) (and (symbolp subform) (eq subform symbol))) (-when-let (subform-matches (elisp-refs--walk buffer subform subform-start subform-end symbol match-p (cons (cons (car-safe form) it-index) path))) (push subform-matches matches))))) ;; Concat the results from all the subforms. (apply #'append (nreverse matches)))))) ;; TODO: condition-case (condition-case ... (error ...)) is not a call ;; TODO: (cl-destructuring-bind (foo &rest bar) ...) is not a call ;; TODO: letf, cl-letf, -let, -let* (defun elisp-refs--function-p (symbol form path) "Return t if FORM looks like a function call to SYMBOL." (cond ((not (consp form)) nil) ;; Ignore (defun _ (SYMBOL ...) ...) ((or (equal (car path) '(defsubst . 2)) (equal (car path) '(defun . 2)) (equal (car path) '(defmacro . 2)) (equal (car path) '(cl-defun . 2))) nil) ;; Ignore (lambda (SYMBOL ...) ...) ((equal (car path) '(lambda . 1)) nil) ;; Ignore (let (SYMBOL ...) ...) ;; and (let* (SYMBOL ...) ...) ((or (equal (car path) '(let . 1)) (equal (car path) '(let* . 1))) nil) ;; Ignore (let ((SYMBOL ...)) ...) ((or (equal (cl-second path) '(let . 1)) (equal (cl-second path) '(let* . 1))) nil) ;; Ignore (declare-function NAME (ARGS...)) ((equal (car path) '(declare-function . 3)) nil) ;; (SYMBOL ...) ((eq (car form) symbol) t) ;; (foo ... #'SYMBOL ...) ((--any-p (equal it (list 'function symbol)) form) t) ;; (funcall 'SYMBOL ...) ((and (eq (car form) 'funcall) (equal `',symbol (cl-second form))) t) ;; (apply 'SYMBOL ...) ((and (eq (car form) 'apply) (equal `',symbol (cl-second form))) t))) (defun elisp-refs--macro-p (symbol form path) "Return t if FORM looks like a macro call to SYMBOL." (cond ((not (consp form)) nil) ;; Ignore (defun _ (SYMBOL ...) ...) ((or (equal (car path) '(defsubst . 2)) (equal (car path) '(defun . 2)) (equal (car path) '(defmacro . 2))) nil) ;; Ignore (lambda (SYMBOL ...) ...) ((equal (car path) '(lambda . 1)) nil) ;; Ignore (let (SYMBOL ...) ...) ;; and (let* (SYMBOL ...) ...) ((or (equal (car path) '(let . 1)) (equal (car path) '(let* . 1))) nil) ;; Ignore (let ((SYMBOL ...)) ...) ((or (equal (cl-second path) '(let . 1)) (equal (cl-second path) '(let* . 1))) nil) ;; (SYMBOL ...) ((eq (car form) symbol) t))) ;; Looking for a special form is exactly the same as looking for a ;; macro. (defalias 'elisp-refs--special-p 'elisp-refs--macro-p) (defun elisp-refs--variable-p (symbol form path) "Return t if this looks like a variable reference to SYMBOL. We consider parameters to be variables too." (cond ((consp form) nil) ;; Ignore (defun _ (SYMBOL ...) ...) ((or (equal (car path) '(defsubst . 1)) (equal (car path) '(defun . 1)) (equal (car path) '(defmacro . 1)) (equal (car path) '(cl-defun . 1))) nil) ;; (let (SYMBOL ...) ...) is a variable, not a function call. ((or (equal (cl-second path) '(let . 1)) (equal (cl-second path) '(let* . 1))) t) ;; (lambda (SYMBOL ...) ...) is a variable ((equal (cl-second path) '(lambda . 1)) t) ;; (let ((SYMBOL ...)) ...) is also a variable. ((or (equal (cl-third path) '(let . 1)) (equal (cl-third path) '(let* . 1))) t) ;; Ignore (SYMBOL ...) otherwise, we assume it's a function/macro ;; call. ((equal (car path) (cons symbol 0)) nil) ((eq form symbol) t))) ;; TODO: benchmark building a list with `push' rather than using ;; mapcat. (defun elisp-refs--read-and-find (buffer symbol match-p) "Read all the forms in BUFFER, and return a list of all forms that contain SYMBOL where MATCH-P returns t. For every matching form found, we return the form itself along with its start and end position." (-non-nil (--mapcat (-let [(form start-pos end-pos symbol-positions _read-start-pos) it] ;; Optimisation: don't bother walking a form if contains no ;; references to the symbol we're looking for. (when (assq symbol symbol-positions) (elisp-refs--walk buffer form start-pos end-pos symbol match-p))) (elisp-refs--read-all-buffer-forms buffer)))) (defun elisp-refs--read-and-find-symbol (buffer symbol) "Read all the forms in BUFFER, and return a list of all positions of SYMBOL." (-non-nil (--mapcat (-let [(_ _ _ symbol-positions read-start-pos) it] (--map (-let [(sym . offset) it] (when (eq sym symbol) (-let* ((start-pos (+ read-start-pos offset)) (end-pos (+ start-pos (length (symbol-name sym))))) (list sym start-pos end-pos)))) symbol-positions)) (elisp-refs--read-all-buffer-forms buffer)))) (defun elisp-refs--filter-obarray (pred) "Return a list of all the items in `obarray' where PRED returns t." (let (symbols) (mapatoms (lambda (symbol) (when (and (funcall pred symbol) (not (equal (symbol-name symbol) ""))) (push symbol symbols)))) symbols)) (defun elisp-refs--loaded-paths () "Return a list of all files that have been loaded in Emacs. Where the file was a .elc, return the path to the .el file instead." (let ((elc-paths (-non-nil (mapcar #'-first-item load-history)))) (-non-nil (--map (let ((el-name (format "%s.el" (file-name-sans-extension it))) (el-gz-name (format "%s.el.gz" (file-name-sans-extension it)))) (cond ((file-exists-p el-name) el-name) ((file-exists-p el-gz-name) el-gz-name) ;; Ignore files where we can't find a .el file. (t nil))) elc-paths)))) (defun elisp-refs--contents-buffer (path) "Read PATH into a disposable buffer, and return it. Works around the fact that Emacs won't allow multiple buffers visiting the same file." (let ((fresh-buffer (generate-new-buffer (format " *refs-%s*" path))) ;; Be defensive against users overriding encoding ;; configurations (Helpful bugs #75 and #147). (coding-system-for-read nil) (file-name-handler-alist '(("\\(?:\\.dz\\|\\.txz\\|\\.xz\\|\\.lzma\\|\\.lz\\|\\.g?z\\|\\.\\(?:tgz\\|svgz\\|sifz\\)\\|\\.tbz2?\\|\\.bz2\\|\\.Z\\)\\(?:~\\|\\.~[-[:alnum:]:#@^._]+\\(?:~[[:digit:]]+\\)?~\\)?\\'" . jka-compr-handler) ("\\`/:" . file-name-non-special)))) (with-current-buffer fresh-buffer (setq-local elisp-refs--path path) (insert-file-contents path) ;; We don't enable emacs-lisp-mode because it slows down this ;; function significantly. We just need the syntax table for ;; scan-sexps to do the right thing with comments. (set-syntax-table emacs-lisp-mode-syntax-table)) fresh-buffer)) (defvar elisp-refs--highlighting-buffer nil "A temporary buffer used for highlighting. Since `elisp-refs--syntax-highlight' is a hot function, we don't want to create lots of temporary buffers.") (defun elisp-refs--syntax-highlight (str) "Apply font-lock properties to a string STR of Emacs lisp code." ;; Ensure we have a highlighting buffer to work with. (unless (and elisp-refs--highlighting-buffer (buffer-live-p elisp-refs--highlighting-buffer)) (setq elisp-refs--highlighting-buffer (generate-new-buffer " *refs-highlighting*")) (with-current-buffer elisp-refs--highlighting-buffer (delay-mode-hooks (emacs-lisp-mode)))) (with-current-buffer elisp-refs--highlighting-buffer (erase-buffer) (insert str) (if (fboundp 'font-lock-ensure) (font-lock-ensure) (with-no-warnings (font-lock-fontify-buffer))) (buffer-string))) (defun elisp-refs--replace-tabs (string) "Replace tabs in STRING with spaces." ;; This is important for unindenting, as we may unindent by less ;; than one whole tab. (s-replace "\t" (s-repeat tab-width " ") string)) (defun elisp-refs--lines (string) "Return a list of all the lines in STRING. 'a\nb' -> ('a\n' 'b')" (let ((lines nil)) (while (> (length string) 0) (let ((index (s-index-of "\n" string))) (if index (progn (push (substring string 0 (1+ index)) lines) (setq string (substring string (1+ index)))) (push string lines) (setq string "")))) (nreverse lines))) (defun elisp-refs--map-lines (string fn) "Execute FN for each line in string, and join the result together." (let ((result nil)) (dolist (line (elisp-refs--lines string)) (push (funcall fn line) result)) (apply #'concat (nreverse result)))) (defun elisp-refs--unindent-rigidly (string) "Given an indented STRING, unindent rigidly until at least one line has no indent. STRING should have a 'elisp-refs-start-pos property. The returned string will have this property updated to reflect the unindent." (let* ((lines (s-lines string)) ;; Get the leading whitespace for each line. (indents (--map (car (s-match (rx bos (+ whitespace)) it)) lines)) (min-indent (-min (--map (length it) indents)))) (propertize (elisp-refs--map-lines string (lambda (line) (substring line min-indent))) 'elisp-refs-unindented min-indent))) (defun elisp-refs--containing-lines (buffer start-pos end-pos) "Return a string, all the lines in BUFFER that are between START-POS and END-POS (inclusive). For the characters that are between START-POS and END-POS, propertize them." (let (expanded-start-pos expanded-end-pos) (with-current-buffer buffer ;; Expand START-POS and END-POS to line boundaries. (goto-char start-pos) (beginning-of-line) (setq expanded-start-pos (point)) (goto-char end-pos) (end-of-line) (setq expanded-end-pos (point)) ;; Extract the rest of the line before and after the section we're interested in. (let* ((before-match (buffer-substring expanded-start-pos start-pos)) (after-match (buffer-substring end-pos expanded-end-pos)) ;; Concat the extra text with the actual match, ensuring we ;; highlight the match as code, but highlight the rest as as ;; comments. (text (concat (propertize before-match 'face 'font-lock-comment-face) (elisp-refs--syntax-highlight (buffer-substring start-pos end-pos)) (propertize after-match 'face 'font-lock-comment-face)))) (-> text (elisp-refs--replace-tabs) (elisp-refs--unindent-rigidly) (propertize 'elisp-refs-start-pos expanded-start-pos 'elisp-refs-path elisp-refs--path)))))) (defun elisp-refs--find-file (button) "Open the file referenced by BUTTON." (find-file (button-get button 'path)) (goto-char (point-min))) (define-button-type 'elisp-refs-path-button 'action 'elisp-refs--find-file 'follow-link t 'help-echo "Open file") (defun elisp-refs--path-button (path) "Return a button that navigates to PATH." (with-temp-buffer (insert-text-button (abbreviate-file-name path) :type 'elisp-refs-path-button 'path path) (buffer-string))) (defun elisp-refs--describe (button) "Show *Help* for the symbol referenced by BUTTON." (let ((symbol (button-get button 'symbol)) (kind (button-get button 'kind))) (cond ((eq kind 'symbol) (describe-symbol symbol)) ((eq kind 'variable) (describe-variable symbol)) (t ;; Emacs uses `describe-function' for functions, macros and ;; special forms. (describe-function symbol))))) (define-button-type 'elisp-refs-describe-button 'action 'elisp-refs--describe 'follow-link t 'help-echo "Describe") (defun elisp-refs--describe-button (symbol kind) "Return a button that shows *Help* for SYMBOL. KIND should be 'function, 'macro, 'variable, 'special or 'symbol." (with-temp-buffer (insert (symbol-name kind) " ") (insert-text-button (symbol-name symbol) :type 'elisp-refs-describe-button 'symbol symbol 'kind kind) (buffer-string))) (defun elisp-refs--pluralize (number thing) "Human-friendly description of NUMBER occurrences of THING." (format "%s %s%s" (elisp-refs--format-int number) thing (if (equal number 1) "" "s"))) (defun elisp-refs--format-count (symbol ref-count file-count searched-file-count prefix) (let* ((file-str (if (zerop file-count) "" (format " in %s" (elisp-refs--pluralize file-count "file")))) (found-str (format "Found %s to %s%s." (elisp-refs--pluralize ref-count "reference") symbol file-str)) (searched-str (if prefix (format "Searched %s in %s." (elisp-refs--pluralize searched-file-count "loaded file") (elisp-refs--path-button (file-name-as-directory prefix))) (format "Searched all %s loaded in Emacs." (elisp-refs--pluralize searched-file-count "file"))))) (s-word-wrap 70 (format "%s %s" found-str searched-str)))) ;; TODO: if we have multiple matches on one line, we repeatedly show ;; that line. That's slightly confusing. (defun elisp-refs--show-results (symbol description results searched-file-count prefix) "Given a RESULTS list where each element takes the form \(forms . buffer\), render a friendly results buffer." (let ((buf (get-buffer-create (format "*refs: %s*" symbol)))) (switch-to-buffer buf) (let ((inhibit-read-only t)) (erase-buffer) (save-excursion ;; Insert the header. (insert (elisp-refs--format-count description (-sum (--map (length (car it)) results)) (length results) searched-file-count prefix) "\n\n") ;; Insert the results. (--each results (-let* (((forms . buf) it) (path (with-current-buffer buf elisp-refs--path))) (insert (propertize "File: " 'face 'bold) (elisp-refs--path-button path) "\n") (--each forms (-let [(_ start-pos end-pos) it] (insert (elisp-refs--containing-lines buf start-pos end-pos) "\n"))) (insert "\n"))) ;; Prepare the buffer for the user. (elisp-refs-mode))) ;; Cleanup buffers created when highlighting results. (when elisp-refs--highlighting-buffer (kill-buffer elisp-refs--highlighting-buffer)))) (defun elisp-refs--loaded-bufs () "Return a list of open buffers, one for each path in `load-path'." (mapcar #'elisp-refs--contents-buffer (elisp-refs--loaded-paths))) (defun elisp-refs--search-1 (bufs match-fn) "Call MATCH-FN on each buffer in BUFS, reporting progress and accumulating results. BUFS should be disposable: we make no effort to preserve their state during searching. MATCH-FN should return a list where each element takes the form: \(form start-pos end-pos)." (let* (;; Our benchmark suggests we spend a lot of time in GC, and ;; performance improves if we GC less frequently. (gc-cons-percentage 0.8) (total-bufs (length bufs))) (let ((searched 0) (forms-and-bufs nil)) (dolist (buf bufs) (let* ((matching-forms (funcall match-fn buf))) ;; If there were any matches in this buffer, push the ;; matches along with the buffer into our results ;; list. (when matching-forms (push (cons matching-forms buf) forms-and-bufs)) ;; Give feedback to the user on our progress, because ;; searching takes several seconds. (when (and (zerop (mod searched 10)) elisp-refs-verbose) (message "Searched %s/%s files" searched total-bufs)) (cl-incf searched))) (when elisp-refs-verbose (message "Searched %s/%s files" total-bufs total-bufs)) forms-and-bufs))) (defun elisp-refs--search (symbol description match-fn &optional path-prefix) "Find references to SYMBOL in all loaded files; call MATCH-FN on each buffer. When PATH-PREFIX, limit to loaded files whose path starts with that prefix. Display the results in a hyperlinked buffer. MATCH-FN should return a list where each element takes the form: \(form start-pos end-pos)." (let* ((loaded-paths (elisp-refs--loaded-paths)) (matching-paths (if path-prefix (--filter (s-starts-with? path-prefix it) loaded-paths) loaded-paths)) (loaded-src-bufs (mapcar #'elisp-refs--contents-buffer matching-paths))) ;; Use unwind-protect to ensure we always cleanup temporary ;; buffers, even if the user hits C-g. (unwind-protect (progn (let ((forms-and-bufs (elisp-refs--search-1 loaded-src-bufs match-fn))) (elisp-refs--show-results symbol description forms-and-bufs (length loaded-src-bufs) path-prefix))) ;; Clean up temporary buffers. (--each loaded-src-bufs (kill-buffer it))))) (defun elisp-refs--completing-read-symbol (prompt &optional filter) "Read an interned symbol from the minibuffer, defaulting to the symbol at point. PROMPT is the string to prompt with. If FILTER is given, only offer symbols where (FILTER sym) returns t." (let ((filter (or filter (lambda (_) t)))) (read (completing-read prompt (elisp-refs--filter-obarray filter) nil nil nil nil (-if-let (sym (thing-at-point 'symbol)) (when (funcall filter (read sym)) sym)))))) ;;; Commands ;;;###autoload (defun elisp-refs-function (symbol &optional path-prefix) "Display all the references to function SYMBOL, in all loaded elisp files. If called with a prefix, prompt for a directory to limit the search. This searches for functions, not macros. For that, see `elisp-refs-macro'." (interactive (list (elisp-refs--completing-read-symbol "Function: " #'functionp) (when current-prefix-arg (read-directory-name "Limit search to loaded files in: ")))) (when (not (functionp symbol)) (if (macrop symbol) (user-error "%s is a macro. Did you mean elisp-refs-macro?" symbol) (user-error "%s is not a function. Did you mean elisp-refs-symbol?" symbol))) (elisp-refs--search symbol (elisp-refs--describe-button symbol 'function) (lambda (buf) (elisp-refs--read-and-find buf symbol #'elisp-refs--function-p)) path-prefix)) ;;;###autoload (defun elisp-refs-macro (symbol &optional path-prefix) "Display all the references to macro SYMBOL, in all loaded elisp files. If called with a prefix, prompt for a directory to limit the search. This searches for macros, not functions. For that, see `elisp-refs-function'." (interactive (list (elisp-refs--completing-read-symbol "Macro: " #'macrop) (when current-prefix-arg (read-directory-name "Limit search to loaded files in: ")))) (when (not (macrop symbol)) (if (functionp symbol) (user-error "%s is a function. Did you mean elisp-refs-function?" symbol) (user-error "%s is not a function. Did you mean elisp-refs-symbol?" symbol))) (elisp-refs--search symbol (elisp-refs--describe-button symbol 'macro) (lambda (buf) (elisp-refs--read-and-find buf symbol #'elisp-refs--macro-p)) path-prefix)) ;;;###autoload (defun elisp-refs-special (symbol &optional path-prefix) "Display all the references to special form SYMBOL, in all loaded elisp files. If called with a prefix, prompt for a directory to limit the search." (interactive (list (elisp-refs--completing-read-symbol "Special form: " #'special-form-p) (when current-prefix-arg (read-directory-name "Limit search to loaded files in: ")))) (elisp-refs--search symbol (elisp-refs--describe-button symbol 'special-form) (lambda (buf) (elisp-refs--read-and-find buf symbol #'elisp-refs--special-p)) path-prefix)) ;;;###autoload (defun elisp-refs-variable (symbol &optional path-prefix) "Display all the references to variable SYMBOL, in all loaded elisp files. If called with a prefix, prompt for a directory to limit the search." (interactive ;; This is awkward. We don't want to just offer defvar variables, ;; because then we can't search for code which uses `let' to bind ;; symbols. There doesn't seem to be a good way to only offer ;; variables that have been bound at some point. (list (elisp-refs--completing-read-symbol "Variable: " ) (when current-prefix-arg (read-directory-name "Limit search to loaded files in: ")))) (elisp-refs--search symbol (elisp-refs--describe-button symbol 'variable) (lambda (buf) (elisp-refs--read-and-find buf symbol #'elisp-refs--variable-p)) path-prefix)) ;;;###autoload (defun elisp-refs-symbol (symbol &optional path-prefix) "Display all the references to SYMBOL in all loaded elisp files. If called with a prefix, prompt for a directory to limit the search." (interactive (list (elisp-refs--completing-read-symbol "Symbol: " ) (when current-prefix-arg (read-directory-name "Limit search to loaded files in: ")))) (elisp-refs--search symbol (elisp-refs--describe-button symbol 'symbol) (lambda (buf) (elisp-refs--read-and-find-symbol buf symbol)) path-prefix)) ;;; Mode (defvar elisp-refs-mode-map (let ((map (make-sparse-keymap))) ;; TODO: it would be nice for TAB to navigate to file buttons too, ;; like *Help* does. (set-keymap-parent map special-mode-map) (define-key map (kbd "") #'elisp-refs-next-match) (define-key map (kbd "") #'elisp-refs-prev-match) (define-key map (kbd "n") #'elisp-refs-next-match) (define-key map (kbd "p") #'elisp-refs-prev-match) (define-key map (kbd "q") #'kill-this-buffer) (define-key map (kbd "RET") #'elisp-refs-visit-match) map) "Keymap for `elisp-refs-mode'.") (define-derived-mode elisp-refs-mode special-mode "Refs" "Major mode for refs results buffers.") (defun elisp-refs-visit-match () "Go to the search result at point." (interactive) (let* ((path (get-text-property (point) 'elisp-refs-path)) (pos (get-text-property (point) 'elisp-refs-start-pos)) (unindent (get-text-property (point) 'elisp-refs-unindented)) (column-offset (current-column)) (line-offset -1)) (when (null path) (user-error "No match here")) ;; If point is not on the first line of the match, work out how ;; far away the first line is. (save-excursion (while (equal pos (get-text-property (point) 'elisp-refs-start-pos)) (forward-line -1) (cl-incf line-offset))) (find-file path) (goto-char pos) ;; Move point so we're on the same char in the buffer that we were ;; on in the results buffer. (forward-line line-offset) (beginning-of-line) (let ((target-offset (+ column-offset unindent)) (i 0)) (while (< i target-offset) (if (looking-at "\t") (cl-incf i tab-width) (cl-incf i)) (forward-char 1))))) (defun elisp-refs--move-to-match (direction) "Move point one match forwards. If DIRECTION is -1, moves backwards instead." (let* ((start-pos (point)) (match-pos (get-text-property start-pos 'elisp-refs-start-pos)) current-match-pos) (condition-case _err (progn ;; Move forward/backwards until we're on the next/previous match. (catch 'done (while t (setq current-match-pos (get-text-property (point) 'elisp-refs-start-pos)) (when (and current-match-pos (not (equal match-pos current-match-pos))) (throw 'done nil)) (forward-char direction))) ;; Move to the beginning of that match. (while (equal (get-text-property (point) 'elisp-refs-start-pos) (get-text-property (1- (point)) 'elisp-refs-start-pos)) (forward-char -1)) ;; Move forward until we're on the first char of match within that ;; line. (while (or (looking-at " ") (eq (get-text-property (point) 'face) 'font-lock-comment-face)) (forward-char 1))) ;; If we're at the last result, don't move point. (end-of-buffer (progn (goto-char start-pos) (signal 'end-of-buffer nil)))))) (defun elisp-refs-prev-match () "Move to the previous search result in the Refs buffer." (interactive) (elisp-refs--move-to-match -1)) (defun elisp-refs-next-match () "Move to the next search result in the Refs buffer." (interactive) (elisp-refs--move-to-match 1)) (provide 'elisp-refs) ;;; elisp-refs.el ends here