- MCP server with stdio transport for local use - Search episodes, transcripts, hosts, and series - 4,511 episodes with metadata and transcripts - Data loader with in-memory JSON storage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
420 lines
27 KiB
Plaintext
420 lines
27 KiB
Plaintext
Episode: 2428
|
|
Title: HPR2428: git Blobs
|
|
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr2428/hpr2428.mp3
|
|
Transcribed: 2025-10-19 02:50:36
|
|
|
|
---
|
|
|
|
This in HPR episode 2428 entitled Get Long, it is hosted by Klaatu and in about 33 minutes
|
|
long and Karimaklin flag.
|
|
The summary is Klaatu talks about Get Media and Get Annex.
|
|
This episode of HPR is brought to you by an honesthost.com, get 15% discount on all shared
|
|
hosting with the offer code HPR15, that's HPR15.
|
|
Better web hosting that's honest and fair at An Honesthost.com.
|
|
Talk about managing binary blobs with Get because that is famously something that people
|
|
say rather disparagingly, oh, Get's not very good at managing large files.
|
|
Get can't manage huge binary files that it can't parse and dip and merge and so on.
|
|
And I'm here to tell you, dear listener, that they are absolutely unquestionably correct.
|
|
Get is not very good at managing large files.
|
|
And I say that with as much love as I can muster forget, which is a lot.
|
|
Get, as I've said on probably previous episodes of this, or at least maybe my own show,
|
|
Can New World Order at CanNewWorldOrder.info.
|
|
Get was my first version control system.
|
|
I had never used a version control system before, I didn't even exactly know what they
|
|
were.
|
|
I knew something called SV and existed and I'd probably checked something out from instructions
|
|
on a website or something, but I had no real experience with it.
|
|
So when I finally got introduced to a version control system, it was Get.
|
|
And so that's what I've been using ever since and that was probably back in 2009 or so.
|
|
So I'm pretty fond of Get, but the fact is that it's just not designed to deal with large
|
|
media files and the reason or large binary blobs.
|
|
And that's because Get isn't our sink, you know, I mean get in fact one of its features
|
|
is that when you clone a repository, you're getting its entire history.
|
|
So if someone is, say, making a 3D model of something and then sending up this huge file
|
|
to the Get repository and they do that in January and then they tweak it a little bit progressively
|
|
until, I don't know, even just until April, then there's probably quite a bit of data
|
|
that you're going to have to download should you ever do a clone and you can get around
|
|
it in a way because you could do a shallow checkout.
|
|
But then how do you know that the thing that you're checking out has the stuff further
|
|
back that you might also need?
|
|
So then you'd have to like sort of cherry pick through the history to find, oh well I've
|
|
got the updated big 3D model, but everything else was checked in way back in December of
|
|
the previous year.
|
|
So my checkout that sort of got everything from March on didn't get those, so now I'll
|
|
have to do.
|
|
I mean, I haven't tried exactly that scenario so it could go better than what I've described,
|
|
but the point is that get starts to add up if you start committing big files and then
|
|
modifying those files, it just gets really, really big and bloated and sometimes prohibitive
|
|
leaf, so I was managing a server for someone who was doing exactly that they were doing
|
|
3D models to a Get repository against my advice I might add.
|
|
And after, you know, in about six months they emailed me and they were like, hey, look,
|
|
we need to redo the Get repository because at this point it's something like 33 gigs
|
|
and it is timing out before I can even down, I can form my developers can clone the repository.
|
|
So in other words, suffice it to say that get, we're going to agree that get does not really
|
|
deal with really large files really, really well.
|
|
It's something that can become a problem.
|
|
The answer to this is possibly 3-fold, well, 4-fold if you really work at it, but let's
|
|
say 3-fold at first.
|
|
So one is get for large files or something like that, I think it's get LFS is what it's
|
|
called and it was put out by GitHub and it's open source and it's, well, I don't know
|
|
if it was actually, I'm not sure if it was put out by GitHub, but it belongs to GitHub
|
|
now anyway.
|
|
And yeah, it's get large file storage is what it's called and you can find out more
|
|
information about it if you want at get-lfs.github.com.
|
|
I've never used it, I can't vouch for it.
|
|
It was a fork of get-media.
|
|
Now get-media and get-annex are the ones I'm going to talk about because those are the
|
|
two that I've used.
|
|
They're a little bit different in the way they approach the problem or the issue.
|
|
So get-media, for instance, takes a centralized approach.
|
|
So a repository for all of your big, common asset files, whatever they are, media, just
|
|
big binaries, whatever, you designate a place where they live.
|
|
And this can be a hard drive on your shelf or it can be a server or whatever, NFS share,
|
|
wherever it may be.
|
|
And each developer on your team then treats that location as essentially a file share and
|
|
that's the place that they grab those files from.
|
|
Now get-annex is distributed, it goes a little bit more distributed and it lets you and
|
|
all, each developer on the team, each user on the team, they can create their own repository.
|
|
So in their local file system they get a .get-slash-annex directory and that's where all the big
|
|
files get committed to and pushed to, it just goes straight to their local file system.
|
|
The annexes, these little get-annexes are synchronized regularly so that all of those
|
|
assets become available to each user as needed.
|
|
And unless configured otherwise, get-annex prefers local storage before it will resort
|
|
to off-site storage.
|
|
And that's from what I've read, it's meant to be a cost-control measure because it's
|
|
kind of assuming that you might be developing on something where it actually costs money
|
|
to transfer data to and from.
|
|
So it prefers the local storage and then resorts to off-site if you tell it to.
|
|
Now I've used both so I'm going to talk about both and you can decide for yourself
|
|
which one you want to use.
|
|
I mean you should probably just try them each but I'll just kind of briefly mention how
|
|
each of these two solutions work.
|
|
So get media is written in Ruby.
|
|
Now if you don't know anything about Ruby that's fine, you don't really need to but you
|
|
will need a somewhat respectable Ruby stack on the computer that you're using in order
|
|
to get this thing installed.
|
|
So you'll do a get clone of get at gethow.com, colon, alb-dev-get-media.get and then you
|
|
change directory into that and you do a gem install bundleer which I don't know what
|
|
that means.
|
|
Bundle install?
|
|
Don't know what that means.
|
|
And then you do a gem build get-media.gem spec, don't know what that means.
|
|
And then you do a pseudo gem install get-media-astrisk.gem and that's the install process.
|
|
So you go through that and suddenly get media is installed on your system and again I don't
|
|
really understand any of that.
|
|
I'm assuming it's basically a pip type situation for Python but yeah it's pretty simple.
|
|
So once you've installed it you have to set a couple of configuration options in get and
|
|
you can do it globally or you can just do it for that repository.
|
|
And the magic incantation for that is getconfig-filter.media.clean and then quote get-media-filter-clean
|
|
close quote and then getconfig-filter.media.smudge space quote get-media-filter-smudge close quote.
|
|
Now you have to do that on every computer that you want to use get media on.
|
|
So if you've got, if you're one of those people who does, you know, you get your laptop
|
|
and your workstation and you're developing on both and you'll want that you'll want
|
|
to obviously install get media and then also create those filters manually on each computer.
|
|
But you only have to do it once per computer.
|
|
That's the good news.
|
|
Now per project you have to create some filters and the way that you do this is with a .get
|
|
attributes file and it's just line one filter, one file type per line and so what you're
|
|
doing is you're telling get what extension, what file extensions it should consider to
|
|
be a big binary blob or in get media terms media.
|
|
So you can do this with, for instance, echo quote asterisk.mp4, for instance, space filter
|
|
equals media, space-crlf, close quote greater than greater than dot get attributes.
|
|
So you're echoing the string asterisk.mp4, space filter equals media, space-crlf, close quote,
|
|
into a file called .get attributes within your repository obviously.
|
|
And you could do that with lots of different file formats.
|
|
I chose MP4 because it's fairly ubiquitous, but it could obviously be .imkv, it could
|
|
be a .og, .flack, it can be whatever, it can be a video file, you know, whatever you're
|
|
committing, whatever wonky big file that you're trying to put into your get repository.
|
|
And anytime you do add such a file, if you've got a filter in place, anytime you add that
|
|
kind of file to your, you know, when you stage it, when you do a get add foo.mp4, then that
|
|
file gets copied to your repository in your repository directory to .get slash media.
|
|
That's where it sits until it's pushed.
|
|
Now assuming that you've got a server somewhere that you're going to push all of this stuff
|
|
too, then you need to tell your get repository where those media files are actually going
|
|
to go once you do push them, because that's the thing about get media.
|
|
It doesn't assume, or that's one of the things about get media.
|
|
It doesn't assume that the place where you're keeping your code is necessarily also the
|
|
place that you're keeping your very large file assets.
|
|
Again, it kind of, I think a lot of these make allowances for people developing on platforms
|
|
that charge them for activity, you know, for bandwidth.
|
|
So you can set this, the location of your stash, not your stash, that's a thing, and get.
|
|
You can set the location of your file share, of your big file share in .get slash config.
|
|
That's a standard file in any get repository, so you should see it already existing.
|
|
The block of information you need to slap in there is, it's an I and I style configuration
|
|
file.
|
|
In square brackets, you but get dash media, so it knows where to find itself, and then
|
|
the transport equals whatever you're using, probably a SCP, but maybe you're using get
|
|
protocol, I don't know.
|
|
Then auto download equals, and you can set this to either true or false.
|
|
If you set it to true, then it pulls in assets by default.
|
|
If you set it to false, then it does not retrieve those large assets.
|
|
It lets you do that yourself.
|
|
And then you want to set your SCP user, so that might be SCP user equals clatu, and then
|
|
your SCP host, which is, let's say example.com, and then your path to the path to the get
|
|
repository.
|
|
SCP path equals, and then it could be, let's say, slash, home slash, get slash, foo.get.
|
|
Now if you've got any more complex settings in that that you need to use for SSH, like
|
|
a non-standard port for SSH or a key file that wouldn't be the default key file, then
|
|
you can enter all that stuff, and this is what get, at least last time I checked, this
|
|
is what get itself recommends, just put all that stuff in your .ssh slash config file.
|
|
And I think I've actually done an episode about that on hacker public radio, so look back
|
|
at some of my episodes, I'm pretty sure I cover the .ssh config stuff.
|
|
So when you're working with get media, I mean now it's set up, so when you're working
|
|
with get media, it's mostly invisible to you.
|
|
You'll work in your get repository, you'll stage files, whether they're text files or media
|
|
files, whatever, you just, you add them and you commit them just as usual.
|
|
The only difference that you'll notice in your workflow is that at some point you'll
|
|
have to sync your little stock pile of assets or media or whatever you want to call it
|
|
to the shared repository.
|
|
When you're ready to publish all of your assets so that everyone else on the team can actually
|
|
see them, then you just use get space media, space sync, s-y-n-c, and then it sends any
|
|
new really big file that you have up to the centralized server that you and your team
|
|
have decided to use for your big files.
|
|
And that's handy because if you're at a coffee shop or something which I used to work in
|
|
coffee shops a lot, so I'd be on some kind of janky public network that sort of barely
|
|
works and so you might push something up to a get repository and the last thing you'd
|
|
want to do is send this huge five megabyte file, yes I said huge and then five megabyte.
|
|
You know, on that connection, so you would just send all of your little tiny text files
|
|
up there and then when you got back to the office or back home or whatever, then you
|
|
would do get media sync and send all of your big files up.
|
|
It's quite handy.
|
|
Now that of course introduces a couple of other things that you might have to learn along
|
|
the way.
|
|
As getting started goes, that's all it takes to get started, but I mean there are some
|
|
times where you realize, oh man, the whole point of me doing get and large files is that
|
|
I want to update these large files and then upload the new version without creating a
|
|
new, you know, sort of file system node as it were, you know, I don't want there to be
|
|
a new blob and get.
|
|
So how do I do that?
|
|
Like, where's the part about the workflow where I can update the media that I have now
|
|
uploaded to my centralized file share and that's pretty simple as well.
|
|
So all you have to do is explicitly tell get to update the media, which overrides get
|
|
media's default setting of, well, don't copy a big file to the server if it already exists.
|
|
The way that you do that is get space update dash index, space dash dash really dash refresh.
|
|
So that again is get update index dash dash really refresh and that forces it to copy
|
|
a large file up to the server and and replaces the one that was already there.
|
|
Now when other members of your team or you yourself on a different computer, when you, when
|
|
you clone that repository, no assets are downloaded by default again because that is as long
|
|
as you've set it to to false in your get config file, it won't download that by default.
|
|
So again, you would just do a get media sync to copy any of the big media files that are
|
|
on the server and that are not on your local computer.
|
|
So in other words, the activity on the big files is always an extra step.
|
|
It's an explicit command from you and I think that's intentional.
|
|
I get the impression that that is very much the design of the system and I think it makes
|
|
a lot of sense because if we're assuming that the big assets are and they usually are,
|
|
there are usually things meant for delivery.
|
|
There are the things that are going to get attached to a project right before it ships
|
|
out, goes out the door.
|
|
You don't need to work on the big file assets all the time.
|
|
You get them done and then you upload them to the server and that's a snapshot.
|
|
So anytime you want to update them or download them, that takes an explicit command from you.
|
|
And that's get media.
|
|
That's a, that's the quick start on get media.
|
|
So now let's talk about get annex.
|
|
Select annex, slightly different workflow, like I say a defaults to local repositories.
|
|
I mean get media kind of does too because it stashes all of your, keep saying stash and
|
|
that's a completely different, I mean that's a thing and get so I shouldn't use that.
|
|
So it squirls away all of your big files into a local place, the dot get slash media.
|
|
But then it sends it up ideally to some central repository and everyone kind of works from
|
|
that central repository in, in theory and get annex isn't completely different from that.
|
|
But it's, it's a little bit, the way that it expresses itself is a little bit different.
|
|
You need get annex installed in order to use it, obviously, and you can install it probably
|
|
from your repository.
|
|
It's pretty well known.
|
|
It's kind of made its way into, at least from what I've seen, it's in all the, all the
|
|
major repositories.
|
|
There is not really any kind of big configuration that you have to do, like the get
|
|
media stuff where you had to sort of do the get config command and then create filters.
|
|
That's not something that you do with get annex.
|
|
So once you've got it installed, it's, it's installed and ready to go.
|
|
So to use it, you just go into your repository, whatever, whatever repository you, you intend
|
|
to use this thing with and you do a get annex init.
|
|
That sets the current directory as, as a get annex location.
|
|
There are no, like I said, there are no filters.
|
|
So you just tell get annex what to check in to into its, its system.
|
|
So it almost, it, it, it does feel a little bit like you're running a parallel version
|
|
of get almost, you know, because you're, you'll do a get add, food.txt, but then you'll
|
|
do a get annex add, food.mp4.
|
|
So that takes us, maybe, maybe possibly some getting used to because it is a separate,
|
|
it's a separate command.
|
|
And so if you, I guess if you're sleepy and you forget that the mp4 file is 2.5 gigabytes
|
|
and you think, oh, I would really like to add this, you, you have to remember that you
|
|
don't just get add food.mp4, you have to do a get space annex, space add, space food.mp4.
|
|
And that adds the, that particular mp4 to get annex.
|
|
It records its state in get and then you'll want to commit it probably.
|
|
So you do the, the get commit is the same as usual, which again, a little bit confusing
|
|
because now you've done get annex add and now you're doing a get commit normal.
|
|
So get commit dash m, space quote, I added a big file, close quote, and then you have
|
|
to push, but you have to push to a new, an extra location.
|
|
So annex, normal annex, that's kind of the, the workflow.
|
|
So get push origin master, well, I guess you would have to do the dash U version because
|
|
this is the first time you pushed.
|
|
So you do a get push dash U, which means create this thing up on the, on the remote.
|
|
And then origin master get dash annex.
|
|
So what you're doing here is you are, you're pushing your current branch, which is probably
|
|
master.
|
|
So you're pushing that to your remote, but you're also creating a new branch called get
|
|
dash annex.
|
|
And I don't, I actually have not looked to see if it actually has to be called get an
|
|
dash annex or if it's just a common name that makes sense that you should probably use
|
|
kind of like master.
|
|
You don't technically have to call it master, but everyone, it's just kind of convention
|
|
and it makes sense.
|
|
So let's just say you have to call it get dash annex.
|
|
Now a get push, just as with get media, the normal, when you do like a get push, that
|
|
does not copy your assets to the server.
|
|
It just sends information about the media to your server.
|
|
When you're ready to actually share those, the media or the assets, whatever, the big binary
|
|
blobs with the rest of your team, then you use a annex sync command.
|
|
And that's pretty straightforward.
|
|
It's get space annex, space sync, dash dash content, and that actually does two things.
|
|
It pushes anything on your drive, on your local system that is not on its destination.
|
|
And it pulls from the destination anything that is not on your local system.
|
|
So so far it's probably sounding a lot like get dash media.
|
|
And it is, it is, they both do really, really similar things.
|
|
The interesting thing about get annex is that you can't, it treats the remote file system
|
|
not as a central location.
|
|
It can be anything that you want it to be.
|
|
And this can get a little bit wonky and crazy because it's really just up to you.
|
|
But maybe you could think of it as adding like little get satellites to whatever you need
|
|
to add get satellites to, or you could just think of them as ad hoc get repositories
|
|
because that's kind of what it is, to be honest.
|
|
But get get annex itself adds a a trait to any remote that you add that you can describe
|
|
what that remote is.
|
|
And that's one thing that I think a lot of people kind of forget about get because we
|
|
all, not we all, but a lot of people kind of think of get, oh well it lives on a server
|
|
somewhere.
|
|
It's get hub, it's get lab, it's whatever, or it's my own private get server.
|
|
It's my own host.
|
|
But I mean get doesn't have to live on, it can just live anywhere.
|
|
It can be just a folder on your hard drive and you could never send it anywhere.
|
|
It could just live there.
|
|
So it doesn't, it doesn't have to be, we don't have to be pushing to a cloud or anything
|
|
like that or even across the room.
|
|
It can just be, it could be on one partition to another, one drive to another.
|
|
And that's all annex kind of actually leverages is this ability to forget to know where
|
|
things are located based on remote definitions of what a remote is.
|
|
So for instance, let's say that we've got a USB drive plugged in.
|
|
So we could go to the USB drive and we could, we could clone a get repository from our actual
|
|
hard drive.
|
|
That would just be a standard get command, it's a difference again, would be that you're
|
|
not doing it over SSH or get or HTTP, you're just doing a straight get clone.
|
|
So you do a get clone slash home slash class who slash my project.
|
|
So now that that folder exists, that get init folder, you know, the thing that you created
|
|
and have get on, that is cloned onto your thumb drive.
|
|
Then you can go into that into the thumb drive version of that repository and you can do
|
|
a get annex init and you can comment for yourself what it is.
|
|
So you might say, quote, my portable USB thumb drive, close quote.
|
|
So now you'll know where that repository is located.
|
|
You don't care right now about that, but you will in the future and I'll tell you why
|
|
in a moment.
|
|
So then you can add a remote, which would be your workstation, you know, the actual hard
|
|
drive from which you cloned this thing.
|
|
So you'll do a get remote add workstation, space slash home slash class who slash my project.
|
|
Okay.
|
|
So you've just cloned a repository.
|
|
You've blessed it as an annex location and then you've added a remote to that clone, which
|
|
is the hard drive from which you cloned it in the first place.
|
|
Now you can go to your workstation, the original repository and do a reciprocal action of adding
|
|
a remote that is your hard drive, your thumb drive, your removable thumb drive.
|
|
So you would do a get remote add thumb drive and then slash run slash media slash thumb
|
|
drive or wherever you keep your thumb drive mounted on your on your workstation.
|
|
Okay.
|
|
So those two locations are now aware of each other.
|
|
They know each other that each other exists.
|
|
Great.
|
|
Right.
|
|
Okay.
|
|
Well, remember, you've marked that thumb drive as an annexed location and get knows that.
|
|
So when you're doing a sync, get annexed sync, it knows what is available to it and what
|
|
is not.
|
|
So if you're on your workstation and you think, oh yeah, I forgot, I stashed a bunch
|
|
of my work on my thumb drive, like my big files on that thumb drive and I should get those
|
|
over locally onto my workstation.
|
|
So you would do a get annex sync dash dash content and the cool thing about get annexed
|
|
is that if it doesn't have that thumb drive installed, it will tell you that you need
|
|
to plug it in.
|
|
So it knows that there's media out there that is not on your workstation because get annex
|
|
has told it, but you're syncing now.
|
|
And so now it's looking for some food.mp4 file, can't find it.
|
|
So it will tell you, unable to access these remotes and it tells you, it can't access
|
|
your thumb drive.
|
|
And it tells you exactly what that thumb drive was, it gives you the UUID of that thumb
|
|
drive and it gives any kind of description that you've provided it.
|
|
So if you'd said my portable thumb drive, then you'd know, oh, right, I don't have my
|
|
thumb drive plugged in or I don't have it mounted right now.
|
|
I should do that.
|
|
So then you would do that.
|
|
And then you just redo your get annex sync dash dash content and you're good to go.
|
|
Simple.
|
|
And you can have as many remotes as you want.
|
|
I mean, if you've got some big files, I don't know why you would manage your life this
|
|
way, but I mean, if you did it, you know, you'd have some big files on a server.
|
|
You should have some big files on your USB hard drive.
|
|
You could have some big files on an NFS share, whatever, it's up to you.
|
|
You can have annexes wherever you want them to exist.
|
|
And that's the idea behind get annex.
|
|
And again, there's a couple of things.
|
|
I mean, I've already talked about some of the stuff that is different in the workflow,
|
|
just the fact that you have to keep invoking get annexes this and get annexed that.
|
|
So that feels a little bit different than get media, which feels a little bit more,
|
|
I'd say, integrated or invisible, maybe would be a better word.
|
|
Get annexed is kind of like right there, yes, I'm using get annex.
|
|
And there's some of that later on too, like when you want to remove files or modify files,
|
|
you know, how do you get them to actually replace those files on your remote?
|
|
It's not really that hard.
|
|
It's pretty simple.
|
|
It's just a bunch of different commands that you can look up on the get annex website.
|
|
It does a full walk through that makes it very, very obvious and very easy.
|
|
But you need to do in order to achieve certain results.
|
|
And that's it.
|
|
Those are the three ways of managing big files with get.
|
|
And again, I said there were three, one of which I did not discuss get LFS.
|
|
And then I also said really a sort of offhand, I said, oh, well, there's really four.
|
|
And the fourth way is just not to not to do it at all, which is not to say commit everything
|
|
to get.
|
|
It's to not commit anything to get.
|
|
And I've done this myself a couple of times and it kind of works.
|
|
It's not as convenient.
|
|
I don't think.
|
|
But in terms of setup, it's basically none.
|
|
And the way that I handled that was I created a bunch of sim links within my get repository
|
|
pointing to a master directory, a file that contains all of the other files and the
|
|
whole file structure of the assets that I knew that the get project technically required
|
|
in order to work.
|
|
And it works the charm.
|
|
You just, you get, you do your get clone and you have a bunch of sim links.
|
|
And then you place your, your, your big master tar file or whatever you've got all your
|
|
big assets in and you decompress it.
|
|
An archive it there in the folder and everything points to it and on all the paths resolve and
|
|
it works perfectly works fine.
|
|
So that's that's I'm working on formalizing that actually because it it works so well that
|
|
I think there might actually be some virtue to it.
|
|
But I haven't really sat down and I earned out all the kinks or made a friendly interface
|
|
to it yet.
|
|
I am getting there, but right now it's just sort of the lazy method that I do.
|
|
It does work.
|
|
You just have to, you know, the burden again is on you to have that master file somewhere
|
|
and to make sure it is backed up.
|
|
And in terms of distributing it, not really sure how easy that's going to be because if
|
|
you've got a bunch of developers and they all need the same files, yeah, sure, you can
|
|
send them the big file and say, well, that's where everything is.
|
|
When an archive that in your Git repository, you'll be good to go.
|
|
But then what if they are also adding big files and that becomes a really problem and
|
|
a big problem and that's where you would want to start looking toward to get media or
|
|
get annex to solve the distribution issue.
|
|
So that's it.
|
|
Those are the solutions to big binary blobs and Git.
|
|
I hope this has been helpful and informative and I will talk to you probably tomorrow.
|
|
You've been listening to Hacker Public Radio at HackerPublicRadio.org.
|
|
We are a community podcast network that releases shows every weekday, Monday through Friday.
|
|
Today's show, like all our shows, was contributed by an HPR listener like yourself.
|
|
If you ever thought of recording a podcast, then click on our contributing to find out
|
|
how easy it really is.
|
|
Hacker Public Radio was founded by the digital dog pound and the Infonomicon Computer Club
|
|
and is part of the binary revolution at binrev.com.
|
|
If you have comments on today's show, please email the host directly, leave a comment
|
|
on the website or record a follow-up episode yourself.
|
|
Unless otherwise stated, today's show is released on the creative comments, attribution,
|
|
share a live 3.0 license.
|