/srv/irclogs.ubuntu.com/2014/02/27/#ubuntu-quality.txt

pittiGood morning05:23
MangledBluecan anybody assist? - simple install - my MD5 checks out - c7f439e864d28d9e5ca2aa885c4ec4cb *ubuntu-12.04.4-desktop-amd64.iso - any thoungts - please assist06:58
jibelGood morning07:49
jibelpitti, apport isn't installed by default on server?08:08
jibelon precise?08:09
pittijibel: it shoudl, it has Tasks: cloud-image and server08:09
pittijibel: ah, precise08:09
pittistill, Tasks: server08:09
jibelhttp://d-jenkins.ubuntu-ci:8080/view/Upgrade/job/upgrade-ubuntu-precise-trusty-server-tasks-amd64/44/artifact/results/bootstrap.log08:09
pittijibel: hmm, maybe Tasks: server means something else then, and it's not in the base installation08:11
jibelpitti, nm, I'll find out. it's probably because in the container we install ubuntu-standard and not the task server08:13
pittijibel: ah, it's not in ubuntu-standard08:13
jibelI'll fix the profile08:13
pittimerci08:13
jibeland file a bug against u-r-u to fail nicely08:14
pittior at least do a check if apport-bug exists08:14
DanChapman__good morning all08:14
=== DanChapman__ is now known as DanChapman
jibelpitti, yes, that's what I meant by nicely, and revert the system to its original state08:19
jibelin this case the failure as due to a hashsum mismatch08:20
jibelDanChapman, Good morning, are you fixing the custom installation tests? otherwise I'll do.09:05
DanChapmanjibel I am indeed, working on it now. Just finishing off an emulator which solves it nicely. I'll give you a shout once i have MP ready09:09
jibelDanChapman, excellent, thanks so much for this work. I'll be happy to review and test it09:10
jibel\o/ upgrade tests dashboard back to green09:34
=== psivaa-afk is now known as psivaa
=== shuduo_ is now known as shuduo
pittijibel: hm, http://d-jenkins.ubuntu-ci:8080/job/trusty-adt-libnih-ppc64el/configure still has the -e11:52
jibelpitti, looking11:53
pittijibel: I retried the libnih job, and it's still hanging (killing now)11:54
pittijibel: that got dropped in r311, seems this didn't re-configure itself?11:55
jibelpitti, right, last request was on 2014-02-24. If the job is triggered from jenkins directly it is not reconfigured.11:57
pittijibel: ah, that's what I did11:57
pittijibel: I suppose I can manually change the configuration then, for manual rebuilds?11:58
jibelpitti, I removed -e from the config in jenkins11:58
jibelpitti, other solution is to retrigger a test from britney11:58
pittioh, all of a sudden -- ah, thanks11:58
pittijibel: for that job, I suppose?11:58
* pitti does that for upstart as well11:58
jibelyes for that job11:59
pittithanks11:59
pittijibel: btw, I taught myself the basics of celery on Monday, I created two containers (master and a slave1) and got a simple job deployed12:02
pittijibel: feels quite a bit more manual, but after seeing all the XML config that we do with Jenkins I'm not even sure that jenkins is easier :)12:02
jibelpitti, celery or jenkins, once it is setup you'll usually won't touch much the configuration12:04
pittijibel: AFAICS there is not really much celery configuation, aside from which redis or rabbitmq server you use? everything is mostly programmatic through python functions12:04
pittijibel: except that you seem to touch the job config all the time :)12:05
jibelpitti, I don't, only when you added new archs :)12:05
pittijibel: anyway, I don't plan anything serious with this anytime soon, I was just curious to get a feeling what it is like12:05
pittiheh12:06
jibelpitti, I think I'll move most of the logic of adt-britney to britney itself directly in autopkgtest.py12:11
jibelpitti, it has all the required information to do the job and will remove lot a redundancy12:12
pittijibel: ah, ok; that'll break the shiny new tests :) but if that makes things easier, so much the better12:12
pittiand we can probably adjust the test to do the file mocking at the lower level12:12
jibelpitti, sure, I'll update the testsuite. That'll remove lot of similar code, and both britney and adt-britney will use the same source or information12:13
jibels/or/of12:13
jibelI'll leave in adt-britney the spool management and integration with jenkins12:14
pittijibel: I guess from britney's POV there is no real reason why we can't introduce more states, like "ERROR" (test bed fail/uninstallable) or "BROKEN" (never succeeded), or is there?12:30
pittias britney only really looks for "pass"12:30
pittii. e. it should then accept PASS and BROKEN, but otherwise just show the error12:31
jibelpitti, it's correct. Currently the state PASS is hardcoded in britney.py. We could also add additional information like the reason it fails (test failure, infra, ...) the status on update_excuses is free text12:42
* infinity is excited about all this talk of improving adt-britney.12:44
=== _salem is now known as salem_
pittiinfinity: so am I :)13:32
DanChapmanjibel https://code.launchpad.net/~dpniel/ubiquity/autopilot_fix_custominstall/+merge/208605 when you get a chance mate13:54
=== bfiller_afk is now known as bfiller
jibelDanChapman, thanks, will do14:01
pittijibel: so would you think it would make any sense at all for me to try and read the current code and fix those three bugs?14:07
pittijibel: (of britney autopkgtest.py, to fix the order and issue of new source taking over a binary, etc.)14:08
jibelpitti, sure if you have time. There is no collision with what I'm doing.14:19
DanChapmanballoons, howdy. is there a way to rotate the screen on grouper?14:27
pittijibel: ah, it's not? good14:29
jibelpitti, the only change I did in britney.py is to teach read_sources about XS-Testsuite otherwise I'm in autopkgtest.py / request()14:31
pittijibel: ah right, and the bugs we found are in britney.py itself14:31
pittiwow, how do you mean "no unstable jobs" at http://d-jenkins.ubuntu-ci:8080/view/Upgrade/ ?14:32
pittithat can't be!14:32
pittiQA engineer rule #1: tests fail as soon as you stop looking at them14:32
pittijibel: so yes, I have time :)14:33
jibelpitti, that was easy, I followed the #2 qa engineer rule: if a test fails too often blame the infrastructure and skip it ;P14:34
jibelj/k14:34
* pitti donne une accolade à jibel14:36
* jibel donne en retour une accolade à pitti14:38
pittiso, off to making a date with britney to get to know her14:39
jibelDanChapman, in the diff: 163+ if num is self.total_number_partitions:15:08
jibelDanChapman, why do you use is to compare the values?15:08
=== Ursinha is now known as Ursinha-afk
jibelDanChapman, so, apart some inconsistencies like 68 + if num == self.part_table_rows:15:39
jibel[...]15:39
jibel172 + if num is not self.part_table_rows + 1:15:39
DanChapmanjibel, sorry was picking boy up from school. self.total_number_partitions is the total number of partitions defined in the config so when creating partitions there is always the 'freespace' row which on the last partition creation we don't gain a row but just replace freespace with the final partition. so instead of waiting for total rows to increment it currently sleeps to let the rows update when on the final partition15:40
jibelan unused call: 144+ item_table = tree_view.get_partition_table_dict()15:40
balloonsDanChapman, I believe the grouper uses a fixed landscape mode15:40
DanChapmanjibel, ahh i thought i'd removed that15:40
jibeland some TODOs, it looks fine. I did a few run and it worked15:40
jibelDanChapman, I meant the use of 'is' instead of '=='15:41
jibelto compare integers which are both the return value of len()15:41
DanChapmanjibel ahh sorry i misread. :-) that's a typo i'll change it to ==15:44
jibelDanChapman, np, it is just that the 2 operators have different meanings 'is' compares identities and '==' compares equality15:47
jibelso, I thought you had a reason to do s15:48
=== Ursinha-afk is now known as Ursinha
DanChapmanjibel, that makes sense :-) I'll quickly make those changes and fix the pep8/pyflake errors15:54
* DanChapman forgot to check them15:54
DanChapmanjibel updates pushed. Thanks for reviewing it.15:59
DanChapmanballoons, ok thanks mate :-)16:04
senanballoons, DanChapman, hii16:04
DanChapmansenan hey there :-)16:04
balloonsDanChapman, I pushed some feedback on the runner and format checks.. Small tweaks, then we should be able to land.16:05
jibelDanChapman, awesome, maybe the world will be greener tonight :)16:05
DanChapmanjibel I really hope so. :-)16:06
DanChapmanballoons, yes i'm waiting on your response for the runner. It was just where would you prefer instead of /tmp.16:07
* DanChapman goes to check the other comments16:07
balloonssent it along ;-) basically /home16:08
senanDanChapman,balloons, do I need to break down all  the big assertions into small ?16:08
jibelDanChapman, I love your comments starting from rev 6131 "hmmm", "ahh", "oops", "lets try this", ... :D16:12
jibelthat makes me think I really need to update the runner to run from a local directory16:12
DanChapmanjibel :-D yes there is only so much you can say trying to fix the same thing16:13
DanChapmanlocal dirs would be awesome!16:13
balloonsre: add pyflakes, DanChapman, I wouldn't worry too much about flake8.. I still don't use it, running them separately. I think the pain would be it's not packaged like the others.16:22
balloonsjust call the folder something besides tests :-)16:22
DanChapmanballoons, sounds good to me :-)16:25
senanballoons, do you want me change all the lambda's I used for selecting gui elements and asserting ?16:32
balloonssenan, ahh yes.. reducing complexity in your asserts is a good thing. As I said, when the assert fails now, it's hard to know why16:38
balloonsand it's kind of cumbersome to read ;-)16:38
senanballoons , :D16:38
jibelpitti, -virtfs local,id=autopkgtest,path=%s,security_model=none,mount_tag=autopkgtest is the magic option to enable 9p, right?16:40
jibeland then mount -t 9p ... on the guest16:41
jibelDanChapman, meh :( testtools.matchers._impl.MismatchError: After 10.0 seconds test on GtkDialog.visible failed: False != dbus.Boolean(True, variant_level=1): Partition dialog did not close16:42
pittijibel: jibel yes16:47
DanChapmanjibel grrr and 'unable to find freespace item'. I didn't change any of that part. :-( i'll look into it16:48
elopioping balloons, are you working on the terminal?16:48
pittijibel: but mind that it got broken wiht the 2.0 PPA package, I filed bug 1285505 this morning16:48
ubot5bug 1285505 in qemu (Ubuntu) "[ppa 2.0~git-20140225] SIGABRT with -virtfs" [Undecided,New] https://launchpad.net/bugs/128550516:48
jibelpitti, ack. I'm running the version from trusty on saucy, not sure I'll play with the PPA in production :)16:50
balloonselopio, yes I pushed an mp quickly16:53
balloonsit need more work, but I stopped myself from going crazy16:54
elopioballoons: ok, thanks :)16:54
elopioI'm also trying to keep the head. That comes first :D16:55
senanballoons, DanChapman, Can you please check this snippet http://paste.ubuntu.com/7006042/17:02
balloonsquick glance that looks more readable. Consider making it into paragraphs were it makes sense. Meaning, add a extra newline in there to group things17:03
senanballoons, okay :)17:04
DanChapmanjibel do you think it's acceptable to try closing the dialog, say 3 times before letting it fail. Since it was probably something like the combobox hadn't closed so the click would have closed it and it just needed another click17:05
elopioping ubuntu-qa, have any of you seen this? https://bugs.launchpad.net/ubuntu-keyboard/+bug/128578117:08
ubot5Ubuntu bug 1285781 in ubuntu-keyboard "Pressing the symbols key sometimes writes 123? to the textfield" [Undecided,New]17:08
elopiodavmor2: have you? ^17:20
davmor2elopio: I haven't no17:21
elopio:( loneliness17:21
davmor2elopio: that's how I feel most of the time then some dev will pipe up :)17:25
senanballoons, I can use like this right self.assertThat(lambda: self.get_spinner_button_control().sensitive,Eventually(Equals(True)))17:27
elopiorobotfuel: if I understand the rss correctly, it goes to the google apis site and the feed is parsed remotely.17:28
elopioso it's not possible to access a local feed.17:29
robotfuelelopio: I didn't realize that.17:29
balloonssenan, consider breaking that down a bit17:29
elopiorobotfuel: what we need is to wrap the api calls, so we can mock them, or inject a different dependency or something like that.17:30
elopioreally easy to do if it was python :) On qml and javascript, I'm clueless.17:30
asacelopio: did we start the job yet?17:30
senanballoons, assign to a variable first and then do the assertion?17:30
asacelopio: i still see the stuck job :/17:30
asacoh now its gone17:31
asacodd17:31
asachmm. now its back :/17:31
balloonssenan, yes, grab the object.. then assert on it17:31
senanok balloons17:31
elopioasac: I didn't, I was in a meeting. I'll do it know, because you seem to be in a hurry :)17:31
robotfuelelopio: I wonder if you could use wireshark to figure out what is needed to mock the api.17:32
asacelopio: well, no need to wait i think.17:33
asacelopio: but no hurry if you have other important things to do17:33
elopiohuh, I don't have permissions17:34
asacjust wanted to enusre it didnt fail etc.17:34
asacsee :P17:34
asacthats what i wanted to ensure we know early :P17:34
elopiofginther: can you give me permissions to rebuild the autopilot release job in http://q-jenkins:8080 ?17:34
elopiocgoldberg: you probably have permissions for that. Can you give me a hand for now?17:35
cgoldbergelopio, my vpn is down.. i'm waiting on IS for new credentials17:36
elopioasac: yes, I see now :)17:40
senanballoons, DanChapman, I've updated the branch, can you please review it17:42
asacelopio: you can go into #ubuntu-ci-eng and ping cihelp17:43
asacin case fginther isnt around... there might be others that can help17:43
asac(all ci folks are subscribed to that keyword)17:43
elopiolast time I did that, they told me to wait for fginther. It's worth a try anyway.17:44
asacyeah17:45
senanballoons,DanChapman, I just resubmitted MP17:51
elopioasac: it's running.18:00
asacnice!18:05
asacthx18:05
DanChapmanjibel i just updated my iso's to todays image and it's not the tests causing the fails. see http://ubuntuone.com/1z3xRFF2BayykE5MjjP9Ju unity and window chrome aren't visible and the mouse and window/dialog focuses are all out of whack18:11
DanChapmanI've ran 3/4 times on both i386 and 64 images, both presenting same18:12
DanChapmanhmmm but that doesn't explain lubuntu18:22
=== bfiller is now known as bfiller_afk
balloonselopio, :-( http://paste.ubuntu.com/7006649/19:06
elopioballoons: could the application have crashed between swiping and confirming?19:19
elopiothat seems to be hapenning a lot.19:19
balloonselopio, yes.. and is it a bug in the emulator?19:20
elopioballoons: if the application crashes, it's not a bug on the emulator. We hold a reference to a qml element, and when we try to click it, it's no longer in the screen19:21
balloonselopio, I can reproduce it easily as long as there is more than 1 item in the list19:21
elopioballoons: I don't get it. So it's not crashing?19:23
balloonselopio, the error I gave you happens whenever the list contains more than 1 element19:23
balloonsif it's only 1 element, the error does not occur19:24
elopioballoons: weird, because on the toolkit the self test for that method is done with more than 1 element.19:25
elopioballoons: I need to pick my girlfriend.19:25
elopiowhen I return, I'll try to reproduce it.19:25
balloonselopio, :-) We should simply test both cases19:25
elopioI can't reproduce it. But I also can't tell my qmlscene not to be full screen.19:31
elopioballoons: please, take a screenshot before the error occurs, to see the size of your clock.19:31
balloonselopio, it was in wideview on the clock19:32
balloonselopio, I will help debug after fixing the test and getting this shipped :-)19:32
=== salem_ is now known as _salem
elopioI'm back.20:07
elopioballoons: I have the clock on wideview, but it is maximized on my screen20:08
elopioI don't know how to unmaximize it. I hate qmlscene.20:08
balloonselopio, hey.. lots of fun today20:08
balloons2 second sidebar elopio : https://bugs.launchpad.net/ubuntu-clock-app/+bug/128303120:08
ubot5Ubuntu bug 1283031 in Ubuntu Clock App "Alarms AP tests need to cleanup alarms after the test is complete" [Medium,Triaged]20:08
balloonswhat was your plan for properly cleaning up and setting up test envs?20:09
balloonsmocking /home was it?20:09
balloonsand I'd like to make one bug and assign all the apps as affected I think so we can track properly20:09
elopioballoons: from the sprint, the plan was either override the environment variables to use a temp config directory, or use a fake in-memory database20:11
balloonsahh fake in-mem db was your other plan. I prefer mocking I think20:11
balloonsin this case, since we rely on things outside our own app, I'm not sure in-mem db works20:11
elopioballoons: in this case, why don't we just delete the alarms we create?20:12
balloonselopio, when AP crashes, well ;-)20:12
balloonswell not AP, but tests not finishing cleanly20:13
elopioah, yes, that's what we need to fix first.20:13
balloonsso I vote just mock the thing.. it'll never matter and go away on it's own even if we don't cleanup well20:13
veebersballoons: good save, I was going to have a word :-)20:14
elopioballoons: I like that too. Just a small detail is that it's not overriding $HOME, it's one of the xdg env vars.20:14
* balloons waves to veebers :-)20:14
veebershow are things balloons?20:14
balloonsnot bad, yourself? I'm awaiting this: https://code.launchpad.net/~veebers/autopilot-qt/reintroduce-exporting-qobject-children-of-qml-items/+merge/20758120:15
veebersballoons: you might find this interesting from our convo in Oakland. Burger place in NZ menu http://www.velvetburger.co.nz/ check out "The Stag"20:15
* veebers looks20:15
balloonsso many things to get going.. testing is a full contact sport20:15
veebersballoons: aye, that MR is in the current release proposal20:16
veeberswe're just doing the testing for it now20:16
balloonsveebers, oO venison :-) Lots of it on the menu.20:16
veebersheh :-)20:16
balloonsveebers, "This one used to be made from Moa (which was a big bird), but we ran out of them a few years back"20:17
balloonsI love the humor20:17
veebers^_^20:17
elopioballoons: you are running too much :) It's contagious if you stay for too long on #ci20:19
elopioI can't reproduce the failure deleting with multiple items on the alarms list, wide mode. :/20:20
balloonselopio, perhaps you can help solve problem 1 atm with clock.. fixing the last test that fails.. have a look at my MP in progress for where I'm going: https://code.launchpad.net/~nskaggs/ubuntu-clock-app/tweak-get-num-alarms/+merge/20868120:22
balloonsthe old version of get_num_alarms didn't seem to work for me (returning 0 all the time)20:23
elopioballoons: but if that doesn't work, is a problem on the QQuickView, that returns the wrong .count property20:24
=== bfiller_afk is now known as bfiller
balloonsyou just can't win.. it's odd because only 1 test failed, and it was the same one every time20:24
elopioyour workaround seems more likely to make a bigger mess.20:25
balloonselopio, but actually listSavedAlarm will only ever be 1.. it's the list20:25
balloonsmy tweaks do seem to have gotten large, heh20:26
elopioballoons: self.page.get_num_of_alarms()20:26
elopio220:26
elopiothe count property of a QQuickListView, returns the number of list elements it has.20:26
balloonsohh sorry, you returned count :-)20:27
balloonsthe code now reproduces the StateNotFoundError I originally attempted to avoid20:27
balloonsbrillant20:27
balloonselopio, so I agree.. scrapping this20:29
elopioballoons: you are going way too fast for me. Now I don't understand three issues you have:20:29
elopio- delete with more than one item failing20:29
elopio- count always returning 020:29
elopio- this state not found StateNotFoundError you have just mentioned20:29
elopio:D can we choose one?20:29
balloonselopio, lol.. gotta keep up20:29
balloonsthey are all issues.. you dig into one thing and find a bunch20:29
elopioballoons: I can understand that, but I can't reproduce anyone.20:31
elopionor jenkins, as it has merged all the branches so far.20:32
* balloons feels special20:32
balloonsall I want is to land something that will make the dashboard green.. From there, we can take everything one at a time20:32
balloonsAnd perhaps it's time we disabled the 1 test that fails for me, test it manually and ship it with a bug to fix the tes20:32
elopioballoons: but just yesterday you were the one saying that we shouldn't be obsessed with getting everything to green, and try to make proper fixes20:36
elopiothis failure for example: http://ci.ubuntu.com/smokeng/trusty/touch/mako/210:20140227:20140224/6849/ubuntu_clock_app/821577/20:36
elopioit sounds like we start with 0 alarms, so we can't delete them.20:36
elopiofirst step for me would be to try to improve that error message we are getting.20:37
elopiolet me try something quick.20:39
balloonselopio, yes I was looking at that one.. it still fails after all you and nik90's changes20:42
elopioballoons: yes, nik got it, it's because we are not waiting for the alarm to be added to the list.20:43
balloonselopio, so add  alarm._confirm_addition() to add_alarm.  _confirm_addition() can poll waiting for the cont to increase.. do we have something more elegant?20:54
elopioballoons: working on it.20:54
balloonselopio, we could wait_select for the new object to be created.. I like that20:55
asacelopio: idea why we have 483 tests there?21:34
asachttp://q-jenkins.ubuntu-ci:8080/job/autopilot-release-gatekeeper/label=mako-07/45/testReport/21:34
asacwe should have 600+ i think21:34
asacat least just short of 60021:35
asace.g. http://ci.ubuntu.com/smokeng/trusty/touch/mako/210:20140227:20140224/6849/21:35
asacrmeove all the non ap ones21:35
asacok mediaplayer is not in there21:36
asachmm. wrong21:36
asacthomi: ^^  did you guys exclude some APs?21:36
asaccan you spot which ones from dashboard are not run?21:36
thomiasac: OTP, one second21:37
thomiveebers: that's for you it hink21:37
thomi*i think21:37
asacso install-and-boot security, sdk and default are not expected to be in there21:37
veebersasac: OTP will check in a moment21:37
asacthats 9 tests in total we can substract from the 610 we run on dashboard21:38
asacthink shorts app21:38
asacok thanks. let me know21:38
asacwondere where i can find ALL tests run at all21:39
asaconly see the number, but cant find the complete list21:39
elopioasac: sorry, I'm with you now.21:55
elopioit's stuck on maguro again. veebers: I'll kill this job so you can use it for your autopilot release. I'll rerun it tomorrow after the 5.2 meeeting.21:57
veeberselopio: ack thanks, I've asked re the maguro being offline but got no answer. Will ask again22:00
elopioasac: I'll check the current results, which are enough to have an ugly night. For the run tomorrow I'll figure out which packages we are missing.22:01
elopioasac: sounds good?22:01
elopioI need a break now. bbl.22:06
=== Ursinha is now known as Ursinha-afk
elopioasac: oh, I forgot, here you can find all the tests that were run:22:07
elopiohttp://q-jenkins:8080/job/autopilot-release-gatekeeper/45/label=mako-07/testReport/?22:08
=== Ursinha-afk is now known as Ursinha
asacelopio: hmm. if you scroll down there is a table "All Tests"22:11
asacelopio: that thing doesnt have 483, right?22:11
asac(yes, i looked at that page)22:11
asacelopio: and yes, sounds good on getting hte rest of the tests into tomorrows run22:12
asacbut at best pretty early in the day so we can digest those results in the meeting22:12
veebersasac, elopio: I'm not too sure why those numbers are different (483 in our jenkins job vs the ~600 on the dashboard) as far as I was told this job was a clone of what produces those dashboard results22:13
asacveebers: could be... we should really cross check. could also mean that some tests crash so miserably they dont even show up22:20
asaci would do it, but as above i just cant see the complete list22:20
asacthat was run22:20
asacthe "All Tests" table surely doesnt have 480 rows :)22:21
asaclet me check with doanac` :)22:21
asacdoanac`: http://q-jenkins:8080/job/autopilot-release-gatekeeper/45/label=mako-07/testReport/? :) ... 483 tests counted on top22:21
asacdoanac`: while i would expect we have 600 or so22:21
asacdoanac`: and "All TestS" table at bottom shows at most 10022:21
asacdoanac`: can you shed some light?22:22
asacguess i am not good at reading the All Tests table :)22:22
asacbut then the 600 vs. 480 quesiton still is interesting22:22
thomiasac: veebers elopio: that's a list of the test case classes, not the tests22:23
thomi# of rows * value in the 'total' column should give you number of tests22:24
veebersthomi: right, it has a count of tests in that class per row22:24
thomiyes, it sucks - I have no godly idea why jenkins decides to display test results like that22:24
veebersyeah, what thomi said :_)22:24
veebersthomi: do you know what the "(root)" is in that table of tests?22:25
thomiveebers: no22:25
thomiveebers: I suspect this is an artifact of collecting more than one junitxml file together22:26
veebersah I see good point.22:26
thomithe sooner we kiull junitxml and stsart using subunit the better :-/22:26
veebersadding the Total column still gives 483 tests, not the 600 shown on the dashboard22:26
asacthomi: ok that make somewhat sense. thx23:52

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