rockstar | jelmer, ping | 00:06 |
---|---|---|
lifeless | spiv: 78->25 | 00:15 |
bignose | lifeless: if you have the bandwitch available, your input on the above questions for loom and quilt would be appreciated | 00:15 |
bignose | s/witch/width/ | 00:15 |
lifeless | bignose: hmm, thought there was a bug open; filing one | 00:16 |
lifeless | I want bzr send to generate a patch series | 00:17 |
lifeless | https://bugs.edge.launchpad.net/bzr-loom/+bug/336470 | 00:19 |
ubottu | Ubuntu bug 336470 in bzr-loom "bzr send should output a patch series (by default, overridable) when used with a loom" [Undecided,New] | 00:19 |
poolie | lifeless: do you have any ideas about bug 336267? | 00:19 |
ubottu | Launchpad bug 336267 in bzr "bzrlib.errors.KnitCorrupt during branching" [Undecided,New] https://launchpad.net/bugs/336267 | 00:19 |
lifeless | poolie: something has mangled the actual error, but from its phrasing I'd guess at zlib | 00:21 |
poolie | yes | 00:21 |
lifeless | poolie: (phrasing and being in the header parsing stage) | 00:21 |
poolie | it seems like a very low-level error to be caused by us | 00:21 |
lifeless | I don't think its a bzr bug, though it might be. I'd instead be expecting bad data | 00:21 |
poolie | i thought so too | 00:21 |
lifeless | its on the client side | 00:22 |
lifeless | and its in the pack repo code | 00:22 |
lifeless | so its using regular vfs methods; and spiv and I haven't done anything nasty to those | 00:22 |
bignose | lifeless: thanks for the response, and the bug report | 00:22 |
lifeless | bignose: the send -r thread:..-1 loop is missing a 'bzr switch next-thread' in it, if you want to reproduce by hand | 00:23 |
bignose | why would I choose ‘send’ over ‘diff’ in this case? | 00:25 |
lifeless | I realise its at my end, but please use plain ascii for this conversation, otherwise I can't read what you are typing. | 00:33 |
lifeless | I saw "why would I choose a over a in this case?" | 00:33 |
fbond | Does anyone here use trac-bzr? Can anyone tell me if it is capable of working with multiple branches? | 00:38 |
fbond | I get the feeling that it is supposed, to, but I'm only able to successfully browse the branch containing the most recent revision. | 00:41 |
bignose | lifeless: why would I choose 'send' over 'diff' in this case? | 00:43 |
lifeless | bignose: if you're submitting to bzr users, use send. If you're submitting to non-bzr users, you can use send or diff | 00:43 |
lifeless | bignose: send includes the revision metadata and any dependent history to allow a normal merge to be done at the far end | 00:44 |
bignose | okay. since in this instance I'm only generating the patch for use with quilt, I'll just use diff. | 00:47 |
greg-g | What is the correct workflow for maintaining two branches of a project with a "dev" and a release branch (eg: 1.0)? Do I commit to dev, then pull that commit from dev to the 1.0 branch somehow? or just commit to both separately (which would have the possibility of non-mergeable branches later, right? I might be wrong with this) | 01:01 |
poolie | greg-g: definitely don't make unrelated commits to both | 01:13 |
poolie | i'd consider having actually a branch per individual release on 1.0 | 01:13 |
poolie | like 1.1, 1.2, etc | 01:13 |
poolie | otherwise, either merge in to 1.0 and then do bzr ci -m "release 1.0.1" | 01:14 |
poolie | or just pull | 01:14 |
poolie | either would work | 01:14 |
greg-g | our 1.0 is the branch that we are going to release as 1.0 when we feel it is ready. basically a "stable" branch | 01:14 |
poolie | the first will be better if you ever need to do little fixes directly in 1.0 to fix packaging bugs for examlpe | 01:14 |
poolie | oh i see | 01:14 |
poolie | so the other thing is, it's generally easier to merge from a more-stable branch into a less-stable | 01:14 |
poolie | than vice versa | 01:15 |
poolie | so i'd consider, for any work that will land in 1.0 | 01:15 |
poolie | doing it in a branch based off 1.0 | 01:15 |
poolie | then merging to 1.0, and then either merging all of that back to trunk, or merging the individual bits | 01:15 |
poolie | this is not so much for technical reasons as just that as the software changes | 01:15 |
poolie | it tends to be easier to update your 1.0 changes to fit other stuff than to backport your fixes | 01:16 |
greg-g | so for things that are more or less self-contained commits, put in 1.0, then merge to dev from there. but what about things that are partially implemented but we want to test with dev? | 01:16 |
poolie | how do you mean partially implemented? | 01:16 |
greg-g | then later, when completed, merge only that feature into 1.0 | 01:16 |
poolie | igc, btw thanks for fixing the status html; what was wrong? | 01:17 |
poolie | igc, also, maybe i should change it to order bzr-dev first? | 01:17 |
poolie | greg-g: ok i think i understand | 01:17 |
poolie | i would: make a branch off 1.0, implement it there | 01:17 |
poolie | and primarily test there | 01:17 |
poolie | if, before you're finished, you also want to check how well it will mesh with dev | 01:17 |
poolie | make *another* branch coming dev, merge your new features in to that | 01:17 |
poolie | then when you're done, you merge those two work branches in to 1.0 and dev respectively | 01:18 |
greg-g | gotcha | 01:18 |
greg-g | would cherrypicking also be an acceptable way to handle that (cherrypick it from dev to 1.0)? | 01:19 |
greg-g | I saw there was something about bzr not tracking cherrypicked revisions. I'm too knew to understand where that will have an adverse effect in the future. | 01:21 |
igc | poolie: status html? you mean the colouring? | 01:23 |
igc | poolie: I think the first tool ought to be bzr-current, i.e. the currently released version | 01:24 |
igc | bzr.dev ought to be compared to that | 01:24 |
igc | poolie: I'm not sure looking at earlier versions (before bzr-current) buys much | 01:24 |
igc | poolie: the 3 interesting versions IMO are bzr-current bzr-dev bzr-brisbane | 01:25 |
igc | lifeless: bzr selftest groupcompress is failing because ... | 01:26 |
igc | 1. I haven't compiled the groupcompress_c stuff using pyrex | 01:27 |
igc | 2. some other issue | 01:27 |
igc | lifeless: it looks like the tests are *meant* to skip ... | 01:27 |
igc | the compiled tests if the compiled stuff isn't there? | 01:27 |
spiv | no | 01:28 |
igc | I wonder if setUp() happens before tests_needs_feature? | 01:28 |
spiv | (^ that was <lifeless>) | 01:28 |
* spiv & lifeless -> food | 01:28 | |
lifeless | igc: possibly; for now, just build them :) | 01:48 |
poolie | igc, i was thinking bzr-dev first because that's what we're more likely to change for good or ill | 01:52 |
poolie | also i should check current is in fact current now :) | 01:52 |
lifeless | as we have a current now, that should be easier to maintain :) | 01:54 |
lifeless | greg-g: the adverse effect is fairly small and isolated. Its two things: | 01:54 |
lifeless | - you can't use bzr to report 'what has been cherrypicked' | 01:54 |
lifeless | - you may get spurious conflicts on subsequent merges if you change the line of code further | 01:55 |
poolie | greg-g: what robert says is correct, but it's not so much about bzr capabilities | 01:55 |
poolie | more that it's actually easier for you to write it in 90% of cases if you do not cherrypick | 01:55 |
poolie | but keep it separate to start with | 01:55 |
greg-g | lifeless / poolie thanks! I think I've got it figured out now. | 01:58 |
lifeless | greg-g: anytime | 01:59 |
mwhudson | poolie, spiv: could one of you make the tweaks you ask for for my "LockableFiles.__del__ must die" as you land it? | 02:11 |
poolie | no promises but i'll try | 02:11 |
mwhudson | thanks | 02:12 |
lifeless | jam: ping | 02:21 |
poolie | abentley: BB is down | 02:32 |
abentley | poolie: restarted | 02:34 |
poolie | thanks | 02:35 |
* igc food | 02:55 | |
lmiller | Hi | 03:59 |
=== abentley1 is now known as abentley | ||
poolie | gar too much mail | 04:21 |
fullermd | I have some ideas on how to handle that. I'll send you an email about it... | 04:22 |
contingencyplan | Have a question for you guy, if anybody's around: | 04:26 |
contingencyplan | I'm currently using mercurial, but I've hit a brick wall, so seeing if bazaar can handle this better. | 04:26 |
contingencyplan | I have a repository with a subdirectory in it with code. When I started making the repository, I was the only one using it, so that was fine, but now I'm in another project that also needs that code. | 04:27 |
contingencyplan | How easy is it to have 2 bazaar repositories that share a common code-base? Ideally, I want that common code-base to be transparent to each repository - for my private repository, it looks and acts just like it always has, for the new repository there's no apparent difference whether it's in that repository or stored elsewhere. | 04:28 |
contingencyplan | (sorry for the lengthy msg there) | 04:28 |
lifeless | contingencyplan: there is a merge-into plugin that can join the two brances | 04:29 |
lmiller | Anyone know how to get the bzrbuildbot plugin working with a central bzr repository? | 04:39 |
lmiller | From what I can tell, each user needs to put it in their own plugins dir | 04:39 |
* igc bbiab | 04:42 | |
lifeless | lmiller: what hook does it use? | 04:46 |
lmiller | on change | 04:47 |
lmiller | post_change_branch_tip I believe | 04:48 |
lifeless | lmiller: that will run on the server | 04:50 |
lifeless | lmiller: as long as you're pushing with bzr 1.6 or so, and over bzr+ssh, not sftp or webdav. | 04:51 |
lmiller | lifeless: It requires a location.conf file, but I don't seem to have anywhere to place it on the server | 04:51 |
lmiller | where the server will find it I mean | 04:51 |
lifeless | lmiller: you can configure the same settings in branch.conf | 04:52 |
lifeless | in the branch you want to test | 04:52 |
lmiller | So, if I wanted to trigger the main branch, I would edit branch.conf inside the repos (eg /repos/main/proj/.bzr/branch/ )? | 04:53 |
lmiller | I'm coming from svn, so excuse me if I ask nervously about editing files inside the repository ... heh heh | 04:54 |
lifeless | yah, repos/main/proj/.bzr/branch/branch.conf, if your branch is bzr+ssh://host/repos/main/proj | 04:54 |
lifeless | its not ideal, we want a better answer here, but it will work :) | 04:54 |
lmiller | exceptions.NameError: global name 'failure' is not defined | 05:36 |
lmiller | Ah, I love programming | 05:36 |
lifeless | :P | 05:37 |
=== chx is now known as chx_sleeping | ||
mwhudson | flymake-mode ftw | 05:48 |
jml | so, it looks like bzr-svn really really really wants more than 360MB of RAM | 05:52 |
lmiller | lifeless: Thanks for that ... all working now | 05:57 |
lifeless | lmiller: cool | 06:25 |
vila | Hi all ! :-) | 07:33 |
fullermd | Wow, that's way too chipper. You obviously have coffee you need to share... | 07:35 |
vila | fullermd: hehe, no, same coffee as usual, but some days are better than others, just from the start (the opposite is also true...) | 07:40 |
poolie | vila: hello, welcome! | 08:09 |
* igc dinner | 08:16 | |
vila | poolie: thanks :) | 08:18 |
poolie | vila, want to talk? | 08:23 |
vila | poolie: with pleasure | 08:23 |
poolie | could you call me here then? | 08:24 |
vila | sure | 08:25 |
lifeless | ok, stream branching collection of patches all landed | 09:07 |
lifeless | tomorrow, streaming from stacked | 09:07 |
poolie | hi | 09:12 |
poolie | way to go | 09:12 |
poolie | vila, does bug 336582 look familar to you at all? | 09:22 |
ubottu | Launchpad bug 336582 in bzr "test hang in TestStackingConnections.test_open_stacked" [Undecided,New] https://launchpad.net/bugs/336582 | 09:22 |
vila | poolie: didn't Andrew mention that on the list today ? | 09:23 |
poolie | it sounded familiar somehow | 09:24 |
vila | poolie: hmm, he mentioned hpss not sftp though | 09:24 |
spiv | vila: yeah, my patch wouldn't affect sftp | 09:29 |
poolie | tired -> good night all | 09:30 |
spiv | Weird that the traceback involves SFTP, but the test doesn't run at all if FTPServer is missing. | 09:31 |
spiv | I suspect the test is not granular enough... | 09:32 |
lifeless | gnight poolie | 09:33 |
lifeless | igc: ping | 10:43 |
igc | hi lifeless | 10:44 |
lifeless | so I've replied to your mail | 10:45 |
lifeless | short story though is that you need to be digging deeper, and I'd like to help you do that | 10:45 |
* igc reads email | 10:47 | |
igc | lifeless: thanks. I've got to run right now - might be back later | 10:49 |
lifeless | igc: ok, well I may be up; if I am, skype will know :P | 10:49 |
lifeless | igc: and if so, chat/call me on skype, I doubt I'll have irc in front of me | 10:52 |
=== montywi|poker is now known as montywi | ||
igc | lifeless: still there? | 10:57 |
lifeless | yes | 10:57 |
igc | so no fast path is running | 10:57 |
igc | in log -v currently | 10:57 |
lifeless | well then :P | 10:58 |
igc | what routine are you thinking of? | 10:58 |
lifeless | CHKInventory._make_delta(aCHKInventory) | 10:58 |
lifeless | line 1709 in my copy of inventory.py | 10:58 |
lifeless | if you're not hitting that, then you're not seeing CHK delta generation, and it will blow chunks. | 10:59 |
lifeless | if you are seeing that, you're at least getting some of the work done by the CHK core | 10:59 |
* igc pulls up profiling data | 11:00 | |
lifeless | but unless you have an lsprof run, its going to be very hard to tell whats going on :) | 11:00 |
igc | lifeless: 77% of time in iter_changes() - inventory.py line 1655 | 11:01 |
igc | no calls to make_delta | 11:02 |
lifeless | ok | 11:02 |
lifeless | thats the CHKInventory fast path | 11:02 |
lifeless | so, I'd look at what its doing | 11:02 |
lifeless | (or it should be - is it CHKInventory.iter_changes?) | 11:03 |
igc | lifeless: oh, I know what's its doing ... | 11:03 |
igc | reo.get_delta_for_revisions() builds trees and calls tree.changes_from() -> delta._compare_trees -> iter_changes | 11:03 |
igc | s/reo/repo/ | 11:03 |
igc | lifeless: yes, CHKInventory.iter_changes() | 11:04 |
lifeless | ok, that all seems normal | 11:05 |
lifeless | so we're looking at the right code path | 11:05 |
lifeless | now, it may be doing duplicate work | 11:06 |
lifeless | it may be discarding one side of the trees, or things may not be getting kept in ram once loaded | 11:06 |
lifeless | I'd be inclined to instrument | 11:06 |
lifeless | finding duplicate CHK page reads, for instance | 11:06 |
lifeless | a cheap way of detecting this | 11:06 |
lifeless | is too look in the call graph | 11:06 |
lifeless | if you're doing (say) a 100 revision range | 11:06 |
lifeless | and you see 1M get_record_stream calls | 11:07 |
lifeless | then something suspect is going on | 11:07 |
lifeless | remember that there is nearly _no_ optimisation in here at the moment | 11:07 |
lifeless | assume that the core data structures are decent - John is tuning them, and they have passed all our design checks along the way | 11:07 |
igc | lifeless: ok, so 1000 revisions -> 15830 get_record_streams calls in groupcompress | 11:08 |
lifeless | 15 pages per revision | 11:08 |
lifeless | what project? | 11:08 |
igc | first 1k revisions of wordpress | 11:09 |
lifeless | how big is wordpress, files in the tree | 11:09 |
igc | lifeless: small, 142 files | 11:11 |
lifeless | so | 11:11 |
lifeless | we expect | 11:12 |
lifeless | 1 read to get the inventory, 1 to get the root of the dir map, 1 to get the root of the inventory entry map | 11:12 |
lifeless | (roughly) | 11:12 |
lifeless | so we can explain 3K reads | 11:12 |
lifeless | that leaves 12K reads to calculate the differences, but 142 entries isn't many | 11:13 |
lifeless | to get 15 reads per diff, I'd expect more files or many very large changes | 11:14 |
lifeless | so - I suggest using my patch for VersionedFileDecorator to whip up a little LoggingVersionedFile | 11:14 |
lifeless | and decorate the chk versioned file object on the repository | 11:14 |
lifeless | then dump the log to disk after the operation, and we can look for repeated requests | 11:15 |
igc | lifeless: interesting | 11:15 |
lifeless | you only need to care about get_record_stream, and the keys parameter | 11:15 |
lifeless | an interesting test would be diffing one revision | 11:16 |
lifeless | log -v 1..2 | 11:16 |
igc | yes | 11:16 |
lifeless | for instance | 11:16 |
igc | lifeless:I'll start digging deeper - thanks for your help | 11:16 |
lifeless | my pleasure | 11:17 |
lifeless | I'm oing to play computer games for a bit | 11:17 |
lifeless | I'll check back in a while | 11:17 |
djr | Is there anyone around who understands how to install from source (bzr-*.tar.gz) on linux, please? | 12:12 |
_MMA_ | Ok. So it's 8hrs later and a upload to a branch I was working on is still locked. "bzr break-lock" does nothing and the recommended command to use when it tells me the branch is locked tells me: "bzr: ERROR: Unsupported protocol for url "lp-45955728:///~ubuntustudio-dev/ubuntustudio-icon-theme/UbuntuStudio/.bzr/repository/lock" | 12:15 |
djr | Installing bzr from source is supposed to require only Python, right? So why does it fail trying to run gcc? | 12:18 |
lifeless | _MMA_: "bzr break-lock lp:~ubuntustudio-dev/ubuntustudio-icon-theme/UbuntuStudio" | 12:18 |
lifeless | djr: it tries to build the C accelerators, if you don't have them then you can still just run from source | 12:18 |
lifeless | djr: but we recommend building them, it makes a big performance difference | 12:19 |
=== UdontKnow is now known as root | ||
_MMA_ | lifeless: Thanx man. I don't know whether I should file a bug. The suggestion it gives seems wrong. | 12:20 |
lifeless | _MMA_: there is one about the url it gives being bad,and another that we should auto-break in some situations | 12:21 |
_MMA_ | Ok. I'll just hope it resolves itself. ;) | 12:22 |
_MMA_ | lifeless: Maybe you can tell about one more. I have a bunch of older branches. So I'll get the "please use 'bzr upgrade' to get better performance" warning from time to time. So, I do. But then when going to upload after that, after upgrading, I get the warning again. Am I missing something? | 12:25 |
lifeless | _MMA_: you need to upgrade each instance - so you need to upgrade where you are pushing to | 12:26 |
lifeless | there is a bug/limitation in upgrade at the moment with launchpad; you need to use 'bzr upgrade sftp://bazaar.launchpad.net/~ubuntustudio-dev/ubuntustudio-icon-theme/UbuntuStudio' rather than 'bzr upgrade lp:~ubuntustudio-dev/ubuntustudio-icon-theme/UbuntuStudio' | 12:27 |
_MMA_ | lifeless: Oh sure sure. Each branch. I didn't mean to imply that I wanted to do it once and it would be fixed for all. | 12:28 |
lifeless | :) | 12:28 |
_MMA_ | I will upgrade a branch. Then on same branch, get the warning again. | 12:29 |
lifeless | _MMA_: do you have a shared repo? | 12:29 |
_MMA_ | ~ubuntustudio-dev's yeah. | 12:30 |
lifeless | on your laptop/workstation I mean | 12:30 |
lifeless | launchpad doesn't have shared repos | 12:30 |
_MMA_ | Oh Oh. ie: 2 machines that work on network shared folder? | 12:31 |
_MMA_ | Both have access to some BZR work Im doing? | 12:32 |
lifeless | _MMA_: no, its a specific term in bzr, a 'shared repository', created by 'bzr init-repo' | 12:32 |
_MMA_ | Ok. I remember now. No. | 12:32 |
lifeless | _MMA_: please run 'bzr info -v' on a branch where you are having this happen | 12:32 |
_MMA_ | Gotcha | 12:32 |
lifeless | if you pastebin the output the next time it warns, I'd be delighted to help you | 12:35 |
_MMA_ | lifeless: I'll be doing some more work later so Ill be sure to if it happens again. | 12:36 |
lifeless | djr: its possible we have a setup.py regression with installing without the extensions; if thats the case, please file a bug | 12:36 |
lifeless | djr: you can run bzr from source without installing it, as a work around - just symlink 'bzr' into your path, or add the source dir to your path | 12:37 |
_MMA_ | lifeless: So when I run "bzr upgrade" it makes a "backup.bzr" folder. After doing "bzr add" it added that folder and now I look to be uploading that content. Can I either *not* create that backup or delete "backup.bzr" later? | 12:37 |
lifeless | you can't avoid the backup; just rm -rf backup.bzr once you've done the upgrade in a given branch | 12:37 |
_MMA_ | lifeless: After or before a push to LP? | 12:38 |
_MMA_ | Oh I see. | 12:38 |
lifeless | before you next commit ;) | 12:38 |
lifeless | if you've committed it, just uncommit | 12:39 |
_MMA_ | Well I did. :( So now I've been sitting at: "[\ ] Transferring:Walking content. 1/1" since I broke the lock. | 12:40 |
lifeless | igc: deeper still :) | 12:44 |
igc | lifeless: in the morning, when I'm awake :-) | 12:45 |
lifeless | igc: sure | 12:45 |
lifeless | igc: are you starting to see the shape of the intent ? | 12:45 |
LarstiQ | beuno: do you know if loggerhead is supposed to generate relative links, instead of hardcoding the hostname in the href? | 12:46 |
igc | lifeless: I think so. just saw your reply ... | 12:46 |
igc | the root would change for a read-centric operation like log though | 12:47 |
igc | s/would/won't/ | 12:47 |
lifeless | igc: Nodes are immutable, so they will never change after being written; | 12:47 |
lifeless | igc: however the root will be different for every inventory unless the inventories are identical | 12:47 |
igc | sure | 12:48 |
lifeless | igc: so for log, we should be reusing the tree - first as child then as parent | 12:48 |
igc | lifeless: we do reuse the trees at the repo level *but* the code for iter_changes (tree.py line 928) always calls through to CHKInventory.iter_changes() | 12:54 |
lifeless | igc: right, that should be fine | 12:55 |
lifeless | oh, the variables you asked about, I was looking in inventory.py | 12:55 |
lifeless | I'll reply again tomorrow after I page this in | 12:56 |
lifeless | igc: _get_node would seem to be buggy, as it notes: does not update | 12:56 |
lifeless | igc: fixing that to actually update the items dict may be useful :) | 12:57 |
igc | :-) | 12:57 |
lifeless | igc: all the same | 12:57 |
lifeless | it kindof assumes that the differences from treeA to treeB will be similar to treeB to treeC | 12:58 |
lifeless | for that to matter | 12:58 |
lifeless | CHKMap is the code to own though | 12:58 |
lifeless | its the driving abstraction | 12:58 |
lifeless | gnight! | 12:58 |
igc | night (and thanks) | 12:58 |
LarstiQ | beuno: it seems loggerhead.apps.branch.url: request.construct_url(...) includes the hostname, so that is one piece were it is already broken | 12:59 |
LarstiQ | beuno: (for my use case at least, maybe there is a reason for this?) | 12:59 |
_MMA_ | lifeless: http://paste.ubuntu.com/125256 | 12:59 |
beuno | LarstiQ, old versions of paste/patedeploy? | 13:01 |
LarstiQ | beuno: python-paste 1.6, python-pastedeploy 1.3.1 | 13:01 |
beuno | hrm, that seems correct | 13:02 |
LarstiQ | let me make sure I'm using loggerhead trunk | 13:03 |
LarstiQ | beuno: yeah, lp:loggerhead 288 | 13:04 |
beuno | LarstiQ, it does use absolute URLs, but it should be generating them properly | 13:05 |
beuno | you've got apache setup properly, etc? | 13:05 |
LarstiQ | beuno: well, how does it generate them? | 13:06 |
beuno | LarstiQ, based on what apache tells it through pastedeploy | 13:06 |
beuno | there's some stuff in the README about it | 13:06 |
beuno | did you follow that? | 13:06 |
LarstiQ | beuno: my situation is (outerhost:4443 -> innerhost:80 -> localhost:8080) | 13:07 |
* LarstiQ needs to look at how pastedeploy works then | 13:07 | |
LarstiQ | beuno: the README.txt is very thin, but yeah I've got a ProxyPass setup like that. | 13:09 |
beuno | LarstiQ, hrm... I don't really know. It's all mwhudson's magic | 13:09 |
LarstiQ | beuno: k, I'll go bother him then (and in fact already have a thread at bugs.launchpad.net) | 13:10 |
LarstiQ | beuno: thanks :) | 13:10 |
igc | night all | 13:11 |
LarstiQ | night igc | 13:11 |
djr | about installing bzr on linux, again. In the absence of gcc, once I have unpacked the tar.gz, what do I do? the InstallationFaq says link to ~bzr/bzr.dev/bzr, but I don't have that file/directory. | 13:18 |
djr | Is the bzr executable in the archive all I need? | 13:19 |
james_w | djr: if you just run ./bzr from the unpacked source it should work | 13:20 |
djr | Indeed it does. I wasn't sure if maybe it was an illusion and wasn't working properly. Could someone who understands these things refresh InstallationFaq on the wiki? | 13:22 |
LarstiQ | beuno: fwiw, I stuck in: relative_url = urlparse.urlunparse(('', '') + urlparse.urlparse(absolute_url)[2:]) | 13:27 |
LarstiQ | beuno: and now it works, I'll followup with mwhudson | 13:28 |
beuno | LarstiQ, ah, cool. Thanks :) | 13:28 |
LarstiQ | beuno: that does destroy the 'To get this branch, use bzr branch /loggerhead' bla, but ah well | 13:31 |
beuno | LarstiQ, right. We're very bad with URLs in LH | 13:31 |
=== barry-away is now known as barry | ||
_MMA_ | lifeless: Man. "bzr upgrade" has never worked for me. :( I puled the branch new. (gave me the upgrade warning) Did "bzr upgrade" and removed "backup.bzr". Made a minor edit then committed/pushed to LP. Gave me the "bzr upgrade" warning again. :( | 14:08 |
awilkins | djr: It will work out of the archive, but there are some parts that can be compiled to give more performance | 14:09 |
Kinnison | _MMA_: It may be warning about the branch on LP | 14:09 |
djr | awilkins: following the wiki seems to violate Principle of Least Surprise. It says 'all you need is Python', but by default tries to invoke gcc, and gives no guidance on how to proceed once it has failed. | 14:13 |
_MMA_ | lifeless: Current output of "bzr info -v ": http://paste.ubuntu.com/125281 | 14:13 |
LarstiQ | _MMA_: that sounds like the _remote_ branch needs to be upgraded | 14:20 |
_MMA_ | LarstiQ: Ahh.. Maybe that's what I'm hitting with alot of my branches. Is that something *I* can do? | 14:21 |
=== chx_sleeping is now known as chx | ||
LarstiQ | _MMA_: ie, `bzr upgrade sftp://bazaar.launchpad.net/~ubuntustudio-dev/ubuntustudio-icon-theme/UbuntuStudio` | 14:22 |
LarstiQ | _MMA_: yes | 14:22 |
_MMA_ | Ah... | 14:22 |
* _MMA_ tries. | 14:22 | |
jam | lifeless: pong (if you are still awake) | 14:26 |
_MMA_ | LarstiQ: That looks like it. Thanx man. | 14:27 |
* _MMA_ goes to upgrade all his branches. | 14:28 | |
LarstiQ | _MMA_: glad I could help | 14:30 |
jam | djr: doesn't it tell you that you can use "build_ext --allow-python-fallback" ? | 14:32 |
Lo-lan-do | Hi all | 14:35 |
Lo-lan-do | I'm having a strange error with bzr-rebase... http://pastebin.com/df38d43c | 14:37 |
Lo-lan-do | It tells me my tree is out of date although it isn't. | 14:38 |
djr | jam: no it doesn't. there is a long an noisy traceback that concludes "log.warn('\n Cannot build extensions.\n' TypeError: not all arguments converted during string formatting | 14:59 |
jam | djr: ok, our warning code has a typo in it. :( | 14:59 |
djr | to (mis)quote Etienne "I tried bzr once. It failed to install!" | 15:00 |
jam | Looking closer, it is the code trying to tell you '--allow-python-fallback', but it falls over at that time. | 15:01 |
jam | I'll make sure that is fixed for the next release | 15:01 |
djr | is that an additional option to 'setup.py install' ? | 15:01 |
djr | A: no, it's not an option that INSTALL recognises | 15:04 |
jam | djr: it is 'python setup.py install build_ext --allow-python-fallback' | 15:04 |
asabil | hi all | 15:11 |
asabil | it seems like bzr doesn't display a progress bar anymore when ran from inside a script | 15:12 |
asabil | (for example from inside jhbuild) | 15:12 |
asabil | is this a known issue ? | 15:12 |
jam | asabil: there have been some reports of the progress bar disappearing on win32, but I haven't heard anything about scripts | 15:13 |
jam | it may be the same root cause, though | 15:13 |
asabil | hmm ok | 15:14 |
jam | it is possible that the code figuring out the 'terminal width' is somehow getting a width of 0 | 15:15 |
jam | or some other strang ebit | 15:15 |
jelmer | jam, it may be related to that | 15:16 |
jelmer | progress bars aren't resized for me anymore | 15:16 |
jelmer | they always stay small | 15:16 |
jam | jelmer: well we don't continually poll | 15:16 |
jam | we used to check on every update, I think | 15:16 |
jam | which isn't great either | 15:16 |
jam | the code has a comment about SIGWINCH | 15:16 |
djr | jam: thanks John, that's done the trick. I think that's a documentation fix as well as a code fix required? Or why not enable fallback by default, so that the first-time would-be user gets a working install even if not an optimum one? | 15:16 |
jam | but I don't see anything that uses a null progress bar anywhere | 15:16 |
jelmer | jam, well, they even stay small if I resize my terminal window *before* starting bzr | 15:17 |
jam | djr: because first-time users should know that they aren't getting an optimum one | 15:17 |
jelmer | jam, that used to work ok with the previous progress bars | 15:17 |
djr | jam: if you've triggered the fallback path you could tell them | 15:18 |
jam | jelmer: we never resize the progress bar itself | 15:18 |
jam | which is intentional | 15:18 |
jam | we *do* write more text off to the right | 15:18 |
jelmer | ah, ok | 15:18 |
jam | vila: are you around? | 15:20 |
jam | (bbiab, changing network connections) | 15:20 |
jam | ok, back | 15:22 |
LarstiQ | jelmer: you want me to file a new bug, and then you can mark it as dupe if that happens to be the case, right? | 15:22 |
jelmer | LarstiQ, please | 15:23 |
vila | jam: yup | 15:23 |
LarstiQ | jelmer: done | 15:30 |
oubiwann | spiv (or anyone else): got a question for you | 15:47 |
oubiwann | is there any way to move/copy/import code from a completely separate branch into a subdirectory of a different codebase and preserve the revision history of the original? | 15:47 |
=== rocky1 is now known as rocky | ||
radix | oubiwann: yes | 15:54 |
radix | with a plugin I think | 15:54 |
radix | The word "join" is floating through my head | 15:54 |
oubiwann | radix: awesome -- I'll google-dig and see what I can find, thanks :-) | 15:54 |
jam | oubiwann: lp:bzr-merge-into | 15:56 |
jam | should get you going | 15:56 |
jam | or https://edge.launchpad.net/bzr-merge-into if you want a bit more info | 15:56 |
oubiwann | jam: thanks! | 15:57 |
radix | okay I guess I was wrong about join :) | 15:57 |
jam | radix: join works, but only in rich-root trees, etc, etc. | 15:57 |
jam | we're getting there :) | 15:57 |
radix | ah :) | 15:57 |
jam | jelmer: quick question about samba | 16:06 |
jam | I have a fairly old samba server running, and for some reason when I mount it, I can see the directories just fine | 16:06 |
jam | but if I try to read any *file* it aborts with a READ ERROR | 16:06 |
jam | Errno 13, Permission Denied (it would seem) | 16:06 |
jelmer | jam, how old is fairly old? | 16:06 |
jam | jelmer: 3.0.23a-1.fc4.1 | 16:07 |
jam | what is weird | 16:07 |
jam | is that it mounts just fine on my Vista machine | 16:07 |
jelmer | jam, doesn't sound familiar | 16:07 |
jelmer | jam, and on the client side? | 16:07 |
jam | $ smbclient --version | 16:08 |
jam | Version 3.0.28a | 16:08 |
jelmer | jam, The kernel version I mean | 16:09 |
jelmer | jam, (since the kernel module is not actually part of Samba) | 16:09 |
jam | client is Hardy, server is FC4 | 16:09 |
jam | 2.6.24-23-generic | 16:09 |
jelmer | hmm, that should work quite well | 16:10 |
jelmer | jam: are you using smbfs or cifsfs? | 16:10 |
jelmer | if you're not using cifsfs yet, you may want to give that a try | 16:10 |
jam | i'm guessing my FC4 server won't have cifsfs | 16:10 |
jam | but my client *is* using cifs | 16:11 |
jelmer | jam: It's the client for which it should matter | 16:11 |
jam | //192.168.2.10/jameinel on /home/jameinel/juju type cifs (rw,mand,nosuid,nodev,user=jameinel) | 16:11 |
jam | //192.168.2.10/jameinel on /home/jameinel/juju type cifs (rw,mand) | 16:11 |
jam | according to mount | 16:11 |
jam | why would there be 2 entries? | 16:11 |
jelmer | as the server doesn't need any kernel stuff | 16:11 |
jelmer | there shouldn't be two entries | 16:11 |
jelmer | jam, that may be the source of the problems | 16:12 |
jam | jelmer: well, after 1 umount, I have a single entry, but then it does: | 16:12 |
jam | $ sudo umount /home/jameinel/juju | 16:12 |
jam | This utility only unmounts cifs filesystems. | 16:12 |
jam | This utility only unmounts cifs filesystems. | 16:12 |
loffe | How can I "bzr upload" with some uncommited changes? | 16:12 |
loffe | To be clear: I want to upload the last commited revision, w/o working changes... | 16:13 |
jam | loffe: 'bzr shelve; bzr upload; bzr unshelve' ? | 16:13 |
james_w | "bzr upload -r -1"? | 16:13 |
jam | jelmer: any idea of how to get it to unmount via something other than 'umount'? | 16:14 |
jelmer | jam: Well, umount.cifs but I think that's also what umount is invoking under the hood | 16:14 |
jam | jelmer: yeah, that gives the same error | 16:14 |
jam | as does 'smbumount' | 16:15 |
jam | though those only give the error 1 time | 16:15 |
jam | while 'umount' gives it twice | 16:15 |
vila | loffe: both suggestion by james_w and jam should work, file a bug if it doesn't | 16:15 |
loffe | jam, james_w thanks, -r did it. However shelve loks like a nice command | 16:15 |
jam | umount -f doesn't work either | 16:15 |
jelmer | jam: no idea then, sorry :-/ | 16:16 |
jelmer | jam, The duplicate mount doesn't seem right to me though | 16:16 |
jam | -f, -n, -l, all der-br0ken | 16:16 |
jam | all say that they can only unmount a cifs filesystem | 16:16 |
jam | and mount certainly thinks that is what I have | 16:16 |
jam | note that there are *no files* if I do "ls mounted/path" | 16:17 |
jam | so there isn't a real mount there | 16:17 |
jam | just something claiming that there is... :( | 16:17 |
jam | jelmer: could there be a UID mapping issue? | 16:18 |
jam | that 'jameinel' on the local machine versus the remote machine is causing problems? | 16:19 |
jelmer | jam: all files will be accessed as the user with which you did the mount | 16:19 |
jam | (I ended up manually removing the line from mtab, and things are a bit nicer now) | 16:19 |
jelmer | and it will also do local access checking | 16:19 |
jelmer | if you have unix extensions enabled in the server, it should just use the same uids the server has | 16:19 |
jam | so the uids *are* different | 16:20 |
jam | 502 == jameinel on the server, 1000 == jameinel locally | 16:20 |
jam | though ls seems to say everything is 'jameinel.jameinel' | 16:21 |
jam | oh well, I guess I'll try repacking over sftp then | 16:25 |
=== bob2 is now known as Guest98584 | ||
jam | ah, but that fails because it tries to read approx 2GB in one pass... | 16:30 |
jelmer | jam: so if you're the only one using the remote server over smb from unix, you can disable the unix extensions | 16:31 |
jelmer | jam: and you should be able to specify a uid= option to mount to indicate what user should appear to own all remote files | 16:32 |
jam | jelmer: I'd be happy to do so, if I knew how to turn them on/off in the first place | 16:32 |
jam | jelmer: I tried uid= and it still failed | 16:32 |
jelmer | jam, "unix extensions = no" in smb.conf on the server side | 16:32 |
jelmer | jam, uid= is ignored if the server has unix extensions enabled | 16:32 |
jam | hmm.. I guess I'll try that | 16:32 |
jam | jelmer: so setting 'unix extensions = no' changed the default file/dir permissions, which seems correct | 16:39 |
jam | setting them manually via the -ofile_mode=XXX sets them as I would expect | 16:39 |
jam | but I still can't read anything | 16:39 |
jelmer | jam, did you override the uid=? | 16:41 |
jam | jelmer: yep | 16:41 |
jelmer | hmm, no idea then - sorry :-( | 16:41 |
jelmer | It's probably a cifsfs bug, but no idea what specifically | 16:42 |
jam | jelmer: I see this in the client's /var/log/message: Mar 2 10:39:45 liliana kernel: [1105324.900870] Status code returned 0xc0000022 NT_STATUS_ACCESS_DENIED | 16:43 |
jelmer | jam, that would suggest the server refusing the operation | 16:44 |
jelmer | jam, can you read these files with a windows machine? | 16:44 |
jam | jelmer: yep | 16:45 |
jam | from Vista | 16:45 |
jam | (I'll note that when I started accessing this share from Vista, it seemed to break mounting via Linux) | 16:45 |
jam | I don't know if that is relevant at all | 16:46 |
jelmer | jam, the vista machine may have a lock open at the moment? | 16:48 |
jelmer | jam, samba will enforce windows-like locks across clients, which are mandatory not advisory | 16:49 |
jam | jelmer: different files | 16:49 |
jam | but on the same fs | 16:49 |
jam | I can't read *any* files via linux | 16:49 |
jam | I can see the directory listing, etc | 16:49 |
jam | but when I go to 'cat foo' it gives me a perm error | 16:49 |
jelmer | hmm, still no idea then | 16:49 |
jam | does 'mount' list the options that you supply when doing 'smbmount', because I'm supplying a lot that I don't see | 16:51 |
jelmer | jam, no, it doesn't list them | 16:51 |
jelmer | jam, man mount.cifs should | 16:51 |
jam | no luck | 17:00 |
jam | and certainly I can supply what are obviously wrong parameters | 17:00 |
jam | and nothing complains | 17:00 |
jam | at least not right away | 17:00 |
=== root is now known as UdontKnow | ||
LarstiQ | jelmer: hmm, I get the impression my bug mail is slower than your bugmail | 17:23 |
=== montywi is now known as montywi|food | ||
=== thekorn_ is now known as thekorn | ||
lifeless | jam: hi | 19:59 |
jam | hi lifeless, you're up early :) | 19:59 |
lifeless | 7am, not so early :P | 19:59 |
=== beuno_ is now known as beuno | ||
lifeless | jam: igc: was having trouble with gc | 20:03 |
lifeless | jam: did you see the bug | 20:03 |
jam | I saw one which has an obvious fix | 20:03 |
jam | something about None not being sortable | 20:03 |
lifeless | None is not indexable? | 20:03 |
jam | yeah | 20:03 |
lifeless | jam: is that fixed? | 20:08 |
jam | lifeless: fix just committed, thanks for the reminder | 20:08 |
lifeless | jam: jinx :) thanks | 20:08 |
lifeless | jam: so, I'd like to have a copy of python in gcrchk255 | 20:09 |
jam | well, gcr is undergoing a lot of flux right now | 20:17 |
jam | but I'm willing to kick of a conversion to have a data point to talk about | 20:17 |
lifeless | jam: not to give them so much as to say, look, this is what we're polishing at the moment | 20:17 |
jam | I suppose the other thing is that I haven't been making the -rich-root variants yet, as I already have too many variants | 20:18 |
jam | but that, again, is easy to fix | 20:18 |
jam | ultimately, I'd certainly rather have rich-root as the default variant | 20:20 |
lifeless | jam: does https://code.edge.launchpad.net/~bzr/bzr-groupcompress/trunk have gcr? or just whats still suitable for bbc ? | 20:20 |
jam | lifeless: trunk does not have gcr | 20:20 |
jam | I'll push up a branch, though | 20:20 |
lifeless | jam: I can't promise to look at it :P. | 20:21 |
jam | lifeless: what is your feeling about disk compatibility | 20:21 |
jam | that's fine | 20:21 |
jam | I'm just trying to decide whether I should leave all-new format strings | 20:21 |
jam | or whether we should somehow support both for a hile | 20:21 |
jam | while | 20:21 |
lifeless | its easy to twiddle them | 20:22 |
lifeless | I do not care about backwards compatibility for repo formats in bbc/gc | 20:22 |
lifeless | they are both entirely experimental | 20:22 |
lifeless | as opposed to beta like devX formats in trunk | 20:22 |
jam | lifeless: lp:~bzr/bzr-groupcompress/rabin for now | 20:24 |
lifeless | jam: so the rabin index extension | 20:29 |
lifeless | jam: you're having some trouble with that? | 20:30 |
jam | I have it working for now. | 20:30 |
jam | Just by using multiple indexes | 20:30 |
jam | I know how to combine them | 20:30 |
lifeless | right | 20:30 |
jam | but this ended up easier to implement | 20:30 |
lifeless | thats how gc started | 20:30 |
lifeless | oh | 20:30 |
lifeless | I see, nice | 20:30 |
=== montywi|food is now known as montywi | ||
dlee | Any chance there's a bzr<-->MediaWiki versioning solution, much like we have for Bzr<-->Subversion? | 20:47 |
poolie | hello all, | 21:02 |
poolie | hello jam | 21:02 |
lifeless | hi | 21:02 |
jam | morning poolie | 21:02 |
poolie | jam, want to talk in 5m? | 21:02 |
jam | poolie: sure, you can call my cell phone, I have to go pick up my wife at the train station | 21:03 |
poolie | sure | 21:03 |
lifeless | jam: btw, streaming pull is landed to now, at least the first cut thereof | 21:06 |
kees | /home/kees/.bazaar/plugins/hooks/__init__.py:20: DeprecationWarning: bzrlib.branch.BranchHooks.install_hook was deprecated in version 1.5. | 21:06 |
kees | what should I be using instead? | 21:07 |
mwhudson | kees: install_named_hook | 21:08 |
kees | mwhudson: so, if I had this: Branch.hooks.install_hook('pre_commit', run_tests) | 21:09 |
kees | I want Branch.install_named_hook now? | 21:09 |
LarstiQ | hey mwhudson | 21:09 |
mwhudson | kees: yes, and you need to pass a name too | 21:09 |
lifeless | kees: Branch.hooks.install_named_hook('pre_commit', run_tests, 'Run my tests') | 21:09 |
lifeless | mwhudson: ITYM "no, keep the hooks component in the object path" :) | 21:10 |
mwhudson | LarstiQ: hello | 21:10 |
kees | mwhudson: cool, great. is there a way to install hooks only in a given bzr tree? | 21:10 |
kees | mwhudson: right now, I have this as a global hook, and it does: | 21:10 |
mwhudson | kees: | 21:10 |
LarstiQ | mwhudson: I suspect I need to file a new bug re my ssl/proxy troubles. | 21:10 |
mwhudson | um | 21:10 |
kees | def run_tests(local, master, old_revno, old_revid, new_revno, new_revid, seven, eight): | 21:10 |
kees | if 'ubuntu-cve-tracker' in master.base: | 21:11 |
kees | as a way to only run it for the ubuntu-cve-tracker tree | 21:11 |
mwhudson | kees: you can put | 21:11 |
mwhudson | [/home/kees/cve-tracker] | 21:11 |
mwhudson | my_magic_config = value | 21:11 |
lifeless | kees: use a config variable | 21:11 |
mwhudson | in ~/.bazaar/locations.conf | 21:11 |
lifeless | kees: if not master.get_config().get_user_option('cvs_enabled'): return | 21:12 |
kees | mwhudson, lifeless: ah, interesting, okay, thanks. | 21:12 |
lifeless | kees: then you can enable per branch using branch.conf, or url prefix via locations.conf | 21:12 |
lifeless | jelmer: we're getting a bad pattern on that bug :) | 21:17 |
mwhudson | LarstiQ: probably sane | 21:27 |
LarstiQ | mwhudson: will do tomorrow, to tired to think now | 21:28 |
LarstiQ | ciao | 21:28 |
mwhudson | :) | 21:28 |
Glenjamin | hey guys, are there any docs around on using bzr's functions programatically? | 21:45 |
Glenjamin | i was going to just write a shell script, but i thought error handling would be much neater just using normal python | 21:45 |
beuno | Glenjamin, maybe something like: http://bazaar-vcs.org/Integrating_with_Bazaar | 21:47 |
Glenjamin | ah perfect | 21:47 |
Glenjamin | thanks | 21:47 |
beuno | welcome' | 21:48 |
=== montywi is now known as montywi|zzz | ||
mxpxpod | jelmer: are there docs for subvertpy? | 21:52 |
igc | morning | 22:01 |
jam | lifeless: i noticed, it breaks brisbane-core when you merge the new streaming code ... :) | 22:06 |
lifeless | jam: :P >< | 22:07 |
* igc breakfast | 22:19 | |
james_w | thanks Aaron | 22:32 |
=== Guest98584 is now known as bob2 | ||
abentley | james_w: np | 22:57 |
james_w | abentley: my reviews won't be counted as votes, correct? | 22:58 |
abentley | james_w: They will. | 22:58 |
=== thekorn_ is now known as thekorn | ||
james_w | oh, ok | 22:59 |
lifeless | yay netsplits | 23:03 |
=== mneptok_ is now known as mneptok | ||
kenichi | feeling blind, are there any sort of instructions for loggerhead setup anywhere? | 23:03 |
=== jbalint_ is now known as jbalint | ||
=== ubott2 is now known as ubottu | ||
kenichi | oh hee, nm. | 23:04 |
lifeless | abentley: I intend to move cloning_metadir down to the format, with a signature like Format.cloning_format(self, a_dir) | 23:04 |
lifeless | abentley: this is to allow avoiding more VFS calls | 23:05 |
lifeless | abentley: alternatively, I could do a network version of cloning_metadir; do you have a preference/haven't thought about it ? | 23:05 |
abentley | lifeless: I think it's okay to move it down, but you've got to make sure that format is accurate, then. | 23:07 |
lifeless | abentley: well the goal is to have RemoteBzrDirFormat.cloning_format(a_dir) call self._real_format.cloning_format(a_dir), where a_dir is a RemoteBzrDir | 23:08 |
lifeless | abentley: I think I'll do a network version, for now | 23:08 |
abentley | lifeless: works for me. | 23:09 |
lifeless | abentley: because its not an api change, and thats easier in some ways | 23:09 |
poolie | jam, regarding weave merge | 23:13 |
poolie | i thought i remembered that we would conflict on delete vs change | 23:13 |
poolie | i might be wrong | 23:13 |
abentley | poolie: I think it's not interpreted as a change because the line is moved. | 23:14 |
poolie | really, does weave know about that kind of merge? | 23:16 |
mwhudson | jelmer: are you here? | 23:21 |
thumper | :( | 23:24 |
thumper | looks like not | 23:24 |
mwhudson | lazy students | 23:38 |
jelmer | mwhudson, hey | 23:45 |
thumper | jelmer: why are you awake! | 23:46 |
mwhudson | jelmer: does bzr-git support branching from non-master branches in a repo? | 23:46 |
mwhudson | (please excuse any lack of understanding of git from me...) | 23:47 |
jelmer | mwhudson: not yet, as bzr has no way to address those branche syet | 23:47 |
mwhudson | ok, that issue | 23:47 |
jelmer | mwhudson, bzr git-import will import them though | 23:47 |
mwhudson | git-import will import all branches in a repo | 23:48 |
mwhudson | ? | 23:48 |
mwhudson | jelmer: also, is lp:bzr-git, lp:dulwich the way to get the latest, most fun, bzr-git? | 23:48 |
jelmer | mwhudson, yes, git-import imports all branches | 23:48 |
jelmer | mwhudson, the latest is lp:dulwich and lp:~jelmer/bzr-git/trunk | 23:50 |
mwhudson | jelmer: ok thanks | 23:50 |
jfroy | Hey people. | 23:51 |
jfroy | Are there specific setup instructions for running the bazaar test suite? | 23:51 |
jfroy | I naively tried to run bzr selftest, only to have it immediately die on me with bzr: ERROR: No module named blackbox.test_diff | 23:51 |
lifeless | jfroy: generally you should be running from the source, not from a binary | 23:52 |
jfroy | that is what I did | 23:53 |
jfroy | I went into the source distribution and ran the ./bzr | 23:54 |
jfroy | perhaps I need to force that path on the sys.path first | 23:54 |
lifeless | jfroy: no, shouldn't need to | 23:59 |
lifeless | jfroy: uhm that was from a tarball? | 23:59 |
Generated by irclog2html.py 2.7 by Marius Gedminas - find it at mg.pov.lt!