# HG changeset patch # User the31k # Date 2017-08-31 15:24:08 # Node ID abf91c4f960818dc06ef2e0b76ebbe54a285ce3c # Parent 7bbc4e113e5f635bc2d4f993a62e6b463bbc338d branches: correctly show inactive multiheaded branches Issue being fixed here: `hg branches` incorrectly renders inactive multiheaded branches as active if they have closed heads. Example: ``` $ hg log --template '{rev}:{node|short} "{desc}" ({branch}) [parents: {parents}]\n' 4:2e2fa7af8357 "merge" (default) [parents: 0:c94e548c8c7d 3:7be622ae5832 ] 3:7be622ae5832 "2" (somebranch) [parents: 1:81c1d9458987 ] 2:be82cf30409c "close" (somebranch) [parents: ] 1:81c1d9458987 "1" (somebranch) [parents: ] 0:c94e548c8c7d "initial" (default) [parents: ] $ hg branches default 4:2e2fa7af8357 somebranch 3:7be622ae5832 ``` Branch `somebranch` have two heads, the 1st one being closed (rev 2) and the other one being merged into default (rev 3). This branch should be shown as inactive one. This happens because we intersect branch heads with repo heads to check branch activity. In this case intersection in a set with one node (rev 2). This head is closed but the branch is marked as active nevertheless. Fix is to check branch activity by intersecting only open heads set. Fixed output: ``` $ hg branches default 4:2e2fa7af8357 somebranch 3:7be622ae5832 (inactive) ``` Relevant tests for multihead branches added to test-branches suite. Implentation note about adding `iteropen` method: At first I have tried to modify `iterbranches` is such a way that it would filter out closed heads itself. For example it could have `closed=False` parameter. But in this case we would have to filter closed tips as well. Reasoning in terms of `hg branches` we actually are not allowed to do this. Also, we need to do heads filtering only if tip is not closed itself. But if it is - we are ok to skip filtering, because branch is already known to be inactive. So we can't implement heads filtering in `iterbranches` in elegant way, because we will end up with something like `closed_heads=False` or even `closed_heads_is_tip_is_open`. Finally I decided to move this logic to the `branches` function, adding `iteropen` helper method. Differential Revision: https://phab.mercurial-scm.org/D583 diff --git a/mercurial/branchmap.py b/mercurial/branchmap.py --- a/mercurial/branchmap.py +++ b/mercurial/branchmap.py @@ -211,10 +211,13 @@ class branchcache(dict): Raise KeyError for unknown branch.''' return self._branchtip(self[branch])[0] + def iteropen(self, nodes): + return (n for n in nodes if n not in self._closednodes) + def branchheads(self, branch, closed=False): heads = self[branch] if not closed: - heads = [h for h in heads if h not in self._closednodes] + heads = list(self.iteropen(heads)) return heads def iterbranches(self): diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -1077,7 +1077,10 @@ def branches(ui, repo, active=False, clo allheads = set(repo.heads()) branches = [] for tag, heads, tip, isclosed in repo.branchmap().iterbranches(): - isactive = not isclosed and bool(set(heads) & allheads) + isactive = False + if not isclosed: + openheads = set(repo.branchmap().iteropen(heads)) + isactive = bool(openheads & allheads) branches.append((tag, repo[tip], isactive, not isclosed)) branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True) diff --git a/tests/test-branches.t b/tests/test-branches.t --- a/tests/test-branches.t +++ b/tests/test-branches.t @@ -418,6 +418,131 @@ branch b date: Thu Jan 01 00:00:09 1970 +0000 summary: prune bad branch + +reclose branch + + $ hg up -C c + 3 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ hg commit -d '9 0' --close-branch -m 'reclosing this branch' + $ hg branches + b 13:e23b5505d1ad + a branch name much longer than the default justification used by branches 7:10ff5895aa57 + a 5:d8cbc61dbaa6 (inactive) + default 0:19709c5a4e75 (inactive) + $ hg branches --closed + b 13:e23b5505d1ad + a branch name much longer than the default justification used by branches 7:10ff5895aa57 + c 14:f894c25619d3 (closed) + a 5:d8cbc61dbaa6 (inactive) + default 0:19709c5a4e75 (inactive) + +multihead branch + + $ hg up -C default + 0 files updated, 0 files merged, 3 files removed, 0 files unresolved + $ hg branch m + marked working directory as branch m + $ touch m + $ hg add m + $ hg commit -d '10 0' -m 'multihead base' + $ echo "m1" >m + $ hg commit -d '10 0' -m 'head 1' + $ hg up -C '.^' + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo "m2" >m + $ hg commit -d '10 0' -m 'head 2' + created new head + $ hg log -b m + changeset: 17:df343b0df04f + branch: m + tag: tip + parent: 15:f3447637f53e + user: test + date: Thu Jan 01 00:00:10 1970 +0000 + summary: head 2 + + changeset: 16:a58ca5d3bdf3 + branch: m + user: test + date: Thu Jan 01 00:00:10 1970 +0000 + summary: head 1 + + changeset: 15:f3447637f53e + branch: m + parent: 0:19709c5a4e75 + user: test + date: Thu Jan 01 00:00:10 1970 +0000 + summary: multihead base + + $ hg heads --topo m + changeset: 17:df343b0df04f + branch: m + tag: tip + parent: 15:f3447637f53e + user: test + date: Thu Jan 01 00:00:10 1970 +0000 + summary: head 2 + + changeset: 16:a58ca5d3bdf3 + branch: m + user: test + date: Thu Jan 01 00:00:10 1970 +0000 + summary: head 1 + + $ hg branches + m 17:df343b0df04f + b 13:e23b5505d1ad + a branch name much longer than the default justification used by branches 7:10ff5895aa57 + a 5:d8cbc61dbaa6 (inactive) + default 0:19709c5a4e75 (inactive) + +partially merge multihead branch + + $ hg up -C default + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg branch md + marked working directory as branch md + $ hg merge m + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + $ hg commit -d '11 0' -m 'merge head 2' + $ hg heads --topo m + changeset: 16:a58ca5d3bdf3 + branch: m + user: test + date: Thu Jan 01 00:00:10 1970 +0000 + summary: head 1 + + $ hg branches + md 18:c914c99f1fbb + m 17:df343b0df04f + b 13:e23b5505d1ad + a branch name much longer than the default justification used by branches 7:10ff5895aa57 + a 5:d8cbc61dbaa6 (inactive) + default 0:19709c5a4e75 (inactive) + +partially close multihead branch + + $ hg up -C a58ca5d3bdf3 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg commit -d '12 0' -m 'close head 1' --close-branch + $ hg heads --topo m + changeset: 19:cd21a80baa3d + branch: m + tag: tip + parent: 16:a58ca5d3bdf3 + user: test + date: Thu Jan 01 00:00:12 1970 +0000 + summary: close head 1 + + $ hg branches + md 18:c914c99f1fbb + b 13:e23b5505d1ad + a branch name much longer than the default justification used by branches 7:10ff5895aa57 + m 17:df343b0df04f (inactive) + a 5:d8cbc61dbaa6 (inactive) + default 0:19709c5a4e75 (inactive) + default branch colors: $ cat <> $HGRCPATH @@ -427,22 +552,23 @@ default branch colors: > mode = ansi > EOF - $ hg up -C c - 3 files updated, 0 files merged, 2 files removed, 0 files unresolved - $ hg commit -d '9 0' --close-branch -m 'reclosing this branch' $ hg up -C b - 2 files updated, 0 files merged, 3 files removed, 0 files unresolved + 2 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg branches --color=always + \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc) \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc) \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc) + \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc) \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc) \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc) default closed branch color: $ hg branches --color=always --closed + \x1b[0;0mmd\x1b[0m\x1b[0;33m 18:c914c99f1fbb\x1b[0m (esc) \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc) \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc) + \x1b[0;0mm\x1b[0m\x1b[0;33m 17:df343b0df04f\x1b[0m (inactive) (esc) \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc) \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc) \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc) @@ -461,16 +587,20 @@ default closed branch color: custom branch colors: $ hg branches --color=always + \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc) \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc) \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc) + \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc) \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc) \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc) custom closed branch color: $ hg branches --color=always --closed + \x1b[0;32mmd\x1b[0m\x1b[0;36m 18:c914c99f1fbb\x1b[0m (esc) \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc) \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc) + \x1b[0;35mm\x1b[0m\x1b[0;36m 17:df343b0df04f\x1b[0m (inactive) (esc) \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc) \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc) \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc) @@ -481,6 +611,14 @@ template output: [ { "active": true, + "branch": "md", + "closed": false, + "current": false, + "node": "c914c99f1fbb2b1d785a0a939ed3f67275df18e9", + "rev": 18 + }, + { + "active": true, "branch": "b", "closed": false, "current": true, @@ -497,6 +635,14 @@ template output: }, { "active": false, + "branch": "m", + "closed": false, + "current": false, + "node": "df343b0df04feb2a946cd4b6e9520e552fef14ee", + "rev": 17 + }, + { + "active": false, "branch": "c", "closed": true, "current": false, @@ -525,8 +671,10 @@ template output: c $ hg branches -T '{word(0, branch)}: {desc|firstline}\n' + md: merge head 2 b: reopen branch with a change a: Adding d branch + m: head 2 a: Adding b branch head 2 default: Adding root node @@ -538,8 +686,10 @@ template output: > EOF $ hg branches -T "$TESTTMP/map-myjson" { + {"branch": "md", "node": "c914c99f1fbb"}, {"branch": "b", "node": "e23b5505d1ad"}, {"branch": "a branch *", "node": "10ff5895aa57"}, (glob) + {"branch": "m", "node": "df343b0df04f"}, {"branch": "a", "node": "d8cbc61dbaa6"}, {"branch": "default", "node": "19709c5a4e75"} } @@ -553,8 +703,10 @@ template output: > EOF $ hg branches -T myjson { + {"branch": "md", "node": "c914c99f1fbb"}, {"branch": "b", "node": "e23b5505d1ad"}, {"branch": "a branch *", "node": "10ff5895aa57"}, (glob) + {"branch": "m", "node": "df343b0df04f"}, {"branch": "a", "node": "d8cbc61dbaa6"}, {"branch": "default", "node": "19709c5a4e75"} } @@ -564,8 +716,10 @@ template output: > :docheader = 'should not be selected as a docheader for literal templates\n' > EOF $ hg branches -T '{branch}\n' + md b a branch name much longer than the default justification used by branches + m a default @@ -579,14 +733,14 @@ revision branch cache is created when bu $ rm -rf .hg/cache; hg head a -T '{rev}\n' 5 $ f --hexdump --size .hg/cache/rbc-* - .hg/cache/rbc-names-v1: size=87 + .hg/cache/rbc-names-v1: size=92 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a | 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much| 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the| 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi| 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b| - 0050: 72 61 6e 63 68 65 73 |ranches| - .hg/cache/rbc-revs-v1: size=120 + 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 |ranches.m.md| + .hg/cache/rbc-revs-v1: size=160 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....| 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....| 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................| @@ -594,7 +748,9 @@ revision branch cache is created when bu 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....| 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....| 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....| - 0070: f8 94 c2 56 80 00 00 03 |...V....| + 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....| + 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....| + 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......| no errors when revbranchcache is not writable @@ -622,9 +778,9 @@ recovery from invalid cache revs file wi $ echo >> .hg/cache/rbc-revs-v1 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug 5 - truncating cache/rbc-revs-v1 to 120 + truncating cache/rbc-revs-v1 to 160 $ f --size .hg/cache/rbc-revs* - .hg/cache/rbc-revs-v1: size=120 + .hg/cache/rbc-revs-v1: size=160 recovery from invalid cache file with partial last record $ mv .hg/cache/rbc-revs-v1 . $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1 @@ -634,14 +790,14 @@ recovery from invalid cache file with pa 5 truncating cache/rbc-revs-v1 to 112 $ f --size .hg/cache/rbc-revs* - .hg/cache/rbc-revs-v1: size=120 + .hg/cache/rbc-revs-v1: size=160 recovery from invalid cache file with missing record - no truncation $ mv .hg/cache/rbc-revs-v1 . $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug 5 $ f --size .hg/cache/rbc-revs* - .hg/cache/rbc-revs-v1: size=120 + .hg/cache/rbc-revs-v1: size=160 recovery from invalid cache file with some bad records $ mv .hg/cache/rbc-revs-v1 . $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1 @@ -658,29 +814,29 @@ recovery from invalid cache file with so 5 truncating cache/rbc-revs-v1 to 104 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs* - .hg/cache/rbc-revs-v1: size=120 + .hg/cache/rbc-revs-v1: size=160 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....| cache is updated when committing $ hg branch i-will-regret-this marked working directory as branch i-will-regret-this $ hg ci -m regrets $ f --size .hg/cache/rbc-* - .hg/cache/rbc-names-v1: size=106 - .hg/cache/rbc-revs-v1: size=128 + .hg/cache/rbc-names-v1: size=111 + .hg/cache/rbc-revs-v1: size=168 update after rollback - the cache will be correct but rbc-names will will still contain the branch name even though it no longer is used $ hg up -qr '.^' $ hg rollback -qf $ f --size --hexdump .hg/cache/rbc-* - .hg/cache/rbc-names-v1: size=106 + .hg/cache/rbc-names-v1: size=111 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a | 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much| 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the| 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi| 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b| - 0050: 72 61 6e 63 68 65 73 00 69 2d 77 69 6c 6c 2d 72 |ranches.i-will-r| - 0060: 65 67 72 65 74 2d 74 68 69 73 |egret-this| - .hg/cache/rbc-revs-v1: size=120 + 0050: 72 61 6e 63 68 65 73 00 6d 00 6d 64 00 69 2d 77 |ranches.m.md.i-w| + 0060: 69 6c 6c 2d 72 65 67 72 65 74 2d 74 68 69 73 |ill-regret-this| + .hg/cache/rbc-revs-v1: size=160 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....| 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....| 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................| @@ -688,12 +844,14 @@ contain the branch name even though it n 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....| 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....| 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....| - 0070: f8 94 c2 56 80 00 00 03 |...V....| + 0070: f8 94 c2 56 80 00 00 03 f3 44 76 37 00 00 00 05 |...V.....Dv7....| + 0080: a5 8c a5 d3 00 00 00 05 df 34 3b 0d 00 00 00 05 |.........4;.....| + 0090: c9 14 c9 9f 00 00 00 06 cd 21 a8 0b 80 00 00 05 |.........!......| cache is updated/truncated when stripping - it is thus very hard to get in a situation where the cache is out of sync and the hash check detects it $ hg --config extensions.strip= strip -r tip --nob $ f --size .hg/cache/rbc-revs* - .hg/cache/rbc-revs-v1: size=112 + .hg/cache/rbc-revs-v1: size=152 cache is rebuilt when corruption is detected $ echo > .hg/cache/rbc-names-v1 @@ -701,13 +859,14 @@ cache is rebuilt when corruption is dete referenced branch names not found - rebuilding revision branch cache from scratch 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40 $ f --size --hexdump .hg/cache/rbc-* - .hg/cache/rbc-names-v1: size=79 + .hg/cache/rbc-names-v1: size=84 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n| 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer | 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default| 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u| - 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 |sed by branches| - .hg/cache/rbc-revs-v1: size=112 + 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 00 |sed by branches.| + 0050: 6d 00 6d 64 |m.md| + .hg/cache/rbc-revs-v1: size=152 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................| @@ -715,6 +874,9 @@ cache is rebuilt when corruption is dete 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....| 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....| 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....| + 0070: f8 94 c2 56 80 00 00 02 f3 44 76 37 00 00 00 04 |...V.....Dv7....| + 0080: a5 8c a5 d3 00 00 00 04 df 34 3b 0d 00 00 00 04 |.........4;.....| + 0090: c9 14 c9 9f 00 00 00 05 |........| Test that cache files are created and grows correctly: @@ -724,7 +886,7 @@ Test that cache files are created and gr $ f --size --hexdump .hg/cache/rbc-* .hg/cache/rbc-names-v1: size=1 0000: 61 |a| - .hg/cache/rbc-revs-v1: size=112 + .hg/cache/rbc-revs-v1: size=152 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................| @@ -732,6 +894,9 @@ Test that cache files are created and gr 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 0080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 0090: 00 00 00 00 00 00 00 00 |........| $ cd ..