Our latest episode of Tag1 Team Talks is an insightful guide through the Extract phase of the ETL (Extract, Transform, Load) process in Drupal migrations. Hosted by Janez Urevc, the episode features experts Mike Ryan and Benji Fisher, who offer a deep understanding of data extraction relevant to migrations from older versions of Drupal (6,7,8) or other CMS platforms.
Beyond just insights, the episode dives in with practical experiences and unique scenarios in data migration. It also delves into the historical context of ETL, providing a comprehensive perspective. This series covers various topics for those interested in learning the details and further enhancing their migration skills, including performance tuning and incremental migrations. We encourage you to listen, subscribe, and stay updated with all the episodes in the series.
Welcome to Tag1 Team Talks brought to you by Tag1 Consulting.
Speaker:With Drupal 7 and Drupal 9 rapidly approaching end of life, we are
Speaker:hearing people talk about migrating and upgrading more than ever before.
Speaker:And anyone who's ever been involved with a large scale migration, migrating
Speaker:a large site or application, from one technology stack to another,
Speaker:will tell you that it's complex, time consuming, and it demands expertise.
Speaker:That's why we are bringing you the series of talks diving deep into
Speaker:the world of Drupal migrations, and who better to guide us than Tag1's
Speaker:very own Drupal migration experts.
Speaker:From the masterminds and maintainers of Drupal's migration tooling, to the
Speaker:individuals behind the most groundbreaking Drupal migrations, we've got an all
Speaker:star lineup who'll cover everything you need to know about every aspect
Speaker:of migrating large scale applications.
Speaker:This team talk is part, of the three part series about ETL.
Speaker:Extract Transform, and Load Process, which is used by many enterprise migration
Speaker:systems, Drupal's Migrate included.
Speaker:In today's episode, we're going to talk about how to use Drupal Migrate
Speaker:system to extract data from a Drupal 7 database or any other third party source.
Speaker:Be sure to stick around to the end because we are also going to announce
Speaker:next few talks in our series.
Speaker:Let's dive in.
Speaker:I'm Janez Urevc, Senior Engineer here at Tag1, and a
Speaker:longtime contributor to Drupal.
Speaker:I'm joined today by well known top contributors to Drupal, Benji Fisher,
Speaker:one of the five current Drupal Migrate core subsystem maintainers,
Speaker:and Mike Ryan, co creator of Migrate.
Speaker:Welcome.
Speaker:Thank you for joining me.
Speaker:Um, we are glad that you are here.
Speaker:Present.
Speaker:Okay.
Speaker:For the beginning, let's, uh, let's explain what ETL stands for.
Speaker:Um, like where, where does this concept come from?
Speaker:And, um, What are other ETL systems besides Drupal Migrate?
Speaker:Mike, I'm sure that you have plenty of experience in this area.
Speaker:Yeah.
Speaker:Um, I think the ETL concept really came from mainframe data
Speaker:migrations, uh, back in the day.
Speaker:I have little doubt that many of them were coded in COBOL.
Speaker:Uh, my first introduction actually was before Drupal.
Speaker:I worked in, uh, HR, human resources information services for a hospital in
Speaker:Boston, and we were switching HR systems.
Speaker:So, um, I was, uh, Primary person responsible for doing that migration.
Speaker:And that was a classic Extract Transform Load.
Speaker:We would extract the data from the original system into CSV files, and
Speaker:I loaded them into Microsoft Access, where I created queries to transform
Speaker:the exported CSV format into the format for importing into the new system.
Speaker:And then, you know, we'd export those CSV files and import them or load
Speaker:them into the destination system.
Speaker:So that was my first introduction to ETL.
Speaker:So access wasn't the final destination.
Speaker:That was just your, what you used for the transform stage.
Speaker:Yes.
Speaker:Um, we, we didn't have.
Speaker:You know, uh, database server to play with or anything like that in between.
Speaker:We're, we're basically limited to, you know, Microsoft Office tools, because
Speaker:this is, we weren't really a data center.
Speaker:We weren't engineers.
Speaker:Or it wasn't an engineering environment.
Speaker:I was a software engineer, previously, but, um, that I learned a lot.
Speaker:And then, uh, around this time at a Drupal meetup in Boston, Moshe Weitzman
Speaker:was also there and people were talking about trying to import raw HTML into
Speaker:Drupal and, um, you know, Moshe looked across the table at me and said, you know,
Speaker:there's There's an opportunity here, which is when we got together to, uh, start
Speaker:developing a migration system for Drupal.
Speaker:And of course, since we wanted to, and I'm getting ahead of ourselves a little
Speaker:bit, but, um, the original concept was importing raw HTML, but of course, you
Speaker:also want to be able to extract from databases or CSVs and so on, which
Speaker:led to the idea of a pluggable system.
Speaker:Uh, in specifically.
Speaker:Relevant to today's talk, uh, pluggable extract, um, plugins.
Speaker:Did you, did you have like a client or a website where you needed to use this?
Speaker:Or was just like, uh, you saw the opportunity and you decided
Speaker:that you want to build a system?
Speaker:Yeah, we, we started, um, building a system.
Speaker:I'm trying to remember what the first, was the Economist the first client?
Speaker:Yeah.
Speaker:I think there was, there was one before that we had, uh, this is, feels like
Speaker:ancient history, like what, 15 years ago.
Speaker:Um, yeah, but we, we saw the need.
Speaker:We saw that sometimes, um, the Drupal upgrade process could be difficult.
Speaker:And sometimes it might be easier to treat it as a migration rather
Speaker:than, uh, with update hooks as was the traditional method at the time.
Speaker:Yeah, that, that discussion, I already remember, I've been around for that.
Speaker:That happened like when we were figuring out how people were going to
Speaker:be upgrading their Drupal 7 sites to Drupal 8, because it was so different.
Speaker:Yes, the, the update method of it prevented making that sort of massive
Speaker:change to Drupal really, because there's no way you could really
Speaker:completely refactor the database.
Speaker:Um, schema using update hooks.
Speaker:Yes.
Speaker:Um.
Speaker:So so ETL stands for Extract, which is about pulling the data from the legacy
Speaker:source, basically, Transform, which is about processing the data along the way
Speaker:and then Load, um, which is basically storing it into the destination system.
Speaker:And today's topic is E, extract.
Speaker:So let's, let's dive into that.
Speaker:Um, what is being done as part of the extract phase and more importantly,
Speaker:how is that done in Drupal, Benji?
Speaker:So there are a variety of plugins.
Speaker:Um, yeah, typically when, or typically we're doing a migration from Drupal
Speaker:six or seven and we have a database.
Speaker:So we have, so we know a lot about the structure of the data and there are.
Speaker:Uh, what we call source plugins built into Drupal.
Speaker:Um, Drupal Migrate API has its own terminology, so the extract
Speaker:phase is called source plugins.
Speaker:Um, but the source can be lots of other things.
Speaker:If you're not talking about migrating from Drupal 6 or 7,
Speaker:you might have a CSV source, just a spreadsheet, or a spreadsheet
Speaker:in some other format like Excel.
Speaker:Uh, you could have JSON, it might be JSON API, um, XML or SOAP.
Speaker:Um, someone suggested that you might want to import emails into Drupal and
Speaker:then you'd have an IMAP formatted file.
Speaker:I've never seen that, but it's certainly something that could be done.
Speaker:And, um...
Speaker:I do want to point out that migrate system can be used not just for creating
Speaker:a Drupal site out of some legacy system.
Speaker:It can also be used for recurring migrations.
Speaker:And typically when, when you're doing that, the source is going
Speaker:to be any of those formats served over an API from somewhere else.
Speaker:And you might be importing articles or events.
Speaker:Users, um, just in any sort of content that you have, um, in any external system
Speaker:and you want to get it into Drupal.
Speaker:Yeah.
Speaker:Or you could use it with commerce, for example, and import, um, products
Speaker:on an ongoing basis from some other system where that is the main
Speaker:source of truth for your products.
Speaker:Yeah, I've, uh, I've worked on projects that were using QuickBooks and we wanted
Speaker:to get information going both ways.
Speaker:We wanted to get, um, I guess, prices out of QuickBooks into Drupal and we wanted
Speaker:to get orders out of Drupal into Commerce.
Speaker:And I think we'll talk about that a little later, um, or maybe in, uh,
Speaker:in one of the, the other episodes.
Speaker:The funny thing is that we ended up using the Migrate API for both directions.
Speaker:Which, uh, proves how well architected it is, in my opinion.
Speaker:Like the fact that you can, that you can come up with use cases.
Speaker:That are definitely not obvious, um, rules, how powerful it is.
Speaker:And I think that the main or not the main, but one of the reasons why it's so
Speaker:powerful, it's that it's, uh, architected as a pluggable system, um, where you have
Speaker:different plugin types and then you can reuse code by implementing plugins and
Speaker:reusing them on different migrations.
Speaker:Um, and this is something I would like to ask you, Mike.
Speaker:Um, because this is so core of the migrate nature.
Speaker:Um, did you, did you know from the beginning it should be a pluggable
Speaker:system or how, how did you decide that you want to architect it this way?
Speaker:Um, and maybe, maybe you can briefly talk about which plugin types do we have.
Speaker:Um, and yeah, why, why, it was done this way in the first place.
Speaker:Uh, well, I, I did allude to that earlier, and that is, um, the original
Speaker:concept we were talking about importing HTML in, um, raw HTML pages into Drupal.
Speaker:But of course, once you're using migration for, um, Drupal upgrades
Speaker:or side grades, which actually that was a common use case we saw where
Speaker:someone wanted to re architect their site on the same version of Drupal.
Speaker:And transform their, um, content types.
Speaker:So anyway, um, at the time this was before Drupal had a general purpose entity system
Speaker:and pretty much every module that had data had its own tables with their own schema.
Speaker:So you, we needed to have distinct plugins, distinct sources for
Speaker:each of those, as well as to handle, um, occasionally you'd
Speaker:need to import a CSV file into a Drupal table or, um, again, HTML.
Speaker:And once, once you start seeing things as pluggable, it becomes natural to just make
Speaker:everything pluggable, all the more so, uh, since Drupal 8, which is, um, Entirely
Speaker:built based on the plugin concept.
Speaker:Yeah.
Speaker:Like the idea of plugins was around even before I remember, like
Speaker:you had to like C tools provided plugins in Drupal seven world and.
Speaker:Even six, I think, uh, I think the Views module had plugins,
Speaker:Right?
Speaker:Yeah, it could be that even the, the thing that was in C tools came
Speaker:from Views and was then extracted into the C tools because C tools
Speaker:were a dependency for Views, right?
Speaker:Yeah.
Speaker:Earl extracted, uh, C tools from Views.
Speaker:As I, if I recall correctly.
Speaker:Yeah, and then in Drupal 8, we got this, it was basically completely
Speaker:re, re architected plugin system and then everything moved to that.
Speaker:And, um, yeah, it's quite pleasant to work with in my opinion.
Speaker:Right.
Speaker:Even plugins have plugins, you can have annotations or YAML, or
Speaker:I think there's a third way of specifying the plugin structure.
Speaker:You can always get very crazy about, you know, we, like when I was working
Speaker:on the media initiative, um, we also use plugins a lot and made everything
Speaker:pluggable, like sometimes when I, when I look back at it, maybe we even made
Speaker:everything too abstract and I think this.
Speaker:Drupal community loves to make everything abstract and everything pluggable
Speaker:and, you know, not opinion and that, that's very powerful, but sometimes it
Speaker:ends up seeing very complex systems.
Speaker:And now looking back, like I would, I would do some things in a more simple way.
Speaker:Um, in the media ecosystem, but, um, yeah, Migrate totally made sense.
Speaker:Every, all the time to me, like I never had issues understanding how it works.
Speaker:So great job, Mike.
Speaker:Um, so we already mentioned that going from Drupal 7 to Drupal
Speaker:8, uh, Migrate became part of core, which is another proof.
Speaker:Uh, how powerful and how solid it is, um, which means that, um, there is some
Speaker:basic functionality that ships with Drupal Core, but then, um, we also have
Speaker:a huge number of modules or plugins in the contributed space, um, which can
Speaker:help you run more esoteric migrations.
Speaker:Uh, Benji, could you tell us what, what ships with Core and
Speaker:what is that mostly used for?
Speaker:And what would we have to turn to Contrib for?
Speaker:Right.
Speaker:So in terms of source plugins for the Extract phase.
Speaker:Um, Core provides the the API that everything is built on.
Speaker:So there will be some, um, sort of base classes.
Speaker:There's a base class for a SQL source.
Speaker:Um, there's the content entity, um, content entity and
Speaker:config entity base classes.
Speaker:Um, but other than the basic things needed for the API.
Speaker:The criterion for being in core is that, um, the migrate system
Speaker:was the way to upgrade a Drupal 7 site to Drupal 8 or later.
Speaker:And so, um, the core migrations are almost entirely focused on that use case.
Speaker:So, in terms of source plugins, uh, we have Drupal 6
Speaker:sources and Drupal 7 sources.
Speaker:That's basically the only thing that is supported in core.
Speaker:So, for your migration projects, getting your pre Drupal 8 databases migrated into
Speaker:modern Drupal, um, that's what's in core.
Speaker:Anything else is going to be in contrib.
Speaker:Um, The only exception I can think of is the, the content entity, which is
Speaker:using the current database as a source.
Speaker:Um, so Mike was talking earlier about side, what did you call it?
Speaker:Side migrations?
Speaker:Side grades.
Speaker:Um,
Speaker:side grades.
Speaker:Right, so you, you can do that in the current site.
Speaker:Using the content entity source and just loop through all of your badly
Speaker:architected foo content types and creating bar content types out of them.
Speaker:Um, so for any other source plugins, we have to turn to contrib.
Speaker:There is the Migrate Plus module, which is maintained by, um.
Speaker:By Lucas Hedding, one of the, uh, one of the other maintainers, current
Speaker:maintainers of the Migrate API.
Speaker:So that's sort of considered core adjacent, um, things that seem generally
Speaker:useful but don't meet the criterion for being in core go into there.
Speaker:So there is, um, a source plugin there for SQL table.
Speaker:And then, uh, really generic, there is a URL source plugin, so anytime
Speaker:you're getting something from an API, you're, you're going to be using the
Speaker:URL plugin, and then the Migrate Plus module introduces its own plugins.
Speaker:So we, we know what the API is, um, we need, typically some
Speaker:sort of authentication, so there are authentication plugins.
Speaker:Um, we need to, um, fetch the data and then parse it.
Speaker:So there are three systems of plugins tied into the URI.
Speaker:I'm sorry, the URL plugin from Migrate Plus.
Speaker:And then there are, uh, a bunch of...
Speaker:Uh, more specialized contrib modules, um, there's one for CSV files, one for other
Speaker:spreadsheets like Excel, um, there's a module devoted to, um, Drupal Commerce
Speaker:and, uh, both earlier versions of Commerce and I think some other systems like
Speaker:Magento are, um, are handled by that.
Speaker:There's the WordPress Migrate module, um, which is a specialized XML source.
Speaker:The idea there is you export your WordPress site to XML, which WordPress
Speaker:provides that functionality, and then we import the XML into Drupal.
Speaker:Um, there's...
Speaker:Um,
Speaker:Just to note, there are other systems that, um, Implement
Speaker:the WordPress XML schema.
Speaker:So not just WordPress, but there are certain other, I can't remember
Speaker:which off the top of my head that use the same, uh, XML schema.
Speaker:So you could use the WordPress migrate to import from those.
Speaker:Cool.
Speaker:I didn't know that.
Speaker:So no reason to use WordPress anymore, right?
Speaker:There there's a Views Migration Module, and that's something that we just
Speaker:decided Drupal Core was too hard.
Speaker:There are too many variations contrib modules can make their own views plugins.
Speaker:And we just didn't think there would.
Speaker:a reliable way to, to migrate views from Drupal 7 into modern Drupal.
Speaker:There is a contrib module that attempts to do that.
Speaker:Use it with care because it is a hard problem.
Speaker:Don't expect it to be the final answer to migrating your views, but
Speaker:it can at least give you a start.
Speaker:Um, and I, I just saw yesterday looking at the list there.
Speaker:There's one that migrates playlists from YouTube.
Speaker:Um, so, so a lot, there are a lot of these specialized source
Speaker:plugins in contrib space.
Speaker:The YouTube one could be used for, uh, like incremental migrations.
Speaker:That we mentioned earlier, right?
Speaker:Like if you have a YouTube channel and you want to pull the videos that
Speaker:you upload there into your Drupal site automatically, you could use that.
Speaker:Exactly.
Speaker:Yeah.
Speaker:I don't, I suppose there might be some sites that would want to download the
Speaker:actual videos and they could do that.
Speaker:Typically we leave the videos on YouTube, let YouTube do what it does well.
Speaker:And, and migrate the metadata of the playlists into the Drupal site, and
Speaker:that would be recurring as you make new playlists as you add to the playlists.
Speaker:You'd want to import the new data.
Speaker:Yeah, you could have a, um.
Speaker:Uh, cron job that runs the migration.
Speaker:It's amazing, like how thriving the contrib is.
Speaker:And, you know, that's usually the case in Drupal, but you know, it
Speaker:amazes me over and over again, how many things developers come up with.
Speaker:And, you know, the ideas that people have just mind blowing, like sometimes
Speaker:you, you run into things that, that you would never think about and yet somebody
Speaker:thought about it and have need for it.
Speaker:Um, it's, it's really, truly amazing.
Speaker:Um, so I personally have done a few migrations in my career,
Speaker:but they were mostly, uh, migrations from third party CMSs.
Speaker:Um, I worked a lot with media companies and a lot of times media companies would
Speaker:have sometimes even internally developed CMSs and, uh, in one of the projects
Speaker:that I've been involved with, they realized that that is not sustainable.
Speaker:So they decided to, first they decided that they want to go with
Speaker:something open source, and then they decided to go to Drupal.
Speaker:Um, so we had to migrate from that and we were basically using the equal.
Speaker:source plugin, loading data from the third party legacy database,
Speaker:and then importing into Drupal.
Speaker:But I'm pretty sure that Mike Ryan, you have, uh, more, more interesting
Speaker:use cases that you've experienced, uh, throughout your career.
Speaker:So can you talk about that?
Speaker:Um, really would have to do some archeology on my memory to dig that up.
Speaker:Um, you know, one interesting use case, I can't remember exactly what
Speaker:project it was, but where there was associated data that the primary content
Speaker:was in the database, but there was associated content which needed to be.
Speaker:Um, pulled from a web API.
Speaker:So the, um, source plugin, the source plugin has hooks that you can implement
Speaker:to add to what the raw source plugin does.
Speaker:the source plugin and produces one row of data equivalent to an SQL row at a time.
Speaker:And you can implement the process row hook to, to add to it.
Speaker:Within the source plugin, so you can read the additional data from
Speaker:an API or CSV or so on and add it to that row before it goes into
Speaker:the transform part of the pipeline.
Speaker:Interesting.
Speaker:How did that affect performance?
Speaker:Because I assume that if you are calling APIs on every row, that can slow the
Speaker:migration down quite significantly.
Speaker:Yeah, it's, I mean, it really depends on the source.
Speaker:Yeah, sure.
Speaker:Yeah, if you're pulling from a local file, not so bad, or, but if it's a web
Speaker:API, then that will slow things down.
Speaker:As long as we're mentioning the process row step, it's worth mentioning that
Speaker:in a Drupal to Drupal migration.
Speaker:Um, there are a lot of fieldable entities in Drupal six or Drupal seven, um, content
Speaker:types of fields on them, for example.
Speaker:And we, we structure it the same way.
Speaker:We have the base table that gives us the, say the node IDs if you're
Speaker:migrating nodes and it produces, uh, you know, a bunch of rows.
Speaker:And then we use that, that same process, row stage, to attach
Speaker:all, all of the fields to that row, one, one row at a time.
Speaker:Yes.
Speaker:And although I said that it's equivalent to an SQL row, but it's, um, a logical
Speaker:row in an SQL row, you're going to have, um, scalar, uh, values.
Speaker:Um, while the row, the, um, row object that we're passing through we can
Speaker:have multi value fields in there.
Speaker:So in the prepare row, the, um, if there are associated fields with multiple
Speaker:values, those can be extracted in the prepare row and plugged into an array.
Speaker:As a member of the row, that's going to go through the pipeline.
Speaker:And then the rest of the pipeline knows how to handle.
Speaker:Uh, arrays and how to process each member of that array within the value.
Speaker:Benji, I heard that you migrated a single page into several nodes in the past.
Speaker:Can you tell us about that?
Speaker:Yeah, this, this was kind of funny.
Speaker:It was part of, uh, uh, a migration from Drupal 7 to Drupal 9, I think.
Speaker:And, uh, and most of it was pretty routine, but they also had.
Speaker:One page, which looked like it was a views listing of some person
Speaker:content type and each person had, uh, several publications and they
Speaker:had a picture and so on and so forth.
Speaker:Um, but in fact, it, it wasn't from structured data.
Speaker:It was one Drupal 7 basic page.
Speaker:Um, with 10 or 20 of these, um, things that looked like, like, like nodes,
Speaker:um, just pasted into the body field.
Speaker:And, uh, we decided we were going to restructure it and make it what it
Speaker:looks like and have a person content type, but with structured data on it.
Speaker:Uh, but we had to extract it from this page since it was only 10 or 20.
Speaker:And this is the funny part.
Speaker:I said, you know, get an intern, have them copy and paste.
Speaker:You will spend as much of the intern's time as you would spend of my time.
Speaker:Um, And, and the insurance would be a lot cheaper, but they said, no, no,
Speaker:no, we want to do it automatically.
Speaker:I said, okay, this will be fun.
Speaker:And, uh, as far as the source was concerned, um, I, I just downloaded
Speaker:that page once and put it into the, uh, the directory for, for the
Speaker:custom module we had for migration.
Speaker:Um, I ran HTML Tidy on it to make sure it was well formed XHTML.
Speaker:And, uh, and then I used the URL plugin that I was talking about from
Speaker:Migrate Plus and, uh, and one of the XML data parsers from Migrate Plus.
Speaker:And, and I guess the important thing to mention is that, um, even though
Speaker:it was not technically structured data, it was just one page of HTML,
Speaker:it did have consistent structure.
Speaker:So every section of the page started off with an H3.
Speaker:Um, and directly beneath that there was, uh, an image, um, so there, there
Speaker:was enough structure there that I could reliably pick it apart and create
Speaker:fields on the, uh, the person nodes.
Speaker:That I was creating.
Speaker:That's very interesting.
Speaker:And the interesting part is that you've been able to use contrib and not
Speaker:have needs for custom code with that.
Speaker:Did you, did you use XPath, uh, to, to parse that markup or something else?
Speaker:Yeah, and anytime that you're parsing XML, and I, as I said, I created XHTML
Speaker:and so anytime you're parsing XML, you want to use XPath, which, um, I'll
Speaker:have more to say about in the episode on the transform or process plugins.
Speaker:Which, uh, which will be the next episode in this mini series.
Speaker:Um, so definitely join us again for the "T" part of ETL, which is Transform.
Speaker:Um, besides this mini series, we have some great talking coming up.
Speaker:Um, our goal is to put one episode per week over the next
Speaker:few months, um, to support the community in the migration process.
Speaker:Um, we will talk about performance because performance is something
Speaker:that we care deeply about at Tag1 and it applies to migration as well.
Speaker:Because when you are handling really large data sets, a full
Speaker:data migration can easily take like 12 hours or sometimes even days.
Speaker:Um, so we'll do a handful of talks on this topic, including on how
Speaker:to profile and tune a migration.
Speaker:Including long running migrations and, uh, we'll also talk on incremental
Speaker:migrations, which we touched on in today's episode already.
Speaker:Um, how you can include or exclude things and run a migration on a
Speaker:subset of data to make it faster.
Speaker:Uh, then, um, every project owner wants their migration to be a success
Speaker:and we will dedicate an episode to discuss the most important factors for
Speaker:a successful Drupal 7 to 10 migration in order to help you successfully
Speaker:navigate your migration project.
Speaker:And other topics that we will cover in the future include porting custom code
Speaker:from Drupal 7 to Drupal 10, the future of migrate tooling, how to port a team.
Speaker:And so much more.
Speaker:We hope that you'll tune in and enjoy our upcoming team talks.
Speaker:A huge thank you to our Tag1 team, Benji Fisher and Mike Ryan.
Speaker:Thank you for joining me.
Speaker:Make sure you check out the other segments in this series.
Speaker:Uh, there will be links to them in the show notes along with all the
Speaker:other links that we mentioned today.
Speaker:If you like this talk, please remember to upvote, subscribe, and share it.
Speaker:Um, you can check our past talks at tag1.
Speaker:com slash TTT.
Speaker:That's three T's for Tag1 Team Talks.
Speaker:Um, as always, we'd love to hear your feedback and any topic suggestions.
Speaker:You can write us at ttt@tag1.com.
Speaker:Again, that's three T's for Tag1 TeamTalks.
Speaker:A big thank you to both our guests and to everyone who tuned in.
Speaker:Thank you for joining us.