From: https://www.kaggle.com/axel81/ensembling-imet
Author: Ram Ramrakhya
This kernel is an implementation for KFolding using the already trained models. Run time for the kernel is 1.5hrs which will work even on the huge test set.
In this Kernel I'll use 6 Folds
import pandas as pd
import gzip
import base64
import os
from pathlib import Path
from typing import Dict
# this is base64 encoded source code
file_data: Dict = {'imet/transforms.py': 'aW1wb3J0IHJhbmRvbQppbXBvcnQgbWF0aAoKZnJvbSBQSUwgaW1wb3J0IEltYWdlCmZyb20gdG9yY2h2aXNpb24udHJhbnNmb3JtcyBpbXBvcnQgKAogICAgVG9UZW5zb3IsIE5vcm1hbGl6ZSwgQ29tcG9zZSwgUmVzaXplLCBDZW50ZXJDcm9wLCBSYW5kb21Dcm9wLAogICAgUmFuZG9tSG9yaXpvbnRhbEZsaXApCgoKY2xhc3MgUmFuZG9tU2l6ZWRDcm9wOgogICAgIiIiUmFuZG9tIGNyb3AgdGhlIGdpdmVuIFBJTC5JbWFnZSB0byBhIHJhbmRvbSBzaXplCiAgICBvZiB0aGUgb3JpZ2luYWwgc2l6ZSBhbmQgYW5kIGEgcmFuZG9tIGFzcGVjdCByYXRpbwogICAgb2YgdGhlIG9yaWdpbmFsIGFzcGVjdCByYXRpby4KICAgIHNpemU6IHNpemUgb2YgdGhlIHNtYWxsZXIgZWRnZQogICAgaW50ZXJwb2xhdGlvbjogRGVmYXVsdDogUElMLkltYWdlLkJJTElORUFSCiAgICAiIiIKCiAgICBkZWYgX19pbml0X18oc2VsZiwgc2l6ZSwgaW50ZXJwb2xhdGlvbj1JbWFnZS5CSUxJTkVBUiwKICAgICAgICAgICAgICAgICBtaW5fYXNwZWN0PTQvNSwgbWF4X2FzcGVjdD01LzQsCiAgICAgICAgICAgICAgICAgbWluX2FyZWE9MC4yNSwgbWF4X2FyZWE9MSk6CiAgICAgICAgc2VsZi5zaXplID0gc2l6ZQogICAgICAgIHNlbGYuaW50ZXJwb2xhdGlvbiA9IGludGVycG9sYXRpb24KICAgICAgICBzZWxmLm1pbl9hc3BlY3QgPSBtaW5fYXNwZWN0CiAgICAgICAgc2VsZi5tYXhfYXNwZWN0ID0gbWF4X2FzcGVjdAogICAgICAgIHNlbGYubWluX2FyZWEgPSBtaW5fYXJlYQogICAgICAgIHNlbGYubWF4X2FyZWEgPSBtYXhfYXJlYQoKICAgIGRlZiBfX2NhbGxfXyhzZWxmLCBpbWcpOgogICAgICAgIGZvciBhdHRlbXB0IGluIHJhbmdlKDEwKToKICAgICAgICAgICAgYXJlYSA9IGltZy5zaXplWzBdICogaW1nLnNpemVbMV0KICAgICAgICAgICAgdGFyZ2V0X2FyZWEgPSByYW5kb20udW5pZm9ybShzZWxmLm1pbl9hcmVhLCBzZWxmLm1heF9hcmVhKSAqIGFyZWEKICAgICAgICAgICAgYXNwZWN0X3JhdGlvID0gcmFuZG9tLnVuaWZvcm0oc2VsZi5taW5fYXNwZWN0LCBzZWxmLm1heF9hc3BlY3QpCgogICAgICAgICAgICB3ID0gaW50KHJvdW5kKG1hdGguc3FydCh0YXJnZXRfYXJlYSAqIGFzcGVjdF9yYXRpbykpKQogICAgICAgICAgICBoID0gaW50KHJvdW5kKG1hdGguc3FydCh0YXJnZXRfYXJlYSAvIGFzcGVjdF9yYXRpbykpKQoKICAgICAgICAgICAgaWYgcmFuZG9tLnJhbmRvbSgpIDwgMC41OgogICAgICAgICAgICAgICAgdywgaCA9IGgsIHcKCiAgICAgICAgICAgIGlmIHcgPD0gaW1nLnNpemVbMF0gYW5kIGggPD0gaW1nLnNpemVbMV06CiAgICAgICAgICAgICAgICB4MSA9IHJhbmRvbS5yYW5kaW50KDAsIGltZy5zaXplWzBdIC0gdykKICAgICAgICAgICAgICAgIHkxID0gcmFuZG9tLnJhbmRpbnQoMCwgaW1nLnNpemVbMV0gLSBoKQoKICAgICAgICAgICAgICAgIGltZyA9IGltZy5jcm9wKCh4MSwgeTEsIHgxICsgdywgeTEgKyBoKSkKICAgICAgICAgICAgICAgIGFzc2VydChpbWcuc2l6ZSA9PSAodywgaCkpCgogICAgICAgICAgICAgICAgcmV0dXJuIGltZy5yZXNpemUoKHNlbGYuc2l6ZSwgc2VsZi5zaXplKSwgc2VsZi5pbnRlcnBvbGF0aW9uKQoKICAgICAgICAjIEZhbGxiYWNrCiAgICAgICAgc2NhbGUgPSBSZXNpemUoc2VsZi5zaXplLCBpbnRlcnBvbGF0aW9uPXNlbGYuaW50ZXJwb2xhdGlvbikKICAgICAgICBjcm9wID0gQ2VudGVyQ3JvcChzZWxmLnNpemUpCiAgICAgICAgcmV0dXJuIGNyb3Aoc2NhbGUoaW1nKSkKCgp0cmFpbl90cmFuc2Zvcm0gPSBDb21wb3NlKFsKICAgIFJhbmRvbUNyb3AoMjg4KSwKICAgIFJhbmRvbUhvcml6b250YWxGbGlwKCksCl0pCgoKdGVzdF90cmFuc2Zvcm0gPSBDb21wb3NlKFsKICAgIFJhbmRvbUNyb3AoMjg4KSwKICAgIFJhbmRvbUhvcml6b250YWxGbGlwKCksCl0pCgoKdGVuc29yX3RyYW5zZm9ybSA9IENvbXBvc2UoWwogICAgVG9UZW5zb3IoKSwKICAgIE5vcm1hbGl6ZShtZWFuPVswLjQ4NSwgMC40NTYsIDAuNDA2XSwgc3RkPVswLjIyOSwgMC4yMjQsIDAuMjI1XSksCl0pCg==',
'imet/make_submission.py': 'aW1wb3J0IGFyZ3BhcnNlCgppbXBvcnQgcGFuZGFzIGFzIHBkCgpmcm9tIC51dGlscyBpbXBvcnQgbWVhbl9kZgpmcm9tIC5kYXRhc2V0IGltcG9ydCBEQVRBX1JPT1QKZnJvbSAubWFpbiBpbXBvcnQgYmluYXJpemVfcHJlZGljdGlvbgoKCmRlZiBtYWluKCk6CiAgICBwYXJzZXIgPSBhcmdwYXJzZS5Bcmd1bWVudFBhcnNlcigpCiAgICBhcmcgPSBwYXJzZXIuYWRkX2FyZ3VtZW50CiAgICBhcmcoJ3ByZWRpY3Rpb25zJywgbmFyZ3M9JysnKQogICAgYXJnKCdvdXRwdXQnKQogICAgYXJnKCctLXRocmVzaG9sZCcsIHR5cGU9ZmxvYXQsIGRlZmF1bHQ9MC4yKQogICAgYXJncyA9IHBhcnNlci5wYXJzZV9hcmdzKCkKICAgIHNhbXBsZV9zdWJtaXNzaW9uID0gcGQucmVhZF9jc3YoCiAgICAgICAgREFUQV9ST09UIC8gJ3NhbXBsZV9zdWJtaXNzaW9uLmNzdicsIGluZGV4X2NvbD0naWQnKQogICAgZGZzID0gW10KICAgIGZvciBwcmVkaWN0aW9uIGluIGFyZ3MucHJlZGljdGlvbnM6CiAgICAgICAgZGYgPSBwZC5yZWFkX2hkZihwcmVkaWN0aW9uLCBpbmRleF9jb2w9J2lkJykKICAgICAgICBkZiA9IGRmLnJlaW5kZXgoc2FtcGxlX3N1Ym1pc3Npb24uaW5kZXgpCiAgICAgICAgZGZzLmFwcGVuZChkZikKICAgIGRmID0gcGQuY29uY2F0KGRmcykKICAgIGRmID0gbWVhbl9kZihkZikKICAgIGRmWzpdID0gYmluYXJpemVfcHJlZGljdGlvbihkZi52YWx1ZXMsIHRocmVzaG9sZD1hcmdzLnRocmVzaG9sZCkKICAgIGRmID0gZGYuYXBwbHkoZ2V0X2NsYXNzZXMsIGF4aXM9MSkKICAgIGRmLm5hbWUgPSAnYXR0cmlidXRlX2lkcycKICAgIGRmLnRvX2NzdihhcmdzLm91dHB1dCwgaGVhZGVyPVRydWUpCgoKZGVmIGdldF9jbGFzc2VzKGl0ZW0pOgogICAgcmV0dXJuICcgJy5qb2luKGNscyBmb3IgY2xzLCBpc19wcmVzZW50IGluIGl0ZW0uaXRlbXMoKSBpZiBpc19wcmVzZW50KQoKCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6CiAgICBtYWluKCkK',
'imet/models.py': 'ZnJvbSBmdW5jdG9vbHMgaW1wb3J0IHBhcnRpYWwKCmltcG9ydCB0b3JjaApmcm9tIHRvcmNoIGltcG9ydCBubgpmcm9tIHRvcmNoLm5uIGltcG9ydCBmdW5jdGlvbmFsIGFzIEYKaW1wb3J0IHRvcmNodmlzaW9uLm1vZGVscyBhcyBNCgpmcm9tIC51dGlscyBpbXBvcnQgT05fS0FHR0xFCgoKY2xhc3MgQXZnUG9vbChubi5Nb2R1bGUpOgogICAgZGVmIGZvcndhcmQoc2VsZiwgeCk6CiAgICAgICAgcmV0dXJuIEYuYXZnX3Bvb2wyZCh4LCB4LnNoYXBlWzI6XSkKCgpkZWYgY3JlYXRlX25ldChuZXRfY2xzLCBwcmV0cmFpbmVkOiBib29sKToKICAgIGlmIE9OX0tBR0dMRSBhbmQgcHJldHJhaW5lZDoKICAgICAgICBuZXQgPSBuZXRfY2xzKCkKICAgICAgICBtb2RlbF9uYW1lID0gbmV0X2Nscy5fX25hbWVfXwogICAgICAgIHdlaWdodHNfcGF0aCA9IGYnLi4vaW5wdXQve21vZGVsX25hbWV9L3ttb2RlbF9uYW1lfS5wdGgnCiAgICAgICAgbmV0LmxvYWRfc3RhdGVfZGljdCh0b3JjaC5sb2FkKHdlaWdodHNfcGF0aCkpCiAgICBlbHNlOgogICAgICAgIG5ldCA9IG5ldF9jbHMocHJldHJhaW5lZD1wcmV0cmFpbmVkKQogICAgcmV0dXJuIG5ldAoKCmNsYXNzIFJlc05ldChubi5Nb2R1bGUpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIG51bV9jbGFzc2VzLAogICAgICAgICAgICAgICAgIHByZXRyYWluZWQ9RmFsc2UsIG5ldF9jbHM9TS5yZXNuZXQxMDEsIGRyb3BvdXQ9RmFsc2UpOgogICAgICAgIHN1cGVyKCkuX19pbml0X18oKQogICAgICAgIHNlbGYubmV0ID0gY3JlYXRlX25ldChuZXRfY2xzLCBwcmV0cmFpbmVkPXByZXRyYWluZWQpCiAgICAgICAgc2VsZi5uZXQuYXZncG9vbCA9IEF2Z1Bvb2woKQogICAgICAgIGlmIGRyb3BvdXQ6CiAgICAgICAgICAgIHNlbGYubmV0LmZjID0gbm4uU2VxdWVudGlhbCgKICAgICAgICAgICAgICAgIG5uLkRyb3BvdXQoKSwKICAgICAgICAgICAgICAgIG5uLkxpbmVhcihzZWxmLm5ldC5mYy5pbl9mZWF0dXJlcywgbnVtX2NsYXNzZXMpLAogICAgICAgICAgICApCiAgICAgICAgZWxzZToKICAgICAgICAgICAgc2VsZi5uZXQuZmMgPSBubi5MaW5lYXIoc2VsZi5uZXQuZmMuaW5fZmVhdHVyZXMsIG51bV9jbGFzc2VzKQoKICAgIGRlZiBmcmVzaF9wYXJhbXMoc2VsZik6CiAgICAgICAgcmV0dXJuIHNlbGYubmV0LmZjLnBhcmFtZXRlcnMoKQoKICAgIGRlZiBmb3J3YXJkKHNlbGYsIHgpOgogICAgICAgIHJldHVybiBzZWxmLm5ldCh4KQoKCmNsYXNzIERlbnNlTmV0KG5uLk1vZHVsZSk6CiAgICBkZWYgX19pbml0X18oc2VsZiwgbnVtX2NsYXNzZXMsCiAgICAgICAgICAgICAgICAgcHJldHJhaW5lZD1GYWxzZSwgbmV0X2Nscz1NLmRlbnNlbmV0MTIxKToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCkKICAgICAgICBzZWxmLm5ldCA9IGNyZWF0ZV9uZXQobmV0X2NscywgcHJldHJhaW5lZD1wcmV0cmFpbmVkKQogICAgICAgIHNlbGYuYXZnX3Bvb2wgPSBBdmdQb29sKCkKICAgICAgICBzZWxmLm5ldC5jbGFzc2lmaWVyID0gbm4uTGluZWFyKAogICAgICAgICAgICBzZWxmLm5ldC5jbGFzc2lmaWVyLmluX2ZlYXR1cmVzLCBudW1fY2xhc3NlcykKCiAgICBkZWYgZnJlc2hfcGFyYW1zKHNlbGYpOgogICAgICAgIHJldHVybiBzZWxmLm5ldC5jbGFzc2lmaWVyLnBhcmFtZXRlcnMoKQoKICAgIGRlZiBmb3J3YXJkKHNlbGYsIHgpOgogICAgICAgIG91dCA9IHNlbGYubmV0LmZlYXR1cmVzKHgpCiAgICAgICAgb3V0ID0gRi5yZWx1KG91dCwgaW5wbGFjZT1UcnVlKQogICAgICAgIG91dCA9IHNlbGYuYXZnX3Bvb2wob3V0KS52aWV3KG91dC5zaXplKDApLCAtMSkKICAgICAgICBvdXQgPSBzZWxmLm5ldC5jbGFzc2lmaWVyKG91dCkKICAgICAgICByZXR1cm4gb3V0CgoKcmVzbmV0MTggPSBwYXJ0aWFsKFJlc05ldCwgbmV0X2Nscz1NLnJlc25ldDE4KQpyZXNuZXQzNCA9IHBhcnRpYWwoUmVzTmV0LCBuZXRfY2xzPU0ucmVzbmV0MzQpCnJlc25ldDUwID0gcGFydGlhbChSZXNOZXQsIG5ldF9jbHM9TS5yZXNuZXQ1MCkKcmVzbmV0MTAxID0gcGFydGlhbChSZXNOZXQsIG5ldF9jbHM9TS5yZXNuZXQxMDEpCnJlc25ldDE1MiA9IHBhcnRpYWwoUmVzTmV0LCBuZXRfY2xzPU0ucmVzbmV0MTUyKQoKZGVuc2VuZXQxMjEgPSBwYXJ0aWFsKERlbnNlTmV0LCBuZXRfY2xzPU0uZGVuc2VuZXQxMjEpCmRlbnNlbmV0MTY5ID0gcGFydGlhbChEZW5zZU5ldCwgbmV0X2Nscz1NLmRlbnNlbmV0MTY5KQpkZW5zZW5ldDIwMSA9IHBhcnRpYWwoRGVuc2VOZXQsIG5ldF9jbHM9TS5kZW5zZW5ldDIwMSkKZGVuc2VuZXQxNjEgPSBwYXJ0aWFsKERlbnNlTmV0LCBuZXRfY2xzPU0uZGVuc2VuZXQxNjEpCg==',
'imet/__init__.py': 'aW1wb3J0IGN2MgoKCmN2Mi5zZXROdW1UaHJlYWRzKDApICAjIGZpeCBwb3RlbnRpYWwgcHl0b3JjaCB3b3JrZXIgaXNzdWVzCg==',
'imet/make_folds.py': 'aW1wb3J0IGFyZ3BhcnNlCmZyb20gY29sbGVjdGlvbnMgaW1wb3J0IGRlZmF1bHRkaWN0LCBDb3VudGVyCmltcG9ydCByYW5kb20KCmltcG9ydCBwYW5kYXMgYXMgcGQKaW1wb3J0IHRxZG0KCmZyb20gLmRhdGFzZXQgaW1wb3J0IERBVEFfUk9PVAoKCmRlZiBtYWtlX2ZvbGRzKG5fZm9sZHM6IGludCkgLT4gcGQuRGF0YUZyYW1lOgogICAgZGYgPSBwZC5yZWFkX2NzdihEQVRBX1JPT1QgLyAndHJhaW4uY3N2JykKICAgIGNsc19jb3VudHMgPSBDb3VudGVyKGNscyBmb3IgY2xhc3NlcyBpbiBkZlsnYXR0cmlidXRlX2lkcyddLnN0ci5zcGxpdCgpCiAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgY2xzIGluIGNsYXNzZXMpCiAgICBmb2xkX2Nsc19jb3VudHMgPSBkZWZhdWx0ZGljdChpbnQpCiAgICBmb2xkcyA9IFstMV0gKiBsZW4oZGYpCiAgICBmb3IgaXRlbSBpbiB0cWRtLnRxZG0oZGYuc2FtcGxlKGZyYWM9MSwgcmFuZG9tX3N0YXRlPTQyKS5pdGVydHVwbGVzKCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgdG90YWw9bGVuKGRmKSk6CiAgICAgICAgY2xzID0gbWluKGl0ZW0uYXR0cmlidXRlX2lkcy5zcGxpdCgpLCBrZXk9bGFtYmRhIGNsczogY2xzX2NvdW50c1tjbHNdKQogICAgICAgIGZvbGRfY291bnRzID0gWyhmLCBmb2xkX2Nsc19jb3VudHNbZiwgY2xzXSkgZm9yIGYgaW4gcmFuZ2Uobl9mb2xkcyldCiAgICAgICAgbWluX2NvdW50ID0gbWluKFtjb3VudCBmb3IgXywgY291bnQgaW4gZm9sZF9jb3VudHNdKQogICAgICAgIHJhbmRvbS5zZWVkKGl0ZW0uSW5kZXgpCiAgICAgICAgZm9sZCA9IHJhbmRvbS5jaG9pY2UoW2YgZm9yIGYsIGNvdW50IGluIGZvbGRfY291bnRzCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIGNvdW50ID09IG1pbl9jb3VudF0pCiAgICAgICAgZm9sZHNbaXRlbS5JbmRleF0gPSBmb2xkCiAgICAgICAgZm9yIGNscyBpbiBpdGVtLmF0dHJpYnV0ZV9pZHMuc3BsaXQoKToKICAgICAgICAgICAgZm9sZF9jbHNfY291bnRzW2ZvbGQsIGNsc10gKz0gMQogICAgZGZbJ2ZvbGQnXSA9IGZvbGRzCiAgICByZXR1cm4gZGYKCgpkZWYgbWFpbigpOgogICAgcGFyc2VyID0gYXJncGFyc2UuQXJndW1lbnRQYXJzZXIoKQogICAgcGFyc2VyLmFkZF9hcmd1bWVudCgnLS1uLWZvbGRzJywgdHlwZT1pbnQsIGRlZmF1bHQ9NSkKICAgIGFyZ3MgPSBwYXJzZXIucGFyc2VfYXJncygpCiAgICBkZiA9IG1ha2VfZm9sZHMobl9mb2xkcz1hcmdzLm5fZm9sZHMpCiAgICBkZi50b19jc3YoJ2ZvbGRzLmNzdicsIGluZGV4PU5vbmUpCgoKaWYgX19uYW1lX18gPT0gJ19fbWFpbl9fJzoKICAgIG1haW4oKQo=',
'imet/dataset.py': 'ZnJvbSBwYXRobGliIGltcG9ydCBQYXRoCmZyb20gdHlwaW5nIGltcG9ydCBDYWxsYWJsZSwgTGlzdAoKaW1wb3J0IGN2MgppbXBvcnQgcGFuZGFzIGFzIHBkCmZyb20gUElMIGltcG9ydCBJbWFnZQppbXBvcnQgdG9yY2gKZnJvbSB0b3JjaC51dGlscy5kYXRhIGltcG9ydCBEYXRhc2V0Cgpmcm9tIC50cmFuc2Zvcm1zIGltcG9ydCB0ZW5zb3JfdHJhbnNmb3JtCmZyb20gLnV0aWxzIGltcG9ydCBPTl9LQUdHTEUKCgpOX0NMQVNTRVMgPSAxMTAzCkRBVEFfUk9PVCA9IFBhdGgoJy4uL2lucHV0L2ltZXQtMjAxOS1mZ3ZjNicgaWYgT05fS0FHR0xFIGVsc2UgJy4vZGF0YScpCgoKY2xhc3MgVHJhaW5EYXRhc2V0KERhdGFzZXQpOgogICAgZGVmIF9faW5pdF9fKHNlbGYsIHJvb3Q6IFBhdGgsIGRmOiBwZC5EYXRhRnJhbWUsCiAgICAgICAgICAgICAgICAgaW1hZ2VfdHJhbnNmb3JtOiBDYWxsYWJsZSwgZGVidWc6IGJvb2wgPSBUcnVlKToKICAgICAgICBzdXBlcigpLl9faW5pdF9fKCkKICAgICAgICBzZWxmLl9yb290ID0gcm9vdAogICAgICAgIHNlbGYuX2RmID0gZGYKICAgICAgICBzZWxmLl9pbWFnZV90cmFuc2Zvcm0gPSBpbWFnZV90cmFuc2Zvcm0KICAgICAgICBzZWxmLl9kZWJ1ZyA9IGRlYnVnCgogICAgZGVmIF9fbGVuX18oc2VsZik6CiAgICAgICAgcmV0dXJuIGxlbihzZWxmLl9kZikKCiAgICBkZWYgX19nZXRpdGVtX18oc2VsZiwgaWR4OiBpbnQpOgogICAgICAgIGl0ZW0gPSBzZWxmLl9kZi5pbG9jW2lkeF0KICAgICAgICBpbWFnZSA9IGxvYWRfdHJhbnNmb3JtX2ltYWdlKAogICAgICAgICAgICBpdGVtLCBzZWxmLl9yb290LCBzZWxmLl9pbWFnZV90cmFuc2Zvcm0sIGRlYnVnPXNlbGYuX2RlYnVnKQogICAgICAgIHRhcmdldCA9IHRvcmNoLnplcm9zKE5fQ0xBU1NFUykKICAgICAgICBmb3IgY2xzIGluIGl0ZW0uYXR0cmlidXRlX2lkcy5zcGxpdCgpOgogICAgICAgICAgICB0YXJnZXRbaW50KGNscyldID0gMQogICAgICAgIHJldHVybiBpbWFnZSwgdGFyZ2V0CgoKY2xhc3MgVFRBRGF0YXNldDoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCByb290OiBQYXRoLCBkZjogcGQuRGF0YUZyYW1lLAogICAgICAgICAgICAgICAgIGltYWdlX3RyYW5zZm9ybTogQ2FsbGFibGUsIHR0YTogaW50KToKICAgICAgICBzZWxmLl9yb290ID0gcm9vdAogICAgICAgIHNlbGYuX2RmID0gZGYKICAgICAgICBzZWxmLl9pbWFnZV90cmFuc2Zvcm0gPSBpbWFnZV90cmFuc2Zvcm0KICAgICAgICBzZWxmLl90dGEgPSB0dGEKCiAgICBkZWYgX19sZW5fXyhzZWxmKToKICAgICAgICByZXR1cm4gbGVuKHNlbGYuX2RmKSAqIHNlbGYuX3R0YQoKICAgIGRlZiBfX2dldGl0ZW1fXyhzZWxmLCBpZHgpOgogICAgICAgIGl0ZW0gPSBzZWxmLl9kZi5pbG9jW2lkeCAlIGxlbihzZWxmLl9kZildCiAgICAgICAgaW1hZ2UgPSBsb2FkX3RyYW5zZm9ybV9pbWFnZShpdGVtLCBzZWxmLl9yb290LCBzZWxmLl9pbWFnZV90cmFuc2Zvcm0pCiAgICAgICAgcmV0dXJuIGltYWdlLCBpdGVtLmlkCgoKZGVmIGxvYWRfdHJhbnNmb3JtX2ltYWdlKAogICAgICAgIGl0ZW0sIHJvb3Q6IFBhdGgsIGltYWdlX3RyYW5zZm9ybTogQ2FsbGFibGUsIGRlYnVnOiBib29sID0gRmFsc2UpOgogICAgaW1hZ2UgPSBsb2FkX2ltYWdlKGl0ZW0sIHJvb3QpCiAgICBpbWFnZSA9IGltYWdlX3RyYW5zZm9ybShpbWFnZSkKICAgIGlmIGRlYnVnOgogICAgICAgIGltYWdlLnNhdmUoJ19kZWJ1Zy5wbmcnKQogICAgcmV0dXJuIHRlbnNvcl90cmFuc2Zvcm0oaW1hZ2UpCgoKZGVmIGxvYWRfaW1hZ2UoaXRlbSwgcm9vdDogUGF0aCkgLT4gSW1hZ2UuSW1hZ2U6CiAgICBpbWFnZSA9IGN2Mi5pbXJlYWQoc3RyKHJvb3QgLyBmJ3tpdGVtLmlkfS5wbmcnKSkKICAgIGltYWdlID0gY3YyLmN2dENvbG9yKGltYWdlLCBjdjIuQ09MT1JfQkdSMlJHQikKICAgIHJldHVybiBJbWFnZS5mcm9tYXJyYXkoaW1hZ2UpCgoKZGVmIGdldF9pZHMocm9vdDogUGF0aCkgLT4gTGlzdFtzdHJdOgogICAgcmV0dXJuIHNvcnRlZCh7cC5uYW1lLnNwbGl0KCdfJylbMF0gZm9yIHAgaW4gcm9vdC5nbG9iKCcqLnBuZycpfSkK',
'imet/utils.py': 'ZnJvbSBkYXRldGltZSBpbXBvcnQgZGF0ZXRpbWUKaW1wb3J0IGpzb24KaW1wb3J0IGdsb2IKaW1wb3J0IG9zCmZyb20gcGF0aGxpYiBpbXBvcnQgUGF0aApmcm9tIG11bHRpcHJvY2Vzc2luZy5wb29sIGltcG9ydCBUaHJlYWRQb29sCmZyb20gdHlwaW5nIGltcG9ydCBEaWN0CgppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHBhbmRhcyBhcyBwZApmcm9tIHNjaXB5LnN0YXRzLm1zdGF0cyBpbXBvcnQgZ21lYW4KaW1wb3J0IHRvcmNoCmZyb20gdG9yY2ggaW1wb3J0IG5uCmZyb20gdG9yY2gudXRpbHMuZGF0YSBpbXBvcnQgRGF0YUxvYWRlcgoKCk9OX0tBR0dMRTogYm9vbCA9ICdLQUdHTEVfV09SS0lOR19ESVInIGluIG9zLmVudmlyb24KCgpkZWYgZ21lYW5fZGYoZGY6IHBkLkRhdGFGcmFtZSkgLT4gcGQuRGF0YUZyYW1lOgogICAgcmV0dXJuIGRmLmdyb3VwYnkobGV2ZWw9MCkuYWdnKGxhbWJkYSB4OiBnbWVhbihsaXN0KHgpKSkKCgpkZWYgbWVhbl9kZihkZjogcGQuRGF0YUZyYW1lKSAtPiBwZC5EYXRhRnJhbWU6CiAgICByZXR1cm4gZGYuZ3JvdXBieShsZXZlbD0wKS5tZWFuKCkKCgpkZWYgbG9hZF9tb2RlbChtb2RlbDogbm4uTW9kdWxlLCBwYXRoOiBQYXRoKSAtPiBEaWN0OgogICAgc3RhdGUgPSB0b3JjaC5sb2FkKHN0cihwYXRoKSkKICAgIG1vZGVsLmxvYWRfc3RhdGVfZGljdChzdGF0ZVsnbW9kZWwnXSkKICAgIHByaW50KCdMb2FkZWQgbW9kZWwgZnJvbSBlcG9jaCB7ZXBvY2h9LCBzdGVwIHtzdGVwOix9Jy5mb3JtYXQoKipzdGF0ZSkpCiAgICByZXR1cm4gc3RhdGUKCgpjbGFzcyBUaHJlYWRpbmdEYXRhTG9hZGVyKERhdGFMb2FkZXIpOgogICAgZGVmIF9faXRlcl9fKHNlbGYpOgogICAgICAgIHNhbXBsZV9pdGVyID0gaXRlcihzZWxmLmJhdGNoX3NhbXBsZXIpCiAgICAgICAgaWYgc2VsZi5udW1fd29ya2VycyA9PSAwOgogICAgICAgICAgICBmb3IgaW5kaWNlcyBpbiBzYW1wbGVfaXRlcjoKICAgICAgICAgICAgICAgIHlpZWxkIHNlbGYuY29sbGF0ZV9mbihbc2VsZi5fZ2V0X2l0ZW0oaSkgZm9yIGkgaW4gaW5kaWNlc10pCiAgICAgICAgZWxzZToKICAgICAgICAgICAgcHJlZmV0Y2ggPSAxCiAgICAgICAgICAgIHdpdGggVGhyZWFkUG9vbChwcm9jZXNzZXM9c2VsZi5udW1fd29ya2VycykgYXMgcG9vbDoKICAgICAgICAgICAgICAgIGZ1dHVyZXMgPSBbXQogICAgICAgICAgICAgICAgZm9yIGluZGljZXMgaW4gc2FtcGxlX2l0ZXI6CiAgICAgICAgICAgICAgICAgICAgZnV0dXJlcy5hcHBlbmQoW3Bvb2wuYXBwbHlfYXN5bmMoc2VsZi5fZ2V0X2l0ZW0sIGFyZ3M9KGksKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIGkgaW4gaW5kaWNlc10pCiAgICAgICAgICAgICAgICAgICAgaWYgbGVuKGZ1dHVyZXMpID4gcHJlZmV0Y2g6CiAgICAgICAgICAgICAgICAgICAgICAgIHlpZWxkIHNlbGYuY29sbGF0ZV9mbihbZi5nZXQoKSBmb3IgZiBpbiBmdXR1cmVzLnBvcCgwKV0pCiAgICAgICAgICAgICAgICAgICAgIyBpdGVtcyA9IHBvb2wubWFwKGxhbWJkYSBpOiBzZWxmLmRhdGFzZXRbaV0sIGluZGljZXMpCiAgICAgICAgICAgICAgICAgICAgIyB5aWVsZCBzZWxmLmNvbGxhdGVfZm4oaXRlbXMpCiAgICAgICAgICAgICAgICBmb3IgYmF0Y2hfZnV0dXJlcyBpbiBmdXR1cmVzOgogICAgICAgICAgICAgICAgICAgIHlpZWxkIHNlbGYuY29sbGF0ZV9mbihbZi5nZXQoKSBmb3IgZiBpbiBiYXRjaF9mdXR1cmVzXSkKCiAgICBkZWYgX2dldF9pdGVtKHNlbGYsIGkpOgogICAgICAgIHJldHVybiBzZWxmLmRhdGFzZXRbaV0KCgpkZWYgd3JpdGVfZXZlbnQobG9nLCBzdGVwOiBpbnQsICoqZGF0YSk6CiAgICBkYXRhWydzdGVwJ10gPSBzdGVwCiAgICBkYXRhWydkdCddID0gZGF0ZXRpbWUubm93KCkuaXNvZm9ybWF0KCkKICAgIGxvZy53cml0ZShqc29uLmR1bXBzKGRhdGEsIHNvcnRfa2V5cz1UcnVlKSkKICAgIGxvZy53cml0ZSgnXG4nKQogICAgbG9nLmZsdXNoKCkKCgpkZWYgcGxvdCgqYXJncywgeW1pbj1Ob25lLCB5bWF4PU5vbmUsIHhtaW49Tm9uZSwgeG1heD1Ob25lLCBwYXJhbXM9RmFsc2UsCiAgICAgICAgIG1heF9wb2ludHM9MjAwLCBsZWdlbmQ9VHJ1ZSwgdGl0bGU9Tm9uZSwKICAgICAgICAgcHJpbnRfa2V5cz1GYWxzZSwgcHJpbnRfcGF0aHM9RmFsc2UsIHBsdD1Ob25lLCBuZXdmaWd1cmU9VHJ1ZSwKICAgICAgICAgeF9zY2FsZT0xKToKICAgICIiIgogICAgVXNlIGluIHRoZSBub3RlYm9vayBsaWtlIHRoaXM6OgoKICAgICAgICAlbWF0cGxvdGxpYiBpbmxpbmUKICAgICAgICBmcm9tIGltZXQudXRpbHMgaW1wb3J0IHBsb3QKICAgICAgICBwbG90KCcuL3J1bnMvb2MyJywgJy4vcnVucy9vYzEnLCAnbG9zcycsICd2YWxpZF9sb3NzJykKCiAgICAiIiIKICAgIGltcG9ydCBqc29uX2xpbmVzICAjIG5vIGF2YWlsYWJsZSBvbiBLYWdnbGUKCiAgICBpZiBwbHQgaXMgTm9uZToKICAgICAgICBmcm9tIG1hdHBsb3RsaWIgaW1wb3J0IHB5cGxvdCBhcyBwbHQKICAgIHBhdGhzLCBrZXlzID0gW10sIFtdCiAgICBmb3IgeCBpbiBhcmdzOgogICAgICAgIGlmIHguc3RhcnRzd2l0aCgnLicpIG9yICcvJyBpbiB4OgogICAgICAgICAgICBpZiAnKicgaW4geDoKICAgICAgICAgICAgICAgIHBhdGhzLmV4dGVuZChnbG9iLmdsb2IoeCkpCiAgICAgICAgICAgIGVsc2U6CiAgICAgICAgICAgICAgICBwYXRocy5hcHBlbmQoeCkKICAgICAgICBlbHNlOgogICAgICAgICAgICBrZXlzLmFwcGVuZCh4KQogICAgaWYgcHJpbnRfcGF0aHM6CiAgICAgICAgcHJpbnQoJ0ZvdW5kIHBhdGhzOiB7fScuZm9ybWF0KCcgJy5qb2luKHNvcnRlZChwYXRocykpKSkKICAgIGlmIG5ld2ZpZ3VyZToKICAgICAgICBwbHQuZmlndXJlKGZpZ3NpemU9KDEyLCA4KSkKICAgIGtleXMgPSBrZXlzIG9yIFsnbG9zcycsICd2YWxpZF9sb3NzJ10KCiAgICB5bGltX2t3ID0ge30KICAgIGlmIHltaW4gaXMgbm90IE5vbmU6CiAgICAgICAgeWxpbV9rd1snYm90dG9tJ10gPSB5bWluCiAgICBpZiB5bWF4IGlzIG5vdCBOb25lOgogICAgICAgIHlsaW1fa3dbJ3RvcCddID0geW1heAogICAgaWYgeWxpbV9rdzoKICAgICAgICBwbHQueWxpbSgqKnlsaW1fa3cpCgogICAgeGxpbV9rdyA9IHt9CiAgICBpZiB4bWluIGlzIG5vdCBOb25lOgogICAgICAgIHhsaW1fa3dbJ2xlZnQnXSA9IHhtaW4KICAgIGlmIHhtYXggaXMgbm90IE5vbmU6CiAgICAgICAgeGxpbV9rd1sncmlnaHQnXSA9IHhtYXgKICAgIGlmIHhsaW1fa3c6CiAgICAgICAgcGx0LnhsaW0oKip4bGltX2t3KQogICAgYWxsX2tleXMgPSBzZXQoKQogICAgZm9yIHBhdGggaW4gc29ydGVkKHBhdGhzKToKICAgICAgICBwYXRoID0gUGF0aChwYXRoKQogICAgICAgIHdpdGgganNvbl9saW5lcy5vcGVuKHBhdGggLyAndHJhaW4ubG9nJywgYnJva2VuPVRydWUpIGFzIGY6CiAgICAgICAgICAgIGV2ZW50cyA9IGxpc3QoZikKICAgICAgICBhbGxfa2V5cy51cGRhdGUoayBmb3IgZSBpbiBldmVudHMgZm9yIGsgaW4gZSkKICAgICAgICBmb3Iga2V5IGluIHNvcnRlZChrZXlzKToKICAgICAgICAgICAgeHMsIHlzLCB5c19lcnIgPSBbXSwgW10sIFtdCiAgICAgICAgICAgIGZvciBlIGluIGV2ZW50czoKICAgICAgICAgICAgICAgIGlmIGtleSBpbiBlOgogICAgICAgICAgICAgICAgICAgIHhzLmFwcGVuZChlWydzdGVwJ10gKiB4X3NjYWxlKQogICAgICAgICAgICAgICAgICAgIHlzLmFwcGVuZChlW2tleV0pCiAgICAgICAgICAgICAgICAgICAgc3RkX2tleSA9IGtleSArICdfc3RkJwogICAgICAgICAgICAgICAgICAgIGlmIHN0ZF9rZXkgaW4gZToKICAgICAgICAgICAgICAgICAgICAgICAgeXNfZXJyLmFwcGVuZChlW3N0ZF9rZXldKQogICAgICAgICAgICBpZiB4czoKICAgICAgICAgICAgICAgIGlmIG5wLmlzbmFuKHlzKS5hbnkoKToKICAgICAgICAgICAgICAgICAgICBwcmludCgnV2FybmluZzogTmFOIHt9IGZvciB7fScuZm9ybWF0KGtleSwgcGF0aCkpCiAgICAgICAgICAgICAgICBpZiBsZW4oeHMpID4gMiAqIG1heF9wb2ludHM6CiAgICAgICAgICAgICAgICAgICAgaW5kaWNlcyA9IChucC5hcmFuZ2UoMCwgbGVuKHhzKSAtIDEsIGxlbih4cykgLyBtYXhfcG9pbnRzKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmFzdHlwZShucC5pbnQzMikpCiAgICAgICAgICAgICAgICAgICAgeHMgPSBucC5hcnJheSh4cylbaW5kaWNlc1sxOl1dCiAgICAgICAgICAgICAgICAgICAgeXMgPSBfc21vb3RoKHlzLCBpbmRpY2VzKQogICAgICAgICAgICAgICAgICAgIGlmIHlzX2VycjoKICAgICAgICAgICAgICAgICAgICAgICAgeXNfZXJyID0gX3Ntb290aCh5c19lcnIsIGluZGljZXMpCiAgICAgICAgICAgICAgICBsYWJlbCA9ICd7fToge30nLmZvcm1hdChwYXRoLCBrZXkpCiAgICAgICAgICAgICAgICBpZiBsYWJlbC5zdGFydHN3aXRoKCdfJyk6CiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAnICcgKyBsYWJlbAogICAgICAgICAgICAgICAgaWYgeXNfZXJyOgogICAgICAgICAgICAgICAgICAgIHlzX2VyciA9IDEuOTYgKiBucC5hcnJheSh5c19lcnIpCiAgICAgICAgICAgICAgICAgICAgcGx0LmVycm9yYmFyKHhzLCB5cywgeWVycj15c19lcnIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZtdD0nLW8nLCBjYXBzaXplPTUsIGNhcHRoaWNrPTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPWxhYmVsKQogICAgICAgICAgICAgICAgZWxzZToKICAgICAgICAgICAgICAgICAgICBwbHQucGxvdCh4cywgeXMsIGxhYmVsPWxhYmVsKQogICAgICAgICAgICAgICAgcGx0LmxlZ2VuZCgpCiAgICBpZiBuZXdmaWd1cmU6CiAgICAgICAgcGx0LmdyaWQoKQogICAgaWYgbGVnZW5kOgogICAgICAgIHBsdC5sZWdlbmQoKQogICAgaWYgdGl0bGU6CiAgICAgICAgcGx0LnRpdGxlKHRpdGxlKQogICAgaWYgcHJpbnRfa2V5czoKICAgICAgICBwcmludCgnRm91bmQga2V5czoge30nCiAgICAgICAgICAgICAgLmZvcm1hdCgnLCAnLmpvaW4oc29ydGVkKGFsbF9rZXlzIC0geydzdGVwJywgJ2R0J30pKSkpCgoKZGVmIF9zbW9vdGgoeXMsIGluZGljZXMpOgogICAgcmV0dXJuIFtucC5tZWFuKHlzW2lkeDogaW5kaWNlc1tpICsgMV1dKQogICAgICAgICAgICBmb3IgaSwgaWR4IGluIGVudW1lcmF0ZShpbmRpY2VzWzotMV0pXQo=',
'imet/main.py': 'aW1wb3J0IGFyZ3BhcnNlCmZyb20gaXRlcnRvb2xzIGltcG9ydCBpc2xpY2UKaW1wb3J0IGpzb24KZnJvbSBwYXRobGliIGltcG9ydCBQYXRoCmltcG9ydCBzaHV0aWwKaW1wb3J0IHdhcm5pbmdzCmZyb20gdHlwaW5nIGltcG9ydCBEaWN0CgppbXBvcnQgbnVtcHkgYXMgbnAKaW1wb3J0IHBhbmRhcyBhcyBwZApmcm9tIHNrbGVhcm4ubWV0cmljcyBpbXBvcnQgZmJldGFfc2NvcmUKZnJvbSBza2xlYXJuLmV4Y2VwdGlvbnMgaW1wb3J0IFVuZGVmaW5lZE1ldHJpY1dhcm5pbmcKaW1wb3J0IHRvcmNoCmZyb20gdG9yY2ggaW1wb3J0IG5uLCBjdWRhCmZyb20gdG9yY2gub3B0aW0gaW1wb3J0IEFkYW0KaW1wb3J0IHRxZG0KCmZyb20gLiBpbXBvcnQgbW9kZWxzCmZyb20gLmRhdGFzZXQgaW1wb3J0IFRyYWluRGF0YXNldCwgVFRBRGF0YXNldCwgZ2V0X2lkcywgTl9DTEFTU0VTLCBEQVRBX1JPT1QKZnJvbSAudHJhbnNmb3JtcyBpbXBvcnQgdHJhaW5fdHJhbnNmb3JtLCB0ZXN0X3RyYW5zZm9ybQpmcm9tIC51dGlscyBpbXBvcnQgKAogICAgd3JpdGVfZXZlbnQsIGxvYWRfbW9kZWwsIG1lYW5fZGYsIFRocmVhZGluZ0RhdGFMb2FkZXIgYXMgRGF0YUxvYWRlciwKICAgIE9OX0tBR0dMRSkKCgpkZWYgbWFpbigpOgogICAgcGFyc2VyID0gYXJncGFyc2UuQXJndW1lbnRQYXJzZXIoKQogICAgYXJnID0gcGFyc2VyLmFkZF9hcmd1bWVudAogICAgYXJnKCdtb2RlJywgY2hvaWNlcz1bJ3RyYWluJywgJ3ZhbGlkYXRlJywgJ3ByZWRpY3RfdmFsaWQnLCAncHJlZGljdF90ZXN0J10pCiAgICBhcmcoJ3J1bl9yb290JykKICAgIGFyZygnLS1tb2RlbCcsIGRlZmF1bHQ9J3Jlc25ldDEwMScpCiAgICBhcmcoJy0tcHJldHJhaW5lZCcsIHR5cGU9aW50LCBkZWZhdWx0PTEpCiAgICBhcmcoJy0tYmF0Y2gtc2l6ZScsIHR5cGU9aW50LCBkZWZhdWx0PTY0KQogICAgYXJnKCctLXN0ZXAnLCB0eXBlPWludCwgZGVmYXVsdD0xKQogICAgYXJnKCctLXdvcmtlcnMnLCB0eXBlPWludCwgZGVmYXVsdD0yIGlmIE9OX0tBR0dMRSBlbHNlIDQpCiAgICBhcmcoJy0tbHInLCB0eXBlPWZsb2F0LCBkZWZhdWx0PTFlLTQpCiAgICBhcmcoJy0tcGF0aWVuY2UnLCB0eXBlPWludCwgZGVmYXVsdD00KQogICAgYXJnKCctLWNsZWFuJywgYWN0aW9uPSdzdG9yZV90cnVlJykKICAgIGFyZygnLS1uLWVwb2NocycsIHR5cGU9aW50LCBkZWZhdWx0PTEwMCkKICAgIGFyZygnLS1lcG9jaC1zaXplJywgdHlwZT1pbnQpCiAgICBhcmcoJy0tdHRhJywgdHlwZT1pbnQsIGRlZmF1bHQ9NCkKICAgIGFyZygnLS11c2Utc2FtcGxlJywgYWN0aW9uPSdzdG9yZV90cnVlJywgaGVscD0ndXNlIGEgc2FtcGxlIG9mIHRoZSBkYXRhc2V0JykKICAgIGFyZygnLS1kZWJ1ZycsIGFjdGlvbj0nc3RvcmVfdHJ1ZScpCiAgICBhcmcoJy0tbGltaXQnLCB0eXBlPWludCkKICAgIGFyZygnLS1mb2xkJywgdHlwZT1pbnQsIGRlZmF1bHQ9MCkKICAgIGFyZ3MgPSBwYXJzZXIucGFyc2VfYXJncygpCgogICAgcnVuX3Jvb3QgPSBQYXRoKGFyZ3MucnVuX3Jvb3QpCiAgICBmb2xkcyA9IHBkLnJlYWRfY3N2KCdmb2xkcy5jc3YnKQogICAgdHJhaW5fcm9vdCA9IERBVEFfUk9PVCAvICgndHJhaW5fc2FtcGxlJyBpZiBhcmdzLnVzZV9zYW1wbGUgZWxzZSAndHJhaW4nKQogICAgaWYgYXJncy51c2Vfc2FtcGxlOgogICAgICAgIGZvbGRzID0gZm9sZHNbZm9sZHNbJ0lkJ10uaXNpbihzZXQoZ2V0X2lkcyh0cmFpbl9yb290KSkpXQogICAgdHJhaW5fZm9sZCA9IGZvbGRzW2ZvbGRzWydmb2xkJ10gIT0gYXJncy5mb2xkXQogICAgdmFsaWRfZm9sZCA9IGZvbGRzW2ZvbGRzWydmb2xkJ10gPT0gYXJncy5mb2xkXQogICAgaWYgYXJncy5saW1pdDoKICAgICAgICB0cmFpbl9mb2xkID0gdHJhaW5fZm9sZFs6YXJncy5saW1pdF0KICAgICAgICB2YWxpZF9mb2xkID0gdmFsaWRfZm9sZFs6YXJncy5saW1pdF0KCiAgICBkZWYgbWFrZV9sb2FkZXIoZGY6IHBkLkRhdGFGcmFtZSwgaW1hZ2VfdHJhbnNmb3JtKSAtPiBEYXRhTG9hZGVyOgogICAgICAgIHJldHVybiBEYXRhTG9hZGVyKAogICAgICAgICAgICBUcmFpbkRhdGFzZXQodHJhaW5fcm9vdCwgZGYsIGltYWdlX3RyYW5zZm9ybSwgZGVidWc9YXJncy5kZWJ1ZyksCiAgICAgICAgICAgIHNodWZmbGU9VHJ1ZSwKICAgICAgICAgICAgYmF0Y2hfc2l6ZT1hcmdzLmJhdGNoX3NpemUsCiAgICAgICAgICAgIG51bV93b3JrZXJzPWFyZ3Mud29ya2VycywKICAgICAgICApCiAgICBjcml0ZXJpb24gPSBubi5CQ0VXaXRoTG9naXRzTG9zcyhyZWR1Y3Rpb249J25vbmUnKQogICAgbW9kZWwgPSBnZXRhdHRyKG1vZGVscywgYXJncy5tb2RlbCkoCiAgICAgICAgbnVtX2NsYXNzZXM9Tl9DTEFTU0VTLCBwcmV0cmFpbmVkPWFyZ3MucHJldHJhaW5lZCkKICAgIHVzZV9jdWRhID0gY3VkYS5pc19hdmFpbGFibGUoKQogICAgZnJlc2hfcGFyYW1zID0gbGlzdChtb2RlbC5mcmVzaF9wYXJhbXMoKSkKICAgIGFsbF9wYXJhbXMgPSBsaXN0KG1vZGVsLnBhcmFtZXRlcnMoKSkKICAgIGlmIHVzZV9jdWRhOgogICAgICAgIG1vZGVsID0gbW9kZWwuY3VkYSgpCgogICAgaWYgYXJncy5tb2RlID09ICd0cmFpbic6CiAgICAgICAgaWYgcnVuX3Jvb3QuZXhpc3RzKCkgYW5kIGFyZ3MuY2xlYW46CiAgICAgICAgICAgIHNodXRpbC5ybXRyZWUocnVuX3Jvb3QpCiAgICAgICAgcnVuX3Jvb3QubWtkaXIoZXhpc3Rfb2s9VHJ1ZSwgcGFyZW50cz1UcnVlKQogICAgICAgIChydW5fcm9vdCAvICdwYXJhbXMuanNvbicpLndyaXRlX3RleHQoCiAgICAgICAgICAgIGpzb24uZHVtcHModmFycyhhcmdzKSwgaW5kZW50PTQsIHNvcnRfa2V5cz1UcnVlKSkKCiAgICAgICAgdHJhaW5fbG9hZGVyID0gbWFrZV9sb2FkZXIodHJhaW5fZm9sZCwgdHJhaW5fdHJhbnNmb3JtKQogICAgICAgIHZhbGlkX2xvYWRlciA9IG1ha2VfbG9hZGVyKHZhbGlkX2ZvbGQsIHRlc3RfdHJhbnNmb3JtKQogICAgICAgIHByaW50KGYne2xlbih0cmFpbl9sb2FkZXIuZGF0YXNldCk6LH0gaXRlbXMgaW4gdHJhaW4sICcKICAgICAgICAgICAgICBmJ3tsZW4odmFsaWRfbG9hZGVyLmRhdGFzZXQpOix9IGluIHZhbGlkJykKCiAgICAgICAgdHJhaW5fa3dhcmdzID0gZGljdCgKICAgICAgICAgICAgYXJncz1hcmdzLAogICAgICAgICAgICBtb2RlbD1tb2RlbCwKICAgICAgICAgICAgY3JpdGVyaW9uPWNyaXRlcmlvbiwKICAgICAgICAgICAgdHJhaW5fbG9hZGVyPXRyYWluX2xvYWRlciwKICAgICAgICAgICAgdmFsaWRfbG9hZGVyPXZhbGlkX2xvYWRlciwKICAgICAgICAgICAgcGF0aWVuY2U9YXJncy5wYXRpZW5jZSwKICAgICAgICAgICAgaW5pdF9vcHRpbWl6ZXI9bGFtYmRhIHBhcmFtcywgbHI6IEFkYW0ocGFyYW1zLCBsciksCiAgICAgICAgICAgIHVzZV9jdWRhPXVzZV9jdWRhLAogICAgICAgICkKCiAgICAgICAgaWYgYXJncy5wcmV0cmFpbmVkOgogICAgICAgICAgICBpZiB0cmFpbihwYXJhbXM9ZnJlc2hfcGFyYW1zLCBuX2Vwb2Nocz0xLCAqKnRyYWluX2t3YXJncyk6CiAgICAgICAgICAgICAgICB0cmFpbihwYXJhbXM9YWxsX3BhcmFtcywgKip0cmFpbl9rd2FyZ3MpCiAgICAgICAgZWxzZToKICAgICAgICAgICAgdHJhaW4ocGFyYW1zPWFsbF9wYXJhbXMsICoqdHJhaW5fa3dhcmdzKQoKICAgIGVsaWYgYXJncy5tb2RlID09ICd2YWxpZGF0ZSc6CiAgICAgICAgdmFsaWRfbG9hZGVyID0gbWFrZV9sb2FkZXIodmFsaWRfZm9sZCwgdGVzdF90cmFuc2Zvcm0pCiAgICAgICAgbG9hZF9tb2RlbChtb2RlbCwgcnVuX3Jvb3QgLyAnbW9kZWwucHQnKQogICAgICAgIHZhbGlkYXRpb24obW9kZWwsIGNyaXRlcmlvbiwgdHFkbS50cWRtKHZhbGlkX2xvYWRlciwgZGVzYz0nVmFsaWRhdGlvbicpLAogICAgICAgICAgICAgICAgICAgdXNlX2N1ZGE9dXNlX2N1ZGEpCgogICAgZWxpZiBhcmdzLm1vZGUuc3RhcnRzd2l0aCgncHJlZGljdCcpOgogICAgICAgIGxvYWRfbW9kZWwobW9kZWwsIHJ1bl9yb290IC8gJ2Jlc3QtbW9kZWwucHQnKQogICAgICAgIHByZWRpY3Rfa3dhcmdzID0gZGljdCgKICAgICAgICAgICAgYmF0Y2hfc2l6ZT1hcmdzLmJhdGNoX3NpemUsCiAgICAgICAgICAgIHR0YT1hcmdzLnR0YSwKICAgICAgICAgICAgdXNlX2N1ZGE9dXNlX2N1ZGEsCiAgICAgICAgICAgIHdvcmtlcnM9YXJncy53b3JrZXJzLAogICAgICAgICkKICAgICAgICBpZiBhcmdzLm1vZGUgPT0gJ3ByZWRpY3RfdmFsaWQnOgogICAgICAgICAgICBwcmVkaWN0KG1vZGVsLCBkZj12YWxpZF9mb2xkLCByb290PXRyYWluX3Jvb3QsIG91dF9wYXRoPXJ1bl9yb290IC8gJ3ZhbC5oNScsICoqcHJlZGljdF9rd2FyZ3MpCiAgICAgICAgZWxpZiBhcmdzLm1vZGUgPT0gJ3ByZWRpY3RfdGVzdCc6CiAgICAgICAgICAgIHRlc3Rfcm9vdCA9IERBVEFfUk9PVCAvICgKICAgICAgICAgICAgICAgICd0ZXN0X3NhbXBsZScgaWYgYXJncy51c2Vfc2FtcGxlIGVsc2UgJ3Rlc3QnKQogICAgICAgICAgICBzcyA9IHBkLnJlYWRfY3N2KERBVEFfUk9PVCAvICdzYW1wbGVfc3VibWlzc2lvbi5jc3YnKQogICAgICAgICAgICBpZiBhcmdzLnVzZV9zYW1wbGU6CiAgICAgICAgICAgICAgICBzcyA9IHNzW3NzWydpZCddLmlzaW4oc2V0KGdldF9pZHModGVzdF9yb290KSkpXQogICAgICAgICAgICBpZiBhcmdzLmxpbWl0OgogICAgICAgICAgICAgICAgc3MgPSBzc1s6YXJncy5saW1pdF0KICAgICAgICAgICAgcHJlZGljdChtb2RlbCwgZGY9c3MsIHJvb3Q9dGVzdF9yb290LAogICAgICAgICAgICAgICAgICAgIG91dF9wYXRoPXJ1bl9yb290IC8gJ3Rlc3QuaDUnLAogICAgICAgICAgICAgICAgICAgICoqcHJlZGljdF9rd2FyZ3MpCgoKZGVmIHByZWRpY3QobW9kZWwsIHJvb3Q6IFBhdGgsIGRmOiBwZC5EYXRhRnJhbWUsIG91dF9wYXRoOiBQYXRoLAogICAgICAgICAgICBiYXRjaF9zaXplOiBpbnQsIHR0YTogaW50LCB3b3JrZXJzOiBpbnQsIHVzZV9jdWRhOiBib29sKToKICAgIGxvYWRlciA9IERhdGFMb2FkZXIoCiAgICAgICAgZGF0YXNldD1UVEFEYXRhc2V0KHJvb3QsIGRmLCB0ZXN0X3RyYW5zZm9ybSwgdHRhPXR0YSksCiAgICAgICAgc2h1ZmZsZT1GYWxzZSwKICAgICAgICBiYXRjaF9zaXplPWJhdGNoX3NpemUsCiAgICAgICAgbnVtX3dvcmtlcnM9d29ya2VycywKICAgICkKICAgIG1vZGVsLmV2YWwoKQogICAgYWxsX291dHB1dHMsIGFsbF9pZHMgPSBbXSwgW10KICAgIHdpdGggdG9yY2gubm9fZ3JhZCgpOgogICAgICAgIGZvciBpbnB1dHMsIGlkcyBpbiB0cWRtLnRxZG0obG9hZGVyLCBkZXNjPSdQcmVkaWN0Jyk6CiAgICAgICAgICAgIGlmIHVzZV9jdWRhOgogICAgICAgICAgICAgICAgaW5wdXRzID0gaW5wdXRzLmN1ZGEoKQogICAgICAgICAgICBvdXRwdXRzID0gdG9yY2guc2lnbW9pZChtb2RlbChpbnB1dHMpKQogICAgICAgICAgICBhbGxfb3V0cHV0cy5hcHBlbmQob3V0cHV0cy5kYXRhLmNwdSgpLm51bXB5KCkpCiAgICAgICAgICAgIGFsbF9pZHMuZXh0ZW5kKGlkcykKICAgIGRmID0gcGQuRGF0YUZyYW1lKAogICAgICAgIGRhdGE9bnAuY29uY2F0ZW5hdGUoYWxsX291dHB1dHMpLAogICAgICAgIGluZGV4PWFsbF9pZHMsCiAgICAgICAgY29sdW1ucz1tYXAoc3RyLCByYW5nZShOX0NMQVNTRVMpKSkKICAgIGRmID0gbWVhbl9kZihkZikKICAgIGRmLnRvX2hkZihvdXRfcGF0aCwgJ3Byb2InLCBpbmRleF9sYWJlbD0naWQnKQogICAgcHJpbnQoZidTYXZlZCBwcmVkaWN0aW9ucyB0byB7b3V0X3BhdGh9JykKCgpkZWYgdHJhaW4oYXJncywgbW9kZWw6IG5uLk1vZHVsZSwgY3JpdGVyaW9uLCAqLCBwYXJhbXMsCiAgICAgICAgICB0cmFpbl9sb2FkZXIsIHZhbGlkX2xvYWRlciwgaW5pdF9vcHRpbWl6ZXIsIHVzZV9jdWRhLAogICAgICAgICAgbl9lcG9jaHM9Tm9uZSwgcGF0aWVuY2U9MiwgbWF4X2xyX2NoYW5nZXM9MikgLT4gYm9vbDoKICAgIGxyID0gYXJncy5scgogICAgbl9lcG9jaHMgPSBuX2Vwb2NocyBvciBhcmdzLm5fZXBvY2hzCiAgICBwYXJhbXMgPSBsaXN0KHBhcmFtcykKICAgIG9wdGltaXplciA9IGluaXRfb3B0aW1pemVyKHBhcmFtcywgbHIpCgogICAgcnVuX3Jvb3QgPSBQYXRoKGFyZ3MucnVuX3Jvb3QpCiAgICBtb2RlbF9wYXRoID0gcnVuX3Jvb3QgLyAnbW9kZWwucHQnCiAgICBiZXN0X21vZGVsX3BhdGggPSBydW5fcm9vdCAvICdiZXN0LW1vZGVsLnB0JwogICAgaWYgbW9kZWxfcGF0aC5leGlzdHMoKToKICAgICAgICBzdGF0ZSA9IGxvYWRfbW9kZWwobW9kZWwsIG1vZGVsX3BhdGgpCiAgICAgICAgZXBvY2ggPSBzdGF0ZVsnZXBvY2gnXQogICAgICAgIHN0ZXAgPSBzdGF0ZVsnc3RlcCddCiAgICAgICAgYmVzdF92YWxpZF9sb3NzID0gc3RhdGVbJ2Jlc3RfdmFsaWRfbG9zcyddCiAgICBlbHNlOgogICAgICAgIGVwb2NoID0gMQogICAgICAgIHN0ZXAgPSAwCiAgICAgICAgYmVzdF92YWxpZF9sb3NzID0gZmxvYXQoJ2luZicpCiAgICBscl9jaGFuZ2VzID0gMAoKICAgIHNhdmUgPSBsYW1iZGEgZXA6IHRvcmNoLnNhdmUoewogICAgICAgICdtb2RlbCc6IG1vZGVsLnN0YXRlX2RpY3QoKSwKICAgICAgICAnZXBvY2gnOiBlcCwKICAgICAgICAnc3RlcCc6IHN0ZXAsCiAgICAgICAgJ2Jlc3RfdmFsaWRfbG9zcyc6IGJlc3RfdmFsaWRfbG9zcwogICAgfSwgc3RyKG1vZGVsX3BhdGgpKQoKICAgIHJlcG9ydF9lYWNoID0gMTAwMDAKICAgIGxvZyA9IHJ1bl9yb290LmpvaW5wYXRoKCd0cmFpbi5sb2cnKS5vcGVuKCdhdCcsIGVuY29kaW5nPSd1dGY4JykKICAgIHZhbGlkX2xvc3NlcyA9IFtdCiAgICBscl9yZXNldF9lcG9jaCA9IGVwb2NoCiAgICBmb3IgZXBvY2ggaW4gcmFuZ2UoZXBvY2gsIG5fZXBvY2hzICsgMSk6CiAgICAgICAgbW9kZWwudHJhaW4oKQogICAgICAgIHRxID0gdHFkbS50cWRtKHRvdGFsPShhcmdzLmVwb2NoX3NpemUgb3IKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuKHRyYWluX2xvYWRlcikgKiBhcmdzLmJhdGNoX3NpemUpKQogICAgICAgIHRxLnNldF9kZXNjcmlwdGlvbihmJ0Vwb2NoIHtlcG9jaH0sIGxyIHtscn0nKQogICAgICAgIGxvc3NlcyA9IFtdCiAgICAgICAgdGwgPSB0cmFpbl9sb2FkZXIKICAgICAgICBpZiBhcmdzLmVwb2NoX3NpemU6CiAgICAgICAgICAgIHRsID0gaXNsaWNlKHRsLCBhcmdzLmVwb2NoX3NpemUgLy8gYXJncy5iYXRjaF9zaXplKQogICAgICAgIHRyeToKICAgICAgICAgICAgbWVhbl9sb3NzID0gMAogICAgICAgICAgICBmb3IgaSwgKGlucHV0cywgdGFyZ2V0cykgaW4gZW51bWVyYXRlKHRsKToKICAgICAgICAgICAgICAgIGlmIHVzZV9jdWRhOgogICAgICAgICAgICAgICAgICAgIGlucHV0cywgdGFyZ2V0cyA9IGlucHV0cy5jdWRhKCksIHRhcmdldHMuY3VkYSgpCiAgICAgICAgICAgICAgICBvdXRwdXRzID0gbW9kZWwoaW5wdXRzKQogICAgICAgICAgICAgICAgbG9zcyA9IF9yZWR1Y2VfbG9zcyhjcml0ZXJpb24ob3V0cHV0cywgdGFyZ2V0cykpCiAgICAgICAgICAgICAgICBiYXRjaF9zaXplID0gaW5wdXRzLnNpemUoMCkKICAgICAgICAgICAgICAgIChiYXRjaF9zaXplICogbG9zcykuYmFja3dhcmQoKQogICAgICAgICAgICAgICAgaWYgKGkgKyAxKSAlIGFyZ3Muc3RlcCA9PSAwOgogICAgICAgICAgICAgICAgICAgIG9wdGltaXplci5zdGVwKCkKICAgICAgICAgICAgICAgICAgICBvcHRpbWl6ZXIuemVyb19ncmFkKCkKICAgICAgICAgICAgICAgICAgICBzdGVwICs9IDEKICAgICAgICAgICAgICAgIHRxLnVwZGF0ZShiYXRjaF9zaXplKQogICAgICAgICAgICAgICAgbG9zc2VzLmFwcGVuZChsb3NzLml0ZW0oKSkKICAgICAgICAgICAgICAgIG1lYW5fbG9zcyA9IG5wLm1lYW4obG9zc2VzWy1yZXBvcnRfZWFjaDpdKQogICAgICAgICAgICAgICAgdHEuc2V0X3Bvc3RmaXgobG9zcz1mJ3ttZWFuX2xvc3M6LjNmfScpCiAgICAgICAgICAgICAgICBpZiBpIGFuZCBpICUgcmVwb3J0X2VhY2ggPT0gMDoKICAgICAgICAgICAgICAgICAgICB3cml0ZV9ldmVudChsb2csIHN0ZXAsIGxvc3M9bWVhbl9sb3NzKQogICAgICAgICAgICB3cml0ZV9ldmVudChsb2csIHN0ZXAsIGxvc3M9bWVhbl9sb3NzKQogICAgICAgICAgICB0cS5jbG9zZSgpCiAgICAgICAgICAgIHNhdmUoZXBvY2ggKyAxKQogICAgICAgICAgICB2YWxpZF9tZXRyaWNzID0gdmFsaWRhdGlvbihtb2RlbCwgY3JpdGVyaW9uLCB2YWxpZF9sb2FkZXIsIHVzZV9jdWRhKQogICAgICAgICAgICB3cml0ZV9ldmVudChsb2csIHN0ZXAsICoqdmFsaWRfbWV0cmljcykKICAgICAgICAgICAgdmFsaWRfbG9zcyA9IHZhbGlkX21ldHJpY3NbJ3ZhbGlkX2xvc3MnXQogICAgICAgICAgICB2YWxpZF9sb3NzZXMuYXBwZW5kKHZhbGlkX2xvc3MpCiAgICAgICAgICAgIGlmIHZhbGlkX2xvc3MgPCBiZXN0X3ZhbGlkX2xvc3M6CiAgICAgICAgICAgICAgICBiZXN0X3ZhbGlkX2xvc3MgPSB2YWxpZF9sb3NzCiAgICAgICAgICAgICAgICBzaHV0aWwuY29weShzdHIobW9kZWxfcGF0aCksIHN0cihiZXN0X21vZGVsX3BhdGgpKQogICAgICAgICAgICBlbGlmIChwYXRpZW5jZSBhbmQgZXBvY2ggLSBscl9yZXNldF9lcG9jaCA+IHBhdGllbmNlIGFuZAogICAgICAgICAgICAgICAgICBtaW4odmFsaWRfbG9zc2VzWy1wYXRpZW5jZTpdKSA+IGJlc3RfdmFsaWRfbG9zcyk6CiAgICAgICAgICAgICAgICAjICJwYXRpZW5jZSIgZXBvY2hzIHdpdGhvdXQgaW1wcm92ZW1lbnQKICAgICAgICAgICAgICAgIGxyX2NoYW5nZXMgKz0xCiAgICAgICAgICAgICAgICBpZiBscl9jaGFuZ2VzID4gbWF4X2xyX2NoYW5nZXM6CiAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgICAgIGxyIC89IDUKICAgICAgICAgICAgICAgIHByaW50KGYnbHIgdXBkYXRlZCB0byB7bHJ9JykKICAgICAgICAgICAgICAgIGxyX3Jlc2V0X2Vwb2NoID0gZXBvY2gKICAgICAgICAgICAgICAgIG9wdGltaXplciA9IGluaXRfb3B0aW1pemVyKHBhcmFtcywgbHIpCiAgICAgICAgZXhjZXB0IEtleWJvYXJkSW50ZXJydXB0OgogICAgICAgICAgICB0cS5jbG9zZSgpCiAgICAgICAgICAgIHByaW50KCdDdHJsK0MsIHNhdmluZyBzbmFwc2hvdCcpCiAgICAgICAgICAgIHNhdmUoZXBvY2gpCiAgICAgICAgICAgIHByaW50KCdkb25lLicpCiAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgcmV0dXJuIFRydWUKCgpkZWYgdmFsaWRhdGlvbigKICAgICAgICBtb2RlbDogbm4uTW9kdWxlLCBjcml0ZXJpb24sIHZhbGlkX2xvYWRlciwgdXNlX2N1ZGEsCiAgICAgICAgKSAtPiBEaWN0W3N0ciwgZmxvYXRdOgogICAgbW9kZWwuZXZhbCgpCiAgICBhbGxfbG9zc2VzLCBhbGxfcHJlZGljdGlvbnMsIGFsbF90YXJnZXRzID0gW10sIFtdLCBbXQogICAgd2l0aCB0b3JjaC5ub19ncmFkKCk6CiAgICAgICAgZm9yIGlucHV0cywgdGFyZ2V0cyBpbiB2YWxpZF9sb2FkZXI6CiAgICAgICAgICAgIGFsbF90YXJnZXRzLmFwcGVuZCh0YXJnZXRzLm51bXB5KCkuY29weSgpKQogICAgICAgICAgICBpZiB1c2VfY3VkYToKICAgICAgICAgICAgICAgIGlucHV0cywgdGFyZ2V0cyA9IGlucHV0cy5jdWRhKCksIHRhcmdldHMuY3VkYSgpCiAgICAgICAgICAgIG91dHB1dHMgPSBtb2RlbChpbnB1dHMpCiAgICAgICAgICAgIGxvc3MgPSBjcml0ZXJpb24ob3V0cHV0cywgdGFyZ2V0cykKICAgICAgICAgICAgYWxsX2xvc3Nlcy5hcHBlbmQoX3JlZHVjZV9sb3NzKGxvc3MpLml0ZW0oKSkKICAgICAgICAgICAgcHJlZGljdGlvbnMgPSB0b3JjaC5zaWdtb2lkKG91dHB1dHMpCiAgICAgICAgICAgIGFsbF9wcmVkaWN0aW9ucy5hcHBlbmQocHJlZGljdGlvbnMuY3B1KCkubnVtcHkoKSkKICAgIGFsbF9wcmVkaWN0aW9ucyA9IG5wLmNvbmNhdGVuYXRlKGFsbF9wcmVkaWN0aW9ucykKICAgIGFsbF90YXJnZXRzID0gbnAuY29uY2F0ZW5hdGUoYWxsX3RhcmdldHMpCgogICAgZGVmIGdldF9zY29yZSh5X3ByZWQpOgogICAgICAgIHdpdGggd2FybmluZ3MuY2F0Y2hfd2FybmluZ3MoKToKICAgICAgICAgICAgd2FybmluZ3Muc2ltcGxlZmlsdGVyKCdpZ25vcmUnLCBjYXRlZ29yeT1VbmRlZmluZWRNZXRyaWNXYXJuaW5nKQogICAgICAgICAgICByZXR1cm4gZmJldGFfc2NvcmUoCiAgICAgICAgICAgICAgICBhbGxfdGFyZ2V0cywgeV9wcmVkLCBiZXRhPTIsIGF2ZXJhZ2U9J3NhbXBsZXMnKQoKICAgIG1ldHJpY3MgPSB7fQogICAgYXJnc29ydGVkID0gYWxsX3ByZWRpY3Rpb25zLmFyZ3NvcnQoYXhpcz0xKQogICAgZm9yIHRocmVzaG9sZCBpbiBbMC4wNSwgMC4wNiwgMC4wNywgMC4wOCwgMC4wOSwgMC4xMCwgMC4xMSwgMC4xMiwgMC4xMywgMC4xNCwgMC4xNSwgMC4yMF06CiAgICAgICAgbWV0cmljc1tmJ3ZhbGlkX2YyX3RoX3t0aHJlc2hvbGQ6LjJmfSddID0gZ2V0X3Njb3JlKAogICAgICAgICAgICBiaW5hcml6ZV9wcmVkaWN0aW9uKGFsbF9wcmVkaWN0aW9ucywgdGhyZXNob2xkLCBhcmdzb3J0ZWQpKQogICAgbWV0cmljc1sndmFsaWRfbG9zcyddID0gbnAubWVhbihhbGxfbG9zc2VzKQogICAgcHJpbnQoJyB8ICcuam9pbihmJ3trfSB7djouM2Z9JyBmb3IgaywgdiBpbiBzb3J0ZWQoCiAgICAgICAgbWV0cmljcy5pdGVtcygpLCBrZXk9bGFtYmRhIGt2OiAta3ZbMV0pKSkKCiAgICByZXR1cm4gbWV0cmljcwoKCmRlZiBiaW5hcml6ZV9wcmVkaWN0aW9uKHByb2JhYmlsaXRpZXMsIHRocmVzaG9sZDogZmxvYXQsIGFyZ3NvcnRlZD1Ob25lLAogICAgICAgICAgICAgICAgICAgICAgICBtaW5fbGFiZWxzPTEsIG1heF9sYWJlbHM9MTApOgogICAgIiIiIFJldHVybiBtYXRyaXggb2YgMC8xIHByZWRpY3Rpb25zLCBzYW1lIHNoYXBlIGFzIHByb2JhYmlsaXRpZXMuCiAgICAiIiIKICAgIGFzc2VydCBwcm9iYWJpbGl0aWVzLnNoYXBlWzFdID09IE5fQ0xBU1NFUwogICAgaWYgYXJnc29ydGVkIGlzIE5vbmU6CiAgICAgICAgYXJnc29ydGVkID0gcHJvYmFiaWxpdGllcy5hcmdzb3J0KGF4aXM9MSkKICAgIG1heF9tYXNrID0gX21ha2VfbWFzayhhcmdzb3J0ZWQsIG1heF9sYWJlbHMpCiAgICBtaW5fbWFzayA9IF9tYWtlX21hc2soYXJnc29ydGVkLCBtaW5fbGFiZWxzKQogICAgcHJvYl9tYXNrID0gcHJvYmFiaWxpdGllcyA+IHRocmVzaG9sZAogICAgcmV0dXJuIChtYXhfbWFzayAmIHByb2JfbWFzaykgfCBtaW5fbWFzawoKCmRlZiBfbWFrZV9tYXNrKGFyZ3NvcnRlZCwgdG9wX246IGludCk6CiAgICBtYXNrID0gbnAuemVyb3NfbGlrZShhcmdzb3J0ZWQsIGR0eXBlPW5wLnVpbnQ4KQogICAgY29sX2luZGljZXMgPSBhcmdzb3J0ZWRbOiwgLXRvcF9uOl0ucmVzaGFwZSgtMSkKICAgIHJvd19pbmRpY2VzID0gW2kgLy8gdG9wX24gZm9yIGkgaW4gcmFuZ2UobGVuKGNvbF9pbmRpY2VzKSldCiAgICBtYXNrW3Jvd19pbmRpY2VzLCBjb2xfaW5kaWNlc10gPSAxCiAgICByZXR1cm4gbWFzawoKCmRlZiBfcmVkdWNlX2xvc3MobG9zcyk6CiAgICByZXR1cm4gbG9zcy5zdW0oKSAvIGxvc3Muc2hhcGVbMF0KCgppZiBfX25hbWVfXyA9PSAnX19tYWluX18nOgogICAgbWFpbigpCg==',
'setup.py': 'ZnJvbSBzZXR1cHRvb2xzIGltcG9ydCBzZXR1cAoKc2V0dXAoCiAgICBuYW1lPSdpbWV0JywKICAgIHBhY2thZ2VzPVsnaW1ldCddLAop'
}
for path, encoded in file_data.items():
print(path)
path = Path(path)
path.parent.mkdir(exist_ok=True)
path.write_bytes(base64.b64decode(encoded))
def run(command):
os.system('export PYTHONPATH=${PYTHONPATH}:/kaggle/working && ' + command)
print(os.listdir('/kaggle/working/'))
run('python setup.py develop --install-dir /kaggle/working')
!cp '../input/public-0615/best-model.pt' '/kaggle/working/'
run('python setup.py develop --install-dir /kaggle/working')
run('python -m imet.make_folds --n-folds 40')
# run('python -m imet.main train model_1 --n-epochs 16')
run('python -m imet.main predict_test .')
run('python -m imet.make_submission ./test.h5 /kaggle/working/sub.csv --threshold 0.10')
print(os.listdir('.'))
try:
test_preds_kon = pd.read_csv('sub.csv')
attr_ids_kon = test_preds_kon['attribute_ids'].apply(lambda x: x.split()).values
attr_id_thr = 0.10
except Exception as e:
pass
len(attr_ids_kon)
!rm -rf /kaggle/working/*
import os
os.system('cp -r ../input/pretrained-models-cadene/pretrained_models_pytroch/ /kaggle/working/')
os.chdir('/kaggle/working/pretrained_models_pytroch/pretrained-models.pytorch-master')
!python setup.py install
import os
import pickle
import fastai
from fastai.vision import *
from fastai.vision.models.cadene_models import *
from shutil import copyfile
fastai.__version__
os.chdir('/kaggle/working')
os.listdir('.')
# Source: https://www.kaggle.com/c/human-protein-atlas-image-classification/discussion/78109
class FocalLoss(nn.Module):
def __init__(self, gamma=2):
super().__init__()
self.gamma = gamma
def forward(self, logit, target):
target = target.float()
max_val = (-logit).clamp(min=0)
loss = logit - logit * target + max_val + \
((-max_val).exp() + (-logit - max_val).exp()).log()
invprobs = F.logsigmoid(-logit * (target * 2.0 - 1.0))
loss = (invprobs * self.gamma).exp() * loss
if len(loss.size())==2:
loss = loss.sum(dim=1)
return loss.mean()
path = Path('../input/imet-2019-fgvc6/') # iMet data path
BATCH = 32
SIZE = 256
from torch.utils import model_zoo
Path('models').mkdir(exist_ok=True)
test_df = pd.read_csv(path/'sample_submission.csv')
test_df.head()
labels_df = pd.read_csv(path/'labels.csv')
labels_df.head()
train_df = pd.read_csv(path/'train.csv')
train_df.head()
t_preds = []
n_fold = 5
val_preds = np.zeros((2, 10923, 1103))
tfms = get_transforms(do_flip=True, flip_vert=False, max_rotate=0.10, max_zoom=1.5, max_warp=0.2, max_lighting=0.2,
xtra_tfms=[(symmetric_warp(magnitude=(-0,0), p=0)), rand_crop(p=0.75),])
train, test = [ImageList.from_df(df, path=path, cols='id', folder=folder, suffix='.png')
for df, folder in zip([train_df, test_df], ['train', 'test'])]
data = (train.split_by_rand_pct(0.1, seed=42)
.label_from_df(cols='attribute_ids', label_delim=' ')
.add_test(test)
.transform(tfms, size=SIZE, resize_method=ResizeMethod.PAD, padding_mode='border',)
.databunch(path=Path('.'), bs=BATCH).normalize(imagenet_stats))
# model dictionary
model = {
'seresnextkfolds_15': 'se_resnext50_32x4d-a260b3a4',
'seresnextkfolds_11': 'se_resnext50_32x4d-a260b3a4',
'resnet5022epochs': 'resnet50',
'seresnextkfolds_16': 'se_resnext50_32x4d-a260b3a4',
'seresnextkfolds_49': 'se_resnext50_32x4d-a260b3a4',
}
for model_path in model.keys():
m_path = 'stage-1.pth'
if len(model_path.split('_')) > 1:
m_path = 'seresnext-' + model_path.split('_')[1] + '.pth'
print(model_path, m_path)
copyfile('../input/' + model_path.split('_')[0] + '/' + m_path, 'models/'+ model[model_path] +'.pth')
def load_url(*args, **kwargs):
model_dir = Path('models')
filename = model[model_path] + '.pth'
if not (model_dir/filename).is_file(): raise FileNotFoundError
return torch.load(model_dir/filename)
model_zoo.load_url = load_url
arch = se_resnext50_32x4d
if model[model_path] == 'resnet50':
arch = models.resnet50
learn = cnn_learner(data, base_arch=arch, loss_func=FocalLoss(), metrics=fbeta, pretrained=False)
learn.load(model[model_path])
preds = learn.TTA(ds_type=DatasetType.Test)
np.save(model_path + '.npy', preds[0].numpy())
t_preds.append(preds[0].numpy())
attr_ids = []
thrs = [0.27, 0.27, 0.28, 0.27, 0.29]
def preds_ids(preds, thr):
preds = [torch.tensor(preds)]
return [i2c[np.where(t==1)[0],1].astype(str) for t in (preds[0].sigmoid()>thr).long()]
attr_ids = [preds_ids(t_preds[i], thrs[i]) for i in range(len(t_preds))]
I take all the preds generated by all models and for every sample I count the frequency of attribute ids.
So for example,
For sample 1 let's say 3 model predicted attr_id_1, and 1 model predicted attr_id_2. Then there is a high chance attr_id_1 must be right one.
In such a way I calculate frequency of all attr ids and then all the attr_id frequency which are greater than equal to a threshold thr I choose those for final preds
attr_ids.append(attr_ids_kon)
thrs.append(attr_id_thr)
res_attr_ids = []
thr = 4/6
for i in range(len(attr_ids[0])):
id_s = np.concatenate([p_attr_id[i] for p_attr_id in attr_ids],
axis=None)
id_s, counts = np.unique(list(id_s),
return_counts=True)
counts = counts/6
pids = ' '.join(id_s[np.where(counts >= thr)])
res_attr_ids.append(pids)
print(len(res_attr_ids), len(attr_ids[0]))
test_df.attribute_ids = res_attr_ids
test_df.to_csv('submission.csv', index=False)
test_df.head()
Please upvote if you find the kernel interesting.
Note: I haven't revealed my private datasets so I dont think this kernel should affect the standings. I have just revealed the approach of my solution.
!rm -rf /kaggle/working/pretrained_models_pytroch