 All right. Hello everyone, we'll start. Again, this slide deck is available online. If you don't decide to download it right now, you'll have the opportunity at the end as well. But I'm Doug Soltez, this is Clay Gerard, and today we are talking about building applications with OpenStack Swift. And so to start your journey, we're going to give you a list of things that you will need to accomplish. And so the first step is figuring out why you're going to use OpenStack Swift in the first place. So I would argue that the best two things about OpenStack Swift is number one, it's API. It's API is different than a file system or a block system. And the reason why is that you can access it from anywhere. You don't need a VPN tunnel. We're not using SIFs or NFS. It's its own protocol. It uses the REST API. And it's going to give developers more control. And so what do I mean by that? Well, some of that Clay's going to talk about in just a couple of minutes, but you have advanced commands like server side copy, versioning, object exploration, things that no file system can normally do. And it puts it in the hands of the developers. In fact, the developers are able to choose something like a storage policy. A storage policy says, well, where will my data reside? Is it going to be just in this data center? Is it going to be in multiple data centers? Is my data going to be in a certain tier of storage? And these are not things that you can normally do when we're talking about a block or file system. Now, why choose OpenStack Swift as the underlying storage in addition to the Swift API? Because there are definitely a lot of systems out there today that have slapped the Swift API on top of a strongly consistent system. And it's because OpenStack Swift was designed from the ground up to actually be a system that can scale to terabytes, petabytes, exabytes. It's eventually consistent. It's able to handle massive failures. So you can lose a data center, a rack, multiple nodes, multiple data centers. The replication is simple. You put the data in and it automatically replicates. Some people are afraid of eventual consistency. You shouldn't be. That protects you in case the system becomes split brain. What it says is when I put an object in, it may not be in all my data centers. But if you want to access it, you better believe that the proxies know how to statelessly find that data and access it. So you're in good hands on this quest. There are a lot of other super users in the OpenStack space that have used object storage and have built a great ecosystem on not just OpenStack and its projects, but specifically OpenStack Swift. As well as a large number of commercial products that have adopted the OpenStack Swift API in their product to allow their users to have increased functionality. So now let me give you a quest. And this is one that I personally worked on. So you're a moving and storage company. You decide that you're gonna roll out tablets. You think all of your truck drivers should have tablets because it's gonna make you more efficient. The paperwork won't get lost. You won't spill coffee on it. In fact, you'll be able to do new things you never did before, like take pictures of chairs and tables if they're already broken or scratched. The condition of the house when you get there so that they can't claim that you broke that door or that hinge or that window was not right before or after the movers came. But that's a lot of data. On each move, you're gonna generate up to a gigabyte of data. And you know what? Roaming charges in the US for 4G data can be kind of expensive, may not roaming, but transmitting all that data. The only data you actually care about in immediate fashion is the actual form data so that you can start billing that move immediately. All those videos and files, you want them to stay on the tablet until the tablet actually makes it back to one of your service centers. And each of these service centers is gonna be running OpenStack Swift. And so what's gonna happen? The driver's gonna walk in the door, it's going to pick up the Wi-Fi network, and it's immediately gonna transmit all of those photos to the object storage onsite. Why? Because all of the object storage has the same global namespace. It's nice and simple from an operator point of view. Now you don't need the same amount of data in each of those data centers. You're gonna have a lot of data in your New Jersey, your California, your primary and your DR site. And so when you walk in the door, we're gonna use what we call write affinity and you're gonna write all the data to the data center right there in, say, Chicago. And then over time, it's going to trickle out to those other data centers. It's gonna be protected and highly available when it's actually needed and it's gonna save you a whole ton of money. Now maybe you're not a moving company. Maybe you have video cameras. In fact, a lot of universities, municipalities, police forces are now installing more and more video cameras. And these generate a ton of data and you wanna store it very economically. In fact, one HD camera generates 86 gigabytes of data a day. So you can imagine if you have 12 cameras, that's a petabyte a day. And a lot of people have more than 12 cameras and they wanna keep it for 90 days. So again, assuming that you want to build a system on commodity hardware that's extremely economical and is resilient to failure so that you can have it in multiple data centers, the cameras can write to any of those data centers. And yet if one data center goes down, all the camera footage is still being captured, whether that's Las Vegas or your small office, then you're covered with OpenStack Swift. So in order to do these questions, you're gonna have to first pick a language. And so you're lucky, this community has been around for several years and there's several SDKs. So if you like Go or Python, we know that Python is the normal language for OpenStack, but if you're a Java developer, then guess what? You've got tools at your disposal today, libraries that you can import and start consuming easily OpenStack Swift and writing it into your program. But if your language isn't up on screen or you like different Java libraries, you're okay too. Because all the modern languages today will have a curl library or something like a request library that you can use standard HTML commands and you'll be able to pass headers, do gets, puts, all the normal RESTful commands. And so with that, I'm actually going to accelerate this talk. I'm assuming that everybody in the room is already familiar with object storages. In fact, I see a bunch of core developers for Swift anyway. And so we're gonna pass the crud and we're gonna jump straight to clay. If you do need more information though, we have a book come by the OpenStack or the Swiss Stack booth and we're glad to give it out. And meanwhile, the talks from Tokyo and Vancouver have been recorded for Swift 101. Hi guys, my name is Clay, I work on Swift. And I'm gonna talk to you guys about a few, I'm just gonna, I'm like randomly picked a couple of API topics. One of the things that we found doing these summits for a while is we'll go through basic Swift architecture, how to use the API and get some puts. And there's really not a lot to talk about that. We can cover it in a single session. But now we're starting to build up a collection of series that we've done and on this one we're picking up a few new API topics where between maybe three or four of our sessions you can sort of really get into that Swift 201, the next level of API topics. And what we're gonna get into to start off with is static large objects. Which is one of the methods that Swift has for supporting, uploading a large object. So you have a single object that exceeds five gigs or maybe it's not huge but you wanna break it up into delineated parts, you just sort of segment it up. It's up to the application how it wants to chunk those up. And it can break all of them up using its local storage and upload all of the pieces concurrently into the object storage. And then you give Swift some additional information, a manifest file that explains how it's stored. So you'll just present a single big file EXE but it's broken out into all these little chunks. So, slows are great. The static large objects, we abbreviate them slows. And they have all of the characteristics that you would get out of the API of a normal object. But it allows you some benefits. One of the first ones that you're gonna see is that you can break it up into smaller pieces, upload them all concurrently. This is gonna improve your throughput. If you have huge data sets, multiple terapite data images, genomics data is one of the use cases that we have here. You can chop that up into 100 megabyte chunks and just upload thousands and thousands of those little pieces. And then in a single put at the end, you can assemble them all back together with this JSON file. And we're gonna get into the semantics of that. And it allows you the user to just be presented with what they feel like to be a single huge object where they can use range request to pull into the middle. It's got a great API for validating your manifest. It can give you back errors that are specific which chunks, what's the problems. And stitch it all together. If you're using the Swift command line clients, which I'm sure a lot of people that have used Swift before are familiar with, then it's really simple. You just throw the dash dash use SLO flag in there when you give it a segment size and that'll allow you to up yield your object into a segment container. It handles all of that, splitting it up, doing multiple puts concurrently. And then there's also a lot of other utilities out there. Swiftly, there's another one, Swift commander. Fred Hutch is one of the IT personnel working at Fred Hutch Cancer Research Institute. So there's another one there. There's lots of them. A lot of those SDKs that Doug was alluding to also get into they have kind of built-in support for some of these things. So you can have access to these features without having to know all the nitty gritties. But you may have reasons for wanting to do it on your own and we're gonna take a look at a little bit about what makes up these segments. So here you can see a blob of JSON. If you kind of pull it apart, you can see it's just a list of JSON objects, dictionaries in Python. The three keys that are really important are the path which says what is the name of this segment? It's a name to another object in Swift. And that's the path that first segment there is gonna be the container, followed by however many different container paths that make up the full object name, the canonical name of the object. That's the first segment to list. So these are order specific. The order that they're presented in is gonna be the order that they get stitched back together. And then it also provides some metadata about that object, the size and the E tag. And that information is what allows different kinds of validation and range requests and validating of the object when it's being served out. If there's any sort of error in downloading it to the client, this can be detected. And this is a huge advantage over a previous implementation that also has some unique characteristics, dynamic large objects. So with static large objects, it's great. Now normally those fields, the E tags and the size bytes, we want the client to send that along. They should have all of that contextual information. They just uploaded the segments. They can present that to Swift and Swift can do some validation to make sure, okay, yeah, make sure I have everything. Everything's accessible. Everything checks out. I got this static large object just as you specified it. But it does add some overhead in bookkeeping to the client. And the API has recently, in a recent release of Swift, been extended and you no longer have to fill in that information. You do still need to explicitly state that you are not sending it. This is different from an error. You forgot to send these keys. But if you send in the nulls, you know, Python dictionary with nuns and then convert it to JSON. They come in as nulls. Swift will still be able to validate those objects. It'll go pull in all the segments and check everything for you and stitch it back together and say, okay, I've got it. And when it writes the manifest down, it will fill in all that information. So a client later can download that manifest and use that information to do, compare us into a local object that they have that's represented by that static large object to do if there's maybe something in the middle of it changed and you need to rewrite one of those segments and then update the manifest to note that this part in the middle has been replaced. But once you get ready to put it, it's more or less like a regular put. You just upload the JSON to Swift. You do have to include this extra bit of query string here to indicate that this is a put for a static large object manifest and it'll include some additional object metadata on there to say x static large object true. So if you're ever looking at a manifest, if you just have the headers, if you do a head on it, you can tell if it's a static large object manifest or a dynamic large object manifest by looking at those two headers. You've got the x static large object true or you have x object manifest in the case of DLOs. Now, a little note on DLOs. Would you have a question? Yeah, absolutely. So for example, the Swift command line client, that's natively how it's gonna do it. When you say use SLOs and you give it an object in a segment size and that's a gigabyte object when you say segment size is 10 mags, it will on that object open up multiple readers, seek out to all the right points and they'll concurrently default to 10 threads at a time be pushing up the segments concurrently. And a lot of the SDKs, an example, have this sort of stuff built in. In the Swift command line client, it's underlying service, the Swift services API has a way to do this sort of work programmatically where you get a context manager and you can load it up with a bunch of different types of requests and then you can stream off those responses as you consume it. So there's a lot of client support for that. Depending on your language or your project needs, maybe we can help you find something that you need. Yeah, so Fred Hutch who wrote the Swift commander, they manipulate large genomic files. They're able to take a human genome which is about 150 gigabytes and send it up and fill a 10 gig pipe with that single file. Wow, that was a pass deck. Yes, preview. And that's not something you can do with a normal filer, right? So if you have a 150 gig file and you want to copy it and you're sending over SIFs or NFS, what you need to do is send multiple of those files to try to fill a 10 gig pipe. So the ability of Swift to break something into pieces and reassemble it can give you massive gains and throughput when you're trying to do research and that really folds into Hadoop and other stories as well. Yeah. Well, as long as you have a bunch of file, blocking file IO mixed in there, the Python threads and the global interpreter will interact successfully in order to have those concurrently. Even though only one object will actually be doing network IO at the time while the other threads are doing the file IO. So maybe we talk about it more later. I mean, you're certainly right. There is some interaction there that is important, but other languages of course don't have that limitation and there's other ways that you can do things in Python as well. But I do want to say DLOs are awesome. They predate static large objects, but there was even a thread on the open stack mailing list not that long ago where someone was struggling about with some of the dynamic nature of the large object support and the original implementation doesn't lend itself well to some of the types of use cases where you need to really be able to manipulate what is this object. So just in general, just start with the static large objects if you're doing large objects and then only if that fails you for some reason if you've got one of those weird niche cases where you're doing logs and you need to continually stream up new data into the object is the only time when you really need DLOs. So start with SLOs and then only when that doesn't work for you. Doug made me write a script to convert a DLO to an SLO so just get rid of them. So that's your bonus, that's your Easter egg. Yes. Okay, next random feature. We're gonna talk about authorization. So account ACLs is a relatively new feature. I mean, it's been out in a number of releases but it doesn't have as large of adoption. There's a lot, especially at these open stack conferences people are using identity management systems that were built and designed for cloud use cases where every resource that you're defining in the cloud you wanna put some information about who can access it in the identity management system. But in the legacy and enterprise use cases there's not always, they don't have a cloud based identity management system. They have something that's defining who a person is, what teams they're a member of and their roles maybe in an LDAP system or something like that. And then they leave it up to the resources themselves to identify based off of those users and those roles who has access. Account ACLs is an extension of that idea. In Swift on the account itself you can set these users, these groups have access to it rather than having to say in the identity management system that this user has access to this Swift account. So you already have to store the resources in Swift it needs to have those accounts there for billing and everything else. Account ACLs is a way that you can store that. It has a little bit different syntax. It may not affect a lot of you guys but if you have a legacy OS system and you're encountering some of these issues where you don't really have a way to tie all of the cloud resources back to your identity management system sometimes there's a way to flip it around and let the resources themselves define which users and groups have access to them. And that's why account ACLs exist. But generally speaking working with Swift you're much more likely to encounter the container ACLs. So it's the same sort of concept within an account you have multiple containers. Each one of those containers can individually sort of define who has access to it. Containers are the natural way in Swift to group objects together. In your single account in your project in your tenant you might have a million objects 10 million objects and they're gonna be grouped more likely into separate containers each one of those containers is a group of objects and you can set behaviors of the object storage system around this group of objects by placing metadata on the container the container ACLs is an example of that. If you have a group of objects in a container and you wanna make those publicly accessible what you can use is through container ACLs you set the refer, refer spelt correctly here although in HTTP parlance it's normally missing one of those Rs has to do with who is the guy that's requesting the object. And because Swift is storage built for the web you see a lot of these HTTP-isms sort of bleeding their way into the Swift API. It takes advantage of a lot of web clients. So for example if you embed a URL you know an href anchor tag href to an image tag in one of your webpages and that points to a URL that's in Swift in a container that you've marked publicly accessible the web browser for your benefit will send along the refer what was the originating website that was making this request and Swift can use that information it's sort of opt in I mean you can get around it with curl but when the information is available you can use that in order to allow or deny that so if you know that you have this public content and you have a web application that is generating references to images that are stored in your Swift cluster you know that a well behaved client accessing that through any web browser I mean even way back into the Netscape old days like it will send those that refer header along and you can trust that to authorize that request or you can just put a splat on it which is what everybody does makes it totally accessible it's not any more or less restrictive protected than the refer thing like I said it's kind of opt in in any ways the client doesn't have to send that and when you put a splat on it anybody can get those objects you just point your web browser at your Swift cluster and you can look at those objects but just like in engine X whenever you have some content that's laying on disk and you know there's no restrictions there I mean maybe you can put basic off in front of or something but generally you have your web server and it's pointing at some data if you know go to that path you've set your web www route path to some section of the file system on disk and you go to a particular object it'll load that up but if you delete the object path and just go back to the directory that's holding all of those by default I mean unless you've enabled web mode or something like this you will not get an object you don't say you're not authorized to view this listing and that's the default operation on a container so if you're using public access you may also if you want to allow it our listing is another and here you can see the example of a container apple and it's just a CSV you can give explicit access to users or an explicit refer an explicit deny refer and then the listings tag so here's an example with curl most things that you might want to do to an HTTP API you can do with curl if you're not familiar with curl syntax it's not super intuitive but we're just sending a header for authorization and then we're setting another header which is that comma separated value list of all of the ACLs and we send that directly to the URL of the container so it's your storage URL slash your container name which you make up there's an example of allowing write access so back onto the listings and back onto large objects there's some synergy here and different components of the API dynamic large objects one of the limitations with them is that in order to generate the full object it has to be able to do a listing so if you're trying to make a dynamic large object manifest publicly accessible you can't just give that manifest and its segments the read option that's the the splat star you also have to enable the listings option on the dynamic large objects segmented container so there's another reason why with segmented objects you have some advantage because the components that make up the large object are explicitly listed there's not a container listing step you just have to be able to retrieve the object you just have to be able to retrieve the manifest so watch out but ACLs are not the only way I mean that's like a one-time thing you unlock the keys of the kingdom you can get into every object in that container which we talked about how you normally use containers to sort of group different things together but if you need more granular control like all the way down to a specific object or a specific object large object manifest you can use another tool for granting temporary access to an object so you have access to all the different kind of verbs you can do it to any URL that you any object URL that you have in the system you have some different tools in there and how it's managed again it's metadata that you set on the container on the account there's two different kinds we'll talk about both account and container temp URLs but they follow basically the same idea there's a temp URL key but also a temp URL key too so you can support rotation without worrying about expiring or invalidating a bunch of keys that you've given out in the interim while you're doing the update so you set your temp URL key then you can do another request which takes your old temp URL key and sets it to temp URL key two and then you replace it with your new temp URL key and you make that single request setting both of them so you change the you set the old the two here you be your backup key that's the one that your application may have recently given out the keys and then you set the new one and then any incoming requests that are still signed with the old key can still be validated now this is different of course if you want to immediately revoke all of those keys you could just change the temp URL key to something new and anything that had gotten previously handed out is immediately no longer valid it doesn't matter what you set the expiration time to because that needs to the key that originally signed the request needs to be able to be validated on the resource we're going to go into the syntax of how you create these HMAX to sign these keys but you also have some help again, the Swift command line client and a bunch of other tools support this stuff yes sir? Maybe not? Yeah, yeah it seems reasonable I haven't had anybody ask me for SHA-256 but SHA-256 probably thrown out too so you know yeah I think right now it would probably just be this sort of thing where you could set it whenever you sign it you'd have to add something to say which algorithm that you actually yeah maybe you extended I don't know might be something to discuss on what would be the best way to implement users to be able to select different things so but the HMAC generation looks like this generally HMAC validation looks like this you there are some required fields that you need to make an HMAC you have to get the key you have to get the body of the body that you're signing and then the algorithm like as our friend was pointing out there's multiple algorithms supported in general although Swift has simplified to SHA-1 but so that's what you need to get the key, the body and the SHA-1 now you see in the body we actually encoded a couple of pieces of information this would be an example body this is the body of the HMAC that you would actually sign with the request using the key that you set one of the two keys that you set on either your account or your container and you can do it here you can also do it on the command line OpenSSL has some built into support to do that so what you fill in your body like this the method, the full path notice it includes the version URL if there ever is a new version of Swift and a different pass have different semantic meanings it's important that we encode the full path to the request that you have authorized and then the expires time on the command line utilities I don't know if I did an example but on the command line utilities you normally set expires after you think about like I wanna make this and I wanna authorize it for three hours or something like that but the actual body of the request that needs to be assigned is the expires at you need to say when the temp URL expires that's a UNIX time stamp it's just time dot time plus however long you want it to be so that's what you fill in you sign that and then that'll be your HMAC and then the HMAC is part of the signature that you hand out to your clients so you just give them HTTP my storage server this full path with a query string including the temp URL signature and then the expire the temp URL expires is sent in the plain text this is one of the inputs to that signature so there's no communication that goes on with the storage system and some third party authorization system it has all of the information it needs embedded in this signature that you signed with your keys in order to authorize the request and you can see here we're setting the X account meta temp URL key to my secret key once that information is set on your account or on your container you can then generate temp URL signatures using this formula here to create signed requests that you can give out to customers and you can allow them to store an object into the storage system via put request or you can make a git that they can download the object or do range requests on it and yeah, so there's a read you can notice no headers, X auth, anything right you just put in the entire URL including the query string and it's able to serve that directly out of Swift Hey Clay, can I ask a question? Yes So the, and that last slide right there that actual request is going to be protected also by the HTTPS, correct? So, you know, you've signed it you've used SHA-1 to sign it and so I don't disagree that SHA-1's they're better algorithms but you're going to be protected within that with the whatever SSL keys you're using Yeah, you'd be subject to replay if anybody, you know, ever got a hold of these but you're presumably passing them out through also a secure channel HTTPS or whatever, so but you know, if you email it to somebody it does have that expires on there so it's only good for so long but yeah, they do what they do so containers, you know, we love the containers and it recently got some love in a recent release we've now expanded with a container temp URL so with container temp URLs you know, it's a lot of the same things that work with account URLs you set that X, let me see if I can do it here X container meta temp URL key or temp URL key two you can set those on your containers and it's a little bit different what do they call that, attack surface everything is limited scoped to the container you can only create temp URLs with the container temp URL key for objects that are in that container any temp URL that you create with your container temp URL key can only authorize requests that go into that container so like for example a static large object if you give someone a temp URL to that manifest some requests that go into different objects that make up that static large object will be pre-authorized by that temp URL so if you have an account level temp URL you can have a manifest sitting there and you create a temp URL for it and then you can hand that back and they can go get that whole static large object as if it was a single object everything is authorized but if you do it with a container temp URL you won't be able to authorize those sub requests so this is another gotcha if you do a container temp URL the large object must have all of its segments inside of that same container or there is no way to create a container temp URL that authorizes that static large object manifest that points to data that's in another container because container temp URLs are always scoped to only that container so if you can lay out your data and keep everything in a certain container you have this smaller surface area the smaller domain that you can control with a single set of keys All right, range reads there's another HTTP ism that's made its way into the Swift API you don't have to download the entire object you can just download a portion of the object a lot of different HTTP tools that already expect to be talking to web services already use these sorts of things one of the biggest use cases is probably HTTP pseudo streaming this is why you can upload a video into Swift and then take any HTML5 browser Chrome newer Firefox just pointed at that URL maybe presumably you made it public with either a temp URL or a public container ACLs so now you have this public video that's in your Swift cluster so you point your newer browser at that URL and you can do all of your little you know you skip into the middle of the video and start resuming playing from the middle of place and that's just the power of HTML5 the way that it does videos but it's doing it using this HTTP ism that's existed via range requests where it can seek out into the middle of a video and just start playing from there it's a byte range offset if you know some stuff about video streaming the time-based offsets were all the rage back in the day and those aren't natively supported through HTTP it requires an extension but with range reads you get a lot of players that are able to work just natively pointing right at Swift you also do multi-range all covered in RFC2616 or whatever it's been replaced by now but you can have a single request requesting multiple byte ranges like for example maybe if you have an MP3 and you wanna get the metadata for the player the name of the artist and that sort of thing that's all in the first few bytes but then you also wanna get a 30 second sample of the chorus somewhere out in the middle of the object you can do a single request get back two ranges it's all packed together in a MIME document from back in the email days, multi-part MIMES and I'll have an example of one of those it looks kinda funny but generally on a range request you would just so here we uploaded an object and you do a range request you specify just a range and the get request will come back and it just has your little bit and then here with a multi-part MIME you can see that make that same range request but you put on two ranges and the body of the request is very different it comes back, you have this terminator here that's included in the first few bytes that's also in the headers telling the client parser what to look out for and then you have these headers that describe this section of the content followed by the content another one of these delaminators some more description of the next set of content and then there's the second set of ranges and then finally that same terminating character string which has been uniquely selected and again that's in the headers but if you have a MIME parser in your library of Java Python tools that'll mostly be handled for you okay, so again new Swift feature I talked about container temp URLs was something that came out in Liberty static large objects with ranges sluranges we're so happy to have a word that rhymes with orange it was really the main impetus for writing this feature but it's kinda interesting we talked about static large objects you have these manifests that describe this other object that doesn't really exist in the storage system it's just I've made a manifest that describes how you would construct such an object should it exist and then I have all these chunks and all these pieces, a bunch of Legos so with the static large objects with ranges inserted them we've kinda added a new piece to the kit so you can construct something else in this situation you may have an object that is maybe some D-duped block data that you put together or maybe you have a single object that's again that MP3 and you wanna create a manifest that doesn't require a bunch of tricky range headers to build this sample that includes the start of the song metadata and then again that 30 second sample down in the middle with the chorus so you can create a static large object and the pieces of this object are made up of this object name and then it takes this ranges and it uses the same ranges you still will include the e-tag and the size of those ranges to describe the segment that it's actually being made of but then you add all these pieces into a manifest and you can create something new that didn't exist before so here we have an example of a manifest oh maybe we didn't fill that section in whoa I don't know if we were swapping some slides around here related to it right before I don't know if we did I'm sorry, well yes and for so at the top is a normal slow and then there's the new manifest and then the bottom combines the new nulls and bonus it's all down here this looked very familiar remember, it's exactly like the previous one and then here is combining the new null feature and the range request to create a new object oh that's a new thing that just came out in Swift just added just came out so you think of a use case for it you wanna do some de-duping blocks or something right yeah, so we're almost out of time but there's plenty more to explore with the Swift API and the commands that you can use with it in the Vancouver OpenStack Summit John Dickinson the PTL gave a great speech it's available online and he includes subjects such as listing temporary roles again form posting cores, bulk updates and large objects I also spoke at OpenStack Vancouver and I covered a lot of middleware topics including how to help check your cluster, cluster information object versioning, object exploration a whole multitude of topics so we're looking to add to that series and we're very happy that earlier today we both attended a session by Christian in the audience right now who did a great de-jango and angular talk on building web applications using OpenStack Swift he had the code up and running we don't have a web link for that but I'm sure there'll be one probably within a day or two yeah, and we might be able to update these I think we have the URL so you guys can do these we'll probably do something on our SwiftStack website there is a lot of features to the Swift API and there's really some creative ways that you can sort of combine things we bumped into a couple of cases where we're talking about how static large objects are interacting with container ACLs and sometimes there can be some tricks on how it can piece together but all of our Swift developers know a little bit about how these things sort of fit together so if you have some use cases you can hit us up say I really need the SHA-256 in my temp URLs maybe or whatever your use case is and we're happy to hear it and talk about what we can do to help make you be successful there's also partners in the industry like SwiftStack we have a lot of successful data architects that have worked with customers and how they wanna design their data architecture and how they wanna design their applications to use Swift and leverage it to the best of its ability so they don't maybe like end up using DLOs when SLOs would have been a better fit for their use case so it never hurts to have someone to you don't have to go it alone yeah, no well thank you very much for your time if you have any questions please let us know otherwise again you can download these slides I know there was a lot of technical talk inside of it so the useful available online in questions nice all right well thank you for your time today