;;; eev-tlinks.el --- hyperlinks to temporary buffers generated by templates  -*- lexical-binding: nil; -*-

;; Copyright (C) 2013-2022 Free Software Foundation, Inc.
;;
;; This file is part of GNU eev.
;;
;; GNU eev 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.
;;
;; GNU eev 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
;;
;; Author:     Eduardo Ochs <eduardoochs@gmail.com>
;; Maintainer: Eduardo Ochs <eduardoochs@gmail.com>
;; Version:    20221227
;; Keywords:   e-scripts
;;
;; Latest version: <http://angg.twu.net/eev-current/eev-tlinks.el>
;;       htmlized: <http://angg.twu.net/eev-current/eev-tlinks.el.html>
;;       See also: <http://angg.twu.net/eev-current/eev-beginner.el.html>
;;                 <http://angg.twu.net/eev-intros/find-eev-intro.html>
;;                 <http://angg.twu.net/eev-intros/find-links-intro.html>
;;                                                (find-eev-intro)
;;                                                (find-links-intro)

;;; Commentary:

;; The functions defined here - `find-latex-links' and other ones -
;; produce buffers made of a series of hyperlinks followed by a
;; templated text. The templated text is usually preceded by a line
;; like `(ee-copy-rest NLINES CODE)'; see the explanation of
;; `ee-copy-rest' below to understand how this is used.
;;
;; The functions here are one complexity step above the functions in:
;;   (find-eev "eev-elinks.el")
;;
;; See:
;;   (find-links-conv-intro "3. Classification")
;;   (find-links-conv-intro "3. Classification" "c)")
;;   (find-links-conv-intro "3. Classification" "find-elinks")
;;   (find-links-conv-intro "3. Classification" "eev-tlinks.el")
;;
;; Many of the functions in this file are "five-minute hacks" whose
;; first versions were written in two steps. In the first step I ran
;; `M-x find-find-links-links-new', adjusted the arguments in the
;; first line of the temporary buffer and regenerated the buffer; this
;; gave me a "skeleton" for the real function. In the second step I
;; adjusted the arguments of the `find-elinks' and the string inside
;; the `ee-template0'. Each function here that was written in this way
;; has a "Skel:" line in the comments about its definition, and if you
;; run the sexp in the "Skel:" line you get its skeleton. There is a
;; video explaining this here:
;;
;;   (to "find-find-links-links-new")
;;
;; Some of the functions in this file were written with an ancestor of
;; `find-find-links-links-new' that generated uglier code; they need
;; to be rewritten. Also, some functions here are very old, and I
;; haven't used or tested them in ages; they deserve to be deleted.

;; Note that all the `find-*-links' functions in this file have very
;; small docstrings. This is intentional: when a function doesn't have
;; a docstring, or has a docstring that is insufficient, this always
;; means "look at the source", and the `find-*-links' functions do
;; very little besides generating a temporary buffer from a
;; template...
;;
;; So: the best way to understand what the `find-*-links' functions do
;; is by looking at their source code, and by executing the sexps in
;; comments - both the "See:"s and the "Test:"s.




;; «.ee-copy-rest»			(to "ee-copy-rest")
;;
;; «.find-find-links-links»		(to "find-find-links-links")
;; «.find-find-links-links-new»		(to "find-find-links-links-new")
;;   «.ee-ffll-functions»		(to "ee-ffll-functions")
;;
;; «.find-intro-links»			(to "find-intro-links")
;; «.find-eev-header-links»		(to "find-eev-header-links")
;;
;; «.find-debpkg-links»			(to "find-debpkg-links")
;; «.find-eev-install-links»		(to "find-eev-install-links")
;; «.find-eev-update-links»		(to "find-eev-update-links")
;; «.find-youtubedl-links»		(to "find-youtubedl-links")
;;   «.ee-youtubedl-command»		(to "ee-youtubedl-command")
;;
;; «.find-psne-links»			(to "find-psne-links")
;;   «.ee-find-psne-echo-options»	(to "ee-find-psne-echo-options")
;; «.find-psne-eevvideo-links»		(to "find-psne-eevvideo-links")
;; «.find-psne-1stclassvideo-links»	(to "find-psne-1stclassvideo-links")
;; «.find-1stclassvideo-video»		(to "find-1stclassvideo-video")
;;
;; «.find-git-links»			(to "find-git-links")
;; «.find-fossil-links»			(to "find-fossil-links")
;; «.find-apt-get-source-links»		(to "find-apt-get-source-links")
;;
;; «.find-eevvideo-links»		(to "find-eevvideo-links")
;; «.find-psnevideo-links»		(to "find-psnevideo-links")
;;   «.ee-psne-if-needed»		(to "ee-psne-if-needed")
;; «.code-psnevideo»			(to "code-psnevideo")
;; «.code-eevvideo»			(to "code-eevvideo")
;; «.code-eevvideo-local»		(to "code-eevvideo-local")
;;   «.hardcoded-paths»			(to "hardcoded-paths")
;; «.find-eev-video-links»		(to "find-eev-video-links")
;; «.find-eevshortvideo-links»		(to "find-eevshortvideo-links")
;; «.find-wgeteevsubtitles-links»	(to "find-wgeteevsubtitles-links")
;;
;; «.find-latex-links»			(to "find-latex-links")
;; «.find-lua-links»			(to "find-lua-links")
;; «.find-escreenshot-links»		(to "find-escreenshot-links")
;; «.find-windows-eepitch-lua-links»	(to "find-windows-eepitch-lua-links")
;; «.find-extra-file-links»		(to "find-extra-file-links")
;; «.find-emacs-tangents-links»		(to "find-emacs-tangents-links")
;; «.find-eeit-links»			(to "find-eeit-links")
;; «.find-texlive-links»		(to "find-texlive-links")
;; «.find-newbrowser-links»		(to "find-newbrowser-links")
;; «.find-newpdfviewer-links»		(to "find-newpdfviewer-links")
;; «.ee-0x0-upload-region»		(to "ee-0x0-upload-region")
;; «.find-0x0-links»			(to "find-0x0-links")
;; «.find-eepitch-bullet-links»		(to "find-eepitch-bullet-links")
;; «.find-red-star-links»		(to "find-red-star-links")
;;   «.ee-use-red-stars»		(to "ee-use-red-stars")
;;   «.ee-use-red-bullets»		(to "ee-use-red-bullets")
;; «.find-angg-es-links»		(to "find-angg-es-links")
;; «.find-1stclassvideo-links»		(to "find-1stclassvideo-links")
;; «.find-1stclassvideoindex»		(to "find-1stclassvideoindex")
;; «.find-1stclassvideodef»		(to "find-1stclassvideodef")
;; «.find-1stclassvideos»		(to "find-1stclassvideos")
;;   «.1c»				(to "1c")
;; «.find-advicebefore-links»		(to "find-advicebefore-links")
;; «.find-osm-links»			(to "find-osm-links")
;; «.find-pip3-links»			(to "find-pip3-links")
;; «.find-yttranscript-links»		(to "find-yttranscript-links")
;; «.find-importlib-links»		(to "find-importlib-links")
;; «.find-pypi-links»			(to "find-pypi-links")
;; «.find-nov-links»			(to "find-nov-links")
;; «.find-telegachat-links»		(to "find-telegachat-links")
;; «.find-eejump-links»			(to "find-eejump-links")
;; «.find-kla-links»			(to "find-kla-links")
;; «.find-rstdoc-links»			(to "find-rstdoc-links")
;; «.find-mpv-links»			(to "find-mpv-links")


