WWDC2000 Session 146
Transcript
Kind: captions Language: en good morning everyone please welcome John Glenn Z user experience technology manager sorry well good morning it's it's a great day and I certainly realized that I haven't had nearly enough sleep this week and that's probably true for many of you but this is session 146 and its high-level toolbox data browser you know it's part of our renewed interest in user experience at apple with aqua and mac OS 10 we've been sort of stressing this message that if you want to have great user experience and you want to deliver the aqua look and feel you need to adopt system control that sort of has come through this year and it's come through in past years and it's particularly true with 10 and data browser is one of those things coming out of Apple that's that's sort of a hybrid high level powerful new type of control and we're going to talk about that this morning but data browser is going to allow you to deliver exactly the user experience that we are delivering in lists in finder and in other components of the OS and it's going to do the right thing on nine under platinum it's going to do the right thing on 10 under aqua so even though it's early in the morning you need to be taking paying close attention to what's going on here because data browser i think is going to allow you to deliver a really awesome and very consistent user experience within your application so to get you the info on this stuff i'd like to welcome Jim Rawdon who's the tech lead for the list manager replacement called data browser good morning want to make sure you're all awake and in the right room I want to ask you a couple questions before I get started now stand up instead of shows hands how many of you have ever used the list manager before now stand up once this audience participation okay now how many of you don't use it anymore okay that's fair number all right now I'm sure the reason for that is pretty consistent it's kind of doesn't present a really sophisticated interface and it's not very robust and it has some serious limitations I'm sure you're using other solutions like power plants table views and things like that data browser is going to take care of all of that stuff for you and present a new user interface well an interface it's been around for a while that hasn't been accessible to developers so with that here's what I'm going to cover today basically what is the data browser thing okay go over briefly the programming model that uses and how you can incorporate that into your code and how it'll help you factor your code then some simple usage examples get into the coding okay what is this data browser thing it's a control I am so I want to emphasize that because it's actually pretty fundamental it acts just like a push button control or pop-up menu control or any other control that's been around for a long time you can send it to size control messages move control messages etc completely self-contained presentation of discrete element so anytime you're presenting say a set of file system objects or database objects but whatever your application does you should seriously consider later browser as a solution for presenting and information it does not list manager list manager is effectively obsolete now it's still in carbon it's not going away because it's too important for backward compatibility the data browsers are simply much much much better it does what everyone wishes the list manager had done all along it does it much in a much better way it takes a totally new programming model it does not store your data as one of the series of limitations of the list enter because it tried to make assumptions about your data and how it should be stored and invariably those assumptions were wrong in many cases data browser only stores references to your data so you can cash your data you can store your data out on network or file maps or whatever is appropriate for your application the data browser only asks for the information that it needs to present those elements they're currently on screen and its standard equipment it is a very fundamental part of tenn the finder uses it the finder lists you is a data browser and it's also in carbon lib on nine so you can rely on it to present the standard list style interface to users you don't have to reinvent this wheel anymore and because it's part of the finder and Sherlock keychain access and many other system components you can rely on the fact that is very robust very fast and very high performance and now with that Jonathan is going to give you a quick demo of exactly what does so you have a visual image fix Jim so here we have a sample application with data browser the data browser control is actually everything in this window that you say that is not the window frame itself you'll notice it looks exactly like the finder no big it's not a uncommon view and we have some sample data showing it so data browser does everything that the finder does you can do have disclosure triangles so you can show more data hierarchical data you can do column resizing you can do column reordering you can also data browser also supports contextual menus and it supports drag-and-drop all internally data order data browser also supports several native data types checkboxes icon in text text only it also supports icon only but we don't have any here it sports date and time supports relevance ranking and it's for pop-up menus one of the nice things since data browser has native data types is that when you do things like resize date and time the date and time format can grow to match the sizes columns they'd rather not only does list views but it also does column view and in this case it's something new to mac OS 9 but it's not new to mac OS 10 so this presents a comb view that is standard in mac OS 10 you can see that it is good for displaying hierarchical data you get automatics traversal of aliases and also when you click on an end node you get a custom preview pane the content of this custom preview pane is entirely up the drawing of it is entirely up to you however you do receive events so you can have something like a push button and even though the control is taking up the entirety of this window you do have certain control over the elements of data browser so if you wanted to say have a placard in the bottom area of the scrollbar much like codewarrior or bbedit have you can also change the size of the score bar so you can have some cut some content showing there and with that Jim will show you how you can incorporate data browser into your code thank you I get the slides back thanks all right Thank You Jonathan one thing I like to point out that the code specific to the data browser in that sample app is very small on the order of 50 lines to get the bare minimum now that demonstration there's quite a bit more it actually puts information in the drag-and-drop and handle some of the contextual menu stuff so it's a little bit bigger than a simple app it's maybe 100 or so lines but very little a lot more lot less than it would take to do the same thing with list manager or any power plant type table view or any of the other solutions out there and it insulates you from the details of the presentation so just to recap there's a fairly exhaustive list of the features yet mostly for free I mean you have to do a little bit where some of them you have to turn on some bit flags set some accessors or and provide some routines of your own to for instance like contextual menu you have to provide the menu to be displayed you have to handle the response to it but that's pretty straightforward stuff some key points it's designed to hold a lot of items to 232 use 32-bit references because the finder used it the Finder has to display the contents of networks and file systems tens of thousands of items that's what this is designed for so no more 32k data limit or anything like that and it again it does a lot of work for you it has several natives display types the idea is you provide the data the raw text the raw icon data browser takes care of the formatting and that list of that list there is not complete for the native type but it's extensible if there's a type of display type that you want that you think it should support let us know and we'll see about adding it also supports custom content so if the view cells there are not sufficient for you you can add your own content have more complex information in the cells and it will store off the user state so as user resizes columns and reorders columns for instance you don't have to record that all yourself you there's a call to ask the data browser what is that stay they'll flatten it out you can throw it off in a press file and load it back in next time your application is run in detail and it's not just for finder anymore this is a screenshot from the 10 finder that is a data browser some additional features that it supports that are not necessarily used by the finder our variable height rose so you can have individual items have their own unique row height and it tracks with the item it is not table index based so as Yuri sort or you add items that item stays that height that you set it to it'll take care of right-to-left support for you so for instance it doesn't at the moment but at some point the future we may want to automatically invert the column ordering on right-to-left systems you don't have to worry about that it'll happen for free and it because everyone is using it it'll happen across the system power coupling this is completely optional if you want to present a flat file or flat list you can you just don't turn on for just a hierarchical miss and you can have it in whatever column you want there's two different highlight styles there's the traditional finder style where it just highlights the bare minimum around the text or you can have the band selection like saying the chooser and you can use whatever whatever is appropriate for your interface under platinum it supports different theme backgrounds so the default is the finder style with the light gray background if it's darker gray for the short column but it also supports the white style background might find into the chooser and you can mix and match that with the highlight style so you can customize the look a little bit under aqua it really only has one team background style white so it doesn't really apply there but the API works just the same so you can call the api to turn off the gray background and doesn't make any difference on aqua just a lot basically and one thing that is coming from aqua back to platinum is the per column short ordering this is something that a lot of the third parties implementations of the style of interface have done where instead of having one sort or during ascending descending that applies regardless of what column is the sort column it's track for a comp so you can have the first column ascending second column defending and as you switch back and forth it remembers his sort orderings there's an example to list see under platinum with the compy excusing convey you support some additional features the most prominent one being alias traversal because the convey is designed for navigating through a hierarchy particularly filesystem hierarchy and file systems has aliases to other containers and it doesn't work to be navigating burrowing down into it and also get blocks because you hit an alias it supports traversing down those and it's smart about it doesn't ask for more data it just it's already has that information or if it already has that container opened it just replicates it it supports custom preview so for instance in the finder how it is the QuickTime preview or the picture preview in the last column that's supported of course you have to provide the code that actually renders in there and do the tracking in there what's completely that's screen space is up to you again you can have variable height the two highlights valve works there as well this defaults to advance selections that you can turn that off and have the minimal highlight style and again you can have custom content in your container in your items I don't want to have too much detail on the performance but I know some of you are concerned about that just again remember the finder uses it and that services use it so it has to be very high performance throw up some numbers here to give you an example it's very lightweight very scalable memory usage it only uses as much memory based on how many items you've added to to be displayed and as containers are opened of course those take a little bit more memory but we've kept it to a minimum and over the next few months I'll be working on performance and may get that down even more excuse me how many of you remember your algorithms class again you don't need to worry about details just remember it's fast basic idea here is its does binary searches internally now this is really just when your clothes is calling in to get information about items for instance is this item selected is this container opened as your code querying the data browser state internally data browser is optimized so you basically order one so interactions with the user and rendering is as fast as it possibly can be so this is all you're really need to remember it's fast and it's optimized for bulk operations so if you want to do say threading retrieval of your items whether they be filesystem items are from database you can spawn that off in a thread and whenever you get a large enough chunk insert it in one step into the data browser and that will give you the best performance so now I want to talk about the programming model a little bit and how you can help use it to help factor your code excusing this is a new paradigm it's not unique to the data browser it's very common in various frameworks power plants Mac App think class library for those that remember that and cocoa frameworks are all oriented around model-view-controller paradigm basic idea is the controller code is your framework code it's your initialization so we throw up your windows you create your menus and it's your event dispatching where you take the raw events this is a mouse click and you figure out which sub Buick belongs to and you got it into that data browser takes on the role of view it's in charge of presenting your information to the user putting things on screen and it takes those raw events of mouse collect for instance and turns into a semantic event a double click or a drag on a particular item and it talks to your application data which is the really value out of your application what makes your application unique and it stores the items they want to present to the user again this is you're in charge of the data storage and the management caching and whatever you need take care of their now how do you get those items into the data browser so they're displayed as a routine called add items where you add the references unique item ids into the data browser such as there's a one-to-one mapping between those item ids and the data they represent the browser uses callbacks to query information about those items as it needs it so if an item isn't on screen it's not going to ask for it text string because it doesn't need it so you can take advantage of that in your caching scheme so once again to summarize controller code passes of creates the windows creates the data browser passes events into the various views including the data browser the browser queries your application data as it needs it and your application data sends messages back to the data browser for adding items or changing the state now Dave browser needs to assume certain things about your data model and how the items relate to each other very minimal set of assumptions but it's basically defines the structure of the data most important of those is that each item have some set of properties these are defined again by unique IDs there are some that are predefined in the header such as is this item access can this item be selected is this item a container canvas container be open so that gives you control over some of the behaviors and it lets the data browser communicating in a known language you can define additional properties for instance the list view is very freeform and you know data browser doesn't know what kind of columns you want to present that's up to you so each time you create a column in the list view your defining a new property so there's a one-to-one mapping between column and properties and those are properties you defines and that you are telling the data browser gives it some in some additional information that I have on this item that I want you to know about and here's how to query detailed on it but these are all optional if you don't respond to the property request data browser assumes default values no you really should respond to the properties that you define or else nothing's going to put on screen now one of those important predefined properties is an item in container this is how you get the nested look and the hierarchical miss and you use the container of a given item when you're adding it so when you add items to the data browser you say put it put these items inside this parent container and that's how it creates the internal tree just to summarize data browser source references not data very fundamental design decision and it queries information about the items as it needs it based on the unique item ids and the property ideas and everything is optional if you don't install a call back you don't respond to a property data browser will assume and perform for you a default behavior and moving on to the API that's a big number 112 API calls but don't let that intimidate you because I did break down here most of those calls are just get set accessors and if you're not interested in some of those you can ignore them you just allow you to customize the behavior and appearance so it's a very flexible very rich API now a trend in control manager in general since this is a control is to move away from type unsafe structures that you turn into a void star pointer and passion via send control message or set get control data so these are really just wrappers literally are rappers in the implementation around get set data calls but they're typesafe which makes your code more cleaner more maintainable less error-prone and the same for on our side this is over and above the standard control manager calls for instance size control move control set control visibility those work just the same because it is a control but when you get right down to it only six calls are really really need to do a bare-bones implementation to get just throw some information on screen so most of those calls you don't need some of for instance the configuration manipulation calls some apply to all view styles with Alyssa you or column view for instance turn on the scrollbar turn off the scroll bar and some RV South Pacific for instance the ListView has a notion of a disclosure column so you can specify the disclosure com or that doesn't mean anything to the column view conversely the column view has a notion of a pack the police tree does not plus there are two sets of callbacks are broken into two pieces there's the high level one to deal with the standard behaviors and the low level ones that apply to the custom content I'll go into those in a moment plus your standard control manager callbacks key filter validate input validation product does work as well now the standard callbacks the high level callbacks these are what you're mostly interested for the standard native type display types most important of these is to get set item data this is how the data browser queries your application for text strings icons date values to present on screen again you just provide raw data data browser take care of the formatting and it's called get set because this is also how the data browser tell you is if the user has completed and edit operation for instance users click the check box or click the pop-up menu menu ordena text edit this is how they bowed to provide that information back to you so you can store it off in your data is item comparison for sorting you're in charge of the sorts of operations it just gives you two item ids and asks for their relative ordering so if you want to do secondary tertiary sort orderings that's up to you if you want to have case sensitive or case insensitive sorting that's up to you if you don't install a comparison call back it provides a present information in insertion order so if you're providing a list of stack elements and you get that for free you don't even need to install a comparison routine data browser will notify you of semantic events on items for instance double-click container opens things like items selected and does that via notification routine there's some drag and drop handlers for adding i adding data into a drag again the data browser sets up the drag but you to provide meaningful information into it the drug flavors it you are in charge of specifying whether a given item is interested in a drag data brought if you respond yes you are interested data browser will take care of highlighting that it item appropriately to give the user feedback and when the dragon is dropped again it's your call to handle that because data browser doesn't know what the data is just know something was dropped on something else and there's a cleanup operator also help tags is the follow-on replacements to balloon help when help is going away their carbon help tags gives a tool tips kind of apparent and interaction and data browser supports that natively then you need to provide the content but the data browser will take care of putting it up on screen and and determining which item it goes with so you can give help tags on an item by item basis and salmon through is contextual menus need to provide the menu you need to handle the user's response with just a couple of routine very good Louisville callbacks are for custom content if you don't have custom content you don't need to worry about these callbacks if you have custom content you are telling the data browser I want to be in charge of all rendering and tracking and hit testing for this item wherever it may be on screen when it's on screen data browser will give you the balance at any given moment when you need to draw or hit test and a custom content is used for the preview column that is a custom content space so if you don't want to preview calm and don't install custom content just get blank column if you do want to present preview information in the preview column you need to install custom callbacks and handle them now it's a code demonstration of getting a bare-bones implementation up and running Johnson's yeah sure that okay so here we have an application that's basically basically the minimalist data browser it's a single column with seven elements you can select them and click on the column and reorder them as Jim said we have no sorts routine in here so they're in insertion order so this is your most basic application let's see what code is needed to create it actually very little code was need to create it if you look at it it's in total about 220 line without half of those are actually needed for the data browser itself and so we're just going to go quickly touch on what is actually needed for the data browser this is a carbon event application so we actually it is a lot smaller because we don't have to do a lot of the event handling ourselves it's between care of automatically so the first thing we do is we create a window to put the date browser in we then create the data browser to fill the entirety of that window will then configure the data browser install the callbacks that are needed by did browser to communicate with our application and will populate the data browser with our item references or item ids which will be given to the callback to request the information to be displayed the rest of the application is basically just showing the window and run and running it so the first thing to do is to configure data browser since data browser is taking up the entirety of the window we don't want to have a focus frame data browser will manage the focus ring for you if you want one if you have say to data browsers in a window and you want to change the focus between them so in our since we have a single window and it's taking up the entire contents we turn it off the second way that we configure it is data browser installs columns by filling out a parameter block Jim will be going into detail about this parameter block but it's not very hard to fill out doesn't take very much once you fill out some parameter blocks with the details about your column you then add that column to the data browser and here we're setting the sort property to be the first column if you have multiple columns you can specify which of those columns you want to be the sort column initially if you don't set it if nothing will be highlighted at the very beginning but as soon as you click on a header button it will highlight once you've installed the column into the data browser he then into need to install your callback callbacks are also filled out or installed via parameter block it's very simple we only have one call back in this application which is to actually get the data from our our data model and return them to the data browser so we fill out the parameter block and install it into the data browser now that that's done we need to populate the data browser with our item ids item ids are entered into data browser by using an array so here we have a simple array of seven elements these are actually indices into a simple string array they can be anything you want to just you know numbers or IDs that are one-to-one mapping to your data model so we create the array with a seven element and we store them into data browser and that's basically all you need to actually configure data browser itself we do of course have a one callback which is for requesting the information from our data model in this case when data browser needs to displays information it will request via callback from our from our application or our data model using the item ids passing in an item ID into our callback this case like i said we have an array of strings with seven element so each time the callback is called it gives an item ID we return a string and data browser displays it that's basically it for the application there's not much to adding data browser to your application we do have a bit more code here one of the interesting things is you can resize data browser by a simple size control call basically our as our window resizes we just resize the control to follow the balance of the window and that's it very easy to add you get a lot of features with very little code anyway here's Jim to the screen describe the api's and the callbacks more Thank You Johnson all right here's the sequence that Jonathan just demonstrates you to contribute in display I data browser pretty straightforward you create it one call you can figure it there's a couple of steps there you set up the format in case the ListView you need to add your column you saw your call backs and you populate with your initial set of items and the last step is just handling the runtime handling the callbacks as they're the data browser dispatches them and routing the raw event into the data browser I'll walk you do that here's how you create a container browser now you notice it's not using new control control manager is moving away from that model because again it's too tight not type safe and it's based on the notion of code resources which are not supported in 10 so instead we're moving towards unique type safe routines for everything you want to do so it means we have more api's but it's no different than all the different structures that were introduced with the appearance manager so arguments for this hour window ref the bounds that you want the initial view style created a list view or column view here we're creating a list view and you get out a control rep pretty straightforward so there we've done step step 2 is formatting it now if the ListView it's a little bit involved but the basic idea is you create a parameters of the pram block and you add your column so the details are really in that paren block first step is to create a property you're defining a new property telling the data browser here's a new property I know about and I want you to know about to that involves defining a property ID it's a unique identifier is how the data browser communicates and queries information about that property you say what visual information you want displayed for that property this is where the native types come in in this case we're displaying icon and text there's other constants for a check box pop-up menu etc need to find some property some behaviors for the property in this case we want this column to reflect the selection state so if you don't if you want certain columns not to be highlighted when a given item is highlighted you don't set this flag for those columns you do if you want all columns to for say you want a band selection to go all the way across you need to set this bit flag for each column and here we're using the default column flags they break down into other constants they control is this called sortable so you don't want sort properties just presenting a list and you don't want the user to be able to change the sort order and sort is meaningless so you're presenting a stack of information and so sort doesn't have any meaning there so it wouldn't set that flag but that's included in the default constant here also controls whether columnist is movable so if you want a column to be glued always to the left and since the finder always has the first name column glued to the left you can't move it over to the right they don't have that flag set next step is to define some behaviors and appearances of the ListView header first part is the sort order again short order is on per column basis you need to provide an initial short order provide the minimum maximum width this is for column resizing if you don't want to convey resize to set these two values to be the same and then the alignment these are the standard te / default te center left align right align and this also affects the appearance of the contents of that column so the column content and the header text are aligned next we put these all together into a column descriptor the end of steps are column is a property contains some header information some formatting information and a CF string ref that is the text to put in the in the header button now CF string refs are the way to communicate textual information with the control manager now giving away with pascal strings because been difficult to localize your script dependent CF string rough it's basically a Unicode string so did browsers unicode capable off the block and you need to go to some of the core foundation sessions for learning more details about how to use CF strings and then you create the column the last argument here is the ordinal position within so you can as you're adding columns you can specify what position you want to be in in this case we set a very large value if you choose a value that's more than the number of columns currently in there it just tax it on the end so we've set up the format and we're going to install the callbacks again another parameter now the k data browser latest callbacks constant may seem a little odd but that's a versioning scheme we came up with so that we can provide backward compatibility in the future as we need to if we need to add to the structure change its formatting maybe change the callback themselves add new callbacks replace callbacks change argument signatures we don't want to break your apps that you work on now as we need to make these changes in the future using this burgeoning scheme will allow us so the version number maps directly to the structure of this parameters paren Block in the future we'll increment that constant value and next time you recompile with the new headers that have that new structure you'll get the new constant and you may need to do a little bit of work to adjust to the new callbacks new layout if you don't want to you can just revert to the previous constant value and you'll maintain binary compatibility we initialize the structure for now this just sets all the values to null the UPP s just sets in the null but at some point we may want to provide some default callbacks for you this is how you can get them basically initialize it to a safe default value then you set each element within the structure to your upp that you create and you install them okay we're done with step 2 but there is a step 3 we populate the create an array of references now again the references or whatever is meaningful to your application they can be raw object pointers C++ object pointers they can be indices into an array that you maintain it can be some hash table value whatever is appropriate the only thing is they need to always map one-to-one consistently to the same piece of data the arguments for the routine here the data browser reference to the control ref the parent item as I mentioned this is how you get the hierarch's goodness if you want it in the root level of the list or you have to displaying a flat list you just say there is no parents the root item you say how many items are in the array and the array itself last argument is a performance opportunity suppose you create your array in some sort of order that maps to one of your sort orderings you can tell the data browser and if the current sort property happens to match data browser can save on some sort operations so they'll make it add a little bit faster okay we're almost done excuse me all right yeah all right I'm only to go over one of the callbacks the most fundamental one to get set data as I said this is used both for retrieving data from your data model and passing it to at the completion of an edit that's what the last argument is for most of the time it'll be set to false that just means the data browser says what's the texturing you want me to display when it sets a true it's saying here's the text during the user just entered or the new checkbox' value the user just entered you need to update your data store if you don't want to accept the value that's fine you can put up a dialog to tell the user sorry that's an invalid new name or you can't check this checkbox right now and just ignore it but the main bulk of this is just a switch statement on the property that's being requested you have a case entry for each property that you are interested in if you don't want to respond to a property data browser assumes a default value you need to check on whether the data browser is giving you information or asking for information but then you just install the information into an item data reference it's a reference to the data that's going to be displayed now if you don't respond to a property it's important that you return this error code because that tells the data browser give me the default value we're almost there one last easy step this is your standard control manager called draw one control handle control click etc there's some new one but I'm not going to go into detail here if you're interested in them go to the carbon enhancement sessions go over them but basically they allow the data browser to set the cursor for instance as a user drugs over a resizable column it will change the arrow cursor into the bi-directional resize cursor some routines for doing drag and drop handling and contextual menu again go to the carbon enhancement session if you're interested in those there's an easier way these carbon events and you install their standard event handlers on your window you get all this for free that's what this the sample application Jenna Johnson showed did so that we're done pretty straightforward you create a data browser and configure it that's the most involved step but it's pretty straightforward to you pop those initial items and you handle the runtime nowaday trouser is API is quite stable it's actually been used by the finder in ten cents pr2 and there are a couple of components in Mac OS 9 to use it so we're pretty confident that it suits everyone's needs but the data browser does a lot more than those core services finder Sherlock etc need for instance the variable row height custom content and so we had to make some best guesses of what reasonable behavior is there since we don't have any clients that are really using it that's where we need your help please use them and give us feedback if something doesn't work the way you think it should let us know the goal of data browsers to do the right thing as much as possible and save you from work and do work for you so let us know if they Tobias can do something additional to make your life even easier it's available right now the macros 10 CD you got on Monday video browsers part of carbon when you use the finder Lister you're using a data browser it's in carbon live 1149 only it went through it's in the d9 release which I don't think has been posted just yet I think it was built last week going through quick looks this week so it should be posted on the web next week or maybe it might be there now I haven't looked and you get through your Apple Developer connection account the api's are defined control definition CH again it hasn't me into the universal releases universal headers releases but the headers that come with the developer previews or the carbon lid seeds it's in there here's some contact information on again bring John back up to go over the rest Pacific Hall if you're if you're working with data browser and need to get some feedback through to gym where the team probably best contact would be to go through myself with John Glenn Z the first email address there and there's also the high level toolbox feedback high level toolbox feedback email tool box at apple com and the carbon mailing list is a great place to basically live and discuss and keep conversations live with other carbon developers who are using data browser documentation address is there so some related sessions that you need to think about or consider attending and these some of them relate specifically data browser or some of the api's that have been discussed here others relate to sort of the aqua interface and doing the right thing and that's sort of where data browser fits in a little bit as well and mostly it's a pretty self-explanatory but a couple that i want to call out is just the carbon event model sessions which happened on tuesday hopefully you went to those and if not hopefully get you some information close to conference carbon hesitancy in car one and two talk what's in the API is that Jim referred to in last few slides and you can get some info there and then the feedback forms please come to the high-level toolbox feedback forms in terms of getting us feedback on how little box or the Aqua form terms of feedback on developer adoption of aqua related issues so I'd like to invite the team up on stage for a Q&A if you have any questions is a few Mike's in the aisle