{"thread":{"id":"5547","subject":"git pull a subtree, embedded trees","startedAt":"2006-09-13T13:05:19Z","lastAt":"2006-09-18T06:47:32Z","messageCount":8,"participants":["Tim Shimmin","Jakub Narebski","Shawn Pearce","Timothy Shimmin"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"26794","messageId":"4508020F.2050604@sgi.com","threadId":"5547","inReplyTo":null,"subject":"git pull a subtree, embedded trees","fromName":"Tim Shimmin","fromEmail":"tes@sgi.com","sentAt":"2006-09-13T13:05:19Z","receivedAt":"2006-09-13T13:05:19Z","isPatch":false,"sender":{"key":"tes@sgi.com","avatar":null},"body":"Hi,\n\nI'm new to git and have a couple of novice questions.\n\n* Is it possible to only pull in a subtree from\na repository.\nMoreover, is it possible to have a subtree based on another\nrepository.\nFor example, have a topdir directory with subdirs,\ns1, s2, s3 and s4. And then have say, s2 linked to\na repository rs2 and s3 linked to rs3, so that\none can update s2 and s3 from these other repositories but\nhaving the rest of the tree linked from a main repository.\n\n* Are there any tools for dumping out the contents of the\ngit objects in the .git/objects directory.\nBy dumping out, I mean an ascii representation of the data\nfields for the commit and tree objects in particular.\nI've written a simple small program to dump out the index\nentries (cache entries).\nI just want to see what is exactly stored in the .git\nbinary files and how they change when I do various git\noperations.\n\nThanks a bunch.\n\n--Tim\n"},{"id":"26795","messageId":"ee945j$h3u$1@sea.gmane.org","threadId":"5547","inReplyTo":"4508020F.2050604@sgi.com","subject":"Re: git pull a subtree, embedded trees","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-09-13T14:21:56Z","receivedAt":"2006-09-13T14:21:56Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Tim Shimmin wrote:\n\n> I'm new to git and have a couple of novice questions.\n> \n> * Is it possible to only pull in a subtree from\n> a repository.\n\nI assume that by pull you mean checkout...\n\nI think it is possible (try git-read-tree with --prefix option, \nand select subtree by giving either it's sha1, or e.g.\nHEAD:<path> form), but not easy to do. Git revisions are \nsnapshots of the whole project (the revisions are states of\nthe whole project).\n\n> Moreover, is it possible to have a subtree based on another\n> repository.\n\nIt is possible. For example, make empty directory <subproject>\nsomewhere, add this directory, or just all the files in it\neither to .gitignore or .git/info/excludes file, then clone\nthe other project (subproject) to this place. You would have\nthe following directory structure\n\n  /\n  dir1\n  dir2\n  dir2/subdir\n  subproject\n  subproject/.git\n  subproject/subprojectsubdir\n  ...\n\n> * Are there any tools for dumping out the contents of the\n> git objects in the .git/objects directory.\n> By dumping out, I mean an ascii representation of the data\n> fields for the commit and tree objects in particular.\n> I've written a simple small program to dump out the index\n> entries (cache entries).\n\ngit-cat-file -p\n\n> I just want to see what is exactly stored in the .git\n> binary files and how they change when I do various git\n> operations.\n\nLoose object are stored type+compressed contents. But usually\neverything except latest work is in packs.\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"26796","messageId":"20060913150028.GB29608@spearce.org","threadId":"5547","inReplyTo":"4508020F.2050604@sgi.com","subject":"Re: git pull a subtree, embedded trees","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-09-13T15:00:28Z","receivedAt":"2006-09-13T15:00:28Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Tim Shimmin <tes@sgi.com> wrote:\n> I've written a simple small program to dump out the index\n> entries (cache entries).\n\n`git-ls-files --stage` also dumps a number of those details, though\nit doesn't dump every available field.\n\n> I just want to see what is exactly stored in the .git\n> binary files and how they change when I do various git\n> operations.\n\nYou may want to review some of the material in\nDocumentation/core-tutorial.txt and Documentation/technical.\nThese documents try to describe some of the formats but reviewing\nthem now it looks like there's still some additional information\nthat could be written down.\n\n-- \nShawn.\n"},{"id":"27111","messageId":"450E3399.5070601@sgi.com","threadId":"5547","inReplyTo":"ee945j$h3u$1@sea.gmane.org","subject":"Re: git pull a subtree, embedded trees","fromName":"Timothy Shimmin","fromEmail":"tes@sgi.com","sentAt":"2006-09-18T05:50:17Z","receivedAt":"2006-09-18T05:50:17Z","isPatch":false,"sender":{"key":"tes@sgi.com","avatar":null},"body":"Hi Jakub,\n\nJakub Narebski wrote:\n> Tim Shimmin wrote:\n> \n>> I'm new to git and have a couple of novice questions.\n>>\n>> * Is it possible to only pull in a subtree from\n>> a repository.\n> \n> I assume that by pull you mean checkout...\n> \n> I think it is possible (try git-read-tree with --prefix option, \n> and select subtree by giving either it's sha1, or e.g.\n> HEAD:<path> form), but not easy to do. Git revisions are \n> snapshots of the whole project (the revisions are states of\n> the whole project).\n> \nI'm not sure if that was what I was wanting.\n\nI'm just starting to understand git better (I think:).\nIt seems like it is about having object snapshots.\nWe have snapshots of files (blobs) and snapshots of a directory,\ntree objects which reference other trees and blob snapshots,\nand then we link the snapshots in time using commit objects.\nSo every time we do a \"git-update-index file\" we create a new blob\nin the object directory and every time we do a \"git-write-tree\" we\ncreate tree objects in the database (.git/object/xx/xxxx....).\nSo at these snapshot points, do we just keep adding more and more objects?\nI'm used to rcs and sccs, where we just keep diffs for file history,\nwe don't do that here do we?; we keep the whole snapshot but in compressed\nform. (And then we have a packed form too.)\n\nSo trying to understand your suggestion and the command:\nGiven a tree object in our object database, we can update our\nindex with the tree objects but they will be stored in the index\nwith entry names which have prepended to them the given \"prefix/\".\nWe can then use git-checkout-index to populate our workarea\nwith the prefix/ files and dirs.\nSo how do I get the foreign tree objects into the database;\njust copy them in?\nAnd this works with prefix/ dir not already existing in workarea.\nHmmmmm....\n\n\n>> Moreover, is it possible to have a subtree based on another\n>> repository.\n> \n> It is possible. For example, make empty directory <subproject>\n> somewhere, add this directory, or just all the files in it\n> either to .gitignore or .git/info/excludes file, then clone\n> the other project (subproject) to this place. You would have\n> the following directory structure\n> \n>   /\n>   dir1\n>   dir2\n>   dir2/subdir\n>   subproject\n>   subproject/.git\n>   subproject/subprojectsubdir\n>   ...\n> \nThis could be handy.\nLooks like by using .gitignore, I can check the file in.\n(So the ingore/excludes are used by git scripts which call\ngit-ls-files --others.)\n\n\n>> * Are there any tools for dumping out the contents of the\n>> git objects in the .git/objects directory.\n>> By dumping out, I mean an ascii representation of the data\n>> fields for the commit and tree objects in particular.\n>> I've written a simple small program to dump out the index\n>> entries (cache entries).\n> \n> git-cat-file -p\n> \nExcellent, thanks. (looks like the option is undocumented - secret option:)\nSo I added this to a script which walks over the objects directory,\nto work out what all the object ids are so I can apply git-cat-file\nto all the objects on my test directory.\nI guess this will fall down if the objects are stored in a pack :)\nI'll have to look and see how to extract all the object ids using\nsome command.\n\n\nWhat I have is an existing full tree with a subproject directory.\nAnd then I have a separate tree just for the subproject.\nThe development happens in the subproject tree.\nAt certain points we want to update the existing full tree's subproject\ndirectory with the work we have done in the subproject tree.\nAt these points I'd like to effectively copy over the new tree objects\nand blobs to the full tree, but I guess I'd need new commits\n(which are based on the new commits of the subproject tree which would\ninclude their commit messages)\nwhich refer to new higher level tree objects (which refer down\nto my subproject tree objects).\nThis presupposes that no other outside changes happened to subproject\nin the full tree - since I'm just copying over objects.\nProbably should be merging, just in case.\nDoes this sound too confusing and awkward? :)\n\n--Tim\n"},{"id":"27113","messageId":"450E3538.4010209@sgi.com","threadId":"5547","inReplyTo":"20060913150028.GB29608@spearce.org","subject":"Re: git pull a subtree, embedded trees","fromName":"Timothy Shimmin","fromEmail":"tes@sgi.com","sentAt":"2006-09-18T05:57:12Z","receivedAt":"2006-09-18T05:57:12Z","isPatch":false,"sender":{"key":"tes@sgi.com","avatar":null},"body":"Hi Shawn,\n\nShawn Pearce wrote:\n> Tim Shimmin <tes@sgi.com> wrote:\n>> I've written a simple small program to dump out the index\n>> entries (cache entries).\n> \n> `git-ls-files --stage` also dumps a number of those details, though\n> it doesn't dump every available field.\n> \nThanks, that's handy.\nHowever, when going through the core-tutorial (copying repository section)\nand populating the index from the .git objects using git-read-tree,\nit was nice to see all the stat fields using my program.\nThese fields were empty at that stage, of course, (it was nice to see it)\nuntil I had populated the workarea using git-checkout-index.\nBut generally, git-ls-files --stage would be fine.\n\n>> I just want to see what is exactly stored in the .git\n>> binary files and how they change when I do various git\n>> operations.\n> \n> You may want to review some of the material in\n> Documentation/core-tutorial.txt and Documentation/technical.\n> These documents try to describe some of the formats but reviewing\n> them now it looks like there's still some additional information\n> that could be written down.\n> \nThanks. I've been going through the core-tutorial.\nIt's great.\n\nCheers,\nTim.\n"},{"id":"27114","messageId":"eelcgd$830$1@sea.gmane.org","threadId":"5547","inReplyTo":"450E3399.5070601@sgi.com","subject":"Re: git pull a subtree, embedded trees","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2006-09-18T05:58:20Z","receivedAt":"2006-09-18T05:58:20Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Timothy Shimmin wrote:\n\n>>> * Are there any tools for dumping out the contents of the\n>>> git objects in the .git/objects directory.\n>>> By dumping out, I mean an ascii representation of the data\n>>> fields for the commit and tree objects in particular.\n>>> I've written a simple small program to dump out the index\n>>> entries (cache entries).\n>> \n>> git-cat-file -p\n>> \n> Excellent, thanks. (looks like the option is undocumented - secret option:)\n\nIt looks not:\n\nusage: git-cat-file [-t|-s|-e|-p|<type>] <sha1>\n\n       -p     Pretty-print the contents of <object> based on its type.\n\n> So I added this to a script which walks over the objects directory,\n> to work out what all the object ids are so I can apply git-cat-file\n> to all the objects on my test directory.\n> I guess this will fall down if the objects are stored in a pack :)\n> I'll have to look and see how to extract all the object ids using\n> some command.\n\ngit-rev-parse and/or git-rev-list (the latter with --objects option) is your\nfriend. And there is git-ls-tree command which list sha1 of blobs (files)\nand trees (subdirectories) for specific revision (specified tree).\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"27118","messageId":"20060918064255.GA20660@spearce.org","threadId":"5547","inReplyTo":"450E3399.5070601@sgi.com","subject":"Re: git pull a subtree, embedded trees","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-09-18T06:42:55Z","receivedAt":"2006-09-18T06:42:55Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Timothy Shimmin <tes@sgi.com> wrote:\n> Jakub Narebski wrote:\n> >Tim Shimmin wrote:\n> >\n> >>I'm new to git and have a couple of novice questions.\n> >>\n> >>* Is it possible to only pull in a subtree from\n> >>a repository.\n> >\n> >I assume that by pull you mean checkout...\n> >\n> >I think it is possible (try git-read-tree with --prefix option, \n> >and select subtree by giving either it's sha1, or e.g.\n> >HEAD:<path> form), but not easy to do. Git revisions are \n> >snapshots of the whole project (the revisions are states of\n> >the whole project).\n> >\n> I'm not sure if that was what I was wanting.\n> \n> I'm just starting to understand git better (I think:).\n> It seems like it is about having object snapshots.\n> We have snapshots of files (blobs) and snapshots of a directory,\n> tree objects which reference other trees and blob snapshots,\n> and then we link the snapshots in time using commit objects.\n> So every time we do a \"git-update-index file\" we create a new blob\n> in the object directory and every time we do a \"git-write-tree\" we\n> create tree objects in the database (.git/object/xx/xxxx....).\n\nRight, but only if the object didn't previously exist.  Git assumes\nthat the SHA1 hash of the given file content or tree content is\nunique and uses that to decide if it already has a copy of the\nobject, or needs to save a copy into .git/objects/xx/xxx...\n\n> So at these snapshot points, do we just keep adding more and\n> more objects?\n\nYes, assuming we don't have the object already.\n\n> I'm used to rcs and sccs, where we just keep diffs for file history,\n> we don't do that here do we?; we keep the whole snapshot but in compressed\n> form. (And then we have a packed form too.)\n\nGit does diffs, but they are delayed.  What happens is the\ncompressed (but complete) content is written to a loose object in\nthe .git/objects directory during git-update-index, git-write-tree\nand git-commit-tree.  Later during git-repack these loose objects\nare bundled up into a new pack file.  Within the pack file objects\ncan be deltafied against one another.  Consequently what you find\nis that revisions of the same file are \"diff'd\" against one another\nonce those objects are all combined up into the same pack.\n\nGit is very good at this compression; the Mozilla CVS repository\nwent from ~3 GiB in CVS to ~430 MiB in Git.  That's 10 years of\nhistory on 120k files.\n\n> So trying to understand your suggestion and the command:\n> Given a tree object in our object database, we can update our\n> index with the tree objects but they will be stored in the index\n> with entry names which have prepended to them the given \"prefix/\".\n\nYes.  But according to the git-read-tree documentation there must be\nno existing entries in the index under \"prefix/\".  This makes merging\nvery difficult.  And merging is a core feature of a distributed SCM.\n\n> We can then use git-checkout-index to populate our workarea\n> with the prefix/ files and dirs.\n\nWell, yes.  Assuming you were able to hammer the index into\nreflecting the structure you'd like to have your working directory\ntake on.\n\n> So how do I get the foreign tree objects into the database;\n> just copy them in?\n\nUh, yes, but don't do that.  Use `git fetch` instead to copy the\ncommit(s) in question and all tree and blob objects they reference.\nFor one thing it should be faster; for another it will correctly\nwalk into pack files and extract only the objects needed.\n\n> And this works with prefix/ dir not already existing in workarea.\n> Hmmmmm....\n\nOnly with it not existing in the working directory.  If prefix/\nalready was there you would likely encounter problems with the\ngit-checkout-index invocation complaining about those files already\nexisting and not wanting to overwrite them.  Same thing happens\nwith a merge git-read-tree invocation, which happens a lot in Git\nto update the working directory.\n\n> >>Moreover, is it possible to have a subtree based on another\n> >>repository.\n> >\n> >It is possible. For example, make empty directory <subproject>\n> >somewhere, add this directory, or just all the files in it\n> >either to .gitignore or .git/info/excludes file, then clone\n> >the other project (subproject) to this place. You would have\n> >the following directory structure\n> >\n> >  /\n> >  dir1\n> >  dir2\n> >  dir2/subdir\n> >  subproject\n> >  subproject/.git\n> >  subproject/subprojectsubdir\n> >  ...\n> >\n> This could be handy.\n> Looks like by using .gitignore, I can check the file in.\n> (So the ingore/excludes are used by git scripts which call\n> git-ls-files --others.)\n\nRight.  By convention .gitignore is read out of each directory to\nfind all ignore patterns for that directory and all subdirectories\ncontined within it.  As such you can check it into the project\nto share it across all users.\n\n> >>* Are there any tools for dumping out the contents of the\n> >>git objects in the .git/objects directory.\n> >>By dumping out, I mean an ascii representation of the data\n> >>fields for the commit and tree objects in particular.\n> >>I've written a simple small program to dump out the index\n> >>entries (cache entries).\n> >\n> >git-cat-file -p\n> >\n> Excellent, thanks. (looks like the option is undocumented - secret option:)\n\nHmm; it's documented in ed90cbf5 by Jeff King; this is 68 commits\nbefore v1.4.0 so I'd say its definately in v1.4.0 and later.\n\n> So I added this to a script which walks over the objects directory,\n> to work out what all the object ids are so I can apply git-cat-file\n> to all the objects on my test directory.\n> I guess this will fall down if the objects are stored in a pack :)\n> I'll have to look and see how to extract all the object ids using\n> some command.\n\nTry this:\n\n\tgit-rev-list --all \n\nthis will scan every ref and tag listed in .git/refs and proceed to\nprint the entire DAG they represent, including all commits, trees\nand blobs.  Git uses this internal to form the list of objects which\nshould be included into a pack file.  It will include everything\nthat is also packed.\n\nBut I'd have to say say its sort of strange to walk over every\nobject in a repository and dump it to text with git-cat-file -p.\n\n> What I have is an existing full tree with a subproject directory.\n> And then I have a separate tree just for the subproject.\n> The development happens in the subproject tree.\n> At certain points we want to update the existing full tree's subproject\n> directory with the work we have done in the subproject tree.\n> At these points I'd like to effectively copy over the new tree objects\n> and blobs to the full tree, but I guess I'd need new commits\n> (which are based on the new commits of the subproject tree which would\n> include their commit messages)\n> which refer to new higher level tree objects (which refer down\n> to my subproject tree objects).\n> This presupposes that no other outside changes happened to subproject\n> in the full tree - since I'm just copying over objects.\n> Probably should be merging, just in case.\n> Does this sound too confusing and awkward? :)\n\nYes.  :)\n\nBut this may be able to be done in a somewhat sane (or perhaps\ninsane) fashion using current tooling.  Lets say you want a\nstructure of:\n\n\tfull/\n\t\tMakefile\n\t\tsubA/\n\t\t\tMakefile\n\t\t\ta.c\n\t\tsubB/\n\t\t\tMakefile\n\t\t\tb.c\n\nwith \"full/\" being the full repository that's updated at specific\npoints to specific revisions of smaller repositories \"subA/\" and\n\"subB/\", each of which are developed on their own independently.\n\nThen make all 3 their own Git repositories.  Except in the \"subA/\"\nrepository layout your files within the \"my-subA\" repository within\na single \"subA\" top level directory:\n\n\tmy-subA/\n\t\tsubA/\n\t\t\tMakefile\n\t\t\ta.c\n\nand do the same for subB.  This will help when it comes time to\nmerge subA and subB into full.\n\nsubA and subB are completely isolated and can develop at will.\nNow to upgrade full's subA to some branch or tag X of subA we can do:\n\n\tcd full\n\tgit fetch ../path/to/my-subA X:refs/heads/tmp-subA\n\nthat just copied everything for commit X from ../path/to/my-subA\ninto full and stored it locally as branch tmp-subA but it hasn't\nmerged it yet.\n\n\tgit pull . tmp-subA\n\nwill merge the tmp-subA branch into the current branch.  Now this\nwill cause a complete merge of the \"subA/\" directory content to\noccur but it will avoid all other directories.  This happens because\nthe tmp-subA branch *ONLY* has a \"subA/\" directory and no other\ntop level files or directories, and because the current branch in\nfull also has a \"subA/\" directory which is a lot like the \"subA/\"\ndirectory in tmp-subA.  (This is why the individual subprojects\nhave only one top level directory in them and why that directory\nmatches with its name within full.)\n\nLater on to upgrade again the merge should pretty much go the\nsame way.  Except the last merge between full and subA will be\nautomatically used as the merge base, which is exactly what you want.\n\n\nThe standard merge driver (git-merge-recursive or git-merge-recur)\nwill freak out and take a *very* long time to execute the \"git pull\"\nportion of the merge process if there are a lot of files in full/\nwhich are not in subA/.  In this case you may wish to use a more\ndirect merge approach if the directory was not changed in full.\n\nSo a faster (but more complex) approach to merging in tmp-subA\nduring an update is:\n\n\tcd full\n\tgit fetch ../my-subA X:refs/heads/tmp-subA\n\tbase=$(git merge-base HEAD tmp-subA)\n\tif [  $(git rev-parse --verify $base:subA) \\\n\t    = $(git rev-parse --verify HEAD:subA)\n\tthen\n\t\tt=$(git ls-tree HEAD | ## replace ID of subA ## | git mk-tree)\n\t\tc=$(echo \"Updated subA\"|git-commit-tree $t -p HEAD -p tmp-subA)\n\t\tgit update-ref HEAD $c\n\telse\n\t\techo panic: full changed subA, full manual merge required\n\t\tgit pull . tmp-subA\n\tfi\n\nI've glossed over the '## replace ID of subA ##' part but the idea\nhere is that you can list an existing tree with ls-tree and if you\nedit the output of that and feed it back into git mk-tree you can\nproduce a different tree with whatever content you want it to have.\n\nThe general concept here is that if the subA subdirectory hasn't\nchanged IDs between the last time full and subA were merged together\nthan that means that full hasn't changed subA.  Consequently we\ncan just wholesale replace the subA directory with the new one\nwe got from subA.  We do that by editing the tree with a simple\nsearch/replace then generate a merge commit which merges the two\nbranches together.\n\nAssuming full never modifies a subrepository the mk-tree hack above\nshould be *very* fast (few milliseconds on nearly all hardware)\nno matter how many files are in full or the individual subrepository.\n\n\nEither method (`git pull` or the mk-tree hack above) will preserve\nthe full development lineage on every subdirectory within the larger\nfull repository yet allow the individual subdirectory repositories\nto be worked on in isolation.  Either method will also record as\npart of full's history who merged in the updated subrepository, when\nthey did it, and what version of the subrepository got merged in.\n\nHowever due to the \"overlay\" structure being applied here there\nis some planning involved with regards to directory naming, as\nwell as some difficulty in forming a temporary working area of just\nsubdirectory repositories that layout the same way as they would when\nmerged into a full repository.  Its also basically impossible to take\nchanges from full and move them back to the relevant subrepository\n(though git-cherry-pick may help there).\n\n\n[*1*] I totally did not expect $(git rev-parse --verify HEAD:subA) to\n      return the ID of subtree subA within branch HEAD.  Yet it does.\n      Talk about an unexpected bonus from Junio's quick cat-file\n      sha1 file path expression hack!\n\n-- \nShawn.\n"},{"id":"27119","messageId":"20060918064732.GB20660@spearce.org","threadId":"5547","inReplyTo":"20060918064255.GA20660@spearce.org","subject":"Re: git pull a subtree, embedded trees","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-09-18T06:47:32Z","receivedAt":"2006-09-18T06:47:32Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Shawn Pearce <spearce@spearce.org> wrote:\n> Timothy Shimmin <tes@sgi.com> wrote:\n> > So I added this to a script which walks over the objects directory,\n> > to work out what all the object ids are so I can apply git-cat-file\n> > to all the objects on my test directory.\n> > I guess this will fall down if the objects are stored in a pack :)\n> > I'll have to look and see how to extract all the object ids using\n> > some command.\n> \n> Try this:\n> \n> \tgit-rev-list --all \n\nSorry, that should have been:\n      \n\tgit-rev-list --objects --all\n\t      \ndamn brain.  I guess its tired and wants some sleep.  :-)\n\n-- \nShawn.\n"}]}