this is my friend hey everybody um great
to be here in Port this is
awesome happy
P20 what does that
mean somebody's birthday
oh um welcome here uh we work at e
together and a lot of the stuff you're
going to see we use we use for work
we're fortunate enough to also get the
word you know time so it's awesome uh
couple notes
first um we have boot sckers as you can
see we have a kind of cool logo on icon
that's courtesy of our employer it's a
little cat in a boot makes to sense
right um and we have those stickers so
if you have questions we may or may not
have questions at the end of the talk
but feel free if you see us just to pull
us aside pester us with your your
trickiest questions um that's the reason
we're here at conference is to hang out
with people and answer questions and
learn new stuff so feel free to talk
with us and we have tons of stickers too
and um there are a couple things you can
do with the stickers you can like put
them on your laptop or some people put
them on their car actually a new thing I
mean it could be a thing it's just
putting them on newborn children maybe
that's a thing we want to do I don't
know um the final note is we're going to
do a lot of interactive demonstration
coding which is fairly dangerous always
um so as a precaution we've done a
couple things including you know turning
the Wi-Fi off on this machine and
prepared screenshots of code but most
importantly our friend and Associate uh
Dave Arwood is in the audience and after
any catastrophic failure his task will
be to start with slow clap so I just ask
you join him and we can lighten the
moment that way anyway I'll I'll let
Misha actually get to the real
presentation yeah a new build tool
another
one uh such excit yeah thank you thank
[Applause]
you but uh I mean anybody who who makes
applications nowadays is involved with
you know complicated things web
applications especially they seem so
simple but when you actually get to the
bottom and you start deploying them they
end up being pretty complicated and the
build is surprisingly complex and
difficult to do you have like five jbms
running like make files and all kinds of
things uh but you know being closure
people people interested in closure
anyway we recognize the need to manage
complexity that's why we use closure it
provides us abstractions and all these
ways that we can manage complexity but
the build tooling hasn't really kept up
with that there's no ways to make uh you
know small modules we can compose to
manage complexity encapsulate things um
so the real problem in our opinion is
that builds which is all right opinion
right we are unanimous that builds are
processes they're not specifications in
other words like you can't make a
program a closure program that's just a
big map of things you want it to do in
some big specification and then you know
it'll generate some program that will
fulfill all your wildest dreams now you
have to process that you know does
things sequentially basically and most
of the tools that are out there now
Maven ant whatever all of them are
oriented around trying to make a
declarative specification for what you
want your outcome to be Gradle is
actually kind of an exception if you're
familiar with Gradle it's sort of the
the boot of the JV sort of is
is but basically we're programmers we
need to be able to program we don't we
don't want something to generate a
program for us we want to be able to I
mean List gives us all the tools that we
can use to generate our own programs the
way we want so boot is what we develop
to solve our own problem and fulfill our
our wildest dreams and uh the main idea
of it is that you can make small parts
that each do one thing they only do one
thing and they do that one thing well
and if you look at tools like Lan or
Maven or whatever if you have a really
successful uh plugin it ends up evolving
into a build tool of its own doing
everything
and it's much better to do to have many
things that each do one thing that you
can compose yourself the user can
compose himself then have a monolithic
program that now has made all these
choices for
you and uh although like small things it
doesn't really help you if you have many
small things and you can't compose them
uniformly so you know that's why you end
up having a big monolithic composition
of them because that's the only way you
can compose them such that it
works so basically our tool empowers you
to take these small pieces put them
together on the fly to make a new build
process uh it's pretty normal that it
uses ma Maven for dependency resolution
so all the things for you know for these
other systems Maven and Lan will work um
and we use it to build closure en
closure script at adzerk and it has a
website so you can go there you can
ignore us right now and just go to the
website so um like I said we're going to
do some sort of interactive stuff one of
the cool things about boot is that you
can start building things and using it
without really having any kind of
descriptor file or project file or
notion of a project at all and for this
example project I know this some closure
project so we chose Java now we all need
to build and love Java software actually
that's probably not true maybe it is um
but for the purposes of demonstrating uh
the facilities of boot we chose to make
a small Java project so there's this
Java hello world file and the process
that Java converts Java source code into
um jbm bite code it's kind of
Representative of of all the things that
build tools do even if they're not Java
in the web's you know domain we we're
doing various Transformations on you
know CSS pre-processors and converting
and optimizing JavaScript so we just
chose Java because it's kind of
Representative of that thing that bu
tools do which is they turn one kind of
thing into another kind of
thing so Misha is showing off now is uh
little boot command line action um you
type in the boot command it emits a
tremendous amount of things
which he's still scrolling through but
uh on you know a smaller font size it's
actually fairly readable and well
organized and nicely formatted and it
shows all of the options and tasks and
so on that uh it it
supports and one of the tasks that you
can run is the Java C task and what he
shows off there is that every single
task also supports this d-h option so
every task you you can access at the
command line um will have some possibly
no well it would definitely have
documentation that documentation may be
sparse in the case of java C it's just
showing us that we have no options
there's also boot DB which will show you
um the version of boot and various
relevant boot pieces of
information um so what we're going to do
is start working on this Java project
from the command line we're going to
start compiling some Java source code so
in the source directory is our Java file
and boot is going to or Misha is going
to inform boot about this source file by
adding The Source directory to to what
what we call Boots Source or resource
paths and that's kind of like adding
that directory to boots class
path then we're executing a task show
and show is a task that comes in with
food and it's sort of a diagnostic task
uh it's kind of like a task that you can
use to see what boot is doing in the
middle of of a pipeline or a series of
tasks and in particular the DF uh option
on on show will print out the value of
the file set and the file set is the the
build context or the set of files that
the build is currently operating on now
me is showing us chaining together these
paths so we start off by informing boot
about our source Rec Pap
there to do source so DS takes a source
directory then we call the show task
which prints the file set program you
guys so
good um then we type it to the Java C
task which compiles Java and then we
show the file set again now the the
difference between the first file set
and the second file set is this do class
file clearly a Java has been compiled
and there it is the class file so um we
have a slide to to show a little bit
more about what's going on let mea take
it away yeah this is pretty typical this
is how pretty much every boot invocation
Works uh you build up a a pipeline so
you can see showus F Java c showus f uh
what gets injected into the beginning of
the pipeline is your source files and
that becomes a file set which we'll talk
about in a little bit uh each task takes
a file set as input does some kind of
processing um either adds removes
modifies files to create a new file set
a new immutable file set object which it
passes to the next task and so on uh
this will be familiar if you're if
you're familiar with like ring uh the
middleware
pattern so to install a jar
now so we're just going to keep rolling
with adding Tas on this thing doing more
more doing more and more things so right
now we've got our Java project compiling
and maybe we want to turn it into a jar
file that's executable because we need
to send this important program someone
else inside our business land or
whatever the case is so um what m is
doing is he's introduced the Palm task
pal is a task that takes a number of
options like- p is the name of the
project- V is the version of the project
those are the two pieces of information
information a program needs to make a
pal XML file and a pal XML file is that
descriptor that goes into m
uh then he's typing that to the jar task
which takes all the things in the file
set and puts them into a jar in a Java
archive file and that picks an option- m
and that specifies what is the main
class in the artifact which in our case
is this boot. demo Java class so in one
fail swoop he has compiled the Java
created a p file created a jar file
specified in the jar file what the main
class is and installed it to his local
Maven
repository now at this point we can um
boot DD we can supply the DD option to
boot and what- D does is it takes a na
artifact name this could be something a
clojars or it could be in this case
something local and then runs another
task and one of the tasks we have is
repple and that starts to boot repple so
we're in a context now where uh boot is
is informed about our boot d demo
artifact which was installed locally and
now from the reppel there's a little
song and dance we need to do to call a
Java static method a main method but
sure enough that class existed on the
class pth when we just compiled and
solved and we just run a composure
so
yeah
so now uh we have added the uh Source
path again to boot and we went straight
into boot
reel man I'm on fire
today there we go guys yeah okay so he's
in a reppel and um the- s option I said
it adds to the file set or an informed
boot about where Source locations are
one of the principles in boot is that
everything you can do at the command
line should be possible at the r vice
versa well it's not really possible to
the other direction um but we try so the
um set end function will take uh various
options that inform you know set and
alter Global build context and the
source path is one of those things so
that set M call he just made is
analogous to the- S option we passed to
boot when we were showing the previous
example so now that boot knows where our
Java code is we can actually create the
and initialize this boot pipeline from
the rapple using this boot macro which
also takes a series of tasks of course
the the calling Convention of the task
is different than it is on the command
line because you know these are clearly
functions we're calling uh and it's
stringing together the results of those
function calls somehow um but
nevertheless it works and does the same
exact thing so we would if we open
another reel now to boot DB we would
find the same result we could add this
dependency which is installed locally to
our our
reppel um one nice thing yeah so uh if
you look at what the so this Java C
thing we're calling a function what is
that well we can call it without the
boot macro and we'll see that it is it's
a function call and it seems to return
another
function and um by itself it's also a
function various we're generating
thingses these are closure functions a
function it is a
function so what we're doing with the
boot macro and what we were doing at the
command line were both actually function
composition slightly different syntax
used to perform the
composition so we actually have yeah so
um yeah go ahead yeah so what we did
just now is we built up this Pipeline
and we did it in the command line at the
rep and it's important that you be able
to do them both ways because when you're
building you need to explore a bit and
so this is what the pipeline looks
like um it's kind of similar to what you
would do in Unix you know Unix is really
powerful for having you know it's well
known for the the power of small tools
and an interface between the small tools
that you can chain them together in
different different ways to do a large
number of things and that's what the
boot that's what boot provides with the
boot executable and the boot macro if
you're in the if you're in the repel and
basically what what's being provided
here is the the abstra the process
abstraction and the connective so you
need to have these little processes that
all communicate meaning they that they
take the same kind of connective object
as input and they emit the same kind of
connect Bo so you can connect them all
together in Unix the uh the process is a
program and they pass text between each
other with boot you have the task which
is a function a special kind of fun
function and uh the thing that they pass
between themselves is this immutable
file
set so here's what a task looks like
basically it is a task is um a function
uh dep task actually returns a function
it's just it adds some metadata so it's
basically defund plus metadata takes an
argument which is how you configure
that's how you parameterize tasks so the
command line options went there um the
yellow is where a task can actually uh
can have accumulated state so it's sort
of like a stateful transducer um if you
know about those or you know if you had
a a middleware factory you could have
state there um and then the green and
blue is the standard middleware pattern
where you have a Handler that um passes
after processing the uh the file set it
passes it to the next Handler which then
continues so you have layers of
middleware uh we have a little macro
that allows you to simplify this in a
lot of cases um sometimes you can't use
this but this is this is essentially
what a task is doing so you have
accumulated State
Handler so now we have uh shown how we
can compose pre-existing tasks um but
Misha's had to uh type in that
composition multiple times Now command
line reppel and he might just St off the
stage do it again so we're going to
introduce a new thing uh this death task
which you saw in the slide death task is
a way for you to name compositions of
either existing things or a new
functionality so defining a task is like
creating a Plugin or extending boot um
like I said can use it to compose
existing things or this is the place
where you might Implement new
functionality here we're just composing
the existing things like we did before
but we're just giving this whole process
a name
build now the uh you'll notice the long
options that the task con structor
functions are taking like colon project
oron main um those are the same options
we were passing on the command line
they're just the long options so boot
supports short and long options at the
command line and in the reppel all the
options are keyword arguments that
are match up with the long options
line um so did you yeah did you do doc
on build yeah so one of the things deas
does uh so tasks are regular functions
but we prefer using the death task macro
to create them just because they have
metadata on them that who can use to
inform itself about them here is the
Misha is showing that the build task has
a documentation scen and and supports
Dash which was functionality
automatically provided by death task and
all the other tasks also can be um
researched at the command line or at the
rep same
way so we have a problem with our thing
no worries I have RL wrap going on here
oh nice yeah fix it so the problem is
that the project or the Palm task needs
in addition to the name of the project
needs a version we only Supply the name
of the project so V is going to provide
the version long option
0.1 or who knows maybe we're ready for
1.0 we type it
in okay then we do jar
let me
install could probably just type
that okay don't worry about that that
warning is totally cool totally normal
it's going to work it's going to work I
know watch watch see told you it's going
to
[Applause]
work got a warning it's going to be
awesome
warning so now we've created our own new
name task it doesn't actually do
anything new it just composes existing
things but for a lot of projects that's
exactly and only what you need to do a
cool thing is that this new task we
created is first class in the sense that
you can call it compose it just like any
of the built-in tasks here Misha has
composed it with the watch task which is
one of the built-in tasks of boot that
is composable with a task it's not
particularly special the watch task
leverages the fact that like any
function that follows this middleware
pattern we showed inside the innermost
function which is the piece of code that
actually does the logic Tas has the
opportunity not to call the next pass or
to call it multiple times what the watch
pass does is it has a handle to that
next Handler and uh it is monitoring The
Source directories and when the source
directories change it calls that
function um so because f are functions
that's
totally it's even fun to do honestly so
now we've been doing a lot of typing in
the repple on the command line and stuff
like that but the more stute abuse will
say ah what if you could put that in a
file then you'd really beet
and it turns out that yes it's occurred
to us too uh the first thing you might
want to the original idea was we just
take a screenshot of the rep check that
in the CVS I keep telling you it doesn't
work that way I mean look at this like
we have a screenshot here which is
pretty sweet
beautiful that's not how you do it all
right uh so you can boot does actually
support just making you know an ad hoc
script with closure in it and you have
access to all the boot the the boot
Library stuff so you can actually make a
build like this bang at the top um make
the file executable you have a main
method down there that can take
arguments and you can you can build your
project like this it'll totally work uh
but what you give up here is that you
have to process the arguments yourself
you can't be composing different tasks
on the command line like this um if you
if you have just an executable where
you're handling the the things in the
main method so um boot does uh boot will
will look for a file called build. boot
in the project directory and it'll
evaluate the code in there and then
it'll take your command line options and
build a pipeline out of them so in other
words it generates the main method for
you uh at run time when you when you
call it and so you can use this to
Define tasks and things like that in
your build. boot which you can then
use from the command
line so we want to show that yeah
yes so the first cool thing now that our
task is in a file and it has is in a
build. boot which is this extension that
boot semi magically knows about we can
do boot d8
and the task that we created will show
up right alongside all the built-in
tasks with a documentation string a PO
documentation but
exist and you'll notice there's an ex
extra new line there between the built
on ones and the ones in your project so
typically you know we'll create these
build uh files for a project of ours and
they're self-documented to the extent
that at least the user who types bo- is
able to discover the pass available
that's a lot like you know or ant show
or
whatever um
yes here we
go and that's the go so the same way we
can use watch at the reel to compose
with this thing at the command line it
also composes with you know watch so
doing all the same stuff we've just
slightly changed the format that we're
storing the build programming and a
build up we
F so again we can you know make full
pipelines that show the
things and uh it's pretty
sweet let make a new task guys so at
this point we've only composed new uh
existing things and given a name to that
composition but one of the more exciting
things about Bo to us is that it gives
you the tools you need to create new
kinds of tasks um so for instance one
thing you might need to do which is
extremely important in some businesses
is you need to convert Java into for
train
and true
fact this is actually little known but
you know check
Wikipedia uh P train is actually just an
uppercase version of
job so it's really quite
trivial unfortunately this is kind of a
controversial view so we haven't built
his tasking to boot yet so we're going
to have an opportunity here to um to to
to write a Java to Fortran
transpiler for your
satisfaction yeah let's talk about the
file set a little bit because we're
going to be dealing with it in a minute
um file set can be the main the main
purpose of the file set is it provides
an immutable abstraction that we can use
to pass information between tasks why is
immutability good and I know there's
somebody out there playing a drinking
game that every time I say immutability
has to like drink so I'm sorry dude but
I'm going to say it a few more times um
immutability you be wasted by like 10
a.m. so immutability is great because
imagine you have this pipeline of tasks
right and each task gets a file set and
it does some things creates a new file
set that it passes on to next guys so it
can hold on to this file set if it's
immutable and use it later which is key
so otherwise you have a situation where
you have a build tool where they're
passing where the the file system is
mutable right so what happens when a
task wants to take this Java file and
make everything uppercase so you were
typing in your editor happily you press
the build button and now everything's
for TR and you don't understand it right
so
yeah and mutability is key because tasks
need to have full reain to modify any
file because what we want to achieve in
the long run is have our tools doing
more and us doing less so our tools need
to be able to modify anything so the
solution here is look at Git You Know
listen to me now believe me later it's
like
G There's real files underneath because
the Java class path is a real thing all
the jbm tools use the class path but we
provide a an immutable snapshot of it
and that's the information that gets
passed between so it's immutable it has
an API for querying it meaning you can
say what's in the file set and it'll
give you these you can either get um
actual file objects or just the relative
path in the in the class path um you can
add or remove things which returns a new
immutable file set object and you can
commit which is a mutating function that
mutates it makes the underlying files
the file system like the immutable thing
so it's like restoring from backup or
you know checking out a commit and get
the underly files are like the working
set which nobody has access to but the
internals of boot and you interact with
that by making commits just like in get
to this file set
object oh this is my part I fell asleep
wake up stage um yeah so here is uh
there are expanded build out our for
that includes our Fortran transpiler
task so actually I'm here for
so we have an upcase death task actually
you know that should be called for TR or
whatever next next presentation we do
that so we're creating a death TK UPC
case and it has a documentation string
and that would be the documentation SC
we see if we did upase
DH next we have an opportunity to
configure the txk so maybe our fortrend
files Go by another name you know PHP or
C maybe are also P TR if you upcase them
they actually are
true um so this is where you can add add
options that somehow configure or
parameterize this task so inform it how
to do this job now inside this closure
um this or this let expression we
mentioned earlier this is a place where
a task can accumulate State and what
we're doing here is we're initializing a
resource that's uh invocations of this
Tas school we use to store intermediate
State this is kind of what your file
system is between G commit this is the
place where you're doing your working
you prepare things and when you're ready
you commit them to the file set but in
between those two times is when you need
to work with sort of a live meable thing
this kind of analogous to the way one
works with transient and closure you
know nobody cares as long as it happened
inside the
function
um
next inside the innermost uh function of
the of this of this task is when we're
calling a f a function called upcase
files and if we look at upcase files up
here it takes a directory a working
directory
and a list of
files um and inside there it calls a
function upcase bang now this is such a
useful thing to do that actually I
created in push to Clow jars a little
Library it's super sweet it uppercases
things he used the install task and
everything yes yeah yeah I was pretty
proud myself unfortunately you all
weren't around to Plat when I did it but
it was pretty awesome um so inside this
task we're calling this function and
this is really typical of a lot of the
tasks we've written so far there are
existing things that have been written
to convert one kind of file to another
whether it's you en closure script or
scss or whatever and we write tasks to
wrap and sort of sanitize that
functionality such that we can compose
these things
together finally at the end oops we have
and I mean at the end of this task so
the task has done its work it called
upcase files on this directory upas
files went in and mutated a bunch of
files in our working directory this dur
and now what we do is we add this
directory to the file set this is the
sort of analogous to a get add followed
by a get commit we're adding things to
the file set value committing it and
preparing it to be passed to the next
PATH in the change if there is one um
which is
great works awesome we could actually
maybe run that one with the command line
yeah let's do that
there it is that's
Lor cool and by default boot will dump
the final file set value or rather
synchronizes that final value to
directory Target directory and there we
have it for
train there's a problem hold
the please be boot show Dash me
execute look at these
dependencies let's let's celebrate these
dependencies for a minute can we scroll
up I like that x Allen
library and J boss so in the course of
developing the updates
Library so when I was Raising this
function to uppercase strings I thought
man you know this surely has been done
in some other Library so I went and got
every Library fromen and clars and I
brought them in cuz I don't know I was
feeling
it which
US yeah a lot of people are like
me brings us to pods anyway so we
invented this
thing first Toby Crawley oh yeah that's
right we that Toby Crawley of mutant
thing actually sort of have the original
idea yes there he is thank you dude yes
you saved us all from dependency heal
and so the idea here is that we have a
program inclosure and we have other
things we want to use from closure but
we can't use them because they have all
these dependencies that interfere with
the things that are in our program and
the way they interfere is basically if
you have a jar file that has a class of
the same name as something that's
already in the jbm already in the class
path you have problem so uh what you do
is he creates pods which are isolated
run times which can have their own set
of dependencies and you can eval valate
expressions in there which is really
useful you can even like you know expand
a macro in there so you have a macro
that has crazy dependencies you could
yeah cool things uh it's easy to create
run code inside of them they're first
class you can have a function that
produces a pod you can have a function
that takes pods as arguments and returns
pods all things you can do with regular
first class things en closure although
unfortunately some things can't be
passed between pods because of the
dynamic nature of closure um each
instance of closure each closure runtime
has dynamically created protocols and
interfaces and all these things that you
can mutate inside this runtime so it's
really not possible to pass things
created by closure to each other but on
the other hand closure is really welld
designed I mean you you you can print
just about everything that's useful all
the data that you that you're going to
need you can read it and print it or
make a tag literal and that's just fine
you can pass strings no problem
so like anything in boot you can
experiment with pods or any of the boot
API and Nisha said that pods are first
class we have Constructors for them and
we do create a pod value and it's kind
of like a we' come to think of them as
kind of like little containers little
Docker containers on CU they're like
little VMS that you can run arbitrary
closure inside of and that closure will
not affect the the the program as the
whole it's
isolated um I think actually recently
one use of pods in a in a work project
was uh I was calling out to the the
Amazon uh sqs API which required
bringing in all of most of Amazon's API
or all kinds of other services unrelated
to sqf and also in that pro project I
was using different versions of the
Amazon API MBR you know all these things
bring in multiple logging libraries and
all kinds of things that can really hose
your program so instead of doing these
different things in different jbms which
is you know memory uh consumptive and
thrown to error just run all these
different things in different
pods so what Misha is doing here is he
defined a pod called pod and in the boot
dop name space there's a constructure
made pod the Pod takes an environment
which is a map describing the
environment that pod should start up
with it's kind of like a Docker file for
pods you're familiar now what he did is
in this pod there's closure 51 was
brought in kind of you know retro
closure version uh a lot of cool things
in closure one 51 but we certainly don't
want to use it anymore but maybe we're
using some library that requires
something in closure1 again that
probably will never happen in closure
but who knows um in there he ran the
expression closure Dash version which is
a a function call that prints out the
version then he back in the parent
environment which is the reppel he ran
closure version uh and you know we can
see that we're in closure one so at the
top
level pause sweet
you some sure um so here we do the same
thing that we did before only we're
running Allen's awesome code in a pod so
we don't have to deal with the
consequences of all those dependencies
so the first thing we do is we Define
the environment that the Pod is going to
have and so this pod is uh podm there is
the environment of the parent so this is
you know our current environment and
what we want to do is we have the
current environment but with different
dependencies so we're setting that pod
to have a dependency on on Allen's
library and then down here uh this is
some accumulated state that our task is
going to have it's going to own its own
pod and this pod is pretty cool it's a
we make an anonymous pod bind it locally
you know lexically which is then in the
closure of our closure with an S of our
task it's pretty pretty
listy um so here we we added a uh a
parameter to the upcase files function
which uses the pod
and you're welcome no thank you sorry
we're not we're done quite
yet uh yeah so at the at the uh at the
end we we commit it and what did I miss
uh I don't know we should run
it fair
enough uh upcase oh right
origal I
there there we
go feel good about this I feel super
good
too no
exceptions
yes
yes is not an
option so did the thing but now did the
Pod help so we can use boot show now to
look at the dependencies
and drum roll there's no dependencies
[Applause]
success so to be clear it's not like our
project has no dependencies it's just
that those dependencies are isolated to
the places in the build process where we
need them um yeah we've got uh another
probably 10 minutes so maybe we can show
some hop on stuff and get some questions
sure yeah you I have
questions definitely ask them so so this
is something that I'm actually doing for
uh hoplon which is a a web framework
which doesn't use react so I know you're
love the sound of this like oh they have
their own bill tool framework oh those
people getting to drink a lot too the
react the react drinking game people
react react
uh so what we have here is uh this is
the bill. boot for hoplon doio which I'm
I'm uh doing some work on and uh because
hopl on. it's a um it's a a website with
a lot of content in it um and uh so
doing content and with hopl on you do
everything in list uh in actual X
Expressions it's a a list program the
actual markup is a list program and
doing content in list in s Expressions
is
surprisingly
unfun but there's stuff like ham which
are basically emitting s Expressions but
they do it without the punctuation so
that means you don't need to escape
anything but you do have to endb things
right and so I wanted to incorporate
haml into my so I wrote a little haml
task which takes my version of haml and
emits s expressions from it which
becomes a hoplon source file you should
show some of the some of the source okay
sufficiently mindblowing I think it
like I mean not to overstate it yeah
I I yeah
content start yeah that's the one so
this this is a pretty sweet file make
you take it away yeah so here's a
Hames thing where you know these uh the
percent means make an S expression with
this thing as the car the head the
operation and so there's a clj macro
this is actually a macro that's getting
called which incorporates all this stuff
which is text to the haml editor as uh
it splies these Expressions into the
final product Oh and actually we're out
of time
so go down to the part the point here is
that we were able to take our existing
workflow and shim in a thing that takes
haml and you know basically we're we're
doing a multipass build where each pass
is totally independent from the others
so I can haml use haml and I can take
haml out and the rest of my build won't
won't change and actually we're using
you can see it on l947 it's marked down
inside of haml inside of that gets
converted to closure script which gets
converted to JavaScript which you know
runs in your browser yeah MD is actually
a
macro MD is a macro which compiles down
to an a which is basically closure
script s expressions and it's a syntax
highlighting using um using uh pigments
in J python in a
pod in a pod
[Applause]