summaryrefslogtreecommitdiffstats
path: root/roles
diff options
context:
space:
mode:
authorSacha Chua <sacha@sachachua.com>2022-11-02 13:08:03 -0400
committerSacha Chua <sacha@sachachua.com>2022-11-02 13:08:03 -0400
commitc569e02d8ab5ebcbb5a44e10c14799fa097c9bc7 (patch)
tree05528005f12160fd505696cb5d89f22d30249f32 /roles
parent4696aa1fed214fe1084d7c3deecaaa289bc0a1fd (diff)
downloademacsconf-ansible-c569e02d8ab5ebcbb5a44e10c14799fa097c9bc7.tar.xz
emacsconf-ansible-c569e02d8ab5ebcbb5a44e10c14799fa097c9bc7.zip
OBS overlays, starting to get publish and edit on res
Diffstat (limited to 'roles')
-rwxr-xr-xroles/caption/templates/process-captions.py12
-rw-r--r--roles/edit/defaults/main.yml3
-rw-r--r--roles/edit/tasks/main.yaml11
-rw-r--r--roles/edit/tasks/main.yml32
-rw-r--r--roles/edit/templates/emacsconf-edit.el52
-rw-r--r--roles/obs/overlay.svg301
-rw-r--r--roles/obs/tasks/main.yml14
-rw-r--r--roles/obs/tasks/obs-setup.yml32
-rw-r--r--roles/obs/tasks/track.yml15
-rw-r--r--roles/obs/tasks/user.yml3
-rw-r--r--roles/obs/templates/mpv.conf2
-rw-r--r--roles/obs/templates/scenes.json77
-rw-r--r--roles/publish/defaults/main.yml4
-rw-r--r--roles/publish/tasks/main.yml93
-rw-r--r--roles/publish/templates/emacsconf-config.el28
-rw-r--r--roles/publish/templates/git-config8
-rw-r--r--roles/user/tasks/main.yml31
17 files changed, 610 insertions, 108 deletions
diff --git a/roles/caption/templates/process-captions.py b/roles/caption/templates/process-captions.py
index 50c62d1..223531b 100755
--- a/roles/caption/templates/process-captions.py
+++ b/roles/caption/templates/process-captions.py
@@ -95,7 +95,7 @@ def get_files_to_work_on(directory):
else:
val['base'] = os.path.join(os.path.dirname(val['video'] or val['audio']),
base_name(val['video'] or val['audio']))
- if ALWAYS or (not 'vtt' in val or (DO_SRV2 and not 'srv2' in val)):
+ if ALWAYS or (not 'vtt' in val or (DO_SRV2 and not 'srv2' in val) or (not 'txt' in val)):
if not 'audio' in val and 'video' in val:
# No audio, need to convert it
val = extract_audio(val)
@@ -142,12 +142,18 @@ def generate_captions(work):
result = clean_up_timestamps(result)
with open(new_file, 'w') as vtt:
whisper.utils.write_vtt(result['segments'], file=vtt)
- with open(work['base'] + '.txt'):
+ with open(work['base'] + '.txt') as txt:
whisper.utils.write_txt(result['segments'], file=txt)
work['vtt'] = new_file
if 'srv2' in work: del work['srv2']
return work
+def generate_text(work):
+ with open(work['base'] + '.txt') as txt:
+ for i, caption in enumerate(webvtt.read(work['vtt'])):
+ txt.write(caption.text)
+ work['text'] = work['base'] + '.txt'
+
def generate_srv2(work):
"""Generate a SRV2 file."""
log("Generating SRV2")
@@ -218,6 +224,8 @@ if len(needs_work) > 0:
# word_cuts = align_words(cuts)
# convert_cuts_to_word_timing(audio_file, word_cuts)
log("Done %s" % str(work['base']))
+ if not 'txt' in work:
+ work = generate_text(work)
needs_work = get_files_to_work_on(directory)
else:
log("No work needed.")
diff --git a/roles/edit/defaults/main.yml b/roles/edit/defaults/main.yml
index ea0fbdb..d57c511 100644
--- a/roles/edit/defaults/main.yml
+++ b/roles/edit/defaults/main.yml
@@ -5,3 +5,6 @@ emacsconf_edit_packages:
- vertico
- magit
- modus-themes
+ - hydra
+ - orderless
+ - projectile
diff --git a/roles/edit/tasks/main.yaml b/roles/edit/tasks/main.yaml
deleted file mode 100644
index f77535f..0000000
--- a/roles/edit/tasks/main.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
----
-- name: Set up Emacs configuration for interactive editing
- template:
- src: emacsconf-edit.el
- dest: "{{ emacs_config_dir }}/emacsconf-edit.el"
-- name: Check if Emacs base configuration already exists
- lineinfile:
- dest: "{{ emacs_config_dir }}/init.el"
- state: present
- regexp: "emacsconf-edit"
- line: "(load-file \"emacsconf-edit.el\")"
diff --git a/roles/edit/tasks/main.yml b/roles/edit/tasks/main.yml
new file mode 100644
index 0000000..f864b23
--- /dev/null
+++ b/roles/edit/tasks/main.yml
@@ -0,0 +1,32 @@
+---
+- name: Check if Emacs is already set up for publishing
+ stat:
+ path: "{{ emacs_config_dir }}/emacsconf-config.el"
+ register: publish_config
+- name: Set up for publishing
+ include_role:
+ name: publish
+ when: not publish_config.stat.exists
+- name: Install Emacs packages
+ shell: |
+ emacs --batch --exec "(progn (require 'package)
+ (let ((packages (seq-remove #'package-installed-p '({% for package in emacsconf_edit_packages %}{{ package }} {% endfor %}))))
+ (when packages
+ (package-refresh-contents)
+ (mapc #'package-install packages))))"
+
+- name: Set up Emacs configuration for interactive editing
+ template:
+ src: emacsconf-edit.el
+ dest: "{{ emacs_config_dir }}/emacsconf-edit.el"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+- name: Check if Emacs base configuration already exists
+ lineinfile:
+ dest: "{{ emacs_config_dir }}/init.el"
+ state: present
+ regexp: "emacsconf-edit"
+ line: "(load-file \"{{ emacs_config_dir }}/emacsconf-edit.el\")"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+ create: yes
diff --git a/roles/edit/templates/emacsconf-edit.el b/roles/edit/templates/emacsconf-edit.el
index 2e360c7..481892b 100644
--- a/roles/edit/templates/emacsconf-edit.el
+++ b/roles/edit/templates/emacsconf-edit.el
@@ -1,7 +1,10 @@
;; {{ ansible_managed }}
-(let ((packages '({% for package in emacsconf_edit_packages %}{{ package }}{% endfor %})))
- (mapc (lambda (package) (unless (package-installed-p package) (package-install package))) packages))
+(progn (require 'package)
+ (let ((packages (seq-remove #'package-installed-p '({% for package in emacsconf_edit_packages %}{{ package }} {% endfor %}))))
+ (when packages
+ (package-refresh-contents)
+ (mapc #'package-install packages))))
;; Configuration
(vertico-mode)
(show-paren-mode)
@@ -19,16 +22,45 @@
(split-window-horizontally)
(magit-status "{{ emacsconf_edit_wiki_dir }}")
(global-auto-revert-mode 1)
-(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
-(projectile-mode +1)
-(setq projectile-completion-system 'default)
-(setq projectile-enable-caching t)
-(setq projectile-indexing-method 'alien)
-(add-to-list 'projectile-globally-ignored-files "node_modules")
-(add-to-list 'projectile-globally-ignored-files ".cache")
-(add-to-list 'projectile-globally-ignored-files "_cache")
+(with-eval-after-load 'projectile
+ (projectile-mode +1)
+ (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
+ (setq projectile-completion-system 'default)
+ (setq projectile-enable-caching t)
+ (setq projectile-indexing-method 'alien)
+ (add-to-list 'projectile-globally-ignored-files "node_modules")
+ (add-to-list 'projectile-globally-ignored-files ".cache")
+ (add-to-list 'projectile-globally-ignored-files "_cache"))
(setq completion-styles '(orderless))
(setq completion-category-defaults nil)
(setq completion-category-overrides '((file (styles orderless))))
+
+(defhydra hydra-emacsconf ()
+ ("e" embark-act "embark")
+ ("t" emacsconf-go-to-talk "talk")
+ ("c"
+ (find-file emacsconf-org-file) "conf.org")
+ ("C"
+ (let ((default-directory (file-name-directory emacsconf-org-file)))
+ (call-interactively #'projectile-find-file))
+ "org dir")
+ ("w"
+ (let ((default-directory emacsconf-directory))
+ (call-interactively #'projectile-find-file))
+ "wiki")
+ ("o" (find-file (expand-file-name (concat emacsconf-year "/organizers-notebook/index.org") emacsconf-directory))
+ "org notes")
+ ("a" (let ((default-directory emacsconf-ansible-directory))
+ (call-interactively #'projectile-find-file))
+ "ansible")
+ ("i" (switch-to-buffer (erc-get-buffer "#emacsconf-org")))
+ ("l" (let ((default-directory "{{ emacsconf_el_dir }}"))
+ (call-interactively #'projectile-find-file))
+ "lisp")
+ ("b" emacsconf-backstage-dired "backstage")
+ ("u" emacsconf-upload-dired "upload"))
+(global-set-key (kbd "C-c e") #'hydra-emacsconf/body)
+
(require 'ox-md)
+(server-start)
diff --git a/roles/obs/overlay.svg b/roles/obs/overlay.svg
new file mode 100644
index 0000000..73a7e6f
--- /dev/null
+++ b/roles/obs/overlay.svg
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="1280"
+ height="720"
+ viewBox="0 0 338.66667 190.5"
+ version="1.1"
+ id="svg2360"
+ inkscape:version="1.2 (1:1.2.1+202207142221+cd75a1ee6d)"
+ sodipodi:docname="overlay.svg"
+ xml:space="preserve"
+ inkscape:export-filename="video.svg"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"><defs
+ id="defs2354" /><sodipodi:namedview
+ id="base"
+ pagecolor="#000000"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.62998576"
+ inkscape:cx="543.66308"
+ inkscape:cy="369.05596"
+ inkscape:document-units="in"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ showgrid="false"
+ units="in"
+ inkscape:window-width="1366"
+ inkscape:window-height="709"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:showpageshadow="0"
+ inkscape:pagecheckerboard="0"
+ inkscape:deskcolor="#d1d1d1" /><metadata
+ id="metadata2357"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"><image
+ width="28.984987"
+ height="28.984987"
+ preserveAspectRatio="none"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAMAAABrrFhUAAAABGdBTUEAALGPC/xhBQAAAAFzUkdC
+AK7OHOkAAAMAUExURUxpcVhRpFhSpohOtnVRsZdMun1Qs1lVqZxMvHpQsoFPtJJNuWlTrVlUp3dQ
+sYRPtWZUrHNRsHFSr1tVqV5VqmJUq3tXtW5Rrm1SrlxSp1lSpW1SrGJTq2BRp29Tr2pQq4ViuVtS
+pVlRol1Spl5TqnJPrVlUqFxSp3ZPrmdSrFpTpnNRr2dPppaRxFxTqXtOr3BRrnJRr1pSpoFOsKFK
+vJNLtXFrtYllu15Qo3pPr4dMsqxKwMvI469Jwbat2HJRrqpKv3p1uurp85VLto6HxKtKv9vZ68rI
+44ZMsqxKv8vI5O3r9WZgr/Hr941OtdfW6/Px+Kuo093b0dHEzf///1lQn1lQoFpQn1pQoFpRn11Q
+oahKvrNJwcBIxZ9LvadKvrVIwo9Nt2BPo6JLvaRLvmdPpYtNtrxIxK5JwFhQomRPpKpKv1tQoL5H
+xLpIw8JMxLhIw8dXw2xPp3BOqcRQxF5TocVUw8phwclewtFxv9uMvFpPoNeAvXVOqv7+/9mGvN2R
+u+ist89swMhbwvf2+lhPoKxKv3hOrMxlwYJNr+OfueWluN+WutV8vvr5/P38/uqxt21ZpP7lsHlx
+sodMsuGbus1owZNLtrFJwWRWonFprfLx+H1NrvDBtKeizWVcpey2turn82BXo51Lue27tdN4vtJ1
+v5uWxvPItNPR5u/s9mpiqfvdsdrY6nNipL252rSv1JhMt+Xi8PfUspCKv+Dd7qCbyYuFvK2p0c/M
+48PA3Xxnpa5cuoZzpfXOs353tY1Yr35Vq4Z/uri115Ntq4NdqoplqnhYqIJ8uMjF4Kdps7ZruJON
+wdzO6aaczLtav5disJR9p6mIzKN/rMGMs8uVtMem2550radsxZ9Xt/bksMV3urGTrOzgsLKEsJdX
+uLx6tr+irsy44LdQwaBis5t7xLSh1LJytbqZrZyOp6pRu9zBrs2isdbD5ruU1L51zs6Autmq4siF
+t960tODbsN+otdems/np6OC55ePJru7S6cy0seizy9aX1od9r/ziv2qV4xcAAABldFJOUwD+/v7+
+/v79/v7+/v3+/v7+/v39/v0MEv607CBP/v3+BdX34mD+eZDsLci29v08atp+n9ZUOf7+9Zemic+y
+I8vt/Sx5/tJJs7tqkLT9oObbaNf27f/////////////+///////+N+r7SgAAIABJREFUeNrsXEtP
+G1kWbpsY/BiDDATahu7wJtBJpifdIZPpTE9nJj3RRJFmY5dJkQAuUw52SJq2QzbIWeFY3oSFLYGM
+hYVZIEAWD/HeRAobI9GMlMVo1tPqLOc3TN16V7nKdcsPTCK+FZSLkr9zz/nO497is8/OcY5znOMc
+5zjHOc5xjlNCY09zR1dXt9Vq7e1tt9na21tbW3ut3V0dzT2Nnzbzhmsd3dZeWxUPXgcPIa+3rb33
+ete1hk9w1Zu7e21ec5UYAgMwQLy23u7mT8cbmjqsNi8CmEEagMKDq7fv/f0T8Prr7RxJbZYBEEnu
+E9GdgwU7wNw/73//Eft9R68mJPBtMX9zNvmH0ZP9KTsPr9L3/vpJsJeKAY3o8/jSwYpdApsfmw1a
+mnslo9ubwwFSW2sLdlm8St//eHJDU7dNTtw0MgoQ31l+Y1fA1O2PQxObW70heW3n6aCZtlJya23F
+Doft+y1n3fc7WrMCW5TkGR3QkusfnVdeej7m7p3lrNDYZZPPbZwJNFqtBghk8vhgxa4aU7e/P9v0
+ibV1QICI+ml7fnhzJk3Q0GVTKG94hU5mfcFeCM6eCVq6bDnSuwCp3bUVe8GYunemsuK1VkF605bC
+8cVYuX9m6PdYRQWeVrLF00T3tl/Zi4j02agLGq5ntTjZBkDq7x7M2YuN6dtnIA6u2ZCsLjdLAzT1
+mcwdAn198fhqksBDkS4kkw/6+vruZO4e78yvry1vwtYGW83lTn1Wr0SXi+QogGUEUtQl9K9m5vch
+rJBGrWUdnDS3IRJdrjgCQhAjAI2EDyV3lNNFBvlj+ZygweqVHHR4c5LTKPUIvJtSB0oGOHBgn98q
+kxL02ELi+l56zGVWGoKIjVRXx1jp4ZpSb4D+7ssvv+4pB/8uHtGQNqvHy98AdXV19aybTCiVjO9q
+AX5/+u7fK+x5mYmvRiLERVlC0gAhPv36eu6DPQUDrAP+FstXDaft/hJNnkYjLXAwHkCLAEW/niej
+80p5wELhdMOgo82hAloIESR1hKZfX88Zsn9TqSm4YLFcALh8itmgG1HDX0kjmbsY9hfr+7mrh4qJ
+8CZJv5rAH06r87Oq4w9VCJGeAthfvPgFdyV5oFwL/VbN4tapDMwaWh2qoYFoFKmGSTPGGxsswfTN
+7wnmBhqnIYVNNkce0FBRYNZIaKdX2qHie3Bjgw8GDpXfNJ1N/nSSyB4Xa0jpM4tNkMrsbcK2hCeA
+OItSW6BHVv5DCIKotoqWUX7uT1czS2vbaoYmO9Uc/Uqj8XJPWfgjWsrDQyr504nv4kUi4uO782vL
+6qdlW5gBEKfRiVy5UcLev01J5MxqvACh6D+4c3d+bX8h31HZWwcaZvn7nQ5H6SzQ06ac5lRYgFjy
+nfWD5YXCxmTTKeJRvk5jTU2NIYCSDy6VBXpsWmkXR3KPw0Jer6D4SUYJ4kfpleLMB7fpp46hnOmv
+lEQHmtq5Da1cpS4irQ6OVPzd0t4B/LQLEutSS1IKC1D8IdpdLtWnVqNvd6+e7B0e7G+vvLGXBlHJ
+8LrSVPz6T3amJZx41fdljucPj9KbJaMsGQFiXC7yqLDFKt/P0hJQ13d172h7zn662JKT2K+L2xd0
+5+rnqqoe3D1Mv7GXAel+2Rz7VVHHX7mmvvEib/io2SSNy2fZsVtFnH7LH+2Z2Erby4elXHUGWrRB
+YZNNbuNj4mSujPSlUyAH7EbREwANphx6t2AvK/+HCrXmleKMB6xV0gaYOHxVTvrTO8rV9l+KIoAy
+5ztT+2Vd/oW3EO3GZBGEsMcrfb5zYrmc9Kf2UlANV+Ey0GDLPt8ZghvXlpD++ipsy1mwDJATYG32
+3udu2di/2b+aUjF0KLAeavaKtv6YANgsz9Iv7+3Ks3diGFrkaqCxTWbks3Q6fOcWNreXl48O1tb3
+5pd23+Z0fF9Ep9frXeExcRAU0hZZQ7zjneYqs5bpdUtW/k2vbP/y33//7/3u23iyX818MainYcJF
+hvlTATNAufnWavEje3P/8GT3t5s1BCoqKrDcbNGwx2SKgQEgg/AgC72PHxZhvf5GIRlAGkWUwFcL
+++tLGdq5cYp+RSA3f9xELbaHDXl8kAfTJHdrhPj9x3wzwXXZIXdxJGAqfXg1KtQ0n5GgX+PPzd+n
+I+kT1FxMwLvcfARFjvFdniWQ/IB3p2CPT68fx9kYRzsrjQYqdJ0+3KcU+y6SPIkwXe8I+LtdbB00
+6HaD2/IbEebYBD0uaOH35zMTgog2gKF2TQ6/R4OxigQucndAVUdd8o8IMMgGAG2RP+dVAsg5ABJy
+RPMW+fSHdxZLrVDjyKE+AUwh5hNO1q2ZtR6h/iYoNMAIIwI64mfyvm/zmALaZPbAQGdgzmsMsLK2
+lbxkIQ90CLhW0tIvF/oYFfN62uETNHcSlOIHhgRwM3/IGMT9Y0seTWCuPaA19Wq/v0v4PUbyr67+
+nP9QIyX9HrkYSNCSN6gnVT/oZngNDY2gNFOBAWYYzwG/ULf+I+8aUHoPrE/tTt4yNb/3WcjjLIYL
+/KcaAH+Px4PLGMBEi57bTZrIR5MH2KBvmRngI8w3AGWEH9Smwu5Q7j2wI3XOz0yvfeRpHoOhWpDW
+KP5GofpjgQAdKHpW8yhmLnapB5iE5x94ymGRSY7YwAB769+K4QC8nqhPzRQ8zRbxKMXfcEnwXD/J
+X6ALkwkQ+BGSygwteiMjVJBgi4A7AJvvHDGO/wCnJYvkXaQBfmgsQg3Eb4r34Pkf8ZIeTp7nqRZ1
+LKg/gAvXP0zpXoRNZqSW0ZWfj/B4QDXGPcYZeU1jhKelEdIglA2+K9wBBLOxum3o8BckfV+nobqT
+KWGdeGenT3Kor6OFD7gFukhHfYL1j0BsZiZCagbCwD/zdHR0dCiG0b+Thh2hnYKAKhfoVt4Gr+qb
+gnzVMSlf4HSC4JcSf5zW/UFK9vRA80YiTuHXEQPF/T7RpfDr10xgDKhwgQaZkxDC0RhkOfjhC/mi
+nhQ/DyrxCSN8lD+PBWOeCJ6LvBxio6OMDVQkgi6ZLsgsnA2vQxngZu0luZoyAPi7XLygdeLhIPB6
+REcJ36CEcRBVCIPAoGwAXwvItcFe4WwYajA8XVtby4a574Khkyf2AZK/i1taJAJCHxgkMEgKX7gw
+9gBYbASYYMiFXy64CxC8+03clITZGTLUWpikh4ODbJWcBTBA3+XhtDxASr8OXAgQdbw+WCh7Cngg
+gBPPxL4tuA0MmYWzwSiEEL63WJjCt5o8z9bJ0zrCAh5eGohR2kfFBOZzFoM9B8c3kHuhOf61S4g+
+88ocFXqnXA+lLRdoD5gkj/PV8KtAFPfx3S1Gap/b7yjc8yU9Ae7gzHXlI6/cl96ahnABRskMRtD4
+Mh6AZbe/AVL5N9CS0CcANR9tIXIgGAFXmbUwZ/6WFHdIp9hzTLiRa/tRo8tVyTHFwgkiFJwxQvoW
+/aVhTyAI0xV3INx/fIIxgbIFVla5Qriyml53AyF/JlbkcB2t/n4qDZaEPoKMwchgK//1BpiDn8eK
+UbAgcZLF4zKZTDU89RscnMkZ+oFIglfn+QIBNA8LQMhgo/A1R3kLeMF/wiA/PVZUwrlM1p/XEPxN
+bHHvAuKny0EfWxweHh+OOWk1W3zy5Mn4jHoTBJQbgi5zFcw7Tsx2IXlgKqOYDafXQUc06ePcGyc8
+wIXxxvdud0xM3xkZebrhB1/cuThOIkbxf/SMxBBlgX4aEAaYVB4L9IpPQyC5SyLSQFHlU+7puAMz
+VlQY2KrHFwxyGoh63G4XKl7+2Ozs7KNRHKwcYP/8+fNHY+D60LNnj0l4GO5oYmNxI4IqG0IxBhqV
+34UXFcWkgVaVNwunD42SvR8Wm0kgwqSIhcNgbTGC/vDw8AzxYwTQJ9z+GbCG/zGNn8YnKcrBX38C
++DXcr+QN/kaVESBjAK341GAK4v2uhfdE7U9V935jGOWFv7Dk9w8QfT3BNADoD48PEd87Adg/Ibye
+uNwfAdwBXrzwUfxfMIj09yvYQCkGWuEMYOa96UtfOoGYk27/xxWgBv06HR3xY6D2EUQ/sjg6OjtL
+rDsO6I+PL4KFI9k/ezwLmEUAdYCXL0kDYP/6+eeXFF7g/QomUIiBBg2cAXj82fd8ozCt0S9kVZTQ
+EaBdwMQOO8Eg1EcE/2si9Gf/T9u1BkV1nuGBUYJElFBJaacLbVLaTGfsn8Y6TScznWk7Y/7kl+xN
+mcrqclkWgV2PIBdBYLjJxQWCAYFF7gqsEu8uS0BZqBIFRGJVVFCigNpY7xoz0+9y9uw5Z885+22E
+99duos4+z3nv7/t9ZzP4sd3I8Rnh796LzD4+A+IyQOjbtyclJY0o4Pe+JKfcUiqlKTD+2k0h6O2R
+BgD8P3Ouxx8ibZAbAf536VJHF9ldSHtGw7/y4jLk8iZg+xuh5av3JibG5OMUJjI6ImIjbePzCGtO
+Tk4f+tqTgiQHSo9SKU2Bm1zoF/yrHERufPBm8K9iE/QNSZts57kKfe1S3AUw5rPzvu68mBjw5A1x
+GzdtwEmP2pH7AEdvMChoUNoRABVA7tGjryPJWBALDHJ1YdP8fHetmk/BOnetEP93CO4EkjP4V3EI
+6ugimxJVOKbXm31Zwa8JdjWh+8/P4OQ4/Keq1PZAwLfosNdTgASRMOL4I/0jwCNsS0jYVMtj4CN3
+lTBZJhjrwM+zEOpuKRkFaM8RRP8tWpqKbp08Hzi/WherVQqJbmiIcnyeqaIFsOAwgb4c6Bi3QQoq
+uXagk6qJf+dyBChW4kg4wC9zmeUHr31IOC05g8Z8qP0Trt4Qlwes3lBoJILPFVM2LYCDfvr5Q5eA
+KUhIqOUy8HdJF8BlwD9WsjMgdOpXHbjkEuHpx64T4Vo6G9TExcR0CwQtaeQKWmZ2QIEU0ApAAbeA
+GEiCDNxRcxhY574bSocCfy/PD8MCBkLDlhwinJ0eOwoXvrW1uvDCvC0GD/ArOKI/34oo2DFMm4Ud
+egSnEtRyooGEE/h5rPMksFdsLOkBULVMJuPNuipIN4mPnVCpt8Rt4dd1GXsL9dDzV3ZXqqXBY7EP
+t7a2Dtvh/6O9QgEKC5iBbk481IrPB34l1QgTOeUergxaDoU//jhDukv61eq4vDyGAE3UXpDtFoK0
+B/xq9TzIeHCso4aGNGLokVDVFPNZOZwNPSLDwDw3IfjY424g3SIS9ggIf3BwCKeRow/zWUl8mmT/
+f3GyowE0NCVuzUuTbwBpX7xamQ/TvRzo1/oLqrKr+hWkMow8IsPAPDcl+sTTfriXVFaoCcD4Q0K5
+az+w/3mYdIa+v40Cj33Tl1p5DKh61PLNoNq5A5J+AD8lBaR72qrsbODlTKQEnIcukVYCwMBVblIo
+Xg584HYe5GoGMhp/YCArImoQ/pU6MzEFBy82NiUmFsqjoqNB8WNIRMHLAOAnJxuVylEAf0dr6yh2
+eSaT3g0BdhwUIANQB/pZBKiNtZ+LVkKx0sMQ5qwA2wMgAiD+QD173xH1f0GO03GWlIJ9d+98CWvg
+DGjzoCpC6UxKcgHM90Gca21paUEEDD7KzHw0IE0Adb2VxcCImqkLDMDEEhPf92g1OFb6PnyZQwEC
+2aEQ4ccbvzWnSfeJ9tU38mOfbqgaOj47gF9Skm4H2AYyMzNTU1PdMGBvdTAAjKCfiR9R0fHR0VsT
+10jlgZ5eg6Sm8b/H8QEGuPnlaP7U3CanwCwXivnqYQA//R74SEH0qVlZqdXSDIy2MAz0Mf9QU0Q8
+IuAzyTxQmgDX2kiGn39wGnfAHxbmHPrqbn1Lagi5h01CUZ8anZoaUMNHC8ADKS4edOcGsBVUJTPP
+X1kZQRPwV4+CgDsCwjXBAH+oXjAr1OnpEWDHScKFkvWltzuU2r5+kaRnEIIH8sWAu0hA2c8PD8/Y
+nXmUNiGCZuBTj9YCCK5D1KsVjnEfhwdjVCSz/Kfzu0uaF+SerUrBiusKywTBAymy4K8D41esEiyw
+dambIeCfHkVBOcGFmDT8Jct8fFjrIGj8H6Vk1l1DjpPeEVP2shWUNf3Dw0MukG4C8EAuo4A4XrR7
+N/hcTcKA/k5CAk3A30QqAbnbrQjJm7DUK+CNRn5OZ2iA4793cbln8PX1zQhvbCPdLSu7XWOCoc8l
+96EuFwHUEwjz+G4sExQBAwZQF2IV2CoSB8XOB7Aug5McFYaiG538/Bgr0EACIvFf0Uf6LoVRUf/9
+S0JnUPYwtaUkXcDXWcfHrSgTsuxCAhi4QkBAhpOArWs8K4WYRqn0sPg9jN/PufFhBPgdPiBNqw6H
+LlGbb27rIjt0XPY6Kx3YwNC9qQHBImh8l0MmCNxAxvZtjBP42IM0wLEk7+/vzSRBallQQIBLMygM
+3+jEXvvXANThugyt4/gCbIWn7Y1UdBwnPHZ2oUJhTQV+f1wI2uweLEAJCAgwAAISJAn4PWn9D+EH
+gBqIt8iBVqC4GzDI+pcu9cUp0VLUANRv3pwWLpdXkF2XtvPcRBb0+0J+brIBCqTgGQEB+hEnAZ95
+kAe5iiwoCOFfvpynA2EQvx9/8aUQEBBFH+2rTMOrMbgqq6gn0oMXb4DfFygE08aam5sxB7MKAgau
+OgkQzoT+QIZfyeAP5jVBlNoVeA1Yk++3jPEEcO2bGX0Z4RSs0WzuqKmBt4w31tS7Dws7AQWCRk49
+aUbS0GAlIQCHAQkCCG+K9KYNANQAwSLxcGUUKwPSRPlG6swV37WdPHTu1LGD+3h1QS5BnbBz/YEK
+hWps4vkkrQgqLNYndXV1gIEx+r9ax2/eHKgWjQPdDAGfvg0BMkYBQkLShFeg0f6nH7447Ou2w6e+
+Ik2DpQYJ00DXm5+YHOCRmGab6+oe2DBQywQMiUXFA2IE6OelCfiQkABGAUJChE/4rUAERNV8c/bA
+ArxMw+kL2gHaSRVPqimVCuN/tgflBEVFV8SSQXX3QhFAK4CICYRF3br07YVFuF/mRW/dE5WQwLT4
+AYyHUAWKvrCK1gMZGySKAcLbQpWMAgQKLsJTFfUXFu1WqRfCBAAGbDAg0gRcFiVAKdfVVlYWfv42
+BAAVoBUgFNeAmlDnsY+OtlO56xdTSo+LMDDZTBMAGagWJ0BiNvJL9l0B/t7i94PSfdBQ5AGUofAU
+kE+YHr5CpmtxL9bJffFDo0qEgOlmlgpY3oYAuZfbS6CVsoDQADrhwfh9fNbWH1tM7GVdJ0+MjVkg
+1sa56ekxis/AghHAvgic4J1Z+iWwCPa79LBsEdHvP3TUzCC1vOoEct/MI2C8uZkhoFj/0wngNMEJ
+GNAA/GtvL6LdHzy9uoMNlHpVjuQ+jwALi4Cbip9EwIeuDTA3r86DBCz77sKiGX7pgfoKarKheZKl
+8LZyWqw8BhgvWFRsEiVA7pYA/3dI3obg3Iu6uH/xjP7fsNEzCbKfdlb6M1lefg1K+RyPAGqWJoCX
+BnhGgJcHLwYG8I8fXCR3//oNHcv1DQB/ex0DM3zuGi1j/DigH3sOCbhpUrizAJHp4G+ECJCwAfPJ
+RblMMPfc6prioiI6wVc0A/y97Sxbv0GL2SUZBOmw1cpKAUyDo6ODJqGduT+JlsPe7l8b5kj4ji+G
+59v3+s0g6nYzajxZ197bO8u29RtPnwL8cyoBAjgN9Kn0Ejge6jG5ErBOtCHiTagBqqMLb/ulp9o6
+HjmnfrjTq6qerWuf5UT9uadA5lRuCBjMTMcEZBf0uxDwiWhLjNAEvl7wpOfYyx9LKPizH2MdNk3s
+emDBlb+ej5WyWiiVGwLsmTQBcDpm5G+N/kW0KSoX3xP1kgFBbUDzAl8lWdZVX6MwzXCGIJd37dnz
+3Nn6UFlxFsgV29ycjRLETz1mFKCqIHkkjUeA8Kbcb6XCoDoId8JkStXqfQur+D/usDu73noLduLP
+AAEN1Q78lvud5eXT/NTnfnln55FXNiECBlkKUMAMyBkChG+Y+6PrNgCjAF4YP6gDKxbyHrWDZ89Q
+QwVVM0oFde86nP7rp7JwRwdoQMNzhwJQIPsFqQ/X7i03AP7OI0d6bQIe4B4ggFGAlJyrvL3pNRJL
+ct5CHkC+ilaA5RcXzvfv/9/3cA1E0TcDzH6wpeQR+OFDWcXFEywfQKt6JyLgFYeAH8qhAgAC7lOu
+BDzmKEAOb0tK877UcNRLwAP60wrw5wW7SDX35X/wqrfRiKbA9pL06xB3VjG7nUFjHcMEXGPjNzvw
+97bbXGPgI44CJN3hKoBBejwe680fhDkU4B8LZP37Tl+KiIjHS81oCQha7Xlk/AMTly0uBFgxAZz6
+x0YbQG97+5wrAVMcBUjiLQp+5G5BAr7wiL0XGRsECVh+eEGcf+ntS1p5RnzEFrzqnlzQI7L9aJud
+tjnUHTHASX5tjuffXicwNzvPUYDtkdyTE/9n7tpim8jOcB5AQkLipQKE4KFSUXnoUmi3F9o+tFW7
+r33CdjIxuYwzYNlD4h3nRuJJwhI5GHLBSsA2G0iIydKwbYIhXBM3Fwgpzu4mCEiIsgogYFMBJSzV
+rlZbrdQ5Z87MnLnaHnur/G8sQuvvm//855z//P/3v5tWiYwQAn+Vleh3+cqj0n1FLqu3ky/dGKs6
+DPaAYCIRVL77dJ89e+qecNG59LeXcXk2+JKA/5T6WSRv0teLOUAlk5tSufQ2g8eg9X/Mwr2n7vqI
+1Rou3bevUyqFoihuBdALvb4FmMUYun8fHQW/AgScFU88EVUKSMD/tVbV4BLuADFF68xv0i0Vtq5f
+/+fMo3/bN8ugHcLBEcBAAoj5Q8OwHNAW6W3x+SIoCB6BNQH0MUDAqa48PYu85PF392utn8iCiP/9
+F4SidUivWHiDvnTGZxlnvOruPAzbi+yUlYoWBvhiwMD7h6rn+VKgqRbfYxAKbjVzBPAJnVeAAHkW
+vH8I94OuJwD/q37tCBKZEiMgqXAAYkN6pbLZUJDc3ddu9YM+UBbrBBjlCBjmCYjMzMA7wBAgYA69
+9HSf7cbTPvGXXNx7glMQicf79d9EJ6bgEWDMpuwdeydt8ZBPMg3/Z5a9VmuUw293YQRQ04eqJ+XF
+YHmL3DmgB53n4/EI9hIYvwTtvxVGd2B5HqSCYQiN3rmd6ZbLj2f40NP4nd/ZYbVSjiKpJYps4g5A
+5CTf6DmRuE2I1/h+eUwTwb7kCbh0NyX8NoPmQf1y+a2a+Nszi3913zx1+50B2LAl9kUwpWXl88LP
+mznwUe+SLhJh/f8D2RM1/ODc4uK9obxk+GnKC7W29MW2NQvlejJLfZx5nu92+/MVIl+OPWXllSz6
+fR9wBLREhMYPrBUofu9ul8DA0F+RvVLCp+8dOXL8eHPz26AhfiYW5pZguKSDNGgg14qCNzL6/AM9
+lqYCpIKAmRMQIGRqToCCQB74XE3zWyGuRV4d6+4+FkdOEDmFCPhc6fuLPP6GmvqgPn4iBjrR7eGw
+0/mekXpClhV0PxzX0UIp3iP2vnO7AUdAgr/G1zQ0NDegssdFkBLo/k8ErYN/neJNGfdvcfg5+A01
+NfULhAZ+SABZ6PFA/BwBv0vWOCmzjzMJAKKSJK5gUBzygl7o8Auv+BMnZybQHaZGKgSnvzoIGYiL
+DgHgC+UwUoh4IOKv903o4KcLJPxOo+7pzdZsLoCBCrUcSpOHOwgGrDqNcI9BKwAioOLoQcDAsbiY
+5rr75NXnqn0/eFzC70to4wcCFMICcPoN5aSUQWDE/Amg7ZyGHgztBwR4SOkqMD/8TApet2EvBFoC
+DwADB4/1G1fFDwnwQQpkShs/4cTwv5ekfV5u5hMgrYNagjguDyBgv1dwAdd01eEThynRn2/V14hB
+cOjoUY6CRVsyAoTP39LSO6WJ38oi/BwBfrexsKTiJHDStAM0jigkYWh4BiDsgIBSl0AA6Io68cGM
+hIfAtsGh+18/mEvWIBYRPz93AX6mid+6F8Pv/mUSITFZFLhg+vvLlZOsZMgdjnrhauQICImdUY8A
+AScSuSm3RNoi/YpCwMfw80P8Bya11SNiYgD0u/+QRE5sE14Rn2c2BdY6rnhEL3ECXRBwGmCj0U6b
+SMBYdRXHwGjKBMQfHD165L4sLASR+3P3/4SOekZUwu9OJjS/FX8LGTHrANuV9cJAFyZsj6n6wolh
+zgWGCX4jCCbeLMwZdoPdOwLtuKyLYAJ9/gNTpM4FICThz08mLLoR74q4ZhL/TWUvUYwnIKzujK8d
+Gx2j+Z0wstDCufIC1v2h7BEdAuA5a26Q5c8mp2D6Z6ZC7wIUkPDnJxUT24Rlw03uAX+vQBJRjhJH
+B6ylCjkBA3a/jACKdcnOAs96QV7Id0vaEmqam2UdkvcBeGANimLQ4MToZIW+egwl4U8+amEr9h5k
+Lg3YioTk1ziAGnQUMNAECQgX4/JwjrKy8hgmDmCb+ggyIN4L52B/YDOGFXbMgbbBmsdGl1+1eE5U
+wF+YXFBw4w9EF6gwtwleQ4KBDkhAIegVqC0GBERJ2X0QXAce4QQcgA2yCeGr1vA9kpK7V/B/Bq2j
+b9PCb2X8CH9JCuLK0howN03owx5xvgk/BgC8KNvYUKgTl4nwQj2w8kpsFczADukW4ZH4FmyS5ViQ
+FsFb/r9w2/6SEXwN/ahOHn9hKsNGtohvwidNETDLa75TIgGUljJmAChjcS7AYrXcCdAinxBXQD3f
+Jl0jrYE5gB2eem4bwNeSELN0QvyFqUhq/vBHQl2MKQJa51dDnUgXLw3N/U9Jrfswu593AQb/5WPP
+ZqQigds+Hm29BDbyBp55fL7HtCZ8gt0bCgVIDfwWCxMDQwZSGjWyTSCgywwBnwoyaasRATHNhADt
+hww49AVSIm8g1vo3eNnTAjjztSxFNL9+4CnsiyuNkWr8XBxiOkKpCcxvFgjINZMMfc0RAHVxGbgG
+CtG8A7WyoZP7sYUuA4GcCbAp+lomZJUft5eWEqieQvEP6SiADxsinIwaP4xLKQ5c2iT8EzOVQA85
+ArxIKJwjQBQJlp4l0BAAgg2wtZL3To4FlRQEEwsLiWAKSV82A1NhAAAKH0lEQVRFb3Spx0lqwLdY
+dqYqri78gwETBAClQNQvRTMsQytuxGTIXuQp9CqFkpqmq6urhhkDpSBj9Lm5LIQP5QE4i2nhp1Me
+tyR0Dmw3kQUFBGhpCaDP7+BVIlk5A2wlkIupqqYM1ZJ0wQNziJ8fZr8oNX5LyvL6Ymqwq82UBzRp
+v7BCnVi7HTLgpGUMPAV6QRwF84aSUUayYuR+6fOD239Ajd/ys9THbAmZsT4zMSBQq09ASZgXSvV4
+8UsRVV5eyUtE5po0qxf7/OD2H1LBt7yTxrgt4Y1s0MQuwNr0HtnBewCvlOvxNOHXQm8ZUAkFFNTi
+KnmjMxOkCio9Nj88PD9Wqzj5sAi+kPwKqfBb0hm9KYzZyUv/Veiy7kBweAMAcqGAAS9+LyShTCxH
+wTQmoAN1IqtGbUotSV4k7gUlP/gxovfzyY+9KvxUWpOWfm4+DG63GDAAtaK5H+mmZap5sT08BR3S
+mhaEQmfk+Kd5lcDK8qeU/N2vCIPPXX7VcSi92asbUU9obvpHgcYRAwaIKGQgrBCOJN1AKbk8SotI
+56FqKjAvTsALqCAMlTIL5af+EO/9KPfjVk2nodKcviu4wEj6G0HjoEo8O1roCDHQBYi9fu5erNJO
+JDry7SUByd2JSiSce+gQvjN4IXgOPTj0yEmk7NLnd/oDKvLTHcMuzloykxgekE1SZQr42WgBPgzQ
+LlJT81rm6gxSTuYMUwrOK4bgy5CyuuLGaxfgO/0x1Ukk/RnkQslYhZnquDNXse9fAGcD5ue72SQD
+I/BPXS6IZyMxQN6iAnhw6FNqkHYK8N0hImMHwEZunjSVG78uDpUIoOmI+W5HrQYDJMu61ByQZUg9
+vbw8ip/3RfT74euCYohMyA+GSkWb1BtxOmcAadaIEAZMVci0DSAKYigvwrkAo7oWuuDghCilcoTo
+HkFCHkuZWAM8+P1Aar40oPYhgmG9WtPrak1NYBfb6a+aqxGquz4OzgQFDsEF+PmQsm/mLIL66XZV
+VHQVIV+P4Zudq5QHDw49RdqJD03baQY/Ji9oukrq4pUuyxqHyIBXkRqoRVcjj0d+LoDcAF3RPftC
+8r/YC8GXStM2UoFvIU1OH5eeipMPEdFdCddfDwsMoBGxEgP8BAVIQZMKjo3dGwpQykRStJQfNuKJ
+0anCt1h+Ynb4ulQtMJJBoUjdt7PLkIEO5Wt5B38uBhwUpzgmprYjDI584QCdMnwTW6AqDnJ7QWZ9
+Yq3ffrk8TyjrBeDBmKcglPKkHIINBFgidfiW3B05pg0rmurJqFqMPx3cuTZ4Mg+jAOzciIKOTKbI
+GdvvzeOXD1+9khVlkNaL1y+cu9reBYM6HKYBKLBT2UTv8rJeSvgb18YMCMAXgcXSns12ycaLfTdu
+zn63vLw8/VT+aghWOsOypEn4RFOsAI5t7IQPEvSOnIxMVjlYcfr7kYepazxz8XJf350bA8BuXpj9
+EtoXp5FdOQfsk8HBwavj/2xvBxpcuq7PrC4o4OdWrl7rzXABwJ1gl7xoqG/3yrDG85f77ty8dm78
+pDwBw6wR4IM5LmwGO4CO2nLe9vO7V5aBoLK9HeUvqDUSfI6Atd4tORnbNoWr9Zxu3L3yrLHvNEeC
+rRjDD8bZ7cjJgqnaKFKXTP//2vmbz+Xw1/42G/hzNu5SVxAPrEwKdp+ffYjhf3dDVgjI+eku0De6
+XjZG4+PvRz8jCzvKvx8i+MV/2ZyTJduCWsdlFPR8dnFlUtD2GsIvLv5FTtbsx4KKJJZrcq1a9/zT
+thVJwSyAX/ynnCzaNkQAxgC1atW6db/+4n/tnb9rImkYx1/QCDM5xtPCH+eAupozu9lddbdIdosN
+pMgeFxa2ya6ZTkGLkCqL1XGphOOapLCLywRtJIooYtYkjWCaFUwKi2AXELJdcv/CzTs/nBnd0VdI
+dJT5FCHFIHy/8zzP+84777yPGsPgoM3of/uQ+oHLLjjwSWIA4wCG3XbUVw3uwuE/XA9qALA84w3o
+HqIYMUED2LPkWncqGxRSsYcaACQbZzy8A93tBibRAYNRZR483AAgd0BWBZwmPgnY8wQNtuq5eqaI
+7wB4NAe6OUCJIcA4QDDFIVNRiQcfwKPw1CMzgK0CggMYf8DkVq1UnlX9zJTw+a+ypmIRs+DAgvRl
+VJI+2ZtJ/TAG5F3Vdpxm6MBCtHdxIlMvTcyEDfCIPA30HqpP9TRWkTwuNIvlWdPPVMLASE0Yj+p0
+Iz3KfPkgkUufHDeKF6c0uwZWr1cq2dNiWg3xz8fAkxEbUBpi4XbrunNZTikZkUgXzs5L9P1/7Ta3
+oBOO9P0M4l6dvT/Bo+P4bSQD/onF2LPWITftWr3azGaz32ia+fuiUv2ePMzz3xfMz4mE+7IK7QvG
+/Y9gDFjcI+jfhh3nRQu+Kl7475yUnj1OoSbSSmRiHYwH+wgBoNPxFnAeUEpGyfTPzUuvC1XRXkjk
+1sC48CFXQlynk1kQVbjub7kBc7viYEKjVcDUexcYHyRiKdyBbQelFnxRyoB5OXwOZJpnaGNI7ooE
+Y8XhQTZAZoGSAXiPAbBYxJEfr3J0wArGjR0lDT6zrScFCxgPdhUuNPRGAPNghbrQUmjG7WACeFHS
+gDAaZRZElGpAWMrNfQP1sXK/UdtcIcFEcCCMh1EcN0o8wBSHS1F9+xr9MaJMH21uuq1gUvh2hnYk
+IXCJBcZtxQu/CurRZ72pC7gtmQqCCTK8FkZgAzbBgi8DrtPFblp36OurifMq+4222wEmy+/SIKCi
+NpNev+CMyDoQ4DjnAb47wKjDqxFeMqQ6LS6YVvxg4oiVIOQ0wVUyuEJgo6SLBpwFRETxoPb6KMtI
+5etbHDcYFphftluAGiC5xyPKZjabBAv0UrWhSDS6rTQJzr9ArvhMzb+8X4bqIZTnJVALviecfokD
+yvdbfuvR9x3t8beeBcNee4GKsNp3fmH7L4sWmIaMEFtJ+hj9XULqjrn1hq56bNHvAurCGlzkHRAs
+cA5Qn68U0bfawN0fUvGM/KAFqA9L1wITZ4FCCBxVL9BLXuLsCu7/+SSKh/KtQJ1Y5Rb8ZNaTqZYK
+yKNdihEv7AHTY5jq5bNvkb0BMQ96ciBTQ0/6g/J5Nrklb2qMYQRBBPwWoHLIJd4Cs8SA+PfTwj6y
+9qtapr+tNWSJBNOAI8iFAW9AvHaKeOcThYtsMq7Q15pYDDrAtOBiwyDKjnVnKNOcxEnnR/UwNGB1
+3U26wFRh9S4ls8PneAfpy86P22WY4TbldSWPzwqmj/WNxMAdrozy1jJGiPx8svzXdKrnMmH9Q67/
+lh8X6WYt79T30b9iHFp55neB6Wbt40aKe/3VKH2r1PJCntv4GbMEW6/4Kap6Q0xYe+e1e1ZkJ0tw
+cyUZNlG72+61gpnDQvoYGyguBsQJYxfz5meKke4jLWCmsbz0Bl/Z3ywxrK4GAqur8L83Qb+XnHXl
+GhoaGhoaGhoaauJ/z6sVgaPaB24AAAAASUVORK5CYII=
+"
+ id="image234"
+ x="2.9323115"
+ y="161.16402"
+ style="stroke-width:2.33685" /><text
+ xml:space="preserve"
+ style="font-size:5.64444px;line-height:70%;font-family:AbcCursiveDottedLined;-inkscape-font-specification:AbcCursiveDottedLined;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-rule:evenodd;stroke-width:2.8448;stop-color:#000000"
+ x="38.344975"
+ y="188.41483"
+ id="url"><tspan
+ sodipodi:role="line"
+ id="tspan398"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:5.64444px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#ffffff;stroke-width:2.8448"
+ x="38.344975"
+ y="188.41483">Initializing...</tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:9.87778px;line-height:70%;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none;stop-color:#000000"
+ x="2.535063"
+ y="10.061478"
+ id="news"><tspan
+ sodipodi:role="line"
+ id="tspan452"
+ style="font-size:9.87778px;fill:#ffffff;stroke:#000000;stroke-width:0.264583;stroke-dasharray:none"
+ x="2.535063"
+ y="10.061478">Initializing...</tspan></text><text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:7.05556px;line-height:70%;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-decoration:none;text-decoration-line:none;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-rule:evenodd;stroke:none;stroke-width:0.264583;stroke-dasharray:none;stop-color:#000000"
+ x="38.2995"
+ y="180.71815"
+ id="bottom"><tspan
+ sodipodi:role="line"
+ id="tspan452-6"
+ style="font-size:7.05556px;fill:#ffffff;stroke:none;stroke-width:0.264583;stroke-dasharray:none"
+ x="38.2995"
+ y="180.71815">Initializing...</tspan></text><rect
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.264583;stroke-dasharray:none;stop-color:#000000"
+ id="rect1531"
+ width="309.6998"
+ height="174.09039"
+ x="33.69672"
+ y="-2.1396465" /></g></svg>
diff --git a/roles/obs/tasks/main.yml b/roles/obs/tasks/main.yml
index 36e14c3..bf856ec 100644
--- a/roles/obs/tasks/main.yml
+++ b/roles/obs/tasks/main.yml
@@ -1,5 +1,5 @@
- name: Load icecast vars
- tags: wip
+ tags: obs-profile, wip
include_vars:
file: ../../stream/defaults/main.yml
- name: Add repo
@@ -53,5 +53,13 @@
regexp: '(AllowUsers(?!.*\b{{ emacsconf_id }}-{{ item.id }}\b).*)$'
replace: \1 {{ emacsconf_id }}-{{ item.id }}
loop: "{{ emacsconf_tracks }}"
-
-
+- name: Allow sudo from {{ emacsconf_user }} to the stream users
+ tags: wip
+ become: true
+ become_user: root
+ copy:
+ content: |
+ {% for item in emacsconf_tracks %}
+ {{ emacsconf_user }} ALL=({{ emacsconf_id }}-{{ item.id }}) NOPASSWD: ALL
+ {% endfor %}
+ dest: /etc/sudoers.d/50_emacsconf
diff --git a/roles/obs/tasks/obs-setup.yml b/roles/obs/tasks/obs-setup.yml
index 1da678a..59170f1 100644
--- a/roles/obs/tasks/obs-setup.yml
+++ b/roles/obs/tasks/obs-setup.yml
@@ -6,13 +6,12 @@
state: directory
- name: Create profile directories
file:
- path: "~{{ emacsconf_user }}/.config/obs-studio/basic/{{ item.name }}"
+ path: "~{{ emacsconf_user }}/.config/obs-studio/basic/profiles/{{ item.name }}"
state: directory
owner: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
mode: 0775
- name: Install OBS global profile
- tags: wip
template:
src: global.ini
owner: "{{ emacsconf_user }}"
@@ -23,7 +22,7 @@
src: profile.ini
owner: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
- dest: "~{{ emacsconf_user }}/.config/obs-studio/basic/{{ item.name }}/basic.ini"
+ dest: "~{{ emacsconf_user }}/.config/obs-studio/basic/profiles/{{ item.name }}/basic.ini"
mode: 0664
- name: Install OBS scenes
tags: obs-scene
@@ -32,17 +31,33 @@
owner: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
dest: "~{{ emacsconf_user }}/.config/obs-studio/basic/scenes/{{ item.id }}.json"
+- name: Copy overlay template for video
+ tags: obs-scene
+ copy:
+ src: overlay.svg
+ dest: "~{{ emacsconf_user }}/video.svg"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+- name: Copy overlay template for video
+ tags: obs-scene
+ copy:
+ src: overlay.svg
+ dest: "~{{ emacsconf_user }}/other.svg"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
- name: Create text files for OBS sources
copy:
content: "Initializing..."
owner: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
- dest: "~{{ emacsconf_user }}/{{ item }}.txt"
+ dest: "~{{ emacsconf_user }}/{{ filename }}.txt"
mode: 0664
loop:
- news
- url
- bottom
+ loop_control:
+ loop_var: filename
- name: Create OBS scripts for tracks
template:
src: obs-track
@@ -50,4 +65,11 @@
owner: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
mode: 0775
-
+- name: Fix permissions
+ become: true
+ become_user: root
+ file:
+ path: "~{{ emacsconf_user }}"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+ recurse: true
diff --git a/roles/obs/tasks/track.yml b/roles/obs/tasks/track.yml
index 93b789d..a0acf16 100644
--- a/roles/obs/tasks/track.yml
+++ b/roles/obs/tasks/track.yml
@@ -1,5 +1,5 @@
- name: Set vars
- tags: wip, obs-scene, mpv
+ tags: obs-scene, obs-profile, mpv, wip
set_fact:
old_emacsconf_user: "{{ emacsconf_user }}"
old_emacsconf_home: "{{ emacsconf_home }}"
@@ -10,7 +10,7 @@
- name: Set up user
include: user.yml
- name: Set up user-related things
- become: "{{ emacsconf_user }}"
+ become_user: "{{ emacsconf_user }}"
block:
- name: Set up track bins for addition to paths
file:
@@ -27,6 +27,7 @@
group: "{{ emacsconf_group }}"
state: directory
- name: Add MPV profile
+ tags: mpv-conf
template:
src: mpv.conf
dest: "~{{ emacsconf_user }}/.config/mpv/mpv.conf"
@@ -40,8 +41,12 @@
group: "{{ emacsconf_group }}"
mode: 0775
- name: Set up OBS profiles and scenes
- tags: obs-profile
- include: obs-setup.yml
+ tags: obs-profile, obs-scene
+ include_tasks:
+ file: obs-setup.yml
+ apply:
+ tags:
+ - obs-profile
- name: Add FFMPEG script for streaming
template:
src: stream-desktop-with-ffmpeg.sh
@@ -75,7 +80,7 @@
owner: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
- name: Reset vars
- tags: wip, obs-scene, mpv
+ tags: obs-scene, obs-profile, mpv, wip
set_fact:
old_emacsconf_user: "{{ emacsconf_user }}"
old_emacsconf_home: "{{ emacsconf_home }}"
diff --git a/roles/obs/tasks/user.yml b/roles/obs/tasks/user.yml
index a941d7f..caaf2d9 100644
--- a/roles/obs/tasks/user.yml
+++ b/roles/obs/tasks/user.yml
@@ -2,7 +2,6 @@
group:
name: "{{ emacsconf_group }}"
- name: Add user
- tags: wip
user:
name: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
@@ -15,10 +14,10 @@
state: directory
mode: 700
- name: Set up SSH key access
+ tags: wip
template:
src: authorized_keys
dest: "/home/{{ emacsconf_user }}/.ssh/authorized_keys"
- force: no
- name: Change ownership of SSH directory
file:
path: "/home/{{ emacsconf_user }}/.ssh"
diff --git a/roles/obs/templates/mpv.conf b/roles/obs/templates/mpv.conf
index 9aff3ee..b1bd1ca 100644
--- a/roles/obs/templates/mpv.conf
+++ b/roles/obs/templates/mpv.conf
@@ -15,7 +15,7 @@ sub-use-margins=yes
sub-scale-by-window=yes
sub-pos=103
sub-margin-x=120
-sub-margin-y=40
+sub-margin-y=20
sub-align-x=left
# Style
sub-font="{{ emacsconf_font }}"
diff --git a/roles/obs/templates/scenes.json b/roles/obs/templates/scenes.json
index 4e6e4bd..a92f29e 100644
--- a/roles/obs/templates/scenes.json
+++ b/roles/obs/templates/scenes.json
@@ -1,6 +1,6 @@
{
- "current_program_scene": "All track audio and screen",
- "current_scene": "All track audio and screen",
+ "current_program_scene": "Video audio and screen",
+ "current_scene": "Video audio and screen",
"current_transition": "Fade",
"groups": [
{
@@ -30,8 +30,8 @@
"push-to-talk-delay": 0,
"settings": {
"custom_size": true,
- "cx": 103,
- "cy": 507,
+ "cx": 494,
+ "cy": 715,
"id_counter": 0,
"items": [
{
@@ -56,11 +56,11 @@
"locked": false,
"name": "News",
"pos": {
- "x": 22,
- "y": 390
+ "x": 12,
+ "y": 0
},
"private_settings": {},
- "rot": -90,
+ "rot": 0,
"scale": {
"x": 1,
"y": 1
@@ -93,11 +93,11 @@
"locked": false,
"name": "URL",
"pos": {
- "x": 55,
- "y": 389
+ "x": 114,
+ "y": 691
},
"private_settings": {},
- "rot": -90,
+ "rot": 0,
"scale": {
"x": 1,
"y": 1
@@ -131,7 +131,7 @@
"name": "Logo",
"pos": {
"x": 0,
- "y": 404
+ "y": 603
},
"private_settings": {},
"rot": 0,
@@ -236,6 +236,8 @@
"push-to-talk": false,
"push-to-talk-delay": 0,
"settings": {
+ "color2": 4294967295,
+ "drop_shadow": false,
"font": {
"face": "Sans Serif",
"flags": 0,
@@ -243,6 +245,7 @@
"style": ""
},
"from_file": true,
+ "outline": true,
"text_file": "/home/{{ emacsconf_id }}-{{ item.id }}/news.txt"
},
"sync": 0,
@@ -271,7 +274,7 @@
"font": {
"face": "Sans Serif",
"flags": 0,
- "size": 24,
+ "size": 20,
"style": ""
},
"from_file": true,
@@ -346,14 +349,14 @@
"OBSBasic.SelectScene": [],
"libobs.hide_scene_item.Bottom": [],
"libobs.hide_scene_item.Screen Capture (XSHM)": [],
- "libobs.hide_scene_item.dev-qa": [],
- "libobs.hide_scene_item.dev-vid": [],
"libobs.hide_scene_item.emacsconf base": [],
+ "libobs.hide_scene_item.gen-qa": [],
+ "libobs.hide_scene_item.gen-vid": [],
"libobs.show_scene_item.Bottom": [],
"libobs.show_scene_item.Screen Capture (XSHM)": [],
- "libobs.show_scene_item.dev-qa": [],
- "libobs.show_scene_item.dev-vid": [],
- "libobs.show_scene_item.emacsconf base": []
+ "libobs.show_scene_item.emacsconf base": [],
+ "libobs.show_scene_item.gen-qa": [],
+ "libobs.show_scene_item.gen-vid": []
},
"id": "scene",
"mixers": 0,
@@ -503,11 +506,11 @@
"locked": false,
"name": "News",
"pos": {
- "x": 31,
- "y": 595
+ "x": 21,
+ "y": 6
},
"private_settings": {},
- "rot": -90,
+ "rot": 0,
"scale": {
"x": 1,
"y": 1
@@ -540,11 +543,11 @@
"locked": false,
"name": "URL",
"pos": {
- "x": 64,
- "y": 594
+ "x": 123,
+ "y": 697
},
"private_settings": {},
- "rot": -90,
+ "rot": 0,
"scale": {
"x": 1,
"y": 1
@@ -615,7 +618,7 @@
"name": "{{ emacsconf_id }} base",
"pos": {
"x": 9,
- "y": 205
+ "y": 6
},
"private_settings": {},
"rot": 0,
@@ -734,11 +737,11 @@
"hotkeys": {
"OBSBasic.SelectScene": [],
"libobs.hide_scene_item.Screen Capture (XSHM)": [],
- "libobs.hide_scene_item.dev-vid": [],
"libobs.hide_scene_item.emacsconf base": [],
+ "libobs.hide_scene_item.gen-vid": [],
"libobs.show_scene_item.Screen Capture (XSHM)": [],
- "libobs.show_scene_item.dev-vid": [],
- "libobs.show_scene_item.emacsconf base": []
+ "libobs.show_scene_item.emacsconf base": [],
+ "libobs.show_scene_item.gen-vid": []
},
"id": "scene",
"mixers": 0,
@@ -851,11 +854,11 @@
"locked": false,
"name": "News",
"pos": {
- "x": 31,
- "y": 580
+ "x": 12,
+ "y": 0
},
"private_settings": {},
- "rot": -90,
+ "rot": 0,
"scale": {
"x": 1,
"y": 1
@@ -888,11 +891,11 @@
"locked": false,
"name": "URL",
"pos": {
- "x": 64,
- "y": 579
+ "x": 114,
+ "y": 691
},
"private_settings": {},
- "rot": -90,
+ "rot": 0,
"scale": {
"x": 1,
"y": 1
@@ -925,8 +928,8 @@
"locked": false,
"name": "Logo",
"pos": {
- "x": 9,
- "y": 594
+ "x": 0,
+ "y": 603
},
"private_settings": {},
"rot": 0,
@@ -962,8 +965,8 @@
"locked": false,
"name": "{{ emacsconf_id }} base",
"pos": {
- "x": 9,
- "y": 190
+ "x": 0,
+ "y": 0
},
"private_settings": {},
"rot": 0,
diff --git a/roles/publish/defaults/main.yml b/roles/publish/defaults/main.yml
index 4de7445..6416e25 100644
--- a/roles/publish/defaults/main.yml
+++ b/roles/publish/defaults/main.yml
@@ -1,9 +1,5 @@
emacsconf_org_file: "{{ emacsconf_private_dir }}/conf.org"
emacsconf_publishing_phase: schedule
-emacsconf_el_dir: ~{{ emacsconf_user }}/emacsconf-el
-emacsconf_edit_wiki_dir: ~{{ emacsconf_user }}/emacsconf-wiki
-emacsconf_private_dir: ~{{ emacsconf_user }}/emacsconf-2022-private
-emacs_config_dir: ~{{ emacsconf_user }}/.emacs.d
emacs_version: 28.2
emacs_build_parent: /usr/src/emacs
emacs_build_dir: "{{ emacs_build_parent }}/emacs-{{ emacs_version }}"
diff --git a/roles/publish/tasks/main.yml b/roles/publish/tasks/main.yml
index 28566a5..ddee975 100644
--- a/roles/publish/tasks/main.yml
+++ b/roles/publish/tasks/main.yml
@@ -1,66 +1,106 @@
---
-- name: Set up SSH directory
- ansible.builtin.file:
- path: "/home/{{ emacsconf_user }}/.ssh"
- state: directory
- mode: '0700'
+- name: Set up user
+ include_role:
+ name: user
- name: Install SSH key for EmacsConf wiki
ansible.builtin.get_url:
url: https://emacsconf.org/id_rsa_anon_git_emacsconf
dest: "/home/{{ emacsconf_user }}/.ssh/id_rsa_anon_git_emacsconf"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
mode: '0600'
-- name: Install the SSH key for orga
- template:
- src: id_rsa
- dest: "/home/{{ emacsconf_user }}/.ssh/id_rsa"
+- name: Check SSH config for line
+ blockinfile:
+ path: /home/{{ emacsconf_user }}/.ssh/config
mode: '0600'
-- name: Change ownership of SSH directory
- file:
- path: "/home/{{ emacsconf_user }}/.ssh"
- recurse: true
owner: "{{ emacsconf_user }}"
-
+ group: "{{ emacsconf_group }}"
+ create: yes
+ block: |
+ Host anon-emacsconf
+ Hostname git.emacsconf.org
+ Port 22
+ User anon
+ IdentityFile ~/.ssh/id_rsa_anon_git_emacsconf
+- name: Install the SSH key for orga
+ copy:
+ src: "{{ item }}"
+ dest: "/home/{{ emacsconf_user }}/.ssh"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+ mode: '0600'
+ loop:
+ - id_rsa
+ - id_rsa.pub
+- name: Check if local Emacs already exists
+ stat:
+ path: "/usr/local/bin/emacs"
+ register: emacs
- name: Set up Emacs
+ become: yes
include: emacs.yml
+ when: not emacs.stat.exists
+- name: Configure git
+ template:
+ src: git-config
+ dest: "~{{ emacsconf_user }}/.gitconfig"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
- name: Ensure configuration directory exists
file:
path: "{{ emacs_config_dir }}"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
state: directory
- name: Set up Emacs configuration for non-interactive publishing
template:
src: emacsconf-config.el
dest: "{{ emacs_config_dir }}/emacsconf-config.el"
-
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
- name: Check if Emacs base configuration already exists
- become: true
lineinfile:
dest: "{{ emacs_config_dir }}/init.el"
state: present
regexp: "emacsconf-config"
- line: "(load-file \"emacsconf-config.el\")"
+ line: "(load-file \"{{ emacs_config_dir }}/emacsconf-config.el\")"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
create: yes
+- name: Set up compile-media
+ become_user: "{{ emacsconf_user }}"
+ git:
+ repo: https://github.com/sachac/compile-media.git
+ dest: "~{{ emacsconf_user }}/compile-media"
- name: Set up or update repositories
- become: false
+ become_user: "{{ emacsconf_user }}"
tags: publish
block:
- name: Check out wiki repository
ansible.builtin.git:
- repo: git://git.emacsconf.org/emacsconf-wiki
+ repo: git@anon-emacsconf:/emacsconf-wiki
dest: "{{ emacsconf_edit_wiki_dir }}"
+ key_file: "~{{ emacsconf_user }}/.ssh/id_rsa_anon_git_emacsconf"
register: wiki_clone
failed_when:
- wiki_clone.failed
- not 'Local modifications exist in repository' in wiki_clone.msg
- not 'Failed to checkout branch' in wiki_clone.msg
+ - name: Configure git to use
+ shell: git config core.sshCommand "ssh -i ~{{ emacsconf_user }}/.ssh/id_rsa_anon_git_emacsconf -F /dev/null"
+ args:
+ chdir: "{{ emacsconf_edit_wiki_dir }}"
- name: Check out emacsconf-el
ansible.builtin.git:
repo: git@git.emacsconf.org:pub/emacsconf-el
+ key_file: "~{{ emacsconf_user }}/.ssh/id_rsa"
dest: "{{ emacsconf_el_dir }}"
register: elisp
failed_when:
- elisp.failed
- not 'Local modifications exist in repository' in elisp.msg
- not 'Failed to checkout branch' in elisp.msg
+ debugger: on_failed
- name: Check out emacsconf-2022-private
ansible.builtin.git:
repo: git@git.emacsconf.org:emacsconf-2022-private
@@ -75,20 +115,23 @@
path: "{{ item }}"
owner: "{{ emacsconf_user }}"
recurse: true
- with_items:
- - "{{ emacsconf_config_dir }}"
+ loop:
+ - "{{ emacs_config_dir }}"
- "{{ emacsconf_el_dir }}"
- "{{ emacsconf_private_dir }}"
- "{{ emacsconf_edit_wiki_dir }}"
- name: Publish
- tags: publish
+ tags: publish, publish-only
block:
- name: Publish the schedule
- command: emacs -l "{{ emacsconf_config_dir }}/emacsconf-config.el" --batch --exec '(emacsconf-generate-main-schedule)'
- when: (force_publish|d(false)) or ((private.changed or elisp.changed) and slug is not defined)
+ command: emacs -l "{{ emacs_config_dir }}/emacsconf-config.el" --batch --exec '(emacsconf-publish-schedule)'
+ when: ((publish|d("")) == "schedule") or (((private is defined and private.changed) or (elisp is defined and elisp.changed)) and slug is not defined)
- name: Update a specific talk's nav page
tags: publish-talk
- command: emacs -l "{{ emacsconf_config_dir }}/emacsconf-config.el" --batch --exec '(emacsconf-with-talk-heading "{{ slug }}" (emacsconf-update-talk))'
+ command: emacs -l "{{ emacs_config_dir }}/emacsconf-config.el" --batch --exec '(emacsconf-with-talk-heading "{{ slug }}" (emacsconf-update-talk))'
when: slug is defined
- name: Commit the wiki and push
shell: cd {{ emacsconf_edit_wiki_dir }}; git commit -m 'Update from ansible' -a; git push
+ - name: Publish the backstage index
+ command: emacs -l "{{ emacs_config_dir }}/emacsconf-config.el" --batch --exec '(emacsconf-publish-backstage-index)'
+ when: (publish|d("")) == "backstage"
diff --git a/roles/publish/templates/emacsconf-config.el b/roles/publish/templates/emacsconf-config.el
index cfb554e..e9e4fcc 100644
--- a/roles/publish/templates/emacsconf-config.el
+++ b/roles/publish/templates/emacsconf-config.el
@@ -1,9 +1,6 @@
;; {{ ansible_managed }}
(add-to-list 'load-path "{{ emacsconf_el_dir }}")
-(require 'emacsconf)
-(require 'emacsconf-publish)
-(require 'emacsconf-schedule)
(org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (shell . t)))
(setq emacsconf-year "{{ emacsconf_year }}")
(setq emacsconf-org-file "{{ emacsconf_org_file }}")
@@ -19,3 +16,28 @@
{% endif %}
(setq emacsconf-pad-api-key "{{ etherpad_api_key }}")
(setq emacsconf-publishing-phase '{{ emacsconf_publishing_phase }})
+(setq emacsconf-backstage-password "{{ emacsconf_backstage_password }}")
+
+(setq emacsconf-backstage-dir "/ssh:orga@media.emacsconf.org:/var/www/media.emacsconf.org/2022/backstage")
+(setq emacsconf-upload-dir "/ssh:orga@media.emacsconf.org:/srv/upload")
+{% if ansible_host == "res.emacsconf.org" %}
+(setq emacsconf-res-dir (format "/ssh:orga@res.emacsconf.org:/data/emacsconf/%s" emacsconf-year))
+(setq emacsconf-cache-dir "/data/{{ emacsconf_id }}/cache")
+(setq emacsconf-stream-host "localhost")
+{% else %}
+(setq emacsconf-res-dir "/data/{{ emacsconf_id }}/{{ emacsconf_year}}")
+{% endif %}
+(add-to-list 'load-path "~/compile-media")
+(require 'compile-media)
+(require 'emacsconf)
+(require 'emacsconf-publish)
+(require 'emacsconf-schedule)
+(require 'emacsconf-erc)
+(require 'emacsconf-stream)
+
+(setq emacsconf-tracks
+ '((:name "General" :color "peachpuff" :id "gen" :channel "emacsconf-gen"
+ :tramp "/ssh:gen:")
+ (:name "Development" :color "skyblue" :id "dev" :channel "emacsconf-dev"
+ :tramp "/ssh:dev:")))
+
diff --git a/roles/publish/templates/git-config b/roles/publish/templates/git-config
new file mode 100644
index 0000000..e03358d
--- /dev/null
+++ b/roles/publish/templates/git-config
@@ -0,0 +1,8 @@
+# {{ ansible_managed }}
+# This is Git's per-user configuration file.
+[user]
+# Please adapt and uncomment the following lines:
+ name = {{ emacsconf_name }}
+ email = {{ emacsconf_email }}
+[push]
+ default = simple
diff --git a/roles/user/tasks/main.yml b/roles/user/tasks/main.yml
new file mode 100644
index 0000000..11c0a74
--- /dev/null
+++ b/roles/user/tasks/main.yml
@@ -0,0 +1,31 @@
+- name: Add group
+ become: yes
+ group:
+ name: "{{ emacsconf_group }}"
+- name: Add user
+ become: yes
+ user:
+ name: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+ shell: /bin/bash
+# password: "{{ emacsconf_unix_password }}"
+- name: Create SSH folder
+ file:
+ path: "/home/{{ emacsconf_user }}/.ssh"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+ state: directory
+ mode: 0700
+- name: Set up SSH key access
+ template:
+ src: authorized_keys
+ dest: "/home/{{ emacsconf_user }}/.ssh/authorized_keys"
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+ force: no
+- name: Change ownership of SSH directory
+ file:
+ path: "/home/{{ emacsconf_user }}/.ssh"
+ recurse: true
+ owner: "{{ emacsconf_user }}"
+ mode: "u+rwX,g-rwx,o-rwx"