emacs-git-messenger-0.18/ 0000755 0001750 0001750 00000000000 13032202234 015122 5 ustar dogsleg dogsleg emacs-git-messenger-0.18/Changes 0000644 0001750 0001750 00000003232 13032202234 016415 0 ustar dogsleg dogsleg Revision history for git-messenger.el
Revision 0.18 2017/01/01 syohex
- Drop older Emacs support
- Implement magit integration
Revision 0.17 2016/08/16 syohex
- Initial support going parent commit(#40)
- Show command keys in prompt(#39)
- Improve deciding VCS type(#38)
- Support merurial(#37 Thanks Sean Farley!!)
- Enable view-mode(#36)
Revision 0.16 2015/03/14 syohex
- Support Subversion
Revision 0.15 2014/08/29 syohex
- Improve quit command.
Thanks tsdh !!
Revision 0.14 2014/08/10 syohex
- Fix customizable variable type
Thanks conleym !!
Revision 0.13 2014/07/06 syohex
- Refactoring
- Improve for tramp
Revision 0.12 2014/05/25 syohex
- Improve for tramp
Revision 0.11 2014/04/02 syohex
- Fix some bugs
- restore popup-ed buffer mode
- set git option for working correctly in Emacs
Revision 0.10 2014/04/02 syohex
- Support 'git diff' and 'git show' command
Revision 0.09 2014/04/02 syohex
- Support key mapping(Thanks stsquad)
Revision 0.08 2014/01/17 syohex
- Only documentation change
Revision 0.07 2014/01/14 syohex
- Fix double escaping issue(#13)
Reported by achitu
Revision 0.06 2014/01/09 syohex
- Support TRAMP
Revision 0.05 2013/07/18 syohex
- add git-messenger:before-popup-hook
- fix case core.autocrlf=true or input(Reported by redguardtoo)
Revision 0.04 2013/06/13 syohex
- Refactoring
rename confused variable name
Revision 0.03 2013/06/13 syohex
- Support showing detail(Advice by redguardtoo)
Revision 0.02 2013/06/11 syohex
- Support not committed line(Thanks @stsquad, @percell)
- Shell Quote file name
Revision 0.01 2013/06/11 syohex
- Initial version
emacs-git-messenger-0.18/Makefile 0000644 0001750 0001750 00000000453 13032202234 016564 0 ustar dogsleg dogsleg .PHONY : test
EMACS ?= emacs
CASK ?= cask
LOADPATH = -L .
ELPA_DIR = $(shell EMACS=$(EMACS) $(CASK) package-directory)
test: elpa
$(CASK) exec $(EMACS) -Q -batch $(LOADPATH) \
-l test/test.el \
-f ert-run-tests-batch-and-exit
elpa: $(ELPA_DIR)
$(ELPA_DIR): Cask
$(CASK) install
touch $@
emacs-git-messenger-0.18/Cask 0000644 0001750 0001750 00000000144 13032202234 015725 0 ustar dogsleg dogsleg (source gnu)
(source melpa)
(package-file "git-messenger.el")
(development
(depends-on "magit"))
emacs-git-messenger-0.18/README.md 0000644 0001750 0001750 00000006534 13032202234 016411 0 ustar dogsleg dogsleg # git-messenger.el [![melpa badge][melpa-badge]][melpa-link] [![melpa stable badge][melpa-stable-badge]][melpa-stable-link]
`git-messenger.el` is Emacs port of [git-messenger.vim](https://github.com/rhysd/git-messenger.vim).
`git-messenger.el` provides function that popup commit message at current line.
This is useful when you want to know why this line was changed.
## Screenshot

## Installation
`git-messenger` is available on [MELPA](https://melpa.org/) and [MELPA stable](https://stable.melpa.org/)
You can install `git-messenger` with the following command.
M-x package-install [RET] git-messenger [RET]
## Dependency
* [popup](https://github.com/auto-complete/popup-el)
## Supported VCS
- Git
- Subversion
- Mercurial
## Commands
### `git-messenger:popup-message`
Pop up last commit message at current line. Show detail message, Commit ID, Author,
Date and commit message with `C-u` prefix

## Key Bindings
You can modify key bindings by customizing `git-messenger-map`.
| Key | Command |
|:--------------------:|:--------------------------------------------------------|
| `M-w` | Copy commit message and quit |
| `c` | Copy commit ID and quit |
| `d` | Pop up `git diff` of last change of this line |
| `s` | Pop up `git show --stat` of last change of this line |
| `S` | Pop up `git show --stat -p` of last change of this line |
| `q` | Quit |
## Customize
### `git-messenger:show-detail`(Default `nil`)
Always show detail message if this value is `t`.
### `git-messenger:handled-backends`(Default `'(git svn)`)
Handled VCS which `git-messenger` uses.
Entries in this list will be tried in order to determine whether a
file is under that sort of version control.
### `git-messenger:use-magit-popup`(Default `nil`)
Use `magit-show-commit` instead of `pop-to-buffer`.
## Hooks
### `git-messenger:before-popup-hook`
Run before popup commit message. Hook function take one argument, commit message.
### `git-messenger:after-popup-hook`
Run after popup commit message. Hook function take one argument, commit message.
### `git-messenger:popup-buffer-hook`
Run after popup buffer.
## Global Variables
You may be able to use these variables useful in commands of `git-messenger-map`.
#### `git-messenger:last-message`
Last popup-ed commit message
#### `git-messenger:last-commit-id`
Last popup-ed commit ID
## Sample Configuration
```lisp
(require 'git-messenger) ;; You need not to load if you install with package.el
(global-set-key (kbd "C-x v p") 'git-messenger:popup-message)
(define-key git-messenger-map (kbd "m") 'git-messenger:copy-message)
;; Enable magit-show-commit instead of pop-to-buffer
(custom-set-variables
'(git-messenger:use-magit-popup t))
```
[melpa-link]: https://melpa.org/#/git-messenger
[melpa-stable-link]: https://stable.melpa.org/#/git-messenger
[melpa-badge]: https://melpa.org/packages/git-messenger-badge.svg
[melpa-stable-badge]: https://stable.melpa.org/packages/git-messenger-badge.svg
emacs-git-messenger-0.18/.gitignore 0000644 0001750 0001750 00000000016 13032202234 017107 0 ustar dogsleg dogsleg /.cask/
*.elc
emacs-git-messenger-0.18/git-messenger.el 0000644 0001750 0001750 00000037370 13032202234 020227 0 ustar dogsleg dogsleg ;;; git-messenger.el --- Pop up last commit information of current line -*- lexical-binding: t -*-
;; Copyright (C) 2017 by Syohei YOSHIDA
;; Author: Syohei YOSHIDA
;; URL: https://github.com/syohex/emacs-git-messenger
;; Version: 0.18
;; Package-Requires: ((emacs "24.3") (popup "0.5.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:
;; This package provides a function called git-messenger:popup-message
;; that when called will pop-up the last git commit message for the
;; current line. This uses the git-blame tool internally.
;;
;; Example usage:
;; (require 'git-messenger)
;; (global-set-key (kbd "C-x v p") 'git-messenger:popup-message)
;;
;;; Code:
(require 'cl-lib)
(require 'popup)
(declare-function magit-show-commit "magit-diff")
(defgroup git-messenger nil
"git messenger"
:group 'vc)
(defcustom git-messenger:show-detail nil
"Pop up commit ID and author name too"
:type 'boolean)
(defcustom git-messenger:before-popup-hook nil
"Hook run before popup commit message. This hook is taken popup-ed message"
:type 'hook)
(defcustom git-messenger:after-popup-hook nil
"Hook run after popup commit message. This hook is taken popup-ed message"
:type 'hook)
(defcustom git-messenger:popup-buffer-hook nil
"Hook run after popup buffer(popup diff, popup show etc)"
:type 'hook)
(defcustom git-messenger:handled-backends '(git svn hg)
"List of version control backends for which `git-messenger' will be used.
Entries in this list will be tried in order to determine whether a
file is under that sort of version control."
:type '(repeat symbol))
(defcustom git-messenger:use-magit-popup nil
"Use magit-show-commit instead pop-to-buffer"
:type 'boolean)
(defvar git-messenger:last-message nil
"Last message displayed by git-messenger.
This is set before the pop-up is displayed so accessible in the hooks
and menus.")
(defvar git-messenger:last-commit-id nil
"Last commit id for the last message displayed.
This is set before the pop-up is displayed so accessible in the hooks
and menus.")
(defvar git-messenger:vcs nil)
(defconst git-messenger:directory-of-vcs
'((git . ".git")
(svn . ".svn")
(hg . ".hg")))
(defun git-messenger:blame-arguments (vcs file line)
(let ((basename (file-name-nondirectory file)))
(cl-case vcs
(git (list "--no-pager" "blame" "-w" "-L"
(format "%d,+1" line)
"--porcelain" basename))
(svn (list "blame" basename))
(hg (list "blame" "-wuc" basename)))))
(defsubst git-messenger:cat-file-arguments (commit-id)
(list "--no-pager" "cat-file" "commit" commit-id))
(defsubst git-messenger:vcs-command (vcs)
(cl-case vcs
(git "git")
(svn "svn")
(hg "hg")))
(defun git-messenger:execute-command (vcs args output)
(cl-case vcs
(git (apply 'process-file "git" nil output nil args))
(svn
(let ((process-environment (cons "LANG=C" process-environment)))
(apply 'process-file "svn" nil output nil args)))
(hg
(let ((process-environment (cons
"HGPLAIN=1"
(cons "LANG=utf-8" process-environment))))
(apply 'process-file "hg" nil output nil args)))))
(defun git-messenger:git-commit-info-at-line ()
(let* ((id-line (buffer-substring-no-properties
(line-beginning-position) (line-end-position)))
(commit-id (car (split-string id-line)))
(author (if (re-search-forward "^author \\(.+\\)$" nil t)
(match-string-no-properties 1)
"unknown")))
(cons commit-id author)))
(defun git-messenger:hg-commit-info-at-line (line)
(forward-line (1- line))
(if (looking-at "^\\s-*\\(\\S-+\\)\\s-+\\([a-z0-9]+\\)")
(cons (match-string-no-properties 2) (match-string-no-properties 1))
(cons "-" "-")))
(defun git-messenger:svn-commit-info-at-line (line)
(forward-line (1- line))
(if (looking-at "^\\s-*\\([0-9]+\\)\\s-+\\(\\S-+\\)")
(cons (match-string-no-properties 1) (match-string-no-properties 2))
(cons "-" "-")))
(defun git-messenger:commit-info-at-line (vcs file line)
(with-temp-buffer
(let ((args (git-messenger:blame-arguments vcs file line)))
(unless (zerop (git-messenger:execute-command vcs args t))
(error "Failed: '%s blame'" (git-messenger:vcs-command vcs)))
(goto-char (point-min))
(cl-case vcs
(git (git-messenger:git-commit-info-at-line))
(svn (git-messenger:svn-commit-info-at-line line))
(hg (git-messenger:hg-commit-info-at-line line))))))
(defsubst git-messenger:not-committed-id-p (commit-id)
(or (string-match-p "\\`\\(?:0+\\|-\\)\\'" commit-id)))
(defun git-messenger:git-commit-message (commit-id)
(let ((args (git-messenger:cat-file-arguments commit-id)))
(unless (zerop (git-messenger:execute-command 'git args t))
(error "Failed: 'git cat-file'"))
(goto-char (point-min))
(forward-paragraph)
(buffer-substring-no-properties (point) (point-max))))
(defun git-messenger:hg-commit-message (commit-id)
(let ((args (list "log" "-T" "{desc}" "-r" commit-id)))
(unless (zerop (git-messenger:execute-command 'hg args t))
(error "Failed: 'hg log"))
(buffer-substring-no-properties (point-min) (point-max))))
(defun git-messenger:svn-commit-message (commit-id)
(let ((args (list "log" "-c" commit-id)))
(unless (zerop (git-messenger:execute-command 'svn args t))
(error "Failed: 'svn log"))
(let (end)
(goto-char (point-max))
(when (re-search-backward "^-\\{25\\}" nil t)
(setq end (point)))
(buffer-substring-no-properties (point-min) (or end (point-max))))))
(defun git-messenger:commit-message (vcs commit-id)
(with-temp-buffer
(if (git-messenger:not-committed-id-p commit-id)
"* not yet committed *"
(cl-case vcs
(git (git-messenger:git-commit-message commit-id))
(svn (git-messenger:svn-commit-message commit-id))
(hg (git-messenger:hg-commit-message commit-id))))))
(defun git-messenger:commit-date (commit-id)
(let ((args (list "--no-pager" "show" "--pretty=%cd" commit-id)))
(with-temp-buffer
(unless (zerop (git-messenger:execute-command 'git args t))
(error "Failed 'git show'"))
(goto-char (point-min))
(buffer-substring-no-properties
(line-beginning-position) (line-end-position)))))
(defun git-messenger:hg-commit-date (commit-id)
(let ((args (list "log" "-T" "{date|rfc822date}" "-r" commit-id)))
(with-temp-buffer
(unless (zerop (git-messenger:execute-command 'hg args t))
(error "Failed 'hg log'"))
(goto-char (point-min))
(buffer-substring-no-properties
(line-beginning-position) (line-end-position)))))
(defun git-messenger:format-detail (vcs commit-id author message)
(cl-case vcs
(git (let ((date (git-messenger:commit-date commit-id)))
(format "commit : %s \nAuthor : %s\nDate : %s \n%s"
(substring commit-id 0 8) author date message)))
(hg (let ((date (git-messenger:hg-commit-date commit-id)))
(format "commit : %s \nAuthor : %s\nDate : %s \n%s"
commit-id author date message)))
(svn (with-temp-buffer
(insert message)
(goto-char (point-min))
(forward-line 1)
(let ((line (buffer-substring-no-properties (point) (line-end-position)))
(re "^\\s-*\\(?:r[0-9]+\\)\\s-+|\\s-+\\([^|]+\\)|\\s-+\\([^|]+\\)"))
(unless (string-match re line)
(error "Can't get revision %s" line))
(let ((author (match-string-no-properties 1 line))
(date (match-string-no-properties 2 line)))
(forward-paragraph)
(format "commit : r%s \nAuthor : %s\nDate : %s\n%s"
commit-id author date
(buffer-substring-no-properties (point) (point-max)))))))))
(defun git-messenger:show-detail-p (commit-id)
(and (or git-messenger:show-detail current-prefix-arg)
(not (git-messenger:not-committed-id-p commit-id))))
(defun git-messenger:popup-close ()
(interactive)
(throw 'git-messenger-loop t))
(defun git-messenger:copy-message ()
"Copy current displayed commit message to kill-ring."
(interactive)
(when git-messenger:last-message
(kill-new git-messenger:last-message))
(git-messenger:popup-close))
(defun git-messenger:copy-commit-id ()
"Copy current displayed commit id to kill-ring."
(interactive)
(when git-messenger:last-commit-id
(kill-new git-messenger:last-commit-id))
(git-messenger:popup-close))
(defun git-messenger:popup-common (vcs args &optional mode)
(with-current-buffer (get-buffer-create "*git-messenger*")
(view-mode -1)
(fundamental-mode)
(erase-buffer)
(unless (zerop (git-messenger:execute-command vcs args t))
(error "Failed: '%s(args=%s)'" (git-messenger:vcs-command vcs) args))
(if git-messenger:use-magit-popup
(magit-show-commit git-messenger:last-commit-id)
(pop-to-buffer (current-buffer))
(when mode
(funcall mode)))
(run-hooks 'git-messenger:popup-buffer-hook)
(view-mode +1)
(goto-char (point-min)))
(git-messenger:popup-close))
(defun git-messenger:popup-svn-show ()
(git-messenger:popup-common
'svn (list "diff" "-c" git-messenger:last-commit-id) 'diff-mode))
(defun git-messenger:popup-hg-show ()
(git-messenger:popup-common
'hg (list "diff" "-c" git-messenger:last-commit-id) 'diff-mode))
(defun git-messenger:popup-diff ()
(interactive)
(cl-case git-messenger:vcs
(git (let ((args (list "--no-pager" "diff" "--no-ext-diff"
(concat git-messenger:last-commit-id "^!"))))
(git-messenger:popup-common 'git args 'diff-mode)))
(svn (git-messenger:popup-svn-show))
(hg (git-messenger:popup-hg-show))))
(defun git-messenger:popup-show ()
(interactive)
(cl-case git-messenger:vcs
(git (let ((args (list "--no-pager" "show" "--no-ext-diff" "--stat"
git-messenger:last-commit-id)))
(git-messenger:popup-common 'git args)))
(svn (git-messenger:popup-svn-show))
(hg (let ((args (list "log" "--stat" "-r"
git-messenger:last-commit-id)))
(git-messenger:popup-common 'hg args)))))
(defun git-messenger:popup-show-verbose ()
(interactive)
(cl-case git-messenger:vcs
(git (let ((args (list "--no-pager" "show" "--no-ext-diff" "--stat" "-p"
git-messenger:last-commit-id)))
(git-messenger:popup-common 'git args)))
(svn (error "'svn' does not support `popup-show-verbose'"))
(hg (let ((args (list "log" "-p" "--stat" "-r"
git-messenger:last-commit-id)))
(git-messenger:popup-common 'hg args)))))
(defvar git-messenger-map
(let ((map (make-sparse-keymap)))
;; key bindings
(define-key map (kbd "q") 'git-messenger:popup-close)
(define-key map (kbd "c") 'git-messenger:copy-commit-id)
(define-key map (kbd "d") 'git-messenger:popup-diff)
(define-key map (kbd "s") 'git-messenger:popup-show)
(define-key map (kbd "S") 'git-messenger:popup-show-verbose)
(define-key map (kbd "M-w") 'git-messenger:copy-message)
(define-key map (kbd ",") 'git-messenger:show-parent)
map)
"Key mappings of git-messenger. This is enabled when commit message is popup-ed.")
(defun git-messenger:find-vcs ()
(let ((longest 0)
result)
(dolist (vcs git-messenger:handled-backends result)
(let* ((dir (assoc-default vcs git-messenger:directory-of-vcs))
(vcs-root (locate-dominating-file default-directory dir)))
(when (and vcs-root (> (length vcs-root) longest))
(setq longest (length vcs-root)
result vcs))))))
(defun git-messenger:svn-message (msg)
(with-temp-buffer
(insert msg)
(goto-char (point-min))
(forward-paragraph)
(buffer-substring-no-properties (point) (point-max))))
(defvar git-messenger:func-prompt
'((git-messenger:popup-show . "Show")
(git-messenger:popup-show-verbose . "Show verbose")
(git-messenger:popup-close . "Close")
(git-messenger:copy-commit-id . "Copy hash")
(git-messenger:popup-diff . "Diff")
(git-messenger:copy-message . "Copy message")
(git-messenger:show-parent . "Go Parent")
(git-messenger:popup-close . "Quit")))
(defsubst git-messenger:function-to-key (func)
(key-description (car-safe (where-is-internal func git-messenger-map))))
(defun git-messenger:prompt ()
(mapconcat (lambda (fp)
(let ((key (git-messenger:function-to-key (car fp))))
(format "[%s]%s" key (cdr fp))))
git-messenger:func-prompt " "))
(defun git-messenger:show-parent ()
(interactive)
(let ((file (buffer-file-name (buffer-base-buffer))))
(cl-case git-messenger:vcs
(git (with-temp-buffer
(unless (zerop (process-file "git" nil t nil
"blame" "--increment" git-messenger:last-commit-id "--" file))
(error "No parent commit ID"))
(goto-char (point-min))
(when (re-search-forward (concat "^" git-messenger:last-commit-id) nil t)
(when (re-search-forward "previous \\(\\S-+\\)" nil t)
(let ((parent (match-string-no-properties 1)))
(setq git-messenger:last-commit-id parent
git-messenger:last-message (git-messenger:commit-message 'git parent)))))
(throw 'git-messenger-loop nil)))
(otherwise (error "%s does not support for getting parent commit ID" git-messenger:vcs)))))
;;;###autoload
(defun git-messenger:popup-message ()
(interactive)
(let* ((vcs (git-messenger:find-vcs))
(file (buffer-file-name (buffer-base-buffer)))
(line (line-number-at-pos))
(commit-info (git-messenger:commit-info-at-line vcs file line))
(commit-id (car commit-info))
(author (cdr commit-info))
(msg (git-messenger:commit-message vcs commit-id))
(popuped-message (if (git-messenger:show-detail-p commit-id)
(git-messenger:format-detail vcs commit-id author msg)
(cl-case vcs
(git msg)
(svn (if (string= commit-id "-")
msg
(git-messenger:svn-message msg)))
(hg msg)))))
(setq git-messenger:vcs vcs
git-messenger:last-message popuped-message
git-messenger:last-commit-id commit-id)
(let (finish)
(run-hook-with-args 'git-messenger:before-popup-hook popuped-message)
(while (not finish)
(let ((menu (popup-tip git-messenger:last-message :nowait t)))
(unwind-protect
(setq finish (catch 'git-messenger-loop
(popup-menu-event-loop menu git-messenger-map 'popup-menu-fallback
:prompt (git-messenger:prompt))
t))
(popup-delete menu)))))
(run-hook-with-args 'git-messenger:after-popup-hook popuped-message)))
(provide 'git-messenger)
;; Local Variables:
;; coding: utf-8
;; indent-tabs-mode: nil
;; End:
;;; git-messenger.el ends here
emacs-git-messenger-0.18/test/ 0000755 0001750 0001750 00000000000 13032202234 016101 5 ustar dogsleg dogsleg emacs-git-messenger-0.18/test/test.el 0000644 0001750 0001750 00000002620 13032202234 017402 0 ustar dogsleg dogsleg ;;; test.el --- test of git-messenger
;; Copyright (C) 2016 by Syohei YOSHIDA
;; Author: Syohei YOSHIDA
;; 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 .
;;; Code:
(require 'ert)
(require 'git-messenger)
(ert-deftest find-vcs ()
""
(let* ((tmp-dir (file-name-as-directory
(concat default-directory (make-temp-name "git-messenger"))))
(git-dir (concat tmp-dir ".git"))
(hg-dir (concat tmp-dir "foo/" ".hg"))
(test-dir (concat tmp-dir "foo/bar/")))
(unwind-protect
(progn
(make-directory git-dir t)
(make-directory hg-dir t)
(make-directory test-dir t)
(let ((default-directory test-dir))
(should (eq (git-messenger:find-vcs) 'hg))))
(delete-directory tmp-dir t))))
;;; test.el ends here
emacs-git-messenger-0.18/image/ 0000755 0001750 0001750 00000000000 13032202234 016204 5 ustar dogsleg dogsleg emacs-git-messenger-0.18/image/git-messenger-detail.png 0000644 0001750 0001750 00000172023 13032202234 022730 0 ustar dogsleg dogsleg PNG
IHDR R ! sBIT|d IDATxy|cs ȡQ, xRVh[KO)[**xP@@@.͝M3#!Hvvs˼^}gfa233_AA૯륬{k& Ѕv Ir!IR 11H+)))i1$$&LDD
VZCU^]uTAA$QRRwffQZZJuuuoJf`)X
عk3;= t
I||<f
%<<NHàƇi'9%lϋf4Q
DAhxiG, I2ӯn'b8Nʕ+nŤIX|9'`2u wj%G/֨|t]|I=#meuQZR}ńG ݃X]/>lTRH!5
}Hd%w;A*UUbѢE
7@UUVr,OLLX:SN'o/X.]1%KJ-""S7l
I䬳iQU#FAh@S}x^>~@_>|^_}U|^/>Տn߇2!]
קoRhhj>TM CHk;۴8YXU~կЏS0U>~Mb004UUњI}Yt)cǎ3`ҥDEE5:(ʕ+ٵkdٲeDڵ+W(JPlqFJ h`.|(Rsy<~kQ37F݅O&&:vVt=iUcӰ6k0,}rC&O
Nu?zM~uz\ON
-~{G'CW?Dҗ)wgZ>ɢ
ȒBg˺%-Iᬒ2kcs_ͧS3܅[Z:z%n@K wr9qd[OrPI.&FOu
)SL5O=ŪbEN:i8N.]ʐ!C_2dK.eҬlߺvsE5駟ۙ>}:555A⌔%߄3P˓/ݲ}7N5U@veܸS6P*r9sIhrξj&Wr+Ğv)dM$ɒHOsѬCs9
{{sjV6?,S6xa6Iܫ3܆1+2r?W掿low'89\3oQ~ڋz^{>Ż(t瞗?_7Cg7nϢG/ͯ,߲/(A@+0do2d-jnh?/v>}:٤Bvvv} ,y{S[WժfaPaok7s҉
) AL~dg`%?m nm-8o0_qsҭ:+ᡅ;y<ƃmt?<2.^|eJt/()o{{`QPءV
V>Fwj,R_Qqȅ\tn+٨0{a^7.̡ϭoѲ,FM.vaձqFOokj0',,0C#QI↲{),tsͧS'{Vq/|m E8kl}NIKLT b؛M\:g'eTUJ%;05?&?bo\IvEЬvN^yx;bAݯ
co_eo+=ܒ!y5ylJ@3ܘJ\('ͽ{Xzx gscϼy#$PuhV+6_'[wOa˘P>ΆZ6G Bl\q/--eҤIw*'))˗Ν;4h˗/gԩgJGU^ ~.Yڢ@g! o-mk 4%kԕ㣒e3BJJ/3.{b|tWd/~ą2zah~Ḇb_z?xy{>u~p'[!WxF/+?mX_xgAwL(?KZOh y@u%LGu}%?aA8f(BXX!6x=S`.ٿ֨=/Xat:Yd {f]L>3fk.z͒%Kzf*v6^oqaAiis_B)>vCƣdwag6<Y3wyQBV#+Vv-YpgzVOE
_L_V"V,]x{L }63*l5$~o<3+?Wr"nP%i`OOGc,|r#nY^^ԩS4i+VR✜#
7i%ǩ+:?=n^,R;ߋ*[Y,ȒCm82*bcAy26W?+~tjǦHj`!^4Ŋ͢ I:~0EW,1MU
aN쪛ZIb(<*FW=x5zuÏϧ!Y(~>ج
dz
VT.aE%B1 }m9jR0Vn!x,#IRO ,LbD2$@۷oS{@cF&f;1OrZI
$JヘAAh%H 0}`AAQ BWbAAh%H HnD&sZ BT"0Ie=`]liiS[\[S:202? Anh:!1x|_~Pru}N tT/xelVfLfb]sp~l5yw66{|LrѤ8K/XtJŃH AQ"Yyסk:#3};>ui~|v=N%ɤ8`#-Rl<>)2tج%pݓ4o8^Z`xhZ]cѽ:xvLgUs{żPb?py_>
+>nmUr38}T7H67ML4|_̏~js{?aFBZ,/LDë_/uf8XxY&ɔU0gD
,j{Mf ^nz*%4F:YwG,$8f&Up˻|PUl)Idh#W
++쮞xpهmê8ia9am?Gۘo%"%rW
jyso_/*+K/
O4>ah4./)=K-5ܸ)S8˓os}:FgRc2i26ՆOѧ{pr߃XR[5Ni~B.>_cUi$N9*<^Qjxr3`^,y-/ ! oV,
iV,2O_`%T;<,qΤDNǬ5ό%&fsp鿫A;f&Vn:=qE8 W51jy
5S+wL[T(d @a¤<\\pbzGD`2O$s^e˅٪'lfLɜ$[Yܟyz4M@㳭l0$ QN\?EWEcE>ڹe@ى̶o6Lߴd|ǿRz`Ǘ|Hq|$mJO%WUnric`lHT RcC]3d[b亼%5"f`Ƈ;f1Z`7%li\dz=N/or/îanHw m~ZE>wp'Ek}{lձW͵T^} >:J~7-:ZoC -Z`
_nT8NY]TKQl_/GYN]r6q^2{m}"7}le0oQ[OJWd|KNP̩b^/n`k^-_$GW1wvGfD*mܾ0V/SGӫy=KbFV-d&ǟ=IcVx|ZMߴ~f|2."}?P~Rˇ(e+c+3hPNDt6#eh.gMs_6
_JdS4
Ϟil{;lKBJLu52Nv꧄8ѡP>g1;m6֚i>I|IdP">f٣6TVj'
KgcU.9a6Ao\zCbdd~)xJGmPvommp|lK䉉A ,Lisi|~$lRpLI̊S2PACE8/7{?Uٔ|Hr1nko`ƷvC1gmp_f`t?rS\\x$8kʄ~q60Ѭ~Pˬ[/߆2Nqy]7 k ɢbYƌH\kSS5
JuSb`ȤGvO5ؽWEI`t3w*}rQ\Y|J9QoYmlq6rZ8.D1DՆ̓2%bPvlHߠO{'
yd}Ŗwfjm|jV.4$2a'?g6!sj}|ׅ2ZƗYw?Ku
#{20dBs6+7u:I=ØB03>un)C$(2dk(Ai
U4{qTp3SzYǐszpƤ1yx,Yírdos7g1Ea| )5ӒlHr%4-ħky~̬ILqD^pV'8!VƊDjbC)$գx;+Y<ݡs>bXp~;*h~֗K:"Ƚoc>eOI3LH1O$wbG+R$oSyfk3XrVkτ2f˴;߅HY"J5Affj˙?K.Ŷ[RxDKp?{˲rz_6I
}Pzi5hro4.77y`i/z +R8y^|qI,E4+jrR>l"`M~DM}X1%6i}vjx>:A?@t%S<(7.2~Tpa|TȜ6뮌c&~TKYP7۶۟WN^{leiRoݻ=Du=VW49>\LL١Or7ַhl|I2>q|iwaRffp b&;
lrAH'$n}ܷ~H}ݖ~I+t[HIKc/fQWg $RRԪw;7 W{%kZAY Bw$whFxYSGd8~I$xB"fUkZ].=¹g$qS]c6? G[HH /)AA)H HAAZI$Ri1zs{|:?6D"ՎB7B]20ӊ't[|,;_K
qE Z?HzYv:f1:~3]$ڧ}pè^>ج̞YaΏ
<]jE?_K$sTF V6r+p@'OG7nwˬ}#t8Hu Ee>(6鸻
O
M
TX ipPOG[q IDAT~wˬ}#t)ß}\.YX^ʼn2Wӯ3^l,'%9\G$ga۰*NZXOD-ܰa` +2ƼTVydq$8NIc~꧆/nH