##// END OF EJS Templates
graphmod: use revsets internally...
Alexander Solovyov -
r14042:9966c95b default
parent child Browse files
Show More
@@ -249,8 +249,6 b' def graphlog(ui, repo, path=None, **opts'
249 249 if start == nullrev:
250 250 return
251 251
252 if path:
253 path = scmutil.canonpath(repo.root, os.getcwd(), path)
254 252 if path: # could be reset in canonpath
255 253 revdag = graphmod.filerevs(repo, path, start, stop, limit)
256 254 else:
@@ -18,43 +18,66 b' Data depends on type.'
18 18 """
19 19
20 20 from mercurial.node import nullrev
21 from mercurial.cmdutil import revrange
21 22
22 23 CHANGESET = 'C'
23 24
24 def revisions(repo, start, stop):
25 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
26
27 This generator function walks through the revision history from revision
28 start to revision stop (which must be less than or equal to start). It
29 returns a tuple for each node. The node and parent ids are arbitrary
30 integers which identify a node in the context of the graph returned.
25 def revisions(repo, start, end):
26 """DAG generator for revisions between start and end
31 27 """
32 cur = start
33 while cur >= stop:
34 ctx = repo[cur]
35 parents = set([p.rev() for p in ctx.parents() if p.rev() != nullrev])
36 yield (cur, CHANGESET, ctx, sorted(parents))
37 cur -= 1
28 revset = '%s:%s' % (start, end)
29 return dagwalker(repo, revrange(repo, [revset]))
38 30
39 31 def filerevs(repo, path, start, stop, limit=None):
40 """file cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
32 """DAG generator, which is limited by file passed
33 """
34 revset = '%s:%s and file("%s")' % (start, stop, path)
35 if limit:
36 revset = 'limit(%s, %s)' % (revset, limit)
37 return dagwalker(repo, revrange(repo, [revset]))
41 38
42 This generator function walks through the revision history of a single
43 file from revision start down to revision stop.
39 def dagwalker(repo, revs):
40 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
41
42 This generator function walks through revisions (which should be ordered
43 from bigger to lower). It returns a tuple for each node. The node and parent
44 ids are arbitrary integers which identify a node in the context of the graph
45 returned.
44 46 """
45 filerev = len(repo.file(path)) - 1
46 rev = stop + 1
47 count = 0
48 while filerev >= 0 and rev > stop:
49 fctx = repo.filectx(path, fileid=filerev)
50 parents = set([f.linkrev() for f in fctx.parents() if f.path() == path])
51 rev = fctx.rev()
52 if rev <= start:
53 yield (rev, CHANGESET, fctx.changectx(), sorted(parents))
54 count += 1
55 if count == limit:
56 break
57 filerev -= 1
47 if not revs:
48 return []
49
50 ns = [repo[r].node() for r in revs]
51 revdag = list(nodes(repo, ns))
52
53 cl = repo.changelog
54 lowestrev = min(revs)
55 gpcache = {}
56 leafs = {}
57
58 for i, (id, c, ctx, parents) in enumerate(revdag):
59 mpars = [p.rev() for p in ctx.parents() if
60 p.rev() != nullrev and p.rev() not in parents]
61 grandparents = []
62
63 for mpar in mpars:
64 gp = gpcache.get(mpar) or grandparent(cl, lowestrev, revs, mpar)
65 gpcache[mpar] = gp
66 if gp is None:
67 leafs.setdefault(mpar, []).append((i, ctx))
68 else:
69 grandparents.append(gp)
70
71 if grandparents:
72 for gp in grandparents:
73 if gp not in revdag[i][3]:
74 revdag[i][3].append(gp)
75
76 for parent, leafs in leafs.iteritems():
77 for i, ctx in leafs:
78 revdag[i][3].append(parent)
79
80 return revdag
58 81
59 82 def nodes(repo, nodes):
60 83 """cset DAG generator yielding (id, CHANGESET, ctx, [parentids]) tuples
@@ -120,3 +143,78 b' def colored(dag):'
120 143 # Yield and move on
121 144 yield (cur, type, data, (col, color), edges)
122 145 seen = next
146
147
148 def grandparent(cl, lowestrev, roots, head):
149 """Return closest 'root' rev in topological path from 'roots' to 'head'.
150
151 Derived from revlog.revlog.nodesbetween, but only returns next rev
152 of topologically sorted list of all nodes N that satisfy of these
153 constraints:
154
155 1. N is a descendant of some node in 'roots'
156 2. N is an ancestor of 'head'
157 3. N is some node in 'roots' or nullrev
158
159 Every node is considered to be both a descendant and an ancestor
160 of itself, so every reachable node in 'roots' and 'head' will be
161 included in 'nodes'.
162 """
163 ancestors = set()
164 # Start at the top and keep marking parents until we're done.
165 revstotag = set([head])
166 revstotag.discard(nullrev)
167 llowestrev = max(nullrev, lowestrev)
168
169 while revstotag:
170 r = revstotag.pop()
171 # A node's revision number represents its place in a
172 # topologically sorted list of nodes.
173 if r >= llowestrev:
174 if r not in ancestors:
175 # If we are possibly a descendent of one of the roots
176 # and we haven't already been marked as an ancestor
177 ancestors.add(r) # Mark as ancestor
178 # Add non-nullrev parents to list of nodes to tag.
179 revstotag.update([p for p in cl.parentrevs(r)])
180
181 if not ancestors:
182 return
183 # Now that we have our set of ancestors, we want to remove any
184 # roots that are not ancestors.
185
186 # If one of the roots was nullrev, everything is included anyway.
187 if lowestrev > nullrev:
188 # But, since we weren't, let's recompute the lowest rev to not
189 # include roots that aren't ancestors.
190
191 # Filter out roots that aren't ancestors of heads
192 _roots = ancestors.intersection(roots)
193 if not _roots:
194 return
195 # Recompute the lowest revision
196 lowestrev = min(roots)
197 else:
198 # We are descending from nullrev, and don't need to care about
199 # any other roots.
200 lowestrev = nullrev
201 _roots = [nullrev]
202
203 # The roots are just the descendants.
204 # Don't start at nullrev since we don't want nullrev in our output list,
205 # and if nullrev shows up in descedents, empty parents will look like
206 # they're descendents.
207 lowestrevisnullrev = (lowestrev == nullrev)
208 for r in xrange(head - 1, max(lowestrev, -1) - 1, -1):
209 if lowestrevisnullrev or r in _roots:
210 pass
211 elif _roots.issuperset(cl.parentrevs(r)):
212 # A node is a descendent if either of its parents are
213 # descendents. (We seeded the dependents list with the roots
214 # up there, remember?)
215 _roots.add(r)
216 else:
217 continue
218 if r in ancestors:
219 # Only include nodes that are both descendents and ancestors.
220 return r
@@ -317,5 +317,5 b' glog'
317 317 glog X
318 318 $ hg glog --template '{rev}: {desc} [{branches}]\n' X
319 319 o 2: r2 []
320
320 |
321 321 $ cd ..
@@ -463,115 +463,115 b' File glog:'
463 463 | | | date: Thu Jan 01 00:00:32 1970 +0000
464 464 | | | summary: (32) expand
465 465 | | |
466 | o | changeset: 31:621d83e11f67
467 | | | parent: 21:d42a756af44d
468 | | | parent: 30:6e11cd4b648f
469 | | | user: test
470 | | | date: Thu Jan 01 00:00:31 1970 +0000
471 | | | summary: (31) expand
472 | | |
473 | o | changeset: 30:6e11cd4b648f
474 | |\ \ parent: 28:44ecd0b9ae99
475 | | | | parent: 29:cd9bb2be7593
476 | | | | user: test
477 | | | | date: Thu Jan 01 00:00:30 1970 +0000
478 | | | | summary: (30) expand
479 | | | |
480 | | o | changeset: 29:cd9bb2be7593
481 | | | | parent: 0:e6eb3150255d
482 | | | | user: test
483 | | | | date: Thu Jan 01 00:00:29 1970 +0000
484 | | | | summary: (29) regular commit
485 | | | |
486 | o | | changeset: 28:44ecd0b9ae99
487 | | | | parent: 1:6db2ef61d156
488 | | | | parent: 26:7f25b6c2f0b9
466 | o | changeset: 31:621d83e11f67
467 | |\ \ parent: 21:d42a756af44d
468 | | | | parent: 30:6e11cd4b648f
489 469 | | | | user: test
490 | | | | date: Thu Jan 01 00:00:28 1970 +0000
491 | | | | summary: (28) merge zero known
492 | | | |
493 o | | | changeset: 27:886ed638191b
494 | | | | parent: 21:d42a756af44d
495 | | | | user: test
496 | | | | date: Thu Jan 01 00:00:27 1970 +0000
497 | | | | summary: (27) collapse
498 | | | |
499 | o | | changeset: 26:7f25b6c2f0b9
500 | | | | parent: 18:1aa84d96232a
501 | | | | parent: 25:91da8ed57247
502 | | | | user: test
503 | | | | date: Thu Jan 01 00:00:26 1970 +0000
504 | | | | summary: (26) merge one known; far right
505 | | | |
506 | o | | changeset: 25:91da8ed57247
507 | | | | parent: 21:d42a756af44d
508 | | | | parent: 24:a9c19a3d96b7
509 | | | | user: test
510 | | | | date: Thu Jan 01 00:00:25 1970 +0000
511 | | | | summary: (25) merge one known; far left
512 | | | |
513 | o | | changeset: 24:a9c19a3d96b7
514 | | | | parent: 0:e6eb3150255d
515 | | | | parent: 23:a01cddf0766d
516 | | | | user: test
517 | | | | date: Thu Jan 01 00:00:24 1970 +0000
518 | | | | summary: (24) merge one known; immediate right
470 | | | | date: Thu Jan 01 00:00:31 1970 +0000
471 | | | | summary: (31) expand
519 472 | | | |
520 | o | | changeset: 23:a01cddf0766d
521 | | | | parent: 1:6db2ef61d156
522 | | | | parent: 22:e0d9cccacb5d
523 | | | | user: test
524 | | | | date: Thu Jan 01 00:00:23 1970 +0000
525 | | | | summary: (23) merge one known; immediate left
526 | | | |
527 | o | | changeset: 22:e0d9cccacb5d
528 |/ / / parent: 18:1aa84d96232a
529 | | | parent: 21:d42a756af44d
530 | | | user: test
531 | | | date: Thu Jan 01 00:00:22 1970 +0000
532 | | | summary: (22) merge two known; one far left, one far right
533 | | |
534 o | | changeset: 21:d42a756af44d
535 |\ \ \ parent: 19:31ddc2c1573b
536 | | | | parent: 20:d30ed6450e32
537 | | | | user: test
538 | | | | date: Thu Jan 01 00:00:21 1970 +0000
539 | | | | summary: (21) expand
473 | | o | changeset: 30:6e11cd4b648f
474 | | |\ \ parent: 28:44ecd0b9ae99
475 | | | | | parent: 29:cd9bb2be7593
476 | | | | | user: test
477 | | | | | date: Thu Jan 01 00:00:30 1970 +0000
478 | | | | | summary: (30) expand
479 | | | | |
480 | | | o | changeset: 29:cd9bb2be7593
481 | | | | | parent: 0:e6eb3150255d
482 | | | | | user: test
483 | | | | | date: Thu Jan 01 00:00:29 1970 +0000
484 | | | | | summary: (29) regular commit
485 | | | | |
486 | | o | | changeset: 28:44ecd0b9ae99
487 | | |\ \ \ parent: 1:6db2ef61d156
488 | | | | | | parent: 26:7f25b6c2f0b9
489 | | | | | | user: test
490 | | | | | | date: Thu Jan 01 00:00:28 1970 +0000
491 | | | | | | summary: (28) merge zero known
492 | | | | | |
493 o | | | | | changeset: 27:886ed638191b
494 |/ / / / / parent: 21:d42a756af44d
495 | | | | | user: test
496 | | | | | date: Thu Jan 01 00:00:27 1970 +0000
497 | | | | | summary: (27) collapse
498 | | | | |
499 | | o---+ changeset: 26:7f25b6c2f0b9
500 | | | | | parent: 18:1aa84d96232a
501 | | | | | parent: 25:91da8ed57247
502 | | | | | user: test
503 | | | | | date: Thu Jan 01 00:00:26 1970 +0000
504 | | | | | summary: (26) merge one known; far right
505 | | | | |
506 +---o | | changeset: 25:91da8ed57247
507 | | | | | parent: 21:d42a756af44d
508 | | | | | parent: 24:a9c19a3d96b7
509 | | | | | user: test
510 | | | | | date: Thu Jan 01 00:00:25 1970 +0000
511 | | | | | summary: (25) merge one known; far left
512 | | | | |
513 | | o | | changeset: 24:a9c19a3d96b7
514 | | |\| | parent: 0:e6eb3150255d
515 | | | | | parent: 23:a01cddf0766d
516 | | | | | user: test
517 | | | | | date: Thu Jan 01 00:00:24 1970 +0000
518 | | | | | summary: (24) merge one known; immediate right
519 | | | | |
520 | | o | | changeset: 23:a01cddf0766d
521 | |/| | | parent: 1:6db2ef61d156
522 | | | | | parent: 22:e0d9cccacb5d
523 | | | | | user: test
524 | | | | | date: Thu Jan 01 00:00:23 1970 +0000
525 | | | | | summary: (23) merge one known; immediate left
526 | | | | |
527 +---o---+ changeset: 22:e0d9cccacb5d
528 | | | | parent: 18:1aa84d96232a
529 | | / / parent: 21:d42a756af44d
530 | | | | user: test
531 | | | | date: Thu Jan 01 00:00:22 1970 +0000
532 | | | | summary: (22) merge two known; one far left, one far right
540 533 | | | |
541 | o---+ changeset: 20:d30ed6450e32
542 | | | parent: 0:e6eb3150255d
543 | / / parent: 18:1aa84d96232a
544 | | | user: test
545 | | | date: Thu Jan 01 00:00:20 1970 +0000
546 | | | summary: (20) merge two known; two far right
547 | | |
548 o | | changeset: 19:31ddc2c1573b
549 |\ \ \ parent: 15:1dda3f72782d
550 | | | | parent: 17:44765d7c06e0
551 | | | | user: test
552 | | | | date: Thu Jan 01 00:00:19 1970 +0000
553 | | | | summary: (19) expand
534 o | | | changeset: 21:d42a756af44d
535 |\ \ \ \ parent: 19:31ddc2c1573b
536 | | | | | parent: 20:d30ed6450e32
537 | | | | | user: test
538 | | | | | date: Thu Jan 01 00:00:21 1970 +0000
539 | | | | | summary: (21) expand
540 | | | | |
541 | o---+-+ changeset: 20:d30ed6450e32
542 | | | | parent: 0:e6eb3150255d
543 | / / / parent: 18:1aa84d96232a
544 | | | | user: test
545 | | | | date: Thu Jan 01 00:00:20 1970 +0000
546 | | | | summary: (20) merge two known; two far right
554 547 | | | |
555 +-----o changeset: 18:1aa84d96232a
556 | | | parent: 1:6db2ef61d156
557 | | | parent: 15:1dda3f72782d
558 | | | user: test
559 | | | date: Thu Jan 01 00:00:18 1970 +0000
560 | | | summary: (18) merge two known; two far left
561 | | |
562 | o | changeset: 17:44765d7c06e0
563 | |\ \ parent: 12:86b91144a6e9
564 | | | | parent: 16:3677d192927d
565 | | | | user: test
566 | | | | date: Thu Jan 01 00:00:17 1970 +0000
567 | | | | summary: (17) expand
548 o | | | changeset: 19:31ddc2c1573b
549 |\ \ \ \ parent: 15:1dda3f72782d
550 | | | | | parent: 17:44765d7c06e0
551 | | | | | user: test
552 | | | | | date: Thu Jan 01 00:00:19 1970 +0000
553 | | | | | summary: (19) expand
554 | | | | |
555 +---+---o changeset: 18:1aa84d96232a
556 | | | | parent: 1:6db2ef61d156
557 | | | | parent: 15:1dda3f72782d
558 | | | | user: test
559 | | | | date: Thu Jan 01 00:00:18 1970 +0000
560 | | | | summary: (18) merge two known; two far left
568 561 | | | |
569 | | o | changeset: 16:3677d192927d
570 | | | | parent: 0:e6eb3150255d
571 | | | | parent: 1:6db2ef61d156
572 | | | | user: test
573 | | | | date: Thu Jan 01 00:00:16 1970 +0000
574 | | | | summary: (16) merge two known; one immediate right, one near right
562 | o | | changeset: 17:44765d7c06e0
563 | |\ \ \ parent: 12:86b91144a6e9
564 | | | | | parent: 16:3677d192927d
565 | | | | | user: test
566 | | | | | date: Thu Jan 01 00:00:17 1970 +0000
567 | | | | | summary: (17) expand
568 | | | | |
569 | | o---+ changeset: 16:3677d192927d
570 | | | | | parent: 0:e6eb3150255d
571 | | |/ / parent: 1:6db2ef61d156
572 | | | | user: test
573 | | | | date: Thu Jan 01 00:00:16 1970 +0000
574 | | | | summary: (16) merge two known; one immediate right, one near right
575 575 | | | |
576 576 o | | | changeset: 15:1dda3f72782d
577 577 |\ \ \ \ parent: 13:22d8966a97e3
@@ -580,9 +580,9 b' File glog:'
580 580 | | | | | date: Thu Jan 01 00:00:15 1970 +0000
581 581 | | | | | summary: (15) expand
582 582 | | | | |
583 | o | | | changeset: 14:8eac370358ef
584 | |/ / / parent: 0:e6eb3150255d
585 | | | | parent: 12:86b91144a6e9
583 | o-----+ changeset: 14:8eac370358ef
584 | | | | | parent: 0:e6eb3150255d
585 | |/ / / parent: 12:86b91144a6e9
586 586 | | | | user: test
587 587 | | | | date: Thu Jan 01 00:00:14 1970 +0000
588 588 | | | | summary: (14) merge two known; one immediate right, one far right
@@ -595,72 +595,72 b' File glog:'
595 595 | | | | | summary: (13) expand
596 596 | | | | |
597 597 +---o | | changeset: 12:86b91144a6e9
598 | | / / parent: 1:6db2ef61d156
598 | | |/ / parent: 1:6db2ef61d156
599 599 | | | | parent: 9:7010c0af0a35
600 600 | | | | user: test
601 601 | | | | date: Thu Jan 01 00:00:12 1970 +0000
602 602 | | | | summary: (12) merge two known; one immediate right, one far left
603 603 | | | |
604 | o | | changeset: 11:832d76e6bdf2
605 | | | | parent: 6:b105a072e251
606 | | | | parent: 10:74c64d036d72
607 | | | | user: test
608 | | | | date: Thu Jan 01 00:00:11 1970 +0000
609 | | | | summary: (11) expand
610 | | | |
611 | o | | changeset: 10:74c64d036d72
612 | | | | parent: 0:e6eb3150255d
613 | | | | parent: 6:b105a072e251
614 | | | | user: test
615 | | | | date: Thu Jan 01 00:00:10 1970 +0000
616 | | | | summary: (10) merge two known; one immediate left, one near right
604 | o | | changeset: 11:832d76e6bdf2
605 | |\ \ \ parent: 6:b105a072e251
606 | | | | | parent: 10:74c64d036d72
607 | | | | | user: test
608 | | | | | date: Thu Jan 01 00:00:11 1970 +0000
609 | | | | | summary: (11) expand
610 | | | | |
611 | | o---+ changeset: 10:74c64d036d72
612 | | | | | parent: 0:e6eb3150255d
613 | |/ / / parent: 6:b105a072e251
614 | | | | user: test
615 | | | | date: Thu Jan 01 00:00:10 1970 +0000
616 | | | | summary: (10) merge two known; one immediate left, one near right
617 617 | | | |
618 o | | | changeset: 9:7010c0af0a35
619 | | | | parent: 7:b632bb1b1224
620 | | | | parent: 8:7a0b11f71937
621 | | | | user: test
622 | | | | date: Thu Jan 01 00:00:09 1970 +0000
623 | | | | summary: (9) expand
624 | | | |
625 o | | | changeset: 8:7a0b11f71937
626 | | | | parent: 0:e6eb3150255d
627 | | | | parent: 7:b632bb1b1224
628 | | | | user: test
629 | | | | date: Thu Jan 01 00:00:08 1970 +0000
630 | | | | summary: (8) merge two known; one immediate left, one far right
618 o | | | changeset: 9:7010c0af0a35
619 |\ \ \ \ parent: 7:b632bb1b1224
620 | | | | | parent: 8:7a0b11f71937
621 | | | | | user: test
622 | | | | | date: Thu Jan 01 00:00:09 1970 +0000
623 | | | | | summary: (9) expand
624 | | | | |
625 | o-----+ changeset: 8:7a0b11f71937
626 | | | | | parent: 0:e6eb3150255d
627 |/ / / / parent: 7:b632bb1b1224
628 | | | | user: test
629 | | | | date: Thu Jan 01 00:00:08 1970 +0000
630 | | | | summary: (8) merge two known; one immediate left, one far right
631 631 | | | |
632 o | | | changeset: 7:b632bb1b1224
633 | | | | parent: 2:3d9a33b8d1e1
634 | | | | parent: 5:4409d547b708
635 | | | | user: test
636 | | | | date: Thu Jan 01 00:00:07 1970 +0000
637 | | | | summary: (7) expand
632 o | | | changeset: 7:b632bb1b1224
633 |\ \ \ \ parent: 2:3d9a33b8d1e1
634 | | | | | parent: 5:4409d547b708
635 | | | | | user: test
636 | | | | | date: Thu Jan 01 00:00:07 1970 +0000
637 | | | | | summary: (7) expand
638 | | | | |
639 +---o | | changeset: 6:b105a072e251
640 | |/ / / parent: 2:3d9a33b8d1e1
641 | | | | parent: 5:4409d547b708
642 | | | | user: test
643 | | | | date: Thu Jan 01 00:00:06 1970 +0000
644 | | | | summary: (6) merge two known; one immediate left, one far left
638 645 | | | |
639 | o | | changeset: 6:b105a072e251
640 |/ / / parent: 2:3d9a33b8d1e1
641 | | | parent: 5:4409d547b708
642 | | | user: test
643 | | | date: Thu Jan 01 00:00:06 1970 +0000
644 | | | summary: (6) merge two known; one immediate left, one far left
645 | | |
646 o | | changeset: 5:4409d547b708
647 | | | parent: 3:27eef8ed80b4
648 | | | parent: 4:26a8bac39d9f
649 | | | user: test
650 | | | date: Thu Jan 01 00:00:05 1970 +0000
651 | | | summary: (5) expand
652 | | |
653 o | | changeset: 4:26a8bac39d9f
654 | | | parent: 1:6db2ef61d156
655 | | | parent: 3:27eef8ed80b4
656 | | | user: test
657 | | | date: Thu Jan 01 00:00:04 1970 +0000
658 | | | summary: (4) merge two known; one immediate left, one immediate right
659 | | |
660 o | | changeset: 3:27eef8ed80b4
661 | | | user: test
662 | | | date: Thu Jan 01 00:00:03 1970 +0000
663 | | | summary: (3) collapse
646 | o | | changeset: 5:4409d547b708
647 | |\ \ \ parent: 3:27eef8ed80b4
648 | | | | | parent: 4:26a8bac39d9f
649 | | | | | user: test
650 | | | | | date: Thu Jan 01 00:00:05 1970 +0000
651 | | | | | summary: (5) expand
652 | | | | |
653 | | o | | changeset: 4:26a8bac39d9f
654 | |/|/ / parent: 1:6db2ef61d156
655 | | | | parent: 3:27eef8ed80b4
656 | | | | user: test
657 | | | | date: Thu Jan 01 00:00:04 1970 +0000
658 | | | | summary: (4) merge two known; one immediate left, one immediate right
659 | | | |
660 | o | | changeset: 3:27eef8ed80b4
661 |/ / / user: test
662 | | | date: Thu Jan 01 00:00:03 1970 +0000
663 | | | summary: (3) collapse
664 664 | | |
665 665 o | | changeset: 2:3d9a33b8d1e1
666 666 |/ / user: test
@@ -733,10 +733,10 b' File log with revs != cset revs:'
733 733 | summary: more
734 734 |
735 735 o changeset: 1:5ac72c0599bf
736 user: test
737 date: Thu Jan 01 00:00:00 1970 +0000
738 summary: two
739
736 | user: test
737 | date: Thu Jan 01 00:00:00 1970 +0000
738 | summary: two
739 |
740 740
741 741 Issue1896: File log with explicit style
742 742 $ hg glog --style=default one
General Comments 0
You need to be logged in to leave comments. Login now