##// END OF EJS Templates
merge with stable
Matt Mackall -
r12718:372abc79 merge default
parent child Browse files
Show More
@@ -1,188 +1,200
1 # darcs.py - darcs support for the convert extension
1 # darcs.py - darcs support for the convert extension
2 #
2 #
3 # Copyright 2007-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2007-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from common import NoRepo, checktool, commandline, commit, converter_source
8 from common import NoRepo, checktool, commandline, commit, converter_source
9 from mercurial.i18n import _
9 from mercurial.i18n import _
10 from mercurial import util
10 from mercurial import encoding, util
11 import os, shutil, tempfile, re
11 import os, shutil, tempfile, re
12
12
13 # The naming drift of ElementTree is fun!
13 # The naming drift of ElementTree is fun!
14
14
15 try:
15 try:
16 from xml.etree.cElementTree import ElementTree
16 from xml.etree.cElementTree import ElementTree, XMLParser
17 except ImportError:
17 except ImportError:
18 try:
18 try:
19 from xml.etree.ElementTree import ElementTree
19 from xml.etree.ElementTree import ElementTree, XMLParser
20 except ImportError:
20 except ImportError:
21 try:
21 try:
22 from elementtree.cElementTree import ElementTree
22 from elementtree.cElementTree import ElementTree, XMLParser
23 except ImportError:
23 except ImportError:
24 try:
24 try:
25 from elementtree.ElementTree import ElementTree
25 from elementtree.ElementTree import ElementTree, XMLParser
26 except ImportError:
26 except ImportError:
27 ElementTree = None
27 ElementTree = None
28
28
29 class darcs_source(converter_source, commandline):
29 class darcs_source(converter_source, commandline):
30 def __init__(self, ui, path, rev=None):
30 def __init__(self, ui, path, rev=None):
31 converter_source.__init__(self, ui, path, rev=rev)
31 converter_source.__init__(self, ui, path, rev=rev)
32 commandline.__init__(self, ui, 'darcs')
32 commandline.__init__(self, ui, 'darcs')
33
33
34 # check for _darcs, ElementTree so that we can easily skip
34 # check for _darcs, ElementTree so that we can easily skip
35 # test-convert-darcs if ElementTree is not around
35 # test-convert-darcs if ElementTree is not around
36 if not os.path.exists(os.path.join(path, '_darcs')):
36 if not os.path.exists(os.path.join(path, '_darcs')):
37 raise NoRepo(_("%s does not look like a darcs repository") % path)
37 raise NoRepo(_("%s does not look like a darcs repository") % path)
38
38
39 checktool('darcs')
39 checktool('darcs')
40 version = self.run0('--version').splitlines()[0].strip()
40 version = self.run0('--version').splitlines()[0].strip()
41 if version < '2.1':
41 if version < '2.1':
42 raise util.Abort(_('darcs version 2.1 or newer needed (found %r)') %
42 raise util.Abort(_('darcs version 2.1 or newer needed (found %r)') %
43 version)
43 version)
44
44
45 if ElementTree is None:
45 if ElementTree is None:
46 raise util.Abort(_("Python ElementTree module is not available"))
46 raise util.Abort(_("Python ElementTree module is not available"))
47
47
48 self.path = os.path.realpath(path)
48 self.path = os.path.realpath(path)
49
49
50 self.lastrev = None
50 self.lastrev = None
51 self.changes = {}
51 self.changes = {}
52 self.parents = {}
52 self.parents = {}
53 self.tags = {}
53 self.tags = {}
54
54
55 # Check darcs repository format
55 # Check darcs repository format
56 format = self.format()
56 format = self.format()
57 if format:
57 if format:
58 if format in ('darcs-1.0', 'hashed'):
58 if format in ('darcs-1.0', 'hashed'):
59 raise NoRepo(_("%s repository format is unsupported, "
59 raise NoRepo(_("%s repository format is unsupported, "
60 "please upgrade") % format)
60 "please upgrade") % format)
61 else:
61 else:
62 self.ui.warn(_('failed to detect repository format!'))
62 self.ui.warn(_('failed to detect repository format!'))
63
63
64 def before(self):
64 def before(self):
65 self.tmppath = tempfile.mkdtemp(
65 self.tmppath = tempfile.mkdtemp(
66 prefix='convert-' + os.path.basename(self.path) + '-')
66 prefix='convert-' + os.path.basename(self.path) + '-')
67 output, status = self.run('init', repodir=self.tmppath)
67 output, status = self.run('init', repodir=self.tmppath)
68 self.checkexit(status)
68 self.checkexit(status)
69
69
70 tree = self.xml('changes', xml_output=True, summary=True,
70 tree = self.xml('changes', xml_output=True, summary=True,
71 repodir=self.path)
71 repodir=self.path)
72 tagname = None
72 tagname = None
73 child = None
73 child = None
74 for elt in tree.findall('patch'):
74 for elt in tree.findall('patch'):
75 node = elt.get('hash')
75 node = elt.get('hash')
76 name = elt.findtext('name', '')
76 name = elt.findtext('name', '')
77 if name.startswith('TAG '):
77 if name.startswith('TAG '):
78 tagname = name[4:].strip()
78 tagname = name[4:].strip()
79 elif tagname is not None:
79 elif tagname is not None:
80 self.tags[tagname] = node
80 self.tags[tagname] = node
81 tagname = None
81 tagname = None
82 self.changes[node] = elt
82 self.changes[node] = elt
83 self.parents[child] = [node]
83 self.parents[child] = [node]
84 child = node
84 child = node
85 self.parents[child] = []
85 self.parents[child] = []
86
86
87 def after(self):
87 def after(self):
88 self.ui.debug('cleaning up %s\n' % self.tmppath)
88 self.ui.debug('cleaning up %s\n' % self.tmppath)
89 shutil.rmtree(self.tmppath, ignore_errors=True)
89 shutil.rmtree(self.tmppath, ignore_errors=True)
90
90
91 def recode(self, s, encoding=None):
92 if isinstance(s, unicode):
93 # XMLParser returns unicode objects for anything it can't
94 # encode into ASCII. We convert them back to str to get
95 # recode's normal conversion behavior.
96 s = s.encode('latin-1')
97 return super(darcs_source, self).recode(s, encoding)
98
91 def xml(self, cmd, **kwargs):
99 def xml(self, cmd, **kwargs):
92 # NOTE: darcs is currently encoding agnostic and will print
100 # NOTE: darcs is currently encoding agnostic and will print
93 # patch metadata byte-for-byte, even in the XML changelog.
101 # patch metadata byte-for-byte, even in the XML changelog.
94 etree = ElementTree()
102 etree = ElementTree()
103 # While we are decoding the XML as latin-1 to be as liberal as
104 # possible, etree will still raise an exception if any
105 # non-printable characters are in the XML changelog.
106 parser = XMLParser(encoding='latin-1')
95 fp = self._run(cmd, **kwargs)
107 fp = self._run(cmd, **kwargs)
96 etree.parse(fp)
108 etree.parse(fp, parser=parser)
97 self.checkexit(fp.close())
109 self.checkexit(fp.close())
98 return etree.getroot()
110 return etree.getroot()
99
111
100 def format(self):
112 def format(self):
101 output, status = self.run('show', 'repo', no_files=True,
113 output, status = self.run('show', 'repo', no_files=True,
102 repodir=self.path)
114 repodir=self.path)
103 self.checkexit(status)
115 self.checkexit(status)
104 m = re.search(r'^\s*Format:\s*(.*)$', output, re.MULTILINE)
116 m = re.search(r'^\s*Format:\s*(.*)$', output, re.MULTILINE)
105 if not m:
117 if not m:
106 return None
118 return None
107 return ','.join(sorted(f.strip() for f in m.group(1).split(',')))
119 return ','.join(sorted(f.strip() for f in m.group(1).split(',')))
108
120
109 def manifest(self):
121 def manifest(self):
110 man = []
122 man = []
111 output, status = self.run('show', 'files', no_directories=True,
123 output, status = self.run('show', 'files', no_directories=True,
112 repodir=self.tmppath)
124 repodir=self.tmppath)
113 self.checkexit(status)
125 self.checkexit(status)
114 for line in output.split('\n'):
126 for line in output.split('\n'):
115 path = line[2:]
127 path = line[2:]
116 if path:
128 if path:
117 man.append(path)
129 man.append(path)
118 return man
130 return man
119
131
120 def getheads(self):
132 def getheads(self):
121 return self.parents[None]
133 return self.parents[None]
122
134
123 def getcommit(self, rev):
135 def getcommit(self, rev):
124 elt = self.changes[rev]
136 elt = self.changes[rev]
125 date = util.strdate(elt.get('local_date'), '%a %b %d %H:%M:%S %Z %Y')
137 date = util.strdate(elt.get('local_date'), '%a %b %d %H:%M:%S %Z %Y')
126 desc = elt.findtext('name') + '\n' + elt.findtext('comment', '')
138 desc = elt.findtext('name') + '\n' + elt.findtext('comment', '')
127 # etree can return unicode objects for name, comment, and author,
139 # etree can return unicode objects for name, comment, and author,
128 # so recode() is used to ensure str objects are emitted.
140 # so recode() is used to ensure str objects are emitted.
129 return commit(author=self.recode(elt.get('author')),
141 return commit(author=self.recode(elt.get('author')),
130 date=util.datestr(date),
142 date=util.datestr(date),
131 desc=self.recode(desc).strip(),
143 desc=self.recode(desc).strip(),
132 parents=self.parents[rev])
144 parents=self.parents[rev])
133
145
134 def pull(self, rev):
146 def pull(self, rev):
135 output, status = self.run('pull', self.path, all=True,
147 output, status = self.run('pull', self.path, all=True,
136 match='hash %s' % rev,
148 match='hash %s' % rev,
137 no_test=True, no_posthook=True,
149 no_test=True, no_posthook=True,
138 external_merge='/bin/false',
150 external_merge='/bin/false',
139 repodir=self.tmppath)
151 repodir=self.tmppath)
140 if status:
152 if status:
141 if output.find('We have conflicts in') == -1:
153 if output.find('We have conflicts in') == -1:
142 self.checkexit(status, output)
154 self.checkexit(status, output)
143 output, status = self.run('revert', all=True, repodir=self.tmppath)
155 output, status = self.run('revert', all=True, repodir=self.tmppath)
144 self.checkexit(status, output)
156 self.checkexit(status, output)
145
157
146 def getchanges(self, rev):
158 def getchanges(self, rev):
147 copies = {}
159 copies = {}
148 changes = []
160 changes = []
149 man = None
161 man = None
150 for elt in self.changes[rev].find('summary').getchildren():
162 for elt in self.changes[rev].find('summary').getchildren():
151 if elt.tag in ('add_directory', 'remove_directory'):
163 if elt.tag in ('add_directory', 'remove_directory'):
152 continue
164 continue
153 if elt.tag == 'move':
165 if elt.tag == 'move':
154 if man is None:
166 if man is None:
155 man = self.manifest()
167 man = self.manifest()
156 source, dest = elt.get('from'), elt.get('to')
168 source, dest = elt.get('from'), elt.get('to')
157 if source in man:
169 if source in man:
158 # File move
170 # File move
159 changes.append((source, rev))
171 changes.append((source, rev))
160 changes.append((dest, rev))
172 changes.append((dest, rev))
161 copies[dest] = source
173 copies[dest] = source
162 else:
174 else:
163 # Directory move, deduce file moves from manifest
175 # Directory move, deduce file moves from manifest
164 source = source + '/'
176 source = source + '/'
165 for f in man:
177 for f in man:
166 if not f.startswith(source):
178 if not f.startswith(source):
167 continue
179 continue
168 fdest = dest + '/' + f[len(source):]
180 fdest = dest + '/' + f[len(source):]
169 changes.append((f, rev))
181 changes.append((f, rev))
170 changes.append((fdest, rev))
182 changes.append((fdest, rev))
171 copies[fdest] = f
183 copies[fdest] = f
172 else:
184 else:
173 changes.append((elt.text.strip(), rev))
185 changes.append((elt.text.strip(), rev))
174 self.pull(rev)
186 self.pull(rev)
175 self.lastrev = rev
187 self.lastrev = rev
176 return sorted(changes), copies
188 return sorted(changes), copies
177
189
178 def getfile(self, name, rev):
190 def getfile(self, name, rev):
179 if rev != self.lastrev:
191 if rev != self.lastrev:
180 raise util.Abort(_('internal calling inconsistency'))
192 raise util.Abort(_('internal calling inconsistency'))
181 path = os.path.join(self.tmppath, name)
193 path = os.path.join(self.tmppath, name)
182 data = open(path, 'rb').read()
194 data = open(path, 'rb').read()
183 mode = os.lstat(path).st_mode
195 mode = os.lstat(path).st_mode
184 mode = (mode & 0111) and 'x' or ''
196 mode = (mode & 0111) and 'x' or ''
185 return data, mode
197 return data, mode
186
198
187 def gettags(self):
199 def gettags(self):
188 return self.tags
200 return self.tags
@@ -1,131 +1,144
1
1
2 $ "$TESTDIR/hghave" darcs || exit 80
2 $ "$TESTDIR/hghave" darcs || exit 80
3 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
4 $ echo "convert=" >> $HGRCPATH
4 $ echo "convert=" >> $HGRCPATH
5 $ echo 'graphlog =' >> $HGRCPATH
5 $ echo 'graphlog =' >> $HGRCPATH
6 $ DARCS_EMAIL='test@example.org'; export DARCS_EMAIL
6 $ DARCS_EMAIL='test@example.org'; export DARCS_EMAIL
7 $ HOME=`pwd`/do_not_use_HOME_darcs; export HOME
7 $ HOME=`pwd`/do_not_use_HOME_darcs; export HOME
8
8
9 skip if we can't import elementtree
9 skip if we can't import elementtree
10
10
11 $ mkdir dummy
11 $ mkdir dummy
12 $ mkdir dummy/_darcs
12 $ mkdir dummy/_darcs
13 $ if hg convert dummy 2>&1 | grep ElementTree > /dev/null; then
13 $ if hg convert dummy 2>&1 | grep ElementTree > /dev/null; then
14 > echo 'skipped: missing feature: elementtree module'
14 > echo 'skipped: missing feature: elementtree module'
15 > exit 80
15 > exit 80
16 > fi
16 > fi
17
17
18 try converting darcs1 repository
18 try converting darcs1 repository
19
19
20 $ hg clone -q "$TESTDIR/darcs1.hg" darcs
20 $ hg clone -q "$TESTDIR/darcs1.hg" darcs
21 $ hg convert -s darcs darcs/darcs1 2>&1 | grep darcs-1.0
21 $ hg convert -s darcs darcs/darcs1 2>&1 | grep darcs-1.0
22 darcs-1.0 repository format is unsupported, please upgrade
22 darcs-1.0 repository format is unsupported, please upgrade
23
23
24 initialize darcs repo
24 initialize darcs repo
25
25
26 $ mkdir darcs-repo
26 $ mkdir darcs-repo
27 $ cd darcs-repo
27 $ cd darcs-repo
28 $ darcs init
28 $ darcs init
29 $ echo a > a
29 $ echo a > a
30 $ darcs record -a -l -m p0
30 $ darcs record -a -l -m p0
31 Finished recording patch 'p0'
31 Finished recording patch 'p0'
32 $ cd ..
32 $ cd ..
33
33
34 branch and update
34 branch and update
35
35
36 $ darcs get darcs-repo darcs-clone >/dev/null
36 $ darcs get darcs-repo darcs-clone >/dev/null
37 $ cd darcs-clone
37 $ cd darcs-clone
38 $ echo c >> a
38 $ echo c >> a
39 $ echo c > c
39 $ echo c > c
40 $ darcs record -a -l -m p1.1
40 $ darcs record -a -l -m p1.1
41 Finished recording patch 'p1.1'
41 Finished recording patch 'p1.1'
42 $ cd ..
42 $ cd ..
43
43
44 update source
44 update source
45
45
46 $ cd darcs-repo
46 $ cd darcs-repo
47 $ echo b >> a
47 $ echo b >> a
48 $ echo b > b
48 $ echo b > b
49 $ darcs record -a -l -m p1.2
49 $ darcs record -a -l -m p1.2
50 Finished recording patch 'p1.2'
50 Finished recording patch 'p1.2'
51
51
52 merge branch
53
54 $ darcs pull -a ../darcs-clone
52 $ darcs pull -a ../darcs-clone
55 Backing up ./a(-darcs-backup0)
53 Backing up ./a(-darcs-backup0)
56 We have conflicts in the following files:
54 We have conflicts in the following files:
57 ./a
55 ./a
58 Finished pulling and applying.
56 Finished pulling and applying.
59 $ sleep 1
57 $ sleep 1
60 $ echo e > a
58 $ echo e > a
61 $ echo f > f
59 $ echo f > f
62 $ mkdir dir
60 $ mkdir dir
63 $ echo d > dir/d
61 $ echo d > dir/d
64 $ echo d > dir/d2
62 $ echo d > dir/d2
65 $ darcs record -a -l -m p2
63 $ darcs record -a -l -m p2
66 Finished recording patch 'p2'
64 Finished recording patch 'p2'
67
65
68 test file and directory move
66 test file and directory move
69
67
70 $ darcs mv f ff
68 $ darcs mv f ff
71
69
72 Test remove + move
70 Test remove + move
73
71
74 $ darcs remove dir/d2
72 $ darcs remove dir/d2
75 $ rm dir/d2
73 $ rm dir/d2
76 $ darcs mv dir dir2
74 $ darcs mv dir dir2
77 $ darcs record -a -l -m p3
75 $ darcs record -a -l -m p3
78 Finished recording patch 'p3'
76 Finished recording patch 'p3'
79
77
80 test utf-8 commit message and author
78 test utf-8 commit message and author
81
79
82 $ echo g > g
80 $ echo g > g
83
81
84 darcs is encoding agnostic, so it takes whatever bytes it's given
82 darcs is encoding agnostic, so it takes whatever bytes it's given
85
83
86 $ darcs record -a -l -m 'p4: desc ñ' -A 'author ñ'
84 $ darcs record -a -l -m 'p4: desc ñ' -A 'author ñ'
87 Finished recording patch 'p4: desc ñ'
85 Finished recording patch 'p4: desc ñ'
86
87 Test latin-1 commit message
88
89 $ echo h > h
90 $ printf "p5: desc " > ../p5
91 $ python -c 'print "".join([chr(i) for i in range(128, 256)])' >> ../p5
92 $ darcs record -a -l --logfile ../p5
93 Finished recording patch 'p5: desc ��������������������������������������������������������������������������������������������������������������������������������'
94
88 $ glog()
95 $ glog()
89 > {
96 > {
90 > HGENCODING=utf-8 hg glog --template '{rev} "{desc|firstline}" ({author}) files: {files}\n' "$@"
97 > HGENCODING=utf-8 hg glog --template '{rev} "{desc|firstline}" ({author}) files: {files}\n' "$@"
91 > }
98 > }
92 $ cd ..
99 $ cd ..
93 $ hg convert darcs-repo darcs-repo-hg
100 $ hg convert darcs-repo darcs-repo-hg
94 initializing destination darcs-repo-hg repository
101 initializing destination darcs-repo-hg repository
95 scanning source...
102 scanning source...
96 sorting...
103 sorting...
97 converting...
104 converting...
98 5 p0
105 6 p0
99 4 p1.2
106 5 p1.2
100 3 p1.1
107 4 p1.1
101 2 p2
108 3 p2
102 1 p3
109 2 p3
103 0 p4: desc ?
110 1 p4: desc ?
111 0 p5: desc ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
104
112
105 The converter does not currently handle patch conflicts very well.
113 The converter does not currently handle patch conflicts very well.
106 When they occur, it reverts *all* changes and moves forward,
114 When they occur, it reverts *all* changes and moves forward,
107 letting the conflict resolving patch fix collisions.
115 letting the conflict resolving patch fix collisions.
108 Unfortunately, non-conflicting changes, like the addition of the
116 Unfortunately, non-conflicting changes, like the addition of the
109 "c" file in p1.1 patch are reverted too.
117 "c" file in p1.1 patch are reverted too.
110 Just to say that manifest not listing "c" here is a bug.
118 Just to say that manifest not listing "c" here is a bug.
111
119
112 $ glog -R darcs-repo-hg
120 $ HGENCODING=latin-1 glog -R darcs-repo-hg -r 6 | "$TESTDIR"/printrepr.py
113 o 5 "p4: desc ñ" (author ñ) files: g
121 o 6 "p5: desc \xc2\x80\xc2\x81\xc2\x82\xc2\x83\xc2\x84\xc2\x85\xc2\x86\xc2\x87\xc2\x88\xc2\x89\xc2\x8a\xc2\x8b\xc2\x8c\xc2\x8d\xc2\x8e\xc2\x8f\xc2\x90\xc2\x91\xc2\x92\xc2\x93\xc2\x94\xc2\x95\xc2\x96\xc2\x97\xc2\x98\xc2\x99\xc2\x9a\xc2\x9b\xc2\x9c\xc2\x9d\xc2\x9e\xc2\x9f\xc2\xa0\xc2\xa1\xc2\xa2\xc2\xa3\xc2\xa4\xc2\xa5\xc2\xa6\xc2\xa7\xc2\xa8\xc2\xa9\xc2\xaa\xc2\xab\xc2\xac\xc2\xad\xc2\xae\xc2\xaf\xc2\xb0\xc2\xb1\xc2\xb2\xc2\xb3\xc2\xb4\xc2\xb5\xc2\xb6\xc2\xb7\xc2\xb8\xc2\xb9\xc2\xba\xc2\xbb\xc2\xbc\xc2\xbd\xc2\xbe\xc2\xbf\xc3\x80\xc3\x81\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x86\xc3\x87\xc3\x88\xc3\x89\xc3\x8a\xc3\x8b\xc3\x8c\xc3\x8d\xc3\x8e\xc3\x8f\xc3\x90\xc3\x91\xc3\x92\xc3\x93\xc3\x94\xc3\x95\xc3\x96\xc3\x97\xc3\x98\xc3\x99\xc3\x9a\xc3\x9b\xc3\x9c\xc3\x9d\xc3\x9e\xc3\x9f\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4\xc3\xa5\xc3\xa6\xc3\xa7\xc3\xa8\xc3\xa9\xc3\xaa\xc3\xab\xc3\xac\xc3\xad\xc3\xae\xc3\xaf\xc3\xb0\xc3\xb1\xc3\xb2\xc3\xb3\xc3\xb4\xc3\xb5\xc3\xb6\xc3\xb7\xc3\xb8\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc3\xbd\xc3\xbe\xc3\xbf" (test@example.org) files: h
122 |
123 $ HGENCODING=utf-8 glog -R darcs-repo-hg -r 0:5 | "$TESTDIR"/printrepr.py
124 o 5 "p4: desc \xc3\xb1" (author \xc3\xb1) files: g
114 |
125 |
115 o 4 "p3" (test@example.org) files: dir/d dir/d2 dir2/d f ff
126 o 4 "p3" (test@example.org) files: dir/d dir/d2 dir2/d f ff
116 |
127 |
117 o 3 "p2" (test@example.org) files: a dir/d dir/d2 f
128 o 3 "p2" (test@example.org) files: a dir/d dir/d2 f
118 |
129 |
119 o 2 "p1.1" (test@example.org) files:
130 o 2 "p1.1" (test@example.org) files:
120 |
131 |
121 o 1 "p1.2" (test@example.org) files: a b
132 o 1 "p1.2" (test@example.org) files: a b
122 |
133 |
123 o 0 "p0" (test@example.org) files: a
134 o 0 "p0" (test@example.org) files: a
124
135
136
125 $ hg up -q -R darcs-repo-hg
137 $ hg up -q -R darcs-repo-hg
126 $ hg -R darcs-repo-hg manifest --debug
138 $ hg -R darcs-repo-hg manifest --debug
127 7225b30cdf38257d5cc7780772c051b6f33e6d6b 644 a
139 7225b30cdf38257d5cc7780772c051b6f33e6d6b 644 a
128 1e88685f5ddec574a34c70af492f95b6debc8741 644 b
140 1e88685f5ddec574a34c70af492f95b6debc8741 644 b
129 37406831adc447ec2385014019599dfec953c806 644 dir2/d
141 37406831adc447ec2385014019599dfec953c806 644 dir2/d
130 b783a337463792a5c7d548ad85a7d3253c16ba8c 644 ff
142 b783a337463792a5c7d548ad85a7d3253c16ba8c 644 ff
131 0973eb1b2ecc4de7fafe7447ce1b7462108b4848 644 g
143 0973eb1b2ecc4de7fafe7447ce1b7462108b4848 644 g
144 fe6f8b4f507fe3eb524c527192a84920a4288dac 644 h
General Comments 0
You need to be logged in to leave comments. Login now