From 339a682e1b832859d7018e42747ec7690cefbb2e Mon Sep 17 00:00:00 2001 From: staticdev Date: Thu, 25 Nov 2021 22:13:05 +0100 Subject: [PATCH 01/21] Fix url for Event Storming --- epilogue_1_how_to_get_there_from_here.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/epilogue_1_how_to_get_there_from_here.asciidoc b/epilogue_1_how_to_get_there_from_here.asciidoc index c5e91f91..aa824b21 100644 --- a/epilogue_1_how_to_get_there_from_here.asciidoc +++ b/epilogue_1_how_to_get_there_from_here.asciidoc @@ -631,7 +631,7 @@ storming and CRC modeling, because humans are good at collaborating through play. _Event modeling_ is another technique that brings engineers and product owners together to understand a system in terms of commands, queries, and events. -TIP: Check out _www.eventmodeling.org_ and _www.eventstorming.org_ for some great +TIP: Check out _www.eventmodeling.org_ and _www.eventstorming.com_ for some great guides to visual modeling of systems with events. The goal is to be able to talk about the system by using the same ubiquitous From 190b5f195c6c711fb6008693124adbb6226811cd Mon Sep 17 00:00:00 2001 From: Conrad Date: Wed, 2 Mar 2022 16:21:29 +0800 Subject: [PATCH 02/21] Fix code comment location --- chapter_01_domain_model.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chapter_01_domain_model.asciidoc b/chapter_01_domain_model.asciidoc index f1df86a8..887bb86e 100644 --- a/chapter_01_domain_model.asciidoc +++ b/chapter_01_domain_model.asciidoc @@ -287,8 +287,8 @@ class Batch: self.eta = eta self.available_quantity = qty - def allocate(self, line: OrderLine): - self.available_quantity -= line.qty #<3> + def allocate(self, line: OrderLine): #<3> + self.available_quantity -= line.qty ---- ==== From f636a80ee241b62e5b4055a36464d6f57059390d Mon Sep 17 00:00:00 2001 From: Stephen Daves Date: Sat, 16 Apr 2022 20:54:35 -0400 Subject: [PATCH 03/21] Fix code indentation in appendix validation --- appendix_validation.asciidoc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/appendix_validation.asciidoc b/appendix_validation.asciidoc index 2bc38a93..1a305cdc 100644 --- a/appendix_validation.asciidoc +++ b/appendix_validation.asciidoc @@ -74,8 +74,8 @@ class Allocate(Command): @classmethod def from_json(cls, data): #<2> - data = json.loads(data) - return cls(**_schema.validate(data)) + data = json.loads(data) + return cls(**_schema.validate(data)) ---- ==== @@ -298,7 +298,7 @@ def handle_change_batch_quantity(m, bus: messagebus.MessageBus): try: bus.handle_message('ChangeBatchQuantity', m) except ValidationError: - print('Skipping invalid message') + print('Skipping invalid message') except exceptions.InvalidSku as e: print(f'Unable to change stock for missing sku {e}') ---- @@ -360,10 +360,10 @@ class MessageUnprocessable(Exception): #<1> self.message = message class ProductNotFound(MessageUnprocessable): #<2> - """" - This exception is raised when we try to perform an action on a product - that doesn't exist in our database. - """" + """" + This exception is raised when we try to perform an action on a product + that doesn't exist in our database. + """" def __init__(self, message): super().__init__(message) @@ -448,9 +448,9 @@ class MessageBus: def handle_message(self, message): try: - ... - except SkipMessage as e: - logging.warn(f"Skipping message {message.id} because {e.reason}") + ... + except SkipMessage as e: + logging.warn(f"Skipping message {message.id} because {e.reason}") ---- ==== From aa7db9e7cc1384b10895c14b2252901f2b2850aa Mon Sep 17 00:00:00 2001 From: Harry Date: Sat, 23 Apr 2022 09:04:15 +0100 Subject: [PATCH 04/21] whitespace tweaks --- chapter_02_repository.asciidoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/chapter_02_repository.asciidoc b/chapter_02_repository.asciidoc index d6b2568d..cd7bd7fe 100644 --- a/chapter_02_repository.asciidoc +++ b/chapter_02_repository.asciidoc @@ -548,7 +548,8 @@ class AbstractRepository(abc.ABC): ((("@abc.abstractmethod"))) ((("abstract methods"))) -<2> `raise NotImplementedError` is nice, but it's neither necessary nor sufficient. In fact, your abstract methods can have real behavior that subclasses +<2> `raise NotImplementedError` is nice, but it's neither necessary nor sufficient. + In fact, your abstract methods can have real behavior that subclasses can call out to, if you really want. [role="pagebreak-before less_space"] @@ -805,7 +806,8 @@ def allocate_endpoint(): We bumped into a friend at a DDD conference the other day who said, "I haven't used an ORM in 10 years." The Repository pattern and an ORM both act as abstractions in front of raw SQL, so using one behind the other isn't really necessary. Why -not have a go at implementing our repository without using the ORM? You'll find the code https://github.com/cosmicpython/code/tree/chapter_02_repository_exercise[on GitHub]. +not have a go at implementing our repository without using the ORM? +You'll find the code https://github.com/cosmicpython/code/tree/chapter_02_repository_exercise[on GitHub]. We've left the repository tests, but figuring out what SQL to write is up to you. Perhaps it'll be harder than you think; perhaps it'll be easier. @@ -904,7 +906,7 @@ summarize the costs and benefits of each architectural pattern we introduce. We want to be clear that we're not saying every single application needs to be built this way; only sometimes does the complexity of the app and domain make it worth investing the time and effort in adding these extra layers of -indirection. +indirection. With that in mind, <> shows some of the pros and cons of the Repository pattern and our persistence-ignorant From b850883e20d3540acf9660c7b6f63e39604d2785 Mon Sep 17 00:00:00 2001 From: Harry Date: Sat, 23 Apr 2022 09:12:59 +0100 Subject: [PATCH 05/21] extra hint for exercise 1 --- chapter_01_domain_model.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter_01_domain_model.asciidoc b/chapter_01_domain_model.asciidoc index 887bb86e..194a8526 100644 --- a/chapter_01_domain_model.asciidoc +++ b/chapter_01_domain_model.asciidoc @@ -232,7 +232,7 @@ how we would construct a model from this business conversation. ****************************************************************************** Why not have a go at solving this problem yourself? Write a few unit tests to see if you can capture the essence of these business rules in nice, clean -code. +code (ideally without looking at the solution we came up with below!) You'll find some https://github.com/cosmicpython/code/tree/chapter_01_domain_model_exercise[placeholder unit tests on GitHub], but you could just start from scratch, or combine/rewrite them however you like. From 667b2fd80e09251871dc4e20e645eae3ecb42442 Mon Sep 17 00:00:00 2001 From: Harry Date: Sat, 23 Apr 2022 09:14:08 +0100 Subject: [PATCH 06/21] thanks to Dmitry --- preface.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/preface.asciidoc b/preface.asciidoc index d132ec4d..12c91f8a 100644 --- a/preface.asciidoc +++ b/preface.asciidoc @@ -347,6 +347,7 @@ Ben Judson, James Gregory, Łukasz Lechowicz, Clinton Roy, Vitorino Araújo, Susan Goodbody, Josh Harwood, Daniel Butler, Liu Haibin, Jimmy Davies, Ignacio Vergara Kausel, Gaia Canestrani, Renne Rocha, pedroabi, Ashia Zawaduk, Jostein Leira, Brandon Rhodes, Jazeps Basko, simkimsia, Adrien Brunet, Sergey Nosko, +Dmitry Bychkov, and many more; our apologies if we missed you on this list. Super-mega-thanks to our editor Corbin Collins for his gentle chivvying, and From cf046d11d3d9b8a16c52aff810412a8e85e55e8d Mon Sep 17 00:00:00 2001 From: Isidro Arias Date: Sun, 18 Sep 2022 14:11:10 +0200 Subject: [PATCH 07/21] Added quotes to dict keys --- appendix_validation.asciidoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appendix_validation.asciidoc b/appendix_validation.asciidoc index 1a305cdc..6be1b574 100644 --- a/appendix_validation.asciidoc +++ b/appendix_validation.asciidoc @@ -63,9 +63,9 @@ from schema import And, Schema, Use class Allocate(Command): _schema = Schema({ #<1> - 'orderid': int, - sku: str, - qty: And(Use(int), lambda n: n > 0) + 'orderid': str, + 'sku': str, + 'qty'': And(Use(int), lambda n: n > 0) }, ignore_extra_keys=True) orderid: str From 395f0167da1b793e35b2de6b52e192164b407283 Mon Sep 17 00:00:00 2001 From: Isidro Arias Date: Sun, 18 Sep 2022 14:11:34 +0200 Subject: [PATCH 08/21] Added class name to 'command' --- appendix_validation.asciidoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appendix_validation.asciidoc b/appendix_validation.asciidoc index 6be1b574..d1b04a1d 100644 --- a/appendix_validation.asciidoc +++ b/appendix_validation.asciidoc @@ -111,12 +111,14 @@ def greater_than_zero(x): quantity = And(Use(int), greater_than_zero) #<4> Allocate = command( #<5> + 'Allocate', orderid=int, sku=str, qty=quantity ) AddStock = command( + 'AddStock', sku=str, qty=quantity ---- From 268add87c5cce7a08308ce81a63bc6b96b2c4263 Mon Sep 17 00:00:00 2001 From: Isidro Arias Date: Sun, 18 Sep 2022 17:50:07 +0200 Subject: [PATCH 09/21] extra quote --- appendix_validation.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appendix_validation.asciidoc b/appendix_validation.asciidoc index d1b04a1d..6fd2eb4c 100644 --- a/appendix_validation.asciidoc +++ b/appendix_validation.asciidoc @@ -65,7 +65,7 @@ class Allocate(Command): _schema = Schema({ #<1> 'orderid': str, 'sku': str, - 'qty'': And(Use(int), lambda n: n > 0) + 'qty': And(Use(int), lambda n: n > 0) }, ignore_extra_keys=True) orderid: str From d96955237bcf0009f1b2aa1ac56004f686a9b726 Mon Sep 17 00:00:00 2001 From: Harry Date: Mon, 6 Feb 2023 16:24:44 +0000 Subject: [PATCH 10/21] tighten language re types of service, thanks Vinicius --- chapter_04_service_layer.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter_04_service_layer.asciidoc b/chapter_04_service_layer.asciidoc index 089220af..83bf6a57 100644 --- a/chapter_04_service_layer.asciidoc +++ b/chapter_04_service_layer.asciidoc @@ -558,7 +558,7 @@ def allocate_endpoint(): <1> We instantiate a database session and some repository objects. <2> We extract the user's commands from the web request and pass them - to a domain service. + to the service layer. <3> We return some JSON responses with the appropriate status codes. The responsibilities of the Flask app are just standard web stuff: per-request From ff3ffb78414803183da63f5458b250a2416ae5f6 Mon Sep 17 00:00:00 2001 From: Harry Date: Mon, 6 Feb 2023 16:32:05 +0000 Subject: [PATCH 11/21] fix broken link thanks banditelol --- chapter_03_abstractions.asciidoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chapter_03_abstractions.asciidoc b/chapter_03_abstractions.asciidoc index 1d9c509b..b85981fb 100644 --- a/chapter_03_abstractions.asciidoc +++ b/chapter_03_abstractions.asciidoc @@ -24,7 +24,8 @@ git checkout chapter_03_abstractions A key theme in this book, hidden among the fancy patterns, is that we can use simple abstractions to hide messy details. When we're writing code for fun, or in a kata,footnote:[A code kata is a small, contained programming challenge often -used to practice TDD. See https://oreil.ly/vhjju["Kata—The Only Way to Learn TDD"] by Peter Provost.] +used to practice TDD. See +https://web.archive.org/web/20221024055359/http://www.peterprovost.org/blog/2012/05/02/kata-the-only-way-to-learn-tdd/["Kata—The Only Way to Learn TDD"] by Peter Provost.] we get to play with ideas freely, hammering things out and refactoring aggressively. In a large-scale system, though, we become constrained by the decisions made elsewhere in the system. From 59b11903c5809cfdb02015fe5ef11b5a97c2df82 Mon Sep 17 00:00:00 2001 From: route92 <133750395+route92@users.noreply.github.com> Date: Tue, 16 May 2023 09:55:59 +0200 Subject: [PATCH 12/21] Pudding should now be less messy Fixed "the proof is in the pudding" to "the proof of the pudding". The phrase is: "The proof of the pudding is in the eating." That's how you know it's pudding. If the proof would be in the pudding, it would just be messy. --- part1.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/part1.asciidoc b/part1.asciidoc index a44eecf2..9e066c8c 100644 --- a/part1.asciidoc +++ b/part1.asciidoc @@ -60,7 +60,7 @@ Three appendices are further explorations of the content from Part I: code: how we build and run the Docker images, where we manage configuration info, and how we run different types of tests. -* <> is a "proof is in the pudding" kind of content, showing +* <> is a "proof of the pudding" kind of content, showing how easy it is to swap out our entire infrastructure--the Flask API, the ORM, and Postgres—for a totally different I/O model involving a CLI and CSVs. From f8fcd9bb80bd51c9f1f6c946aa9101077cc67a05 Mon Sep 17 00:00:00 2001 From: birdca Date: Tue, 23 May 2023 20:11:24 +0800 Subject: [PATCH 13/21] fix: grep command --- chapter_05_high_gear_low_gear.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter_05_high_gear_low_gear.asciidoc b/chapter_05_high_gear_low_gear.asciidoc index bfb1366e..265f159c 100644 --- a/chapter_05_high_gear_low_gear.asciidoc +++ b/chapter_05_high_gear_low_gear.asciidoc @@ -48,7 +48,7 @@ does to our test pyramid: [source,sh] [role="skip"] ---- -$ grep -c test_ **/test_*.py +$ grep -c test_ */*/test_*.py tests/unit/test_allocate.py:4 tests/unit/test_batches.py:8 tests/unit/test_services.py:3 From 609d5a2303c632012bee7105a6d83eb03f4b708a Mon Sep 17 00:00:00 2001 From: Harry Date: Mon, 11 Sep 2023 14:11:01 +0100 Subject: [PATCH 14/21] Fix code issue 4, add explanation re nested tuple unpacking --- chapter_06_uow.asciidoc | 14 +++++++++++--- code | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/chapter_06_uow.asciidoc b/chapter_06_uow.asciidoc index 9420e0ad..24c9a2a2 100644 --- a/chapter_06_uow.asciidoc +++ b/chapter_06_uow.asciidoc @@ -169,11 +169,11 @@ def insert_batch(session, ref, sku, qty, eta): def get_allocated_batch_ref(session, orderid, sku): - [[orderlineid]] = session.execute( + [[orderlineid]] = session.execute( #<1> "SELECT id FROM order_lines WHERE orderid=:orderid AND sku=:sku", dict(orderid=orderid, sku=sku), ) - [[batchref]] = session.execute( + [[batchref]] = session.execute( #<1> "SELECT b.reference FROM allocations JOIN batches AS b ON batch_id = b.id" " WHERE orderline_id=:orderlineid", dict(orderlineid=orderlineid), @@ -182,7 +182,15 @@ def get_allocated_batch_ref(session, orderid, sku): ---- ==== -// TODO: that double-unpacking is freaking ppl out. maybe [(orderlineid, )] ? +<1> The `[[orderlineid]] =` syntax is a little too-clever-by-half, apologies. + What's happening is that `session.execute` returns a list of rows, + where each row is a tuple of column values; + in our specific case, it's a list of one row, + which is a tuple with one column value in. + The double-square-bracket on the left hand side + is doing (double) assignment-unpacking to get the single value + back out of these two nested sequences. + It becomes readable once you've used it a few times! === Unit of Work and Its Context Manager diff --git a/code b/code index 3ed6ff0f..734df09a 160000 --- a/code +++ b/code @@ -1 +1 @@ -Subproject commit 3ed6ff0fab52e14edba6ced4b258af68c521115f +Subproject commit 734df09afc65ba43c851271def147c70ac3c3b98 From a0679777ac4372bf6de572f055af0614f8f61fa9 Mon Sep 17 00:00:00 2001 From: Harry Date: Thu, 22 Feb 2024 23:21:14 +0000 Subject: [PATCH 15/21] fix a problem with the isolated-fakemessagebus --- chapter_09_all_messagebus.asciidoc | 7 +++---- preface.asciidoc | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/chapter_09_all_messagebus.asciidoc b/chapter_09_all_messagebus.asciidoc index df129145..0ef9a65d 100644 --- a/chapter_09_all_messagebus.asciidoc +++ b/chapter_09_all_messagebus.asciidoc @@ -845,10 +845,9 @@ class FakeUnitOfWorkWithFakeMessageBus(FakeUnitOfWork): super().__init__() self.events_published = [] # type: List[events.Event] - def publish_events(self): - for product in self.products.seen: - while product.events: - self.events_published.append(product.events.pop(0)) + def collect_new_events(self): + self.events_published += super().collect_new_events() + return [] ---- ==== diff --git a/preface.asciidoc b/preface.asciidoc index 12c91f8a..4369e2d1 100644 --- a/preface.asciidoc +++ b/preface.asciidoc @@ -347,7 +347,7 @@ Ben Judson, James Gregory, Łukasz Lechowicz, Clinton Roy, Vitorino Araújo, Susan Goodbody, Josh Harwood, Daniel Butler, Liu Haibin, Jimmy Davies, Ignacio Vergara Kausel, Gaia Canestrani, Renne Rocha, pedroabi, Ashia Zawaduk, Jostein Leira, Brandon Rhodes, Jazeps Basko, simkimsia, Adrien Brunet, Sergey Nosko, -Dmitry Bychkov, +Dmitry Bychkov, dayres2, programmer-ke and many more; our apologies if we missed you on this list. Super-mega-thanks to our editor Corbin Collins for his gentle chivvying, and From d25c4c2dc006166cf927fbf776ade9eb49e3fc26 Mon Sep 17 00:00:00 2001 From: Harry Date: Thu, 6 Jun 2024 09:50:44 +0100 Subject: [PATCH 16/21] Add asjhita to acks, he helped fix #352 cf https://github.com/cosmicpython/cosmicpython.github.io/commit/af73230b3950023383282070e00e6c68e3b009f6 --- preface.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/preface.asciidoc b/preface.asciidoc index 4369e2d1..3c740cd8 100644 --- a/preface.asciidoc +++ b/preface.asciidoc @@ -347,7 +347,7 @@ Ben Judson, James Gregory, Łukasz Lechowicz, Clinton Roy, Vitorino Araújo, Susan Goodbody, Josh Harwood, Daniel Butler, Liu Haibin, Jimmy Davies, Ignacio Vergara Kausel, Gaia Canestrani, Renne Rocha, pedroabi, Ashia Zawaduk, Jostein Leira, Brandon Rhodes, Jazeps Basko, simkimsia, Adrien Brunet, Sergey Nosko, -Dmitry Bychkov, dayres2, programmer-ke +Dmitry Bychkov, dayres2, programmer-ke, asjhita, and many more; our apologies if we missed you on this list. Super-mega-thanks to our editor Corbin Collins for his gentle chivvying, and From ff1fe7aedd734fcda1a7b88d25907c1288269cb4 Mon Sep 17 00:00:00 2001 From: Dmytro Chebruchan <47272162+DmytroChebruchan@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:56:57 +0300 Subject: [PATCH 17/21] Update part1.asciidoc Change of link to Service Layer pattern. Link should be for words "Service Layer pattern" as with other patterns and not only for words "Service Layer". --- part1.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/part1.asciidoc b/part1.asciidoc index 9e066c8c..2d357b7d 100644 --- a/part1.asciidoc +++ b/part1.asciidoc @@ -32,7 +32,7 @@ To do that, we present four key design patterns: * The <>, an abstraction over the idea of persistent storage -* The <> pattern to clearly define where our +* The <> to clearly define where our use cases begin and end [role="pagebreak-before"] From 5574eb4bd3118978f2f6a86cd2f9022520685a78 Mon Sep 17 00:00:00 2001 From: Harry Date: Wed, 5 Feb 2025 13:06:17 +0000 Subject: [PATCH 18/21] fix link to nat freeman mocking talk --- chapter_03_abstractions.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter_03_abstractions.asciidoc b/chapter_03_abstractions.asciidoc index b85981fb..8f7af2a8 100644 --- a/chapter_03_abstractions.asciidoc +++ b/chapter_03_abstractions.asciidoc @@ -784,7 +784,7 @@ story we care about. ((("PyCon talk on Mocking Pitfalls"))) ((("Jung, Ed"))) Steve Freeman has a great example of overmocked tests in his talk -https://oreil.ly/jAmtr["Test-Driven Development"]. +https://youtu.be/yuEbZYKgZas?si=ZpBoivlDH13XTG9p&t=294["Test-Driven Development: That's Not What We Meant"]. You should also check out this PyCon talk, https://oreil.ly/s3e05["Mocking and Patching Pitfalls"], by our esteemed tech reviewer, Ed Jung, which also addresses mocking and its alternatives. From 140f177023db7d171bf510be8664fcdf5d0d1eff Mon Sep 17 00:00:00 2001 From: Filip Lajszczak Date: Sat, 15 Feb 2025 07:16:53 +0000 Subject: [PATCH 19/21] Makes presentation of alternative constructor of FakeRepository consistent with the current shape of it in Chapter 2. --- chapter_05_high_gear_low_gear.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chapter_05_high_gear_low_gear.asciidoc b/chapter_05_high_gear_low_gear.asciidoc index 265f159c..a6d8550d 100644 --- a/chapter_05_high_gear_low_gear.asciidoc +++ b/chapter_05_high_gear_low_gear.asciidoc @@ -310,7 +310,7 @@ function on `FakeRepository`: [source,python] [role="skip"] ---- -class FakeRepository(set): +class FakeRepository(repository.AbstractRepository): @staticmethod def for_batch(ref, sku, qty, eta=None): From 7e10e79c1db961ea071daf57c4aed3089d9b7ed2 Mon Sep 17 00:00:00 2001 From: Harry Date: Mon, 12 May 2025 12:03:27 +0100 Subject: [PATCH 20/21] extra ack for filip --- preface.asciidoc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/preface.asciidoc b/preface.asciidoc index 3c740cd8..d8b98e78 100644 --- a/preface.asciidoc +++ b/preface.asciidoc @@ -347,7 +347,7 @@ Ben Judson, James Gregory, Łukasz Lechowicz, Clinton Roy, Vitorino Araújo, Susan Goodbody, Josh Harwood, Daniel Butler, Liu Haibin, Jimmy Davies, Ignacio Vergara Kausel, Gaia Canestrani, Renne Rocha, pedroabi, Ashia Zawaduk, Jostein Leira, Brandon Rhodes, Jazeps Basko, simkimsia, Adrien Brunet, Sergey Nosko, -Dmitry Bychkov, dayres2, programmer-ke, asjhita, +Dmitry Bychkov, dayres2, programmer-ke, asjhita, Filip Lajszczak, and many more; our apologies if we missed you on this list. Super-mega-thanks to our editor Corbin Collins for his gentle chivvying, and @@ -356,6 +356,4 @@ the production staff, Katherine Tozer, Sharon Wilkey, Ellen Troutman-Zaig, and Rebecca Demarest, for your dedication, professionalism, and attention to detail. This book is immeasurably improved thanks to you. -// TODO thanks to rest of OR team. - Any errors remaining in the book are our own, naturally. From 14c204a609f50ef3a38c0bff87b1db6c7d14cbc9 Mon Sep 17 00:00:00 2001 From: Tom Nguyen <7121553+tunggnu@users.noreply.github.com> Date: Thu, 17 Jul 2025 14:24:59 +0700 Subject: [PATCH 21/21] Fix a minor syntax error in asciidoctor-clean.custom.css Although all browsers will render the generated HTML files correctly even if they are missing a curly bracket, it's better to fix this error. --- theme/asciidoctor-clean.custom.css | 1 + 1 file changed, 1 insertion(+) diff --git a/theme/asciidoctor-clean.custom.css b/theme/asciidoctor-clean.custom.css index 00a945c5..ac11c462 100644 --- a/theme/asciidoctor-clean.custom.css +++ b/theme/asciidoctor-clean.custom.css @@ -89,3 +89,4 @@ table { width: 55vw!important; font-size: 3vw; } +}