/srv/irclogs.ubuntu.com/2007/12/02/#bzr.txt

=== mw is now known as mw|out
lifelessabentley: pon00:17
abentleySo I started hacking on per-file base selection yesterday, and I found a locality-of-reference problem.00:18
lifelessok00:18
abentleyThe file content is stored in the versionedfile.  The file type is stored in the inventory.00:18
abentleySo to do it absolutely correctly, I'd have to retrieve all the trees for the selected revisions.00:19
abentleyBecause the selected revision may not be a file-- it may be a directory, symlink or tree reference.00:20
lifelessok00:21
lifelessI see00:21
lifelessnow, if the kind is the same on both tips00:21
lifelessdoes that make it easier ?00:21
abentleyIn fact, we're already assuming it's a file on both tips.  Otherwise, we wouldn't need a base at all.00:21
lifelessso if its the same on both tips00:22
lifeless3-way merge says that if the base is a different kind00:22
lifeless -> we'd treat is as empty of the same kind ?00:22
abentleyNot quite.  We'd still emit foo.BASE in the correct kind.  But wrt the file merge, yes.00:23
lifelessnow symlinks and dirs have an existing empty text for their revisions00:24
abentleyAFAIK, correct.00:25
abentleySo we can shortcut the kind check 99% of the time.00:25
lifelessso; and I realise this is hacky;00:25
lifelessif doing a 3-way custom base on two currently-file-texts, w.get_lines(custom_base) will give us [] when the kind has changed.00:26
abentleyI hate to have it shortcutted 99% of the time, though.  It makes me fear the full path won't get adequately tested.00:27
lifelessare you doing custom bases for symlinks and dirs too?00:27
abentleyNo.  Those will get handled by the standard merger, which also handles inventory issues such as renames and executability.00:28
abentleyI don't think those things change enough to require the same care as text files.00:29
lifelessso I guess I'm saying; if we're only doing custom base on (text, text) pairs; and get_lines(custom_base) will always return a suitable set of lines, ([] when the common base has a different kind), then its not a shutcut situation00:30
abentleyBy shortcut, I mean that we're avoiding retrieving the file kind from the relevant inventory.00:31
abentleyBut in the case where it's [], we will have to do so.00:31
lifelessI don't see that we ever need the file kind for the base if the parents are both texts; other than to write foo.BASE.00:32
abentleyRight.  But we will have to write foo.BASE.00:32
lifelessok00:32
lifelessso lets look at that00:32
lifelesswe write foo.BASE when we ended up doing a merge right00:32
abentleyRight.00:33
lifelessnow, will we avoid doing 'merges' sometimes with custom file bases ?00:33
abentleyNo, but if the BASE is not a file, we will do a two-way merge between THIS and OTHER.00:34
lifelesswhich is where [] is useful because it's just a clean degradde.00:34
abentleyA clean what?00:35
lifelessdegrade00:35
lifelessit's what 3-way degrades too00:35
abentleyOkay.00:35
lifelesshmm, one sec local interrupt00:35
lifelessback00:39
lifelesswondering if we will ever get base == left or base == right with custom merge bases00:40
lifelessI think we can00:40
lifelessconsider this00:40
lifelessat the graph level we have two lca's00:41
lifelessso we recurse00:41
lifelessits easy then for at the file level for one side to be purely an extension of the other for a single file00:41
lifelessso when we are considering that single file we'll not need to merge at all00:41
lifelessI'm going to think out lout now00:42
lifelessand enumerate what I think the possible cases are00:42
lifeless* Base is one side (common I suspect in criss-cross merges; many files won't be actually unmerges)00:43
lifeless* Base is the revision the graph level base had00:43
lifeless* Base is another inventory00:44
lifelesss/another inventory/from &/00:44
lifelessdone00:44
lifelessabentley: ^00:54
=== josep17 is now known as linuxpararato
=== linuxpararato is now known as josep17
josep17buenas noches01:03
josep17desde venezuela01:03
abentleylifeless: I would expect base==left or base==right to be rare.  But I would imagine we can get it.  I'm not sure why it matters.02:24
abentleyWe need a general solution.02:25
abentleySure, I can hack up something gross to do per-file bases, but I think you ought to consider how an upcoming repo format could give us cheap access to file kind, symlink target, and maybe execute bit.02:27
abentleyRight now, I'm re-implementing annotate merge, and it's going swimmingly.02:27
jelmerdato: resubmitting bzr-svn fixed it02:50
jelmerdato: your upload of 0.4.4-2 hadn't been processed yet, apparently02:50
abentleyjelmer: Have you noticed that the bzr-gtk test suite is completely borked if run as part of the bazaar test suite?03:19
lifelessabentley: I'm pretty sure I hit it all the time.03:25
lifelessabentley: anyhow, our current format can give use kind/target/execute quite cheaply03:25
lifelessabentley: just use the same parse-a-delta-fragment logic.03:25
abentleyOy.  Can't we do up a format where that works by design instead of being a tremendous hack?03:27
lifelessabentley: yes, both the ones poolie and I have been fiddling/mailing about will work by design03:28
abentleyAwesome.03:29
lifelessabentley: but they largely formalise useful properties we have been able to leverage from the current format.03:29
lifelessabentley: I have been thinking that content object information should be pushed down to the per file graph anyhow; as metadata on the node03:30
abentleyWell, I know the new format will do comparisons much faster, but that sounds like it would slow them down.03:32
lifelessabentley: I'm thinking some duplication actually03:42
lifelessabentley: but also there is locality of data possibilities.03:42
lifelessabentley: this would be a 2nd or 3rd iteration out.03:42
lifelessabentley: one possibility is:03:42
abentleyOh, by "pushing down", I thought you'd be taking it out of the inventory.03:42
lifelesskind + exec + content in the 'knit'03:43
lifelessinventory has parent + name + pointer to the knit version03:47
lifeless'knit' index can pull kind + exec into it.03:47
lifelessabentley: the open things in my mind about whether this makes sense are what datum we actually need at the same time03:48
abentleyFor our tree-manipulation functions, we generally use inventory and file texts simultaneously.03:50
abentleyWhen building a tree, to create a file, we need file_id, name, parent, kind, execute bit, and content basically simultaneously.03:51
abentleyThat's not a hard requirement.  TreeTransform could work efficiently if you learned names, parents and file-ids in one pass, and everything else in a second pass.03:52
lifelessabentley: so its the case of status/diff when the last-mod is different and the value is the same that would be hurt03:58
lifelessabentley: -> how common is that03:58
lifeless(assuming we don't want false positives for st03:58
lifelessanother possibility here though is to decouple the metadata graph from the content graph03:59
abentleyThis is assuming we're not diffing against a DirstateRevisionTree?03:59
lifelessright03:59
abentleySo we wouldn't have the md5sum in the inventory?03:59
lifelessso you'd have (fileid, parentid, name, content-pointer[revid, validator]) as a graph04:00
lifelessand (kind, exec, content) as a graph04:00
abentleyI'm not sure at all how common that is.  Merges can produce it, though.04:00
lifelessyou'd have a sha1, but not of the lines, of the lines & kind and exec bit04:00
lifelessthis would for instance, allow us to start only storing one copy of 'COPYING' etc, depending on how we want to take it.04:01
lifelessthis is all still wildly speculative04:01
abentleyI don't think kind is a big concern.  If it changes, we definitely need to get all the data.04:01
abentleyI dunno, though.  I think having all the data in the inventory might well be a win.04:03
lifelessI'd like to be in a position to experiment04:04
abentleyJust because there are many operations that just want to know which files changed.04:04
lifelesswrite some arbitrary benchmarks outside bzr that simulate access patterns and the like04:04
lifelessmaybe this is something we can reason about in march04:06
abentleyAlso, some stats on real trees might help us answer these questions about what's common better.04:17
lifelessabentley: indeed. So having an analyser that can report what a transformed tree would look like would be good04:27
abentleyI'm not sure what you have in mind.  The PreviewTree thing?04:28
lifelessnah04:28
lifelessjust a script to take a branch04:28
lifelessand break it out into the things I'm talking about, without doing disk transformations, just in-memory, and report04:29
abentleyOh, to simulate a changed repo format?04:30
lifelessright04:30
jelmerlifeless: what breaks about it?04:50
jelmers/lifeless/abentley/04:50
jelmerah, I see04:51
lifelessmeh05:16
lifelesssorry about disappearing; what did I not respond to05:16
Odd_Bloke-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------05:16
Odd_Bloke05:03:21 -!- lifeless [n=robertc@ppp245-86.static.internode.on.net] has quit [Read error: 113 (No route to host)]05:16
Odd_Bloke05:15:45 -!- lifeless [n=robertc@ppp245-86.static.internode.on.net] has joined #bzr05:16
Odd_BlokeOops, got the trackbar.05:16
Odd_BlokeBut yeah, nothing. :p05:17
lifelessthanks05:17
=== n2diy_ is now known as n2diy
alecwhhello, I'm considering using bazaar for a project of mine... we're using subversion right now, because subversion is offered on Google Code, and Gna! (http://gna.org). Are there any free repository hosts that our GPL program can use (using bazaar)?08:07
beunoalecwh, sure, https://launchpad.net/08:08
beunoit also works as a bug tracker08:08
beuno(and a bunch of other stuff)08:09
alecwhno way... it hosts a free bazaar repository? that's awesome.08:09
alecwhhow do I set it up?08:10
alecwhhttps://code.launchpad.net/phpns/08:10
alecwhThis is our project08:10
alecwhRegister branch?08:10
beunoalecwh, let me fetch you a how-to real quick08:17
PengHmm. I just started using LP a bit. I should look into the launchpad plugin.08:17
beunoalecwh, https://help.launchpad.net/FeatureHighlights/BazaarHosting might help a bit08:18
beunobut you basically just push to the right address with bzr08:19
beunoand the branch gets created08:19
beunothe folks at #launchpad might be able to give you more details though08:19
beunoit's a bit over 5am here, so I'm going to bed08:20
beunogood luck  :D08:20
alecwhok, thanks a lot bueno. ;_08:21
alecwh;)08:21
PengMight be even simpler using lp: URIs.08:23
PengNew Pyrex release.09:19
alecwhHow do I import a subversion repository into a bazaar repository?09:32
Pengalecwh: You could use bzr-svn.09:33
alecwhwhat does that do?09:34
Pengalecwh: bzr-svn can even allow pushing from bzr to svn. It's pretty neat.09:34
Pengalecwh: Well, for one thing, it imports svn repos into bzr repos.09:34
alecwhyeah, that's what I'm looking for. =D09:34
alecwhhow does that look like?09:34
alecwhthe bash command.09:34
PengNot sure.09:35
Peng"bzr branch" might do it.09:35
PengRead the docs.09:35
alecwhok, thanks Peng. =)09:35
lifelessalecwh: www.bazaar-vcs.org/svn IIRC09:47
alecwhThis page does not exist yet. You can create a new empty page, or use one of the page templates.09:47
alecwhlifeless: I got that error.09:47
lifelessalecwh: there is a link on it09:48
lifelessalecwh: to BzrSvn :)09:48
alecwhok, thanks lifeless. I'll read over it.09:48
JordanCHey there09:50
JordanCTried to get things working with olive, but no dice/09:50
alecwhhey JordanC. =D09:50
Odd_BlokeJordanC: Define 'no dice'. :p09:52
alecwhOdd_Bloke: It didn't work.09:53
Odd_BlokeYeah, I got that much. :p  I was hoping for something a little for specific. :D09:53
Odd_Blokes/for/more/09:53
JordanCI came in here a while back, and yeah09:55
Odd_BlokeJordanC: Are you using Olive or bzr-gtk?09:55
JordanCI spoke to some developers, and they said that because of the SSH factor, I can't connect to launchpad using olive09:55
Odd_BlokeAh, OK.09:55
Odd_BlokeHave you looked at QBzr?09:55
JordanCHmm, lesee09:56
JordanCKDE Bazaar proggy?09:56
Odd_BlokeJordanC: http://bazaar-vcs.org/QBzr09:57
luksno, in two ways09:57
Odd_BlokeQt, not KDE.09:57
luksnot a program, not kde09:57
JordanCDamnit09:57
=== kiko-zzz is now known as kiko
ronnyyo13:01
ronnyis there a way to get more easy to parse output from bzr ?13:01
ronny(im parsing the status output for an ide, an its really tricky to get it together atm)13:02
Odd_Blokeronny: There's an xmloutput plugin, I believe.13:22
Odd_Blokeronny: https://edge.launchpad.net/bzr-xmloutput13:22
Odd_Blokeronny: Which IDE were you thinking of?13:22
abentleyluks: I'm looking at your patch more carefully now.13:22
luksthanks :)13:23
abentleyI think a nicer way to extract the name would be to have a pattern that only matches if there's "name <email>", and if it fails to match, just return the original string.13:23
ronnyOdd_Bloke: pida13:24
lukswell, I think returning "email" from short_author is better than "<email>"13:24
luksunless you want to match "(name )?<email>", which is exactly what the patch does13:25
abentleyI think that's highly unlikely.13:25
ronnyOdd_Bloke: right now we parse the command output, cause the subsystem for python-api based vcs tools is basically nonexistant13:25
luksabentley, "<email>" is the use case from the bug report13:26
ronnythe bad thig is - we get wrong data sometimes, but cant figure the exact source, cause the bzr output aint nice to parse (so the parser is tricky)13:27
abentleyAlso, I don't know if lazy_regex was meant to be used in new code.13:27
abentleyI thought it was just to make existing code faster.13:27
abentleyAnd I really doubt there's a performance win by using it.13:28
luksbut what's the point of compiling a regular expession you are not going to use13:29
lukssure, it's not a big win, but there is a lot of small things like this13:29
abentleyThere's no win, there's loss in compiling a regular expresion.  I was talking about not compiling at all.13:29
lukshm? you mean parsing the string manually?13:30
abentleyno, just using re.match13:31
luksthat compiles it every time you use it13:31
abentleyRight.13:31
luksso about 3k times for log on bzr13:31
ronnyactually its cached13:32
abentleyluks: I really doubt that performance difference is observable.13:32
ronnythe more often a re is used, the more sense it makes just to compile it13:33
ronnybut the difference is only small, cause all re's u use are cached in re._cache13:34
luksabentley, I mean, bzrlib already has code to delay regex compilation, pre-compiled regex is faster than re.match, there is a patch that use it -- why make is slower? even if the difference is small13:37
abentleyBecause it's clearer to just write re.match13:37
abentleyTakes fewer lines.  Doesn't require people to grok lazy_regex.13:38
ronnyhmm - how does lazy_regex work ?13:38
lukscompiles the regex when it's first used13:39
luks*first time13:40
ronnyim more intrested how the store works13:40
ronnycause i doubt it has any notable gain compared to re.match13:40
abentleyronny: It allows the "lazy_compiled" patterns to be substituted for really compiled patterns-- that's what it's for.13:42
abentleySo you can fix import slowness without rewriting the module.13:42
ronny"import slowness" ?13:43
abentleyregexes that compile at import time reduce cause latency problems for programs like Bazaar.13:43
abentleyYou run bzr, it imports a whole bunch of modules, they compile a whole bunch of regexes, and then, finally, it starts doing what you asked.13:44
ronnyhmm - why do you guys need so many regexes ?13:45
abentleyThe libraries we import need them.13:45
abentley(well, they *have* them.  *need* is debatable)13:47
ronnybtw - any timeframe when bzr will be as fast as hg ?13:47
abentleyFor example ConfigObj has regexes that produce a noticeable compile delay.13:47
abentleyronny: It depends what you're talking about.  With the packs format, commit speed is pretty similar.  With the smart server, pull time is similar.13:48
abentleystatus has been comparable for some time now.13:49
ronnyah - so its mostly cause bzr has tonns of other operation modes ?13:50
abentleyWell, it depends what operation you want to speed up.13:50
ronnyall i care for is fast sync and fast commit13:51
abentleyI think 1.0 will give you that.13:51
ronnyhmm - i didnt exactly use bzr for quite some time13:52
ronnydoes it still try hide the existence of multiple heads (for example by allways enforcing merges)13:53
abentleyI think we've got the pieces in place to support good performance for most commands.13:53
abentleyI don't know what you mean by hiding the existence of multiple heads.13:53
abentleyBut in some cases, the commands must be updated to take advantage of them.13:54
ronnylast time i used it it dodnt allowme to hae multiple heads in my repo13:54
abentleyRepositories typically have many heads due to people uncommitting revisions.13:55
abentleyBut we don't have multiple heads for a single branch.  Instead we allow multiple branches per repository.13:55
ronnyhmmk - thats a problem for me13:56
abentleyWhy?13:56
ronnyenforces me to split one semantical branch into multiple branches if more than one person is working on that13:58
abentleyNo, they can use heavyweight checkouts.13:58
Odd_Blokeronny: That's what you're doing with multiple heads anyways...13:58
abentleyThat lets them commit locally.13:58
abentleyAnd then sync up with the main branch when they're ready.13:59
ronnydamn - how many modes of operation does bzr have ????13:59
abentleyWe support a range from svn-like to fully distributed.14:00
ronnyhmm - having too many choices tends to be confusing14:00
abentleyWell, we have three: a "tree" has a branch and working copy at the same location.  A "heavyweight checkout" has a branch in one location and the working copy is at different location, but has a local copy of the branch to act as cache.  A lightweight checkout is like a heavyweight checkout with no local cache.14:04
=== kiko is now known as kiko-afk
=== mwhudson_ is now known as mwhudson
=== aosida is now known as iSoron
alecwhI just created a bazaar branch at launchpad (https://code.launchpad.net/~alecwh/phpns/devel), and now I want to upload my project (which is in /var/www/devel) to the repository. In the terminal, my working directory is /var/www/devel, and I gave the command:  bzr push bzr+ssh://alecwh@bazaar.launchpad.net/~alecwh/phpns/devel , but it doesn't seem to be working. I get the error: bzr: ERROR: Not a branch: /var/www/devel/ , can anyone help me upload19:28
lukscd /var/www/devel; bzr init; bzr add; (check if it added only files you want); bzr commit19:29
luksand then you can use bzr push19:30
lukshttp://doc.bazaar-vcs.org/bzr.0.92/en/mini-tutorial/index.html#putting-files-under-version-control19:30
alecwhok, I'll try that. will 'bzr add' add every single directory and file inside /var/www/devel?19:31
lifelessmoin19:31
alecwhmoin?19:31
lifelessalecwh: yes, add adds recursively, obeying your ignore rules19:35
alecwhthanks lifeless. I've got one more question: when I was using svn, every 'commit' you made actually uploaded your changes to the online repository. Is this not the case with bazaar?19:36
lifelessalecwh: if you have a checkout it acts like svn19:37
alecwha checkout?19:38
lifelessalecwh: that is, if you do 'bzr checkout bzr+ssh://alecwh@bazaar.launchpad.net/~alecwh/phpns/devel local-dir-name'19:38
lifelessthen you can cd local-dir-name, and do19:38
alecwhthat will download the project, right?19:38
lifeless'bzr commit', which will commit back to bzr+ssh://alecwh@bazaar.launchpad.net/~alecwh/phpns/devel, just like svn19:38
alecwhoh.19:38
beunoalecwh, or, when you want to send all your commits, just use "bzr push"19:39
lifelessalecwh: if you have a separate 'branch' though, then your commits are performed just on your machine19:39
alecwhok, that makes sense.19:39
alecwhhttps://code.launchpad.net/~alecwh/phpns/devel19:39
beuno(when using branches instead of checkouts)19:39
alecwhI just finished uploading everything...19:39
lifelessalecwh: and then when you want them to be in bzr+ssh://alecwh@bazaar.launchpad.net/~alecwh/phpns/devel, you do 'bzr push bzr+ssh://alecwh@bazaar.launchpad.net/~alecwh/phpns/devel' (bzr will remember the push location the first time, so you don't need to type it every time019:39
alecwhhow do I make it so every time I 'commit' it will update this repository?19:40
lifelessalecwh: bzr bind bzr+ssh://alecwh@bazaar.launchpad.net/~alecwh/phpns/devel19:40
alecwhok lifeless, that worked. =D19:40
alecwhI was using 'cia.vc', which puts a bot inside your channel on freenode, and then it will post a message inside the channel whenever a commit/change is made. Is there something like this for bazaar?19:41
lifelessalecwh: there is a plugin for bzr to announce to cia19:42
lifelessalecwh: you can also subscribe to the branches on launchpad19:42
lifelessalecwh: or install bzr-email to send emails to arbitrary email address's on commits19:42
alecwhok, cool. Do you know what the plugin was called? I'm just looking for it...19:43
lifelesshttp://www.google.com/search?q=bzr+cia&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:official&client=firefox-a19:44
lifeless3rd and 4th hits look relevant to me19:44
alecwhhttps://launchpad.net/bzr-cia19:46
alecwhlifeless, uhm, how do I get the plugin? =P19:50
beunoalecwh, with bzr, of course  :D19:51
alecwhhttps://code.launchpad.net/~jelmer/bzr-cia/main19:52
alecwhis this the one I'm looking for?19:52
beunoalecwh, yeap19:52
alecwhbzr branch http://bazaar.launchpad.net/~jelmer/bzr-cia/main?19:52
alecwhuse that command?19:52
beunoalecwh, yeah, you download it with that command19:53
alecwhok, done. =D19:53
alecwhI think I got it now19:53
beunonow, follow the instructions in: https://launchpad.net/bzr-cia19:53
=== me_too is now known as too_short
=== too_short is now known as me_too
=== me_too is now known as turbo0O
=== turbo0O is now known as me_too
=== me_too is now known as too_short
=== too_short is now known as me_too
=== adib is now known as theAdib
lifelesssuccess; we have a 1.0 build on dapper-amd6422:17
lifelessi386 testing now22:17
lifelessbrb foodstuff time22:17
=== mwhudson_ is now known as mwhudson
datojelmer: very well22:34
datojelmer: btw, I guess there is no way to convert from svn a trunk and a branch, if I somehow say which revisions from the trunk are merges from the branch, right?22:35
jelmerdato: only if you can go back in history and set some magic svn properties22:40
datojelmer: can I a dump of the repository, load it locally, set the properties there, and redump? that ought to work?22:40
jelmerdato: yes, but you would want to change the uuid22:42
datook. is there a document explaining what properties I should set?22:42
jelmerand pulling from the original in the future may be problematic22:43
jelmerhttp://bazaar-vcs.org/BzrForeignBranches/Subversion/mapping22:43
jelmerbasically, you'd want to set the bzr:ancestry:vX-SCHEME property22:46
lifelessdato: is it really worth doing? why not just do a merge after the conversion?22:47
datojelmer: it's a one-time conversion22:47
datolifeless: I seem to find a strange pleasure fiddling with the tools.22:48
lifelessdato: :)22:49
datojelmer: ok, thanks for the link. I'll try to do it. also, I svn-import trunk didn't work for me yesterday, but the packaged version worked fine. I'll try again tomorrow. finally ;), changing the UUID is just a matter of editing the dumpfile by hand, or?22:53
jelmerdato: the trunk branch for bzr-svn is highly experimental23:08
jelmerdato: 0.4 is the branch that is packaged23:08
jelmerdato: yep, editing the dumpfile should be all that's needed to change the uuid23:09
abentleylifeless: What do you consider a good way to decide if something should be a separate module or not?23:09
abentleyI was expecting plan_merge to be bigger than it is, which is why I originally did it.23:11
lifelessabentley: I don't have a good rule; sometimes I get there and combine; sometimes I start in the same module and split.23:11
vilawtf ? test_revision.TestIsAncestor.test_is_ancestor is failing just under the comment:23:13
vila        # NB: if you see an assertion error here, its probably access against23:13
vila        # an unlocked repo. Naughty.23:13
abentleyI guess by analogy, I'd think if merge3 has its own module, then annotate merge can have one, too.23:13
vilathe problem is I'm working on http response parsing rewrite and I can't find any link >-/23:14
vilaWorse, the same test on bzr.dev@3059 fails too, midnight bug ?23:15
vilaand on top of that, I see (when doing bzr missing in my bzr.dev branch) revno: 3061, deprecate bzrlib.revision.is_ancestor23:16
vilaRan 9939 tests in 437.020s23:18
vilaFAILED (failures=1, known_failure_count=5)23:18
vilabah, time to sleep anyway, a bit frustrating though23:19
vilanot failing anymore in bzr.dev@3065... at least....23:21
lifelessjelmer: where is bzr-gtk for 1.0 ?23:27
lifelessabentley: oh it can have one if you think it should; I was asking the question.23:30
abentleySure, and I've actually decided to move them into versionedfile and merge.23:31
abentleyJust because there's so much related stuff in those modules.23:31
jelmerlifeless: phanatic is doing release management these days, I'll ping him by email23:49

Generated by irclog2html.py 2.7 by Marius Gedminas - find it at mg.pov.lt!