(require 'eev-env)
(require 'eev-wrap)    ; For: (find-eev "eev-wrap.el" "ee-template0") 
(require 'cl-lib)      ; For `cl-remove-if'



;;;                                                            _   
;;;   ___  ___        ___ ___  _ __  _   _       _ __ ___  ___| |_ 
;;;  / _ \/ _ \_____ / __/ _ \| '_ \| | | |_____| '__/ _ \/ __| __|
;;; |  __/  __/_____| (_| (_) | |_) | |_| |_____| | |  __/\__ \ |_ 
;;;  \___|\___|      \___\___/| .__/ \__, |     |_|  \___||___/\__|
;;;                           |_|    |___/                         
;;
;; «ee-copy-rest» (to ".ee-copy-rest")
;; Some hyperlinks buffers - for example those generated by:
;;
;;   (find-latex-links)
;;   (find-eev-install-links)
;;
;; are composed of a series of hyperlinks, then a sexp like
;; `(ee-copy-rest NLINES CODE)', then some templated text. When we run
;; the `(ee-copy-rest ...)' the templated text is flashed for a
;; fraction of a second and copied to the kill ring, and the window is
;; split in two like this:
;;
;;    ____________________________
;;   |              |             |
;;   |  hyperlinks  |  target of  |
;;   |    buffer    |    CODE     |
;;   |              |             |
;;   |______________|_____________|
;;
;; For example,
;;
;;   (find-latex-links "/tmp/foo")
;;
;; generates this hyperlinks buffer:
;;
;;    _________________________________________________________________ 
;;   |# (find-latex-links "/tmp/foo")                                  |
;;   |# (find-latex-links "/tmp/teste1")                               |
;;   |# (find-latex-links "~/2019-CLG/teste2")                         |
;;   |# (find-eev-quick-intro "`find-latex-links'")                    |
;;   |# (ee-copy-rest 1 '(find-fline "/tmp/foo.tex"))                  |
;;   |                                                                 |
;;   |% (defun c () (interactive) (find-sh "pdflatex foo.tex"))        |
;;   |% (defun d () (interactive) (find-pdf-page "/tmp/foo.pdf"))      |
;;   |% (defun e () (interactive) (find-fline "/tmp/foo.tex"))         |
;;   |% (defun w () (interactive) (find-texworks "/tmp/foo.tex"))      |
;;   |%                                                                |
;;   |\documentclass{article}                                          |
;;   |\begin{document}                                                 |
;;   |                                                                 |
;;   |\end{document}                                                   |
;;   |                                                                 |
;;   |                                                                 |
;;   |                                                                 |
;;   | -:**-  *Elisp hyperlinks*   All L1     (Fundamental)  ----------|
;;   |_________________________________________________________________|
;;
;; in which CODE is `(find-fline "/tmp/foo.tex")'. When we execute the
;; `ee-copy-rest' line all the material from "% (defun c..." downwards
;; - the "templated text" - is flashed, copied to the kill ring, the
;; file "/tmp/foo.tex" is opened in the right window, and the
;; following message is displayed in the echo area:
;;
;;   "(Copied 9 lines to the kill ring - use C-y to paste)"
;;
;; If the file "/tmp/foo.tex" is empty and we want to initialize it
;; with the templated string we only need to go to the right window
;; and type `C-y'; if it is non-empty its present contents will be
;; displayed and we can decide what to do.
;;
;; TO DO: update the decumentation here:
;;   (find-eev-quick-intro "7.5. `find-latex-links'")
;;   (find-links-intro "10. The rest of the buffer")

(defvar eeflash-copy '(highlight 0.5))

(defun ee-count-lines (str)
  "Count the number of lines in STR (which should be newline-terminated)."
  (length (replace-regexp-in-string "[^\n]" "" str)))

(defun ee-copy-rest00 (skip gotoend code)
  "An internal function used by `ee-copy-rest0'."
  (setq skip (or skip 0))
  (let* ((start (save-excursion (move-beginning-of-line (+ 2 skip)) (point)))
	 (end   (eval gotoend))
	 (str   (buffer-substring start end))
	 (len   (ee-count-lines str))
	 (msg   `(Copied ,len lines to the kill ring - use C-y to paste)))
    (eeflash+ start end eeflash-copy)
    (kill-new str)
    (eval code)
    msg))

(defun ee-copy-rest0 (skip code)
  "Copy the rest of this buffer to the kill ring and execute CODE.
The rest of this buffer is everything from the beginning of the next line -
optionally moving down SKIP lines - to the end of the buffer."
  (ee-copy-rest00 skip '(point-max) code))

(defun ee-copy-rest  (skip code)
  "Copy the rest of this buffer to the kill ring and execute CODE.
See: (find-eev \"eev-tlinks.el\" \"ee-copy-rest\")"
  (ee-copy-rest0 skip `(find-2a nil ',code)))


;; Obsolete:
;;
;; (defun ee-copy-after-and (nlines code)
;;   "Copy into the kill ring everything from NLINES down on, and run CODE."
;;   (move-beginning-of-line (- nlines 1))
;;   (kill-new (buffer-substring (point) (point-max)))
;;   (eval code)
;;   (let ((n (ee-count-lines (ee-last-kill))))
;;     `(Copied ,n lines to the kill ring - use C-y to paste)))
;; 
;; (defun ee-copy-after-and-2b (nlines code)
;;   "Copy into the kill ring everything from NLINES down on, and run CODE.
;; The target of the hyperlink in CODE is opened in the right-side window."
;;   (ee-copy-after-and nlines `(find-2b nil ',code)))




;;;   __ _           _       _ _       _       /\ ____  
;;;  / _(_)_ __   __| |     | (_)_ __ | | ____|/\|___ \ 
;;; | |_| | '_ \ / _` |_____| | | '_ \| |/ / __|   __) |
;;; |  _| | | | | (_| |_____| | | | | |   <\__ \  / __/ 
;;; |_| |_|_| |_|\__,_|     |_|_|_| |_|_|\_\___/ |_____|
;;;                                                     
;;
;; «find-find-links-links» (to ".find-find-links-links")
;; Test: (find-find-links-links "u" "find-links" "k stem args")
;; THIS IS OBSOLETE - DON'T USE THIS!
;; Use `find-find-links-links-new' instead.

(defun ee-prepend-commas (str)
  (save-match-data
    (replace-regexp-in-string "\\([^ ]+\\)" ",\\1" str)))
(defun ee-if-nil-setq (str)
  (format "(setq %s (or %s \"{%s}\"))" str str str))
(defun ee-if-nil-setqs (vars sep)
  (mapconcat 'ee-if-nil-setq (save-match-data (ee-split vars)) sep))

(defalias 'find-find-links-links-old 'find-find-links-links)

(defun find-find-links-links (&optional k stem args &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for foo."
  ;; (interactive)
  ;; ^ Commented out because this is obsolete!
  (setq k    (or k    "{k}"))
  (setq stem (or stem "{stem}"))
  (setq args (or args "{args}"))
  (apply 'find-elinks-elisp
   `((find-find-links-links ,k ,stem ,args ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-find-links-links)
     ""
     ,(ee-template0 "\
;; See: (find-links-intro)
;;      (find-templates-intro)

;; <find-{stem}-links>
;; {(ee-S `(find-find-links-links ,k ,stem ,args))}
;; A test: (find-{stem}-links ___)
\(define-key eev-mode-map \"\\M-h{k}\" 'find-{stem}-links)

\(defun find-{stem}-links (&optional {args} &rest pos-spec-list)
\"Visit a temporary buffer containing hyperlinks for foo.\"
  (interactive)
  {(ee-if-nil-setqs args \"\n  \")}
  (apply 'find-elinks
   `((find-{stem}-links {(ee-prepend-commas args)} ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-{stem}-links)
     \"\"
     ,(ee-template0 \"\\
\")
     )
   pos-spec-list))

;; Test: (find-{stem}-links ___)


;;   ,@(ee-find-{stem}-links {args})
;;
\(defun ee-find-{stem}-links ({args})
  \"Return a list of sexps and strings for {stem}.
This is an internal function used by `find-{stem}-links'.\"
  `(
    ))")
     ) pos-spec-list))






;;;   __ _           _       _ _       _       /\ ____                           
;;;  / _(_)_ __   __| |     | (_)_ __ | | ____|/\|___ \      _ __   _____      __
;;; | |_| | '_ \ / _` |_____| | | '_ \| |/ / __|   __) |____| '_ \ / _ \ \ /\ / /
;;; |  _| | | | | (_| |_____| | | | | |   <\__ \  / __/_____| | | |  __/\ V  V / 
;;; |_| |_|_| |_|\__,_|     |_|_|_| |_|_|\_\___/ |_____|    |_| |_|\___| \_/\_/  
;;;                                                                              
;; «find-find-links-links-new»  (to ".find-find-links-links-new")
;; Test: (find-find-links-links-new)
;; Many of the templated functions of eev were written using this.
;; They all have a line saying ";; Skel:" that generates their "skeleton".
;; See: (find-eevgrep "grep --color -nH --null -e Skel: *.el")
;;      (find-eevtemplvideo "0:18" "1. `find-find-links-links-new'")
;;      (find-eevtemplvideo "1:15"   "if I execute (find-emacs-tangents-links)")
;;      (find-eevtemplvideo "1:29"   "generated again with these values")
;;      (find-eevtemplvideo "1:50"   "the implementation is very simple")
;;      (find-eevtemplvideo "2:00"   "in five minutes because")
;;      (find-eevtemplvideo "2:15"   ";; Skel:")
;;      (find-eevtemplvideo "2:32"   "optional arguments, then this field")
;;      (find-eevtemplvideo "2:40"   "temporary variables set by a let*")
;;      (find-eevtemplvideo "3:25"   "to write `find-emacs-tangents-links'")
;;      (find-eevtemplvideo "3:40"   "backslashes in the right places")
;;
(defun find-find-links-links-new (&optional stem args vars &rest pos-spec-list)
"Visit a temporary buffer containing a skeleton of a find-*-links function."
  (interactive)
  (setq stem (or stem "{stem}"))
  (setq args (or args "{args}"))
  (setq vars (or vars "{vars}"))
  (apply 'find-elinks-elisp
   `((find-find-links-links-new ,stem ,args ,vars ,@pos-spec-list)
     (find-find-links-links-new)
     (find-find-links-links-new "mytaskA" "" "")
     (find-find-links-links-new "mytaskB" "foo" "")
     (find-find-links-links-new "mytaskC" "foo bar" "")
     (find-find-links-links-new "mytaskD" "foo bar baz" "plic bletch")
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-find-links-links-new)
     ""
     ,(ee-template0 ";; <find-{stem}-links>")
     ,(concat       ";; Skel: " (ee-S `(find-find-links-links-new ,stem ,args ,vars)))
     ,(ee-template0 ";; Test: (find-{stem}-links)")
     ";;"
     ,(ee-ffll-defun stem args vars)
     )
   pos-spec-list))


;;;                   __  __ _ _ _            
;;;   ___  ___       / _|/ _| | | |     __/\__
;;;  / _ \/ _ \_____| |_| |_| | | |_____\    /
;;; |  __/  __/_____|  _|  _| | | |_____/_  _\
;;;  \___|\___|     |_| |_| |_|_|_|       \/  
;;;                                           
;; «ee-ffll-functions»  (to ".ee-ffll-functions")
;; Low-level functions used by find-find-links-links-new.
;;
;; Tests:
;; (ee-ffll-optional "")
;; (ee-ffll-optional "foo bar")
;; (ee-ffll-comma-args "plic bletch")
;; (find-estring (ee-ffll-setqs "  " "foo bar"))
;; (find-estring (ee-ffll-lets "  " "foo bar"))
;; (find-estring-elisp (ee-ffll-defun-without-lets "mytask" "foo bar"))
;; (find-estring-elisp (ee-ffll-defun-with-lets "mytask" "foo bar" "plc bltch"))
;; (find-estring-elisp (ee-ffll-defun "mytask" "foo bar"))
;; (find-estring-elisp (ee-ffll-defun "mytask" "foo bar" "plic bletch"))
;;
(defun ee-ffll-optional (args)
  (if (< 0 (length (split-string args)))
      (concat "&optional " args " ")
    ""))
	 
(defun ee-ffll-setqs (spaces args)
  (mapconcat (lambda (arg) (format "%s(setq %s (or %s \"{%s}\"))\n"
				   spaces arg arg arg))
	     (split-string args)
	     ""))

(defun ee-ffll-lets (spaces vars)
  (format "let* (%s)"
	  (mapconcat (lambda (var) (format "(%s \"{%s}\")" var var))
		     (split-string vars)
		     (concat "\n" spaces "       "))))

(defun ee-ffll-comma-args (args)
  (mapconcat (lambda (arg) (format ",%s " arg))
	     (split-string args)
	     ""))

(defun ee-ffll-defun-without-lets (stem args)
  (let* ((optional   (ee-ffll-optional args))
	 (setqs      (ee-ffll-setqs "  " args))
	 (comma-args (ee-ffll-comma-args args))
	 )
    (ee-template0 "\
(defun find-{stem}-links ({optional}&rest pos-spec-list)
\"Visit a temporary buffer containing hyperlinks for {stem}.\"
  (interactive)
{setqs}\
  (apply
   'find-elinks
   `((find-{stem}-links {comma-args},@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-{stem}-links)
     \"\"
     ,(ee-template0 \"\\
\")
     )
   pos-spec-list))
")))

(defun ee-ffll-defun-with-lets (stem args vars)
  (let* ((optional   (ee-ffll-optional   args))
	 (setqs      (ee-ffll-setqs "  " args))
	 (comma-args (ee-ffll-comma-args args))
	 (lets       (ee-ffll-lets "  "  vars))
	 )
    (ee-template0 "\
(defun find-{stem}-links ({optional}&rest pos-spec-list)
\"Visit a temporary buffer containing hyperlinks for {stem}.\"
  (interactive)
{setqs}\
  ({lets}
    (apply
     'find-elinks
     `((find-{stem}-links {comma-args},@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-{stem}-links)
       \"\"
       ,(ee-template0 \"\\
\")
       )
     pos-spec-list)))
")))

(defun ee-ffll-defun (stem args &optional vars)
  (if (equal vars "") (setq vars nil))
  (if vars (ee-ffll-defun-with-lets stem args vars)
     (ee-ffll-defun-without-lets stem args)))









;;;  _       _                   _ _       _        
;;; (_)_ __ | |_ _ __ ___       | (_)_ __ | | _____ 
;;; | | '_ \| __| '__/ _ \ _____| | | '_ \| |/ / __|
;;; | | | | | |_| | | (_) |_____| | | | | |   <\__ \
;;; |_|_| |_|\__|_|  \___/      |_|_|_| |_|_|\_\___/
;;;                                                 
;; «find-intro-links»  (to ".find-intro-links")
;; Skel: (find-find-links-links-new "intro" "stem" "")
;; Test: (find-intro-links)
;;
(defun find-intro-links (&optional stem &rest pos-spec-list)
"Visit a temporary buffer with a skeleton for defining `find-<STEM>-intro'.
All `find-*-intro' functions in eev-intro.el were written using this.
See: (find-eev \"eev-intro.el\")"
  (interactive)
  (setq stem (or stem "{stem}"))
  (apply
   'find-elinks-elisp
   `((find-intro-links ,stem ,@pos-spec-list)
     (find-intro-links "{stem}" ,@pos-spec-list)
     (find-intro-links "foo"    ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-intro-links)
     ""
     ,(ee-template0 "\
;; (ee-copy-rest 1 '(find-eev \"eev-intro.el\"))
;; (find-{stem}-intro)

;; <find-{stem}-intro>
;; Skel: (find-intro-links \"{stem}\")
;; Test: (find-{stem}-intro)

\(defun find-{stem}-intro (&rest pos-spec-list) (interactive)
  (let ((ee-buffer-name \"*(find-{stem}-intro)*\"))
    (apply 'find-eintro \"\\
\\(Re)generate: (find-{stem}-intro)
Source code:  (find-efunction 'find-{stem}-intro)
More intros:  (find-eev-quick-intro)
              (find-eev-intro)
              (find-eepitch-intro)
This buffer is _temporary_ and _editable_.
It is meant as both a tutorial and a sandbox.

Hello
=====
\" pos-spec-list)))

;; (find-{stem}-intro)
")
     )
   pos-spec-list))

;; (find-intro-links)
;; (find-intro-links "emacs")





;;;                       _                    _           
;;;   ___  _____   __    | |__   ___  __ _  __| | ___ _ __ 
;;;  / _ \/ _ \ \ / /____| '_ \ / _ \/ _` |/ _` |/ _ \ '__|
;;; |  __/  __/\ V /_____| | | |  __/ (_| | (_| |  __/ |   
;;;  \___|\___| \_/      |_| |_|\___|\__,_|\__,_|\___|_|   
;;;                                                        
;; «find-eev-header-links» (to ".find-eev-header-links")
;; (find-find-links-links "<none>" "eev-header" "stem-el date")
;; A test: (find-eev-header-links "eev-audiovideo.el")

(defun find-eev-header-links (&optional stem-el date &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for foo."
  (interactive)
  (setq stem-el (or stem-el "{stem-el}"))
  (setq date    (or date (downcase (format-time-string "%Y%b%d"))))
  (apply 'find-elinks-elisp
   `((find-eev-header-links ,stem-el ,date ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-eev-header-links)
     (find-eev ,stem-el)
     (wrobak 2 '(find-eev ,stem-el))
     ,(ee-template0 "
;;; {stem-el} -- ???.

;; Copyright (C) 2019 Free Software Foundation, Inc.
;;
;; This file is part of GNU eev.
;;
;; GNU eev 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.
;;
;; GNU eev 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 GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
;;
;; Author:     Eduardo Ochs <eduardoochs@gmail.com>
;; Maintainer: Eduardo Ochs <eduardoochs@gmail.com>
;; Version:    {date}
;; Keywords:   e-scripts
;;
;; Latest version: <http://angg.twu.net/eev-current/{stem-el}>
;;       htmlized: <http://angg.twu.net/eev-current/{stem-el}.html>
;;       See also: <http://angg.twu.net/eev-current/eev-readme.el.html>
;;                 <http://angg.twu.net/eev-intros/find-eev-intro.html>
;;                                                (find-eev-intro)

;;; Commentary:


;; Local Variables:
;; coding:            utf-8-unix
;; ee-anchor-format:  \"defun %s \"
;; no-byte-compile:   t
;; End:
")) pos-spec-list))




;;;   __ _           _           _      _           _         
;;;  / _(_)_ __   __| |       __| | ___| |__  _ __ | | ____ _ 
;;; | |_| | '_ \ / _` |_____ / _` |/ _ \ '_ \| '_ \| |/ / _` |
;;; |  _| | | | | (_| |_____| (_| |  __/ |_) | |_) |   < (_| |
;;; |_| |_|_| |_|\__,_|      \__,_|\___|_.__/| .__/|_|\_\__, |
;;;                                          |_|        |___/ 
;;
;; «find-debpkg-links»  (to ".find-debpkg-links")

(defun ee-links-for-debpkg (pkgname)
  "Return the three main links for the debian package PKGNAME."
  (list (ee-template0 "\
{ee-H}(find-status   \"{pkgname}\")
{ee-H}(find-vldifile \"{pkgname}.list\")
{ee-H}(find-udfile   \"{pkgname}/\")")))

(defun ee-dfs0 (pkg ext)
  "If the file /var/lib/dpkg/info/PKG.EXT exists, return a link to it."
  (let ((fname (concat pkg "." ext)))
    (if (file-exists-p (ee-vldifile fname))
	`(find-vldifile ,fname))))

(defun ee-links-for-debpkg-extra-vldi (pkg)
  "Return a list of links for files in /var/lib/dpkg/info/ belonging to PKG.
This is an internal function used by `find-debpkg-links'."
   (list (ee-dfs0 pkg "preinst")   (ee-dfs0 pkg "postinst")
	 (ee-dfs0 pkg "prerm")     (ee-dfs0 pkg "postrm")
	 (ee-dfs0 pkg "conffiles") (ee-dfs0 pkg "config")
	 (ee-dfs0 pkg "templates")
	 (ee-dfs0 pkg "md5sums")   (ee-dfs0 pkg "shlibs")
	 ))

(defun ee-debian-pooldir (pkg)
  "Used by `find-debpkg-links'; \"foo\" -> \"f\", \"libfoo\" -> \"libf\"."
  (if (string-match "^\\(lib\\)?." pkgname)
      (match-string 0 pkgname)))

;; Tests: (find-debpkg-links "bash")
;;        (find-debpkg-links "libicu")
;;
(defun find-debpkg-links (&optional pkgname &rest rest)
  "Visit a temporary buffer containing hyperlinks related to a Debian package.
Try this: (find-debpkg-links \"bash\")"
  (interactive (list (ee-debpkgname-ask)))
  (setq pkgname (or pkgname "{pkgname}"))
  (let ((p (ee-debian-pooldir pkgname)))
    (apply 'find-elinks `(
      ;; Convention: the first sexp always regenerates the buffer.
      (find-debpkg-links ,pkgname ,@rest)
      (find-efunction 'find-debpkg-links)
      (find-available ,pkgname)
      ""
      ,@(ee-links-for-debpkg pkgname)
      ""
      ,@(ee-links-for-debpkg-extra-vldi pkgname)
      ""
      ,(ee-template0 "\
{ee-H}(find-sh \"apt-file search {pkgname}\")
{ee-H}(find-sh \"apt-cache dump | grep-dctrl -P {pkgname}\")
{ee-H}(find-sh \"apt-cache showpkg {pkgname}\")
{ee-H}(find-sh \"apt-cache search {pkgname} | sort\")
{ee-H}(find-sh \"apt-cache search '{pkgname}*' | sort\")
{ee-H}(find-sh \"apt search '{pkgname}*'\")
{ee-H}(find-sh \"apt search '{pkgname}*' 2> /dev/null\")
{ee-H}(find-sh \"grep-aptavail -P {pkgname}\")
{ee-H}(find-sh \"grep-aptavail -P -s Package {pkgname}\")
{ee-H}(find-sh \"grep-aptavail -P -s Package {pkgname} | sort\")
{ee-H}(find-sh \"grep-aptavail -P -s Package,Version {pkgname}\")
{ee-H}(find-sh \"dpkg-query -W '{pkgname}*'\")

http://packages.debian.org/{pkgname}
http://packages.debian.org/sid/{pkgname}
http://packages.debian.org/source/sid/{pkgname}
http://packages.debian.org/src:{pkgname}
http://ftp.debian.org/debian/pool/main/{p}/{pkgname}/
http://backports.org/debian/pool/main/{p}/{pkgname}/
http://bugs.debian.org/cgi-bin/pkgreport.cgi?which=pkg&data={pkgname}&archive=no

http://packages.ubuntu.org/{pkgname}

 (eepitch-shell2)
sudo apt-get install    {pkgname}
sudo apt-get install -y {pkgname}

 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
# (find-man \"8 apt-cache\")
apt-cache show {pkgname}
apt-cache search {pkgname}
apt-cache depends {pkgname}
apt-cache rdepends {pkgname}

apt-cache showpkg {pkgname}

# (find-man \"1 dpkg-query\")
apt-file search {pkgname}
dpkg-query --search {pkgname}
")
      ) rest)))



;;;   __ _           _           _          _           _ _     _ 
;;;  / _(_)_ __   __| |       __| |___  ___| |__  _   _(_) | __| |
;;; | |_| | '_ \ / _` |_____ / _` / __|/ __| '_ \| | | | | |/ _` |
;;; |  _| | | | | (_| |_____| (_| \__ \ (__| |_) | |_| | | | (_| |
;;; |_| |_|_| |_|\__,_|      \__,_|___/\___|_.__/ \__,_|_|_|\__,_|
;;;                                                               
;; This is a VERY EARLY prototype (hi Marc!)
;; of a rewrite of something that was very ugly.

;; (find-angg ".emacs" "find-dpkg-build-escript")

(defun ee-dsc-url-split (dsc-url)
  "Example:
  (ee-dsc-url-split
   \"http://ftp.debian.org/debian/pool/main/i/imagemagick/imagemagick_6.2.4.5.dfsg1-0.9.dsc\")
  -> (\"http\" \"ftp.debian.org/debian/pool/main/i/imagemagick/\"
      \"imagemagick\" \"6.2.4.5.dfsg1\" \"-0.9\")"
  (let ((prot://dir/ (file-name-directory dsc-url))
	(fname-dsc (file-name-nondirectory dsc-url))
	prot dir/ xxx vvv -sv)
    (if (string-match "^\\([a-z]+\\)://\\(.*\\)" prot://dir/)
	(setq prot (match-string 1 prot://dir/)
	      dir/ (match-string 2 prot://dir/)))
    (if (string-match "^\\([^_]+\\)_\\([^-]+\\)\\(-.*\\)?\\.dsc$" fname-dsc)
	(setq xxx (match-string 1 fname-dsc)
	      vvv (match-string 2 fname-dsc)
	      -sv (or (match-string 3 fname-dsc) "")))
    (list prot dir/ xxx vvv -sv)))

(defun ee-links-for-dscbuild (dsc-url)
  (apply 'ee-links-for-dscbuild0
	 (downcase (format-time-string "%Y%b%d"))
	 (ee-dsc-url-split dsc-url)))

(defun ee-links-for-dscbuild0 (date prot dir/ xxx vvv -sv)
  (ee-template
   '(date prot dir/ xxx vvv -sv) "\
#####
#
# {xxx} (from the debian sources)
# {date}
#
#####

# <{xxx}-deb-src>
# {prot}://{dir/}
# {prot}://{dir/}{xxx}_{vvv}{-sv}.dsc
# {prot}://{dir/}{xxx}_{vvv}{-sv}.diff.gz
# {prot}://{dir/}{xxx}_{vvv}.orig.tar.gz
#
rm -Rv ~/usrc/{xxx}/
mkdir  ~/usrc/{xxx}/
cd $S/{prot}/{dir/}
cp -v {xxx}_{vvv}* ~/usrc/{xxx}/
cd     ~/usrc/{xxx}/
dpkg-source -sn -x {xxx}_{vvv}{-sv}.dsc
cd     ~/usrc/{xxx}/{xxx}-{vvv}/
dpkg-buildpackage -us -uc -b -rfakeroot     2>&1 | tee odb

#
# (find-fline \"~/usrc/{xxx}/\")
 (eepitch-shell)
cd ~/usrc/{xxx}/
sudo dpkg -i *.deb

#
# (code-c-d \"{xxx}\" \"~/usrc/{xxx}/{xxx}-{vvv}/\")
# (find-{xxx}file \"\")"))



;;;                       _           _        _ _ 
;;;   ___  _____   __    (_)_ __  ___| |_ __ _| | |
;;;  / _ \/ _ \ \ / /____| | '_ \/ __| __/ _` | | |
;;; |  __/  __/\ V /_____| | | | \__ \ || (_| | | |
;;;  \___|\___| \_/      |_|_| |_|___/\__\__,_|_|_|
;;;                                                

;; «find-eev-install-links» (to ".find-eev-install-links")
;; (find-find-links-links "{k}" "eev-install" "dir script comment")
;; A test: (find-eev-install-links)

(defun find-eev-install-links (&optional dir script comment &rest pos-spec-list)
"Visit a temporary buffer containing an e-script for installing eev."
  (interactive)
  (setq dir (or dir "~/eev2/"))
  (setq script (or script "~/eev"))
  (setq comment (or comment ""))
  (apply 'find-elinks
   `((find-eev-install-links ,dir ,script ,comment ,@pos-spec-list)
     (find-eev-install-links "~/eev2/" "~/eev")
     (find-eev-install-links "~/eev2/" "~/eev" "#")
     (find-eev-install-links "/tmp/eev2/" "/tmp/eev")
     (find-eev-install-links "/tmp/eev2/" "/tmp/eev" "#")
     (find-eev-install-links "{dir}" "{script}" "{comment}")
     (find-eev-install-links)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-eev-install-links)
     ""
     (find-eev-install-intro)
     ""
     ,(ee-template0 "\
# This function is explained at:
#   (find-eev-install-intro \"2. Running `(find-eev-install-links)'\")
#
# The default way to use it to install eev in your home directory is with:
#   (find-eev-install-links \"~/eev2/\" \"~/eev\" \"#\")
#
# The default way to use it to install eev in /tmp/ for tests is with:
#   (find-eev-install-links \"/tmp/eev2/\" \"/tmp/eev\" \"#\")



# The script below downloads eev2.tgz and unpacks it into {dir}
# and creates a shell script {script}
# that can be used to start emacs+eev.

 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
{comment}{<}
  rm -Rv {script}
  rm -Rv {dir}
  mkdir  {dir}
  cd     {dir}
  rm -fv eev2.tgz
  wget http://angg.twu.net/eev-current/eev2.tgz
  tar -xvzf eev2.tgz
  {<}
    echo '#!/bin/sh'
    echo 'cd {dir} && emacs -l eev-beginner.el --eval=\"(find-eev-quick-intro)\" $*'
  {>} > {script}
  chmod 755 {script}
{comment}{>}

# Test:
{script}



;; If you have unpacked eev2.tgz into some permanent place you can
;; put this is your .emacs to load eev when Emacs starts. Don't
;; copy this to your .emacs if either 1) you have only unpacked
;; eev in /tmp/, or 2) if you don't know how to use Lisp well
;; enough!
;;
;; See: (find-eev-install-intro \"3. Changing your .emacs\")

;; (ee-copy-rest 0 '(find-fline \"~/.emacs\"))

;; Load eev.
;; Generated by: (find-eev-install-links \"{dir}\" \"{script}\" \"{comment}\")
;;        Check: (find-fline \"{dir}\")
;;          See: (find-eev-install-intro \"3. Changing your .emacs\")
;;
\(add-to-list 'load-path \"{dir}\")
\(require 'eev-load)                 ; (find-eev \"eev-load.el\")
\(eev-mode 1)                        ; (find-eev \"eev-mode.el\")

")
     )
   pos-spec-list))

;; A test: (find-eev-install-links)
;;         (find-eev-install-links "~/eev2/" "~/eev" "#" 60)


;;;                                       _       _       
;;;   ___  _____   __     _   _ _ __   __| | __ _| |_ ___ 
;;;  / _ \/ _ \ \ / /____| | | | '_ \ / _` |/ _` | __/ _ \
;;; |  __/  __/\ V /_____| |_| | |_) | (_| | (_| | ||  __/
;;;  \___|\___| \_/       \__,_| .__/ \__,_|\__,_|\__\___|
;;;                            |_|                        
;;
;; «find-eev-update-links» (to ".find-eev-update-links")
;; A test: (find-eev-update-links)
;; TODO: Check that this has been superseded by
;;   (find-eev-install-links)
;; and flag this as obsolete.

(defun find-eev-update-links (&optional dir script &rest pos-spec-list)
"Visit a temporary buffer with scripts for installing and updating eev."
  (interactive)
  (setq dir (or dir ee-eevdir))
  (setq script (or script "~/e"))
  (apply 'find-elinks
   `((find-eev-update-links ,dir ,script)
     (find-eev-update-links "/tmp/eev/" ,script)
     (find-eev-update-links "~/eev2/" ,script)
     (find-eev-update-links "~/eev/" ,script)
     (find-eev-update-links "{dir}" "{script}")
     (find-eev-update-links)
     ,(ee-template0 "\

# NOTE! This function is obsolete and has been superseded by:
# (find-eev-install-links)



# Download , unpack and create a script \"~/e\"
# ============================================
# See: (find-eev-quick-intro \"1. Installing eev\")

{
  rm -Rv {dir}
  mkdir  {dir}
  cd     {dir}
  rm -v eev2.tgz
  wget http://angg.twu.net/eev-current/eev2.tgz
  tar -xvzf eev2.tgz
  {
    echo '#!/bin/sh'
    echo 'cd {dir} && emacs -l eev-readme.el --eval=\"(find-eev-quick-intro)\"'
  } > {script}
  chmod 755 {script}
}



# Download / unpack the tarball (an older way)
# ============================================
# See: (find-eepitch-intro)
#      (find-eev \"eev-readme.el\")

 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
#rm -Rv {dir}
mkdir   {dir}
cd      {dir}
rm -v eev2.tgz
wget http://angg.twu.net/eev-current/eev2.tgz
tar -xvzf eev2.tgz

# Tests:
emacs -Q -fg bisque -bg black -l eev-readme.el eev-readme.el
emacs -Q -fg bisque -bg black                  eev-readme.el
emacs    -fg bisque -bg black                  eev-readme.el



# Tell Emacs to load eev2 by default
# ==================================
# Emacs executes the file ~/.emacs when it starts up - see:
#   (find-enode \"Init File\")
# The easiest way to make Emacs load eev2 by default is to
# open your ~/.emacs in another window with the sexp below,
# and then copy the block below to it with `C-y'.
#   (ee-copy-rest 0 '(find-fline \"~/.emacs\"))

;; Load eev2.
;; See:  (find-file \"{dir}\")
;;       (find-file \"{dir}eev-readme.el\")
;; Generated by: (find-eev-update-links \"{dir}\")
;;
\(add-to-list 'load-path \"{dir}\")
\(require 'eev2-all)                 ; (find-eev \"eev2-all.el\")
\(eev-mode 1)                        ; (find-eev \"eev-mode.el\")
")) pos-spec-list))

;; (find-eev-update-links)




;;;                    _         _                    _ _ 
;;;  _   _  ___  _   _| |_ _   _| |__   ___        __| | |
;;; | | | |/ _ \| | | | __| | | | '_ \ / _ \_____ / _` | |
;;; | |_| | (_) | |_| | |_| |_| | |_) |  __/_____| (_| | |
;;;  \__, |\___/ \__,_|\__|\__,_|_.__/ \___|      \__,_|_|
;;;  |___/                                                
;;
;; «find-youtubedl-links»  (to ".find-youtubedl-links")
;; Skel: (find-find-links-links-new "youtubedl" "dir title hash ext- stem" "")
;; Test: (find-youtubedl-links nil nil "K6LmZ0A1s9U")
;; See:  (find-audiovideo-intro "6. Youtube-dl")
;;       (find-audiovideo-intro "6.1. Downloading a local copy")
;;       (find-eevtemplvideo "19:23" "5. `find-youtubedl-links'")
;;       (find-eevtemplvideo "19:43"   "if we twist the notion of user enough")
;;       (find-eevtemplvideo "20:02"   "user-friendly to me")
;;       (find-eevtemplvideo "20:05"   "The documentation is in this tutorial:")
;;       (find-eevtemplvideo "21:36"   "its code is here")
;;       (find-eevtemplvideo "21:55"   "Let me show a demo")
;;       (find-eevtemplvideo "22:15"   "I never type these rm -Rv/mkdir/cd by hand")
;;       (find-eevtemplvideo "22:48"   "let me show how to download ... the hash is here")
;;       (find-eevtemplvideo "23:25"   "they regenerate this buffer in slightly different ways")
;;       (find-eevtemplvideo "24:03"   "a video with this hash. If I visit the directory")
;;       (find-eevtemplvideo "24:32"   "my magic functions have to")
;;       (find-eevtemplvideo "24:50"   "if I run this sexp here with nil in the title")
;;       (find-eevtemplvideo "25:00"   "it tries to guess the title")
;;       (find-eevtemplvideo "25:28"   "and if I change this {stem} here I get short links")
;;       (find-eevtemplvideo "26:14"   "has very long lines, but if I type super-w")
;;       (find-eevtemplvideo "26:28"   "I get a buffer that shows the code for")
;;       (find-eevtemplvideo "26:50"   "if I execute this I play the video")
;;       (find-eevtemplvideo "27:15"   "a copy of that points to the right position")
;;       (find-eevtemplvideo "27:53"   "summary: this is how I download videos from youtube")
;;
(defun find-youtubedl-links (&optional dir title hash ext- stem &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for youtube-dl."
  (interactive)
  (setq dir   (or dir   ee-youtubedl-dir "{dir}"))
  (setq hash  (or hash  (ee-youtubedl-hash-around-point)    "{hash}"))
  (setq title (or title (ee-youtubedl-guess-title dir hash) "{title}"))
  (setq ext-  (or ext-  (ee-youtubedl-guess-ext- dir hash)  "{ext-}"))
  (setq stem  (or stem "{stem}"))
  (let ((ee-buffer-name (or ee-buffer-name "*find-youtubedl-links*")))
    (apply
     'find-elinks
     `((find-youtubedl-links ,dir ,title ,hash ,ext- ,stem ,@pos-spec-list)
       (find-youtubedl-links ,dir nil ,hash nil ,stem)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-youtubedl-links)
       ""
       ,@(ee-youtubedl-dir-links nil hash stem)
       (setq ee-youtubedl-dirs ',ee-youtubedl-dirs)
       (setq ee-youtubedl-dir   ,ee-youtubedl-dir)
       ""
       (find-audiovideo-intro "6. Youtube-dl")
       (find-eev "eev-tlinks.el" "ee-youtubedl-command")
       ""
       ,(ee-template0 "\
 (sh-mode)
 (eepitch-shell2)
 (eepitch-kill)
 (eepitch-shell2)
# http://www.youtube.com/watch?v={hash}
# http://www.youtube.com/watch?v={hash}#t=0m00s
# http://www.youtube.com/watch?v={hash}#t=0h00m00s
cd {dir}
{ee-youtubedl-command} -f 18 --restrict-filenames 'http://www.youtube.com/watch?v={hash}'

# Or:
{ee-youtubedl-command}       'http://www.youtube.com/watch?v={hash}'
{ee-youtubedl-command} -F    'http://www.youtube.com/watch?v={hash}'
{ee-youtubedl-command} -f 18 'http://www.youtube.com/watch?v={hash}'
{ee-youtubedl-command} -f 18 --restrict-filenames --all-subs 'http://www.youtube.com/watch?v={hash}'
{ee-youtubedl-command}       --restrict-filenames --all-subs 'http://www.youtube.com/watch?v={hash}'

# Play the local copy:
# (find-fline \"{dir}\" \"{hash}\")
# (find-fline \"{dir}\" \"{title}-{hash}\")
# (find-fline \"{dir}\" \"{title}-{hash}{ext-}\")
# (find-video \"{dir}{title}-{hash}{ext-}\")
# (code-video \"{stem}video\" \"{dir}{title}-{hash}{ext-}\")
# (find-{stem}video)
# (find-{stem}video \"0:00\")

# Error messages (for the player):
# (find-ebuffer \"*Messages*\")

# Play on youtube:
# (find-youtube-video \"{hash}\" \"0:00\")
# (code-youtubevideo \"{stem}\" \"{hash}\" \"{title}\")
# (find-{stem}video \"0:00\")

# Transcript:
# (find-yttranscript-links \"{stem}\" \"{hash}\")
")
       )
     pos-spec-list)))




;; `find-youtubedl-links' uses LOTS of internal functions and
;; variables. They are defined below.

;; Code for splitting filenames of downloaded videos into components.
;; Test: (ee-youtubedl-split "~/tmp/videos/foo_bar-abF7go7RLTc.flv")
;;       --> ("~/tmp/videos/" "foo_bar" "abF7go7RLTc" ".flv" ".flv")
;;
(defvar ee-youtubedl-ext-re
  "\\(\\.[A-Za-z0-9]\\{2,5\\}\\)\\(\\.part\\)?$")

(defun ee-youtubedl-split (fname)
  "Split FNAME into (dir title hash ext ext-)."
  (string-match ee-youtubedl-ext-re fname)
  (let* ((ext-  (match-string 1 fname))
	 (ext   (match-string 0 fname))
	 (dth   (substring fname 0 (match-beginning 0)))
	 (hash  (substring dth -11))
	 (dt    (substring dth 0 -12))
	 (title (file-name-nondirectory dt))
	 (dir   (file-name-directory dt)))
    (list dir title hash ext- ext)))

(defun ee-youtubedl-dir   (fname) (nth 0 (ee-youtubedl-split fname)))
(defun ee-youtubedl-title (fname) (nth 1 (ee-youtubedl-split fname)))
(defun ee-youtubedl-hash  (fname) (nth 2 (ee-youtubedl-split fname)))
(defun ee-youtubedl-ext-  (fname) (nth 3 (ee-youtubedl-split fname)))
(defun ee-youtubedl-ext   (fname) (nth 4 (ee-youtubedl-split fname)))

;; Code for guessing the "title" and the "ext" parts of a video from
;; the "dir" and "hash" parts (in case the video has already been
;; downloaded).
;;
(defun ee-youtubedl-guess* (dir hash)
  "Return all the files in DIR containing the string HASH."
  (file-expand-wildcards (format "%s*%s*" dir hash)))

(defun ee-youtubedl-subtitle-p (fname)
  "Return true if FNAME looks like a subtitle file."
  (string-match "\\.\\(srt\\|vtt\\)$" fname))

(defun ee-youtubedl-not-subtitles (fnames)
  "Return the elements of FNAMES that don't look like subtitle files."
     (cl-remove-if 'ee-youtubedl-subtitle-p fnames))

(defun ee-youtubedl-guess (dir hash n)
  "Return a component of the first file in DIR containing the string HASH.
Files that look like subtitle files are ignored."
  (let* ((fnames0 (ee-youtubedl-guess* dir hash))
	 (fnames1 (ee-youtubedl-not-subtitles fnames0))
	 (fname (car fnames1)))
    (if fname (nth n (ee-youtubedl-split fname)))))

(defun ee-youtubedl-guess-title (dir hash) (ee-youtubedl-guess dir hash 1))
(defun ee-youtubedl-guess-ext-  (dir hash) (ee-youtubedl-guess dir hash 3))

(defun ee-youtubedl-hash-around-point ()
  (let ((hash (ee-stuff-around-point "-0-9A-Za-z_")))
    (if (>= (length hash) 11)
	(substring hash -11))))

;; «ee-youtubedl-command»  (to ".ee-youtubedl-command")
;; The default value is `ee-youtubedl-command' is (still) this one:
;;
(defvar ee-youtubedl-command "youtube-dl -t")
;;
;; but this is outdated in several ways:
;;
;;   1. when we use it we get this warning:
;;      "WARNING: --title is deprecated. Use
;;       -o "%(title)s-%(id)s.%(ext)s" instead."
;;
;;   2. youtube-dl is currently sort of dead. See:
;;      https://old.reddit.com/r/DataHoarder/comments/p9riey/youtubedl_is_possibly_dead/
;;      https://news.ycombinator.com/item?id=28289981 Youtube-dl is possibly dead
;;
;;   3. yt-dlp doesn't support the options `-t' and `--title':
;;      https://github.com/yt-dlp/yt-dlp
;;      https://github.com/yt-dlp/yt-dlp#Removed
;;
;; Suggestion (2021nov26): install yt-dlp and either put this in your .emacs,
;;
;;   ;; From: (find-eev "eev-tlinks.el" "ee-youtubedl-command")
;;   (setq ee-youtubedl-command "yt-dlp -o '%(title)s-%(id)s.%(ext)s'")
;;
;; and put a copy of this fake youtube-dl script
;;
;;   http://angg.twu.net/bin/youtube-dl.html
;;   http://angg.twu.net/bin/youtube-dl
;;
;; somewhere in your PATH, and use this:
;;
;;   (setq ee-youtubedl-command "youtube-dl -t")


;; The directories into which we usually download videos.
;; Tests: (find-elinks (ee-youtubedl-dir-links))
;;        (find-elinks (ee-youtubedl-dir-links '("DIR1" "DIR2")))
;;        (let ((ee-youtubedl-dirs '("DIR1" "DIR2"))) (find-youtubedl-links))
;;
(defvar ee-youtubedl-dir "~/videos/")

(defvar ee-youtubedl-dirs
  '("~/videos/" "~/videos/tech/" "/tmp/videos/" "/tmp/"))

(defun ee-youtubedl-dir-links (&optional dirs hash stem)
  (setq dirs (or dirs ee-youtubedl-dirs))
  (setq hash (or hash "{hash}"))
  (setq stem (or stem "{stem}"))
  (mapcar (lambda (dir) `(find-youtubedl-links ,dir nil ,hash nil ,stem))
	  dirs))

;; This is a hack (written in 2013sep10) that plays a local copy of a
;; video from its URL. To easiest way to use it is to put the point on
;; a youtube URL and type `M-x bryl'.
;;
(defun ee-youtubedl-guess** (dirs hash)
  (apply 'append (mapcar (lambda (d) (ee-youtubedl-guess* d hash)) dirs)))

(defun ee-youtubedl-hash-to-fname (hash)
  (and hash (car (ee-youtubedl-guess** ee-youtubedl-dirs hash))))

(defun ee-youtubedl-url-to-hash (url)
  (if (and url (string-match "[&?]v=\\([^&?#]+\\)" url))
      (match-string 1 url)
    url))

(defun ee-youtubedl-url-to-fname (url)
  (ee-youtubedl-hash-to-fname
   (ee-youtubedl-url-to-hash url)))

(autoload 'browse-url-url-at-point "browse-url")

;; TODO:
;; Redefine this using: (find-eevfile "eev-brxxx.el")
;; and add error handling. Tests:
;;   (setq ee-my-url "http://www.youtube.com/watch?v=tby5aMrMu6Q")
;;   (ee-youtubedl-url-to-hash ee-my-url)
;;   (ee-youtubedl-url-to-fname ee-my-url)
;;   (find-evardescr 'ee-youtubedl-dirs)
;;
;; (defun bryl (url)
;;   "Play a local copy of a video downloaded from youtube."
;;   (interactive (list (browse-url-url-at-point)))
;;   (let ((fname (and url (ee-youtubedl-url-to-fname url))))
;;     (if fname (find-video fname))))





;;;                       
;;;  _ __  ___ _ __   ___ 
;;; | '_ \/ __| '_ \ / _ \
;;; | |_) \__ \ | | |  __/
;;; | .__/|___/_| |_|\___|
;;; |_|                   
;;
;; «find-psne-links» (to ".find-psne-links")
;; Skel: (find-find-links-links-new "psne" "url wget-options echo-options" "")
;; Test: (find-psne-links "http://foo/bar")
;;       (find-psne-links "http://foo/bar" "-nc" "-N")
;;  See: (find-psne-intro "3. The new way: `M-x brep'")
;;       (find-psne-intro "3. The new way: `M-x brep'" "find-psne-links")
;;       (find-windows-beginner-intro "5.6.1. Echo in Eshell")
;;
(defun find-psne-links (&optional url wget-options echo-options &rest pos-spec-list)
"See: (find-psne-intro)"
  (interactive)
  (setq url (or url "{url}"))
  (setq wget-options (or wget-options "-nc"))
  (setq echo-options (or echo-options (ee-find-psne-echo-options)))
  (apply
   'find-elinks
   `((find-psne-links ,url ,wget-options ,echo-options ,@pos-spec-list)
     (find-psne-links ,url "-c" "" ,@pos-spec-list)
     (find-psne-links ,url "" "" ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-psne-links)
     ""
     ,(ee-adjust-red-stars " (eepitch-shell2)")
     ,(ee-find-psne-core url wget-options echo-options)
     )
   pos-spec-list))

;; Tests:
;; (find-estring (ee-find-psne-core "http://www.lua.org/start.html"))
;; (find-estring (ee-find-psne-core "http://www.lua.org/start.html" "-nc" "-N"))
;;
(defun ee-find-psne-core (url &optional wget-options echo-options)
  "This is an internal function used by `find-psne-links'."
  (let* ((localurl (ee-url-to-fname0 url))
	 (localdir (file-name-directory localurl))
	 (fname0 (file-name-nondirectory localurl))
	 (o (format "%-3s" (or wget-options "")))
	 (e (format "%-3s" (or echo-options
			       (ee-find-psne-echo-options)))))
    (ee-template0 "\
mkdir -p {localdir}
cd       {localdir}
wget {o} '{url}'
echo {e} '{url}' >> ~/.psne.log

# (find-fline \"{localdir}\")
# (find-fline \"{localdir}\" \"{fname0}\")
# (find-fline \"{localurl}\")
")))


;; «ee-find-psne-echo-options»  (to ".ee-find-psne-echo-options")
;; See: (find-windows-beginner-intro "5.6.1. Echo in Eshell")
(defun ee-find-psne-echo-options ()
  (if (eq system-type 'windows-nt) "-N" ""))




;;;                                                    _     _            
;;;  _ __  ___ _ __   ___        ___  _____   ____   _(_) __| | ___  ___  
;;; | '_ \/ __| '_ \ / _ \_____ / _ \/ _ \ \ / /\ \ / / |/ _` |/ _ \/ _ \ 
;;; | |_) \__ \ | | |  __/_____|  __/  __/\ V /  \ V /| | (_| |  __/ (_) |
;;; | .__/|___/_| |_|\___|      \___|\___| \_/    \_/ |_|\__,_|\___|\___/ 
;;; |_|                                                                   
;;
;; «find-psne-eevvideo-links»  (to ".find-psne-eevvideo-links")
;; Skel:  (find-find-links-links-new "psne-eevvideo" "stem exts time" "")
;; Tests: (find-psne-eevvideo-links "NAMEOFTHEVIDEO" ".srt .vtt")
;;        (find-psne-eevvideo-links "NAMEOFTHEVIDEO" ".srt")
;;        (find-psne-eevvideo-links "NAMEOFTHEVIDEO" "")
;;        (find-psne-eevvideo-links "NAMEOFTHEVIDEO" "" "1:23")
;; See:  (find-video-links-intro "5.1. Subtitles")
;;
;; NOTE: `find-psne-eevvideo-links', `ee-psne-eevvideo-core',
;;       `find-psne-1stclassvideo-links',
;;       `ee-psne-1stclassvideo-play', and `find-1stclassvideo-video'
;;       were written in 2022may11 and will probably replace several
;;       older functions soon... these new functions have support for
;;       subtitles, and the older ones didn't.
;;
(defun find-psne-eevvideo-links (&optional stem exts time &rest pos-spec-list)
"Visit a temporary buffer containing a script for downloading a video."
  (interactive)
  (setq stem (or stem "{stem}"))
  (setq exts (or exts "{exts}"))
  (setq time (or time "0:00"))
  (apply
   'find-elinks
   `((find-psne-eevvideo-links ,stem ,exts ,time ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-psne-eevvideo-links)
     ""
     ,(ee-psne-eevvideo-core stem exts time)
     )
   pos-spec-list))

;; Tests:
;; (find-estring (ee-psne-eevvideo-core "NAME" ".vtt .srt" "0:00"))
;; (find-estring (ee-psne-eevvideo-core "NAME" ".vtt"      "0:00"))
;; (find-estring (ee-psne-eevvideo-core "NAME" ""          "0:00"))
;; (defun ee-find-psne-echo-options () "-N")
;; (defun ee-find-psne-echo-options () "")
;;
(defun ee-psne-eevvideo-core (stem exts time)
  "An internal function used by `find-psne-eevvideo-links'."
  (let* ((dir         "$S/http/angg.twu.net/eev-videos/")
         (url- (concat "http://angg.twu.net/eev-videos/" stem))
	 (eo (format "%-3s" (ee-find-psne-echo-options)))
         (wf (lambda (ext) (format "wget -N   %s%s\n" url- ext)))
         (ef (lambda (ext) (format "echo %s  %s%s >> ~/.psne.log\n" eo url- ext)))
         (wgets (mapconcat wf (split-string exts) ""))
         (echos (mapconcat ef (cons ".mp4" (split-string exts)) ""))
	 )
    (ee-template0 "\
# (find-psne-intro \"1. Local copies of files from the internet\")
# (find-video-links-intro \"5. Local copies\")
# (find-video-links-intro \"5.1. Subtitles\")
# http://angg.twu.net/eev-videos.html

 (sh-mode)
 (eepitch-shell2)
 (eepitch-kill)
 (eepitch-shell2)
mkdir -p {dir}
cd       {dir}
wget -nc  {url-}.mp4
{wgets}\
{echos}\

# (find-fline \"{dir}\" \"{stem}.mp4\")
# (find-video \"{dir}{stem}.mp4\")
# (find-video \"{dir}{stem}.mp4\" \"{time}\")
")))


;;;                             _     _       _               
;;;  _ __  ___ _ __   ___      / |___| |_ ___| | __ _ ___ ___ 
;;; | '_ \/ __| '_ \ / _ \_____| / __| __/ __| |/ _` / __/ __|
;;; | |_) \__ \ | | |  __/_____| \__ \ || (__| | (_| \__ \__ \
;;; | .__/|___/_| |_|\___|     |_|___/\__\___|_|\__,_|___/___/
;;; |_|                                                       
;;
;; «find-psne-1stclassvideo-links»  (to ".find-psne-1stclassvideo-links")
;; Skel: (find-find-links-links-new "psne-1stclassvideo" "c time" "stem subexts")
;; Test: (find-psne-1stclassvideo-links "eev2021")
;;       (find-psne-1stclassvideo-links "2021workshop6")
;;
(defun find-psne-1stclassvideo-links (&optional c time &rest pos-spec-list)
"Visit a temporary buffer with a script for downloading the video C."
  (interactive)
  (setq c (or c "{c}"))
  (setq time (or time "0:00"))
  (let* ((stem    (ee-1stclassvideos-mp4stem c))
         (subexts (or (ee-1stclassvideos-field c :subs) "")))
    (apply
     'find-elinks
     `((find-psne-1stclassvideo-links ,c ,time ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-psne-1stclassvideo-links)
       ""
       ,(ee-psne-eevvideo-core stem subexts time)
       ,(ee-psne-1stclassvideo-play c time)
       )
     pos-spec-list)))

;; Test:
;; (find-estring (ee-psne-1stclassvideo-play "eev2021" "1:23"))
;;
(defun ee-psne-1stclassvideo-play (c time)
  "An internal function used by `find-psne-1sclassvideo-links'."
  (let* ((localmp4 (ee-1stclassvideos-localmp4 c))
	 (yt       (ee-1stclassvideos-field    c :yt))
	 (timearg  (ee-time-to-arg          time))
         (yttime   (ee-time-to-youtube-time time))
	 )
    (ee-template0 "\
# (find-1stclassvideo-video \"{c}\" \"{time}\")
# (find-{c}video \"{time}\")

# {yt}{yttime}
")))


;; «find-1stclassvideo-video»  (to ".find-1stclassvideo-video")
;; Tests: (find-1stclassvideo-video "eev2021")
;;        (find-eevvideossh0 "mv -v emacsconf2021.mp4 /tmp/")
;;        (find-eevvideossh0 "mv -v /tmp/emacsconf2021.mp4 .")
;;
(defun find-1stclassvideo-video (c &optional time &rest rest)
  "Play the first-class video C starting at TIME.
If a local copy of C is not found, run `find-psne-1stclassvideo-links'."
  (setq time (or time "0:00"))
  (if (ee-1stclassvideos-mp4found c)
      (find-video (ee-1stclassvideos-localmp4 c) time)
    (find-psne-1stclassvideo-links c time)))








;;;        _ _   
;;;   __ _(_) |_ 
;;;  / _` | | __|
;;; | (_| | | |_ 
;;;  \__, |_|\__|
;;;  |___/       

;; «find-git-links» (to ".find-git-links")
;; (find-find-links-links "g" "git" "usrc/ git/ gitname")
;; (find-find-links-links "g" "git" "url c")

(defvar ee-git-dir "~/usrc/" "See `find-git-links'.")

(defun ee-git-url-stem (url)
  (replace-regexp-in-string "^\\(.*/\\)\\([^/]+?\\)\\(\\.git\\)?$" "\\2" url))

(defun ee-git-url-at-point ()
  (require 'thingatpt)
  (let ((thing-at-point-url-regexp
	 (concat "\\<\\(https?:\\|git:\\)"
		 thing-at-point-url-path-regexp)))
    (thing-at-point 'url)))

(defun find-git-links (&optional url c &rest pos-spec-list)
"Visit a temporary buffer containing a script for downloading a git repo."
  (interactive)
  (let (gitstem dir)
    (setq url (or url (ee-git-url-at-point) "{url}"))
    (setq gitstem (or gitstem (ee-git-url-stem url)))
    (setq c (or c (replace-regexp-in-string "[-.]" "" gitstem)))
    (setq dir (format "%s%s/" ee-git-dir gitstem))
    (apply 'find-elinks
     `((find-git-links ,url ,c)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-git-links)
       ""
       (setq ee-git-dir ,ee-git-dir)
       (setq ee-git-dir "~/usrc/")
       (setq ee-git-dir "~/bigsrc/")
       (setq ee-git-dir "/tmp/")
       ""
       (find-fline ,ee-git-dir)
       (find-fline ,dir)
       ""
       ,(ee-template0 "\
# {url}

 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
# rm -Rfv {dir}
cd      {ee-git-dir}
git clone {url}
cd      {dir}

export PAGER=cat
git branch --list -a
git for-each-ref
git log --oneline --graph --all -20

# (find-fline \"{ee-git-dir}\")
# (find-fline \"{dir}\")
# (find-gitk  \"{dir}\")

# (code-c-d \"{c}\" \"{dir}\")
# (find-{c}file \"\")

# git pull --depth 1
# git pull
# git reset
# git clean -dfx
# git reset --hard
")
     )
   pos-spec-list)))

;; Test:
;; (find-git-links "https://github.com/kikito/inspect.lua" "inspectlua")




;; «find-fossil-links»  (to ".find-fossil-links")
;; Skel: (find-find-links-links-new "fossil" "url subdir c" "")
;; Test: (find-fossil-links "http://fossil.0branch.com/oorexx-mode")
;; See:  https://fossil-scm.org/
;;
(defun ee-fossil-url-stem (url) (ee-git-url-stem url))

(defun find-fossil-links (&optional url subdir c &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for fossil."
  (interactive (list (ee-url-at-point)))
  (setq url (or url "{url}"))
  (setq subdir (or subdir (ee-fossil-url-stem url) "{subdir}"))
  (setq c (or c (replace-regexp-in-string "[-.]" "" subdir) "{c}"))
  (apply
   'find-elinks
   `((find-fossil-links ,url ,subdir ,c ,@pos-spec-list)
     (find-fossil-links "{url}" "{subdir}" "{c}")
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-fossil-links)
     ""
     ,(ee-template0 "\
# (find-sh \"fossil help\")
# (find-sh \"fossil help clone\")
# (find-sh \"fossil help pull\")
# (find-sh \"fossil help all\")
# (find-sh \"fossil help open\")

 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
# rm -fv ~/usrc/fossil-repos/{subdir}.fsl
mkdir -p ~/usrc/fossil-repos/
cd       ~/usrc/fossil-repos/

fossil clone {url}    {subdir}.fsl
fossil pull  {url} -R {subdir}.fsl
fossil all ls

# cd        ~/usrc/{subdir}/ && fossil close
# rm -Rfv   ~/usrc/{subdir}/
mkdir -p    ~/usrc/{subdir}/
cd          ~/usrc/{subdir}/
fossil open ~/usrc/fossil-repos/{subdir}.fsl

# (code-c-d \"{c}\" \"~/usrc/{subdir}/\")
# (find-{c}file \"\")
")
     )
   pos-spec-list))





;;;              _                   _                                     
;;;   __ _ _ __ | |_       __ _  ___| |_      ___  ___  _   _ _ __ ___ ___ 
;;;  / _` | '_ \| __|____ / _` |/ _ \ __|____/ __|/ _ \| | | | '__/ __/ _ \
;;; | (_| | |_) | ||_____| (_| |  __/ ||_____\__ \ (_) | |_| | | | (_|  __/
;;;  \__,_| .__/ \__|     \__, |\___|\__|    |___/\___/ \__,_|_|  \___\___|
;;;       |_|             |___/                                            
;;
;; «find-apt-get-source-links»  (to ".find-apt-get-source-links")
;; (find-find-links-links "{k}" "apt-get-source" "pkg")
;; A test: (find-apt-get-source-links)

(defun find-apt-get-source-links (&optional pkg &rest pos-spec-list)
"Visit a temporary buffer containing a script for apt-get source."
  (interactive)
  (setq pkg (or pkg "{pkg}"))
  (let ((letter (replace-regexp-in-string "^\\(\\(lib\\)?.\\).*" "\\1" pkg)))
    (apply 'find-elinks
     `((find-apt-get-source-links ,pkg ,@pos-spec-list)
       (find-apt-get-source-links "lua5.1")
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-apt-get-source-links)
       ""
       ,(ee-template0 "\
# https://packages.debian.org/search?searchon=sourcenames&keywords={pkg}
# https://packages.debian.org/source/sid/{pkg}
# http://deb.debian.org/debian/pool/main/{letter}/{pkg}/

 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
# (find-sh \"apt-cache show    {pkg}\")
# (find-sh \"apt-cache showsrc {pkg}\")
rm -Rv /tmp/d/
mkdir  /tmp/d/
cd     /tmp/d/
sudo apt-get build-dep -y   {pkg}
     apt-get source         {pkg}   2>&1 | tee osource
     apt-get source --build {pkg}   2>&1 | tee osourceb

# (find-fline \"/tmp/d/\")

")
       )
     pos-spec-list)))

;; Test: (find-apt-get-source-links)






;;;             _            _        _            _   
;;;  _ __   ___| |_ ___ __ _| |_     | |_ ___  ___| |_ 
;;; | '_ \ / _ \ __/ __/ _` | __|____| __/ _ \/ __| __|
;;; | | | |  __/ || (_| (_| | ||_____| ||  __/\__ \ |_ 
;;; |_| |_|\___|\__\___\__,_|\__|     \__\___||___/\__|
;;;                                                    

;; «find-netcat-test-links» (to ".find-netcat-test-links")
;; (find-find-links-links "{k}" "netcat-test" "eesrc eetgt tgtname tgtport")
;; A test: (find-netcat-test-links)

(defun find-netcat-test-links (&optional eesrc eetgt tgtname tgtport &rest pos-spec-list)
"Visit a temporary buffer with a script to test sending data though netcat."
  (interactive)
  (setq eesrc (or eesrc "{eesrc}"))
  (setq eetgt (or eetgt "{eetgt}"))
  (setq tgtname (or tgtname "{tgtname}"))
  (setq tgtport (or tgtport "{tgtport}"))
  (apply 'find-elinks
   `((find-netcat-test-links ,eesrc ,eetgt ,tgtname ,tgtport)
     (find-netcat-test-links "shell" "shell2" "localhost" "1234")
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-netcat-test-links)
     ""
     ,(ee-template0 "\
 (find-3EE '(eepitch-{eesrc}) '(eepitch-{eetgt}))
 (find-3ee '(eepitch-{eesrc}) '(eepitch-{eetgt}))
 (eepitch-{eetgt})
# listen on port {tgtport}
netcat -l -p {tgtport}

 (eepitch-{eesrc})
# Send things to port {tgtport} (on {tgtname})
{<}
  echo hi
  sleep 1
  echo bye
  sleep 1
{>} | netcat -q 0 {tgtname} {tgtport}

")
     )
   pos-spec-list))

;; Test: (find-netcat-test-links)






;;;                         _     _            
;;;   ___  _____   ____   _(_) __| | ___  ___  
;;;  / _ \/ _ \ \ / /\ \ / / |/ _` |/ _ \/ _ \ 
;;; |  __/  __/\ V /  \ V /| | (_| |  __/ (_) |
;;;  \___|\___| \_/    \_/ |_|\__,_|\___|\___/ 
;;;                                            
;; «find-eevvideo-links»  (to ".find-eevvideo-links")
;; Used by: (find-videos-intro "2. Short links to eev video tutorials")
;;          (find-eev "eev-audiovideo.el" "video-tutorials")
;;     See: (find-audiovideo-intro "7.2. `find-eevvideo-links'")
;;    Skel: (find-find-links-links-new "eevvideo" "c stem youtubeid time" "url")
;;    Test: (find-eevvideo-links "eevnav" "M-x-list-packages-eev-nav" "0:00")
;;
(defun find-eevvideo-links (&optional c stem youtubeid time &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for eevvideo."
  (interactive)
  (setq c (or c "{c}"))
  (setq stem (or stem "{stem}"))
  (setq youtubeid (or youtubeid "{youtubeid}"))
  (setq time (or time "{time}"))
  (let* ((url (format "http://angg.twu.net/eev-videos/%s.mp4" stem)))
    (apply
     'find-elinks
     `((find-eevvideo-links ,c ,stem ,youtubeid ,time ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       ;; (find-efunction 'find-eevvideo-links)
       ,(ee-psnevideo-links c url youtubeid time)
       )
     pos-spec-list)))



;;;                             _     _            
;;;  _ __  ___ _ __   _____   _(_) __| | ___  ___  
;;; | '_ \/ __| '_ \ / _ \ \ / / |/ _` |/ _ \/ _ \ 
;;; | |_) \__ \ | | |  __/\ V /| | (_| |  __/ (_) |
;;; | .__/|___/_| |_|\___| \_/ |_|\__,_|\___|\___/ 
;;; |_|                                            
;;
;; «find-psnevideo-links»  (to ".find-psnevideo-links")
;; Skel: (find-find-links-links-new "psnevideo" "c url youtubeid time" "url")
;; Tests: (find-psnevideo-links "C" "http://foo.org/bar.mp4")
;;        (find-psnevideo-links "C" "http://foo.org/bar.mp4" nil "1:23")
;;
(defun find-psnevideo-links (&optional c url youtubeid time &rest pos-spec-list)
"Visit a temporary buffer containing an e-script for downloading and playing URL."
  (interactive)
  (setq c (or c "{c}"))
  (setq url (or url "{url}"))
  (setq youtubeid (or youtubeid "{youtubeid}"))
  (setq time (or time "{time}"))
  (apply
   'find-elinks
   `((find-psnevideo-links ,c ,url ,youtubeid ,time ,@pos-spec-list)
     ,(ee-psnevideo-links c url youtubeid time)
     )
   pos-spec-list))

;; Tests:
;; (find-estring (ee-psnevideo-links "C" "http://foo.org/bar.mp4"))
;; (find-estring (ee-psnevideo-links "C" "http://foo.org/bar.mp4" nil "1:23"))
;; (find-estring (ee-psnevideo-links "C" "http://foo.org/bar.mp4" "YID" "1:23"))
;;
(defun ee-psnevideo-links (c url &optional youtubeid time)
  (setq youtubeid (or youtubeid "{youtubeid}"))
  (setq time      (or time      "{time}"))
  (let* ((fname   (ee-shorten-file-name (ee-url-to-fname url)))
	 (argtime (ee-time-to-arg time)))
    (concat
     ;;
     ;; See:
     ;; (find-audiovideo-intro "7. `code-psnevideo'" "second line")
     ;; (find-audiovideo-intro "7. `code-psnevideo'" "redefine")
     ;; (find-audiovideo-intro "7. `code-psnevideo'" "last part")
     ;;
     (ee-template0 "\
# (find-video \"{fname}\"{argtime})

# (find-audiovideo-intro \"7. `code-psnevideo'\" \"second line\")
# (find-audiovideo-intro \"7. `code-psnevideo'\" \"redefine\")
#   (code-video \"{c}video\" \"{fname}\")
#   (find-{c}video{argtime})

")
     (ee-psnevideo-url-youtube url youtubeid time)
     "\n\n"
     "# (find-audiovideo-intro \"7. `code-psnevideo'\" \"last part\")\n"
     "\n\n"
     (ee-psne-if-needed url)
     )))



;; Tests:
;; (find-estring (ee-psnevideo-url-youtube "http://foo.org/bar.mp4"))
;; (find-estring (ee-psnevideo-url-youtube "http://foo.org/bar.mp4" nil "1:23"))
;;
(defun ee-psnevideo-url-youtube (url &optional youtubeid time)
  (setq youtubeid (or youtubeid "{youtubeid}"))
  (setq time      (or time      "{time}"))
  (let* ((fname       (ee-shorten-file-name (ee-url-to-fname url)))
         (fname0      (file-name-nondirectory fname))
         (dir         (file-name-directory fname))
	 (youtubeurl  (format "http://www.youtube.com/watch?v=%s" youtubeid))
	 (youtubetime (or (ee-time-to-youtube-time time) "")))
    (ee-template0 "\
# URL, local file, and links to the directory of the local file:
#               {url}
#              {fname}
# (find-fline \"{dir}\" \"{fname0}\")
# (find-fline \"{dir}\")

# Youtube:
# (kill-new \"{youtubeurl}{youtubetime}\")
#            {youtubeurl}{youtubetime}")
    ))




;; «ee-psne-if-needed»  (to ".ee-psne-if-needed")
;; Tests:
;;               (ee-psne-if-needed "https://www.lua.org/index.html")
;; (find-estring (ee-psne-if-needed "https://www.lua.org/index.html"))
;; (find-estring (ee-psne-if-needed "http://www.foo.org/bar.html"))
;; (find-estring (ee-psne-download  "http://www.foo.org/bar.html"))
;; (find-estring (ee-psne-download0 "http://www.foo.org/bar.html"))
;;
(defun ee-psne-if-needed (url)
  (if (ee-psne-downloaded-p url)
      "# Local file found. No need to download it again.\n"
    (ee-adjust-red-stars (ee-psne-download url))))

(defun ee-psne-downloaded-p (url)
  (file-exists-p (ee-expand (ee-url-to-fname url))))

(defun ee-psne-download (url)
  (concat "\
#  Local file not found! 
#  You need to run this: \n
" (ee-psne-download0 url)))

(defun ee-psne-download0 (url)
  (let* ((fname  (ee-shorten-file-name (ee-url-to-fname url)))
         (fname0 (file-name-nondirectory fname))
         (dir    (file-name-directory fname)))
    (ee-template0 "\
 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
mkdir -p {dir}
cd       {dir}
wget -nc '{url}'
echo     '{url}' >> ~/.psne.log

# (find-fline \"{dir}\")
# (find-fline \"{dir}\" \"{fname0}\")
# See: (find-psne-intro)
")))

;; Test: (find-estring (ee-psne-url-comment "http://www.foo.org/bar.html"))
(defun ee-psne-url-comment (url)
  (let* ((fname  (ee-shorten-file-name (ee-url-to-fname url)))
         (fname0 (file-name-nondirectory fname))
         (dir    (file-name-directory fname)))
    (ee-template0 "\
# URL, local file, and links to the directory of the local file:
#               {url}
#              {fname}
# (find-fline \"{dir}\" \"{fname0}\")
# (find-fline \"{dir}\")
")))







;;;                _                                       _     _            
;;;   ___ ___   __| | ___       _ __  ___ _ __   _____   _(_) __| | ___  ___  
;;;  / __/ _ \ / _` |/ _ \_____| '_ \/ __| '_ \ / _ \ \ / / |/ _` |/ _ \/ _ \ 
;;; | (_| (_) | (_| |  __/_____| |_) \__ \ | | |  __/\ V /| | (_| |  __/ (_) |
;;;  \___\___/ \__,_|\___|     | .__/|___/_| |_|\___| \_/ |_|\__,_|\___|\___/ 
;;;                            |_|                                            
;;
;; «code-psnevideo»  (to ".code-psnevideo")
;; See: (find-audiovideo-intro "7. `code-psnevideo'")

(defun      code-psnevideo (c url &optional youtubeid)
  (eval (ee-read (ee-code-psnevideo c url youtubeid))))
(defun find-code-psnevideo (&optional c url youtubeid &rest rest)
  (setq c (or c "{c}"))
  (setq url (or url "{url}"))
  (setq youtubeid (or youtubeid "{youtubeid}"))
  (find-estring-elisp (apply 'ee-code-psnevideo c url youtubeid rest)))
(defun   ee-code-psnevideo (c url youtubeid)
  (ee-template0 "\
;; (find-code-psnevideo \"{c}\" \"{url}\" \"{youtubeid}\")
;;      (code-psnevideo \"{c}\" \"{url}\" \"{youtubeid}\")
;;                 (find-{c}video \"0:00\")

(defun find-{c}video (&optional time &rest rest)
  (interactive)
  (find-psnevideo-links \"{c}\" \"{url}\" \"{youtubeid}\" time))
"))





;; The functions below were totally rewritten, and their new definions
;; are here:

;; ;;;                _                                   _     _            
;; ;;;   ___ ___   __| | ___        ___  _____   ____   _(_) __| | ___  ___  
;; ;;;  / __/ _ \ / _` |/ _ \_____ / _ \/ _ \ \ / /\ \ / / |/ _` |/ _ \/ _ \ 
;; ;;; | (_| (_) | (_| |  __/_____|  __/  __/\ V /  \ V /| | (_| |  __/ (_) |
;; ;;;  \___\___/ \__,_|\___|      \___|\___| \_/    \_/ |_|\__,_|\___|\___/ 
;; ;;;                                                                       
;; ;; «code-eevvideo»  (to ".code-eevvideo")
;; ;; TODO: rewrite this reusing parts of:
;; ;;     (find-eev "eev-videolinks.el" "find-eevlocal-links")
;; ;; See: (find-audiovideo-intro "7.1. `code-eevvideo'")
;; ;; Test: (find-code-eevvideo "eevnav" "M-x-list-packages-eev-nav")
;; ;;            (code-eevvideo "eevnav" "M-x-list-packages-eev-nav")
;; ;;                      (find-eevnavvideo "0:00")
;; ;;
;; (defun      code-eevvideo (c stem &optional youtubeid)
;;   (eval (ee-read (ee-code-eevvideo c stem youtubeid))))
;; (defun find-code-eevvideo (&optional c stem youtubeid &rest rest)
;;   (setq c (or c "{c}"))
;;   (setq stem (or stem "{stem}"))
;;   (setq youtubeid (or youtubeid "{youtubeid}"))
;;   (find-estring-elisp (apply 'ee-code-eevvideo c stem youtubeid rest)))
;; (defun   ee-code-eevvideo (c stem youtubeid)
;;   (ee-template0 "\
;; ;; (find-code-eevvideo \"{c}\" \"{stem}\" \"{youtubeid}\")
;; ;;      (code-eevvideo \"{c}\" \"{stem}\" \"{youtubeid}\")
;; ;;                (find-{c}video \"0:00\")
;; ;;
;; ;; See: (find-audiovideo-intro \"7.1. `code-eevvideo'\")
;; 
;; (defun find-{c}video (&optional time &rest rest)
;;   (interactive)
;;   (find-eevvideo-links \"{c}\" \"{stem}\" \"{youtubeid}\" time))
;; "))
;; 
;; ;; «code-eevvideo-local»  (to ".code-eevvideo-local")
;; ;; Test: (code-eevvideo-local "vlinks" "2021-video-links" "xQqWufQgzVY")
;; ;;  (find-code-eevvideo-local "vlinks" "2021-video-links" "xQqWufQgzVY")
;; ;;
;; (defun      code-eevvideo-local (c stem &optional youtubeid)
;;   (eval (ee-read (ee-code-eevvideo-local c stem youtubeid))))
;; (defun find-code-eevvideo-local (&optional c stem youtubeid &rest rest)
;;   (setq c (or c "{c}"))
;;   (setq stem (or stem "{stem}"))
;;   (setq youtubeid (or youtubeid "{youtubeid}"))
;;   (find-estring-elisp (apply 'ee-code-eevvideo-local c stem youtubeid rest)))
;; (defun   ee-code-eevvideo-local (c stem youtubeid)
;;   (ee-template0 "\
;; ;; (find-code-eevvideo-local \"{c}\" \"{stem}\" \"{youtubeid}\")
;; ;;      (code-eevvideo-local \"{c}\" \"{stem}\" \"{youtubeid}\")
;; ;;
;; ;;                    (find-fline \"$S/http/angg.twu.net/eev-videos/\" \"{stem}\")
;; ;; (find-code-video \"{c}video\" \"$S/http/angg.twu.net/eev-videos/{stem}.mp4\")
;;         (code-video \"{c}video\" \"$S/http/angg.twu.net/eev-videos/{stem}.mp4\")
;; ;;             (find-{c}video \"0:00\")
;; "))



;; «hardcoded-paths»  (to ".hardcoded-paths")
;;
;; The definitions of `find-eevvideo-links' and `code-eevvideo' above
;; have strings like "eev" and "http://angg.twu.net/eev-videos/"
;; hardcoded in several places... it is easy, but not entirely
;; trivial, to create variants of them that point to other sites that
;; stores video tutorials and presentations in ways that are easy to
;; download. If you are aware of sites like that, please get in touch
;; and I'll create functions pointing to them!

;;;                            _     _            
;;;   ___  _____   __   __   _(_) __| | ___  ___  
;;;  / _ \/ _ \ \ / /___\ \ / / |/ _` |/ _ \/ _ \ 
;;; |  __/  __/\ V /_____\ V /| | (_| |  __/ (_) |
;;;  \___|\___| \_/       \_/ |_|\__,_|\___|\___/ 
;;;                                               
;; «find-eev-video-links» (to ".find-eev-video-links")
;; Obsolete?
;; See: (find-audiovideo-intro "7.2. `find-eevvideo-links'")
;; and: (find-video-links-intro)
;;
;; Skel: (find-find-links-links "{k}" "eev-video" "c anggstem youtubehash")
;;       (find-find-links-links-new "eev-video" "c anggstem youtubehash" "")
;;
(defun find-eev-video-links (&optional c anggstem youtubehash &rest pos-spec-list)
"Visit a temporary buffer containing a script for downloading an eev video.
See: (find-videos-intro)
Examples:
  (find-eev-video-links \"eepitchvideo\" \"video4-eepitch\" \"Lj_zKC5BR64\")
  (find-eev-video-links \"eevvideo2\"    \"video2\"         \"doeyn5MOaB8\")
  (find-eev-video-links \"eevvideo2-pt\" \"video2pt\"       \"yztYD9Y7Iz4\")
Warning: the last one is in Portuguese..."
  (interactive)
  (setq c (or c "{c}"))
  (setq anggstem (or anggstem "{anggstem}"))
  (setq youtubehash (or youtubehash "{youtubehash}"))
  (let ((s (replace-regexp-in-string "." " " c)))
    (apply 'find-elinks
     `((find-eev-video-links ,c ,anggstem ,youtubehash)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-eev-video-links)
       ""
       ,(ee-template0 "\
 Download (or make sure we have) a local copy of the video:
 (eepitch-shell2)
 (eepitch-kill)
 (eepitch-shell2)
mkdir -p $S/http/angg.twu.net/eev-videos/
cd       $S/http/angg.twu.net/eev-videos/
wget -nc 'http://angg.twu.net/eev-videos/{anggstem}.mp4'
echo     'http://angg.twu.net/eev-videos/{anggstem}.mp4' >> ~/.psne.log

# Test:
# (find-fline  {s}  \"$S/http/angg.twu.net/eev-videos/\")
# (find-video  {s}  \"$S/http/angg.twu.net/eev-videos/{anggstem}.mp4\")
# (code-video \"{c}\" \"$S/http/angg.twu.net/eev-videos/{anggstem}.mp4\")
# (find-{c})
# Error messages:
# (find-ebuffer \"*Messages*\")

# See: (find-audiovideo-intro \"eev-avadj-mode\")
#      (find-audiovideo-intro \"The time-from-bol\")
# (eev-avadj-mode 1)
# (find-{c} t)
# 0:00

# Links to the version at youtube:
# http://www.youtube.com/watch?v={youtubehash}
# http://www.youtube.com/watch?v={youtubehash}&t=0m00s
# http://www.youtube.com/watch?v={youtubehash}&t=0h00m00s
")
       )
     pos-spec-list)))

;; Links to all the eev videos (best ones first):
;;   (find-eev-video-links "eepitchvideo" "video4-eepitch" "Lj_zKC5BR64")
;;   (find-eev-video-links "eevvideo2"    "video2"         "doeyn5MOaB8")
;;   (find-eev-video-links "eevvideo2-pt" "video2pt"       "yztYD9Y7Iz4")
;; The ones with "pt" are in Portuguese, the other ones are in English.

;; (find-eepitchvideo "0:18" "Demonstration (first time, very quickly)")



;; «find-eevshortvideo-links»  (to ".find-eevshortvideo-links")
;; Skel: (find-find-links-links-new "eevshortvideo" "c stem youtubeid" "")
;; Used in: (find-eev "eev-audiovideo.el" "video-tutorials")
;;
(defun find-eevshortvideo-links (&optional c stem youtubeid &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for eevshortvideo."
  (interactive)
  (setq c (or c "{c}"))
  (setq stem (or stem "{stem}"))
  (setq youtubeid (or youtubeid "{youtubeid}"))
  (apply
   'find-elinks-elisp
   `((find-eevshortvideo-links ,c ,stem ,youtubeid ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-eevshortvideo-links)
     ""
     ,(ee-template0 "\
;; (find-1stclassvideo-links \"{c}\")

;; Skel: (find-eevshortvideo-links \"{c}\" \"{stem}\" \"{youtubeid}\")
;;  See: (find-videos-intro \"1. Some videos\" \"{stem}\")
;; Index: http://angg.twu.net/.emacs.videos.html#{c}
;;  Test: (find-{c}video \"0:00\")
(defun find-{c}video (&optional time &rest rest)
  \"Play one of the video tutorials of eev starting at TIME.
See: (find-videos-intro \\\"1. Some videos\\\" \\\"{stem}\\\")
     http://angg.twu.net/{stem}.html
     for more info on this particular video,
and: (find-video-links-intro \\\"7. `find-eev-video'\\\")
 or: http://angg.twu.net/eev-intros/find-video-links-intro.html#7
     for more info on these video tutorials.\"
  (interactive)
  (find-eev-video \"{stem}\" \"{youtubeid}\" time))
")
     )
   pos-spec-list))



;; «find-wgeteevsubtitles-links»  (to ".find-wgeteevsubtitles-links")
;; Skel:  (find-find-links-links-new "wgeteevsubtitles" "stem exts" "cmds")
;; Tests: (find-wgeteevsubtitles-links "emacsconf2021" ".vtt")
;;        (find-estring (ee-wgeteevsubtitles-cmds "emacsconf2021" ".vtt .srt"))
;; See:   (find-wgetnode "Download Options" "-nc" "--no-clobber")
;;        (find-wgetnode "Download Options" "-N" "--timestamping")
;;        (find-wgetnode "Time-Stamping")
;;
;; NOTE: this function was superseded by
;;       `find-psne-1stclassvideo-links' and will be deleted soon!
;;
(defun find-wgeteevsubtitles-links (&optional stem exts &rest pos-spec-list)
"Visit a temporary buffer containing a script for downloading subtitles.
The script downloads an eev video and it subtitles. For example,
if STEM is \"emacsconf2021\" and EXTS is \".vtt .srt\" then the
main part of the script will be:\n
  mkdir -p $S/http/angg.twu.net/eev-videos/
  cd       $S/http/angg.twu.net/eev-videos/
  wget -nc  http://angg.twu.net/eev-videos/emacsconf2021.mp4
  wget -N   http://angg.twu.net/eev-videos/emacsconf2021.vtt
  wget -N   http://angg.twu.net/eev-videos/emacsconf2021.srt\n
The subtitles are downloaded again if the ones in
http://angg.twu.net/ are newer than the local copy."
  (interactive)
  (setq stem (or stem "{stem}"))
  (setq exts (or exts "{exts}"))
  (let* ((cmds (ee-wgeteevsubtitles-cmds stem exts)))
    (apply
     'find-elinks
     `((find-wgeteevsubtitles-links ,stem ,exts ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-wgeteevsubtitles-links)
       (find-video-links-intro "5.1. Subtitles")
       ""
       ,(ee-template0 "\
 (eepitch-shell2)
 (eepitch-kill)
 (eepitch-shell2)
{cmds}
# (find-fline \"$S/http/angg.twu.net/eev-videos/\" \"{stem}.mp4\")
# (find-video \"$S/http/angg.twu.net/eev-videos/{stem}.mp4\")
")
       )
     pos-spec-list)))

(defun ee-wgeteevsubtitles-cmds (stem exts)
  "An internal function used by `find-wgeteevsubtitles-links'."
  (let* ((dir         "$S/http/angg.twu.net/eev-videos/")
         (url- (concat "http://angg.twu.net/eev-videos/" stem))
         (f (lambda (ext) (format "wget -N   %s%s\n" url- ext)))
         (wgets (mapconcat f (split-string exts))))
    (ee-template0 "\
mkdir -p {dir}
cd       {dir}
wget -nc  {url-}.mp4
{wgets}\
")))

;; 2022may10: 




;;;   __ _           _       _       _                 _ _       _        
;;;  / _(_)_ __   __| |     | | __ _| |_ _____  __    | (_)_ __ | | _____ 
;;; | |_| | '_ \ / _` |_____| |/ _` | __/ _ \ \/ /____| | | '_ \| |/ / __|
;;; |  _| | | | | (_| |_____| | (_| | ||  __/>  <_____| | | | | |   <\__ \
;;; |_| |_|_| |_|\__,_|     |_|\__,_|\__\___/_/\_\    |_|_|_| |_|_|\_\___/
;;;                                                                       
;; «find-latex-links» (to ".find-latex-links")
;; Skel: (find-find-links-links-new "latex" "stem" "stem-")
;; Tests: (find-latex-links)
;;        (find-latex-links "/tmp/foo")
;;        (find-latex-links "/tmp/foo" 2)
;;        (find-latex-links "/tmp/foo" 2 "copy-rest")
;;   See: (find-eev-quick-intro "7.5. `find-latex-links'")
;;
(defun find-latex-links (&optional stem &rest pos-spec-list)
"Visit a temporary buffer containing a template for creating a LaTeX document."
  (interactive)
  (setq stem (or stem "{stem}"))
  (let* ((stem- (file-name-nondirectory stem)))
    (apply
     'find-elinks
     `((find-latex-links ,stem ,@pos-spec-list)
       (find-latex-links "/tmp/test")
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-latex-links)
       (find-eev-quick-intro "7.5. `find-latex-links'")
       (find-eev-quick-intro "7.5. `find-latex-links'" "change the \"{stem}\"")
       (find-eev-quick-intro "7.5. `find-latex-links'" "top line")
       (find-eev-quick-intro "7.5. `find-latex-links'" "(ee-copy-rest ...)")
       (find-eev-quick-intro "7.5. `find-latex-links'" "`C-y'")
       (find-eev-quick-intro "7.5. `find-latex-links'" "save the file foo.tex")
       (find-eev-quick-intro "7.5. `find-latex-links'" "execute the three defuns")
       ""
       (ee-copy-rest 1 '(find-fline ,(concat stem ".tex")))
       ""
       ,(ee-template0 "\
% (defun c () (interactive) (find-sh \"pdflatex {stem-}.tex\"))
% (defun d () (interactive) (find-pdf-page \"{stem}.pdf\"))
% (defun e () (interactive) (find-fline    \"{stem}.tex\"))
% (defun w () (interactive) (find-texworks \"{stem}.tex\"))
%
\\documentclass{<}article{>}
\\begin{<}document{>}

\\end{<}document{>}
")
       )
     pos-spec-list)))







;;;   __ _           _       _                   _ _       _        
;;;  / _(_)_ __   __| |     | |_   _  __ _      | (_)_ __ | | _____ 
;;; | |_| | '_ \ / _` |_____| | | | |/ _` |_____| | | '_ \| |/ / __|
;;; |  _| | | | | (_| |_____| | |_| | (_| |_____| | | | | |   <\__ \
;;; |_| |_|_| |_|\__,_|     |_|\__,_|\__,_|     |_|_|_| |_|_|\_\___/
;;;                                                                 
;; «find-lua-links» (to ".find-lua-links")
;; (find-find-links-links "{k}" "lua" "fname")
;;
;; Test: (find-sh0 "rm -v /tmp/foo.lua")
;;       (find-lua-links "/tmp/foo.lua")
;;
(defun find-lua-links (&optional fname &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for foo."
  (interactive)
  (setq fname (or fname "{fname}"))
  (let ((dir    (file-name-directory    fname))
	(fname0 (file-name-nondirectory fname)))
    (find-elinks
     `((find-lua-links ,fname ,@pos-spec-list)
       (find-lua-links "~/LUA/foo.lua")
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-lua-links)
       ""
       (find-fline ,dir ,fname0)
       (find-fline ,fname)
       (find-sh0 ,(format "touch %s && chmod 755 %s" fname fname))
       ""
       (ee-copy-rest 1 '(find-fline ,fname))
       ""
       ,(ee-template0 "\
#!/usr/bin/env lua5.1
-- (defun c () (interactive) (find-sh \"cd {dir}; ./{fname0}\"))
-- (defun d () (interactive) (find-fline \"{dir}\"))
-- (defun e () (interactive) (find-fline \"{fname}\"))
--
-- (find-sh \"./{fname0} arg1 arg2\")
--
-- (find-lua51manual \"\")
-- (find-pil2page 8 \"Contents\")
-- (find-pil2text 8 \"Contents\")
-- (find-fline \"~/LUA/lua50init.lua\")

print(\"Hello from {fname}\")

--[[
 (eepitch-lua51)
 (eepitch-kill)
 (eepitch-lua51)
dofile \"{fname0}\"

--]]\
")
     ))))




;;;                                         _           _   
;;;   ___  ___  ___ _ __ ___  ___ _ __  ___| |__   ___ | |_ 
;;;  / _ \/ __|/ __| '__/ _ \/ _ \ '_ \/ __| '_ \ / _ \| __|
;;; |  __/\__ \ (__| | |  __/  __/ | | \__ \ | | | (_) | |_ 
;;;  \___||___/\___|_|  \___|\___|_| |_|___/_| |_|\___/ \__|
;;;                                                         
;; «find-escreenshot-links» (to ".find-escreenshot-links")
;; Produce an ascii screenshot of an emacs window.
;; To test this, copy a block of lines to the kill ring and do:
;;
;;   (setq ee-ss-width 80)
;;   (find-escreenshot-links)
;;
;; Tests: (ee-ss-string-pad "" "_" " ")
;;        (ee-ss-string-pad "foo")
;;        (ee-ss-string-pad ee-ss-mode-line "-")
;;        (ee-ss-string-pad "M-x foo" "_")
;;        (find-estring (ee-ss-screenshot ";;  %s\n"))
;;        (find-escreenshot0-links)
;;        (find-escreenshot-links)
;;
(defun ee-untabify-string (string)
  (with-temp-buffer
    (insert string)
    (untabify 0 (point-max))
    (buffer-substring 0 (point-max))))

(defvar ee-ss-strings '("foo" "bar") "A list of strings, for screenshots.")
(defvar ee-ss-width 70 "The intended width of the screenshot.")
(defvar ee-ss-mode-line "-:**-" "The mode line of the screenshot.")
(defvar ee-ss-echo-area "" "The acho area or mode line of the screenshot.")
(defvar ee-ss-linefmt ";; %s\n" "??")

(defun ee-ss-string-pad (str &optional padchar barchar)
  (setq barchar (or barchar "|"))
  (let* ((padc   (if padchar (aref padchar 0) 32))
         (padlen (- ee-ss-width (length str)))
	 (padstr (make-string padlen padc)))
    (concat barchar str padstr barchar)))

(defun ee-ss-screenshot0 ()
  `(,(ee-ss-string-pad "" "_" " ")
    ,@(mapcar 'ee-ss-string-pad ee-ss-strings)
    ,(ee-ss-string-pad ee-ss-mode-line "-")
    ,(ee-ss-string-pad ee-ss-echo-area "_")
    ))

(defun ee-ss-screenshot (linefmt)
  (mapconcat (lambda (li) (format linefmt li))
	     (ee-ss-screenshot0) ""))

(defun find-escreenshot0-links (&rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for an ascii screenshot."
  ;; (interactive)
  (apply 'find-elinks
   `((find-escreenshot0-links ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-escreenshot0-links)
     (setq ee-ss-strings '(split-string (ee-last-kill) "\n"))
     (setq ee-ss-width ,ee-ss-width)
     (setq ee-ss-mode-line ,ee-ss-mode-line)
     (setq ee-ss-echo-area ,ee-ss-echo-area)
     (setq ee-ss-linefmt ,ee-ss-linefmt)
     ""
     ,(ee-ss-screenshot ee-ss-linefmt))
   pos-spec-list))

(defun find-escreenshot-links (&rest pos-spec-list)
  (interactive)
  (setq ee-ss-mode-line (format-mode-line mode-line-format 0))
  (setq ee-ss-strings (split-string (ee-last-kill) "\n"))
  (apply 'find-escreenshot0-links pos-spec-list))





;; «find-windows-eepitch-lua-links»  (to ".find-windows-eepitch-lua-links")
;; Skel: (find-find-links-links-new "windows-eepitch-lua" "dir" "")
;; Test: (find-windows-eepitch-lua-links "/tmp/")
;;
;; THIS IS OBSOLETE!
;; The new way is this one:
;;   (find-windows-beginner-intro "7.3. Lua")
;;
(defun find-windows-eepitch-lua-links (&optional dir &rest pos-spec-list)
"Visit a temporary buffer that helps in setting up `eepitch-lua52's on M$ Windows."
  (interactive)
  ;; (setq dir (or dir "{dir}"))
  (setq dir (or dir default-directory))
  (apply
   'find-elinks-elisp
   `((find-windows-eepitch-lua-links ,dir ,@pos-spec-list)
     (find-windows-eepitch-lua-links "{dir}" ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     ;; (find-efunction 'find-windows-eepitch-lua-links)
     ""
     ,(ee-template0 "\
;; Instructions:
;; To configure the `eepitch-lua52' function on M$ Windows, do this:
;;
;; 1) Install ZeroBrane from:
;;      https://studio.zerobrane.com/
;;
;; 2) Find the directory inside the ZeroBrane installation that
;;    has the file lua52.exe.
;;
;; 3) Open that directory in Emacs using Dired - see:
;;      (find-node \"(emacs)Dired\")
;;    Hints: use RET to enter into a subdirectory; use M-k to go back;
;;    you may start here:
;;      (find-fline \"C:/\")
;;
;; 4) Run `M-x find-windows-eepitch-lua-links' there. You should get
;;    a buffer like this one, but with that directory in the first line.
;;    This is like adjusting the parameter of `find-latex-links',
;;    but the value of \"{<}dir{>}\" is set to the current directory. See:
;;      (find-eev-quick-intro \"7.5. `find-latex-links'\")
;;
;; 5) Test if you've got the correct \"{<}dir{>}\". If you got it
;;    right then the sexp below should open that directory and go to
;;    line where the \"lua52.exe\" is:
;;      (find-fline \"{dir}\" \"lua52.exe\")
;;
;; 6) Try the sexp below - it is a low-level test to see a) if our
;;    current path to \"lua52.exe\" is the right one AND b) if we can run
;;    that \"lua52.exe\" as a \"shell-like program\" in a target buffer.
;;    These ideas are explained here,
;;      (find-eev-quick-intro \"6.1. The main key: <F8>\")
;;      (find-eepitch-intro \"1.1. Another target\")
;;    and the test sexp is:
;;      (eepitch-comint \"lua52\" \"{dir}lua52.exe\")
;;
;; 7) If you got a prompt like this one
;;
;;      Lua 5.2.4  ... 1994-2015 Lua.org, PUC-Rio
;;      > 
;;
;;    in the right window in the test in item (6) then everything is
;;    working. If you didn't get a prompt like that then you NEED to run
;;    this before performing another test:
;;      (eepitch-kill)
;;      
;; 8) Override the current definition of eepitch-lua52 by running this:

(defun eepitch-lua52 () (interactive)
  (eepitch-comint \"lua52\"
     \"{dir}lua52.exe\"))

;;    Note that it is a 3-line sexp! If you execute it with `M-e'
;;    the result in the echo area should be \"eepitch-lua52\".
;;
;; 9) Test if the eepitch block below works: run it by typing
;;    `<f8>'s on its three red star lines, and then `<f8>'s on its three
;;    non-red star lines.

 (eepitch-lua52)
 (eepitch-kill)
 (eepitch-lua52)
print(2+3)
for i=2,20,3 do print(i) end
os.exit()

")
     )
   pos-spec-list))





;; «find-extra-file-links»  (to ".find-extra-file-links")
;; Skel: (find-find-links-links-new "extra-file" "fname c" "dir")
;; Docs: (find-audiovideo-intro "4.1. `find-extra-file-links'")
;;
(defun find-extra-file-links (&optional fname c &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for extra-file."
  (interactive (list (if (eq major-mode 'dired-mode)
			 (ee-dired-to-fname)
		       buffer-file-name)))
  (if fname (setq fname (ee-shorten-file-name fname)))
  (setq fname (or fname "{fname}"))
  (setq c (or c "{c}"))
  (let* ((dir (file-name-directory fname))
	 (fname0 (file-name-nondirectory fname)))
    (apply
     'find-elinks-elisp
     `((find-extra-file-links ,fname ,c ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       ;; (find-efunction 'find-extra-file-links)
       ;; ""
       ,(ee-template0 "\
;; See: (find-eev-quick-intro \"9.1. `code-c-d'\")
;;      (find-audiovideo-intro \"4.1. `find-extra-file-links'\")
;;      (find-pdf-like-intro \"9. Generating three pairs\" \"`M-h M-p'\")

;; Links to this file and directory:
;; (find-fline {(ee-S dir)} {(ee-S fname0)})
;; (find-fline {(ee-S fname)})
;; (find-fline {(ee-S dir)})
\(code-c-d \"{c}\" \"{dir}\")
;; (find-{c}file \"\")

;; Links to a PDF file:
;; (find-pdf-page \"{fname}\")
;; (find-pdf-text \"{fname}\")
\(code-pdf-page \"{c}\" \"{fname}\")
\(code-pdf-text \"{c}\" \"{fname}\")
;; (find-{c}page)
;; (find-{c}text)

;; Links to an audio file:
;; (find-audio \"{fname}\")
\(code-audio \"{c}audio\" \"{fname}\")
;; (find-{c}audio)
;; (find-{c}audio \"0:00\")

;; Links to a video file:
;; (find-video \"{fname}\")
\(code-video \"{c}video\" \"{fname}\")
;; (find-{c}video)
;; (find-{c}video \"0:00\")
;;
;; (eev-avadj-mode 0)
;; (eev-avadj-mode)

;; Links to an shell-like program (for eepitch):
;; (eepitch-comint \"{c}\" \"{fname}\")

(defun eepitch-{c} () (interactive)
  (eepitch-comint \"{c}\"
     \"{fname}\"))

;; Test:

 (eepitch-{c})
 (eepitch-kill)
 (eepitch-{c})
")
       )
     pos-spec-list)))

;; Tests:
;; (find-extra-file-links "~/eev-videos/three-keys-2.mp4")





;; «find-emacs-tangents-links»  (to ".find-emacs-tangents-links")
;; Skel: (find-find-links-links-new "emacs-tangents" "yyyy mm dd msg txtstem" "")
;; Test: (find-emacs-tangents-links "2022" "06" "06")
;;
(defun find-emacs-tangents-links (&optional yyyy mm dd msg txtstem &rest pos-spec-list)
"Visit a temporary buffer with hyperlinks to a post in emacs-tangents."
  (interactive)
  (setq yyyy (or yyyy "{yyyy}"))
  (setq mm (or mm "{mm}"))
  (setq dd (or dd "{dd}"))
  (setq msg (or msg "{msg}"))
  (setq txtstem (or txtstem "{txtstem}"))
  (apply
   'find-elinks
   `((find-emacs-tangents-links ,yyyy ,mm ,dd ,msg ,txtstem ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-emacs-tangents-links "2020" "10" "05" "msg00000" "txts2ETp920ql")
     (find-emacs-tangents-links "2018" "01" "29" "msg00025" "txtJ1ftXqItdm")
     (find-efunction 'find-emacs-tangents-links)
     ""
     ,(ee-template0 "\
# https://sachachua.com/blog/{yyyy}/
# https://sachachua.com/blog/{yyyy}/{mm}/
# https://sachachua.com/blog/{yyyy}/{mm}/{yyyy}-{mm}-{dd}-emacs-news/
# https://lists.gnu.org/archive/html/emacs-tangents/{yyyy}-{mm}/
# https://lists.gnu.org/archive/html/emacs-tangents/{yyyy}-{mm}/{msg}.html

 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
# (find-fline \"~/usrc/emacs-tangents/\")
# (find-fline \"~/usrc/emacs-tangents/{yyyy}-{mm}-{dd}-emacs-news.org\")

mkdir -p ~/usrc/emacs-tangents/
cd       ~/usrc/emacs-tangents/
# rm -v     {yyyy}-{mm}-{dd}-emacs-news.org
wget -nc -O {yyyy}-{mm}-{dd}-emacs-news.org \\
  https://lists.gnu.org/archive/html/emacs-tangents/{yyyy}-{mm}/{txtstem}.txt
")
     )
   pos-spec-list))




;; «find-eeit-links»  (to ".find-eeit-links")
;; Skel: (find-find-links-links-new "eeit" "majormode" "majormodestr eeitfunstr eeitfun")
;; See:  (find-eepitch-intro "3.1. `find-eeit-links'")
;; Test: (find-eeit-links 'lua-mode)
;;
(defun find-eeit-links (&optional majormode &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for eeit."
  (interactive)
  (setq majormode (or majormode major-mode))
  (let* ((majormodestr (symbol-name majormode))
         (eeitfunstr (concat "ee-insert-test-" majormodestr))
         (eeitfun (intern eeitfunstr)))
    (apply
     'find-elinks-elisp
     `((find-eeit-links ',majormode ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       ;; ""
       ,(ee-template0 "\
;; (find-efunction 'find-eeit-links)
;; (find-eepitch-intro \"3. Test blocks\")
;; (find-eepitch-intro \"3.1. `find-eeit-links'\")
;; (find-eev \"eev-testblocks.el\" \"examples\")

;; Current definition:
;; (find-efunction              '{eeitfun})
;; (find-efunctionpp            '{eeitfun})
;; (find-epp (ee-defun-sexp-for '{eeitfun}))


;; <{eeitfunstr}>
;;
(defun {eeitfunstr} ()
  (interactive)
  (insert (ee-adjust-red-stars (format \"
--[[
 (eepitch-lua51)
 (eepitch-kill)
 (eepitch-lua51)
dofile \\\"%s\\\"

--]]
\" (buffer-name)))))

;; Test:
;; ({eeitfunstr})

")
       )
     pos-spec-list)))




;;;  _____   __  ___     _           
;;; |_   _|__\ \/ / |   (_)_   _____ 
;;;   | |/ _ \\  /| |   | \ \ / / _ \
;;;   | |  __//  \| |___| |\ V /  __/
;;;   |_|\___/_/\_\_____|_| \_/ \___|
;;;                                  
;; «find-texlive-links»  (to ".find-texlive-links")

(defun find-texlive-links (&optional date &rest pos-spec-list)
"Visit a temporary buffer containing an e-script for installing texlive from upstream."
  (interactive)
  (setq date (or date "{date}"))
  (apply 'find-elinks
   `((find-texlive-links ,date ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-texlive-links "20210816")
     (find-efunction 'find-texlive-links)
     ""
     ,(ee-template0 "\
# https://www.tug.org/texlive/
# https://www.tug.org/texlive/acquire-netinstall.html
# https://www.tug.org/texlive/quickinstall.html
# http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
#   (find-fline \"$S/http/mirror.ctan.org/systems/texlive/tlnet/\")
#   (find-fline \"$S/http/mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz\")
# https://www.tug.org/texlive/doc/install-tl.html
# (find-fline \"~/usrc/\" \"install-tl-\")
# (find-fline \"~/.texlive2018/\")
# (find-fline \"~/.texlive2019/\")
# (find-fline \"~/.texlive2021/\")
# (find-fline \"/usr/local/texlive/2018/\")
# (find-fline \"/usr/local/texlive/2019/\")
# (find-fline \"/usr/local/texlive/2019/\" \"install-tl.log\")
# (find-fline \"/usr/local/texlive/2019/release-texlive.txt\")

 (eepitch-shell2)
 (eepitch-kill)
 (eepitch-shell2)
# rm -rfv ~/.texlive2021/
# sudo rm -rfv /usr/local/texlive/2021/

mkdir -p $S/http/mirror.ctan.org/systems/texlive/tlnet/
cd       $S/http/mirror.ctan.org/systems/texlive/tlnet/
rm -fv   $S/http/mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
wget      http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
echo      http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz >> ~/.psne.log
# (find-fline \"$S/http/mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz\")
# ^ Check the date here and adjust the {<}date{>} parameter of the template

rm -Rfv ~/usrc/install-tl-{date}/
mkdir   ~/usrc/
tar  -C ~/usrc/ -xvzf \
  $S/http/mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
cd      ~/usrc/install-tl-{date}/
# sudo ./install-tl
sudo ./install-tl -select-repository

# (code-c-d \"tlinstall\" \"~/usrc/install-tl-{date}/\")
# (find-tlinstallfile \"\")
# (find-tlinstallfile \"install-tl.log\")
# (find-tlinstallfile \"install-tl\")
# https://www.tug.org/texlive/doc/install-tl.html

")
     )
   pos-spec-list))

;; Test: (find-texlive-links)




;;;                      _                                     
;;;  _ __   _____      _| |__  _ __ _____      _____  ___ _ __ 
;;; | '_ \ / _ \ \ /\ / / '_ \| '__/ _ \ \ /\ / / __|/ _ \ '__|
;;; | | | |  __/\ V  V /| |_) | | | (_) \ V  V /\__ \  __/ |   
;;; |_| |_|\___| \_/\_/ |_.__/|_|  \___/ \_/\_/ |___/\___|_|   
;;;                                                            
;; «find-newbrowser-links»  (to ".find-newbrowser-links")
;; Skel: (find-find-links-links-new "newbrowser" "browser binary b" "")
;; Test: (find-newbrowser-links "g" "googlechrome" "google-chrome")
;;
(defun find-newbrowser-links (&optional browser binary b &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for newbrowser."
  (interactive)
  (setq browser (or browser "{browser}"))
  (setq binary (or binary "{binary}"))
  (setq b (or b "{b}"))
  (apply
   'find-elinks-elisp
   `((find-newbrowser-links ,browser ,binary ,b ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-newbrowser-links)
     ""
     ,(ee-template0 "\
;; This block defines `find-{browser}', `br{b}', `br{b}l', and `br{b}d'.
;; See: (find-eev-quick-intro \"3.1. Non-elisp hyperlinks\")
;;      (find-brxxx-intro \"3. The `d' variants\")
;;      (find-brxxx-intro \"5. `code-brurl'\")
;;      (find-eev \"eev-brxxx.el\" \"code-brxxxs\")
;;
(defun find-{browser} (url) (find-bgprocess `(\"{binary}\" ,url)))
;;
;; (find-code-brurl 'find-{browser}  :remote 'br{b}  :local 'br{b}l  :dired 'br{b}d)
        (code-brurl 'find-{browser}  :remote 'br{b}  :local 'br{b}l  :dired 'br{b}d)



;; This block defines `find-{browser}-page'.
;; See: (find-eev \"eev-pdflike.el\" \"find-googlechrome-page\")
;;
(defun ee-find-{browser}-page (fname &optional page)
  `(\"{binary}\" ,(ee-fname-page-to-url fname page)))
;;
;; (find-code-pdfbackend \"{browser}-page\")
        (code-pdfbackend \"{browser}-page\")



;; Run the `defalias' below if you want to make
;; `find-pdf-page' use `find-{browser}-page'.
;; See: (find-eev \"eev-pdflike.el\" \"change-default-viewer\")
;;
(defalias 'find-pdf-page 'find-{browser}-page)



;; Tests:
;; (find-{browser} \"http://angg.twu.net/#eev\")
;; (find-{browser}-page \"~/Coetzee99.pdf\")
;; (find-{browser}-page \"~/Coetzee99.pdf\" 3)
;; (find-pdf-page \"~/Coetzee99.pdf\" 3)
")
     )
   pos-spec-list))



;; «find-newbrowser-links»  (to ".find-newbrowser-links")
;; Skel: (find-find-links-links-new "newbrowser" "shrt longname binary" "")
;; Test: (find-newbrowser-links)
;;       (find-newbrowser-links "g" "googlechrome" "google-chrome")
;; See:  http://angg.twu.net/eev-customize.html
;;
(defun find-newbrowser-links (&optional shrt longname binary &rest pos-spec-list)
"Visit a temporary buffer containing a script to set up an atypical browser."
  (interactive)
  (setq shrt (or shrt "{shrt}"))
  (setq longname (or longname "{longname}"))
  (setq binary (or binary "{binary}"))
  (apply
   'find-elinks-elisp
   `((find-newbrowser-links ,shrt ,longname ,binary ,@pos-spec-list)
     (find-newbrowser-links "g" "googlechrome" "google-chrome")
     (find-newbrowser-links "g" "iceweasel" "iceweasel-uxp")
     (find-newbrowser-links "v" "vivaldi" "vivaldi")
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-newbrowser-links)
     ""
     ,(ee-template0 "\
;; 0. Basic tests:
;; (setq ee-nb-prog \"{binary}\")
;; (setq ee-nb-pdfp \"https://tannerlectures.utah.edu/_resources/documents/a-to-z/c/Coetzee99.pdf#page=3\")
;; (find-bgprocess (list ee-nb-prog \"http://www.lua.org/start.html\"))
;; (find-bgprocess (list ee-nb-prog ee-nb-pdfp))


;; 1. Define `find-{longname}' and `br{shrt}'.
;; See:  (find-eev-quick-intro \"3.1. Non-elisp hyperlinks\")
;;       (find-eev-quick-intro \"3.1. Non-elisp hyperlinks\" \"not free\")
;;       (find-eev-quick-intro \"3.1. Non-elisp hyperlinks\" \"find-googlechrome\")
;;       (find-eev-quick-intro \"3.1. Non-elisp hyperlinks\" \"M-x brff\")
;;       (find-eev \"eev-plinks.el\" \"find-googlechrome\")
;;       (find-eev \"eev-brxxx.el\" \"code-brxxxs\")
;; Test: (find-{longname} \"http://www.lua.org/start.html\")
;;       (br{shrt} \"http://www.lua.org/start.html\")
;;
(defun find-{longname} (url &rest rest)
  (find-bgprocess `(\"{binary}\" ,url)))
;;
(code-brurl 'find-{longname}  :remote 'br{shrt}  :local 'br{shrt}l  :dired 'br{shrt}d)


;; 2. Configure `find-youtube-video'.
;; You will need this if you don't want to
;; set up a video player like mpv or vlc.
;; See:  (find-video-links-intro \"3. `find-youtube-video'\")
;;       (find-video-links-intro \"5. Local copies\")
;;       (find-eev \"eev-audiovideo.el\" \"find-youtube-video\")
;; Test: (ee-find-youtube-video \"FoAzpGzFCSE\" \"15:14\" \"nice\")
;;          (find-youtube-video \"FoAzpGzFCSE\" \"15:14\")
;;                 (find-2022findeevanggvideo \"15:14\")
(setq ee-find-youtube-video-program 'find-{longname})


;; 3. Configure `find-pdf-page' to make it use the browser.
;; Use this when you don't want to set up a standalone PDF viewer.
;; See:  (find-pdf-like-intro \"2. Preparation\")
;;       (find-pdf-like-intro \"3. Hyperlinks to PDF files\")
;;       (find-pdf-like-intro \"3. Hyperlinks to PDF files\" \"If you have xpdf\")
;;       (find-eev \"eev-pdflike.el\" \"change-default-viewer\")
;;       (find-eev \"eev-pdflike.el\" \"find-firefox-page\")
;;       (find-code-pdfbackend \"{longname}-page\")
;; Test: (ee-find-{longname}-page \"~/Coetzee99.pdf\" 3)
;;          (find-{longname}-page \"~/Coetzee99.pdf\" 3)
;;                 (find-pdf-page \"~/Coetzee99.pdf\" 3)
;;
(defun ee-find-{longname}-page (fname &optional page)
  `(\"{binary}\" ,(ee-fname-page-to-url fname page)))
(code-pdfbackend \"{longname}-page\")
(defalias 'find-pdf-page 'find-{longname}-page)
;;
;; To configure `find-pdf-page' to make it use a
;; standalone PDF viewer, run one of the sexps below:
;;   (defalias 'find-pdf-page 'find-xpdf-page)
;;   (defalias 'find-pdf-page 'find-mupdf-page)
;; or see: (find-eev \"eev-pdflike.el\" \"change-default-viewer\")

")
     )
   pos-spec-list))









;; «find-newpdfviewer-links»  (to ".find-newpdfviewer-links")
;; Skel: (find-find-links-links-new "newpdfviewer" "short binary" "")
;; Test: (find-newpdfviewer-links "okular")
;;
(defun find-newpdfviewer-links (&optional short binary &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for newpdfviewer."
  (interactive)
  (setq short (or short "{short}"))
  (setq binary (or binary short "{binary}"))
  (apply
   'find-elinks-elisp
   `((find-newpdfviewer-links ,short ,binary ,@pos-spec-list)
     (find-newpdfviewer-links "{short}" "{binary}" ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-newpdfviewer-links)
     ""
     ,(ee-template0 "\

;; <find-{short}-page>
;; Skel:  (find-newpdfviewer-links \"{short}\" \"{binary}\")
;; Tests: (find-pdf-like-intro \"2. Preparation\")
;;        (ee-find-{short}-page \"~/Coetzee99.pdf\" 3)
;;           (find-{short}-page \"~/Coetzee99.pdf\" 3)
;;
\(defun     find-{short}-page (fname &optional page &rest rest)
  (find-bgprocess (ee-find-{short}-page fname page)))
\(defvar ee-find-{short}-page-options '())
\(defun  ee-find-{short}-page (fname &optional page &rest rest)
  `(\"{binary}\"
    ,@ee-find-{short}-page-options
    ;; Each PDF viewer selects the initial page in a different way.
    ;; See: (find-man \"{binary}\")
    ,@(if page `(\"-p\" ,(format \"%s\" page)))
    ,fname
    ))

;; Extra definitions:
;; (find-code-pdfbackend \"mupdf-page\")
        (code-pdfbackend \"mupdf-page\")

;; Compare the code above with:
;; (find-eev \"eev-pdflike.el\" \"find-mupdfpage\")



;; To make `find-{short}-page' the default viewer for PDFs,
;; read: (find-eev \"eev-pdflike.el\" \"change-default-viewer\") 
;; and run:
(defalias 'find-pdf-page 'find-{short}-page)
;;
;; Test: (find-pdf-like-intro \"2. Preparation\")
;;       (find-pdf-page \"~/Coetzee99.pdf\" 3)
")
     )
   pos-spec-list))




;;;   ___        ___  
;;;  / _ \__  __/ _ \ 
;;; | | | \ \/ / | | |
;;; | |_| |>  <| |_| |
;;;  \___//_/\_\\___/ 
;;;                   
;; «ee-0x0-upload-region»  (to ".ee-0x0-upload-region")
;; Needs: https://melpa.org/#/0x0
;;        (find-epackage-links '0x0)
;;   See: https://lists.gnu.org/archive/html/eev/2021-08/msg00000.html
;;
(defvar ee-0x0-url nil
  "The last URL generated by a call to `ee-0x0-upload-region'.")

(defun ee-0x0-upload (b e &rest ignore)
  "Upload the current region using `0x0-dwim'.
See: https://gitlab.com/willvaughn/emacs-0x0/-/issues/2
This is a hack."
  (deactivate-mark 'force)
  (eek "C-x C-x C-x C-x     ;; reactivate the mark
        M-x 0x0-dwim RET"))

(defun ee-0x0-upload-region (b e)
  "Upload the current region to 0x0 and show some elisp hyperlinks.
I use this mainly on IRC chats, to send elisp snippets to people
who use eev. I use this function aliased to `u0', with:

  (defalias 'u0 'ee-0x0-upload-region)

If I mark the region with the snippet and run `M-x u0', `u0'
uploads the snippet to https://0x0.st/ and shows some sexps in a
temporary buffer; the two main sexps in that temporary buffer
there will be things like:

  (find-wget \"https://0x0.st/-J1W.el\")
  (find-wget-elisp \"https://0x0.st/-J1W.el\")

The one that starts with `find-wget-elisp' downloads the URL with
wget and runs `emacs-lisp-mode' on the resulting \"*wget: URL*\"
buffer. If the other person on IRC is using some IRC client that
runs in Emacs I can send the find-wget-elisp sexp to her and she
only needs to type `M-e' on it to access the elisp code that I
sent."
  (interactive "r")
  (ee-0x0-upload b e '0x0)
  (setq ee-0x0-url (ee-last-kill))
  (find-0x0-links))

;; «find-0x0-links»  (to ".find-0x0-links")
;; Skel: (find-find-links-links-new "0x0" "url" "")
;;
(defun find-0x0-links (&optional url &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks to an upload to 0x0.st.
This function is used by `ee-0x0-upload-region'."
  (interactive)
  (setq url (or url ee-0x0-url))
  (apply
   'find-elinks
   `((find-0x0-links ,url ,@pos-spec-list)
     (find-0x0-links "{url}" ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-0x0-links)
     ""
     ,(ee-template0 "\
{url}
(find-wget \"{url}\")
(find-wget-elisp \"{url}\")
")
     )
   pos-spec-list))




;; «find-eepitch-bullet-links»  (to ".find-eepitch-bullet-links")
;; «find-red-star-links»        (to ".find-red-star-links")
;; Skel: (find-find-links-links-new "red-star" "" "")
;; Test: (find-red-star-links)
;;
(defalias 'find-eepitch-bullet-links 'find-red-star-links)
(defun find-red-star-links (&rest pos-spec-list)
"Show code that makes eepitch use red bullets instead of red stars."
  (interactive)
  (apply
   'find-elinks-elisp
   `((find-red-star-links ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-red-star-links)
     ;; ""
     ,(ee-template0 "\
;; The code below was based on:
;;   https://lists.gnu.org/archive/html/help-gnu-emacs/2021-05/msg01080.html
;;   https://lists.gnu.org/archive/html/help-gnu-emacs/2021-05/msg01079.html
;; Note that the default regexes for eepitch accept both the red
;; stars and the bullets - chars 15 and 8226 respectively...
;; See: (find-eev \"eepitch.el\" \"glyphs\")
;;      (find-eev \"eepitch.el\" \"eepitch\" \"eepitch-regexp\")
;;      (find-eev-quick-intro \"6.3. Creating eepitch blocks: `M-T'\")
;; And try: (insert \"\\n;; \" 15 8226)



;; Run this to make the bullets use the default face:
\(eepitch-set-glyph0 ?• nil)
;;
;; Run this to make the bullets appear in the same face as the red stars:
\(eepitch-set-glyph0 ?• ?• 'eepitch-star-face)
;;
;; You'll need to force a redisplay to see the change.
;; One way to do that is with `C-l' (`recenter-top-bottom').


;; Most of the functions in eev that generate text with red stars
;; use the function `ee-adjust-red-stars' to replace the red
;; stars in the generated text by some non-default character if
;; needed. Use the first defun below to use red stars, and use
;; the second one to use bullets.
;;  See: (find-eev \"eepitch.el\" \"ee-adjust-red-stars\")
;;       (find-eval-intro \"3. What to execute, and in what order\")
;; Test: (ee-adjust-red-stars \"foobar\")
;;
\(defun ee-adjust-red-stars (str) str)
\(defun ee-adjust-red-stars (str) (replace-regexp-in-string \"\" \"•\" str))



;; To make eepitch blocks use red bullets by default, add the
;; block below to your ~/.emacs (including the line with the
;; \"See:\"). Note that this will make bullets appear in red in
;; other places too, like in info manuals - for example here:
;;   (find-enode \"Using Region\")
;;
;; See: (find-red-star-links)
\(eepitch-set-glyph0 ?• ?• 'eepitch-star-face)
\(defun ee-adjust-red-stars (str) (replace-regexp-in-string \"\" \"•\" str))



;; The high-level way to switch the default between \"use red bullets\"
;; and \"use red stars\" is to use `M-x ee-use-red-bullets' and `M-x
;; ee-use-red-stars'. Try the two sexps below...
;;
;; (progn (insert \"\\nshell\\n\") (eek \"<up> <<ee-use-red-bullets>> M-T\"))
;; (progn (insert \"\\nshell\\n\") (eek \"<up> <<ee-use-red-stars>>   M-T\"))
")
     )
   pos-spec-list))

;; «ee-use-red-stars»    (to ".ee-use-red-stars")
;; «ee-use-red-bullets»  (to ".ee-use-red-bullets")
;; See: (find-red-star-links 2 "high-level")

(defun ee-use-red-stars ()
  "See: (find-red-star-links 2 \"high-level\")"
  (interactive)
  (eepitch-set-glyph0 ?• nil)
  (defun ee-adjust-red-stars (str) str)
  (redisplay 'force)
  (message "Now `M-T' and `M-x eeit' will use red stars."))

(defun ee-use-red-bullets ()
  "See: (find-red-star-links 2 \"high-level\")"
  (interactive)
  (eepitch-set-glyph0 ?• ?• 'eepitch-star-face)
  (defun ee-adjust-red-stars (str) (replace-regexp-in-string "" "•" str))
  (redisplay 'force)
  (message "Now `M-T' and `M-x eeit' will use red bullets."))






;; «find-angg-es-links»  (to ".find-angg-es-links")
;; Skel: (find-find-links-links-new "angg-es" "" "")
;; Test: (find-angg-es-links)
;;  See: http://angg.twu.net/eev-find-angg.html
;;
(defun find-angg-es-links (&rest pos-spec-list)
"Show an e-script for configuring `find-angg' and `find-es'."
  (interactive)
  (apply
   'find-elinks-elisp
   `((find-angg-es-links ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-angg-es-links)
     (find-eev-quick-intro "9. Shorter hyperlinks")
     (find-eev-quick-intro "9.1. `code-c-d'")
     (find-eev-quick-intro "9.2. Extra arguments to `code-c-d'" "to anchors")
     (find-2022findeevanggvideo "11:30" "(find-angg-es-links)")
     (find-2022findeevanggvideo "14:12" "the find-wgeta searches for")
     ""
     ,(ee-template0 "\


;; The `progn' below is how I (edrx) define `find-angg' and
;; `find-es' in my machine to point to local files. Note that the
;; sexps
;;
;;   (find-angg \"foo\" \"anchor\")
;;   (find-es   \"foo\" \"anchor\")
;;
;; search for anchor \"anchor\" in the files \"~/foo\" and
;; \"~/e/foo.e\" respectively... in 1996, when I wrote `find-es',
;; I had several functions like it, that appended arbitrary
;; prefixes _and suffixes_ to their first arguments. I stopped
;; using all of them except `find-es' - that is a kind of
;; living fossil.
;;
(progn

  (code-c-d \"angg\" \"~/\" :anchor :grep)
  (code-c-d \"es\"   \"$ES/\")
  (defun find-es (stem &rest rest)
    (apply 'find-anchor (ee-esfile (concat stem \".e\")) rest))

)



;; The `progn' below defines versions of `find-angg' and
;; `find-es' that use `find-wget' to access the
;; public copies of my files at angg.twu.net:
;;
(progn

  (defun find-angg (fname &rest rest)
    (apply 'find-wgeta (format \"http://angg.twu.net/%s\" fname) rest))
  (defun find-es (fname &rest rest)
    (apply 'find-wgeta (format \"http://angg.twu.net/e/%s.e\" fname) rest))

)



;; Tests:
;; (find-angg \"e/bullseye.e\")
;; (find-angg \"e/bullseye.e\" \"2021aug16\")
;; (find-es     \"bullseye\")
;; (find-es     \"bullseye\"   \"2021aug16\")
")
     )
   pos-spec-list))


;; Based on this suggestion by Quiliro Ordoñez, but simpler:
;; https://lists.gnu.org/archive/html/eev/2022-08/msg00005.html
;;
(defun find-angg-not-configured (&rest rest) (interactive)
  (error "`find-angg' not configured! Run: (find-angg-es-links)"))

(defun find-es-not-configured (&rest rest) (interactive)
  (error "`find-es' not configured! Run: (find-angg-es-links)"))

(if (not (fboundp 'find-angg)) (defalias 'find-angg 'find-angg-not-configured))
(if (not (fboundp 'find-es))   (defalias 'find-es   'find-es-not-configured))





;; «find-1stclassvideo-links»  (to ".find-1stclassvideo-links")
;; Skel: (find-find-links-links-new "1stclassvideo" "c" "body")
;;  See: (find-eev "eev-videolinks.el" "first-class-videos")
;;       (find-eev "eev-videolinks.el" "second-class-videos")
;; Tests: (find-1stclassvideo-links "eev2019")
;;        (find-1stclassvideo-links "foo")
;;        (find-1stclassvideo-links)
;;        (find-estring (ee-find-1stclassvideo-links "eev2019"))
;;        (find-estring (ee-find-1stclassvideo-links "foo"))
;;
(defun find-1stclassvideo-links (&optional c &rest pos-spec-list)
"Visit a temporary buffer containing links about a first-class video."
  (interactive (list (ee-1stclassvideo-around-point-ask)))
  (setq c (or c "{c}"))
  (let* ((ee-buffer-name (or ee-buffer-name "*find-1stclassvideo-links*"))
	 (body (if (member c (ee-1stclassvideos))
		   (ee-find-1stclassvideo-links c)
		 ";; Not in: (ee-1stclassvideos)")))
    (apply
     'find-elinks-elisp
     `((find-1stclassvideo-links ,c ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-1stclassvideo-links)
       (find-1stclassvideos)
       ""
       ,body
       )
     pos-spec-list)))

;; Test:
;; (find-estring-elisp (ee-find-1stclassvideo-links "eev2021"))
;;
(defun ee-find-1stclassvideo-links (c)
  "An internal function used by `find-1stclassvideo-links'."
  (let* ((title    (ee-1stclassvideos-field c :title))
	 (mp4      (ee-1stclassvideos-field c :mp4))
	 (yt       (ee-1stclassvideos-field c :yt))
	 (page     (ee-1stclassvideos-field c :page))
	 (date     (ee-1stclassvideos-field c :date))
	 (length   (ee-1stclassvideos-field c :length))
	 (comment  (ee-1stclassvideos-field c :comment))
	 (lang     (ee-1stclassvideos-field c :lang))
	 (mp4stem  (ee-1stclassvideos-mp4stem c))
         (mp4found (ee-1stclassvideos-mp4found c))
	 (hash     (ee-1stclassvideos-hash c))
	 (dlsubs   (ee-1stclassvideos-dlsubs c))
	 (defun    (ee-find-1stclassvideo-defun c mp4stem hash)))
    (ee-template0 "\
;; Title: {title}
;; MP4:   {mp4}
;; YT:    {yt}
;; Page:  {page}
;; Comment: {comment}
;; Date:    {date}
;; Length:  {length}
;;
;; Play:  (find-{c}video \"0:00\")
;; Info:  (find-1stclassvideodef        \"{c}\")
;;        (find-eev \"eev-videolinks.el\" \"{c}\")
;;            (find-1stclassvideo-links \"{c}\")
;;
;; Index: (find-1stclassvideoindex              \"{c}\")
;;        http://angg.twu.net/.emacs.videos.html#{c}
;;        (find-angg         \".emacs.videos\"    \"{c}\")
;;        (find-angg-es-links)
{dlsubs}\

;; See:
;; (find-video-links-intro \"9. First-class videos\")
;; (find-eev \"eev-videolinks.el\" \"first-class-videos\")
;; (find-eev \"eev-videolinks.el\" \"second-class-videos\")


;;-- Some super-technical things:

;; Setup (as a 2nd-class video):
 ' (find-ssr-links     \"{c}\" \"{mp4stem}\" \"{hash}\")
 ' (code-eevvideo      \"{c}\" \"{mp4stem}\" \"{hash}\")
 ' (code-eevlinksvideo \"{c}\" \"{mp4stem}\" \"{hash}\")
;; (find-{c}video \"0:00\")

;; Definition of the function:
;; (find-eev \"eev-videolinks.el\" \"first-class-videos\")
;; (find-eev \"eev-videolinks.el\" \"find-{c}video\")
;;               (find-efunction 'find-{c}video)

{defun}")))

;; Test:
;; (find-estring-elisp (ee-find-1stclassvideo-defun "C" "M" "H"))
;;
(defun ee-find-1stclassvideo-defun (c mp4stem hash)
  (ee-template0 "\
;; <find-{c}video>
;; Info: (find-1stclassvideo-links \"{c}\")
;; Play: (find-{c}video \"0:00\")
\(defun find-{c}video (&optional time &rest rest)
  \"Play one of the first-class videos of eev starting at TIME.
For more info on this particular video, run:
  (find-1stclassvideo-links \\\"{c}\\\")\"
  (interactive)
  (find-1stclassvideo-video \"{c}\" time))
"))

;; Tests: (ee-1stclassvideos-dlsubs "2022pict2elua")
;;        (find-1stclassvideo-links "2022pict2elua")
;;        (ee-1stclassvideos-dlsubs "2021workshop6")
;;        (find-1stclassvideo-links "2021workshop6")
;; See: (find-eev "eev-videolinks.el" "ee-1stclassvideos-field")
;;
(defun ee-1stclassvideos-dlsubs (c)
  "An internal function used by `find-1stclassvideo-links'."
  (let* ((mp4stem  (ee-1stclassvideos-mp4stem c))
         (mp4found (ee-1stclassvideos-mp4found c))
	 (exts     (ee-1stclassvideos-field c :subs))
	 (hassubs  exts)
	 (template00 ";;
;; You don't have a local copy of this video.
;; To download a local copy, run this:
;;       (find-psne-1stclassvideo-links \"{c}\")
;; This video doesn't have subtitles.\n")
	 (template01 ";;
;; You don't have a local copy of this video.
;; To download a local copy of the video with subtitles, run:
;;       (find-psne-1stclassvideo-links \"{c}\")
;;   or: (find-psne-eevvideo-links \"{mp4stem}\" \"{exts}\")\n")
	 (template10 ";;
;; We have a local copy of this video.
;; This video doesn't have subtitles.\n")
	 (template11 ";;
;; You have a local copy of this video.
;; The upstream copy of this video has subtitles.
;; If you don't have a local copy of its subtitles, or if you
;; want to update the local copy of the subtitles, run this:
;;        (find-psne-1stclassvideo-links \"{c}\")
;;    or: (find-psne-eevvideo-links \"{mp4stem}\" \"{exts}\")\n"))
    (if mp4found
	(if hassubs
	    (ee-template0 template11)
	  (ee-template0 template10))
      (if hassubs
	  (ee-template0 template01)
	(ee-template0 template00)))))




;; «find-1stclassvideoindex»  (to ".find-1stclassvideoindex")
;; «find-1stclassvideodef»    (to ".find-1stclassvideodef")
;; Tests: (find-1stclassvideoindex "2022findeevangg")
;;        (find-1stclassvideoindex "2022findelispintro")
;;        (find-1stclassvideodef   "2022findelispintro")
;;
(defun find-1stclassvideoindex (c &rest pos-spec-list)
  (interactive (list (ee-1stclassvideo-around-point-ask)))
  (apply 'find-anggwgeta-elisp ".emacs.videos" c pos-spec-list))

(defun find-1stclassvideodef (c &rest pos-spec-list)
  (interactive (list (ee-1stclassvideo-around-point-ask)))
  (apply 'find-eev "eev-videolinks.el" c pos-spec-list))

;; «find-1stclassvideos»  (to ".find-1stclassvideos")
;; Test: (find-1stclassvideos)
;;
(defun find-1stclassvideos (&rest rest)
  "Visit a temporary buffer with a list of all first-class videos of eev."
  (interactive)
  (let* ((ee-buffer-name (or ee-buffer-name "*(find-1stclassvideos)*"))
	 (f (lambda (s) (list 'find-1stclassvideo-links s)))
	 (finds (mapcar f (ee-1stclassvideos))))
    (apply 'find-elinks-elisp
	   `((find-1stclassvideos)
	     ,@finds)
	   rest)))

;; «1c»  (to ".1c")
;; Suggestion: put the alias below in your init file.
;; (defalias '1c 'find-1stclassvideos)




;; «find-advicebefore-links»  (to ".find-advicebefore-links")
;; Skel: (find-find-links-links-new "advicebefore" "fun" "")
;; Test: (find-advicebefore-links)
;;       (find-advicebefore-links "FOO")
;; Screenshot: http://angg.twu.net/IMAGES/find-advicebefore-links.png
;;
;; I wrote this when I was trying to learn edebug and I was failing
;; miserably.
;;
(defun find-advicebefore-links (&optional fun &rest pos-spec-list)
"Visit a temporary buffer containing code for adding advice to FUN.
The temporary buffer will contain code for advice-add'ing a
logging function to FUN, for advice-remove'ing the logging
function, and for inspecting the log. See the demo to understand
how this works."
  (interactive)
  (setq fun (or fun "{fun}"))
  (apply
   'find-elinks-elisp
   `((find-advicebefore-links ,fun ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-advicebefore-links)
     ";;"
     ,(ee-template0 "\
;; See: (find-elnode \"Advice Combinators\")
;; Demo: http://angg.twu.net/elisp/find-advicebefore-links.el.html
;;       http://angg.twu.net/elisp/find-advicebefore-links.el
;; (find-wget-elisp \"http://angg.twu.net/elisp/find-advicebefore-links.el\")

(setq  ee-log nil)
(defun ee-log (f r) (setq ee-log (cons (cons f r) ee-log)))
(defun ee-log-{fun} (&rest r) (ee-log '{fun} r))
(advice-add   '{fun}  :before 'ee-log-{fun})
;;
(advice-remove '{fun}         'ee-log-{fun})
(find-2a nil '(find-eppp ee-log))
")
     )
   pos-spec-list))





;; «find-osm-links»  (to ".find-osm-links")
;; Skel: (find-find-links-links-new "osm" "lat lon zoom" "")
;; Test: (find-osm-links)
;;       (find-osm-links  43.7731  11.2562 17 "Il Duomo")
;;  See: (find-eev "eev-plinks.el" "find-osm")
;;
(defun find-osm-links (&optional lat lon zoom &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for OpenStreetMap viewer."
  (interactive)
  (setq lat  (or lat  (ee-osm-lat)  "{lat}"))
  (setq lon  (or lon  (ee-osm-lon)  "{lon}"))
  (setq zoom (or zoom (ee-osm-zoom) "{zoom}"))
  (apply
   'find-elinks
   `((find-osm-links ,lat ,lon ,zoom ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-osm-links)
     ""
     ,@(ee-find-osm-links lat lon zoom)
     )
   pos-spec-list))

(defun ee-find-osm-links (&optional lat lon zoom)
  "An internal function used by `find-osm-links'."
  (setq lat  (or lat  (ee-osm-lat)  "{lat}"))
  (setq lon  (or lon  (ee-osm-lon)  "{lon}"))
  (setq zoom (or zoom (ee-osm-zoom) "{zoom}"))
  ;;
  `((find-osm ,lat ,lon ,zoom)
    (osm-goto ,lat ,lon ,zoom)
    (find-efunction 'find-osm)
    (find-efunction 'osm-goto)
    ""
    ,(ee-template0 "\
# (find-osm-str \"{lat},{lon},{zoom}\")
# https://www.google.com.br/maps/@{lat},{lon},{zoom}z?hl=en")
    ))

(defun ee-osm-lat  () (if (eq major-mode 'osm-mode) osm--lat))
(defun ee-osm-lon  () (if (eq major-mode 'osm-mode) osm--lon))
(defun ee-osm-zoom () (if (eq major-mode 'osm-mode) osm--zoom))





;; «find-pip3-links»  (to ".find-pip3-links")
;; Skel: (find-find-links-links-new "pip3" "pkg" "pkg_")
;; Test: (find-pip3-links "youtube-transcript-downloader")
;; See:  http://angg.twu.net/find-yttranscript-links.html
;;
(defun find-pip3-links (&optional pkg &rest pos-spec-list)
"Visit a temporary buffer containing a script for pip3."
  (interactive)
  (setq pkg (or pkg "{pkg}"))
  (let* ((pkg_ (string-replace "-" "_" pkg)))
    (apply
     'find-elinks
     `((find-pip3-links ,pkg ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-pip3-links)
       ""
       ,(ee-template0 "\
# https://pip.pypa.io/en/stable/
# (find-status   \"python3-pip\")
# (find-vldifile \"python3-pip.list\")
# (find-udfile   \"python3-pip/\")
# (find-sh \"pip3 list\" \"{pkg}\")
# (find-sh \"pip3 show {pkg}\")
# (find-importlib-links \"{pkg}\")
# (find-pypi-links \"{pkg}\")

 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
sudo apt-get install python3-pip

 (eepitch-shell)
 (eepitch-kill)
 (eepitch-shell)
# (find-man \"1 pip3\")
pip3 show {pkg}
pip3 install {pkg}
")
       )
     pos-spec-list)))




;; «find-yttranscript-links»  (to ".find-yttranscript-links")
;; Skel: (find-find-links-links-new "yttranscript" "c hash" "")
;; Test: (find-yttranscript-links)
;;       (find-yttranscript-links "acmetour" "dP1xVpMPn8M")
;; See:  http://angg.twu.net/find-yttranscript-links.html
;;
(defun find-yttranscript-links (&optional c hash &rest pos-spec-list)
"Display a temporary script that downloads a transcript from youtube."
  (interactive (list nil (ee-youtubedl-hash-around-point)))
  (setq c (or c "{c}"))
  (setq hash (or hash "{hash}"))
  (let ((ee-buffer-name (or ee-buffer-name "*find-yttranscript-links*")))
    (apply
     'find-elinks
     `((find-yttranscript-links ,c ,hash ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-yttranscript-links)
       ""
       ,(ee-template0 "\
# (find-pip3-links \"youtube-transcript-downloader\")
# (find-youtubedl-links nil nil \"{hash}\" nil \"{c}\")

 (python-mode)
 (eepitch-python)
 (eepitch-kill)
 (eepitch-python)
import youtube_transcript_downloader
url    = \"http://www.youtube.com/watch?v={hash}\"
f      = \"find-{c}video\"
tr     = youtube_transcript_downloader.get_transcript(url)
trits0 = tr.items()
trits1 = '\\n'.join((key + ' ' + text for key, text in trits0))
trits1 = '\\n'.join(('% (' + f + ' \"' + key + '\" \"' + text + '\")' for key, text in trits0))
print(trits1)

")
       )
     pos-spec-list)))


;; «find-importlib-links»  (to ".find-importlib-links")
;; Skel: (find-find-links-links-new "importlib" "pkg" "pkg_")
;; Tests: (find-importlib-links)
;;        (find-importlib-links "requests")
;; See:   http://angg.twu.net/find-yttranscript-links.html
;;
(defun find-importlib-links (&optional pkg &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for importlib."
  (interactive)
  (setq pkg (or pkg "{pkg}"))
  (let* ((pkg_ (string-replace "-" "_" pkg)))
    (apply
     'find-elinks
     `((find-importlib-links ,pkg ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-importlib-links)
       ""
       (find-pip3-links ,pkg)
       (find-pypi-links ,pkg)
       (find-pydoc "library/importlib")
       (find-pydoc "library/importlib.metadata")
       ""
       ,(ee-template0 "\
 (python-mode)
 (eepitch-python)
 (eepitch-kill)
 (eepitch-python)
import importlib.metadata, pprint
import {pkg_}
{pkg_}.__file__
dist = importlib.metadata.distribution('{pkg}')
pprint.pprint(dist.files)
md = dist.metadata
print('\\n'.join(md.keys()))
md['Name']
md['Version']
md['Summary']
md['Home-Page']
")
       )
     pos-spec-list)))


;; «find-pypi-links»  (to ".find-pypi-links")
;; Skel: (find-find-links-links-new "pypi" "pkg" "pkg_")
;; Test: (find-pypi-links)
;;       (find-pypi-links "requests")
;; See:  http://angg.twu.net/find-yttranscript-links.html
;;
(defun find-pypi-links (&optional pkg &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for pypi."
  (interactive)
  (setq pkg (or pkg "{pkg}"))
  (let* ((pkg_ (string-replace "-" "_" pkg)))
    (apply
     'find-elinks
     `((find-pypi-links ,pkg ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-pypi-links)
       ""
       ,(ee-template0 "\
# https://warehouse.pypa.io/api-reference/json.html
# https://requests.readthedocs.io/en/latest/
# (find-pip3-links \"requests\")
# (find-importlib-links \"requests\")
# (find-sh \"curl -s https://pypi.org/pypi/{pkg}/json | jq\")

 (python-mode)
 (eepitch-python)
 (eepitch-kill)
 (eepitch-python)
import requests, pprint
r = requests.get('https://pypi.org/pypi/{pkg}/json')
d = r.json()
pprint.pprint(d['info'])
pprint.pprint(d['info']['home_page'])
")
       )
     pos-spec-list)))




;;;                       _ 
;;;  _ __   _____   _____| |
;;; | '_ \ / _ \ \ / / _ \ |
;;; | | | | (_) \ V /  __/ |
;;; |_| |_|\___/ \_(_)___|_|
;;;                         
;; «find-nov-links»  (to ".find-nov-links")
;; Skel:  (find-find-links-links-new "nov" "fname" "")
;; Tests: (find-elinks-elisp (ee-find-nov-links "FOO.epub"))
;;                              (find-nov-links "FOO.epub")
;;                              (find-nov-links)
;;
(defun find-nov-links (&optional fname &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for nov."
  (interactive (list (if (ee-nov-bufferp) buffer-file-truename)))
  (setq fname (or fname "{fname}"))
  (apply
   'find-elinks-elisp
   `((find-nov-links ,fname ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-nov-links)
     ""
     ,@(ee-find-nov-links fname)
     )
   pos-spec-list))

(defun ee-find-nov-links (&optional fname)
  (setq fname (or fname (if (ee-nov-bufferp) buffer-file-truename)))
  (setq fname (or fname "{fname}"))
  (list (ee-template0 "\
;; See: (find-epackage-links 'nov)
;;      https://depp.brause.cc/nov.el/
;; Needs: (add-to-list 'auto-mode-alist '(\"\\\\.epub\\\\'\" . nov-mode))
;;
(find-fline {(ee-S fname)})
(find-nov {(ee-S fname)})
")))

(defun find-nov (fname &rest rest)
  "Open FNAME in nov.el mode. See: (find-nov-links)
This doesn't support pos-spec lists yet."
  (find-fline fname))


;;;  _       _                  
;;; | |_ ___| | ___  __ _  __ _ 
;;; | __/ _ \ |/ _ \/ _` |/ _` |
;;; | ||  __/ |  __/ (_| | (_| |
;;;  \__\___|_|\___|\__, |\__,_|
;;;                 |___/       
;;
;; «find-telegachat-links»  (to ".find-telegachat-links")
;; Skel: (find-find-links-links-new "telegachat" "bufname" "")
;; Test: (find-telegachat-links "◀<Emacs News and Posts@emacs_posts>")
;; See:  (find-eev "eev-plinks.el" "find-telegachat")
;;
(defun find-telegachat-links (&optional bufname &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for telegachat."
  (interactive (list (buffer-name)))
  (setq bufname (or bufname "{bufname}"))
  (apply
   'find-elinks
   `((find-telegachat-links ,bufname ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-telegachat-links)
     ""
     ,@(ee-find-telegachat-links bufname)
     )
   pos-spec-list))

(defun ee-find-telegachat-links (&optional bufname msgn)
  (setq bufname (or bufname (buffer-name)))
  (setq msgn    (or msgn (ee-telega-msgn)))
  (let* ((chat        (with-current-buffer bufname telega-chatbuf--chat))
         (username    (telega-chat-username chat))
         (atusername  (if username (format "@%s" username)))
         (atusernamen (format "%s#%s" atusername msgn))
         (title       (plist-get chat :title))
         (id          (plist-get chat :id))
         (idn         (format "%s#%s" id msgn))
	 )
    `((find-telegachat ,atusername)
      (find-telegachat ,atusername ,title)
      (find-telegachat ,atusernamen)
      (find-telegachat ,atusernamen ,title)
      (find-telegachat ,id)
      (find-telegachat ,id ,title)
      (find-telegachat ,idn)
      (find-telegachat ,idn ,title)
      ""
      (find-ebuffer ,bufname)
      (setq tcbuf ,bufname)
      (setq tcchat (with-current-buffer tcbuf telega-chatbuf--chat))
      (telega-tme-internal-link-to tcchat)
      (find-eppp tcchat)
      (plist-get tcchat :chat_id)
      (plist-get tcchat :title)
      (plist-get tcchat :id)
      )))

(defun ee-telega-msgn (&optional msg)
  (setq msg (or msg (telega-msg-for-interactive)))
  (/ (plist-get msg :id) telega-msg-id-step))




;; «find-eejump-links»  (to ".find-eejump-links")
;; Skel: (find-find-links-links-new "eejump" "n sexp" "strn strsexp def call")
;; Test: (find-eejump-links)
;;
(defun find-eejump-links (&optional n sexp &rest pos-spec-list)
"Visit a temporary buffer that (sort of) explains how to use eejump.
N should be either a number or a symbol; SEXP should be a sexp."
  (interactive)
  (setq n (or n 999))
  (setq sexp (or sexp '(find-elnode "")))
  (let* ((strn    (format "%s" n))
         (strsexp (ee-S sexp))
         (call    (if (numberp n)
		      (format "M-%sj" n)
		    (format "M-x %s"n )))
         (def     (ee-wrap-eejump strn strsexp)))
    (apply
     'find-elinks-elisp
     `((find-eejump-links ,n ,sexp ,@pos-spec-list)
       (find-eejump-links 999 '(find-elnode ""))
       (find-eejump-links 'el '(find-elisp-intro))
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-eejump-links)
       ""
       ";; See:"
       (find-eev-quick-intro "7. Quick access to one-liners")
       (find-eev-quick-intro "7.3. Defining eejump targets")
       (find-eev-quick-intro "7.4. Commands with very short names")
       (find-elisp-intro "6. Defining functions")
       (find-eejump-intro "shorthand" "`M-123j'")
       (find-eejumps)
       (find-eeshortdefs)
       ""
       ,(ee-template0 "\
;; Typing `M-J' on the line below...
{strn} {strsexp}

;; ...converts it to:
{def}

;; After executing the defun above
;; you will be able to run the sexp
;;   {strsexp}
;; by typing `{call}'.
")
       )
     pos-spec-list)))



;; «find-kla-links»  (to ".find-kla-links")
;; Skel: (find-find-links-links-new "kla" "fname" "r c d lrcd")
;; Tests: (find-kla-links)
;;        (find-kla-links (ee-efile "array.el"))
;;
(defun find-kla-links (&optional fname &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks about eev-kla.el."
  (interactive)
  (setq fname (ee-expand (or fname (ee-kl-fname))))
  (let* ((r (ee-kl-r :fname fname))
         (c (ee-kl-c :fname fname))
         (d (ee-kl-d :fname fname))
         (ee-buffer-name (or ee-buffer-name "*find-kla-links*")))
    (apply
     'find-elinks-elisp
     `((find-kla-links ,fname ,@pos-spec-list)
       ;; Convention: the first sexp always regenerates the buffer.
       (find-efunction 'find-kla-links)
       ""
       ,(ee-template0 "\
;; See: (find-kla-intro \"3. The components\")
;;   fname  =>  {(ee-S fname)}
;;       c  =>  {(ee-S c)}
;;       d  =>  {(ee-S d)}
;;       r  =>  {(ee-S r)}
;;
;; See: (find-kla-intro \"2. `ee-code-c-d-pairs'\")
;;   (eek \"<down> M-2 M-e\")
;;     (find-eppp ee-code-c-d-pairs)
;;   (eek \"<down> M-3 M-e M-h M-h\")
;;     (find-fline {(ee-S fname)})
;;
;; See: (find-kla-intro \"4. The best `l-r-c-d'\")
;;   (eek \"<down> M-2 M-e\")
;;     (find-eppp (ee-kl-lrcds :fname {(ee-S fname)}))
;;                (ee-kl-lrcd  :fname {(ee-S fname)})
;;
;; Source code: (find-eev \"eev-kla.el\")
")
       )
     pos-spec-list)))



;; «find-rstdoc-links»  (to ".find-rstdoc-links")
;; Skel: (find-find-links-links-new "rstdoc" "kw" "bweb bhtml brst kil")
;; Tests: (find-rstdoc-links)
;;        (find-rstdoc-links :py)
;;
(defun find-rstdoc-links (&optional kw &rest pos-spec-list)
"Visit a temporary buffer containing hyperlinks for rstdoc."
  (interactive)
  (setq kw (or kw "{kw}"))
  (let* ((bweb   (or (ee-rstdoc-getfield0 kw :base-web)
		     "https://BASE-WEB/"
		     "{bweb}"))
         (bhtml  (or (ee-rstdoc-getfield0 kw :base-html)
		     "file:///BASE-HTML/"
		     "{bhtml}"))
         (brst   (or (ee-rstdoc-getfield0 kw :base-rst)
		     "/BASE-RST/"
		     "{brst}"))
	 (bhtml0 (replace-regexp-in-string "^file://" "" bhtml))
         (kil    (or (ee-rstdoc-getfield0 kw :kill)
		     "{kil}")))
    (let ((ee-buffer-name
	   (or ee-buffer-name
	       (format "*(find-rstdoc-links %S)*" kw))))
      (apply
       'find-elinks-elisp
       `((find-rstdoc-links ,kw ,@pos-spec-list)
	 ;; Convention: the first sexp always regenerates the buffer.
	 (find-efunction 'find-rstdoc-links)
	 ""
	 ,(ee-template0 "\
;; See: (find-rstdoc-intro \"7. `find-rstdoc-links'\")

;; <ee-rstdoc-{kw}>
;; Skel: (find-rstdoc-links {kw})
\(setq ee-rstdoc-{kw}
      '(:base      \"index\"
        :base-web  \"{bweb}\"
        :base-html \"{bhtml}\"
        :base-rst  \"{brst}\"
        :rst       \".rst\"
        :res       (\"#.*$\" \"\\\\?.*$\" \".html$\" \".txt$\" \".rst$\" \"^file://\"
                    \"^{bweb}\"
                    \"^{bhtml0}\"
                    \"^{brst}\")
        :kill      {kil}
	))

;; (find-code-rstdoc {kw})
        (code-rstdoc {kw})
")
	 )
       pos-spec-list))))


;; «find-mpv-links»  (to ".find-mpv-links")
;; Skel: (find-find-links-links-new "mpv" "" "")
;; Test: (find-mpv-links)
;; See: https://lists.gnu.org/archive/html/eev/2022-12/msg00019.html
;;
(defun find-mpv-links (&rest pos-spec-list)
"Visit a temporary buffer containing code for configuring mpv."
  (interactive)
  (apply
   'find-elinks-elisp
   `((find-mpv-links ,@pos-spec-list)
     ;; Convention: the first sexp always regenerates the buffer.
     (find-efunction 'find-mpv-links)
     ""
     ,(ee-template0 "\
;; See:  (find-evariable 'ee-mpv-video-options)
;;       (find-evardescr 'ee-mpv-video-options)
;; Idea: use commands like `M-x mf' and `M-x ms', defined below,
;;       to change, or (sort of) toggle, how eev calls mpv.
;;       To use this, copy the block below to your init file,
;;       modifying it to adjust the options and their values.

;; From: (find-mpv-links)
;; See:  http://angg.twu.net/eev-videos.html#smaller-fullscreen

(defun mf ()
  \"Make mpv use (real) full screen.\"
  (interactive)
  (setq ee-mpv-video-options '(\"--fs\" \"--osd-level=2\")))

(defun ms ()
  \"Make mpv use a \\\"smaller full screen\\\".\"
  (interactive)
  (setq ee-mpv-video-options
	'(\"--fs\" \"--osd-level=2\"
	  \"--video-margin-ratio-bottom=0.15\"
	  \"--sub-font-size=35\")))
")
     )
   pos-spec-list))





(provide 'eev-tlinks)



;; Local Variables:
;; coding:            utf-8-unix
;; no-byte-compile:   t
;; End:
