ZnJvbSB0a2ludGVyIGltcG9ydCAqCgpDQU5WQVNfV0lEVEggPSA2NDAKQ0FOVkFTX0hFSUdIVCA9IDQ4MApDQU5WQVNfQ0VOVEVSX1ggPSBDQU5WQVNfV0lEVEggLyAyCkNBTlZBU19DRU5URVJfWSA9IENBTlZBU19IRUlHSFQgLyAyCklNQUdFX0VOTEFSR0VfRkFDVE9SID0gMTEKSEVBUlRfQ09MT1IgPSAmcXVvdDsjRkY2OUI0JnF1b3Q7CgpkZWYgZ2VuZXJhdGVfaGVhcnRfY29vcmRpbmF0ZSh0LCBzaHJpbmtfcmF0aW89SU1BR0VfRU5MQVJHRV9GQUNUT1IpOgogICAgIyDln7rnoYDlh73mlbDvvIznlJ/miJDniLHlv4PnmoTln7rmnKzlvaLnirYKICAgIHggPSAxNiAqIChzaW4odCkgKiogMykKICAgIHkgPSAtKDEzICogY29zKHQpIC0gNSAqIGNvcygyICogdCkgLSAyICogY29zKDMgKiB0KSAtIGNvcyg0ICogdCkpCgogICAgIyDmlL7lpKfniLHlv4MKICAgIHggKj0gc2hyaW5rX3JhdGlvCiAgICB5ICo9IHNocmlua19yYXRpbwoKICAgICMg5bCG54ix5b+D56e75Yiw55S75biD5Lit5aSuCiAgICB4ICs9IENBTlZBU19DRU5URVJfWAogICAgeSArPSBDQU5WQVNfQ0VOVEVSX1kKCiAgICByZXR1cm4gaW50KHgpLCBpbnQoeSkKCmRlZiBzY2F0dGVyX2luc2lkZSh4LCB5LCBiZXRhPTAuMTUpOgoKICAgIHJhdGlvX3ggPSAtIGJldGEgKiBsb2cocmFuZG9tLnJhbmRvbSgpKQogICAgcmF0aW9feSA9IC0gYmV0YSAqIGxvZyhyYW5kb20ucmFuZG9tKCkpCgogICAgZHggPSByYXRpb194ICogKHggLSBDQU5WQVNfQ0VOVEVSX1gpCiAgICBkeSA9IHJhdGlvX3kgKiAoeSAtIENBTlZBU19DRU5URVJfWSkKCiAgICByZXR1cm4geCAtIGR4LCB5IC0gZHkKCmRlZiBzaHJpbmtfY29vcmRpbmF0ZSh4LCB5LCByYXRpbyk6CiAgICAmcXVvdDsmcXVvdDsmcXVvdDsKICAgIOaKluWKqOaViOaenO+8jOeUqOS6juiwg+aVtOeIseW/g+eahOi3s+WKqAogICAgOnBhcmFtIHg6IOWOn+eCueeahCB4IOWdkOaghwogICAgOnBhcmFtIHk6IOWOn+eCueeahCB5IOWdkOaghwogICAgOnBhcmFtIHJhdGlvOiDmipbliqjnmoTmr5TkvosKICAgIDpyZXR1cm46IOaWsOeCueeahOWdkOaghyAoeCwgeSkKICAgICZxdW90OyZxdW90OyZxdW90OwogICAgZm9yY2UgPSAtMSAvICgoKHggLSBDQU5WQVNfQ0VOVEVSX1gpICoqIDIgKyAoeSAtIENBTlZBU19DRU5URVJfWSkgKiogMikgKiogMC42KSAgIyDosIPmlbTniLHlv4Pot7PliqjnmoTlj4LmlbAKICAgIGR4ID0gcmF0aW8gKiBmb3JjZSAqICh4IC0gQ0FOVkFTX0NFTlRFUl9YKQogICAgZHkgPSByYXRpbyAqIGZvcmNlICogKHkgLSBDQU5WQVNfQ0VOVEVSX1kpCiAgICByZXR1cm4geCAtIGR4LCB5IC0gZHkKCmRlZiBjdXN0b21fY3VydmUocCk6CiAgICAmcXVvdDsmcXVvdDsmcXVvdDsKICAgIOiHquWumuS5ieabsue6v+WHveaVsO+8jOiwg+aVtOi3s+WKqOWRqOacnwogICAgOnBhcmFtIHA6IOWPguaVsO+8jOaOp+WItuabsue6v+eahOW9oueKtgogICAgOnJldHVybjog5q2j5bym5YC877yM55So5LqO6LCD5pW054ix5b+D55qE6Lez5YqoCiAgICAmcXVvdDsmcXVvdDsmcXVvdDsKICAgICMg5Y+v5Lul5bCd6K+V5o2i5YW25LuW55qE5Yqo5oCB5Ye95pWw77yM6L6+5Yiw5pu05pyJ5Yqb6YeP55qE5pWI5p6c77yI5aaC6LSd5aGe5bCU5puy57q/77yJCiAgICByZXR1cm4gMiAqICgyICogc2luKDQgKiBwKSkgLyAoMiAqIHBpKQoKY2xhc3MgQmVhdGluZ0hlYXJ0OgogICAgJnF1b3Q7JnF1b3Q7JnF1b3Q7CiAgICDot7PliqjnmoTniLHlv4PnsbsKICAgICZxdW90OyZxdW90OyZxdW90OwoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBnZW5lcmF0ZV9mcmFtZT0yMCk6CiAgICAgICAgc2VsZi5fb3JpZ2luYWxfcG9pbnRzID0gc2V0KCkgICMg5Y6f5aeL54ix5b+D55qE5Z2Q5qCH6ZuG5ZCICiAgICAgICAgc2VsZi5fZWRnZV9kaWZmdXNpb25fcG9pbnRzID0gc2V0KCkgICMg6L6557yY5omp5pWj5pWI5p6c55qE54K55Z2Q5qCH6ZuG5ZCICiAgICAgICAgc2VsZi5fY2VudGVyX2RpZmZ1c2lvbl9wb2ludHMgPSBzZXQoKSAgIyDkuK3lv4PmianmlaPmlYjmnpznmoTngrnlnZDmoIfpm4blkIgKICAgICAgICBzZWxmLmFsbF9mcmFtZV9wb2ludHMgPSB7fSAgIyDmr4/luKfnmoTliqjmgIHngrnlnZDmoIcKICAgICAgICBzZWxmLmJ1aWxkKDIwMDApCgogICAgICAgIHNlbGYucmFuZG9tX2hhbG8gPSAxMDAwCgogICAgICAgIHNlbGYuZ2VuZXJhdGVfZnJhbWUgPSBnZW5lcmF0ZV9mcmFtZQogICAgICAgIGZvciBmcmFtZSBpbiByYW5nZShnZW5lcmF0ZV9mcmFtZSk6CiAgICAgICAgICAgIHNlbGYuY2FsY3VsYXRlX2ZyYW1lKGZyYW1lKQoKICAgIGRlZiBidWlsZChzZWxmLCBudW1iZXJfb2ZfcG9pbnRzKToKICAgICAgICAjIOeUn+aIkOWOn+Wni+eIseW/g+eahOWdkOaghwogICAgICAgIGZvciBfIGluIHJhbmdlKG51bWJlcl9vZl9wb2ludHMpOgogICAgICAgICAgICB0ID0gcmFuZG9tLnVuaWZvcm0oMCwgMiAqIHBpKSAgIyDpmo/mnLrlj4LmlbDvvIznlKjkuo7nlJ/miJDkuI3lrozmlbTnmoTniLHlv4MKICAgICAgICAgICAgeCwgeSA9IGdlbmVyYXRlX2hlYXJ0X2Nvb3JkaW5hdGUodCkKICAgICAgICAgICAgc2VsZi5fb3JpZ2luYWxfcG9pbnRzLmFkZCgoeCwgeSkpCgogICAgICAgICMg55Sf5oiQ54ix5b+D5YaF5omp5pWj55qE54K5CiAgICAgICAgZm9yIHgsIHkgaW4gbGlzdChzZWxmLl9vcmlnaW5hbF9wb2ludHMpOgogICAgICAgICAgICBmb3IgXyBpbiByYW5nZSgzKToKICAgICAgICAgICAgICAgIHgsIHkgPSBzY2F0dGVyX2luc2lkZSh4LCB5LCAwLjA1KQogICAgICAgICAgICAgICAgc2VsZi5fZWRnZV9kaWZmdXNpb25fcG9pbnRzLmFkZCgoeCwgeSkpCgogICAgICAgICMg55Sf5oiQ54ix5b+D5YaF5YaN5qyh5omp5pWj55qE54K5CiAgICAgICAgcG9pbnRfbGlzdCA9IGxpc3Qoc2VsZi5fb3JpZ2luYWxfcG9pbnRzKQogICAgICAgIGZvciBfIGluIHJhbmdlKDYwMDApOgogICAgICAgICAgICB4LCB5ID0gcmFuZG9tLmNob2ljZShwb2ludF9saXN0KQogICAgICAgICAgICB4LCB5ID0gc2NhdHRlcl9pbnNpZGUoeCwgeSwgMC4xNykKICAgICAgICAgICAgc2VsZi5fY2VudGVyX2RpZmZ1c2lvbl9wb2ludHMuYWRkKCh4LCB5KSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgY2FsY3VsYXRlX3Bvc2l0aW9uKHgsIHksIHJhdGlvKToKICAgICAgICAjIOiwg+aVtOe8qeaUvuavlOS+iwogICAgICAgIGZvcmNlID0gMSAvICgoKHggLSBDQU5WQVNfQ0VOVEVSX1gpICoqIDIgKyAoeSAtIENBTlZBU19DRU5URVJfWSkgKiogMikgKiogMC41MjApICAjIOiwg+aVtOeIseW/g+i3s+WKqOeahOWPguaVsAoKICAgICAgICBkeCA9IHJhdGlvICogZm9yY2UgKiAoeCAtIENBTlZBU19DRU5URVJfWCkgKyByYW5kb20ucmFuZGludCgtMSwgMSkKICAgICAgICBkeSA9IHJhdGlvICogZm9yY2UgKiAoeSAtIENBTlZBU19DRU5URVJfWSkgKyByYW5kb20ucmFuZGludCgtMSwgMSkKCiAgICAgICAgcmV0dXJuIHggLSBkeCwgeSAtIGR5CgogICAgZGVmIGNhbGN1bGF0ZV9mcmFtZShzZWxmLCBmcmFtZV9udW1iZXIpOgogICAgICAgIHJhdGlvID0gMTAgKiBjdXN0b21fY3VydmUoZnJhbWVfbnVtYmVyIC8gMTAgKiBwaSkgICMg5ZyG5ruR55qE5ZGo5pyf55qE57yp5pS+5q+U5L6LCgogICAgICAgIGhhbG9fcmFkaXVzID0gaW50KDQgKyA2ICogKDEgKyBjdXN0b21fY3VydmUoZnJhbWVfbnVtYmVyIC8gMTAgKiBwaSkpKQogICAgICAgIGhhbG9fbnVtYmVyID0gaW50KDMwMDAgKyA0MDAwICogYWJzKGN1c3RvbV9jdXJ2ZShmcmFtZV9udW1iZXIgLyAxMCAqIHBpKSAqKiAyKSkKCiAgICAgICAgYWxsX3BvaW50cyA9IFtdCgogICAgICAgICMg55Sf5oiQ5YWJ546v55qE54K5CiAgICAgICAgaGVhcnRfaGFsb19wb2ludHMgPSBzZXQoKQogICAgICAgIGZvciBfIGluIHJhbmdlKGhhbG9fbnVtYmVyKToKICAgICAgICAgICAgdCA9IHJhbmRvbS51bmlmb3JtKDAsIDQgKiBwaSkKICAgICAgICAgICAgeCwgeSA9IGdlbmVyYXRlX2hlYXJ0X2Nvb3JkaW5hdGUodCwgc2hyaW5rX3JhdGlvPTExLjUpCiAgICAgICAgICAgIHgsIHkgPSBzaHJpbmtfY29vcmRpbmF0ZSh4LCB5LCBoYWxvX3JhZGl1cykKICAgICAgICAgICAgaWYgKHgsIHkpIG5vdCBpbiBoZWFydF9oYWxvX3BvaW50czoKICAgICAgICAgICAgICAgICMg5aSE55CG5paw55qE54K5CiAgICAgICAgICAgICAgICBoZWFydF9oYWxvX3BvaW50cy5hZGQoKHgsIHkpKQogICAgICAgICAgICAgICAgeCArPSByYW5kb20ucmFuZGludCgtMTQsIDE0KQogICAgICAgICAgICAgICAgeSArPSByYW5kb20ucmFuZGludCgtMTQsIDE0KQogICAgICAgICAgICAgICAgc2l6ZSA9IHJhbmRvbS5jaG9pY2UoKDEsIDIsIDIpKQogICAgICAgICAgICAgICAgYWxsX3BvaW50cy5hcHBlbmQoKHgsIHksIHNpemUpKQoKICAgICAgICAjIOeUn+aIkOeIseW/g+i9ruW7k+eahOeCuQogICAgICAgIGZvciB4LCB5IGluIHNlbGYuX29yaWdpbmFsX3BvaW50czoKICAgICAgICAgICAgeCwgeSA9IHNlbGYuY2FsY3VsYXRlX3Bvc2l0aW9uKHgsIHksIHJhdGlvKQogICAgICAgICAgICBzaXplID0gcmFuZG9tLnJhbmRpbnQoMSwgMykKICAgICAgICAgICAgYWxsX3BvaW50cy5hcHBlbmQoKHgsIHksIHNpemUpKQoKICAgICAgICAjIOeUn+aIkOeIseW/g+WGheWuueeahOeCuQogICAgICAgIGZvciB4LCB5IGluIHNlbGYuX2VkZ2VfZGlmZnVzaW9uX3BvaW50czoKICAgICAgICAgICAgeCwgeSA9IHNlbGYuY2FsY3VsYXRlX3Bvc2l0aW9uKHgsIHksIHJhdGlvKQogICAgICAgICAgICBzaXplID0gcmFuZG9tLnJhbmRpbnQoMSwgMikKICAgICAgICAgICAgYWxsX3BvaW50cy5hcHBlbmQoKHgsIHksIHNpemUpKQoKICAgICAgICBmb3IgeCwgeSBpbiBzZWxmLl9jZW50ZXJfZGlmZnVzaW9uX3BvaW50czoKICAgICAgICAgICAgeCwgeSA9IHNlbGYuY2FsY3VsYXRlX3Bvc2l0aW9uKHgsIHksIHJhdGlvKQogICAgICAgICAgICBzaXplID0gcmFuZG9tLnJhbmRpbnQoMSwgMikKICAgICAgICAgICAgYWxsX3BvaW50cy5hcHBlbmQoKHgsIHksIHNpemUpKQoKICAgICAgICBzZWxmLmFsbF9mcmFtZV9wb2ludHNbZnJhbWVfbnVtYmVyXSA9IGFsbF9wb2ludHMKCiAgICBkZWYgcmVuZGVyKHNlbGYsIHJlbmRlcl9jYW52YXMsIHJlbmRlcl9mcmFtZSk6CiAgICAgICAgZm9yIHgsIHksIHNpemUgaW4gc2VsZi5hbGxfZnJhbWVfcG9pbnRzW3JlbmRlcl9mcmFtZSAlIHNlbGYuZ2VuZXJhdGVfZnJhbWVdOgogICAgICAgICAgICByZW5kZXJfY2FudmFzLmNyZWF0ZV9yZWN0YW5nbGUoeCwgeSwgeCArIHNpemUsIHkgKyBzaXplLCB3aWR0aD0wLCBmaWxsPUhFQVJUX0NPTE9SKQoKZGVmIGRyYXcobWFpbl93aW5kb3csIHJlbmRlcl9jYW52YXMsIHJlbmRlcl9oZWFydCwgcmVuZGVyX2ZyYW1lPTApOgogICAgcmVuZGVyX2NhbnZhcy5kZWxldGUoJ2FsbCcpCiAgICByZW5kZXJfaGVhcnQucmVuZGVyKHJlbmRlcl9jYW52YXMsIHJlbmRlcl9mcmFtZSkKICAgIG1haW5fd2luZG93LmFmdGVyKDE2MCwgZHJhdywgbWFpbl93aW5kb3csIHJlbmRlcl9jYW52YXMsIHJlbmRlcl9oZWFydCwgcmVuZGVyX2ZyYW1lICsgMSkKCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6CiAgICByb290ID0gVGsoKQogICAgcm9vdC50aXRsZSgnQmVhdGluZyBIZWFydCcpCiAgICBjYW52YXMgPSBDYW52YXMocm9vdCwgYmc9J2JsYWNrJywgaGVpZ2h0PUNBTlZBU19IRUlHSFQsIHdpZHRoPUNBTlZBU19XSURUSCkKICAgIGNhbnZhcy5wYWNrKCkKICAgIGhlYXJ0ID0gQmVhdGluZ0hlYXJ0KCkKICAgIGRyYXcocm9vdCwgY2FudmFzLCBoZWFydCkKICAgIExhYmVsKHJvb3QsIHRleHQ9JnF1b3Q75aSa5ZCD54K55oqb5pil5oGoJnF1b3Q7LCBiZz0mcXVvdDtibGFjayZxdW90OywgZmc9JnF1b3Q7I0ZGNjlCNCZxdW90OywgKS5wbGFjZShyZWx4PS41LCByZWx5PS41LCBhbmNob3I9Q0VOVEVSKQogICAgIyDlnKjniLHlv4PkuK3pl7TliqDkuIrlrZcKICAgIExhYmVsKHJvb3QsIHRleHQ9JnF1b3Q75Y+v5Y+v5LiT6Zeo5Li65bCP5LqR5a6a5Yi2JnF1b3Q7LCBiZz0mcXVvdDtibGFjayZxdW90OywgZmc9JnF1b3Q7I0ZGNjlCNCZxdW90OywgZm9udD0oJ+Wui+S9kycsIDE4KSkucGxhY2UocmVseD0uNTAsIHJlbHk9LjEsIGFuY2hvcj1DRU5URVIpCiAgICAjIOWcqOeIseW/g+S4iumdouWKoOS4iuWtlwogICAgcm9vdC5tYWlubG9vcCgpZnJvbSB0a2ludGVyIGltcG9ydCAqCgpDQU5WQVNfV0lEVEggPSA2NDAKQ0FOVkFTX0hFSUdIVCA9IDQ4MApDQU5WQVNfQ0VOVEVSX1ggPSBDQU5WQVNfV0lEVEggLyAyCkNBTlZBU19DRU5URVJfWSA9IENBTlZBU19IRUlHSFQgLyAyCklNQUdFX0VOTEFSR0VfRkFDVE9SID0gMTEKSEVBUlRfQ09MT1IgPSAmcXVvdDsjRkY2OUI0JnF1b3Q7CgpkZWYgZ2VuZXJhdGVfaGVhcnRfY29vcmRpbmF0ZSh0LCBzaHJpbmtfcmF0aW89SU1BR0VfRU5MQVJHRV9GQUNUT1IpOgogICAgIyDln7rnoYDlh73mlbDvvIznlJ/miJDniLHlv4PnmoTln7rmnKzlvaLnirYKICAgIHggPSAxNiAqIChzaW4odCkgKiogMykKICAgIHkgPSAtKDEzICogY29zKHQpIC0gNSAqIGNvcygyICogdCkgLSAyICogY29zKDMgKiB0KSAtIGNvcyg0ICogdCkpCgogICAgIyDmlL7lpKfniLHlv4MKICAgIHggKj0gc2hyaW5rX3JhdGlvCiAgICB5ICo9IHNocmlua19yYXRpbwoKICAgICMg5bCG54ix5b+D56e75Yiw55S75biD5Lit5aSuCiAgICB4ICs9IENBTlZBU19DRU5URVJfWAogICAgeSArPSBDQU5WQVNfQ0VOVEVSX1kKCiAgICByZXR1cm4gaW50KHgpLCBpbnQoeSkKCmRlZiBzY2F0dGVyX2luc2lkZSh4LCB5LCBiZXRhPTAuMTUpOgoKICAgIHJhdGlvX3ggPSAtIGJldGEgKiBsb2cocmFuZG9tLnJhbmRvbSgpKQogICAgcmF0aW9feSA9IC0gYmV0YSAqIGxvZyhyYW5kb20ucmFuZG9tKCkpCgogICAgZHggPSByYXRpb194ICogKHggLSBDQU5WQVNfQ0VOVEVSX1gpCiAgICBkeSA9IHJhdGlvX3kgKiAoeSAtIENBTlZBU19DRU5URVJfWSkKCiAgICByZXR1cm4geCAtIGR4LCB5IC0gZHkKCmRlZiBzaHJpbmtfY29vcmRpbmF0ZSh4LCB5LCByYXRpbyk6CiAgICAmcXVvdDsmcXVvdDsmcXVvdDsKICAgIOaKluWKqOaViOaenO+8jOeUqOS6juiwg+aVtOeIseW/g+eahOi3s+WKqAogICAgOnBhcmFtIHg6IOWOn+eCueeahCB4IOWdkOaghwogICAgOnBhcmFtIHk6IOWOn+eCueeahCB5IOWdkOaghwogICAgOnBhcmFtIHJhdGlvOiDmipbliqjnmoTmr5TkvosKICAgIDpyZXR1cm46IOaWsOeCueeahOWdkOaghyAoeCwgeSkKICAgICZxdW90OyZxdW90OyZxdW90OwogICAgZm9yY2UgPSAtMSAvICgoKHggLSBDQU5WQVNfQ0VOVEVSX1gpICoqIDIgKyAoeSAtIENBTlZBU19DRU5URVJfWSkgKiogMikgKiogMC42KSAgIyDosIPmlbTniLHlv4Pot7PliqjnmoTlj4LmlbAKICAgIGR4ID0gcmF0aW8gKiBmb3JjZSAqICh4IC0gQ0FOVkFTX0NFTlRFUl9YKQogICAgZHkgPSByYXRpbyAqIGZvcmNlICogKHkgLSBDQU5WQVNfQ0VOVEVSX1kpCiAgICByZXR1cm4geCAtIGR4LCB5IC0gZHkKCmRlZiBjdXN0b21fY3VydmUocCk6CiAgICAmcXVvdDsmcXVvdDsmcXVvdDsKICAgIOiHquWumuS5ieabsue6v+WHveaVsO+8jOiwg+aVtOi3s+WKqOWRqOacnwogICAgOnBhcmFtIHA6IOWPguaVsO+8jOaOp+WItuabsue6v+eahOW9oueKtgogICAgOnJldHVybjog5q2j5bym5YC877yM55So5LqO6LCD5pW054ix5b+D55qE6Lez5YqoCiAgICAmcXVvdDsmcXVvdDsmcXVvdDsKICAgICMg5Y+v5Lul5bCd6K+V5o2i5YW25LuW55qE5Yqo5oCB5Ye95pWw77yM6L6+5Yiw5pu05pyJ5Yqb6YeP55qE5pWI5p6c77yI5aaC6LSd5aGe5bCU5puy57q/77yJCiAgICByZXR1cm4gMiAqICgyICogc2luKDQgKiBwKSkgLyAoMiAqIHBpKQoKY2xhc3MgQmVhdGluZ0hlYXJ0OgogICAgJnF1b3Q7JnF1b3Q7JnF1b3Q7CiAgICDot7PliqjnmoTniLHlv4PnsbsKICAgICZxdW90OyZxdW90OyZxdW90OwoKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBnZW5lcmF0ZV9mcmFtZT0yMCk6CiAgICAgICAgc2VsZi5fb3JpZ2luYWxfcG9pbnRzID0gc2V0KCkgICMg5Y6f5aeL54ix5b+D55qE5Z2Q5qCH6ZuG5ZCICiAgICAgICAgc2VsZi5fZWRnZV9kaWZmdXNpb25fcG9pbnRzID0gc2V0KCkgICMg6L6557yY5omp5pWj5pWI5p6c55qE54K55Z2Q5qCH6ZuG5ZCICiAgICAgICAgc2VsZi5fY2VudGVyX2RpZmZ1c2lvbl9wb2ludHMgPSBzZXQoKSAgIyDkuK3lv4PmianmlaPmlYjmnpznmoTngrnlnZDmoIfpm4blkIgKICAgICAgICBzZWxmLmFsbF9mcmFtZV9wb2ludHMgPSB7fSAgIyDmr4/luKfnmoTliqjmgIHngrnlnZDmoIcKICAgICAgICBzZWxmLmJ1aWxkKDIwMDApCgogICAgICAgIHNlbGYucmFuZG9tX2hhbG8gPSAxMDAwCgogICAgICAgIHNlbGYuZ2VuZXJhdGVfZnJhbWUgPSBnZW5lcmF0ZV9mcmFtZQogICAgICAgIGZvciBmcmFtZSBpbiByYW5nZShnZW5lcmF0ZV9mcmFtZSk6CiAgICAgICAgICAgIHNlbGYuY2FsY3VsYXRlX2ZyYW1lKGZyYW1lKQoKICAgIGRlZiBidWlsZChzZWxmLCBudW1iZXJfb2ZfcG9pbnRzKToKICAgICAgICAjIOeUn+aIkOWOn+Wni+eIseW/g+eahOWdkOaghwogICAgICAgIGZvciBfIGluIHJhbmdlKG51bWJlcl9vZl9wb2ludHMpOgogICAgICAgICAgICB0ID0gcmFuZG9tLnVuaWZvcm0oMCwgMiAqIHBpKSAgIyDpmo/mnLrlj4LmlbDvvIznlKjkuo7nlJ/miJDkuI3lrozmlbTnmoTniLHlv4MKICAgICAgICAgICAgeCwgeSA9IGdlbmVyYXRlX2hlYXJ0X2Nvb3JkaW5hdGUodCkKICAgICAgICAgICAgc2VsZi5fb3JpZ2luYWxfcG9pbnRzLmFkZCgoeCwgeSkpCgogICAgICAgICMg55Sf5oiQ54ix5b+D5YaF5omp5pWj55qE54K5CiAgICAgICAgZm9yIHgsIHkgaW4gbGlzdChzZWxmLl9vcmlnaW5hbF9wb2ludHMpOgogICAgICAgICAgICBmb3IgXyBpbiByYW5nZSgzKToKICAgICAgICAgICAgICAgIHgsIHkgPSBzY2F0dGVyX2luc2lkZSh4LCB5LCAwLjA1KQogICAgICAgICAgICAgICAgc2VsZi5fZWRnZV9kaWZmdXNpb25fcG9pbnRzLmFkZCgoeCwgeSkpCgogICAgICAgICMg55Sf5oiQ54ix5b+D5YaF5YaN5qyh5omp5pWj55qE54K5CiAgICAgICAgcG9pbnRfbGlzdCA9IGxpc3Qoc2VsZi5fb3JpZ2luYWxfcG9pbnRzKQogICAgICAgIGZvciBfIGluIHJhbmdlKDYwMDApOgogICAgICAgICAgICB4LCB5ID0gcmFuZG9tLmNob2ljZShwb2ludF9saXN0KQogICAgICAgICAgICB4LCB5ID0gc2NhdHRlcl9pbnNpZGUoeCwgeSwgMC4xNykKICAgICAgICAgICAgc2VsZi5fY2VudGVyX2RpZmZ1c2lvbl9wb2ludHMuYWRkKCh4LCB5KSkKCiAgICBAc3RhdGljbWV0aG9kCiAgICBkZWYgY2FsY3VsYXRlX3Bvc2l0aW9uKHgsIHksIHJhdGlvKToKICAgICAgICAjIOiwg+aVtOe8qeaUvuavlOS+iwogICAgICAgIGZvcmNlID0gMSAvICgoKHggLSBDQU5WQVNfQ0VOVEVSX1gpICoqIDIgKyAoeSAtIENBTlZBU19DRU5URVJfWSkgKiogMikgKiogMC41MjApICAjIOiwg+aVtOeIseW/g+i3s+WKqOeahOWPguaVsAoKICAgICAgICBkeCA9IHJhdGlvICogZm9yY2UgKiAoeCAtIENBTlZBU19DRU5URVJfWCkgKyByYW5kb20ucmFuZGludCgtMSwgMSkKICAgICAgICBkeSA9IHJhdGlvICogZm9yY2UgKiAoeSAtIENBTlZBU19DRU5URVJfWSkgKyByYW5kb20ucmFuZGludCgtMSwgMSkKCiAgICAgICAgcmV0dXJuIHggLSBkeCwgeSAtIGR5CgogICAgZGVmIGNhbGN1bGF0ZV9mcmFtZShzZWxmLCBmcmFtZV9udW1iZXIpOgogICAgICAgIHJhdGlvID0gMTAgKiBjdXN0b21fY3VydmUoZnJhbWVfbnVtYmVyIC8gMTAgKiBwaSkgICMg5ZyG5ruR55qE5ZGo5pyf55qE57yp5pS+5q+U5L6LCgogICAgICAgIGhhbG9fcmFkaXVzID0gaW50KDQgKyA2ICogKDEgKyBjdXN0b21fY3VydmUoZnJhbWVfbnVtYmVyIC8gMTAgKiBwaSkpKQogICAgICAgIGhhbG9fbnVtYmVyID0gaW50KDMwMDAgKyA0MDAwICogYWJzKGN1c3RvbV9jdXJ2ZShmcmFtZV9udW1iZXIgLyAxMCAqIHBpKSAqKiAyKSkKCiAgICAgICAgYWxsX3BvaW50cyA9IFtdCgogICAgICAgICMg55Sf5oiQ5YWJ546v55qE54K5CiAgICAgICAgaGVhcnRfaGFsb19wb2ludHMgPSBzZXQoKQogICAgICAgIGZvciBfIGluIHJhbmdlKGhhbG9fbnVtYmVyKToKICAgICAgICAgICAgdCA9IHJhbmRvbS51bmlmb3JtKDAsIDQgKiBwaSkKICAgICAgICAgICAgeCwgeSA9IGdlbmVyYXRlX2hlYXJ0X2Nvb3JkaW5hdGUodCwgc2hyaW5rX3JhdGlvPTExLjUpCiAgICAgICAgICAgIHgsIHkgPSBzaHJpbmtfY29vcmRpbmF0ZSh4LCB5LCBoYWxvX3JhZGl1cykKICAgICAgICAgICAgaWYgKHgsIHkpIG5vdCBpbiBoZWFydF9oYWxvX3BvaW50czoKICAgICAgICAgICAgICAgICMg5aSE55CG5paw55qE54K5CiAgICAgICAgICAgICAgICBoZWFydF9oYWxvX3BvaW50cy5hZGQoKHgsIHkpKQogICAgICAgICAgICAgICAgeCArPSByYW5kb20ucmFuZGludCgtMTQsIDE0KQogICAgICAgICAgICAgICAgeSArPSByYW5kb20ucmFuZGludCgtMTQsIDE0KQogICAgICAgICAgICAgICAgc2l6ZSA9IHJhbmRvbS5jaG9pY2UoKDEsIDIsIDIpKQogICAgICAgICAgICAgICAgYWxsX3BvaW50cy5hcHBlbmQoKHgsIHksIHNpemUpKQoKICAgICAgICAjIOeUn+aIkOeIseW/g+i9ruW7k+eahOeCuQogICAgICAgIGZvciB4LCB5IGluIHNlbGYuX29yaWdpbmFsX3BvaW50czoKICAgICAgICAgICAgeCwgeSA9IHNlbGYuY2FsY3VsYXRlX3Bvc2l0aW9uKHgsIHksIHJhdGlvKQogICAgICAgICAgICBzaXplID0gcmFuZG9tLnJhbmRpbnQoMSwgMykKICAgICAgICAgICAgYWxsX3BvaW50cy5hcHBlbmQoKHgsIHksIHNpemUpKQoKICAgICAgICAjIOeUn+aIkOeIseW/g+WGheWuueeahOeCuQogICAgICAgIGZvciB4LCB5IGluIHNlbGYuX2VkZ2VfZGlmZnVzaW9uX3BvaW50czoKICAgICAgICAgICAgeCwgeSA9IHNlbGYuY2FsY3VsYXRlX3Bvc2l0aW9uKHgsIHksIHJhdGlvKQogICAgICAgICAgICBzaXplID0gcmFuZG9tLnJhbmRpbnQoMSwgMikKICAgICAgICAgICAgYWxsX3BvaW50cy5hcHBlbmQoKHgsIHksIHNpemUpKQoKICAgICAgICBmb3IgeCwgeSBpbiBzZWxmLl9jZW50ZXJfZGlmZnVzaW9uX3BvaW50czoKICAgICAgICAgICAgeCwgeSA9IHNlbGYuY2FsY3VsYXRlX3Bvc2l0aW9uKHgsIHksIHJhdGlvKQogICAgICAgICAgICBzaXplID0gcmFuZG9tLnJhbmRpbnQoMSwgMikKICAgICAgICAgICAgYWxsX3BvaW50cy5hcHBlbmQoKHgsIHksIHNpemUpKQoKICAgICAgICBzZWxmLmFsbF9mcmFtZV9wb2ludHNbZnJhbWVfbnVtYmVyXSA9IGFsbF9wb2ludHMKCiAgICBkZWYgcmVuZGVyKHNlbGYsIHJlbmRlcl9jYW52YXMsIHJlbmRlcl9mcmFtZSk6CiAgICAgICAgZm9yIHgsIHksIHNpemUgaW4gc2VsZi5hbGxfZnJhbWVfcG9pbnRzW3JlbmRlcl9mcmFtZSAlIHNlbGYuZ2VuZXJhdGVfZnJhbWVdOgogICAgICAgICAgICByZW5kZXJfY2FudmFzLmNyZWF0ZV9yZWN0YW5nbGUoeCwgeSwgeCArIHNpemUsIHkgKyBzaXplLCB3aWR0aD0wLCBmaWxsPUhFQVJUX0NPTE9SKQoKZGVmIGRyYXcobWFpbl93aW5kb3csIHJlbmRlcl9jYW52YXMsIHJlbmRlcl9oZWFydCwgcmVuZGVyX2ZyYW1lPTApOgogICAgcmVuZGVyX2NhbnZhcy5kZWxldGUoJ2FsbCcpCiAgICByZW5kZXJfaGVhcnQucmVuZGVyKHJlbmRlcl9jYW52YXMsIHJlbmRlcl9mcmFtZSkKICAgIG1haW5fd2luZG93LmFmdGVyKDE2MCwgZHJhdywgbWFpbl93aW5kb3csIHJlbmRlcl9jYW52YXMsIHJlbmRlcl9oZWFydCwgcmVuZGVyX2ZyYW1lICsgMSkKCmlmIF9fbmFtZV9fID09ICdfX21haW5fXyc6CiAgICByb290ID0gVGsoKQogICAgcm9vdC50aXRsZSgnQmVhdGluZyBIZWFydCcpCiAgICBjYW52YXMgPSBDYW52YXMocm9vdCwgYmc9J2JsYWNrJywgaGVpZ2h0PUNBTlZBU19IRUlHSFQsIHdpZHRoPUNBTlZBU19XSURUSCkKICAgIGNhbnZhcy5wYWNrKCkKICAgIGhlYXJ0ID0gQmVhdGluZ0hlYXJ0KCkKICAgIGRyYXcocm9vdCwgY2FudmFzLCBoZWFydCkKICAgIExhYmVsKHJvb3QsIHRleHQ9JnF1b3Q75aSa5ZCD54K55oqb5pil5oGoJnF1b3Q7LCBiZz0mcXVvdDtibGFjayZxdW90OywgZmc9JnF1b3Q7I0ZGNjlCNCZxdW90OywgKS5wbGFjZShyZWx4PS41LCByZWx5PS41LCBhbmNob3I9Q0VOVEVSKQogICAgIyDlnKjniLHlv4PkuK3pl7TliqDkuIrlrZcKICAgIExhYmVsKHJvb3QsIHRleHQ9JnF1b3Q75Y+v5Y+v5LiT6Zeo5Li65bCP5LqR5a6a5Yi2JnF1b3Q7LCBiZz0mcXVvdDtibGFjayZxdW90OywgZmc9JnF1b3Q7I0ZGNjlCNCZxdW90OywgZm9udD0oJ+Wui+S9kycsIDE4KSkucGxhY2UocmVseD0uNTAsIHI=
from tkinter import *
CANVAS_WIDTH = 640
CANVAS_HEIGHT = 480
CANVAS_CENTER_X = CANVAS_WIDTH / 2
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2
IMAGE_ENLARGE_FACTOR = 11
HEART_COLOR = "#FF69B4"
def generate_heart_coordinate(t, shrink_ratio=IMAGE_ENLARGE_FACTOR):
# 基础函数,生成爱心的基本形状
x = 16 * (sin(t) ** 3)
y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))
# 放大爱心
x *= shrink_ratio
y *= shrink_ratio
# 将爱心移到画布中央
x += CANVAS_CENTER_X
y += CANVAS_CENTER_Y
return int(x), int(y)
def scatter_inside(x, y, beta=0.15):
ratio_x = - beta * log(random.random())
ratio_y = - beta * log(random.random())
dx = ratio_x * (x - CANVAS_CENTER_X)
dy = ratio_y * (y - CANVAS_CENTER_Y)
return x - dx, y - dy
def shrink_coordinate(x, y, ratio):
"""
抖动效果,用于调整爱心的跳动
:param x: 原点的 x 坐标
:param y: 原点的 y 坐标
:param ratio: 抖动的比例
:return: 新点的坐标 (x, y)
"""
force = -1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.6) # 调整爱心跳动的参数
dx = ratio * force * (x - CANVAS_CENTER_X)
dy = ratio * force * (y - CANVAS_CENTER_Y)
return x - dx, y - dy
def custom_curve(p):
"""
自定义曲线函数,调整跳动周期
:param p: 参数,控制曲线的形状
:return: 正弦值,用于调整爱心的跳动
"""
# 可以尝试换其他的动态函数,达到更有力量的效果(如贝塞尔曲线)
return 2 * (2 * sin(4 * p)) / (2 * pi)
class BeatingHeart:
"""
跳动的爱心类
"""
def __init__(self, generate_frame=20):
self._original_points = set() # 原始爱心的坐标集合
self._edge_diffusion_points = set() # 边缘扩散效果的点坐标集合
self._center_diffusion_points = set() # 中心扩散效果的点坐标集合
self.all_frame_points = {} # 每帧的动态点坐标
self.build(2000)
self.random_halo = 1000
self.generate_frame = generate_frame
for frame in range(generate_frame):
self.calculate_frame(frame)
def build(self, number_of_points):
# 生成原始爱心的坐标
for _ in range(number_of_points):
t = random.uniform(0, 2 * pi) # 随机参数,用于生成不完整的爱心
x, y = generate_heart_coordinate(t)
self._original_points.add((x, y))
# 生成爱心内扩散的点
for x, y in list(self._original_points):
for _ in range(3):
x, y = scatter_inside(x, y, 0.05)
self._edge_diffusion_points.add((x, y))
# 生成爱心内再次扩散的点
point_list = list(self._original_points)
for _ in range(6000):
x, y = random.choice(point_list)
x, y = scatter_inside(x, y, 0.17)
self._center_diffusion_points.add((x, y))
@staticmethod
def calculate_position(x, y, ratio):
# 调整缩放比例
force = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520) # 调整爱心跳动的参数
dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1)
dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1)
return x - dx, y - dy
def calculate_frame(self, frame_number):
ratio = 10 * custom_curve(frame_number / 10 * pi) # 圆滑的周期的缩放比例
halo_radius = int(4 + 6 * (1 + custom_curve(frame_number / 10 * pi)))
halo_number = int(3000 + 4000 * abs(custom_curve(frame_number / 10 * pi) ** 2))
all_points = []
# 生成光环的点
heart_halo_points = set()
for _ in range(halo_number):
t = random.uniform(0, 4 * pi)
x, y = generate_heart_coordinate(t, shrink_ratio=11.5)
x, y = shrink_coordinate(x, y, halo_radius)
if (x, y) not in heart_halo_points:
# 处理新的点
heart_halo_points.add((x, y))
x += random.randint(-14, 14)
y += random.randint(-14, 14)
size = random.choice((1, 2, 2))
all_points.append((x, y, size))
# 生成爱心轮廓的点
for x, y in self._original_points:
x, y = self.calculate_position(x, y, ratio)
size = random.randint(1, 3)
all_points.append((x, y, size))
# 生成爱心内容的点
for x, y in self._edge_diffusion_points:
x, y = self.calculate_position(x, y, ratio)
size = random.randint(1, 2)
all_points.append((x, y, size))
for x, y in self._center_diffusion_points:
x, y = self.calculate_position(x, y, ratio)
size = random.randint(1, 2)
all_points.append((x, y, size))
self.all_frame_points[frame_number] = all_points
def render(self, render_canvas, render_frame):
for x, y, size in self.all_frame_points[render_frame % self.generate_frame]:
render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=HEART_COLOR)
def draw(main_window, render_canvas, render_heart, render_frame=0):
render_canvas.delete('all')
render_heart.render(render_canvas, render_frame)
main_window.after(160, draw, main_window, render_canvas, render_heart, render_frame + 1)
if __name__ == '__main__':
root = Tk()
root.title('Beating Heart')
canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
canvas.pack()
heart = BeatingHeart()
draw(root, canvas, heart)
Label(root, text="多吃点抛春恨", bg="black", fg="#FF69B4", ).place(relx=.5, rely=.5, anchor=CENTER)
# 在爱心中间加上字
Label(root, text="可可专门为小云定制", bg="black", fg="#FF69B4", font=('宋体', 18)).place(relx=.50, rely=.1, anchor=CENTER)
# 在爱心上面加上字
root.mainloop()from tkinter import *
CANVAS_WIDTH = 640
CANVAS_HEIGHT = 480
CANVAS_CENTER_X = CANVAS_WIDTH / 2
CANVAS_CENTER_Y = CANVAS_HEIGHT / 2
IMAGE_ENLARGE_FACTOR = 11
HEART_COLOR = "#FF69B4"
def generate_heart_coordinate(t, shrink_ratio=IMAGE_ENLARGE_FACTOR):
# 基础函数,生成爱心的基本形状
x = 16 * (sin(t) ** 3)
y = -(13 * cos(t) - 5 * cos(2 * t) - 2 * cos(3 * t) - cos(4 * t))
# 放大爱心
x *= shrink_ratio
y *= shrink_ratio
# 将爱心移到画布中央
x += CANVAS_CENTER_X
y += CANVAS_CENTER_Y
return int(x), int(y)
def scatter_inside(x, y, beta=0.15):
ratio_x = - beta * log(random.random())
ratio_y = - beta * log(random.random())
dx = ratio_x * (x - CANVAS_CENTER_X)
dy = ratio_y * (y - CANVAS_CENTER_Y)
return x - dx, y - dy
def shrink_coordinate(x, y, ratio):
"""
抖动效果,用于调整爱心的跳动
:param x: 原点的 x 坐标
:param y: 原点的 y 坐标
:param ratio: 抖动的比例
:return: 新点的坐标 (x, y)
"""
force = -1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.6) # 调整爱心跳动的参数
dx = ratio * force * (x - CANVAS_CENTER_X)
dy = ratio * force * (y - CANVAS_CENTER_Y)
return x - dx, y - dy
def custom_curve(p):
"""
自定义曲线函数,调整跳动周期
:param p: 参数,控制曲线的形状
:return: 正弦值,用于调整爱心的跳动
"""
# 可以尝试换其他的动态函数,达到更有力量的效果(如贝塞尔曲线)
return 2 * (2 * sin(4 * p)) / (2 * pi)
class BeatingHeart:
"""
跳动的爱心类
"""
def __init__(self, generate_frame=20):
self._original_points = set() # 原始爱心的坐标集合
self._edge_diffusion_points = set() # 边缘扩散效果的点坐标集合
self._center_diffusion_points = set() # 中心扩散效果的点坐标集合
self.all_frame_points = {} # 每帧的动态点坐标
self.build(2000)
self.random_halo = 1000
self.generate_frame = generate_frame
for frame in range(generate_frame):
self.calculate_frame(frame)
def build(self, number_of_points):
# 生成原始爱心的坐标
for _ in range(number_of_points):
t = random.uniform(0, 2 * pi) # 随机参数,用于生成不完整的爱心
x, y = generate_heart_coordinate(t)
self._original_points.add((x, y))
# 生成爱心内扩散的点
for x, y in list(self._original_points):
for _ in range(3):
x, y = scatter_inside(x, y, 0.05)
self._edge_diffusion_points.add((x, y))
# 生成爱心内再次扩散的点
point_list = list(self._original_points)
for _ in range(6000):
x, y = random.choice(point_list)
x, y = scatter_inside(x, y, 0.17)
self._center_diffusion_points.add((x, y))
@staticmethod
def calculate_position(x, y, ratio):
# 调整缩放比例
force = 1 / (((x - CANVAS_CENTER_X) ** 2 + (y - CANVAS_CENTER_Y) ** 2) ** 0.520) # 调整爱心跳动的参数
dx = ratio * force * (x - CANVAS_CENTER_X) + random.randint(-1, 1)
dy = ratio * force * (y - CANVAS_CENTER_Y) + random.randint(-1, 1)
return x - dx, y - dy
def calculate_frame(self, frame_number):
ratio = 10 * custom_curve(frame_number / 10 * pi) # 圆滑的周期的缩放比例
halo_radius = int(4 + 6 * (1 + custom_curve(frame_number / 10 * pi)))
halo_number = int(3000 + 4000 * abs(custom_curve(frame_number / 10 * pi) ** 2))
all_points = []
# 生成光环的点
heart_halo_points = set()
for _ in range(halo_number):
t = random.uniform(0, 4 * pi)
x, y = generate_heart_coordinate(t, shrink_ratio=11.5)
x, y = shrink_coordinate(x, y, halo_radius)
if (x, y) not in heart_halo_points:
# 处理新的点
heart_halo_points.add((x, y))
x += random.randint(-14, 14)
y += random.randint(-14, 14)
size = random.choice((1, 2, 2))
all_points.append((x, y, size))
# 生成爱心轮廓的点
for x, y in self._original_points:
x, y = self.calculate_position(x, y, ratio)
size = random.randint(1, 3)
all_points.append((x, y, size))
# 生成爱心内容的点
for x, y in self._edge_diffusion_points:
x, y = self.calculate_position(x, y, ratio)
size = random.randint(1, 2)
all_points.append((x, y, size))
for x, y in self._center_diffusion_points:
x, y = self.calculate_position(x, y, ratio)
size = random.randint(1, 2)
all_points.append((x, y, size))
self.all_frame_points[frame_number] = all_points
def render(self, render_canvas, render_frame):
for x, y, size in self.all_frame_points[render_frame % self.generate_frame]:
render_canvas.create_rectangle(x, y, x + size, y + size, width=0, fill=HEART_COLOR)
def draw(main_window, render_canvas, render_heart, render_frame=0):
render_canvas.delete('all')
render_heart.render(render_canvas, render_frame)
main_window.after(160, draw, main_window, render_canvas, render_heart, render_frame + 1)
if __name__ == '__main__':
root = Tk()
root.title('Beating Heart')
canvas = Canvas(root, bg='black', height=CANVAS_HEIGHT, width=CANVAS_WIDTH)
canvas.pack()
heart = BeatingHeart()
draw(root, canvas, heart)
Label(root, text="多吃点抛春恨", bg="black", fg="#FF69B4", ).place(relx=.5, rely=.5, anchor=CENTER)
# 在爱心中间加上字
Label(root, text="可可专门为小云定制", bg="black", fg="#FF69B4", font=('宋体', 18)).place(relx=.50, r