diff --git a/resources/compass/schedule_20240909.edn b/resources/compass/schedule_20240909.edn
new file mode 100644
index 0000000..ce63d00
--- /dev/null
+++ b/resources/compass/schedule_20240909.edn
@@ -0,0 +1,261 @@
+({:session/time #time/zdt "2024-09-18T09:30+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/lu-wilson.png",
+ :session/title "What it means to be open",
+ :session/description
+ "As a community, as collaborators, as coders, what does it mean to be \"open\"?\r\n\r\nThis goes way beyond \"open source\". Open practice can mean opening yourself up to vulnerability. It can mean opening the door to outside influence. It can also bring great benefit and *surprise*.\r\n\r\nI know this because I used to work in a very closed-off way. But over the past ten years, I've gradually adopted a more open practice. I am still learning what it really means to be open, but I want to (openly) share everything I've learned so far about the unexpected rewards it can bring.\r\n\r\nNormalise sharing scrappy fiddles!\n\n## Speakers\n\n\n### Lu Wilson\n\nLu creates slightly-surreal videos about creative-coding under the Todepond moniker. They are one of the hosts of the Future of Coding podcast, a coder at tldraw, and a researcher in residence at Ink and Switch.\n",
+ :session/subtitle "Lu Wilson",
+ :session/location :location.type/depot,
+ :session/code "GJF8UZ",
+ :session/type :session.type/keynote,
+ :session/capacity 300,
+ :session/duration "PT45M"}
+ {:session/time #time/zdt "2024-09-18T10:35+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/anna-colom.png",
+ :session/title
+ "From hype to responsibility: what works and matters for whom in data and AI?",
+ :session/description
+ "We are going through unprecedented times in the pace and scale of technological development driven by data and AI systems. Yet, these developments and their applications are being led and decided by a few in -still by large- a regulatory vacuum, supported by narratives driven by hype and power asymmetries. There is however a large and more diverse community of technology developers across the globe who can claim back the authority if it refuses to be blinded by hype; if it questions decisions made by a few; if it favours evidence and ethics over magic; and if it works collaborative with the rest of society to answer some of the most pressing questions of out times on how data and AI can be responsibly used to help people make this world a better place.\n\n## Speakers\n\n\n### Anna Colom\n\nAnna is a senior lead, researcher and evaluator working at the intersections of digital technologies, democratic processes, justice and climate. She's currently active at The Data Tank, an organisation championing a holistic approach to re-using data for the common good.\r\n\r\nBefore joining The Data Tank, she was the Public Participation and Research Lead at the Ada Lovelace Institute. Her role focused on ensuring public perspectives and experiences are embedded in Ada’s research in rigorous, inclusive and meaningful ways.\r\n\r\nPrior to joining Ada, Anna managed the research on democratic innovations at Democratic Society, including the evaluation of deliberative mini-publics across the European Union and the UK. She was Director of Innovations and Learning at Africa’s Voices Foundation and worked as a Senior Research Manager at BBC Media Action, working with teams across South Asia, and East and West Africa. Anna holds a PhD in Political Science from The Open University, where she has applied an intersectional lens to understanding how instant messaging mediates citizenship capabilities. She was formerly a journalist, documentary filmmaker and participatory video facilitator.\n",
+ :session/subtitle "Anna Colom",
+ :session/location :location.type/depot,
+ :session/code "3ULPRX",
+ :session/type :session.type/keynote,
+ :session/capacity 300,
+ :session/duration "PT45M"}
+ {:session/time #time/zdt "2024-09-18T11:30+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/sami-kallinen.png",
+ :session/title "Sailing with Scicloj: A Bayesian Adventure",
+ :session/description
+ "The presentation, created in collaboration with Daniel Slutsky and the Scicloj community, discusses the Scicloj project and the data science tools for Clojure. Sami Kallinen shares his personal journey of learning to sail during the Covid-19 pandemic. The main focus of the presentation is on Polar diagrams, which are crucial for assessing a boat's performance, important for racing tactics and choosing the optimal sailing routes. The speaker has collected and analyzes various data points to create these diagrams for a 46-year-old Finnish half-tonner cruising sailboat with a classic design. The primary focus is on showcasing how Clojure's data science tools are used to analyze data and construct models, especially through Bayesian analysis.\n\n## Speakers\n\n\n### Sami Kallinen\n\nSami is a full-stack Clojure developer, data scientist, and the founder of 8-bit-sheep.com, with experience in leading digital products and media strategy since the early 1990s. Sami has been working at KP System in Växjö, Sweden, for the past three years.\n",
+ :session/subtitle "Sami Kallinen",
+ :session/location :location.type/depot,
+ :session/code "JYHR9S",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-18T14:00+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/chris-mccormick.jpg",
+ :session/title
+ "Build full-stack ClojureScript apps with and without Sitefox",
+ :session/description
+ "Interested in building \"full stack\" ClojureScript software running on the Node ecosystem instead of Java? I'll take you step by step through different options for going all-in on ClojureScript. We'll start with simple backend-only websites and work our way up to apps with both frontend and backend components. We'll learn about shadow-cljs (front and backend), Nbb, Squint, Scittle and my web framework, Sitefox. We'll look at the tradeoffs of different approaches and learn to get web projects up and running quickly and with minimum fuss.\n\n## Speakers\n\n\n### Chris McCormick\n\nChris is an independent computer programmer building open source software, freelancing, and bootstrapping online micro-businesses with ClojureScript. He's always looking for efficient and joyful ways to create software, so when a friend introduced him to Clojure at a game jam he was instantly hooked. He also enjoys tinkering with game dev and making procedural music, and uses ClojureScript for this too.\n",
+ :session/subtitle "Chris McCormick",
+ :session/location :location.type/hal5,
+ :session/code "XXE9RM",
+ :session/type :session.type/workshop,
+ :session/capacity 300,
+ :session/duration "PT105M"}
+ {:session/time #time/zdt "2024-09-18T14:30+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/jeaye-wilkerson.png",
+ :session/title "An Exceptionally Janky Tale",
+ :session/description
+ "Gather 'round, friends, it's story time! Hear the adventurous tale of plunging into unknown depths and meeting new friends along the way.\r\n\r\nMeanwhile, in the interludes, we'll be plunging ourselves deep into the jank compiler and implementing our story's chapters: throw, try, catch, and finally. We won't shy away from the C++ involved, so be ready for a highly technical discussion.\r\n\r\nBy the end of the talk, you'll not only have your heart warmed, you'll also have a clear idea of how a non-trivial compiler feature is implemented, from parsing through to code generation.\n\n## Speakers\n\n\n### Jeaye Wilkerson\n\nJeaye has a background in C++ systems programming, focusing on games and game engines. After several years of making games, he co-founded and built an e-sports tournament startup written in full-stack Clojure. These days, he’s writing Clojure at Electronic Arts (EA) to build tooling used for making some of the world’s top games.\r\n\r\nJeaye is the creator of the jank programming language, a Clojure dialect on LLVM with a native runtime and C++ interop.\n",
+ :session/subtitle "Jeaye Wilkerson",
+ :session/location :location.type/depot,
+ :session/code "9WTPNL",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-18T15:05+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/daniel-szmulewicz.jpg",
+ :session/title
+ "The Shoulders of Giants or Uncovering the Foundational Ideas of Lisp",
+ :session/description
+ "In the world of computer science, we often acknowledge that we are standing on the shoulders of giants. However, the identities and contributions of these giants are sometimes less known than we might expect. While many Lisp practitioners recognize John McCarthy as the inventor of Lisp, the story of the foundational ideas that enabled its discovery remains largely untold.\r\nThis talk aims to explore two essential questions: Why do we know so little about the foundational ideas that enable our practice, and what are those ideas and their connections?\n\n## Speakers\n\n\n### Daniel Szmulewicz\n\nFunctional programmer. Closet philosopher. Emacs meshugge.\n",
+ :session/subtitle "Daniel Szmulewicz",
+ :session/location :location.type/depot,
+ :session/code "RDA8K9",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-18T15:55+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/mitesh-shah.png",
+ :session/title
+ "Beyond the Hype: Obstacles on the Path to Clojure Adoption",
+ :session/description
+ "To the mainstream public (devs and business folks), clojure is either seen as an arcane lisp, or as a hyped language. This perception of Clojure is further solidified by the fact that it's hard to get started with Clojure.\r\n\r\nClojure definitely has a very passionate community and undeniable strengths, then what is holding it back? \r\n\r\nBy openly discussing these issues and collborating on solutions, we can propel Clojure beyond it's current position as a powerful defacto business choice. There are many low hanging fruits and quick wins we can do to get the ball rolling.\n\n## Speakers\n\n\n### Mitesh Shah\n\nMitesh / @oxalorg has created Clojure screencasts, contributed to LambdaIsland open source repos and also recently volunteered at a ClojureBridge workshop!\r\n\r\nMitesh works as a Senior full-stack Clojure[script] Engineer at Gaiwan!\n",
+ :session/subtitle "Mitesh Shah",
+ :session/location :location.type/depot,
+ :session/code "KPLYME",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-18T16:00+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/katja-bohnke.jpg",
+ :session/title "Open hearts for diversity",
+ :session/description
+ "As women in tech I am used to being the only women in the room. I am used to feeling different. At time this raises the question: Do I belong here?\r\n\r\nWorking on a team with people of different age, gender, sexual orientation, religion, physical and mental abilities, ethnic and social background helps me to realize that we are all different and we all belong. Unfortunately, many teams are less diverse and not all people get to make this experience. Therefore, it is important to create opportunities to learn about each other and to become aware of similarities and differences.\r\n\r\nIn this interactive session we share experiences and talk about challenges. The goal is to raise awareness for the topic, to hear each others stories and to support each other. The session is open for all! I invite you to open your hearts for diversity and connect with each other!\n\n## Speakers\n\n\n### Katja Böhnke\n\nKatja Böhnke is a software engineer and psychology student. She values connection and learning. She loves to work on diverse teams and to create spaces where people can be themselves and connect with each other.\n",
+ :session/subtitle "Katja Böhnke",
+ :session/location :location.type/hal5,
+ :session/code "RYKWPQ",
+ :session/type :session.type/session,
+ :session/capacity 300,
+ :session/duration "PT45M"}
+ {:session/time #time/zdt "2024-09-18T16:30+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/lovro-lugovic-sung-shik-jongmans.png",
+ :session/title "Klor: Choreographic Programming in Clojure",
+ :session/description
+ "Over the past five years, the European Commission has invested over 250M EUR in its **Next Generation Internet** initiative. As part of this ambitious program, we are developing a new free and open-source core technology for distributed systems -- in Clojure, of course.\n\n## Speakers\n\n\n### Lovro Lugović\n\nLovro Lugović is a C++ software engineer turned Lisp hacker and a recent PhD graduate from the University of Southern Denmark, specializing in programming languages and concurrency theory. He likes functional programming, designing domain-specific languages and solving problems using a combination thereof.\n\n### Sung-Shik Jongmans\n\nSung-Shik Jongmans is language engineer at Swat.engineering. Before, he was associate professor at Open University of the Netherlands and researcher at the Dutch National Research Institute for Mathematics and Computer Science. His interests include programming languages, concurrency theory, and software engineering. And Clojure, of course.\n",
+ :session/subtitle "Lovro Lugović, Sung-Shik Jongmans",
+ :session/location :location.type/depot,
+ :session/code "L8VJWX",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-18T17:20+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/dimitris-kyriakoudis.png",
+ :session/title
+ "TimeLines: Crafting a Live Coding Musical Instrument with & out of Clojure",
+ :session/description
+ "TimeLines is an ongoing PhD research project in the design and implementation of Live Coding musical instruments. Live Coding is a creative practice that, at its core, involves real-time Human-Computer Interaction (HCI) with a live and dynamic computational system - as much an instrument as an open-ended instrument-building workbench. TimeLines follows a purely functional approach to music, treating both the synthesis of sounds and of musical structure to be functions of just a single numerical argument: time itself. All time-varying behavior is encoded in those pure functions, enabling the potential for massive parallelization and static analyses. Clojure's Lisp-heritage's metaprogramming powers are greatly relied upon to make an instrument that is capable of creating and extending itself.\n\n## Speakers\n\n\n### Dimitris Kyriakoudis\n\nDimitris is a music tech PhD Student at Univeristy of Sussex, as well as a Live Coding Luthier & Performer\r\n\r\nHe's the creator of the TimeLines live coding system, originally written in Haskell, but since ported to Clojure.\n",
+ :session/subtitle "Dimitris Kyriakoudis",
+ :session/location :location.type/depot,
+ :session/code "FCPHWU",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-18T20:30+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/pulu.jpg",
+ :session/title "UFORAVE!timewarp",
+ :session/description
+ "In this algorithmic music performance collapsing the distance between 2000 and 2024, pulu unleashes a janky multi-computer contraption^W^W^Wcustom code-jockeying system to conjure hacker dreamworlds and hypnotic trance-scapes!\r\n\r\nFunctional programming permeates the performance, with SuperCollider 2 for Mac OS 9, TidalCycles (Haskell) and Emacs Lisp all playing a part in making the whole thing work(?)\n\n## Speakers\n\n\n### pulu\n\nMiranda Kastemaa is a Helsinki-based musician, programmer and sound designer exploring sonic universes through a variety of algorithmic, electronic and acoustic means. Since 2002, they have worked with DAWs, livecoding, retrocomputing, field recording, game development, sensors, microcontrollers, game boys, piano and more, to create musical-visual instruments, interactive installations, participatory performances, as well as plain old tunes. Their scattershot and fragmentary artistic process is reflected in the resulting sounds, which meander through numerous styles like trance, ambient, drum & bass, downtempo, and noise, as well as the various aliases under which they've released music, including Foldplop, Verkosto and pulu.\r\n\r\n- \r\n- \r\n- \r\n- \r\n- \n",
+ :session/subtitle "pulu",
+ :session/location :location.type/hal5,
+ :session/code "PAMX77",
+ :session/type :session.type/live-set,
+ :session/capacity 300,
+ :session/duration "PT45M"}
+ {:session/time #time/zdt "2024-09-19T09:00+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/jack-rusher-paolo-holinski.png",
+ :session/title "An introduction to application.garden",
+ :session/description
+ "Learn how to use application.garden to quickly deploy a working application with hassle-free authentication, cron jobs, email handling, and a live REPL.\n\n## Speakers\n\n\n### Jack Rusher\n\nJack Rusher's long career as a computer scientist includes time at Bell Labs/AT&T Research and a number of successful startups. Much of his current work focuses on the deep relationship between art and technology.\n\n### Paolo Holinski\n\nPaolo has been programming with Clojure for the past 10 years. He is interested in making programming more accessible and has helped build application.garden at Nextjournal.\n",
+ :session/subtitle "Jack Rusher, Paolo Holinski",
+ :session/location :location.type/hal5,
+ :session/code "7CHPV8",
+ :session/type :session.type/workshop,
+ :session/capacity 300,
+ :session/duration "PT105M"}
+ {:session/time #time/zdt "2024-09-19T09:50+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/jeremy-taylor.jpg",
+ :session/title
+ "Richer SQL — Steering SQL's Future Towards Clojure's Philosophy",
+ :session/description
+ "SELECT NAME FROM EMP WHERE DEPT = 'TOY'\r\n\r\n...SQL has been celebrating its 50th birthday this year, and this original query still runs flawlessly across countless implementations - an impressive milestone in the world of software that nobody could have predicted back in 1974. SQL is the most potent example of declarative programming and backwards compatibility.\r\n\r\nHowever SQL's continued dominance and legacy has not been without significant downsides. Mountains of complexity has been built, and continues to be built, upon its sprawling, anachronistic designs.\r\n\r\nIn search of some antidote to SQL's myriad issues the Clojure community has always been a vibrant melting pot of visions and attempts to tame SQL or surpass it entirely.\r\n\r\nThe XTDB team has spent the past 3 years working on _evolving_ SQL to make it more compatible with Clojure's philosophy and in this talk we will take a tour through how this is achieved and where it might lead.\n\n## Speakers\n\n\n### Jeremy Taylor\n\nJeremy is the Head of Product at JUXT, with primary responsibility for XTDB. Jeremy has been digging into databases and \"tools for thought\" for much of his career. He was initially drawn to Clojure for the Datalog, but stayed for the parens.\n",
+ :session/subtitle "Jeremy Taylor",
+ :session/location :location.type/depot,
+ :session/code "DHG7BC",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-19T10:30+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/pawel-stroinski.jpeg",
+ :session/title
+ "Building Conversational Speech Annotation Tool in Clojure",
+ :session/description
+ "This talk will be a story of inheriting a bespoke text editor with annotation features written in ClojureScript and turning it into a number of things. It will include horror stories of debugging in-house Specter macros running in browser as well as calming stories of how nice it is to work in a code with a good test coverage even if it is difficult to approach, or how enjoyable it is to create interactive audio annotation tooling in ClojureScript.\n\n## Speakers\n\n\n### Paweł Stroiński\n\nPaweł first started writing code 25 years ago in Turbo Pascal. He's programmed professionally using Delphi, XSLT, VB.NET, C#, JavaScript, TypeScript, and Clojure. Has experience on the entrepreneurial side and passion for music. A proud father of a six years old.\n",
+ :session/subtitle "Paweł Stroiński",
+ :session/location :location.type/depot,
+ :session/code "SL7C7G",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-19T11:00+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/colin-fleming.jpeg",
+ :session/title "Cursive office hours",
+ :session/description
+ "Come with all your questions about Cursive! I have developed Cursive from the very start, and I'd love to hear your questions, see how you're using Cursive and (hopefully!) help you with any problems you're experiencing. Whether you're an experienced Cursive user, an experienced Emacs user curious about why anyone might want to use anything else, or anywhere in between those two points, I'd love to hear from you and help with any issues you're experiencing.\n\n## Speakers\n\n\n### Colin Fleming\n\nColin is the developer of Cursive. He has programmed things for a long time now, in a bunch of different programming languages. When he's not hacking on Cursive, he's mostly climbing in the hills nearby.\n",
+ :session/subtitle "Colin Fleming",
+ :session/location :location.type/hal5,
+ :session/code "R8UFRM",
+ :session/type :session.type/office-hours,
+ :session/capacity 300,
+ :session/duration "PT60M"}
+ {:session/time #time/zdt "2024-09-19T11:30+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/felix-alm.jpeg",
+ :session/title "Squint: a taste of Clojure for JavaScript devs",
+ :session/description
+ "Diving head first into shadow-cljs and the surrounding ecosystem can be daunting. What if we could incrementally introduce Clojure into our existing JS applications from the safety of our favourite frontend frameworks like React or Svelte to tame its more complex logic - hopefully with the help of a trusted REPL\n\n## Speakers\n\n\n### Felix Alm\n\nFelix left a biochemistry major after an \"Intro to Programming\"-course during his second year completely stole the show. Some zigzagging later he's now been working in the industry using functional languages since 2017. Clojure became his favourite side project tool early on and 2.5 years ago, when he joined JUXT, it has been his full-time language as well.\n",
+ :session/subtitle "Felix Alm",
+ :session/location :location.type/depot,
+ :session/code "MZV7H9",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-19T13:00+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/nikita-prokopov.jpg",
+ :session/title "Build a Desktop Application with Humble UI",
+ :session/description
+ "Humble UI is an ongoing project to build desktop-class UIs in Clojure without help of the browser.\r\n\r\nIn this workshop, we’ll try to build a new graphical desktop application that works across all three OSes from scratch.\n\n## Speakers\n\n\n### Nikita Prokopov\n\nNikita is a Clojure developer with an eye for design and UX. He is the author of DataScript, Humble UI, Rum, Clojure Sublimed, Tongue, Clj-reload, Uberjars, Clj-simple-router, and Fira Code.\n",
+ :session/subtitle "Nikita Prokopov",
+ :session/location :location.type/hal5,
+ :session/code "W8JQNR",
+ :session/type :session.type/workshop,
+ :session/capacity 300,
+ :session/duration "PT105M"}
+ {:session/time #time/zdt "2024-09-19T15:00+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/michiel-borkent-teodor-heggelund-christian-johansen.png",
+ :session/title "Babashka in practice",
+ :session/description
+ "What is Babashka? Why should you care?\r\n\r\nIn 90 minutes you’ll get an introduction to Babashka, and hands-on experience with it through a shared programming experience with the rest of the group and two veteran Clojure programmers. You’ll learn what Babashka is, how it fits in with JVM Clojure, and how to work with it in a practical sense.\r\n\r\nThe workshop aims to be a joyful learning experience where we’ll get to know each other better and learn more about REPL-driven programming, testing Clojure, and, of course scripting with Babashka.\n\n## Speakers\n\n\n### Michiel Borkent\n\nMichiel Borkent (@borkdude) is the author of babashka, clj-kondo, SCI, cherry\r\nand several other Clojure projects. He has been using Clojure since 2010 as a\r\ntinkerer, lecturer and professional software developer. Since 2021 he dedicates\r\nmost his time to open source Clojure software. Hobbies include eating vegetables\r\nand walking.\n\n### Teodor Heggelund\n\nTeodor likes to program computers, especially with along other people. In previous lives, he has taught Elm to kids, Matlab and mechanics to students, and Python to civil engineers. His experience is that Clojure's interactivity makes it uniquely well suited to explore problems together.\n\n### Christian Johansen\n\nI am a Clojure developer at the Norwegian Food Safety Authority. I have 20 years of experience building software, and have done Clojure full-time for the past 10 years. I write about software development occasionally at https://cjohansen.no and regularly at https://parenteser.mattilsynet.io (in Norwegian). I am the maintainer of some open source projects, notably Portfolio (https://github.com/cjohansen/portfolio), which was sponsored by Clojurists Together in 2023. I also demonstrate pair programming and using Clojure and ClojureScript to fight zombies in the screencast https://parensofthedead.com/\n",
+ :session/subtitle
+ "Michiel Borkent, Teodor Heggelund, Christian Johansen",
+ :session/location :location.type/hal5,
+ :session/code "RYJ78V",
+ :session/type :session.type/workshop,
+ :session/capacity 300,
+ :session/duration "PT105M"}
+ {:session/time #time/zdt "2024-09-19T15:30+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/philippa-markovics-martin-kavalar.png",
+ :session/title
+ "Staring into the PLFZABYSS - From the IBM AS/400 to Clojure & Datomic",
+ :session/description
+ "Starting in 2021, we naively took on the task of bringing mission-critical legacy systems in the automotive logistics sector into the modern era. \r\n\r\nThis experience report covers our eventually successful live migration from the IBM AS/400 to Clojure and Datomic. We look at both the technical and human organizational challenges we faced and share our failures and learnings along the way.\r\n\r\nThousands of globally unique 8-character column names, green-screen terminal UIs, skunk work projects and personal drama — this talk has it all!\n\n## Speakers\n\n\n### Philippa Markovics\n\nPhilippa works as UI Designer and Frontend Lead at Nextjournal, mostly working on Clerk at the moment. Her main interests are in how we can make programming more tangible and data science more accessible. When she’s not working, you can find her planting food plots somewhere in the Austrian countryside.\n\n### Martin Kavalar\n\nMartin Kavalar is a co-founder at Nextjournal, a hybrid between startup and research lab trying to improve programming. Nextjournal makes a polyglot computational notebook with a focus on reproducibility and a variety of open source tools, including Clerk, a programmer's assistant for Clojure.\n",
+ :session/subtitle "Philippa Markovics, Martin Kavalar",
+ :session/location :location.type/depot,
+ :session/code "3PV78J",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-19T16:10+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/james-reeves.jpeg",
+ :session/title "Living With Legacy Code",
+ :session/description
+ "A look into maintaining backward compatibility in Clojure codebases.\n\n## Speakers\n\n\n### James Reeves\n\nA Clojure developer since 2008, and the maintainer of several prominent libraries such as Ring, Hiccup and Integrant. James currently works as a freelance contractor just outside of London.\n",
+ :session/subtitle "James Reeves",
+ :session/location :location.type/depot,
+ :session/code "SEFW3N",
+ :session/type :session.type/talk,
+ :session/capacity 300,
+ :session/duration "PT30M"}
+ {:session/time #time/zdt "2024-09-19T18:05+02:00[Europe/Brussels]",
+ :session/image
+ "https://2024.heartofclojure.eu/img/speakers/eric-normand.jpg",
+ :session/title "The Wonders of Abstraction",
+ :session/description
+ "Fish are to water as programmers are to abstraction. We swim in it all day, barely aware of it. We say \"abstraction\" all the time, but have we thought about what it means? \r\n\r\nI've spent 20 years asking how computers--that move electrons around in a complex circuit--do work useful to humans. Abstraction is the key. In this philosophical talk, we explore this wonderous process called abstraction. We'll wade through the everyday uses of the term, paddle out to formal definitions, and dive into why some abstractions give us incredible leverage. Along the way, we'll see how abstraction is at the heart of getting computers to do useful work. I hope you leave with a deeper appreciation of the wonders of programming.\n\n## Speakers\n\n\n### Eric Normand\n\nEric Normand has been programming functionally since 2001. He teaches, speaks, and writes. He consults with companies to help them build better software one function at a time. He lives with his family in Madison, Wisconsin. You can find his writing and other projects at [ericnormand.me](https://ericnormand.me/).\n",
+ :session/subtitle "Eric Normand",
+ :session/location :location.type/depot,
+ :session/code "ULRJXZ",
+ :session/type :session.type/keynote,
+ :session/capacity 300,
+ :session/duration "PT45M"})
diff --git a/resources/public/css/styles.css b/resources/public/css/styles.css
index a72295e..7eb6779 100644
--- a/resources/public/css/styles.css
+++ b/resources/public/css/styles.css
@@ -122,6 +122,34 @@ body {
font-family: Open Sans, sans-serif;
}
+.site-copy p {
+ line-height: 2;
+}
+
+.site-copy h1 {
+ margin-top: var(--size-5);
+ margin-bottom: var(--size-4);
+}
+
+.site-copy h2 {
+ margin-top: var(--size-4);
+ margin-bottom: var(--size-3);
+}
+
+.site-copy h3 {
+ margin-top: var(--size-3);
+ margin-bottom: var(--size-2);
+}
+
+.site-copy h4 {
+ margin-top: var(--size-2);
+ margin-bottom: var(--size-1);
+}
+
+.site-copy h5 {
+ margin-top: var(--size-1);
+}
+
.graphics-compass_logo path {
fill: var(--hoc-pink);
}
@@ -555,16 +583,7 @@ body {
width: 100px;
}
-.sessions-session_card {
- display: flex;
- gap: var(--size-1);
- background-color: var(--surface-2);
- box-shadow: var(--shadow-2);
- border-style: solid;
- border-color: var(--surface-3);
-}
-
-.sessions-session_card .left {
+.sessions-img_PLUS_join_widget {
display: flex;
flex-direction: column;
align-items: center;
@@ -574,6 +593,15 @@ body {
margin-right: var(--size-2);
}
+.sessions-session_card {
+ display: flex;
+ gap: var(--size-1);
+ background-color: var(--surface-2);
+ box-shadow: var(--shadow-2);
+ border-style: solid;
+ border-color: var(--surface-3);
+}
+
.sessions-session_card .title {
font-size: var(--size-4);
font-weight: 600;
@@ -626,7 +654,7 @@ body {
display: block;
}
-.sessions-session_card.htmx-request .left, .sessions-session_card.htmx-request .details {
+.sessions-session_card.htmx-request .details, .sessions-session_card.htmx-request .sessions-img_PLUS_join_widget {
opacity: 0.5;
animation: session-card-pulse 1s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@@ -643,6 +671,7 @@ body {
display: flex;
gap: var(--size-2);
margin-bottom: var(--size-8);
+ align-items: center;
}
.sessions-session_detail .header-row .title {
@@ -661,7 +690,8 @@ body {
.sessions-session_detail .header-row .type {
background: var(--sessions-session-type-color);
- margin: var(--size-0);
+ margin-top: var(--size-1);
+ margin-bottom: var(--size-1);
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
@@ -691,7 +721,6 @@ body {
position: relative;
margin-top: var(--size-4);
margin-bottom: var(--size-4);
- display: flex;
padding: var(--size-4);
gap: var(--size-4);
display: flex;
@@ -712,14 +741,7 @@ body {
font-weight: 600;
padding: var(--size-4);
text-align: center;
-}
-
-@media (min-width: 1024px) {
-
- .sessions-session_detail .three-box >div {
- width: 33%;
- }
-
+ flex-grow: 1;
}
.sessions-session_detail .three-box >div >.small {
diff --git a/src/co/gaiwan/compass/css/styles.clj b/src/co/gaiwan/compass/css/styles.clj
index 17f89aa..5f63ca4 100644
--- a/src/co/gaiwan/compass/css/styles.clj
+++ b/src/co/gaiwan/compass/css/styles.clj
@@ -18,4 +18,16 @@
[:dialog :p-0]
[:body {:font-family "Open Sans, sans-serif"}]
+
+ [:.site-copy
+ [:p {:line-height 2}]
+ [:h1 {:margin-top t/--size-5
+ :margin-bottom t/--size-4}]
+ [:h2 {:margin-top t/--size-4
+ :margin-bottom t/--size-3}]
+ [:h3 {:margin-top t/--size-3
+ :margin-bottom t/--size-2}]
+ [:h4 {:margin-top t/--size-2
+ :margin-bottom t/--size-1}]
+ [:h5 {:margin-top t/--size-1}]]
])
diff --git a/src/co/gaiwan/compass/db.clj b/src/co/gaiwan/compass/db.clj
index 33fa091..8f553f8 100644
--- a/src/co/gaiwan/compass/db.clj
+++ b/src/co/gaiwan/compass/db.clj
@@ -101,4 +101,9 @@
:session/capacity 1}])
(wagontrain/applied? (conn) :add-locations)
+
+ (wagontrain/rollback! (conn) :add-live-set)
+ (wagontrain/rollback! (conn) :add-updated-schedule)
+ (wagontrain/migrate! (conn) (munge-to-db migrations/all))
+
)
diff --git a/src/co/gaiwan/compass/db/data.clj b/src/co/gaiwan/compass/db/data.clj
index 8488d79..abd284a 100644
--- a/src/co/gaiwan/compass/db/data.clj
+++ b/src/co/gaiwan/compass/db/data.clj
@@ -51,9 +51,9 @@
:session.type/color "var(--activity-color)"
:db/ident :session.type/activity}])
-(defn schedule []
+(defn load-schedule [resource-path]
(map
(fn [s]
(update s :session/image #(assets/download-image %)))
- (read-string (slurp (io/resource "compass/schedule.edn")))))
+ (read-string (slurp (io/resource resource-path)))))
diff --git a/src/co/gaiwan/compass/db/migrations.clj b/src/co/gaiwan/compass/db/migrations.clj
index 166f276..08d8d56 100644
--- a/src/co/gaiwan/compass/db/migrations.clj
+++ b/src/co/gaiwan/compass/db/migrations.clj
@@ -9,5 +9,23 @@
:tx-data (data/session-types)}
{:label :add-initial-schedule
- :tx-data (data/schedule)}
+ :tx-data (data/load-schedule "compass/schedule.edn")}
+
+ {:label :add-live-set
+ :tx-data [{:session.type/name "Live Set"
+ :session.type/color "var(--workshop-color)"
+ :db/ident :session.type/live-set}]}
+
+ {:label :add-updated-schedule
+ :tx-data (data/load-schedule "compass/schedule_20240909.edn")}
+
+ {:label :update-locations
+ :tx-data
+ [[:db/retractEntity :location.type/depot-main-stage]
+ [:db/retractEntity :location.type/hal5-zone-a]
+ [:db/retractEntity :location.type/hal5-zone-b]
+ [:db/retractEntity :location.type/hal5-hoc-cafe]
+ {:db/ident :location.type/hal5
+ :location/name "Hal 5 - Workshop Zone"}
+ {:location/name "Hal 5 - Community Space"}]}
])
diff --git a/src/co/gaiwan/compass/db/queries.clj b/src/co/gaiwan/compass/db/queries.clj
index 5ce74be..b5cffbe 100644
--- a/src/co/gaiwan/compass/db/queries.clj
+++ b/src/co/gaiwan/compass/db/queries.clj
@@ -53,3 +53,10 @@
:where
[?t :session.type/name]]
(db/db)))
+
+(defn all-locations []
+ (db/q
+ '[:find [(pull ?t [*]) ...]
+ :where
+ [?t :location/name]]
+ (db/db)))
diff --git a/src/co/gaiwan/compass/html/sessions.clj b/src/co/gaiwan/compass/html/sessions.clj
index 3543add..e526f87 100644
--- a/src/co/gaiwan/compass/html/sessions.clj
+++ b/src/co/gaiwan/compass/html/sessions.clj
@@ -4,6 +4,7 @@
(:require
[clojure.string :as str]
[co.gaiwan.compass.css.tokens :as t :refer :all]
+ [co.gaiwan.compass.db.queries :as q]
[co.gaiwan.compass.html.components :as c]
[co.gaiwan.compass.html.filters :as filters]
[co.gaiwan.compass.html.graphics :as graphics]
@@ -110,13 +111,19 @@
(when (< 0 m)
(str m " min")))))
+(o/defstyled img+join-widget :div
+ :flex-col :items-center :py-3 :mx-2
+ ([session user]
+ [:<>
+ [session-image+guage session user]
+ [join-btn session user]]))
+
(o/defstyled session-card :div
:flex :gap-1
:bg-surface-2
:shadow-2
:boder :border-solid :border-surface-3
#_:text-center
- [:.left :flex-col :items-center :py-3 :mx-2]
[:.title :font-size-4 :font-semibold :mt-3 :mb-2
[:a {:color t/--text-1}]]
[:.subtitle :font-size-3 :font-medium :mb-3
@@ -135,7 +142,7 @@
[:.expansion {:display "none"}]
[:&.expanded [:.expansion {:display "block"}]]
[:&.htmx-request
- [#{:.left :.details}
+ [#{(str "." img+join-widget) :.details}
{:opacity "0.5"
:animation "session-card-pulse 1s cubic-bezier(0.4, 0, 0.6, 1) infinite"}]]
([{:session/keys [type title subtitle organized time
@@ -153,9 +160,8 @@
:hx-disinherit "hx-target hx-select"}
[:div.type (:session.type/name type)]
- [:div.left
- [session-image+guage session user]
- [join-btn session user]]
+ [img+join-widget session user]
+
[:div.details
[:h2.title
@@ -163,9 +169,7 @@
[:span.datetime
(str (time/truncate-to (time/local-time time) :minutes)) " · "]
title]]
- [:h3.subtitle (if-let [organizer-name (and (str/blank? subtitle) (-> session :session/organized :public-profile/name))]
- (str "organized by " organizer-name)
- subtitle)]
+ [:h3.subtitle (session/subtitle session)]
#_[:div.expansion
[session-card-actions session user]]
[:div.loc (fmt-dur duration) " @ " (:location/name location)]
@@ -188,6 +192,7 @@
[capacity-gauge :w-100px]
:mt-8
[:.header-row :flex :gap-2 :mb-8
+ :items-center
[:.title :lg:font-size-8
:font-size-7
{:text-wrap :wrap
@@ -195,7 +200,7 @@
[:.header-row-text]
[:.type
{:background --session-type-color}
- :m-0 :font-bold :uppercase :tracking-widest :p-1]]
+ :my-1 :font-bold :uppercase :tracking-widest :p-1]]
[:.event-at
{:box-shadow "-14px 14px 0 -4px black"
:background t/--highlight-yellow}
@@ -203,8 +208,8 @@
[:>p :font-semibold]
[:.datetime :font-size-7 :font-bold]]
[:.three-box #_{:background t/--activity-color}
- :relative :my-4 :flex :p-4 :gap-4 :lg:flex-row :flex-col
- [:>div :border-8 :font-semibold :p-4 :lg:w-33% :text-center
+ :relative :my-4 :p-4 :gap-4 :lg:flex-row :flex-col
+ [:>div :border-8 :font-semibold :p-4 :text-center :flex-grow
[:>.small :lg:font-size-3 :uppercase :tracking-widest]
[:>.large :font-size-6 :lg:font-size-7 :font-bold]]
[:&:before
@@ -220,7 +225,7 @@
:transform "rotate(1deg)"}]]
([{:session/keys [type title subtitle organized
- time location image capacity
+ time duration location image capacity
signup-count description
participants] :as session}
user]
@@ -238,21 +243,25 @@
:style {:display "none"}
:hx-trigger (str "session-" (:db/id session) "-deleted from:body")}]
[:div.header-row
- [session-image+guage session user]
+ [img+join-widget session user]
[:div.header-row-text
- [:div.type (:session.type/name type)]
- [:h3.title title]]]
+ [:div [:span.type (:session.type/name type)]]
+ [:h3.title title]
+ [:h4 (session/subtitle session)]]]
[:div.event-at
- [:p "Event scheduled at"]
+ #_[:p "Event scheduled at"]
[:div.datetime
(when time
- (str (time/truncate-to (time/local-time time) :minutes)
- ", "
- (subs (str/capitalize (str (time/day-of-week time))) 0 3)
- " "
- (time/format "dd.MM" time)))]]
- [:h3.subtitle subtitle]
- [:div.description
+ (str
+ (subs (str/capitalize (str (time/day-of-week time))) 0 3)
+ " "
+ (time/format "dd.MM" time)
+ ", "
+ (time/truncate-to (time/local-time time) :minutes)))
+ " → "
+ (fmt-dur duration)]]
+
+ [:div.description.site-copy
[:div (m/component (m/md->hiccup description))]]
[:div.three-box
[:div.location
@@ -261,11 +270,11 @@
[:div.capacity
[:div.small "Spots available"]
[:div.large (- (or capacity 0) (or signup-count 0))]]
- [:div
- [:p.small "Ticket required"]
- (if (:session/ticket-required? session)
- [:p.large "YES ✅"]
- [:p.large "NO ❎"])]]
+ #_[:div
+ [:p.small "Ticket required"]
+ (if (:session/ticket-required? session)
+ [:p.large "YES ✅"]
+ [:p.large "NO ❎"])]]
(when (session/organizing? session user)
;; Only show the participants' list to organizer.
[:div.participants
@@ -273,7 +282,7 @@
[:ol (map attendee participants)]])
[:div.actions
- [join-btn session user]
+
(when (or (user/admin? user)
(session/organizing? session user))
[:<>
@@ -388,19 +397,13 @@
n])]])
[:label {:for "location"} "Location"]
- [:select (cond-> {:id "location" :name "location"}
- session
- (assoc :value
- (name (get-in session [:session/location :db/ident]))))
- [:option {:value "depot-main-stage"} "Het Depot - main stage"]
- [:option {:value "depot-bar"} "Het Depot - Bar"]
- [:option {:value "hal5-zone-a"} "Hal 5 - zone A"]
- [:option {:value "hal5-zone-b"} "Hal 5 - zone B"]
- [:option {:value "hal5-hoc-cafe"} "Hal 5 - HoC Café"]
- [:option {:value "hal5-foodcourt"} "Hal 5 - Foodcourt"]
- [:option {:value "hal5-park"} "Hal 5 - park"]
- [:option {:value "hal5-outside-seating"} "Hal 5 - outside seating"]
- [:option {:value "hal5-long-table"} "Hal 5 - long table"]]
+
+ [:select {:id "location" :name "location"}
+ (for [{:location/keys [name] :db/keys [id]} (q/all-locations)]
+ [:option (cond-> {:value id}
+ (= id (get-in session [:session/location :db/id]))
+ (assoc :selected "selected"))
+ name])]
[:label {:for "capacity"} "How many people can you accomodate?"]
[:input (cond-> {:id "capacity" :name "capacity" :type "number"
diff --git a/src/co/gaiwan/compass/model/session.clj b/src/co/gaiwan/compass/model/session.clj
index ad967ae..78b983a 100644
--- a/src/co/gaiwan/compass/model/session.clj
+++ b/src/co/gaiwan/compass/model/session.clj
@@ -116,3 +116,10 @@
(defn session-image-css-value [session]
(str "url(" (assets/image-url (:session/image session)) ")"))
+
+(defn subtitle
+ "Returns the subtitle if there is one, or 'organized by ' otherwise."
+ [{:session/keys [subtitle] :as session}]
+ (if-let [organizer-name (and (str/blank? subtitle) (-> session :session/organized :public-profile/name))]
+ (str "organized by " organizer-name)
+ subtitle))
diff --git a/src/lambdaisland/wagontrain.clj b/src/lambdaisland/wagontrain.clj
index 0df9dcc..7aaaab8 100644
--- a/src/lambdaisland/wagontrain.clj
+++ b/src/lambdaisland/wagontrain.clj
@@ -52,7 +52,7 @@
(defn migrate1
[conn {:keys [label tx-data]}]
- @(d/transact conn (up-tx label tx-data)))
+ @(d/transact conn (up-tx label (if (fn? tx-data) (tx-data) tx-data))))
(defn migrate! [conn migrations]
(run! (partial migrate1 conn) migrations))