1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.data;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.IdentityCache;
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.lang.ref.WeakReference;
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class Path {
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "Path";
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static Path sRoot = new Path(null, "ROOT");
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final Path mParent;
30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final String mSegment;
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private WeakReference<MediaObject> mObject;
32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private IdentityCache<String, Path> mChildren;
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private Path(Path parent, String segment) {
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mParent = parent;
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mSegment = segment;
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public Path getChild(String segment) {
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mChildren == null) {
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mChildren = new IdentityCache<String, Path>();
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Path p = mChildren.get(segment);
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (p != null) return p;
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Path p = new Path(this, segment);
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mChildren.put(segment, p);
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return p;
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public Path getParent() {
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return mParent;
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public Path getChild(int segment) {
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return getChild(String.valueOf(segment));
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public Path getChild(long segment) {
65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return getChild(String.valueOf(segment));
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setObject(MediaObject object) {
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Utils.assertTrue(mObject == null || mObject.get() == null);
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mObject = new WeakReference<MediaObject>(object);
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
75676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin    MediaObject getObject() {
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return (mObject == null) ? null : mObject.get();
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
820addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu    // TODO: toString() should be more efficient, will fix it later
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public String toString() {
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            StringBuilder sb = new StringBuilder();
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String[] segments = split();
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = 0; i < segments.length; i++) {
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                sb.append("/");
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                sb.append(segments[i]);
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return sb.toString();
92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
950addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu    public boolean equalsIgnoreCase (String p) {
960addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu        String path = toString();
970addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu        return path.equalsIgnoreCase(p);
980addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu    }
990addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static Path fromString(String s) {
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String[] segments = split(s);
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Path current = sRoot;
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = 0; i < segments.length; i++) {
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                current = current.getChild(segments[i]);
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return current;
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public String[] split() {
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int n = 0;
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (Path p = this; p != sRoot; p = p.mParent) {
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                n++;
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String[] segments = new String[n];
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int i = n - 1;
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (Path p = this; p != sRoot; p = p.mParent) {
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                segments[i--] = p.mSegment;
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return segments;
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static String[] split(String s) {
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int n = s.length();
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (n == 0) return new String[0];
129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (s.charAt(0) != '/') {
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            throw new RuntimeException("malformed path:" + s);
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ArrayList<String> segments = new ArrayList<String>();
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int i = 1;
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        while (i < n) {
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int brace = 0;
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int j;
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (j = i; j < n; j++) {
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                char c = s.charAt(j);
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (c == '{') ++brace;
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                else if (c == '}') --brace;
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                else if (brace == 0 && c == '/') break;
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (brace != 0) {
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                throw new RuntimeException("unbalanced brace in path:" + s);
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            segments.add(s.substring(i, j));
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            i = j + 1;
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String[] result = new String[segments.size()];
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        segments.toArray(result);
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return result;
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // Splits a string to an array of strings.
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // For example, "{foo,bar,baz}" -> {"foo","bar","baz"}.
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static String[] splitSequence(String s) {
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int n = s.length();
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (s.charAt(0) != '{' || s.charAt(n-1) != '}') {
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            throw new RuntimeException("bad sequence: " + s);
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ArrayList<String> segments = new ArrayList<String>();
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int i = 1;
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        while (i < n - 1) {
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int brace = 0;
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int j;
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (j = i; j < n - 1; j++) {
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                char c = s.charAt(j);
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (c == '{') ++brace;
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                else if (c == '}') --brace;
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                else if (brace == 0 && c == ',') break;
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (brace != 0) {
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                throw new RuntimeException("unbalanced brace in path:" + s);
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            segments.add(s.substring(i, j));
176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            i = j + 1;
177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String[] result = new String[segments.size()];
179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        segments.toArray(result);
180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return result;
181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public String getPrefix() {
18431cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin        if (this == sRoot) return "";
18531cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin        return getPrefixPath().mSegment;
18631cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin    }
18731cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin
18831cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin    public Path getPrefixPath() {
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Path current = this;
19131cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin            if (current == sRoot) {
19231cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin                throw new IllegalStateException();
19331cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin            }
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            while (current.mParent != sRoot) {
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                current = current.mParent;
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
19731cac30e46a293f6d0901e22c6ab0d083cae7021Owen Lin            return current;
198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public String getSuffix() {
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // We don't need lock because mSegment is final.
203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mSegment;
204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // Below are for testing/debugging only
207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    static void clearAll() {
208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            sRoot = new Path(null, "");
210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    static void dumpAll() {
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        dumpAll(sRoot, "", "");
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    static void dumpAll(Path p, String prefix1, String prefix2) {
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (Path.class) {
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            MediaObject obj = p.getObject();
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.d(TAG, prefix1 + p.mSegment + ":"
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    + (obj == null ? "null" : obj.getClass().getSimpleName()));
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (p.mChildren != null) {
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ArrayList<String> childrenKeys = p.mChildren.keys();
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                int i = 0, n = childrenKeys.size();
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                for (String key : childrenKeys) {
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    Path child = p.mChildren.get(key);
227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    if (child == null) {
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        ++i;
229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        continue;
230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    Log.d(TAG, prefix2 + "|");
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    if (++i < n) {
233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        dumpAll(child, prefix2 + "+-- ", prefix2 + "|   ");
234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    } else {
235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        dumpAll(child, prefix2 + "+-- ", prefix2 + "    ");
236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
242