summaryrefslogtreecommitdiffstats
path: root/2023/info/parallel-after.md
diff options
context:
space:
mode:
Diffstat (limited to '2023/info/parallel-after.md')
-rw-r--r--2023/info/parallel-after.md631
1 files changed, 631 insertions, 0 deletions
diff --git a/2023/info/parallel-after.md b/2023/info/parallel-after.md
new file mode 100644
index 00000000..2f390ff8
--- /dev/null
+++ b/2023/info/parallel-after.md
@@ -0,0 +1,631 @@
+<!-- Automatically generated by emacsconf-publish-after-page -->
+
+
+<a name="parallel-mainVideo-transcript"></a>
+# Transcript
+
+
+[[!template new="1" text="""Introduction""" start="00:00:00.000" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""Hi everyone!""" start="00:00:00.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Welcome to our talk on Parallel Text Replacement.""" start="00:00:01.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""My name is Lovro, and I'll be telling you about an""" start="00:00:04.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""interesting problem that my friend Valentino and I""" start="00:00:07.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""set out to solve one afternoon.""" start="00:00:09.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We will describe the problem, take a look at some""" start="00:00:11.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""of the existing work and then present our solution.""" start="00:00:13.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Afterwards, we will show some demos and conclude""" start="00:00:16.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""with a quick overview of the implementation.""" start="00:00:19.080" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Let's get straight into it!""" start="00:00:21.520" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Problem: Goal""" start="00:00:23.440" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""Here is a problem that most of us have dealt with""" start="00:00:23.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""at some point.""" start="00:00:25.800" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Assume we have a piece of code such as the following.""" start="00:00:27.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We use a code example here, but in general what we're""" start="00:00:29.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""about to discuss can be applied to any piece of text.""" start="00:00:32.520" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""After a bit of thinking, we decide that the names of""" start="00:00:35.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""the two variables, &quot;foo&quot; and &quot;bar&quot;, should actually be""" start="00:00:37.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""swapped.""" start="00:00:39.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""That is, &quot;foo&quot; should be replaced with &quot;bar&quot;, and &quot;bar&quot;""" start="00:00:40.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""should be replaced with &quot;foo&quot;.""" start="00:00:43.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The question is: what is a good way to achieve this?""" start="00:00:45.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We could perform the edits manually if the code is""" start="00:00:49.080" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""small enough, and we might even be done reasonably""" start="00:00:51.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""quickly.""" start="00:00:53.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""However, consider two things.""" start="00:00:54.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Imagine the usual case where there's just too much""" start="00:00:56.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""code to edit by hand.""" start="00:00:58.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We have no other option than to automate the task.""" start="00:01:00.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""More importantly though, we have a whole programmable""" start="00:01:03.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""text editor right at our fingertips.""" start="00:01:06.120" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We should object to doing things that the computer""" start="00:01:08.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""can do for us.""" start="00:01:10.280" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Problem: Naive Multi-pass""" start="00:01:12.360" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""So, one way to automate it is by using our old friend""" start="00:01:12.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""query-replace (M-%) multiple times in a sequence.""" start="00:01:15.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We first do a pass where we replace &quot;foo&quot; with &quot;bar&quot;,""" start="00:01:19.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""then we do another pass where we replace &quot;bar&quot; with &quot;foo&quot;.""" start="00:01:22.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""But that's clearly not right.""" start="00:01:25.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We all know that this naive multi-pass approach""" start="00:01:26.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""doesn't work because it results in interference""" start="00:01:29.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""between the two replacements.""" start="00:01:31.560" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Problem: Clever Multi-pass""" start="00:01:34.200" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""Instead, we have to be a bit more clever.""" start="00:01:34.200" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We should first replace &quot;foo&quot; with a temporary string,""" start="00:01:36.800" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""in this case &quot;oof&quot;, that we will call a &quot;token&quot;.""" start="00:01:39.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""To avoid interference, we must be careful to ensure""" start="00:01:42.120" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""that the token does not contain whatever we're about""" start="00:01:45.480" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""to replace next.""" start="00:01:48.120" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Then we do a second pass to replace &quot;bar&quot; with &quot;foo&quot;,""" start="00:01:49.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and finally a third pass to replace the token with &quot;bar&quot;.""" start="00:01:52.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This gives us the result we want.""" start="00:01:56.080" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Problem: Terminology""" start="00:01:57.720" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""Putting the implementation aside for a moment, this style""" start="00:01:57.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""of text replacement, where we replace multiple sources""" start="00:02:01.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""with their targets, without running into interference""" start="00:02:05.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""issues between replacement pairs, is what we call""" start="00:02:09.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""a &quot;parallel replacement&quot;.""" start="00:02:11.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This is the essence of the problem we're trying to solve.""" start="00:02:12.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The examples with swapping that we've shown so far""" start="00:02:16.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""are really just one of the many use cases that are""" start="00:02:18.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""supported by a general parallel replacement utility.""" start="00:02:21.320" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""To avoid confusion, let us clarify that the word &quot;parallel&quot;""" start="00:02:25.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""is not in reference to hardware parallelization, but""" start="00:02:28.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""rather comes from analogy with the Lisp let operator,""" start="00:02:31.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""where the bindings of variables are performed in parallel,""" start="00:02:34.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""rather than sequentially as in let*.""" start="00:02:38.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Parallel in this context means that none of the bindings""" start="00:02:40.200" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""are in scope within any of the initial value forms.""" start="00:02:43.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""In other words, just like a let's initialization form""" start="00:02:46.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""cannot refer to any of the earlier bindings, a""" start="00:02:50.200" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""replacement pair's source should not be able to replace""" start="00:02:53.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""the previously substituted targets of any other pair.""" start="00:02:56.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This is what we mean by &quot;no interference&quot;.""" start="00:03:00.200" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Problem: Scaling Multi-pass""" start="00:03:04.440" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""However, manually invoking multiple carefully chosen""" start="00:03:04.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""query-replace commands gets old very quickly.""" start="00:03:08.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Say we scaled up the problem and wanted to perform n""" start="00:03:11.520" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""swaps instead of just two, e.g. to swap, or rather,""" start="00:03:14.200" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""rotate, &quot;foo&quot; to &quot;bar&quot;, &quot;bar&quot; to &quot;baz&quot;, &quot;baz&quot; to &quot;quux&quot;""" start="00:03:18.320" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and &quot;quux&quot; to &quot;foo&quot;.""" start="00:03:22.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We would first have to perform n - 1 additional""" start="00:03:23.800" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""replacements to introduce the necessary tokens,""" start="00:03:26.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""effectively doubling the number of steps.""" start="00:03:29.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Even if we tried to automate this, think about what""" start="00:03:32.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""tokens the code would have to generate if we had no""" start="00:03:34.800" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""prior knowledge of the replacement pairs given by the""" start="00:03:37.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""user.""" start="00:03:40.520" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We would have to program defensively and use long""" start="00:03:41.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""randomly-generated strings that, one, hopefully do""" start="00:03:44.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""not interfere with any of the replacement pairs,""" start="00:03:47.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and two, might slow down the search if they're overly long.""" start="00:03:50.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Can we do better?""" start="00:03:53.480" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Solution: Single-pass""" start="00:03:55.920" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""Yes we can!""" start="00:03:55.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We can actually perform just a single pass.""" start="00:03:56.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The trick is to alternate between the replacement""" start="00:03:59.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""pairs, replacing whichever source occurs the earliest,""" start="00:04:02.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and making sure to continue scanning after the end""" start="00:04:06.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""of the substituted target in order to avoid interference.""" start="00:04:08.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This interleaving of replacements is not something""" start="00:04:12.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""that's easy to do by hand with query-replace.""" start="00:04:14.520" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Solution: Existing""" start="00:04:18.240" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""Since this is Emacs we're talking about, of course""" start="00:04:18.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""there already exist solutions that implement this idea.""" start="00:04:20.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Here are few that we could find.""" start="00:04:23.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The EmacsWiki has a page dedicated to this problem.""" start="00:04:25.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Stack Overflow has an old post where a couple of""" start="00:04:28.800" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""users provided their solutions.""" start="00:04:31.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Mastering Emacs also gives a method along with other""" start="00:04:33.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""interesting query-replace-regexp (C-M-%) patterns.""" start="00:04:36.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""More recently, Tony Zorman made a blogpost providing""" start="00:04:39.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""a solution with an interface based on query-replace.""" start="00:04:42.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""I encourage you to take a look at these solutions if""" start="00:04:45.080" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""you're interested in the details.""" start="00:04:47.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""But while a step in the right direction, these solutions""" start="00:04:50.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""are not satisfactory because they all lack one or""" start="00:04:53.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""more of the following.""" start="00:04:55.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""One, they are not completely automated and require""" start="00:04:56.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""the user to come up with a relatively complicated""" start="00:05:00.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and verbose query-replace-regexp invocation.""" start="00:05:02.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Two, they are restricted to performing only 2-element""" start="00:05:06.080" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""swaps rather than general parallel replacements.""" start="00:05:09.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Three, they don't provide any sort of interactivity""" start="00:05:12.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""during replacement and instead perform it in one shot.""" start="00:05:15.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Four, they don't attempt to integrate with the familiar""" start="00:05:18.620" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""query-replace interface, which supports skipping, undo,""" start="00:05:21.400" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""history and more advanced features like Lisp expressions""" start="00:05:25.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and recursive query edits.""" start="00:05:28.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Most importantly however, five, none of them were""" start="00:05:30.700" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""designed with regular expressions in mind and instead""" start="00:05:33.800" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""only ever consider literal strings.""" start="00:05:36.480" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""In fact, the only one that comes close is the""" start="00:05:39.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""half-automated solution that invokes query-replace-regexp""" start="00:05:43.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""with a specially crafted replacement.""" start="00:05:46.520" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""As an example, here's how you would use this technique""" start="00:05:48.800" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""to perform a 3-element parallel regex replacement.""" start="00:05:51.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""It uses the backslash-comma Lisp expression feature""" start="00:05:54.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""in order to choose the appropriate target to substitute.""" start="00:05:57.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Aside from being very clumsy and tedious to write out,""" start="00:06:01.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""this approach makes it really hard to use more complex""" start="00:06:03.800" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""regular expressions that make use of capture groups""" start="00:06:06.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""themselves.""" start="00:06:09.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This was the biggest limitation that we wanted""" start="00:06:10.800" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""to get rid of and the main motivation for our work.""" start="00:06:12.200" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""So, as an alternative to the existing zoo of 80% solutions,""" start="00:06:15.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""we aim to provide a 100% solution, one that handles""" start="00:06:19.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""regexes and consolidates all of the existing ideas""" start="00:06:24.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""into a single package.""" start="00:06:27.120" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Solution: query-replace-parallel""" start="00:06:29.080" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""We call it query-replace-parallel.""" start="00:06:29.080" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The package is free and open-source and can currently""" start="00:06:31.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""be found on GitHub under hokomo/query-replace-parallel.""" start="00:06:34.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The name is not yet finalized and we're open to any""" start="00:06:37.400" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""suggestions.""" start="00:06:40.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We hope to get it published on an Elisp""" start="00:06:41.503" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""package archive in the near future, but for now you""" start="00:06:43.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""can just download and load the main Elisp file manually.""" start="00:06:45.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""With all of that said, let's go through a few demos""" start="00:06:48.900" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""to illustrate some use cases and see how to use the package.""" start="00:06:51.400" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Demonstration: Swap""" start="00:06:55.240" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""Our first demo is a simple swap, like the one we""" start="00:06:55.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""showed at the beginning of the presentation.""" start="00:06:57.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This chunk of text is actually one of the tests""" start="00:06:59.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""from our package's code.""" start="00:07:02.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Assuming we have loaded the package, we can execute""" start="00:07:03.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""the query-replace-parallel command, a parallel version""" start="00:07:06.520" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""of the standard query-replace.""" start="00:07:09.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This command works with literal strings and will""" start="00:07:11.320" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""ask for each source and target in turn.""" start="00:07:14.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Our goal is to replace &quot;foo&quot; with &quot;bar&quot;""" start="00:07:16.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and &quot;bar&quot; with &quot;foo&quot;.""" start="00:07:21.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""After inputting our replacements, we terminate the""" start="00:07:24.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""prompt by pressing enter with empty input.""" start="00:07:27.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""At this point, everything functions the same as in""" start="00:07:29.860" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""a standard query-replace invocation.""" start="00:07:32.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The echo area shows the match and the replacement""" start="00:07:35.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""we're about to make.""" start="00:07:37.400" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We can perform replacements,""" start="00:07:38.703" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""undo them,""" start="00:07:43.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""skip them,""" start="00:07:46.503" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""execute them until the end,""" start="00:07:49.203" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and so on.""" start="00:07:50.240" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Demonstration: LaTeX""" start="00:07:53.970" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""The second demo shows our first regex use case.""" start="00:07:53.970" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Imagine we have the following LaTeX code.""" start="00:07:56.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We realize that we haven't been completely consistent""" start="00:07:58.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""in our use and naming of macros, so we decide to""" start="00:08:01.480" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""fix the problem.""" start="00:08:04.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This time we execute query-replace-parallel-regexp""" start="00:08:05.536" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""because we want to work with regex instead of literal""" start="00:08:08.400" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""strings.""" start="00:08:11.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We want to achieve two things.""" start="00:08:12.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""First, we want to wrap all usages of the variable n""" start="00:08:13.520" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""with the natvar macro.""" start="00:08:16.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Using the backslash-less-than and blackslash-greater-than""" start="00:08:18.080" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""constructs allows us to only match letters n not""" start="00:08:21.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""appearing as part of a larger word.""" start="00:08:23.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Second, we want to rename natvar to intvar because""" start="00:08:25.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""the variables a, b and c are integers and not natural""" start="00:08:29.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""numbers.""" start="00:08:32.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We enter empty input to terminate the prompt and can""" start="00:08:33.300" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""now perform the replacements.""" start="00:08:35.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""There we go, the fixes are done and we didn't have""" start="00:08:42.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""to think about in which order to apply them.""" start="00:08:44.480" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Demonstration: Regex""" start="00:08:48.700" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""We now take a look at a more complicated regex""" start="00:08:48.700" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""example to demonstrate that even advanced query-replace""" start="00:08:51.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""features are supported.""" start="00:08:53.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Each &quot;foo&quot; and &quot;bar&quot; in this example is followed by""" start="00:08:55.100" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""a number.""" start="00:08:57.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The goal is to not only swap &quot;foo&quot; and &quot;bar&quot;, but""" start="00:08:58.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""also increase or decrease the corresponding number.""" start="00:09:01.380" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We first match &quot;foo&quot; and capture the number that""" start="00:09:03.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""follows it.""" start="00:09:06.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""For the target, we make use of the backslash-comma""" start="00:09:07.200" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Lisp expression feature in order to replace the""" start="00:09:10.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""match with &quot;bar&quot; followed by the number's successor.""" start="00:09:12.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We do the same thing for &quot;bar&quot;, except that we""" start="00:09:15.540" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""replace the number with its predecessor.""" start="00:09:17.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Performing the replacements, we can see how each""" start="00:09:27.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""number is incremented or decremented appropriately.""" start="00:09:29.120" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Demonstration: Order""" start="00:09:36.320" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""We haven't covered it explicitly so some of you may""" start="00:09:36.320" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""be wondering how parallel replacement deals with""" start="00:09:38.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""overlapping matches and whether the order of the""" start="00:09:41.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""replacement pairs is significant.""" start="00:09:43.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This demo will clarify the exact behavior.""" start="00:09:45.480" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The first example has the sources &quot;watch&quot; and &quot;stopwatch&quot;.""" start="00:09:48.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Conceptually, the matches overlap, but the rule is""" start="00:09:57.500" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""that matches are always processed earliest first,""" start="00:10:00.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""regardless of their length or the ordering of the pairs.""" start="00:10:03.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Therefore it is &quot;stopwatch&quot; that gets replaced,""" start="00:10:06.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and not its substring &quot;watch&quot;.""" start="00:10:09.080" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The second example uses the sources &quot;watch&quot; and &quot;watchword&quot;.""" start="00:10:16.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Both of the matches now conceptually start at the same""" start="00:10:19.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""position.""" start="00:10:22.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""In situations like these the order of the pairs does""" start="00:10:23.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""matter, and ties are broken by prefering the pair that""" start="00:10:26.400" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""was entered first, which is behavior that is inherited""" start="00:10:29.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""from the Elisp regex engine.""" start="00:10:32.280" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""So, the substring &quot;watch&quot; in &quot;watchword&quot; is what gets""" start="00:10:34.460" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""replaced in this case.""" start="00:10:37.480" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Situations where the order of the pairs is significant""" start="00:10:39.460" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""are not very common however, so the user generally""" start="00:10:41.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""doesn't have to worry about this edge case.""" start="00:10:44.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The order only matters when two or more sources""" start="00:10:46.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""share the same prefix, as in this example.""" start="00:10:49.960" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Demonstration: Fun""" start="00:10:54.440" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""The final demo tests the limits of the package and""" start="00:10:54.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""shows that it fully integrates with query-replace.""" start="00:10:56.960" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""It is really just for fun and can even serve as a""" start="00:10:59.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""small Emacs brainteaser.""" start="00:11:03.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""See if you can keep up!""" start="00:11:04.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We open a directory and enter Writable Dired mode""" start="00:11:06.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""in order to rename the directories &quot;foo&quot; and &quot;bar&quot;.""" start="00:11:09.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Instead of doing it quickly by hand, we decide to""" start="00:11:11.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""show off and use query-replace-parallel-regexp.""" start="00:11:14.760" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We enter our pairs and make use of the""" start="00:11:17.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""backslash-question-mark query edit feature.""" start="00:11:20.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Now whenever we perform a replacement, the query""" start="00:11:25.080" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""edit makes Emacs stop and prompt us for additional""" start="00:11:27.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""input to use as the target.""" start="00:11:30.840" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We confirm the renames and now enter the &quot;bar-lib&quot;""" start="00:11:36.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""directory in order to perform the same kind of""" start="00:11:39.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""replacement on &quot;baz&quot; and &quot;quux&quot;.""" start="00:11:42.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Rather than save time, we decide to be extra lazy""" start="00:11:44.500" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and take the long route.""" start="00:11:47.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We recall the first pair and initiate a recursive""" start="00:11:48.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""invocation of query-replace-parallel-regexp.""" start="00:11:52.320" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We are now replacing the replacement.""" start="00:11:54.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We apply our fixes and then do the same thing again""" start="00:12:01.020" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""with the second pair.""" start="00:12:04.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Recall and recurse.""" start="00:12:05.970" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We confirm the prompt and finally rename our directories.""" start="00:12:16.300" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Wow, that really paid off.""" start="00:12:25.360" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""Implementation""" start="00:12:29.120" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""Before we finish, a few quick words about the""" start="00:12:29.120" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""implementation for the curious.""" start="00:12:31.480" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Both query-replace-parallel and query-replace-parallel-regexp""" start="00:12:33.300" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""delegate to the complex perform-replace function""" start="00:12:36.480" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""which is the workhorse of query-replace's interactive""" start="00:12:39.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""mechanism.""" start="00:12:41.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The way we achieve multiple interleaved replacements""" start="00:12:43.120" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""is by providing perform-replace with a big &quot;matcher regex&quot;""" start="00:12:45.520" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and a special replacement function.""" start="00:12:49.120" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Essentially, a complex parallel replacement like this""" start="00:12:50.480" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""is transformed into a standard replacement like this.""" start="00:12:54.400" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This is similar to the trick shown earlier in the""" start="00:12:57.520" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""presentation.""" start="00:13:00.200" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Each source is put in its own capture group to allow""" start="00:13:00.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""the replacement function to determine which one matched""" start="00:13:03.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""and return the appropriate target.""" start="00:13:06.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""However, we now take care to support arbitrary""" start="00:13:08.980" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""regular expressions as sources.""" start="00:13:11.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We achieve this by converting each source regex into""" start="00:13:13.480" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""an equivalent one for which we can guarantee that its""" start="00:13:17.080" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""capture groups will not clash with our matcher regex.""" start="00:13:19.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Information about this conversion is stored, and""" start="00:13:22.920" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""once the replacement function is called it has""" start="00:13:26.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""enough data to apply the replacement from the""" start="00:13:28.320" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""viewpoint of the original regex.""" start="00:13:30.360" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""The regex transformation is reliable because it""" start="00:13:32.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""uses the rx library, allowing us to treat regexes""" start="00:13:35.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""as s-expressions and avoid any nasty manual parsing.""" start="00:13:38.520" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""In fact, rx itself is based on one of Olin Shivers'""" start="00:13:42.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""100% solutions:""" start="00:13:46.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""SRE, or the S-expression regex notation.""" start="00:13:48.436" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""We all stand on the shoulders of many giants, so""" start="00:13:51.320" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""let's strive to design good solutions that we can""" start="00:13:54.440" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""all benefit from, many years into the future!""" start="00:13:56.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Finally, because query-replace's core is not completely""" start="00:13:59.240" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""customizable, we did have to sprinkle in some advice""" start="00:14:03.000" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""to get certain things working.""" start="00:14:06.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""This concerns only minor cosmetic fixes and not the""" start="00:14:07.600" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""core replacement functionality, but we have nontheless""" start="00:14:11.160" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""tried to do it in the simplest and least intrusive way""" start="00:14:14.040" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""possible.""" start="00:14:16.680" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template new="1" text="""End""" start="00:14:18.740" video="mainVideo-parallel" id="subtitle"]]
+
+[[!template text="""In conclusion, go download and play with the package.""" start="00:14:18.740" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Even if you're not performing overlapping replacements,""" start="00:14:21.680" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""you can still use query-replace-parallel for the""" start="00:14:24.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""peace of mind knowing that things won't go wrong if""" start="00:14:26.880" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""you perform more than one replacement at a time.""" start="00:14:29.720" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Feel free to let us know about any interesting or""" start="00:14:32.460" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""crazy use cases you might come up with, as well as""" start="00:14:34.640" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""improvements or bugs that make it only a 99% solution.""" start="00:14:37.560" video="mainVideo-parallel" id="subtitle"]]
+[[!template text="""Thanks for listening and have a great EmacsConf!""" start="00:14:40.640" video="mainVideo-parallel" id="subtitle"]]
+
+<a name="parallel-qanda-transcript"></a>
+# Q&A transcript (unedited)
+
+[[!template text="""[Speaker 0]: And I think we are live.""" start="00:00:08.620" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Hello again, everyone.""" start="00:00:09.620" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And hi, Lovro. How are you doing?""" start="00:00:10.940" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: Just a second. Should I join the other room?""" start="00:00:15.339" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: Oh, no, no, you can stay here.""" start="00:00:18.460" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: I can stay in the backstage.""" start="00:00:20.860" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: Everything is fine. I don't think you are""" start="00:00:24.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""technically in the backstage right now you're""" start="00:00:25.520" video="qanda-parallel" id="subtitle"]]
+[[!template text="""just in Big Blue Button with us.""" start="00:00:26.750" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: Oh thanks. Oh because I have 2 of them open I""" start="00:00:30.040" video="qanda-parallel" id="subtitle"]]
+[[!template text="""thought there were 2 different rooms.""" start="00:00:30.920" video="qanda-parallel" id="subtitle"]]
+[[!template text="""1 is the backstage and the other,""" start="00:00:32.720" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: whichever, I can hear you and so can the""" start="00:00:38.239" video="qanda-parallel" id="subtitle"]]
+[[!template text="""stream, so don't worry too much about which""" start="00:00:39.840" video="qanda-parallel" id="subtitle"]]
+[[!template text="""is the backstage and which is the front page.""" start="00:00:41.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: I have no idea. Well, great,""" start="00:00:41.540" video="qanda-parallel" id="subtitle"]]
+[[!template text="""great. Okay, yeah. Yeah,""" start="00:00:43.660" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I'm doing great, just to answer your""" start="00:00:45.280" video="qanda-parallel" id="subtitle"]]
+[[!template text="""question.""" start="00:00:45.480" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: Okay, great, great, Okay,""" start="00:00:47.379" video="qanda-parallel" id="subtitle"]]
+[[!template text="""well splendid. So, I've pasted a link again""" start="00:00:49.900" video="qanda-parallel" id="subtitle"]]
+[[!template text="""on IRC if you want to ask your questions,""" start="00:00:51.520" video="qanda-parallel" id="subtitle"]]
+[[!template text="""and I'd invite you to do so,""" start="00:00:53.000" video="qanda-parallel" id="subtitle"]]
+[[!template text="""because we have about 9 minutes of laborious""" start="00:00:54.620" video="qanda-parallel" id="subtitle"]]
+[[!template text="""time to answer as many of them as possible.""" start="00:00:56.580" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And I'm going to start with the first 1.""" start="00:00:58.360" video="qanda-parallel" id="subtitle"]]
+[[!template text="""This looks great and was very well-presented.""" start="00:01:01.100" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Do you have plans to upstream this""" start="00:01:03.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""functionality into Emacs?""" start="00:01:04.239" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: That's a good idea. That's something we""" start="00:01:08.000" video="qanda-parallel" id="subtitle"]]
+[[!template text="""thought about as well.""" start="00:01:08.860" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Currently, we haven't really contacted anyone""" start="00:01:11.640" video="qanda-parallel" id="subtitle"]]
+[[!template text="""to do this. Also, the current implementation,""" start="00:01:16.160" video="qanda-parallel" id="subtitle"]]
+[[!template text="""so as I mentioned in the presentation towards""" start="00:01:19.760" video="qanda-parallel" id="subtitle"]]
+[[!template text="""the end, so we use a little bit of advice to""" start="00:01:22.120" video="qanda-parallel" id="subtitle"]]
+[[!template text="""sort of patch some functionality of query""" start="00:01:24.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""replace because not everything was easy to""" start="00:01:26.479" video="qanda-parallel" id="subtitle"]]
+[[!template text="""implement. The core functionality luckily""" start="00:01:28.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""was, But there's a couple of fixes we need to""" start="00:01:32.220" video="qanda-parallel" id="subtitle"]]
+[[!template text="""apply to the message function in order to""" start="00:01:34.200" video="qanda-parallel" id="subtitle"]]
+[[!template text="""display a nice message in the echo buffer""" start="00:01:36.380" video="qanda-parallel" id="subtitle"]]
+[[!template text="""because this doesn't happen on its own when""" start="00:01:39.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""we're using this trick with this big regex""" start="00:01:41.100" video="qanda-parallel" id="subtitle"]]
+[[!template text="""and whatnot. So I don't think that the code""" start="00:01:45.360" video="qanda-parallel" id="subtitle"]]
+[[!template text="""as it is would be upstreamable.""" start="00:01:47.080" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I think probably if we wanted to upstream it,""" start="00:01:50.600" video="qanda-parallel" id="subtitle"]]
+[[!template text="""we would have to do some proper work on""" start="00:01:54.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""refactoring query place itself in order to""" start="00:01:57.180" video="qanda-parallel" id="subtitle"]]
+[[!template text="""integrate all of this functionality just""" start="00:01:58.780" video="qanda-parallel" id="subtitle"]]
+[[!template text="""directly without any patching left and right.""" start="00:02:01.880" video="qanda-parallel" id="subtitle"]]
+[[!template text="""But yeah, definitely something I've given""" start="00:02:05.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""some thought, but so far no progress on it.""" start="00:02:10.080" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I haven't actually started doing anything""" start="00:02:11.640" video="qanda-parallel" id="subtitle"]]
+[[!template text="""about it.""" start="00:02:12.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: Right, So I'm curious now,""" start="00:02:17.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""you developed the feature and then you moved""" start="00:02:19.640" video="qanda-parallel" id="subtitle"]]
+[[!template text="""on to the presentation or did you want to do""" start="00:02:21.600" video="qanda-parallel" id="subtitle"]]
+[[!template text="""a presentation for EmacsConf and then you""" start="00:02:23.080" video="qanda-parallel" id="subtitle"]]
+[[!template text="""worked on something like this?""" start="00:02:24.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Which was it first, the chicken or the egg?""" start="00:02:26.360" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: Yeah, it was the former.""" start="00:02:28.220" video="qanda-parallel" id="subtitle"]]
+[[!template text="""So this is a problem I've been aware of for,""" start="00:02:31.320" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I mean, probably a couple of years.""" start="00:02:33.340" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And, you know, I talked to my friend""" start="00:02:35.280" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Valentino about it and we had like a little""" start="00:02:37.600" video="qanda-parallel" id="subtitle"]]
+[[!template text="""discussion, you know, how would we do this?""" start="00:02:39.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And then I remember back when I was""" start="00:02:41.880" video="qanda-parallel" id="subtitle"]]
+[[!template text="""researching about this problem and the""" start="00:02:44.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""various Emacs Lisp solutions,""" start="00:02:45.100" video="qanda-parallel" id="subtitle"]]
+[[!template text="""all I could find were these solutions that""" start="00:02:47.780" video="qanda-parallel" id="subtitle"]]
+[[!template text="""would, you know, just shy away from""" start="00:02:49.400" video="qanda-parallel" id="subtitle"]]
+[[!template text="""implementing the RegEx case,""" start="00:02:50.640" video="qanda-parallel" id="subtitle"]]
+[[!template text="""which is a really complicated 1.""" start="00:02:52.340" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And, after some discussion,""" start="00:02:54.720" video="qanda-parallel" id="subtitle"]]
+[[!template text="""my friend and I decided,""" start="00:02:56.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""okay, what the hell? Let's,""" start="00:02:58.080" video="qanda-parallel" id="subtitle"]]
+[[!template text="""let's try and implement this.""" start="00:02:59.280" video="qanda-parallel" id="subtitle"]]
+[[!template text="""How hard can it be? And yeah,""" start="00:03:01.800" video="qanda-parallel" id="subtitle"]]
+[[!template text="""basically in 1 afternoon,""" start="00:03:03.280" video="qanda-parallel" id="subtitle"]]
+[[!template text="""the idea, our little trick and the whole""" start="00:03:06.300" video="qanda-parallel" id="subtitle"]]
+[[!template text="""implementation was born.""" start="00:03:07.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And then I think that was maybe around a year""" start="00:03:11.480" video="qanda-parallel" id="subtitle"]]
+[[!template text="""ago, maybe a bit less.""" start="00:03:12.540" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And then through the months,""" start="00:03:14.480" video="qanda-parallel" id="subtitle"]]
+[[!template text="""we just thought, oh yeah,""" start="00:03:15.920" video="qanda-parallel" id="subtitle"]]
+[[!template text="""maybe we could present this,""" start="00:03:17.420" video="qanda-parallel" id="subtitle"]]
+[[!template text="""maybe it would be interesting for people to""" start="00:03:18.960" video="qanda-parallel" id="subtitle"]]
+[[!template text="""see and that's how we came up with the idea""" start="00:03:20.660" video="qanda-parallel" id="subtitle"]]
+[[!template text="""to present at EmacsConf.""" start="00:03:22.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: Okay, great. I don't see other people asking""" start="00:03:27.900" video="qanda-parallel" id="subtitle"]]
+[[!template text="""questions. So people, it's nice if I ask""" start="00:03:30.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""questions but you know,""" start="00:03:31.100" video="qanda-parallel" id="subtitle"]]
+[[!template text="""the point is kind of for you to ask the""" start="00:03:33.160" video="qanda-parallel" id="subtitle"]]
+[[!template text="""questions. I see someone who's joined us on""" start="00:03:35.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""BBB. Peter, would you like to ask a question""" start="00:03:36.780" video="qanda-parallel" id="subtitle"]]
+[[!template text="""maybe? Otherwise I see another person writing""" start="00:03:41.720" video="qanda-parallel" id="subtitle"]]
+[[!template text="""a question on the pad,""" start="00:03:43.040" video="qanda-parallel" id="subtitle"]]
+[[!template text="""so we can either move for this 1.""" start="00:03:44.540" video="qanda-parallel" id="subtitle"]]
+[[!template text="""So I'll leave Peter to figure out if they""" start="00:03:46.640" video="qanda-parallel" id="subtitle"]]
+[[!template text="""want to ask a question.""" start="00:03:47.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""So I'm moving on to the next question.""" start="00:03:49.160" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 2]: I can jump in. That's a really well done talk""" start="00:03:57.900" video="qanda-parallel" id="subtitle"]]
+[[!template text="""and you really clearly laid out the problem""" start="00:04:01.780" video="qanda-parallel" id="subtitle"]]
+[[!template text="""and the solution there.""" start="00:04:03.000" video="qanda-parallel" id="subtitle"]]
+[[!template text="""While I was watching it,""" start="00:04:05.600" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I was thinking maybe the nice way to name it""" start="00:04:10.740" video="qanda-parallel" id="subtitle"]]
+[[!template text="""is just to name it query replace and query""" start="00:04:13.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""replace regext, you know,""" start="00:04:15.700" video="qanda-parallel" id="subtitle"]]
+[[!template text="""overloading the original functions and then""" start="00:04:18.480" video="qanda-parallel" id="subtitle"]]
+[[!template text="""using a prefix number,""" start="00:04:23.000" video="qanda-parallel" id="subtitle"]]
+[[!template text="""like control number to indicate how many""" start="00:04:26.880" video="qanda-parallel" id="subtitle"]]
+[[!template text="""replacements you're going to do.""" start="00:04:29.280" video="qanda-parallel" id="subtitle"]]
+[[!template text="""But maybe that doesn't work with the""" start="00:04:31.640" video="qanda-parallel" id="subtitle"]]
+[[!template text="""recursive editing stuff,""" start="00:04:36.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""which I don't use much.""" start="00:04:37.960" video="qanda-parallel" id="subtitle"]]
+[[!template text="""So I don't have a good method.""" start="00:04:40.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: I think it would definitely work.""" start="00:04:43.260" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Well, the question is,""" start="00:04:46.260" video="qanda-parallel" id="subtitle"]]
+[[!template text="""if we just overwrite the definitions,""" start="00:04:47.880" video="qanda-parallel" id="subtitle"]]
+[[!template text="""then, oh, well, I guess we could do that.""" start="00:04:51.700" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Nothing stops us. I mean,""" start="00:04:53.410" video="qanda-parallel" id="subtitle"]]
+[[!template text="""we're in Emacs. We could definitely do that.""" start="00:04:54.800" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And then if you give, like,""" start="00:04:55.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""a prefix argument, maybe it just drops you""" start="00:04:57.540" video="qanda-parallel" id="subtitle"]]
+[[!template text="""back to the original query replace.""" start="00:04:59.060" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Yeah, that's an idea. For now,""" start="00:05:01.000" video="qanda-parallel" id="subtitle"]]
+[[!template text="""we decided, OK, let's just keep everything""" start="00:05:02.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""explicitly separate just to avoid any""" start="00:05:05.000" video="qanda-parallel" id="subtitle"]]
+[[!template text="""confusion.""" start="00:05:05.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 2]: Yeah, I think that's the right thing to do""" start="00:05:09.220" video="qanda-parallel" id="subtitle"]]
+[[!template text="""for now. What I'm actually thinking is that""" start="00:05:11.820" video="qanda-parallel" id="subtitle"]]
+[[!template text="""when you do query replace,""" start="00:05:13.620" video="qanda-parallel" id="subtitle"]]
+[[!template text="""it just does the regular query replace.""" start="00:05:15.600" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And if you're going to do,""" start="00:05:17.220" video="qanda-parallel" id="subtitle"]]
+[[!template text="""say, 3 parallel replacements,""" start="00:05:20.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""then you do Control-U,""" start="00:05:21.340" video="qanda-parallel" id="subtitle"]]
+[[!template text="""query replace. Sorry. Control-3,""" start="00:05:25.580" video="qanda-parallel" id="subtitle"]]
+[[!template text="""query replace. And then that way you don't""" start="00:05:28.580" video="qanda-parallel" id="subtitle"]]
+[[!template text="""have The final prompt that you give nothing""" start="00:05:33.400" video="qanda-parallel" id="subtitle"]]
+[[!template text="""to.""" start="00:05:33.760" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: Exactly, that's actually not a bad idea.""" start="00:05:36.880" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I think I like that. Yeah,""" start="00:05:39.720" video="qanda-parallel" id="subtitle"]]
+[[!template text="""that's not a bad idea.""" start="00:05:40.800" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: It's always a quagmire whether to ask for an""" start="00:05:44.760" video="qanda-parallel" id="subtitle"]]
+[[!template text="""argument or to use the universal argument.""" start="00:05:47.080" video="qanda-parallel" id="subtitle"]]
+[[!template text="""When you're working with Emacs and especially""" start="00:05:51.060" video="qanda-parallel" id="subtitle"]]
+[[!template text="""the UX side of things in the package,""" start="00:05:52.640" video="qanda-parallel" id="subtitle"]]
+[[!template text="""it's so complicated to figure out which 1 you""" start="00:05:54.900" video="qanda-parallel" id="subtitle"]]
+[[!template text="""want to do. In this particular case,""" start="00:05:56.880" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I think it's the better option to use the""" start="00:06:00.340" video="qanda-parallel" id="subtitle"]]
+[[!template text="""universal argument or any kind of argument""" start="00:06:02.800" video="qanda-parallel" id="subtitle"]]
+[[!template text="""with a control number before.""" start="00:06:04.040" video="qanda-parallel" id="subtitle"]]
+[[!template text="""All right, we have about 3 more minutes of""" start="00:06:10.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""questions. Peter, if you don't mind,""" start="00:06:12.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I'll keep reading the questions in the chat.""" start="00:06:14.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Did you use pair programming while developing""" start="00:06:19.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""it, it being a package,""" start="00:06:21.100" video="qanda-parallel" id="subtitle"]]
+[[!template text="""or did you work independently,""" start="00:06:22.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""alternating and reviewing with Valentino?""" start="00:06:24.840" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: It was definitely a pair programming kind of""" start="00:06:28.320" video="qanda-parallel" id="subtitle"]]
+[[!template text="""thing. So if I remember correctly,""" start="00:06:29.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I was sitting at the computer and Valentino""" start="00:06:32.760" video="qanda-parallel" id="subtitle"]]
+[[!template text="""was in front of a whiteboard and we were just""" start="00:06:36.020" video="qanda-parallel" id="subtitle"]]
+[[!template text="""dissecting this regex and a bunch of examples""" start="00:06:38.400" video="qanda-parallel" id="subtitle"]]
+[[!template text="""and trying to get these capture groups and""" start="00:06:41.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""stuff that we have to remap internally to get""" start="00:06:44.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""these offsets right and avoid off by 1 error""" start="00:06:46.560" video="qanda-parallel" id="subtitle"]]
+[[!template text="""and stuff like that. So yeah,""" start="00:06:48.160" video="qanda-parallel" id="subtitle"]]
+[[!template text="""definitely a team effort.""" start="00:06:49.280" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: Okay, great. Moving on to the next question.""" start="00:06:53.660" video="qanda-parallel" id="subtitle"]]
+[[!template text="""What is your background in programming?""" start="00:06:55.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Was it difficult to implement following the""" start="00:06:57.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""same API and architecture as what is already""" start="00:06:59.700" video="qanda-parallel" id="subtitle"]]
+[[!template text="""in Emacs?""" start="00:07:00.200" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: So maybe just a quick back story.""" start="00:07:05.400" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Both Valentino and I are actually PhD""" start="00:07:06.960" video="qanda-parallel" id="subtitle"]]
+[[!template text="""students in computer science,""" start="00:07:08.300" video="qanda-parallel" id="subtitle"]]
+[[!template text="""and we literally share an office.""" start="00:07:09.960" video="qanda-parallel" id="subtitle"]]
+[[!template text="""So that's how we even started talking about""" start="00:07:12.960" video="qanda-parallel" id="subtitle"]]
+[[!template text="""this whole thing. And we both use Emacs,""" start="00:07:14.480" video="qanda-parallel" id="subtitle"]]
+[[!template text="""of course. But I don't think this was too""" start="00:07:18.380" video="qanda-parallel" id="subtitle"]]
+[[!template text="""hard to implement because luckily all of the""" start="00:07:20.740" video="qanda-parallel" id="subtitle"]]
+[[!template text="""interactive functionality like this""" start="00:07:22.300" video="qanda-parallel" id="subtitle"]]
+[[!template text="""complicated undo, skipping,""" start="00:07:23.600" video="qanda-parallel" id="subtitle"]]
+[[!template text="""execute until the end and so on,""" start="00:07:25.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""all of this is really just already provided""" start="00:07:27.980" video="qanda-parallel" id="subtitle"]]
+[[!template text="""by the Emacs queer replace implementation.""" start="00:07:29.860" video="qanda-parallel" id="subtitle"]]
+[[!template text="""So sort of what we do is we just invoke it as""" start="00:07:34.160" video="qanda-parallel" id="subtitle"]]
+[[!template text="""a function and delegate to it.""" start="00:07:36.080" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And we came up with this clever trick to""" start="00:07:37.800" video="qanda-parallel" id="subtitle"]]
+[[!template text="""basically delegate this multi-replacement to""" start="00:07:42.380" video="qanda-parallel" id="subtitle"]]
+[[!template text="""this 1 single function that's already there.""" start="00:07:45.160" video="qanda-parallel" id="subtitle"]]
+[[!template text="""So it wasn't too complicated.""" start="00:07:47.980" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: Alright. And we have about 2 minutes of time""" start="00:07:54.780" video="qanda-parallel" id="subtitle"]]
+[[!template text="""for the last question.""" start="00:07:55.560" video="qanda-parallel" id="subtitle"]]
+[[!template text="""What did you learn about Emacs programming or""" start="00:07:58.040" video="qanda-parallel" id="subtitle"]]
+[[!template text="""programming in general while working on this""" start="00:08:00.020" video="qanda-parallel" id="subtitle"]]
+[[!template text="""project? A very wide question for me.""" start="00:08:02.320" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: Maybe 1 thing I would like to add to the""" start="00:08:05.840" video="qanda-parallel" id="subtitle"]]
+[[!template text="""previous just answer is I don't want to say""" start="00:08:09.220" video="qanda-parallel" id="subtitle"]]
+[[!template text="""like you know we're PhDs,""" start="00:08:10.160" video="qanda-parallel" id="subtitle"]]
+[[!template text="""a PhD is required for this or anything,""" start="00:08:12.780" video="qanda-parallel" id="subtitle"]]
+[[!template text="""not at all. It's mostly just for a little bit""" start="00:08:15.800" video="qanda-parallel" id="subtitle"]]
+[[!template text="""of context, but I think obviously,""" start="00:08:19.220" video="qanda-parallel" id="subtitle"]]
+[[!template text="""even if you're not a PhD,""" start="00:08:20.640" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I mean, you don't even require like""" start="00:08:22.360" video="qanda-parallel" id="subtitle"]]
+[[!template text="""university, you know, education or anything.""" start="00:08:24.960" video="qanda-parallel" id="subtitle"]]
+[[!template text="""It wasn't overly difficult to implement,""" start="00:08:27.540" video="qanda-parallel" id="subtitle"]]
+[[!template text="""sort of just read some code that's already""" start="00:08:30.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""there and you know follow what you see and""" start="00:08:33.539" video="qanda-parallel" id="subtitle"]]
+[[!template text="""poke Emacs a little bit and do a little bit""" start="00:08:35.860" video="qanda-parallel" id="subtitle"]]
+[[!template text="""of debugging on the internals and you can""" start="00:08:38.140" video="qanda-parallel" id="subtitle"]]
+[[!template text="""definitely get it. So definitely not a""" start="00:08:40.280" video="qanda-parallel" id="subtitle"]]
+[[!template text="""prerequisite to have a degree or anything to""" start="00:08:42.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""do any of this stuff. Okay so Coming back to""" start="00:08:45.480" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: Yeah, I'm going to amend a little bit the""" start="00:08:48.420" video="qanda-parallel" id="subtitle"]]
+[[!template text="""question because we only have 1 minute.""" start="00:08:49.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""So just 1 thing in 10 seconds,""" start="00:08:51.600" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 2]: what did you""" start="00:08:52.490" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: learn about this?""" start="00:08:53.040" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: your last question. What did I learn about""" start="00:08:54.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Emacs programming? That Emacs is so flexible""" start="00:08:56.420" video="qanda-parallel" id="subtitle"]]
+[[!template text="""that I can go and I can patch literally its""" start="00:08:59.160" video="qanda-parallel" id="subtitle"]]
+[[!template text="""message function. And that is how we achieve""" start="00:09:01.480" video="qanda-parallel" id="subtitle"]]
+[[!template text="""the nice message function in the echo buffer.""" start="00:09:03.680" video="qanda-parallel" id="subtitle"]]
+[[!template text="""So I can literally go and patch something as""" start="00:09:06.720" video="qanda-parallel" id="subtitle"]]
+[[!template text="""crucial as message.""" start="00:09:07.560" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: It's great. That's a lovely 1.""" start="00:09:09.920" video="qanda-parallel" id="subtitle"]]
+[[!template text="""And I think, again, we're going back to the""" start="00:09:12.260" video="qanda-parallel" id="subtitle"]]
+[[!template text="""philosophy of Emacs. Everything is""" start="00:09:13.660" video="qanda-parallel" id="subtitle"]]
+[[!template text="""programmable and even changing the message""" start="00:09:15.200" video="qanda-parallel" id="subtitle"]]
+[[!template text="""function is great. All right,""" start="00:09:16.640" video="qanda-parallel" id="subtitle"]]
+[[!template text="""well, thank you so much,""" start="00:09:17.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Lovro, and thanks to Valentino as well,""" start="00:09:19.540" video="qanda-parallel" id="subtitle"]]
+[[!template text="""who's not here, but who's contributed to this""" start="00:09:21.820" video="qanda-parallel" id="subtitle"]]
+[[!template text="""talk. Any last word?""" start="00:09:23.900" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: Well, just if you're gonna build any""" start="00:09:29.540" video="qanda-parallel" id="subtitle"]]
+[[!template text="""solutions, try to make them as foolproof and""" start="00:09:31.980" video="qanda-parallel" id="subtitle"]]
+[[!template text="""as 100% as possible so we get more of these""" start="00:09:34.360" video="qanda-parallel" id="subtitle"]]
+[[!template text="""goodies that are nice and robust for""" start="00:09:36.280" video="qanda-parallel" id="subtitle"]]
+[[!template text="""everybody to use.""" start="00:09:37.000" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: All right, lovely. Well,""" start="00:09:39.400" video="qanda-parallel" id="subtitle"]]
+[[!template text="""thank you so much, Lover,""" start="00:09:40.240" video="qanda-parallel" id="subtitle"]]
+[[!template text="""for your presentation and your answer.""" start="00:09:41.940" video="qanda-parallel" id="subtitle"]]
+[[!template text="""We'll be moving on to the next talk in just""" start="00:09:44.340" video="qanda-parallel" id="subtitle"]]
+[[!template text="""about 5 seconds, and I'll see you after.""" start="00:09:47.260" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Bye, Lovro!""" start="00:09:47.900" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: Yep, bye bye!""" start="00:09:49.760" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 0]: So I'm just waiting to make sure my VNC is a""" start="00:10:01.440" video="qanda-parallel" id="subtitle"]]
+[[!template text="""little slow. Okay, we switch to the next""" start="00:10:02.840" video="qanda-parallel" id="subtitle"]]
+[[!template text="""talk. All right, Lover,""" start="00:10:03.480" video="qanda-parallel" id="subtitle"]]
+[[!template text="""I'm gonna need to go get ready now.""" start="00:10:04.960" video="qanda-parallel" id="subtitle"]]
+[[!template text="""Yep. Bye-bye, and thanks for your talk.""" start="00:10:09.060" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 1]: Bye, thank you, see you.""" start="00:10:11.160" video="qanda-parallel" id="subtitle"]]
+[[!template text="""[Speaker 2]: You""" start="00:10:15.060" video="qanda-parallel" id="subtitle"]]
+
+Questions or comments? Please e-mail [hokomo@disroot.org](mailto:hokomo@disroot.org?subject=Comment%20for%20EmacsConf%202023%20parallel%3A%20Parallel%20text%20replacement)
+
+
+<!-- End of emacsconf-publish-after-page -->