-
Notifications
You must be signed in to change notification settings - Fork 1
/
apng.coffee
104 lines (84 loc) · 22.1 KB
/
apng.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
###*
# framerjs-apng v0.0.1
# @copyright 2015 KimDaeWook
# @link https://github.com/KimDaeWook/framerjs-apng
# @license MIT
###
updateAPNGLayerSize = (layer)->
if !layer._APNG
return
apng = layer._APNG;
if !apng.animation
apng.canvas.width = 0
apng.canvas.height = 0
else
apng.canvas.width = apng.animation.width
apng.canvas.height = apng.animation.height
scaleX = layer.width / apng.canvas.width
scaleY = layer.height / apng.canvas.height
coverScale = Math.max(0, Math.max(scaleX, scaleY)).toString();
apng.canvas.style.transform = "scale(" + coverScale + "," + coverScale + ")"
apng.canvas.style.transformOrigin = "0% 0%"
apng.canvas.style.webkitTransform = "scale(" + coverScale + "," + coverScale + ")"
apng.canvas.style.webkitTransformOrigin = "0% 0%"
apngImageDescriptor =
propertyName: "apngImage"
get: ->
return @_getPropertyValue "apngImage"
set: (value) ->
self = @
currentValue = @_getPropertyValue "apngImage"
if currentValue == value
return self.emit "load"
if !self._APNG
self._APNG =
canvas : document.createElement 'canvas'
context : null
loop : 0,
isPlayed : false
@_element.appendChild(self._APNG.canvas)
self._APNG.context = self._APNG.canvas.getContext("2d")
@.on "change:size", ->
updateAPNGLayerSize(self)
print "try load " + value
APNG.parseURL(value).then (animation) ->
if self._APNG.animation
self._APNG.animation.removeContext(self._APNG.context)
self._APNG.animation = animation
updateAPNGLayerSize(self)
animation.numPlays = self._APNG.loop
if self._APNG.isPlayed
self.playAPNG()
self.emit "load"
, (err)->
if self._APNG.animation
self._APNG.animation.removeContext(self._APNG.context)
self._APNG.animation = null
updateAPNGLayerSize(self)
self.emit "error" , err
@_setPropertyValue("apngImage", value)
importable : true
exportable : true
Object.defineProperty Layer.prototype, 'apngImage', apngImageDescriptor
Layer["_DefinedPropertiesKey"]["apngImage"] = apngImageDescriptor
Layer.prototype.playAPNG = ->
@._APNG.isPlayed = true
animation = @._APNG.animation;
if(animation)
animation.removeContext(@._APNG.context)
animation.addContext(@._APNG.context)
animation.play()
Layer.prototype.stopAPNG = ->
@._APNG.isPlayed = false
animation = @._APNG.animation;
if(animation)
animation.removeContext(@._APNG.context)
###*
# apng-canvas v2.0.1
# @copyright 2011, 2015 David Mzareulyan
# @link https://github.com/davidmz/apng-canvas
# @license MIT
###
_APNG_CANVAS_BASE64_ENCODED = "IWZ1bmN0aW9uIHQoZSxuLHIpe2Z1bmN0aW9uIGkoYSxzKXtpZighblthXSl7aWYoIWVbYV0pe3ZhciB1PSJmdW5jdGlvbiI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlO2lmKCFzJiZ1KXJldHVybiB1KGEsITApO2lmKG8pcmV0dXJuIG8oYSwhMCk7dGhyb3cgbmV3IEVycm9yKCJDYW5ub3QgZmluZCBtb2R1bGUgJyIrYSsiJyIpfXZhciBjPW5bYV09e2V4cG9ydHM6e319O2VbYV1bMF0uY2FsbChjLmV4cG9ydHMsZnVuY3Rpb24odCl7dmFyIG49ZVthXVsxXVt0XTtyZXR1cm4gaShuP246dCl9LGMsYy5leHBvcnRzLHQsZSxuLHIpfXJldHVybiBuW2FdLmV4cG9ydHN9Zm9yKHZhciBvPSJmdW5jdGlvbiI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlLGE9MDthPHIubGVuZ3RoO2ErKylpKHJbYV0pO3JldHVybiBpfSh7MTpbZnVuY3Rpb24odCxlKXsoZnVuY3Rpb24odCxuKXsoZnVuY3Rpb24oKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gcih0KXtyZXR1cm4iZnVuY3Rpb24iPT10eXBlb2YgdHx8Im9iamVjdCI9PXR5cGVvZiB0JiZudWxsIT09dH1mdW5jdGlvbiBpKHQpe3JldHVybiJmdW5jdGlvbiI9PXR5cGVvZiB0fWZ1bmN0aW9uIG8odCl7cmV0dXJuIm9iamVjdCI9PXR5cGVvZiB0JiZudWxsIT09dH1mdW5jdGlvbiBhKCl7fWZ1bmN0aW9uIHMoKXtyZXR1cm4gZnVuY3Rpb24oKXt0Lm5leHRUaWNrKGgpfX1mdW5jdGlvbiB1KCl7dmFyIHQ9MCxlPW5ldyBNKGgpLG49ZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoIiIpO3JldHVybiBlLm9ic2VydmUobix7Y2hhcmFjdGVyRGF0YTohMH0pLGZ1bmN0aW9uKCl7bi5kYXRhPXQ9Kyt0JTJ9fWZ1bmN0aW9uIGMoKXt2YXIgdD1uZXcgTWVzc2FnZUNoYW5uZWw7cmV0dXJuIHQucG9ydDEub25tZXNzYWdlPWgsZnVuY3Rpb24oKXt0LnBvcnQyLnBvc3RNZXNzYWdlKDApfX1mdW5jdGlvbiBmKCl7cmV0dXJuIGZ1bmN0aW9uKCl7c2V0VGltZW91dChoLDEpfX1mdW5jdGlvbiBoKCl7Zm9yKHZhciB0PTA7TD50O3QrPTIpe3ZhciBlPXFbdF0sbj1xW3QrMV07ZShuKSxxW3RdPXZvaWQgMCxxW3QrMV09dm9pZCAwfUw9MH1mdW5jdGlvbiBsKCl7fWZ1bmN0aW9uIGQoKXtyZXR1cm4gbmV3IFR5cGVFcnJvcigiWW91IGNhbm5vdCByZXNvbHZlIGEgcHJvbWlzZSB3aXRoIGl0c2VsZiIpfWZ1bmN0aW9uIHAoKXtyZXR1cm4gbmV3IFR5cGVFcnJvcigiQSBwcm9taXNlcyBjYWxsYmFjayBjYW5ub3QgcmV0dXJuIHRoYXQgc2FtZSBwcm9taXNlLiIpfWZ1bmN0aW9uIG0odCl7dHJ5e3JldHVybiB0LnRoZW59Y2F0Y2goZSl7cmV0dXJuIEouZXJyb3I9ZSxKfX1mdW5jdGlvbiBBKHQsZSxuLHIpe3RyeXt0LmNhbGwoZSxuLHIpfWNhdGNoKGkpe3JldHVybiBpfX1mdW5jdGlvbiB3KHQsZSxuKXtGKGZ1bmN0aW9uKHQpe3ZhciByPSExLGk9QShuLGUsZnVuY3Rpb24obil7cnx8KHI9ITAsZSE9PW4/eSh0LG4pOmIodCxuKSl9LGZ1bmN0aW9uKGUpe3J8fChyPSEwLEUodCxlKSl9LCJTZXR0bGU6ICIrKHQuX2xhYmVsfHwiIHVua25vd24gcHJvbWlzZSIpKTshciYmaSYmKHI9ITAsRSh0LGkpKX0sdCl9ZnVuY3Rpb24gZyh0LGUpe2UuX3N0YXRlPT09Vj9iKHQsZS5fcmVzdWx0KTp0Ll9zdGF0ZT09PUg/RSh0LGUuX3Jlc3VsdCk6UChlLHZvaWQgMCxmdW5jdGlvbihlKXt5KHQsZSl9LGZ1bmN0aW9uKGUpe0UodCxlKX0pfWZ1bmN0aW9uIHYodCxlKXtpZihlLmNvbnN0cnVjdG9yPT09dC5jb25zdHJ1Y3RvcilnKHQsZSk7ZWxzZXt2YXIgbj1tKGUpO249PT1KP0UodCxKLmVycm9yKTp2b2lkIDA9PT1uP2IodCxlKTppKG4pP3codCxlLG4pOmIodCxlKX19ZnVuY3Rpb24geSh0LGUpe3Q9PT1lP0UodCxkKCkpOnIoZSk/dih0LGUpOmIodCxlKX1mdW5jdGlvbiBfKHQpe3QuX29uZXJyb3ImJnQuX29uZXJyb3IodC5fcmVzdWx0KSx4KHQpfWZ1bmN0aW9uIGIodCxlKXt0Ll9zdGF0ZT09PVkmJih0Ll9yZXN1bHQ9ZSx0Ll9zdGF0ZT1WLDA9PT10Ll9zdWJzY3JpYmVycy5sZW5ndGh8fEYoeCx0KSl9ZnVuY3Rpb24gRSh0LGUpe3QuX3N0YXRlPT09WSYmKHQuX3N0YXRlPUgsdC5fcmVzdWx0PWUsRihfLHQpKX1mdW5jdGlvbiBQKHQsZSxuLHIpe3ZhciBpPXQuX3N1YnNjcmliZXJzLG89aS5sZW5ndGg7dC5fb25lcnJvcj1udWxsLGlbb109ZSxpW28rVl09bixpW28rSF09ciwwPT09byYmdC5fc3RhdGUmJkYoeCx0KX1mdW5jdGlvbiB4KHQpe3ZhciBlPXQuX3N1YnNjcmliZXJzLG49dC5fc3RhdGU7aWYoMCE9PWUubGVuZ3RoKXtmb3IodmFyIHIsaSxvPXQuX3Jlc3VsdCxhPTA7YTxlLmxlbmd0aDthKz0zKXI9ZVthXSxpPWVbYStuXSxyP0MobixyLGksbyk6aShvKTt0Ll9zdWJzY3JpYmVycy5sZW5ndGg9MH19ZnVuY3Rpb24gTigpe3RoaXMuZXJyb3I9bnVsbH1mdW5jdGlvbiBUKHQsZSl7dHJ5e3JldHVybiB0KGUpfWNhdGNoKG4pe3JldHVybiBRLmVycm9yPW4sUX19ZnVuY3Rpb24gQyh0LGUsbixyKXt2YXIgbyxhLHMsdSxjPWkobik7aWYoYyl7aWYobz1UKG4sciksbz09PVE/KHU9ITAsYT1vLmVycm9yLG89bnVsbCk6cz0hMCxlPT09bylyZXR1cm4gdm9pZCBFKGUscCgpKX1lbHNlIG89cixzPSEwO2UuX3N0YXRlIT09WXx8KGMmJnM/eShlLG8pOnU/RShlLGEpOnQ9PT1WP2IoZSxvKTp0PT09SCYmRShlLG8pKX1mdW5jdGlvbiBSKHQsZSl7dHJ5e2UoZnVuY3Rpb24oZSl7eSh0LGUpfSxmdW5jdGlvbihlKXtFKHQsZSl9KX1jYXRjaChuKXtFKHQsbil9fWZ1bmN0aW9uIEkodCxlLG4scil7dGhpcy5faW5zdGFuY2VDb25zdHJ1Y3Rvcj10LHRoaXMucHJvbWlzZT1uZXcgdChsLHIpLHRoaXMuX2Fib3J0T25SZWplY3Q9bix0aGlzLl92YWxpZGF0ZUlucHV0KGUpPyh0aGlzLl9pbnB1dD1lLHRoaXMubGVuZ3RoPWUubGVuZ3RoLHRoaXMuX3JlbWFpbmluZz1lLmxlbmd0aCx0aGlzLl9pbml0KCksMD09PXRoaXMubGVuZ3RoP2IodGhpcy5wcm9taXNlLHRoaXMuX3Jlc3VsdCk6KHRoaXMubGVuZ3RoPXRoaXMubGVuZ3RofHwwLHRoaXMuX2VudW1lcmF0ZSgpLDA9PT10aGlzLl9yZW1haW5pbmcmJmIodGhpcy5wcm9taXNlLHRoaXMuX3Jlc3VsdCkpKTpFKHRoaXMucHJvbWlzZSx0aGlzLl92YWxpZGF0aW9uRXJyb3IoKSl9ZnVuY3Rpb24gVSgpe3Rocm93IG5ldyBUeXBlRXJyb3IoIllvdSBtdXN0IHBhc3MgYSByZXNvbHZlciBmdW5jdGlvbiBhcyB0aGUgZmlyc3QgYXJndW1lbnQgdG8gdGhlIHByb21pc2UgY29uc3RydWN0b3IiKX1mdW5jdGlvbiBqKCl7dGhyb3cgbmV3IFR5cGVFcnJvcigiRmFpbGVkIHRvIGNvbnN0cnVjdCAnUHJvbWlzZSc6IFBsZWFzZSB1c2UgdGhlICduZXcnIG9wZXJhdG9yLCB0aGlzIG9iamVjdCBjb25zdHJ1Y3RvciBjYW5ub3QgYmUgY2FsbGVkIGFzIGEgZnVuY3Rpb24uIil9ZnVuY3Rpb24gayh0KXt0aGlzLl9pZD1YKyssdGhpcy5fc3RhdGU9dm9pZCAwLHRoaXMuX3Jlc3VsdD12b2lkIDAsdGhpcy5fc3Vic2NyaWJlcnM9W10sbCE9PXQmJihpKHQpfHxVKCksdGhpcyBpbnN0YW5jZW9mIGt8fGooKSxSKHRoaXMsdCkpfXZhciBCO0I9QXJyYXkuaXNBcnJheT9BcnJheS5pc0FycmF5OmZ1bmN0aW9uKHQpe3JldHVybiJbb2JqZWN0IEFycmF5XSI9PT1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodCl9O3ZhciBELE89QixMPShEYXRlLm5vd3x8ZnVuY3Rpb24oKXtyZXR1cm4obmV3IERhdGUpLmdldFRpbWUoKX0sT2JqZWN0LmNyZWF0ZXx8ZnVuY3Rpb24odCl7aWYoYXJndW1lbnRzLmxlbmd0aD4xKXRocm93IG5ldyBFcnJvcigiU2Vjb25kIGFyZ3VtZW50IG5vdCBzdXBwb3J0ZWQiKTtpZigib2JqZWN0IiE9dHlwZW9mIHQpdGhyb3cgbmV3IFR5cGVFcnJvcigiQXJndW1lbnQgbXVzdCBiZSBhbiBvYmplY3QiKTtyZXR1cm4gYS5wcm90b3R5cGU9dCxuZXcgYX0sMCksRj1mdW5jdGlvbih0LGUpe3FbTF09dCxxW0wrMV09ZSxMKz0yLDI9PT1MJiZEKCl9LEc9InVuZGVmaW5lZCIhPXR5cGVvZiB3aW5kb3c/d2luZG93Ont9LE09Ry5NdXRhdGlvbk9ic2VydmVyfHxHLldlYktpdE11dGF0aW9uT2JzZXJ2ZXIsUz0idW5kZWZpbmVkIiE9dHlwZW9mIFVpbnQ4Q2xhbXBlZEFycmF5JiYidW5kZWZpbmVkIiE9dHlwZW9mIGltcG9ydFNjcmlwdHMmJiJ1bmRlZmluZWQiIT10eXBlb2YgTWVzc2FnZUNoYW5uZWwscT1uZXcgQXJyYXkoMWUzKTtEPSJ1bmRlZmluZWQiIT10eXBlb2YgdCYmIltvYmplY3QgcHJvY2Vzc10iPT09e30udG9TdHJpbmcuY2FsbCh0KT9zKCk6TT91KCk6Uz9jKCk6ZigpO3ZhciBZPXZvaWQgMCxWPTEsSD0yLEo9bmV3IE4sUT1uZXcgTjtJLnByb3RvdHlwZS5fdmFsaWRhdGVJbnB1dD1mdW5jdGlvbih0KXtyZXR1cm4gTyh0KX0sSS5wcm90b3R5cGUuX3ZhbGlkYXRpb25FcnJvcj1mdW5jdGlvbigpe3JldHVybiBuZXcgRXJyb3IoIkFycmF5IE1ldGhvZHMgbXVzdCBiZSBwcm92aWRlZCBhbiBBcnJheSIpfSxJLnByb3RvdHlwZS5faW5pdD1mdW5jdGlvbigpe3RoaXMuX3Jlc3VsdD1uZXcgQXJyYXkodGhpcy5sZW5ndGgpfTt2YXIgWj1JO0kucHJvdG90eXBlLl9lbnVtZXJhdGU9ZnVuY3Rpb24oKXtmb3IodmFyIHQ9dGhpcy5sZW5ndGgsZT10aGlzLnByb21pc2Usbj10aGlzLl9pbnB1dCxyPTA7ZS5fc3RhdGU9PT1ZJiZ0PnI7cisrKXRoaXMuX2VhY2hFbnRyeShuW3JdLHIpfSxJLnByb3RvdHlwZS5fZWFjaEVudHJ5PWZ1bmN0aW9uKHQsZSl7dmFyIG49dGhpcy5faW5zdGFuY2VDb25zdHJ1Y3RvcjtvKHQpP3QuY29uc3RydWN0b3I9PT1uJiZ0Ll9zdGF0ZSE9PVk/KHQuX29uZXJyb3I9bnVsbCx0aGlzLl9zZXR0bGVkQXQodC5fc3RhdGUsZSx0Ll9yZXN1bHQpKTp0aGlzLl93aWxsU2V0dGxlQXQobi5yZXNvbHZlKHQpLGUpOih0aGlzLl9yZW1haW5pbmctLSx0aGlzLl9yZXN1bHRbZV09dGhpcy5fbWFrZVJlc3VsdChWLGUsdCkpfSxJLnByb3RvdHlwZS5fc2V0dGxlZEF0PWZ1bmN0aW9uKHQsZSxuKXt2YXIgcj10aGlzLnByb21pc2U7ci5fc3RhdGU9PT1ZJiYodGhpcy5fcmVtYWluaW5nLS0sdGhpcy5fYWJvcnRPblJlamVjdCYmdD09PUg/RShyLG4pOnRoaXMuX3Jlc3VsdFtlXT10aGlzLl9tYWtlUmVzdWx0KHQsZSxuKSksMD09PXRoaXMuX3JlbWFpbmluZyYmYihyLHRoaXMuX3Jlc3VsdCl9LEkucHJvdG90eXBlLl9tYWtlUmVzdWx0PWZ1bmN0aW9uKHQsZSxuKXtyZXR1cm4gbn0sSS5wcm90b3R5cGUuX3dpbGxTZXR0bGVBdD1mdW5jdGlvbih0LGUpe3ZhciBuPXRoaXM7UCh0LHZvaWQgMCxmdW5jdGlvbih0KXtuLl9zZXR0bGVkQXQoVixlLHQpfSxmdW5jdGlvbih0KXtuLl9zZXR0bGVkQXQoSCxlLHQpfSl9O3ZhciBLPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIG5ldyBaKHRoaXMsdCwhMCxlKS5wcm9taXNlfSxXPWZ1bmN0aW9uKHQsZSl7ZnVuY3Rpb24gbih0KXt5KG8sdCl9ZnVuY3Rpb24gcih0KXtFKG8sdCl9dmFyIGk9dGhpcyxvPW5ldyBpKGwsZSk7aWYoIU8odCkpcmV0dXJuIEUobyxuZXcgVHlwZUVycm9yKCJZb3UgbXVzdCBwYXNzIGFuIGFycmF5IHRvIHJhY2UuIikpLG87Zm9yKHZhciBhPXQubGVuZ3RoLHM9MDtvLl9zdGF0ZT09PVkmJmE+cztzKyspUChpLnJlc29sdmUodFtzXSksdm9pZCAwLG4scik7cmV0dXJuIG99LCQ9ZnVuY3Rpb24odCxlKXt2YXIgbj10aGlzO2lmKHQmJiJvYmplY3QiPT10eXBlb2YgdCYmdC5jb25zdHJ1Y3Rvcj09PW4pcmV0dXJuIHQ7dmFyIHI9bmV3IG4obCxlKTtyZXR1cm4geShyLHQpLHJ9LHo9ZnVuY3Rpb24odCxlKXt2YXIgbj10aGlzLHI9bmV3IG4obCxlKTtyZXR1cm4gRShyLHQpLHJ9LFg9MCx0ZT1rO2suYWxsPUssay5yYWNlPVcsay5yZXNvbHZlPSQsay5yZWplY3Q9eixrLnByb3RvdHlwZT17Y29uc3RydWN0b3I6ayx0aGVuOmZ1bmN0aW9uKHQsZSl7dmFyIG49dGhpcyxyPW4uX3N0YXRlO2lmKHI9PT1WJiYhdHx8cj09PUgmJiFlKXJldHVybiB0aGlzO3ZhciBpPW5ldyB0aGlzLmNvbnN0cnVjdG9yKGwpLG89bi5fcmVzdWx0O2lmKHIpe3ZhciBhPWFyZ3VtZW50c1tyLTFdO0YoZnVuY3Rpb24oKXtDKHIsaSxhLG8pfSl9ZWxzZSBQKG4saSx0LGUpO3JldHVybiBpfSwiY2F0Y2giOmZ1bmN0aW9uKHQpe3JldHVybiB0aGlzLnRoZW4obnVsbCx0KX19O3ZhciBlZT1mdW5jdGlvbigpe3ZhciB0O3Q9InVuZGVmaW5lZCIhPXR5cGVvZiBuP246InVuZGVmaW5lZCIhPXR5cGVvZiB3aW5kb3cmJndpbmRvdy5kb2N1bWVudD93aW5kb3c6c2VsZjt2YXIgZT0iUHJvbWlzZSJpbiB0JiYicmVzb2x2ZSJpbiB0LlByb21pc2UmJiJyZWplY3QiaW4gdC5Qcm9taXNlJiYiYWxsImluIHQuUHJvbWlzZSYmInJhY2UiaW4gdC5Qcm9taXNlJiZmdW5jdGlvbigpe3ZhciBlO3JldHVybiBuZXcgdC5Qcm9taXNlKGZ1bmN0aW9uKHQpe2U9dH0pLGkoZSl9KCk7ZXx8KHQuUHJvbWlzZT10ZSl9LG5lPXtQcm9taXNlOnRlLHBvbHlmaWxsOmVlfTsiZnVuY3Rpb24iPT10eXBlb2YgZGVmaW5lJiZkZWZpbmUuYW1kP2RlZmluZShmdW5jdGlvbigpe3JldHVybiBuZX0pOiJ1bmRlZmluZWQiIT10eXBlb2YgZSYmZS5leHBvcnRzP2UuZXhwb3J0cz1uZToidW5kZWZpbmVkIiE9dHlwZW9mIHRoaXMmJih0aGlzLkVTNlByb21pc2U9bmUpfSkuY2FsbCh0aGlzKX0pLmNhbGwodGhpcyx0KCJWQ21Fc3ciKSwidW5kZWZpbmVkIiE9dHlwZW9mIHNlbGY/c2VsZjoidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdz93aW5kb3c6e30pfSx7VkNtRXN3OjJ9XSwyOltmdW5jdGlvbih0LGUpe2Z1bmN0aW9uIG4oKXt9dmFyIHI9ZS5leHBvcnRzPXt9O3IubmV4dFRpY2s9ZnVuY3Rpb24oKXt2YXIgdD0idW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdyYmd2luZG93LnNldEltbWVkaWF0ZSxlPSJ1bmRlZmluZWQiIT10eXBlb2Ygd2luZG93JiZ3aW5kb3cucG9zdE1lc3NhZ2UmJndpbmRvdy5hZGRFdmVudExpc3RlbmVyO2lmKHQpcmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiB3aW5kb3cuc2V0SW1tZWRpYXRlKHQpfTtpZihlKXt2YXIgbj1bXTtyZXR1cm4gd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uKHQpe3ZhciBlPXQuc291cmNlO2lmKChlPT09d2luZG93fHxudWxsPT09ZSkmJiJwcm9jZXNzLXRpY2siPT09dC5kYXRhJiYodC5zdG9wUHJvcGFnYXRpb24oKSxuLmxlbmd0aD4wKSl7dmFyIHI9bi5zaGlmdCgpO3IoKX19LCEwKSxmdW5jdGlvbih0KXtuLnB1c2godCksd2luZG93LnBvc3RNZXNzYWdlKCJwcm9jZXNzLXRpY2siLCIqIil9fXJldHVybiBmdW5jdGlvbih0KXtzZXRUaW1lb3V0KHQsMCl9fSgpLHIudGl0bGU9ImJyb3dzZXIiLHIuYnJvd3Nlcj0hMCxyLmVudj17fSxyLmFyZ3Y9W10sci5vbj1uLHIuYWRkTGlzdGVuZXI9bixyLm9uY2U9bixyLm9mZj1uLHIucmVtb3ZlTGlzdGVuZXI9bixyLnJlbW92ZUFsbExpc3RlbmVycz1uLHIuZW1pdD1uLHIuYmluZGluZz1mdW5jdGlvbigpe3Rocm93IG5ldyBFcnJvcigicHJvY2Vzcy5iaW5kaW5nIGlzIG5vdCBzdXBwb3J0ZWQiKX0sci5jd2Q9ZnVuY3Rpb24oKXtyZXR1cm4iLyJ9LHIuY2hkaXI9ZnVuY3Rpb24oKXt0aHJvdyBuZXcgRXJyb3IoInByb2Nlc3MuY2hkaXIgaXMgbm90IHN1cHBvcnRlZCIpfX0se31dLDM6W2Z1bmN0aW9uKHQsZSl7InVzZSBzdHJpY3QiO3ZhciBuPWZ1bmN0aW9uKCl7dGhpcy53aWR0aD0wLHRoaXMuaGVpZ2h0PTAsdGhpcy5udW1QbGF5cz0wLHRoaXMucGxheVRpbWU9MCx0aGlzLmZyYW1lcz1bXSx0aGlzLnBsYXk9ZnVuY3Rpb24oKXtpfHxvfHwodGhpcy5yZXdpbmQoKSxpPSEwLHJlcXVlc3RBbmltYXRpb25GcmFtZShzKSl9LHRoaXMucmV3aW5kPWZ1bmN0aW9uKCl7ZT0wLG49MCxyPW51bGwsaT0hMSxvPSExfSx0aGlzLmFkZENvbnRleHQ9ZnVuY3Rpb24odCl7aWYoYS5sZW5ndGg+MCl7dmFyIGU9YVswXS5nZXRJbWFnZURhdGEoMCwwLHRoaXMud2lkdGgsdGhpcy5oZWlnaHQpO3QucHV0SW1hZ2VEYXRhKGUsMCwwKX1hLnB1c2godCksdC5fYXBuZ19hbmltYXRpb249dGhpc30sdGhpcy5yZW1vdmVDb250ZXh0PWZ1bmN0aW9uKHQpe3ZhciBlPWEuaW5kZXhPZih0KTstMSE9PWUmJihhLnNwbGljZShlLDEpLDA9PT1hLmxlbmd0aCYmdGhpcy5yZXdpbmQoKSwiX2FwbmdfYW5pbWF0aW9uImluIHQmJmRlbGV0ZSB0Ll9hcG5nX2FuaW1hdGlvbil9LHRoaXMuaXNQbGF5ZWQ9ZnVuY3Rpb24oKXtyZXR1cm4gaX0sdGhpcy5pc0ZpbmlzaGVkPWZ1bmN0aW9uKCl7cmV0dXJuIG99O3ZhciB0PXRoaXMsZT0wLG49MCxyPW51bGwsaT0hMSxvPSExLGE9W10scz1mdW5jdGlvbih0KXtmb3IoO2kmJnQ+PWU7KXUodCk7aSYmcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHMpfSx1PWZ1bmN0aW9uKHMpe3ZhciB1PW4rKyV0LmZyYW1lcy5sZW5ndGgsYz10LmZyYW1lc1t1XTtpZigwPT11JiYoYS5mb3JFYWNoKGZ1bmN0aW9uKGUpe2UuY2xlYXJSZWN0KDAsMCx0LndpZHRoLHQuaGVpZ2h0KX0pLHI9bnVsbCwyPT1jLmRpc3Bvc2VPcCYmKGMuZGlzcG9zZU9wPTEpKSxyJiYxPT1yLmRpc3Bvc2VPcD9hLmZvckVhY2goZnVuY3Rpb24odCl7dC5jbGVhclJlY3Qoci5sZWZ0LHIudG9wLHIud2lkdGgsci5oZWlnaHQpfSk6ciYmMj09ci5kaXNwb3NlT3AmJmEuZm9yRWFjaChmdW5jdGlvbih0KXt0LnB1dEltYWdlRGF0YShyLmlEYXRhLHIubGVmdCxyLnRvcCl9KSxyPWMsci5pRGF0YT1udWxsLDI9PXIuZGlzcG9zZU9wJiYoci5pRGF0YT1hWzBdLmdldEltYWdlRGF0YShjLmxlZnQsYy50b3AsYy53aWR0aCxjLmhlaWdodCkpLDA9PWMuYmxlbmRPcCYmYS5mb3JFYWNoKGZ1bmN0aW9uKHQpe3QuY2xlYXJSZWN0KGMubGVmdCxjLnRvcCxjLndpZHRoLGMuaGVpZ2h0KX0pLGEuZm9yRWFjaChmdW5jdGlvbih0KXt0LmRyYXdJbWFnZShjLmltZyxjLmxlZnQsYy50b3ApfSksMD09dC5udW1QbGF5c3x8bi90LmZyYW1lcy5sZW5ndGg8dC5udW1QbGF5cyl7Zm9yKDA9PWUmJihlPXMpO3M+ZSt0LnBsYXlUaW1lOyllKz10LnBsYXlUaW1lO2UrPWMuZGVsYXl9ZWxzZSBpPSExLG89ITF9fTtlLmV4cG9ydHM9bn0se31dLDQ6W2Z1bmN0aW9uKHQsZSl7InVzZSBzdHJpY3QiO2Zvcih2YXIgbj1uZXcgVWludDMyQXJyYXkoMjU2KSxyPTA7MjU2PnI7cisrKXtmb3IodmFyIGk9cixvPTA7OD5vO28rKylpPTEmaT8zOTg4MjkyMzg0Xmk+Pj4xOmk+Pj4xO25bcl09aX1lLmV4cG9ydHM9ZnVuY3Rpb24odCxlLHIpe2U9ZXx8MCxyPXJ8fHQubGVuZ3RoLWU7Zm9yKHZhciBpPS0xLG89ZSxhPWUrcjthPm87bysrKWk9aT4+PjheblsyNTUmKGledFtvXSldO3JldHVybi0xXml9fSx7fV0sNTpbZnVuY3Rpb24odCl7KGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0Ijt2YXIgbj1ufHx0KCJlczYtcHJvbWlzZSIpLlByb21pc2Uscj10KCIuL3N1cHBvcnQtdGVzdCIpLGk9dCgiLi9wYXJzZXIiKSxvPXQoIi4vbG9hZGVyIiksYT1lLkFQTkc9e307YS5jaGVja05hdGl2ZUZlYXR1cmVzPXIuY2hlY2tOYXRpdmVGZWF0dXJlcyxhLmlmTmVlZGVkPXIuaWZOZWVkZWQsYS5wYXJzZUJ1ZmZlcj1mdW5jdGlvbih0KXtyZXR1cm4gaShuZXcgVWludDhBcnJheSh0KSl9O3ZhciBzPXt9O2EucGFyc2VVUkw9ZnVuY3Rpb24odCl7cmV0dXJuIHQgaW4gc3x8KHNbdF09byh0KS50aGVuKGkpKSxzW3RdfSxhLmFuaW1hdGVDb250ZXh0PWZ1bmN0aW9uKHQsZSl7cmV0dXJuIGEucGFyc2VVUkwodCkudGhlbihmdW5jdGlvbih0KXtyZXR1cm4gdC5hZGRDb250ZXh0KGUpLHQucGxheSgpLHR9KX0sYS5hbmltYXRlSW1hZ2U9ZnVuY3Rpb24odCl7cmV0dXJuIHQuc2V0QXR0cmlidXRlKCJkYXRhLWlzLWFwbmciLCJwcm9ncmVzcyIpLGEucGFyc2VVUkwodC5zcmMpLnRoZW4oZnVuY3Rpb24oZSl7dC5zZXRBdHRyaWJ1dGUoImRhdGEtaXMtYXBuZyIsInllcyIpO3ZhciBuPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImNhbnZhcyIpO24ud2lkdGg9ZS53aWR0aCxuLmhlaWdodD1lLmhlaWdodCxBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCh0LmF0dHJpYnV0ZXMpLmZvckVhY2goZnVuY3Rpb24odCl7LTE9PVsiYWx0Iiwic3JjIiwidXNlbWFwIiwiaXNtYXAiLCJkYXRhLWlzLWFwbmciLCJ3aWR0aCIsImhlaWdodCJdLmluZGV4T2YodC5ub2RlTmFtZSkmJm4uc2V0QXR0cmlidXRlTm9kZSh0LmNsb25lTm9kZSgpKX0pLG4uc2V0QXR0cmlidXRlKCJkYXRhLWFwbmctc3JjIix0LnNyYyksIiIhPXQuYWx0JiZuLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHQuYWx0KSk7dmFyIHI9IiIsaT0iIixvPTAsYT0iIjsiIiE9dC5zdHlsZS53aWR0aCYmImF1dG8iIT10LnN0eWxlLndpZHRoP3I9dC5zdHlsZS53aWR0aDp0Lmhhc0F0dHJpYnV0ZSgid2lkdGgiKSYmKHI9dC5nZXRBdHRyaWJ1dGUoIndpZHRoIikrInB4IiksIiIhPXQuc3R5bGUuaGVpZ2h0JiYiYXV0byIhPXQuc3R5bGUuaGVpZ2h0P2k9dC5zdHlsZS5oZWlnaHQ6dC5oYXNBdHRyaWJ1dGUoImhlaWdodCIpJiYoaT10LmdldEF0dHJpYnV0ZSgiaGVpZ2h0IikrInB4IiksIiIhPXImJiIiPT1pJiYobz1wYXJzZUZsb2F0KHIpLGE9ci5tYXRjaCgvXEQrJC8pWzBdLGk9TWF0aC5yb3VuZChuLmhlaWdodCpvL24ud2lkdGgpK2EpLCIiIT1pJiYiIj09ciYmKG89cGFyc2VGbG9hdChpKSxhPWkubWF0Y2goL1xEKyQvKVswXSxyPU1hdGgucm91bmQobi53aWR0aCpvL24uaGVpZ2h0KSthKSxuLnN0eWxlLndpZHRoPXIsbi5zdHlsZS5oZWlnaHQ9aTt2YXIgcz10LnBhcmVudE5vZGU7cy5pbnNlcnRCZWZvcmUobix0KSxzLnJlbW92ZUNoaWxkKHQpLGUuYWRkQ29udGV4dChuLmdldENvbnRleHQoIjJkIikpLGUucGxheSgpfSxmdW5jdGlvbigpe3Quc2V0QXR0cmlidXRlKCJkYXRhLWlzLWFwbmciLCJubyIpfSl9LGEucmVsZWFzZUNhbnZhcz1mdW5jdGlvbih0KXt2YXIgZT10LmdldENvbnRleHQoIjJkIik7Il9hcG5nX2FuaW1hdGlvbiJpbiBlJiZlLl9hcG5nX2FuaW1hdGlvbi5yZW1vdmVDb250ZXh0KGUpfX0pLmNhbGwodGhpcywidW5kZWZpbmVkIiE9dHlwZW9mIHNlbGY/c2VsZjoidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdz93aW5kb3c6e30pfSx7Ii4vbG9hZGVyIjo2LCIuL3BhcnNlciI6NywiLi9zdXBwb3J0LXRlc3QiOjgsImVzNi1wcm9taXNlIjoxfV0sNjpbZnVuY3Rpb24odCxlKXsidXNlIHN0cmljdCI7dmFyIG49bnx8dCgiZXM2LXByb21pc2UiKS5Qcm9taXNlO2UuZXhwb3J0cz1mdW5jdGlvbih0KXtyZXR1cm4gbmV3IG4oZnVuY3Rpb24oZSxuKXt2YXIgcj1uZXcgWE1MSHR0cFJlcXVlc3Q7ci5vcGVuKCJHRVQiLHQpLHIucmVzcG9uc2VUeXBlPSJhcnJheWJ1ZmZlciIsci5vbmxvYWQ9ZnVuY3Rpb24oKXsyMDA9PXRoaXMuc3RhdHVzP2UodGhpcy5yZXNwb25zZSk6bih0aGlzKX0sci5zZW5kKCl9KX19LHsiZXM2LXByb21pc2UiOjF9XSw3OltmdW5jdGlvbih0LGUpeyJ1c2Ugc3RyaWN0Ijt2YXIgbj1ufHx0KCJlczYtcHJvbWlzZSIpLlByb21pc2Uscj10KCIuL2FuaW1hdGlvbiIpLGk9dCgiLi9jcmMzMiIpLG89bmV3IFVpbnQ4QXJyYXkoWzEzNyw4MCw3OCw3MSwxMywxMCwyNiwxMF0pO2UuZXhwb3J0cz1mdW5jdGlvbih0KXt2YXIgZT1uZXcgVWludDhBcnJheSh0KTtyZXR1cm4gbmV3IG4oZnVuY3Rpb24odCxuKXtmb3IodmFyIGk9MDtpPG8ubGVuZ3RoO2krKylpZihvW2ldIT1lW2ldKXJldHVybiB2b2lkIG4oIk5vdCBhIFBORyBmaWxlIChpbnZhbGlkIGZpbGUgc2lnbmF0dXJlKSIpO3ZhciBoPSExO2lmKGEoZSxmdW5jdGlvbih0KXtyZXR1cm4iYWNUTCI9PXQ/KGg9ITAsITEpOiEwfSksIWgpcmV0dXJuIHZvaWQgbigiTm90IGFuIGFuaW1hdGVkIFBORyIpO3ZhciBkPVtdLG09W10sQT1udWxsLHc9bnVsbCxnPW5ldyByO2lmKGEoZSxmdW5jdGlvbih0LGUsbixyKXtzd2l0Y2godCl7Y2FzZSJJSERSIjpBPWUuc3ViYXJyYXkobis4LG4rOCtyKSxnLndpZHRoPXMoZSxuKzgpLGcuaGVpZ2h0PXMoZSxuKzEyKTticmVhaztjYXNlImFjVEwiOmcubnVtUGxheXM9cyhlLG4rOCs0KTticmVhaztjYXNlImZjVEwiOncmJmcuZnJhbWVzLnB1c2godyksdz17fSx3LndpZHRoPXMoZSxuKzgrNCksdy5oZWlnaHQ9cyhlLG4rOCs4KSx3LmxlZnQ9cyhlLG4rOCsxMiksdy50b3A9cyhlLG4rOCsxNik7dmFyIGk9dShlLG4rOCsyMCksbz11KGUsbis4KzIyKTswPT1vJiYobz0xMDApLHcuZGVsYXk9MWUzKmkvbyx3LmRlbGF5PD0xMCYmKHcuZGVsYXk9MTAwKSxnLnBsYXlUaW1lKz13LmRlbGF5LHcuZGlzcG9zZU9wPWMoZSxuKzgrMjQpLHcuYmxlbmRPcD1jKGUsbis4KzI1KSx3LmRhdGFQYXJ0cz1bXTticmVhaztjYXNlImZkQVQiOncmJncuZGF0YVBhcnRzLnB1c2goZS5zdWJhcnJheShuKzgrNCxuKzgrcikpO2JyZWFrO2Nhc2UiSURBVCI6dyYmdy5kYXRhUGFydHMucHVzaChlLnN1YmFycmF5KG4rOCxuKzgrcikpO2JyZWFrO2Nhc2UiSUVORCI6bS5wdXNoKGYoZSxuLDEyK3IpKTticmVhaztkZWZhdWx0OmQucHVzaChmKGUsbiwxMityKSl9fSksdyYmZy5mcmFtZXMucHVzaCh3KSwwPT1nLmZyYW1lcy5sZW5ndGgpcmV0dXJuIHZvaWQgbigiTm90IGFuIGFuaW1hdGVkIFBORyIpO2Zvcih2YXIgdj0wLHk9bmV3IEJsb2IoZCksXz1uZXcgQmxvYihtKSxiPTA7YjxnLmZyYW1lcy5sZW5ndGg7YisrKXt3PWcuZnJhbWVzW2JdO3ZhciBFPVtdO0UucHVzaChvKSxBLnNldChsKHcud2lkdGgpLDApLEEuc2V0KGwody5oZWlnaHQpLDQpLEUucHVzaChwKCJJSERSIixBKSksRS5wdXNoKHkpO2Zvcih2YXIgUD0wO1A8dy5kYXRhUGFydHMubGVuZ3RoO1ArKylFLnB1c2gocCgiSURBVCIsdy5kYXRhUGFydHNbUF0pKTtFLnB1c2goXyk7dmFyIHg9VVJMLmNyZWF0ZU9iamVjdFVSTChuZXcgQmxvYihFLHt0eXBlOiJpbWFnZS9wbmcifSkpO2RlbGV0ZSB3LmRhdGFQYXJ0cyxFPW51bGwsdy5pbWc9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiaW1nIiksdy5pbWcub25sb2FkPWZ1bmN0aW9uKCl7VVJMLnJldm9rZU9iamVjdFVSTCh0aGlzLnNyYyksdisrLHY9PWcuZnJhbWVzLmxlbmd0aCYmdChnKX0sdy5pbWcub25lcnJvcj1mdW5jdGlvbigpe24oIkltYWdlIGNyZWF0aW9uIGVycm9yIil9LHcuaW1nLnNyYz14fX0pfTt2YXIgYT1mdW5jdGlvbih0LGUpe3ZhciBuPTg7ZG97dmFyIHI9cyh0LG4pLGk9aCh0LG4rNCw0KSxvPWUoaSx0LG4scik7bis9MTIrcn13aGlsZShvIT09ITEmJiJJRU5EIiE9aSYmbjx0Lmxlbmd0aCl9LHM9ZnVuY3Rpb24odCxlKXt2YXIgbj0wO24rPXRbMCtlXTw8MjQ+Pj4wO2Zvcih2YXIgcj0xOzQ+cjtyKyspbis9dFtyK2VdPDw4KigzLXIpO3JldHVybiBufSx1PWZ1bmN0aW9uKHQsZSl7Zm9yKHZhciBuPTAscj0wOzI+cjtyKyspbis9dFtyK2VdPDw4KigxLXIpO3JldHVybiBufSxjPWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHRbZV19LGY9ZnVuY3Rpb24odCxlLG4pe3ZhciByPW5ldyBVaW50OEFycmF5KG4pO3JldHVybiByLnNldCh0LnN1YmFycmF5KGUsZStuKSkscn0saD1mdW5jdGlvbih0LGUsbil7dmFyIHI9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwodC5zdWJhcnJheShlLGUrbikpO3JldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KFN0cmluZyxyKX0sbD1mdW5jdGlvbih0KXtyZXR1cm5bdD4+PjI0JjI1NSx0Pj4+MTYmMjU1LHQ+Pj44JjI1NSwyNTUmdF19LGQ9ZnVuY3Rpb24odCl7Zm9yKHZhciBlPVtdLG49MDtuPHQubGVuZ3RoO24rKyllLnB1c2godC5jaGFyQ29kZUF0KG4pKTtyZXR1cm4gZX0scD1mdW5jdGlvbih0LGUpe3ZhciBuPXQubGVuZ3RoK2UubGVuZ3RoLHI9bmV3IFVpbnQ4QXJyYXkobmV3IEFycmF5QnVmZmVyKG4rOCkpO3Iuc2V0KGwoZS5sZW5ndGgpLDApLHIuc2V0KGQodCksNCksci5zZXQoZSw4KTt2YXIgbz1pKHIsNCxuKTtyZXR1cm4gci5zZXQobChvKSxuKzQpLHJ9fSx7Ii4vYW5pbWF0aW9uIjozLCIuL2NyYzMyIjo0LCJlczYtcHJvbWlzZSI6MX1dLDg6W2Z1bmN0aW9uKHQsZSl7KGZ1bmN0aW9uKG4peyJ1c2Ugc3RyaWN0Ijt2YXIgcj1yfHx0KCJlczYtcHJvbWlzZSIpLlByb21pc2UsaT1mdW5jdGlvbih0KXt2YXIgZT1udWxsO3JldHVybiBmdW5jdGlvbihuKXtyZXR1cm4gZXx8KGU9bmV3IHIodCkpLG4mJmUudGhlbihuKSxlfX0sbz1pKGZ1bmN0aW9uKHQpe3ZhciBlPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImNhbnZhcyIpLHI9e1R5cGVkQXJyYXlzOiJBcnJheUJ1ZmZlciJpbiBuLEJsb2JVUkxzOiJVUkwiaW4gbixyZXF1ZXN0QW5pbWF0aW9uRnJhbWU6InJlcXVlc3RBbmltYXRpb25GcmFtZSJpbiBuLHBhZ2VQcm90b2NvbDoiaHR0cDoiPT1sb2NhdGlvbi5wcm90b2NvbCYmImh0dHBzOiI9PWxvY2F0aW9uLnByb3RvY29sLGNhbnZhczoiZ2V0Q29udGV4dCJpbiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCJjYW52YXMiKSxBUE5HOiExfTtpZihyLmNhbnZhcyl7dmFyIGk9bmV3IEltYWdlO2kub25sb2FkPWZ1bmN0aW9uKCl7dmFyIG49ZS5nZXRDb250ZXh0KCIyZCIpO24uZHJhd0ltYWdlKGksMCwwKSxyLkFQTkc9MD09PW4uZ2V0SW1hZ2VEYXRhKDAsMCwxLDEpLmRhdGFbM10sdChyKX0saS5zcmM9ImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQUVBQUFBQkNBWUFBQUFmRmNTSkFBQUFDR0ZqVkV3QUFBQUJBQUFBQWNNcTJUWUFBQUFOU1VSQlZBaVpZMkJnWVBnUEFBRUVBUUI5c3NqZkFBQUFHbVpqVkV3QUFBQUFBQUFBQVFBQUFBRUFBQUFBQUFBQUFBRDZBK2dCQWJOVSsyc0FBQUFSWm1SQlZBQUFBQUVJbVdOZ1lHQmdBQUFBQlFBQjZNekZkZ0FBQUFCSlJVNUVya0pnZ2c9PSJ9ZWxzZSB0KHIpfSksYT1mdW5jdGlvbih0KXtyZXR1cm4idW5kZWZpbmVkIj09dHlwZW9mIHQmJih0PSExKSxvKCkudGhlbihmdW5jdGlvbihlKXtpZihlLkFQTkcmJiF0KXJlamVjdCgpO2Vsc2V7dmFyIG49ITA7Zm9yKHZhciByIGluIGUpZS5oYXNPd25Qcm9wZXJ0eShyKSYmIkFQTkciIT1yJiYobj1uJiZlW3JdKX19KX07ZS5leHBvcnRzPXtjaGVja05hdGl2ZUZlYXR1cmVzOm8saWZOZWVkZWQ6YX19KS5jYWxsKHRoaXMsInVuZGVmaW5lZCIhPXR5cGVvZiBzZWxmP3NlbGY6InVuZGVmaW5lZCIhPXR5cGVvZiB3aW5kb3c/d2luZG93Ont9KX0seyJlczYtcHJvbWlzZSI6MX1dfSx7fSxbNV0pOw=="
apngCanvasSource = atob(_APNG_CANVAS_BASE64_ENCODED)
eval(apngCanvasSource)