From 96ee4bd0bd7b5cc8a6d9ca918ede26e82a9b20a7 Mon Sep 17 00:00:00 2001 From: Kyle Meyer Date: Sat, 12 Jan 2013 12:44:44 -0500 Subject: glob init files files for loading --- init/00-km-ui.el | 33 ++++++++++++ init/10-km-pkg.el | 31 +++++++++++ init/km-editor.el | 28 ++++++++++ init/km-evil.el | 124 ++++++++++++++++++++++++++++++++++++++++++++ init/km-func.el | 47 +++++++++++++++++ init/km-general.el | 21 ++++++++ init/km-haskell.el | 3 ++ init/km-ibuffer.el | 48 +++++++++++++++++ init/km-ido.el | 22 ++++++++ init/km-mail.el | 15 ++++++ init/km-org.el | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++ init/km-python.el | 34 ++++++++++++ init/km-tex.el | 42 +++++++++++++++ 13 files changed, 597 insertions(+) create mode 100644 init/00-km-ui.el create mode 100644 init/10-km-pkg.el create mode 100644 init/km-editor.el create mode 100644 init/km-evil.el create mode 100644 init/km-func.el create mode 100644 init/km-general.el create mode 100644 init/km-haskell.el create mode 100644 init/km-ibuffer.el create mode 100644 init/km-ido.el create mode 100644 init/km-mail.el create mode 100644 init/km-org.el create mode 100644 init/km-python.el create mode 100644 init/km-tex.el (limited to 'init') diff --git a/init/00-km-ui.el b/init/00-km-ui.el new file mode 100644 index 0000000..19c7aac --- /dev/null +++ b/init/00-km-ui.el @@ -0,0 +1,33 @@ +;; check km-editor.el if don't find something in here + +;; to customize font +(setq default-frame-alist '((font . "Droid Sans Mono-9"))) + +(require 'font-lock) +(global-font-lock-mode t) +(add-to-list 'auto-mode-alist '("\\.*rc$" . conf-unix-mode)) + +;; splash screen +(setq inhibit-splash-screen t + initial-scratch-message nil) + +(scroll-bar-mode -1) +(tool-bar-mode -1) +(menu-bar-mode -1) + +(setq-default indicate-empty-lines t) +(when (not indicate-empty-lines) + (toggle-indicate-empty-lines)) + +(setq echo-keystrokes 0.1 + use-dialog-box nil + visible-bell t) +(show-paren-mode t) + +;; y or n +(defalias 'yes-or-no-p 'y-or-n-p) + +;; line info +(line-number-mode t) +(column-number-mode t) +(size-indication-mode t) diff --git a/init/10-km-pkg.el b/init/10-km-pkg.el new file mode 100644 index 0000000..91c0462 --- /dev/null +++ b/init/10-km-pkg.el @@ -0,0 +1,31 @@ +;; http://www.aaronbedra.com/emacs.d/ + +(require 'package) +(add-to-list 'package-archives + '("melpa" . "http://melpa.milkbox.net/packages/") t) +(package-initialize) + +(require 'cl) +(defvar km/packages '( + evil + undo-tree + key-chord + org + ess + lua-mode + haskell-mode + ) + "Default packages") + +(defun km/packages-installed-p () + (loop for pkg in km/packages + when (not (package-installed-p pkg)) do (return nil) + finally (return t))) + +(unless (km/packages-installed-p) + (message "%s" "Refreshing package database...") + (package-refresh-contents) + (dolist (pkg km/packages) + (when (not (package-installed-p pkg)) + (message "installing %s" pkg) + (package-install pkg)))) diff --git a/init/km-editor.el b/init/km-editor.el new file mode 100644 index 0000000..0fe2a31 --- /dev/null +++ b/init/km-editor.el @@ -0,0 +1,28 @@ +;; check km-ui.el if don't find something in here + +(setq-default fill-column 72) +(add-hook 'text-mode-hook 'turn-on-auto-fill) + +;; ess +;; (require 'ess-site) +(add-hook 'ess-mode-hook (lambda () + (setq ess-indent-level 4))) + +;; shell scripts +(add-hook 'sh-mode-hook (lambda () + (setq sh-basic-offset 4))) + +(global-set-key (kbd "C-x \\") 'align-regexp) + +;; make whitespace-mode use just basic coloring +;; http://ergoemacs.org/emacs/whitespace-mode.html +(setq whitespace-style (quote + (spaces tabs newline space-mark + tab-mark newline-mark))) + +(delete-selection-mode t) ;; write over selected text +(transient-mark-mode t) +;; share clipboard with system +(setq x-select-enable-clipboard t) + +(blink-cursor-mode -1) diff --git a/init/km-evil.el b/init/km-evil.el new file mode 100644 index 0000000..677b55a --- /dev/null +++ b/init/km-evil.el @@ -0,0 +1,124 @@ +;; evil mode uses undo-tree +(require 'undo-tree) + +(require 'evil) +(evil-mode 1) +;; much of this it taken from http://permalink.gmane.org/gmane.emacs.vim-emulation/1135 + +;; red box in emacs mode +(setq evil-emacs-state-cursor '("red" box)) + +(define-key evil-motion-state-map "H" 'evil-scroll-up) +(define-key evil-motion-state-map "L" 'evil-scroll-down) + +(defun km/save-and-kill-buffer () + "Save current buffer and then kill it" + (interactive) + (save-buffer) + (kill-this-buffer) + ) + + +(define-key evil-normal-state-map ",w" 'save-buffer) +(define-key evil-normal-state-map ",q" 'kill-buffer) +(define-key evil-normal-state-map ",d" 'km/save-and-kill-buffer) +(define-key evil-normal-state-map "Q" 'fill-paragraph) + +(evil-define-key 'visual emacs-lisp-mode-map + ",e" 'eval-region) +(evil-define-key 'visual lisp-interaction-mode-map + ",e" 'eval-region) + +(evil-define-key 'normal mail-mode-map ",q" 'server-edit) +(evil-define-key 'normal mail-mode-map ",d" 'server-edit) + +(define-key evil-visual-state-map ",c" 'comment-or-uncomment-region) +(fset 'comment-this-line ;; this depends on evil bindings + "0v$,c") +(define-key evil-normal-state-map ",c" 'comment-this-line) + +(require 'key-chord) +(key-chord-mode 1) + +(key-chord-define-global ",r" 'km/recentf-ido-find-file) +(key-chord-define-global ",t" 'org-capture) +;; instead of alt-x +(key-chord-define-global ",x" 'execute-extended-command) +(key-chord-define-global ",f" 'find-file) +(key-chord-define-global ",g" 'indent-relative) +(key-chord-define-global ",b" 'ido-switch-buffer) +;; cannot map this to insert mode because it jams up the first letter +;; switch from jf because often pressing j to go up/down, so probably +;; best not to have it have to consider whether it is a chord each time +(key-chord-define-global ";a" 'evil-normal-state) + +;; org bindings +(defun km/always-insert-item () + (interactive) + (if (not (org-in-item-p)) + (insert "\n- ") + (org-insert-item))) + +;; most from cofi config +(evil-define-key 'normal org-mode-map + (kbd "RET") 'org-open-at-point + "za" 'org-cycle + "zA" 'org-shifttab + "zm" 'hide-body + "zr" 'show-all + "zo" 'show-subtree + "zO" 'show-all + "zc" 'hide-subtree + "zC" 'hide-all + ",e" 'org-export-as-pdf + ",a" 'org-archive-subtree + ",s" 'org-todo + "O" (lambda () + (interactive) + (end-of-line) + (org-insert-heading t) + (evil-append nil)) + "o" (lambda () + (interactive) + (end-of-line) + (km/always-insert-item) + (evil-append nil)) +(kbd "M-j") 'org-shiftleft + (kbd "M-k") 'org-shiftright + (kbd "M-H") 'org-metaleft + (kbd "M-J") 'org-metadown + (kbd "M-K") 'org-metaup + (kbd "M-L") 'org-metaright) + +(evil-define-key 'normal orgstruct-mode-map + (kbd "RET") 'org-open-at-point + "za" 'org-cycle + "zA" 'org-shifttab + "zm" 'hide-body + "zr" 'show-all + "zo" 'show-subtree + "zO" 'show-all + "zc" 'hide-subtree + "zC" 'hide-all + (kbd "M-j") 'org-shiftleft + (kbd "M-k") 'org-shiftright + (kbd "M-H") 'org-metaleft + (kbd "M-J") 'org-metadown + (kbd "M-K") 'org-metaup + (kbd "M-L") 'org-metaright) + +(evil-define-key 'insert org-mode-map + (kbd "M-j") 'org-shiftleft + (kbd "M-k") 'org-shiftright + (kbd "M-H") 'org-metaleft + (kbd "M-J") 'org-metadown + (kbd "M-K") 'org-metaup + (kbd "M-L") 'org-metaright) + +(evil-define-key 'insert orgstruct-mode-map + (kbd "M-j") 'org-shiftleft + (kbd "M-k") 'org-shiftright + (kbd "M-H") 'org-metaleft + (kbd "M-J") 'org-metadown + (kbd "M-K") 'org-metaup + (kbd "M-L") 'org-metaright) diff --git a/init/km-func.el b/init/km-func.el new file mode 100644 index 0000000..3366363 --- /dev/null +++ b/init/km-func.el @@ -0,0 +1,47 @@ +;; http://whattheemacsd.com/ +;; whitespace cleanup +(defun km/cleanup-buffer () + (interactive) + (untabify (point-min) (point-max)) + (delete-trailing-whitespace) + (set-buffer-file-coding-system 'utf-8)) +(add-hook 'before-save-hook 'km/cleanup-buffer) + +(defun km/rename-current-buffer-file () + "Renames current buffer and file it is visiting." + (interactive) + (let ((name (buffer-name)) + (filename (buffer-file-name))) + (if (not (and filename (file-exists-p filename))) + (error "Buffer '%s' is not visiting a file!" name) + (let ((new-name (read-file-name "New name: " filename))) + (if (get-buffer new-name) + (error "A buffer named '%s' already exists!" new-name) + (rename-file filename new-name 1) + (rename-buffer new-name) + (set-visited-file-name new-name) + (set-buffer-modified-p nil) + (message "File '%s' successfully renamed to '%s'" + name (file-name-nondirectory new-name))))))) + +(global-set-key (kbd "C-x C-r") 'km/rename-current-buffer-file) + +(defun km/shebang (&optional lang) + (interactive "s\language (default python):") + (if (= (length lang) 0) + (setq lang "python")) + (insert "#!/usr/bin/env " lang "\n")) +(global-set-key (kbd "C-c s") 'km/shebang) + +(defun km/insert-random-string (&optional strlen) + "Insert a random string (default length: 5)" + (interactive) + (unless strlen + (setq strlen 5)) + (let (mycharset (ii 0) ) + (setq mycharset ["a" "b" "c" "d" "e" "f" "g" "h" "i" + "j" "k" "l" "m" "n" "o" "p" "q" "r" + "s" "t" "u" "v" "w" "x" "y" "z"]) + (while (< ii strlen) + (insert (elt mycharset (random (length mycharset)))) + (setq ii (1+ ii))))) diff --git a/init/km-general.el b/init/km-general.el new file mode 100644 index 0000000..5d661e9 --- /dev/null +++ b/init/km-general.el @@ -0,0 +1,21 @@ +;; set location of custom.el +(setq custom-file "~/.emacs.d/custom.el") +(load custom-file) + +;; store all backup and autosave files in the tmp dir +(setq backup-directory-alist + `((".*" . ,temporary-file-directory))) +(setq auto-save-file-name-transforms + `((".*" ,temporary-file-directory t))) + +;; revert buffers automatically when underlying files are changed externally +(global-auto-revert-mode t) + +;; tramp +(require 'tramp) +(setq tramp-default-method "ssh") + +(setq browse-url-browser-function 'browse-url-generic + browse-url-generic-program "google-chrome") + +;;(require 'dired+) diff --git a/init/km-haskell.el b/init/km-haskell.el new file mode 100644 index 0000000..58bc2c8 --- /dev/null +++ b/init/km-haskell.el @@ -0,0 +1,3 @@ +;; randomly chose one of three given in help +(custom-set-variables + '(haskell-mode-hook '(turn-on-haskell-indentation))) diff --git a/init/km-ibuffer.el b/init/km-ibuffer.el new file mode 100644 index 0000000..3fa6a03 --- /dev/null +++ b/init/km-ibuffer.el @@ -0,0 +1,48 @@ +;; replace buffer-menu with ibuffer +(global-set-key (kbd "C-x C-b") 'ibuffer) + +;; modified from http://martinowen.net/blog/2010/02/tips-for-emacs-ibuffer.html +;; and here http://www.elliotglaysher.org/emacs/ + +(setq ibuffer-saved-filter-groups + '(("home" + ("emacs-config" (or (filename . ".emacs.d") + (filename . ".el"))) + ("org" (or (mode . org-mode) + (name . "^\\*Org Agenda") + (name . "^\\*Calendar\\*$"))) + ("web" (or (mode . html-mode) + (mode . nxml-mode) + (mode . css-mode))) + ("r" (or (mode . ess-mode) + (name . "^\\*R\\*$"))) + ("markup" (or (mode . markdown-mode) + (mode . rst-mode))) + ("lua" (name . ".lua$")) + ("perl" (name . ".pl$")) + ("python" (name . ".py$")) + ("git" (name . "\*git")) + ("text" (name . ".txt")) + ("shell" (name . ".sh$")) + ("latex" (or (mode . latex-mode) + (mode . LaTeX-mode) + (mode . bibtex-mode) + (mode . reftex-mode))) + ("dirs" (or (mode . dired-mode) + (name . "^\\*tramp"))) + ("terminal" (name . "^\\*ansi-term\\*$")) + ("help" (or (name . "\*Help\*") + (name . "\*Apropos\*") + (name . "\*info\*") + (name . "^\\*Completions\\*$")))))) + +(add-hook 'ibuffer-mode-hook + '(lambda () + (ibuffer-auto-mode 1) ; keep buffer list up-to-date + (ibuffer-switch-to-saved-filter-groups "home"))) + +;; do not prompt to delete unmodified buffers +(setq ibuffer-expert t) + +;; don't show empty filter groups +(setq ibuffer-show-empty-filter-groups nil) diff --git a/init/km-ido.el b/init/km-ido.el new file mode 100644 index 0000000..d06163c --- /dev/null +++ b/init/km-ido.el @@ -0,0 +1,22 @@ +(ido-mode t) +(setq ido-enable-prefix nil + ido-everywhere t + ido-enable-flex-matching t + ido-create-new-buffer 'always + ido-use-filename-at-point 'guess + ido-max-prospects 10 + ido-save-directory-list-file "~/.emacs.d/cache/ido.hist") + +;; recent files +(setq recentf-save-file "~/.emacs.d/cache/recentf" + recentf-max-saved-items 200 + recentf-max-menu-items 15) +(recentf-mode t) + +;; from prelude +(defun km/recentf-ido-find-file () + "Find a recent file using ido." + (interactive) + (let ((file (ido-completing-read "Choose recent file: " recentf-list nil t))) + (when file + (find-file file)))) diff --git a/init/km-mail.el b/init/km-mail.el new file mode 100644 index 0000000..7a48417 --- /dev/null +++ b/init/km-mail.el @@ -0,0 +1,15 @@ +(add-to-list 'auto-mode-alist '("/mutt" . mail-mode)) + +(defun km/mail-position () + "Move cursor to first blank line +and position cursor between two blank lines" + (interactive) + (forward-paragraph) + (insert "\n\n") + (previous-line)) + +(defun km/mail-mode-hook () + (auto-fill-mode 1) + (km/mail-position)) + +(add-hook 'mail-mode-hook 'km/mail-mode-hook) diff --git a/init/km-org.el b/init/km-org.el new file mode 100644 index 0000000..1d7a80a --- /dev/null +++ b/init/km-org.el @@ -0,0 +1,149 @@ +;;;; org-mode +(setq org-log-done t) +(setq org-todo-keywords + '((sequence "TODO" "STARTED" "|" "DONE" "NA"))) + + ;(setq org-agenda-files (list "~/notes/tasks.org")) + +;; next 6 lines merged from prelude-org +(global-set-key "\C-cl" 'org-store-link) +(global-set-key "\C-ca" 'org-agenda) +(global-set-key "\C-cb" 'org-iswitchb) +(setq org-log-done t) + +;; allow for file to end in txt +(add-to-list 'auto-mode-alist '("\\.org.txt$" . org-mode)) + +;; set up capture +;; (setq org-default-notes-file (expand-file-name "~/notes/tasks.org")) +(setq org-capture-templates + '(("c" "cal" entry (file+headline "~/notes/calendar.org" "misc") + "* %?") + ("t" "Todo" entry (file+headline "~/notes/tasks.org" "To file") + "* TODO %?") + ("m" "mail todo" entry (file+headline "~/notes/tasks.org" "mail") + "* TODO %?\nSource: %u, %c\n%i") + ("d" "mail date" entry (file+headline "~/notes/calendar.org" "mail") + "* %?\nSource: %u, %c\n%i"))) + +;; for mutt capture +(require 'org-protocol) +;; ensure that emacsclient will show just the note to be edited when invoked +;; from Mutt, and that it will shut down emacsclient once finished; +;; fallback to legacy behavior when not invoked via org-protocol. +(add-hook 'org-capture-mode-hook 'delete-other-windows) +(setq my-org-protocol-flag nil) +(defadvice org-capture-finalize (after delete-frame-at-end activate) + "Delete frame at capture finalization" + (progn (if my-org-protocol-flag (delete-frame)) + (setq my-org-protocol-flag nil))) +(defadvice org-capture-kill (after delete-frame-at-end activate) + "Delete frame at capture abort" + (progn (if my-org-protocol-flag (delete-frame)) + (setq my-org-protocol-flag nil))) +(defadvice org-protocol-capture (before set-org-protocol-flag activate) + (setq my-org-protocol-flag t)) + +(custom-set-variables + '(org-agenda-files (quote ("~/notes/calendar.org" "~/notes/tasks.org"))) + '(org-default-notes-file "~/notes/tasks.org") + '(org-agenda-ndays 7) +;; '(org-deadline-warning-days 14) + '(org-agenda-show-all-dates t) + '(org-agenda-skip-deadline-if-done t) + '(org-agenda-skip-scheduled-if-done t) + '(org-agenda-start-on-weekday nil) + '(org-reverse-note-order t) + '(org-fast-tag-selection-single-key (quote expert)) + '(org-agenda-custom-commands + (quote (("d" todo "DONE" nil) + ("s" todo "STARTED" nil) + ("A" agenda "" + ((org-agenda-skip-function + (lambda nil + (org-agenda-skip-entry-if (quote notregexp) "\\=.*\\[#A\\]"))) + (org-agenda-ndays 1) + (org-agenda-overriding-header "Today's Priority #A tasks: "))) + ("u" alltodo "" + ((org-agenda-skip-function + (lambda nil + (org-agenda-skip-entry-if (quote scheduled) (quote deadline) + (quote regexp) "\n]+>"))) + (org-agenda-overriding-header "Unscheduled TODO entries: "))))))) + +;; other customization in prelude's org module + +;; have font colors in code blocks +(setq org-src-fontify-natively t) + +;; from http://doc.norang.ca/org-mode.html +;; this should prevent blank lines from being inserted +;; before headers +(setq org-blank-before-new-entry (quote ((heading) + (plain-list-item . auto)))) +(setq org-cycle-separator-lines 1) + + +;; from http://doc.norang.ca/org-mode.html +(setq org-refile-targets (quote ((nil :maxlevel . 5) + (org-agenda-files :maxlevel . 5)))) + +;; Stop using paths for refile targets - we file directly with IDO +(setq org-refile-use-outline-path nil) + +;; Targets complete directly with IDO +(setq org-outline-path-complete-in-steps nil) + +;; Allow refile to create parent tasks with confirmation +(setq org-refile-allow-creating-parent-nodes (quote confirm)) + +;; Use IDO for both buffer and file completion and ido-everywhere to t +(setq org-completion-use-ido t) +(setq ido-everywhere t) +(setq ido-max-directory-size 100000) +(ido-mode (quote both)) + +;;;; Refile settings +;; Exclude DONE state tasks from refile targets +(defun km/verify-refile-target () + "Exclude todo keywords with a done state from refile targets" + (not (member (nth 2 (org-heading-components)) org-done-keywords))) + +(setq org-refile-target-verify-function 'km/verify-refile-target) + +;; set up babel languages +(org-babel-do-load-languages + 'org-babel-load-languages + '( (perl . t) + (sh . t) + (python . t) + (R . t) + (emacs-lisp . t) + (latex . t) + (ditaa . t) + )) +;; don't ask for confirmation before running code +(setq org-confirm-babel-evaluate nil) + +;; babel minted latex export +;; modified from +;; http://orgmode.org/worg/org-tutorials/org-latex-export.html +(setq org-export-latex-listings 'minted) +(setq org-export-latex-custom-lang-environments + '( + (R "rcode") + (sh "shcode") + (python "pythoncode") + )) +;; (setq org-export-latex-custom-lang-environments +;; '( +;; (emacs-lisp "common-lispcode") +;; )) +;; (setq org-export-latex-minted-options +;; '(("frame" "lines") +;; ("fontsize" "\\scriptsize") +;; ("linenos" ""))) +(setq org-latex-to-pdf-process + '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f" + "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f" + "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f")) diff --git a/init/km-python.el b/init/km-python.el new file mode 100644 index 0000000..ce7aa53 --- /dev/null +++ b/init/km-python.el @@ -0,0 +1,34 @@ +(defun km/python-sysexit () + (interactive) + (insert "sys.exit()")) + +(defun km/python-random-assignment () + (interactive) + (km/insert-random-string 10) + (insert " = None")) + +(defun km/python-shebang () + (interactive) + (km/shebang "python")) + +(defconst km/python-analysis-imports + "import sys +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +from matplotlib.ticker import MaxNLocator + +from colors import brew, fgry, bgry" + ) + +(defun km/python-insert-analysis-imports () + "Common imports for analysis scripts" + (interactive) + (insert km/python-analysis-imports)) + +(defun km/python-hook () + (local-set-key (kbd "C-c p r") 'km/python-random-assignment) + (local-set-key (kbd "C-c p e") 'km/python-sysexit) + (local-set-key (kbd "C-c p s") 'km/python-shebang) + (local-set-key (kbd "C-c p a") 'km/python-insert-analysis-imports)) +(add-hook 'python-mode-hook 'km/python-hook) diff --git a/init/km-tex.el b/init/km-tex.el new file mode 100644 index 0000000..1c69dbd --- /dev/null +++ b/init/km-tex.el @@ -0,0 +1,42 @@ +;;; add path for pdflatex +(getenv "PATH") +(setenv "PATH" + (concat + "/usr/texbin" ":" + (getenv "PATH"))) + +;; for viewing in-frame +;;http://www.sigmafield.org/2009/10/03/using-doc-view-with-auto-revert-to-view-latex-pdf-output-in-emacs/ + ;(setq TeX-PDF-mode t) + ;(add-hook 'doc-view-mode-hook 'auto-revert-mode) + +;; reftex +;; mostly from http://www.kieranhealy.org/esk/starter-kit-latex.html +;; (add-hook 'LaTeX-mode-hook 'turn-on-reftex) ; with AUCTeX LaTeX mode +;; (autoload 'reftex-mode "reftex" "RefTeX Minor Mode" t) +;; (autoload 'turn-on-reftex "reftex" "RefTeX Minor Mode" nil) +;; (autoload 'reftex-citation "reftex-cite" "Make citation" nil) +;; (autoload 'reftex-index-phrase-mode "reftex-index" "Phrase mode" t) +;; (add-hook 'LaTeX-mode-hook 'turn-on-reftex) ; with AUCTeX LaTeX mode +;; (add-hook 'latex-mode-hook 'turn-on-reftex) ; with Emacs latex mode + +;; ;; Make RefTeX faster +;; (setq reftex-enable-partial-scans t) +;; (setq reftex-save-parse-info t) +;; (setq reftex-use-multiple-selection-buffers t) + +;; commented out the rest of it because something was causing it to +;; prompt for master file in org mode +(defun km/org-mode-reftex-setup () + (load-library "reftex") + ;; (and (buffer-file-name) + ;; (file-exists-p (buffer-file-name)) + ;; (reftex-parse-all)) + (define-key org-mode-map (kbd "C-c [") 'reftex-citation) + ) + +(add-hook 'org-mode-hook 'km/org-mode-reftex-setup) + +(setq reftex-default-bibliography + (quote + ("~/refs/refs.bib"))) -- cgit v1.2.3