{"thread":{"id":"21624","subject":"Preserving empty directories when doing a git-svn clone/rebase","startedAt":"2009-11-15T02:06:05Z","lastAt":"2009-11-16T03:32:16Z","messageCount":7,"participants":["Steven J. Murdoch","Todd A. Jacobs","Jacob Helwig","Daniel Barkalow","Eric Wong"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"127580","messageId":"20091115020605.GE15966@cl.cam.ac.uk","threadId":"21624","inReplyTo":null,"subject":"Preserving empty directories when doing a git-svn clone/rebase","fromName":"Steven J. Murdoch","fromEmail":"git+steven.murdoch@cl.cam.ac.uk","sentAt":"2009-11-15T02:06:05Z","receivedAt":"2009-11-15T02:06:05Z","isPatch":false,"sender":{"key":"git+steven.murdoch@cl.cam.ac.uk","avatar":null},"body":"When git-svn clones a Subversion repository, any empty directories\nappear to be silently dropped (tested using git version 1.6.5.2 on Mac\nOS X Snow Leopard). This causes problems for using git with software\nprojects which depend on Subversion's ability to track empty\ndirectories. I was recently caught out by this, and it was difficult\nto debug what had gone wrong.\n\nWould it be possible to change git-svn to handle this case? Since git\ndoesn't have the ability to track empty directories, probably the\nsimplest thing to do would be to automatically add a file (e.g.\n.gitignore) to any empty directories. In theory this could cause\nproblems, but I would think the chances of this are far lower than\nwith the current behaviour.\n\nI think this feature would help projects in which some contributors\nare transitioning to git. It would especially be useful to novice\nusers of git, who are not aware of the potential problems with having\nempty directories.\n\nI see there was a discussion in 2006:\n http://kerneltrap.org/mailarchive/git/2006/11/29/231586\n\nHowever, since then I haven't seen any updates. The rationale behind\nthe original request still seems applicable today:\n\n \"I think there are many potential git users out there who are\n currently svn users.  And git-svn is a really nice way to get started,\n but this sort of stumbling block could really turn people off.  For\n example, it made me look pretty dumb when I carelessly complained to\n my colleague about his code not working and then it turns out to be\n because my super-advanced scm tool \"messed things up\".\"\n  (git-svn and empty directories in svn (was: [PATCH 1.2/2 (fixed)]\n   git-svn: fix output reporting from the delta fetcher))\n\nThanks,\nSteven Murdoch.\n\n-- \nhttp://www.cl.cam.ac.uk/users/sjm217/\n"},{"id":"127582","messageId":"20091115050227.GD5934@penguin.codegnome.org","threadId":"21624","inReplyTo":"20091115020605.GE15966@cl.cam.ac.uk","subject":"PEBKAC or bug: unable to create path-like branch names","fromName":"Todd A. Jacobs","fromEmail":"nospam@codegnome.org","sentAt":"2009-11-15T05:02:27Z","receivedAt":"2009-11-15T05:02:27Z","isPatch":false,"sender":{"key":"nospam@codegnome.org","avatar":null},"body":"I want to create a nested feature branch, but git keeps complaining if I\nnest more than one level deep:\n\n    $ git checkout -b dev/feature/foo\n    error: unable to resolve reference refs/heads/dev/feature/foo:\n    Not a directory\n    fatal: Failed to lock ref for update: Not a directory\n\nBased on my reading of the manual pages, it seems like I should be able\nto nest branch names as long as it conforms to certain rules. I read\ngit-branch(1), which points me to git-check-ref-format(1), which seems\nto say that the rules are being followed.\n\nOn the other hand, running:\n\n    $ git check-ref-format foo; echo $?\n\nalways results in a non-zero error code, even with a literal 'foo' as a\nbranch name, so clearly it isn't saying what I think it's saying.\n*shrug*\n\nCan someone provide a little clarity here?\n\n-- \n\"Oh, look: rocks!\"\n\t-- Doctor Who, \"Destiny of the Daleks\"\n"},{"id":"127583","messageId":"8c9a060911142136s68a08892ifa27989f3a5bfdfb@mail.gmail.com","threadId":"21624","inReplyTo":"20091115050227.GD5934@penguin.codegnome.org","subject":"Re: PEBKAC or bug: unable to create path-like branch names","fromName":"Jacob Helwig","fromEmail":"jacob.helwig@gmail.com","sentAt":"2009-11-15T05:36:47Z","receivedAt":"2009-11-15T05:36:47Z","isPatch":false,"sender":{"key":"jacob.helwig@gmail.com","avatar":"https://avatars.githubusercontent.com/u/14557?v=4"},"body":"On Sat, Nov 14, 2009 at 21:02, Todd A. Jacobs <nospam@codegnome.org> wrote:\n> I want to create a nested feature branch, but git keeps complaining if I\n> nest more than one level deep:\n>\n>    $ git checkout -b dev/feature/foo\n>    error: unable to resolve reference refs/heads/dev/feature/foo:\n>    Not a directory\n>    fatal: Failed to lock ref for update: Not a directory\n>\n> Based on my reading of the manual pages, it seems like I should be able\n> to nest branch names as long as it conforms to certain rules. I read\n> git-branch(1), which points me to git-check-ref-format(1), which seems\n> to say that the rules are being followed.\n>\n> On the other hand, running:\n>\n>    $ git check-ref-format foo; echo $?\n>\n> always results in a non-zero error code, even with a literal 'foo' as a\n> branch name, so clearly it isn't saying what I think it's saying.\n> *shrug*\n>\n> Can someone provide a little clarity here?\n>\n> --\n> \"Oh, look: rocks!\"\n>        -- Doctor Who, \"Destiny of the Daleks\"\n>\n\nWhat version of git are you using?  git checkout -b foo/bar/baz works\nfor me on 1.6.5.2.  As far as git check-ref-format, it works (returns\n0) if I do 'refs/heads/foo', but returns 1 on 'foo'.  This makes\nsense, given rule 2 from the manpage: They must contain at least one\n/. This enforces the presence of a category like heads/, tags/ etc.\nbut the actual names are not restricted.\n\nHope this helps.\n\n-Jacob\n"},{"id":"127585","messageId":"alpine.LNX.2.00.0911150150160.14365@iabervon.org","threadId":"21624","inReplyTo":"20091115050227.GD5934@penguin.codegnome.org","subject":"Re: PEBKAC or bug: unable to create path-like branch names","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2009-11-15T07:16:34Z","receivedAt":"2009-11-15T07:16:34Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sat, 14 Nov 2009, Todd A. Jacobs wrote:\n\n> I want to create a nested feature branch, but git keeps complaining if I\n> nest more than one level deep:\n> \n>     $ git checkout -b dev/feature/foo\n>     error: unable to resolve reference refs/heads/dev/feature/foo:\n>     Not a directory\n>     fatal: Failed to lock ref for update: Not a directory\n> \n> Based on my reading of the manual pages, it seems like I should be able\n> to nest branch names as long as it conforms to certain rules. I read\n> git-branch(1), which points me to git-check-ref-format(1), which seems\n> to say that the rules are being followed.\n\nDo you have a branch \"dev/feature\"? Branch names are path-like in that you \ncan't have dev/feature as both a branch and a prefix for branches.\n\n> On the other hand, running:\n> \n>     $ git check-ref-format foo; echo $?\n> \n> always results in a non-zero error code, even with a literal 'foo' as a\n> branch name, so clearly it isn't saying what I think it's saying.\n> *shrug*\n\nYou want either \"git check-ref-format --branch foo\" or \"git \ncheck-ref-format refs/heads/foo\".\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"127586","messageId":"20091115073628.GE5934@penguin.codegnome.org","threadId":"21624","inReplyTo":"8c9a060911142136s68a08892ifa27989f3a5bfdfb@mail.gmail.com","subject":"Re: PEBKAC or bug: unable to create path-like branch names","fromName":"Todd A. Jacobs","fromEmail":"nospam@codegnome.org","sentAt":"2009-11-15T07:36:28Z","receivedAt":"2009-11-15T07:36:28Z","isPatch":false,"sender":{"key":"nospam@codegnome.org","avatar":null},"body":"On Sat, Nov 14, 2009 at 09:36:47PM -0800, Jacob Helwig wrote:\n\n> What version of git are you using?  git checkout -b foo/bar/baz works\n\nI'm using 1.6.5.2 as well. Okay, try this in a temp directory, and\nyou'll see what I mean:\n\n    git init\n    echo foo > foo\n    git add foo\n    git commit -m testing foo\n    git checkout -b dev\n    git checkout -b dev/feature/foobar\n\nThe first branch works fine, but after attempting the nested branch the\nmessage reappears:\n\n    error: unable to resolve reference refs/heads/dev/feature/foobar: Not a directory\n    fatal: Failed to lock ref for update: Not a directory\n\nI can recreate this behavior at any time; it isn't just a problem with\nan existing repository.\n\n-- \n\"Oh, look: rocks!\"\n\t-- Doctor Who, \"Destiny of the Daleks\"\n"},{"id":"127587","messageId":"8c9a060911142355i1e722f50uf21446524fe9cb9c@mail.gmail.com","threadId":"21624","inReplyTo":"20091115073628.GE5934@penguin.codegnome.org","subject":"Re: PEBKAC or bug: unable to create path-like branch names","fromName":"Jacob Helwig","fromEmail":"jacob.helwig@gmail.com","sentAt":"2009-11-15T07:55:11Z","receivedAt":"2009-11-15T07:55:11Z","isPatch":false,"sender":{"key":"jacob.helwig@gmail.com","avatar":"https://avatars.githubusercontent.com/u/14557?v=4"},"body":"On Sat, Nov 14, 2009 at 23:36, Todd A. Jacobs <nospam@codegnome.org> wrote:\n> On Sat, Nov 14, 2009 at 09:36:47PM -0800, Jacob Helwig wrote:\n>\n>> What version of git are you using?  git checkout -b foo/bar/baz works\n>\n> I'm using 1.6.5.2 as well. Okay, try this in a temp directory, and\n> you'll see what I mean:\n>\n>    git init\n>    echo foo > foo\n>    git add foo\n>    git commit -m testing foo\n>    git checkout -b dev\n>    git checkout -b dev/feature/foobar\n>\n> The first branch works fine, but after attempting the nested branch the\n> message reappears:\n>\n>    error: unable to resolve reference refs/heads/dev/feature/foobar: Not a directory\n>    fatal: Failed to lock ref for update: Not a directory\n>\n> I can recreate this behavior at any time; it isn't just a problem with\n> an existing repository.\n>\n> --\n> \"Oh, look: rocks!\"\n>        -- Doctor Who, \"Destiny of the Daleks\"\n>\n\nThe problem is that you have a branch dev.  You can't have both a\nfile, and a directory with the same name.\n\nYou're trying to get git to do basically this:\n\n% cd .git/refs/heads\n% ls -l\ntotal 0\n-rw-rw-r-- 1 jhe jhe 41 2009-11-14 23:51 dev\n-rw-rw-r-- 1 jhe jhe 41 2009-11-14 23:51 master\n% mkdir dev\nmkdir: cannot create directory `dev': File exists\n\nYou're getting the equivalent of the \"cannot create directory\" error.\nWhen you have a branch with slashes in it, it gets stored as a\ndirectory hierarchy under .git/refs/heads.\n\n-Jacob\n"},{"id":"127657","messageId":"20091116033216.GA16092@dcvr.yhbt.net","threadId":"21624","inReplyTo":"20091115020605.GE15966@cl.cam.ac.uk","subject":"Re: Preserving empty directories when doing a git-svn clone/rebase","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2009-11-16T03:32:16Z","receivedAt":"2009-11-16T03:32:16Z","isPatch":false,"sender":{"key":"e@80x24.org","avatar":null},"body":"\"Steven J. Murdoch\" <git+Steven.Murdoch@cl.cam.ac.uk> wrote:\n> When git-svn clones a Subversion repository, any empty directories\n> appear to be silently dropped (tested using git version 1.6.5.2 on Mac\n> OS X Snow Leopard). This causes problems for using git with software\n> projects which depend on Subversion's ability to track empty\n> directories. I was recently caught out by this, and it was difficult\n> to debug what had gone wrong.\n> \n> Would it be possible to change git-svn to handle this case? Since git\n> doesn't have the ability to track empty directories, probably the\n> simplest thing to do would be to automatically add a file (e.g.\n> .gitignore) to any empty directories. In theory this could cause\n> problems, but I would think the chances of this are far lower than\n> with the current behaviour.\n\nHi Steven,\n\nThe problem is that some git-svn using folks have started using\n.gitignore to create empty directories on their own.  Dealing with\nconflicts like this is very problematic because we have to know\nif the .gitignore file is supposed to be committed up to SVN or\nnot (it can be quite expensive to check).\n\nAttempting to deal with mismatching the information stored in the git\nindex and SVN nearly made my head explode when I tried to implement\nsvn:externals support via git submodules.  Fortunately I stopped in\ntime, but the mental scars still remain.\n\n> I think this feature would help projects in which some contributors\n> are transitioning to git. It would especially be useful to novice\n> users of git, who are not aware of the potential problems with having\n> empty directories.\n> \n> I see there was a discussion in 2006:\n>  http://kerneltrap.org/mailarchive/git/2006/11/29/231586\n> \n> However, since then I haven't seen any updates. The rationale behind\n> the original request still seems applicable today:\n> \n>  \"I think there are many potential git users out there who are\n>  currently svn users.  And git-svn is a really nice way to get started,\n>  but this sort of stumbling block could really turn people off.  For\n>  example, it made me look pretty dumb when I carelessly complained to\n>  my colleague about his code not working and then it turns out to be\n>  because my super-advanced scm tool \"messed things up\".\"\n>   (git-svn and empty directories in svn (was: [PATCH 1.2/2 (fixed)]\n>    git-svn: fix output reporting from the delta fetcher))\n\nShortly afterwards, git svn started logging unhandled information into\nunhandled.log files.  I hoped that somebody would write a parser for\nthose log files to be able to recreate useful information from them.\nSince I'm lazy, forgetful and absent-minded, I never got around to it\nuntil now.\n\nLet me know how it works and if the \"git svn mkdirs\" command name makes\nsense.  Thanks for reminding me :)\n\n>From 023675791988373beab921ad3ada115b2c224edf Mon Sep 17 00:00:00 2001\nFrom: Eric Wong <normalperson@yhbt.net>\nDate: Sun, 15 Nov 2009 18:57:16 -0800\nSubject: [PATCH] git svn: attempt to create empty dirs on clone+rebase\n\nAttempt to parse unhandled.log files for empty_dir statements\nand make a best effort attempt to recreate empty directories\non fresh clones and rebase.\n\nThis cannot affect \"normal\" git commands like \"checkout\" or\n\"reset\", so users switching between branches in a single working\ndirectory should use the new \"git svn mkdirs\" command after\nswitching branches.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n Documentation/git-svn.txt                |    7 +++\n git-svn.perl                             |   45 ++++++++++++++++\n t/t9115-git-svn-dcommit-funky-renames.sh |    4 +-\n t/t9146-git-svn-empty-dirs.sh            |   85 ++++++++++++++++++++++++++++++\n 4 files changed, 139 insertions(+), 2 deletions(-)\n create mode 100755 t/t9146-git-svn-empty-dirs.sh\n\ndiff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt\nindex 1812890..db00ed4 100644\n--- a/Documentation/git-svn.txt\n+++ b/Documentation/git-svn.txt\n@@ -320,6 +320,13 @@ Any other arguments are passed directly to 'git log'\n \tdirectories.  The output is suitable for appending to\n \tthe $GIT_DIR/info/exclude file.\n \n+'mkdirs'::\n+\tAttempts to recreate empty directories that core git cannot track\n+\tbased on information in $GIT_DIR/svn/<refname>/unhandled.log files.\n+\tEmpty directories are automatically recreated when using\n+\t\"git svn clone\" and \"git svn rebase\", so \"mkdirs\" is intended\n+\tfor use after commands like \"git checkout\" or \"git reset\".\n+\n 'commit-diff'::\n \tCommits the diff of two tree-ish arguments from the\n \tcommand-line.  This command does not rely on being inside an `git svn\ndiff --git a/git-svn.perl b/git-svn.perl\nindex ea922ac..ab0a8dd 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -168,6 +168,9 @@ my %cmd = (\n \t\t\t     'Create a .gitignore per svn:ignore',\n \t\t\t     { 'revision|r=i' => \\$_revision\n \t\t\t     } ],\n+\t'mkdirs' => [ \\&cmd_mkdirs ,\n+\t              \"recreate empty directories after a checkout\",\n+\t              { 'revision|r=i' => \\$_revision } ],\n         'propget' => [ \\&cmd_propget,\n \t\t       'Print the value of a property on a file or directory',\n \t\t       { 'revision|r=i' => \\$_revision } ],\n@@ -769,6 +772,7 @@ sub cmd_rebase {\n \t\t$_fetch_all ? $gs->fetch_all : $gs->fetch;\n \t}\n \tcommand_noisy(rebase_cmd(), $gs->refname);\n+\t$gs->mkemptydirs;\n }\n \n sub cmd_show_ignore {\n@@ -830,6 +834,12 @@ sub cmd_create_ignore {\n \t});\n }\n \n+sub cmd_mkdirs {\n+\tmy ($url, $rev, $uuid, $gs) = working_head_info('HEAD');\n+\t$gs ||= Git::SVN->new;\n+\t$gs->mkemptydirs($_revision);\n+}\n+\n sub canonicalize_path {\n \tmy ($path) = @_;\n \tmy $dot_slash_added = 0;\n@@ -1196,6 +1206,7 @@ sub post_fetch_checkout {\n \tcommand_noisy(qw/read-tree -m -u -v HEAD HEAD/);\n \tprint STDERR \"Checked out HEAD:\\n  \",\n \t             $gs->full_url, \" r\", $gs->last_rev, \"\\n\";\n+\t$gs->mkemptydirs($gs->last_rev);\n }\n \n sub complete_svn_url {\n@@ -2724,6 +2735,34 @@ sub do_fetch {\n \t$self->make_log_entry($rev, \\@parents, $ed);\n }\n \n+sub mkemptydirs {\n+\tmy ($self, $r) = @_;\n+\tmy %empty_dirs = ();\n+\n+\topen my $fh, '<', \"$self->{dir}/unhandled.log\" or return;\n+\tbinmode $fh or croak \"binmode: $!\";\n+\twhile (<$fh>) {\n+\t\tif (defined $r && /^r(\\d+)$/) {\n+\t\t\tlast if $1 > $r;\n+\t\t} elsif (/^  \\+empty_dir: (.+)$/) {\n+\t\t\t$empty_dirs{$1} = 1;\n+\t\t} elsif (/^  \\-empty_dir: (.+)$/) {\n+\t\t\tdelete $empty_dirs{$1};\n+\t\t}\n+\t}\n+\tclose $fh;\n+\tforeach my $d (sort keys %empty_dirs) {\n+\t\t$d = uri_decode($d);\n+\t\tnext if -d $d;\n+\t\tif (-e _) {\n+\t\t\twarn \"$d exists but is not a directory\\n\";\n+\t\t} else {\n+\t\t\tprint \"creating empty directory: $d\\n\";\n+\t\t\tmkpath([$d]);\n+\t\t}\n+\t}\n+}\n+\n sub get_untracked {\n \tmy ($self, $ed) = @_;\n \tmy @out;\n@@ -3556,6 +3595,12 @@ sub uri_encode {\n \t$f\n }\n \n+sub uri_decode {\n+\tmy ($f) = @_;\n+\t$f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg;\n+\t$f\n+}\n+\n sub remove_username {\n \t$_[0] =~ s{^([^:]*://)[^@]+@}{$1};\n }\ndiff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh\nindex 9be7aef..767799e 100755\n--- a/t/t9115-git-svn-dcommit-funky-renames.sh\n+++ b/t/t9115-git-svn-dcommit-funky-renames.sh\n@@ -19,7 +19,7 @@ test_expect_success 'init and fetch repository' '\n \t'\n \n test_expect_success 'create file in existing ugly and empty dir' '\n-\tmkdir \"#{bad_directory_name}\" &&\n+\tmkdir -p \"#{bad_directory_name}\" &&\n \techo hi > \"#{bad_directory_name}/ foo\" &&\n \tgit update-index --add \"#{bad_directory_name}/ foo\" &&\n \tgit commit -m \"new file in ugly parent\" &&\n@@ -37,7 +37,7 @@ test_expect_success 'rename pretty file' '\n \tgit update-index --add pretty &&\n \tgit commit -m \"pretty :x\" &&\n \tgit svn dcommit &&\n-\tmkdir regular_dir_name &&\n+\tmkdir -p regular_dir_name &&\n \tgit mv pretty regular_dir_name/pretty &&\n \tgit commit -m \"moved pretty file\" &&\n \tgit svn dcommit\ndiff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh\nnew file mode 100755\nindex 0000000..5948544\n--- /dev/null\n+++ b/t/t9146-git-svn-empty-dirs.sh\n@@ -0,0 +1,85 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2009 Eric Wong\n+\n+test_description='git svn creates empty directories'\n+. ./lib-git-svn.sh\n+\n+test_expect_success 'initialize repo' '\n+\tfor i in a b c d d/e d/e/f \"weird file name\"\n+\tdo\n+\t\tsvn_cmd mkdir -m \"mkdir $i\" \"$svnrepo\"/\"$i\"\n+\tdone\n+'\n+\n+test_expect_success 'clone' 'git svn clone \"$svnrepo\" cloned'\n+\n+test_expect_success 'empty directories exist' '\n+\t(\n+\t\tcd cloned &&\n+\t\tfor i in a b c d d/e d/e/f \"weird file name\"\n+\t\tdo\n+\t\t\tif ! test -d \"$i\"\n+\t\t\tthen\n+\t\t\t\techo >&2 \"$i does not exist\"\n+\t\t\t\texit 1\n+\t\t\tfi\n+\t\tdone\n+\t)\n+'\n+\n+test_expect_success 'more emptiness' '\n+\tsvn_cmd mkdir -m \"bang bang\"  \"$svnrepo\"/\"! !\"\n+'\n+\n+test_expect_success 'git svn rebase creates empty directory' '\n+\t( cd cloned && git svn rebase )\n+\ttest -d cloned/\"! !\"\n+'\n+\n+test_expect_success 'git svn mkdirs recreates empty directories' '\n+\t(\n+\t\tcd cloned &&\n+\t\trm -r * &&\n+\t\tgit svn mkdirs &&\n+\t\tfor i in a b c d d/e d/e/f \"weird file name\" \"! !\"\n+\t\tdo\n+\t\t\tif ! test -d \"$i\"\n+\t\t\tthen\n+\t\t\t\techo >&2 \"$i does not exist\"\n+\t\t\t\texit 1\n+\t\t\tfi\n+\t\tdone\n+\t)\n+'\n+\n+test_expect_success 'git svn mkdirs -r works' '\n+\t(\n+\t\tcd cloned &&\n+\t\trm -r * &&\n+\t\tgit svn mkdirs -r7 &&\n+\t\tfor i in a b c d d/e d/e/f \"weird file name\"\n+\t\tdo\n+\t\t\tif ! test -d \"$i\"\n+\t\t\tthen\n+\t\t\t\techo >&2 \"$i does not exist\"\n+\t\t\t\texit 1\n+\t\t\tfi\n+\t\tdone\n+\n+\t\tif test -d \"! !\"\n+\t\tthen\n+\t\t\techo >&2 \"$i should not exist\"\n+\t\t\texit 1\n+\t\tfi\n+\n+\t\tgit svn mkdirs -r8 &&\n+\t\tif ! test -d \"! !\"\n+\t\tthen\n+\t\t\techo >&2 \"$i not exist\"\n+\t\t\texit 1\n+\t\tfi\n+\t)\n+'\n+\n+test_done\n-- \nEric Wong\n"}]}