summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-07-15 12:01:49 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2016-07-15 12:01:49 -0300
commit90060b2cf06033ede8f6d3c2f5acf4d180174905 (patch)
tree4664208d55a7b3048053acb1ac064d325f25ef91
parent7a31146918cdceef14689bf05d8f1602ec05bfcb (diff)
Add TimedMediaHandler extension that allows display audio and video files in wiki pages, using the same syntax as for image files
-rw-r--r--extensions/TimedMediaHandler/.gitignore6
-rw-r--r--extensions/TimedMediaHandler/.gitreview5
-rw-r--r--extensions/TimedMediaHandler/.jscsrc3
-rw-r--r--extensions/TimedMediaHandler/.jshintignore1
-rw-r--r--extensions/TimedMediaHandler/.jshintrc44
-rw-r--r--extensions/TimedMediaHandler/ApiQueryVideoInfo.php268
-rw-r--r--extensions/TimedMediaHandler/ApiTranscodeReset.php184
-rw-r--r--extensions/TimedMediaHandler/ApiTranscodeStatus.php79
-rw-r--r--extensions/TimedMediaHandler/COPYING342
-rw-r--r--extensions/TimedMediaHandler/Gruntfile.js34
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.config.php194
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.loader.js69
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.php103
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/LightDoodleskin.swfbin0 -> 190545 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/README20
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/config.xml9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/expressInstall.swfbin0 -> 727 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/kdp3.3.5.27.swfbin0 -> 272405 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/kdp3.swfbin0 -> 256262 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/skin.swfbin0 -> 67435 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING21
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-ogg.txt28
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-opus.txt44
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-theora.txt28
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-vorbis.txt28
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/dynamicaudio.swfbin0 -> 1865 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-audio-opus.js24
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-audio-vorbis.js23
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-video-theora.js22
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-demuxer-ogg.js23
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-support.js201
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-version.js1
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-worker-audio.js317
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-worker-video.js317
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv.js3966
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/readme.md237
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/af.json23
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/aln.json34
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ar.json59
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/arc.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ast.json89
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/az.json10
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ba.json16
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/be-tarask.json86
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bg.json12
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bho.json13
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bn.json74
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/br.json76
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bs.json12
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ca.json46
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ce.json15
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/cs.json68
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/cu.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/de.json98
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/diq.json70
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/dsb.json83
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/el.json77
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/en-gb.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/en.json95
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/eo.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/es.json99
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/et.json48
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/eu.json17
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fa.json87
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fi.json41
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fr.json97
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/frp.json76
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fy.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ga.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/gl.json96
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/grc.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/gsw.json80
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/he.json83
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/hsb.json83
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/hu.json75
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ia.json79
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/id.json76
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ilo.json16
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/is.json64
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/it.json92
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ja.json84
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ka.json73
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ko.json83
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ksh.json84
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ku-latn.json10
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ky.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lb.json55
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lt.json90
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lv.json60
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/mk.json95
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ml.json96
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ms.json82
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/mt.json23
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nb.json92
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nds-nl.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nl.json85
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nn.json84
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/oc.json50
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pam.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pdc.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pl.json81
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pms.json80
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ps.json21
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pt-br.json86
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pt.json101
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/qqq.json50
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/qu.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ro.json83
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/roa-tara.json33
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ru.json100
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/rue.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/si.json78
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sk.json6
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sr-ec.json78
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sr-el.json77
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sv.json96
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ta.json40
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/te.json17
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tet.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tl.json83
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tr.json85
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tzm.json11
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/uk.json92
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ur.json12
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vec.json38
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vep.json12
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vi.json77
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/yi.json10
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/zh-hans.json102
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/zh-hant.json86
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/blackvideo.mp4bin0 -> 4575 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayer.js2760
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerGeneric.js36
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerIEWebMPrompt.css18
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerIEWebMPrompt.js46
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerImageOverlay.js307
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerKplayer.js485
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerNative.js1088
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerOgvJs.js222
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerVLCApp.js101
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerVlc.js358
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedTypes.js360
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaElement.js491
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaPlayer.js85
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaPlayers.js195
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaSource.js490
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.processEmbedPlayers.js353
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/EmbedPlayer.css166
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/PlayerSkinKskin.css484
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/kaltura_open_source_video_platform.gifbin0 -> 3368 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/kaltura_open_source_video_platform.pngbin0 -> 302 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/ksprite.pngbin0 -> 13520 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/mw.PlayerSkinKskin.js394
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/PlayerSkinMvpcf.css194
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/images/player_big_play_button.pngbin0 -> 2935 bytes
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/mw.PlayerSkinMvpcf.js7
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mw.PlayerControlBuilder.js2721
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Audio.html16
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_DynamicEmbed.html24
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_IncludeJQuery.html27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Native_Bindings.html129
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Seek.html35
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_ServerSeek.html35
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_ServerSideSeek.html14
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Sources.html24
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Themable.html71
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.config.php31
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.loader.js52
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.php21
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/af.json10
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ar.json14
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ast.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/be-tarask.json28
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bg.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bn.json15
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/br.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bs.json10
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ca.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ce.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cs.json16
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cy.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de-formal.json7
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de.json28
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/diq.json13
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/dsb.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/el.json24
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/en.json25
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eo.json7
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/es.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/et.json18
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eu.json10
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fa.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fi.json16
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fr.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/frp.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fy.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gl.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gsw.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/he.json28
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hsb.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hu.json23
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ia.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/id.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/it.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ja.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ka.json24
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ko.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ksh.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lb.json23
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lt.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lv.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/mk.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ml.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ms.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nb.json25
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nl.json26
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nn.json14
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pdc.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pfl.json7
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pl.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pms.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ps.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt-br.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/qqq.json19
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ro.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/roa-tara.json14
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ru.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/rue.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/si.json25
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sl.json8
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/so.json7
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-ec.json15
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-el.json14
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sv.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ta.json16
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/te.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tl.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tr.json11
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/uk.json27
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ur.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/vi.json18
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/wa.json15
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/yi.json9
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hans.json30
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hant.json29
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TextSource.js504
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TimedText.js1313
-rw-r--r--extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.style.TimedText.css18
-rw-r--r--extensions/TimedMediaHandler/README127
-rw-r--r--extensions/TimedMediaHandler/SpecialOrphanedTimedText.php258
-rw-r--r--extensions/TimedMediaHandler/SpecialTimedMediaHandler.php235
-rw-r--r--extensions/TimedMediaHandler/TimedMediaHandler.hooks.php485
-rw-r--r--extensions/TimedMediaHandler/TimedMediaHandler.i18n.alias.php76
-rw-r--r--extensions/TimedMediaHandler/TimedMediaHandler.i18n.magic.php86
-rw-r--r--extensions/TimedMediaHandler/TimedMediaHandler.php306
-rw-r--r--extensions/TimedMediaHandler/TimedMediaHandler.sql19
-rw-r--r--extensions/TimedMediaHandler/TimedMediaHandler_body.php483
-rw-r--r--extensions/TimedMediaHandler/TimedMediaIframeOutput.php152
-rw-r--r--extensions/TimedMediaHandler/TimedMediaThumbnail.php240
-rw-r--r--extensions/TimedMediaHandler/TimedMediaTransformOutput.php486
-rw-r--r--extensions/TimedMediaHandler/TimedTextPage.php187
-rw-r--r--extensions/TimedMediaHandler/TranscodeStatusTable.php236
-rw-r--r--extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscode.php1192
-rw-r--r--extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscodeJob.php965
-rw-r--r--extensions/TimedMediaHandler/archives/transcode_name_key.sql3
-rw-r--r--extensions/TimedMediaHandler/composer.json10
-rw-r--r--extensions/TimedMediaHandler/gitinfo.json1
-rw-r--r--extensions/TimedMediaHandler/handlers/FLACHandler/FLACHandler.php74
-rw-r--r--extensions/TimedMediaHandler/handlers/ID3Handler/ID3Handler.php107
-rw-r--r--extensions/TimedMediaHandler/handlers/Mp4Handler/Mp4Handler.php139
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg.php631
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Bitstream.php125
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Flac.php133
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Media.php262
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Opus.php126
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Speex.php122
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Theora.php240
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Vorbis.php790
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/README2
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/OggException.php4
-rw-r--r--extensions/TimedMediaHandler/handlers/OggHandler/OggHandler.php379
-rw-r--r--extensions/TimedMediaHandler/handlers/TextHandler/TextHandler.php305
-rw-r--r--extensions/TimedMediaHandler/handlers/WAVHandler/WAVHandler.php87
-rw-r--r--extensions/TimedMediaHandler/handlers/WebMHandler/WebMHandler.php175
-rw-r--r--extensions/TimedMediaHandler/i18n/ady-cyrl.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/aeb-latn.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/af.json25
-rw-r--r--extensions/TimedMediaHandler/i18n/akz.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/aln.json23
-rw-r--r--extensions/TimedMediaHandler/i18n/an.json20
-rw-r--r--extensions/TimedMediaHandler/i18n/ang.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/ar.json67
-rw-r--r--extensions/TimedMediaHandler/i18n/arc.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/arq.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/arz.json24
-rw-r--r--extensions/TimedMediaHandler/i18n/as.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/ast.json122
-rw-r--r--extensions/TimedMediaHandler/i18n/av.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/avk.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/awa.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/az.json13
-rw-r--r--extensions/TimedMediaHandler/i18n/azb.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/ba.json14
-rw-r--r--extensions/TimedMediaHandler/i18n/bcc.json24
-rw-r--r--extensions/TimedMediaHandler/i18n/bcl.json90
-rw-r--r--extensions/TimedMediaHandler/i18n/be-tarask.json71
-rw-r--r--extensions/TimedMediaHandler/i18n/be.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/bg.json24
-rw-r--r--extensions/TimedMediaHandler/i18n/bgn.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/bho.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/bn.json48
-rw-r--r--extensions/TimedMediaHandler/i18n/br.json51
-rw-r--r--extensions/TimedMediaHandler/i18n/bs.json31
-rw-r--r--extensions/TimedMediaHandler/i18n/ca.json44
-rw-r--r--extensions/TimedMediaHandler/i18n/ce.json85
-rw-r--r--extensions/TimedMediaHandler/i18n/ckb.json14
-rw-r--r--extensions/TimedMediaHandler/i18n/cs.json75
-rw-r--r--extensions/TimedMediaHandler/i18n/cu.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/cv.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/cy.json50
-rw-r--r--extensions/TimedMediaHandler/i18n/da.json100
-rw-r--r--extensions/TimedMediaHandler/i18n/de-formal.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/de.json130
-rw-r--r--extensions/TimedMediaHandler/i18n/din.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/diq.json41
-rw-r--r--extensions/TimedMediaHandler/i18n/dsb.json30
-rw-r--r--extensions/TimedMediaHandler/i18n/dty.json12
-rw-r--r--extensions/TimedMediaHandler/i18n/ee.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/el.json28
-rw-r--r--extensions/TimedMediaHandler/i18n/en-gb.json12
-rw-r--r--extensions/TimedMediaHandler/i18n/en.json154
-rw-r--r--extensions/TimedMediaHandler/i18n/eo.json26
-rw-r--r--extensions/TimedMediaHandler/i18n/es.json117
-rw-r--r--extensions/TimedMediaHandler/i18n/et.json122
-rw-r--r--extensions/TimedMediaHandler/i18n/eu.json29
-rw-r--r--extensions/TimedMediaHandler/i18n/fa.json123
-rw-r--r--extensions/TimedMediaHandler/i18n/fi.json78
-rw-r--r--extensions/TimedMediaHandler/i18n/fo.json12
-rw-r--r--extensions/TimedMediaHandler/i18n/fr.json150
-rw-r--r--extensions/TimedMediaHandler/i18n/frp.json38
-rw-r--r--extensions/TimedMediaHandler/i18n/frr.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/fur.json23
-rw-r--r--extensions/TimedMediaHandler/i18n/fy.json16
-rw-r--r--extensions/TimedMediaHandler/i18n/ga.json13
-rw-r--r--extensions/TimedMediaHandler/i18n/gl.json125
-rw-r--r--extensions/TimedMediaHandler/i18n/gom-deva.json12
-rw-r--r--extensions/TimedMediaHandler/i18n/gom-latn.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/grc.json13
-rw-r--r--extensions/TimedMediaHandler/i18n/gsw.json62
-rw-r--r--extensions/TimedMediaHandler/i18n/gu.json23
-rw-r--r--extensions/TimedMediaHandler/i18n/gv.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/he.json125
-rw-r--r--extensions/TimedMediaHandler/i18n/hi.json39
-rw-r--r--extensions/TimedMediaHandler/i18n/hr.json31
-rw-r--r--extensions/TimedMediaHandler/i18n/hrx.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/hsb.json83
-rw-r--r--extensions/TimedMediaHandler/i18n/ht.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/hu.json37
-rw-r--r--extensions/TimedMediaHandler/i18n/hy.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/ia.json92
-rw-r--r--extensions/TimedMediaHandler/i18n/id.json97
-rw-r--r--extensions/TimedMediaHandler/i18n/ilo.json89
-rw-r--r--extensions/TimedMediaHandler/i18n/io.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/is.json60
-rw-r--r--extensions/TimedMediaHandler/i18n/it.json108
-rw-r--r--extensions/TimedMediaHandler/i18n/ja.json91
-rw-r--r--extensions/TimedMediaHandler/i18n/jut.json21
-rw-r--r--extensions/TimedMediaHandler/i18n/jv.json65
-rw-r--r--extensions/TimedMediaHandler/i18n/ka.json89
-rw-r--r--extensions/TimedMediaHandler/i18n/khw.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/kk-arab.json15
-rw-r--r--extensions/TimedMediaHandler/i18n/kk-cyrl.json56
-rw-r--r--extensions/TimedMediaHandler/i18n/kk-latn.json15
-rw-r--r--extensions/TimedMediaHandler/i18n/km.json24
-rw-r--r--extensions/TimedMediaHandler/i18n/kn.json17
-rw-r--r--extensions/TimedMediaHandler/i18n/ko.json104
-rw-r--r--extensions/TimedMediaHandler/i18n/krc.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/krj.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/ksh.json81
-rw-r--r--extensions/TimedMediaHandler/i18n/ku-latn.json14
-rw-r--r--extensions/TimedMediaHandler/i18n/ky.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/la.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/lad.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/lb.json73
-rw-r--r--extensions/TimedMediaHandler/i18n/lfn.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/li.json21
-rw-r--r--extensions/TimedMediaHandler/i18n/lrc.json44
-rw-r--r--extensions/TimedMediaHandler/i18n/lt.json123
-rw-r--r--extensions/TimedMediaHandler/i18n/luz.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/lv.json22
-rw-r--r--extensions/TimedMediaHandler/i18n/mai.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/mg.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/min.json30
-rw-r--r--extensions/TimedMediaHandler/i18n/mk.json144
-rw-r--r--extensions/TimedMediaHandler/i18n/ml.json124
-rw-r--r--extensions/TimedMediaHandler/i18n/mr.json28
-rw-r--r--extensions/TimedMediaHandler/i18n/ms.json97
-rw-r--r--extensions/TimedMediaHandler/i18n/mt.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/myv.json13
-rw-r--r--extensions/TimedMediaHandler/i18n/mzn.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/nah.json12
-rw-r--r--extensions/TimedMediaHandler/i18n/nap.json122
-rw-r--r--extensions/TimedMediaHandler/i18n/nb.json105
-rw-r--r--extensions/TimedMediaHandler/i18n/nds-nl.json24
-rw-r--r--extensions/TimedMediaHandler/i18n/nds.json20
-rw-r--r--extensions/TimedMediaHandler/i18n/ne.json25
-rw-r--r--extensions/TimedMediaHandler/i18n/nl.json108
-rw-r--r--extensions/TimedMediaHandler/i18n/nn.json41
-rw-r--r--extensions/TimedMediaHandler/i18n/oc.json31
-rw-r--r--extensions/TimedMediaHandler/i18n/olo.json18
-rw-r--r--extensions/TimedMediaHandler/i18n/or.json85
-rw-r--r--extensions/TimedMediaHandler/i18n/os.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/pa.json13
-rw-r--r--extensions/TimedMediaHandler/i18n/pdc.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/pfl.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/pl.json101
-rw-r--r--extensions/TimedMediaHandler/i18n/pms.json96
-rw-r--r--extensions/TimedMediaHandler/i18n/pnb.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/ps.json29
-rw-r--r--extensions/TimedMediaHandler/i18n/pt-br.json40
-rw-r--r--extensions/TimedMediaHandler/i18n/pt.json102
-rw-r--r--extensions/TimedMediaHandler/i18n/qqq.json172
-rw-r--r--extensions/TimedMediaHandler/i18n/qu.json14
-rw-r--r--extensions/TimedMediaHandler/i18n/ro.json93
-rw-r--r--extensions/TimedMediaHandler/i18n/roa-tara.json91
-rw-r--r--extensions/TimedMediaHandler/i18n/ru.json111
-rw-r--r--extensions/TimedMediaHandler/i18n/rue.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/sa.json19
-rw-r--r--extensions/TimedMediaHandler/i18n/sah.json23
-rw-r--r--extensions/TimedMediaHandler/i18n/scn.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/sco.json16
-rw-r--r--extensions/TimedMediaHandler/i18n/sdh.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/sgs.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/shn.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/shy-latn.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/si.json85
-rw-r--r--extensions/TimedMediaHandler/i18n/sk.json25
-rw-r--r--extensions/TimedMediaHandler/i18n/sl.json96
-rw-r--r--extensions/TimedMediaHandler/i18n/sq.json20
-rw-r--r--extensions/TimedMediaHandler/i18n/sr-ec.json55
-rw-r--r--extensions/TimedMediaHandler/i18n/sr-el.json53
-rw-r--r--extensions/TimedMediaHandler/i18n/stq.json20
-rw-r--r--extensions/TimedMediaHandler/i18n/su.json19
-rw-r--r--extensions/TimedMediaHandler/i18n/sv.json125
-rw-r--r--extensions/TimedMediaHandler/i18n/sw.json14
-rw-r--r--extensions/TimedMediaHandler/i18n/szl.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/ta.json32
-rw-r--r--extensions/TimedMediaHandler/i18n/tcy.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/te.json37
-rw-r--r--extensions/TimedMediaHandler/i18n/tg-cyrl.json20
-rw-r--r--extensions/TimedMediaHandler/i18n/tg-latn.json20
-rw-r--r--extensions/TimedMediaHandler/i18n/tk.json20
-rw-r--r--extensions/TimedMediaHandler/i18n/tl.json84
-rw-r--r--extensions/TimedMediaHandler/i18n/tly.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/tr.json80
-rw-r--r--extensions/TimedMediaHandler/i18n/ts.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/tt-cyrl.json17
-rw-r--r--extensions/TimedMediaHandler/i18n/tzm.json8
-rw-r--r--extensions/TimedMediaHandler/i18n/ug-arab.json13
-rw-r--r--extensions/TimedMediaHandler/i18n/uk.json134
-rw-r--r--extensions/TimedMediaHandler/i18n/ur.json21
-rw-r--r--extensions/TimedMediaHandler/i18n/vec.json85
-rw-r--r--extensions/TimedMediaHandler/i18n/vep.json11
-rw-r--r--extensions/TimedMediaHandler/i18n/vi.json130
-rw-r--r--extensions/TimedMediaHandler/i18n/vo.json14
-rw-r--r--extensions/TimedMediaHandler/i18n/vro.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/wa.json4
-rw-r--r--extensions/TimedMediaHandler/i18n/war.json9
-rw-r--r--extensions/TimedMediaHandler/i18n/wuu.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/xmf.json10
-rw-r--r--extensions/TimedMediaHandler/i18n/yi.json15
-rw-r--r--extensions/TimedMediaHandler/i18n/yue.json24
-rw-r--r--extensions/TimedMediaHandler/i18n/zh-hans.json137
-rw-r--r--extensions/TimedMediaHandler/i18n/zh-hant.json119
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/getid3.lib.php1346
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/getid3.php1776
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/license.txt340
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.audio-video.matroska.php1771
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.audio-video.mpeg.php296
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.audio-video.quicktime.php2192
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.audio-video.riff.php2435
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.audio.ac3.php473
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.audio.dts.php291
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.audio.flac.php442
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.audio.mp3.php2009
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.audio.ogg.php671
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.tag.id3v1.php359
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/module.tag.id3v2.php3414
-rw-r--r--extensions/TimedMediaHandler/libs/getid3/readme.txt591
-rw-r--r--extensions/TimedMediaHandler/maintenance/cleanupTranscodes.php46
-rw-r--r--extensions/TimedMediaHandler/maintenance/moveTranscoded.php56
-rw-r--r--extensions/TimedMediaHandler/maintenance/resetTranscodes.php41
-rw-r--r--extensions/TimedMediaHandler/maintenance/retryTranscodes.php55
-rw-r--r--extensions/TimedMediaHandler/mwEmbedLoader.php24
-rw-r--r--extensions/TimedMediaHandler/package.json14
-rw-r--r--extensions/TimedMediaHandler/resources/PopUpThumbVideo.css29
-rw-r--r--extensions/TimedMediaHandler/resources/download_sprite.pngbin0 -> 806 bytes
-rw-r--r--extensions/TimedMediaHandler/resources/embedPlayerIframe.css7
-rw-r--r--extensions/TimedMediaHandler/resources/ext.tmh.OgvJsSupport.js67
-rw-r--r--extensions/TimedMediaHandler/resources/ext.tmh.TimedTextSelector.js8
-rw-r--r--extensions/TimedMediaHandler/resources/ext.tmh.transcodetable.js90
-rw-r--r--extensions/TimedMediaHandler/resources/mw.MediaWikiPlayer.loader.js8
-rw-r--r--extensions/TimedMediaHandler/resources/mw.MediaWikiPlayerSupport.js380
-rw-r--r--extensions/TimedMediaHandler/resources/mw.PopUpThumbVideo.js44
-rw-r--r--extensions/TimedMediaHandler/resources/mw.TMHGalleryHook.js46
-rw-r--r--extensions/TimedMediaHandler/resources/player_big_play_button.pngbin0 -> 987 bytes
-rw-r--r--extensions/TimedMediaHandler/resources/player_big_play_button_hover.pngbin0 -> 1022 bytes
-rw-r--r--extensions/TimedMediaHandler/resources/transcodeTable.css14
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/ApiTestCaseVideoUpload.php130
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/README11
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/TestApiUploadVideo.php34
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/TestOggHandler.php67
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/TestTimeParsing.php42
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/TestTimedMediaHandler.php47
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/TestTimedMediaTransformOutput.php142
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/TestVideoThumbnail.php80
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/TestVideoTranscode.php121
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/TestWebMHandler.php52
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/media/README38
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/media/VP9-tractor.webmbin0 -> 179277 bytes
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/media/bear-vp9-opus.webmbin0 -> 101414 bytes
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/media/broken-file.oggbin0 -> 11424 bytes
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/media/doubleTag.ogabin0 -> 11423 bytes
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/media/shuttle10seconds.1080x608.webmbin0 -> 699018 bytes
-rw-r--r--extensions/TimedMediaHandler/tests/phpunit/media/test5seconds.electricsheep.300x400.ogvbin0 -> 299761 bytes
-rw-r--r--extensions/TimedMediaHandler/version5
527 files changed, 64411 insertions, 0 deletions
diff --git a/extensions/TimedMediaHandler/.gitignore b/extensions/TimedMediaHandler/.gitignore
new file mode 100644
index 00000000..0172e092
--- /dev/null
+++ b/extensions/TimedMediaHandler/.gitignore
@@ -0,0 +1,6 @@
+.svn
+*~
+*.kate-swp
+.*.swp
+.project
+node_modules/
diff --git a/extensions/TimedMediaHandler/.gitreview b/extensions/TimedMediaHandler/.gitreview
new file mode 100644
index 00000000..39e4aad6
--- /dev/null
+++ b/extensions/TimedMediaHandler/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.wikimedia.org
+port=29418
+project=mediawiki/extensions/TimedMediaHandler.git
+defaultbranch=REL1_26
diff --git a/extensions/TimedMediaHandler/.jscsrc b/extensions/TimedMediaHandler/.jscsrc
new file mode 100644
index 00000000..9d22e3f2
--- /dev/null
+++ b/extensions/TimedMediaHandler/.jscsrc
@@ -0,0 +1,3 @@
+{
+ "preset": "wikimedia"
+}
diff --git a/extensions/TimedMediaHandler/.jshintignore b/extensions/TimedMediaHandler/.jshintignore
new file mode 100644
index 00000000..0f77f29d
--- /dev/null
+++ b/extensions/TimedMediaHandler/.jshintignore
@@ -0,0 +1 @@
+MwEmbedModules
diff --git a/extensions/TimedMediaHandler/.jshintrc b/extensions/TimedMediaHandler/.jshintrc
new file mode 100644
index 00000000..ef363f81
--- /dev/null
+++ b/extensions/TimedMediaHandler/.jshintrc
@@ -0,0 +1,44 @@
+{
+ /* Common */
+
+ // Enforcing
+ "camelcase": true,
+ "curly": true,
+ "eqeqeq": true,
+ "immed": true,
+ "latedef": true,
+ "newcap": true,
+ "noarg": true,
+ "noempty": true,
+ "nonew": true,
+ "quotmark": "single",
+ "trailing": true,
+ "undef": true,
+ "unused": true,
+ // Legacy
+ "onevar": true,
+
+ /* Local */
+
+ // Enforcing
+ "bitwise": true,
+ "es3": true,
+ // Relaxing
+ "laxbreak": true,
+ "smarttabs": true,
+ "multistr": true,
+ // Environment
+ "browser": true,
+ // Legacy
+ "nomen": true,
+
+ "predef": [
+ "mediaWiki",
+ "mw",
+ "jQuery",
+ "OGVVersion",
+ "OGVSupport",
+ "OGVPlayer",
+ "OGVLoader"
+ ]
+}
diff --git a/extensions/TimedMediaHandler/ApiQueryVideoInfo.php b/extensions/TimedMediaHandler/ApiQueryVideoInfo.php
new file mode 100644
index 00000000..65239166
--- /dev/null
+++ b/extensions/TimedMediaHandler/ApiQueryVideoInfo.php
@@ -0,0 +1,268 @@
+<?php
+/**
+ * Extends imageinfo with support for videoinfo sources property.
+ *
+ * Alternatively core ApiQueryImageInfo could support being extended in some straightforward ways.
+ * see: http://www.mediawiki.org/wiki/User:Catrope/Extension_review/TimedMediaHandler#ApiQueryVideoInfo.php
+ *
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ // Eclipse helper - will be ignored in production
+ require_once( "ApiBase.php" );
+}
+
+class ApiQueryVideoInfo extends ApiQueryImageInfo {
+
+ public function __construct( $query, $moduleName, $prefix = 'vi' ) {
+ // We allow a subclass to override the prefix, to create a related API module.
+ // Some other parts of MediaWiki construct this with a null $prefix, which used to be ignored when this only took two arguments
+ if ( is_null( $prefix ) ) {
+ $prefix = 'vi';
+ }
+ parent::__construct( $query, $moduleName, $prefix );
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getDescription() {
+ return 'Extends imageinfo to include video source (derivatives) information';
+ }
+
+ static function getInfo( $file, $prop, $result, $thumbParams = null, $version = 'latest' ) {
+ $vals = parent::getInfo( $file, $prop, $result, $thumbParams );
+ if( isset( $prop['derivatives'] ) ) {
+ if ( $file->getHandler() && $file->getHandler() instanceof TimedMediaHandler ) {
+ $vals['derivatives'] = WebVideoTranscode::getSources( $file, array( 'fullurl') );
+ $result->setIndexedTagName( $vals['derivatives'], "derivative" );
+ } else {
+ // Non-TMH file, no derivatives.
+ $vals['derivatives'] = array();
+ }
+ }
+ return $vals;
+ }
+
+ public static function getPropertyNames( $filter = array() ) {
+ $prop = parent::getPropertyNames();
+ $prop[] = 'derivatives';
+ return $prop;
+ }
+
+ public static function getPropertyDescriptions( $filter = array(), $modulePrefix = '' ) {
+ $s = parent::getPropertyDescriptions( $filter, $modulePrefix );
+ $s[] = ' derivatives - Adds an array of the different format and quality versions of an audio or video file that are available.';
+ return $s;
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getExamples() {
+ return array(
+ 'api.php?action=query&titles=File:Folgers.ogv&prop=videoinfo',
+ );
+ }
+
+ /**
+ * @see ApiBase::getExamplesMessages()
+ */
+ protected function getExamplesMessages() {
+ return array(
+ 'action=query&titles=File:Folgers.ogv&prop=videoinfo'
+ => 'apihelp-query+videoinfo-example-1',
+ );
+ }
+
+ /**
+ * Execute and getAllowedprops have to be copied verbatim because of static self:: references
+ *
+ * With late static binding this would be avoidable:
+ * http://php.net/manual/en/language.oop5.late-static-bindings.php
+ */
+ public function execute() {
+ $params = $this->extractRequestParams();
+
+ $prop = array_flip( $params['prop'] );
+
+ $scale = $this->getScale( $params );
+
+ $pageIds = $this->getPageSet()->getAllTitlesByNamespace();
+ if ( !empty( $pageIds[NS_FILE] ) ) {
+ $titles = array_keys( $pageIds[NS_FILE] );
+ asort( $titles ); // Ensure the order is always the same
+
+ $skip = false;
+ if ( !is_null( $params['continue'] ) ) {
+ $skip = true;
+ $cont = explode( '|', $params['continue'] );
+ if ( count( $cont ) != 2 ) {
+ $this->dieUsage( 'Invalid continue param. You should pass the original ' .
+ 'value returned by the previous query', '_badcontinue' );
+ }
+ $fromTitle = strval( $cont[0] );
+ $fromTimestamp = $cont[1];
+ // Filter out any titles before $fromTitle
+ foreach ( $titles as $key => $title ) {
+ if ( $title < $fromTitle ) {
+ unset( $titles[$key] );
+ } else {
+ break;
+ }
+ }
+ }
+
+ $result = $this->getResult();
+ $images = RepoGroup::singleton()->findFiles( $titles );
+ foreach ( $images as $img ) {
+ // Skip redirects
+ if ( $img->getOriginalTitle()->isRedirect() ) {
+ continue;
+ }
+
+ $start = $skip ? $fromTimestamp : $params['start'];
+ $pageId = $pageIds[NS_IMAGE][ $img->getOriginalTitle()->getDBkey() ];
+
+ $fit = $result->addValue(
+ array( 'query', 'pages', intval( $pageId ) ),
+ 'imagerepository', $img->getRepoName()
+ );
+ if ( !$fit ) {
+ if ( count( $pageIds[NS_IMAGE] ) == 1 ) {
+ // The user is screwed. imageinfo can't be solely
+ // responsible for exceeding the limit in this case,
+ // so set a query-continue that just returns the same
+ // thing again. When the violating queries have been
+ // out-continued, the result will get through
+ $this->setContinueEnumParameter( 'start',
+ wfTimestamp( TS_ISO_8601, $img->getTimestamp() ) );
+ } else {
+ $this->setContinueEnumParameter( 'continue',
+ $this->getContinueStr( $img ) );
+ }
+ break;
+ }
+
+ // Check if we can make the requested thumbnail, and get transform parameters.
+ $finalThumbParams = $this->mergeThumbParams( $img, $scale, $params['urlparam'] );
+
+ // Get information about the current version first
+ // Check that the current version is within the start-end boundaries
+ $gotOne = false;
+ if (
+ ( is_null( $start ) || $img->getTimestamp() <= $start ) &&
+ ( is_null( $params['end'] ) || $img->getTimestamp() >= $params['end'] )
+ ) {
+ $gotOne = true;
+
+ $fit = $this->addPageSubItem( $pageId,
+ self::getInfo( $img, $prop, $result, $finalThumbParams ) );
+ if ( !$fit ) {
+ if ( count( $pageIds[NS_IMAGE] ) == 1 ) {
+ // See the 'the user is screwed' comment above
+ $this->setContinueEnumParameter( 'start',
+ wfTimestamp( TS_ISO_8601, $img->getTimestamp() ) );
+ } else {
+ $this->setContinueEnumParameter( 'continue',
+ $this->getContinueStr( $img ) );
+ }
+ break;
+ }
+ }
+
+ // Now get the old revisions
+ // Get one more to facilitate query-continue functionality
+ $count = ( $gotOne ? 1 : 0 );
+ $oldies = $img->getHistory( $params['limit'] - $count + 1, $start, $params['end'] );
+ foreach ( $oldies as $oldie ) {
+ if ( ++$count > $params['limit'] ) {
+ // We've reached the extra one which shows that there are additional pages to be had. Stop here...
+ // Only set a query-continue if there was only one title
+ if ( count( $pageIds[NS_FILE] ) == 1 ) {
+ $this->setContinueEnumParameter( 'start',
+ wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
+ }
+ break;
+ }
+ $fit = $this->addPageSubItem( $pageId,
+ self::getInfo( $oldie, $prop, $result, $finalThumbParams ) );
+ if ( !$fit ) {
+ if ( count( $pageIds[NS_IMAGE] ) == 1 ) {
+ $this->setContinueEnumParameter( 'start',
+ wfTimestamp( TS_ISO_8601, $oldie->getTimestamp() ) );
+ } else {
+ $this->setContinueEnumParameter( 'continue',
+ $this->getContinueStr( $oldie ) );
+ }
+ break;
+ }
+ }
+ if ( !$fit ) {
+ break;
+ }
+ $skip = false;
+ }
+
+ if ( defined( 'ApiResult::META_CONTENT' ) ) {
+ $pages = (array)$this->getResult()->getResultData( array( 'query', 'pages' ), array( 'Strip' => 'base' ) );
+ } else {
+ $data = $this->getResultData();
+ $pages = $data['query']['pages'];
+ }
+ foreach ( $pages as $pageid => $arr ) {
+ if ( !isset( $arr['imagerepository'] ) ) {
+ $result->addValue(
+ array( 'query', 'pages', intval( $pageid ) ),
+ 'imagerepository', ''
+ );
+ }
+ // The above can't fail because it doesn't increase the result size
+ }
+ }
+ }
+
+ public function getAllowedParams() {
+ // Get imageinfo params
+ $params = array_intersect_key(
+ parent::getAllowedParams(),
+ array_flip( array(
+ 'limit', 'start', 'end', 'urlwidth', 'urlheight', 'urlparam', 'continue'
+ ) )
+ );
+ if ( defined( 'ApiBase::PARAM_HELP_MSG' ) ) {
+ foreach ( $params as $k => $v ) {
+ if ( !isset( $params[$k][ApiBase::PARAM_HELP_MSG] ) ) {
+ $params[$k][ApiBase::PARAM_HELP_MSG] = "apihelp-query+imageinfo-param-$k";
+ }
+ }
+ }
+
+ // Add our param
+ $params = array(
+ 'prop' => array(
+ ApiBase::PARAM_ISMULTI => true,
+ ApiBase::PARAM_DFLT => 'timestamp|user',
+ ApiBase::PARAM_TYPE => self::getPropertyNames(),
+ ),
+ ) + $params;
+
+ return $params;
+ }
+
+ /**
+ * Get API self-documentation.
+ *
+ * Needed since core calls self::getPropertyDescriptions(),
+ * (and not static::getPropertyDescriptions() ) which binds
+ * to the static method in that class instead of the static
+ * method of the same name in this class.
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getParamDescription() {
+ $params = parent::getParamDescription();
+ $p = $this->getModulePrefix();
+ $params['prop'] = self::getPropertyDescriptions( array(), $p );
+ return $params;
+ }
+}
diff --git a/extensions/TimedMediaHandler/ApiTranscodeReset.php b/extensions/TimedMediaHandler/ApiTranscodeReset.php
new file mode 100644
index 00000000..597d17e1
--- /dev/null
+++ b/extensions/TimedMediaHandler/ApiTranscodeReset.php
@@ -0,0 +1,184 @@
+<?php
+if ( !defined( 'MEDIAWIKI' ) ) {
+ // Eclipse helper - will be ignored in production
+ require_once( 'ApiBase.php' );
+}
+
+/**
+ * Allows users with the 'transcode-reset' right to reset / re-run a transcode job.
+ *
+ * You can specify must specify a media asset title. You optionally can specify
+ * a transcode key, to only reset a single transcode job for a particular media asset.
+ * @ingroup API
+ */
+class ApiTranscodeReset extends ApiBase {
+ public function execute() {
+ global $wgUser, $wgEnableTranscode, $wgWaitTimeForTranscodeReset;
+ // Check if transcoding is enabled on this wiki at all:
+ if( !$wgEnableTranscode ){
+ $this->dieUsage( 'Transcode is disabled on this wiki', 'disabledtranscode' );
+ }
+
+ // Confirm the user has the transcode-reset right
+ if( !$wgUser->isAllowed( 'transcode-reset' ) ){
+ $this->dieUsage( 'You don\'t have permission to reset transcodes', 'missingpermission' );
+ }
+ $params = $this->extractRequestParams();
+
+ // Make sure we have a valid Title
+ $titleObj = Title::newFromText( $params['title'] );
+ if ( !$titleObj || $titleObj->isExternal() ) {
+ $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) );
+ }
+ // Make sure the title can be transcoded
+ if( !TimedMediaHandlerHooks::isTranscodableTitle( $titleObj ) ){
+ $this->dieUsageMsg( array( 'invalidtranscodetitle', $params['title'] ) );
+ }
+ $transcodeKey = false;
+ // Make sure its a enabled transcode key we are trying to remove:
+ // ( if you update your transcode keys the api is not how you purge the database of expired keys )
+ if( isset( $params['transcodekey'] ) ){
+ global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet;
+ $transcodeSet = array_merge($wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet);
+ if( !in_array( $params['transcodekey'], $transcodeSet ) ){
+ $this->dieUsage( 'Invalid or disabled transcode key: ' . htmlspecialchars( $params['transcodekey'] ) , 'badtranscodekey' );
+ } else {
+ $transcodeKey = $params['transcodekey'];
+ }
+ }
+
+ // Don't reset if less than 1 hour has passed and we have no error )
+ $file = wfFindFile( $titleObj );
+ $timeSinceLastReset = self::checkTimeSinceLastRest( $file, $transcodeKey );
+ if( $timeSinceLastReset < $wgWaitTimeForTranscodeReset){
+ $this->dieUsage( 'Not enough time has passed since the last reset of this transcode. ' .
+ TimedMediaHandler::getTimePassedMsg( $wgWaitTimeForTranscodeReset - $timeSinceLastReset ) .
+ ' until this transcode can be reset', 'notenoughtimereset');
+ }
+
+ // All good do the transcode removal:
+ WebVideoTranscode::removeTranscodes( $file, $transcodeKey );
+
+ // Oh and we wanted to reset it, right? Trigger again.
+ WebVideoTranscode::updateJobQueue( $file, $transcodeKey );
+
+ $this->getResult()->addValue(null, 'success', 'removed transcode');
+ }
+
+ /**
+ * @param $file
+ * @param $transcodeKey
+ * @return int|string
+ */
+ static public function checkTimeSinceLastRest( $file, $transcodeKey ){
+ global $wgWaitTimeForTranscodeReset;
+ $transcodeStates = WebVideoTranscode::getTranscodeState( $file );
+ if( $transcodeKey ){
+ if( ! $transcodeStates[$transcodeKey] ){
+ // transcode key not found
+ return $wgWaitTimeForTranscodeReset + 1;
+ }
+ return self::getStateResetTime( $transcodeStates[$transcodeKey] );
+ }
+ // least wait is set to reset time:
+ $leastWait = $wgWaitTimeForTranscodeReset + 1;
+ // else check for lowest reset time
+ foreach($transcodeStates as $state ){
+ $ctime = self::getStateResetTime( $state );
+ if( $ctime < $leastWait){
+ $leastWait = $ctime;
+ }
+ }
+ return $leastWait;
+ }
+
+ /**
+ * @param $state
+ * @return int|string
+ */
+ static public function getStateResetTime( $state ){
+ global $wgWaitTimeForTranscodeReset;
+ $db = wfGetDB( DB_SLAVE );
+ // if an error return waitTime +1
+ if( !is_null( $state['time_error']) ){
+ return $wgWaitTimeForTranscodeReset + 1;
+ }
+ // return wait time from most recent event
+ foreach( array( 'time_success', 'time_startwork', 'time_addjob' ) as $timeField ){
+ if( !is_null( $state[ $timeField ] )){
+ return $db->timestamp() - $db->timestamp( $state[ $timeField ] );
+ }
+ }
+ // No time info, return resetWaitTime
+ return $wgWaitTimeForTranscodeReset + 1;
+ }
+
+ public function mustBePosted() {
+ return true;
+ }
+
+ public function isWriteMode() {
+ return true;
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ protected function getDescription() {
+ return 'Users with the \'transcode-reset\' right can reset and re-run a transcode job';
+ }
+
+ protected function getAllowedParams() {
+ return array(
+ 'title' => array(
+ ApiBase::PARAM_TYPE => 'string',
+ ApiBase::PARAM_REQUIRED => true
+ ),
+ 'transcodekey' => null,
+ 'token' => null,
+ );
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ protected function getParamDescription() {
+ return array(
+ 'title' => 'The media file title',
+ 'transcodekey' => 'The transcode key you wish to reset',
+ 'token' => 'An edit token obtained via action=tokens',
+ );
+ }
+
+ public function needsToken() {
+ return 'csrf';
+ }
+
+ public function getTokenSalt() {
+ return '';
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ protected function getExamples() {
+ return array(
+ 'Reset all transcodes for Clip.webm :',
+ ' api.php?action=transcodereset&title=File:Clip.webm&token=%2B\\',
+ 'Reset the \'360_560kbs.webm\' transcode key for clip.webm. Get a list of transcode keys via a \'transcodestatus\' query',
+ ' api.php?action=transcodereset&title=File:Clip.webm&transcodekey=360_560kbs.webm&token=%2B\\',
+ );
+ }
+
+ /**
+ * @see ApiBase::getExamplesMessages()
+ */
+ protected function getExamplesMessages() {
+ return array(
+ 'action=transcodereset&title=File:Clip.webm&token=123ABC'
+ => 'apihelp-transcodereset-example-1',
+ 'action=transcodereset&title=File:Clip.webm&transcodekey=360_560kbs.webm&token=123ABC'
+ => 'apihelp-transcodereset-example-2',
+ );
+ }
+}
diff --git a/extensions/TimedMediaHandler/ApiTranscodeStatus.php b/extensions/TimedMediaHandler/ApiTranscodeStatus.php
new file mode 100644
index 00000000..38dcccc6
--- /dev/null
+++ b/extensions/TimedMediaHandler/ApiTranscodeStatus.php
@@ -0,0 +1,79 @@
+<?php
+/**
+ * Allows for api queries to get detailed information about the transcode state of a particular
+ * media asset. ( basically directly returns the transcode status table )
+ *
+ * This information can be used to generate status tables similar to the one seen
+ * on the image page.
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ // Eclipse helper - will be ignored in production
+ require_once( "ApiBase.php" );
+}
+
+class ApiTranscodeStatus extends ApiQueryBase {
+ public function execute() {
+ $pageIds = $this->getPageSet()->getAllTitlesByNamespace();
+ // Make sure we have files in the title set:
+ if ( !empty( $pageIds[NS_FILE] ) ) {
+ $titles = array_keys( $pageIds[NS_FILE] );
+ asort( $titles ); // Ensure the order is always the same
+
+ $result = $this->getResult();
+ $images = RepoGroup::singleton()->findFiles( $titles );
+ /**
+ * @var $img File
+ */
+ foreach ( $images as $img ) {
+ // if its a "transcode" add the transcode status table output
+ if( TimedMediaHandlerHooks::isTranscodableTitle( $img->getTitle() ) ){
+ $transcodeStatus = WebVideoTranscode::getTranscodeState( $img );
+ // remove useless properties
+ foreach($transcodeStatus as $key=>&$val ){
+ unset( $val['id'] );
+ unset( $val['image_name']);
+ unset( $val['key'] );
+ }
+ $result->addValue( array( 'query', 'pages', $img->getTitle()->getArticleID() ), 'transcodestatus', $transcodeStatus );
+ }
+ }
+ }
+ }
+
+ public function getCacheMode( $params ) {
+ return 'public';
+ }
+
+ public function getAllowedParams() {
+ return array();
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ public function getDescription() {
+ return array(
+ 'Get transcode status for a given file page'
+ );
+ }
+
+ /**
+ * @deprecated since MediaWiki core 1.25
+ */
+ protected function getExamples() {
+ return array (
+ 'api.php?action=query&prop=transcodestatus&titles=File:Clip.webm',
+ );
+ }
+
+ /**
+ * @see ApiBase::getExamplesMessages()
+ */
+ protected function getExamplesMessages() {
+ return array(
+ 'action=query&prop=transcodestatus&titles=File:Clip.webm'
+ => 'apihelp-query+transcodestatus-example-1',
+ );
+ }
+}
diff --git a/extensions/TimedMediaHandler/COPYING b/extensions/TimedMediaHandler/COPYING
new file mode 100644
index 00000000..019694a9
--- /dev/null
+++ b/extensions/TimedMediaHandler/COPYING
@@ -0,0 +1,342 @@
+== GNU GENERAL PUBLIC LICENSE ==
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+=== Preamble ===
+
+The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+== TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ==
+
+'''0.''' This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+'''1.''' You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+'''2.''' You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ '''a)''' You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ '''b)''' You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ '''c)''' If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+'''3.''' You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ '''a)''' Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ '''b)''' Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ '''c)''' Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+'''4.''' You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+'''5.''' You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+'''6.''' Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+'''7.''' If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+'''8.''' If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+'''9.''' The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+'''10.''' If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+=== NO WARRANTY ===
+
+'''11.''' BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+'''12.''' IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ '''END OF TERMS AND CONDITIONS'''
+
+== How to Apply These Terms to Your New Programs ==
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/extensions/TimedMediaHandler/Gruntfile.js b/extensions/TimedMediaHandler/Gruntfile.js
new file mode 100644
index 00000000..45380710
--- /dev/null
+++ b/extensions/TimedMediaHandler/Gruntfile.js
@@ -0,0 +1,34 @@
+/*jshint node:true */
+module.exports = function ( grunt ) {
+ grunt.loadNpmTasks( 'grunt-contrib-jshint' );
+ grunt.loadNpmTasks( 'grunt-jsonlint' );
+ grunt.loadNpmTasks( 'grunt-banana-checker' );
+ grunt.loadNpmTasks( 'grunt-jscs' );
+
+ grunt.initConfig( {
+ jshint: {
+ options: {
+ jshintrc: true
+ },
+ all: [
+ '*.js'
+ ]
+ },
+ jscs: {
+ src: '<%= jshint.all %>'
+ },
+ banana: {
+ all: 'i18n/'
+ },
+ jsonlint: {
+ all: [
+ '*.json',
+ '**/*.json',
+ '!node_modules/**'
+ ]
+ }
+ } );
+
+ grunt.registerTask( 'test', [ 'jshint', 'jscs', 'jsonlint', 'banana' ] );
+ grunt.registerTask( 'default', 'test' );
+};
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.config.php b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.config.php
new file mode 100644
index 00000000..af32b4d7
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.config.php
@@ -0,0 +1,194 @@
+<?php
+ /**
+ * Do not edit this file instead use LocalSettings.php and
+ * $wgMwEmbedModuleConfig[ {configuration name} ] = value; format
+ */
+ return array (
+ // If the player controls should be overlaid on top of the video ( if supported by playback method)
+ // can be set to false per embed player via overlayControls attribute
+ 'EmbedPlayer.OverlayControls' => true,
+
+ // The preferred media codec preference
+ // Note user selected format order
+ 'EmbedPlayer.CodecPreference' => array( 'vp9', 'webm', 'h264', 'ogg' ),
+
+ // If video tag support should be disabled all-together, used to test
+ // fallback decoding methods and direct file links
+ 'EmbedPlayer.DisableVideoTagSupport' => false,
+
+ // If detected browser flash support should be ignored, and flash support,
+ // set to false. This will eliminate support for flash based playback.
+ 'EmbedPlayer.DisableHTML5FlashFallback'=> false,
+
+ // Can be used to set player sources via configuration, useful in cases,
+ // where metadata is loaded from an api, but actual sources need to be pointed
+ // to another location at runtime via config
+ 'EmbedPlayer.ReplaceSources' => null,
+
+ // If the flavor selector menu option should be displayed:
+ // This will be enabled by default in some future release of the library
+ 'EmbedPlayer.EnableFlavorSelector' => false,
+
+ // If the iPad should use html controls
+ // With html controls you can't access native fullscreen
+ // With html controls you can support html themed controls, overlays, ads etc. )
+ 'EmbedPlayer.EnableIpadHTMLControls' => true,
+
+ // If the webkit-playsinline attribute should be added to the video tag. Will cause the player
+ // to play inline on iPhone
+ 'EmbedPlayer.WebKitPlaysInline'=> false,
+
+ // If we should use the native device fullscreen call,
+ // this gives you hybrid player, where controls are in HTML for in browser playback,
+ // and native controls when the fullscreen button is pressed.
+ // its not the default since often users want playback control if using html controls,
+ // ( i.e no add skip etc )
+ 'EmbedPlayer.EnableIpadNativeFullscreen' => false,
+
+ // By default we display an html play screen, image thumb and play button.
+ // even though this is still a 'native' player.
+ // If you are not using ad plugins you may want to set this to false
+ // and display the native play button:
+ 'EmbedPlayer.iPhoneShowHTMLPlayScreen' => true,
+
+ // If the large play button should be disabled on replay:
+ 'EmbedPlayer.ForceLargeReplayButton' => false,
+
+ // The attribution library page
+ 'EmbedPlayer.LibraryPage' => 'http://www.kaltura.org/project/HTML5_Video_Media_JavaScript_Library',
+
+ // What tags will be re-written to video player by default
+ // Set to empty string or null to avoid automatic video tag rewrites to embedPlayer
+ "EmbedPlayer.RewriteSelector" => "video,audio,playlist",
+
+ // Default video size ( if no size provided )
+ "EmbedPlayer.DefaultSize" => "400x300",
+
+ // Default player controls size:
+ 'EmbedPlayer.ControlsHeight' => 31,
+
+ // Default time display size:
+ 'EmbedPlayer.TimeDisplayWidth' => 85,
+
+ // If the video player should attribute kaltura
+ "EmbedPlayer.KalturaAttribution" => true,
+
+ // The attribution button
+ 'EmbedPlayer.AttributionButton' => array(
+ 'title' => 'Kaltura html5 video library',
+ 'href' => 'http://www.kaltura.com',
+ // Style icon to be applied
+ 'class' => 'kaltura-icon',
+ // Style to be applied to the outer attribution button container div
+ 'style' => array(),
+ // An icon image url 16x16 image url or data url )
+ 'iconurl' => false
+ ),
+
+ // If the options control bar menu item should be enabled:
+ 'EmbedPlayer.EnableOptionsMenu' => false,
+
+ // If users can right click on the player
+ 'EmbedPlayer.EnableRightClick' => true,
+
+ // Default supported menu items is merged with skin menu items
+ 'EmbedPlayer.EnabledOptionsMenuItems' => array(
+ // Player Select
+ 'playerSelect',
+
+ // Download the file menu
+ 'download',
+
+ // Share the video menu
+ 'share',
+
+ // Player library link
+ 'aboutPlayerLibrary'
+ ),
+
+ // If the player should wait for metadata like video size and duration, before trying to draw
+ // the player interface.
+ 'EmbedPlayer.WaitForMeta' => true,
+
+ // Set the browser player warning flag displays warning for non optimal playback
+ "EmbedPlayer.ShowNativeWarning" => true,
+
+ // If player errors / alerts should be displayed:
+ "EmbedPlayer.ShowPlayerAlerts" => true,
+
+ // If fullscreen is global enabled.
+ "EmbedPlayer.EnableFullscreen" => true,
+
+ // If the embed player time display should be shown
+ 'EmbedPlayer.EnableTimeDisplay' => true,
+
+ // If the embed player volume control should be displayed
+ 'EmbedPlayer.EnableVolumeControl' => true,
+
+ // If fullscreen should pop-open a new window
+ //( instead of trying to expand the video player to browser fullscreen )
+ "EmbedPlayer.NewWindowFullscreen" => false,
+
+ // If a fullscreen tip to press f11 should be displayed when entering fullscreen
+ "EmbedPlayer.FullscreenTip" => true,
+
+ // if the browser should display a warning for direct file links:
+ "EmbedPlayer.DirectFileLinkWarning" => false,
+
+ "EmbedPlayer.FirefoxLink" => 'http://www.mozilla.com/en-US/firefox/upgrade.html?from=mwEmbed',
+
+ // If mwEmbed should use the Native player controls
+ // this will prevent video tag rewriting and skinning
+ // useful for devices such as iPad / iPod that
+ // don't fully support DOM overlays or don't expose full-screen
+ // functionality to javascript
+ "EmbedPlayer.NativeControls" => false,
+
+ // If mwEmbed should use native controls on mobile safari
+ "EmbedPlayer.NativeControlsMobileSafari" => true,
+
+ // The z-index given to the player interface during full screen ( high z-index )
+ "EmbedPlayer.FullScreenZIndex" => 999998,
+
+ // The default share embed mode ( can be "iframe" or "xssVideo" )
+ //
+ // "iframe" will provide a <iframe tag pointing to mwEmbedFrame.php
+ // Object embedding should be much more compatible with sites that
+ // let users embed flash applets
+ // "xssVideo" will include the source javascript and video tag to
+ // rewrite the player on the remote page DOM
+ // Video tag embedding is much more mash-up friendly but exposes
+ // the remote site to the mwEmbed javascript and can be a xss issue.
+ "EmbedPlayer.ShareEmbedMode" => 'iframe',
+
+ // The skin framework list:
+ "EmbedPlayer.SkinList" => array( 'mvpcf', 'kskin' ),
+
+ // Default player skin name
+ "EmbedPlayer.DefaultSkin" => "mvpcf",
+
+ // Number of milliseconds between interface updates
+ 'EmbedPlayer.MonitorRate' => 250,
+
+ // If on Android should use html5 ( even if flash is installed on the machine )
+ 'EmbedPlayer.UseFlashOnAndroid' => false,
+
+ // If embedPlayer should support server side temporal urls for seeking options are
+ // flash|always|none default is support for flash only.
+ 'EmbedPlayer.EnableURLTimeEncoding' => 'flash',
+
+ // The domains which can read and send events to the video player
+ 'EmbedPLayer.IFramePlayer.DomainWhiteList' => '*',
+
+ // If the iframe should send and receive javascript events across domains via postMessage
+ 'EmbedPlayer.EnableIframeApi' => true,
+
+ // If set to true will output the iframe as inline contents on the same domain as page contents
+ 'EmbedPlayer.PageDomainIframe' => true,
+
+ // When there is no in-browser playback mechanism provide a download link for the play button
+ 'EmbedPlayer.NotPlayableDownloadLink' => true,
+
+ // A black pixel for source switching
+ 'EmbedPlayer.BlackPixel' => "data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%01%00%00%00%01%08%02%00%00%00%90wS%DE%00%00%00%01sRGB%00%AE%CE%1C%E9%00%00%00%09pHYs%00%00%0B%13%00%00%0B%13%01%00%9A%9C%18%00%00%00%07tIME%07%DB%0B%0A%17%041%80%9B%E7%F2%00%00%00%19tEXtComment%00Created%20with%20GIMPW%81%0E%17%00%00%00%0CIDAT%08%D7c%60%60%60%00%00%00%04%00%01'4'%0A%00%00%00%00IEND%AEB%60%82"
+ );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.loader.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.loader.js
new file mode 100644
index 00000000..f63a9393
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.loader.js
@@ -0,0 +1,69 @@
+/**
+* EmbedPlayer loader
+*/
+( function( mw, $ ) {
+ /**
+ * Add a DOM ready check for player tags
+ */
+ $( function() {
+ var $selected = $( mw.config.get( 'EmbedPlayer.RewriteSelector' ) );
+ if ( $selected.length ) {
+ var inx = 0;
+ var checkSetDone = function() {
+ if ( inx < $selected.length ) {
+ // put in timeout to avoid browser lockup, and function stack
+ $selected.slice( inx, inx + 1 ).embedPlayer( function() {
+ setTimeout( function() {
+ checkSetDone();
+ }, 5 );
+ } );
+ }
+ inx++;
+ };
+
+ checkSetDone();
+ }
+ } );
+
+ /**
+ * Add the mwEmbed jQuery loader wrapper
+ */
+ $.fn.embedPlayer = function( readyCallback ) {
+ var playerSet = this;
+ mw.log( 'jQuery.fn.embedPlayer :: ' + $( playerSet ).length );
+
+ // Set up the embed video player class request: (include the skin js as well)
+ var dependencySet = [
+ 'mw.EmbedPlayer'
+ ];
+
+ mw.loader.using( [ 'jquery.client', 'jquery.mwEmbedUtil', 'mw.MwEmbedSupport' ], function() {
+ $( playerSet ).each( function( inx, playerElement ) {
+ // we have javascript ( disable controls )
+ $( playerElement ).removeAttr( 'controls' );
+ // Add an overlay loader ( firefox has its own native loading spinner )
+
+ if ( $.client.profile().name !== 'firefox' ) {
+ $( playerElement )
+ .parent()
+ .getAbsoluteOverlaySpinner()
+ .attr('id', 'loadingSpinner_' + $( playerElement ).attr('id') );
+ }
+ // Allow other modules update the dependencies
+ $( mw ).trigger( 'EmbedPlayerUpdateDependencies',
+ [ playerElement, dependencySet ] );
+ } );
+
+ // Remove any duplicates in the dependencySet:
+ dependencySet = $.uniqueArray( dependencySet );
+
+ // Do the request and process the playerElements with updated dependency set
+ mw.loader.using( dependencySet, function() {
+ // Setup the enhanced language:
+ mw.processEmbedPlayers( playerSet, readyCallback );
+ }, function( e ) {
+ throw new Error( 'Error loading EmbedPlayer dependency set: ' + e.message );
+ } );
+ } );
+ };
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.php b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.php
new file mode 100644
index 00000000..a813c8d0
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/EmbedPlayer.php
@@ -0,0 +1,103 @@
+<?php
+ global $wgVideoPlayerSkinModule;
+ // Register all the EmbedPlayer modules
+ return array(
+ "mw.MediaElement" => array(
+ 'scripts' => 'resources/mw.MediaElement.js',
+ 'dependencies' => array(
+ 'ext.tmh.OgvJsSupport',
+ )
+ ),
+ "mw.MediaPlayer" => array( 'scripts' => 'resources/mw.MediaPlayer.js' ),
+ "mw.MediaPlayers" => array(
+ 'scripts' => 'resources/mw.MediaPlayers.js',
+ 'dependencies' => 'mw.MediaPlayer'
+ ),
+ "mw.MediaSource" => array( 'scripts' => 'resources/mw.MediaSource.js' ),
+ "mw.EmbedTypes" => array(
+ 'scripts' => 'resources/mw.EmbedTypes.js',
+ 'dependencies' => array(
+ 'mw.MediaPlayers',
+ 'mediawiki.Uri',
+ 'jquery.client',
+ )
+ ),
+ "mw.EmbedPlayer" => array(
+ 'scripts' => array(
+ "resources/mw.processEmbedPlayers.js",
+ "resources/mw.EmbedPlayer.js",
+ "resources/skins/mw.PlayerControlBuilder.js",
+ ),
+ 'dependencies' => array(
+ // mwEmbed support module
+ 'mediawiki.client',
+ 'mediawiki.UtilitiesTime',
+ 'mediawiki.Uri',
+ 'mediawiki.absoluteUrl',
+ 'mediawiki.jqueryMsg',
+
+ // Browser fullscreen api support:
+ 'fullScreenApi',
+
+ // Kinda need this
+ 'mw.MwEmbedSupport',
+
+ // We always end up loading native player
+ 'mw.EmbedPlayerNative',
+
+ // Sub classes:
+ 'mw.MediaElement',
+ 'mw.MediaPlayers',
+ 'mw.MediaSource',
+ 'mw.EmbedTypes',
+
+ // jQuery dependencies:
+ 'jquery.client',
+ 'jquery.hoverIntent',
+ 'jquery.cookie',
+ 'jquery.ui.mouse',
+ 'jquery.debouncedresize',
+ 'jquery.embedMenu',
+ 'jquery.ui.slider',
+ 'jquery.ui.touchPunch',
+
+ // Set to mw.PlayerSkinKskin or mw.PlayerSkinMvpcf in config
+ $wgVideoPlayerSkinModule
+ ),
+ 'styles' => "resources/skins/EmbedPlayer.css",
+ 'messageDir' => 'i18n',
+ ),
+
+ "mw.EmbedPlayerKplayer" => array( 'scripts'=> "resources/mw.EmbedPlayerKplayer.js" ),
+ "mw.EmbedPlayerGeneric" => array( 'scripts'=> "resources/mw.EmbedPlayerGeneric.js" ),
+ "mw.EmbedPlayerNative" => array( 'scripts'=> "resources/mw.EmbedPlayerNative.js" ),
+ "mw.EmbedPlayerVLCApp" => array(
+ 'scripts'=> "resources/mw.EmbedPlayerVLCApp.js",
+ 'dependencies' => array( 'mediawiki.Uri' )
+ ),
+ "mw.EmbedPlayerIEWebMPrompt" => array(
+ 'scripts' => 'resources/mw.EmbedPlayerIEWebMPrompt.js',
+ 'styles' => 'resources/mw.EmbedPlayerIEWebMPrompt.css',
+ ),
+ "mw.EmbedPlayerOgvJs" => array(
+ 'scripts' => 'resources/mw.EmbedPlayerOgvJs.js',
+ 'dependencies' => array(
+ 'jquery.spinner',
+ 'ext.tmh.OgvJsSupport',
+ ),
+ ),
+ "mw.EmbedPlayerImageOverlay" => array( 'scripts'=> "resources/mw.EmbedPlayerImageOverlay.js" ),
+
+ "mw.EmbedPlayerVlc" => array( 'scripts'=> "resources/mw.EmbedPlayerVlc.js" ),
+
+ "mw.PlayerSkinKskin" => array(
+ 'scripts' => "resources/skins/kskin/mw.PlayerSkinKskin.js",
+ 'styles' => "resources/skins/kskin/PlayerSkinKskin.css"
+ ),
+
+ "mw.PlayerSkinMvpcf" => array(
+ 'scripts'=> "resources/skins/mvpcf/mw.PlayerSkinMvpcf.js",
+ 'styles'=> "resources/skins/mvpcf/PlayerSkinMvpcf.css"
+ ),
+ );
+?>
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/LightDoodleskin.swf b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/LightDoodleskin.swf
new file mode 100644
index 00000000..5f25450e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/LightDoodleskin.swf
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/README b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/README
new file mode 100644
index 00000000..7b11a51b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/README
@@ -0,0 +1,20 @@
+
+File: kdp3.swf
+
+This Kaltura Dynamic Player +Playlist (KDP) is a sub package of the taken Kaltura Community Edition (CE) Built from Kaltura.org source.
+
+The full Kaltura Community Edition is licensed under the ( GNU Affero General Public License v3 )
+
+And the source code is available on the kaltura.org site:
+http://www.kaltura.org/project/kalturaCE
+
+More info about the KDP:
+http://www.kaltura.org/kdp-dynamic-player-and-playlist-widget
+
+
+
+File: expressInstall.swf
+is part of SWFObject v2.2 <http://code.google.com/p/swfobject/>
+ and is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
+
+
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/config.xml b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/config.xml
new file mode 100644
index 00000000..a4c4e9c8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/config.xml
@@ -0,0 +1,9 @@
+<layout id="full" skinPath="assets/skin.swf">
+ <HBox id="topLevel" width="100%" height="100%">
+ <VBox id="player" width="100%" height="100%" styleName="black">
+ <Canvas height="100%" width="100%" id="PlayerHolder" styleName="black">
+ <Video id="video" width="100%" height="100%" />
+ </Canvas>
+ </VBox>
+ </HBox>
+</layout> \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/expressInstall.swf b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/expressInstall.swf
new file mode 100644
index 00000000..0fbf8fca
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/expressInstall.swf
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/kdp3.3.5.27.swf b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/kdp3.3.5.27.swf
new file mode 100644
index 00000000..b400fa68
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/kdp3.3.5.27.swf
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/kdp3.swf b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/kdp3.swf
new file mode 100644
index 00000000..c2f3891c
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/kdp3.swf
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/skin.swf b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/skin.swf
new file mode 100644
index 00000000..3c8bf053
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/kaltura-player/skin.swf
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING
new file mode 100644
index 00000000..96498a60
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING
@@ -0,0 +1,21 @@
+ogv.js & ogv.swf wrapper and player code
+
+Copyright (c) 2013-2014 Brion Vibber and other contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-ogg.txt b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-ogg.txt
new file mode 100644
index 00000000..6111c6c5
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-ogg.txt
@@ -0,0 +1,28 @@
+Copyright (c) 2002, Xiph.org Foundation
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-opus.txt b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-opus.txt
new file mode 100644
index 00000000..9c739c34
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-opus.txt
@@ -0,0 +1,44 @@
+Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic,
+ Jean-Marc Valin, Timothy B. Terriberry,
+ CSIRO, Gregory Maxwell, Mark Borgerding,
+ Erik de Castro Lopo
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Opus is subject to the royalty-free patent licenses which are
+specified at:
+
+Xiph.Org Foundation:
+https://datatracker.ietf.org/ipr/1524/
+
+Microsoft Corporation:
+https://datatracker.ietf.org/ipr/1914/
+
+Broadcom Corporation:
+https://datatracker.ietf.org/ipr/1526/
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-theora.txt b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-theora.txt
new file mode 100644
index 00000000..c8ccce4f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-theora.txt
@@ -0,0 +1,28 @@
+Copyright (C) 2002-2009 Xiph.org Foundation
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-vorbis.txt b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-vorbis.txt
new file mode 100644
index 00000000..28de72a9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/COPYING-vorbis.txt
@@ -0,0 +1,28 @@
+Copyright (c) 2002-2008 Xiph.org Foundation
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Xiph.org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/dynamicaudio.swf b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/dynamicaudio.swf
new file mode 100644
index 00000000..2e3ce4e4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/dynamicaudio.swf
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-audio-opus.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-audio-opus.js
new file mode 100644
index 00000000..4e73c95a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-audio-opus.js
@@ -0,0 +1,24 @@
+var OGVDecoderAudioOpus = function(Module) {
+ Module = Module || {};
+
+var options=Module;Module={print:(function(str){console.log(str)})};var Module;if(!Module)Module=(typeof OGVDecoderAudioOpus!=="undefined"?OGVDecoderAudioOpus:null)||{};var moduleOverrides={};for(var key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var ENVIRONMENT_IS_WEB=typeof window==="object";var ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB;var ENVIRONMENT_IS_WORKER=typeof importScripts==="function";var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){if(!Module["print"])Module["print"]=function print(x){process["stdout"].write(x+"\n")};if(!Module["printErr"])Module["printErr"]=function printErr(x){process["stderr"].write(x+"\n")};var nodeFS=require("fs");var nodePath=require("path");Module["read"]=function read(filename,binary){filename=nodePath["normalize"](filename);var ret=nodeFS["readFileSync"](filename);if(!ret&&filename!=nodePath["resolve"](filename)){filename=path.join(__dirname,"..","src",filename);ret=nodeFS["readFileSync"](filename)}if(ret&&!binary)ret=ret.toString();return ret};Module["readBinary"]=function readBinary(filename){return Module["read"](filename,true)};Module["load"]=function load(f){globalEval(read(f))};if(!Module["thisProgram"]){if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}else{Module["thisProgram"]="unknown-program"}}Module["arguments"]=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(!Module["print"])Module["print"]=print;if(typeof printErr!="undefined")Module["printErr"]=printErr;if(typeof read!="undefined"){Module["read"]=read}else{Module["read"]=function read(){throw"no read() available (jsc?)"}}Module["readBinary"]=function readBinary(f){if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}var data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof console!=="undefined"){if(!Module["print"])Module["print"]=function print(x){console.log(x)};if(!Module["printErr"])Module["printErr"]=function printErr(x){console.log(x)}}else{var TRY_USE_DUMP=false;if(!Module["print"])Module["print"]=TRY_USE_DUMP&&typeof dump!=="undefined"?(function(x){dump(x)}):(function(x){})}if(ENVIRONMENT_IS_WORKER){Module["load"]=importScripts}if(typeof Module["setWindowTitle"]==="undefined"){Module["setWindowTitle"]=(function(title){document.title=title})}}else{throw"Unknown runtime environment. Where are we?"}function globalEval(x){eval.call(null,x)}if(!Module["load"]&&Module["read"]){Module["load"]=function load(f){globalEval(Module["read"](f))}}if(!Module["print"]){Module["print"]=(function(){})}if(!Module["printErr"]){Module["printErr"]=Module["print"]}if(!Module["arguments"]){Module["arguments"]=[]}if(!Module["thisProgram"]){Module["thisProgram"]="./this.program"}Module.print=Module["print"];Module.printErr=Module["printErr"];Module["preRun"]=[];Module["postRun"]=[];for(var key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}var Runtime={setTempRet0:(function(value){tempRet0=value}),getTempRet0:(function(){return tempRet0}),stackSave:(function(){return STACKTOP}),stackRestore:(function(stackTop){STACKTOP=stackTop}),getNativeTypeSize:(function(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return Runtime.QUANTUM_SIZE}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0);return bits/8}else{return 0}}}}),getNativeFieldSize:(function(type){return Math.max(Runtime.getNativeTypeSize(type),Runtime.QUANTUM_SIZE)}),STACK_ALIGN:16,prepVararg:(function(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){assert((ptr&7)===4);ptr+=4}}else{assert((ptr&3)===0)}return ptr}),getAlignSize:(function(type,size,vararg){if(!vararg&&(type=="i64"||type=="double"))return 8;if(!type)return Math.min(size,8);return Math.min(size||(type?Runtime.getNativeFieldSize(type):0),Runtime.QUANTUM_SIZE)}),dynCall:(function(sig,ptr,args){if(args&&args.length){if(!args.splice)args=Array.prototype.slice.call(args);args.splice(0,0,ptr);return Module["dynCall_"+sig].apply(null,args)}else{return Module["dynCall_"+sig].call(null,ptr)}}),functionPointers:[],addFunction:(function(func){for(var i=0;i<Runtime.functionPointers.length;i++){if(!Runtime.functionPointers[i]){Runtime.functionPointers[i]=func;return 2*(1+i)}}throw"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS."}),removeFunction:(function(index){Runtime.functionPointers[(index-2)/2]=null}),warnOnce:(function(text){if(!Runtime.warnOnce.shown)Runtime.warnOnce.shown={};if(!Runtime.warnOnce.shown[text]){Runtime.warnOnce.shown[text]=1;Module.printErr(text)}}),funcWrappers:{},getFuncWrapper:(function(func,sig){assert(sig);if(!Runtime.funcWrappers[sig]){Runtime.funcWrappers[sig]={}}var sigCache=Runtime.funcWrappers[sig];if(!sigCache[func]){sigCache[func]=function dynCall_wrapper(){return Runtime.dynCall(sig,func,arguments)}}return sigCache[func]}),getCompilerSetting:(function(name){throw"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work"}),stackAlloc:(function(size){var ret=STACKTOP;STACKTOP=STACKTOP+size|0;STACKTOP=STACKTOP+15&-16;return ret}),staticAlloc:(function(size){var ret=STATICTOP;STATICTOP=STATICTOP+size|0;STATICTOP=STATICTOP+15&-16;return ret}),dynamicAlloc:(function(size){var ret=DYNAMICTOP;DYNAMICTOP=DYNAMICTOP+size|0;DYNAMICTOP=DYNAMICTOP+15&-16;if(DYNAMICTOP>=TOTAL_MEMORY){var success=enlargeMemory();if(!success){DYNAMICTOP=ret;return 0}}return ret}),alignMemory:(function(size,quantum){var ret=size=Math.ceil(size/(quantum?quantum:16))*(quantum?quantum:16);return ret}),makeBigInt:(function(low,high,unsigned){var ret=unsigned?+(low>>>0)+ +(high>>>0)*+4294967296:+(low>>>0)+ +(high|0)*+4294967296;return ret}),GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module["Runtime"]=Runtime;var __THREW__=0;var ABORT=false;var EXITSTATUS=0;var undef=0;var tempValue,tempInt,tempBigInt,tempInt2,tempBigInt2,tempPair,tempBigIntI,tempBigIntR,tempBigIntS,tempBigIntP,tempBigIntD,tempDouble,tempFloat;var tempI64,tempI64b;var tempRet0,tempRet1,tempRet2,tempRet3,tempRet4,tempRet5,tempRet6,tempRet7,tempRet8,tempRet9;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var globalScope=this;function getCFunc(ident){var func=Module["_"+ident];if(!func){try{func=eval("_"+ident)}catch(e){}}assert(func,"Cannot call unknown function "+ident+" (perhaps LLVM optimizations or closure removed it?)");return func}var cwrap,ccall;((function(){var JSfuncs={"stackSave":(function(){Runtime.stackSave()}),"stackRestore":(function(){Runtime.stackRestore()}),"arrayToC":(function(arr){var ret=Runtime.stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}),"stringToC":(function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=Runtime.stackAlloc((str.length<<2)+1);writeStringToMemory(str,ret)}return ret})};var toC={"string":JSfuncs["stringToC"],"array":JSfuncs["arrayToC"]};ccall=function ccallFunc(ident,returnType,argTypes,args,opts){var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=Runtime.stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func.apply(null,cArgs);if(returnType==="string")ret=Pointer_stringify(ret);if(stack!==0){if(opts&&opts.async){EmterpreterAsync.asyncFinalizers.push((function(){Runtime.stackRestore(stack)}));return}Runtime.stackRestore(stack)}return ret};var sourceRegex=/^function\s*\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;function parseJSFunc(jsfunc){var parsed=jsfunc.toString().match(sourceRegex).slice(1);return{arguments:parsed[0],body:parsed[1],returnValue:parsed[2]}}var JSsource={};for(var fun in JSfuncs){if(JSfuncs.hasOwnProperty(fun)){JSsource[fun]=parseJSFunc(JSfuncs[fun])}}cwrap=function cwrap(ident,returnType,argTypes){argTypes=argTypes||[];var cfunc=getCFunc(ident);var numericArgs=argTypes.every((function(type){return type==="number"}));var numericRet=returnType!=="string";if(numericRet&&numericArgs){return cfunc}var argNames=argTypes.map((function(x,i){return"$"+i}));var funcstr="(function("+argNames.join(",")+") {";var nargs=argTypes.length;if(!numericArgs){funcstr+="var stack = "+JSsource["stackSave"].body+";";for(var i=0;i<nargs;i++){var arg=argNames[i],type=argTypes[i];if(type==="number")continue;var convertCode=JSsource[type+"ToC"];funcstr+="var "+convertCode.arguments+" = "+arg+";";funcstr+=convertCode.body+";";funcstr+=arg+"="+convertCode.returnValue+";"}}var cfuncname=parseJSFunc((function(){return cfunc})).returnValue;funcstr+="var ret = "+cfuncname+"("+argNames.join(",")+");";if(!numericRet){var strgfy=parseJSFunc((function(){return Pointer_stringify})).returnValue;funcstr+="ret = "+strgfy+"(ret);"}if(!numericArgs){funcstr+=JSsource["stackRestore"].body.replace("()","(stack)")+";"}funcstr+="return ret})";return eval(funcstr)}}))();Module["cwrap"]=cwrap;Module["ccall"]=ccall;function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=+1?tempDouble>+0?(Math_min(+Math_floor(tempDouble/+4294967296),+4294967295)|0)>>>0:~~+Math_ceil((tempDouble- +(~~tempDouble>>>0))/+4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}Module["setValue"]=setValue;function getValue(ptr,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP32[ptr>>2];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];default:abort("invalid type for setValue: "+type)}return null}Module["getValue"]=getValue;var ALLOC_NORMAL=0;var ALLOC_STACK=1;var ALLOC_STATIC=2;var ALLOC_DYNAMIC=3;var ALLOC_NONE=4;Module["ALLOC_NORMAL"]=ALLOC_NORMAL;Module["ALLOC_STACK"]=ALLOC_STACK;Module["ALLOC_STATIC"]=ALLOC_STATIC;Module["ALLOC_DYNAMIC"]=ALLOC_DYNAMIC;Module["ALLOC_NONE"]=ALLOC_NONE;function allocate(slab,types,allocator,ptr){var zeroinit,size;if(typeof slab==="number"){zeroinit=true;size=slab}else{zeroinit=false;size=slab.length}var singleType=typeof types==="string"?types:null;var ret;if(allocator==ALLOC_NONE){ret=ptr}else{ret=[_malloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][allocator===undefined?ALLOC_STATIC:allocator](Math.max(size,singleType?1:types.length))}if(zeroinit){var ptr=ret,stop;assert((ret&3)==0);stop=ret+(size&~3);for(;ptr<stop;ptr+=4){HEAP32[ptr>>2]=0}stop=ret+size;while(ptr<stop){HEAP8[ptr++>>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i<size){var curr=slab[i];if(typeof curr==="function"){curr=Runtime.getFunctionIndex(curr)}type=singleType||types[i];if(type===0){i++;continue}if(type=="i64")type="i32";setValue(ret+i,curr,type);if(previousType!==type){typeSize=Runtime.getNativeTypeSize(type);previousType=type}i+=typeSize}return ret}Module["allocate"]=allocate;function getMemory(size){if(!staticSealed)return Runtime.staticAlloc(size);if(typeof _sbrk!=="undefined"&&!_sbrk.called||!runtimeInitialized)return Runtime.dynamicAlloc(size);return _malloc(size)}Module["getMemory"]=getMemory;function Pointer_stringify(ptr,length){if(length===0||!ptr)return"";var hasUtf=0;var t;var i=0;while(1){t=HEAPU8[ptr+i>>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return Module["UTF8ToString"](ptr)}Module["Pointer_stringify"]=Pointer_stringify;function AsciiToString(ptr){var str="";while(1){var ch=HEAP8[ptr++>>0];if(!ch)return str;str+=String.fromCharCode(ch)}}Module["AsciiToString"]=AsciiToString;function stringToAscii(str,outPtr){return writeAsciiToMemory(str,outPtr,false)}Module["stringToAscii"]=stringToAscii;function UTF8ArrayToString(u8Array,idx){var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}Module["UTF8ArrayToString"]=UTF8ArrayToString;function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}Module["UTF8ToString"]=UTF8ToString;function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=2097151){if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=67108863){if(outIdx+4>=endIdx)break;outU8Array[outIdx++]=248|u>>24;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+5>=endIdx)break;outU8Array[outIdx++]=252|u>>30;outU8Array[outIdx++]=128|u>>24&63;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}Module["stringToUTF8Array"]=stringToUTF8Array;function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}Module["stringToUTF8"]=stringToUTF8;function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){++len}else if(u<=2047){len+=2}else if(u<=65535){len+=3}else if(u<=2097151){len+=4}else if(u<=67108863){len+=5}else{len+=6}}return len}Module["lengthBytesUTF8"]=lengthBytesUTF8;function UTF16ToString(ptr){var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)return str;++i;str+=String.fromCharCode(codeUnit)}}Module["UTF16ToString"]=UTF16ToString;function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite<str.length*2?maxBytesToWrite/2:str.length;for(var i=0;i<numCharsToWrite;++i){var codeUnit=str.charCodeAt(i);HEAP16[outPtr>>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}Module["stringToUTF16"]=stringToUTF16;function lengthBytesUTF16(str){return str.length*2}Module["lengthBytesUTF16"]=lengthBytesUTF16;function UTF32ToString(ptr){var i=0;var str="";while(1){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)return str;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}}Module["UTF32ToString"]=UTF32ToString;function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i<str.length;++i){var codeUnit=str.charCodeAt(i);if(codeUnit>=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}Module["stringToUTF32"]=stringToUTF32;function lengthBytesUTF32(str){var len=0;for(var i=0;i<str.length;++i){var codeUnit=str.charCodeAt(i);if(codeUnit>=55296&&codeUnit<=57343)++i;len+=4}return len}Module["lengthBytesUTF32"]=lengthBytesUTF32;function demangle(func){var hasLibcxxabi=!!Module["___cxa_demangle"];if(hasLibcxxabi){try{var buf=_malloc(func.length);writeStringToMemory(func.substr(1),buf);var status=_malloc(4);var ret=Module["___cxa_demangle"](buf,0,0,status);if(getValue(status,"i32")===0&&ret){return Pointer_stringify(ret)}}catch(e){}finally{if(buf)_free(buf);if(status)_free(status);if(ret)_free(ret)}}var i=3;var basicTypes={"v":"void","b":"bool","c":"char","s":"short","i":"int","l":"long","f":"float","d":"double","w":"wchar_t","a":"signed char","h":"unsigned char","t":"unsigned short","j":"unsigned int","m":"unsigned long","x":"long long","y":"unsigned long long","z":"..."};var subs=[];var first=true;function dump(x){if(x)Module.print(x);Module.print(func);var pre="";for(var a=0;a<i;a++)pre+=" ";Module.print(pre+"^")}function parseNested(){i++;if(func[i]==="K")i++;var parts=[];while(func[i]!=="E"){if(func[i]==="S"){i++;var next=func.indexOf("_",i);var num=func.substring(i,next)||0;parts.push(subs[num]||"?");i=next+1;continue}if(func[i]==="C"){parts.push(parts[parts.length-1]);i+=2;continue}var size=parseInt(func.substr(i));var pre=size.toString().length;if(!size||!pre){i--;break}var curr=func.substr(i+pre,size);parts.push(curr);subs.push(curr);i+=pre+size}i++;return parts}function parse(rawList,limit,allowVoid){limit=limit||Infinity;var ret="",list=[];function flushList(){return"("+list.join(", ")+")"}var name;if(func[i]==="N"){name=parseNested().join("::");limit--;if(limit===0)return rawList?[name]:name}else{if(func[i]==="K"||first&&func[i]==="L")i++;var size=parseInt(func.substr(i));if(size){var pre=size.toString().length;name=func.substr(i+pre,size);i+=pre+size}}first=false;if(func[i]==="I"){i++;var iList=parse(true);var iRet=parse(true,1,true);ret+=iRet[0]+" "+name+"<"+iList.join(", ")+">"}else{ret=name}paramLoop:while(i<func.length&&limit-->0){var c=func[i++];if(c in basicTypes){list.push(basicTypes[c])}else{switch(c){case"P":list.push(parse(true,1,true)[0]+"*");break;case"R":list.push(parse(true,1,true)[0]+"&");break;case"L":{i++;var end=func.indexOf("E",i);var size=end-i;list.push(func.substr(i,size));i+=size+2;break};case"A":{var size=parseInt(func.substr(i));i+=size.toString().length;if(func[i]!=="_")throw"?";i++;list.push(parse(true,1,true)[0]+" ["+size+"]");break};case"E":break paramLoop;default:ret+="?"+c;break paramLoop}}}if(!allowVoid&&list.length===1&&list[0]==="void")list=[];if(rawList){if(ret){list.push(ret+"?")}return list}else{return ret+flushList()}}var parsed=func;try{if(func=="Object._main"||func=="_main"){return"main()"}if(typeof func==="number")func=Pointer_stringify(func);if(func[0]!=="_")return func;if(func[1]!=="_")return func;if(func[2]!=="Z")return func;switch(func[3]){case"n":return"operator new()";case"d":return"operator delete()"}parsed=parse()}catch(e){parsed+="?"}if(parsed.indexOf("?")>=0&&!hasLibcxxabi){Runtime.warnOnce("warning: a problem occurred in builtin C++ name demangling; build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling")}return parsed}function demangleAll(text){return text.replace(/__Z[\w\d_]+/g,(function(x){var y=demangle(x);return x===y?x:x+" ["+y+"]"}))}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error(0)}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){return demangleAll(jsStackTrace())}Module["stackTrace"]=stackTrace;var PAGE_SIZE=4096;function alignMemoryPage(x){if(x%4096>0){x+=4096-x%4096}return x}var HEAP;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;var STATIC_BASE=0,STATICTOP=0,staticSealed=false;var STACK_BASE=0,STACKTOP=0,STACK_MAX=0;var DYNAMIC_BASE=0,DYNAMICTOP=0;function enlargeMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.")}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;var totalMemory=64*1024;while(totalMemory<TOTAL_MEMORY||totalMemory<2*TOTAL_STACK){if(totalMemory<16*1024*1024){totalMemory*=2}else{totalMemory+=16*1024*1024}}if(totalMemory!==TOTAL_MEMORY){Module.printErr("increasing TOTAL_MEMORY to "+totalMemory+" to be compliant with the asm.js spec (and given that TOTAL_STACK="+TOTAL_STACK+")");TOTAL_MEMORY=totalMemory}assert(typeof Int32Array!=="undefined"&&typeof Float64Array!=="undefined"&&!!(new Int32Array(1))["subarray"]&&!!(new Int32Array(1))["set"],"JS engine does not provide full typed array support");var buffer;buffer=new ArrayBuffer(TOTAL_MEMORY);HEAP8=new Int8Array(buffer);HEAP16=new Int16Array(buffer);HEAP32=new Int32Array(buffer);HEAPU8=new Uint8Array(buffer);HEAPU16=new Uint16Array(buffer);HEAPU32=new Uint32Array(buffer);HEAPF32=new Float32Array(buffer);HEAPF64=new Float64Array(buffer);HEAP32[0]=255;assert(HEAPU8[0]===255&&HEAPU8[3]===0,"Typed arrays 2 must be run on a little-endian system");Module["HEAP"]=HEAP;Module["buffer"]=buffer;Module["HEAP8"]=HEAP8;Module["HEAP16"]=HEAP16;Module["HEAP32"]=HEAP32;Module["HEAPU8"]=HEAPU8;Module["HEAPU16"]=HEAPU16;Module["HEAPU32"]=HEAPU32;Module["HEAPF32"]=HEAPF32;Module["HEAPF64"]=HEAPF64;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Runtime.dynCall("v",func)}else{Runtime.dynCall("vi",func,[callback.arg])}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}Module["addOnPreRun"]=Module.addOnPreRun=addOnPreRun;function addOnInit(cb){__ATINIT__.unshift(cb)}Module["addOnInit"]=Module.addOnInit=addOnInit;function addOnPreMain(cb){__ATMAIN__.unshift(cb)}Module["addOnPreMain"]=Module.addOnPreMain=addOnPreMain;function addOnExit(cb){__ATEXIT__.unshift(cb)}Module["addOnExit"]=Module.addOnExit=addOnExit;function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}Module["addOnPostRun"]=Module.addOnPostRun=addOnPostRun;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["intArrayFromString"]=intArrayFromString;function intArrayToString(array){var ret=[];for(var i=0;i<array.length;i++){var chr=array[i];if(chr>255){chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}Module["intArrayToString"]=intArrayToString;function writeStringToMemory(string,buffer,dontAddNull){var array=intArrayFromString(string,dontAddNull);var i=0;while(i<array.length){var chr=array[i];HEAP8[buffer+i>>0]=chr;i=i+1}}Module["writeStringToMemory"]=writeStringToMemory;function writeArrayToMemory(array,buffer){for(var i=0;i<array.length;i++){HEAP8[buffer++>>0]=array[i]}}Module["writeArrayToMemory"]=writeArrayToMemory;function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i<str.length;++i){HEAP8[buffer++>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}Module["writeAsciiToMemory"]=writeAsciiToMemory;function unSign(value,bits,ignore){if(value>=0){return value}return bits<=32?2*Math.abs(1<<bits-1)+value:Math.pow(2,bits)+value}function reSign(value,bits,ignore){if(value<=0){return value}var half=bits<=32?Math.abs(1<<bits-1):Math.pow(2,bits-1);if(value>=half&&(bits<=32||value>half)){value=-2*half+value}return value}if(!Math["imul"]||Math["imul"](4294967295,5)!==-5)Math["imul"]=function imul(a,b){var ah=a>>>16;var al=a&65535;var bh=b>>>16;var bl=b&65535;return al*bl+(ah*bl+al*bh<<16)|0};Math.imul=Math["imul"];if(!Math["clz32"])Math["clz32"]=(function(x){x=x>>>0;for(var i=0;i<32;i++){if(x&1<<31-i)return i}return 32});Math.clz32=Math["clz32"];var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_min=Math.min;var Math_clz32=Math.clz32;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}Module["addRunDependency"]=addRunDependency;function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["removeRunDependency"]=removeRunDependency;Module["preloadedImages"]={};Module["preloadedAudios"]={};var memoryInitializer=null;var ASM_CONSTS=[];STATIC_BASE=8;STATICTOP=STATIC_BASE+25856;__ATINIT__.push();allocate([0,255,0,255,0,255,0,255,0,255,0,254,1,0,1,255,0,254,0,253,2,0,1,255,0,254,0,253,3,0,1,255,0,0,206,64,0,0,200,64,0,0,184,64,0,0,170,64,0,0,162,64,0,0,154,64,0,0,144,64,0,0,140,64,0,0,156,64,0,0,150,64,0,0,146,64,0,0,142,64,0,0,156,64,0,0,148,64,0,0,138,64,0,0,144,64,0,0,140,64,0,0,148,64,0,0,152,64,0,0,142,64,0,0,112,64,0,0,112,64,0,0,112,64,0,0,112,64,0,0,112,64,0,0,0,0,224,112,44,15,3,2,1,0,254,237,192,132,70,23,4,0,255,252,226,155,61,11,2,0,250,245,234,203,71,50,42,38,35,33,31,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0,0,0,0,0,0,0,0,179,99,0,0,0,0,0,0,232,11,0,0,240,11,0,0,0,12,0,0,0,0,0,0,32,12,0,0,72,12,0,0,152,12,0,0,0,0,0,0,32,0,10,0,20,46,100,1,56,13,0,0,120,14,0,0,184,14,0,0,208,14,0,0,112,15,0,0,184,15,0,0,0,16,0,0,0,0,0,0,32,0,16,0,102,38,171,1,24,16,0,0,24,18,0,0,88,18,0,0,120,18,0,0,120,19,0,0,192,19,0,0,8,20,0,0,0,0,0,0,92,202,190,216,182,223,154,226,156,230,120,236,122,244,204,252,52,3,134,11,136,19,100,25,102,29,74,32,66,39,164,53,249,247,246,245,244,234,210,202,201,200,197,174,82,59,56,55,54,46,22,12,11,10,9,7,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,48,20,0,0,56,20,0,0,120,0,0,0,0,0,0,0,128,64,0,0,0,0,0,0,232,158,10,0,0,0,0,0,230,0,0,0,0,0,0,0,243,221,192,181,0,0,0,0,100,0,240,0,32,0,100,0,205,60,0,48,0,32,0,0,171,85,0,0,0,0,0,0,192,128,64,0,0,0,0,0,205,154,102,51,0,0,0,0,213,171,128,85,43,0,0,0,224,192,160,128,96,64,32,0,100,40,16,7,3,1,0,0,253,250,244,233,212,182,150,131,120,110,98,85,72,60,49,40,32,25,19,15,13,11,9,8,7,6,5,4,3,2,1,0,210,208,206,203,199,193,183,168,142,104,74,52,37,27,20,14,10,6,4,2,0,0,0,0,223,201,183,167,152,138,124,111,98,88,79,70,62,56,50,44,39,35,31,27,24,21,18,16,14,12,10,8,6,4,3,2,1,0,0,0,0,0,0,0,188,176,155,138,119,97,67,43,26,10,0,0,0,0,0,0,165,119,80,61,47,35,27,20,14,9,4,0,0,0,0,0,113,63,0,0,0,0,0,0,125,51,26,18,15,12,11,10,9,8,7,6,5,4,3,2,1,0,198,105,45,22,15,12,11,10,9,8,7,6,5,4,3,2,1,0,213,162,116,83,59,43,32,24,18,15,12,9,7,6,5,3,2,0,239,187,116,59,28,16,11,10,9,8,7,6,5,4,3,2,1,0,250,229,188,135,86,51,30,19,13,10,8,6,5,4,3,2,1,0,249,235,213,185,156,128,103,83,66,53,42,33,26,21,17,13,10,0,254,249,235,206,164,118,77,46,27,16,10,7,5,4,3,2,1,0,255,253,249,239,220,191,156,119,85,57,37,23,15,10,6,4,2,0,255,253,251,246,237,223,203,179,152,124,98,75,55,40,29,21,15,0,255,254,253,247,220,162,106,67,42,28,18,12,9,6,4,3,2,0,0,0,0,0,241,190,178,132,87,74,41,14,0,223,193,157,140,106,57,39,18,0,0,0,0,0,0,0,128,0,214,42,0,235,128,21,0,244,184,72,11,0,248,214,128,42,7,0,248,225,170,80,25,5,0,251,236,198,126,54,18,3,0,250,238,211,159,82,35,15,5,0,250,231,203,168,128,88,53,25,6,0,252,238,216,185,148,108,71,40,18,4,0,253,243,225,199,166,128,90,57,31,13,3,0,254,246,233,212,183,147,109,73,44,23,10,2,0,255,250,240,223,198,166,128,90,58,33,16,6,1,0,255,251,244,231,210,181,146,110,75,46,25,12,5,1,0,255,253,248,238,221,196,164,128,92,60,35,18,8,3,1,0,255,253,249,242,229,208,180,146,110,76,48,27,14,7,3,1,0,129,0,207,50,0,236,129,20,0,245,185,72,10,0,249,213,129,42,6,0,250,226,169,87,27,4,0,251,233,194,130,62,20,4,0,250,236,207,160,99,47,17,3,0,255,240,217,182,131,81,41,11,1,0,255,254,233,201,159,107,61,20,2,1,0,255,249,233,206,170,128,86,50,23,7,1,0,255,250,238,217,186,148,108,70,39,18,6,1,0,255,252,243,226,200,166,128,90,56,30,13,4,1,0,255,252,245,231,209,180,146,110,76,47,25,11,4,1,0,255,253,248,237,219,194,163,128,93,62,37,19,8,3,1,0,255,254,250,241,226,205,177,145,111,79,51,30,15,6,2,1,0,129,0,203,54,0,234,129,23,0,245,184,73,10,0,250,215,129,41,5,0,252,232,173,86,24,3,0,253,240,200,129,56,15,2,0,253,244,217,164,94,38,10,1,0,253,245,226,189,132,71,27,7,1,0,253,246,231,203,159,105,56,23,6,1,0,255,248,235,213,179,133,85,47,19,5,1,0,255,254,243,221,194,159,117,70,37,12,2,1,0,255,254,248,234,208,171,128,85,48,22,8,2,1,0,255,254,250,240,220,189,149,107,67,36,16,6,2,1,0,255,254,251,243,227,201,166,128,90,55,29,13,5,2,1,0,255,254,252,246,234,213,183,147,109,73,43,22,10,4,2,1,0,130,0,200,58,0,231,130,26,0,244,184,76,12,0,249,214,130,43,6,0,252,232,173,87,24,3,0,253,241,203,131,56,14,2,0,254,246,221,167,94,35,8,1,0,254,249,232,193,130,65,23,5,1,0,255,251,239,211,162,99,45,15,4,1,0,255,251,243,223,186,131,74,33,11,3,1,0,255,252,245,230,202,158,105,57,24,8,2,1,0,255,253,247,235,214,179,132,84,44,19,7,2,1,0,255,254,250,240,223,196,159,112,69,36,15,6,2,1,0,255,254,253,245,231,209,176,136,93,55,27,11,3,2,1,0,255,254,253,252,239,221,194,158,117,76,42,18,4,3,2,1,0,0,0,2,5,9,14,20,27,35,44,54,65,77,90,104,119,135,0,0,0,0,0,0,0,254,49,67,77,82,93,99,198,11,18,24,31,36,45,255,46,66,78,87,94,104,208,14,21,32,42,51,66,255,94,104,109,112,115,118,248,53,69,80,88,95,102,0,0,0,0,0,0,0,32,254,31,246,31,234,31,216,31,194,31,168,31,136,31,98,31,58,31,10,31,216,30,160,30,98,30,34,30,220,29,144,29,66,29,238,28,150,28,58,28,216,27,114,27,10,27,156,26,42,26,180,25,58,25,188,24,60,24,182,23,46,23,160,22,16,22,126,21,232,20,78,20,176,19,16,19,110,18,200,17,30,17,116,16,198,15,22,15,100,14,174,13,248,12,64,12,132,11,200,10,10,10,74,9,138,8,198,7,2,7,62,6,120,5,178,4,234,3,34,3,90,2,146,1,202,0,0,0,54,255,110,254,166,253,222,252,22,252,78,251,136,250,194,249,254,248,58,248,118,247,182,246,246,245,56,245,124,244,192,243,8,243,82,242,156,241,234,240,58,240,140,239,226,238,56,238,146,237,240,236,80,236,178,235,24,235,130,234,240,233,96,233,210,232,74,232,196,231,68,231,198,230,76,230,214,229,100,229,246,228,142,228,40,228,198,227,106,227,18,227,190,226,112,226,36,226,222,225,158,225,96,225,40,225,246,224,198,224,158,224,120,224,88,224,62,224,40,224,22,224,10,224,2,224,0,224,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,255,1,255,2,254,2,254,3,253,0,1,0,1,255,2,255,2,254,3,254,3,0,2,255,255,255,0,0,1,1,0,1,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,255,2,1,0,1,1,0,0,255,255,0,0,0,0,0,0,1,255,0,1,255,0,255,1,254,2,254,254,2,253,2,3,253,252,3,252,4,4,251,5,250,251,6,249,6,5,8,247,0,0,1,0,0,0,0,0,0,0,255,1,0,0,1,255,0,1,255,255,1,255,2,1,255,2,254,254,2,254,2,2,3,253,0,1,0,0,0,0,0,0,1,0,1,0,0,1,255,1,0,0,2,1,255,2,255,255,2,255,2,2,255,3,254,254,254,3,0,1,0,0,1,0,1,255,2,255,2,255,2,3,254,3,254,254,4,4,253,5,253,252,6,252,6,5,251,8,250,251,249,9,42,175,213,201,207,255,64,0,17,0,99,255,97,1,16,254,163,0,39,43,189,86,217,255,6,0,91,0,86,255,186,0,23,0,128,252,192,24,216,77,237,255,220,255,102,0,167,255,232,255,72,1,73,252,8,10,37,62,0,0,0,0,0,0,135,199,61,201,64,0,128,0,134,255,36,0,54,1,0,253,72,2,51,36,69,69,12,0,128,0,18,0,114,255,32,1,139,255,159,252,27,16,123,56,104,2,13,200,246,255,39,0,58,0,210,255,172,255,120,0,184,0,197,254,227,253,4,5,4,21,64,35,0,0,0,0,230,62,198,196,243,255,0,0,20,0,26,0,5,0,225,255,213,255,252,255,65,0,90,0,7,0,99,255,8,255,212,255,81,2,47,6,52,10,199,12,228,87,5,197,3,0,242,255,236,255,241,255,2,0,25,0,37,0,25,0,240,255,185,255,149,255,177,255,50,0,36,1,111,2,214,3,8,5,184,5,148,107,103,196,17,0,12,0,8,0,1,0,246,255,234,255,226,255,224,255,234,255,3,0,44,0,100,0,168,0,243,0,61,1,125,1,173,1,199,1,189,0,168,253,105,2,103,119,117,0,97,255,210,251,8,116,52,0,221,0,168,246,116,110,252,255,17,2,234,242,229,102,208,255,246,2,140,240,165,93,176,255,137,3,117,239,6,83,157,255,204,3,130,239,102,71,149,255,199,3,139,240,39,59,153,255,128,3,97,242,174,46,165,255,5,3,207,244,94,34,185,255,99,2,161,247,152,22,210,255,169,1,161,250,180,11,0,0,157,62,0,64,94,62,0,192,4,62,0,128,237,62,0,64,137,62,0,0,0,0,0,192,76,63,0,0,205,61,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,25,23,2,0,0,0,0,0,126,124,119,109,87,41,19,9,4,2,0,0,0,0,0,0,24,78,0,0,216,80,0,0,148,83,0,0,76,86,0,0,0,89,0,0,176,91,0,0,92,94,0,0,196,95,0,0,128,96,0,0,244,96,0,0,64,97,0,0,120,97,0,0,152,97,0,0,176,97,0,0,188,97,0,0,0,0,0,0,149,139,0,0,55,152,0,0,255,165,0,0,4,181,0,0,103,197,0,0,69,215,0,0,193,234,0,0,255,255,0,0,112,20,0,0,0,0,0,0,72,127,65,129,66,128,65,128,64,128,62,128,64,128,64,128,92,78,92,79,92,78,90,79,116,41,115,40,114,40,132,26,132,26,145,17,161,12,176,10,177,11,24,179,48,138,54,135,54,132,53,134,56,133,55,132,55,132,61,114,70,96,74,88,75,88,87,74,89,66,91,67,100,59,108,50,120,40,122,37,97,43,78,50,83,78,84,81,88,75,86,74,87,71,90,73,93,74,93,74,109,40,114,36,117,34,117,34,143,17,145,18,146,19,162,12,165,10,178,7,189,6,190,8,177,9,23,178,54,115,63,102,66,98,69,99,74,89,71,91,73,91,78,89,86,80,92,66,93,64,102,59,103,60,104,60,117,52,123,44,138,35,133,31,97,38,77,45,61,90,93,60,105,42,107,41,110,45,116,38,113,38,112,38,124,26,132,27,136,19,140,20,155,14,159,16,158,18,170,13,177,10,187,8,192,6,175,9,159,10,21,178,59,110,71,86,75,85,84,83,91,66,88,73,87,72,92,75,98,72,105,58,107,54,115,52,114,55,112,56,129,51,132,40,150,33,140,29,98,35,77,42,42,121,96,66,108,43,111,40,117,44,123,32,120,36,119,33,127,33,134,34,139,21,147,23,152,20,158,25,154,26,166,21,173,16,184,13,184,10,150,13,139,15,22,178,63,114,74,82,84,83,92,82,103,62,96,72,96,67,101,73,107,72,113,55,118,52,125,52,118,52,117,55,135,49,137,39,157,32,145,29,97,33,77,40,0,0,102,63,0,0,76,63,0,0,38,63,0,0,0,63,0,134,107,63,0,20,46,63,0,112,189,62,0,208,76,62,2,1,0,0,0,0,0,0,0,8,13,16,19,21,23,24,26,27,28,29,30,31,32,32,33,34,34,35,36,36,37,37,6,0,0,0,4,0,0,0,3,0,0,0,0,0,0,0,0,15,8,7,4,11,12,3,2,13,10,5,6,9,14,1,0,9,6,3,4,5,8,1,2,7,0,0,0,0,0,0,6,0,3,0,7,3,0,1,10,0,2,6,18,10,12,0,4,0,2,0,0,0,9,4,7,4,0,3,12,7,7,0,210,6,138,58,171,152,0,0,198,26,169,100,246,216,0,0,71,56,43,30,21,12,6,0,199,165,144,124,109,96,84,71,61,51,42,32,23,15,8,0,241,225,211,199,187,175,164,153,142,132,123,114,105,96,88,80,72,64,57,50,44,38,33,29,24,20,16,12,9,5,2,0,4,6,24,7,5,0,0,2,0,0,12,28,41,13,252,247,15,42,25,14,1,254,62,41,247,246,37,65,252,3,250,4,66,7,248,16,14,38,253,33,13,22,39,23,12,255,36,64,27,250,249,10,55,43,17,1,1,8,1,1,6,245,74,53,247,244,55,76,244,8,253,3,93,27,252,26,39,59,3,248,2,0,77,11,9,248,22,44,250,7,40,9,26,3,9,249,20,101,249,4,3,248,42,26,0,241,33,68,2,23,254,55,46,254,15,3,255,21,16,41,250,27,61,39,5,245,42,88,4,1,254,60,65,6,252,255,251,73,56,1,247,19,94,29,247,0,12,99,6,4,8,237,102,46,243,3,2,13,3,2,9,235,84,72,238,245,46,104,234,8,18,38,48,23,0,240,70,83,235,11,5,245,117,22,248,250,23,117,244,3,3,248,95,28,4,246,15,77,60,241,255,4,124,2,252,3,38,84,24,231,2,13,42,13,31,21,252,56,46,255,255,35,79,243,19,249,65,88,247,242,20,4,81,49,227,20,0,75,3,239,5,247,44,92,248,1,253,22,69,31,250,95,41,244,5,39,67,16,252,1,0,250,120,55,220,243,44,122,4,232,81,5,11,3,7,2,0,9,10,88,12,35,60,83,108,132,157,180,206,228,15,32,55,77,101,125,151,175,201,225,19,42,66,89,114,137,162,184,209,230,12,25,50,72,97,120,147,172,200,223,26,44,69,90,114,135,159,180,205,225,13,22,53,80,106,130,156,180,205,228,15,25,44,64,90,115,142,168,196,222,19,24,62,82,100,120,145,168,190,214,22,31,50,79,103,120,151,170,203,227,21,29,45,65,106,124,150,171,196,224,30,49,75,97,121,142,165,186,209,229,19,25,52,70,93,116,143,166,192,219,26,34,62,75,97,118,145,167,194,217,25,33,56,70,91,113,143,165,196,223,21,34,51,72,97,117,145,171,196,222,20,29,50,67,90,117,144,168,197,221,22,31,48,66,95,117,146,168,196,222,24,33,51,77,116,134,158,180,200,224,21,28,70,87,106,124,149,170,194,217,26,33,53,64,83,117,152,173,204,225,27,34,65,95,108,129,155,174,210,225,20,26,72,99,113,131,154,176,200,219,34,43,61,78,93,114,155,177,205,229,23,29,54,97,124,138,163,179,209,229,30,38,56,89,118,129,158,178,200,231,21,29,49,63,85,111,142,163,193,222,27,48,77,103,133,158,179,196,215,232,29,47,74,99,124,151,176,198,220,237,33,42,61,76,93,121,155,174,207,225,29,53,87,112,136,154,170,188,208,227,24,30,52,84,131,150,166,186,203,229,37,48,64,84,104,118,156,177,201,230,212,178,148,129,108,96,85,82,79,77,61,59,57,56,51,49,48,45,42,41,40,38,36,34,31,30,21,12,10,3,1,0,255,245,244,236,233,225,217,203,190,176,175,161,149,136,125,114,102,91,81,71,60,52,43,35,28,20,19,18,12,11,5,0,179,138,140,148,151,149,153,151,163,116,67,82,59,92,72,100,89,92,0,0,0,0,0,0,16,0,0,0,0,99,66,36,36,34,36,34,34,34,34,83,69,36,52,34,116,102,70,68,68,176,102,68,68,34,65,85,68,84,36,116,141,152,139,170,132,187,184,216,137,132,249,168,185,139,104,102,100,68,68,178,218,185,185,170,244,216,187,187,170,244,187,187,219,138,103,155,184,185,137,116,183,155,152,136,132,217,184,184,170,164,217,171,155,139,244,169,184,185,170,164,216,223,218,138,214,143,188,218,168,244,141,136,155,170,168,138,220,219,139,164,219,202,216,137,168,186,246,185,139,116,185,219,185,138,100,100,134,100,102,34,68,68,100,68,168,203,221,218,168,167,154,136,104,70,164,246,171,137,139,137,155,218,219,139,255,254,253,238,14,3,2,1,0,255,254,252,218,35,3,2,1,0,255,254,250,208,59,4,2,1,0,255,254,246,194,71,10,2,1,0,255,252,236,183,82,8,2,1,0,255,252,235,180,90,17,2,1,0,255,248,224,171,97,30,4,1,0,255,254,236,173,95,37,7,1,0,255,255,255,131,6,145,255,255,255,255,255,236,93,15,96,255,255,255,255,255,194,83,25,71,221,255,255,255,255,162,73,34,66,162,255,255,255,210,126,73,43,57,173,255,255,255,201,125,71,48,58,130,255,255,255,166,110,73,57,62,104,210,255,255,251,123,65,55,68,100,171,255,250,0,3,0,6,0,3,0,3,0,3,0,4,0,3,0,3,0,3,0,205,1,0,0,7,23,38,54,69,85,100,116,131,147,162,178,193,208,223,239,13,25,41,55,69,83,98,112,127,142,157,171,187,203,220,236,15,21,34,51,61,78,92,106,126,136,152,167,185,205,225,240,10,21,36,50,63,79,95,110,126,141,157,173,189,205,221,237,17,20,37,51,59,78,89,107,123,134,150,164,184,205,224,240,10,15,32,51,67,81,96,112,129,142,158,173,189,204,220,236,8,21,37,51,65,79,98,113,126,138,155,168,179,192,209,218,12,15,34,55,63,78,87,108,118,131,148,167,185,203,219,236,16,19,32,36,56,79,91,108,118,136,154,171,186,204,220,237,11,28,43,58,74,89,105,120,135,150,165,180,196,211,226,241,6,16,33,46,60,75,92,107,123,137,156,169,185,199,214,225,11,19,30,44,57,74,89,105,121,135,152,169,186,202,218,234,12,19,29,46,57,71,88,100,120,132,148,165,182,199,216,233,17,23,35,46,56,77,92,106,123,134,152,167,185,204,222,237,14,17,45,53,63,75,89,107,115,132,151,171,188,206,221,240,9,16,29,40,56,71,88,103,119,137,154,171,189,205,222,237,16,19,36,48,57,76,87,105,118,132,150,167,185,202,218,236,12,17,29,54,71,81,94,104,126,136,149,164,182,201,221,237,15,28,47,62,79,97,115,129,142,155,168,180,194,208,223,238,8,14,30,45,62,78,94,111,127,143,159,175,192,207,223,239,17,30,49,62,79,92,107,119,132,145,160,174,190,204,220,235,14,19,36,45,61,76,91,108,121,138,154,172,189,205,222,238,12,18,31,45,60,76,91,107,123,138,154,171,187,204,221,236,13,17,31,43,53,70,83,103,114,131,149,167,185,203,220,237,17,22,35,42,58,78,93,110,125,139,155,170,188,206,224,240,8,15,34,50,67,83,99,115,131,146,162,178,193,209,224,239,13,16,41,66,73,86,95,111,128,137,150,163,183,206,225,241,17,25,37,52,63,75,92,102,119,132,144,160,175,191,212,231,19,31,49,65,83,100,117,133,147,161,174,187,200,213,227,242,18,31,52,68,88,103,117,126,138,149,163,177,192,207,223,239,16,29,47,61,76,90,106,119,133,147,161,176,193,209,224,240,15,21,35,50,61,73,86,97,110,119,129,141,175,198,218,237,225,204,201,184,183,175,158,154,153,135,119,115,113,110,109,99,98,95,79,68,52,50,48,45,43,32,31,27,18,10,3,0,255,251,235,230,212,201,196,182,167,166,163,151,138,124,110,104,90,78,76,70,69,57,45,34,24,21,11,6,5,4,3,0,175,148,160,176,178,173,174,164,177,174,196,182,198,192,182,68,62,66,60,72,117,85,90,118,136,151,142,160,142,155,0,0,0,0,0,0,0,0,0,1,100,102,102,68,68,36,34,96,164,107,158,185,180,185,139,102,64,66,36,34,34,0,1,32,208,139,141,191,152,185,155,104,96,171,104,166,102,102,102,132,1,0,0,0,0,16,16,0,80,109,78,107,185,139,103,101,208,212,141,139,173,153,123,103,36,0,0,0,0,0,0,1,48,0,0,0,0,0,0,32,68,135,123,119,119,103,69,98,68,103,120,118,118,102,71,98,134,136,157,184,182,153,139,134,208,168,248,75,189,143,121,107,32,49,34,34,34,0,17,2,210,235,139,123,185,137,105,134,98,135,104,182,100,183,171,134,100,70,68,70,66,66,34,131,64,166,102,68,36,2,1,0,134,166,102,68,34,34,66,132,212,246,158,139,107,107,87,102,100,219,125,122,137,118,103,132,114,135,137,105,171,106,50,34,164,214,141,143,185,151,121,103,192,34,0,0,0,0,0,1,208,109,74,187,134,249,159,137,102,110,154,118,87,101,119,101,0,2,0,36,36,66,68,35,96,164,102,100,36,0,2,33,167,138,174,102,100,84,2,2,100,107,120,119,36,197,24,0,255,254,253,244,12,3,2,1,0,255,254,252,224,38,3,2,1,0,255,254,251,209,57,4,2,1,0,255,254,244,195,69,4,2,1,0,255,251,232,184,84,7,2,1,0,255,254,240,186,86,14,2,1,0,255,254,239,178,91,30,5,1,0,255,248,227,177,100,19,2,1,0,255,255,255,156,4,154,255,255,255,255,255,227,102,15,92,255,255,255,255,255,213,83,24,72,236,255,255,255,255,150,76,33,63,214,255,255,255,190,121,77,43,55,185,255,255,255,245,137,71,43,59,139,255,255,255,255,131,66,50,66,107,194,255,255,166,116,76,55,53,125,255,255,100,0,3,0,40,0,3,0,3,0,3,0,5,0,14,0,14,0,10,0,11,0,3,0,8,0,9,0,7,0,3,0,91,1,0,0,0,0,0,0,203,150,0,0,0,0,0,0,215,195,166,125,110,82,0,0,255,255,0,0,0,0,0,0,184,126,154,121,0,0,0,0,154,121,102,102,0,0,0,0,184,126,51,115,0,0,0,0,15,0,0,0,10,0,0,0,5,0,0,0,0,0,0,0,128,187,0,0,120,0,0,0,21,0,0,0,21,0,0,0,0,154,89,63,0,0,0,0,0,0,128,63,0,0,128,63,224,20,0,0,3,0,0,0,8,0,0,0,120,0,0,0,11,0,0,0,16,21,0,0,248,21,0,0,40,22,0,0,128,7,0,0,3,0,0,0,8,24,0,0,64,24,0,0,120,24,0,0,176,24,0,0,232,24,0,0,136,1,0,0,8,53,0,0,224,53,0,0,104,55,0,0,0,0,0,0,0,0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,10,0,12,0,14,0,16,0,20,0,24,0,28,0,34,0,40,0,48,0,60,0,78,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,80,75,69,63,56,49,40,34,29,20,18,10,0,0,0,0,0,0,0,0,110,100,90,84,78,71,65,58,51,45,39,32,26,20,12,0,0,0,0,0,0,118,110,103,93,86,80,75,70,65,59,53,47,40,31,23,15,4,0,0,0,0,126,119,112,104,95,89,83,78,72,66,60,54,47,39,32,25,17,12,1,0,0,134,127,120,114,103,97,91,85,78,72,66,60,54,47,41,35,29,23,16,10,1,144,137,130,124,113,107,101,95,88,82,76,70,64,57,51,45,39,33,26,15,1,152,145,138,132,123,117,111,105,98,92,86,80,74,67,61,55,49,43,36,20,1,162,155,148,142,133,127,121,115,108,102,96,90,84,77,71,65,59,53,46,30,1,172,165,158,152,143,137,131,125,118,112,106,100,94,87,81,75,69,63,56,45,20,200,200,200,200,200,200,200,200,198,193,188,183,178,173,168,163,158,153,148,129,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,8,0,8,0,8,0,16,0,16,0,16,0,21,0,21,0,24,0,29,0,34,0,36,0,0,0,0,0,0,0,106,28,141,56,82,187,30,58,8,105,220,58,130,237,87,59,137,99,178,59,3,42,5,60,48,220,57,60,180,62,119,60,28,163,158,60,209,242,197,60,254,134,241,60,155,171,16,61,5,173,42,61,132,194,70,61,83,230,100,61,17,137,130,61,135,159,147,61,203,178,165,61,209,190,184,61,58,191,204,61,84,175,225,61,20,138,247,61,14,37,7,62,217,244,18,62,95,49,31,62,104,215,43,62,138,227,56,62,48,82,70,62,148,31,84,62,191,71,98,62,142,198,112,62,176,151,127,62,82,91,135,62,96,15,143,62,152,229,150,62,121,219,158,62,112,238,166,62,216,27,175,62,251,96,183,62,17,187,191,62,70,39,200,62,183,162,208,62,120,42,217,62,148,187,225,62,12,83,234,62,222,237,242,62,6,137,251,62,190,16,2,63,31,90,6,63,36,159,10,63,80,222,14,63,43,22,19,63,65,69,23,63,37,106,27,63,115,131,31,63,206,143,35,63,230,141,39,63,116,124,43,63,63,90,47,63,25,38,51,63,231,222,54,63,153,131,58,63,51,19,62,63,197,140,65,63,119,239,68,63,127,58,72,63,39,109,75,63,206,134,78,63,229,134,81,63,241,108,84,63,142,56,87,63,105,233,89,63,69,127,92,63,250,249,94,63,115,89,97,63,175,157,99,63,193,198,101,63,207,212,103,63,17,200,105,63,210,160,107,63,110,95,109,63,80,4,111,63,244,143,112,63,230,2,114,63,189,93,115,63,31,161,116,63,191,205,117,63,87,228,118,63,176,229,119,63,151,210,120,63,227,171,121,63,115,114,122,63,39,39,123,63,231,202,123,63,157,94,124,63,53,227,124,63,156,89,125,63,189,194,125,63,134,31,126,63,222,112,126,63,171,183,126,63,207,244,126,63,38,41,127,63,134,85,127,63,190,122,127,63,150,153,127,63,204,178,127,63,20,199,127,63,28,215,127,63,130,227,127,63,221,236,127,63,182,243,127,63,138,248,127,63,200,251,127,63,214,253,127,63,7,255,127,63,165,255,127,63,232,255,127,63,253,255,127,63,0,0,128,63,224,1,0,0,135,136,8,59,255,255,255,255,5,0,96,0,3,0,32,0,4,0,8,0,2,0,4,0,4,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,88,74,0,0,136,56,0,0,0,0,0,0,240,0,0,0,137,136,136,59,1,0,0,0,5,0,48,0,3,0,16,0,4,0,4,0,4,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,72,0,0,136,56,0,0,0,0,0,0,120,0,0,0,136,136,8,60,2,0,0,0,5,0,24,0,3,0,8,0,2,0,4,0,4,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,136,71,0,0,136,56,0,0,0,0,0,0,60,0,0,0,137,136,136,60,3,0,0,0,5,0,12,0,3,0,4,0,4,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,56,0,0,136,56,0,0,0,0,0,0,255,255,127,63,142,255,127,63,106,254,127,63,147,252,127,63,7,250,127,63,200,246,127,63,214,242,127,63,48,238,127,63,214,232,127,63,200,226,127,63,7,220,127,63,147,212,127,63,107,204,127,63,143,195,127,63,0,186,127,63,189,175,127,63,199,164,127,63,29,153,127,63,192,140,127,63,176,127,127,63,236,113,127,63,118,99,127,63,75,84,127,63,110,68,127,63,222,51,127,63,154,34,127,63,163,16,127,63,250,253,126,63,157,234,126,63,141,214,126,63,203,193,126,63,86,172,126,63,46,150,126,63,83,127,126,63,198,103,126,63,134,79,126,63,148,54,126,63,239,28,126,63,152,2,126,63,143,231,125,63,211,203,125,63,102,175,125,63,70,146,125,63,116,116,125,63,241,85,125,63,188,54,125,63,213,22,125,63,60,246,124,63,242,212,124,63,246,178,124,63,73,144,124,63,235,108,124,63,219,72,124,63,27,36,124,63,169,254,123,63,135,216,123,63,180,177,123,63,48,138,123,63,252,97,123,63,23,57,123,63,130,15,123,63,61,229,122,63,72,186,122,63,162,142,122,63,77,98,122,63,72,53,122,63,148,7,122,63,48,217,121,63,29,170,121,63,90,122,121,63,233,73,121,63,200,24,121,63,249,230,120,63,123,180,120,63,78,129,120,63,115,77,120,63,234,24,120,63,178,227,119,63,205,173,119,63,58,119,119,63,249,63,119,63,10,8,119,63,110,207,118,63,37,150,118,63,47,92,118,63,140,33,118,63,60,230,117,63,64,170,117,63,151,109,117,63,66,48,117,63,65,242,116,63,148,179,116,63,59,116,116,63,55,52,116,63,135,243,115,63,44,178,115,63,38,112,115,63,118,45,115,63,26,234,114,63,20,166,114,63,100,97,114,63,10,28,114,63,5,214,113,63,87,143,113,63,0,72,113,63,255,255,112,63,85,183,112,63,2,110,112,63,6,36,112,63,98,217,111,63,21,142,111,63,32,66,111,63,132,245,110,63,63,168,110,63,83,90,110,63,192,11,110,63,134,188,109,63,165,108,109,63,29,28,109,63,239,202,108,63,27,121,108,63,161,38,108,63,128,211,107,63,187,127,107,63,80,43,107,63,64,214,106,63,140,128,106,63,50,42,106,63,53,211,105,63,147,123,105,63,77,35,105,63,100,202,104,63,216,112,104,63,168,22,104,63,213,187,103,63,96,96,103,63,72,4,103,63,143,167,102,63,51,74,102,63,54,236,101,63,151,141,101,63,87,46,101,63,119,206,100,63,245,109,100,63,212,12,100,63,18,171,99,63,177,72,99,63,176,229,98,63,16,130,98,63,209,29,98,63,243,184,97,63,119,83,97,63,92,237,96,63,164,134,96,63,78,31,96,63,91,183,95,63,203,78,95,63,158,229,94,63,213,123,94,63,112,17,94,63,110,166,93,63,210,58,93,63,154,206,92,63,198,97,92,63,89,244,91,63,81,134,91,63,174,23,91,63,114,168,90,63,157,56,90,63,46,200,89,63,39,87,89,63,135,229,88,63,79,115,88,63,127,0,88,63,23,141,87,63,24,25,87,63,130,164,86,63,86,47,86,63,147,185,85,63,58,67,85,63,75,204,84,63,199,84,84,63,174,220,83,63,1,100,83,63,191,234,82,63,233,112,82,63,127,246,81,63,130,123,81,63,242,255,80,63,207,131,80,63,26,7,80,63,210,137,79,63,250,11,79,63,144,141,78,63,148,14,78,63,9,143,77,63,237,14,77,63,65,142,76,63,5,13,76,63,59,139,75,63,225,8,75,63,249,133,74,63,131,2,74,63,127,126,73,63,238,249,72,63,207,116,72,63,36,239,71,63,237,104,71,63,41,226,70,63,218,90,70,63,0,211,69,63,155,74,69,63,172,193,68,63,50,56,68,63,47,174,67,63,162,35,67,63,141,152,66,63,239,12,66,63,200,128,65,63,26,244,64,63,229,102,64,63,40,217,63,63,229,74,63,63,27,188,62,63,204,44,62,63,247,156,61,63,157,12,61,63,190,123,60,63,92,234,59,63,117,88,59,63,10,198,58,63,29,51,58,63,173,159,57,63,187,11,57,63,71,119,56,63,81,226,55,63,218,76,55,63,227,182,54,63,107,32,54,63,116,137,53,63,253,241,52,63,7,90,52,63,147,193,51,63,160,40,51,63,48,143,50,63,66,245,49,63,216,90,49,63,241,191,48,63,142,36,48,63,175,136,47,63,85,236,46,63,129,79,46,63,50,178,45,63,105,20,45,63,39,118,44,63,107,215,43,63,55,56,43,63,139,152,42,63,103,248,41,63,204,87,41,63,186,182,40,63,50,21,40,63,51,115,39,63,191,208,38,63,214,45,38,63,121,138,37,63,167,230,36,63,97,66,36,63,169,157,35,63,125,248,34,63,223,82,34,63,207,172,33,63,77,6,33,63,91,95,32,63,248,183,31,63,37,16,31,63,226,103,30,63,48,191,29,63,16,22,29,63,129,108,28,63,132,194,27,63,26,24,27,63,67,109,26,63,0,194,25,63,81,22,25,63,54,106,24,63,177,189,23,63,193,16,23,63,103,99,22,63,163,181,21,63,118,7,21,63,225,88,20,63,228,169,19,63,127,250,18,63,179,74,18,63,128,154,17,63,231,233,16,63,232,56,16,63,132,135,15,63,187,213,14,63,142,35,14,63,254,112,13,63,10,190,12,63,179,10,12,63,250,86,11,63,223,162,10,63,99,238,9,63,134,57,9,63,73,132,8,63,172,206,7,63,175,24,7,63,84,98,6,63,155,171,5,63,131,244,4,63,15,61,4,63,61,133,3,63,15,205,2,63,134,20,2,63,161,91,1,63,97,162,0,63,143,209,255,62,167,93,254,62,14,233,252,62,194,115,251,62,198,253,249,62,27,135,248,62,193,15,247,62,186,151,245,62,6,31,244,62,168,165,242,62,158,43,241,62,236,176,239,62,145,53,238,62,144,185,236,62,232,60,235,62,154,191,233,62,169,65,232,62,21,195,230,62,223,67,229,62,8,196,227,62,145,67,226,62,124,194,224,62,200,64,223,62,120,190,221,62,140,59,220,62,6,184,218,62,230,51,217,62,46,175,215,62,223,41,214,62,249,163,212,62,125,29,211,62,110,150,209,62,204,14,208,62,151,134,206,62,210,253,204,62,125,116,203,62,153,234,201,62,39,96,200,62,40,213,198,62,159,73,197,62,138,189,195,62,236,48,194,62,198,163,192,62,25,22,191,62,230,135,189,62,45,249,187,62,241,105,186,62,50,218,184,62,241,73,183,62,47,185,181,62,238,39,180,62,47,150,178,62,242,3,177,62,57,113,175,62,4,222,173,62,86,74,172,62,47,182,170,62,144,33,169,62,122,140,167,62,239,246,165,62,239,96,164,62,124,202,162,62,151,51,161,62,64,156,159,62,122,4,158,62,68,108,156,62,161,211,154,62,145,58,153,62,22,161,151,62,48,7,150,62,225,108,148,62,41,210,146,62,11,55,145,62,135,155,143,62,158,255,141,62,81,99,140,62,162,198,138,62,145,41,137,62,32,140,135,62,80,238,133,62,34,80,132,62,151,177,130,62,176,18,129,62,222,230,126,62,169,167,123,62,195,103,120,62,47,39,117,62,238,229,113,62,4,164,110,62,115,97,107,62,60,30,104,62,98,218,100,62,232,149,97,62,207,80,94,62,26,11,91,62,204,196,87,62,230,125,84,62,107,54,81,62,93,238,77,62,191,165,74,62,146,92,71,62,218,18,68,62,151,200,64,62,206,125,61,62,128,50,58,62,174,230,54,62,93,154,51,62,141,77,48,62,66,0,45,62,125,178,41,62,66,100,38,62,145,21,35,62,110,198,31,62,219,118,28,62,218,38,25,62,109,214,21,62,152,133,18,62,91,52,15,62,186,226,11,62,183,144,8,62,84,62,5,62,148,235,1,62,240,48,253,61,6,138,246,61,113,226,239,61,51,58,233,61,79,145,226,61,207,231,219,61,181,61,213,61,3,147,206,61,192,231,199,61,242,59,193,61,156,143,186,61,195,226,179,61,108,53,173,61,155,135,166,61,85,217,159,61,159,42,153,61,126,123,146,61,246,203,139,61,11,28,133,61,135,215,124,61,70,118,111,61,93,20,98,61,214,177,84,61,185,78,71,61,16,235,57,61,229,134,44,61,64,34,31,61,44,189,17,61,178,87,4,61,181,227,237,60,96,23,211,60,118,74,184,60,11,125,157,60,50,175,130,60,250,193,79,60,254,36,26,60,42,15,201,59,153,167,59,59,46,125,214,185,210,70,113,187,171,222,227,187,166,140,39,188,129,41,93,188,225,98,137,188,160,48,164,188,236,253,190,188,179,202,217,188,224,150,244,188,49,177,7,189,147,22,21,189,140,123,34,189,19,224,47,189,30,68,61,189,165,167,74,189,157,10,88,189,254,108,101,189,190,206,114,189,234,23,128,189,27,200,134,189,237,119,141,189,92,39,148,189,99,214,154,189,253,132,161,189,38,51,168,189,217,224,174,189,17,142,181,189,202,58,188,189,254,230,194,189,170,146,201,189,200,61,208,189,84,232,214,189,74,146,221,189,164,59,228,189,93,228,234,189,114,140,241,189,221,51,248,189,154,218,254,189,82,192,2,190,252,18,6,190,71,101,9,190,50,183,12,190,186,8,16,190,221,89,19,190,152,170,22,190,234,250,25,190,208,74,29,190,71,154,32,190,78,233,35,190,225,55,39,190,0,134,42,190,166,211,45,190,211,32,49,190,131,109,52,190,181,185,55,190,101,5,59,190,147,80,62,190,58,155,65,190,90,229,68,190,240,46,72,190,249,119,75,190,116,192,78,190,93,8,82,190,179,79,85,190,115,150,88,190,156,220,91,190,42,34,95,190,27,103,98,190,109,171,101,190,31,239,104,190,44,50,108,190,148,116,111,190,84,182,114,190,106,247,117,190,211,55,121,190,141,119,124,190,150,182,127,190,117,122,129,190,69,25,131,190,185,183,132,190,208,85,134,190,136,243,135,190,225,144,137,190,218,45,139,190,112,202,140,190,164,102,142,190,116,2,144,190,223,157,145,190,228,56,147,190,129,211,148,190,182,109,150,190,129,7,152,190,226,160,153,190,215,57,155,190,95,210,156,190,121,106,158,190,35,2,160,190,94,153,161,190,38,48,163,190,125,198,164,190,96,92,166,190,206,241,167,190,198,134,169,190,71,27,171,190,80,175,172,190,224,66,174,190,245,213,175,190,143,104,177,190,173,250,178,190,77,140,180,190,110,29,182,190,16,174,183,190,48,62,185,190,207,205,186,190,234,92,188,190,130,235,189,190,148,121,191,190,31,7,193,190,35,148,194,190,159,32,196,190,145,172,197,190,248,55,199,190,211,194,200,190,34,77,202,190,226,214,203,190,19,96,205,190,181,232,206,190,197,112,208,190,66,248,209,190,45,127,211,190,131,5,213,190,67,139,214,190,109,16,216,190,255,148,217,190,249,24,219,190,89,156,220,190,29,31,222,190,70,161,223,190,211,34,225,190,193,163,226,190,16,36,228,190,190,163,229,190,204,34,231,190,56,161,232,190,0,31,234,190,36,156,235,190,162,24,237,190,122,148,238,190,171,15,240,190,51,138,241,190,18,4,243,190,70,125,244,190,207,245,245,190,170,109,247,190,217,228,248,190,88,91,250,190,40,209,251,190,71,70,253,190,181,186,254,190,56,23,0,191,187,208,0,191,228,137,1,191,178,66,2,191,37,251,2,191,59,179,3,191,246,106,4,191,83,34,5,191,83,217,5,191,245,143,6,191,56,70,7,191,29,252,7,191,162,177,8,191,199,102,9,191,140,27,10,191,240,207,10,191,243,131,11,191,147,55,12,191,209,234,12,191,172,157,13,191,36,80,14,191,56,2,15,191,232,179,15,191,50,101,16,191,24,22,17,191,151,198,17,191,176,118,18,191,99,38,19,191,174,213,19,191,145,132,20,191,13,51,21,191,31,225,21,191,200,142,22,191,8,60,23,191,221,232,23,191,72,149,24,191,72,65,25,191,220,236,25,191,4,152,26,191,192,66,27,191,15,237,27,191,240,150,28,191,99,64,29,191,104,233,29,191,254,145,30,191,37,58,31,191,220,225,31,191,35,137,32,191,250,47,33,191,95,214,33,191,82,124,34,191,212,33,35,191,227,198,35,191,127,107,36,191,167,15,37,191,92,179,37,191,157,86,38,191,104,249,38,191,191,155,39,191,160,61,40,191,11,223,40,191,255,127,41,191,125,32,42,191,131,192,42,191,17,96,43,191,39,255,43,191,196,157,44,191,232,59,45,191,146,217,45,191,195,118,46,191,121,19,47,191,180,175,47,191,115,75,48,191,183,230,48,191,127,129,49,191,203,27,50,191,153,181,50,191,234,78,51,191,189,231,51,191,18,128,52,191,232,23,53,191,63,175,53,191,22,70,54,191,110,220,54,191,69,114,55,191,156,7,56,191,113,156,56,191,197,48,57,191,150,196,57,191,230,87,58,191,178,234,58,191,252,124,59,191,194,14,60,191,3,160,60,191,193,48,61,191,250,192,61,191,173,80,62,191,219,223,62,191,131,110,63,191,165,252,63,191,64,138,64,191,83,23,65,191,224,163,65,191,228,47,66,191,96,187,66,191,83,70,67,191,190,208,67,191,158,90,68,191,246,227,68,191,194,108,69,191,5,245,69,191,188,124,70,191,232,3,71,191,137,138,71,191,157,16,72,191,37,150,72,191,32,27,73,191,142,159,73,191,111,35,74,191,193,166,74,191,134,41,75,191,188,171,75,191,99,45,76,191,122,174,76,191,2,47,77,191,250,174,77,191,98,46,78,191,57,173,78,191,126,43,79,191,51,169,79,191,85,38,80,191,230,162,80,191,228,30,81,191,80,154,81,191,40,21,82,191,109,143,82,191,30,9,83,191,59,130,83,191,195,250,83,191,183,114,84,191,22,234,84,191,223,96,85,191,18,215,85,191,176,76,86,191,183,193,86,191,39,54,87,191,0,170,87,191,66,29,88,191,236,143,88,191,254,1,89,191,120,115,89,191,89,228,89,191,162,84,90,191,81,196,90,191,102,51,91,191,226,161,91,191,195,15,92,191,10,125,92,191,183,233,92,191,200,85,93,191,62,193,93,191,24,44,94,191,87,150,94,191,249,255,94,191,255,104,95,191,104,209,95,191,51,57,96,191,98,160,96,191,243,6,97,191,229,108,97,191,58,210,97,191,240,54,98,191,8,155,98,191,128,254,98,191,89,97,99,191,146,195,99,191,44,37,100,191,37,134,100,191,126,230,100,191,55,70,101,191,78,165,101,191,197,3,102,191,154,97,102,191,205,190,102,191,94,27,103,191,77,119,103,191,154,210,103,191,68,45,104,191,75,135,104,191,174,224,104,191,111,57,105,191,139,145,105,191,4,233,105,191,217,63,106,191,9,150,106,191,148,235,106,191,123,64,107,191,188,148,107,191,89,232,107,191,79,59,108,191,160,141,108,191,75,223,108,191,79,48,109,191,173,128,109,191,101,208,109,191,117,31,110,191,223,109,110,191,161,187,110,191,187,8,111,191,46,85,111,191,248,160,111,191,27,236,111,191,149,54,112,191,103,128,112,191,144,201,112,191,15,18,113,191,230,89,113,191,19,161,113,191,151,231,113,191,113,45,114,191,160,114,114,191,38,183,114,191,1,251,114,191,50,62,115,191,184,128,115,191,148,194,115,191,196,3,116,191,73,68,116,191,34,132,116,191,80,195,116,191,210,1,117,191,168,63,117,191,210,124,117,191,80,185,117,191,33,245,117,191,69,48,118,191,189,106,118,191,136,164,118,191,166,221,118,191,22,22,119,191,217,77,119,191,239,132,119,191,87,187,119,191,17,241,119,191,29,38,120,191,122,90,120,191,42,142,120,191,43,193,120,191,125,243,120,191,33,37,121,191,22,86,121,191,92,134,121,191,242,181,121,191,218,228,121,191,18,19,122,191,154,64,122,191,115,109,122,191,157,153,122,191,22,197,122,191,223,239,122,191,248,25,123,191,97,67,123,191,26,108,123,191,34,148,123,191,122,187,123,191,32,226,123,191,23,8,124,191,92,45,124,191,240,81,124,191,211,117,124,191,5,153,124,191,134,187,124,191,85,221,124,191,115,254,124,191,223,30,125,191,154,62,125,191,163,93,125,191,250,123,125,191,159,153,125,191,146,182,125,191,211,210,125,191,98,238,125,191,63,9,126,191,105,35,126,191,225,60,126,191,167,85,126,191,186,109,126,191,27,133,126,191,201,155,126,191,196,177,126,191,13,199,126,191,162,219,126,191,133,239,126,191,181,2,127,191,50,21,127,191,252,38,127,191,19,56,127,191,118,72,127,191,39,88,127,191,36,103,127,191,110,117,127,191,5,131,127,191,232,143,127,191,25,156,127,191,149,167,127,191,95,178,127,191,116,188,127,191,215,197,127,191,133,206,127,191,129,214,127,191,200,221,127,191,93,228,127,191,61,234,127,191,106,239,127,191,227,243,127,191,169,247,127,191,187,250,127,191,25,253,127,191,196,254,127,191,187,255,127,191,250,255,127,63,57,254,127,63,169,249,127,63,75,242,127,63,30,232,127,63,35,219,127,63,89,203,127,63,193,184,127,63],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE);allocate([91,163,127,63,40,139,127,63,39,112,127,63,90,82,127,63,191,49,127,63,88,14,127,63,37,232,126,63,38,191,126,63,92,147,126,63,200,100,126,63,105,51,126,63,65,255,125,63,79,200,125,63,150,142,125,63,20,82,125,63,203,18,125,63,188,208,124,63,231,139,124,63,77,68,124,63,239,249,123,63,205,172,123,63,233,92,123,63,67,10,123,63,221,180,122,63,182,92,122,63,209,1,122,63,46,164,121,63,206,67,121,63,178,224,120,63,220,122,120,63,76,18,120,63,4,167,119,63,4,57,119,63,79,200,118,63,228,84,118,63,198,222,117,63,246,101,117,63,117,234,116,63,68,108,116,63,101,235,115,63,218,103,115,63,163,225,114,63,194,88,114,63,57,205,113,63,9,63,113,63,52,174,112,63,187,26,112,63,160,132,111,63,228,235,110,63,138,80,110,63,147,178,109,63,1,18,109,63,213,110,108,63,17,201,107,63,183,32,107,63,201,117,106,63,73,200,105,63,57,24,105,63,155,101,104,63,111,176,103,63,186,248,102,63,124,62,102,63,184,129,101,63,111,194,100,63,164,0,100,63,90,60,99,63,145,117,98,63,76,172,97,63,142,224,96,63,89,18,96,63,174,65,95,63,145,110,94,63,3,153,93,63,8,193,92,63,160,230,91,63,207,9,91,63,152,42,90,63,251,72,89,63,253,100,88,63,159,126,87,63,229,149,86,63,208,170,85,63,99,189,84,63,161,205,83,63,140,219,82,63,39,231,81,63,117,240,80,63,121,247,79,63,52,252,78,63,171,254,77,63,223,254,76,63,212,252,75,63,140,248,74,63,10,242,73,63,82,233,72,63,101,222,71,63,71,209,70,63,251,193,69,63,132,176,68,63,229,156,67,63,32,135,66,63,58,111,65,63,52,85,64,63,19,57,63,63,216,26,62,63,136,250,60,63,38,216,59,63,180,179,58,63,54,141,57,63,175,100,56,63,34,58,55,63,147,13,54,63,5,223,52,63,124,174,51,63,249,123,50,63,130,71,49,63,25,17,48,63,194,216,46,63,127,158,45,63,86,98,44,63,72,36,43,63,90,228,41,63,144,162,40,63,235,94,39,63,113,25,38,63,37,210,36,63,9,137,35,63,35,62,34,63,117,241,32,63,4,163,31,63,210,82,30,63,228,0,29,63,61,173,27,63,225,87,26,63,211,0,25,63,25,168,23,63,180,77,22,63,170,241,20,63,253,147,19,63,178,52,18,63,204,211,16,63,80,113,15,63,66,13,14,63,164,167,12,63,124,64,11,63,205,215,9,63,154,109,8,63,233,1,7,63,189,148,5,63,25,38,4,63,3,182,2,63,126,68,1,63,28,163,255,62,110,186,252,62,250,206,249,62,202,224,246,62,228,239,243,62,81,252,240,62,26,6,238,62,71,13,235,62,224,17,232,62,237,19,229,62,119,19,226,62,135,16,223,62,36,11,220,62,88,3,217,62,42,249,213,62,164,236,210,62,205,221,207,62,175,204,204,62,82,185,201,62,191,163,198,62,254,139,195,62,24,114,192,62,22,86,189,62,0,56,186,62,224,23,183,62,189,245,179,62,161,209,176,62,149,171,173,62,162,131,170,62,207,89,167,62,39,46,164,62,178,0,161,62,121,209,157,62,133,160,154,62,223,109,151,62,143,57,148,62,160,3,145,62,26,204,141,62,5,147,138,62,107,88,135,62,86,28,132,62,205,222,128,62,182,63,123,62,16,191,116,62,187,59,110,62,201,181,103,62,77,45,97,62,89,162,90,62,255,20,84,62,81,133,77,62,99,243,70,62,70,95,64,62,13,201,57,62,202,48,51,62,144,150,44,62,114,250,37,62,130,92,31,62,210,188,24,62,118,27,18,62,127,120,11,62,1,212,4,62,29,92,252,61,114,13,239,61,41,188,225,61,102,104,212,61,78,18,199,61,8,186,185,61,184,95,172,61,132,3,159,61,146,165,145,61,7,70,132,61,18,202,109,61,122,5,83,61,145,62,56,61,164,117,29,61,252,170,2,61,202,189,207,60,86,35,154,60,97,14,73,60,197,167,187,59,61,122,86,186,9,70,241,187,18,221,99,188,80,138,167,188,65,36,221,188,227,93,9,189,35,40,36,189,150,240,62,189,242,182,89,189,234,122,116,189,26,158,135,189,66,253,148,189,200,90,162,189,134,182,175,189,87,16,189,189,22,104,202,189,155,189,215,189,195,16,229,189,105,97,242,189,101,175,255,189,74,125,6,190,104,33,13,190,250,195,19,190,237,100,26,190,46,4,33,190,172,161,39,190,83,61,46,190,16,215,52,190,210,110,59,190,134,4,66,190,25,152,72,190,121,41,79,190,148,184,85,190,86,69,92,190,174,207,98,190,137,87,105,190,214,220,111,190,128,95,118,190,120,223,124,190,84,174,129,190,129,235,132,190,56,39,136,190,114,97,139,190,36,154,142,190,69,209,145,190,205,6,149,190,179,58,152,190,238,108,155,190,116,157,158,190,61,204,161,190,64,249,164,190,115,36,168,190,207,77,171,190,73,117,174,190,218,154,177,190,120,190,180,190,27,224,183,190,186,255,186,190,75,29,190,190,199,56,193,190,37,82,196,190,91,105,199,190,97,126,202,190,48,145,205,190,188,161,208,190,0,176,211,190,241,187,214,190,135,197,217,190,186,204,220,190,129,209,223,190,211,211,226,190,169,211,229,190,250,208,232,190,189,203,235,190,234,195,238,190,120,185,241,190,96,172,244,190,154,156,247,190,28,138,250,190,223,116,253,190,109,46,0,191,3,161,1,191,45,18,3,191,230,129,4,191,44,240,5,191,250,92,7,191,76,200,8,191,30,50,10,191,108,154,11,191,50,1,13,191,108,102,14,191,23,202,15,191,45,44,17,191,172,140,18,191,144,235,19,191,213,72,21,191,118,164,22,191,113,254,23,191,192,86,25,191,98,173,26,191,81,2,28,191,138,85,29,191,9,167,30,191,203,246,31,191,204,68,33,191,9,145,34,191,124,219,35,191,36,36,37,191,253,106,38,191,2,176,39,191,48,243,40,191,132,52,42,191,250,115,43,191,143,177,44,191,63,237,45,191,7,39,47,191,227,94,48,191,208,148,49,191,202,200,50,191,206,250,51,191,218,42,53,191,232,88,54,191,247,132,55,191,2,175,56,191,7,215,57,191,3,253,58,191,241,32,60,191,207,66,61,191,154,98,62,191,79,128,63,191,233,155,64,191,104,181,65,191,198,204,66,191,1,226,67,191,23,245,68,191,3,6,70,191,196,20,71,191,86,33,72,191,182,43,73,191,225,51,74,191,212,57,75,191,141,61,76,191,9,63,77,191,68,62,78,191,61,59,79,191,240,53,80,191,90,46,81,191,121,36,82,191,74,24,83,191,202,9,84,191,247,248,84,191,206,229,85,191,77,208,86,191,112,184,87,191,55,158,88,191,156,129,89,191,160,98,90,191,62,65,91,191,117,29,92,191,65,247,92,191,162,206,93,191,148,163,94,191,20,118,95,191,34,70,96,191,186,19,97,191,217,222,97,191,127,167,98,191,169,109,99,191,84,49,100,191,126,242,100,191,38,177,101,191,73,109,102,191,229,38,103,191,248,221,103,191,128,146,104,191,123,68,105,191,232,243,105,191,195,160,106,191,12,75,107,191,192,242,107,191,222,151,108,191,100,58,109,191,80,218,109,191,160,119,110,191,83,18,111,191,102,170,111,191,217,63,112,191,169,210,112,191,213,98,113,191,91,240,113,191,58,123,114,191,113,3,115,191,253,136,115,191,222,11,116,191,17,140,116,191,150,9,117,191,107,132,117,191,143,252,117,191,0,114,118,191,189,228,118,191,198,84,119,191,24,194,119,191,178,44,120,191,147,148,120,191,187,249,120,191,40,92,121,191,217,187,121,191,205,24,122,191,2,115,122,191,121,202,122,191,47,31,123,191,36,113,123,191,88,192,123,191,201,12,124,191,118,86,124,191,95,157,124,191,130,225,124,191,224,34,125,191,119,97,125,191,71,157,125,191,79,214,125,191,142,12,126,191,4,64,126,191,176,112,126,191,146,158,126,191,169,201,126,191,245,241,126,191,117,23,127,191,41,58,127,191,16,90,127,191,43,119,127,191,120,145,127,191,248,168,127,191,170,189,127,191,143,207,127,191,165,222,127,191,237,234,127,191,102,244,127,191,17,251,127,191,237,254,127,191,234,255,127,63,229,248,127,63,166,230,127,63,45,201,127,63,124,160,127,63,149,108,127,63,121,45,127,63,44,227,126,63,177,141,126,63,11,45,126,63,63,193,125,63,82,74,125,63,72,200,124,63,40,59,124,63,247,162,123,63,189,255,122,63,128,81,122,63,72,152,121,63,30,212,120,63,9,5,120,63,19,43,119,63,70,70,118,63,172,86,117,63,78,92,116,63,56,87,115,63,118,71,114,63,19,45,113,63,28,8,112,63,158,216,110,63,165,158,109,63,64,90,108,63,126,11,107,63,107,178,105,63,25,79,104,63,150,225,102,63,242,105,101,63,62,232,99,63,139,92,98,63,234,198,96,63,109,39,95,63,38,126,93,63,40,203,91,63,133,14,90,63,83,72,88,63,163,120,86,63,139,159,84,63,32,189,82,63,118,209,80,63,163,220,78,63,189,222,76,63,219,215,74,63,19,200,72,63,124,175,70,63,46,142,68,63,65,100,66,63,206,49,64,63,236,246,61,63,180,179,59,63,66,104,57,63,173,20,55,63,16,185,52,63,134,85,50,63,41,234,47,63,21,119,45,63,101,252,42,63,53,122,40,63,161,240,37,63,198,95,35,63,192,199,32,63,172,40,30,63,169,130,27,63,212,213,24,63,74,34,22,63,42,104,19,63,147,167,16,63,164,224,13,63,123,19,11,63,57,64,8,63,253,102,5,63,231,135,2,63,45,70,255,62,91,113,249,62,151,145,243,62,36,167,237,62,69,178,231,62,60,179,225,62,76,170,219,62,186,151,213,62,201,123,207,62,190,86,201,62,223,40,195,62,112,242,188,62,183,179,182,62,251,108,176,62,129,30,170,62,146,200,163,62,115,107,157,62,108,7,151,62,197,156,144,62,199,43,138,62,185,180,131,62,199,111,122,62,33,107,109,62,17,92,96,62,41,67,83,62,253,32,70,62,32,246,56,62,38,195,43,62,164,136,30,62,45,71,17,62,87,255,3,62,110,99,237,61,194,189,210,61,218,14,184,61,222,87,157,61,251,153,130,61,188,172,79,61,101,28,26,61,153,10,201,60,42,167,59,60,193,120,214,186,45,68,113,188,87,215,227,188,76,129,39,189,148,15,93,189,21,74,137,189,90,6,164,189,109,187,190,189,34,104,217,189,78,11,244,189,227,81,7,190,47,152,20,190,247,215,33,190,165,16,47,190,166,65,60,190,100,106,73,190,77,138,86,190,205,160,99,190,80,173,112,190,69,175,125,190,13,83,133,190,158,200,139,190,13,56,146,190,18,161,152,190,102,3,159,190,191,94,165,190,216,178,171,190,105,255,177,190,43,68,184,190,216,128,190,190,42,181,196,190,219,224,202,190,165,3,209,190,69,29,215,190,117,45,221,190,241,51,227,190,118,48,233,190,192,34,239,190,141,10,245,190,155,231,250,190,211,92,0,191,56,64,3,191,219,29,6,191,155,245,8,191,90,199,11,191,247,146,14,191,84,88,17,191,80,23,20,191,205,207,22,191,172,129,25,191,208,44,28,191,26,209,30,191,109,110,33,191,171,4,36,191,183,147,38,191,116,27,41,191,199,155,43,191,147,20,46,191,187,133,48,191,38,239,50,191,183,80,53,191,85,170,55,191,227,251,57,191,74,69,60,191,110,134,62,191,55,191,64,191,139,239,66,191,83,23,69,191,117,54,71,191,218,76,73,191,107,90,75,191,16,95,77,191,179,90,79,191,62,77,81,191,154,54,83,191,179,22,85,191,114,237,86,191,197,186,88,191,149,126,90,191,208,56,92,191,98,233,93,191,56,144,95,191,64,45,97,191,103,192,98,191,156,73,100,191,206,200,101,191,235,61,103,191,227,168,104,191,167,9,106,191,39,96,107,191,84,172,108,191,31,238,109,191,122,37,111,191,88,82,112,191,171,116,113,191,103,140,114,191,127,153,115,191,231,155,116,191,149,147,117,191,126,128,118,191,150,98,119,191,212,57,120,191,47,6,121,191,158,199,121,191,23,126,122,191,148,41,123,191,13,202,123,191,122,95,124,191,213,233,124,191,24,105,125,191,62,221,125,191,64,70,126,191,28,164,126,191,204,246,126,191,77,62,127,191,156,122,127,191,182,171,127,191,153,209,127,191,67,236,127,191,180,251,127,191,166,255,127,63,148,227,127,63,156,154,127,63,204,36,127,63,56,130,126,63,253,178,125,63,63,183,124,63,42,143,123,63,243,58,122,63,212,186,120,63,17,15,119,63,246,55,117,63,213,53,115,63,8,9,113,63,241,177,110,63,249,48,108,63,144,134,105,63,47,179,102,63,83,183,99,63,132,147,96,63,78,72,93,63,69,214,89,63,3,62,86,63,43,128,82,63,101,157,78,63,94,150,74,63,204,107,70,63,106,30,66,63,249,174,61,63,64,30,57,63,13,109,52,63,50,156,47,63,135,172,42,63,235,158,37,63,63,116,32,63,109,45,27,63,97,203,21,63,13,79,16,63,104,185,10,63,107,11,5,63,46,140,254,62,221,212,242,62,241,242,230,62,127,232,218,62,166,183,206,62,136,98,194,62,78,235,181,62,42,84,169,62,81,159,156,62,253,206,143,62,109,229,130,62,206,201,107,62,98,159,81,62,48,80,55,62,211,224,28,62,241,85,2,62,98,104,207,61,124,0,154,61,36,251,72,61,27,164,187,60,243,119,86,187,100,61,241,188,187,192,99,189,103,93,167,189,20,189,220,189,3,251,8,190,115,127,35,190,52,231,61,190,164,45,88,190,38,78,114,190,18,34,134,190,137,5,147,190,52,207,159,190,213,124,172,190,51,12,185,190,26,123,197,190,91,199,209,190,205,238,221,190,80,239,233,190,199,198,245,190,144,185,0,191,38,121,6,191,36,33,12,191,141,176,17,191,102,38,23,191,186,129,28,191,152,193,33,191,21,229,38,191,74,235,43,191,86,211,48,191,91,156,53,191,131,69,58,191,253,205,62,191,252,52,67,191,188,121,71,191,125,155,75,191,132,153,79,191,31,115,83,191,161,39,87,191,99,182,90,191,198,30,94,191,48,96,97,191,15,122,100,191,216,107,103,191,7,53,106,191,31,213,108,191,169,75,111,191,55,152,113,191,98,186,115,191,201,177,117,191,22,126,119,191,246,30,121,191,33,148,122,191,85,221,123,191,89,250,124,191,250,234,125,191,14,175,126,191,116,70,127,191,15,177,127,191,206,238,127,191,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,41,0,41,0,41,0,82,0,82,0,123,0,164,0,200,0,222,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,0,41,0,41,0,41,0,123,0,123,0,123,0,164,0,164,0,240,0,10,1,27,1,39,1,41,0,41,0,41,0,41,0,41,0,41,0,41,0,41,0,123,0,123,0,123,0,123,0,240,0,240,0,240,0,10,1,10,1,49,1,62,1,72,1,80,1,123,0,123,0,123,0,123,0,123,0,123,0,123,0,123,0,240,0,240,0,240,0,240,0,49,1,49,1,49,1,62,1,62,1,87,1,95,1,102,1,108,1,240,0,240,0,240,0,240,0,240,0,240,0,240,0,240,0,49,1,49,1,49,1,49,1,87,1,87,1,87,1,95,1,95,1,114,1,120,1,126,1,131,1,0,0,0,0,0,0,40,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,40,15,23,28,31,34,36,38,39,41,42,43,44,45,46,47,47,49,50,51,52,53,54,55,55,57,58,59,60,61,62,63,63,65,66,67,68,69,70,71,71,40,20,33,41,48,53,57,61,64,66,69,71,73,75,76,78,80,82,85,87,89,91,92,94,96,98,101,103,105,107,108,110,112,114,117,119,121,123,124,126,128,40,23,39,51,60,67,73,79,83,87,91,94,97,100,102,105,107,111,115,118,121,124,126,129,131,135,139,142,145,148,150,153,155,159,163,166,169,172,174,177,179,35,28,49,65,78,89,99,107,114,120,126,132,136,141,145,149,153,159,165,171,176,180,185,189,192,199,205,211,216,220,225,229,232,239,245,251,21,33,58,79,97,112,125,137,148,157,166,174,182,189,195,201,207,217,227,235,243,251,17,35,63,86,106,123,139,152,165,177,187,197,206,214,222,230,237,250,25,31,55,75,91,105,117,128,138,146,154,161,168,174,180,185,190,200,208,215,222,229,235,240,245,255,16,36,65,89,110,128,144,159,173,185,196,207,217,226,234,242,250,11,41,74,103,128,151,172,191,209,225,241,255,9,43,79,110,138,163,186,207,227,246,12,39,71,99,123,144,164,182,198,214,228,241,253,9,44,81,113,142,168,192,214,235,255,7,49,90,127,160,191,220,247,6,51,95,134,170,203,234,7,47,87,123,155,184,212,237,6,52,97,137,174,208,240,5,57,106,151,192,231,5,59,111,158,202,243,5,55,103,147,187,224,5,60,113,161,206,248,4,65,122,175,224,4,67,127,182,234,224,224,224,224,224,224,224,224,160,160,160,160,185,185,185,178,178,168,134,61,37,224,224,224,224,224,224,224,224,240,240,240,240,207,207,207,198,198,183,144,66,40,160,160,160,160,160,160,160,160,185,185,185,185,193,193,193,183,183,172,138,64,38,240,240,240,240,240,240,240,240,207,207,207,207,204,204,204,193,193,180,143,66,40,185,185,185,185,185,185,185,185,193,193,193,193,193,193,193,183,183,172,138,65,39,207,207,207,207,207,207,207,207,204,204,204,204,201,201,201,188,188,176,141,66,40,193,193,193,193,193,193,193,193,193,193,193,193,194,194,194,184,184,173,139,65,39,204,204,204,204,204,204,204,204,201,201,201,201,198,198,198,187,187,175,140,66,40,0,0,12,0,24,0,36,0,48,0,4,0,16,0,28,0,40,0,52,0,8,0,20,0,32,0,44,0,56,0,1,0,13,0,25,0,37,0,49,0,5,0,17,0,29,0,41,0,53,0,9,0,21,0,33,0,45,0,57,0,2,0,14,0,26,0,38,0,50,0,6,0,18,0,30,0,42,0,54,0,10,0,22,0,34,0,46,0,58,0,3,0,15,0,27,0,39,0,51,0,7,0,19,0,31,0,43,0,55,0,11,0,23,0,35,0,47,0,59,0,0,0,128,63,0,0,0,128,99,250,127,63,191,117,86,188,139,233,127,63,10,113,214,188,121,205,127,63,231,206,32,189,47,166,127,63,58,94,86,189,175,115,127,63,19,242,133,189,249,53,127,63,42,175,160,189,18,237,126,63,51,101,187,189,253,152,126,63,4,19,214,189,188,57,126,63,115,183,240,189,85,207,125,63,168,168,5,190,203,89,125,63,187,239,18,190,37,217,124,63,92,48,32,190,103,77,124,63,245,105,45,190,152,182,123,63,243,155,58,190,190,20,123,63,194,197,71,190,226,103,122,63,205,230,84,190,9,176,121,63,130,254,97,190,60,237,120,63,77,12,111,190,132,31,120,63,156,15,124,190,234,70,119,63,238,131,132,190,119,99,118,63,62,250,138,190,54,117,117,63,117,106,145,190,48,124,116,63,76,212,151,190,113,120,115,63,122,55,158,190,3,106,114,63,183,147,164,190,244,80,113,63,188,232,170,190,79,45,112,63,65,54,177,190,33,255,110,63,1,124,183,190,118,198,109,63,180,185,189,190,94,131,108,63,21,239,195,190,231,53,107,63,222,27,202,190,30,222,105,63,201,63,208,190,18,124,104,63,146,90,214,190,212,15,103,63,243,107,220,190,116,153,101,63,170,115,226,190,1,25,100,63,113,113,232,190,141,142,98,63,7,101,238,190,40,250,96,63,39,78,244,190,230,91,95,63,144,44,250,190,215,179,93,63,0,0,0,191,15,2,92,63,27,228,2,191,160,70,90,63,119,194,5,191,158,129,88,63,246,154,8,191,29,179,86,63,119,109,11,191,49,219,84,63,218,57,14,191,239,249,82,63,0,0,17,191,108,15,81,63,202,191,19,191,189,27,79,63,24,121,22,191,248,30,77,63,205,43,25,191,52,25,75,63,202,215,27,191,136,10,73,63,241,124,30,191,10,243,70,63,36,27,33,191,209,210,68,63,70,178,35,191,247,169,66,63,58,66,38,191,147,120,64,63,227,202,40,191,189,62,62,63,37,76,43,191,143,252,59,63,227,197,45,191,34,178,57,63,1,56,48,191,144,95,55,63,101,162,50,191,243,4,53,63,243,4,53,191,101,162,50,63,144,95,55,191,1,56,48,63,34,178,57,191,227,197,45,63,143,252,59,191,37,76,43,63,189,62,62,191,227,202,40,63,147,120,64,191,58,66,38,63,247,169,66,191,70,178,35,63,209,210,68,191,36,27,33,63,10,243,70,191,241,124,30,63,136,10,73,191,202,215,27,63,52,25,75,191,205,43,25,63,248,30,77,191,24,121,22,63,189,27,79,191,202,191,19,63,108,15,81,191,0,0,17,63,239,249,82,191,218,57,14,63,49,219,84,191,119,109,11,63,29,179,86,191,246,154,8,63,158,129,88,191,119,194,5,63,160,70,90,191,27,228,2,63,15,2,92,191,0,0,0,63,215,179,93,191,144,44,250,62,230,91,95,191,39,78,244,62,40,250,96,191,7,101,238,62,141,142,98,191,113,113,232,62,1,25,100,191,170,115,226,62,116,153,101,191,243,107,220,62,212,15,103,191,146,90,214,62,18,124,104,191,201,63,208,62,30,222,105,191,222,27,202,62,231,53,107,191,21,239,195,62,94,131,108,191,180,185,189,62,118,198,109,191,1,124,183,62,33,255,110,191,65,54,177,62,79,45,112,191,188,232,170,62,244,80,113,191,183,147,164,62,3,106,114,191,122,55,158,62,113,120,115,191,76,212,151,62,48,124,116,191,117,106,145,62,54,117,117,191,62,250,138,62,119,99,118,191,238,131,132,62,234,70,119,191,156,15,124,62,132,31,120,191,77,12,111,62,60,237,120,191,130,254,97,62,9,176,121,191,205,230,84,62,226,103,122,191,194,197,71,62,190,20,123,191,243,155,58,62,152,182,123,191,245,105,45,62,103,77,124,191,92,48,32,62,37,217,124,191,187,239,18,62,203,89,125,191,168,168,5,62,85,207,125,191,115,183,240,61,188,57,126,191,4,19,214,61,253,152,126,191,51,101,187,61,18,237,126,191,42,175,160,61,249,53,127,191,19,242,133,61,175,115,127,191,58,94,86,61,47,166,127,191,231,206,32,61,121,205,127,191,10,113,214,60,139,233,127,191,191,117,86,60,99,250,127,191,0,48,141,36,0,0,128,191,191,117,86,188,99,250,127,191,10,113,214,188,139,233,127,191,231,206,32,189,121,205,127,191,58,94,86,189,47,166,127,191,19,242,133,189,175,115,127,191,42,175,160,189,249,53,127,191,51,101,187,189,18,237,126,191,4,19,214,189,253,152,126,191,115,183,240,189,188,57,126,191,168,168,5,190,85,207,125,191,187,239,18,190,203,89,125,191,92,48,32,190,37,217,124,191,245,105,45,190,103,77,124,191,243,155,58,190,152,182,123,191,194,197,71,190,190,20,123,191,205,230,84,190,226,103,122,191,130,254,97,190,9,176,121,191,77,12,111,190,60,237,120,191,156,15,124,190,132,31,120,191,238,131,132,190,234,70,119,191,62,250,138,190,119,99,118,191,117,106,145,190,54,117,117,191,76,212,151,190,48,124,116,191,122,55,158,190,113,120,115,191,183,147,164,190,3,106,114,191,188,232,170,190,244,80,113,191,65,54,177,190,79,45,112,191,1,124,183,190,33,255,110,191,180,185,189,190,118,198,109,191,21,239,195,190,94,131,108,191,222,27,202,190,231,53,107,191,201,63,208,190,30,222,105,191,146,90,214,190,18,124,104,191,243,107,220,190,212,15,103,191,170,115,226,190,116,153,101,191,113,113,232,190,1,25,100,191,7,101,238,190,141,142,98,191,39,78,244,190,40,250,96,191,144,44,250,190,230,91,95,191,0,0,0,191,215,179,93,191,27,228,2,191,15,2,92,191,119,194,5,191,160,70,90,191,246,154,8,191,158,129,88,191,119,109,11,191,29,179,86,191,218,57,14,191,49,219,84,191,0,0,17,191,239,249,82,191,202,191,19,191,108,15,81,191,24,121,22,191,189,27,79,191,205,43,25,191,248,30,77,191,202,215,27,191,52,25,75,191,241,124,30,191,136,10,73,191,36,27,33,191,10,243,70,191,70,178,35,191,209,210,68,191,58,66,38,191,247,169,66,191,227,202,40,191,147,120,64,191,37,76,43,191,189,62,62,191,227,197,45,191,143,252,59,191,1,56,48,191,34,178,57,191,101,162,50,191,144,95,55,191,243,4,53,191,243,4,53,191,144,95,55,191,101,162,50,191,34,178,57,191,1,56,48,191,143,252,59,191,227,197,45,191,189,62,62,191,37,76,43,191,147,120,64,191,227,202,40,191,247,169,66,191,58,66,38,191,209,210,68,191,70,178,35,191,10,243,70,191,36,27,33,191,136,10,73,191,241,124,30,191,52,25,75,191,202,215,27,191,248,30,77,191,205,43,25,191,189,27,79,191,24,121,22,191,108,15,81,191,202,191,19,191,239,249,82,191,0,0,17,191,49,219,84,191,218,57,14,191,29,179,86,191,119,109,11,191,158,129,88,191,246,154,8,191,160,70,90,191,119,194,5,191,15,2,92,191,27,228,2,191,215,179,93,191,0,0,0,191,230,91,95,191,144,44,250,190,40,250,96,191,39,78,244,190,141,142,98,191,7,101,238,190,1,25,100,191,113,113,232,190,116,153,101,191,170,115,226,190,212,15,103,191,243,107,220,190,18,124,104,191,146,90,214,190,30,222,105,191,201,63,208,190,231,53,107,191,222,27,202,190,94,131,108,191,21,239,195,190,118,198,109,191,180,185,189,190,33,255,110,191,1,124,183,190,79,45,112,191,65,54,177,190,244,80,113,191,188,232,170,190,3,106,114,191,183,147,164,190,113,120,115,191,122,55,158,190,48,124,116,191,76,212,151,190,54,117,117,191,117,106,145,190,119,99,118,191,62,250,138,190,234,70,119,191,238,131,132,190,132,31,120,191,156,15,124,190,60,237,120,191,77,12,111,190,9,176,121,191,130,254,97,190,226,103,122,191,205,230,84,190,190,20,123,191,194,197,71,190,152,182,123,191,243,155,58,190,103,77,124,191,245,105,45,190,37,217,124,191,92,48,32,190,203,89,125,191,187,239,18,190,85,207,125,191,168,168,5,190,188,57,126,191,115,183,240,189,253,152,126,191,4,19,214,189,18,237,126,191,51,101,187,189,249,53,127,191,42,175,160,189,175,115,127,191,19,242,133,189,47,166,127,191,58,94,86,189,121,205,127,191,231,206,32,189,139,233,127,191,10,113,214,188,99,250,127,191,191,117,86,188,0,0,128,191,0,48,13,165,99,250,127,191,191,117,86,60,139,233,127,191,10,113,214,60,121,205,127,191,231,206,32,61,47,166,127,191,58,94,86,61,175,115,127,191,19,242,133,61,249,53,127,191,42,175,160,61,18,237,126,191,51,101,187,61,253,152,126,191,4,19,214,61,188,57,126,191,115,183,240,61,85,207,125,191,168,168,5,62,203,89,125,191,187,239,18,62,37,217,124,191,92,48,32,62,103,77,124,191,245,105,45,62,152,182,123,191,243,155,58,62,190,20,123,191,194,197,71,62,226,103,122,191,205,230,84,62,9,176,121,191,130,254,97,62,60,237,120,191,77,12,111,62,132,31,120,191,156,15,124,62,234,70,119,191,238,131,132,62,119,99,118,191,62,250,138,62,54,117,117,191,117,106,145,62,48,124,116,191,76,212,151,62,113,120,115,191,122,55,158,62,3,106,114,191,183,147,164,62,244,80,113,191,188,232,170,62,79,45,112,191,65,54,177,62,33,255,110,191,1,124,183,62,118,198,109,191,180,185,189,62,94,131,108,191,21,239,195,62,231,53,107,191,222,27,202,62,30,222,105,191,201,63,208,62,18,124,104,191,146,90,214,62,212,15,103,191,243,107,220,62,116,153,101,191,170,115,226,62,1,25,100,191,113,113,232,62,141,142,98,191,7,101,238,62,40,250,96,191,39,78,244,62,230,91,95,191,144,44,250,62,215,179,93,191,0,0,0,63,15,2,92,191,27,228,2,63,160,70,90,191,119,194,5,63,158,129,88,191,246,154,8,63,29,179,86,191,119,109,11,63,49,219,84,191,218,57,14,63,239,249,82,191,0,0,17,63,108,15,81,191,202,191,19,63,189,27,79,191,24,121,22,63,248,30,77,191,205,43,25,63,52,25,75,191,202,215,27,63,136,10,73,191,241,124,30,63,10,243,70,191,36,27,33,63,209,210,68,191,70,178,35,63,247,169,66,191,58,66,38,63,147,120,64,191,227,202,40,63,189,62,62,191,37,76,43,63,143,252,59,191,227,197,45,63,34,178,57,191,1,56,48,63,144,95,55,191,101,162,50,63,243,4,53,191,243,4,53,63,101,162,50,191,144,95,55,63,1,56,48,191,34,178,57,63,227,197,45,191,143,252,59,63,37,76,43,191,189,62,62,63,227,202,40,191,147,120,64,63,58,66,38,191,247,169,66,63,70,178,35,191,209,210,68,63,36,27,33,191,10,243,70,63,241,124,30,191,136,10,73,63,202,215,27,191,52,25,75,63,205,43,25,191,248,30,77,63,24,121,22,191,189,27,79,63,202,191,19,191,108,15,81,63,0,0,17,191,239,249,82,63,218,57,14,191,49,219,84,63,119,109,11,191,29,179,86,63,246,154,8,191,158,129,88,63,119,194,5,191,160,70,90,63,27,228,2,191,15,2,92,63,0,0,0,191,215,179,93,63,144,44,250,190,230,91,95,63,39,78,244,190,40,250,96,63,7,101,238,190,141,142,98,63,113,113,232,190,1,25,100,63,170,115,226,190,116,153,101,63,243,107,220,190,212,15,103,63,146,90,214,190,18,124,104,63,201,63,208,190,30,222,105,63,222,27,202,190,231,53,107,63,21,239,195,190,94,131,108,63,180,185,189,190,118,198,109,63,1,124,183,190,33,255,110,63,65,54,177,190,79,45,112,63,188,232,170,190,244,80,113,63,183,147,164,190,3,106,114,63,122,55,158,190,113,120,115,63,76,212,151,190,48,124,116,63,117,106,145,190,54,117,117,63,62,250,138,190,119,99,118,63,238,131,132,190,234,70,119,63,156,15,124,190,132,31,120,63,77,12,111,190,60,237,120,63,130,254,97,190,9,176,121,63,205,230,84,190,226,103,122,63,194,197,71,190,190,20,123,63,243,155,58,190,152,182,123,63,245,105,45,190,103,77,124,63,92,48,32,190,37,217,124,63,187,239,18,190,203,89,125,63,168,168,5,190,85,207,125,63,115,183,240,189,188,57,126,63,4,19,214,189,253,152,126,63,51,101,187,189,18,237,126,63,42,175,160,189,249,53,127,63,19,242,133,189,175,115,127,63,58,94,86,189,47,166,127,63,231,206,32,189,121,205,127,63,10,113,214,188,139,233,127,63,191,117,86,188,99,250,127,63,0,200,83,165,0,0,128,63,191,117,86,60,99,250,127,63,10,113,214,60,139,233,127,63,231,206,32,61,121,205,127,63,58,94,86,61,47,166,127,63,19,242,133,61,175,115,127,63,42,175,160,61,249,53,127,63,51,101,187,61,18,237,126,63,4,19,214,61,253,152,126,63,115,183,240,61,188,57,126,63,168,168,5,62,85,207,125,63,187,239,18,62,203,89,125,63,92,48,32,62,37,217,124,63,245,105,45,62,103,77,124,63,243,155,58,62,152,182,123,63,194,197,71,62,190,20,123,63,205,230,84,62,226,103,122,63,130,254,97,62,9,176,121,63,77,12,111,62,60,237,120,63,156,15,124,62,132,31,120,63,238,131,132,62,234,70,119,63,62,250,138,62,119,99,118,63,117,106,145,62,54,117,117,63,76,212,151,62,48,124,116,63,122,55,158,62,113,120,115,63,183,147,164,62,3,106,114,63,188,232,170,62,244,80,113,63,65,54,177,62,79,45,112,63,1,124,183,62,33,255,110,63,180,185,189,62,118,198,109,63,21,239,195,62,94,131,108,63,222,27,202,62,231,53,107,63,201,63,208,62,30,222,105,63,146,90,214,62,18,124,104,63,243,107,220,62,212,15,103,63,170,115,226,62,116,153,101,63,113,113,232,62,1,25,100,63,7,101,238,62,141,142,98,63,39,78,244,62,40,250,96,63,144,44,250,62,230,91,95,63,0,0,0,63,215,179,93,63,27,228,2,63,15,2,92,63,119,194,5,63,160,70,90,63,246,154,8,63,158,129,88,63,119,109,11,63,29,179,86,63,218,57,14,63,49,219,84,63,0,0,17,63,239,249,82,63,202,191,19,63,108,15,81,63,24,121,22,63,189,27,79,63,205,43,25,63,248,30,77,63,202,215,27,63,52,25,75,63,241,124,30,63,136,10,73,63,36,27,33,63,10,243,70,63,70,178,35,63,209,210,68,63,58,66,38,63,247,169,66,63,227,202,40,63,147,120,64,63,37,76,43,63,189,62,62,63,227,197,45,63,143,252,59,63,1,56,48,63,34,178,57,63,101,162,50,63,144,95,55,63,243,4,53,63,243,4,53,63,144,95,55,63,101,162,50,63,34,178,57,63,1,56,48,63,143,252,59,63,227,197,45,63,189,62,62,63,37,76,43,63,147,120,64,63,227,202,40,63,247,169,66,63,58,66,38,63,209,210,68,63,70,178,35,63,10,243,70,63,36,27,33,63,136,10,73,63,241,124,30,63,52,25,75,63,202,215,27,63,248,30,77,63,205,43,25,63,189,27,79,63,24,121,22,63,108,15,81,63,202,191,19,63,239,249,82,63,0,0,17,63,49,219,84,63,218,57,14,63,29,179,86,63,119,109,11,63,158,129,88,63,246,154,8,63,160,70,90,63,119,194,5,63,15,2,92,63,27,228,2,63,215,179,93,63,0,0,0,63,230,91,95,63,144,44,250,62,40,250,96,63,39,78,244,62,141,142,98,63,7,101,238,62,1,25,100,63,113,113,232,62,116,153,101,63,170,115,226,62,212,15,103,63,243,107,220,62,18,124,104,63,146,90,214,62,30,222,105,63,201,63,208,62,231,53,107,63,222,27,202,62,94,131,108,63,21,239,195,62,118,198,109,63,180,185,189,62,33,255,110,63,1,124,183,62,79,45,112,63,65,54,177,62,244,80,113,63,188,232,170,62,3,106,114,63,183,147,164,62,113,120,115,63,122,55,158,62,48,124,116,63,76,212,151,62,54,117,117,63,117,106,145,62,119,99,118,63,62,250,138,62,234,70,119,63,238,131,132,62,132,31,120,63,156,15,124,62,60,237,120,63,77,12,111,62,9,176,121,63,130,254,97,62,226,103,122,63,205,230,84,62,190,20,123,63,194,197,71,62,152,182,123,63,243,155,58,62,103,77,124,63,245,105,45,62,37,217,124,63,92,48,32,62,203,89,125,63,187,239,18,62,85,207,125,63,168,168,5,62,188,57,126,63,115,183,240,61,253,152,126,63,4,19,214,61,18,237,126,63,51,101,187,61,249,53,127,63,42,175,160,61,175,115,127,63,19,242,133,61,47,166,127,63,58,94,86,61,121,205,127,63,231,206,32,61,139,233,127,63,10,113,214,60,99,250,127,63,191,117,86,60,0,0,24,0,48,0,72,0,96,0,8,0,32,0,56,0,80,0,104,0,16,0,40,0,64,0,88,0,112,0,4,0,28,0,52,0,76,0,100,0,12,0,36,0,60,0,84,0,108,0,20,0,44,0,68,0,92,0,116,0,1,0,25,0,49,0,73,0,97,0,9,0,33,0,57,0,81,0,105,0,17,0,41,0,65,0,89,0,113,0,5,0,29,0,53,0,77,0,101,0,13,0,37,0,61,0,85,0,109,0,21,0,45,0,69,0,93,0,117,0,2,0,26,0,50,0,74,0,98,0,10,0,34,0,58,0,82,0,106,0,18,0,42,0,66,0,90,0,114,0,6,0,30,0,54,0,78,0,102,0,14,0,38,0,62,0,86,0,110,0,22,0,46,0,70,0,94,0,118,0,3,0,27,0,51,0,75,0,99,0,11,0,35,0,59,0,83,0,107,0,19,0,43,0,67,0,91,0,115,0,7,0,31,0,55,0,79,0,103,0,15,0,39,0,63,0,87,0,111,0,23,0,47,0,71,0,95,0,119,0,0,0,48,0,96,0,144,0,192,0,16,0,64,0,112,0,160,0,208,0,32,0,80,0,128,0,176,0,224,0,4,0,52,0,100,0,148,0,196,0,20,0,68,0,116,0,164,0,212,0,36,0,84,0,132,0,180,0,228,0,8,0,56,0,104,0,152,0,200,0,24,0,72,0,120,0,168,0,216,0,40,0,88,0,136,0,184,0,232,0,12,0,60,0,108,0,156,0,204,0,28,0,76,0,124,0,172,0,220,0,44,0,92,0,140,0,188,0,236,0,1,0,49,0,97,0,145,0,193,0,17,0,65,0,113,0,161,0,209,0,33,0,81,0,129,0,177,0,225,0,5,0,53,0,101,0,149,0,197,0,21,0,69,0,117,0,165,0,213,0,37,0,85,0,133,0,181,0,229,0,9,0,57,0,105,0,153,0,201,0,25,0,73,0,121,0,169,0,217,0,41,0,89,0,137,0,185,0,233,0,13,0,61,0,109,0,157,0,205,0,29,0,77,0,125,0,173,0,221,0,45,0,93,0,141,0,189,0,237,0,2,0,50,0,98,0,146,0,194,0,18,0,66,0,114,0,162,0,210,0,34,0,82,0,130,0,178,0,226,0,6,0,54,0,102,0,150,0,198,0,22,0,70,0,118,0,166,0,214,0,38,0,86,0,134,0,182,0,230,0,10,0,58,0,106,0,154,0,202,0,26,0,74,0,122,0,170,0,218,0,42,0,90,0,138,0,186,0,234,0,14,0,62,0,110,0,158,0,206,0,30,0,78,0,126,0,174,0,222,0,46,0,94,0,142,0,190,0,238,0,3,0,51,0,99,0,147,0,195,0,19,0,67,0,115,0,163,0,211,0,35,0,83,0,131,0,179,0,227,0,7,0,55,0,103,0,151,0,199,0,23,0,71,0,119,0,167,0,215,0,39,0,87,0,135,0,183,0,231,0,11,0,59,0,107,0,155,0,203,0,27,0,75,0,123,0,171,0,219,0,43,0,91,0,139,0,187,0,235,0,15,0,63,0,111,0,159,0,207,0,31,0,79,0,127,0,175,0,223,0,47,0,95,0,143,0,191,0,239,0,0,0,96,0,192,0,32,1,128,1,32,0,128,0,224,0,64,1,160,1,64,0,160,0,0,1,96,1,192,1,8,0,104,0,200,0,40,1,136,1,40,0,136,0,232,0,72,1,168,1,72,0,168,0,8,1,104,1,200,1,16,0,112,0,208,0,48,1,144,1,48,0,144,0,240,0,80,1,176,1,80,0,176,0,16,1,112,1,208,1,24,0,120,0,216,0,56,1,152,1,56,0,152,0,248,0,88,1,184,1,88,0,184,0,24,1,120,1,216,1,4,0,100,0,196,0,36,1,132,1,36,0,132,0,228,0,68,1,164,1,68,0,164,0,4,1,100,1,196,1,12,0,108,0,204,0,44,1,140,1,44,0,140,0,236,0,76,1,172,1,76,0,172,0,12,1,108,1,204,1,20,0,116,0,212,0,52,1,148,1,52,0,148,0,244,0,84,1,180,1,84,0,180,0,20,1,116,1,212,1,28,0,124,0,220,0,60,1,156,1,60,0,156,0,252,0,92,1,188,1,92,0,188,0,28,1,124,1,220,1,1,0,97,0,193,0,33,1,129,1,33,0,129,0,225,0,65,1,161,1,65,0,161,0,1,1,97,1,193,1,9,0,105,0,201,0,41,1,137,1,41,0,137,0,233,0,73,1,169,1,73,0,169,0,9,1,105,1,201,1,17,0,113,0,209,0,49,1,145,1,49,0,145,0,241,0,81,1,177,1,81,0,177,0,17,1,113,1,209,1,25,0,121,0,217,0,57,1,153,1,57,0,153,0,249,0,89,1,185,1,89,0,185,0,25,1,121,1,217,1,5,0,101,0,197,0,37,1,133,1,37,0,133,0,229,0,69,1,165,1,69,0,165,0,5,1,101,1,197,1,13,0,109,0,205,0,45,1,141,1,45,0,141,0,237,0,77,1,173,1,77,0,173,0,13,1,109,1,205,1,21,0,117,0,213,0,53,1,149,1,53,0,149,0,245,0,85,1,181,1,85,0,181,0,21,1,117,1,213,1,29,0,125,0,221,0,61,1,157,1,61,0,157,0,253,0,93,1,189,1,93,0,189,0,29,1,125,1,221,1,2,0,98,0,194,0,34,1,130,1,34,0,130,0,226,0,66,1,162,1,66,0,162,0,2,1,98,1,194,1,10,0,106,0,202,0,42,1,138,1,42,0,138,0,234,0,74,1,170,1,74,0,170,0,10,1,106,1,202,1,18,0,114,0,210,0,50,1,146,1,50,0,146,0,242,0,82,1,178,1,82,0,178,0,18,1,114,1,210,1,26,0,122,0,218,0,58,1,154,1,58,0,154,0,250,0,90,1,186,1,90,0,186,0,26,1,122,1,218,1,6,0,102,0,198,0,38,1,134,1,38,0,134,0,230,0,70,1,166,1,70,0,166,0,6,1,102,1,198,1,14,0,110,0,206,0,46,1,142,1,46,0,142,0,238,0,78,1,174,1,78,0,174,0,14,1,110,1,206,1,22,0,118,0,214,0,54,1,150,1,54,0,150,0,246,0,86,1,182,1,86,0,182,0,22,1,118,1,214,1,30,0,126,0,222,0,62,1,158,1,62,0,158,0,254,0,94,1,190,1,94,0,190,0,30,1,126,1,222,1,3,0,99,0,195,0,35,1,131,1,35,0,131,0,227,0,67,1,163,1,67,0,163,0,3,1,99,1,195,1,11,0,107,0,203,0,43,1,139,1,43,0,139,0,235,0,75,1,171,1,75,0,171,0,11,1,107,1,203,1,19,0,115,0,211,0,51,1,147,1,51,0,147,0,243,0,83,1,179,1,83,0,179,0,19,1,115,1,211,1,27,0,123,0,219,0,59,1,155,1,59,0,155,0,251,0,91,1,187,1,91,0,187,0,27,1,123,1,219,1,7,0,103,0,199,0,39,1,135,1,39,0,135,0,231,0,71,1,167,1,71,0,167,0,7,1,103,1,199,1,15,0,111,0,207,0,47,1,143,1,47,0,143,0,239,0,79,1,175,1,79,0,175,0,15,1,111,1,207,1,23,0,119,0,215,0,55,1,151,1,55,0,151,0,247,0,87,1,183,1,87,0,183,0,23,1,119,1,215,1,31,0,127,0,223,0,63,1,159,1,63,0,159,0,255,0,95,1,191,1,95,0,191,0,31,1,127,1,223,1,1],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE+10240);allocate([1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,3,0,0,0,5,0,0,0,7,0,0,0,9,0,0,0,11,0,0,0,13,0,0,0,15,0,0,0,17,0,0,0,19,0,0,0,21,0,0,0,23,0,0,0,25,0,0,0,27,0,0,0,29,0,0,0,31,0,0,0,33,0,0,0,35,0,0,0,37,0,0,0,39,0,0,0,41,0,0,0,43,0,0,0,45,0,0,0,47,0,0,0,49,0,0,0,51,0,0,0,53,0,0,0,55,0,0,0,57,0,0,0,59,0,0,0,61,0,0,0,63,0,0,0,65,0,0,0,67,0,0,0,69,0,0,0,71,0,0,0,73,0,0,0,75,0,0,0,77,0,0,0,79,0,0,0,81,0,0,0,83,0,0,0,85,0,0,0,87,0,0,0,89,0,0,0,91,0,0,0,93,0,0,0,95,0,0,0,97,0,0,0,99,0,0,0,101,0,0,0,103,0,0,0,105,0,0,0,107,0,0,0,109,0,0,0,111,0,0,0,113,0,0,0,115,0,0,0,117,0,0,0,119,0,0,0,121,0,0,0,123,0,0,0,125,0,0,0,127,0,0,0,129,0,0,0,131,0,0,0,133,0,0,0,135,0,0,0,137,0,0,0,139,0,0,0,141,0,0,0,143,0,0,0,145,0,0,0,147,0,0,0,149,0,0,0,151,0,0,0,153,0,0,0,155,0,0,0,157,0,0,0,159,0,0,0,161,0,0,0,163,0,0,0,165,0,0,0,167,0,0,0,169,0,0,0,171,0,0,0,173,0,0,0,175,0,0,0,177,0,0,0,179,0,0,0,181,0,0,0,183,0,0,0,185,0,0,0,187,0,0,0,189,0,0,0,191,0,0,0,193,0,0,0,195,0,0,0,197,0,0,0,199,0,0,0,201,0,0,0,203,0,0,0,205,0,0,0,207,0,0,0,209,0,0,0,211,0,0,0,213,0,0,0,215,0,0,0,217,0,0,0,219,0,0,0,221,0,0,0,223,0,0,0,225,0,0,0,227,0,0,0,229,0,0,0,231,0,0,0,233,0,0,0,235,0,0,0,237,0,0,0,239,0,0,0,241,0,0,0,243,0,0,0,245,0,0,0,247,0,0,0,249,0,0,0,251,0,0,0,253,0,0,0,255,0,0,0,1,1,0,0,3,1,0,0,5,1,0,0,7,1,0,0,9,1,0,0,11,1,0,0,13,1,0,0,15,1,0,0,17,1,0,0,19,1,0,0,21,1,0,0,23,1,0,0,25,1,0,0,27,1,0,0,29,1,0,0,31,1,0,0,33,1,0,0,35,1,0,0,37,1,0,0,39,1,0,0,41,1,0,0,43,1,0,0,45,1,0,0,47,1,0,0,49,1,0,0,51,1,0,0,53,1,0,0,55,1,0,0,57,1,0,0,59,1,0,0,61,1,0,0,63,1,0,0,65,1,0,0,67,1,0,0,69,1,0,0,71,1,0,0,73,1,0,0,75,1,0,0,77,1,0,0,79,1,0,0,81,1,0,0,83,1,0,0,85,1,0,0,87,1,0,0,89,1,0,0,91,1,0,0,93,1,0,0,95,1,0,0,13,0,0,0,25,0,0,0,41,0,0,0,61,0,0,0,85,0,0,0,113,0,0,0,145,0,0,0,181,0,0,0,221,0,0,0,9,1,0,0,57,1,0,0,109,1,0,0,165,1,0,0,225,1,0,0,33,2,0,0,101,2,0,0,173,2,0,0,249,2,0,0,73,3,0,0,157,3,0,0,245,3,0,0,81,4,0,0,177,4,0,0,21,5,0,0,125,5,0,0,233,5,0,0,89,6,0,0,205,6,0,0,69,7,0,0,193,7,0,0,65,8,0,0,197,8,0,0,77,9,0,0,217,9,0,0,105,10,0,0,253,10,0,0,149,11,0,0,49,12,0,0,209,12,0,0,117,13,0,0,29,14,0,0,201,14,0,0,121,15,0,0,45,16,0,0,229,16,0,0,161,17,0,0,97,18,0,0,37,19,0,0,237,19,0,0,185,20,0,0,137,21,0,0,93,22,0,0,53,23,0,0,17,24,0,0,241,24,0,0,213,25,0,0,189,26,0,0,169,27,0,0,153,28,0,0,141,29,0,0,133,30,0,0,129,31,0,0,129,32,0,0,133,33,0,0,141,34,0,0,153,35,0,0,169,36,0,0,189,37,0,0,213,38,0,0,241,39,0,0,17,41,0,0,53,42,0,0,93,43,0,0,137,44,0,0,185,45,0,0,237,46,0,0,37,48,0,0,97,49,0,0,161,50,0,0,229,51,0,0,45,53,0,0,121,54,0,0,201,55,0,0,29,57,0,0,117,58,0,0,209,59,0,0,49,61,0,0,149,62,0,0,253,63,0,0,105,65,0,0,217,66,0,0,77,68,0,0,197,69,0,0,65,71,0,0,193,72,0,0,69,74,0,0,205,75,0,0,89,77,0,0,233,78,0,0,125,80,0,0,21,82,0,0,177,83,0,0,81,85,0,0,245,86,0,0,157,88,0,0,73,90,0,0,249,91,0,0,173,93,0,0,101,95,0,0,33,97,0,0,225,98,0,0,165,100,0,0,109,102,0,0,57,104,0,0,9,106,0,0,221,107,0,0,181,109,0,0,145,111,0,0,113,113,0,0,85,115,0,0,61,117,0,0,41,119,0,0,25,121,0,0,13,123,0,0,5,125,0,0,1,127,0,0,1,129,0,0,5,131,0,0,13,133,0,0,25,135,0,0,41,137,0,0,61,139,0,0,85,141,0,0,113,143,0,0,145,145,0,0,181,147,0,0,221,149,0,0,9,152,0,0,57,154,0,0,109,156,0,0,165,158,0,0,225,160,0,0,33,163,0,0,101,165,0,0,173,167,0,0,249,169,0,0,73,172,0,0,157,174,0,0,245,176,0,0,81,179,0,0,177,181,0,0,21,184,0,0,125,186,0,0,233,188,0,0,89,191,0,0,205,193,0,0,69,196,0,0,193,198,0,0,65,201,0,0,197,203,0,0,77,206,0,0,217,208,0,0,105,211,0,0,253,213,0,0,149,216,0,0,49,219,0,0,209,221,0,0,117,224,0,0,29,227,0,0,201,229,0,0,121,232,0,0,45,235,0,0,229,237,0,0,161,240,0,0,63,0,0,0,129,0,0,0,231,0,0,0,121,1,0,0,63,2,0,0,65,3,0,0,135,4,0,0,25,6,0,0,255,7,0,0,65,10,0,0,231,12,0,0,249,15,0,0,127,19,0,0,129,23,0,0,7,28,0,0,25,33,0,0,191,38,0,0,1,45,0,0,231,51,0,0,121,59,0,0,191,67,0,0,193,76,0,0,135,86,0,0,25,97,0,0,127,108,0,0,193,120,0,0,231,133,0,0,249,147,0,0,255,162,0,0,1,179,0,0,7,196,0,0,25,214,0,0,63,233,0,0,129,253,0,0,231,18,1,0,121,41,1,0,63,65,1,0,65,90,1,0,135,116,1,0,25,144,1,0,255,172,1,0,65,203,1,0,231,234,1,0,249,11,2,0,127,46,2,0,129,82,2,0,7,120,2,0,25,159,2,0,191,199,2,0,1,242,2,0,231,29,3,0,121,75,3,0,191,122,3,0,193,171,3,0,135,222,3,0,25,19,4,0,127,73,4,0,193,129,4,0,231,187,4,0,249,247,4,0,255,53,5,0,1,118,5,0,7,184,5,0,25,252,5,0,63,66,6,0,129,138,6,0,231,212,6,0,121,33,7,0,63,112,7,0,65,193,7,0,135,20,8,0,25,106,8,0,255,193,8,0,65,28,9,0,231,120,9,0,249,215,9,0,127,57,10,0,129,157,10,0,7,4,11,0,25,109,11,0,191,216,11,0,1,71,12,0,231,183,12,0,121,43,13,0,191,161,13,0,193,26,14,0,135,150,14,0,25,21,15,0,127,150,15,0,193,26,16,0,231,161,16,0,249,43,17,0,255,184,17,0,1,73,18,0,7,220,18,0,25,114,19,0,63,11,20,0,129,167,20,0,231,70,21,0,121,233,21,0,63,143,22,0,65,56,23,0,135,228,23,0,25,148,24,0,255,70,25,0,65,253,25,0,231,182,26,0,249,115,27,0,127,52,28,0,129,248,28,0,7,192,29,0,25,139,30,0,191,89,31,0,1,44,32,0,231,1,33,0,121,219,33,0,191,184,34,0,193,153,35,0,135,126,36,0,25,103,37,0,127,83,38,0,193,67,39,0,231,55,40,0,249,47,41,0,255,43,42,0,1,44,43,0,7,48,44,0,25,56,45,0,63,68,46,0,129,84,47,0,231,104,48,0,121,129,49,0,63,158,50,0,65,191,51,0,135,228,52,0,25,14,54,0,255,59,55,0,65,110,56,0,231,164,57,0,249,223,58,0,127,31,60,0,129,99,61,0,7,172,62,0,25,249,63,0,191,74,65,0,1,161,66,0,231,251,67,0,121,91,69,0,191,191,70,0,193,40,72,0,135,150,73,0,25,9,75,0,127,128,76,0,193,252,77,0,231,125,79,0,249,3,81,0,255,142,82,0,1,31,84,0,7,180,85,0,25,78,87,0,63,237,88,0,129,145,90,0,231,58,92,0,121,233,93,0,63,157,95,0,65,86,97,0,135,20,99,0,25,216,100,0,255,160,102,0,65,111,104,0,231,66,106,0,249,27,108,0,127,250,109,0,65,1,0,0,169,2,0,0,9,5,0,0,193,8,0,0,65,14,0,0,9,22,0,0,169,32,0,0,193,46,0,0,1,65,0,0,41,88,0,0,9,117,0,0,129,152,0,0,129,195,0,0,9,247,0,0,41,52,1,0,1,124,1,0,193,207,1,0,169,48,2,0,9,160,2,0,65,31,3,0,193,175,3,0,9,83,4,0,169,10,5,0,65,216,5,0,129,189,6,0,41,188,7,0,9,214,8,0,1,13,10,0,1,99,11,0,9,218,12,0,41,116,14,0,129,51,16,0,65,26,18,0,169,42,20,0,9,103,22,0,193,209,24,0,65,109,27,0,9,60,30,0,169,64,33,0,193,125,36,0,1,246,39,0,41,172,43,0,9,163,47,0,129,221,51,0,129,94,56,0,9,41,61,0,41,64,66,0,1,167,71,0,193,96,77,0,169,112,83,0,9,218,89,0,65,160,96,0,193,198,103,0,9,81,111,0,169,66,119,0,65,159,127,0,129,106,136,0,41,168,145,0,9,92,155,0,1,138,165,0,1,54,176,0,9,100,187,0,41,24,199,0,129,86,211,0,65,35,224,0,169,130,237,0,9,121,251,0,193,10,10,1,65,60,25,1,9,18,41,1,169,144,57,1,193,188,74,1,1,155,92,1,41,48,111,1,9,129,130,1,129,146,150,1,129,105,171,1,9,11,193,1,41,124,215,1,1,194,238,1,193,225,6,2,169,224,31,2,9,196,57,2,65,145,84,2,193,77,112,2,9,255,140,2,169,170,170,2,65,86,201,2,129,7,233,2,41,196,9,3,9,146,43,3,1,119,78,3,1,121,114,3,9,158,151,3,41,236,189,3,129,105,229,3,65,28,14,4,169,10,56,4,9,59,99,4,193,179,143,4,65,123,189,4,9,152,236,4,169,16,29,5,193,235,78,5,1,48,130,5,41,228,182,5,9,15,237,5,129,183,36,6,129,228,93,6,9,157,152,6,41,232,212,6,1,205,18,7,193,82,82,7,169,128,147,7,9,94,214,7,65,242,26,8,193,68,97,8,9,93,169,8,169,66,243,8,65,253,62,9,129,148,140,9,41,16,220,9,9,120,45,10,1,212,128,10,1,44,214,10,9,136,45,11,41,240,134,11,129,108,226,11,65,5,64,12,169,194,159,12,9,173,1,13,193,204,101,13,65,42,204,13,9,206,52,14,169,192,159,14,193,10,13,15,1,181,124,15,41,200,238,15,9,77,99,16,129,76,218,16,129,207,83,17,9,223,207,17,41,132,78,18,1,200,207,18,193,179,83,19,169,80,218,19,9,168,99,20,65,195,239,20,193,171,126,21,9,107,16,22,169,10,165,22,65,148,60,23,129,17,215,23,41,140,116,24,9,14,21,25,1,161,184,25,1,79,95,26,9,34,9,27,41,36,182,27,129,95,102,28,65,222,25,29,169,170,208,29,9,207,138,30,193,85,72,31,65,73,9,32,9,180,205,32,169,160,149,33,193,25,97,34,1,42,48,35,41,220,2,36,9,59,217,36,129,81,179,37,147,6,0,0,69,14,0,0,15,28,0,0,17,51,0,0,91,87,0,0,13,142,0,0,119,221,0,0,57,77,1,0,99,230,1,0,149,179,2,0,31,193,3,0,33,29,5,0,171,215,6,0,221,2,9,0,7,179,11,0,201,254,14,0,51,255,18,0,229,207,23,0,47,143,29,0,49,94,36,0,251,96,44,0,173,190,53,0,151,161,64,0,89,55,77,0,3,177,91,0,53,67,108,0,63,38,127,0,65,150,148,0,75,211,172,0,125,33,200,0,39,201,230,0,233,22,9,1,211,91,47,1,133,237,89,1,79,38,137,1,81,101,189,1,155,14,247,1,77,139,54,2,183,73,124,2,121,189,200,2,163,95,28,3,213,174,119,3,95,47,219,3,97,107,71,4,235,242,188,4,29,92,60,5,71,67,198,5,9,75,91,6,115,28,252,6,37,103,169,7,111,225,99,8,113,72,44,9,59,96,3,10,237,243,233,10,215,213,224,11,153,223,232,12,67,242,2,14,117,246,47,15,127,220,112,16,129,156,198,17,139,54,50,19,189,178,180,20,103,33,79,22,41,155,2,24,19,65,208,25,197,60,185,27,143,192,190,29,145,7,226,31,219,85,36,34,141,248,134,36,247,69,11,39,185,157,178,41,227,104,126,44,21,26,112,47,159,45,137,50,161,41,203,53,43,158,55,57,93,37,208,60,135,99,150,64,73,7,140,68,179,201,178,72,101,110,12,77,175,195,154,81,177,162,95,86,123,239,92,91,45,153,148,96,23,154,8,102,217,247,186,107,131,195,173,113,181,25,227,119,191,34,93,126,29,35,0,0,113,77,0,0,145,156,0,0,253,38,1,0,101,12,2,0,233,119,3,0,153,162,5,0,53,214,8,0,45,112,13,0,225,228,19,0,33,195,28,0,237,183,40,0,117,146,56,0,89,72,77,0,41,250,103,0,37,248,137,0,61,199,180,0,81,38,234,0,177,19,44,1,221,210,124,1,133,242,222,1,201,82,85,2,185,43,227,2,21,20,140,3,77,8,84,4,193,113,63,5,65,46,83,6,205,151,148,7,149,140,9,9,57,119,184,10,73,87,168,12,5,202,224,14,93,19,106,17,49,39,77,20,209,178,147,23,189,38,72,27,165,192,117,31,169,149,40,36,217,156,109,41,245,185,82,47,109,200,230,53,161,166,57,61,97,65,92,69,173,159,96,78,181,238,89,88,25,142,92,99,105,28,126,111,229,131,213,124,255,189,0,0,1,168,1,0,143,107,3,0,241,158,6,0,63,35,12,0,193,61,21,0,143,182,35,0,241,252,57,0,255,81,91,0,1,250,139,0,15,117,209,0,113,191,50,1,63,154,184,1,193,220,109,2,15,207,95,3,113,142,158,4,255,123,61,6,1,182,83,8,143,156,252,10,241,97,88,14,63,167,140,18,193,37,197,23,143,101,52,30,241,129,20,38,255,251,167,47,1,156,58,59,15,98,34,73,113,134,192,89,63,138,130,109,193,88,227,132,1,14,4,0,145,33,9,0,17,44,19,0,65,238,37,0,65,79,71,0,145,67,128,0,17,247,221,0,1,70,115,1,1,146,90,2,17,1,184,3,145,53,188,5,65,143,167,8,65,6,206,12,17,178,155,18,145,15,154,26,1,26,118,37,1,76,7,52,145,158,87,71,17,157,172,96,65,166,145,129,35,81,22,0,197,158,50,0,23,185,107,0,153,246,216,0,107,137,160,1,13,196,254,2,31,1,80,5,33,217,29,9,51,108,48,15,213,162,164,24,167,103,8,39,41,253,125,60,123,181,231,91,29,119,29,137,175,160,45,201,173,142,123,0,137,230,25,1,57,150,94,2,61,22,216,4,181,99,119,9,225,40,198,17,33,3,52,32,117,72,130,56,125,87,87,96,191,91,175,2,129,216,39,6,247,132,94,13,233,254,173,27,127,139,235,54,129,183,229,104,23,3,156,193,193,12,255,14,57,106,133,34,25,238,145,75,129,120,43,158,51,225,9,84,0,64,202,69,27,76,255,82,130,90,179,98,162,107,96,117,0,1,1,1,2,3,3,3,2,3,3,3,2,3,3,3,0,3,12,15,48,51,60,63,192,195,204,207,240,243,252,255,1,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,3,0,0,0,6,0,0,0,1,0,0,0,5,0,0,0,2,0,0,0,15,0,0,0,0,0,0,0,8,0,0,0,7,0,0,0,12,0,0,0,3,0,0,0,11,0,0,0,4,0,0,0,14,0,0,0,1,0,0,0,9,0,0,0,6,0,0,0,13,0,0,0,2,0,0,0,10,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,112,117,115,32,100,101,99,111,100,105,110,103,32,101,114,114,111,114,44,32,99,111,100,101,32,37,100,10,0,0,0,79,112,117,115,72,101,97,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE+20692);var tempDoublePtr=Runtime.alignMemory(allocate(12,"i8",ALLOC_STATIC),8);assert(tempDoublePtr%8==0);function copyTempFloat(ptr){HEAP8[tempDoublePtr]=HEAP8[ptr];HEAP8[tempDoublePtr+1]=HEAP8[ptr+1];HEAP8[tempDoublePtr+2]=HEAP8[ptr+2];HEAP8[tempDoublePtr+3]=HEAP8[ptr+3]}function copyTempDouble(ptr){HEAP8[tempDoublePtr]=HEAP8[ptr];HEAP8[tempDoublePtr+1]=HEAP8[ptr+1];HEAP8[tempDoublePtr+2]=HEAP8[ptr+2];HEAP8[tempDoublePtr+3]=HEAP8[ptr+3];HEAP8[tempDoublePtr+4]=HEAP8[ptr+4];HEAP8[tempDoublePtr+5]=HEAP8[ptr+5];HEAP8[tempDoublePtr+6]=HEAP8[ptr+6];HEAP8[tempDoublePtr+7]=HEAP8[ptr+7]}Module["_bitshift64Ashr"]=_bitshift64Ashr;function _time(ptr){var ret=Date.now()/1e3|0;if(ptr){HEAP32[ptr>>2]=ret}return ret}var ___errno_state=0;function ___setErrNo(value){HEAP32[___errno_state>>2]=value;return value}var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};function _sysconf(name){switch(name){case 30:return PAGE_SIZE;case 85:return totalMemory/PAGE_SIZE;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:return 200809;case 79:return 0;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1e3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:{if(typeof navigator==="object")return navigator["hardwareConcurrency"]||1;return 1}}___setErrNo(ERRNO_CODES.EINVAL);return-1}var _llvm_ctlz_i32=true;function ___errno_location(){return ___errno_state}Module["_memset"]=_memset;function _ogvjs_callback_audio(buffers,channels,sampleCount){var HEAPU32=Module.HEAPU32;var HEAPF32=Module.HEAPF32;var outputBuffers=[];if(buffers!==0){var inPtr,inArray,outArray,i;for(var channel=0;channel<channels;channel++){inPtr=HEAPU32[buffers/4+channel];inArray=HEAPF32.subarray(inPtr/4,inPtr/4+sampleCount);outArray=new Float32Array(inArray);outputBuffers.push(outArray)}}Module.audioBuffer=outputBuffers}function _abort(){Module["abort"]()}var FS=undefined;var SOCKFS=undefined;function _send(fd,buf,len,flags){var sock=SOCKFS.getSocket(fd);if(!sock){___setErrNo(ERRNO_CODES.EBADF);return-1}return _write(fd,buf,len)}function _pwrite(fildes,buf,nbyte,offset){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{var slab=HEAP8;return FS.write(stream,slab,buf,nbyte,offset)}catch(e){FS.handleFSError(e);return-1}}function _write(fildes,buf,nbyte){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{var slab=HEAP8;return FS.write(stream,slab,buf,nbyte)}catch(e){FS.handleFSError(e);return-1}}function _fileno(stream){stream=FS.getStreamFromPtr(stream);if(!stream)return-1;return stream.fd}function _fwrite(ptr,size,nitems,stream){var bytesToWrite=nitems*size;if(bytesToWrite==0)return 0;var fd=_fileno(stream);var bytesWritten=_write(fd,ptr,bytesToWrite);if(bytesWritten==-1){var streamObj=FS.getStreamFromPtr(stream);if(streamObj)streamObj.error=true;return 0}else{return bytesWritten/size|0}}Module["_strlen"]=_strlen;function __reallyNegative(x){return x<0||x===0&&1/x===-Infinity}function __formatString(format,varargs){assert((varargs&3)===0);var textIndex=format;var argIndex=0;function getNextArg(type){var ret;argIndex=Runtime.prepVararg(argIndex,type);if(type==="double"){ret=(HEAP32[tempDoublePtr>>2]=HEAP32[varargs+argIndex>>2],HEAP32[tempDoublePtr+4>>2]=HEAP32[varargs+(argIndex+4)>>2],+HEAPF64[tempDoublePtr>>3]);argIndex+=8}else if(type=="i64"){ret=[HEAP32[varargs+argIndex>>2],HEAP32[varargs+(argIndex+4)>>2]];argIndex+=8}else{assert((argIndex&3)===0);type="i32";ret=HEAP32[varargs+argIndex>>2];argIndex+=4}return ret}var ret=[];var curr,next,currArg;while(1){var startTextIndex=textIndex;curr=HEAP8[textIndex>>0];if(curr===0)break;next=HEAP8[textIndex+1>>0];if(curr==37){var flagAlwaysSigned=false;var flagLeftAlign=false;var flagAlternative=false;var flagZeroPad=false;var flagPadSign=false;flagsLoop:while(1){switch(next){case 43:flagAlwaysSigned=true;break;case 45:flagLeftAlign=true;break;case 35:flagAlternative=true;break;case 48:if(flagZeroPad){break flagsLoop}else{flagZeroPad=true;break};case 32:flagPadSign=true;break;default:break flagsLoop}textIndex++;next=HEAP8[textIndex+1>>0]}var width=0;if(next==42){width=getNextArg("i32");textIndex++;next=HEAP8[textIndex+1>>0]}else{while(next>=48&&next<=57){width=width*10+(next-48);textIndex++;next=HEAP8[textIndex+1>>0]}}var precisionSet=false,precision=-1;if(next==46){precision=0;precisionSet=true;textIndex++;next=HEAP8[textIndex+1>>0];if(next==42){precision=getNextArg("i32");textIndex++}else{while(1){var precisionChr=HEAP8[textIndex+1>>0];if(precisionChr<48||precisionChr>57)break;precision=precision*10+(precisionChr-48);textIndex++}}next=HEAP8[textIndex+1>>0]}if(precision<0){precision=6;precisionSet=false}var argSize;switch(String.fromCharCode(next)){case"h":var nextNext=HEAP8[textIndex+2>>0];if(nextNext==104){textIndex++;argSize=1}else{argSize=2}break;case"l":var nextNext=HEAP8[textIndex+2>>0];if(nextNext==108){textIndex++;argSize=8}else{argSize=4}break;case"L":case"q":case"j":argSize=8;break;case"z":case"t":case"I":argSize=4;break;default:argSize=null}if(argSize)textIndex++;next=HEAP8[textIndex+1>>0];switch(String.fromCharCode(next)){case"d":case"i":case"u":case"o":case"x":case"X":case"p":{var signed=next==100||next==105;argSize=argSize||4;var currArg=getNextArg("i"+argSize*8);var origArg=currArg;var argText;if(argSize==8){currArg=Runtime.makeBigInt(currArg[0],currArg[1],next==117)}if(argSize<=4){var limit=Math.pow(256,argSize)-1;currArg=(signed?reSign:unSign)(currArg&limit,argSize*8)}var currAbsArg=Math.abs(currArg);var prefix="";if(next==100||next==105){if(argSize==8&&i64Math)argText=i64Math.stringify(origArg[0],origArg[1],null);else argText=reSign(currArg,8*argSize,1).toString(10)}else if(next==117){if(argSize==8&&i64Math)argText=i64Math.stringify(origArg[0],origArg[1],true);else argText=unSign(currArg,8*argSize,1).toString(10);currArg=Math.abs(currArg)}else if(next==111){argText=(flagAlternative?"0":"")+currAbsArg.toString(8)}else if(next==120||next==88){prefix=flagAlternative&&currArg!=0?"0x":"";if(argSize==8&&i64Math){if(origArg[1]){argText=(origArg[1]>>>0).toString(16);var lower=(origArg[0]>>>0).toString(16);while(lower.length<8)lower="0"+lower;argText+=lower}else{argText=(origArg[0]>>>0).toString(16)}}else if(currArg<0){currArg=-currArg;argText=(currAbsArg-1).toString(16);var buffer=[];for(var i=0;i<argText.length;i++){buffer.push((15-parseInt(argText[i],16)).toString(16))}argText=buffer.join("");while(argText.length<argSize*2)argText="f"+argText}else{argText=currAbsArg.toString(16)}if(next==88){prefix=prefix.toUpperCase();argText=argText.toUpperCase()}}else if(next==112){if(currAbsArg===0){argText="(nil)"}else{prefix="0x";argText=currAbsArg.toString(16)}}if(precisionSet){while(argText.length<precision){argText="0"+argText}}if(currArg>=0){if(flagAlwaysSigned){prefix="+"+prefix}else if(flagPadSign){prefix=" "+prefix}}if(argText.charAt(0)=="-"){prefix="-"+prefix;argText=argText.substr(1)}while(prefix.length+argText.length<width){if(flagLeftAlign){argText+=" "}else{if(flagZeroPad){argText="0"+argText}else{prefix=" "+prefix}}}argText=prefix+argText;argText.split("").forEach((function(chr){ret.push(chr.charCodeAt(0))}));break};case"f":case"F":case"e":case"E":case"g":case"G":{var currArg=getNextArg("double");var argText;if(isNaN(currArg)){argText="nan";flagZeroPad=false}else if(!isFinite(currArg)){argText=(currArg<0?"-":"")+"inf";flagZeroPad=false}else{var isGeneral=false;var effectivePrecision=Math.min(precision,20);if(next==103||next==71){isGeneral=true;precision=precision||1;var exponent=parseInt(currArg.toExponential(effectivePrecision).split("e")[1],10);if(precision>exponent&&exponent>=-4){next=(next==103?"f":"F").charCodeAt(0);precision-=exponent+1}else{next=(next==103?"e":"E").charCodeAt(0);precision--}effectivePrecision=Math.min(precision,20)}if(next==101||next==69){argText=currArg.toExponential(effectivePrecision);if(/[eE][-+]\d$/.test(argText)){argText=argText.slice(0,-1)+"0"+argText.slice(-1)}}else if(next==102||next==70){argText=currArg.toFixed(effectivePrecision);if(currArg===0&&__reallyNegative(currArg)){argText="-"+argText}}var parts=argText.split("e");if(isGeneral&&!flagAlternative){while(parts[0].length>1&&parts[0].indexOf(".")!=-1&&(parts[0].slice(-1)=="0"||parts[0].slice(-1)==".")){parts[0]=parts[0].slice(0,-1)}}else{if(flagAlternative&&argText.indexOf(".")==-1)parts[0]+=".";while(precision>effectivePrecision++)parts[0]+="0"}argText=parts[0]+(parts.length>1?"e"+parts[1]:"");if(next==69)argText=argText.toUpperCase();if(currArg>=0){if(flagAlwaysSigned){argText="+"+argText}else if(flagPadSign){argText=" "+argText}}}while(argText.length<width){if(flagLeftAlign){argText+=" "}else{if(flagZeroPad&&(argText[0]=="-"||argText[0]=="+")){argText=argText[0]+"0"+argText.slice(1)}else{argText=(flagZeroPad?"0":" ")+argText}}}if(next<97)argText=argText.toUpperCase();argText.split("").forEach((function(chr){ret.push(chr.charCodeAt(0))}));break};case"s":{var arg=getNextArg("i8*");var argLength=arg?_strlen(arg):"(null)".length;if(precisionSet)argLength=Math.min(argLength,precision);if(!flagLeftAlign){while(argLength<width--){ret.push(32)}}if(arg){for(var i=0;i<argLength;i++){ret.push(HEAPU8[arg++>>0])}}else{ret=ret.concat(intArrayFromString("(null)".substr(0,argLength),true))}if(flagLeftAlign){while(argLength<width--){ret.push(32)}}break};case"c":{if(flagLeftAlign)ret.push(getNextArg("i8"));while(--width>0){ret.push(32)}if(!flagLeftAlign)ret.push(getNextArg("i8"));break};case"n":{var ptr=getNextArg("i32*");HEAP32[ptr>>2]=ret.length;break};case"%":{ret.push(curr);break};default:{for(var i=startTextIndex;i<textIndex+2;i++){ret.push(HEAP8[i>>0])}}}textIndex+=2}else{ret.push(curr);textIndex+=1}}return ret}function _fprintf(stream,format,varargs){var result=__formatString(format,varargs);var stack=Runtime.stackSave();var ret=_fwrite(allocate(result,"i8",ALLOC_STACK),1,result.length,stream);Runtime.stackRestore(stack);return ret}function _printf(format,varargs){var result=__formatString(format,varargs);var string=intArrayToString(result);if(string[string.length-1]==="\n")string=string.substr(0,string.length-1);Module.print(string);return result.length}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest);return dest}Module["_memcpy"]=_memcpy;function _llvm_stackrestore(p){var self=_llvm_stacksave;var ret=self.LLVM_SAVEDSTACKS[p];self.LLVM_SAVEDSTACKS.splice(p,1);Runtime.stackRestore(ret)}var _cos=Math_cos;Module["_i64Add"]=_i64Add;var _fabs=Math_abs;var _floor=Math_floor;function _llvm_stacksave(){var self=_llvm_stacksave;if(!self.LLVM_SAVEDSTACKS){self.LLVM_SAVEDSTACKS=[]}self.LLVM_SAVEDSTACKS.push(Runtime.stackSave());return self.LLVM_SAVEDSTACKS.length-1}function _ogvjs_callback_init_audio(channels,rate){Module.audioFormat={channels:channels,rate:rate};Module.loadedMetadata=true}var _sqrt=Math_sqrt;var _atan2=Math_atan2;var _abs=Math_abs;function _sbrk(bytes){var self=_sbrk;if(!self.called){DYNAMICTOP=alignMemoryPage(DYNAMICTOP);self.called=true;assert(Runtime.dynamicAlloc);self.alloc=Runtime.dynamicAlloc;Runtime.dynamicAlloc=(function(){abort("cannot dynamically allocate, sbrk now has control")})}var ret=DYNAMICTOP;if(bytes!=0){var success=self.alloc(bytes);if(!success)return-1>>>0}return ret}var _exp=Math_exp;var _llvm_pow_f64=Math_pow;Module["_memmove"]=_memmove;___errno_state=Runtime.staticAlloc(4);HEAP32[___errno_state>>2]=0;STACK_BASE=STACKTOP=Runtime.alignMemory(STATICTOP);staticSealed=true;STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=DYNAMICTOP=Runtime.alignMemory(STACK_MAX);assert(DYNAMIC_BASE<TOTAL_MEMORY,"TOTAL_MEMORY not big enough for stack");var cttz_i8=allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0],"i8",ALLOC_DYNAMIC);function invoke_viiiiii(index,a1,a2,a3,a4,a5,a6){try{Module["dynCall_viiiiii"](index,a1,a2,a3,a4,a5,a6)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}Module.asmGlobalArg={"Math":Math,"Int8Array":Int8Array,"Int16Array":Int16Array,"Int32Array":Int32Array,"Uint8Array":Uint8Array,"Uint16Array":Uint16Array,"Uint32Array":Uint32Array,"Float32Array":Float32Array,"Float64Array":Float64Array,"NaN":NaN,"Infinity":Infinity};Module.asmLibraryArg={"abort":abort,"assert":assert,"invoke_viiiiii":invoke_viiiiii,"_fabs":_fabs,"_exp":_exp,"_llvm_pow_f64":_llvm_pow_f64,"_send":_send,"_atan2":_atan2,"___setErrNo":___setErrNo,"_llvm_stackrestore":_llvm_stackrestore,"_floor":_floor,"_pwrite":_pwrite,"__reallyNegative":__reallyNegative,"_sbrk":_sbrk,"_ogvjs_callback_init_audio":_ogvjs_callback_init_audio,"_fileno":_fileno,"_sysconf":_sysconf,"_emscripten_memcpy_big":_emscripten_memcpy_big,"_cos":_cos,"_llvm_stacksave":_llvm_stacksave,"_printf":_printf,"_ogvjs_callback_audio":_ogvjs_callback_audio,"_write":_write,"___errno_location":___errno_location,"_abort":_abort,"_fwrite":_fwrite,"_time":_time,"_fprintf":_fprintf,"_abs":_abs,"__formatString":__formatString,"_sqrt":_sqrt,"STACKTOP":STACKTOP,"STACK_MAX":STACK_MAX,"tempDoublePtr":tempDoublePtr,"ABORT":ABORT,"cttz_i8":cttz_i8};// EMSCRIPTEN_START_ASM
+var asm=(function(global,env,buffer) {
+"use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.tempDoublePtr|0;var l=env.ABORT|0;var m=env.cttz_i8|0;var n=0;var o=0;var p=0;var q=0;var r=global.NaN,s=global.Infinity;var t=0,u=0,v=0,w=0,x=0.0,y=0,z=0,A=0,B=0.0;var C=0;var D=0;var E=0;var F=0;var G=0;var H=0;var I=0;var J=0;var K=0;var L=0;var M=global.Math.floor;var N=global.Math.abs;var O=global.Math.sqrt;var P=global.Math.pow;var Q=global.Math.cos;var R=global.Math.sin;var S=global.Math.tan;var T=global.Math.acos;var U=global.Math.asin;var V=global.Math.atan;var W=global.Math.atan2;var X=global.Math.exp;var Y=global.Math.log;var Z=global.Math.ceil;var _=global.Math.imul;var $=global.Math.min;var aa=global.Math.clz32;var ba=env.abort;var ca=env.assert;var da=env.invoke_viiiiii;var ea=env._fabs;var fa=env._exp;var ga=env._llvm_pow_f64;var ha=env._send;var ia=env._atan2;var ja=env.___setErrNo;var ka=env._llvm_stackrestore;var la=env._floor;var ma=env._pwrite;var na=env.__reallyNegative;var oa=env._sbrk;var pa=env._ogvjs_callback_init_audio;var qa=env._fileno;var ra=env._sysconf;var sa=env._emscripten_memcpy_big;var ta=env._cos;var ua=env._llvm_stacksave;var va=env._printf;var wa=env._ogvjs_callback_audio;var xa=env._write;var ya=env.___errno_location;var za=env._abort;var Aa=env._fwrite;var Ba=env._time;var Ca=env._fprintf;var Da=env._abs;var Ea=env.__formatString;var Fa=env._sqrt;var Ga=0.0;
+// EMSCRIPTEN_START_FUNCS
+function kc(a,d,e){a=a|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;f=i;i=i+48|0;g=f+12|0;h=f+16|0;j=f+28|0;k=f+4|0;l=f+32|0;m=f+36|0;n=f+40|0;o=f+44|0;p=f+20|0;q=f+8|0;r=f;s=f+24|0;c[g>>2]=a;c[h>>2]=d;c[j>>2]=e;c[l>>2]=0;c[n>>2]=0;while(1){if((c[n>>2]|0)>=20)break;c[q>>2]=(b[c[g>>2]>>1]|0)-(b[c[h>>2]>>1]|0);c[l>>2]=0;c[k>>2]=1;while(1){if((c[k>>2]|0)>((c[j>>2]|0)-1|0))break;c[p>>2]=(b[(c[g>>2]|0)+(c[k>>2]<<1)>>1]|0)-((b[(c[g>>2]|0)+((c[k>>2]|0)-1<<1)>>1]|0)+(b[(c[h>>2]|0)+(c[k>>2]<<1)>>1]|0));if((c[p>>2]|0)<(c[q>>2]|0)){c[q>>2]=c[p>>2];c[l>>2]=c[k>>2]}c[k>>2]=(c[k>>2]|0)+1}c[p>>2]=32768-((b[(c[g>>2]|0)+((c[j>>2]|0)-1<<1)>>1]|0)+(b[(c[h>>2]|0)+(c[j>>2]<<1)>>1]|0));if((c[p>>2]|0)<(c[q>>2]|0)){c[q>>2]=c[p>>2];c[l>>2]=c[j>>2]}if((c[q>>2]|0)>=0){t=41;break}do if(!(c[l>>2]|0))b[c[g>>2]>>1]=b[c[h>>2]>>1]|0;else{if((c[l>>2]|0)==(c[j>>2]|0)){b[(c[g>>2]|0)+((c[j>>2]|0)-1<<1)>>1]=32768-(b[(c[h>>2]|0)+(c[j>>2]<<1)>>1]|0);break}c[r>>2]=0;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[l>>2]|0))break;c[r>>2]=(c[r>>2]|0)+(b[(c[h>>2]|0)+(c[m>>2]<<1)>>1]|0);c[m>>2]=(c[m>>2]|0)+1}c[r>>2]=(c[r>>2]|0)+(b[(c[h>>2]|0)+(c[l>>2]<<1)>>1]>>1);c[s>>2]=32768;c[m>>2]=c[j>>2];while(1){if((c[m>>2]|0)<=(c[l>>2]|0))break;c[s>>2]=(c[s>>2]|0)-(b[(c[h>>2]|0)+(c[m>>2]<<1)>>1]|0);c[m>>2]=(c[m>>2]|0)+-1}c[s>>2]=(c[s>>2]|0)-(b[(c[h>>2]|0)+(c[l>>2]<<1)>>1]>>1);e=((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)>>1)+((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)&1)|0;do if((c[r>>2]|0)>(c[s>>2]|0)){if((e|0)>(c[r>>2]|0)){u=c[r>>2]|0;break}if((((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)>>1)+((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)&1)|0)<(c[s>>2]|0)){u=c[s>>2]|0;break}else{u=((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)>>1)+((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)&1)|0;break}}else{if((e|0)>(c[s>>2]|0)){u=c[s>>2]|0;break}if((((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)>>1)+((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)&1)|0)<(c[r>>2]|0)){u=c[r>>2]|0;break}else{u=((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)>>1)+((b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]|0)&1)|0;break}}while(0);b[o>>1]=u;b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]=(b[o>>1]|0)-(b[(c[h>>2]|0)+(c[l>>2]<<1)>>1]>>1);b[(c[g>>2]|0)+(c[l>>2]<<1)>>1]=(b[(c[g>>2]|0)+((c[l>>2]|0)-1<<1)>>1]|0)+(b[(c[h>>2]|0)+(c[l>>2]<<1)>>1]|0)}while(0);c[n>>2]=(c[n>>2]|0)+1}if((t|0)==41){i=f;return}if((c[n>>2]|0)!=20){i=f;return}tc(c[g>>2]|0,c[j>>2]|0);n=(Rd(b[c[g>>2]>>1]|0,b[c[h>>2]>>1]|0)|0)&65535;b[c[g>>2]>>1]=n;c[k>>2]=1;while(1){if((c[k>>2]|0)>=(c[j>>2]|0))break;n=(Rd(b[(c[g>>2]|0)+(c[k>>2]<<1)>>1]|0,(b[(c[g>>2]|0)+((c[k>>2]|0)-1<<1)>>1]|0)+(b[(c[h>>2]|0)+(c[k>>2]<<1)>>1]|0)|0)|0)&65535;b[(c[g>>2]|0)+(c[k>>2]<<1)>>1]=n;c[k>>2]=(c[k>>2]|0)+1}n=(Sd(b[(c[g>>2]|0)+((c[j>>2]|0)-1<<1)>>1]|0,32768-(b[(c[h>>2]|0)+(c[j>>2]<<1)>>1]|0)|0)|0)&65535;b[(c[g>>2]|0)+((c[j>>2]|0)-1<<1)>>1]=n;c[k>>2]=(c[j>>2]|0)-2;while(1){if((c[k>>2]|0)<0)break;j=(Sd(b[(c[g>>2]|0)+(c[k>>2]<<1)>>1]|0,(b[(c[g>>2]|0)+((c[k>>2]|0)+1<<1)>>1]|0)-(b[(c[h>>2]|0)+((c[k>>2]|0)+1<<1)>>1]|0)|0)|0)&65535;b[(c[g>>2]|0)+(c[k>>2]<<1)>>1]=j;c[k>>2]=(c[k>>2]|0)+-1}i=f;return}function lc(a,d,e){a=a|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+32|0;g=f+20|0;h=f+16|0;j=f+12|0;k=f+8|0;l=f+4|0;m=f;c[g>>2]=a;c[h>>2]=d;c[j>>2]=e;c[l>>2]=Td(b[c[h>>2]>>1]|0,1)|0;c[l>>2]=131072/(c[l>>2]|0)|0;c[m>>2]=Td((b[(c[h>>2]|0)+2>>1]|0)-(b[c[h>>2]>>1]|0)|0,1)|0;c[m>>2]=131072/(c[m>>2]|0)|0;e=(Ud((c[l>>2]|0)+(c[m>>2]|0)|0,32767)|0)&65535;b[c[g>>2]>>1]=e;c[k>>2]=1;while(1){if((c[k>>2]|0)>=((c[j>>2]|0)-1|0))break;c[l>>2]=Td((b[(c[h>>2]|0)+((c[k>>2]|0)+1<<1)>>1]|0)-(b[(c[h>>2]|0)+(c[k>>2]<<1)>>1]|0)|0,1)|0;c[l>>2]=131072/(c[l>>2]|0)|0;e=(Ud((c[l>>2]|0)+(c[m>>2]|0)|0,32767)|0)&65535;b[(c[g>>2]|0)+(c[k>>2]<<1)>>1]=e;c[m>>2]=Td((b[(c[h>>2]|0)+((c[k>>2]|0)+2<<1)>>1]|0)-(b[(c[h>>2]|0)+((c[k>>2]|0)+1<<1)>>1]|0)|0,1)|0;c[m>>2]=131072/(c[m>>2]|0)|0;e=(Ud((c[l>>2]|0)+(c[m>>2]|0)|0,32767)|0)&65535;b[(c[g>>2]|0)+((c[k>>2]|0)+1<<1)>>1]=e;c[k>>2]=(c[k>>2]|0)+2}c[l>>2]=Td(32768-(b[(c[h>>2]|0)+((c[j>>2]|0)-1<<1)>>1]|0)|0,1)|0;c[l>>2]=131072/(c[l>>2]|0)|0;h=(Ud((c[l>>2]|0)+(c[m>>2]|0)|0,32767)|0)&65535;b[(c[g>>2]|0)+((c[j>>2]|0)-1<<1)>>1]=h;i=f;return}function mc(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;g=i;i=i+32|0;h=g+20|0;j=g+16|0;k=g+12|0;l=g+8|0;m=g+4|0;n=g;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;bf(c[j>>2]|0,0,300)|0;f=(c[k>>2]|0)!=8e3&(c[k>>2]|0)!=12e3&(c[k>>2]|0)!=16e3;do if(c[m>>2]|0){if(!(f&(c[k>>2]|0)!=24e3&(c[k>>2]|0)!=48e3)?!((c[l>>2]|0)!=8e3&(c[l>>2]|0)!=12e3&(c[l>>2]|0)!=16e3):0){c[(c[j>>2]|0)+292>>2]=a[3e3+((((c[k>>2]>>12)-((c[k>>2]|0)>16e3&1)>>((c[k>>2]|0)>24e3&1))-1|0)*3|0)+(((c[l>>2]>>12)-((c[l>>2]|0)>16e3&1)>>((c[l>>2]|0)>24e3&1))-1)>>0];break}c[h>>2]=-1;o=c[h>>2]|0;i=g;return o|0}else{if(!f?!((c[l>>2]|0)!=8e3&(c[l>>2]|0)!=12e3&(c[l>>2]|0)!=16e3&(c[l>>2]|0)!=24e3&(c[l>>2]|0)!=48e3):0){c[(c[j>>2]|0)+292>>2]=a[3016+((((c[k>>2]>>12)-((c[k>>2]|0)>16e3&1)>>((c[k>>2]|0)>24e3&1))-1|0)*5|0)+(((c[l>>2]>>12)-((c[l>>2]|0)>16e3&1)>>((c[l>>2]|0)>24e3&1))-1)>>0];break}c[h>>2]=-1;o=c[h>>2]|0;i=g;return o|0}while(0);c[(c[j>>2]|0)+284>>2]=(c[k>>2]|0)/1e3|0;c[(c[j>>2]|0)+288>>2]=(c[l>>2]|0)/1e3|0;c[(c[j>>2]|0)+268>>2]=(c[(c[j>>2]|0)+284>>2]|0)*10;c[n>>2]=0;f=c[l>>2]|0;m=c[k>>2]|0;do if((c[l>>2]|0)>(c[k>>2]|0)){e=(c[j>>2]|0)+264|0;if((f|0)==(m<<1|0)){c[e>>2]=1;break}else{c[e>>2]=2;c[n>>2]=1;break}}else{e=(c[j>>2]|0)+264|0;if((f|0)>=(m|0)){c[e>>2]=0;break}c[e>>2]=3;if((c[l>>2]<<2|0)==((c[k>>2]|0)*3|0)){c[(c[j>>2]|0)+280>>2]=3;c[(c[j>>2]|0)+276>>2]=18;c[(c[j>>2]|0)+296>>2]=2024;break}if(((c[l>>2]|0)*3|0)==(c[k>>2]<<1|0)){c[(c[j>>2]|0)+280>>2]=2;c[(c[j>>2]|0)+276>>2]=18;c[(c[j>>2]|0)+296>>2]=2088;break}if((c[l>>2]<<1|0)==(c[k>>2]|0)){c[(c[j>>2]|0)+280>>2]=1;c[(c[j>>2]|0)+276>>2]=24;c[(c[j>>2]|0)+296>>2]=2128;break}if(((c[l>>2]|0)*3|0)==(c[k>>2]|0)){c[(c[j>>2]|0)+280>>2]=1;c[(c[j>>2]|0)+276>>2]=36;c[(c[j>>2]|0)+296>>2]=2160;break}if((c[l>>2]<<2|0)==(c[k>>2]|0)){c[(c[j>>2]|0)+280>>2]=1;c[(c[j>>2]|0)+276>>2]=36;c[(c[j>>2]|0)+296>>2]=2200;break}if(((c[l>>2]|0)*6|0)==(c[k>>2]|0)){c[(c[j>>2]|0)+280>>2]=1;c[(c[j>>2]|0)+276>>2]=36;c[(c[j>>2]|0)+296>>2]=2240;break}c[h>>2]=-1;o=c[h>>2]|0;i=g;return o|0}while(0);c[(c[j>>2]|0)+272>>2]=((c[k>>2]<<14+(c[n>>2]|0)|0)/(c[l>>2]|0)|0)<<2;while(1){m=_(c[(c[j>>2]|0)+272>>2]>>16,(c[l>>2]&65535)<<16>>16)|0;f=m+((_(c[(c[j>>2]|0)+272>>2]&65535,(c[l>>2]&65535)<<16>>16)|0)>>16)|0;m=f+(_(c[(c[j>>2]|0)+272>>2]|0,(c[l>>2]>>15)+1>>1)|0)|0;if((m|0)>=(c[k>>2]<<c[n>>2]|0))break;m=(c[j>>2]|0)+272|0;c[m>>2]=(c[m>>2]|0)+1}c[h>>2]=0;o=c[h>>2]|0;i=g;return o|0}function nc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=e;c[l>>2]=(c[(c[g>>2]|0)+284>>2]|0)-(c[(c[g>>2]|0)+292>>2]|0);df((c[g>>2]|0)+168+(c[(c[g>>2]|0)+292>>2]<<1)|0,c[j>>2]|0,c[l>>2]<<1|0)|0;e=c[(c[g>>2]|0)+264>>2]|0;if((e|0)==1){sc(c[g>>2]|0,c[h>>2]|0,(c[g>>2]|0)+168|0,c[(c[g>>2]|0)+284>>2]|0);sc(c[g>>2]|0,(c[h>>2]|0)+(c[(c[g>>2]|0)+288>>2]<<1)|0,(c[j>>2]|0)+(c[l>>2]<<1)|0,(c[k>>2]|0)-(c[(c[g>>2]|0)+284>>2]|0)|0)}else if((e|0)==2){qc(c[g>>2]|0,c[h>>2]|0,(c[g>>2]|0)+168|0,c[(c[g>>2]|0)+284>>2]|0);qc(c[g>>2]|0,(c[h>>2]|0)+(c[(c[g>>2]|0)+288>>2]<<1)|0,(c[j>>2]|0)+(c[l>>2]<<1)|0,(c[k>>2]|0)-(c[(c[g>>2]|0)+284>>2]|0)|0)}else if((e|0)==3){pc(c[g>>2]|0,c[h>>2]|0,(c[g>>2]|0)+168|0,c[(c[g>>2]|0)+284>>2]|0);pc(c[g>>2]|0,(c[h>>2]|0)+(c[(c[g>>2]|0)+288>>2]<<1)|0,(c[j>>2]|0)+(c[l>>2]<<1)|0,(c[k>>2]|0)-(c[(c[g>>2]|0)+284>>2]|0)|0)}else{df(c[h>>2]|0,(c[g>>2]|0)+168|0,c[(c[g>>2]|0)+284>>2]<<1|0)|0;df((c[h>>2]|0)+(c[(c[g>>2]|0)+288>>2]<<1)|0,(c[j>>2]|0)+(c[l>>2]<<1)|0,(c[k>>2]|0)-(c[(c[g>>2]|0)+284>>2]|0)<<1|0)|0}df((c[g>>2]|0)+168|0,(c[j>>2]|0)+((c[k>>2]|0)-(c[(c[g>>2]|0)+292>>2]|0)<<1)|0,c[(c[g>>2]|0)+292>>2]<<1|0)|0;i=f;return 0}function oc(a,d,e,f,g){a=a|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;h=i;i=i+32|0;j=h+8|0;k=h+16|0;l=h+20|0;m=h+24|0;n=h+4|0;o=h;p=h+12|0;c[j>>2]=a;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[o>>2]=0;while(1){if((c[o>>2]|0)>=(c[n>>2]|0))break;c[p>>2]=(c[c[j>>2]>>2]|0)+(b[(c[l>>2]|0)+(c[o>>2]<<1)>>1]<<8);c[(c[k>>2]|0)+(c[o>>2]<<2)>>2]=c[p>>2];c[p>>2]=c[p>>2]<<2;g=_(c[p>>2]>>16,b[c[m>>2]>>1]|0)|0;f=(c[(c[j>>2]|0)+4>>2]|0)+(g+((_(c[p>>2]&65535,b[c[m>>2]>>1]|0)|0)>>16))|0;c[c[j>>2]>>2]=f;f=_(c[p>>2]>>16,b[(c[m>>2]|0)+2>>1]|0)|0;g=f+((_(c[p>>2]&65535,b[(c[m>>2]|0)+2>>1]|0)|0)>>16)|0;c[(c[j>>2]|0)+4>>2]=g;c[o>>2]=(c[o>>2]|0)+1}i=h;return}function pc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;f=i;i=i+48|0;g=f;h=f+16|0;j=f+28|0;k=f+4|0;l=f+32|0;m=f+36|0;n=f+12|0;o=f+24|0;p=f+20|0;q=f+8|0;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=e;c[l>>2]=c[g>>2];g=(c[(c[l>>2]|0)+268>>2]|0)+(c[(c[l>>2]|0)+276>>2]|0)|0;c[q>>2]=ua()|0;e=i;i=i+((1*(g<<2)|0)+15&-16)|0;df(e|0,(c[l>>2]|0)+24|0,c[(c[l>>2]|0)+276>>2]<<2|0)|0;c[p>>2]=(c[(c[l>>2]|0)+296>>2]|0)+4;c[o>>2]=c[(c[l>>2]|0)+272>>2];while(1){if((c[k>>2]|0)<(c[(c[l>>2]|0)+268>>2]|0))r=c[k>>2]|0;else r=c[(c[l>>2]|0)+268>>2]|0;c[m>>2]=r;oc(c[l>>2]|0,e+(c[(c[l>>2]|0)+276>>2]<<2)|0,c[j>>2]|0,c[(c[l>>2]|0)+296>>2]|0,c[m>>2]|0);c[n>>2]=c[m>>2]<<16;c[h>>2]=Vd(c[h>>2]|0,e,c[p>>2]|0,c[(c[l>>2]|0)+276>>2]|0,c[(c[l>>2]|0)+280>>2]|0,c[n>>2]|0,c[o>>2]|0)|0;c[j>>2]=(c[j>>2]|0)+(c[m>>2]<<1);c[k>>2]=(c[k>>2]|0)-(c[m>>2]|0);if((c[k>>2]|0)<=1)break;df(e|0,e+(c[m>>2]<<2)|0,c[(c[l>>2]|0)+276>>2]<<2|0)|0}df((c[l>>2]|0)+24|0,e+(c[m>>2]<<2)|0,c[(c[l>>2]|0)+276>>2]<<2|0)|0;ka(c[q>>2]|0);i=f;return}function qc(a,d,e,f){a=a|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;g=i;i=i+48|0;h=g+28|0;j=g+16|0;k=g+4|0;l=g+8|0;m=g+32|0;n=g;o=g+12|0;p=g+24|0;q=g+20|0;c[h>>2]=a;c[j>>2]=d;c[k>>2]=e;c[l>>2]=f;c[m>>2]=c[h>>2];h=(c[(c[m>>2]|0)+268>>2]<<1)+8|0;c[q>>2]=ua()|0;f=i;i=i+((1*(h<<1)|0)+15&-16)|0;h=(c[m>>2]|0)+24|0;b[f>>1]=b[h>>1]|0;b[f+2>>1]=b[h+2>>1]|0;b[f+4>>1]=b[h+4>>1]|0;b[f+6>>1]=b[h+6>>1]|0;b[f+8>>1]=b[h+8>>1]|0;b[f+10>>1]=b[h+10>>1]|0;b[f+12>>1]=b[h+12>>1]|0;b[f+14>>1]=b[h+14>>1]|0;c[p>>2]=c[(c[m>>2]|0)+272>>2];while(1){if((c[l>>2]|0)<(c[(c[m>>2]|0)+268>>2]|0))r=c[l>>2]|0;else r=c[(c[m>>2]|0)+268>>2]|0;c[n>>2]=r;rc(c[m>>2]|0,f+16|0,c[k>>2]|0,c[n>>2]|0);c[o>>2]=c[n>>2]<<17;c[j>>2]=Wd(c[j>>2]|0,f,c[o>>2]|0,c[p>>2]|0)|0;c[k>>2]=(c[k>>2]|0)+(c[n>>2]<<1);c[l>>2]=(c[l>>2]|0)-(c[n>>2]|0);if((c[l>>2]|0)<=0)break;h=f+(c[n>>2]<<1<<1)|0;b[f>>1]=b[h>>1]|0;b[f+2>>1]=b[h+2>>1]|0;b[f+4>>1]=b[h+4>>1]|0;b[f+6>>1]=b[h+6>>1]|0;b[f+8>>1]=b[h+8>>1]|0;b[f+10>>1]=b[h+10>>1]|0;b[f+12>>1]=b[h+12>>1]|0;b[f+14>>1]=b[h+14>>1]|0}l=(c[m>>2]|0)+24|0;m=f+(c[n>>2]<<1<<1)|0;b[l>>1]=b[m>>1]|0;b[l+2>>1]=b[m+2>>1]|0;b[l+4>>1]=b[m+4>>1]|0;b[l+6>>1]=b[m+6>>1]|0;b[l+8>>1]=b[m+8>>1]|0;b[l+10>>1]=b[m+10>>1]|0;b[l+12>>1]=b[m+12>>1]|0;b[l+14>>1]=b[m+14>>1]|0;ka(c[q>>2]|0);i=g;return}function rc(a,d,e,f){a=a|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;g=i;i=i+48|0;h=g;j=g+16|0;k=g+28|0;l=g+4|0;m=g+32|0;n=g+36|0;o=g+12|0;p=g+24|0;q=g+20|0;r=g+8|0;c[h>>2]=a;c[j>>2]=d;c[k>>2]=e;c[l>>2]=f;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[l>>2]|0))break;c[n>>2]=b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]<<10;c[q>>2]=(c[n>>2]|0)-(c[c[h>>2]>>2]|0);f=_(c[q>>2]>>16,b[1516]|0)|0;c[r>>2]=f+((_(c[q>>2]&65535,b[1516]|0)|0)>>16);c[o>>2]=(c[c[h>>2]>>2]|0)+(c[r>>2]|0);c[c[h>>2]>>2]=(c[n>>2]|0)+(c[r>>2]|0);c[q>>2]=(c[o>>2]|0)-(c[(c[h>>2]|0)+4>>2]|0);f=_(c[q>>2]>>16,b[1517]|0)|0;c[r>>2]=f+((_(c[q>>2]&65535,b[1517]|0)|0)>>16);c[p>>2]=(c[(c[h>>2]|0)+4>>2]|0)+(c[r>>2]|0);c[(c[h>>2]|0)+4>>2]=(c[o>>2]|0)+(c[r>>2]|0);c[q>>2]=(c[p>>2]|0)-(c[(c[h>>2]|0)+8>>2]|0);f=_(c[q>>2]>>16,b[1518]|0)|0;c[r>>2]=(c[q>>2]|0)+(f+((_(c[q>>2]&65535,b[1518]|0)|0)>>16));c[o>>2]=(c[(c[h>>2]|0)+8>>2]|0)+(c[r>>2]|0);c[(c[h>>2]|0)+8>>2]=(c[p>>2]|0)+(c[r>>2]|0);if(((c[o>>2]>>9)+1>>1|0)<=32767)if(((c[o>>2]>>9)+1>>1|0)<-32768)s=-32768;else s=(c[o>>2]>>9)+1>>1;else s=32767;b[(c[j>>2]|0)+(c[m>>2]<<1<<1)>>1]=s;c[q>>2]=(c[n>>2]|0)-(c[(c[h>>2]|0)+12>>2]|0);f=_(c[q>>2]>>16,b[1520]|0)|0;c[r>>2]=f+((_(c[q>>2]&65535,b[1520]|0)|0)>>16);c[o>>2]=(c[(c[h>>2]|0)+12>>2]|0)+(c[r>>2]|0);c[(c[h>>2]|0)+12>>2]=(c[n>>2]|0)+(c[r>>2]|0);c[q>>2]=(c[o>>2]|0)-(c[(c[h>>2]|0)+16>>2]|0);f=_(c[q>>2]>>16,b[1521]|0)|0;c[r>>2]=f+((_(c[q>>2]&65535,b[1521]|0)|0)>>16);c[p>>2]=(c[(c[h>>2]|0)+16>>2]|0)+(c[r>>2]|0);c[(c[h>>2]|0)+16>>2]=(c[o>>2]|0)+(c[r>>2]|0);c[q>>2]=(c[p>>2]|0)-(c[(c[h>>2]|0)+20>>2]|0);f=_(c[q>>2]>>16,b[1522]|0)|0;c[r>>2]=(c[q>>2]|0)+(f+((_(c[q>>2]&65535,b[1522]|0)|0)>>16));c[o>>2]=(c[(c[h>>2]|0)+20>>2]|0)+(c[r>>2]|0);c[(c[h>>2]|0)+20>>2]=(c[p>>2]|0)+(c[r>>2]|0);if(((c[o>>2]>>9)+1>>1|0)<=32767)if(((c[o>>2]>>9)+1>>1|0)<-32768)t=-32768;else t=(c[o>>2]>>9)+1>>1;else t=32767;b[(c[j>>2]|0)+((c[m>>2]<<1)+1<<1)>>1]=t;c[m>>2]=(c[m>>2]|0)+1}i=g;return}function sc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=e;c[l>>2]=c[g>>2];rc(c[l>>2]|0,c[h>>2]|0,c[j>>2]|0,c[k>>2]|0);i=f;return}function tc(a,d){a=a|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[f>>2]=a;c[g>>2]=d;c[j>>2]=1;while(1){if((c[j>>2]|0)>=(c[g>>2]|0))break;c[h>>2]=b[(c[f>>2]|0)+(c[j>>2]<<1)>>1];c[k>>2]=(c[j>>2]|0)-1;while(1){if((c[k>>2]|0)<0)break;if((c[h>>2]|0)>=(b[(c[f>>2]|0)+(c[k>>2]<<1)>>1]|0))break;b[(c[f>>2]|0)+((c[k>>2]|0)+1<<1)>>1]=b[(c[f>>2]|0)+(c[k>>2]<<1)>>1]|0;c[k>>2]=(c[k>>2]|0)+-1}b[(c[f>>2]|0)+((c[k>>2]|0)+1<<1)>>1]=c[h>>2];c[j>>2]=(c[j>>2]|0)+1}i=e;return}function uc(a,d,e,f){a=a|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;g=i;i=i+32|0;h=g+4|0;j=g+16|0;k=g+8|0;l=g+20|0;m=g+28|0;n=g;o=g+12|0;p=g+24|0;c[h>>2]=a;c[j>>2]=d;c[k>>2]=e;c[l>>2]=f;c[p>>2]=0;c[n>>2]=0;c[l>>2]=(c[l>>2]|0)+-1;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[l>>2]|0))break;c[p>>2]=(c[p>>2]|0)+(_(b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]|0,b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]|0)|0);c[p>>2]=(c[p>>2]|0)+(_(b[(c[k>>2]|0)+((c[m>>2]|0)+1<<1)>>1]|0,b[(c[k>>2]|0)+((c[m>>2]|0)+1<<1)>>1]|0)|0);if((c[p>>2]|0)<0){q=4;break}c[m>>2]=(c[m>>2]|0)+2}if((q|0)==4){c[p>>2]=(c[p>>2]|0)>>>2;c[n>>2]=2}while(1){r=c[m>>2]|0;if((c[m>>2]|0)>=(c[l>>2]|0))break;c[o>>2]=_(b[(c[k>>2]|0)+(r<<1)>>1]|0,b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(_(b[(c[k>>2]|0)+((c[m>>2]|0)+1<<1)>>1]|0,b[(c[k>>2]|0)+((c[m>>2]|0)+1<<1)>>1]|0)|0);c[p>>2]=(c[p>>2]|0)+((c[o>>2]|0)>>>(c[n>>2]|0));if((c[p>>2]|0)<0){c[p>>2]=(c[p>>2]|0)>>>2;c[n>>2]=(c[n>>2]|0)+2}c[m>>2]=(c[m>>2]|0)+2}if((r|0)==(c[l>>2]|0)){c[o>>2]=_(b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]|0,b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]|0)|0;c[p>>2]=(c[p>>2]|0)+(c[o>>2]>>c[n>>2])}if(!(c[p>>2]&-1073741824)){s=c[n>>2]|0;t=c[j>>2]|0;c[t>>2]=s;u=c[p>>2]|0;v=c[h>>2]|0;c[v>>2]=u;i=g;return}c[p>>2]=(c[p>>2]|0)>>>2;c[n>>2]=(c[n>>2]|0)+2;s=c[n>>2]|0;t=c[j>>2]|0;c[t>>2]=s;u=c[p>>2]|0;v=c[h>>2]|0;c[v>>2]=u;i=g;return}function vc(a,d){a=a|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+48|0;f=e+40|0;g=e+36|0;h=e+32|0;j=e+8|0;k=e+4|0;l=e;c[f>>2]=a;c[g>>2]=d;c[h>>2]=jb(c[f>>2]|0,368,8)|0;c[j+8>>2]=(c[h>>2]|0)/5|0;c[j+12+8>>2]=(c[h>>2]|0)-((c[j+8>>2]|0)*5|0);c[h>>2]=0;while(1){if((c[h>>2]|0)>=2)break;d=jb(c[f>>2]|0,472,8)|0;c[j+((c[h>>2]|0)*12|0)>>2]=d;d=jb(c[f>>2]|0,488,8)|0;c[j+((c[h>>2]|0)*12|0)+4>>2]=d;c[h>>2]=(c[h>>2]|0)+1}c[h>>2]=0;while(1){if((c[h>>2]|0)>=2)break;f=j+((c[h>>2]|0)*12|0)|0;c[f>>2]=(c[f>>2]|0)+((c[j+((c[h>>2]|0)*12|0)+8>>2]|0)*3|0);c[k>>2]=b[336+(c[j+((c[h>>2]|0)*12|0)>>2]<<1)>>1];c[l>>2]=(((b[336+((c[j+((c[h>>2]|0)*12|0)>>2]|0)+1<<1)>>1]|0)-(c[k>>2]|0)>>16)*6554|0)+(((b[336+((c[j+((c[h>>2]|0)*12|0)>>2]|0)+1<<1)>>1]|0)-(c[k>>2]|0)&65535)*6554>>16);f=(c[k>>2]|0)+(_((c[l>>2]&65535)<<16>>16,((c[j+((c[h>>2]|0)*12|0)+4>>2]<<1)+1&65535)<<16>>16)|0)|0;c[(c[g>>2]|0)+(c[h>>2]<<2)>>2]=f;c[h>>2]=(c[h>>2]|0)+1}h=c[g>>2]|0;c[h>>2]=(c[h>>2]|0)-(c[(c[g>>2]|0)+4>>2]|0);i=e;return}function wc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;b=jb(c[e>>2]|0,400,8)|0;c[c[f>>2]>>2]=b;i=d;return}function xc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0.0,A=0.0,B=0,C=0,D=0.0,E=0.0;f=i;i=i+80|0;h=f+60|0;j=f+44|0;k=f+24|0;l=f+28|0;m=f+12|0;n=f+40|0;o=f+48|0;p=f+56|0;q=f+64|0;r=f+8|0;s=f+4|0;t=f+32|0;u=f;v=f+16|0;w=f+36|0;x=f+20|0;y=f+52|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;if(!((((c[k>>2]|0)<1|(c[j>>2]|0)<1)^1)&(c[h>>2]|0)!=0&(c[l>>2]|0)!=0)){i=f;return}c[n>>2]=0;while(1){if((c[n>>2]|0)>=(_(c[j>>2]|0,c[k>>2]|0)|0))break;if(2.0<+g[(c[h>>2]|0)+(c[n>>2]<<2)>>2])z=2.0;else z=+g[(c[h>>2]|0)+(c[n>>2]<<2)>>2];if(!(-2.0>z))if(2.0<+g[(c[h>>2]|0)+(c[n>>2]<<2)>>2])A=2.0;else A=+g[(c[h>>2]|0)+(c[n>>2]<<2)>>2];else A=-2.0;g[(c[h>>2]|0)+(c[n>>2]<<2)>>2]=A;c[n>>2]=(c[n>>2]|0)+1}c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break;c[o>>2]=(c[h>>2]|0)+(c[m>>2]<<2);g[p>>2]=+g[(c[l>>2]|0)+(c[m>>2]<<2)>>2];c[n>>2]=0;while(1){if((c[n>>2]|0)>=(c[j>>2]|0))break;e=_(c[n>>2]|0,c[k>>2]|0)|0;if(+g[(c[o>>2]|0)+(e<<2)>>2]*+g[p>>2]>=0.0)break;e=_(c[n>>2]|0,c[k>>2]|0)|0;d=_(c[n>>2]|0,c[k>>2]|0)|0;b=_(c[n>>2]|0,c[k>>2]|0)|0;a=_(c[n>>2]|0,c[k>>2]|0)|0;g[(c[o>>2]|0)+(a<<2)>>2]=+g[(c[o>>2]|0)+(e<<2)>>2]+ +g[p>>2]*+g[(c[o>>2]|0)+(d<<2)>>2]*+g[(c[o>>2]|0)+(b<<2)>>2];c[n>>2]=(c[n>>2]|0)+1}c[r>>2]=0;g[q>>2]=+g[c[o>>2]>>2];do{c[v>>2]=0;c[n>>2]=c[r>>2];while(1){if((c[n>>2]|0)>=(c[j>>2]|0))break;b=_(c[n>>2]|0,c[k>>2]|0)|0;if(+g[(c[o>>2]|0)+(b<<2)>>2]>1.0)break;b=_(c[n>>2]|0,c[k>>2]|0)|0;if(+g[(c[o>>2]|0)+(b<<2)>>2]<-1.0)break;c[n>>2]=(c[n>>2]|0)+1}if((c[n>>2]|0)==(c[j>>2]|0)){B=23;break}c[w>>2]=c[n>>2];b=c[n>>2]|0;c[t>>2]=b;c[s>>2]=b;b=_(c[n>>2]|0,c[k>>2]|0)|0;g[u>>2]=+N(+(+g[(c[o>>2]|0)+(b<<2)>>2]));while(1){if((c[s>>2]|0)<=0)break;b=_(c[n>>2]|0,c[k>>2]|0)|0;d=_((c[s>>2]|0)-1|0,c[k>>2]|0)|0;if(!(+g[(c[o>>2]|0)+(b<<2)>>2]*+g[(c[o>>2]|0)+(d<<2)>>2]>=0.0))break;c[s>>2]=(c[s>>2]|0)+-1}while(1){if((c[t>>2]|0)>=(c[j>>2]|0))break;d=_(c[n>>2]|0,c[k>>2]|0)|0;b=_(c[t>>2]|0,c[k>>2]|0)|0;if(!(+g[(c[o>>2]|0)+(d<<2)>>2]*+g[(c[o>>2]|0)+(b<<2)>>2]>=0.0))break;b=_(c[t>>2]|0,c[k>>2]|0)|0;A=+N(+(+g[(c[o>>2]|0)+(b<<2)>>2]));if(A>+g[u>>2]){b=_(c[t>>2]|0,c[k>>2]|0)|0;g[u>>2]=+N(+(+g[(c[o>>2]|0)+(b<<2)>>2]));c[w>>2]=c[t>>2]}c[t>>2]=(c[t>>2]|0)+1}if(!(c[s>>2]|0)){b=_(c[n>>2]|0,c[k>>2]|0)|0;C=+g[(c[o>>2]|0)+(b<<2)>>2]*+g[c[o>>2]>>2]>=0.0}else C=0;c[v>>2]=C&1;g[p>>2]=(+g[u>>2]-1.0)/(+g[u>>2]*+g[u>>2]);b=_(c[n>>2]|0,c[k>>2]|0)|0;if(+g[(c[o>>2]|0)+(b<<2)>>2]>0.0)g[p>>2]=-+g[p>>2];c[n>>2]=c[s>>2];while(1){if((c[n>>2]|0)>=(c[t>>2]|0))break;b=_(c[n>>2]|0,c[k>>2]|0)|0;d=_(c[n>>2]|0,c[k>>2]|0)|0;e=_(c[n>>2]|0,c[k>>2]|0)|0;a=_(c[n>>2]|0,c[k>>2]|0)|0;g[(c[o>>2]|0)+(a<<2)>>2]=+g[(c[o>>2]|0)+(b<<2)>>2]+ +g[p>>2]*+g[(c[o>>2]|0)+(d<<2)>>2]*+g[(c[o>>2]|0)+(e<<2)>>2];c[n>>2]=(c[n>>2]|0)+1}a:do if((c[v>>2]|0)!=0&(c[w>>2]|0)>=2){g[y>>2]=+g[q>>2]-+g[c[o>>2]>>2];g[x>>2]=+g[y>>2]/+(c[w>>2]|0);c[n>>2]=c[r>>2];while(1){if((c[n>>2]|0)>=(c[w>>2]|0))break a;g[y>>2]=+g[y>>2]-+g[x>>2];e=_(c[n>>2]|0,c[k>>2]|0)|0;d=(c[o>>2]|0)+(e<<2)|0;g[d>>2]=+g[d>>2]+ +g[y>>2];d=_(c[n>>2]|0,c[k>>2]|0)|0;if(1.0<+g[(c[o>>2]|0)+(d<<2)>>2])D=1.0;else{d=_(c[n>>2]|0,c[k>>2]|0)|0;D=+g[(c[o>>2]|0)+(d<<2)>>2]}if(!(-1.0>D)){d=_(c[n>>2]|0,c[k>>2]|0)|0;if(1.0<+g[(c[o>>2]|0)+(d<<2)>>2])E=1.0;else{d=_(c[n>>2]|0,c[k>>2]|0)|0;E=+g[(c[o>>2]|0)+(d<<2)>>2]}}else E=-1.0;d=_(c[n>>2]|0,c[k>>2]|0)|0;g[(c[o>>2]|0)+(d<<2)>>2]=E;c[n>>2]=(c[n>>2]|0)+1}}while(0);c[r>>2]=c[t>>2]}while((c[r>>2]|0)!=(c[j>>2]|0));if((B|0)==23){B=0;g[p>>2]=0.0}g[(c[l>>2]|0)+(c[m>>2]<<2)>>2]=+g[p>>2];c[m>>2]=(c[m>>2]|0)+1}i=f;return}function yc(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,j=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[f>>2]=a;c[g>>2]=b;b=d[c[f>>2]>>0]|0;if((d[c[f>>2]>>0]|0)&128){c[h>>2]=b>>3&3;c[h>>2]=(c[g>>2]<<c[h>>2]|0)/400|0;j=c[h>>2]|0;i=e;return j|0}a=d[c[f>>2]>>0]|0;if((b&96|0)==96){b=c[g>>2]|0;c[h>>2]=(a&8|0)!=0?(b|0)/50|0:(b|0)/100|0;j=c[h>>2]|0;i=e;return j|0}c[h>>2]=a>>3&3;a=c[g>>2]|0;if((c[h>>2]|0)==3){c[h>>2]=(a*60|0)/1e3|0;j=c[h>>2]|0;i=e;return j|0}else{c[h>>2]=(a<<c[h>>2]|0)/100|0;j=c[h>>2]|0;i=e;return j|0}return 0}function zc(e,f,g,h,j,k,l,m){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;var n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0;n=i;i=i+80|0;o=n+36|0;p=n+24|0;q=n+44|0;r=n+60|0;s=n+12|0;t=n+16|0;u=n+48|0;v=n+56|0;w=n+64|0;x=n+68|0;y=n+72|0;z=n+8|0;A=n;B=n+76|0;C=n+77|0;D=n+20|0;E=n+52|0;F=n+28|0;G=n+32|0;H=n+40|0;I=n+4|0;c[p>>2]=e;c[q>>2]=f;c[r>>2]=g;c[s>>2]=h;c[t>>2]=j;c[u>>2]=k;c[v>>2]=l;c[w>>2]=m;c[F>>2]=0;c[G>>2]=c[p>>2];if(!(c[u>>2]|0)){c[o>>2]=-1;J=c[o>>2]|0;i=n;return J|0}c[D>>2]=yc(c[p>>2]|0,48e3)|0;c[A>>2]=0;m=c[p>>2]|0;c[p>>2]=m+1;a[C>>0]=a[m>>0]|0;c[q>>2]=(c[q>>2]|0)+-1;c[E>>2]=c[q>>2];m=d[C>>0]&3;a:do if(!m)c[z>>2]=1;else if((m|0)==1){c[z>>2]=2;c[A>>2]=1;if(!(c[r>>2]|0)){if(!(c[q>>2]&1)){c[E>>2]=(c[q>>2]|0)/2|0;b[c[u>>2]>>1]=c[E>>2];break}c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}}else if((m|0)==2){c[z>>2]=2;c[y>>2]=Xd(c[p>>2]|0,c[q>>2]|0,c[u>>2]|0)|0;c[q>>2]=(c[q>>2]|0)-(c[y>>2]|0);if((b[c[u>>2]>>1]|0)>=0?(b[c[u>>2]>>1]|0)<=(c[q>>2]|0):0){c[p>>2]=(c[p>>2]|0)+(c[y>>2]|0);c[E>>2]=(c[q>>2]|0)-(b[c[u>>2]>>1]|0);break}c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}else{if((c[q>>2]|0)<1){c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}l=c[p>>2]|0;c[p>>2]=l+1;a[B>>0]=a[l>>0]|0;c[z>>2]=d[B>>0]&63;if((c[z>>2]|0)>0?(_(c[D>>2]|0,c[z>>2]|0)|0)<=5760:0){c[q>>2]=(c[q>>2]|0)+-1;b:do if(d[B>>0]&64){while(1){if((c[q>>2]|0)<=0)break;l=c[p>>2]|0;c[p>>2]=l+1;c[H>>2]=d[l>>0];c[q>>2]=(c[q>>2]|0)+-1;c[I>>2]=(c[H>>2]|0)==255?254:c[H>>2]|0;c[q>>2]=(c[q>>2]|0)-(c[I>>2]|0);c[F>>2]=(c[F>>2]|0)+(c[I>>2]|0);if((c[H>>2]|0)!=255)break b}c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}while(0);if((c[q>>2]|0)<0){c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}c[A>>2]=((d[B>>0]&128|0)!=0^1)&1;if(c[A>>2]|0){if(c[r>>2]|0)break;c[E>>2]=(c[q>>2]|0)/(c[z>>2]|0)|0;l=_(c[E>>2]|0,c[z>>2]|0)|0;if((l|0)!=(c[q>>2]|0)){c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}c[x>>2]=0;while(1){if((c[x>>2]|0)>=((c[z>>2]|0)-1|0))break a;b[(c[u>>2]|0)+(c[x>>2]<<1)>>1]=c[E>>2];c[x>>2]=(c[x>>2]|0)+1}}c[E>>2]=c[q>>2];c[x>>2]=0;while(1){if((c[x>>2]|0)>=((c[z>>2]|0)-1|0))break;c[y>>2]=Xd(c[p>>2]|0,c[q>>2]|0,(c[u>>2]|0)+(c[x>>2]<<1)|0)|0;c[q>>2]=(c[q>>2]|0)-(c[y>>2]|0);if((b[(c[u>>2]|0)+(c[x>>2]<<1)>>1]|0)<0){K=29;break}if((b[(c[u>>2]|0)+(c[x>>2]<<1)>>1]|0)>(c[q>>2]|0)){K=29;break}c[p>>2]=(c[p>>2]|0)+(c[y>>2]|0);c[E>>2]=(c[E>>2]|0)-((c[y>>2]|0)+(b[(c[u>>2]|0)+(c[x>>2]<<1)>>1]|0));c[x>>2]=(c[x>>2]|0)+1}if((K|0)==29){c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}if((c[E>>2]|0)>=0)break;c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}while(0);c:do if(c[r>>2]|0){c[y>>2]=Xd(c[p>>2]|0,c[q>>2]|0,(c[u>>2]|0)+(c[z>>2]<<1)+-2|0)|0;c[q>>2]=(c[q>>2]|0)-(c[y>>2]|0);if((b[(c[u>>2]|0)+((c[z>>2]|0)-1<<1)>>1]|0)>=0?(b[(c[u>>2]|0)+((c[z>>2]|0)-1<<1)>>1]|0)<=(c[q>>2]|0):0){c[p>>2]=(c[p>>2]|0)+(c[y>>2]|0);if(!(c[A>>2]|0)){if(((c[y>>2]|0)+(b[(c[u>>2]|0)+((c[z>>2]|0)-1<<1)>>1]|0)|0)<=(c[E>>2]|0))break;c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}K=_(b[(c[u>>2]|0)+((c[z>>2]|0)-1<<1)>>1]|0,c[z>>2]|0)|0;if((K|0)>(c[q>>2]|0)){c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}c[x>>2]=0;while(1){if((c[x>>2]|0)>=((c[z>>2]|0)-1|0))break c;b[(c[u>>2]|0)+(c[x>>2]<<1)>>1]=b[(c[u>>2]|0)+((c[z>>2]|0)-1<<1)>>1]|0;c[x>>2]=(c[x>>2]|0)+1}}c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}else{if((c[E>>2]|0)<=1275){b[(c[u>>2]|0)+((c[z>>2]|0)-1<<1)>>1]=c[E>>2];break}c[o>>2]=-4;J=c[o>>2]|0;i=n;return J|0}while(0);if(c[v>>2]|0)c[c[v>>2]>>2]=(c[p>>2]|0)-(c[G>>2]|0);c[x>>2]=0;while(1){if((c[x>>2]|0)>=(c[z>>2]|0))break;if(c[t>>2]|0)c[(c[t>>2]|0)+(c[x>>2]<<2)>>2]=c[p>>2];c[p>>2]=(c[p>>2]|0)+(b[(c[u>>2]|0)+(c[x>>2]<<1)>>1]|0);c[x>>2]=(c[x>>2]|0)+1}if(c[w>>2]|0)c[c[w>>2]>>2]=(c[F>>2]|0)+((c[p>>2]|0)-(c[G>>2]|0));if(c[s>>2]|0)a[c[s>>2]>>0]=a[C>>0]|0;c[o>>2]=c[z>>2];J=c[o>>2]|0;i=n;return J|0}function Ac(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0;b=i;i=i+32|0;d=b+16|0;e=b+12|0;f=b+8|0;g=b+4|0;h=b;c[e>>2]=a;if((c[e>>2]|0)<1|(c[e>>2]|0)>2){c[d>>2]=0;j=c[d>>2]|0;i=b;return j|0}c[h>>2]=Ub(f)|0;if(c[h>>2]|0){c[d>>2]=0;j=c[d>>2]|0;i=b;return j|0}else{c[f>>2]=Yd(c[f>>2]|0)|0;c[g>>2]=Za(c[e>>2]|0)|0;e=Yd(84)|0;c[d>>2]=e+(c[f>>2]|0)+(c[g>>2]|0);j=c[d>>2]|0;i=b;return j|0}return 0}function Bc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;e=i;i=i+48|0;f=e;g=e+24|0;h=e+20|0;j=e+8|0;k=e+16|0;l=e+4|0;m=e+12|0;n=e+28|0;o=e+32|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;if(!((c[j>>2]|0)!=48e3&(c[j>>2]|0)!=24e3&(c[j>>2]|0)!=16e3&(c[j>>2]|0)!=12e3&(c[j>>2]|0)!=8e3)?!((c[k>>2]|0)!=1&(c[k>>2]|0)!=2):0){d=c[h>>2]|0;bf(d|0,0,Ac(c[k>>2]|0)|0)|0;c[n>>2]=Ub(o)|0;if(c[n>>2]|0){c[g>>2]=-3;p=c[g>>2]|0;i=e;return p|0}c[o>>2]=Yd(c[o>>2]|0)|0;d=Yd(84)|0;c[(c[h>>2]|0)+4>>2]=d;c[c[h>>2]>>2]=(c[(c[h>>2]|0)+4>>2]|0)+(c[o>>2]|0);c[l>>2]=(c[h>>2]|0)+(c[(c[h>>2]|0)+4>>2]|0);c[m>>2]=(c[h>>2]|0)+(c[c[h>>2]>>2]|0);o=c[k>>2]|0;c[(c[h>>2]|0)+8>>2]=o;c[(c[h>>2]|0)+44>>2]=o;c[(c[h>>2]|0)+12>>2]=c[j>>2];c[(c[h>>2]|0)+16+8>>2]=c[(c[h>>2]|0)+12>>2];c[(c[h>>2]|0)+16>>2]=c[(c[h>>2]|0)+8>>2];c[n>>2]=Vb(c[l>>2]|0)|0;if(c[n>>2]|0){c[g>>2]=-3;p=c[g>>2]|0;i=e;return p|0}c[n>>2]=_a(c[m>>2]|0,c[j>>2]|0,c[k>>2]|0)|0;if(c[n>>2]|0){c[g>>2]=-3;p=c[g>>2]|0;i=e;return p|0}else{n=c[m>>2]|0;c[f>>2]=0;ab(n,10016,f)|0;c[(c[h>>2]|0)+56>>2]=0;c[(c[h>>2]|0)+60>>2]=(c[j>>2]|0)/400|0;c[g>>2]=0;p=c[g>>2]|0;i=e;return p|0}}c[g>>2]=-1;p=c[g>>2]|0;i=e;return p|0}function Cc(a,d,e,f,h,j,k,l,m){a=a|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;var n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0;n=i;i=i+208|0;o=n+44|0;p=n+4|0;q=n;r=n+76|0;s=n+36|0;t=n+16|0;u=n+20|0;v=n+24|0;w=n+64|0;x=n+72|0;y=n+80|0;z=n+84|0;A=n+88|0;B=n+48|0;C=n+192|0;D=n+8|0;E=n+56|0;F=n+28|0;G=n+60|0;H=n+96|0;I=n+32|0;J=n+68|0;K=n+40|0;L=n+12|0;M=n+52|0;c[p>>2]=a;c[q>>2]=d;c[r>>2]=e;c[s>>2]=f;c[t>>2]=h;c[u>>2]=j;c[v>>2]=k;c[w>>2]=l;c[x>>2]=m;if((c[u>>2]|0)<0|(c[u>>2]|0)>1){c[o>>2]=-1;N=c[o>>2]|0;i=n;return N|0}if((c[u>>2]|0)!=0|(c[r>>2]|0)==0|(c[q>>2]|0)==0?((c[t>>2]|0)%((c[(c[p>>2]|0)+12>>2]|0)/400|0|0)|0|0)!=0:0){c[o>>2]=-1;N=c[o>>2]|0;i=n;return N|0}if((c[r>>2]|0)==0|(c[q>>2]|0)==0){c[I>>2]=0;while(1){m=(c[s>>2]|0)+((_(c[I>>2]|0,c[(c[p>>2]|0)+8>>2]|0)|0)<<2)|0;c[J>>2]=Zd(c[p>>2]|0,0,0,m,(c[t>>2]|0)-(c[I>>2]|0)|0,0)|0;O=c[J>>2]|0;if((c[J>>2]|0)<0){P=9;break}c[I>>2]=(c[I>>2]|0)+O;if((c[I>>2]|0)>=(c[t>>2]|0)){P=11;break}}if((P|0)==9){c[o>>2]=O;N=c[o>>2]|0;i=n;return N|0}else if((P|0)==11){_d()|0;c[(c[p>>2]|0)+68>>2]=c[I>>2];c[o>>2]=c[I>>2];N=c[o>>2]|0;i=n;return N|0}}if((c[r>>2]|0)<0){c[o>>2]=-1;N=c[o>>2]|0;i=n;return N|0}c[F>>2]=$d(c[q>>2]|0)|0;c[E>>2]=Dc(c[q>>2]|0)|0;c[D>>2]=yc(c[q>>2]|0,c[(c[p>>2]|0)+12>>2]|0)|0;c[G>>2]=Ec(c[q>>2]|0)|0;c[A>>2]=zc(c[q>>2]|0,c[r>>2]|0,c[v>>2]|0,C,0,H,B,c[w>>2]|0)|0;if((c[A>>2]|0)<0){c[o>>2]=c[A>>2];N=c[o>>2]|0;i=n;return N|0}c[q>>2]=(c[q>>2]|0)+(c[B>>2]|0);if(c[u>>2]|0){if(!((c[F>>2]|0)==1002?1:(c[t>>2]|0)<(c[D>>2]|0))?(c[(c[p>>2]|0)+52>>2]|0)!=1002:0){c[K>>2]=c[(c[p>>2]|0)+68>>2];if(((c[t>>2]|0)-(c[D>>2]|0)|0)!=0?(c[L>>2]=Cc(c[p>>2]|0,0,0,c[s>>2]|0,(c[t>>2]|0)-(c[D>>2]|0)|0,0,0,0,c[x>>2]|0)|0,(c[L>>2]|0)<0):0){c[(c[p>>2]|0)+68>>2]=c[K>>2];c[o>>2]=c[L>>2];N=c[o>>2]|0;i=n;return N|0}c[(c[p>>2]|0)+52>>2]=c[F>>2];c[(c[p>>2]|0)+48>>2]=c[E>>2];c[(c[p>>2]|0)+60>>2]=c[D>>2];c[(c[p>>2]|0)+44>>2]=c[G>>2];K=(c[s>>2]|0)+((_(c[(c[p>>2]|0)+8>>2]|0,(c[t>>2]|0)-(c[D>>2]|0)|0)|0)<<2)|0;c[L>>2]=Zd(c[p>>2]|0,c[q>>2]|0,b[H>>1]|0,K,c[D>>2]|0,1)|0;if((c[L>>2]|0)<0){c[o>>2]=c[L>>2];N=c[o>>2]|0;i=n;return N|0}else{_d()|0;c[(c[p>>2]|0)+68>>2]=c[t>>2];c[o>>2]=c[t>>2];N=c[o>>2]|0;i=n;return N|0}}c[o>>2]=Cc(c[p>>2]|0,0,0,c[s>>2]|0,c[t>>2]|0,0,0,0,c[x>>2]|0)|0;N=c[o>>2]|0;i=n;return N|0}L=_(c[A>>2]|0,c[D>>2]|0)|0;if((L|0)>(c[t>>2]|0)){c[o>>2]=-2;N=c[o>>2]|0;i=n;return N|0}c[(c[p>>2]|0)+52>>2]=c[F>>2];c[(c[p>>2]|0)+48>>2]=c[E>>2];c[(c[p>>2]|0)+60>>2]=c[D>>2];c[(c[p>>2]|0)+44>>2]=c[G>>2];c[z>>2]=0;c[y>>2]=0;while(1){if((c[y>>2]|0)>=(c[A>>2]|0))break;G=(c[s>>2]|0)+((_(c[z>>2]|0,c[(c[p>>2]|0)+8>>2]|0)|0)<<2)|0;c[M>>2]=Zd(c[p>>2]|0,c[q>>2]|0,b[H+(c[y>>2]<<1)>>1]|0,G,(c[t>>2]|0)-(c[z>>2]|0)|0,0)|0;if((c[M>>2]|0)<0){P=31;break}c[q>>2]=(c[q>>2]|0)+(b[H+(c[y>>2]<<1)>>1]|0);c[z>>2]=(c[z>>2]|0)+(c[M>>2]|0);c[y>>2]=(c[y>>2]|0)+1}if((P|0)==31){c[o>>2]=c[M>>2];N=c[o>>2]|0;i=n;return N|0}c[(c[p>>2]|0)+68>>2]=c[z>>2];_d()|0;if(c[x>>2]|0)xc(c[s>>2]|0,c[z>>2]|0,c[(c[p>>2]|0)+8>>2]|0,(c[p>>2]|0)+72|0);else{g[(c[p>>2]|0)+72+4>>2]=0.0;g[(c[p>>2]|0)+72>>2]=0.0}c[o>>2]=c[z>>2];N=c[o>>2]|0;i=n;return N|0}function Dc(a){a=a|0;var b=0,e=0,f=0,g=0,h=0;b=i;i=i+16|0;e=b+4|0;f=b;c[e>>2]=a;a=d[c[e>>2]>>0]|0;if((d[c[e>>2]>>0]|0)&128){g=1102+(a>>5&3)|0;c[f>>2]=g;c[f>>2]=(c[f>>2]|0)==1102?1101:g;h=c[f>>2]|0;i=b;return h|0}g=d[c[e>>2]>>0]|0;if((a&96|0)==96){c[f>>2]=(g&16|0)!=0?1105:1104;h=c[f>>2]|0;i=b;return h|0}else{c[f>>2]=1101+(g>>5&3);h=c[f>>2]|0;i=b;return h|0}return 0}function Ec(a){a=a|0;var b=0,e=0;b=i;i=i+16|0;e=b;c[e>>2]=a;i=b;return (((d[c[e>>2]>>0]|0)&4|0)!=0?2:1)|0}function Fc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;e=i;i=i+80|0;f=e+8|0;g=e;h=e+12|0;j=e+16|0;k=e+20|0;l=e+44|0;m=e+24|0;n=e+40|0;o=e+48|0;p=e+52|0;q=e+56|0;r=e+60|0;s=e+64|0;t=e+68|0;u=e+72|0;v=e+76|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=0;c[n>>2]=(c[j>>2]|0)+(c[(c[j>>2]|0)+4>>2]|0);c[o>>2]=(c[j>>2]|0)+(c[c[j>>2]>>2]|0);c[m>>2]=d;a:do switch(c[k>>2]|0){case 4029:{d=(c[m>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[m>>2]=d+4;c[r>>2]=b;if(c[r>>2]|0){c[c[r>>2]>>2]=c[(c[j>>2]|0)+12>>2];w=20}else w=21;break}case 4033:{b=(c[m>>2]|0)+(4-1)&~(4-1);d=c[b>>2]|0;c[m>>2]=b+4;c[s>>2]=d;if(c[s>>2]|0)if((c[(c[j>>2]|0)+56>>2]|0)==1002){d=c[o>>2]|0;c[f>>2]=(c[s>>2]|0)+((((c[s>>2]|0)-(c[s>>2]|0)|0)/4|0)<<2);ab(d,4033,f)|0;w=20;break a}else{c[c[s>>2]>>2]=c[(c[j>>2]|0)+16+20>>2];w=20;break a}else w=21;break}case 4045:{d=(c[m>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[m>>2]=d+4;c[t>>2]=b;if(c[t>>2]|0){c[c[t>>2]>>2]=c[(c[j>>2]|0)+40>>2];w=20}else w=21;break}case 4034:{b=(c[m>>2]|0)+(4-1)&~(4-1);d=c[b>>2]|0;c[m>>2]=b+4;c[u>>2]=d;if((c[u>>2]|0)<-32768|(c[u>>2]|0)>32767)w=21;else{c[(c[j>>2]|0)+40>>2]=c[u>>2];w=20}break}case 4039:{d=(c[m>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[m>>2]=d+4;c[v>>2]=b;if(c[v>>2]|0){c[c[v>>2]>>2]=c[(c[j>>2]|0)+68>>2];w=20}else w=21;break}case 4009:{b=(c[m>>2]|0)+(4-1)&~(4-1);d=c[b>>2]|0;c[m>>2]=b+4;c[p>>2]=d;if(c[p>>2]|0){c[c[p>>2]>>2]=c[(c[j>>2]|0)+48>>2];w=20}else w=21;break}case 4031:{d=(c[m>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[m>>2]=d+4;c[q>>2]=b;if(c[q>>2]|0){c[c[q>>2]>>2]=c[(c[j>>2]|0)+80>>2];w=20}else w=21;break}case 4028:{bf((c[j>>2]|0)+44|0,0,84-((c[j>>2]|0)+44-(c[j>>2]|0))|0)|0;ab(c[o>>2]|0,4028,g)|0;Vb(c[n>>2]|0)|0;c[(c[j>>2]|0)+44>>2]=c[(c[j>>2]|0)+8>>2];c[(c[j>>2]|0)+60>>2]=(c[(c[j>>2]|0)+12>>2]|0)/400|0;w=20;break}default:{c[l>>2]=-5;w=20}}while(0);if((w|0)==20){c[h>>2]=c[l>>2];x=c[h>>2]|0;i=e;return x|0}else if((w|0)==21){c[h>>2]=-1;x=c[h>>2]|0;i=e;return x|0}return 0}function Gc(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,j=0;e=i;i=i+16|0;f=e+12|0;g=e+8|0;h=e+4|0;j=e;c[g>>2]=a;c[h>>2]=b;do if((c[h>>2]|0)>=1){c[j>>2]=(d[c[g>>2]>>0]|0)&3;if(!(c[j>>2]|0)){c[f>>2]=1;break}if((c[j>>2]|0)!=3){c[f>>2]=2;break}if((c[h>>2]|0)<2){c[f>>2]=-4;break}else{c[f>>2]=(d[(c[g>>2]|0)+1>>0]|0)&63;break}}else c[f>>2]=-1;while(0);i=e;return c[f>>2]|0}function Hc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0;e=i;i=i+32|0;f=e+20|0;g=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[l>>2]=Gc(c[g>>2]|0,c[h>>2]|0)|0;h=c[l>>2]|0;if((c[l>>2]|0)<0){c[f>>2]=h;m=c[f>>2]|0;i=e;return m|0}c[k>>2]=_(h,yc(c[g>>2]|0,c[j>>2]|0)|0)|0;if(((c[k>>2]|0)*25|0)>((c[j>>2]|0)*3|0)){c[f>>2]=-4;m=c[f>>2]|0;i=e;return m|0}else{c[f>>2]=c[k>>2];m=c[f>>2]|0;i=e;return m|0}return 0}function Ic(a){a=a|0;var b=0,e=0,f=0,g=0,h=0,j=0,k=0;b=i;i=i+16|0;e=b+12|0;f=b+8|0;g=b+4|0;h=b;c[f>>2]=a;c[h>>2]=(c[(c[f>>2]|0)+4>>2]|0)+(c[(c[f>>2]|0)+8>>2]|0);if((c[h>>2]|0)>255){c[e>>2]=0;j=c[e>>2]|0;i=b;return j|0}c[g>>2]=0;while(1){if((c[g>>2]|0)>=(c[c[f>>2]>>2]|0)){k=9;break}if((d[(c[f>>2]|0)+12+(c[g>>2]|0)>>0]|0|0)>=(c[h>>2]|0)?(d[(c[f>>2]|0)+12+(c[g>>2]|0)>>0]|0|0)!=255:0){k=7;break}c[g>>2]=(c[g>>2]|0)+1}if((k|0)==7){c[e>>2]=0;j=c[e>>2]|0;i=b;return j|0}else if((k|0)==9){c[e>>2]=1;j=c[e>>2]|0;i=b;return j|0}return 0}function Jc(a,b,e){a=a|0;b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=e;c[l>>2]=(c[k>>2]|0)<0?0:(c[k>>2]|0)+1|0;while(1){if((c[l>>2]|0)>=(c[c[h>>2]>>2]|0)){m=6;break}n=c[l>>2]|0;if((d[(c[h>>2]|0)+12+(c[l>>2]|0)>>0]|0|0)==(c[j>>2]<<1|0)){m=4;break}c[l>>2]=n+1}if((m|0)==4){c[g>>2]=n;o=c[g>>2]|0;i=f;return o|0}else if((m|0)==6){c[g>>2]=-1;o=c[g>>2]|0;i=f;return o|0}return 0}function Kc(a,b,e){a=a|0;b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=e;c[l>>2]=(c[k>>2]|0)<0?0:(c[k>>2]|0)+1|0;while(1){if((c[l>>2]|0)>=(c[c[h>>2]>>2]|0)){m=6;break}n=c[l>>2]|0;if((d[(c[h>>2]|0)+12+(c[l>>2]|0)>>0]|0|0)==((c[j>>2]<<1)+1|0)){m=4;break}c[l>>2]=n+1}if((m|0)==4){c[g>>2]=n;o=c[g>>2]|0;i=f;return o|0}else if((m|0)==6){c[g>>2]=-1;o=c[g>>2]|0;i=f;return o|0}return 0}function Lc(a,b,e){a=a|0;b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=e;c[l>>2]=(c[k>>2]|0)<0?0:(c[k>>2]|0)+1|0;while(1){if((c[l>>2]|0)>=(c[c[h>>2]>>2]|0)){m=6;break}n=c[l>>2]|0;if((d[(c[h>>2]|0)+12+(c[l>>2]|0)>>0]|0|0)==((c[j>>2]|0)+(c[(c[h>>2]|0)+8>>2]|0)|0)){m=4;break}c[l>>2]=n+1}if((m|0)==4){c[g>>2]=n;o=c[g>>2]|0;i=f;return o|0}else if((m|0)==6){c[g>>2]=-1;o=c[g>>2]|0;i=f;return o|0}return 0}function Mc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;d=i;i=i+32|0;e=d+16|0;f=d+12|0;g=d+8|0;h=d+4|0;j=d;c[f>>2]=a;c[g>>2]=b;if((c[f>>2]|0)>=1?!((c[g>>2]|0)<0?1:(c[g>>2]|0)>(c[f>>2]|0)):0){c[h>>2]=Ac(2)|0;c[j>>2]=Ac(1)|0;b=ae(268)|0;a=c[g>>2]|0;k=b+(_(a,ae(c[h>>2]|0)|0)|0)|0;h=(c[f>>2]|0)-(c[g>>2]|0)|0;c[e>>2]=k+(_(h,ae(c[j>>2]|0)|0)|0);l=c[e>>2]|0;i=d;return l|0}c[e>>2]=0;l=c[e>>2]|0;i=d;return l|0}function Nc(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;j=i;i=i+48|0;k=j+4|0;l=j+16|0;m=j+36|0;n=j;o=j+32|0;p=j+40|0;q=j+44|0;r=j+24|0;s=j+20|0;t=j+8|0;u=j+12|0;v=j+28|0;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=g;c[q>>2]=h;if((!((c[n>>2]|0)>255|(c[n>>2]|0)<1)?(c[p>>2]|0)<=(c[o>>2]|0):0)?!(((c[o>>2]|0)<1?1:((c[p>>2]|0)+(c[o>>2]|0)|0)>255)|(c[p>>2]|0)<0):0){c[c[l>>2]>>2]=c[n>>2];c[(c[l>>2]|0)+4>>2]=c[o>>2];c[(c[l>>2]|0)+8>>2]=c[p>>2];c[t>>2]=0;while(1){if((c[t>>2]|0)>=(c[c[l>>2]>>2]|0))break;a[(c[l>>2]|0)+12+(c[t>>2]|0)>>0]=a[(c[q>>2]|0)+(c[t>>2]|0)>>0]|0;c[t>>2]=(c[t>>2]|0)+1}if(!(Ic(c[l>>2]|0)|0)){c[k>>2]=-1;w=c[k>>2]|0;i=j;return w|0}q=c[l>>2]|0;c[v>>2]=q+(ae(268)|0);c[r>>2]=Ac(2)|0;c[s>>2]=Ac(1)|0;c[t>>2]=0;while(1){if((c[t>>2]|0)>=(c[(c[l>>2]|0)+8>>2]|0))break;c[u>>2]=Bc(c[v>>2]|0,c[m>>2]|0,2)|0;if(c[u>>2]|0){x=13;break}q=ae(c[r>>2]|0)|0;c[v>>2]=(c[v>>2]|0)+q;c[t>>2]=(c[t>>2]|0)+1}if((x|0)==13){c[k>>2]=c[u>>2];w=c[k>>2]|0;i=j;return w|0}while(1){if((c[t>>2]|0)>=(c[(c[l>>2]|0)+4>>2]|0)){x=19;break}c[u>>2]=Bc(c[v>>2]|0,c[m>>2]|0,1)|0;if(c[u>>2]|0){x=17;break}r=ae(c[s>>2]|0)|0;c[v>>2]=(c[v>>2]|0)+r;c[t>>2]=(c[t>>2]|0)+1}if((x|0)==17){c[k>>2]=c[u>>2];w=c[k>>2]|0;i=j;return w|0}else if((x|0)==19){c[k>>2]=0;w=c[k>>2]|0;i=j;return w|0}}c[k>>2]=-1;w=c[k>>2]|0;i=j;return w|0}function Oc(a,b,d,e,f,g){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;h=i;i=i+48|0;j=h+28|0;k=h+16|0;l=h+4|0;m=h+8|0;n=h+32|0;o=h;p=h+12|0;q=h+24|0;r=h+20|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=g;if((!((c[l>>2]|0)>255|(c[l>>2]|0)<1)?(c[n>>2]|0)<=(c[m>>2]|0):0)?!(((c[m>>2]|0)<1?1:((c[n>>2]|0)+(c[m>>2]|0)|0)>255)|(c[n>>2]|0)<0):0){c[r>>2]=be(Mc(c[m>>2]|0,c[n>>2]|0)|0)|0;if(!(c[r>>2]|0)){if(c[p>>2]|0)c[c[p>>2]>>2]=-7;c[j>>2]=0;s=c[j>>2]|0;i=h;return s|0}c[q>>2]=Nc(c[r>>2]|0,c[k>>2]|0,c[l>>2]|0,c[m>>2]|0,c[n>>2]|0,c[o>>2]|0)|0;if(c[p>>2]|0)c[c[p>>2]>>2]=c[q>>2];if(c[q>>2]|0){ce(c[r>>2]|0);c[r>>2]=0}c[j>>2]=c[r>>2];s=c[j>>2]|0;i=h;return s|0}if(c[p>>2]|0)c[c[p>>2]>>2]=-1;c[j>>2]=0;s=c[j>>2]|0;i=h;return s|0}function Pc(a,b,d,e,f,g){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0;h=i;i=i+32|0;j=h+20|0;k=h+16|0;l=h+12|0;m=h+8|0;n=h+4|0;o=h;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;c[o>>2]=g;g=de(c[j>>2]|0,c[k>>2]|0,c[l>>2]|0,c[m>>2]|0,1,c[n>>2]|0,c[o>>2]|0,0)|0;i=h;return g|0}function Qc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0;e=i;i=i+128|0;f=e+8|0;g=e;h=e+24|0;j=e+16|0;k=e+44|0;l=e+36|0;m=e+32|0;n=e+80|0;o=e+52|0;p=e+40|0;q=e+48|0;r=e+28|0;s=e+56|0;t=e+60|0;u=e+64|0;v=e+72|0;w=e+68|0;x=e+76|0;y=e+96|0;z=e+100|0;A=e+104|0;B=e+108|0;C=e+112|0;D=e+116|0;E=e+120|0;F=e+124|0;c[l>>2]=a;c[m>>2]=b;c[r>>2]=0;c[n>>2]=d;c[o>>2]=Ac(2)|0;c[p>>2]=Ac(1)|0;d=c[l>>2]|0;c[q>>2]=d+(ae(268)|0);a:do switch(c[m>>2]|0){case 4031:{d=(c[n>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[n>>2]=d+4;c[v>>2]=b;if(c[v>>2]|0){c[c[v>>2]>>2]=0;c[u>>2]=0;while(1){if((c[u>>2]|0)>=(c[(c[l>>2]|0)+4>>2]|0)){G=37;break a}c[x>>2]=c[q>>2];if((c[u>>2]|0)<(c[(c[l>>2]|0)+8>>2]|0)){b=ae(c[o>>2]|0)|0;c[q>>2]=(c[q>>2]|0)+b}else{b=ae(c[p>>2]|0)|0;c[q>>2]=(c[q>>2]|0)+b}b=c[x>>2]|0;d=c[m>>2]|0;c[h>>2]=w;c[r>>2]=Fc(b,d,h)|0;if(c[r>>2]|0){G=37;break a}d=c[v>>2]|0;c[d>>2]=c[d>>2]^c[w>>2];c[u>>2]=(c[u>>2]|0)+1}}else G=38;break}case 4028:{c[y>>2]=0;while(1){if((c[y>>2]|0)>=(c[(c[l>>2]|0)+4>>2]|0)){G=37;break a}c[z>>2]=c[q>>2];if((c[y>>2]|0)<(c[(c[l>>2]|0)+8>>2]|0)){d=ae(c[o>>2]|0)|0;c[q>>2]=(c[q>>2]|0)+d}else{d=ae(c[p>>2]|0)|0;c[q>>2]=(c[q>>2]|0)+d}c[r>>2]=Fc(c[z>>2]|0,4028,g)|0;if(c[r>>2]|0){G=37;break a}c[y>>2]=(c[y>>2]|0)+1}break}case 5122:{d=(c[n>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[n>>2]=d+4;c[B>>2]=b;if(!((c[B>>2]|0)>=0?(c[B>>2]|0)<(c[(c[l>>2]|0)+4>>2]|0):0))c[r>>2]=-1;b=(c[n>>2]|0)+(4-1)&~(4-1);d=c[b>>2]|0;c[n>>2]=b+4;c[C>>2]=d;if(c[C>>2]|0){c[A>>2]=0;while(1){if((c[A>>2]|0)>=(c[B>>2]|0))break;if((c[A>>2]|0)<(c[(c[l>>2]|0)+8>>2]|0)){d=ae(c[o>>2]|0)|0;c[q>>2]=(c[q>>2]|0)+d}else{d=ae(c[p>>2]|0)|0;c[q>>2]=(c[q>>2]|0)+d}c[A>>2]=(c[A>>2]|0)+1}c[c[C>>2]>>2]=c[q>>2];G=37}else G=38;break}case 4034:{d=(c[n>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[n>>2]=d+4;c[E>>2]=b;c[D>>2]=0;while(1){if((c[D>>2]|0)>=(c[(c[l>>2]|0)+4>>2]|0)){G=37;break a}c[F>>2]=c[q>>2];if((c[D>>2]|0)<(c[(c[l>>2]|0)+8>>2]|0)){b=ae(c[o>>2]|0)|0;c[q>>2]=(c[q>>2]|0)+b}else{b=ae(c[p>>2]|0)|0;c[q>>2]=(c[q>>2]|0)+b}b=c[F>>2]|0;d=c[m>>2]|0;c[f>>2]=c[E>>2];c[r>>2]=Fc(b,d,f)|0;if(c[r>>2]|0){G=37;break a}c[D>>2]=(c[D>>2]|0)+1}break}case 4039:case 4045:case 4029:case 4009:{d=(c[n>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[n>>2]=d+4;c[t>>2]=b;c[s>>2]=c[q>>2];b=c[s>>2]|0;d=c[m>>2]|0;c[j>>2]=c[t>>2];c[r>>2]=Fc(b,d,j)|0;G=37;break}default:{c[r>>2]=-5;G=37}}while(0);if((G|0)==37){c[k>>2]=c[r>>2];H=c[k>>2]|0;i=e;return H|0}else if((G|0)==38){c[k>>2]=-1;H=c[k>>2]|0;i=e;return H|0}return 0}function Rc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>>>0)/((c[f>>2]|0)>>>0)|0|0}function Sc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return (c[e>>2]|0)/(c[f>>2]|0)|0|0}function Tc(a,b,e,f,h,j,k,l,m,n,o){a=a|0;b=b|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;m=+m;n=n|0;o=o|0;var p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,P=0,Q=0,R=0;p=i;i=i+112|0;q=p+48|0;r=p+44|0;s=p+84|0;t=p+92|0;u=p+40|0;v=p+16|0;w=p+20|0;x=p+24|0;y=p+28|0;z=p+72|0;A=p+80|0;B=p+88|0;C=p+96|0;D=p+100|0;E=p+52|0;F=p+56|0;G=p+60|0;H=p+64|0;I=p+8|0;J=p+12|0;K=p+68|0;L=p+32|0;M=p+36|0;N=p+76|0;P=p;Q=p+4|0;c[r>>2]=a;c[s>>2]=b;c[t>>2]=e;c[u>>2]=f;c[v>>2]=h;c[w>>2]=j;c[x>>2]=k;c[y>>2]=l;g[z>>2]=m;c[A>>2]=n;c[B>>2]=o;c[C>>2]=c[t>>2];c[D>>2]=c[t>>2];c[F>>2]=c[v>>2];c[G>>2]=0;c[H>>2]=0;c[J>>2]=0;c[K>>2]=((c[c[r>>2]>>2]|0)!=0^1)&1;c[M>>2]=c[c[r>>2]>>2];c[N>>2]=c[(c[r>>2]|0)+20>>2];c[I>>2]=(c[F>>2]|0)==1&1;c[D>>2]=Rc(c[D>>2]|0,c[v>>2]|0)|0;if((c[t>>2]|0)==1){c[q>>2]=Ce(c[r>>2]|0,c[s>>2]|0,0,c[u>>2]|0,c[y>>2]|0)|0;R=c[q>>2]|0;i=p;return R|0}if((c[N>>2]|0)>0)c[H>>2]=c[N>>2];do if((c[A>>2]|0)!=0&(c[w>>2]|0)!=0){if((c[H>>2]|0)==0?!((c[D>>2]&1|0)==0&(c[N>>2]|0)<0|(c[F>>2]|0)>1):0)break;df(c[A>>2]|0,c[w>>2]|0,(c[t>>2]<<2)+0|0)|0;c[w>>2]=c[A>>2]}while(0);c[L>>2]=0;while(1){if((c[L>>2]|0)>=(c[H>>2]|0))break;if(c[M>>2]|0)Ua(c[s>>2]|0,c[t>>2]>>c[L>>2],1<<c[L>>2]);if(c[w>>2]|0)Ua(c[w>>2]|0,c[t>>2]>>c[L>>2],1<<c[L>>2]);c[B>>2]=d[25096+(c[B>>2]&15)>>0]|0|(d[25096+(c[B>>2]>>4)>>0]|0)<<2;c[L>>2]=(c[L>>2]|0)+1}c[v>>2]=c[v>>2]>>c[H>>2];c[D>>2]=c[D>>2]<<c[H>>2];while(1){if(!((c[D>>2]&1|0)==0?(c[N>>2]|0)<0:0))break;if(c[M>>2]|0)Ua(c[s>>2]|0,c[D>>2]|0,c[v>>2]|0);if(c[w>>2]|0)Ua(c[w>>2]|0,c[D>>2]|0,c[v>>2]|0);c[B>>2]=c[B>>2]|c[B>>2]<<c[v>>2];c[v>>2]=c[v>>2]<<1;c[D>>2]=c[D>>2]>>1;c[G>>2]=(c[G>>2]|0)+1;c[N>>2]=(c[N>>2]|0)+1}c[F>>2]=c[v>>2];c[E>>2]=c[D>>2];if((c[F>>2]|0)>1){if(c[M>>2]|0)Le(c[s>>2]|0,c[D>>2]>>c[H>>2],c[F>>2]<<c[H>>2],c[I>>2]|0);if(c[w>>2]|0)Le(c[w>>2]|0,c[D>>2]>>c[H>>2],c[F>>2]<<c[H>>2],c[I>>2]|0)}c[J>>2]=Me(c[r>>2]|0,c[s>>2]|0,c[t>>2]|0,c[u>>2]|0,c[v>>2]|0,c[w>>2]|0,c[x>>2]|0,+g[z>>2],c[B>>2]|0)|0;if(c[K>>2]|0){if((c[F>>2]|0)>1)Ne(c[s>>2]|0,c[D>>2]>>c[H>>2],c[F>>2]<<c[H>>2],c[I>>2]|0);c[D>>2]=c[E>>2];c[v>>2]=c[F>>2];c[L>>2]=0;while(1){if((c[L>>2]|0)>=(c[G>>2]|0))break;c[v>>2]=c[v>>2]>>1;c[D>>2]=c[D>>2]<<1;c[J>>2]=c[J>>2]|(c[J>>2]|0)>>>(c[v>>2]|0);Ua(c[s>>2]|0,c[D>>2]|0,c[v>>2]|0);c[L>>2]=(c[L>>2]|0)+1}c[L>>2]=0;while(1){if((c[L>>2]|0)>=(c[H>>2]|0))break;c[J>>2]=d[25112+(c[J>>2]|0)>>0];Ua(c[s>>2]|0,c[C>>2]>>c[L>>2],1<<c[L>>2]);c[L>>2]=(c[L>>2]|0)+1}c[v>>2]=c[v>>2]<<c[H>>2];a:do if(c[y>>2]|0){g[Q>>2]=+O(+(+(c[C>>2]|0)));c[P>>2]=0;while(1){if((c[P>>2]|0)>=(c[C>>2]|0))break a;g[(c[y>>2]|0)+(c[P>>2]<<2)>>2]=+g[Q>>2]*+g[(c[s>>2]|0)+(c[P>>2]<<2)>>2];c[P>>2]=(c[P>>2]|0)+1}}while(0);c[J>>2]=c[J>>2]&(1<<c[v>>2])-1}c[q>>2]=c[J>>2];R=c[q>>2]|0;i=p;return R|0}function Uc(a,b,d,e,f,h,j,k,l,m,n){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;var o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0;o=i;i=i+176|0;p=o+156|0;q=o+132|0;r=o+8|0;s=o+56|0;t=o+64|0;u=o+16|0;v=o+20|0;w=o+24|0;x=o+28|0;y=o+32|0;z=o+36|0;A=o+40|0;B=o+44|0;C=o+128|0;D=o+136|0;E=o+144|0;F=o+152|0;G=o+160|0;H=o+68|0;I=o+72|0;J=o+76|0;K=o+80|0;L=o+84|0;M=o+88|0;N=o+96|0;O=o+12|0;P=o+4|0;Q=o;R=o+120|0;S=o+48|0;T=o+124|0;U=o+52|0;V=o+140|0;W=o+60|0;X=o+148|0;c[q>>2]=a;c[r>>2]=b;c[s>>2]=d;c[t>>2]=e;c[u>>2]=f;c[v>>2]=h;c[w>>2]=j;c[x>>2]=k;c[y>>2]=l;c[z>>2]=m;c[A>>2]=n;c[B>>2]=0;c[C>>2]=0;c[D>>2]=0;g[E>>2]=0.0;g[F>>2]=0.0;c[G>>2]=0;c[H>>2]=((c[c[q>>2]>>2]|0)!=0^1)&1;c[P>>2]=c[c[q>>2]>>2];c[Q>>2]=c[(c[q>>2]|0)+24>>2];if((c[t>>2]|0)==1){c[p>>2]=Ce(c[q>>2]|0,c[r>>2]|0,c[s>>2]|0,c[u>>2]|0,c[y>>2]|0)|0;Y=c[p>>2]|0;i=o;return Y|0}c[O>>2]=c[A>>2];De(c[q>>2]|0,N,c[r>>2]|0,c[s>>2]|0,c[t>>2]|0,u,c[v>>2]|0,c[v>>2]|0,c[x>>2]|0,1,A);c[D>>2]=c[N>>2];c[B>>2]=c[N+4>>2];c[C>>2]=c[N+8>>2];c[K>>2]=c[N+12>>2];c[L>>2]=c[N+16>>2];c[M>>2]=c[N+20>>2];g[E>>2]=+(c[B>>2]|0)*.000030517578125;g[F>>2]=+(c[C>>2]|0)*.000030517578125;do if((c[t>>2]|0)==2){c[S>>2]=0;c[I>>2]=c[u>>2];c[J>>2]=0;c[J>>2]=(c[L>>2]|0)!=0&(c[L>>2]|0)!=16384?8:0;c[I>>2]=(c[I>>2]|0)-(c[J>>2]|0);c[R>>2]=(c[L>>2]|0)>8192&1;C=(c[q>>2]|0)+28|0;c[C>>2]=(c[C>>2]|0)-((c[M>>2]|0)+(c[J>>2]|0));c[T>>2]=(c[R>>2]|0)!=0?c[s>>2]|0:c[r>>2]|0;c[U>>2]=(c[R>>2]|0)!=0?c[r>>2]|0:c[s>>2]|0;do if(c[J>>2]|0)if(c[P>>2]|0){c[S>>2]=+g[c[T>>2]>>2]*+g[(c[U>>2]|0)+4>>2]-+g[(c[T>>2]|0)+4>>2]*+g[c[U>>2]>>2]<0.0&1;pb(c[Q>>2]|0,c[S>>2]|0,1);break}else{c[S>>2]=lb(c[Q>>2]|0,1)|0;break}while(0);c[S>>2]=1-(c[S>>2]<<1);c[G>>2]=Tc(c[q>>2]|0,c[T>>2]|0,c[t>>2]|0,c[I>>2]|0,c[v>>2]|0,c[w>>2]|0,c[x>>2]|0,c[y>>2]|0,1.0,c[z>>2]|0,c[O>>2]|0)|0;g[c[U>>2]>>2]=+(0-(c[S>>2]|0)|0)*+g[(c[T>>2]|0)+4>>2];g[(c[U>>2]|0)+4>>2]=+(c[S>>2]|0)*+g[c[T>>2]>>2];if(c[H>>2]|0){g[c[r>>2]>>2]=+g[E>>2]*+g[c[r>>2]>>2];g[(c[r>>2]|0)+4>>2]=+g[E>>2]*+g[(c[r>>2]|0)+4>>2];g[c[s>>2]>>2]=+g[F>>2]*+g[c[s>>2]>>2];g[(c[s>>2]|0)+4>>2]=+g[F>>2]*+g[(c[s>>2]|0)+4>>2];g[V>>2]=+g[c[r>>2]>>2];g[c[r>>2]>>2]=+g[V>>2]-+g[c[s>>2]>>2];g[c[s>>2]>>2]=+g[V>>2]+ +g[c[s>>2]>>2];g[V>>2]=+g[(c[r>>2]|0)+4>>2];g[(c[r>>2]|0)+4>>2]=+g[V>>2]-+g[(c[s>>2]|0)+4>>2];g[(c[s>>2]|0)+4>>2]=+g[V>>2]+ +g[(c[s>>2]|0)+4>>2]}}else{C=c[u>>2]|0;if((c[u>>2]|0)<(((c[u>>2]|0)-(c[K>>2]|0)|0)/2|0|0))Z=C;else Z=(C-(c[K>>2]|0)|0)/2|0;if(0<=(Z|0)){C=c[u>>2]|0;if((c[u>>2]|0)<(((c[u>>2]|0)-(c[K>>2]|0)|0)/2|0|0))_=C;else _=(C-(c[K>>2]|0)|0)/2|0}else _=0;c[I>>2]=_;c[J>>2]=(c[u>>2]|0)-(c[I>>2]|0);C=(c[q>>2]|0)+28|0;c[C>>2]=(c[C>>2]|0)-(c[M>>2]|0);c[W>>2]=c[(c[q>>2]|0)+28>>2];C=c[q>>2]|0;if((c[I>>2]|0)>=(c[J>>2]|0)){c[G>>2]=Tc(C,c[r>>2]|0,c[t>>2]|0,c[I>>2]|0,c[v>>2]|0,c[w>>2]|0,c[x>>2]|0,c[y>>2]|0,1.0,c[z>>2]|0,c[A>>2]|0)|0;c[W>>2]=(c[I>>2]|0)-((c[W>>2]|0)-(c[(c[q>>2]|0)+28>>2]|0));if((c[W>>2]|0)>24&(c[L>>2]|0)!=0)c[J>>2]=(c[J>>2]|0)+((c[W>>2]|0)-24);B=Tc(c[q>>2]|0,c[s>>2]|0,c[t>>2]|0,c[J>>2]|0,c[v>>2]|0,0,c[x>>2]|0,0,+g[F>>2],0,c[A>>2]>>c[v>>2])|0;c[G>>2]=c[G>>2]|B;break}else{c[G>>2]=Tc(C,c[s>>2]|0,c[t>>2]|0,c[J>>2]|0,c[v>>2]|0,0,c[x>>2]|0,0,+g[F>>2],0,c[A>>2]>>c[v>>2])|0;c[W>>2]=(c[J>>2]|0)-((c[W>>2]|0)-(c[(c[q>>2]|0)+28>>2]|0));if((c[W>>2]|0)>24&(c[L>>2]|0)!=16384)c[I>>2]=(c[I>>2]|0)+((c[W>>2]|0)-24);C=Tc(c[q>>2]|0,c[r>>2]|0,c[t>>2]|0,c[I>>2]|0,c[v>>2]|0,c[w>>2]|0,c[x>>2]|0,c[y>>2]|0,1.0,c[z>>2]|0,c[A>>2]|0)|0;c[G>>2]=c[G>>2]|C;break}}while(0);a:do if(c[H>>2]|0){if((c[t>>2]|0)!=2)Ee(c[r>>2]|0,c[s>>2]|0,+g[E>>2],c[t>>2]|0);if(c[D>>2]|0){c[X>>2]=0;while(1){if((c[X>>2]|0)>=(c[t>>2]|0))break a;g[(c[s>>2]|0)+(c[X>>2]<<2)>>2]=-+g[(c[s>>2]|0)+(c[X>>2]<<2)>>2];c[X>>2]=(c[X>>2]|0)+1}}}while(0);c[p>>2]=c[G>>2];Y=c[p>>2]|0;i=o;return Y|0}function Vc(a,b,d,e,f,h,j){a=a|0;b=b|0;d=d|0;e=e|0;f=+f;h=+h;j=+j;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;k=i;i=i+64|0;l=k+44|0;m=k+36|0;n=k+20|0;o=k+16|0;p=k+32|0;q=k+40|0;r=k+48|0;s=k+8|0;t=k+4|0;u=k+24|0;v=k+12|0;w=k+28|0;x=k;c[l>>2]=a;c[m>>2]=b;c[n>>2]=d;c[o>>2]=e;g[p>>2]=f;g[q>>2]=h;g[r>>2]=j;g[w>>2]=+g[(c[m>>2]|0)+(0-(c[n>>2]|0)-2<<2)>>2];g[v>>2]=+g[(c[m>>2]|0)+(0-(c[n>>2]|0)-1<<2)>>2];g[u>>2]=+g[(c[m>>2]|0)+(0-(c[n>>2]|0)<<2)>>2];g[t>>2]=+g[(c[m>>2]|0)+(0-(c[n>>2]|0)+1<<2)>>2];c[x>>2]=0;while(1){if((c[x>>2]|0)>=(c[o>>2]|0))break;g[s>>2]=+g[(c[m>>2]|0)+((c[x>>2]|0)-(c[n>>2]|0)+2<<2)>>2];g[(c[l>>2]|0)+(c[x>>2]<<2)>>2]=+g[(c[m>>2]|0)+(c[x>>2]<<2)>>2]+ +g[p>>2]*+g[u>>2]+ +g[q>>2]*(+g[t>>2]+ +g[v>>2])+ +g[r>>2]*(+g[s>>2]+ +g[w>>2]);g[w>>2]=+g[v>>2];g[v>>2]=+g[u>>2];g[u>>2]=+g[t>>2];g[t>>2]=+g[s>>2];c[x>>2]=(c[x>>2]|0)+1}i=k;return}function Wc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[e>>2]=a;c[f>>2]=b;b=88+((_(c[f>>2]|0,2048+(c[(c[e>>2]|0)+4>>2]|0)|0)|0)-1<<2)|0;c[g>>2]=b+((c[f>>2]|0)*24<<2)+(c[(c[e>>2]|0)+8>>2]<<3<<2);i=d;return c[g>>2]|0}function Xc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;if((c[j>>2]|0)<0|(c[j>>2]|0)>2){c[f>>2]=-1;k=c[f>>2]|0;i=e;return k|0}if(!(c[g>>2]|0)){c[f>>2]=-7;k=c[f>>2]|0;i=e;return k|0}else{d=c[g>>2]|0;bf(d|0,0,Wc(c[h>>2]|0,c[j>>2]|0)|0)|0;c[c[g>>2]>>2]=c[h>>2];c[(c[g>>2]|0)+4>>2]=c[(c[h>>2]|0)+4>>2];h=c[j>>2]|0;c[(c[g>>2]|0)+8>>2]=h;c[(c[g>>2]|0)+12>>2]=h;c[(c[g>>2]|0)+16>>2]=1;c[(c[g>>2]|0)+20>>2]=0;c[(c[g>>2]|0)+24>>2]=c[(c[c[g>>2]>>2]|0)+12>>2];c[(c[g>>2]|0)+28>>2]=1;h=Be()|0;c[(c[g>>2]|0)+32>>2]=h;c[(c[g>>2]|0)+48>>2]=0;ab(c[g>>2]|0,4028,e)|0;c[f>>2]=0;k=c[f>>2]|0;i=e;return k|0}return 0}function Yc(a,d,e){a=a|0;d=d|0;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0;f=i;i=i+4624|0;h=f+212|0;j=f+204|0;k=f+4568|0;l=f+12|0;m=f+4584|0;n=f+4600|0;o=f+24|0;p=f+32|0;q=f+40|0;r=f+44|0;s=f+48|0;t=f+52|0;u=f+56|0;v=f+60|0;w=f+64|0;x=f+68|0;y=f+72|0;z=f+76|0;A=f+80|0;B=f+84|0;C=f+88|0;D=f+92|0;E=f+4572|0;F=f+4580|0;G=f+4588|0;H=f+4596|0;I=f+4604|0;J=f+4608|0;K=f+216|0;L=f+220|0;M=f+224|0;N=f+228|0;P=f+232|0;Q=f+240|0;R=f+4336|0;S=f+4340|0;T=f+4344|0;U=f+4348|0;V=f+4352|0;W=f+4356|0;X=f+4360|0;Y=f+4364|0;Z=f+4368|0;$=f+4472|0;aa=f+16|0;ba=f+4|0;ca=f+8|0;da=f;ea=f+96|0;fa=f+104|0;ga=f+4576|0;ha=f+200|0;ia=f+4592|0;ja=f+208|0;c[h>>2]=a;c[j>>2]=d;c[k>>2]=e;c[n>>2]=c[(c[h>>2]|0)+8>>2];c[v>>2]=c[c[h>>2]>>2];c[w>>2]=c[(c[v>>2]|0)+8>>2];c[x>>2]=c[(c[v>>2]|0)+4>>2];c[B>>2]=c[(c[v>>2]|0)+32>>2];c[l>>2]=0;do{e=(c[h>>2]|0)+84+((_(c[l>>2]|0,2048+(c[x>>2]|0)|0)|0)<<2)|0;c[o+(c[l>>2]<<2)>>2]=e;c[p+(c[l>>2]<<2)>>2]=(c[o+(c[l>>2]<<2)>>2]|0)+8192+(0-(c[j>>2]|0)<<2);e=(c[l>>2]|0)+1|0;c[l>>2]=e}while((e|0)<(c[n>>2]|0));c[q>>2]=(c[h>>2]|0)+84+((_(2048+(c[x>>2]|0)|0,c[n>>2]|0)|0)<<2);c[r>>2]=(c[q>>2]|0)+((c[n>>2]|0)*24<<2);c[s>>2]=(c[r>>2]|0)+(c[w>>2]<<1<<2);c[t>>2]=(c[s>>2]|0)+(c[w>>2]<<1<<2);c[u>>2]=(c[t>>2]|0)+(c[w>>2]<<1<<2);c[z>>2]=c[(c[h>>2]|0)+48>>2];c[y>>2]=c[(c[h>>2]|0)+20>>2];c[A>>2]=((c[z>>2]|0)>=5?1:(c[y>>2]|0)!=0)&1;if(c[A>>2]|0){c[E>>2]=c[(c[h>>2]|0)+24>>2];if((c[E>>2]|0)<(c[(c[v>>2]|0)+12>>2]|0))la=c[E>>2]|0;else la=c[(c[v>>2]|0)+12>>2]|0;do if((c[y>>2]|0)<=(la|0))if((c[E>>2]|0)<(c[(c[v>>2]|0)+12>>2]|0)){ma=c[E>>2]|0;break}else{ma=c[(c[v>>2]|0)+12>>2]|0;break}else ma=c[y>>2]|0;while(0);c[F>>2]=ma;ma=_(c[n>>2]|0,c[j>>2]|0)|0;c[G>>2]=ua()|0;la=i;i=i+((1*(ma<<2)|0)+15&-16)|0;if((c[z>>2]|0)>=5)c[D>>2]=c[u>>2];else{g[H>>2]=(c[z>>2]|0)==0?1.5:.5;c[l>>2]=0;do{c[m>>2]=c[y>>2];while(1){if((c[m>>2]|0)>=(c[E>>2]|0))break;u=_(c[l>>2]|0,c[w>>2]|0)|0;ma=(c[r>>2]|0)+(u+(c[m>>2]|0)<<2)|0;g[ma>>2]=+g[ma>>2]-+g[H>>2];c[m>>2]=(c[m>>2]|0)+1}ma=(c[l>>2]|0)+1|0;c[l>>2]=ma}while((ma|0)<(c[n>>2]|0));c[D>>2]=c[r>>2]}c[C>>2]=c[(c[h>>2]|0)+36>>2];c[l>>2]=0;while(1){if((c[l>>2]|0)>=(c[n>>2]|0))break;c[m>>2]=c[y>>2];while(1){if((c[m>>2]|0)>=(c[F>>2]|0))break;r=_(c[j>>2]|0,c[l>>2]|0)|0;c[J>>2]=r+(b[(c[B>>2]|0)+(c[m>>2]<<1)>>1]<<c[k>>2]);c[K>>2]=(b[(c[B>>2]|0)+((c[m>>2]|0)+1<<1)>>1]|0)-(b[(c[B>>2]|0)+(c[m>>2]<<1)>>1]|0)<<c[k>>2];c[I>>2]=0;while(1){if((c[I>>2]|0)>=(c[K>>2]|0))break;c[C>>2]=Ra(c[C>>2]|0)|0;g[la+((c[J>>2]|0)+(c[I>>2]|0)<<2)>>2]=+(c[C>>2]>>20|0);c[I>>2]=(c[I>>2]|0)+1}Ib(la+(c[J>>2]<<2)|0,c[K>>2]|0,1.0);c[m>>2]=(c[m>>2]|0)+1}c[l>>2]=(c[l>>2]|0)+1}c[(c[h>>2]|0)+36>>2]=c[C>>2];c[l>>2]=0;do{ff(c[o+(c[l>>2]<<2)>>2]|0,(c[o+(c[l>>2]<<2)>>2]|0)+(c[j>>2]<<2)|0,(2048-(c[j>>2]|0)+(c[x>>2]>>1)<<2)+0|0)|0;C=(c[l>>2]|0)+1|0;c[l>>2]=C}while((C|0)<(c[n>>2]|0));ad(c[v>>2]|0,la,p,c[D>>2]|0,c[y>>2]|0,c[F>>2]|0,c[n>>2]|0,c[n>>2]|0,0,c[k>>2]|0,c[(c[h>>2]|0)+16>>2]|0,0);ka(c[G>>2]|0);na=c[z>>2]|0;oa=na+1|0;pa=c[h>>2]|0;qa=pa+48|0;c[qa>>2]=oa;i=f;return}g[M>>2]=1.0;if(!(c[z>>2]|0)){G=Ae(o,c[n>>2]|0,c[(c[h>>2]|0)+32>>2]|0)|0;c[N>>2]=G;c[(c[h>>2]|0)+44>>2]=G}else{c[N>>2]=c[(c[h>>2]|0)+44>>2];g[M>>2]=.800000011920929}G=c[x>>2]|0;c[P>>2]=ua()|0;k=i;i=i+((1*(G<<2)|0)+15&-16)|0;c[L>>2]=c[(c[v>>2]|0)+60>>2];c[l>>2]=0;do{g[T>>2]=0.0;c[U>>2]=c[o+(c[l>>2]<<2)>>2];c[m>>2]=0;while(1){if((c[m>>2]|0)>=1024)break;g[Q+(c[m>>2]<<2)>>2]=+g[(c[U>>2]|0)+(1024+(c[m>>2]|0)<<2)>>2];c[m>>2]=(c[m>>2]|0)+1}if(!(c[z>>2]|0)){Bb(Q,Z,c[L>>2]|0,c[x>>2]|0,24,1024,c[(c[h>>2]|0)+32>>2]|0)|0;g[Z>>2]=+g[Z>>2]*1.000100016593933;c[m>>2]=1;while(1){if((c[m>>2]|0)>24)break;v=Z+(c[m>>2]<<2)|0;g[v>>2]=+g[v>>2]-+g[Z+(c[m>>2]<<2)>>2]*6.400000711437315e-05*+(c[m>>2]|0)*+(c[m>>2]|0);c[m>>2]=(c[m>>2]|0)+1}yb((c[q>>2]|0)+((c[l>>2]|0)*24<<2)|0,Z,24)}c[X>>2]=(c[N>>2]<<1|0)<1024?c[N>>2]<<1:1024;c[m>>2]=0;while(1){if((c[m>>2]|0)>=24)break;g[$+(c[m>>2]<<2)>>2]=+g[(c[U>>2]|0)+(2048-(c[X>>2]|0)-1-(c[m>>2]|0)<<2)>>2];c[m>>2]=(c[m>>2]|0)+1}zb(Q+4096+(0-(c[X>>2]|0)<<2)|0,(c[q>>2]|0)+((c[l>>2]|0)*24<<2)|0,Q+4096+(0-(c[X>>2]|0)<<2)|0,c[X>>2]|0,24,$);g[aa>>2]=1.0;g[ba>>2]=1.0;c[ca>>2]=c[X>>2]>>1;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[ca>>2]|0))break;g[da>>2]=+g[Q+(1024-(c[ca>>2]|0)+(c[m>>2]|0)<<2)>>2];g[aa>>2]=+g[aa>>2]+ +g[da>>2]*+g[da>>2];g[da>>2]=+g[Q+(1024-(c[ca>>2]<<1)+(c[m>>2]|0)<<2)>>2];g[ba>>2]=+g[ba>>2]+ +g[da>>2]*+g[da>>2];c[m>>2]=(c[m>>2]|0)+1}g[aa>>2]=+g[aa>>2]<+g[ba>>2]?+g[aa>>2]:+g[ba>>2];g[R>>2]=+O(+(+g[aa>>2]/+g[ba>>2]));ff(c[U>>2]|0,(c[U>>2]|0)+(c[j>>2]<<2)|0,(2048-(c[j>>2]|0)<<2)+0|0)|0;c[V>>2]=1024-(c[N>>2]|0);c[W>>2]=(c[j>>2]|0)+(c[x>>2]|0);g[S>>2]=+g[M>>2]*+g[R>>2];c[Y>>2]=0;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[W>>2]|0))break;if((c[Y>>2]|0)>=(c[N>>2]|0)){c[Y>>2]=(c[Y>>2]|0)-(c[N>>2]|0);g[S>>2]=+g[S>>2]*+g[R>>2]}g[(c[U>>2]|0)+(2048-(c[j>>2]|0)+(c[m>>2]|0)<<2)>>2]=+g[S>>2]*+g[Q+((c[V>>2]|0)+(c[Y>>2]|0)<<2)>>2];g[ea>>2]=+g[(c[U>>2]|0)+(1024-(c[j>>2]|0)+(c[V>>2]|0)+(c[Y>>2]|0)<<2)>>2];g[T>>2]=+g[T>>2]+ +g[ea>>2]*+g[ea>>2];c[m>>2]=(c[m>>2]|0)+1;c[Y>>2]=(c[Y>>2]|0)+1}c[m>>2]=0;while(1){if((c[m>>2]|0)>=24)break;g[fa+(c[m>>2]<<2)>>2]=+g[(c[U>>2]|0)+(2048-(c[j>>2]|0)-1-(c[m>>2]|0)<<2)>>2];c[m>>2]=(c[m>>2]|0)+1}Ab((c[U>>2]|0)+8192+(0-(c[j>>2]|0)<<2)|0,(c[q>>2]|0)+((c[l>>2]|0)*24<<2)|0,(c[U>>2]|0)+8192+(0-(c[j>>2]|0)<<2)|0,c[W>>2]|0,24,fa);g[ga>>2]=0.0;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[W>>2]|0))break;g[ha>>2]=+g[(c[U>>2]|0)+(2048-(c[j>>2]|0)+(c[m>>2]|0)<<2)>>2];g[ga>>2]=+g[ga>>2]+ +g[ha>>2]*+g[ha>>2];c[m>>2]=(c[m>>2]|0)+1}a:do if(+g[T>>2]>+g[ga>>2]*.20000000298023224){if(+g[T>>2]<+g[ga>>2]){g[ia>>2]=+O(+((+g[T>>2]+1.0)/(+g[ga>>2]+1.0)));c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[x>>2]|0))break;g[ja>>2]=1.0-+g[(c[L>>2]|0)+(c[m>>2]<<2)>>2]*(1.0-+g[ia>>2]);g[(c[U>>2]|0)+(2048-(c[j>>2]|0)+(c[m>>2]|0)<<2)>>2]=+g[ja>>2]*+g[(c[U>>2]|0)+(2048-(c[j>>2]|0)+(c[m>>2]|0)<<2)>>2];c[m>>2]=(c[m>>2]|0)+1}c[m>>2]=c[x>>2];while(1){if((c[m>>2]|0)>=(c[W>>2]|0))break a;g[(c[U>>2]|0)+(2048-(c[j>>2]|0)+(c[m>>2]|0)<<2)>>2]=+g[ia>>2]*+g[(c[U>>2]|0)+(2048-(c[j>>2]|0)+(c[m>>2]|0)<<2)>>2];c[m>>2]=(c[m>>2]|0)+1}}}else{c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[W>>2]|0))break a;g[(c[U>>2]|0)+(2048-(c[j>>2]|0)+(c[m>>2]|0)<<2)>>2]=0.0;c[m>>2]=(c[m>>2]|0)+1}}while(0);Xa(k,(c[U>>2]|0)+8192|0,c[(c[h>>2]|0)+52>>2]|0,c[(c[h>>2]|0)+52>>2]|0,c[x>>2]|0,-+g[(c[h>>2]|0)+60>>2],-+g[(c[h>>2]|0)+60>>2],c[(c[h>>2]|0)+68>>2]|0,c[(c[h>>2]|0)+68>>2]|0,0,0);c[m>>2]=0;while(1){if((c[m>>2]|0)>=((c[x>>2]|0)/2|0|0))break;g[(c[U>>2]|0)+(2048+(c[m>>2]|0)<<2)>>2]=+g[(c[L>>2]|0)+(c[m>>2]<<2)>>2]*+g[k+((c[x>>2]|0)-1-(c[m>>2]|0)<<2)>>2]+ +g[(c[L>>2]|0)+((c[x>>2]|0)-(c[m>>2]|0)-1<<2)>>2]*+g[k+(c[m>>2]<<2)>>2];c[m>>2]=(c[m>>2]|0)+1}v=(c[l>>2]|0)+1|0;c[l>>2]=v}while((v|0)<(c[n>>2]|0));ka(c[P>>2]|0);na=c[z>>2]|0;oa=na+1|0;pa=c[h>>2]|0;qa=pa+48|0;c[qa>>2]=oa;i=f;return}function Zc(a,b,d,e,f,h,j,k){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0.0;l=i;i=i+80|0;m=l+68|0;n=l+44|0;o=l+24|0;p=l+32|0;q=l+12|0;r=l+16|0;s=l+48|0;t=l+64|0;u=l+72|0;v=l+36|0;w=l+8|0;x=l;y=l+4|0;z=l+40|0;A=l+20|0;B=l+52|0;C=l+28|0;D=l+60|0;c[m>>2]=a;c[n>>2]=b;c[o>>2]=d;c[p>>2]=e;c[q>>2]=f;c[r>>2]=h;c[s>>2]=j;c[l+56>>2]=k;c[v>>2]=0;k=c[o>>2]|0;c[x>>2]=ua()|0;j=i;i=i+((1*(k<<2)|0)+15&-16)|0;g[w>>2]=+g[c[r>>2]>>2];c[u>>2]=(c[o>>2]|0)/(c[q>>2]|0)|0;c[t>>2]=0;do{g[B>>2]=+g[(c[s>>2]|0)+(c[t>>2]<<2)>>2];c[z>>2]=c[(c[m>>2]|0)+(c[t>>2]<<2)>>2];c[A>>2]=(c[n>>2]|0)+(c[t>>2]<<2);r=(c[q>>2]|0)>1;c[y>>2]=0;a:do if(r){while(1){if((c[y>>2]|0)>=(c[o>>2]|0))break;g[C>>2]=+g[(c[z>>2]|0)+(c[y>>2]<<2)>>2]+ +g[B>>2]+1.0000000031710769e-30;g[B>>2]=+g[w>>2]*+g[C>>2];g[j+(c[y>>2]<<2)>>2]=+g[C>>2];c[y>>2]=(c[y>>2]|0)+1}c[v>>2]=1}else while(1){if((c[y>>2]|0)>=(c[o>>2]|0))break a;g[D>>2]=+g[(c[z>>2]|0)+(c[y>>2]<<2)>>2]+ +g[B>>2]+1.0000000031710769e-30;g[B>>2]=+g[w>>2]*+g[D>>2];k=_(c[y>>2]|0,c[p>>2]|0)|0;g[(c[A>>2]|0)+(k<<2)>>2]=+g[D>>2]*.000030517578125;c[y>>2]=(c[y>>2]|0)+1}while(0);g[(c[s>>2]|0)+(c[t>>2]<<2)>>2]=+g[B>>2];b:do if(c[v>>2]|0){c[y>>2]=0;while(1){if((c[y>>2]|0)>=(c[u>>2]|0))break b;E=+g[j+((_(c[y>>2]|0,c[q>>2]|0)|0)<<2)>>2]*.000030517578125;r=_(c[y>>2]|0,c[p>>2]|0)|0;g[(c[A>>2]|0)+(r<<2)>>2]=E;c[y>>2]=(c[y>>2]|0)+1}}while(0);r=(c[t>>2]|0)+1|0;c[t>>2]=r}while((r|0)<(c[p>>2]|0));ka(c[x>>2]|0);i=l;return}function _c(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;a=(c[(c[d>>2]|0)+20>>2]|0)-(32-(aa(c[(c[d>>2]|0)+28>>2]|0)|0))|0;i=b;return a|0}function $c(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0;j=i;i=i+64|0;k=j+24|0;l=j+20|0;m=j+44|0;n=j+36|0;o=j+32|0;p=j+40|0;q=j+48|0;r=j+52|0;s=j+8|0;t=j+4|0;u=j+28|0;v=j+12|0;w=j;x=j+16|0;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;c[o>>2]=g;c[p>>2]=h;c[w>>2]=c[(c[p>>2]|0)+4>>2]<<3;c[x>>2]=_c(c[p>>2]|0)|0;c[v>>2]=(c[m>>2]|0)!=0?2:4;if((c[o>>2]|0)>0)y=((c[x>>2]|0)+(c[v>>2]|0)+1|0)>>>0<=(c[w>>2]|0)>>>0;else y=0;c[t>>2]=y&1;c[w>>2]=(c[w>>2]|0)-(c[t>>2]|0);c[r>>2]=0;c[u>>2]=0;c[q>>2]=c[k>>2];while(1){if((c[q>>2]|0)>=(c[l>>2]|0))break;if(((c[x>>2]|0)+(c[v>>2]|0)|0)>>>0<=(c[w>>2]|0)>>>0){y=ib(c[p>>2]|0,c[v>>2]|0)|0;c[r>>2]=c[r>>2]^y;c[x>>2]=_c(c[p>>2]|0)|0;c[u>>2]=c[u>>2]|c[r>>2]}c[(c[n>>2]|0)+(c[q>>2]<<2)>>2]=c[r>>2];c[v>>2]=(c[m>>2]|0)!=0?4:5;c[q>>2]=(c[q>>2]|0)+1}c[s>>2]=0;if((c[t>>2]|0)!=0?(a[8+(c[o>>2]<<3)+((c[m>>2]<<2)+0+(c[u>>2]|0))>>0]|0)!=(a[8+(c[o>>2]<<3)+((c[m>>2]<<2)+2+(c[u>>2]|0))>>0]|0):0)c[s>>2]=ib(c[p>>2]|0,1)|0;c[q>>2]=c[k>>2];while(1){if((c[q>>2]|0)>=(c[l>>2]|0))break;c[(c[n>>2]|0)+(c[q>>2]<<2)>>2]=a[8+(c[o>>2]<<3)+((c[m>>2]<<2)+(c[s>>2]<<1)+(c[(c[n>>2]|0)+(c[q>>2]<<2)>>2]|0))>>0];c[q>>2]=(c[q>>2]|0)+1}i=j;return}function ad(a,b,d,e,f,h,j,k,l,m,n,o){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;var p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0;p=i;i=i+112|0;q=p+92|0;r=p+84|0;s=p+40|0;t=p+44|0;u=p;v=p+16|0;w=p+20|0;x=p+24|0;y=p+28|0;z=p+72|0;A=p+80|0;B=p+88|0;C=p+96|0;D=p+48|0;E=p+52|0;F=p+56|0;G=p+60|0;H=p+8|0;I=p+64|0;J=p+12|0;K=p+32|0;L=p+68|0;M=p+36|0;N=p+76|0;O=p+4|0;c[q>>2]=a;c[r>>2]=b;c[s>>2]=d;c[t>>2]=e;c[u>>2]=f;c[v>>2]=h;c[w>>2]=j;c[x>>2]=k;c[y>>2]=l;c[z>>2]=m;c[A>>2]=n;c[B>>2]=o;c[L>>2]=c[(c[q>>2]|0)+4>>2];c[K>>2]=c[(c[q>>2]|0)+8>>2];c[H>>2]=c[(c[q>>2]|0)+44>>2]<<c[z>>2];o=c[H>>2]|0;c[M>>2]=ua()|0;n=i;i=i+((1*(o<<2)|0)+15&-16)|0;c[E>>2]=1<<c[z>>2];if(c[y>>2]|0){c[G>>2]=c[E>>2];c[I>>2]=c[(c[q>>2]|0)+44>>2];c[J>>2]=c[(c[q>>2]|0)+36>>2]}else{c[G>>2]=1;c[I>>2]=c[(c[q>>2]|0)+44>>2]<<c[z>>2];c[J>>2]=(c[(c[q>>2]|0)+36>>2]|0)-(c[z>>2]|0)}if((c[x>>2]|0)==2&(c[w>>2]|0)==1){Sa(c[q>>2]|0,c[r>>2]|0,n,c[t>>2]|0,c[u>>2]|0,c[v>>2]|0,c[E>>2]|0,c[A>>2]|0,c[B>>2]|0);c[N>>2]=(c[(c[s>>2]|0)+4>>2]|0)+(((c[L>>2]|0)/2|0)<<2);df(c[N>>2]|0,n|0,(c[H>>2]<<2)+0|0)|0;c[F>>2]=0;while(1){if((c[F>>2]|0)>=(c[G>>2]|0))break;z=(c[c[s>>2]>>2]|0)+((_(c[I>>2]|0,c[F>>2]|0)|0)<<2)|0;tb((c[q>>2]|0)+64|0,(c[N>>2]|0)+(c[F>>2]<<2)|0,z,c[(c[q>>2]|0)+60>>2]|0,c[L>>2]|0,c[J>>2]|0,c[G>>2]|0);c[F>>2]=(c[F>>2]|0)+1}c[F>>2]=0;while(1){if((c[F>>2]|0)>=(c[G>>2]|0))break;N=(c[(c[s>>2]|0)+4>>2]|0)+((_(c[I>>2]|0,c[F>>2]|0)|0)<<2)|0;tb((c[q>>2]|0)+64|0,n+(c[F>>2]<<2)|0,N,c[(c[q>>2]|0)+60>>2]|0,c[L>>2]|0,c[J>>2]|0,c[G>>2]|0);c[F>>2]=(c[F>>2]|0)+1}P=c[M>>2]|0;ka(P|0);i=p;return}if(!((c[x>>2]|0)==1&(c[w>>2]|0)==2)){c[C>>2]=0;do{w=(c[r>>2]|0)+((_(c[C>>2]|0,c[H>>2]|0)|0)<<2)|0;N=(c[t>>2]|0)+((_(c[C>>2]|0,c[K>>2]|0)|0)<<2)|0;Sa(c[q>>2]|0,w,n,N,c[u>>2]|0,c[v>>2]|0,c[E>>2]|0,c[A>>2]|0,c[B>>2]|0);c[F>>2]=0;while(1){if((c[F>>2]|0)>=(c[G>>2]|0))break;N=(c[(c[s>>2]|0)+(c[C>>2]<<2)>>2]|0)+((_(c[I>>2]|0,c[F>>2]|0)|0)<<2)|0;tb((c[q>>2]|0)+64|0,n+(c[F>>2]<<2)|0,N,c[(c[q>>2]|0)+60>>2]|0,c[L>>2]|0,c[J>>2]|0,c[G>>2]|0);c[F>>2]=(c[F>>2]|0)+1}N=(c[C>>2]|0)+1|0;c[C>>2]=N}while((N|0)<(c[x>>2]|0));P=c[M>>2]|0;ka(P|0);i=p;return}c[O>>2]=(c[c[s>>2]>>2]|0)+(((c[L>>2]|0)/2|0)<<2);Sa(c[q>>2]|0,c[r>>2]|0,n,c[t>>2]|0,c[u>>2]|0,c[v>>2]|0,c[E>>2]|0,c[A>>2]|0,c[B>>2]|0);Sa(c[q>>2]|0,(c[r>>2]|0)+(c[H>>2]<<2)|0,c[O>>2]|0,(c[t>>2]|0)+(c[K>>2]<<2)|0,c[u>>2]|0,c[v>>2]|0,c[E>>2]|0,c[A>>2]|0,c[B>>2]|0);c[D>>2]=0;while(1){if((c[D>>2]|0)>=(c[H>>2]|0))break;g[n+(c[D>>2]<<2)>>2]=(+g[n+(c[D>>2]<<2)>>2]+ +g[(c[O>>2]|0)+(c[D>>2]<<2)>>2])*.5;c[D>>2]=(c[D>>2]|0)+1}c[F>>2]=0;while(1){if((c[F>>2]|0)>=(c[G>>2]|0))break;D=(c[c[s>>2]>>2]|0)+((_(c[I>>2]|0,c[F>>2]|0)|0)<<2)|0;tb((c[q>>2]|0)+64|0,n+(c[F>>2]<<2)|0,D,c[(c[q>>2]|0)+60>>2]|0,c[L>>2]|0,c[J>>2]|0,c[G>>2]|0);c[F>>2]=(c[F>>2]|0)+1}P=c[M>>2]|0;ka(P|0);i=p;return}function bd(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;i=b;return c[(c[d>>2]|0)+44>>2]|0}function cd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;d=i;i=i+32|0;e=d+16|0;f=d+12|0;g=d+8|0;h=d+4|0;j=d;c[e>>2]=a;c[f>>2]=b;c[h>>2]=(c[e>>2]|0)-1;c[g>>2]=(c[(c[f>>2]|0)+(c[h>>2]<<2)>>2]|0)<0&1;c[j>>2]=N(c[(c[f>>2]|0)+(c[h>>2]<<2)>>2]|0)|0;do{c[h>>2]=(c[h>>2]|0)+-1;if(((c[e>>2]|0)-(c[h>>2]|0)|0)>(c[j>>2]|0))k=(c[e>>2]|0)-(c[h>>2]|0)|0;else k=c[j>>2]|0;if(((c[e>>2]|0)-(c[h>>2]|0)|0)<(c[j>>2]|0))l=(c[e>>2]|0)-(c[h>>2]|0)|0;else l=c[j>>2]|0;c[g>>2]=(c[g>>2]|0)+(c[(c[2448+(l<<2)>>2]|0)+(k<<2)>>2]|0);b=N(c[(c[f>>2]|0)+(c[h>>2]<<2)>>2]|0)|0;c[j>>2]=(c[j>>2]|0)+b;if((c[(c[f>>2]|0)+(c[h>>2]<<2)>>2]|0)<0){if(((c[e>>2]|0)-(c[h>>2]|0)|0)>((c[j>>2]|0)+1|0))m=(c[e>>2]|0)-(c[h>>2]|0)|0;else m=(c[j>>2]|0)+1|0;if(((c[e>>2]|0)-(c[h>>2]|0)|0)<((c[j>>2]|0)+1|0))n=(c[e>>2]|0)-(c[h>>2]|0)|0;else n=(c[j>>2]|0)+1|0;c[g>>2]=(c[g>>2]|0)+(c[(c[2448+(n<<2)>>2]|0)+(m<<2)>>2]|0)}}while((c[h>>2]|0)>0);i=d;return c[g>>2]|0}function dd(a,d,e,f){a=a|0;d=d|0;e=e|0;f=f|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0.0,I=0,J=0.0,K=0,L=0.0,M=0.0,N=0.0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0.0,_=0,$=0.0,aa=0,ba=0.0,ca=0.0,da=0.0,ea=0.0;h=i;i=i+48|0;j=h;k=h+16|0;l=h+4|0;m=h+8|0;n=h+32|0;o=h+36|0;p=h+12|0;q=h+40|0;r=h+20|0;s=h+28|0;t=h+24|0;c[j>>2]=a;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;g[r>>2]=0.0;while(1){u=c[k>>2]|0;if((c[j>>2]|0)<=2)break;f=c[j>>2]|0;do if((u|0)>=(c[j>>2]|0)){c[t>>2]=c[2448+(f<<2)>>2];c[n>>2]=c[(c[t>>2]|0)+((c[k>>2]|0)+1<<2)>>2];c[o>>2]=0-((c[l>>2]|0)>>>0>=(c[n>>2]|0)>>>0&1);c[l>>2]=(c[l>>2]|0)-(c[n>>2]&c[o>>2]);c[p>>2]=c[k>>2];c[s>>2]=c[(c[t>>2]|0)+(c[j>>2]<<2)>>2];a:do if((c[s>>2]|0)>>>0>(c[l>>2]|0)>>>0){c[k>>2]=c[j>>2];do{e=c[j>>2]|0;d=(c[k>>2]|0)+-1|0;c[k>>2]=d;c[n>>2]=c[(c[2448+(d<<2)>>2]|0)+(e<<2)>>2]}while((c[n>>2]|0)>>>0>(c[l>>2]|0)>>>0)}else{c[n>>2]=c[(c[t>>2]|0)+(c[k>>2]<<2)>>2];while(1){if((c[n>>2]|0)>>>0<=(c[l>>2]|0)>>>0)break a;c[k>>2]=(c[k>>2]|0)+-1;c[n>>2]=c[(c[t>>2]|0)+(c[k>>2]<<2)>>2]}}while(0);c[l>>2]=(c[l>>2]|0)-(c[n>>2]|0);b[q>>1]=(c[p>>2]|0)-(c[k>>2]|0)+(c[o>>2]|0)^c[o>>2];e=b[q>>1]|0;d=c[m>>2]|0;c[m>>2]=d+4;c[d>>2]=e;g[r>>2]=+g[r>>2]+ +(b[q>>1]|0)*+(b[q>>1]|0)}else{c[n>>2]=c[(c[2448+(c[k>>2]<<2)>>2]|0)+(f<<2)>>2];c[s>>2]=c[(c[2448+((c[k>>2]|0)+1<<2)>>2]|0)+(c[j>>2]<<2)>>2];if((c[n>>2]|0)>>>0<=(c[l>>2]|0)>>>0?(c[l>>2]|0)>>>0<(c[s>>2]|0)>>>0:0){c[l>>2]=(c[l>>2]|0)-(c[n>>2]|0);e=c[m>>2]|0;c[m>>2]=e+4;c[e>>2]=0;break}c[o>>2]=0-((c[l>>2]|0)>>>0>=(c[s>>2]|0)>>>0&1);c[l>>2]=(c[l>>2]|0)-(c[s>>2]&c[o>>2]);c[p>>2]=c[k>>2];do{e=c[j>>2]|0;d=(c[k>>2]|0)+-1|0;c[k>>2]=d;c[n>>2]=c[(c[2448+(d<<2)>>2]|0)+(e<<2)>>2]}while((c[n>>2]|0)>>>0>(c[l>>2]|0)>>>0);c[l>>2]=(c[l>>2]|0)-(c[n>>2]|0);b[q>>1]=(c[p>>2]|0)-(c[k>>2]|0)+(c[o>>2]|0)^c[o>>2];e=b[q>>1]|0;d=c[m>>2]|0;c[m>>2]=d+4;c[d>>2]=e;g[r>>2]=+g[r>>2]+ +(b[q>>1]|0)*+(b[q>>1]|0)}while(0);c[j>>2]=(c[j>>2]|0)+-1}c[n>>2]=(u<<1)+1;c[o>>2]=0-((c[l>>2]|0)>>>0>=(c[n>>2]|0)>>>0&1);c[l>>2]=(c[l>>2]|0)-(c[n>>2]&c[o>>2]);c[p>>2]=c[k>>2];c[k>>2]=((c[l>>2]|0)+1|0)>>>1;if(!(c[k>>2]|0)){v=c[p>>2]|0;w=c[k>>2]|0;x=v-w|0;y=c[o>>2]|0;z=x+y|0;A=c[o>>2]|0;B=z^A;C=B&65535;b[q>>1]=C;D=b[q>>1]|0;E=D<<16>>16;F=c[m>>2]|0;G=F+4|0;c[m>>2]=G;c[F>>2]=E;H=+g[r>>2];I=b[q>>1]|0;J=+(I<<16>>16);K=b[q>>1]|0;L=+(K<<16>>16);M=J*L;N=H+M;g[r>>2]=N;O=c[l>>2]|0;P=0-O|0;c[o>>2]=P;Q=c[k>>2]|0;R=c[o>>2]|0;S=Q+R|0;T=c[o>>2]|0;U=S^T;V=U&65535;b[q>>1]=V;W=b[q>>1]|0;X=W<<16>>16;Y=c[m>>2]|0;c[Y>>2]=X;Z=+g[r>>2];_=b[q>>1]|0;$=+(_<<16>>16);aa=b[q>>1]|0;ba=+(aa<<16>>16);ca=$*ba;da=Z+ca;g[r>>2]=da;ea=+g[r>>2];i=h;return +ea}c[l>>2]=(c[l>>2]|0)-((c[k>>2]<<1)-1);v=c[p>>2]|0;w=c[k>>2]|0;x=v-w|0;y=c[o>>2]|0;z=x+y|0;A=c[o>>2]|0;B=z^A;C=B&65535;b[q>>1]=C;D=b[q>>1]|0;E=D<<16>>16;F=c[m>>2]|0;G=F+4|0;c[m>>2]=G;c[F>>2]=E;H=+g[r>>2];I=b[q>>1]|0;J=+(I<<16>>16);K=b[q>>1]|0;L=+(K<<16>>16);M=J*L;N=H+M;g[r>>2]=N;O=c[l>>2]|0;P=0-O|0;c[o>>2]=P;Q=c[k>>2]|0;R=c[o>>2]|0;S=Q+R|0;T=c[o>>2]|0;U=S^T;V=U&65535;b[q>>1]=V;W=b[q>>1]|0;X=W<<16>>16;Y=c[m>>2]|0;c[Y>>2]=X;Z=+g[r>>2];_=b[q>>1]|0;$=+(_<<16>>16);aa=b[q>>1]|0;ba=+(aa<<16>>16);ca=$*ba;da=Z+ca;g[r>>2]=da;ea=+g[r>>2];i=h;return +ea}function ed(a){a=a|0;var b=0,e=0,f=0,g=0;b=i;i=i+16|0;e=b;c[e>>2]=a;if((c[(c[e>>2]|0)+24>>2]|0)>>>0>=(c[(c[e>>2]|0)+4>>2]|0)>>>0){f=0;i=b;return f|0}a=(c[e>>2]|0)+24|0;g=c[a>>2]|0;c[a>>2]=g+1;f=d[(c[c[e>>2]>>2]|0)+g>>0]|0;i=b;return f|0}function fd(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;while(1){if((c[(c[d>>2]|0)+28>>2]|0)>>>0>8388608)break;a=(c[d>>2]|0)+20|0;c[a>>2]=(c[a>>2]|0)+8;a=(c[d>>2]|0)+28|0;c[a>>2]=c[a>>2]<<8;c[e>>2]=c[(c[d>>2]|0)+40>>2];a=ed(c[d>>2]|0)|0;c[(c[d>>2]|0)+40>>2]=a;c[e>>2]=(c[e>>2]<<8|c[(c[d>>2]|0)+40>>2])>>1;c[(c[d>>2]|0)+32>>2]=(c[(c[d>>2]|0)+32>>2]<<8)+(255&~c[e>>2])&2147483647}i=b;return}function gd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>>>0)/((c[f>>2]|0)>>>0)|0|0}function hd(a){a=a|0;var b=0,e=0,f=0,g=0,h=0;b=i;i=i+16|0;e=b;c[e>>2]=a;if((c[(c[e>>2]|0)+8>>2]|0)>>>0>=(c[(c[e>>2]|0)+4>>2]|0)>>>0){f=0;i=b;return f|0}a=c[(c[e>>2]|0)+4>>2]|0;g=(c[e>>2]|0)+8|0;h=(c[g>>2]|0)+1|0;c[g>>2]=h;f=d[(c[c[e>>2]>>2]|0)+(a-h)>>0]|0;i=b;return f|0}function id(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>>>0)/((c[f>>2]|0)>>>0)|0|0}function jd(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;while(1){if((c[(c[d>>2]|0)+28>>2]|0)>>>0>8388608)break;ld(c[d>>2]|0,(c[(c[d>>2]|0)+32>>2]|0)>>>23);c[(c[d>>2]|0)+32>>2]=c[(c[d>>2]|0)+32>>2]<<8&2147483647;a=(c[d>>2]|0)+28|0;c[a>>2]=c[a>>2]<<8;a=(c[d>>2]|0)+20|0;c[a>>2]=(c[a>>2]|0)+8}i=b;return}function kd(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[g>>2]=b;c[h>>2]=d;if(((c[(c[g>>2]|0)+24>>2]|0)+(c[(c[g>>2]|0)+8>>2]|0)|0)>>>0>=(c[(c[g>>2]|0)+4>>2]|0)>>>0){c[f>>2]=-1;j=c[f>>2]|0;i=e;return j|0}else{d=c[h>>2]&255;h=c[(c[g>>2]|0)+4>>2]|0;b=(c[g>>2]|0)+8|0;k=(c[b>>2]|0)+1|0;c[b>>2]=k;a[(c[c[g>>2]>>2]|0)+(h-k)>>0]=d;c[f>>2]=0;j=c[f>>2]|0;i=e;return j|0}return 0}function ld(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[e>>2]=a;c[f>>2]=b;if((c[f>>2]|0)==255){b=(c[e>>2]|0)+36|0;c[b>>2]=(c[b>>2]|0)+1;i=d;return}c[g>>2]=c[f>>2]>>8;if((c[(c[e>>2]|0)+40>>2]|0)>=0){b=ze(c[e>>2]|0,(c[(c[e>>2]|0)+40>>2]|0)+(c[g>>2]|0)|0)|0;a=(c[e>>2]|0)+44|0;c[a>>2]=c[a>>2]|b}if((c[(c[e>>2]|0)+36>>2]|0)>>>0>0){c[h>>2]=255+(c[g>>2]|0)&255;do{g=ze(c[e>>2]|0,c[h>>2]|0)|0;b=(c[e>>2]|0)+44|0;c[b>>2]=c[b>>2]|g;g=(c[e>>2]|0)+36|0;b=(c[g>>2]|0)+-1|0;c[g>>2]=b}while(b>>>0>0)}c[(c[e>>2]|0)+40>>2]=c[f>>2]&255;i=d;return}function md(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0;e=i;i=i+48|0;f=e+8|0;h=e+28|0;j=e+32|0;k=e+4|0;l=e;m=e+16|0;c[f>>2]=a;c[e+24>>2]=b;c[h>>2]=d;g[l>>2]=.7071067690849304;c[k>>2]=0;while(1){if((c[k>>2]|0)>=(c[h>>2]|0))break;c[j>>2]=(c[f>>2]|0)+32;d=c[j>>2]|0;c[m>>2]=c[d>>2];c[m+4>>2]=c[d+4>>2];g[c[j>>2]>>2]=+g[c[f>>2]>>2]-+g[m>>2];g[(c[j>>2]|0)+4>>2]=+g[(c[f>>2]|0)+4>>2]-+g[m+4>>2];d=c[f>>2]|0;g[d>>2]=+g[d>>2]+ +g[m>>2];d=(c[f>>2]|0)+4|0;g[d>>2]=+g[d>>2]+ +g[m+4>>2];g[m>>2]=(+g[(c[j>>2]|0)+8>>2]+ +g[(c[j>>2]|0)+8+4>>2])*+g[l>>2];g[m+4>>2]=(+g[(c[j>>2]|0)+8+4>>2]-+g[(c[j>>2]|0)+8>>2])*+g[l>>2];g[(c[j>>2]|0)+8>>2]=+g[(c[f>>2]|0)+8>>2]-+g[m>>2];g[(c[j>>2]|0)+8+4>>2]=+g[(c[f>>2]|0)+8+4>>2]-+g[m+4>>2];d=(c[f>>2]|0)+8|0;g[d>>2]=+g[d>>2]+ +g[m>>2];d=(c[f>>2]|0)+8+4|0;g[d>>2]=+g[d>>2]+ +g[m+4>>2];g[m>>2]=+g[(c[j>>2]|0)+16+4>>2];g[m+4>>2]=-+g[(c[j>>2]|0)+16>>2];g[(c[j>>2]|0)+16>>2]=+g[(c[f>>2]|0)+16>>2]-+g[m>>2];g[(c[j>>2]|0)+16+4>>2]=+g[(c[f>>2]|0)+16+4>>2]-+g[m+4>>2];d=(c[f>>2]|0)+16|0;g[d>>2]=+g[d>>2]+ +g[m>>2];d=(c[f>>2]|0)+16+4|0;g[d>>2]=+g[d>>2]+ +g[m+4>>2];g[m>>2]=(+g[(c[j>>2]|0)+24+4>>2]-+g[(c[j>>2]|0)+24>>2])*+g[l>>2];g[m+4>>2]=(-+g[(c[j>>2]|0)+24+4>>2]-+g[(c[j>>2]|0)+24>>2])*+g[l>>2];g[(c[j>>2]|0)+24>>2]=+g[(c[f>>2]|0)+24>>2]-+g[m>>2];g[(c[j>>2]|0)+24+4>>2]=+g[(c[f>>2]|0)+24+4>>2]-+g[m+4>>2];d=(c[f>>2]|0)+24|0;g[d>>2]=+g[d>>2]+ +g[m>>2];d=(c[f>>2]|0)+24+4|0;g[d>>2]=+g[d>>2]+ +g[m+4>>2];c[f>>2]=(c[f>>2]|0)+64;c[k>>2]=(c[k>>2]|0)+1}i=e;return}function nd(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;j=i;i=i+128|0;k=j+112|0;l=j+88|0;m=j+64|0;n=j+60|0;o=j+48|0;p=j+84|0;q=j+92|0;r=j+104|0;s=j+120|0;t=j+68|0;u=j;v=j+76|0;w=j+72|0;x=j+52|0;y=j+80|0;z=j+56|0;A=j+96|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;if((c[n>>2]|0)==1){c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;g[r>>2]=+g[c[k>>2]>>2]-+g[(c[k>>2]|0)+16>>2];g[r+4>>2]=+g[(c[k>>2]|0)+4>>2]-+g[(c[k>>2]|0)+16+4>>2];h=c[k>>2]|0;g[h>>2]=+g[h>>2]+ +g[(c[k>>2]|0)+16>>2];h=(c[k>>2]|0)+4|0;g[h>>2]=+g[h>>2]+ +g[(c[k>>2]|0)+16+4>>2];g[s>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[(c[k>>2]|0)+24>>2];g[s+4>>2]=+g[(c[k>>2]|0)+8+4>>2]+ +g[(c[k>>2]|0)+24+4>>2];g[(c[k>>2]|0)+16>>2]=+g[c[k>>2]>>2]-+g[s>>2];g[(c[k>>2]|0)+16+4>>2]=+g[(c[k>>2]|0)+4>>2]-+g[s+4>>2];h=c[k>>2]|0;g[h>>2]=+g[h>>2]+ +g[s>>2];h=(c[k>>2]|0)+4|0;g[h>>2]=+g[h>>2]+ +g[s+4>>2];g[s>>2]=+g[(c[k>>2]|0)+8>>2]-+g[(c[k>>2]|0)+24>>2];g[s+4>>2]=+g[(c[k>>2]|0)+8+4>>2]-+g[(c[k>>2]|0)+24+4>>2];g[(c[k>>2]|0)+8>>2]=+g[r>>2]+ +g[s+4>>2];g[(c[k>>2]|0)+8+4>>2]=+g[r+4>>2]-+g[s>>2];g[(c[k>>2]|0)+24>>2]=+g[r>>2]-+g[s+4>>2];g[(c[k>>2]|0)+24+4>>2]=+g[r+4>>2]+ +g[s>>2];c[k>>2]=(c[k>>2]|0)+32;c[q>>2]=(c[q>>2]|0)+1}i=j;return}c[y>>2]=c[n>>2]<<1;c[z>>2]=(c[n>>2]|0)*3;c[A>>2]=c[k>>2];c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;c[k>>2]=(c[A>>2]|0)+((_(c[q>>2]|0,c[p>>2]|0)|0)<<3);s=c[(c[m>>2]|0)+48>>2]|0;c[v>>2]=s;c[w>>2]=s;c[x>>2]=s;c[t>>2]=0;while(1){if((c[t>>2]|0)>=(c[n>>2]|0))break;g[u>>2]=+g[(c[k>>2]|0)+(c[n>>2]<<3)>>2]*+g[c[v>>2]>>2]-+g[(c[k>>2]|0)+(c[n>>2]<<3)+4>>2]*+g[(c[v>>2]|0)+4>>2];g[u+4>>2]=+g[(c[k>>2]|0)+(c[n>>2]<<3)>>2]*+g[(c[v>>2]|0)+4>>2]+ +g[(c[k>>2]|0)+(c[n>>2]<<3)+4>>2]*+g[c[v>>2]>>2];g[u+8>>2]=+g[(c[k>>2]|0)+(c[y>>2]<<3)>>2]*+g[c[w>>2]>>2]-+g[(c[k>>2]|0)+(c[y>>2]<<3)+4>>2]*+g[(c[w>>2]|0)+4>>2];g[u+8+4>>2]=+g[(c[k>>2]|0)+(c[y>>2]<<3)>>2]*+g[(c[w>>2]|0)+4>>2]+ +g[(c[k>>2]|0)+(c[y>>2]<<3)+4>>2]*+g[c[w>>2]>>2];g[u+16>>2]=+g[(c[k>>2]|0)+(c[z>>2]<<3)>>2]*+g[c[x>>2]>>2]-+g[(c[k>>2]|0)+(c[z>>2]<<3)+4>>2]*+g[(c[x>>2]|0)+4>>2];g[u+16+4>>2]=+g[(c[k>>2]|0)+(c[z>>2]<<3)>>2]*+g[(c[x>>2]|0)+4>>2]+ +g[(c[k>>2]|0)+(c[z>>2]<<3)+4>>2]*+g[c[x>>2]>>2];g[u+40>>2]=+g[c[k>>2]>>2]-+g[u+8>>2];g[u+40+4>>2]=+g[(c[k>>2]|0)+4>>2]-+g[u+8+4>>2];s=c[k>>2]|0;g[s>>2]=+g[s>>2]+ +g[u+8>>2];s=(c[k>>2]|0)+4|0;g[s>>2]=+g[s>>2]+ +g[u+8+4>>2];g[u+24>>2]=+g[u>>2]+ +g[u+16>>2];g[u+24+4>>2]=+g[u+4>>2]+ +g[u+16+4>>2];g[u+32>>2]=+g[u>>2]-+g[u+16>>2];g[u+32+4>>2]=+g[u+4>>2]-+g[u+16+4>>2];g[(c[k>>2]|0)+(c[y>>2]<<3)>>2]=+g[c[k>>2]>>2]-+g[u+24>>2];g[(c[k>>2]|0)+(c[y>>2]<<3)+4>>2]=+g[(c[k>>2]|0)+4>>2]-+g[u+24+4>>2];c[v>>2]=(c[v>>2]|0)+(c[l>>2]<<3);c[w>>2]=(c[w>>2]|0)+(c[l>>2]<<1<<3);c[x>>2]=(c[x>>2]|0)+((c[l>>2]|0)*3<<3);s=c[k>>2]|0;g[s>>2]=+g[s>>2]+ +g[u+24>>2];s=(c[k>>2]|0)+4|0;g[s>>2]=+g[s>>2]+ +g[u+24+4>>2];g[(c[k>>2]|0)+(c[n>>2]<<3)>>2]=+g[u+40>>2]+ +g[u+32+4>>2];g[(c[k>>2]|0)+(c[n>>2]<<3)+4>>2]=+g[u+40+4>>2]-+g[u+32>>2];g[(c[k>>2]|0)+(c[z>>2]<<3)>>2]=+g[u+40>>2]-+g[u+32+4>>2];g[(c[k>>2]|0)+(c[z>>2]<<3)+4>>2]=+g[u+40+4>>2]+ +g[u+32>>2];c[k>>2]=(c[k>>2]|0)+8;c[t>>2]=(c[t>>2]|0)+1}c[q>>2]=(c[q>>2]|0)+1}i=j;return}function od(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;j=i;i=i+112|0;k=j+56|0;l=j+52|0;m=j+88|0;n=j+80|0;o=j+76|0;p=j+84|0;q=j+92|0;r=j+96|0;s=j+60|0;t=j;u=j+72|0;v=j+8|0;w=j+64|0;x=j+48|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;c[s>>2]=c[n>>2]<<1;c[x>>2]=c[k>>2];h=_(c[l>>2]|0,c[n>>2]|0)|0;f=(c[(c[m>>2]|0)+48>>2]|0)+(h<<3)|0;c[w>>2]=c[f>>2];c[w+4>>2]=c[f+4>>2];c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;c[k>>2]=(c[x>>2]|0)+((_(c[q>>2]|0,c[p>>2]|0)|0)<<3);f=c[(c[m>>2]|0)+48>>2]|0;c[u>>2]=f;c[t>>2]=f;c[r>>2]=c[n>>2];do{g[v+8>>2]=+g[(c[k>>2]|0)+(c[n>>2]<<3)>>2]*+g[c[t>>2]>>2]-+g[(c[k>>2]|0)+(c[n>>2]<<3)+4>>2]*+g[(c[t>>2]|0)+4>>2];g[v+8+4>>2]=+g[(c[k>>2]|0)+(c[n>>2]<<3)>>2]*+g[(c[t>>2]|0)+4>>2]+ +g[(c[k>>2]|0)+(c[n>>2]<<3)+4>>2]*+g[c[t>>2]>>2];g[v+16>>2]=+g[(c[k>>2]|0)+(c[s>>2]<<3)>>2]*+g[c[u>>2]>>2]-+g[(c[k>>2]|0)+(c[s>>2]<<3)+4>>2]*+g[(c[u>>2]|0)+4>>2];g[v+16+4>>2]=+g[(c[k>>2]|0)+(c[s>>2]<<3)>>2]*+g[(c[u>>2]|0)+4>>2]+ +g[(c[k>>2]|0)+(c[s>>2]<<3)+4>>2]*+g[c[u>>2]>>2];g[v+24>>2]=+g[v+8>>2]+ +g[v+16>>2];g[v+24+4>>2]=+g[v+8+4>>2]+ +g[v+16+4>>2];g[v>>2]=+g[v+8>>2]-+g[v+16>>2];g[v+4>>2]=+g[v+8+4>>2]-+g[v+16+4>>2];c[t>>2]=(c[t>>2]|0)+(c[l>>2]<<3);c[u>>2]=(c[u>>2]|0)+(c[l>>2]<<1<<3);g[(c[k>>2]|0)+(c[n>>2]<<3)>>2]=+g[c[k>>2]>>2]-+g[v+24>>2]*.5;g[(c[k>>2]|0)+(c[n>>2]<<3)+4>>2]=+g[(c[k>>2]|0)+4>>2]-+g[v+24+4>>2]*.5;g[v>>2]=+g[v>>2]*+g[w+4>>2];f=v+4|0;g[f>>2]=+g[f>>2]*+g[w+4>>2];f=c[k>>2]|0;g[f>>2]=+g[f>>2]+ +g[v+24>>2];f=(c[k>>2]|0)+4|0;g[f>>2]=+g[f>>2]+ +g[v+24+4>>2];g[(c[k>>2]|0)+(c[s>>2]<<3)>>2]=+g[(c[k>>2]|0)+(c[n>>2]<<3)>>2]+ +g[v+4>>2];g[(c[k>>2]|0)+(c[s>>2]<<3)+4>>2]=+g[(c[k>>2]|0)+(c[n>>2]<<3)+4>>2]-+g[v>>2];f=(c[k>>2]|0)+(c[n>>2]<<3)|0;g[f>>2]=+g[f>>2]-+g[v+4>>2];f=(c[k>>2]|0)+(c[n>>2]<<3)+4|0;g[f>>2]=+g[f>>2]+ +g[v>>2];c[k>>2]=(c[k>>2]|0)+8;f=(c[r>>2]|0)+-1|0;c[r>>2]=f}while((f|0)!=0);c[q>>2]=(c[q>>2]|0)+1}i=j;return}function pd(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0;j=i;i=i+192|0;k=j+28|0;l=j+32|0;m=j+156|0;n=j+180|0;o=j+4|0;p=j+152|0;q=j+160|0;r=j+176|0;s=j+184|0;t=j+188|0;u=j+36|0;v=j;w=j+40|0;x=j+48|0;y=j+8|0;z=j+16|0;A=j+168|0;B=j+24|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;c[B>>2]=c[k>>2];h=_(c[l>>2]|0,c[n>>2]|0)|0;f=(c[(c[m>>2]|0)+48>>2]|0)+(h<<3)|0;c[z>>2]=c[f>>2];c[z+4>>2]=c[f+4>>2];f=_(c[l>>2]<<1,c[n>>2]|0)|0;h=(c[(c[m>>2]|0)+48>>2]|0)+(f<<3)|0;c[A>>2]=c[h>>2];c[A+4>>2]=c[h+4>>2];c[y>>2]=c[(c[m>>2]|0)+48>>2];c[v>>2]=0;while(1){if((c[v>>2]|0)>=(c[o>>2]|0))break;c[k>>2]=(c[B>>2]|0)+((_(c[v>>2]|0,c[p>>2]|0)|0)<<3);c[q>>2]=c[k>>2];c[r>>2]=(c[q>>2]|0)+(c[n>>2]<<3);c[s>>2]=(c[q>>2]|0)+(c[n>>2]<<1<<3);c[t>>2]=(c[q>>2]|0)+((c[n>>2]|0)*3<<3);c[u>>2]=(c[q>>2]|0)+(c[n>>2]<<2<<3);c[w>>2]=0;while(1){if((c[w>>2]|0)>=(c[n>>2]|0))break;m=c[q>>2]|0;c[x>>2]=c[m>>2];c[x+4>>2]=c[m+4>>2];m=_(c[w>>2]|0,c[l>>2]|0)|0;h=_(c[w>>2]|0,c[l>>2]|0)|0;g[x+8>>2]=+g[c[r>>2]>>2]*+g[(c[y>>2]|0)+(m<<3)>>2]-+g[(c[r>>2]|0)+4>>2]*+g[(c[y>>2]|0)+(h<<3)+4>>2];h=_(c[w>>2]|0,c[l>>2]|0)|0;m=_(c[w>>2]|0,c[l>>2]|0)|0;g[x+8+4>>2]=+g[c[r>>2]>>2]*+g[(c[y>>2]|0)+(h<<3)+4>>2]+ +g[(c[r>>2]|0)+4>>2]*+g[(c[y>>2]|0)+(m<<3)>>2];m=_(c[w>>2]<<1,c[l>>2]|0)|0;h=_(c[w>>2]<<1,c[l>>2]|0)|0;g[x+16>>2]=+g[c[s>>2]>>2]*+g[(c[y>>2]|0)+(m<<3)>>2]-+g[(c[s>>2]|0)+4>>2]*+g[(c[y>>2]|0)+(h<<3)+4>>2];h=_(c[w>>2]<<1,c[l>>2]|0)|0;m=_(c[w>>2]<<1,c[l>>2]|0)|0;g[x+16+4>>2]=+g[c[s>>2]>>2]*+g[(c[y>>2]|0)+(h<<3)+4>>2]+ +g[(c[s>>2]|0)+4>>2]*+g[(c[y>>2]|0)+(m<<3)>>2];m=_((c[w>>2]|0)*3|0,c[l>>2]|0)|0;h=_((c[w>>2]|0)*3|0,c[l>>2]|0)|0;g[x+24>>2]=+g[c[t>>2]>>2]*+g[(c[y>>2]|0)+(m<<3)>>2]-+g[(c[t>>2]|0)+4>>2]*+g[(c[y>>2]|0)+(h<<3)+4>>2];h=_((c[w>>2]|0)*3|0,c[l>>2]|0)|0;m=_((c[w>>2]|0)*3|0,c[l>>2]|0)|0;g[x+24+4>>2]=+g[c[t>>2]>>2]*+g[(c[y>>2]|0)+(h<<3)+4>>2]+ +g[(c[t>>2]|0)+4>>2]*+g[(c[y>>2]|0)+(m<<3)>>2];m=_(c[w>>2]<<2,c[l>>2]|0)|0;h=_(c[w>>2]<<2,c[l>>2]|0)|0;g[x+32>>2]=+g[c[u>>2]>>2]*+g[(c[y>>2]|0)+(m<<3)>>2]-+g[(c[u>>2]|0)+4>>2]*+g[(c[y>>2]|0)+(h<<3)+4>>2];h=_(c[w>>2]<<2,c[l>>2]|0)|0;m=_(c[w>>2]<<2,c[l>>2]|0)|0;g[x+32+4>>2]=+g[c[u>>2]>>2]*+g[(c[y>>2]|0)+(h<<3)+4>>2]+ +g[(c[u>>2]|0)+4>>2]*+g[(c[y>>2]|0)+(m<<3)>>2];g[x+56>>2]=+g[x+8>>2]+ +g[x+32>>2];g[x+56+4>>2]=+g[x+8+4>>2]+ +g[x+32+4>>2];g[x+80>>2]=+g[x+8>>2]-+g[x+32>>2];g[x+80+4>>2]=+g[x+8+4>>2]-+g[x+32+4>>2];g[x+64>>2]=+g[x+16>>2]+ +g[x+24>>2];g[x+64+4>>2]=+g[x+16+4>>2]+ +g[x+24+4>>2];g[x+72>>2]=+g[x+16>>2]-+g[x+24>>2];g[x+72+4>>2]=+g[x+16+4>>2]-+g[x+24+4>>2];m=c[q>>2]|0;g[m>>2]=+g[m>>2]+(+g[x+56>>2]+ +g[x+64>>2]);m=(c[q>>2]|0)+4|0;g[m>>2]=+g[m>>2]+(+g[x+56+4>>2]+ +g[x+64+4>>2]);g[x+40>>2]=+g[x>>2]+ +g[x+56>>2]*+g[z>>2]+ +g[x+64>>2]*+g[A>>2];g[x+40+4>>2]=+g[x+4>>2]+ +g[x+56+4>>2]*+g[z>>2]+ +g[x+64+4>>2]*+g[A>>2];g[x+48>>2]=+g[x+80+4>>2]*+g[z+4>>2]+ +g[x+72+4>>2]*+g[A+4>>2];g[x+48+4>>2]=-(+g[x+80>>2]*+g[z+4>>2])-+g[x+72>>2]*+g[A+4>>2];g[c[r>>2]>>2]=+g[x+40>>2]-+g[x+48>>2];g[(c[r>>2]|0)+4>>2]=+g[x+40+4>>2]-+g[x+48+4>>2];g[c[u>>2]>>2]=+g[x+40>>2]+ +g[x+48>>2];g[(c[u>>2]|0)+4>>2]=+g[x+40+4>>2]+ +g[x+48+4>>2];g[x+88>>2]=+g[x>>2]+ +g[x+56>>2]*+g[A>>2]+ +g[x+64>>2]*+g[z>>2];g[x+88+4>>2]=+g[x+4>>2]+ +g[x+56+4>>2]*+g[A>>2]+ +g[x+64+4>>2]*+g[z>>2];g[x+96>>2]=-(+g[x+80+4>>2]*+g[A+4>>2])+ +g[x+72+4>>2]*+g[z+4>>2];g[x+96+4>>2]=+g[x+80>>2]*+g[A+4>>2]-+g[x+72>>2]*+g[z+4>>2];g[c[s>>2]>>2]=+g[x+88>>2]+ +g[x+96>>2];g[(c[s>>2]|0)+4>>2]=+g[x+88+4>>2]+ +g[x+96+4>>2];g[c[t>>2]>>2]=+g[x+88>>2]-+g[x+96>>2];g[(c[t>>2]|0)+4>>2]=+g[x+88+4>>2]-+g[x+96+4>>2];c[q>>2]=(c[q>>2]|0)+8;c[r>>2]=(c[r>>2]|0)+8;c[s>>2]=(c[s>>2]|0)+8;c[t>>2]=(c[t>>2]|0)+8;c[u>>2]=(c[u>>2]|0)+8;c[w>>2]=(c[w>>2]|0)+1}c[v>>2]=(c[v>>2]|0)+1}i=j;return}function qd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[e>>2]=a;c[f>>2]=b;c[g>>2]=32736-(c[e>>2]|0);e=(_(c[g>>2]|0,16384-(c[f>>2]|0)|0)|0)>>>15;i=d;return e|0}function rd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0;h=i;i=i+80|0;j=h+60|0;k=h+44|0;l=h+20|0;m=h+16|0;n=h+4|0;o=h+40|0;p=h+48|0;q=h+56|0;r=h+64|0;s=h+24|0;t=h;u=h+32|0;v=h+28|0;w=h+8|0;x=h+36|0;y=h+12|0;z=h+52|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;g[p>>2]=+g[c[k>>2]>>2];g[q>>2]=+g[(c[k>>2]|0)+4>>2];g[r>>2]=+g[(c[k>>2]|0)+8>>2];g[s>>2]=+g[(c[k>>2]|0)+12>>2];g[t>>2]=+g[(c[k>>2]|0)+16>>2];g[u>>2]=+g[c[n>>2]>>2];g[v>>2]=+g[(c[n>>2]|0)+4>>2];g[w>>2]=+g[(c[n>>2]|0)+8>>2];g[x>>2]=+g[(c[n>>2]|0)+12>>2];g[y>>2]=+g[(c[n>>2]|0)+16>>2];c[o>>2]=0;while(1){if((c[o>>2]|0)>=(c[m>>2]|0))break;g[z>>2]=+g[(c[j>>2]|0)+(c[o>>2]<<2)>>2];g[z>>2]=+g[z>>2]+ +g[p>>2]*+g[u>>2];g[z>>2]=+g[z>>2]+ +g[q>>2]*+g[v>>2];g[z>>2]=+g[z>>2]+ +g[r>>2]*+g[w>>2];g[z>>2]=+g[z>>2]+ +g[s>>2]*+g[x>>2];g[z>>2]=+g[z>>2]+ +g[t>>2]*+g[y>>2];g[y>>2]=+g[x>>2];g[x>>2]=+g[w>>2];g[w>>2]=+g[v>>2];g[v>>2]=+g[u>>2];g[u>>2]=+g[(c[j>>2]|0)+(c[o>>2]<<2)>>2];g[(c[l>>2]|0)+(c[o>>2]<<2)>>2]=+g[z>>2];c[o>>2]=(c[o>>2]|0)+1}g[c[n>>2]>>2]=+g[u>>2];g[(c[n>>2]|0)+4>>2]=+g[v>>2];g[(c[n>>2]|0)+8>>2]=+g[w>>2];g[(c[n>>2]|0)+12>>2]=+g[x>>2];g[(c[n>>2]|0)+16>>2]=+g[y>>2];i=h;return}function sd(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;f=i;i=i+64|0;h=f+44|0;j=f+36|0;k=f+12|0;l=f+8|0;m=f+32|0;n=f+40|0;o=f+48|0;p=f+16|0;q=f;r=f+24|0;s=f+4|0;t=f+28|0;u=f+20|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;g[q>>2]=0.0;e=c[j>>2]|0;c[j>>2]=e+4;g[n>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[o>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[p>>2]=+g[e>>2];c[m>>2]=0;while(1){if((c[m>>2]|0)>=((c[l>>2]|0)-3|0))break;e=c[h>>2]|0;c[h>>2]=e+4;g[r>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[q>>2]=+g[e>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[r>>2]*+g[n>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[r>>2]*+g[o>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[r>>2]*+g[p>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[r>>2]*+g[q>>2];e=c[h>>2]|0;c[h>>2]=e+4;g[r>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[n>>2]=+g[e>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[r>>2]*+g[o>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[r>>2]*+g[p>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[r>>2]*+g[q>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[r>>2]*+g[n>>2];e=c[h>>2]|0;c[h>>2]=e+4;g[r>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[o>>2]=+g[e>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[r>>2]*+g[p>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[r>>2]*+g[q>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[r>>2]*+g[n>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[r>>2]*+g[o>>2];e=c[h>>2]|0;c[h>>2]=e+4;g[r>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[p>>2]=+g[e>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[r>>2]*+g[q>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[r>>2]*+g[n>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[r>>2]*+g[o>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[r>>2]*+g[p>>2];c[m>>2]=(c[m>>2]|0)+4}r=c[m>>2]|0;c[m>>2]=r+1;if((r|0)<(c[l>>2]|0)){r=c[h>>2]|0;c[h>>2]=r+4;g[s>>2]=+g[r>>2];r=c[j>>2]|0;c[j>>2]=r+4;g[q>>2]=+g[r>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[s>>2]*+g[n>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[s>>2]*+g[o>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[s>>2]*+g[p>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[s>>2]*+g[q>>2]}s=c[m>>2]|0;c[m>>2]=s+1;if((s|0)<(c[l>>2]|0)){s=c[h>>2]|0;c[h>>2]=s+4;g[t>>2]=+g[s>>2];s=c[j>>2]|0;c[j>>2]=s+4;g[n>>2]=+g[s>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[t>>2]*+g[o>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[t>>2]*+g[p>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[t>>2]*+g[q>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[t>>2]*+g[n>>2]}if((c[m>>2]|0)>=(c[l>>2]|0)){i=f;return}l=c[h>>2]|0;c[h>>2]=l+4;g[u>>2]=+g[l>>2];l=c[j>>2]|0;c[j>>2]=l+4;g[o>>2]=+g[l>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[u>>2]*+g[p>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[u>>2]*+g[q>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[u>>2]*+g[n>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[u>>2]*+g[o>>2];i=f;return}function td(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0.0;e=i;i=i+32|0;f=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[f>>2]=a;c[h>>2]=b;c[j>>2]=d;g[l>>2]=0.0;c[k>>2]=0;while(1){m=+g[l>>2];if((c[k>>2]|0)>=(c[j>>2]|0))break;g[l>>2]=m+ +g[(c[f>>2]|0)+(c[k>>2]<<2)>>2]*+g[(c[h>>2]|0)+(c[k>>2]<<2)>>2];c[k>>2]=(c[k>>2]|0)+1}i=e;return +m}function ud(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;h=i;i=i+64|0;j=h;k=h+8|0;l=h+52|0;m=h+24|0;n=h+48|0;o=h+56|0;p=h+60|0;q=h+40|0;r=h+32|0;s=h+16|0;t=h+4|0;u=h+44|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;g[q>>2]=1.0;g[r>>2]=-1.0;g[r+4>>2]=-1.0;g[s>>2]=0.0;g[s+4>>2]=0.0;c[c[n>>2]>>2]=0;c[(c[n>>2]|0)+4>>2]=1;c[p>>2]=0;while(1){if((c[p>>2]|0)>=(c[l>>2]|0))break;g[q>>2]=+g[q>>2]+ +g[(c[k>>2]|0)+(c[p>>2]<<2)>>2]*+g[(c[k>>2]|0)+(c[p>>2]<<2)>>2];c[p>>2]=(c[p>>2]|0)+1}c[o>>2]=0;while(1){if((c[o>>2]|0)>=(c[m>>2]|0))break;do if(+g[(c[j>>2]|0)+(c[o>>2]<<2)>>2]>0.0?(g[u>>2]=+g[(c[j>>2]|0)+(c[o>>2]<<2)>>2],g[u>>2]=+g[u>>2]*9.999999960041972e-13,g[t>>2]=+g[u>>2]*+g[u>>2],+g[t>>2]*+g[s+4>>2]>+g[r+4>>2]*+g[q>>2]):0)if(+g[t>>2]*+g[s>>2]>+g[r>>2]*+g[q>>2]){g[r+4>>2]=+g[r>>2];g[s+4>>2]=+g[s>>2];c[(c[n>>2]|0)+4>>2]=c[c[n>>2]>>2];g[r>>2]=+g[t>>2];g[s>>2]=+g[q>>2];c[c[n>>2]>>2]=c[o>>2];break}else{g[r+4>>2]=+g[t>>2];g[s+4>>2]=+g[q>>2];c[(c[n>>2]|0)+4>>2]=c[o>>2];break}while(0);g[q>>2]=+g[q>>2]+(+g[(c[k>>2]|0)+((c[o>>2]|0)+(c[l>>2]|0)<<2)>>2]*+g[(c[k>>2]|0)+((c[o>>2]|0)+(c[l>>2]|0)<<2)>>2]-+g[(c[k>>2]|0)+(c[o>>2]<<2)>>2]*+g[(c[k>>2]|0)+(c[o>>2]<<2)>>2]);g[q>>2]=1.0>+g[q>>2]?1.0:+g[q>>2];c[o>>2]=(c[o>>2]|0)+1}i=h;return}function vd(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;f=i;i=i+64|0;h=f+44|0;j=f+36|0;k=f+12|0;l=f+8|0;m=f+32|0;n=f+40|0;o=f+48|0;p=f+16|0;q=f;r=f+24|0;s=f+4|0;t=f+28|0;u=f+20|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;g[q>>2]=0.0;e=c[j>>2]|0;c[j>>2]=e+4;g[n>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[o>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[p>>2]=+g[e>>2];c[m>>2]=0;while(1){if((c[m>>2]|0)>=((c[l>>2]|0)-3|0))break;e=c[h>>2]|0;c[h>>2]=e+4;g[r>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[q>>2]=+g[e>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[r>>2]*+g[n>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[r>>2]*+g[o>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[r>>2]*+g[p>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[r>>2]*+g[q>>2];e=c[h>>2]|0;c[h>>2]=e+4;g[r>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[n>>2]=+g[e>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[r>>2]*+g[o>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[r>>2]*+g[p>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[r>>2]*+g[q>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[r>>2]*+g[n>>2];e=c[h>>2]|0;c[h>>2]=e+4;g[r>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[o>>2]=+g[e>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[r>>2]*+g[p>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[r>>2]*+g[q>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[r>>2]*+g[n>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[r>>2]*+g[o>>2];e=c[h>>2]|0;c[h>>2]=e+4;g[r>>2]=+g[e>>2];e=c[j>>2]|0;c[j>>2]=e+4;g[p>>2]=+g[e>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[r>>2]*+g[q>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[r>>2]*+g[n>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[r>>2]*+g[o>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[r>>2]*+g[p>>2];c[m>>2]=(c[m>>2]|0)+4}r=c[m>>2]|0;c[m>>2]=r+1;if((r|0)<(c[l>>2]|0)){r=c[h>>2]|0;c[h>>2]=r+4;g[s>>2]=+g[r>>2];r=c[j>>2]|0;c[j>>2]=r+4;g[q>>2]=+g[r>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[s>>2]*+g[n>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[s>>2]*+g[o>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[s>>2]*+g[p>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[s>>2]*+g[q>>2]}s=c[m>>2]|0;c[m>>2]=s+1;if((s|0)<(c[l>>2]|0)){s=c[h>>2]|0;c[h>>2]=s+4;g[t>>2]=+g[s>>2];s=c[j>>2]|0;c[j>>2]=s+4;g[n>>2]=+g[s>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[t>>2]*+g[o>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[t>>2]*+g[p>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[t>>2]*+g[q>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[t>>2]*+g[n>>2]}if((c[m>>2]|0)>=(c[l>>2]|0)){i=f;return}l=c[h>>2]|0;c[h>>2]=l+4;g[u>>2]=+g[l>>2];l=c[j>>2]|0;c[j>>2]=l+4;g[o>>2]=+g[l>>2];g[c[k>>2]>>2]=+g[c[k>>2]>>2]+ +g[u>>2]*+g[p>>2];g[(c[k>>2]|0)+4>>2]=+g[(c[k>>2]|0)+4>>2]+ +g[u>>2]*+g[q>>2];g[(c[k>>2]|0)+8>>2]=+g[(c[k>>2]|0)+8>>2]+ +g[u>>2]*+g[n>>2];g[(c[k>>2]|0)+12>>2]=+g[(c[k>>2]|0)+12>>2]+ +g[u>>2]*+g[o>>2];i=f;return}function wd(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;a=(c[(c[d>>2]|0)+20>>2]|0)-(32-(aa(c[(c[d>>2]|0)+28>>2]|0)|0))|0;i=b;return a|0}function xd(a,e,f,g,h,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B){a=a|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;r=r|0;s=s|0;t=t|0;u=u|0;v=v|0;w=w|0;x=x|0;y=y|0;z=z|0;A=A|0;B=B|0;var C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0,Oa=0,Pa=0;C=i;i=i+224|0;D=C+204|0;E=C+188|0;F=C+168|0;G=C+68|0;H=C+80|0;I=C+84|0;J=C+12|0;K=C+156|0;L=C+16|0;M=C+20|0;N=C+24|0;O=C+28|0;P=C+32|0;Q=C+36|0;R=C+40|0;S=C+152|0;T=C+44|0;U=C+48|0;V=C+52|0;W=C+56|0;X=C+60|0;Y=C+64|0;Z=C+176|0;$=C+184|0;aa=C+192|0;ba=C+200|0;ca=C+208|0;da=C+88|0;ea=C+92|0;fa=C+96|0;ga=C+100|0;ha=C+148|0;ia=C+104|0;ja=C+108|0;ka=C+112|0;la=C+116|0;ma=C+120|0;na=C+124|0;oa=C+128|0;pa=C+132|0;qa=C+136|0;ra=C+140|0;sa=C+144|0;ta=C+8|0;ua=C;va=C+160|0;wa=C+164|0;xa=C+4|0;ya=C+172|0;za=C+72|0;Aa=C+180|0;Ba=C+76|0;Ca=C+196|0;c[D>>2]=a;c[E>>2]=e;c[F>>2]=f;c[G>>2]=g;c[H>>2]=h;c[I>>2]=j;c[J>>2]=k;c[K>>2]=l;c[L>>2]=m;c[M>>2]=n;c[N>>2]=o;c[O>>2]=p;c[P>>2]=q;c[Q>>2]=r;c[R>>2]=s;c[S>>2]=t;c[T>>2]=u;c[U>>2]=v;c[V>>2]=w;c[W>>2]=x;c[X>>2]=y;c[Y>>2]=z;c[Z>>2]=A;c[$>>2]=B;c[ha>>2]=-1;c[ia>>2]=c[V>>2]<<3;c[ga>>2]=(c[V>>2]|0)>1&1;c[fa>>2]=c[W>>2]<<3;c[ba>>2]=0;c[ca>>2]=64;c[da>>2]=0;while(1){if((c[da>>2]|0)>=6)break;c[na>>2]=(c[ba>>2]|0)+(c[ca>>2]|0)>>1;c[aa>>2]=0;c[la>>2]=0;c[ea>>2]=c[F>>2];while(1){B=c[ea>>2]|0;c[ea>>2]=B+-1;if((B|0)<=(c[E>>2]|0))break;c[oa>>2]=(c[(c[H>>2]|0)+(c[ea>>2]<<2)>>2]|0)+((_(c[na>>2]|0,c[(c[I>>2]|0)+(c[ea>>2]<<2)>>2]|0)|0)>>6);if(!((c[la>>2]|0)!=0?1:(c[oa>>2]|0)>=(c[(c[J>>2]|0)+(c[ea>>2]<<2)>>2]|0))){if((c[oa>>2]|0)<(c[ia>>2]|0))continue;c[aa>>2]=(c[aa>>2]|0)+(c[ia>>2]|0);continue}c[la>>2]=1;if((c[oa>>2]|0)<(c[(c[K>>2]|0)+(c[ea>>2]<<2)>>2]|0))Da=c[oa>>2]|0;else Da=c[(c[K>>2]|0)+(c[ea>>2]<<2)>>2]|0;c[aa>>2]=(c[aa>>2]|0)+Da}B=c[na>>2]|0;if((c[aa>>2]|0)>(c[L>>2]|0))c[ca>>2]=B;else c[ba>>2]=B;c[da>>2]=(c[da>>2]|0)+1}c[aa>>2]=0;c[la>>2]=0;c[ea>>2]=c[F>>2];while(1){da=c[ea>>2]|0;c[ea>>2]=da+-1;if((da|0)<=(c[E>>2]|0))break;c[pa>>2]=(c[(c[H>>2]|0)+(c[ea>>2]<<2)>>2]|0)+((_(c[ba>>2]|0,c[(c[I>>2]|0)+(c[ea>>2]<<2)>>2]|0)|0)>>6);do if(!((c[la>>2]|0)!=0?1:(c[pa>>2]|0)>=(c[(c[J>>2]|0)+(c[ea>>2]<<2)>>2]|0)))if((c[pa>>2]|0)>=(c[ia>>2]|0)){c[pa>>2]=c[ia>>2];break}else{c[pa>>2]=0;break}else c[la>>2]=1;while(0);if((c[pa>>2]|0)<(c[(c[K>>2]|0)+(c[ea>>2]<<2)>>2]|0))Ea=c[pa>>2]|0;else Ea=c[(c[K>>2]|0)+(c[ea>>2]<<2)>>2]|0;c[pa>>2]=Ea;c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]=c[pa>>2];c[aa>>2]=(c[aa>>2]|0)+(c[pa>>2]|0)}c[ha>>2]=c[F>>2];while(1){c[ea>>2]=(c[ha>>2]|0)-1;if((c[ea>>2]|0)<=(c[G>>2]|0)){Fa=29;break}c[ja>>2]=(c[L>>2]|0)-(c[aa>>2]|0);c[ka>>2]=ye(c[ja>>2]|0,(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ha>>2]<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[E>>2]<<1)>>1]|0)|0)|0;pa=_((b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ha>>2]<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[E>>2]<<1)>>1]|0)|0,c[ka>>2]|0)|0;c[ja>>2]=(c[ja>>2]|0)-pa;if(((c[ja>>2]|0)-((b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ea>>2]<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[E>>2]<<1)>>1]|0))|0)>0)Ga=(c[ja>>2]|0)-((b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ea>>2]<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[E>>2]<<1)>>1]|0))|0;else Ga=0;c[sa>>2]=Ga;c[qa>>2]=(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ha>>2]<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ea>>2]<<1)>>1]|0);pa=(c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]|0)+(_(c[ka>>2]|0,c[qa>>2]|0)|0)|0;c[ra>>2]=pa+(c[sa>>2]|0);if((c[(c[J>>2]|0)+(c[ea>>2]<<2)>>2]|0)>((c[ia>>2]|0)+8|0))Ha=c[(c[J>>2]|0)+(c[ea>>2]<<2)>>2]|0;else Ha=(c[ia>>2]|0)+8|0;if((c[ra>>2]|0)>=(Ha|0)){if(!(c[Y>>2]|0)){if(ib(c[X>>2]|0,1)|0)break}else{if((c[ha>>2]|0)<=((c[E>>2]|0)+2|0)){Fa=40;break}pa=_((c[ea>>2]|0)<(c[Z>>2]|0)?7:9,c[qa>>2]|0)|0;if((c[ra>>2]|0)>(pa<<c[W>>2]<<3>>4|0)?(c[ea>>2]|0)<=(c[$>>2]|0):0){Fa=40;break}nb(c[X>>2]|0,0,1)}c[aa>>2]=(c[aa>>2]|0)+8;c[ra>>2]=(c[ra>>2]|0)-8}c[aa>>2]=(c[aa>>2]|0)-((c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]|0)+(c[P>>2]|0));if((c[P>>2]|0)>0)c[P>>2]=d[2928+((c[ea>>2]|0)-(c[E>>2]|0))>>0];c[aa>>2]=(c[aa>>2]|0)+(c[P>>2]|0);if((c[ra>>2]|0)>=(c[ia>>2]|0)){c[aa>>2]=(c[aa>>2]|0)+(c[ia>>2]|0);c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]=c[ia>>2]}else c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]=0;c[ha>>2]=(c[ha>>2]|0)+-1}if((Fa|0)==29)c[L>>2]=(c[L>>2]|0)+(c[N>>2]|0);else if((Fa|0)==40)nb(c[X>>2]|0,1,1);do if((c[P>>2]|0)>0){if(!(c[Y>>2]|0)){Fa=c[E>>2]|0;N=Fa+(kb(c[X>>2]|0,(c[ha>>2]|0)+1-(c[E>>2]|0)|0)|0)|0;c[c[O>>2]>>2]=N;break}if((c[c[O>>2]>>2]|0)<(c[ha>>2]|0))Ia=c[c[O>>2]>>2]|0;else Ia=c[ha>>2]|0;c[c[O>>2]>>2]=Ia;ob(c[X>>2]|0,(c[c[O>>2]>>2]|0)-(c[E>>2]|0)|0,(c[ha>>2]|0)+1-(c[E>>2]|0)|0)}else c[c[O>>2]>>2]=0;while(0);if((c[c[O>>2]>>2]|0)<=(c[E>>2]|0)){c[L>>2]=(c[L>>2]|0)+(c[R>>2]|0);c[R>>2]=0}do if((c[R>>2]|0)>0){Ia=c[X>>2]|0;if(c[Y>>2]|0){nb(Ia,c[c[Q>>2]>>2]|0,1);break}else{P=ib(Ia,1)|0;c[c[Q>>2]>>2]=P;break}}else c[c[Q>>2]>>2]=0;while(0);c[ja>>2]=(c[L>>2]|0)-(c[aa>>2]|0);c[ka>>2]=ye(c[ja>>2]|0,(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ha>>2]<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[E>>2]<<1)>>1]|0)|0)|0;aa=_((b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ha>>2]<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[E>>2]<<1)>>1]|0)|0,c[ka>>2]|0)|0;c[ja>>2]=(c[ja>>2]|0)-aa;c[ea>>2]=c[E>>2];while(1){if((c[ea>>2]|0)>=(c[ha>>2]|0))break;aa=_(c[ka>>2]|0,(b[(c[(c[D>>2]|0)+32>>2]|0)+((c[ea>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ea>>2]<<1)>>1]|0)|0)|0;L=(c[S>>2]|0)+(c[ea>>2]<<2)|0;c[L>>2]=(c[L>>2]|0)+aa;c[ea>>2]=(c[ea>>2]|0)+1}c[ea>>2]=c[E>>2];while(1){if((c[ea>>2]|0)>=(c[ha>>2]|0))break;if((c[ja>>2]|0)<((b[(c[(c[D>>2]|0)+32>>2]|0)+((c[ea>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ea>>2]<<1)>>1]|0)|0))Ja=c[ja>>2]|0;else Ja=(b[(c[(c[D>>2]|0)+32>>2]|0)+((c[ea>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ea>>2]<<1)>>1]|0)|0;c[ta>>2]=Ja;ka=(c[S>>2]|0)+(c[ea>>2]<<2)|0;c[ka>>2]=(c[ka>>2]|0)+(c[ta>>2]|0);c[ja>>2]=(c[ja>>2]|0)-(c[ta>>2]|0);c[ea>>2]=(c[ea>>2]|0)+1}c[ma>>2]=0;c[ea>>2]=c[E>>2];while(1){if((c[ea>>2]|0)>=(c[ha>>2]|0))break;c[ua>>2]=(b[(c[(c[D>>2]|0)+32>>2]|0)+((c[ea>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[D>>2]|0)+32>>2]|0)+(c[ea>>2]<<1)>>1]|0);c[va>>2]=c[ua>>2]<<c[W>>2];c[Aa>>2]=(c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]|0)+(c[ma>>2]|0);E=c[Aa>>2]|0;if((c[va>>2]|0)>1){if((E-(c[(c[K>>2]|0)+(c[ea>>2]<<2)>>2]|0)|0)>0)Ka=(c[Aa>>2]|0)-(c[(c[K>>2]|0)+(c[ea>>2]<<2)>>2]|0)|0;else Ka=0;c[za>>2]=Ka;c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]=(c[Aa>>2]|0)-(c[za>>2]|0);ta=_(c[V>>2]|0,c[va>>2]|0)|0;if((c[V>>2]|0)==2&(c[va>>2]|0)>2?(c[c[Q>>2]>>2]|0)==0:0)La=(c[ea>>2]|0)<(c[c[O>>2]>>2]|0);else La=0;c[wa>>2]=ta+(La?1:0);c[ya>>2]=_(c[wa>>2]|0,(b[(c[(c[D>>2]|0)+56>>2]|0)+(c[ea>>2]<<1)>>1]|0)+(c[fa>>2]|0)|0)|0;c[xa>>2]=(c[ya>>2]>>1)-((c[wa>>2]|0)*21|0);if((c[va>>2]|0)==2)c[xa>>2]=(c[xa>>2]|0)+(c[wa>>2]<<3>>2);if(((c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]|0)+(c[xa>>2]|0)|0)>=(c[wa>>2]<<1<<3|0)){if(((c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]|0)+(c[xa>>2]|0)|0)<((c[wa>>2]|0)*3<<3|0))c[xa>>2]=(c[xa>>2]|0)+(c[ya>>2]>>3)}else c[xa>>2]=(c[xa>>2]|0)+(c[ya>>2]>>2);if(0>((c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]|0)+(c[xa>>2]|0)+(c[wa>>2]<<2)|0))Ma=0;else Ma=(c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]|0)+(c[xa>>2]|0)+(c[wa>>2]<<2)|0;c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]=Ma;ta=(ye(c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]|0,c[wa>>2]|0)|0)>>>3;c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]=ta;ta=_(c[V>>2]|0,c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]|0)|0;if((ta|0)>(c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]>>3|0))c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]=c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]>>c[ga>>2]>>3;if((c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]|0)<8)Na=c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]|0;else Na=8;c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]=Na;ta=_(c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]|0,c[wa>>2]<<3)|0;c[(c[U>>2]|0)+(c[ea>>2]<<2)>>2]=(ta|0)>=((c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]|0)+(c[xa>>2]|0)|0)&1;ta=(_(c[V>>2]|0,c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]|0)|0)<<3;ja=(c[S>>2]|0)+(c[ea>>2]<<2)|0;c[ja>>2]=(c[ja>>2]|0)-ta}else{if(0>(E-(c[V>>2]<<3)|0))Oa=0;else Oa=(c[Aa>>2]|0)-(c[V>>2]<<3)|0;c[za>>2]=Oa;c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]=(c[Aa>>2]|0)-(c[za>>2]|0);c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]=0;c[(c[U>>2]|0)+(c[ea>>2]<<2)>>2]=1}if((c[za>>2]|0)>0){if((c[za>>2]>>(c[ga>>2]|0)+3|0)<(8-(c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]|0)|0))Pa=c[za>>2]>>(c[ga>>2]|0)+3;else Pa=8-(c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]|0)|0;c[Ba>>2]=Pa;E=(c[T>>2]|0)+(c[ea>>2]<<2)|0;c[E>>2]=(c[E>>2]|0)+(c[Ba>>2]|0);c[Ca>>2]=(_(c[Ba>>2]|0,c[V>>2]|0)|0)<<3;c[(c[U>>2]|0)+(c[ea>>2]<<2)>>2]=(c[Ca>>2]|0)>=((c[za>>2]|0)-(c[ma>>2]|0)|0)&1;c[za>>2]=(c[za>>2]|0)-(c[Ca>>2]|0)}c[ma>>2]=c[za>>2];c[ea>>2]=(c[ea>>2]|0)+1}c[c[M>>2]>>2]=c[ma>>2];while(1){if((c[ea>>2]|0)>=(c[F>>2]|0))break;c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]=c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]>>c[ga>>2]>>3;c[(c[S>>2]|0)+(c[ea>>2]<<2)>>2]=0;c[(c[U>>2]|0)+(c[ea>>2]<<2)>>2]=(c[(c[T>>2]|0)+(c[ea>>2]<<2)>>2]|0)<1&1;c[ea>>2]=(c[ea>>2]|0)+1}i=C;return c[ha>>2]|0}function yd(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;j=i;i=i+64|0;k=j+44|0;l=j+36|0;m=j+12|0;n=j+8|0;o=j+32|0;p=j+40|0;q=j+48|0;r=j+16|0;s=j;t=j+24|0;u=j+4|0;v=j+28|0;w=j+20|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;c[v>>2]=0;if((c[p>>2]|0)==0?1:(c[o>>2]<<1|0)>=(c[l>>2]|0)){i=j;return}c[w>>2]=c[5216+((c[p>>2]|0)-1<<2)>>2];g[t>>2]=+(c[l>>2]|0)*1.0/+((c[l>>2]|0)+(_(c[w>>2]|0,c[o>>2]|0)|0)|0);g[u>>2]=+g[t>>2]*+g[t>>2]*.5;g[r>>2]=+Q(+(+g[u>>2]*1.5707963705062866));g[s>>2]=+Q(+((1.0-+g[u>>2])*1.5707963705062866));a:do if((c[l>>2]|0)>=(c[n>>2]<<3|0)){c[v>>2]=1;while(1){u=_(c[v>>2]|0,c[v>>2]|0)|0;t=_(u+(c[v>>2]|0)|0,c[n>>2]|0)|0;if((t+(c[n>>2]>>2)|0)>=(c[l>>2]|0))break a;c[v>>2]=(c[v>>2]|0)+1}}while(0);c[l>>2]=we(c[l>>2]|0,c[n>>2]|0)|0;c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[n>>2]|0))break;if((c[m>>2]|0)>=0){t=(c[k>>2]|0)+((_(c[q>>2]|0,c[l>>2]|0)|0)<<2)|0;xe(t,c[l>>2]|0,1,+g[r>>2],-+g[s>>2]);if(c[v>>2]|0){t=(c[k>>2]|0)+((_(c[q>>2]|0,c[l>>2]|0)|0)<<2)|0;xe(t,c[l>>2]|0,c[v>>2]|0,+g[s>>2],-+g[r>>2])}}else{if(c[v>>2]|0){t=(c[k>>2]|0)+((_(c[q>>2]|0,c[l>>2]|0)|0)<<2)|0;xe(t,c[l>>2]|0,c[v>>2]|0,+g[s>>2],+g[r>>2])}t=(c[k>>2]|0)+((_(c[q>>2]|0,c[l>>2]|0)|0)<<2)|0;xe(t,c[l>>2]|0,1,+g[r>>2],+g[s>>2])}c[q>>2]=(c[q>>2]|0)+1}i=j;return}function zd(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;e=i;i=i+48|0;f=e+28|0;g=e+16|0;h=e+4|0;j=e+8|0;k=e+32|0;l=e;m=e+12|0;n=e+24|0;o=e+20|0;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;if((c[j>>2]|0)<=1){c[f>>2]=1;p=c[f>>2]|0;i=e;return p|0}c[l>>2]=we(c[h>>2]|0,c[j>>2]|0)|0;c[k>>2]=0;c[m>>2]=0;do{c[o>>2]=0;c[n>>2]=0;do{h=_(c[m>>2]|0,c[l>>2]|0)|0;c[o>>2]=c[o>>2]|c[(c[g>>2]|0)+(h+(c[n>>2]|0)<<2)>>2];h=(c[n>>2]|0)+1|0;c[n>>2]=h}while((h|0)<(c[l>>2]|0));c[k>>2]=c[k>>2]|((c[o>>2]|0)!=0&1)<<c[m>>2];h=(c[m>>2]|0)+1|0;c[m>>2]=h}while((h|0)<(c[j>>2]|0));c[f>>2]=c[k>>2];p=c[f>>2]|0;i=e;return p|0}function Ad(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=+e;f=+f;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;h=i;i=i+32|0;j=h+4|0;k=h+16|0;l=h+8|0;m=h+20|0;n=h+28|0;o=h;p=h+12|0;q=h+24|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;g[m>>2]=e;g[n>>2]=f;g[p>>2]=+g[m>>2];f=1.0/+O(+(+g[p>>2]));g[q>>2]=f*+g[n>>2];c[o>>2]=0;do{g[(c[k>>2]|0)+(c[o>>2]<<2)>>2]=+g[q>>2]*+(c[(c[j>>2]|0)+(c[o>>2]<<2)>>2]|0);n=(c[o>>2]|0)+1|0;c[o>>2]=n}while((n|0)<(c[l>>2]|0));i=h;return}function Bd(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0.0;e=i;i=i+32|0;f=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[f>>2]=a;c[h>>2]=b;c[j>>2]=d;g[l>>2]=0.0;c[k>>2]=0;while(1){m=+g[l>>2];if((c[k>>2]|0)>=(c[j>>2]|0))break;g[l>>2]=m+ +g[(c[f>>2]|0)+(c[k>>2]<<2)>>2]*+g[(c[h>>2]|0)+(c[k>>2]<<2)>>2];c[k>>2]=(c[k>>2]|0)+1}i=e;return +m}function Cd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;g=i;i=i+48|0;h=g+28|0;j=g+16|0;k=g+4|0;l=g+8|0;m=g+32|0;n=g;o=g+12|0;p=g+24|0;q=g+20|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;c[q>>2]=255;while(1){if((c[q>>2]|0)<=(c[l>>2]|0))break;c[q>>2]=c[q>>2]>>1}c[n>>2]=c[c[m>>2]>>2];c[o>>2]=0;while(1){r=c[n>>2]|0;if((c[o>>2]|0)>=(c[l>>2]|0))break;c[n>>2]=907633515+(_(r,196314165)|0);c[p>>2]=c[n>>2]>>24&c[q>>2];f=_(c[(c[j>>2]|0)+(c[p>>2]<<2)>>2]>>16,(c[k>>2]>>4&65535)<<16>>16)|0;e=f+((_(c[(c[j>>2]|0)+(c[p>>2]<<2)>>2]&65535,(c[k>>2]>>4&65535)<<16>>16)|0)>>16)|0;if((e+(_(c[(c[j>>2]|0)+(c[p>>2]<<2)>>2]|0,(c[k>>2]>>4>>15)+1>>1)|0)|0)<=32767){e=_(c[(c[j>>2]|0)+(c[p>>2]<<2)>>2]>>16,(c[k>>2]>>4&65535)<<16>>16)|0;f=e+((_(c[(c[j>>2]|0)+(c[p>>2]<<2)>>2]&65535,(c[k>>2]>>4&65535)<<16>>16)|0)>>16)|0;if((f+(_(c[(c[j>>2]|0)+(c[p>>2]<<2)>>2]|0,(c[k>>2]>>4>>15)+1>>1)|0)|0)<-32768)s=-32768;else{f=_(c[(c[j>>2]|0)+(c[p>>2]<<2)>>2]>>16,(c[k>>2]>>4&65535)<<16>>16)|0;e=f+((_(c[(c[j>>2]|0)+(c[p>>2]<<2)>>2]&65535,(c[k>>2]>>4&65535)<<16>>16)|0)>>16)|0;s=e+(_(c[(c[j>>2]|0)+(c[p>>2]<<2)>>2]|0,(c[k>>2]>>4>>15)+1>>1)|0)|0}}else s=32767;c[(c[h>>2]|0)+(c[o>>2]<<2)>>2]=(s&65535)<<16>>16;c[o>>2]=(c[o>>2]|0)+1}c[c[m>>2]>>2]=r;i=g;return}function Dd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;d=i;i=i+48|0;e=d+28|0;f=d+16|0;g=d+4|0;h=d+8|0;j=d+32|0;k=d;l=d+12|0;m=d+24|0;n=d+20|0;c[f>>2]=a;c[g>>2]=b;b=c[f>>2]|0;c[h>>2]=(ve((c[f>>2]|0)>0?b:0-b|0)|0)-1;c[l>>2]=c[f>>2]<<c[h>>2];c[k>>2]=536870911/(c[l>>2]>>16|0)|0;c[n>>2]=c[k>>2]<<16;f=_(c[l>>2]>>16,(c[k>>2]&65535)<<16>>16)|0;c[m>>2]=536870912-(f+((_(c[l>>2]&65535,(c[k>>2]&65535)<<16>>16)|0)>>16))<<3;l=_(c[m>>2]>>16,(c[k>>2]&65535)<<16>>16)|0;f=(c[n>>2]|0)+(l+((_(c[m>>2]&65535,(c[k>>2]&65535)<<16>>16)|0)>>16))|0;c[n>>2]=f+(_(c[m>>2]|0,(c[k>>2]>>15)+1>>1)|0);c[j>>2]=61-(c[h>>2]|0)-(c[g>>2]|0);g=c[j>>2]|0;if((c[j>>2]|0)>0)if((g|0)<32){c[e>>2]=c[n>>2]>>c[j>>2];o=c[e>>2]|0;i=d;return o|0}else{c[e>>2]=0;o=c[e>>2]|0;i=d;return o|0}h=c[n>>2]|0;k=0-(c[j>>2]|0)|0;do if((-2147483648>>0-g|0)>(2147483647>>0-(c[j>>2]|0)|0)){if((h|0)>(-2147483648>>k|0)){p=-2147483648>>0-(c[j>>2]|0);break}if((c[n>>2]|0)<(2147483647>>0-(c[j>>2]|0)|0)){p=2147483647>>0-(c[j>>2]|0);break}else{p=c[n>>2]|0;break}}else{if((h|0)>(2147483647>>k|0)){p=2147483647>>0-(c[j>>2]|0);break}if((c[n>>2]|0)<(-2147483648>>0-(c[j>>2]|0)|0)){p=-2147483648>>0-(c[j>>2]|0);break}else{p=c[n>>2]|0;break}}while(0);c[e>>2]=p<<0-(c[j>>2]|0);o=c[e>>2]|0;i=d;return o|0}function Ed(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;e=i;i=i+48|0;f=e+36|0;g=e+16|0;h=e;j=e+28|0;k=e+32|0;l=e+40|0;m=e+12|0;n=e+24|0;o=e+20|0;p=e+8|0;q=e+4|0;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;d=c[g>>2]|0;c[k>>2]=(ve((c[g>>2]|0)>0?d:0-d|0)|0)-1;c[o>>2]=c[g>>2]<<c[k>>2];g=c[h>>2]|0;c[l>>2]=(ve((c[h>>2]|0)>0?g:0-g|0)|0)-1;c[p>>2]=c[h>>2]<<c[l>>2];c[n>>2]=536870911/(c[p>>2]>>16|0)|0;h=_(c[o>>2]>>16,(c[n>>2]&65535)<<16>>16)|0;c[q>>2]=h+((_(c[o>>2]&65535,(c[n>>2]&65535)<<16>>16)|0)>>16);h=c[o>>2]|0;g=c[p>>2]|0;p=c[q>>2]|0;d=of(g|0,((g|0)<0)<<31>>31|0,p|0,((p|0)<0)<<31>>31|0)|0;p=af(d|0,C|0,32)|0;c[o>>2]=h-(p<<3);p=_(c[o>>2]>>16,(c[n>>2]&65535)<<16>>16)|0;c[q>>2]=(c[q>>2]|0)+(p+((_(c[o>>2]&65535,(c[n>>2]&65535)<<16>>16)|0)>>16));c[m>>2]=29+(c[k>>2]|0)-(c[l>>2]|0)-(c[j>>2]|0);j=c[m>>2]|0;if((c[m>>2]|0)>=0)if((j|0)<32){c[f>>2]=c[q>>2]>>c[m>>2];r=c[f>>2]|0;i=e;return r|0}else{c[f>>2]=0;r=c[f>>2]|0;i=e;return r|0}l=c[q>>2]|0;k=0-(c[m>>2]|0)|0;do if((-2147483648>>0-j|0)>(2147483647>>0-(c[m>>2]|0)|0)){if((l|0)>(-2147483648>>k|0)){s=-2147483648>>0-(c[m>>2]|0);break}if((c[q>>2]|0)<(2147483647>>0-(c[m>>2]|0)|0)){s=2147483647>>0-(c[m>>2]|0);break}else{s=c[q>>2]|0;break}}else{if((l|0)>(2147483647>>k|0)){s=2147483647>>0-(c[m>>2]|0);break}if((c[q>>2]|0)<(-2147483648>>0-(c[m>>2]|0)|0)){s=-2147483648>>0-(c[m>>2]|0);break}else{s=c[q>>2]|0;break}}while(0);c[f>>2]=s<<0-(c[m>>2]|0);r=c[f>>2]|0;i=e;return r|0}function Fd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)<(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}function Gd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}function Hd(e,f,g,h,j){e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;k=i;i=i+32|0;l=k+24|0;m=k+16|0;n=k+12|0;o=k+8|0;p=k+28|0;q=k;r=k+20|0;s=k+4|0;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[o>>2]=h;b[p>>1]=j;c[r>>2]=0;c[q>>2]=(b[p>>1]|0)-1;while(1){if((c[q>>2]|0)<0)break;c[s>>2]=(_((c[r>>2]&65535)<<16>>16,d[(c[n>>2]|0)+(c[q>>2]|0)>>0]|0)|0)>>8;c[r>>2]=a[(c[m>>2]|0)+(c[q>>2]|0)>>0]<<10;p=c[r>>2]|0;if((c[r>>2]|0)<=0){if((p|0)<0)c[r>>2]=(c[r>>2]|0)+102}else c[r>>2]=p-102;p=_(c[r>>2]>>16,(c[o>>2]&65535)<<16>>16)|0;c[r>>2]=(c[s>>2]|0)+(p+((_(c[r>>2]&65535,(c[o>>2]&65535)<<16>>16)|0)>>16));b[(c[l>>2]|0)+(c[q>>2]<<1)>>1]=c[r>>2];c[q>>2]=(c[q>>2]|0)+-1}i=k;return}function Id(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0;b=i;i=i+32|0;d=b+16|0;e=b+12|0;f=b+8|0;g=b+4|0;h=b;c[e>>2]=a;if((c[e>>2]|0)<=0){c[d>>2]=0;j=c[d>>2]|0;i=b;return j|0}se(c[e>>2]|0,g,h);if(c[g>>2]&1)c[f>>2]=32768;else c[f>>2]=46214;c[f>>2]=c[f>>2]>>(c[g>>2]>>1);g=_(c[f>>2]>>16,(((c[h>>2]&65535)<<16>>16)*213&65535)<<16>>16)|0;c[f>>2]=(c[f>>2]|0)+(g+((_(c[f>>2]&65535,(((c[h>>2]&65535)<<16>>16)*213&65535)<<16>>16)|0)>>16));c[d>>2]=c[f>>2];j=c[d>>2]|0;i=b;return j|0}function Jd(a,d,e){a=a|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0;f=i;i=i+160|0;g=f+68|0;h=f+100|0;j=f+40|0;k=f+44|0;l=f+92|0;m=f+8|0;n=f+12|0;o=f+72|0;p=f+16|0;q=f+20|0;r=f+88|0;s=f+96|0;t=f+104|0;u=f+112|0;v=f+48|0;w=f+116|0;x=f+52|0;y=f+56|0;z=f+60|0;A=f+64|0;B=f+4|0;C=f+120|0;D=f+84|0;E=f+24|0;F=f+128|0;G=f;H=f+32|0;I=f+108|0;J=f+80|0;K=f+76|0;c[g>>2]=a;c[h>>2]=d;c[j>>2]=e;c[G>>2]=(c[g>>2]|0)+4168;e=(c[(c[g>>2]|0)+2336>>2]|0)+(c[(c[g>>2]|0)+2328>>2]|0)|0;c[I>>2]=ua()|0;d=i;i=i+((1*(e<<2)|0)+15&-16)|0;e=i;i=i+((1*(c[(c[g>>2]|0)+2336>>2]<<1)|0)+15&-16)|0;c[H>>2]=c[(c[G>>2]|0)+72>>2]>>6;c[H+4>>2]=c[(c[G>>2]|0)+72+4>>2]>>6;if(c[(c[g>>2]|0)+2376>>2]|0){L=(c[G>>2]|0)+14|0;M=L+32|0;do{b[L>>1]=0;L=L+2|0}while((L|0)<(M|0))}me(w,q,x,r,(c[g>>2]|0)+4|0,H,c[(c[g>>2]|0)+2332>>2]|0,c[(c[g>>2]|0)+2324>>2]|0);a=c[(c[G>>2]|0)+84>>2]|0;if((c[w>>2]>>c[r>>2]|0)<(c[x>>2]>>c[q>>2]|0)){q=ne(0,(_(a-1|0,c[(c[G>>2]|0)+88>>2]|0)|0)-128|0)|0;c[y>>2]=(c[g>>2]|0)+4+(q<<2)}else{q=ne(0,(_(a,c[(c[G>>2]|0)+88>>2]|0)|0)-128|0)|0;c[y>>2]=(c[g>>2]|0)+4+(q<<2)}c[D>>2]=(c[G>>2]|0)+4;b[C>>1]=b[(c[G>>2]|0)+56>>1]|0;c[t>>2]=b[5192+((oe(1,c[(c[g>>2]|0)+4160>>2]|0)|0)<<1)>>1];q=(c[(c[g>>2]|0)+4164>>2]|0)==2;a=oe(1,c[(c[g>>2]|0)+4160>>2]|0)|0;if(q)c[u>>2]=b[5200+(a<<1)>>1];else c[u>>2]=b[5208+(a<<1)>>1];ec((c[G>>2]|0)+14|0,c[(c[g>>2]|0)+2340>>2]|0,64881);df(F|0,(c[G>>2]|0)+14|0,c[(c[g>>2]|0)+2340>>2]<<1|0)|0;do if(!(c[(c[g>>2]|0)+4160>>2]|0)){b[C>>1]=16384;if((c[(c[g>>2]|0)+4164>>2]|0)!=2){c[J>>2]=ic((c[G>>2]|0)+14|0,c[(c[g>>2]|0)+2340>>2]|0)|0;c[K>>2]=qe(134217728,c[J>>2]|0)|0;c[K>>2]=Md(4194304,c[K>>2]|0)|0;c[K>>2]=c[K>>2]<<3;a=_(c[K>>2]>>16,(c[u>>2]&65535)<<16>>16)|0;c[u>>2]=a+((_(c[K>>2]&65535,(c[u>>2]&65535)<<16>>16)|0)>>16)>>14;break}c[k>>2]=0;while(1){if((c[k>>2]|0)>=5)break;b[C>>1]=(b[C>>1]|0)-(b[(c[D>>2]|0)+(c[k>>2]<<1)>>1]|0);c[k>>2]=(c[k>>2]|0)+1}b[C>>1]=pe(3277,b[C>>1]|0)|0;b[C>>1]=(_(b[C>>1]|0,b[(c[G>>2]|0)+68>>1]|0)|0)>>14}while(0);c[s>>2]=c[(c[G>>2]|0)+52>>2];c[n>>2]=(c[c[G>>2]>>2]>>7)+1>>1;c[p>>2]=c[(c[g>>2]|0)+2336>>2];c[o>>2]=(c[(c[g>>2]|0)+2336>>2]|0)-(c[n>>2]|0)-(c[(c[g>>2]|0)+2340>>2]|0)-2;hc(e+(c[o>>2]<<1)|0,(c[g>>2]|0)+1348+(c[o>>2]<<1)|0,F,(c[(c[g>>2]|0)+2336>>2]|0)-(c[o>>2]|0)|0,c[(c[g>>2]|0)+2340>>2]|0);c[v>>2]=re(c[(c[G>>2]|0)+72+4>>2]|0,46)|0;c[v>>2]=(c[v>>2]|0)<1073741823?c[v>>2]|0:1073741823;c[k>>2]=(c[o>>2]|0)+(c[(c[g>>2]|0)+2340>>2]|0);while(1){if((c[k>>2]|0)>=(c[(c[g>>2]|0)+2336>>2]|0))break;K=_(c[v>>2]>>16,b[e+(c[k>>2]<<1)>>1]|0)|0;J=K+((_(c[v>>2]&65535,b[e+(c[k>>2]<<1)>>1]|0)|0)>>16)|0;c[d+(c[k>>2]<<2)>>2]=J;c[k>>2]=(c[k>>2]|0)+1}c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[(c[g>>2]|0)+2324>>2]|0))break;c[z>>2]=d+((c[p>>2]|0)-(c[n>>2]|0)+2<<2);c[k>>2]=0;while(1){if((c[k>>2]|0)>=(c[(c[g>>2]|0)+2332>>2]|0))break;c[B>>2]=2;e=_(c[c[z>>2]>>2]>>16,b[c[D>>2]>>1]|0)|0;c[B>>2]=(c[B>>2]|0)+(e+((_(c[c[z>>2]>>2]&65535,b[c[D>>2]>>1]|0)|0)>>16));e=_(c[(c[z>>2]|0)+-4>>2]>>16,b[(c[D>>2]|0)+2>>1]|0)|0;c[B>>2]=(c[B>>2]|0)+(e+((_(c[(c[z>>2]|0)+-4>>2]&65535,b[(c[D>>2]|0)+2>>1]|0)|0)>>16));e=_(c[(c[z>>2]|0)+-8>>2]>>16,b[(c[D>>2]|0)+4>>1]|0)|0;c[B>>2]=(c[B>>2]|0)+(e+((_(c[(c[z>>2]|0)+-8>>2]&65535,b[(c[D>>2]|0)+4>>1]|0)|0)>>16));e=_(c[(c[z>>2]|0)+-12>>2]>>16,b[(c[D>>2]|0)+6>>1]|0)|0;c[B>>2]=(c[B>>2]|0)+(e+((_(c[(c[z>>2]|0)+-12>>2]&65535,b[(c[D>>2]|0)+6>>1]|0)|0)>>16));e=_(c[(c[z>>2]|0)+-16>>2]>>16,b[(c[D>>2]|0)+8>>1]|0)|0;c[B>>2]=(c[B>>2]|0)+(e+((_(c[(c[z>>2]|0)+-16>>2]&65535,b[(c[D>>2]|0)+8>>1]|0)|0)>>16));c[z>>2]=(c[z>>2]|0)+4;c[s>>2]=907633515+(_(c[s>>2]|0,196314165)|0);c[o>>2]=c[s>>2]>>25&127;e=_(c[(c[y>>2]|0)+(c[o>>2]<<2)>>2]>>16,b[C>>1]|0)|0;v=(c[B>>2]|0)+(e+((_(c[(c[y>>2]|0)+(c[o>>2]<<2)>>2]&65535,b[C>>1]|0)|0)>>16))<<2;c[d+(c[p>>2]<<2)>>2]=v;c[p>>2]=(c[p>>2]|0)+1;c[k>>2]=(c[k>>2]|0)+1}c[l>>2]=0;while(1){if((c[l>>2]|0)>=5)break;v=(_((c[t>>2]&65535)<<16>>16,b[(c[D>>2]|0)+(c[l>>2]<<1)>>1]|0)|0)>>15&65535;b[(c[D>>2]|0)+(c[l>>2]<<1)>>1]=v;c[l>>2]=(c[l>>2]|0)+1}b[C>>1]=(_(b[C>>1]|0,(c[u>>2]&65535)<<16>>16)|0)>>15;c[c[G>>2]>>2]=(c[c[G>>2]>>2]|0)+(((c[c[G>>2]>>2]>>16)*655|0)+((c[c[G>>2]>>2]&65535)*655>>16));v=qe(c[c[G>>2]>>2]|0,((c[(c[g>>2]|0)+2316>>2]&65535)<<16>>16)*18<<8)|0;c[c[G>>2]>>2]=v;c[n>>2]=(c[c[G>>2]>>2]>>7)+1>>1;c[m>>2]=(c[m>>2]|0)+1}c[E>>2]=d+((c[(c[g>>2]|0)+2336>>2]|0)-16<<2);L=c[E>>2]|0;d=(c[g>>2]|0)+1284|0;M=L+64|0;do{c[L>>2]=c[d>>2];L=L+4|0;d=d+4|0}while((L|0)<(M|0));c[k>>2]=0;while(1){N=c[g>>2]|0;if((c[k>>2]|0)>=(c[(c[g>>2]|0)+2328>>2]|0))break;c[A>>2]=c[N+2340>>2]>>1;m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-1<<2)>>2]>>16,b[F>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-1<<2)>>2]&65535,b[F>>1]|0)|0)>>16));m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-2<<2)>>2]>>16,b[F+2>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-2<<2)>>2]&65535,b[F+2>>1]|0)|0)>>16));m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-3<<2)>>2]>>16,b[F+4>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-3<<2)>>2]&65535,b[F+4>>1]|0)|0)>>16));m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-4<<2)>>2]>>16,b[F+6>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-4<<2)>>2]&65535,b[F+6>>1]|0)|0)>>16));m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-5<<2)>>2]>>16,b[F+8>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-5<<2)>>2]&65535,b[F+8>>1]|0)|0)>>16));m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-6<<2)>>2]>>16,b[F+10>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-6<<2)>>2]&65535,b[F+10>>1]|0)|0)>>16));m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-7<<2)>>2]>>16,b[F+12>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-7<<2)>>2]&65535,b[F+12>>1]|0)|0)>>16));m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-8<<2)>>2]>>16,b[F+14>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-8<<2)>>2]&65535,b[F+14>>1]|0)|0)>>16));m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-9<<2)>>2]>>16,b[F+16>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-9<<2)>>2]&65535,b[F+16>>1]|0)|0)>>16));m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-10<<2)>>2]>>16,b[F+18>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-10<<2)>>2]&65535,b[F+18>>1]|0)|0)>>16));c[l>>2]=10;while(1){if((c[l>>2]|0)>=(c[(c[g>>2]|0)+2340>>2]|0))break;m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-(c[l>>2]|0)-1<<2)>>2]>>16,b[F+(c[l>>2]<<1)>>1]|0)|0;c[A>>2]=(c[A>>2]|0)+(m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)-(c[l>>2]|0)-1<<2)>>2]&65535,b[F+(c[l>>2]<<1)>>1]|0)|0)>>16));c[l>>2]=(c[l>>2]|0)+1}c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]=(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0)+(c[A>>2]<<4);m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]>>16,(c[H+4>>2]&65535)<<16>>16)|0;u=m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]&65535,(c[H+4>>2]&65535)<<16>>16)|0)>>16)|0;if(((u+(_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0,(c[H+4>>2]>>15)+1>>1)|0)>>7)+1>>1|0)<=32767){u=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]>>16,(c[H+4>>2]&65535)<<16>>16)|0;m=u+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]&65535,(c[H+4>>2]&65535)<<16>>16)|0)>>16)|0;if(((m+(_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0,(c[H+4>>2]>>15)+1>>1)|0)>>7)+1>>1|0)<-32768)O=-32768;else{m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]>>16,(c[H+4>>2]&65535)<<16>>16)|0;u=m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]&65535,(c[H+4>>2]&65535)<<16>>16)|0)>>16)|0;O=(u+(_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0,(c[H+4>>2]>>15)+1>>1)|0)>>7)+1>>1}}else O=32767;if((O|0)<=32767){u=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]>>16,(c[H+4>>2]&65535)<<16>>16)|0;m=u+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]&65535,(c[H+4>>2]&65535)<<16>>16)|0)>>16)|0;if(((m+(_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0,(c[H+4>>2]>>15)+1>>1)|0)>>7)+1>>1|0)<=32767){m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]>>16,(c[H+4>>2]&65535)<<16>>16)|0;u=m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]&65535,(c[H+4>>2]&65535)<<16>>16)|0)>>16)|0;if(((u+(_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0,(c[H+4>>2]>>15)+1>>1)|0)>>7)+1>>1|0)<-32768)P=-32768;else{u=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]>>16,(c[H+4>>2]&65535)<<16>>16)|0;m=u+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]&65535,(c[H+4>>2]&65535)<<16>>16)|0)>>16)|0;P=(m+(_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0,(c[H+4>>2]>>15)+1>>1)|0)>>7)+1>>1}}else P=32767;if((P|0)>=-32768){m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]>>16,(c[H+4>>2]&65535)<<16>>16)|0;u=m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]&65535,(c[H+4>>2]&65535)<<16>>16)|0)>>16)|0;if(((u+(_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0,(c[H+4>>2]>>15)+1>>1)|0)>>7)+1>>1|0)<=32767){u=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]>>16,(c[H+4>>2]&65535)<<16>>16)|0;m=u+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]&65535,(c[H+4>>2]&65535)<<16>>16)|0)>>16)|0;if(((m+(_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0,(c[H+4>>2]>>15)+1>>1)|0)>>7)+1>>1|0)<-32768)Q=-32768;else{m=_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]>>16,(c[H+4>>2]&65535)<<16>>16)|0;u=m+((_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]&65535,(c[H+4>>2]&65535)<<16>>16)|0)>>16)|0;Q=(u+(_(c[(c[E>>2]|0)+(16+(c[k>>2]|0)<<2)>>2]|0,(c[H+4>>2]>>15)+1>>1)|0)>>7)+1>>1}}else Q=32767}else Q=-32768}else Q=32767;b[(c[j>>2]|0)+(c[k>>2]<<1)>>1]=Q;c[k>>2]=(c[k>>2]|0)+1}L=N+1284|0;d=(c[E>>2]|0)+(c[(c[g>>2]|0)+2328>>2]<<2)|0;M=L+64|0;do{c[L>>2]=c[d>>2];L=L+4|0;d=d+4|0}while((L|0)<(M|0));c[(c[G>>2]|0)+52>>2]=c[s>>2];b[(c[G>>2]|0)+56>>1]=b[C>>1]|0;c[k>>2]=0;while(1){if((c[k>>2]|0)>=4)break;c[(c[h>>2]|0)+(c[k>>2]<<2)>>2]=c[n>>2];c[k>>2]=(c[k>>2]|0)+1}ka(c[I>>2]|0);i=f;return}function Kd(d,e){d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;f=i;i=i+48|0;g=f+36|0;h=f+16|0;j=f;k=f+28|0;l=f+32|0;m=f+40|0;n=f+12|0;o=f+24|0;p=f+20|0;q=f+8|0;r=f+4|0;c[g>>2]=d;c[h>>2]=e;c[n>>2]=(c[g>>2]|0)+4168;c[(c[g>>2]|0)+4164>>2]=a[(c[g>>2]|0)+2736+29>>0];c[j>>2]=0;a:do if((a[(c[g>>2]|0)+2736+29>>0]|0)==2){c[m>>2]=0;while(1){e=_(c[m>>2]|0,c[(c[g>>2]|0)+2332>>2]|0)|0;if((e|0)>=(c[(c[h>>2]|0)+((c[(c[g>>2]|0)+2324>>2]|0)-1<<2)>>2]|0))break;if((c[m>>2]|0)==(c[(c[g>>2]|0)+2324>>2]|0))break;c[k>>2]=0;c[l>>2]=0;while(1){if((c[l>>2]|0)>=5)break;c[k>>2]=(c[k>>2]|0)+(b[(c[h>>2]|0)+96+((((c[(c[g>>2]|0)+2324>>2]|0)-1-(c[m>>2]|0)|0)*5|0)+(c[l>>2]|0)<<1)>>1]|0);c[l>>2]=(c[l>>2]|0)+1}if((c[k>>2]|0)>(c[j>>2]|0)){c[j>>2]=c[k>>2];e=(c[n>>2]|0)+4|0;d=(c[h>>2]|0)+96+((((c[(c[g>>2]|0)+2324>>2]|0)-1-(c[m>>2]|0)&65535)<<16>>16)*5<<1)|0;b[e>>1]=b[d>>1]|0;b[e+2>>1]=b[d+2>>1]|0;b[e+4>>1]=b[d+4>>1]|0;b[e+6>>1]=b[d+6>>1]|0;b[e+8>>1]=b[d+8>>1]|0;c[c[n>>2]>>2]=c[(c[h>>2]|0)+((c[(c[g>>2]|0)+2324>>2]|0)-1-(c[m>>2]|0)<<2)>>2]<<8}c[m>>2]=(c[m>>2]|0)+1}d=(c[n>>2]|0)+4|0;b[d>>1]=0;b[d+2>>1]=0;b[d+4>>1]=0;b[d+6>>1]=0;b[d+8>>1]=0;b[(c[n>>2]|0)+4+4>>1]=c[j>>2];if((c[j>>2]|0)<11469){c[p>>2]=11744256;c[o>>2]=(c[p>>2]|0)/(((c[j>>2]|0)>1?c[j>>2]|0:1)|0)|0;c[l>>2]=0;while(1){if((c[l>>2]|0)>=5)break a;d=(_(b[(c[n>>2]|0)+4+(c[l>>2]<<1)>>1]|0,(c[o>>2]&65535)<<16>>16)|0)>>10&65535;b[(c[n>>2]|0)+4+(c[l>>2]<<1)>>1]=d;c[l>>2]=(c[l>>2]|0)+1}}if((c[j>>2]|0)>15565){c[r>>2]=255016960;c[q>>2]=(c[r>>2]|0)/(((c[j>>2]|0)>1?c[j>>2]|0:1)|0)|0;c[l>>2]=0;while(1){if((c[l>>2]|0)>=5)break a;d=(_(b[(c[n>>2]|0)+4+(c[l>>2]<<1)>>1]|0,(c[q>>2]&65535)<<16>>16)|0)>>14&65535;b[(c[n>>2]|0)+4+(c[l>>2]<<1)>>1]=d;c[l>>2]=(c[l>>2]|0)+1}}}else{c[c[n>>2]>>2]=((c[(c[g>>2]|0)+2316>>2]&65535)<<16>>16)*18<<8;d=(c[n>>2]|0)+4|0;b[d>>1]=0;b[d+2>>1]=0;b[d+4>>1]=0;b[d+6>>1]=0;b[d+8>>1]=0}while(0);df((c[n>>2]|0)+14|0,(c[h>>2]|0)+32+32|0,c[(c[g>>2]|0)+2340>>2]<<1|0)|0;b[(c[n>>2]|0)+68>>1]=c[(c[h>>2]|0)+136>>2];l=(c[n>>2]|0)+72|0;q=(c[h>>2]|0)+16+((c[(c[g>>2]|0)+2324>>2]|0)-2<<2)|0;c[l>>2]=c[q>>2];c[l+4>>2]=c[q+4>>2];c[(c[n>>2]|0)+88>>2]=c[(c[g>>2]|0)+2332>>2];c[(c[n>>2]|0)+84>>2]=c[(c[g>>2]|0)+2324>>2];i=f;return}function Ld(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b;c[d>>2]=a;if(!(c[d>>2]|0)){e=32;i=b;return e|0}e=32-(32-(aa(c[d>>2]|0)|0))|0;i=b;return e|0}function Md(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}function Nd(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0;b=i;i=i+32|0;d=b+16|0;e=b+12|0;f=b+8|0;g=b+4|0;h=b;c[e>>2]=a;if((c[e>>2]|0)<=0){c[d>>2]=0;j=c[d>>2]|0;i=b;return j|0}ke(c[e>>2]|0,g,h);if(c[g>>2]&1)c[f>>2]=32768;else c[f>>2]=46214;c[f>>2]=c[f>>2]>>(c[g>>2]>>1);g=_(c[f>>2]>>16,(((c[h>>2]&65535)<<16>>16)*213&65535)<<16>>16)|0;c[f>>2]=(c[f>>2]|0)+(g+((_(c[f>>2]&65535,(((c[h>>2]&65535)<<16>>16)*213&65535)<<16>>16)|0)>>16));c[d>>2]=c[f>>2];j=c[d>>2]|0;i=b;return j|0}function Od(a,e,f,g,h){a=a|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0;j=i;i=i+32|0;k=j+16|0;l=j+12|0;m=j+8|0;n=j+4|0;o=j;c[k>>2]=a;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[o>>2]=h;if((c[n>>2]|0)>0){h=(jb(c[m>>2]|0,(c[o>>2]|0)+(d[1472+(c[n>>2]|0)>>0]|0)|0,8)|0)&65535;b[c[k>>2]>>1]=h;b[c[l>>2]>>1]=(c[n>>2]|0)-(b[c[k>>2]>>1]|0);i=j;return}else{b[c[k>>2]>>1]=0;b[c[l>>2]>>1]=0;i=j;return}}function Pd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0;d=i;i=i+64|0;e=d+44|0;f=d+36|0;g=d+12|0;h=d+8|0;j=d+32|0;k=d+40|0;l=d+48|0;m=d+16|0;n=d;o=d+24|0;p=d+4|0;q=d+28|0;r=d+20|0;c[f>>2]=a;c[g>>2]=b;c[r>>2]=(c[f>>2]|0)+((c[g>>2]&1)<<6);c[l>>2]=1073741824;c[h>>2]=(c[g>>2]|0)-1;while(1){if((c[h>>2]|0)<=0)break;if((c[(c[r>>2]|0)+(c[h>>2]<<2)>>2]|0)>16773022){s=5;break}if((c[(c[r>>2]|0)+(c[h>>2]<<2)>>2]|0)<-16773022){s=5;break}c[m>>2]=0-(c[(c[r>>2]|0)+(c[h>>2]<<2)>>2]<<7);g=c[m>>2]|0;b=c[m>>2]|0;a=of(g|0,((g|0)<0)<<31>>31|0,b|0,((b|0)<0)<<31>>31|0)|0;b=af(a|0,C|0,32)|0;c[n>>2]=1073741824-b;b=c[n>>2]|0;c[k>>2]=32-(ie((c[n>>2]|0)>0?b:0-b|0)|0);c[o>>2]=je(c[n>>2]|0,(c[k>>2]|0)+30|0)|0;b=c[l>>2]|0;a=c[n>>2]|0;g=of(b|0,((b|0)<0)<<31>>31|0,a|0,((a|0)<0)<<31>>31|0)|0;a=af(g|0,C|0,32)|0;c[l>>2]=a<<2;c[q>>2]=c[r>>2];c[r>>2]=(c[f>>2]|0)+((c[h>>2]&1)<<6);c[j>>2]=0;while(1){if((c[j>>2]|0)>=(c[h>>2]|0))break;a=c[(c[q>>2]|0)+(c[j>>2]<<2)>>2]|0;g=c[(c[q>>2]|0)+((c[h>>2]|0)-(c[j>>2]|0)-1<<2)>>2]|0;b=c[m>>2]|0;t=of(g|0,((g|0)<0)<<31>>31|0,b|0,((b|0)<0)<<31>>31|0)|0;b=af(t|0,C|0,30)|0;t=ef(b|0,C|0,1,0)|0;b=af(t|0,C|0,1)|0;c[p>>2]=a-b;b=(c[k>>2]|0)==1;a=c[p>>2]|0;t=c[o>>2]|0;g=of(a|0,((a|0)<0)<<31>>31|0,t|0,((t|0)<0)<<31>>31|0)|0;t=C;if(b){b=af(g|0,t|0,1)|0;a=C;u=c[p>>2]|0;v=c[o>>2]|0;w=of(u|0,((u|0)<0)<<31>>31|0,v|0,((v|0)<0)<<31>>31|0)|0;v=ef(b|0,a|0,w&1|0,0)|0;x=v;y=C}else{v=af(g|0,t|0,(c[k>>2]|0)-1|0)|0;t=ef(v|0,C|0,1,0)|0;v=af(t|0,C|0,1)|0;x=v;y=C}c[(c[r>>2]|0)+(c[j>>2]<<2)>>2]=x;c[j>>2]=(c[j>>2]|0)+1}c[h>>2]=(c[h>>2]|0)+-1}if((s|0)==5){c[e>>2]=0;z=c[e>>2]|0;i=d;return z|0}if((c[c[r>>2]>>2]|0)<=16773022?(c[c[r>>2]>>2]|0)>=-16773022:0){c[m>>2]=0-(c[c[r>>2]>>2]<<7);r=c[m>>2]|0;s=c[m>>2]|0;m=of(r|0,((r|0)<0)<<31>>31|0,s|0,((s|0)<0)<<31>>31|0)|0;s=af(m|0,C|0,32)|0;c[n>>2]=1073741824-s;s=c[l>>2]|0;m=c[n>>2]|0;n=of(s|0,((s|0)<0)<<31>>31|0,m|0,((m|0)<0)<<31>>31|0)|0;m=af(n|0,C|0,32)|0;c[l>>2]=m<<2;c[e>>2]=c[l>>2];z=c[e>>2]|0;i=d;return z|0}c[e>>2]=0;z=c[e>>2]|0;i=d;return z|0}function Qd(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0;e=i;i=i+32|0;f=e+20|0;g=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[c[f>>2]>>2]=65536;c[(c[f>>2]|0)+4>>2]=0-(c[c[g>>2]>>2]|0);c[j>>2]=1;while(1){if((c[j>>2]|0)>=(c[h>>2]|0))break;c[l>>2]=c[(c[g>>2]|0)+(c[j>>2]<<1<<2)>>2];d=c[(c[f>>2]|0)+((c[j>>2]|0)-1<<2)>>2]<<1;b=c[l>>2]|0;a=c[(c[f>>2]|0)+(c[j>>2]<<2)>>2]|0;m=of(b|0,((b|0)<0)<<31>>31|0,a|0,((a|0)<0)<<31>>31|0)|0;a=af(m|0,C|0,15)|0;m=ef(a|0,C|0,1,0)|0;a=af(m|0,C|0,1)|0;c[(c[f>>2]|0)+((c[j>>2]|0)+1<<2)>>2]=d-a;c[k>>2]=c[j>>2];while(1){if((c[k>>2]|0)<=1)break;a=c[(c[f>>2]|0)+((c[k>>2]|0)-2<<2)>>2]|0;d=c[l>>2]|0;m=c[(c[f>>2]|0)+((c[k>>2]|0)-1<<2)>>2]|0;b=of(d|0,((d|0)<0)<<31>>31|0,m|0,((m|0)<0)<<31>>31|0)|0;m=af(b|0,C|0,15)|0;b=ef(m|0,C|0,1,0)|0;m=af(b|0,C|0,1)|0;b=(c[f>>2]|0)+(c[k>>2]<<2)|0;c[b>>2]=(c[b>>2]|0)+(a-m);c[k>>2]=(c[k>>2]|0)+-1}m=(c[f>>2]|0)+4|0;c[m>>2]=(c[m>>2]|0)-(c[l>>2]|0);c[j>>2]=(c[j>>2]|0)+1}i=e;return}function Rd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}function Sd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)<(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}
+function Ia(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function Ja(){return i|0}function Ka(a){a=a|0;i=a}function La(a,b){a=a|0;b=b|0;i=a;j=b}function Ma(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Na(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0]}function Oa(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0];a[k+4>>0]=a[b+4>>0];a[k+5>>0]=a[b+5>>0];a[k+6>>0]=a[b+6>>0];a[k+7>>0]=a[b+7>>0]}function Pa(a){a=a|0;C=a}function Qa(){return C|0}function Ra(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;a=(_(1664525,c[d>>2]|0)|0)+1013904223|0;i=b;return a|0}function Sa(a,d,e,f,h,j,k,l,m){a=a|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;var n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0.0;n=i;i=i+80|0;o=n+68|0;p=n+44|0;q=n+24|0;r=n+32|0;s=n+12|0;t=n+16|0;u=n+48|0;v=n+56|0;w=n+64|0;x=n+72|0;y=n+36|0;z=n+8|0;A=n;B=n+4|0;C=n+40|0;D=n+20|0;E=n+52|0;F=n+28|0;G=n+60|0;c[o>>2]=a;c[p>>2]=d;c[q>>2]=e;c[r>>2]=f;c[s>>2]=h;c[t>>2]=j;c[u>>2]=k;c[v>>2]=l;c[w>>2]=m;c[C>>2]=c[(c[o>>2]|0)+32>>2];c[y>>2]=_(c[u>>2]|0,c[(c[o>>2]|0)+44>>2]|0)|0;c[z>>2]=_(c[u>>2]|0,b[(c[C>>2]|0)+(c[t>>2]<<1)>>1]|0)|0;if((c[v>>2]|0)!=1){if((c[z>>2]|0)<((c[y>>2]|0)/(c[v>>2]|0)|0|0))H=c[z>>2]|0;else H=(c[y>>2]|0)/(c[v>>2]|0)|0;c[z>>2]=H}if(c[w>>2]|0){c[z>>2]=0;c[t>>2]=0;c[s>>2]=0}c[A>>2]=c[q>>2];c[B>>2]=(c[p>>2]|0)+((_(c[u>>2]|0,b[(c[C>>2]|0)+(c[s>>2]<<1)>>1]|0)|0)<<2);c[x>>2]=0;while(1){if((c[x>>2]|0)>=(_(c[u>>2]|0,b[(c[C>>2]|0)+(c[s>>2]<<1)>>1]|0)|0))break;p=c[A>>2]|0;c[A>>2]=p+4;g[p>>2]=0.0;c[x>>2]=(c[x>>2]|0)+1}c[x>>2]=c[s>>2];while(1){if((c[x>>2]|0)>=(c[t>>2]|0))break;c[D>>2]=_(c[u>>2]|0,b[(c[C>>2]|0)+(c[x>>2]<<1)>>1]|0)|0;c[E>>2]=_(c[u>>2]|0,b[(c[C>>2]|0)+((c[x>>2]|0)+1<<1)>>1]|0)|0;g[G>>2]=+g[(c[r>>2]|0)+(c[x>>2]<<2)>>2]+ +g[40+(c[x>>2]<<2)>>2];g[F>>2]=+X(+(+g[G>>2]*.6931471805599453));do{s=c[B>>2]|0;c[B>>2]=s+4;I=+g[s>>2]*+g[F>>2];s=c[A>>2]|0;c[A>>2]=s+4;g[s>>2]=I;s=(c[D>>2]|0)+1|0;c[D>>2]=s}while((s|0)<(c[E>>2]|0));c[x>>2]=(c[x>>2]|0)+1}bf((c[q>>2]|0)+(c[z>>2]<<2)|0,0,(c[y>>2]|0)-(c[z>>2]|0)<<2|0)|0;i=n;return}function Ta(a,e,f,h,j,k,l,m,n,o,p,q,r){a=a|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;r=r|0;var s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0.0,W=0.0,Y=0.0;s=i;i=i+112|0;t=s+100|0;u=s+92|0;v=s+44|0;w=s+48|0;x=s+84|0;y=s+16|0;z=s+20|0;A=s+24|0;B=s+28|0;C=s+32|0;D=s+80|0;E=s+88|0;F=s+96|0;G=s+104|0;H=s+52|0;I=s+56|0;J=s+60|0;K=s+64|0;L=s+68|0;M=s+12|0;N=s+8|0;P=s+72|0;Q=s+36|0;R=s+76|0;S=s+4|0;T=s;U=s+40|0;c[t>>2]=a;c[u>>2]=e;c[v>>2]=f;c[w>>2]=h;c[x>>2]=j;c[y>>2]=k;c[z>>2]=l;c[A>>2]=m;c[B>>2]=n;c[C>>2]=o;c[D>>2]=p;c[E>>2]=q;c[F>>2]=r;c[H>>2]=c[z>>2];while(1){if((c[H>>2]|0)>=(c[A>>2]|0))break;c[K>>2]=(b[(c[(c[t>>2]|0)+32>>2]|0)+((c[H>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[t>>2]|0)+32>>2]|0)+(c[H>>2]<<1)>>1]|0);z=Rc(1+(c[(c[E>>2]|0)+(c[H>>2]<<2)>>2]|0)|0,(b[(c[(c[t>>2]|0)+32>>2]|0)+((c[H>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[t>>2]|0)+32>>2]|0)+(c[H>>2]<<1)>>1]|0)|0)|0;c[N>>2]=z>>>(c[w>>2]|0);g[L>>2]=+X(+(+(c[N>>2]|0)*-.125*.6931471805599453))*.5;g[M>>2]=1.0/+O(+(+(c[K>>2]<<c[w>>2]|0)));c[G>>2]=0;do{c[U>>2]=0;z=_(c[G>>2]|0,c[(c[t>>2]|0)+8>>2]|0)|0;g[Q>>2]=+g[(c[C>>2]|0)+(z+(c[H>>2]|0)<<2)>>2];z=_(c[G>>2]|0,c[(c[t>>2]|0)+8>>2]|0)|0;g[R>>2]=+g[(c[D>>2]|0)+(z+(c[H>>2]|0)<<2)>>2];if((c[x>>2]|0)==1){if(+g[Q>>2]>+g[(c[C>>2]|0)+((c[(c[t>>2]|0)+8>>2]|0)+(c[H>>2]|0)<<2)>>2])V=+g[Q>>2];else V=+g[(c[C>>2]|0)+((c[(c[t>>2]|0)+8>>2]|0)+(c[H>>2]|0)<<2)>>2];g[Q>>2]=V;if(+g[R>>2]>+g[(c[D>>2]|0)+((c[(c[t>>2]|0)+8>>2]|0)+(c[H>>2]|0)<<2)>>2])W=+g[R>>2];else W=+g[(c[D>>2]|0)+((c[(c[t>>2]|0)+8>>2]|0)+(c[H>>2]|0)<<2)>>2];g[R>>2]=W}z=_(c[G>>2]|0,c[(c[t>>2]|0)+8>>2]|0)|0;g[S>>2]=+g[(c[B>>2]|0)+(z+(c[H>>2]|0)<<2)>>2]-(+g[Q>>2]<+g[R>>2]?+g[Q>>2]:+g[R>>2]);g[S>>2]=0.0>+g[S>>2]?0.0:+g[S>>2];g[T>>2]=+X(+(-+g[S>>2]*.6931471805599453))*2.0;if((c[w>>2]|0)==3)g[T>>2]=+g[T>>2]*1.4142135381698608;g[T>>2]=+g[L>>2]<+g[T>>2]?+g[L>>2]:+g[T>>2];g[T>>2]=+g[T>>2]*+g[M>>2];z=(c[u>>2]|0)+((_(c[G>>2]|0,c[y>>2]|0)|0)<<2)|0;c[P>>2]=z+(b[(c[(c[t>>2]|0)+32>>2]|0)+(c[H>>2]<<1)>>1]<<c[w>>2]<<2);c[J>>2]=0;while(1){if((c[J>>2]|0)>=(1<<c[w>>2]|0))break;z=_(c[H>>2]|0,c[x>>2]|0)|0;if(!(d[(c[v>>2]|0)+(z+(c[G>>2]|0))>>0]&1<<c[J>>2])){c[I>>2]=0;while(1){if((c[I>>2]|0)>=(c[K>>2]|0))break;c[F>>2]=Ra(c[F>>2]|0)|0;Y=+g[T>>2];g[(c[P>>2]|0)+((c[I>>2]<<c[w>>2])+(c[J>>2]|0)<<2)>>2]=(c[F>>2]&32768|0)!=0?Y:-Y;c[I>>2]=(c[I>>2]|0)+1}c[U>>2]=1}c[J>>2]=(c[J>>2]|0)+1}if(c[U>>2]|0)Ib(c[P>>2]|0,c[K>>2]<<c[w>>2],1.0);z=(c[G>>2]|0)+1|0;c[G>>2]=z}while((z|0)<(c[x>>2]|0));c[H>>2]=(c[H>>2]|0)+1}i=s;return}function Ua(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0,n=0;e=i;i=i+32|0;f=e+8|0;h=e+16|0;j=e+20|0;k=e+24|0;l=e+4|0;m=e;n=e+12|0;c[f>>2]=a;c[h>>2]=b;c[j>>2]=d;c[h>>2]=c[h>>2]>>1;c[k>>2]=0;while(1){if((c[k>>2]|0)>=(c[j>>2]|0))break;c[l>>2]=0;while(1){if((c[l>>2]|0)>=(c[h>>2]|0))break;d=_(c[j>>2]<<1,c[l>>2]|0)|0;g[m>>2]=+g[(c[f>>2]|0)+(d+(c[k>>2]|0)<<2)>>2]*.7071067690849304;d=_(c[j>>2]|0,(c[l>>2]<<1)+1|0)|0;g[n>>2]=+g[(c[f>>2]|0)+(d+(c[k>>2]|0)<<2)>>2]*.7071067690849304;d=_(c[j>>2]<<1,c[l>>2]|0)|0;g[(c[f>>2]|0)+(d+(c[k>>2]|0)<<2)>>2]=+g[m>>2]+ +g[n>>2];d=_(c[j>>2]|0,(c[l>>2]<<1)+1|0)|0;g[(c[f>>2]|0)+(d+(c[k>>2]|0)<<2)>>2]=+g[m>>2]-+g[n>>2];c[l>>2]=(c[l>>2]|0)+1}c[k>>2]=(c[k>>2]|0)+1}i=e;return}function Va(e,f,h,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z){e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;r=r|0;s=s|0;t=t|0;u=u|0;v=v|0;w=w|0;x=x|0;y=y|0;z=z|0;var A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0;A=i;i=i+240|0;B=A+96|0;C=A+92|0;D=A+84|0;E=A+200|0;F=A+224|0;G=A+216|0;H=A+20|0;I=A+24|0;J=A+28|0;K=A+32|0;L=A+36|0;M=A+40|0;N=A+44|0;O=A+48|0;P=A+52|0;Q=A+56|0;R=A+60|0;S=A+64|0;T=A+68|0;U=A+72|0;V=A+196|0;W=A+204|0;X=A+212|0;Y=A+220|0;Z=A+228|0;$=A+232|0;aa=A+100|0;ba=A+104|0;ca=A+108|0;da=A+112|0;ea=A+116|0;fa=A+120|0;ga=A+124|0;ha=A+128|0;ia=A+168|0;ja=A+172|0;la=A+176|0;ma=A+180|0;na=A+184|0;oa=A+188|0;pa=A+16|0;qa=A+8|0;ra=A;sa=A+12|0;ta=A+4|0;va=A+192|0;wa=A+76|0;xa=A+80|0;ya=A+208|0;za=A+88|0;c[B>>2]=e;c[C>>2]=f;c[D>>2]=h;c[E>>2]=j;c[F>>2]=k;c[G>>2]=l;c[H>>2]=m;c[I>>2]=n;c[J>>2]=o;c[K>>2]=p;c[L>>2]=q;c[M>>2]=r;c[N>>2]=s;c[O>>2]=t;c[P>>2]=u;c[Q>>2]=v;c[R>>2]=w;c[S>>2]=x;c[T>>2]=y;c[U>>2]=z;c[X>>2]=c[(c[C>>2]|0)+32>>2];c[da>>2]=1;c[ea>>2]=(c[G>>2]|0)!=0?2:1;c[ga>>2]=((c[B>>2]|0)!=0^1)&1;c[ba>>2]=1<<c[S>>2];c[aa>>2]=(c[K>>2]|0)!=0?c[ba>>2]|0:1;c[fa>>2]=_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[D>>2]<<1)>>1]|0)|0;K=_(c[ba>>2]|0,b[(c[X>>2]|0)+((c[(c[C>>2]|0)+8>>2]|0)-1<<1)>>1]|0)|0;z=_(c[ea>>2]|0,K-(c[fa>>2]|0)|0)|0;c[ia>>2]=ua()|0;K=i;i=i+((1*(z<<2)|0)+15&-16)|0;c[Y>>2]=K;K=(c[Y>>2]|0)+((_(c[ba>>2]|0,b[(c[X>>2]|0)+((c[(c[C>>2]|0)+8>>2]|0)-1<<1)>>1]|0)|0)<<2)|0;c[Z>>2]=K+(0-(c[fa>>2]|0)<<2);c[$>>2]=(c[F>>2]|0)+((_(c[ba>>2]|0,b[(c[X>>2]|0)+((c[(c[C>>2]|0)+8>>2]|0)-1<<1)>>1]|0)|0)<<2);c[ca>>2]=0;c[ha+32>>2]=c[I>>2];c[ha+24>>2]=c[R>>2];c[ha>>2]=c[B>>2];c[ha+12>>2]=c[N>>2];c[ha+4>>2]=c[C>>2];c[ha+36>>2]=c[c[U>>2]>>2];c[ha+16>>2]=c[L>>2];c[V>>2]=c[D>>2];while(1){if((c[V>>2]|0)>=(c[E>>2]|0))break;c[oa>>2]=-1;c[ra>>2]=0;c[ha+8>>2]=c[V>>2];c[va>>2]=(c[V>>2]|0)==((c[E>>2]|0)-1|0)&1;c[pa>>2]=(c[F>>2]|0)+((_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[V>>2]<<1)>>1]|0)|0)<<2);if(c[G>>2]|0)c[qa>>2]=(c[G>>2]|0)+((_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[V>>2]<<1)>>1]|0)|0)<<2);else c[qa>>2]=0;B=_(c[ba>>2]|0,b[(c[X>>2]|0)+((c[V>>2]|0)+1<<1)>>1]|0)|0;c[ma>>2]=B-(_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[V>>2]<<1)>>1]|0)|0);c[ja>>2]=db(c[R>>2]|0)|0;if((c[V>>2]|0)!=(c[D>>2]|0))c[Q>>2]=(c[Q>>2]|0)-(c[ja>>2]|0);c[W>>2]=(c[P>>2]|0)-(c[ja>>2]|0)-1;c[ha+28>>2]=c[W>>2];if((c[V>>2]|0)<=((c[T>>2]|0)-1|0)){if(3<((c[T>>2]|0)-(c[V>>2]|0)|0))Aa=3;else Aa=(c[T>>2]|0)-(c[V>>2]|0)|0;c[na>>2]=Sc(c[Q>>2]|0,Aa)|0;if(((c[W>>2]|0)+1|0)<((c[(c[J>>2]|0)+(c[V>>2]<<2)>>2]|0)+(c[na>>2]|0)|0))Ba=(c[W>>2]|0)+1|0;else Ba=(c[(c[J>>2]|0)+(c[V>>2]<<2)>>2]|0)+(c[na>>2]|0)|0;do if(16383>=(Ba|0))if(((c[W>>2]|0)+1|0)<((c[(c[J>>2]|0)+(c[V>>2]<<2)>>2]|0)+(c[na>>2]|0)|0)){Ca=(c[W>>2]|0)+1|0;break}else{Ca=(c[(c[J>>2]|0)+(c[V>>2]<<2)>>2]|0)+(c[na>>2]|0)|0;break}else Ca=16383;while(0);do if(0<=(Ca|0)){if(((c[W>>2]|0)+1|0)<((c[(c[J>>2]|0)+(c[V>>2]<<2)>>2]|0)+(c[na>>2]|0)|0))Da=(c[W>>2]|0)+1|0;else Da=(c[(c[J>>2]|0)+(c[V>>2]<<2)>>2]|0)+(c[na>>2]|0)|0;if(16383>=(Da|0))if(((c[W>>2]|0)+1|0)<((c[(c[J>>2]|0)+(c[V>>2]<<2)>>2]|0)+(c[na>>2]|0)|0)){Ea=(c[W>>2]|0)+1|0;break}else{Ea=(c[(c[J>>2]|0)+(c[V>>2]<<2)>>2]|0)+(c[na>>2]|0)|0;break}else Ea=16383}else Ea=0;while(0);c[la>>2]=Ea}else c[la>>2]=0;if(((c[ga>>2]|0)!=0?(B=_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[V>>2]<<1)>>1]|0)|0,(B-(c[ma>>2]|0)|0)>=(_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[D>>2]<<1)>>1]|0)|0)):0)?(c[da>>2]|0)!=0|(c[ca>>2]|0)==0:0)c[ca>>2]=c[V>>2];c[ra>>2]=c[(c[O>>2]|0)+(c[V>>2]<<2)>>2];c[ha+20>>2]=c[ra>>2];if((c[V>>2]|0)>=(c[(c[C>>2]|0)+12>>2]|0)){c[pa>>2]=c[Y>>2];if(c[G>>2]|0)c[qa>>2]=c[Y>>2];c[$>>2]=0}if((c[V>>2]|0)==((c[E>>2]|0)-1|0))c[$>>2]=0;if((c[ca>>2]|0)!=0?(c[L>>2]|0)!=3|(c[aa>>2]|0)>1|(c[ra>>2]|0)<0:0){B=_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[ca>>2]<<1)>>1]|0)|0;if(0>(B-(c[fa>>2]|0)-(c[ma>>2]|0)|0))Fa=0;else{B=_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[ca>>2]<<1)>>1]|0)|0;Fa=B-(c[fa>>2]|0)-(c[ma>>2]|0)|0}c[oa>>2]=Fa;c[wa>>2]=c[ca>>2];do{B=c[ba>>2]|0;I=(c[wa>>2]|0)+-1|0;c[wa>>2]=I;K=_(B,b[(c[X>>2]|0)+(I<<1)>>1]|0)|0}while((K|0)>((c[oa>>2]|0)+(c[fa>>2]|0)|0));c[xa>>2]=(c[ca>>2]|0)-1;do{K=c[ba>>2]|0;I=(c[xa>>2]|0)+1|0;c[xa>>2]=I;B=_(K,b[(c[X>>2]|0)+(I<<1)>>1]|0)|0}while((B|0)<((c[oa>>2]|0)+(c[fa>>2]|0)+(c[ma>>2]|0)|0));c[ta>>2]=0;c[sa>>2]=0;c[ya>>2]=c[wa>>2];do{B=(_(c[ya>>2]|0,c[ea>>2]|0)|0)+0|0;c[sa>>2]=c[sa>>2]|d[(c[H>>2]|0)+B>>0];B=_(c[ya>>2]|0,c[ea>>2]|0)|0;c[ta>>2]=c[ta>>2]|d[(c[H>>2]|0)+(B+(c[ea>>2]|0)-1)>>0];B=(c[ya>>2]|0)+1|0;c[ya>>2]=B}while((B|0)<(c[xa>>2]|0))}else{B=(1<<c[aa>>2])-1|0;c[ta>>2]=B;c[sa>>2]=B}a:do if(((c[M>>2]|0)!=0?(c[V>>2]|0)==(c[N>>2]|0):0)?(c[M>>2]=0,(c[ga>>2]|0)!=0):0){c[za>>2]=0;while(1){B=_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[V>>2]<<1)>>1]|0)|0;if((c[za>>2]|0)>=(B-(c[fa>>2]|0)|0))break a;g[(c[Y>>2]|0)+(c[za>>2]<<2)>>2]=(+g[(c[Y>>2]|0)+(c[za>>2]<<2)>>2]+ +g[(c[Z>>2]|0)+(c[za>>2]<<2)>>2])*.5;c[za>>2]=(c[za>>2]|0)+1}}while(0);if(c[M>>2]|0){if((c[oa>>2]|0)!=-1)Ga=(c[Y>>2]|0)+(c[oa>>2]<<2)|0;else Ga=0;if(c[va>>2]|0)Ha=0;else{B=(c[Y>>2]|0)+((_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[V>>2]<<1)>>1]|0)|0)<<2)|0;Ha=B+(0-(c[fa>>2]|0)<<2)|0}c[sa>>2]=Tc(ha,c[pa>>2]|0,c[ma>>2]|0,(c[la>>2]|0)/2|0,c[aa>>2]|0,Ga,c[S>>2]|0,Ha,1.0,c[$>>2]|0,c[sa>>2]|0)|0;if((c[oa>>2]|0)!=-1)Ia=(c[Z>>2]|0)+(c[oa>>2]<<2)|0;else Ia=0;if(c[va>>2]|0)Ja=0;else{B=(c[Z>>2]|0)+((_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[V>>2]<<1)>>1]|0)|0)<<2)|0;Ja=B+(0-(c[fa>>2]|0)<<2)|0}c[ta>>2]=Tc(ha,c[qa>>2]|0,c[ma>>2]|0,(c[la>>2]|0)/2|0,c[aa>>2]|0,Ia,c[S>>2]|0,Ja,1.0,c[$>>2]|0,c[ta>>2]|0)|0}else{B=c[pa>>2]|0;if(c[qa>>2]|0){if((c[oa>>2]|0)!=-1)Ka=(c[Y>>2]|0)+(c[oa>>2]<<2)|0;else Ka=0;if(c[va>>2]|0)La=0;else{I=(c[Y>>2]|0)+((_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[V>>2]<<1)>>1]|0)|0)<<2)|0;La=I+(0-(c[fa>>2]|0)<<2)|0}c[sa>>2]=Uc(ha,B,c[qa>>2]|0,c[ma>>2]|0,c[la>>2]|0,c[aa>>2]|0,Ka,c[S>>2]|0,La,c[$>>2]|0,c[sa>>2]|c[ta>>2])|0}else{if((c[oa>>2]|0)!=-1)Ma=(c[Y>>2]|0)+(c[oa>>2]<<2)|0;else Ma=0;if(c[va>>2]|0)Na=0;else{I=(c[Y>>2]|0)+((_(c[ba>>2]|0,b[(c[X>>2]|0)+(c[V>>2]<<1)>>1]|0)|0)<<2)|0;Na=I+(0-(c[fa>>2]|0)<<2)|0}c[sa>>2]=Tc(ha,B,c[ma>>2]|0,c[la>>2]|0,c[aa>>2]|0,Ma,c[S>>2]|0,Na,1.0,c[$>>2]|0,c[sa>>2]|c[ta>>2])|0}c[ta>>2]=c[sa>>2]}B=(_(c[V>>2]|0,c[ea>>2]|0)|0)+0|0;a[(c[H>>2]|0)+B>>0]=c[sa>>2];B=_(c[V>>2]|0,c[ea>>2]|0)|0;a[(c[H>>2]|0)+(B+(c[ea>>2]|0)-1)>>0]=c[ta>>2];c[Q>>2]=(c[Q>>2]|0)+((c[(c[J>>2]|0)+(c[V>>2]<<2)>>2]|0)+(c[ja>>2]|0));c[da>>2]=(c[la>>2]|0)>(c[ma>>2]<<3|0)&1;c[V>>2]=(c[V>>2]|0)+1}c[c[U>>2]>>2]=c[ha+36>>2];ka(c[ia>>2]|0);i=A;return}function Wa(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;a=c[d>>2]|0;if((a|0)==8e3)c[e>>2]=6;else if((a|0)==48e3)c[e>>2]=1;else if((a|0)==24e3)c[e>>2]=2;else if((a|0)==16e3)c[e>>2]=3;else if((a|0)==12e3)c[e>>2]=4;else c[e>>2]=0;i=b;return c[e>>2]|0}function Xa(a,b,d,e,f,h,j,k,l,m,n){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=+h;j=+j;k=k|0;l=l|0;m=m|0;n=n|0;var o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;o=i;i=i+96|0;p=o+44|0;q=o+40|0;r=o+4|0;s=o+84|0;t=o;u=o+16|0;v=o+20|0;w=o+24|0;x=o+64|0;y=o+72|0;z=o+80|0;A=o+88|0;B=o+92|0;C=o+48|0;D=o+52|0;E=o+56|0;F=o+8|0;G=o+60|0;H=o+28|0;I=o+12|0;J=o+32|0;K=o+68|0;L=o+36|0;M=o+76|0;c[p>>2]=a;c[q>>2]=b;c[r>>2]=d;c[s>>2]=e;c[t>>2]=f;g[u>>2]=h;g[v>>2]=j;c[w>>2]=k;c[x>>2]=l;c[y>>2]=m;c[z>>2]=n;if(+g[u>>2]==0.0&+g[v>>2]==0.0){if((c[q>>2]|0)==(c[p>>2]|0)){i=o;return}ff(c[p>>2]|0,c[q>>2]|0,(c[t>>2]<<2)+0|0)|0;i=o;return}g[B>>2]=+g[u>>2]*+g[2376+((c[w>>2]|0)*12|0)>>2];g[C>>2]=+g[u>>2]*+g[2376+((c[w>>2]|0)*12|0)+4>>2];g[D>>2]=+g[u>>2]*+g[2376+((c[w>>2]|0)*12|0)+8>>2];g[E>>2]=+g[v>>2]*+g[2376+((c[x>>2]|0)*12|0)>>2];g[F>>2]=+g[v>>2]*+g[2376+((c[x>>2]|0)*12|0)+4>>2];g[G>>2]=+g[v>>2]*+g[2376+((c[x>>2]|0)*12|0)+8>>2];g[I>>2]=+g[(c[q>>2]|0)+(0-(c[s>>2]|0)+1<<2)>>2];g[J>>2]=+g[(c[q>>2]|0)+(0-(c[s>>2]|0)<<2)>>2];g[K>>2]=+g[(c[q>>2]|0)+(0-(c[s>>2]|0)-1<<2)>>2];g[L>>2]=+g[(c[q>>2]|0)+(0-(c[s>>2]|0)-2<<2)>>2];if((+g[u>>2]==+g[v>>2]?(c[r>>2]|0)==(c[s>>2]|0):0)?(c[w>>2]|0)==(c[x>>2]|0):0)c[z>>2]=0;c[A>>2]=0;while(1){if((c[A>>2]|0)>=(c[z>>2]|0))break;g[H>>2]=+g[(c[q>>2]|0)+((c[A>>2]|0)-(c[s>>2]|0)+2<<2)>>2];g[M>>2]=+g[(c[y>>2]|0)+(c[A>>2]<<2)>>2]*+g[(c[y>>2]|0)+(c[A>>2]<<2)>>2];g[(c[p>>2]|0)+(c[A>>2]<<2)>>2]=+g[(c[q>>2]|0)+(c[A>>2]<<2)>>2]+(1.0-+g[M>>2])*+g[B>>2]*+g[(c[q>>2]|0)+((c[A>>2]|0)-(c[r>>2]|0)<<2)>>2]+(1.0-+g[M>>2])*+g[C>>2]*(+g[(c[q>>2]|0)+((c[A>>2]|0)-(c[r>>2]|0)+1<<2)>>2]+ +g[(c[q>>2]|0)+((c[A>>2]|0)-(c[r>>2]|0)-1<<2)>>2])+(1.0-+g[M>>2])*+g[D>>2]*(+g[(c[q>>2]|0)+((c[A>>2]|0)-(c[r>>2]|0)+2<<2)>>2]+ +g[(c[q>>2]|0)+((c[A>>2]|0)-(c[r>>2]|0)-2<<2)>>2])+ +g[M>>2]*+g[E>>2]*+g[J>>2]+ +g[M>>2]*+g[F>>2]*(+g[I>>2]+ +g[K>>2])+ +g[M>>2]*+g[G>>2]*(+g[H>>2]+ +g[L>>2]);g[L>>2]=+g[K>>2];g[K>>2]=+g[J>>2];g[J>>2]=+g[I>>2];g[I>>2]=+g[H>>2];c[A>>2]=(c[A>>2]|0)+1}if(!(+g[v>>2]==0.0)){Vc((c[p>>2]|0)+(c[A>>2]<<2)|0,(c[q>>2]|0)+(c[A>>2]<<2)|0,c[s>>2]|0,(c[t>>2]|0)-(c[A>>2]|0)|0,+g[E>>2],+g[F>>2],+g[G>>2]);i=o;return}if((c[q>>2]|0)==(c[p>>2]|0)){i=o;return}ff((c[p>>2]|0)+(c[z>>2]<<2)|0,(c[q>>2]|0)+(c[z>>2]<<2)|0,((c[t>>2]|0)-(c[z>>2]|0)<<2)+0|0)|0;i=o;return}function Ya(a,e,f,g){a=a|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0;h=i;i=i+32|0;j=h+20|0;k=h+16|0;l=h+12|0;m=h+8|0;n=h+4|0;o=h;c[j>>2]=a;c[k>>2]=e;c[l>>2]=f;c[m>>2]=g;c[n>>2]=0;while(1){if((c[n>>2]|0)>=(c[(c[j>>2]|0)+8>>2]|0))break;c[o>>2]=(b[(c[(c[j>>2]|0)+32>>2]|0)+((c[n>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[j>>2]|0)+32>>2]|0)+(c[n>>2]<<1)>>1]|0)<<c[l>>2];g=_(c[(c[j>>2]|0)+8>>2]|0,(c[l>>2]<<1)+(c[m>>2]|0)-1|0)|0;f=_((d[(c[(c[j>>2]|0)+92+12>>2]|0)+(g+(c[n>>2]|0))>>0]|0)+64|0,c[m>>2]|0)|0;g=(_(f,c[o>>2]|0)|0)>>2;c[(c[k>>2]|0)+(c[n>>2]<<2)>>2]=g;c[n>>2]=(c[n>>2]|0)+1}i=h;return}function Za(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;c[e>>2]=ub(48e3,960,0)|0;a=Wc(c[e>>2]|0,c[d>>2]|0)|0;i=b;return a|0}function _a(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;d=c[g>>2]|0;b=ub(48e3,960,0)|0;c[k>>2]=Xc(d,b,c[j>>2]|0)|0;if(c[k>>2]|0){c[f>>2]=c[k>>2];l=c[f>>2]|0;i=e;return l|0}k=Wa(c[h>>2]|0)|0;c[(c[g>>2]|0)+16>>2]=k;if(!(c[(c[g>>2]|0)+16>>2]|0)){c[f>>2]=-1;l=c[f>>2]|0;i=e;return l|0}else{c[f>>2]=0;l=c[f>>2]|0;i=e;return l|0}return 0}function $a(a,d,e,f,h,j,k){a=a|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0.0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0.0,Ca=0.0,Da=0;l=i;i=i+288|0;m=l+164|0;n=l+148|0;o=l+4|0;p=l+8|0;q=l+144|0;r=l+272|0;s=l+160|0;t=l+24|0;u=l+28|0;v=l+32|0;w=l+36|0;x=l+40|0;y=l+44|0;z=l+48|0;A=l+96|0;B=l+104|0;C=l+112|0;D=l+116|0;E=l+120|0;F=l+124|0;G=l+128|0;H=l+132|0;I=l+136|0;J=l+140|0;K=l+244|0;L=l+252|0;M=l+260|0;N=l+268|0;O=l+276|0;P=l+280|0;Q=l+168|0;R=l+172|0;S=l+176|0;T=l+180|0;U=l+184|0;V=l+188|0;W=l+192|0;X=l+196|0;Y=l+200|0;Z=l+204|0;$=l+208|0;aa=l+212|0;ba=l+216|0;ca=l+220|0;da=l+224|0;ea=l+228|0;fa=l+232|0;ga=l+236|0;ha=l+16|0;ia=l;ja=l+12|0;la=l+240|0;ma=l+248|0;na=l+152|0;oa=l+256|0;pa=l+20|0;qa=l+156|0;ra=l+264|0;c[n>>2]=a;c[o>>2]=d;c[p>>2]=e;c[q>>2]=f;c[r>>2]=h;c[s>>2]=j;c[t>>2]=k;c[K>>2]=c[(c[n>>2]|0)+8>>2];c[U>>2]=0;c[V>>2]=0;c[ba>>2]=0;c[da>>2]=c[(c[n>>2]|0)+12>>2];c[ea>>2]=c[c[n>>2]>>2];c[fa>>2]=c[(c[ea>>2]|0)+8>>2];c[ga>>2]=c[(c[ea>>2]|0)+4>>2];c[ha>>2]=c[(c[ea>>2]|0)+32>>2];c[N>>2]=c[(c[n>>2]|0)+20>>2];c[O>>2]=c[(c[n>>2]|0)+24>>2];c[r>>2]=_(c[r>>2]|0,c[(c[n>>2]|0)+16>>2]|0)|0;c[C>>2]=(c[n>>2]|0)+84+((_(2048+(c[ga>>2]|0)|0,c[K>>2]|0)|0)<<2);c[D>>2]=(c[C>>2]|0)+((c[K>>2]|0)*24<<2);c[E>>2]=(c[D>>2]|0)+(c[fa>>2]<<1<<2);c[F>>2]=(c[E>>2]|0)+(c[fa>>2]<<1<<2);c[G>>2]=(c[F>>2]|0)+(c[fa>>2]<<1<<2);c[L>>2]=0;while(1){if((c[L>>2]|0)>(c[(c[ea>>2]|0)+36>>2]|0))break;if((c[(c[ea>>2]|0)+44>>2]<<c[L>>2]|0)==(c[r>>2]|0))break;c[L>>2]=(c[L>>2]|0)+1}if((c[L>>2]|0)>(c[(c[ea>>2]|0)+36>>2]|0)){c[m>>2]=-1;sa=c[m>>2]|0;i=l;return sa|0}c[M>>2]=1<<c[L>>2];if((c[p>>2]|0)<0|(c[p>>2]|0)>1275|(c[q>>2]|0)==0){c[m>>2]=-1;sa=c[m>>2]|0;i=l;return sa|0}c[w>>2]=_(c[M>>2]|0,c[(c[ea>>2]|0)+44>>2]|0)|0;c[u>>2]=0;do{C=(c[n>>2]|0)+84+((_(c[u>>2]|0,2048+(c[ga>>2]|0)|0)|0)<<2)|0;c[A+(c[u>>2]<<2)>>2]=C;c[B+(c[u>>2]<<2)>>2]=(c[A+(c[u>>2]<<2)>>2]|0)+8192+(0-(c[w>>2]|0)<<2);C=(c[u>>2]|0)+1|0;c[u>>2]=C}while((C|0)<(c[K>>2]|0));c[P>>2]=c[O>>2];if((c[P>>2]|0)>(c[(c[ea>>2]|0)+12>>2]|0))c[P>>2]=c[(c[ea>>2]|0)+12>>2];if((c[o>>2]|0)==0|(c[p>>2]|0)<=1){Yc(c[n>>2]|0,c[w>>2]|0,c[L>>2]|0);Zc(B,c[q>>2]|0,c[w>>2]|0,c[K>>2]|0,c[(c[n>>2]|0)+16>>2]|0,(c[ea>>2]|0)+16|0,(c[n>>2]|0)+76|0,c[t>>2]|0);c[m>>2]=(c[r>>2]|0)/(c[(c[n>>2]|0)+16>>2]|0)|0;sa=c[m>>2]|0;i=l;return sa|0}if(!(c[s>>2]|0)){eb(z,c[o>>2]|0,c[p>>2]|0);c[s>>2]=z}a:do if((c[da>>2]|0)==1){c[v>>2]=0;while(1){if((c[v>>2]|0)>=(c[fa>>2]|0))break a;if(+g[(c[D>>2]|0)+(c[v>>2]<<2)>>2]>+g[(c[D>>2]|0)+((c[fa>>2]|0)+(c[v>>2]|0)<<2)>>2])ta=+g[(c[D>>2]|0)+(c[v>>2]<<2)>>2];else ta=+g[(c[D>>2]|0)+((c[fa>>2]|0)+(c[v>>2]|0)<<2)>>2];g[(c[D>>2]|0)+(c[v>>2]<<2)>>2]=ta;c[v>>2]=(c[v>>2]|0)+1}}while(0);c[W>>2]=c[p>>2]<<3;c[Y>>2]=_c(c[s>>2]|0)|0;do if((c[Y>>2]|0)<(c[W>>2]|0))if((c[Y>>2]|0)==1){c[ca>>2]=ib(c[s>>2]|0,15)|0;break}else{c[ca>>2]=0;break}else c[ca>>2]=1;while(0);if(c[ca>>2]|0){c[Y>>2]=c[p>>2]<<3;z=c[Y>>2]|0;o=z-(_c(c[s>>2]|0)|0)|0;z=(c[s>>2]|0)+20|0;c[z>>2]=(c[z>>2]|0)+o}g[T>>2]=0.0;c[S>>2]=0;c[$>>2]=0;if((c[N>>2]|0)==0?((c[Y>>2]|0)+16|0)<=(c[W>>2]|0):0){if(ib(c[s>>2]|0,1)|0){c[ja>>2]=kb(c[s>>2]|0,6)|0;o=16<<c[ja>>2];c[S>>2]=o+(lb(c[s>>2]|0,4+(c[ja>>2]|0)|0)|0)-1;c[ia>>2]=lb(c[s>>2]|0,3)|0;ja=(_c(c[s>>2]|0)|0)+2|0;if((ja|0)<=(c[W>>2]|0))c[$>>2]=jb(c[s>>2]|0,2416,2)|0;g[T>>2]=+((c[ia>>2]|0)+1|0)*.09375}c[Y>>2]=_c(c[s>>2]|0)|0}if((c[L>>2]|0)>0?((c[Y>>2]|0)+3|0)<=(c[W>>2]|0):0){c[I>>2]=ib(c[s>>2]|0,3)|0;c[Y>>2]=_c(c[s>>2]|0)|0}else c[I>>2]=0;if(c[I>>2]|0)c[H>>2]=c[M>>2];else c[H>>2]=0;if(((c[Y>>2]|0)+3|0)<=(c[W>>2]|0))va=ib(c[s>>2]|0,3)|0;else va=0;c[J>>2]=va;Cb(c[ea>>2]|0,c[N>>2]|0,c[O>>2]|0,c[D>>2]|0,c[J>>2]|0,c[s>>2]|0,c[da>>2]|0,c[L>>2]|0);J=c[fa>>2]|0;c[la>>2]=ua()|0;va=i;i=i+((1*(J<<2)|0)+15&-16)|0;$c(c[N>>2]|0,c[O>>2]|0,c[I>>2]|0,va,c[L>>2]|0,c[s>>2]|0);c[Y>>2]=_c(c[s>>2]|0)|0;c[x>>2]=2;if(((c[Y>>2]|0)+4|0)<=(c[W>>2]|0))c[x>>2]=jb(c[s>>2]|0,2424,5)|0;J=i;i=i+((1*(c[fa>>2]<<2)|0)+15&-16)|0;Ya(c[ea>>2]|0,J,c[L>>2]|0,c[da>>2]|0);ia=i;i=i+((1*(c[fa>>2]<<2)|0)+15&-16)|0;c[Z>>2]=6;c[W>>2]=c[W>>2]<<3;c[Y>>2]=db(c[s>>2]|0)|0;c[v>>2]=c[N>>2];while(1){if((c[v>>2]|0)>=(c[O>>2]|0))break;ja=_(c[da>>2]|0,(b[(c[ha>>2]|0)+((c[v>>2]|0)+1<<1)>>1]|0)-(b[(c[ha>>2]|0)+(c[v>>2]<<1)>>1]|0)|0)|0;c[ma>>2]=ja<<c[L>>2];ja=c[ma>>2]|0;if((c[ma>>2]<<3|0)<((48>(c[ma>>2]|0)?48:c[ma>>2]|0)|0))wa=ja<<3;else wa=48>(ja|0)?48:c[ma>>2]|0;c[na>>2]=wa;c[oa>>2]=c[Z>>2];c[pa>>2]=0;while(1){if(((c[Y>>2]|0)+(c[oa>>2]<<3)|0)>=(c[W>>2]|0))break;if((c[pa>>2]|0)>=(c[J+(c[v>>2]<<2)>>2]|0))break;c[qa>>2]=ib(c[s>>2]|0,c[oa>>2]|0)|0;c[Y>>2]=db(c[s>>2]|0)|0;if(!(c[qa>>2]|0))break;c[pa>>2]=(c[pa>>2]|0)+(c[na>>2]|0);c[W>>2]=(c[W>>2]|0)-(c[na>>2]|0);c[oa>>2]=1}c[ia+(c[v>>2]<<2)>>2]=c[pa>>2];if((c[pa>>2]|0)>0)c[Z>>2]=2>((c[Z>>2]|0)-1|0)?2:(c[Z>>2]|0)-1|0;c[v>>2]=(c[v>>2]|0)+1}Z=i;i=i+((1*(c[fa>>2]<<2)|0)+15&-16)|0;if(((c[Y>>2]|0)+48|0)<=(c[W>>2]|0))xa=jb(c[s>>2]|0,2432,7)|0;else xa=5;c[R>>2]=xa;xa=c[p>>2]<<3<<3;c[y>>2]=xa-(db(c[s>>2]|0)|0)-1;if((c[I>>2]|0)!=0&(c[L>>2]|0)>=2)ya=(c[y>>2]|0)>=((c[L>>2]|0)+2<<3|0);else ya=0;c[aa>>2]=ya?8:0;c[y>>2]=(c[y>>2]|0)-(c[aa>>2]|0);ya=i;i=i+((1*(c[fa>>2]<<2)|0)+15&-16)|0;xa=i;i=i+((1*(c[fa>>2]<<2)|0)+15&-16)|0;c[Q>>2]=Fb(c[ea>>2]|0,c[N>>2]|0,c[O>>2]|0,ia,J,c[R>>2]|0,U,V,c[y>>2]|0,X,ya,Z,xa,c[da>>2]|0,c[L>>2]|0,c[s>>2]|0,0,0,0)|0;Db(c[ea>>2]|0,c[N>>2]|0,c[O>>2]|0,c[D>>2]|0,Z,c[s>>2]|0,c[da>>2]|0);c[u>>2]=0;do{ff(c[A+(c[u>>2]<<2)>>2]|0,(c[A+(c[u>>2]<<2)>>2]|0)+(c[w>>2]<<2)|0,(2048-(c[w>>2]|0)+((c[ga>>2]|0)/2|0)<<2)+0|0)|0;y=(c[u>>2]|0)+1|0;c[u>>2]=y}while((y|0)<(c[K>>2]|0));A=_(c[da>>2]|0,c[fa>>2]|0)|0;y=i;i=i+((1*A|0)+15&-16)|0;A=(_(c[da>>2]|0,c[w>>2]|0)|0)<<2;R=i;i=i+((1*A|0)+15&-16)|0;Va(0,c[ea>>2]|0,c[N>>2]|0,c[O>>2]|0,R,(c[da>>2]|0)==2?R+(c[w>>2]<<2)|0:0,y,0,ya,c[H>>2]|0,c[x>>2]|0,c[V>>2]|0,c[U>>2]|0,va,(c[p>>2]<<6)-(c[aa>>2]|0)|0,c[X>>2]|0,c[s>>2]|0,c[L>>2]|0,c[Q>>2]|0,(c[n>>2]|0)+36|0);if((c[aa>>2]|0)>0)c[ba>>2]=lb(c[s>>2]|0,1)|0;aa=c[ea>>2]|0;Q=c[N>>2]|0;X=c[O>>2]|0;va=c[D>>2]|0;U=c[p>>2]<<3;V=U-(_c(c[s>>2]|0)|0)|0;Eb(aa,Q,X,va,Z,xa,V,c[s>>2]|0,c[da>>2]|0);if(c[ba>>2]|0)Ta(c[ea>>2]|0,R,y,c[L>>2]|0,c[da>>2]|0,c[w>>2]|0,c[N>>2]|0,c[O>>2]|0,c[D>>2]|0,c[E>>2]|0,c[F>>2]|0,ya,c[(c[n>>2]|0)+36>>2]|0);b:do if(c[ca>>2]|0){c[v>>2]=0;while(1){if((c[v>>2]|0)>=(_(c[da>>2]|0,c[fa>>2]|0)|0))break b;g[(c[D>>2]|0)+(c[v>>2]<<2)>>2]=-28.0;c[v>>2]=(c[v>>2]|0)+1}}while(0);ad(c[ea>>2]|0,R,B,c[D>>2]|0,c[N>>2]|0,c[P>>2]|0,c[da>>2]|0,c[K>>2]|0,c[I>>2]|0,c[L>>2]|0,c[(c[n>>2]|0)+16>>2]|0,c[ca>>2]|0);c[u>>2]=0;do{if((c[(c[n>>2]|0)+52>>2]|0)>15)za=c[(c[n>>2]|0)+52>>2]|0;else za=15;c[(c[n>>2]|0)+52>>2]=za;if((c[(c[n>>2]|0)+56>>2]|0)>15)Aa=c[(c[n>>2]|0)+56>>2]|0;else Aa=15;c[(c[n>>2]|0)+56>>2]=Aa;Xa(c[B+(c[u>>2]<<2)>>2]|0,c[B+(c[u>>2]<<2)>>2]|0,c[(c[n>>2]|0)+56>>2]|0,c[(c[n>>2]|0)+52>>2]|0,c[(c[ea>>2]|0)+44>>2]|0,+g[(c[n>>2]|0)+64>>2],+g[(c[n>>2]|0)+60>>2],c[(c[n>>2]|0)+72>>2]|0,c[(c[n>>2]|0)+68>>2]|0,c[(c[ea>>2]|0)+60>>2]|0,c[ga>>2]|0);if(c[L>>2]|0)Xa((c[B+(c[u>>2]<<2)>>2]|0)+(c[(c[ea>>2]|0)+44>>2]<<2)|0,(c[B+(c[u>>2]<<2)>>2]|0)+(c[(c[ea>>2]|0)+44>>2]<<2)|0,c[(c[n>>2]|0)+52>>2]|0,c[S>>2]|0,(c[w>>2]|0)-(c[(c[ea>>2]|0)+44>>2]|0)|0,+g[(c[n>>2]|0)+60>>2],+g[T>>2],c[(c[n>>2]|0)+68>>2]|0,c[$>>2]|0,c[(c[ea>>2]|0)+60>>2]|0,c[ga>>2]|0);ca=(c[u>>2]|0)+1|0;c[u>>2]=ca}while((ca|0)<(c[K>>2]|0));c[(c[n>>2]|0)+56>>2]=c[(c[n>>2]|0)+52>>2];g[(c[n>>2]|0)+64>>2]=+g[(c[n>>2]|0)+60>>2];c[(c[n>>2]|0)+72>>2]=c[(c[n>>2]|0)+68>>2];c[(c[n>>2]|0)+52>>2]=c[S>>2];g[(c[n>>2]|0)+60>>2]=+g[T>>2];c[(c[n>>2]|0)+68>>2]=c[$>>2];if(c[L>>2]|0){c[(c[n>>2]|0)+56>>2]=c[(c[n>>2]|0)+52>>2];g[(c[n>>2]|0)+64>>2]=+g[(c[n>>2]|0)+60>>2];c[(c[n>>2]|0)+72>>2]=c[(c[n>>2]|0)+68>>2]}if((c[da>>2]|0)==1)df((c[D>>2]|0)+(c[fa>>2]<<2)|0,c[D>>2]|0,(c[fa>>2]<<2)+0|0)|0;c:do if(c[I>>2]|0){c[v>>2]=0;while(1){if((c[v>>2]|0)>=(c[fa>>2]<<1|0))break c;da=c[v>>2]|0;if(+g[(c[E>>2]|0)+(c[v>>2]<<2)>>2]<+g[(c[D>>2]|0)+(c[v>>2]<<2)>>2])Ba=+g[(c[E>>2]|0)+(da<<2)>>2];else Ba=+g[(c[D>>2]|0)+(da<<2)>>2];g[(c[E>>2]|0)+(c[v>>2]<<2)>>2]=Ba;c[v>>2]=(c[v>>2]|0)+1}}else{df(c[F>>2]|0,c[E>>2]|0,(c[fa>>2]<<1<<2)+0|0)|0;df(c[E>>2]|0,c[D>>2]|0,(c[fa>>2]<<1<<2)+0|0)|0;c[v>>2]=0;while(1){if((c[v>>2]|0)>=(c[fa>>2]<<1|0))break c;da=c[v>>2]|0;if(+g[(c[G>>2]|0)+(c[v>>2]<<2)>>2]+ +(c[M>>2]|0)*1.0000000474974513e-03<+g[(c[D>>2]|0)+(c[v>>2]<<2)>>2])Ca=+g[(c[G>>2]|0)+(da<<2)>>2]+ +(c[M>>2]|0)*1.0000000474974513e-03;else Ca=+g[(c[D>>2]|0)+(da<<2)>>2];g[(c[G>>2]|0)+(c[v>>2]<<2)>>2]=Ca;c[v>>2]=(c[v>>2]|0)+1}}while(0);c[u>>2]=0;do{c[v>>2]=0;while(1){if((c[v>>2]|0)>=(c[N>>2]|0))break;G=_(c[u>>2]|0,c[fa>>2]|0)|0;g[(c[D>>2]|0)+(G+(c[v>>2]|0)<<2)>>2]=0.0;G=_(c[u>>2]|0,c[fa>>2]|0)|0;g[(c[F>>2]|0)+(G+(c[v>>2]|0)<<2)>>2]=-28.0;G=_(c[u>>2]|0,c[fa>>2]|0)|0;g[(c[E>>2]|0)+(G+(c[v>>2]|0)<<2)>>2]=-28.0;c[v>>2]=(c[v>>2]|0)+1}c[v>>2]=c[O>>2];while(1){Da=c[u>>2]|0;if((c[v>>2]|0)>=(c[fa>>2]|0))break;G=_(Da,c[fa>>2]|0)|0;g[(c[D>>2]|0)+(G+(c[v>>2]|0)<<2)>>2]=0.0;G=_(c[u>>2]|0,c[fa>>2]|0)|0;g[(c[F>>2]|0)+(G+(c[v>>2]|0)<<2)>>2]=-28.0;G=_(c[u>>2]|0,c[fa>>2]|0)|0;g[(c[E>>2]|0)+(G+(c[v>>2]|0)<<2)>>2]=-28.0;c[v>>2]=(c[v>>2]|0)+1}G=Da+1|0;c[u>>2]=G}while((G|0)<2);c[(c[n>>2]|0)+36>>2]=c[(c[s>>2]|0)+28>>2];Zc(B,c[q>>2]|0,c[w>>2]|0,c[K>>2]|0,c[(c[n>>2]|0)+16>>2]|0,(c[ea>>2]|0)+16|0,(c[n>>2]|0)+76|0,c[t>>2]|0);c[(c[n>>2]|0)+48>>2]=0;t=_c(c[s>>2]|0)|0;if((t|0)>(c[p>>2]<<3|0)){c[m>>2]=-3;c[ra>>2]=1}else{if(bd(c[s>>2]|0)|0)c[(c[n>>2]|0)+40>>2]=1;c[m>>2]=(c[r>>2]|0)/(c[(c[n>>2]|0)+16>>2]|0)|0;c[ra>>2]=1}ka(c[la>>2]|0);sa=c[m>>2]|0;i=l;return sa|0}function ab(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;e=i;i=i+96|0;f=e+32|0;h=e+24|0;j=e+44|0;k=e+64|0;l=e+12|0;m=e+40|0;n=e+48|0;o=e+56|0;p=e+80|0;q=e+84|0;r=e+8|0;s=e+4|0;t=e;u=e+36|0;v=e+16|0;w=e+20|0;x=e+52|0;y=e+28|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;a:do switch(c[j>>2]|0){case 10010:{d=(c[k>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[k>>2]=d+4;c[l>>2]=b;if((c[l>>2]|0)>=0?(c[l>>2]|0)<(c[(c[c[h>>2]>>2]|0)+8>>2]|0):0){c[(c[h>>2]|0)+20>>2]=c[l>>2];z=24}else z=25;break}case 10012:{b=(c[k>>2]|0)+(4-1)&~(4-1);d=c[b>>2]|0;c[k>>2]=b+4;c[m>>2]=d;if((c[m>>2]|0)>=1?(c[m>>2]|0)<=(c[(c[c[h>>2]>>2]|0)+8>>2]|0):0){c[(c[h>>2]|0)+24>>2]=c[m>>2];z=24}else z=25;break}case 4028:{c[r>>2]=(c[h>>2]|0)+84+((_(2048+(c[(c[h>>2]|0)+4>>2]|0)|0,c[(c[h>>2]|0)+8>>2]|0)|0)<<2);c[s>>2]=(c[r>>2]|0)+((c[(c[h>>2]|0)+8>>2]|0)*24<<2);c[t>>2]=(c[s>>2]|0)+(c[(c[c[h>>2]>>2]|0)+8>>2]<<1<<2);c[u>>2]=(c[t>>2]|0)+(c[(c[c[h>>2]>>2]|0)+8>>2]<<1<<2);bf((c[h>>2]|0)+36|0,0,(Wc(c[c[h>>2]>>2]|0,c[(c[h>>2]|0)+8>>2]|0)|0)-((c[h>>2]|0)+36-(c[h>>2]|0))|0)|0;c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[(c[c[h>>2]>>2]|0)+8>>2]<<1|0)){z=24;break a}g[(c[u>>2]|0)+(c[q>>2]<<2)>>2]=-28.0;g[(c[t>>2]|0)+(c[q>>2]<<2)>>2]=-28.0;c[q>>2]=(c[q>>2]|0)+1}break}case 4033:{d=(c[k>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[k>>2]=d+4;c[v>>2]=b;if(!(c[v>>2]|0))z=25;else{c[c[v>>2]>>2]=c[(c[h>>2]|0)+52>>2];z=24}break}case 10015:{b=(c[k>>2]|0)+(4-1)&~(4-1);d=c[b>>2]|0;c[k>>2]=b+4;c[w>>2]=d;if(!(c[w>>2]|0))z=25;else{c[c[w>>2]>>2]=c[c[h>>2]>>2];z=24}break}case 10016:{d=(c[k>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[k>>2]=d+4;c[x>>2]=b;c[(c[h>>2]|0)+28>>2]=c[x>>2];z=24;break}case 4031:{b=(c[k>>2]|0)+(4-1)&~(4-1);d=c[b>>2]|0;c[k>>2]=b+4;c[y>>2]=d;if(!(c[y>>2]|0))z=25;else{c[c[y>>2]>>2]=c[(c[h>>2]|0)+36>>2];z=24}break}case 10008:{d=(c[k>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[k>>2]=d+4;c[n>>2]=b;if((c[n>>2]|0)<1|(c[n>>2]|0)>2)z=25;else{c[(c[h>>2]|0)+12>>2]=c[n>>2];z=24}break}case 10007:{b=(c[k>>2]|0)+(4-1)&~(4-1);d=c[b>>2]|0;c[k>>2]=b+4;c[o>>2]=d;if(!(c[o>>2]|0))z=25;else{c[c[o>>2]>>2]=c[(c[h>>2]|0)+40>>2];c[(c[h>>2]|0)+40>>2]=0;z=24}break}case 4027:{d=(c[k>>2]|0)+(4-1)&~(4-1);b=c[d>>2]|0;c[k>>2]=d+4;c[p>>2]=b;if(!(c[p>>2]|0))z=25;else{c[c[p>>2]>>2]=(c[(c[h>>2]|0)+4>>2]|0)/(c[(c[h>>2]|0)+16>>2]|0)|0;z=24}break}default:{c[f>>2]=-5;A=c[f>>2]|0;i=e;return A|0}}while(0);if((z|0)==24){c[f>>2]=0;A=c[f>>2]|0;i=e;return A|0}else if((z|0)==25){c[f>>2]=-1;A=c[f>>2]|0;i=e;return A|0}return 0}function bb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0;f=i;i=i+16|0;g=f+12|0;h=f+8|0;j=f+4|0;k=f;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=e;e=c[k>>2]|0;k=cd(c[h>>2]|0,c[g>>2]|0)|0;ob(e,k,(c[(c[2448+(((c[h>>2]|0)<(c[j>>2]|0)?c[h>>2]|0:c[j>>2]|0)<<2)>>2]|0)+(((c[h>>2]|0)>(c[j>>2]|0)?c[h>>2]|0:c[j>>2]|0)<<2)>>2]|0)+(c[(c[2448+(((c[h>>2]|0)<((c[j>>2]|0)+1|0)?c[h>>2]|0:(c[j>>2]|0)+1|0)<<2)>>2]|0)+(((c[h>>2]|0)>((c[j>>2]|0)+1|0)?c[h>>2]|0:(c[j>>2]|0)+1|0)<<2)>>2]|0)|0);i=f;return}function cb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0.0;f=i;i=i+16|0;g=f+12|0;h=f+8|0;j=f+4|0;k=f;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=e;e=c[h>>2]|0;d=c[j>>2]|0;b=kb(c[k>>2]|0,(c[(c[2448+(((c[h>>2]|0)<(c[j>>2]|0)?c[h>>2]|0:c[j>>2]|0)<<2)>>2]|0)+(((c[h>>2]|0)>(c[j>>2]|0)?c[h>>2]|0:c[j>>2]|0)<<2)>>2]|0)+(c[(c[2448+(((c[h>>2]|0)<((c[j>>2]|0)+1|0)?c[h>>2]|0:(c[j>>2]|0)+1|0)<<2)>>2]|0)+(((c[h>>2]|0)>((c[j>>2]|0)+1|0)?c[h>>2]|0:(c[j>>2]|0)+1|0)<<2)>>2]|0)|0)|0;l=+dd(e,d,b,c[g>>2]|0);i=f;return +l}function db(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=i;i=i+32|0;d=b+16|0;e=b+12|0;f=b+8|0;g=b+4|0;h=b;c[d>>2]=a;c[e>>2]=c[(c[d>>2]|0)+20>>2]<<3;c[g>>2]=32-(aa(c[(c[d>>2]|0)+28>>2]|0)|0);c[f>>2]=(c[(c[d>>2]|0)+28>>2]|0)>>>((c[g>>2]|0)-16|0);c[h>>2]=((c[f>>2]|0)>>>12)-8;c[h>>2]=(c[h>>2]|0)+((c[f>>2]|0)>>>0>(c[2512+(c[h>>2]<<2)>>2]|0)>>>0&1);c[g>>2]=(c[g>>2]<<3)+(c[h>>2]|0);i=b;return (c[e>>2]|0)-(c[g>>2]|0)|0}function eb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[c[f>>2]>>2]=c[g>>2];c[(c[f>>2]|0)+4>>2]=c[h>>2];c[(c[f>>2]|0)+8>>2]=0;c[(c[f>>2]|0)+12>>2]=0;c[(c[f>>2]|0)+16>>2]=0;c[(c[f>>2]|0)+20>>2]=9;c[(c[f>>2]|0)+24>>2]=0;c[(c[f>>2]|0)+28>>2]=128;h=ed(c[f>>2]|0)|0;c[(c[f>>2]|0)+40>>2]=h;c[(c[f>>2]|0)+32>>2]=(c[(c[f>>2]|0)+28>>2]|0)-1-(c[(c[f>>2]|0)+40>>2]>>1);c[(c[f>>2]|0)+44>>2]=0;fd(c[f>>2]|0);i=e;return}function fb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[e>>2]=a;c[f>>2]=b;b=gd(c[(c[e>>2]|0)+28>>2]|0,c[f>>2]|0)|0;c[(c[e>>2]|0)+36>>2]=b;c[g>>2]=((c[(c[e>>2]|0)+32>>2]|0)>>>0)/((c[(c[e>>2]|0)+36>>2]|0)>>>0)|0;i=d;return (c[f>>2]|0)-((c[g>>2]|0)+1+((c[f>>2]|0)-((c[g>>2]|0)+1)&0-((c[f>>2]|0)>>>0<((c[g>>2]|0)+1|0)>>>0&1)))|0}function gb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[e>>2]=a;c[f>>2]=b;c[(c[e>>2]|0)+36>>2]=(c[(c[e>>2]|0)+28>>2]|0)>>>(c[f>>2]|0);c[g>>2]=((c[(c[e>>2]|0)+32>>2]|0)>>>0)/((c[(c[e>>2]|0)+36>>2]|0)>>>0)|0;i=d;return (1<<c[f>>2])-((c[g>>2]|0)+1+((1<<c[f>>2])-((c[g>>2]|0)+1)&0-(1<<c[f>>2]>>>0<((c[g>>2]|0)+1|0)>>>0&1)))|0}function hb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=e;c[l>>2]=_(c[(c[g>>2]|0)+36>>2]|0,(c[k>>2]|0)-(c[j>>2]|0)|0)|0;k=(c[g>>2]|0)+32|0;c[k>>2]=(c[k>>2]|0)-(c[l>>2]|0);k=c[g>>2]|0;if((c[h>>2]|0)>>>0>0){m=_(c[k+36>>2]|0,(c[j>>2]|0)-(c[h>>2]|0)|0)|0;n=c[g>>2]|0;o=n+28|0;c[o>>2]=m;p=c[g>>2]|0;fd(p);i=f;return}else{m=(c[k+28>>2]|0)-(c[l>>2]|0)|0;n=c[g>>2]|0;o=n+28|0;c[o>>2]=m;p=c[g>>2]|0;fd(p);i=f;return}}function ib(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;d=i;i=i+32|0;e=d+20|0;f=d+16|0;g=d+12|0;h=d+8|0;j=d+4|0;k=d;c[e>>2]=a;c[f>>2]=b;c[g>>2]=c[(c[e>>2]|0)+28>>2];c[h>>2]=c[(c[e>>2]|0)+32>>2];c[j>>2]=(c[g>>2]|0)>>>(c[f>>2]|0);c[k>>2]=(c[h>>2]|0)>>>0<(c[j>>2]|0)>>>0&1;if(!(c[k>>2]|0))c[(c[e>>2]|0)+32>>2]=(c[h>>2]|0)-(c[j>>2]|0);if(c[k>>2]|0){l=c[j>>2]|0;m=c[e>>2]|0;n=m+28|0;c[n>>2]=l;o=c[e>>2]|0;fd(o);p=c[k>>2]|0;i=d;return p|0}else{l=(c[g>>2]|0)-(c[j>>2]|0)|0;m=c[e>>2]|0;n=m+28|0;c[n>>2]=l;o=c[e>>2]|0;fd(o);p=c[k>>2]|0;i=d;return p|0}return 0}function jb(a,b,e){a=a|0;b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;f=i;i=i+32|0;g=f+4|0;h=f+16|0;j=f+8|0;k=f+20|0;l=f+28|0;m=f;n=f+12|0;o=f+24|0;c[g>>2]=a;c[h>>2]=b;c[j>>2]=e;c[m>>2]=c[(c[g>>2]|0)+28>>2];c[l>>2]=c[(c[g>>2]|0)+32>>2];c[k>>2]=(c[m>>2]|0)>>>(c[j>>2]|0);c[o>>2]=-1;do{c[n>>2]=c[m>>2];j=c[k>>2]|0;e=(c[o>>2]|0)+1|0;c[o>>2]=e;c[m>>2]=_(j,d[(c[h>>2]|0)+e>>0]|0)|0}while((c[l>>2]|0)>>>0<(c[m>>2]|0)>>>0);c[(c[g>>2]|0)+32>>2]=(c[l>>2]|0)-(c[m>>2]|0);c[(c[g>>2]|0)+28>>2]=(c[n>>2]|0)-(c[m>>2]|0);fd(c[g>>2]|0);i=f;return c[o>>2]|0}function kb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0;d=i;i=i+32|0;e=d+8|0;f=d+16|0;g=d+20|0;h=d+24|0;j=d+4|0;k=d;l=d+12|0;c[f>>2]=a;c[g>>2]=b;c[g>>2]=(c[g>>2]|0)+-1;c[k>>2]=32-(aa(c[g>>2]|0)|0);if((c[k>>2]|0)<=8){c[g>>2]=(c[g>>2]|0)+1;c[j>>2]=fb(c[f>>2]|0,c[g>>2]|0)|0;hb(c[f>>2]|0,c[j>>2]|0,(c[j>>2]|0)+1|0,c[g>>2]|0);c[e>>2]=c[j>>2];m=c[e>>2]|0;i=d;return m|0}c[k>>2]=(c[k>>2]|0)-8;c[h>>2]=((c[g>>2]|0)>>>(c[k>>2]|0))+1;c[j>>2]=fb(c[f>>2]|0,c[h>>2]|0)|0;hb(c[f>>2]|0,c[j>>2]|0,(c[j>>2]|0)+1|0,c[h>>2]|0);h=c[j>>2]<<c[k>>2];c[l>>2]=h|(lb(c[f>>2]|0,c[k>>2]|0)|0);if((c[l>>2]|0)>>>0<=(c[g>>2]|0)>>>0){c[e>>2]=c[l>>2];m=c[e>>2]|0;i=d;return m|0}else{c[(c[f>>2]|0)+44>>2]=1;c[e>>2]=c[g>>2];m=c[e>>2]|0;i=d;return m|0}return 0}function lb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;i=i+32|0;e=d+16|0;f=d+12|0;g=d+8|0;h=d+4|0;j=d;c[e>>2]=a;c[f>>2]=b;c[g>>2]=c[(c[e>>2]|0)+12>>2];c[h>>2]=c[(c[e>>2]|0)+16>>2];if((c[h>>2]|0)>>>0<(c[f>>2]|0)>>>0)do{b=hd(c[e>>2]|0)|0;c[g>>2]=c[g>>2]|b<<c[h>>2];c[h>>2]=(c[h>>2]|0)+8}while((c[h>>2]|0)<=24);c[j>>2]=c[g>>2]&(1<<c[f>>2])-1;c[g>>2]=(c[g>>2]|0)>>>(c[f>>2]|0);c[h>>2]=(c[h>>2]|0)-(c[f>>2]|0);c[(c[e>>2]|0)+12>>2]=c[g>>2];c[(c[e>>2]|0)+16>>2]=c[h>>2];h=(c[e>>2]|0)+20|0;c[h>>2]=(c[h>>2]|0)+(c[f>>2]|0);i=d;return c[j>>2]|0}function mb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=e;c[l>>2]=id(c[(c[g>>2]|0)+28>>2]|0,c[k>>2]|0)|0;if((c[h>>2]|0)>>>0>0){e=(c[(c[g>>2]|0)+28>>2]|0)-(_(c[l>>2]|0,(c[k>>2]|0)-(c[h>>2]|0)|0)|0)|0;d=(c[g>>2]|0)+32|0;c[d>>2]=(c[d>>2]|0)+e;e=_(c[l>>2]|0,(c[j>>2]|0)-(c[h>>2]|0)|0)|0;c[(c[g>>2]|0)+28>>2]=e;m=c[g>>2]|0;jd(m);i=f;return}else{e=_(c[l>>2]|0,(c[k>>2]|0)-(c[j>>2]|0)|0)|0;j=(c[g>>2]|0)+28|0;c[j>>2]=(c[j>>2]|0)-e;m=c[g>>2]|0;jd(m);i=f;return}}function nb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+20|0;g=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[j>>2]=c[(c[f>>2]|0)+28>>2];c[l>>2]=c[(c[f>>2]|0)+32>>2];c[k>>2]=(c[j>>2]|0)>>>(c[h>>2]|0);c[j>>2]=(c[j>>2]|0)-(c[k>>2]|0);if(c[g>>2]|0)c[(c[f>>2]|0)+32>>2]=(c[l>>2]|0)+(c[j>>2]|0);c[(c[f>>2]|0)+28>>2]=(c[g>>2]|0)!=0?c[k>>2]|0:c[j>>2]|0;jd(c[f>>2]|0);i=e;return}function ob(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+20|0;g=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[h>>2]=(c[h>>2]|0)+-1;c[l>>2]=32-(aa(c[h>>2]|0)|0);if((c[l>>2]|0)>8){c[l>>2]=(c[l>>2]|0)-8;c[j>>2]=((c[h>>2]|0)>>>(c[l>>2]|0))+1;c[k>>2]=(c[g>>2]|0)>>>(c[l>>2]|0);mb(c[f>>2]|0,c[k>>2]|0,(c[k>>2]|0)+1|0,c[j>>2]|0);pb(c[f>>2]|0,c[g>>2]&(1<<c[l>>2])-1,c[l>>2]|0);i=e;return}else{mb(c[f>>2]|0,c[g>>2]|0,(c[g>>2]|0)+1|0,(c[h>>2]|0)+1|0);i=e;return}}function pb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[j>>2]=c[(c[f>>2]|0)+12>>2];c[k>>2]=c[(c[f>>2]|0)+16>>2];if(((c[k>>2]|0)+(c[h>>2]|0)|0)>>>0>32)do{d=kd(c[f>>2]|0,c[j>>2]&255)|0;b=(c[f>>2]|0)+44|0;c[b>>2]=c[b>>2]|d;c[j>>2]=(c[j>>2]|0)>>>8;c[k>>2]=(c[k>>2]|0)-8}while((c[k>>2]|0)>=8);c[j>>2]=c[j>>2]|c[g>>2]<<c[k>>2];c[k>>2]=(c[k>>2]|0)+(c[h>>2]|0);c[(c[f>>2]|0)+12>>2]=c[j>>2];c[(c[f>>2]|0)+16>>2]=c[k>>2];k=(c[f>>2]|0)+20|0;c[k>>2]=(c[k>>2]|0)+(c[h>>2]|0);i=e;return}function qb(a,d){a=a|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;e=i;i=i+80|0;f=e+60|0;g=e+48|0;h=e+4|0;j=e+8|0;k=e+64|0;l=e;m=e+16|0;n=e+56|0;o=e+52|0;c[f>>2]=a;c[g>>2]=d;if((c[(c[f>>2]|0)+8>>2]|0)>0)p=c[(c[f>>2]|0)+8>>2]|0;else p=0;c[o>>2]=p;c[m>>2]=1;c[l>>2]=0;do{c[k>>2]=b[(c[f>>2]|0)+12+(c[l>>2]<<1<<1)>>1];c[j>>2]=b[(c[f>>2]|0)+12+((c[l>>2]<<1)+1<<1)>>1];p=_(c[m+(c[l>>2]<<2)>>2]|0,c[k>>2]|0)|0;c[m+((c[l>>2]|0)+1<<2)>>2]=p;c[l>>2]=(c[l>>2]|0)+1}while((c[j>>2]|0)!=1);c[j>>2]=b[(c[f>>2]|0)+12+((c[l>>2]<<1)-1<<1)>>1];c[n>>2]=(c[l>>2]|0)-1;while(1){if((c[n>>2]|0)<0)break;if(c[n>>2]|0)c[h>>2]=b[(c[f>>2]|0)+12+((c[n>>2]<<1)-1<<1)>>1];else c[h>>2]=1;l=b[(c[f>>2]|0)+12+(c[n>>2]<<1<<1)>>1]|0;if((l|0)==2)md(c[g>>2]|0,c[j>>2]|0,c[m+(c[n>>2]<<2)>>2]|0);else if((l|0)==4)nd(c[g>>2]|0,c[m+(c[n>>2]<<2)>>2]<<c[o>>2],c[f>>2]|0,c[j>>2]|0,c[m+(c[n>>2]<<2)>>2]|0,c[h>>2]|0);else if((l|0)==3)od(c[g>>2]|0,c[m+(c[n>>2]<<2)>>2]<<c[o>>2],c[f>>2]|0,c[j>>2]|0,c[m+(c[n>>2]<<2)>>2]|0,c[h>>2]|0);else if((l|0)==5)pd(c[g>>2]|0,c[m+(c[n>>2]<<2)>>2]<<c[o>>2],c[f>>2]|0,c[j>>2]|0,c[m+(c[n>>2]<<2)>>2]|0,c[h>>2]|0);c[j>>2]=c[h>>2];c[n>>2]=(c[n>>2]|0)+-1}i=e;return}function rb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;e=i;i=i+32|0;f=e+8|0;g=e+16|0;h=e+20|0;j=e+24|0;k=e+4|0;l=e;m=e+12|0;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[j>>2]=0;c[l>>2]=gb(c[f>>2]|0,15)|0;c[k>>2]=0;do if((c[l>>2]|0)>>>0>=(c[g>>2]|0)>>>0){c[j>>2]=(c[j>>2]|0)+1;c[k>>2]=c[g>>2];c[g>>2]=(qd(c[g>>2]|0,c[h>>2]|0)|0)+1;while(1){if((c[g>>2]|0)>>>0>1)n=(c[l>>2]|0)>>>0>=((c[k>>2]|0)+(c[g>>2]<<1)|0)>>>0;else n=0;o=c[g>>2]|0;if(!n)break;c[g>>2]=o<<1;c[k>>2]=(c[k>>2]|0)+(c[g>>2]|0);c[g>>2]=(_((c[g>>2]|0)-2|0,c[h>>2]|0)|0)>>>15;c[g>>2]=(c[g>>2]|0)+1;c[j>>2]=(c[j>>2]|0)+1}if(o>>>0<=1){c[m>>2]=((c[l>>2]|0)-(c[k>>2]|0)|0)>>>1;c[j>>2]=(c[j>>2]|0)+(c[m>>2]|0);c[k>>2]=(c[k>>2]|0)+(c[m>>2]<<1)}if((c[l>>2]|0)>>>0<((c[k>>2]|0)+(c[g>>2]|0)|0)>>>0){c[j>>2]=0-(c[j>>2]|0);break}else{c[k>>2]=(c[k>>2]|0)+(c[g>>2]|0);break}}while(0);l=c[f>>2]|0;f=c[k>>2]|0;if(((c[k>>2]|0)+(c[g>>2]|0)|0)>>>0>=32768){p=32768;hb(l,f,p,32768);q=c[j>>2]|0;i=e;return q|0}p=(c[k>>2]|0)+(c[g>>2]|0)|0;hb(l,f,p,32768);q=c[j>>2]|0;i=e;return q|0}function sb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=i;i=i+32|0;d=b+16|0;e=b+12|0;f=b+8|0;g=b+4|0;h=b;c[d>>2]=a;c[f>>2]=0;c[g>>2]=32-(aa(c[d>>2]|0)|0)-1>>1;c[e>>2]=1<<c[g>>2];do{c[h>>2]=(c[f>>2]<<1)+(c[e>>2]|0)<<c[g>>2];if((c[h>>2]|0)>>>0<=(c[d>>2]|0)>>>0){c[f>>2]=(c[f>>2]|0)+(c[e>>2]|0);c[d>>2]=(c[d>>2]|0)-(c[h>>2]|0)}c[e>>2]=(c[e>>2]|0)>>>1;c[g>>2]=(c[g>>2]|0)+-1}while((c[g>>2]|0)>=0);i=b;return c[f>>2]|0}function tb(a,d,e,f,h,j,k){a=a|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0.0;l=i;i=i+144|0;m=l+132|0;n=l+108|0;o=l+8|0;p=l+56|0;q=l+64|0;r=l+16|0;s=l+20|0;t=l+24|0;u=l+28|0;v=l+32|0;w=l+36|0;x=l+40|0;y=l+44|0;z=l+104|0;A=l+112|0;B=l+120|0;C=l+128|0;D=l+136|0;E=l+68|0;F=l+72|0;G=l+76|0;H=l+80|0;I=l+84|0;J=l+88|0;K=l+92|0;L=l+12|0;M=l+4|0;N=l;O=l+96|0;P=l+48|0;Q=l+100|0;R=l+52|0;S=l+116|0;T=l+60|0;U=l+124|0;c[m>>2]=a;c[n>>2]=d;c[o>>2]=e;c[p>>2]=f;c[q>>2]=h;c[r>>2]=j;c[s>>2]=k;c[u>>2]=c[c[m>>2]>>2];c[x>>2]=c[(c[m>>2]|0)+24>>2];c[t>>2]=0;while(1){V=c[u>>2]>>1;if((c[t>>2]|0)>=(c[r>>2]|0))break;c[u>>2]=V;c[x>>2]=(c[x>>2]|0)+(c[u>>2]<<2);c[t>>2]=(c[t>>2]|0)+1}c[v>>2]=V;c[w>>2]=c[u>>2]>>2;c[y>>2]=c[n>>2];c[z>>2]=(c[n>>2]|0)+((_(c[s>>2]|0,(c[v>>2]|0)-1|0)|0)<<2);c[A>>2]=(c[o>>2]|0)+(c[q>>2]>>1<<2);c[B>>2]=c[x>>2];c[C>>2]=c[(c[(c[m>>2]|0)+8+(c[r>>2]<<2)>>2]|0)+44>>2];c[t>>2]=0;while(1){if((c[t>>2]|0)>=(c[w>>2]|0))break;n=c[C>>2]|0;c[C>>2]=n+2;c[D>>2]=b[n>>1];g[E>>2]=+g[c[z>>2]>>2]*+g[(c[B>>2]|0)+(c[t>>2]<<2)>>2]+ +g[c[y>>2]>>2]*+g[(c[B>>2]|0)+((c[w>>2]|0)+(c[t>>2]|0)<<2)>>2];g[F>>2]=+g[c[y>>2]>>2]*+g[(c[B>>2]|0)+(c[t>>2]<<2)>>2]-+g[c[z>>2]>>2]*+g[(c[B>>2]|0)+((c[w>>2]|0)+(c[t>>2]|0)<<2)>>2];g[(c[A>>2]|0)+((c[D>>2]<<1)+1<<2)>>2]=+g[E>>2];g[(c[A>>2]|0)+(c[D>>2]<<1<<2)>>2]=+g[F>>2];c[y>>2]=(c[y>>2]|0)+(c[s>>2]<<1<<2);c[z>>2]=(c[z>>2]|0)+(0-(c[s>>2]<<1)<<2);c[t>>2]=(c[t>>2]|0)+1}qb(c[(c[m>>2]|0)+8+(c[r>>2]<<2)>>2]|0,(c[o>>2]|0)+(c[q>>2]>>1<<2)|0);c[G>>2]=(c[o>>2]|0)+(c[q>>2]>>1<<2);c[H>>2]=(c[o>>2]|0)+(c[q>>2]>>1<<2)+(c[v>>2]<<2)+-8;c[I>>2]=c[x>>2];c[t>>2]=0;while(1){if((c[t>>2]|0)>=((c[w>>2]|0)+1>>1|0))break;g[J>>2]=+g[(c[G>>2]|0)+4>>2];g[K>>2]=+g[c[G>>2]>>2];g[N>>2]=+g[(c[I>>2]|0)+(c[t>>2]<<2)>>2];g[O>>2]=+g[(c[I>>2]|0)+((c[w>>2]|0)+(c[t>>2]|0)<<2)>>2];g[L>>2]=+g[J>>2]*+g[N>>2]+ +g[K>>2]*+g[O>>2];g[M>>2]=+g[J>>2]*+g[O>>2]-+g[K>>2]*+g[N>>2];g[J>>2]=+g[(c[H>>2]|0)+4>>2];g[K>>2]=+g[c[H>>2]>>2];g[c[G>>2]>>2]=+g[L>>2];g[(c[H>>2]|0)+4>>2]=+g[M>>2];g[N>>2]=+g[(c[I>>2]|0)+((c[w>>2]|0)-(c[t>>2]|0)-1<<2)>>2];g[O>>2]=+g[(c[I>>2]|0)+((c[v>>2]|0)-(c[t>>2]|0)-1<<2)>>2];g[L>>2]=+g[J>>2]*+g[N>>2]+ +g[K>>2]*+g[O>>2];g[M>>2]=+g[J>>2]*+g[O>>2]-+g[K>>2]*+g[N>>2];g[c[H>>2]>>2]=+g[L>>2];g[(c[G>>2]|0)+4>>2]=+g[M>>2];c[G>>2]=(c[G>>2]|0)+8;c[H>>2]=(c[H>>2]|0)+-8;c[t>>2]=(c[t>>2]|0)+1}c[P>>2]=(c[o>>2]|0)+(c[q>>2]<<2)+-4;c[Q>>2]=c[o>>2];c[R>>2]=c[p>>2];c[S>>2]=(c[p>>2]|0)+(c[q>>2]<<2)+-4;c[t>>2]=0;while(1){if((c[t>>2]|0)>=((c[q>>2]|0)/2|0|0))break;g[T>>2]=+g[c[P>>2]>>2];g[U>>2]=+g[c[Q>>2]>>2];W=+g[c[S>>2]>>2]*+g[U>>2]-+g[c[R>>2]>>2]*+g[T>>2];p=c[Q>>2]|0;c[Q>>2]=p+4;g[p>>2]=W;W=+g[c[R>>2]>>2]*+g[U>>2]+ +g[c[S>>2]>>2]*+g[T>>2];p=c[P>>2]|0;c[P>>2]=p+-4;g[p>>2]=W;c[R>>2]=(c[R>>2]|0)+4;c[S>>2]=(c[S>>2]|0)+-4;c[t>>2]=(c[t>>2]|0)+1}i=l;return}function ub(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;e=i;i=i+32|0;f=e+20|0;g=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=0;a:while(1){if((c[k>>2]|0)>=1){m=12;break}c[l>>2]=0;while(1){if((c[l>>2]|0)>=4)break;if((c[g>>2]|0)==(c[c[2544+(c[k>>2]<<2)>>2]>>2]|0)?(c[h>>2]<<c[l>>2]|0)==(_(c[(c[2544+(c[k>>2]<<2)>>2]|0)+44>>2]|0,c[(c[2544+(c[k>>2]<<2)>>2]|0)+40>>2]|0)|0):0){m=7;break a}c[l>>2]=(c[l>>2]|0)+1}c[k>>2]=(c[k>>2]|0)+1}if((m|0)==7){if(c[j>>2]|0)c[c[j>>2]>>2]=0;c[f>>2]=c[2544+(c[k>>2]<<2)>>2];n=c[f>>2]|0;i=e;return n|0}else if((m|0)==12){if(c[j>>2]|0)c[c[j>>2]>>2]=-1;c[f>>2]=0;n=c[f>>2]|0;i=e;return n|0}return 0}function vb(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;h=i;i=i+112|0;j=h+4|0;k=h+48|0;l=h+84|0;m=h;n=h+80|0;o=h+88|0;p=h+92|0;q=h+72|0;r=h+56|0;s=h+8|0;t=h+28|0;u=h+76|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;g[q>>2]=1.0;c[s>>2]=0;c[s+4>>2]=0;c[s+8>>2]=0;c[s+12>>2]=0;c[s+16>>2]=0;g[u>>2]=.800000011920929;c[o>>2]=1;while(1){if((c[o>>2]|0)>=(c[l>>2]>>1|0))break;g[(c[k>>2]|0)+(c[o>>2]<<2)>>2]=((+g[(c[c[j>>2]>>2]|0)+((c[o>>2]<<1)-1<<2)>>2]+ +g[(c[c[j>>2]>>2]|0)+((c[o>>2]<<1)+1<<2)>>2])*.5+ +g[(c[c[j>>2]>>2]|0)+(c[o>>2]<<1<<2)>>2])*.5;c[o>>2]=(c[o>>2]|0)+1}g[c[k>>2]>>2]=(+g[(c[c[j>>2]>>2]|0)+4>>2]*.5+ +g[c[c[j>>2]>>2]>>2])*.5;if((c[m>>2]|0)==2){c[o>>2]=1;while(1){if((c[o>>2]|0)>=(c[l>>2]>>1|0))break;m=(c[k>>2]|0)+(c[o>>2]<<2)|0;g[m>>2]=+g[m>>2]+((+g[(c[(c[j>>2]|0)+4>>2]|0)+((c[o>>2]<<1)-1<<2)>>2]+ +g[(c[(c[j>>2]|0)+4>>2]|0)+((c[o>>2]<<1)+1<<2)>>2])*.5+ +g[(c[(c[j>>2]|0)+4>>2]|0)+(c[o>>2]<<1<<2)>>2])*.5;c[o>>2]=(c[o>>2]|0)+1}m=c[k>>2]|0;g[m>>2]=+g[m>>2]+(+g[(c[(c[j>>2]|0)+4>>2]|0)+4>>2]*.5+ +g[c[(c[j>>2]|0)+4>>2]>>2])*.5}Bb(c[k>>2]|0,p,0,0,4,c[l>>2]>>1,c[n>>2]|0)|0;g[p>>2]=+g[p>>2]*1.000100016593933;c[o>>2]=1;while(1){if((c[o>>2]|0)>4)break;n=p+(c[o>>2]<<2)|0;g[n>>2]=+g[n>>2]-+g[p+(c[o>>2]<<2)>>2]*(+(c[o>>2]|0)*.00800000037997961)*(+(c[o>>2]|0)*.00800000037997961);c[o>>2]=(c[o>>2]|0)+1}yb(r,p,4);c[o>>2]=0;while(1){if((c[o>>2]|0)>=4)break;g[q>>2]=+g[q>>2]*.8999999761581421;g[r+(c[o>>2]<<2)>>2]=+g[r+(c[o>>2]<<2)>>2]*+g[q>>2];c[o>>2]=(c[o>>2]|0)+1}g[t>>2]=+g[r>>2]+.800000011920929;g[t+4>>2]=+g[r+4>>2]+ +g[u>>2]*+g[r>>2];g[t+8>>2]=+g[r+8>>2]+ +g[u>>2]*+g[r+4>>2];g[t+12>>2]=+g[r+12>>2]+ +g[u>>2]*+g[r+8>>2];g[t+16>>2]=+g[u>>2]*+g[r+12>>2];rd(c[k>>2]|0,t,c[k>>2]|0,c[l>>2]>>1,s);i=h;return}function wb(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;h=i;i=i+48|0;j=h+4|0;k=h+32|0;l=h+8|0;m=h+36|0;n=h+44|0;o=h;p=h+16|0;q=h+40|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;c[o>>2]=0;while(1){if((c[o>>2]|0)>=((c[n>>2]|0)-3|0))break;c[p>>2]=0;c[p+4>>2]=0;c[p+8>>2]=0;c[p+12>>2]=0;sd(c[j>>2]|0,(c[k>>2]|0)+(c[o>>2]<<2)|0,p,c[m>>2]|0);g[(c[l>>2]|0)+(c[o>>2]<<2)>>2]=+g[p>>2];g[(c[l>>2]|0)+((c[o>>2]|0)+1<<2)>>2]=+g[p+4>>2];g[(c[l>>2]|0)+((c[o>>2]|0)+2<<2)>>2]=+g[p+8>>2];g[(c[l>>2]|0)+((c[o>>2]|0)+3<<2)>>2]=+g[p+12>>2];c[o>>2]=(c[o>>2]|0)+4}while(1){if((c[o>>2]|0)>=(c[n>>2]|0))break;g[q>>2]=+td(c[j>>2]|0,(c[k>>2]|0)+(c[o>>2]<<2)|0,c[m>>2]|0);g[(c[l>>2]|0)+(c[o>>2]<<2)>>2]=+g[q>>2];c[o>>2]=(c[o>>2]|0)+1}i=h;return}function xb(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0;j=i;i=i+80|0;k=j+16|0;l=j+32|0;m=j+52|0;n=j+60|0;o=j+40|0;p=j+56|0;q=j+64|0;r=j+68|0;s=j+8|0;t=j+36|0;u=j+20|0;v=j;w=j+24|0;x=j+44|0;y=j+28|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[j+48>>2]=h;c[s>>2]=0;c[s+4>>2]=0;c[r>>2]=(c[m>>2]|0)+(c[n>>2]|0);h=c[m>>2]>>2;c[u>>2]=ua()|0;f=i;i=i+((1*(h<<2)|0)+15&-16)|0;h=i;i=i+((1*(c[r>>2]>>2<<2)|0)+15&-16)|0;e=i;i=i+((1*(c[n>>2]>>1<<2)|0)+15&-16)|0;c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[m>>2]>>2|0))break;g[f+(c[q>>2]<<2)>>2]=+g[(c[k>>2]|0)+(c[q>>2]<<1<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[r>>2]>>2|0))break;g[h+(c[q>>2]<<2)>>2]=+g[(c[l>>2]|0)+(c[q>>2]<<1<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}wb(f,h,e,c[m>>2]>>2,c[n>>2]>>2);ud(e,h,c[m>>2]>>2,c[n>>2]>>2,s);c[p>>2]=0;while(1){if((c[p>>2]|0)>=(c[n>>2]>>1|0))break;g[e+(c[p>>2]<<2)>>2]=0.0;if(!((N((c[p>>2]|0)-(c[s>>2]<<1)|0)|0)>2?(N((c[p>>2]|0)-(c[s+4>>2]<<1)|0)|0)>2:0)){g[v>>2]=+td(c[k>>2]|0,(c[l>>2]|0)+(c[p>>2]<<2)|0,c[m>>2]>>1);g[e+(c[p>>2]<<2)>>2]=-1.0>+g[v>>2]?-1.0:+g[v>>2]}c[p>>2]=(c[p>>2]|0)+1}ud(e,c[l>>2]|0,c[m>>2]>>1,c[n>>2]>>1,s);if((c[s>>2]|0)>0?(c[s>>2]|0)<((c[n>>2]>>1)-1|0):0){g[w>>2]=+g[e+((c[s>>2]|0)-1<<2)>>2];g[x>>2]=+g[e+(c[s>>2]<<2)>>2];g[y>>2]=+g[e+((c[s>>2]|0)+1<<2)>>2];if(+g[y>>2]-+g[w>>2]>(+g[x>>2]-+g[w>>2])*.699999988079071){c[t>>2]=1;z=c[s>>2]|0;A=z<<1;B=c[t>>2]|0;C=A-B|0;D=c[o>>2]|0;c[D>>2]=C;E=c[u>>2]|0;ka(E|0);i=j;return}if(+g[w>>2]-+g[y>>2]>(+g[x>>2]-+g[y>>2])*.699999988079071){c[t>>2]=-1;z=c[s>>2]|0;A=z<<1;B=c[t>>2]|0;C=A-B|0;D=c[o>>2]|0;c[D>>2]=C;E=c[u>>2]|0;ka(E|0);i=j;return}else{c[t>>2]=0;z=c[s>>2]|0;A=z<<1;B=c[t>>2]|0;C=A-B|0;D=c[o>>2]|0;c[D>>2]=C;E=c[u>>2]|0;ka(E|0);i=j;return}}c[t>>2]=0;z=c[s>>2]|0;A=z<<1;B=c[t>>2]|0;C=A-B|0;D=c[o>>2]|0;c[D>>2]=C;E=c[u>>2]|0;ka(E|0);i=j;return}function yb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;e=i;i=i+48|0;f=e+36|0;h=e+16|0;j=e;k=e+28|0;l=e+32|0;m=e+40|0;n=e+12|0;o=e+24|0;p=e+20|0;q=e+8|0;r=e+4|0;c[f>>2]=a;c[h>>2]=b;c[j>>2]=d;g[n>>2]=+g[c[h>>2]>>2];c[o>>2]=c[f>>2];c[k>>2]=0;while(1){if((c[k>>2]|0)>=(c[j>>2]|0))break;g[(c[o>>2]|0)+(c[k>>2]<<2)>>2]=0.0;c[k>>2]=(c[k>>2]|0)+1}if(!(+g[c[h>>2]>>2]!=0.0)){i=e;return}c[k>>2]=0;while(1){if((c[k>>2]|0)>=(c[j>>2]|0)){s=15;break}g[p>>2]=0.0;c[l>>2]=0;while(1){if((c[l>>2]|0)>=(c[k>>2]|0))break;g[p>>2]=+g[p>>2]+ +g[(c[o>>2]|0)+(c[l>>2]<<2)>>2]*+g[(c[h>>2]|0)+((c[k>>2]|0)-(c[l>>2]|0)<<2)>>2];c[l>>2]=(c[l>>2]|0)+1}g[p>>2]=+g[p>>2]+ +g[(c[h>>2]|0)+((c[k>>2]|0)+1<<2)>>2];g[m>>2]=-(+g[p>>2]/+g[n>>2]);g[(c[o>>2]|0)+(c[k>>2]<<2)>>2]=+g[m>>2];c[l>>2]=0;while(1){if((c[l>>2]|0)>=((c[k>>2]|0)+1>>1|0))break;g[q>>2]=+g[(c[o>>2]|0)+(c[l>>2]<<2)>>2];g[r>>2]=+g[(c[o>>2]|0)+((c[k>>2]|0)-1-(c[l>>2]|0)<<2)>>2];g[(c[o>>2]|0)+(c[l>>2]<<2)>>2]=+g[q>>2]+ +g[m>>2]*+g[r>>2];g[(c[o>>2]|0)+((c[k>>2]|0)-1-(c[l>>2]|0)<<2)>>2]=+g[r>>2]+ +g[m>>2]*+g[q>>2];c[l>>2]=(c[l>>2]|0)+1}g[n>>2]=+g[n>>2]-+g[m>>2]*+g[m>>2]*+g[n>>2];if(+g[n>>2]<+g[c[h>>2]>>2]*1.0000000474974513e-03){s=15;break}c[k>>2]=(c[k>>2]|0)+1}if((s|0)==15){i=e;return}}function zb(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;j=i;i=i+64|0;k=j+48|0;l=j+28|0;m=j;n=j+40|0;o=j+44|0;p=j+52|0;q=j+24|0;r=j+36|0;s=j+32|0;t=j+8|0;u=j+4|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;h=c[o>>2]|0;c[s>>2]=ua()|0;f=i;i=i+((1*(h<<2)|0)+15&-16)|0;h=i;i=i+((1*((c[n>>2]|0)+(c[o>>2]|0)<<2)|0)+15&-16)|0;c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;g[f+(c[q>>2]<<2)>>2]=+g[(c[l>>2]|0)+((c[o>>2]|0)-(c[q>>2]|0)-1<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;g[h+(c[q>>2]<<2)>>2]=+g[(c[p>>2]|0)+((c[o>>2]|0)-(c[q>>2]|0)-1<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[n>>2]|0))break;g[h+((c[q>>2]|0)+(c[o>>2]|0)<<2)>>2]=+g[(c[k>>2]|0)+(c[q>>2]<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;g[(c[p>>2]|0)+(c[q>>2]<<2)>>2]=+g[(c[k>>2]|0)+((c[n>>2]|0)-(c[q>>2]|0)-1<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}c[q>>2]=0;while(1){if((c[q>>2]|0)>=((c[n>>2]|0)-3|0))break;c[t>>2]=0;c[t+4>>2]=0;c[t+8>>2]=0;c[t+12>>2]=0;vd(f,h+(c[q>>2]<<2)|0,t,c[o>>2]|0);g[(c[m>>2]|0)+(c[q>>2]<<2)>>2]=+g[(c[k>>2]|0)+(c[q>>2]<<2)>>2]+ +g[t>>2];g[(c[m>>2]|0)+((c[q>>2]|0)+1<<2)>>2]=+g[(c[k>>2]|0)+((c[q>>2]|0)+1<<2)>>2]+ +g[t+4>>2];g[(c[m>>2]|0)+((c[q>>2]|0)+2<<2)>>2]=+g[(c[k>>2]|0)+((c[q>>2]|0)+2<<2)>>2]+ +g[t+8>>2];g[(c[m>>2]|0)+((c[q>>2]|0)+3<<2)>>2]=+g[(c[k>>2]|0)+((c[q>>2]|0)+3<<2)>>2]+ +g[t+12>>2];c[q>>2]=(c[q>>2]|0)+4}while(1){if((c[q>>2]|0)>=(c[n>>2]|0))break;g[u>>2]=0.0;c[r>>2]=0;while(1){if((c[r>>2]|0)>=(c[o>>2]|0))break;g[u>>2]=+g[u>>2]+ +g[f+(c[r>>2]<<2)>>2]*+g[h+((c[q>>2]|0)+(c[r>>2]|0)<<2)>>2];c[r>>2]=(c[r>>2]|0)+1}g[(c[m>>2]|0)+(c[q>>2]<<2)>>2]=+g[(c[k>>2]|0)+(c[q>>2]<<2)>>2]+ +g[u>>2];c[q>>2]=(c[q>>2]|0)+1}ka(c[s>>2]|0);i=j;return}function Ab(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;j=i;i=i+64|0;k=j+48|0;l=j+28|0;m=j;n=j+40|0;o=j+44|0;p=j+52|0;q=j+24|0;r=j+36|0;s=j+32|0;t=j+8|0;u=j+4|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;h=c[o>>2]|0;c[s>>2]=ua()|0;f=i;i=i+((1*(h<<2)|0)+15&-16)|0;h=i;i=i+((1*((c[n>>2]|0)+(c[o>>2]|0)<<2)|0)+15&-16)|0;c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;g[f+(c[q>>2]<<2)>>2]=+g[(c[l>>2]|0)+((c[o>>2]|0)-(c[q>>2]|0)-1<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;g[h+(c[q>>2]<<2)>>2]=-+g[(c[p>>2]|0)+((c[o>>2]|0)-(c[q>>2]|0)-1<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}while(1){if((c[q>>2]|0)>=((c[n>>2]|0)+(c[o>>2]|0)|0))break;g[h+(c[q>>2]<<2)>>2]=0.0;c[q>>2]=(c[q>>2]|0)+1}c[q>>2]=0;while(1){if((c[q>>2]|0)>=((c[n>>2]|0)-3|0))break;g[t>>2]=+g[(c[k>>2]|0)+(c[q>>2]<<2)>>2];g[t+4>>2]=+g[(c[k>>2]|0)+((c[q>>2]|0)+1<<2)>>2];g[t+8>>2]=+g[(c[k>>2]|0)+((c[q>>2]|0)+2<<2)>>2];g[t+12>>2]=+g[(c[k>>2]|0)+((c[q>>2]|0)+3<<2)>>2];vd(f,h+(c[q>>2]<<2)|0,t,c[o>>2]|0);g[h+((c[q>>2]|0)+(c[o>>2]|0)<<2)>>2]=-+g[t>>2];g[(c[m>>2]|0)+(c[q>>2]<<2)>>2]=+g[t>>2];g[t+4>>2]=+g[t+4>>2]+ +g[h+((c[q>>2]|0)+(c[o>>2]|0)<<2)>>2]*+g[c[l>>2]>>2];g[h+((c[q>>2]|0)+(c[o>>2]|0)+1<<2)>>2]=-+g[t+4>>2];g[(c[m>>2]|0)+((c[q>>2]|0)+1<<2)>>2]=+g[t+4>>2];g[t+8>>2]=+g[t+8>>2]+ +g[h+((c[q>>2]|0)+(c[o>>2]|0)+1<<2)>>2]*+g[c[l>>2]>>2];g[t+8>>2]=+g[t+8>>2]+ +g[h+((c[q>>2]|0)+(c[o>>2]|0)<<2)>>2]*+g[(c[l>>2]|0)+4>>2];g[h+((c[q>>2]|0)+(c[o>>2]|0)+2<<2)>>2]=-+g[t+8>>2];g[(c[m>>2]|0)+((c[q>>2]|0)+2<<2)>>2]=+g[t+8>>2];g[t+12>>2]=+g[t+12>>2]+ +g[h+((c[q>>2]|0)+(c[o>>2]|0)+2<<2)>>2]*+g[c[l>>2]>>2];g[t+12>>2]=+g[t+12>>2]+ +g[h+((c[q>>2]|0)+(c[o>>2]|0)+1<<2)>>2]*+g[(c[l>>2]|0)+4>>2];g[t+12>>2]=+g[t+12>>2]+ +g[h+((c[q>>2]|0)+(c[o>>2]|0)<<2)>>2]*+g[(c[l>>2]|0)+8>>2];g[h+((c[q>>2]|0)+(c[o>>2]|0)+3<<2)>>2]=-+g[t+12>>2];g[(c[m>>2]|0)+((c[q>>2]|0)+3<<2)>>2]=+g[t+12>>2];c[q>>2]=(c[q>>2]|0)+4}while(1){if((c[q>>2]|0)>=(c[n>>2]|0))break;g[u>>2]=+g[(c[k>>2]|0)+(c[q>>2]<<2)>>2];c[r>>2]=0;while(1){if((c[r>>2]|0)>=(c[o>>2]|0))break;g[u>>2]=+g[u>>2]-+g[f+(c[r>>2]<<2)>>2]*+g[h+((c[q>>2]|0)+(c[r>>2]|0)<<2)>>2];c[r>>2]=(c[r>>2]|0)+1}g[h+((c[q>>2]|0)+(c[o>>2]|0)<<2)>>2]=+g[u>>2];g[(c[m>>2]|0)+(c[q>>2]<<2)>>2]=+g[u>>2];c[q>>2]=(c[q>>2]|0)+1}c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;g[(c[p>>2]|0)+(c[q>>2]<<2)>>2]=+g[(c[m>>2]|0)+((c[n>>2]|0)-(c[q>>2]|0)-1<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}ka(c[s>>2]|0);i=j;return}function Bb(a,b,d,e,f,h,j){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0.0;k=i;i=i+64|0;l=k+52|0;m=k+44|0;n=k+24|0;o=k+20|0;p=k+12|0;q=k+40|0;r=k+56|0;s=k+28|0;t=k+8|0;u=k+4|0;v=k+32|0;w=k;x=k+16|0;y=k+36|0;c[l>>2]=a;c[m>>2]=b;c[n>>2]=d;c[o>>2]=e;c[p>>2]=f;c[q>>2]=h;c[k+48>>2]=j;c[u>>2]=(c[q>>2]|0)-(c[p>>2]|0);j=c[q>>2]|0;c[x>>2]=ua()|0;h=i;i=i+((1*(j<<2)|0)+15&-16)|0;if(!(c[o>>2]|0))c[w>>2]=c[l>>2];else{c[s>>2]=0;while(1){if((c[s>>2]|0)>=(c[q>>2]|0))break;g[h+(c[s>>2]<<2)>>2]=+g[(c[l>>2]|0)+(c[s>>2]<<2)>>2];c[s>>2]=(c[s>>2]|0)+1}c[s>>2]=0;while(1){if((c[s>>2]|0)>=(c[o>>2]|0))break;g[h+(c[s>>2]<<2)>>2]=+g[(c[l>>2]|0)+(c[s>>2]<<2)>>2]*+g[(c[n>>2]|0)+(c[s>>2]<<2)>>2];g[h+((c[q>>2]|0)-(c[s>>2]|0)-1<<2)>>2]=+g[(c[l>>2]|0)+((c[q>>2]|0)-(c[s>>2]|0)-1<<2)>>2]*+g[(c[n>>2]|0)+(c[s>>2]<<2)>>2];c[s>>2]=(c[s>>2]|0)+1}c[w>>2]=h}c[v>>2]=0;wb(c[w>>2]|0,c[w>>2]|0,c[m>>2]|0,c[u>>2]|0,(c[p>>2]|0)+1|0);c[t>>2]=0;while(1){if((c[t>>2]|0)>(c[p>>2]|0))break;c[s>>2]=(c[t>>2]|0)+(c[u>>2]|0);g[r>>2]=0.0;while(1){z=+g[r>>2];if((c[s>>2]|0)>=(c[q>>2]|0))break;g[r>>2]=z+ +g[(c[w>>2]|0)+(c[s>>2]<<2)>>2]*+g[(c[w>>2]|0)+((c[s>>2]|0)-(c[t>>2]|0)<<2)>>2];c[s>>2]=(c[s>>2]|0)+1}h=(c[m>>2]|0)+(c[t>>2]<<2)|0;g[h>>2]=+g[h>>2]+z;c[t>>2]=(c[t>>2]|0)+1}t=c[v>>2]|0;c[y>>2]=1;ka(c[x>>2]|0);i=k;return t|0}function Cb(a,b,e,f,h,j,k,l){a=a|0;b=b|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0.0;m=i;i=i+96|0;n=m+36|0;o=m+24|0;p=m+20|0;q=m+72|0;r=m+32|0;s=m+16|0;t=m+52|0;u=m+60|0;v=m+68|0;w=m+76|0;x=m+80|0;y=m+40|0;z=m+8|0;A=m;B=m+4|0;C=m+48|0;D=m+56|0;E=m+28|0;F=m+64|0;G=m+12|0;c[n>>2]=a;c[o>>2]=b;c[p>>2]=e;c[q>>2]=f;c[r>>2]=h;c[s>>2]=j;c[t>>2]=k;c[u>>2]=l;c[v>>2]=2552+((c[u>>2]|0)*84|0)+((c[r>>2]|0)*42|0);c[y>>2]=0;c[y+4>>2]=0;if(c[r>>2]|0){g[z>>2]=0.0;g[A>>2]=.149993896484375}else{g[A>>2]=+g[2904+(c[u>>2]<<2)>>2];g[z>>2]=+g[2888+(c[u>>2]<<2)>>2]}c[B>>2]=c[(c[s>>2]|0)+4>>2]<<3;c[w>>2]=c[o>>2];while(1){if((c[w>>2]|0)>=(c[p>>2]|0))break;c[x>>2]=0;do{c[C>>2]=wd(c[s>>2]|0)|0;do if(((c[B>>2]|0)-(c[C>>2]|0)|0)<15){if(((c[B>>2]|0)-(c[C>>2]|0)|0)>=2){c[D>>2]=jb(c[s>>2]|0,2920,2)|0;c[D>>2]=c[D>>2]>>1^0-(c[D>>2]&1);break}if(((c[B>>2]|0)-(c[C>>2]|0)|0)>=1){c[D>>2]=0-(ib(c[s>>2]|0,1)|0);break}else{c[D>>2]=-1;break}}else{c[G>>2]=((c[w>>2]|0)<20?c[w>>2]|0:20)<<1;c[D>>2]=rb(c[s>>2]|0,(d[(c[v>>2]|0)+(c[G>>2]|0)>>0]|0)<<7,(d[(c[v>>2]|0)+((c[G>>2]|0)+1)>>0]|0)<<6)|0}while(0);g[E>>2]=+(c[D>>2]|0);o=(c[w>>2]|0)+(_(c[x>>2]|0,c[(c[n>>2]|0)+8>>2]|0)|0)|0;if(-9.0>+g[(c[q>>2]|0)+(o<<2)>>2])H=-9.0;else{o=(c[w>>2]|0)+(_(c[x>>2]|0,c[(c[n>>2]|0)+8>>2]|0)|0)|0;H=+g[(c[q>>2]|0)+(o<<2)>>2]}o=(c[w>>2]|0)+(_(c[x>>2]|0,c[(c[n>>2]|0)+8>>2]|0)|0)|0;g[(c[q>>2]|0)+(o<<2)>>2]=H;o=(c[w>>2]|0)+(_(c[x>>2]|0,c[(c[n>>2]|0)+8>>2]|0)|0)|0;g[F>>2]=+g[z>>2]*+g[(c[q>>2]|0)+(o<<2)>>2]+ +g[y+(c[x>>2]<<2)>>2]+ +g[E>>2];o=(c[w>>2]|0)+(_(c[x>>2]|0,c[(c[n>>2]|0)+8>>2]|0)|0)|0;g[(c[q>>2]|0)+(o<<2)>>2]=+g[F>>2];g[y+(c[x>>2]<<2)>>2]=+g[y+(c[x>>2]<<2)>>2]+ +g[E>>2]-+g[A>>2]*+g[E>>2];o=(c[x>>2]|0)+1|0;c[x>>2]=o}while((o|0)<(c[t>>2]|0));c[w>>2]=(c[w>>2]|0)+1}i=m;return}function Db(a,b,d,e,f,h,j){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;k=i;i=i+48|0;l=k+36|0;m=k+16|0;n=k;o=k+28|0;p=k+32|0;q=k+40|0;r=k+12|0;s=k+24|0;t=k+20|0;u=k+8|0;v=k+4|0;c[l>>2]=a;c[m>>2]=b;c[n>>2]=d;c[o>>2]=e;c[p>>2]=f;c[q>>2]=h;c[r>>2]=j;c[s>>2]=c[m>>2];while(1){if((c[s>>2]|0)>=(c[n>>2]|0))break;if((c[(c[p>>2]|0)+(c[s>>2]<<2)>>2]|0)>0){c[t>>2]=0;do{c[u>>2]=lb(c[q>>2]|0,c[(c[p>>2]|0)+(c[s>>2]<<2)>>2]|0)|0;g[v>>2]=(+(c[u>>2]|0)+.5)*+(1<<14-(c[(c[p>>2]|0)+(c[s>>2]<<2)>>2]|0)|0)*.00006103515625-.5;m=(c[s>>2]|0)+(_(c[t>>2]|0,c[(c[l>>2]|0)+8>>2]|0)|0)|0;j=(c[o>>2]|0)+(m<<2)|0;g[j>>2]=+g[j>>2]+ +g[v>>2];j=(c[t>>2]|0)+1|0;c[t>>2]=j}while((j|0)<(c[r>>2]|0))}c[s>>2]=(c[s>>2]|0)+1}i=k;return}function Eb(a,b,d,e,f,h,j,k,l){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;m=i;i=i+64|0;n=m+24|0;o=m+20|0;p=m+44|0;q=m+36|0;r=m+32|0;s=m+40|0;t=m+48|0;u=m+52|0;v=m+8|0;w=m+4|0;x=m+28|0;y=m+12|0;z=m;A=m+16|0;c[n>>2]=a;c[o>>2]=b;c[p>>2]=d;c[q>>2]=e;c[r>>2]=f;c[s>>2]=h;c[t>>2]=j;c[u>>2]=k;c[v>>2]=l;c[x>>2]=0;while(1){if((c[x>>2]|0)>=2)break;c[w>>2]=c[o>>2];while(1){if((c[w>>2]|0)>=(c[p>>2]|0))break;if((c[t>>2]|0)<(c[v>>2]|0))break;if((c[(c[r>>2]|0)+(c[w>>2]<<2)>>2]|0)<8?(c[(c[s>>2]|0)+(c[w>>2]<<2)>>2]|0)==(c[x>>2]|0):0){c[y>>2]=0;do{c[z>>2]=lb(c[u>>2]|0,1)|0;g[A>>2]=(+(c[z>>2]|0)-.5)*+(1<<14-(c[(c[r>>2]|0)+(c[w>>2]<<2)>>2]|0)-1|0)*.00006103515625;l=(c[w>>2]|0)+(_(c[y>>2]|0,c[(c[n>>2]|0)+8>>2]|0)|0)|0;k=(c[q>>2]|0)+(l<<2)|0;g[k>>2]=+g[k>>2]+ +g[A>>2];c[t>>2]=(c[t>>2]|0)+-1;k=(c[y>>2]|0)+1|0;c[y>>2]=k}while((k|0)<(c[v>>2]|0))}c[w>>2]=(c[w>>2]|0)+1}c[x>>2]=(c[x>>2]|0)+1}i=m;return}function Fb(a,e,f,g,h,j,k,l,m,n,o,p,q,r,s,t,u,v,w){a=a|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;p=p|0;q=q|0;r=r|0;s=s|0;t=t|0;u=u|0;v=v|0;w=w|0;var x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0;x=i;i=i+160|0;y=x+72|0;z=x+56|0;A=x+4|0;B=x+52|0;C=x+140|0;D=x+68|0;E=x+20|0;F=x+24|0;G=x+28|0;H=x+32|0;I=x+36|0;J=x+40|0;K=x+44|0;L=x+48|0;M=x+112|0;N=x+120|0;O=x+128|0;P=x+136|0;Q=x+144|0;R=x+148|0;S=x+76|0;T=x+80|0;U=x+84|0;V=x+88|0;W=x+92|0;X=x+96|0;Y=x+100|0;Z=x+104|0;$=x+12|0;aa=x;ba=x+8|0;ca=x+108|0;da=x+116|0;ea=x+60|0;fa=x+124|0;ga=x+16|0;ha=x+64|0;ia=x+132|0;c[y>>2]=a;c[z>>2]=e;c[A>>2]=f;c[B>>2]=g;c[C>>2]=h;c[D>>2]=j;c[E>>2]=k;c[F>>2]=l;c[G>>2]=m;c[H>>2]=n;c[I>>2]=o;c[J>>2]=p;c[K>>2]=q;c[L>>2]=r;c[M>>2]=s;c[N>>2]=t;c[O>>2]=u;c[P>>2]=v;c[Q>>2]=w;c[G>>2]=(c[G>>2]|0)>0?c[G>>2]|0:0;c[T>>2]=c[(c[y>>2]|0)+8>>2];c[W>>2]=c[z>>2];c[X>>2]=(c[G>>2]|0)>=8?8:0;c[G>>2]=(c[G>>2]|0)-(c[X>>2]|0);c[Z>>2]=0;c[Y>>2]=0;do if((c[L>>2]|0)==2){c[Y>>2]=d[2928+((c[A>>2]|0)-(c[z>>2]|0))>>0];if((c[Y>>2]|0)>(c[G>>2]|0)){c[Y>>2]=0;break}else{c[G>>2]=(c[G>>2]|0)-(c[Y>>2]|0);c[Z>>2]=(c[G>>2]|0)>=8?8:0;c[G>>2]=(c[G>>2]|0)-(c[Z>>2]|0);break}}while(0);w=c[T>>2]|0;c[$>>2]=ua()|0;v=i;i=i+((1*(w<<2)|0)+15&-16)|0;w=i;i=i+((1*(c[T>>2]<<2)|0)+15&-16)|0;u=i;i=i+((1*(c[T>>2]<<2)|0)+15&-16)|0;t=i;i=i+((1*(c[T>>2]<<2)|0)+15&-16)|0;c[U>>2]=c[z>>2];while(1){if((c[U>>2]|0)>=(c[A>>2]|0))break;if((c[L>>2]<<3|0)>(((b[(c[(c[y>>2]|0)+32>>2]|0)+((c[U>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[y>>2]|0)+32>>2]|0)+(c[U>>2]<<1)>>1]|0)|0)*3<<c[M>>2]<<3>>4|0))ja=c[L>>2]<<3;else ja=((b[(c[(c[y>>2]|0)+32>>2]|0)+((c[U>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[y>>2]|0)+32>>2]|0)+(c[U>>2]<<1)>>1]|0)|0)*3<<c[M>>2]<<3>>4;c[u+(c[U>>2]<<2)>>2]=ja;s=_(c[L>>2]|0,(b[(c[(c[y>>2]|0)+32>>2]|0)+((c[U>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[y>>2]|0)+32>>2]|0)+(c[U>>2]<<1)>>1]|0)|0)|0;r=_(s,(c[D>>2]|0)-5-(c[M>>2]|0)|0)|0;s=_(r,(c[A>>2]|0)-(c[U>>2]|0)-1|0)|0;r=(_(s,1<<(c[M>>2]|0)+3)|0)>>6;c[t+(c[U>>2]<<2)>>2]=r;if(((b[(c[(c[y>>2]|0)+32>>2]|0)+((c[U>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[y>>2]|0)+32>>2]|0)+(c[U>>2]<<1)>>1]|0)<<c[M>>2]|0)==1){r=t+(c[U>>2]<<2)|0;c[r>>2]=(c[r>>2]|0)-(c[L>>2]<<3)}c[U>>2]=(c[U>>2]|0)+1}c[R>>2]=1;c[S>>2]=(c[(c[y>>2]|0)+48>>2]|0)-1;do{c[aa>>2]=0;c[ba>>2]=0;c[ca>>2]=(c[R>>2]|0)+(c[S>>2]|0)>>1;c[U>>2]=c[A>>2];while(1){D=c[U>>2]|0;c[U>>2]=D+-1;if((D|0)<=(c[z>>2]|0))break;c[ea>>2]=(b[(c[(c[y>>2]|0)+32>>2]|0)+((c[U>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[y>>2]|0)+32>>2]|0)+(c[U>>2]<<1)>>1]|0);D=_(c[L>>2]|0,c[ea>>2]|0)|0;ja=_(c[ca>>2]|0,c[T>>2]|0)|0;r=_(D,d[(c[(c[y>>2]|0)+52>>2]|0)+(ja+(c[U>>2]|0))>>0]|0)|0;c[da>>2]=r<<c[M>>2]>>2;if((c[da>>2]|0)>0){if(0>((c[da>>2]|0)+(c[t+(c[U>>2]<<2)>>2]|0)|0))la=0;else la=(c[da>>2]|0)+(c[t+(c[U>>2]<<2)>>2]|0)|0;c[da>>2]=la}c[da>>2]=(c[da>>2]|0)+(c[(c[B>>2]|0)+(c[U>>2]<<2)>>2]|0);if(!((c[aa>>2]|0)!=0?1:(c[da>>2]|0)>=(c[u+(c[U>>2]<<2)>>2]|0))){if((c[da>>2]|0)<(c[L>>2]<<3|0))continue;c[ba>>2]=(c[ba>>2]|0)+(c[L>>2]<<3);continue}c[aa>>2]=1;if((c[da>>2]|0)<(c[(c[C>>2]|0)+(c[U>>2]<<2)>>2]|0))ma=c[da>>2]|0;else ma=c[(c[C>>2]|0)+(c[U>>2]<<2)>>2]|0;c[ba>>2]=(c[ba>>2]|0)+ma}r=c[ca>>2]|0;if((c[ba>>2]|0)>(c[G>>2]|0))c[S>>2]=r-1;else c[R>>2]=r+1}while((c[R>>2]|0)<=(c[S>>2]|0));ba=c[R>>2]|0;c[R>>2]=ba+-1;c[S>>2]=ba;c[U>>2]=c[z>>2];while(1){if((c[U>>2]|0)>=(c[A>>2]|0))break;c[ha>>2]=(b[(c[(c[y>>2]|0)+32>>2]|0)+((c[U>>2]|0)+1<<1)>>1]|0)-(b[(c[(c[y>>2]|0)+32>>2]|0)+(c[U>>2]<<1)>>1]|0);ba=_(c[L>>2]|0,c[ha>>2]|0)|0;ca=_(c[R>>2]|0,c[T>>2]|0)|0;ma=_(ba,d[(c[(c[y>>2]|0)+52>>2]|0)+(ca+(c[U>>2]|0))>>0]|0)|0;c[fa>>2]=ma<<c[M>>2]>>2;if((c[S>>2]|0)>=(c[(c[y>>2]|0)+48>>2]|0))na=c[(c[C>>2]|0)+(c[U>>2]<<2)>>2]|0;else{ma=_(c[L>>2]|0,c[ha>>2]|0)|0;ca=_(c[S>>2]|0,c[T>>2]|0)|0;ba=_(ma,d[(c[(c[y>>2]|0)+52>>2]|0)+(ca+(c[U>>2]|0))>>0]|0)|0;na=ba<<c[M>>2]>>2}c[ga>>2]=na;if((c[fa>>2]|0)>0){if(0>((c[fa>>2]|0)+(c[t+(c[U>>2]<<2)>>2]|0)|0))oa=0;else oa=(c[fa>>2]|0)+(c[t+(c[U>>2]<<2)>>2]|0)|0;c[fa>>2]=oa}if((c[ga>>2]|0)>0){if(0>((c[ga>>2]|0)+(c[t+(c[U>>2]<<2)>>2]|0)|0))pa=0;else pa=(c[ga>>2]|0)+(c[t+(c[U>>2]<<2)>>2]|0)|0;c[ga>>2]=pa}if((c[R>>2]|0)>0)c[fa>>2]=(c[fa>>2]|0)+(c[(c[B>>2]|0)+(c[U>>2]<<2)>>2]|0);c[ga>>2]=(c[ga>>2]|0)+(c[(c[B>>2]|0)+(c[U>>2]<<2)>>2]|0);if((c[(c[B>>2]|0)+(c[U>>2]<<2)>>2]|0)>0)c[W>>2]=c[U>>2];if(0>((c[ga>>2]|0)-(c[fa>>2]|0)|0))qa=0;else qa=(c[ga>>2]|0)-(c[fa>>2]|0)|0;c[ga>>2]=qa;c[v+(c[U>>2]<<2)>>2]=c[fa>>2];c[w+(c[U>>2]<<2)>>2]=c[ga>>2];c[U>>2]=(c[U>>2]|0)+1}c[V>>2]=xd(c[y>>2]|0,c[z>>2]|0,c[A>>2]|0,c[W>>2]|0,v,w,u,c[C>>2]|0,c[G>>2]|0,c[H>>2]|0,c[X>>2]|0,c[E>>2]|0,c[Y>>2]|0,c[F>>2]|0,c[Z>>2]|0,c[I>>2]|0,c[J>>2]|0,c[K>>2]|0,c[L>>2]|0,c[M>>2]|0,c[N>>2]|0,c[O>>2]|0,c[P>>2]|0,c[Q>>2]|0)|0;Q=c[V>>2]|0;c[ia>>2]=1;ka(c[$>>2]|0);i=x;return Q|0}function Gb(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0;j=i;i=i+96|0;k=j+84|0;l=j;m=j+4|0;n=j+40|0;o=j+76|0;p=j+16|0;q=j+20|0;r=j+24|0;s=j+64|0;t=j+72|0;u=j+80|0;v=j+88|0;w=j+44|0;x=j+48|0;y=j+52|0;z=j+8|0;A=j+56|0;B=j+28|0;C=j+60|0;D=j+12|0;E=j+32|0;F=j+68|0;G=j+36|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;h=c[l>>2]|0;c[y>>2]=ua()|0;f=i;i=i+((1*(h<<2)|0)+15&-16)|0;h=i;i=i+((1*(c[l>>2]<<2)|0)+15&-16)|0;e=i;i=i+((1*(c[l>>2]<<2)|0)+15&-16)|0;yd(c[k>>2]|0,c[l>>2]|0,1,c[o>>2]|0,c[m>>2]|0,c[n>>2]|0);g[u>>2]=0.0;c[r>>2]=0;do{n=e+(c[r>>2]<<2)|0;if(+g[(c[k>>2]|0)+(c[r>>2]<<2)>>2]>0.0)g[n>>2]=1.0;else{g[n>>2]=-1.0;g[(c[k>>2]|0)+(c[r>>2]<<2)>>2]=-+g[(c[k>>2]|0)+(c[r>>2]<<2)>>2]}c[h+(c[r>>2]<<2)>>2]=0;g[f+(c[r>>2]<<2)>>2]=0.0;n=(c[r>>2]|0)+1|0;c[r>>2]=n}while((n|0)<(c[l>>2]|0));g[w>>2]=0.0;g[v>>2]=0.0;c[t>>2]=c[m>>2];if((c[m>>2]|0)>(c[l>>2]>>1|0)){c[r>>2]=0;do{g[u>>2]=+g[u>>2]+ +g[(c[k>>2]|0)+(c[r>>2]<<2)>>2];n=(c[r>>2]|0)+1|0;c[r>>2]=n}while((n|0)<(c[l>>2]|0));if(!(+g[u>>2]>1.0000000036274937e-15&+g[u>>2]<64.0)){g[c[k>>2]>>2]=1.0;c[r>>2]=1;do{g[(c[k>>2]|0)+(c[r>>2]<<2)>>2]=0.0;n=(c[r>>2]|0)+1|0;c[r>>2]=n}while((n|0)<(c[l>>2]|0));g[u>>2]=1.0}g[z>>2]=+((c[m>>2]|0)-1|0)*(1.0/+g[u>>2]);c[r>>2]=0;do{u=~~+M(+(+g[z>>2]*+g[(c[k>>2]|0)+(c[r>>2]<<2)>>2]));c[h+(c[r>>2]<<2)>>2]=u;g[f+(c[r>>2]<<2)>>2]=+(c[h+(c[r>>2]<<2)>>2]|0);g[w>>2]=+g[w>>2]+ +g[f+(c[r>>2]<<2)>>2]*+g[f+(c[r>>2]<<2)>>2];g[v>>2]=+g[v>>2]+ +g[(c[k>>2]|0)+(c[r>>2]<<2)>>2]*+g[f+(c[r>>2]<<2)>>2];u=f+(c[r>>2]<<2)|0;g[u>>2]=+g[u>>2]*2.0;c[t>>2]=(c[t>>2]|0)-(c[h+(c[r>>2]<<2)>>2]|0);u=(c[r>>2]|0)+1|0;c[r>>2]=u}while((u|0)<(c[l>>2]|0))}if((c[t>>2]|0)>((c[l>>2]|0)+3|0)){g[A>>2]=+(c[t>>2]|0);g[w>>2]=+g[w>>2]+ +g[A>>2]*+g[A>>2];g[w>>2]=+g[w>>2]+ +g[A>>2]*+g[f>>2];c[h>>2]=(c[h>>2]|0)+(c[t>>2]|0);c[t>>2]=0}g[s>>2]=1.0;c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[t>>2]|0))break;g[C>>2]=-999999986991104.0;g[D>>2]=0.0;c[B>>2]=0;g[w>>2]=+g[w>>2]+1.0;c[r>>2]=0;do{g[E>>2]=+g[v>>2]+ +g[(c[k>>2]|0)+(c[r>>2]<<2)>>2];g[F>>2]=+g[w>>2]+ +g[f+(c[r>>2]<<2)>>2];g[E>>2]=+g[E>>2]*+g[E>>2];if(+g[D>>2]*+g[E>>2]>+g[F>>2]*+g[C>>2]){g[D>>2]=+g[F>>2];g[C>>2]=+g[E>>2];c[B>>2]=c[r>>2]}A=(c[r>>2]|0)+1|0;c[r>>2]=A}while((A|0)<(c[l>>2]|0));g[v>>2]=+g[v>>2]+ +g[(c[k>>2]|0)+(c[B>>2]<<2)>>2];g[w>>2]=+g[w>>2]+ +g[f+(c[B>>2]<<2)>>2];A=f+(c[B>>2]<<2)|0;g[A>>2]=+g[A>>2]+ +g[s>>2]*2.0;A=h+(c[B>>2]<<2)|0;c[A>>2]=(c[A>>2]|0)+1;c[q>>2]=(c[q>>2]|0)+1}c[r>>2]=0;do{g[(c[k>>2]|0)+(c[r>>2]<<2)>>2]=+g[e+(c[r>>2]<<2)>>2]*+g[(c[k>>2]|0)+(c[r>>2]<<2)>>2];if(+g[e+(c[r>>2]<<2)>>2]<0.0)c[h+(c[r>>2]<<2)>>2]=0-(c[h+(c[r>>2]<<2)>>2]|0);q=(c[r>>2]|0)+1|0;c[r>>2]=q}while((q|0)<(c[l>>2]|0));bb(h,c[l>>2]|0,c[m>>2]|0,c[p>>2]|0);c[x>>2]=zd(h,c[l>>2]|0,c[o>>2]|0)|0;o=c[x>>2]|0;c[G>>2]=1;ka(c[y>>2]|0);i=j;return o|0}function Hb(a,b,d,e,f,h,j){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;j=+j;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;k=i;i=i+48|0;l=k+36|0;m=k+16|0;n=k;o=k+28|0;p=k+32|0;q=k+40|0;r=k+12|0;s=k+24|0;t=k+20|0;u=k+8|0;c[l>>2]=a;c[m>>2]=b;c[n>>2]=d;c[o>>2]=e;c[p>>2]=f;c[q>>2]=h;g[r>>2]=j;h=c[m>>2]|0;c[u>>2]=ua()|0;f=i;i=i+((1*(h<<2)|0)+15&-16)|0;g[s>>2]=+cb(f,c[m>>2]|0,c[n>>2]|0,c[q>>2]|0);Ad(f,c[l>>2]|0,c[m>>2]|0,+g[s>>2],+g[r>>2]);yd(c[l>>2]|0,c[m>>2]|0,-1,c[p>>2]|0,c[n>>2]|0,c[o>>2]|0);c[t>>2]=zd(f,c[m>>2]|0,c[p>>2]|0)|0;p=c[t>>2]|0;c[k+4>>2]=1;ka(c[u>>2]|0);i=k;return p|0}function Ib(a,b,d){a=a|0;b=b|0;d=+d;var e=0,f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;e=i;i=i+32|0;f=e+4|0;h=e+16|0;j=e+8|0;k=e+20|0;l=e+28|0;m=e;n=e+12|0;o=e+24|0;c[f>>2]=a;c[h>>2]=b;g[j>>2]=d;g[l>>2]=+Bd(c[f>>2]|0,c[f>>2]|0,c[h>>2]|0)+1.0000000036274937e-15;g[n>>2]=+g[l>>2];d=1.0/+O(+(+g[n>>2]));g[m>>2]=d*+g[j>>2];c[o>>2]=c[f>>2];c[k>>2]=0;while(1){if((c[k>>2]|0)>=(c[h>>2]|0))break;g[c[o>>2]>>2]=+g[m>>2]*+g[c[o>>2]>>2];c[o>>2]=(c[o>>2]|0)+4;c[k>>2]=(c[k>>2]|0)+1}i=e;return}function Jb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0.0;f=i;i=i+48|0;h=f+4|0;j=f+16|0;k=f+36|0;l=f;m=f+32|0;n=f+40|0;o=f+44|0;p=f+24|0;q=f+20|0;r=f+8|0;s=f+12|0;t=f+28|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;g[r>>2]=1.0000000036274937e-15;g[q>>2]=1.0000000036274937e-15;a:do if(c[k>>2]|0){c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[l>>2]|0))break a;g[s>>2]=+g[(c[h>>2]|0)+(c[m>>2]<<2)>>2]+ +g[(c[j>>2]|0)+(c[m>>2]<<2)>>2];g[t>>2]=+g[(c[h>>2]|0)+(c[m>>2]<<2)>>2]-+g[(c[j>>2]|0)+(c[m>>2]<<2)>>2];g[q>>2]=+g[q>>2]+ +g[s>>2]*+g[s>>2];g[r>>2]=+g[r>>2]+ +g[t>>2]*+g[t>>2];c[m>>2]=(c[m>>2]|0)+1}}else{u=+Bd(c[h>>2]|0,c[h>>2]|0,c[l>>2]|0);g[q>>2]=+g[q>>2]+u;u=+Bd(c[j>>2]|0,c[j>>2]|0,c[l>>2]|0);g[r>>2]=+g[r>>2]+u}while(0);g[o>>2]=+O(+(+g[q>>2]));g[p>>2]=+O(+(+g[r>>2]));c[n>>2]=~~+M(+(+W(+(+g[p>>2]),+(+g[o>>2]))*10430.3818359375+.5));i=f;return c[n>>2]|0}function Kb(a){a=a|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[e>>2]=a;c[g>>2]=32767/((c[(c[e>>2]|0)+2340>>2]|0)+1|0)|0;c[h>>2]=0;c[f>>2]=0;while(1){if((c[f>>2]|0)>=(c[(c[e>>2]|0)+2340>>2]|0))break;c[h>>2]=(c[h>>2]|0)+(c[g>>2]|0);b[(c[e>>2]|0)+2772+1280+(c[f>>2]<<1)>>1]=c[h>>2];c[f>>2]=(c[f>>2]|0)+1}c[(c[e>>2]|0)+2772+1376>>2]=0;c[(c[e>>2]|0)+2772+1380>>2]=3176576;i=d;return}function Lb(a,d,e,f){a=a|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;g=i;i=i+80|0;h=g;j=g+16|0;k=g+4|0;l=g+8|0;m=g+32|0;n=g+36|0;o=g+12|0;p=g+24|0;q=g+40|0;r=g+28|0;s=g+20|0;c[h>>2]=a;c[j>>2]=d;c[k>>2]=e;c[l>>2]=f;c[r>>2]=(c[h>>2]|0)+2772;if((c[(c[h>>2]|0)+2316>>2]|0)!=(c[(c[r>>2]|0)+1384>>2]|0)){Kb(c[h>>2]|0);c[(c[r>>2]|0)+1384>>2]=c[(c[h>>2]|0)+2316>>2]}a:do if((c[(c[h>>2]|0)+4160>>2]|0)==0?(c[(c[h>>2]|0)+4164>>2]|0)==0:0){c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[(c[h>>2]|0)+2340>>2]|0))break;f=(c[r>>2]|0)+1280+(c[m>>2]<<1)|0;b[f>>1]=(b[f>>1]|0)+((((b[(c[h>>2]|0)+2344+(c[m>>2]<<1)>>1]|0)-(b[(c[r>>2]|0)+1280+(c[m>>2]<<1)>>1]|0)>>16)*16348|0)+(((b[(c[h>>2]|0)+2344+(c[m>>2]<<1)>>1]|0)-(b[(c[r>>2]|0)+1280+(c[m>>2]<<1)>>1]|0)&65535)*16348>>16));c[m>>2]=(c[m>>2]|0)+1}c[p>>2]=0;c[n>>2]=0;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[(c[h>>2]|0)+2324>>2]|0))break;if((c[(c[j>>2]|0)+16+(c[m>>2]<<2)>>2]|0)>(c[p>>2]|0)){c[p>>2]=c[(c[j>>2]|0)+16+(c[m>>2]<<2)>>2];c[n>>2]=c[m>>2]}c[m>>2]=(c[m>>2]|0)+1}ff((c[r>>2]|0)+(c[(c[h>>2]|0)+2332>>2]<<2)|0,c[r>>2]|0,(_((c[(c[h>>2]|0)+2324>>2]|0)-1|0,c[(c[h>>2]|0)+2332>>2]|0)|0)<<2|0)|0;f=_(c[n>>2]|0,c[(c[h>>2]|0)+2332>>2]|0)|0;df(c[r>>2]|0,(c[h>>2]|0)+4+(f<<2)|0,c[(c[h>>2]|0)+2332>>2]<<2|0)|0;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[(c[h>>2]|0)+2324>>2]|0))break a;f=(c[r>>2]|0)+1376|0;c[f>>2]=(c[f>>2]|0)+((((c[(c[j>>2]|0)+16+(c[m>>2]<<2)>>2]|0)-(c[(c[r>>2]|0)+1376>>2]|0)>>16)*4634|0)+(((c[(c[j>>2]|0)+16+(c[m>>2]<<2)>>2]|0)-(c[(c[r>>2]|0)+1376>>2]|0)&65535)*4634>>16));c[m>>2]=(c[m>>2]|0)+1}}while(0);if(!(c[(c[h>>2]|0)+4160>>2]|0)){bf((c[r>>2]|0)+1312|0,0,c[(c[h>>2]|0)+2340>>2]<<2|0)|0;i=g;return}j=(c[l>>2]|0)+16|0;c[s>>2]=ua()|0;n=i;i=i+((1*(j<<2)|0)+15&-16)|0;Cd(n+64|0,c[r>>2]|0,c[(c[r>>2]|0)+1376>>2]|0,c[l>>2]|0,(c[r>>2]|0)+1380|0);jc(q,(c[r>>2]|0)+1280|0,c[(c[h>>2]|0)+2340>>2]|0);j=n;p=(c[r>>2]|0)+1312|0;f=j+64|0;do{c[j>>2]=c[p>>2];j=j+4|0;p=p+4|0}while((j|0)<(f|0));c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[l>>2]|0))break;c[o>>2]=c[(c[h>>2]|0)+2340>>2]>>1;e=_(c[n+(16+(c[m>>2]|0)-1<<2)>>2]>>16,b[q>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-1<<2)>>2]&65535,b[q>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-2<<2)>>2]>>16,b[q+2>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-2<<2)>>2]&65535,b[q+2>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-3<<2)>>2]>>16,b[q+4>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-3<<2)>>2]&65535,b[q+4>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-4<<2)>>2]>>16,b[q+6>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-4<<2)>>2]&65535,b[q+6>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-5<<2)>>2]>>16,b[q+8>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-5<<2)>>2]&65535,b[q+8>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-6<<2)>>2]>>16,b[q+10>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-6<<2)>>2]&65535,b[q+10>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-7<<2)>>2]>>16,b[q+12>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-7<<2)>>2]&65535,b[q+12>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-8<<2)>>2]>>16,b[q+14>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-8<<2)>>2]&65535,b[q+14>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-9<<2)>>2]>>16,b[q+16>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-9<<2)>>2]&65535,b[q+16>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-10<<2)>>2]>>16,b[q+18>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-10<<2)>>2]&65535,b[q+18>>1]|0)|0)>>16));if((c[(c[h>>2]|0)+2340>>2]|0)==16){e=_(c[n+(16+(c[m>>2]|0)-11<<2)>>2]>>16,b[q+20>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-11<<2)>>2]&65535,b[q+20>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-12<<2)>>2]>>16,b[q+22>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-12<<2)>>2]&65535,b[q+22>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-13<<2)>>2]>>16,b[q+24>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-13<<2)>>2]&65535,b[q+24>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-14<<2)>>2]>>16,b[q+26>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-14<<2)>>2]&65535,b[q+26>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-15<<2)>>2]>>16,b[q+28>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-15<<2)>>2]&65535,b[q+28>>1]|0)|0)>>16));e=_(c[n+(16+(c[m>>2]|0)-16<<2)>>2]>>16,b[q+30>>1]|0)|0;c[o>>2]=(c[o>>2]|0)+(e+((_(c[n+(16+(c[m>>2]|0)-16<<2)>>2]&65535,b[q+30>>1]|0)|0)>>16))}c[n+(16+(c[m>>2]|0)<<2)>>2]=(c[n+(16+(c[m>>2]|0)<<2)>>2]|0)+(c[o>>2]<<4);if(((b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]|0)+((c[o>>2]>>5)+1>>1)|0)<=32767)if(((b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]|0)+((c[o>>2]>>5)+1>>1)|0)<-32768)t=-32768;else t=(b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]|0)+((c[o>>2]>>5)+1>>1)|0;else t=32767;b[(c[k>>2]|0)+(c[m>>2]<<1)>>1]=t;c[m>>2]=(c[m>>2]|0)+1}j=(c[r>>2]|0)+1312|0;p=n+(c[l>>2]<<2)|0;f=j+64|0;do{c[j>>2]=c[p>>2];j=j+4|0;p=p+4|0}while((j|0)<(f|0));ka(c[s>>2]|0);i=g;return}function Mb(d,e,f,g,h,j){d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;k=i;i=i+48|0;l=k+12|0;m=k+16|0;n=k+28|0;o=k+4|0;p=k+32|0;q=k+36|0;r=k+40|0;s=k+24|0;t=k+20|0;u=k+44|0;v=k;w=k+8|0;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;c[o>>2]=g;c[p>>2]=h;c[q>>2]=j;a[u+1>>0]=0;c[v>>2]=c[m>>2];c[r>>2]=(((c[p>>2]|0)+(c[o>>2]<<1)&65535)<<16>>16)*7;c[w>>2]=1496+(c[r>>2]|0);c[n>>2]=(c[n>>2]|0)+8>>4;c[r>>2]=0;while(1){if((c[r>>2]|0)>=(c[n>>2]|0))break;c[t>>2]=c[(c[q>>2]|0)+(c[r>>2]<<2)>>2];a:do if((c[t>>2]|0)>0){a[u>>0]=a[(c[w>>2]|0)+((c[t>>2]&31|0)<6?c[t>>2]&31:6)>>0]|0;c[s>>2]=0;while(1){if((c[s>>2]|0)>=16)break a;if((b[(c[v>>2]|0)+(c[s>>2]<<1)>>1]|0)>0){o=((jb(c[l>>2]|0,u,8)|0)<<1)-1|0;p=(c[v>>2]|0)+(c[s>>2]<<1)|0;b[p>>1]=_(b[p>>1]|0,o)|0}c[s>>2]=(c[s>>2]|0)+1}}while(0);c[v>>2]=(c[v>>2]|0)+32;c[r>>2]=(c[r>>2]|0)+1}i=k;return}function Nb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;bf(c[d>>2]|0,0,4260)|0;c[(c[d>>2]|0)+2376>>2]=1;c[c[d>>2]>>2]=65536;Kb(c[d>>2]|0);Zb(c[d>>2]|0);i=b;return 0}function Ob(d,e,f,g){d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;h=i;i=i+144|0;j=h+48|0;k=h+40|0;l=h;m=h+84|0;n=h+4|0;o=h+16|0;p=h+20|0;q=h+24|0;r=h+28|0;s=h+72|0;t=h+80|0;u=h+88|0;v=h+92|0;w=h+96|0;x=h+104|0;y=h+56|0;z=h+60|0;A=h+8|0;B=h+64|0;C=h+12|0;D=h+32|0;E=h+68|0;F=h+36|0;G=h+76|0;H=h+44|0;I=h+52|0;c[j>>2]=d;c[k>>2]=e;c[l>>2]=f;c[m>>2]=g;c[p>>2]=0;g=c[(c[j>>2]|0)+2336>>2]|0;c[I>>2]=ua()|0;f=i;i=i+((1*(g<<1)|0)+15&-16)|0;g=i;i=i+((1*((c[(c[j>>2]|0)+2336>>2]|0)+(c[(c[j>>2]|0)+2328>>2]|0)<<2)|0)+15&-16)|0;e=i;i=i+((1*(c[(c[j>>2]|0)+2332>>2]<<2)|0)+15&-16)|0;d=i;i=i+((1*((c[(c[j>>2]|0)+2332>>2]|0)+16<<2)|0)+15&-16)|0;c[E>>2]=b[456+(a[(c[j>>2]|0)+2736+29>>0]>>1<<2)+(a[(c[j>>2]|0)+2736+30>>0]<<1)>>1];if((a[(c[j>>2]|0)+2736+31>>0]|0)<4)c[s>>2]=1;else c[s>>2]=0;c[D>>2]=a[(c[j>>2]|0)+2736+34>>0];c[n>>2]=0;while(1){if((c[n>>2]|0)>=(c[(c[j>>2]|0)+2328>>2]|0))break;c[D>>2]=907633515+(_(c[D>>2]|0,196314165)|0);c[(c[j>>2]|0)+4+(c[n>>2]<<2)>>2]=b[(c[m>>2]|0)+(c[n>>2]<<1)>>1]<<14;J=(c[j>>2]|0)+4+(c[n>>2]<<2)|0;K=c[J>>2]|0;if((c[(c[j>>2]|0)+4+(c[n>>2]<<2)>>2]|0)<=0){if((K|0)<0){L=(c[j>>2]|0)+4+(c[n>>2]<<2)|0;c[L>>2]=(c[L>>2]|0)+1280}}else c[J>>2]=K-1280;K=(c[j>>2]|0)+4+(c[n>>2]<<2)|0;c[K>>2]=(c[K>>2]|0)+(c[E>>2]<<4);if((c[D>>2]|0)<0)c[(c[j>>2]|0)+4+(c[n>>2]<<2)>>2]=0-(c[(c[j>>2]|0)+4+(c[n>>2]<<2)>>2]|0);c[D>>2]=(c[D>>2]|0)+(b[(c[m>>2]|0)+(c[n>>2]<<1)>>1]|0);c[n>>2]=(c[n>>2]|0)+1}m=d;D=(c[j>>2]|0)+1284|0;E=m+64|0;do{c[m>>2]=c[D>>2];m=m+4|0;D=D+4|0}while((m|0)<(E|0));c[G>>2]=(c[j>>2]|0)+4;c[w>>2]=c[l>>2];c[r>>2]=c[(c[j>>2]|0)+2336>>2];c[o>>2]=0;while(1){if((c[o>>2]|0)>=(c[(c[j>>2]|0)+2324>>2]|0))break;c[H>>2]=e;c[u>>2]=(c[k>>2]|0)+32+(c[o>>2]>>1<<5);df(x|0,c[u>>2]|0,c[(c[j>>2]|0)+2340>>2]<<1|0)|0;c[v>>2]=(c[k>>2]|0)+96+((c[o>>2]|0)*5<<1);c[t>>2]=a[(c[j>>2]|0)+2736+29>>0];c[A>>2]=c[(c[k>>2]|0)+16+(c[o>>2]<<2)>>2]>>6;c[B>>2]=Dd(c[(c[k>>2]|0)+16+(c[o>>2]<<2)>>2]|0,47)|0;a:do if((c[(c[k>>2]|0)+16+(c[o>>2]<<2)>>2]|0)!=(c[c[j>>2]>>2]|0)){c[C>>2]=Ed(c[c[j>>2]>>2]|0,c[(c[k>>2]|0)+16+(c[o>>2]<<2)>>2]|0,16)|0;c[n>>2]=0;while(1){if((c[n>>2]|0)>=16)break a;K=_(c[C>>2]>>16,(c[d+(c[n>>2]<<2)>>2]&65535)<<16>>16)|0;J=K+((_(c[C>>2]&65535,(c[d+(c[n>>2]<<2)>>2]&65535)<<16>>16)|0)>>16)|0;K=J+(_(c[C>>2]|0,(c[d+(c[n>>2]<<2)>>2]>>15)+1>>1)|0)|0;c[d+(c[n>>2]<<2)>>2]=K;c[n>>2]=(c[n>>2]|0)+1}}else c[C>>2]=65536;while(0);c[c[j>>2]>>2]=c[(c[k>>2]|0)+16+(c[o>>2]<<2)>>2];if(((c[(c[j>>2]|0)+4160>>2]|0)!=0?(c[(c[j>>2]|0)+4164>>2]|0)==2:0)?((c[o>>2]|0)<2?(a[(c[j>>2]|0)+2736+29>>0]|0)!=2:0):0){K=c[v>>2]|0;b[K>>1]=0;b[K+2>>1]=0;b[K+4>>1]=0;b[K+6>>1]=0;b[K+8>>1]=0;b[(c[v>>2]|0)+4>>1]=4096;c[t>>2]=2;c[(c[k>>2]|0)+(c[o>>2]<<2)>>2]=c[(c[j>>2]|0)+2308>>2]}b:do if((c[t>>2]|0)==2){c[p>>2]=c[(c[k>>2]|0)+(c[o>>2]<<2)>>2];if((c[o>>2]|0)!=0?!((c[o>>2]|0)==2&(c[s>>2]|0)!=0):0){if((c[C>>2]|0)==65536)break;c[n>>2]=0;while(1){if((c[n>>2]|0)>=((c[p>>2]|0)+2|0))break b;K=_(c[C>>2]>>16,(c[g+((c[r>>2]|0)-(c[n>>2]|0)-1<<2)>>2]&65535)<<16>>16)|0;J=K+((_(c[C>>2]&65535,(c[g+((c[r>>2]|0)-(c[n>>2]|0)-1<<2)>>2]&65535)<<16>>16)|0)>>16)|0;K=J+(_(c[C>>2]|0,(c[g+((c[r>>2]|0)-(c[n>>2]|0)-1<<2)>>2]>>15)+1>>1)|0)|0;c[g+((c[r>>2]|0)-(c[n>>2]|0)-1<<2)>>2]=K;c[n>>2]=(c[n>>2]|0)+1}}c[q>>2]=(c[(c[j>>2]|0)+2336>>2]|0)-(c[p>>2]|0)-(c[(c[j>>2]|0)+2340>>2]|0)-2;if((c[o>>2]|0)==2)df((c[j>>2]|0)+1348+(c[(c[j>>2]|0)+2336>>2]<<1)|0,c[l>>2]|0,c[(c[j>>2]|0)+2332>>2]<<1<<1|0)|0;K=(c[q>>2]|0)+(_(c[o>>2]|0,c[(c[j>>2]|0)+2332>>2]|0)|0)|0;hc(f+(c[q>>2]<<1)|0,(c[j>>2]|0)+1348+(K<<1)|0,c[u>>2]|0,(c[(c[j>>2]|0)+2336>>2]|0)-(c[q>>2]|0)|0,c[(c[j>>2]|0)+2340>>2]|0);if(!(c[o>>2]|0)){K=_(c[B>>2]>>16,(c[(c[k>>2]|0)+136>>2]&65535)<<16>>16)|0;c[B>>2]=K+((_(c[B>>2]&65535,(c[(c[k>>2]|0)+136>>2]&65535)<<16>>16)|0)>>16)<<2}c[n>>2]=0;while(1){if((c[n>>2]|0)>=((c[p>>2]|0)+2|0))break b;K=_(c[B>>2]>>16,b[f+((c[(c[j>>2]|0)+2336>>2]|0)-(c[n>>2]|0)-1<<1)>>1]|0)|0;J=K+((_(c[B>>2]&65535,b[f+((c[(c[j>>2]|0)+2336>>2]|0)-(c[n>>2]|0)-1<<1)>>1]|0)|0)>>16)|0;c[g+((c[r>>2]|0)-(c[n>>2]|0)-1<<2)>>2]=J;c[n>>2]=(c[n>>2]|0)+1}}while(0);c:do if((c[t>>2]|0)==2){c[F>>2]=g+((c[r>>2]|0)-(c[p>>2]|0)+2<<2);c[n>>2]=0;while(1){if((c[n>>2]|0)>=(c[(c[j>>2]|0)+2332>>2]|0))break c;c[y>>2]=2;J=_(c[c[F>>2]>>2]>>16,b[c[v>>2]>>1]|0)|0;c[y>>2]=(c[y>>2]|0)+(J+((_(c[c[F>>2]>>2]&65535,b[c[v>>2]>>1]|0)|0)>>16));J=_(c[(c[F>>2]|0)+-4>>2]>>16,b[(c[v>>2]|0)+2>>1]|0)|0;c[y>>2]=(c[y>>2]|0)+(J+((_(c[(c[F>>2]|0)+-4>>2]&65535,b[(c[v>>2]|0)+2>>1]|0)|0)>>16));J=_(c[(c[F>>2]|0)+-8>>2]>>16,b[(c[v>>2]|0)+4>>1]|0)|0;c[y>>2]=(c[y>>2]|0)+(J+((_(c[(c[F>>2]|0)+-8>>2]&65535,b[(c[v>>2]|0)+4>>1]|0)|0)>>16));J=_(c[(c[F>>2]|0)+-12>>2]>>16,b[(c[v>>2]|0)+6>>1]|0)|0;c[y>>2]=(c[y>>2]|0)+(J+((_(c[(c[F>>2]|0)+-12>>2]&65535,b[(c[v>>2]|0)+6>>1]|0)|0)>>16));J=_(c[(c[F>>2]|0)+-16>>2]>>16,b[(c[v>>2]|0)+8>>1]|0)|0;c[y>>2]=(c[y>>2]|0)+(J+((_(c[(c[F>>2]|0)+-16>>2]&65535,b[(c[v>>2]|0)+8>>1]|0)|0)>>16));c[F>>2]=(c[F>>2]|0)+4;c[(c[H>>2]|0)+(c[n>>2]<<2)>>2]=(c[(c[G>>2]|0)+(c[n>>2]<<2)>>2]|0)+(c[y>>2]<<1);c[g+(c[r>>2]<<2)>>2]=c[(c[H>>2]|0)+(c[n>>2]<<2)>>2]<<1;c[r>>2]=(c[r>>2]|0)+1;c[n>>2]=(c[n>>2]|0)+1}}else c[H>>2]=c[G>>2];while(0);c[n>>2]=0;while(1){if((c[n>>2]|0)>=(c[(c[j>>2]|0)+2332>>2]|0))break;c[z>>2]=c[(c[j>>2]|0)+2340>>2]>>1;J=_(c[d+(16+(c[n>>2]|0)-1<<2)>>2]>>16,b[x>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-1<<2)>>2]&65535,b[x>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-2<<2)>>2]>>16,b[x+2>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-2<<2)>>2]&65535,b[x+2>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-3<<2)>>2]>>16,b[x+4>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-3<<2)>>2]&65535,b[x+4>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-4<<2)>>2]>>16,b[x+6>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-4<<2)>>2]&65535,b[x+6>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-5<<2)>>2]>>16,b[x+8>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-5<<2)>>2]&65535,b[x+8>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-6<<2)>>2]>>16,b[x+10>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-6<<2)>>2]&65535,b[x+10>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-7<<2)>>2]>>16,b[x+12>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-7<<2)>>2]&65535,b[x+12>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-8<<2)>>2]>>16,b[x+14>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-8<<2)>>2]&65535,b[x+14>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-9<<2)>>2]>>16,b[x+16>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-9<<2)>>2]&65535,b[x+16>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-10<<2)>>2]>>16,b[x+18>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-10<<2)>>2]&65535,b[x+18>>1]|0)|0)>>16));if((c[(c[j>>2]|0)+2340>>2]|0)==16){J=_(c[d+(16+(c[n>>2]|0)-11<<2)>>2]>>16,b[x+20>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-11<<2)>>2]&65535,b[x+20>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-12<<2)>>2]>>16,b[x+22>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-12<<2)>>2]&65535,b[x+22>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-13<<2)>>2]>>16,b[x+24>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-13<<2)>>2]&65535,b[x+24>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-14<<2)>>2]>>16,b[x+26>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-14<<2)>>2]&65535,b[x+26>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-15<<2)>>2]>>16,b[x+28>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-15<<2)>>2]&65535,b[x+28>>1]|0)|0)>>16));J=_(c[d+(16+(c[n>>2]|0)-16<<2)>>2]>>16,b[x+30>>1]|0)|0;c[z>>2]=(c[z>>2]|0)+(J+((_(c[d+(16+(c[n>>2]|0)-16<<2)>>2]&65535,b[x+30>>1]|0)|0)>>16))}c[d+(16+(c[n>>2]|0)<<2)>>2]=(c[(c[H>>2]|0)+(c[n>>2]<<2)>>2]|0)+(c[z>>2]<<4);J=_(c[d+(16+(c[n>>2]|0)<<2)>>2]>>16,(c[A>>2]&65535)<<16>>16)|0;K=J+((_(c[d+(16+(c[n>>2]|0)<<2)>>2]&65535,(c[A>>2]&65535)<<16>>16)|0)>>16)|0;if(((K+(_(c[d+(16+(c[n>>2]|0)<<2)>>2]|0,(c[A>>2]>>15)+1>>1)|0)>>7)+1>>1|0)<=32767){K=_(c[d+(16+(c[n>>2]|0)<<2)>>2]>>16,(c[A>>2]&65535)<<16>>16)|0;J=K+((_(c[d+(16+(c[n>>2]|0)<<2)>>2]&65535,(c[A>>2]&65535)<<16>>16)|0)>>16)|0;if(((J+(_(c[d+(16+(c[n>>2]|0)<<2)>>2]|0,(c[A>>2]>>15)+1>>1)|0)>>7)+1>>1|0)<-32768)M=-32768;else{J=_(c[d+(16+(c[n>>2]|0)<<2)>>2]>>16,(c[A>>2]&65535)<<16>>16)|0;K=J+((_(c[d+(16+(c[n>>2]|0)<<2)>>2]&65535,(c[A>>2]&65535)<<16>>16)|0)>>16)|0;M=(K+(_(c[d+(16+(c[n>>2]|0)<<2)>>2]|0,(c[A>>2]>>15)+1>>1)|0)>>7)+1>>1}}else M=32767;b[(c[w>>2]|0)+(c[n>>2]<<1)>>1]=M;c[n>>2]=(c[n>>2]|0)+1}m=d;D=d+(c[(c[j>>2]|0)+2332>>2]<<2)|0;E=m+64|0;do{c[m>>2]=c[D>>2];m=m+4|0;D=D+4|0}while((m|0)<(E|0));c[G>>2]=(c[G>>2]|0)+(c[(c[j>>2]|0)+2332>>2]<<2);c[w>>2]=(c[w>>2]|0)+(c[(c[j>>2]|0)+2332>>2]<<1);c[o>>2]=(c[o>>2]|0)+1}m=(c[j>>2]|0)+1284|0;D=d;E=m+64|0;do{c[m>>2]=c[D>>2];m=m+4|0;D=D+4|0}while((m|0)<(E|0));ka(c[I>>2]|0);i=h;return}function Pb(b,d,e,f,g,h){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;j=i;i=i+192|0;k=j+172|0;l=j+152|0;m=j;n=j+164|0;o=j+168|0;p=j+176|0;q=j+148|0;r=j+160|0;s=j+156|0;t=j+8|0;u=j+4|0;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;c[o>>2]=g;c[p>>2]=h;c[s>>2]=0;c[q>>2]=c[(c[k>>2]|0)+2328>>2];c[t+136>>2]=0;do if(!(c[o>>2]|0))v=4;else{if((c[o>>2]|0)==2?(c[(c[k>>2]|0)+2420+(c[(c[k>>2]|0)+2388>>2]<<2)>>2]|0)==1:0){v=4;break}_b(c[k>>2]|0,t,c[m>>2]|0,1)}while(0);if((v|0)==4){v=(c[q>>2]|0)+16-1&-16;c[u>>2]=ua()|0;h=i;i=i+((1*(v<<1)|0)+15&-16)|0;Rb(c[k>>2]|0,c[l>>2]|0,c[(c[k>>2]|0)+2388>>2]|0,c[o>>2]|0,c[p>>2]|0);Sb(c[l>>2]|0,h,a[(c[k>>2]|0)+2736+29>>0]|0,a[(c[k>>2]|0)+2736+30>>0]|0,c[(c[k>>2]|0)+2328>>2]|0);Qb(c[k>>2]|0,t,c[p>>2]|0);Ob(c[k>>2]|0,t,c[m>>2]|0,h);_b(c[k>>2]|0,t,c[m>>2]|0,0);c[(c[k>>2]|0)+4160>>2]=0;c[(c[k>>2]|0)+4164>>2]=a[(c[k>>2]|0)+2736+29>>0];c[(c[k>>2]|0)+2376>>2]=0;ka(c[u>>2]|0)}c[r>>2]=(c[(c[k>>2]|0)+2336>>2]|0)-(c[(c[k>>2]|0)+2328>>2]|0);ff((c[k>>2]|0)+1348|0,(c[k>>2]|0)+1348+(c[(c[k>>2]|0)+2328>>2]<<1)|0,c[r>>2]<<1|0)|0;df((c[k>>2]|0)+1348+(c[r>>2]<<1)|0,c[m>>2]|0,c[(c[k>>2]|0)+2328>>2]<<1|0)|0;$b(c[k>>2]|0,c[m>>2]|0,c[q>>2]|0);Lb(c[k>>2]|0,t,c[m>>2]|0,c[q>>2]|0);c[(c[k>>2]|0)+2308>>2]=c[t+((c[(c[k>>2]|0)+2324>>2]|0)-1<<2)>>2];c[c[n>>2]>>2]=c[q>>2];i=j;return c[s>>2]|0}function Qb(d,e,f){d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;g=i;i=i+96|0;h=g+4|0;j=g+16|0;k=g+12|0;l=g+8|0;m=g+24|0;n=g;o=g+32|0;p=g+64|0;q=g+20|0;c[h>>2]=d;c[j>>2]=e;c[k>>2]=f;Xb((c[j>>2]|0)+16|0,(c[h>>2]|0)+2736|0,(c[h>>2]|0)+2312|0,(c[k>>2]|0)==2&1,c[(c[h>>2]|0)+2324>>2]|0);Yb(o,(c[h>>2]|0)+2736+8|0,c[(c[h>>2]|0)+2732>>2]|0);jc((c[j>>2]|0)+32+32|0,o,c[(c[h>>2]|0)+2340>>2]|0);if((c[(c[h>>2]|0)+2376>>2]|0)==1)a[(c[h>>2]|0)+2736+31>>0]=4;if((a[(c[h>>2]|0)+2736+31>>0]|0)<4){c[l>>2]=0;while(1){if((c[l>>2]|0)>=(c[(c[h>>2]|0)+2340>>2]|0))break;k=(b[(c[h>>2]|0)+2344+(c[l>>2]<<1)>>1]|0)+((_(a[(c[h>>2]|0)+2736+31>>0]|0,(b[o+(c[l>>2]<<1)>>1]|0)-(b[(c[h>>2]|0)+2344+(c[l>>2]<<1)>>1]|0)|0)|0)>>2)&65535;b[p+(c[l>>2]<<1)>>1]=k;c[l>>2]=(c[l>>2]|0)+1}jc((c[j>>2]|0)+32|0,p,c[(c[h>>2]|0)+2340>>2]|0)}else df((c[j>>2]|0)+32|0,(c[j>>2]|0)+32+32|0,c[(c[h>>2]|0)+2340>>2]<<1|0)|0;df((c[h>>2]|0)+2344|0,o|0,c[(c[h>>2]|0)+2340>>2]<<1|0)|0;if(c[(c[h>>2]|0)+4160>>2]|0){ec((c[j>>2]|0)+32|0,c[(c[h>>2]|0)+2340>>2]|0,63570);ec((c[j>>2]|0)+32+32|0,c[(c[h>>2]|0)+2340>>2]|0,63570)}if((a[(c[h>>2]|0)+2736+29>>0]|0)!=2){bf(c[j>>2]|0,0,c[(c[h>>2]|0)+2324>>2]<<2|0)|0;bf((c[j>>2]|0)+96|0,0,(c[(c[h>>2]|0)+2324>>2]|0)*5<<1|0)|0;a[(c[h>>2]|0)+2736+32>>0]=0;c[(c[j>>2]|0)+136>>2]=0;i=g;return}fc(b[(c[h>>2]|0)+2736+26>>1]|0,a[(c[h>>2]|0)+2736+28>>0]|0,c[j>>2]|0,c[(c[h>>2]|0)+2316>>2]|0,c[(c[h>>2]|0)+2324>>2]|0);c[q>>2]=c[240+(a[(c[h>>2]|0)+2736+32>>0]<<2)>>2];c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[(c[h>>2]|0)+2324>>2]|0))break;c[n>>2]=a[(c[h>>2]|0)+2736+4+(c[m>>2]|0)>>0];c[l>>2]=0;while(1){if((c[l>>2]|0)>=5)break;b[(c[j>>2]|0)+96+(((c[m>>2]|0)*5|0)+(c[l>>2]|0)<<1)>>1]=a[(c[q>>2]|0)+(((c[n>>2]|0)*5|0)+(c[l>>2]|0))>>0]<<7;c[l>>2]=(c[l>>2]|0)+1}c[m>>2]=(c[m>>2]|0)+1}c[n>>2]=a[(c[h>>2]|0)+2736+33>>0];c[(c[j>>2]|0)+136>>2]=b[464+(c[n>>2]<<1)>>1];i=g;return}function Rb(d,e,f,g,h){d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;j=i;i=i+96|0;k=j+36|0;l=j+4|0;m=j+28|0;n=j+16|0;o=j+32|0;p=j;q=j+12|0;r=j+24|0;s=j+20|0;t=j+8|0;u=j+40|0;v=j+72|0;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[o>>2]=h;if((c[n>>2]|0)==0?(c[(c[k>>2]|0)+2404+(c[m>>2]<<2)>>2]|0)==0:0)c[r>>2]=jb(c[l>>2]|0,440,8)|0;else c[r>>2]=(jb(c[l>>2]|0,432,8)|0)+2;a[(c[k>>2]|0)+2736+29>>0]=c[r>>2]>>1;a[(c[k>>2]|0)+2736+30>>0]=c[r>>2]&1;m=c[l>>2]|0;if((c[o>>2]|0)==2){n=(jb(m,168,8)|0)&255;a[(c[k>>2]|0)+2736>>0]=n}else{n=(jb(m,144+(a[(c[k>>2]|0)+2736+29>>0]<<3)|0,8)|0)<<3&255;a[(c[k>>2]|0)+2736>>0]=n;n=((jb(c[l>>2]|0,504,8)|0)&255)<<24>>24;m=(c[k>>2]|0)+2736|0;a[m>>0]=(a[m>>0]|0)+n}c[p>>2]=1;while(1){w=c[l>>2]|0;if((c[p>>2]|0)>=(c[(c[k>>2]|0)+2324>>2]|0))break;n=(jb(w,168,8)|0)&255;a[(c[k>>2]|0)+2736+(c[p>>2]|0)>>0]=n;c[p>>2]=(c[p>>2]|0)+1}n=_(a[(c[k>>2]|0)+2736+29>>0]>>1,b[c[(c[k>>2]|0)+2732>>2]>>1]|0)|0;m=(jb(w,(c[(c[(c[k>>2]|0)+2732>>2]|0)+12>>2]|0)+n|0,8)|0)&255;a[(c[k>>2]|0)+2736+8>>0]=m;bc(u,v,c[(c[k>>2]|0)+2732>>2]|0,a[(c[k>>2]|0)+2736+8>>0]|0);c[p>>2]=0;while(1){if((c[p>>2]|0)>=(b[(c[(c[k>>2]|0)+2732>>2]|0)+2>>1]|0))break;c[r>>2]=jb(c[l>>2]|0,(c[(c[(c[k>>2]|0)+2732>>2]|0)+24>>2]|0)+(b[u+(c[p>>2]<<1)>>1]|0)|0,8)|0;if(c[r>>2]|0){if((c[r>>2]|0)==8){v=jb(c[l>>2]|0,512,8)|0;c[r>>2]=(c[r>>2]|0)+v}}else{v=jb(c[l>>2]|0,512,8)|0;c[r>>2]=(c[r>>2]|0)-v}a[(c[k>>2]|0)+2736+8+((c[p>>2]|0)+1)>>0]=(c[r>>2]|0)-4;c[p>>2]=(c[p>>2]|0)+1}if((c[(c[k>>2]|0)+2324>>2]|0)==4){p=(jb(c[l>>2]|0,448,8)|0)&255;a[(c[k>>2]|0)+2736+31>>0]=p}else a[(c[k>>2]|0)+2736+31>>0]=4;if((a[(c[k>>2]|0)+2736+29>>0]|0)!=2){x=c[k>>2]|0;y=x+2736|0;z=y+29|0;A=a[z>>0]|0;B=A<<24>>24;C=c[k>>2]|0;D=C+2396|0;c[D>>2]=B;E=c[l>>2]|0;F=jb(E,480,8)|0;G=F&255;H=c[k>>2]|0;I=H+2736|0;J=I+34|0;a[J>>0]=G;i=j;return}c[s>>2]=1;if(((c[o>>2]|0)==2?(c[(c[k>>2]|0)+2396>>2]|0)==2:0)?(c[t>>2]=((jb(c[l>>2]|0,552,8)|0)&65535)<<16>>16,(c[t>>2]|0)>0):0){c[t>>2]=(c[t>>2]|0)-9;b[(c[k>>2]|0)+2736+26>>1]=(b[(c[k>>2]|0)+2400>>1]|0)+(c[t>>2]|0);c[s>>2]=0}if(c[s>>2]|0){s=((jb(c[l>>2]|0,520,8)|0)&65535)<<16>>16;t=(_(s,c[(c[k>>2]|0)+2316>>2]>>1)|0)&65535;b[(c[k>>2]|0)+2736+26>>1]=t;t=((jb(c[l>>2]|0,c[(c[k>>2]|0)+2380>>2]|0,8)|0)&65535)<<16>>16;s=(c[k>>2]|0)+2736+26|0;b[s>>1]=(b[s>>1]|0)+t}b[(c[k>>2]|0)+2400>>1]=b[(c[k>>2]|0)+2736+26>>1]|0;t=(jb(c[l>>2]|0,c[(c[k>>2]|0)+2384>>2]|0,8)|0)&255;a[(c[k>>2]|0)+2736+28>>0]=t;t=(jb(c[l>>2]|0,216,8)|0)&255;a[(c[k>>2]|0)+2736+32>>0]=t;c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[(c[k>>2]|0)+2324>>2]|0))break;t=(jb(c[l>>2]|0,c[224+(a[(c[k>>2]|0)+2736+32>>0]<<2)>>2]|0,8)|0)&255;a[(c[k>>2]|0)+2736+4+(c[q>>2]|0)>>0]=t;c[q>>2]=(c[q>>2]|0)+1}if(!(c[o>>2]|0)){o=(jb(c[l>>2]|0,424,8)|0)&255;a[(c[k>>2]|0)+2736+33>>0]=o;x=c[k>>2]|0;y=x+2736|0;z=y+29|0;A=a[z>>0]|0;B=A<<24>>24;C=c[k>>2]|0;D=C+2396|0;c[D>>2]=B;E=c[l>>2]|0;F=jb(E,480,8)|0;G=F&255;H=c[k>>2]|0;I=H+2736|0;J=I+34|0;a[J>>0]=G;i=j;return}else{a[(c[k>>2]|0)+2736+33>>0]=0;x=c[k>>2]|0;y=x+2736|0;z=y+29|0;A=a[z>>0]|0;B=A<<24>>24;C=c[k>>2]|0;D=C+2396|0;c[D>>2]=B;E=c[l>>2]|0;F=jb(E,480,8)|0;G=F&255;H=c[k>>2]|0;I=H+2736|0;J=I+34|0;a[J>>0]=G;i=j;return}}function Sb(a,d,e,f,g){a=a|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;h=i;i=i+224|0;j=h+84|0;k=h+180|0;l=h+200|0;m=h+208|0;n=h+188|0;o=h+196|0;p=h+204|0;q=h+212|0;r=h+216|0;s=h+80|0;t=h+184|0;u=h+88|0;v=h;w=h+96|0;x=h+192|0;y=h+176|0;c[j>>2]=a;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[u>>2]=jb(c[j>>2]|0,840+((c[l>>2]>>1)*9|0)|0,8)|0;c[r>>2]=c[n>>2]>>4;if((c[r>>2]<<4|0)<(c[n>>2]|0))c[r>>2]=(c[r>>2]|0)+1;c[y>>2]=656+((c[u>>2]|0)*18|0);c[o>>2]=0;while(1){if((c[o>>2]|0)>=(c[r>>2]|0))break;c[w+(c[o>>2]<<2)>>2]=0;u=jb(c[j>>2]|0,c[y>>2]|0,8)|0;c[v+(c[o>>2]<<2)>>2]=u;while(1){z=c[o>>2]|0;if((c[v+(c[o>>2]<<2)>>2]|0)!=17)break;u=w+(z<<2)|0;c[u>>2]=(c[u>>2]|0)+1;u=jb(c[j>>2]|0,818+((c[w+(c[o>>2]<<2)>>2]|0)==10&1)|0,8)|0;c[v+(c[o>>2]<<2)>>2]=u}c[o>>2]=z+1}c[o>>2]=0;while(1){if((c[o>>2]|0)>=(c[r>>2]|0))break;z=(c[k>>2]|0)+((c[o>>2]&65535)<<16>>16<<4<<1)|0;if((c[v+(c[o>>2]<<2)>>2]|0)>0)ac(z,c[j>>2]|0,c[v+(c[o>>2]<<2)>>2]|0);else{y=z;z=y+32|0;do{b[y>>1]=0;y=y+2|0}while((y|0)<(z|0))}c[o>>2]=(c[o>>2]|0)+1}c[o>>2]=0;while(1){if((c[o>>2]|0)>=(c[r>>2]|0))break;if((c[w+(c[o>>2]<<2)>>2]|0)>0){c[t>>2]=c[w+(c[o>>2]<<2)>>2];c[x>>2]=(c[k>>2]|0)+((c[o>>2]&65535)<<16>>16<<4<<1);c[q>>2]=0;while(1){if((c[q>>2]|0)>=16)break;c[s>>2]=b[(c[x>>2]|0)+(c[q>>2]<<1)>>1];c[p>>2]=0;while(1){A=c[s>>2]|0;if((c[p>>2]|0)>=(c[t>>2]|0))break;c[s>>2]=A<<1;y=jb(c[j>>2]|0,416,8)|0;c[s>>2]=(c[s>>2]|0)+y;c[p>>2]=(c[p>>2]|0)+1}b[(c[x>>2]|0)+(c[q>>2]<<1)>>1]=A;c[q>>2]=(c[q>>2]|0)+1}y=v+(c[o>>2]<<2)|0;c[y>>2]=c[y>>2]|c[t>>2]<<5}c[o>>2]=(c[o>>2]|0)+1}Mb(c[j>>2]|0,c[k>>2]|0,c[n>>2]|0,c[l>>2]|0,c[m>>2]|0,v);i=h;return}function Tb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[g>>2]=b;c[h>>2]=d;c[j>>2]=e;c[l>>2]=0;c[(c[g>>2]|0)+2332>>2]=((c[h>>2]&65535)<<16>>16)*5;c[k>>2]=_((c[(c[g>>2]|0)+2324>>2]&65535)<<16>>16,(c[(c[g>>2]|0)+2332>>2]&65535)<<16>>16)|0;if(!((c[(c[g>>2]|0)+2316>>2]|0)==(c[h>>2]|0)?(c[(c[g>>2]|0)+2320>>2]|0)==(c[j>>2]|0):0)){e=mc((c[g>>2]|0)+2432|0,((c[h>>2]&65535)<<16>>16)*1e3|0,c[j>>2]|0,0)|0;c[l>>2]=(c[l>>2]|0)+e;c[(c[g>>2]|0)+2320>>2]=c[j>>2]}if((c[(c[g>>2]|0)+2316>>2]|0)==(c[h>>2]|0)?(c[k>>2]|0)==(c[(c[g>>2]|0)+2328>>2]|0):0){m=c[l>>2]|0;i=f;return m|0}j=(c[(c[g>>2]|0)+2324>>2]|0)==4;e=(c[g>>2]|0)+2384|0;do if((c[h>>2]|0)==8)if(j){c[e>>2]=616;break}else{c[e>>2]=648;break}else if(j){c[e>>2]=576;break}else{c[e>>2]=632;break}while(0);if((c[(c[g>>2]|0)+2316>>2]|0)!=(c[h>>2]|0)){c[(c[g>>2]|0)+2336>>2]=((c[h>>2]&65535)<<16>>16)*20;e=(c[g>>2]|0)+2340|0;if((c[h>>2]|0)==8|(c[h>>2]|0)==12){c[e>>2]=10;c[(c[g>>2]|0)+2732>>2]=256}else{c[e>>2]=16;c[(c[g>>2]|0)+2732>>2]=296}do if((c[h>>2]|0)!=16){if((c[h>>2]|0)==12){c[(c[g>>2]|0)+2380>>2]=496;break}if((c[h>>2]|0)==8)c[(c[g>>2]|0)+2380>>2]=480}else c[(c[g>>2]|0)+2380>>2]=504;while(0);c[(c[g>>2]|0)+2376>>2]=1;c[(c[g>>2]|0)+2308>>2]=100;a[(c[g>>2]|0)+2312>>0]=10;c[(c[g>>2]|0)+4164>>2]=0;bf((c[g>>2]|0)+1348|0,0,960)|0;e=(c[g>>2]|0)+1284|0;j=e+64|0;do{c[e>>2]=0;e=e+4|0}while((e|0)<(j|0))}c[(c[g>>2]|0)+2316>>2]=c[h>>2];c[(c[g>>2]|0)+2328>>2]=c[k>>2];m=c[l>>2]|0;i=f;return m|0}function Ub(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;c[e>>2]=0;c[c[d>>2]>>2]=8544;i=b;return c[e>>2]|0}function Vb(a){a=a|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[e>>2]=a;c[g>>2]=0;c[h>>2]=c[e>>2];c[f>>2]=0;while(1){if((c[f>>2]|0)>=2)break;c[g>>2]=Nb((c[h>>2]|0)+((c[f>>2]|0)*4260|0)|0)|0;c[f>>2]=(c[f>>2]|0)+1}f=(c[e>>2]|0)+8520|0;b[f>>1]=0;b[f+2>>1]=0;b[f+4>>1]=0;b[f+6>>1]=0;b[f+8>>1]=0;b[f+10>>1]=0;c[(c[e>>2]|0)+8540>>2]=0;i=d;return c[g>>2]|0}function Wb(d,e,f,g,h,j,k){d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0;l=i;i=i+784|0;m=l+64|0;n=l+48|0;o=l+44|0;p=l+108|0;q=l+100|0;r=l+16|0;s=l+20|0;t=l+24|0;u=l+28|0;v=l+32|0;w=l+36|0;x=l+96|0;y=l+104|0;z=l+112|0;A=l+120|0;B=l+128|0;C=l+68|0;D=l+72|0;E=l+76|0;F=l+80|0;G=l+84|0;H=l+12|0;I=l+8|0;J=l+136|0;K=l+4|0;L=l;M=l+40|0;N=l+92|0;O=l+52|0;P=l+88|0;c[n>>2]=d;c[o>>2]=e;c[p>>2]=f;c[q>>2]=g;c[r>>2]=h;c[s>>2]=j;c[t>>2]=k;c[w>>2]=0;c[x>>2]=0;c[B>>2]=0;c[B+4>>2]=0;c[D>>2]=c[n>>2];c[E>>2]=c[D>>2];a:do if(c[q>>2]|0){c[v>>2]=0;while(1){if((c[v>>2]|0)>=(c[(c[o>>2]|0)+4>>2]|0))break a;c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2388>>2]=0;c[v>>2]=(c[v>>2]|0)+1}}while(0);if((c[(c[o>>2]|0)+4>>2]|0)>(c[(c[D>>2]|0)+8536>>2]|0)){q=Nb((c[E>>2]|0)+4260|0)|0;c[x>>2]=(c[x>>2]|0)+q}if((c[(c[o>>2]|0)+4>>2]|0)==1?(c[(c[D>>2]|0)+8536>>2]|0)==2:0)Q=(c[(c[o>>2]|0)+12>>2]|0)==((c[(c[E>>2]|0)+2316>>2]|0)*1e3|0);else Q=0;c[G>>2]=Q&1;b:do if(!(c[(c[E>>2]|0)+2388>>2]|0)){c[v>>2]=0;c:while(1){if((c[v>>2]|0)>=(c[(c[o>>2]|0)+4>>2]|0))break b;do if(!(c[(c[o>>2]|0)+16>>2]|0)){c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2392>>2]=1;c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2324>>2]=2}else{if((c[(c[o>>2]|0)+16>>2]|0)==10){c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2392>>2]=1;c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2324>>2]=2;break}if((c[(c[o>>2]|0)+16>>2]|0)==20){c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2392>>2]=1;c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2324>>2]=4;break}if((c[(c[o>>2]|0)+16>>2]|0)==40){c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2392>>2]=2;c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2324>>2]=4;break}if((c[(c[o>>2]|0)+16>>2]|0)!=60){R=23;break c}c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2392>>2]=3;c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2324>>2]=4}while(0);c[I>>2]=(c[(c[o>>2]|0)+12>>2]>>10)+1;if((c[I>>2]|0)!=8&(c[I>>2]|0)!=12&(c[I>>2]|0)!=16){R=25;break}Q=Tb((c[E>>2]|0)+((c[v>>2]|0)*4260|0)|0,c[I>>2]|0,c[(c[o>>2]|0)+8>>2]|0)|0;c[x>>2]=(c[x>>2]|0)+Q;c[v>>2]=(c[v>>2]|0)+1}if((R|0)==23){c[m>>2]=-203;S=c[m>>2]|0;i=l;return S|0}else if((R|0)==25){c[m>>2]=-200;S=c[m>>2]|0;i=l;return S|0}}while(0);do if((c[c[o>>2]>>2]|0)==2?(c[(c[o>>2]|0)+4>>2]|0)==2:0){if((c[(c[D>>2]|0)+8532>>2]|0)!=1?(c[(c[D>>2]|0)+8536>>2]|0)!=1:0)break;I=(c[D>>2]|0)+8520|0;b[I>>1]=0;b[I+2>>1]=0;I=(c[D>>2]|0)+8520+8|0;b[I>>1]=0;b[I+2>>1]=0;df((c[E>>2]|0)+4260+2432|0,(c[E>>2]|0)+2432|0,300)|0}while(0);c[(c[D>>2]|0)+8532>>2]=c[c[o>>2]>>2];c[(c[D>>2]|0)+8536>>2]=c[(c[o>>2]|0)+4>>2];if((c[(c[o>>2]|0)+8>>2]|0)<=48e3?(c[(c[o>>2]|0)+8>>2]|0)>=8e3:0){d:do if((c[p>>2]|0)!=1?(c[(c[E>>2]|0)+2388>>2]|0)==0:0){c[v>>2]=0;while(1){if((c[v>>2]|0)>=(c[(c[o>>2]|0)+4>>2]|0))break;c[u>>2]=0;while(1){I=(c[u>>2]|0)<(c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2392>>2]|0);T=ib(c[r>>2]|0,1)|0;if(!I)break;c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2404+(c[u>>2]<<2)>>2]=T;c[u>>2]=(c[u>>2]|0)+1}c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2416>>2]=T;c[v>>2]=(c[v>>2]|0)+1}c[v>>2]=0;while(1){if((c[v>>2]|0)>=(c[(c[o>>2]|0)+4>>2]|0))break;I=(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2420|0;c[I>>2]=0;c[I+4>>2]=0;c[I+8>>2]=0;e:do if(c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2416>>2]|0){if((c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2392>>2]|0)==1){c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2420>>2]=1;break}c[z>>2]=(jb(c[r>>2]|0,c[408+((c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2392>>2]|0)-2<<2)>>2]|0,8)|0)+1;c[u>>2]=0;while(1){if((c[u>>2]|0)>=(c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2392>>2]|0))break e;c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2420+(c[u>>2]<<2)>>2]=c[z>>2]>>c[u>>2]&1;c[u>>2]=(c[u>>2]|0)+1}}while(0);c[v>>2]=(c[v>>2]|0)+1}if(!(c[p>>2]|0)){c[u>>2]=0;while(1){if((c[u>>2]|0)>=(c[(c[E>>2]|0)+2392>>2]|0))break d;c[v>>2]=0;while(1){U=c[u>>2]|0;if((c[v>>2]|0)>=(c[(c[o>>2]|0)+4>>2]|0))break;if(c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2420+(U<<2)>>2]|0){do if((c[v>>2]|0)==0?(c[(c[o>>2]|0)+4>>2]|0)==2:0){vc(c[r>>2]|0,B);if(c[(c[E>>2]|0)+4260+2420+(c[u>>2]<<2)>>2]|0)break;wc(c[r>>2]|0,w)}while(0);do if((c[u>>2]|0)>0){if(!(c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2420+((c[u>>2]|0)-1<<2)>>2]|0)){R=64;break}c[K>>2]=2}else R=64;while(0);if((R|0)==64){R=0;c[K>>2]=0}Rb((c[E>>2]|0)+((c[v>>2]|0)*4260|0)|0,c[r>>2]|0,c[u>>2]|0,1,c[K>>2]|0);Sb(c[r>>2]|0,J,a[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2736+29>>0]|0,a[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2736+30>>0]|0,c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2328>>2]|0)}c[v>>2]=(c[v>>2]|0)+1}c[u>>2]=U+1}}}while(0);f:do if((c[(c[o>>2]|0)+4>>2]|0)==2){do if(c[p>>2]|0){if((c[p>>2]|0)==2?(c[(c[E>>2]|0)+2420+(c[(c[E>>2]|0)+2388>>2]<<2)>>2]|0)==1:0)break;c[v>>2]=0;while(1){if((c[v>>2]|0)>=2)break f;c[B+(c[v>>2]<<2)>>2]=b[(c[D>>2]|0)+8520+(c[v>>2]<<1)>>1];c[v>>2]=(c[v>>2]|0)+1}}while(0);vc(c[r>>2]|0,B);if(!((c[p>>2]|0)==0?(c[(c[E>>2]|0)+4260+2404+(c[(c[E>>2]|0)+2388>>2]<<2)>>2]|0)==0:0))R=74;do if((R|0)==74){if((c[p>>2]|0)==2?(c[(c[E>>2]|0)+4260+2420+(c[(c[E>>2]|0)+2388>>2]<<2)>>2]|0)==0:0)break;c[w>>2]=0;break f}while(0);wc(c[r>>2]|0,w)}while(0);if(((c[w>>2]|0)==0?(c[(c[o>>2]|0)+4>>2]|0)==2:0)?(c[(c[D>>2]|0)+8540>>2]|0)==1:0){bf((c[D>>2]|0)+4260+1348|0,0,960)|0;R=(c[D>>2]|0)+4260+1284|0;U=R+64|0;do{c[R>>2]=0;R=R+4|0}while((R|0)<(U|0));c[(c[D>>2]|0)+4260+2308>>2]=100;a[(c[D>>2]|0)+4260+2312>>0]=10;c[(c[D>>2]|0)+4260+4164>>2]=0;c[(c[D>>2]|0)+4260+2376>>2]=1}R=_(c[(c[o>>2]|0)+12>>2]|0,c[(c[o>>2]|0)+4>>2]|0)|0;c[H>>2]=(R|0)<(_(c[(c[o>>2]|0)+8>>2]|0,c[c[o>>2]>>2]|0)|0)&1;if(c[H>>2]|0)V=1;else V=_(c[(c[o>>2]|0)+4>>2]|0,(c[(c[E>>2]|0)+2328>>2]|0)+2|0)|0;c[L>>2]=ua()|0;R=i;i=i+((1*(V<<1)|0)+15&-16)|0;if(c[H>>2]|0){c[A>>2]=c[s>>2];c[A+4>>2]=(c[s>>2]|0)+(c[(c[E>>2]|0)+2328>>2]<<1)+4}else{c[A>>2]=R;c[A+4>>2]=R+(c[(c[E>>2]|0)+2328>>2]<<1)+4}if(!(c[p>>2]|0))c[F>>2]=((c[w>>2]|0)!=0^1)&1;else{if(c[(c[D>>2]|0)+8540>>2]|0)if((c[p>>2]|0)==2?(c[(c[o>>2]|0)+4>>2]|0)==2:0)W=(c[(c[E>>2]|0)+4260+2420+(c[(c[E>>2]|0)+4260+2388>>2]<<2)>>2]|0)==1;else W=0;else W=1;c[F>>2]=W&1}c[v>>2]=0;while(1){if((c[v>>2]|0)>=(c[(c[o>>2]|0)+4>>2]|0))break;if((c[v>>2]|0)==0|(c[F>>2]|0)!=0){c[M>>2]=(c[(c[E>>2]|0)+2388>>2]|0)-(c[v>>2]|0);g:do if((c[M>>2]|0)<=0)c[N>>2]=0;else{if((c[p>>2]|0)==2){c[N>>2]=(c[(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2420+((c[M>>2]|0)-1<<2)>>2]|0)!=0?2:0;break}do if((c[v>>2]|0)>0){if(!(c[(c[D>>2]|0)+8540>>2]|0))break;c[N>>2]=1;break g}while(0);c[N>>2]=2}while(0);W=Pb((c[E>>2]|0)+((c[v>>2]|0)*4260|0)|0,c[r>>2]|0,(c[A+(c[v>>2]<<2)>>2]|0)+4|0,y,c[p>>2]|0,c[N>>2]|0)|0;c[x>>2]=(c[x>>2]|0)+W}else bf((c[A+(c[v>>2]<<2)>>2]|0)+4|0,0,c[y>>2]<<1|0)|0;W=(c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2388|0;c[W>>2]=(c[W>>2]|0)+1;c[v>>2]=(c[v>>2]|0)+1}if((c[c[o>>2]>>2]|0)==2?(c[(c[o>>2]|0)+4>>2]|0)==2:0)cc((c[D>>2]|0)+8520|0,c[A>>2]|0,c[A+4>>2]|0,B,c[(c[E>>2]|0)+2316>>2]|0,c[y>>2]|0);else{B=c[A>>2]|0;N=(c[D>>2]|0)+8520+4|0;b[B>>1]=b[N>>1]|0;b[B+2>>1]=b[N+2>>1]|0;N=(c[D>>2]|0)+8520+4|0;B=(c[A>>2]|0)+(c[y>>2]<<1)|0;b[N>>1]=b[B>>1]|0;b[N+2>>1]=b[B+2>>1]|0}B=_(c[y>>2]|0,c[(c[o>>2]|0)+8>>2]|0)|0;c[c[t>>2]>>2]=(B|0)/(((c[(c[E>>2]|0)+2316>>2]&65535)<<16>>16)*1e3|0)|0;if((c[c[o>>2]>>2]|0)==2)X=c[c[t>>2]>>2]|0;else X=1;B=i;i=i+((1*(X<<1)|0)+15&-16)|0;if((c[c[o>>2]>>2]|0)==2)c[C>>2]=B;else c[C>>2]=c[s>>2];if(c[H>>2]|0)Y=_(c[(c[o>>2]|0)+4>>2]|0,(c[(c[E>>2]|0)+2328>>2]|0)+2|0)|0;else Y=1;B=i;i=i+((1*(Y<<1)|0)+15&-16)|0;if(c[H>>2]|0){H=(_(c[(c[o>>2]|0)+4>>2]|0,(c[(c[E>>2]|0)+2328>>2]|0)+2|0)|0)<<1;df(B|0,c[s>>2]|0,H+0|0)|0;c[A>>2]=B;c[A+4>>2]=B+(c[(c[E>>2]|0)+2328>>2]<<1)+4}c[v>>2]=0;while(1){B=c[o>>2]|0;if((c[c[o>>2]>>2]|0)<(c[(c[o>>2]|0)+4>>2]|0))Z=c[B>>2]|0;else Z=c[B+4>>2]|0;if((c[v>>2]|0)>=(Z|0))break;B=nc((c[E>>2]|0)+((c[v>>2]|0)*4260|0)+2432|0,c[C>>2]|0,(c[A+(c[v>>2]<<2)>>2]|0)+2|0,c[y>>2]|0)|0;c[x>>2]=(c[x>>2]|0)+B;h:do if((c[c[o>>2]>>2]|0)==2){c[u>>2]=0;while(1){if((c[u>>2]|0)>=(c[c[t>>2]>>2]|0))break h;b[(c[s>>2]|0)+((c[v>>2]|0)+(c[u>>2]<<1)<<1)>>1]=b[(c[C>>2]|0)+(c[u>>2]<<1)>>1]|0;c[u>>2]=(c[u>>2]|0)+1}}while(0);c[v>>2]=(c[v>>2]|0)+1}i:do if((c[c[o>>2]>>2]|0)==2){if((c[(c[o>>2]|0)+4>>2]|0)!=1)break;if(c[G>>2]|0){v=nc((c[E>>2]|0)+4260+2432|0,c[C>>2]|0,(c[A>>2]|0)+2|0,c[y>>2]|0)|0;c[x>>2]=(c[x>>2]|0)+v;c[u>>2]=0;while(1){if((c[u>>2]|0)>=(c[c[t>>2]>>2]|0))break i;b[(c[s>>2]|0)+(1+(c[u>>2]<<1)<<1)>>1]=b[(c[C>>2]|0)+(c[u>>2]<<1)>>1]|0;c[u>>2]=(c[u>>2]|0)+1}}else{c[u>>2]=0;while(1){if((c[u>>2]|0)>=(c[c[t>>2]>>2]|0))break i;b[(c[s>>2]|0)+(1+(c[u>>2]<<1)<<1)>>1]=b[(c[s>>2]|0)+(0+(c[u>>2]<<1)<<1)>>1]|0;c[u>>2]=(c[u>>2]|0)+1}}}while(0);if((c[(c[E>>2]|0)+4164>>2]|0)==2){c[O>>2]=c[738];c[O+4>>2]=c[739];c[O+8>>2]=c[740];s=_(c[(c[E>>2]|0)+2308>>2]|0,c[O+((c[(c[E>>2]|0)+2316>>2]|0)-8>>2<<2)>>2]|0)|0;c[(c[o>>2]|0)+20>>2]=s}else c[(c[o>>2]|0)+20>>2]=0;j:do if((c[p>>2]|0)==1){c[u>>2]=0;while(1){if((c[u>>2]|0)>=(c[(c[D>>2]|0)+8536>>2]|0))break j;a[(c[D>>2]|0)+((c[u>>2]|0)*4260|0)+2312>>0]=10;c[u>>2]=(c[u>>2]|0)+1}}else c[(c[D>>2]|0)+8540>>2]=c[w>>2];while(0);c[m>>2]=c[x>>2];c[P>>2]=1;ka(c[L>>2]|0);S=c[m>>2]|0;i=l;return S|0}c[x>>2]=-200;c[m>>2]=c[x>>2];S=c[m>>2]|0;i=l;return S|0}function Xb(b,d,e,f,g){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;h=i;i=i+32|0;j=h+4|0;k=h+16|0;l=h+8|0;m=h+20|0;n=h+28|0;o=h;p=h+12|0;q=h+24|0;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[o>>2]=0;while(1){if((c[o>>2]|0)>=(c[n>>2]|0))break;g=a[(c[k>>2]|0)+(c[o>>2]|0)>>0]|0;do if(!((c[o>>2]|0)==0&(c[m>>2]|0)==0)){c[p>>2]=g+-4;c[q>>2]=8+(a[c[l>>2]>>0]|0);f=c[p>>2]|0;if((c[p>>2]|0)>(c[q>>2]|0)){e=c[l>>2]|0;a[e>>0]=(a[e>>0]|0)+((f<<1)-(c[q>>2]|0));break}else{e=c[l>>2]|0;a[e>>0]=(a[e>>0]|0)+f;break}}else{f=(Gd(g,(a[c[l>>2]>>0]|0)-16|0)|0)&255;a[c[l>>2]>>0]=f}while(0);if((a[c[l>>2]>>0]|0)<=63)if((a[c[l>>2]>>0]|0)<0)r=0;else r=a[c[l>>2]>>0]|0;else r=63;a[c[l>>2]>>0]=r;g=gc(Fd(((a[c[l>>2]>>0]<<16>>16)*29|0)+((a[c[l>>2]>>0]<<16>>16)*7281>>16)+2090|0,3967)|0)|0;c[(c[j>>2]|0)+(c[o>>2]<<2)>>2]=g;c[o>>2]=(c[o>>2]|0)+1}i=h;return}function Yb(e,f,g){e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;h=i;i=i+144|0;j=h+24|0;k=h+16|0;l=h+12|0;m=h+8|0;n=h+128|0;o=h+32|0;p=h+64|0;q=h+96|0;r=h+20|0;s=h;t=h+4|0;c[j>>2]=e;c[k>>2]=f;c[l>>2]=g;g=_(a[c[k>>2]>>0]|0,b[(c[l>>2]|0)+2>>1]|0)|0;c[t>>2]=(c[(c[l>>2]|0)+8>>2]|0)+g;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(b[(c[l>>2]|0)+2>>1]|0))break;b[(c[j>>2]|0)+(c[m>>2]<<1)>>1]=d[(c[t>>2]|0)+(c[m>>2]|0)>>0]<<7;c[m>>2]=(c[m>>2]|0)+1}bc(o,n,c[l>>2]|0,a[c[k>>2]>>0]|0);Hd(p,(c[k>>2]|0)+1|0,n,b[(c[l>>2]|0)+4>>1]|0,b[(c[l>>2]|0)+2>>1]|0);lc(q,c[j>>2]|0,b[(c[l>>2]|0)+2>>1]|0);c[m>>2]=0;while(1){if((c[m>>2]|0)>=(b[(c[l>>2]|0)+2>>1]|0))break;c[r>>2]=Id(b[q+(c[m>>2]<<1)>>1]<<16)|0;c[s>>2]=(b[(c[j>>2]|0)+(c[m>>2]<<1)>>1]|0)+((b[p+(c[m>>2]<<1)>>1]<<14|0)/(c[r>>2]|0)|0);if((c[s>>2]|0)>32767)u=32767;else u=(c[s>>2]|0)<0?0:c[s>>2]|0;b[(c[j>>2]|0)+(c[m>>2]<<1)>>1]=u;c[m>>2]=(c[m>>2]|0)+1}kc(c[j>>2]|0,c[(c[l>>2]|0)+32>>2]|0,b[(c[l>>2]|0)+2>>1]|0);i=h;return}function Zb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;c[(c[d>>2]|0)+4168>>2]=c[(c[d>>2]|0)+2328>>2]<<7;c[(c[d>>2]|0)+4168+72>>2]=65536;c[(c[d>>2]|0)+4168+72+4>>2]=65536;c[(c[d>>2]|0)+4168+88>>2]=20;c[(c[d>>2]|0)+4168+84>>2]=2;i=b;return}function _b(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0;f=i;i=i+16|0;g=f+12|0;h=f+8|0;j=f+4|0;k=f;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=e;if((c[(c[g>>2]|0)+2316>>2]|0)!=(c[(c[g>>2]|0)+4168+80>>2]|0)){Zb(c[g>>2]|0);c[(c[g>>2]|0)+4168+80>>2]=c[(c[g>>2]|0)+2316>>2]}e=c[g>>2]|0;d=c[h>>2]|0;if(c[k>>2]|0){Jd(e,d,c[j>>2]|0);j=(c[g>>2]|0)+4160|0;c[j>>2]=(c[j>>2]|0)+1;i=f;return}else{Kd(e,d);i=f;return}}function $b(a,d,e){a=a|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;f=i;i=i+48|0;g=f+36|0;h=f+16|0;j=f;k=f+28|0;l=f+32|0;m=f+40|0;n=f+12|0;o=f+24|0;p=f+20|0;q=f+8|0;r=f+4|0;c[g>>2]=a;c[h>>2]=d;c[j>>2]=e;c[n>>2]=(c[g>>2]|0)+4168;if(c[(c[g>>2]|0)+4160>>2]|0){uc((c[n>>2]|0)+60|0,(c[n>>2]|0)+64|0,c[h>>2]|0,c[j>>2]|0);c[(c[n>>2]|0)+48>>2]=1;i=f;return}a:do if(c[(c[g>>2]|0)+4168+48>>2]|0){uc(m,l,c[h>>2]|0,c[j>>2]|0);if((c[l>>2]|0)<=(c[(c[n>>2]|0)+64>>2]|0)){if((c[l>>2]|0)<(c[(c[n>>2]|0)+64>>2]|0))c[m>>2]=c[m>>2]>>(c[(c[n>>2]|0)+64>>2]|0)-(c[l>>2]|0)}else c[(c[n>>2]|0)+60>>2]=c[(c[n>>2]|0)+60>>2]>>(c[l>>2]|0)-(c[(c[n>>2]|0)+64>>2]|0);if((c[m>>2]|0)>(c[(c[n>>2]|0)+60>>2]|0)){c[p>>2]=Ld(c[(c[n>>2]|0)+60>>2]|0)|0;c[p>>2]=(c[p>>2]|0)-1;c[(c[n>>2]|0)+60>>2]=c[(c[n>>2]|0)+60>>2]<<c[p>>2];e=c[m>>2]|0;c[m>>2]=e>>(Md(24-(c[p>>2]|0)|0,0)|0);c[o>>2]=(c[(c[n>>2]|0)+60>>2]|0)/(((c[m>>2]|0)>1?c[m>>2]|0:1)|0)|0;c[q>>2]=(Nd(c[o>>2]|0)|0)<<4;c[r>>2]=(65536-(c[q>>2]|0)|0)/(c[j>>2]|0)|0;c[r>>2]=c[r>>2]<<2;c[k>>2]=0;while(1){if((c[k>>2]|0)>=(c[j>>2]|0))break a;e=_(c[q>>2]>>16,b[(c[h>>2]|0)+(c[k>>2]<<1)>>1]|0)|0;d=e+((_(c[q>>2]&65535,b[(c[h>>2]|0)+(c[k>>2]<<1)>>1]|0)|0)>>16)&65535;b[(c[h>>2]|0)+(c[k>>2]<<1)>>1]=d;c[q>>2]=(c[q>>2]|0)+(c[r>>2]|0);if((c[q>>2]|0)>65536)break a;c[k>>2]=(c[k>>2]|0)+1}}}while(0);c[(c[n>>2]|0)+48>>2]=0;i=f;return}function ac(a,d,e){a=a|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+48|0;g=f+8|0;h=f+4|0;j=f;k=f+40|0;l=f+32|0;m=f+16|0;c[g>>2]=a;c[h>>2]=d;c[j>>2]=e;Od(k,k+2|0,c[h>>2]|0,c[j>>2]|0,1320);Od(l,l+2|0,c[h>>2]|0,b[k>>1]|0,1168);Od(m,m+2|0,c[h>>2]|0,b[l>>1]|0,1016);Od(c[g>>2]|0,(c[g>>2]|0)+2|0,c[h>>2]|0,b[m>>1]|0,864);Od((c[g>>2]|0)+4|0,(c[g>>2]|0)+6|0,c[h>>2]|0,b[m+2>>1]|0,864);Od(m+4|0,m+6|0,c[h>>2]|0,b[l+2>>1]|0,1016);Od((c[g>>2]|0)+8|0,(c[g>>2]|0)+10|0,c[h>>2]|0,b[m+4>>1]|0,864);Od((c[g>>2]|0)+12|0,(c[g>>2]|0)+14|0,c[h>>2]|0,b[m+6>>1]|0,864);Od(l+4|0,l+6|0,c[h>>2]|0,b[k+2>>1]|0,1168);Od(m+8|0,m+10|0,c[h>>2]|0,b[l+4>>1]|0,1016);Od((c[g>>2]|0)+16|0,(c[g>>2]|0)+18|0,c[h>>2]|0,b[m+8>>1]|0,864);Od((c[g>>2]|0)+20|0,(c[g>>2]|0)+22|0,c[h>>2]|0,b[m+10>>1]|0,864);Od(m+12|0,m+14|0,c[h>>2]|0,b[l+6>>1]|0,1016);Od((c[g>>2]|0)+24|0,(c[g>>2]|0)+26|0,c[h>>2]|0,b[m+12>>1]|0,864);Od((c[g>>2]|0)+28|0,(c[g>>2]|0)+30|0,c[h>>2]|0,b[m+14>>1]|0,864);i=f;return}function bc(e,f,g,h){e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;j=i;i=i+32|0;k=j+4|0;l=j+12|0;m=j+8|0;n=j+20|0;o=j;p=j+24|0;q=j+16|0;c[k>>2]=e;c[l>>2]=f;c[m>>2]=g;c[n>>2]=h;h=(_(c[n>>2]|0,b[(c[m>>2]|0)+2>>1]|0)|0)/2|0;c[q>>2]=(c[(c[m>>2]|0)+20>>2]|0)+h;c[o>>2]=0;while(1){if((c[o>>2]|0)>=(b[(c[m>>2]|0)+2>>1]|0))break;h=c[q>>2]|0;c[q>>2]=h+1;a[p>>0]=a[h>>0]|0;b[(c[k>>2]|0)+(c[o>>2]<<1)>>1]=((d[p>>0]>>1&7)<<16>>16)*9;h=(c[o>>2]|0)+(_(d[p>>0]&1,(b[(c[m>>2]|0)+2>>1]|0)-1|0)|0)|0;a[(c[l>>2]|0)+(c[o>>2]|0)>>0]=a[(c[(c[m>>2]|0)+16>>2]|0)+h>>0]|0;b[(c[k>>2]|0)+((c[o>>2]|0)+1<<1)>>1]=((d[p>>0]>>5&7)<<16>>16)*9;h=(c[o>>2]|0)+(_(d[p>>0]>>4&1,(b[(c[m>>2]|0)+2>>1]|0)-1|0)|0)+1|0;a[(c[l>>2]|0)+((c[o>>2]|0)+1)>>0]=a[(c[(c[m>>2]|0)+16>>2]|0)+h>>0]|0;c[o>>2]=(c[o>>2]|0)+2}i=j;return}function cc(a,d,e,f,g,h){a=a|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0;j=i;i=i+64|0;k=j+24|0;l=j+20|0;m=j+44|0;n=j+36|0;o=j+32|0;p=j+40|0;q=j+48|0;r=j+52|0;s=j+8|0;t=j+4|0;u=j+28|0;v=j+12|0;w=j;x=j+16|0;c[k>>2]=a;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;c[o>>2]=g;c[p>>2]=h;h=c[l>>2]|0;g=(c[k>>2]|0)+4|0;b[h>>1]=b[g>>1]|0;b[h+2>>1]=b[g+2>>1]|0;g=c[m>>2]|0;h=(c[k>>2]|0)+8|0;b[g>>1]=b[h>>1]|0;b[g+2>>1]=b[h+2>>1]|0;h=(c[k>>2]|0)+4|0;g=(c[l>>2]|0)+(c[p>>2]<<1)|0;b[h>>1]=b[g>>1]|0;b[h+2>>1]=b[g+2>>1]|0;g=(c[k>>2]|0)+8|0;h=(c[m>>2]|0)+(c[p>>2]<<1)|0;b[g>>1]=b[h>>1]|0;b[g+2>>1]=b[h+2>>1]|0;c[w>>2]=b[c[k>>2]>>1];c[x>>2]=b[(c[k>>2]|0)+2>>1];c[r>>2]=65536/(c[o>>2]<<3|0)|0;c[s>>2]=((_(((c[c[n>>2]>>2]|0)-(b[c[k>>2]>>1]|0)&65535)<<16>>16,(c[r>>2]&65535)<<16>>16)|0)>>15)+1>>1;c[t>>2]=((_(((c[(c[n>>2]|0)+4>>2]|0)-(b[(c[k>>2]|0)+2>>1]|0)&65535)<<16>>16,(c[r>>2]&65535)<<16>>16)|0)>>15)+1>>1;c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]<<3|0))break;c[w>>2]=(c[w>>2]|0)+(c[s>>2]|0);c[x>>2]=(c[x>>2]|0)+(c[t>>2]|0);c[u>>2]=(b[(c[l>>2]|0)+(c[q>>2]<<1)>>1]|0)+(b[(c[l>>2]|0)+((c[q>>2]|0)+2<<1)>>1]|0)+(b[(c[l>>2]|0)+((c[q>>2]|0)+1<<1)>>1]<<1)<<9;r=_(c[u>>2]>>16,(c[w>>2]&65535)<<16>>16)|0;c[u>>2]=(b[(c[m>>2]|0)+((c[q>>2]|0)+1<<1)>>1]<<8)+(r+((_(c[u>>2]&65535,(c[w>>2]&65535)<<16>>16)|0)>>16));r=_(b[(c[l>>2]|0)+((c[q>>2]|0)+1<<1)>>1]<<11>>16,(c[x>>2]&65535)<<16>>16)|0;c[u>>2]=(c[u>>2]|0)+(r+((_(b[(c[l>>2]|0)+((c[q>>2]|0)+1<<1)>>1]<<11&65535,(c[x>>2]&65535)<<16>>16)|0)>>16));if(((c[u>>2]>>7)+1>>1|0)<=32767)if(((c[u>>2]>>7)+1>>1|0)<-32768)y=-32768;else y=(c[u>>2]>>7)+1>>1;else y=32767;b[(c[m>>2]|0)+((c[q>>2]|0)+1<<1)>>1]=y;c[q>>2]=(c[q>>2]|0)+1}c[w>>2]=c[c[n>>2]>>2];c[x>>2]=c[(c[n>>2]|0)+4>>2];c[q>>2]=c[o>>2]<<3;while(1){if((c[q>>2]|0)>=(c[p>>2]|0))break;c[u>>2]=(b[(c[l>>2]|0)+(c[q>>2]<<1)>>1]|0)+(b[(c[l>>2]|0)+((c[q>>2]|0)+2<<1)>>1]|0)+(b[(c[l>>2]|0)+((c[q>>2]|0)+1<<1)>>1]<<1)<<9;o=_(c[u>>2]>>16,(c[w>>2]&65535)<<16>>16)|0;c[u>>2]=(b[(c[m>>2]|0)+((c[q>>2]|0)+1<<1)>>1]<<8)+(o+((_(c[u>>2]&65535,(c[w>>2]&65535)<<16>>16)|0)>>16));o=_(b[(c[l>>2]|0)+((c[q>>2]|0)+1<<1)>>1]<<11>>16,(c[x>>2]&65535)<<16>>16)|0;c[u>>2]=(c[u>>2]|0)+(o+((_(b[(c[l>>2]|0)+((c[q>>2]|0)+1<<1)>>1]<<11&65535,(c[x>>2]&65535)<<16>>16)|0)>>16));if(((c[u>>2]>>7)+1>>1|0)<=32767)if(((c[u>>2]>>7)+1>>1|0)<-32768)z=-32768;else z=(c[u>>2]>>7)+1>>1;else z=32767;b[(c[m>>2]|0)+((c[q>>2]|0)+1<<1)>>1]=z;c[q>>2]=(c[q>>2]|0)+1}b[c[k>>2]>>1]=c[c[n>>2]>>2];b[(c[k>>2]|0)+2>>1]=c[(c[n>>2]|0)+4>>2];c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[p>>2]|0))break;c[u>>2]=(b[(c[l>>2]|0)+((c[q>>2]|0)+1<<1)>>1]|0)+(b[(c[m>>2]|0)+((c[q>>2]|0)+1<<1)>>1]|0);c[v>>2]=(b[(c[l>>2]|0)+((c[q>>2]|0)+1<<1)>>1]|0)-(b[(c[m>>2]|0)+((c[q>>2]|0)+1<<1)>>1]|0);if((c[u>>2]|0)>32767)A=32767;else A=(c[u>>2]|0)<-32768?-32768:c[u>>2]|0;b[(c[l>>2]|0)+((c[q>>2]|0)+1<<1)>>1]=A;if((c[v>>2]|0)>32767)B=32767;else B=(c[v>>2]|0)<-32768?-32768:c[v>>2]|0;b[(c[m>>2]|0)+((c[q>>2]|0)+1<<1)>>1]=B;c[q>>2]=(c[q>>2]|0)+1}i=j;return}function dc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[k>>2]=(c[h>>2]|0)-65536;c[j>>2]=0;while(1){l=c[h>>2]>>16;if((c[j>>2]|0)>=((c[g>>2]|0)-1|0))break;d=_(l,(c[(c[f>>2]|0)+(c[j>>2]<<2)>>2]&65535)<<16>>16)|0;b=d+((_(c[h>>2]&65535,(c[(c[f>>2]|0)+(c[j>>2]<<2)>>2]&65535)<<16>>16)|0)>>16)|0;d=b+(_(c[h>>2]|0,(c[(c[f>>2]|0)+(c[j>>2]<<2)>>2]>>15)+1>>1)|0)|0;c[(c[f>>2]|0)+(c[j>>2]<<2)>>2]=d;d=((_(c[h>>2]|0,c[k>>2]|0)|0)>>15)+1>>1;c[h>>2]=(c[h>>2]|0)+d;c[j>>2]=(c[j>>2]|0)+1}j=_(l,(c[(c[f>>2]|0)+((c[g>>2]|0)-1<<2)>>2]&65535)<<16>>16)|0;l=j+((_(c[h>>2]&65535,(c[(c[f>>2]|0)+((c[g>>2]|0)-1<<2)>>2]&65535)<<16>>16)|0)>>16)|0;j=l+(_(c[h>>2]|0,(c[(c[f>>2]|0)+((c[g>>2]|0)-1<<2)>>2]>>15)+1>>1)|0)|0;c[(c[f>>2]|0)+((c[g>>2]|0)-1<<2)>>2]=j;i=e;return}function ec(a,d,e){a=a|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[g>>2]=a;c[h>>2]=d;c[j>>2]=e;c[l>>2]=(c[j>>2]|0)-65536;c[k>>2]=0;while(1){m=c[j>>2]|0;if((c[k>>2]|0)>=((c[h>>2]|0)-1|0))break;e=((_(m,b[(c[g>>2]|0)+(c[k>>2]<<1)>>1]|0)|0)>>15)+1>>1&65535;b[(c[g>>2]|0)+(c[k>>2]<<1)>>1]=e;e=((_(c[j>>2]|0,c[l>>2]|0)|0)>>15)+1>>1;c[j>>2]=(c[j>>2]|0)+e;c[k>>2]=(c[k>>2]|0)+1}k=((_(m,b[(c[g>>2]|0)+((c[h>>2]|0)-1<<1)>>1]|0)|0)>>15)+1>>1&65535;b[(c[g>>2]|0)+((c[h>>2]|0)-1<<1)>>1]=k;i=f;return}function fc(d,e,f,g,h){d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;j=i;i=i+48|0;k=j+36|0;l=j+38|0;m=j+8|0;n=j+20|0;o=j+28|0;p=j+32|0;q=j+12|0;r=j+24|0;s=j+4|0;t=j;u=j+16|0;b[k>>1]=d;a[l>>0]=e;c[m>>2]=f;c[n>>2]=g;c[o>>2]=h;h=(c[o>>2]|0)==4;do if((c[n>>2]|0)==8)if(h){c[u>>2]=1840;c[t>>2]=11;break}else{c[u>>2]=1808;c[t>>2]=3;break}else if(h){c[u>>2]=1888;c[t>>2]=34;break}else{c[u>>2]=1816;c[t>>2]=12;break}while(0);c[r>>2]=(c[n>>2]&65535)<<16>>16<<1;c[s>>2]=((c[n>>2]&65535)<<16>>16)*18;c[p>>2]=(c[r>>2]|0)+(b[k>>1]|0);c[q>>2]=0;while(1){if((c[q>>2]|0)>=(c[o>>2]|0))break;k=_(c[q>>2]|0,c[t>>2]|0)|0;c[(c[m>>2]|0)+(c[q>>2]<<2)>>2]=(c[p>>2]|0)+(a[(c[u>>2]|0)+(k+(a[l>>0]|0))>>0]|0);k=c[(c[m>>2]|0)+(c[q>>2]<<2)>>2]|0;do if((c[r>>2]|0)>(c[s>>2]|0)){if((k|0)>(c[r>>2]|0)){v=c[r>>2]|0;break}if((c[(c[m>>2]|0)+(c[q>>2]<<2)>>2]|0)<(c[s>>2]|0)){v=c[s>>2]|0;break}else{v=c[(c[m>>2]|0)+(c[q>>2]<<2)>>2]|0;break}}else{if((k|0)>(c[s>>2]|0)){v=c[s>>2]|0;break}if((c[(c[m>>2]|0)+(c[q>>2]<<2)>>2]|0)<(c[r>>2]|0)){v=c[r>>2]|0;break}else{v=c[(c[m>>2]|0)+(c[q>>2]<<2)>>2]|0;break}}while(0);c[(c[m>>2]|0)+(c[q>>2]<<2)>>2]=v;c[q>>2]=(c[q>>2]|0)+1}i=j;return}function gc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0;b=i;i=i+16|0;d=b+12|0;e=b+8|0;f=b+4|0;g=b;c[e>>2]=a;if((c[e>>2]|0)<0){c[d>>2]=0;h=c[d>>2]|0;i=b;return h|0}if((c[e>>2]|0)>=3967){c[d>>2]=2147483647;h=c[d>>2]|0;i=b;return h|0}c[f>>2]=1<<(c[e>>2]>>7);c[g>>2]=c[e>>2]&127;a=c[f>>2]|0;j=c[f>>2]|0;if((c[e>>2]|0)<2048){e=_((_((c[g>>2]&65535)<<16>>16,(128-(c[g>>2]|0)&65535)<<16>>16)|0)>>16,-174)|0;c[f>>2]=a+((_(j,(c[g>>2]|0)+(e+((_((_((c[g>>2]&65535)<<16>>16,(128-(c[g>>2]|0)&65535)<<16>>16)|0)&65535,-174)|0)>>16))|0)|0)>>7)}else{e=_((_((c[g>>2]&65535)<<16>>16,(128-(c[g>>2]|0)&65535)<<16>>16)|0)>>16,-174)|0;c[f>>2]=a+(_(j>>7,(c[g>>2]|0)+(e+((_((_((c[g>>2]&65535)<<16>>16,(128-(c[g>>2]|0)&65535)<<16>>16)|0)&65535,-174)|0)>>16))|0)|0)}c[d>>2]=c[f>>2];h=c[d>>2]|0;i=b;return h|0}function hc(a,d,e,f,g){a=a|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;h=i;i=i+48|0;j=h;k=h+16|0;l=h+28|0;m=h+4|0;n=h+32|0;o=h+36|0;p=h+12|0;q=h+24|0;r=h+20|0;s=h+8|0;c[j>>2]=a;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[p>>2]=c[n>>2];while(1){if((c[p>>2]|0)>=(c[m>>2]|0))break;c[s>>2]=(c[k>>2]|0)+((c[p>>2]|0)-1<<1);c[q>>2]=_(b[c[s>>2]>>1]|0,b[c[l>>2]>>1]|0)|0;c[q>>2]=(c[q>>2]|0)+(_(b[(c[s>>2]|0)+-2>>1]|0,b[(c[l>>2]|0)+2>>1]|0)|0);c[q>>2]=(c[q>>2]|0)+(_(b[(c[s>>2]|0)+-4>>1]|0,b[(c[l>>2]|0)+4>>1]|0)|0);c[q>>2]=(c[q>>2]|0)+(_(b[(c[s>>2]|0)+-6>>1]|0,b[(c[l>>2]|0)+6>>1]|0)|0);c[q>>2]=(c[q>>2]|0)+(_(b[(c[s>>2]|0)+-8>>1]|0,b[(c[l>>2]|0)+8>>1]|0)|0);c[q>>2]=(c[q>>2]|0)+(_(b[(c[s>>2]|0)+-10>>1]|0,b[(c[l>>2]|0)+10>>1]|0)|0);c[o>>2]=6;while(1){if((c[o>>2]|0)>=(c[n>>2]|0))break;c[q>>2]=(c[q>>2]|0)+(_(b[(c[s>>2]|0)+(0-(c[o>>2]|0)<<1)>>1]|0,b[(c[l>>2]|0)+(c[o>>2]<<1)>>1]|0)|0);c[q>>2]=(c[q>>2]|0)+(_(b[(c[s>>2]|0)+(0-(c[o>>2]|0)-1<<1)>>1]|0,b[(c[l>>2]|0)+((c[o>>2]|0)+1<<1)>>1]|0)|0);c[o>>2]=(c[o>>2]|0)+2}c[q>>2]=(b[(c[s>>2]|0)+2>>1]<<12)-(c[q>>2]|0);c[r>>2]=(c[q>>2]>>11)+1>>1;if((c[r>>2]|0)>32767)t=32767;else t=(c[r>>2]|0)<-32768?-32768:c[r>>2]|0;b[(c[j>>2]|0)+(c[p>>2]<<1)>>1]=t;c[p>>2]=(c[p>>2]|0)+1}bf(c[j>>2]|0,0,c[n>>2]<<1|0)|0;i=h;return}function ic(a,d){a=a|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;e=i;i=i+160|0;f=e+136|0;g=e+144|0;h=e+148|0;j=e+152|0;k=e+8|0;l=e;m=e+140|0;c[g>>2]=a;c[h>>2]=d;c[m>>2]=0;c[l>>2]=k+((c[h>>2]&1)<<6);c[j>>2]=0;while(1){if((c[j>>2]|0)>=(c[h>>2]|0))break;c[m>>2]=(c[m>>2]|0)+(b[(c[g>>2]|0)+(c[j>>2]<<1)>>1]|0);c[(c[l>>2]|0)+(c[j>>2]<<2)>>2]=b[(c[g>>2]|0)+(c[j>>2]<<1)>>1]<<12;c[j>>2]=(c[j>>2]|0)+1}if((c[m>>2]|0)>=4096){c[f>>2]=0;n=c[f>>2]|0;i=e;return n|0}else{c[f>>2]=Pd(k,c[h>>2]|0)|0;n=c[f>>2]|0;i=e;return n|0}return 0}function jc(a,e,f){a=a|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0;g=i;i=i+272|0;h=g+264|0;j=g+48|0;k=g+24|0;l=g+36|0;m=g+224|0;n=g+16|0;o=g+20|0;p=g+120|0;q=g+188|0;r=g+228|0;s=g+268|0;t=g+40|0;u=g+44|0;v=g+8|0;w=g;x=g+4|0;y=g+56|0;z=g+28|0;A=g+184|0;B=g+12|0;C=g+32|0;c[h>>2]=a;c[j>>2]=e;c[k>>2]=f;c[B>>2]=0;c[l>>2]=(c[k>>2]|0)==16?2968:2984;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break;c[u>>2]=b[(c[j>>2]|0)+(c[m>>2]<<1)>>1]>>8;c[v>>2]=(b[(c[j>>2]|0)+(c[m>>2]<<1)>>1]|0)-(c[u>>2]<<8);c[w>>2]=b[1544+(c[u>>2]<<1)>>1];c[x>>2]=(b[1544+((c[u>>2]|0)+1<<1)>>1]|0)-(c[w>>2]|0);f=((c[w>>2]<<8)+(_(c[x>>2]|0,c[v>>2]|0)|0)>>3)+1>>1;c[p+(d[(c[l>>2]|0)+(c[m>>2]|0)>>0]<<2)>>2]=f;c[m>>2]=(c[m>>2]|0)+1}c[o>>2]=c[k>>2]>>1;Qd(q,p,c[o>>2]|0);Qd(r,p+4|0,c[o>>2]|0);c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[o>>2]|0))break;c[s>>2]=(c[q+((c[m>>2]|0)+1<<2)>>2]|0)+(c[q+(c[m>>2]<<2)>>2]|0);c[t>>2]=(c[r+((c[m>>2]|0)+1<<2)>>2]|0)-(c[r+(c[m>>2]<<2)>>2]|0);c[y+(c[m>>2]<<2)>>2]=0-(c[t>>2]|0)-(c[s>>2]|0);c[y+((c[k>>2]|0)-(c[m>>2]|0)-1<<2)>>2]=(c[t>>2]|0)-(c[s>>2]|0);c[m>>2]=(c[m>>2]|0)+1}c[n>>2]=0;while(1){if((c[n>>2]|0)>=10)break;c[z>>2]=0;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break;s=c[y+(c[m>>2]<<2)>>2]|0;c[A>>2]=(c[y+(c[m>>2]<<2)>>2]|0)>0?s:0-s|0;if((c[A>>2]|0)>(c[z>>2]|0)){c[z>>2]=c[A>>2];c[B>>2]=c[m>>2]}c[m>>2]=(c[m>>2]|0)+1}c[z>>2]=(c[z>>2]>>4)+1>>1;if((c[z>>2]|0)<=32767)break;c[z>>2]=(c[z>>2]|0)<163838?c[z>>2]|0:163838;c[C>>2]=65470-(((c[z>>2]|0)-32767<<14|0)/((_(c[z>>2]|0,(c[B>>2]|0)+1|0)|0)>>2|0)|0);dc(y,c[k>>2]|0,c[C>>2]|0);c[n>>2]=(c[n>>2]|0)+1}C=(c[n>>2]|0)==10;c[m>>2]=0;a:do if(C)while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break a;if(((c[y+(c[m>>2]<<2)>>2]>>4)+1>>1|0)<=32767)if(((c[y+(c[m>>2]<<2)>>2]>>4)+1>>1|0)<-32768)D=-32768;else D=(c[y+(c[m>>2]<<2)>>2]>>4)+1>>1;else D=32767;b[(c[h>>2]|0)+(c[m>>2]<<1)>>1]=D;c[y+(c[m>>2]<<2)>>2]=b[(c[h>>2]|0)+(c[m>>2]<<1)>>1]<<5;c[m>>2]=(c[m>>2]|0)+1}else while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break a;b[(c[h>>2]|0)+(c[m>>2]<<1)>>1]=(c[y+(c[m>>2]<<2)>>2]>>4)+1>>1;c[m>>2]=(c[m>>2]|0)+1}while(0);c[n>>2]=0;while(1){if((c[n>>2]|0)>=16){E=31;break}if((ic(c[h>>2]|0,c[k>>2]|0)|0)>=107374){E=31;break}dc(y,c[k>>2]|0,65536-(2<<c[n>>2])|0);c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break;b[(c[h>>2]|0)+(c[m>>2]<<1)>>1]=(c[y+(c[m>>2]<<2)>>2]>>4)+1>>1;c[m>>2]=(c[m>>2]|0)+1}c[n>>2]=(c[n>>2]|0)+1}if((E|0)==31){i=g;return}}
+function Td(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}function Ud(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)<(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}function Vd(a,d,e,f,g,h,j){a=a|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;k=i;i=i+48|0;l=k;m=k+8|0;n=k+36|0;o=k+16|0;p=k+32|0;q=k+40|0;r=k+44|0;s=k+24|0;t=k+20|0;u=k+12|0;v=k+4|0;w=k+28|0;c[l>>2]=a;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=g;c[q>>2]=h;c[r>>2]=j;j=c[o>>2]|0;if((j|0)==18){c[s>>2]=0;while(1){if((c[s>>2]|0)>=(c[q>>2]|0))break;c[u>>2]=(c[m>>2]|0)+(c[s>>2]>>16<<2);o=_((c[s>>2]&65535)>>16,(c[p>>2]&65535)<<16>>16)|0;c[v>>2]=o+((_(c[s>>2]&65535,(c[p>>2]&65535)<<16>>16)|0)>>16);c[w>>2]=(c[n>>2]|0)+((c[v>>2]|0)*9<<1);o=_(c[c[u>>2]>>2]>>16,b[c[w>>2]>>1]|0)|0;c[t>>2]=o+((_(c[c[u>>2]>>2]&65535,b[c[w>>2]>>1]|0)|0)>>16);o=_(c[(c[u>>2]|0)+4>>2]>>16,b[(c[w>>2]|0)+2>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+4>>2]&65535,b[(c[w>>2]|0)+2>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+8>>2]>>16,b[(c[w>>2]|0)+4>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+8>>2]&65535,b[(c[w>>2]|0)+4>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+12>>2]>>16,b[(c[w>>2]|0)+6>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+12>>2]&65535,b[(c[w>>2]|0)+6>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+16>>2]>>16,b[(c[w>>2]|0)+8>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+16>>2]&65535,b[(c[w>>2]|0)+8>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+20>>2]>>16,b[(c[w>>2]|0)+10>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+20>>2]&65535,b[(c[w>>2]|0)+10>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+24>>2]>>16,b[(c[w>>2]|0)+12>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+24>>2]&65535,b[(c[w>>2]|0)+12>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+28>>2]>>16,b[(c[w>>2]|0)+14>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+28>>2]&65535,b[(c[w>>2]|0)+14>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+32>>2]>>16,b[(c[w>>2]|0)+16>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+32>>2]&65535,b[(c[w>>2]|0)+16>>1]|0)|0)>>16));c[w>>2]=(c[n>>2]|0)+(((c[p>>2]|0)-1-(c[v>>2]|0)|0)*9<<1);o=_(c[(c[u>>2]|0)+68>>2]>>16,b[c[w>>2]>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+68>>2]&65535,b[c[w>>2]>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+64>>2]>>16,b[(c[w>>2]|0)+2>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+64>>2]&65535,b[(c[w>>2]|0)+2>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+60>>2]>>16,b[(c[w>>2]|0)+4>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+60>>2]&65535,b[(c[w>>2]|0)+4>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+56>>2]>>16,b[(c[w>>2]|0)+6>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+56>>2]&65535,b[(c[w>>2]|0)+6>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+52>>2]>>16,b[(c[w>>2]|0)+8>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+52>>2]&65535,b[(c[w>>2]|0)+8>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+48>>2]>>16,b[(c[w>>2]|0)+10>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+48>>2]&65535,b[(c[w>>2]|0)+10>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+44>>2]>>16,b[(c[w>>2]|0)+12>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+44>>2]&65535,b[(c[w>>2]|0)+12>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+40>>2]>>16,b[(c[w>>2]|0)+14>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+40>>2]&65535,b[(c[w>>2]|0)+14>>1]|0)|0)>>16));o=_(c[(c[u>>2]|0)+36>>2]>>16,b[(c[w>>2]|0)+16>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(o+((_(c[(c[u>>2]|0)+36>>2]&65535,b[(c[w>>2]|0)+16>>1]|0)|0)>>16));if(((c[t>>2]>>5)+1>>1|0)<=32767)if(((c[t>>2]>>5)+1>>1|0)<-32768)x=-32768;else x=(c[t>>2]>>5)+1>>1;else x=32767;o=c[l>>2]|0;c[l>>2]=o+2;b[o>>1]=x;c[s>>2]=(c[s>>2]|0)+(c[r>>2]|0)}y=c[l>>2]|0;i=k;return y|0}else if((j|0)==24){c[s>>2]=0;while(1){if((c[s>>2]|0)>=(c[q>>2]|0))break;c[u>>2]=(c[m>>2]|0)+(c[s>>2]>>16<<2);x=_((c[c[u>>2]>>2]|0)+(c[(c[u>>2]|0)+92>>2]|0)>>16,b[c[n>>2]>>1]|0)|0;c[t>>2]=x+((_((c[c[u>>2]>>2]|0)+(c[(c[u>>2]|0)+92>>2]|0)&65535,b[c[n>>2]>>1]|0)|0)>>16);x=_((c[(c[u>>2]|0)+4>>2]|0)+(c[(c[u>>2]|0)+88>>2]|0)>>16,b[(c[n>>2]|0)+2>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+4>>2]|0)+(c[(c[u>>2]|0)+88>>2]|0)&65535,b[(c[n>>2]|0)+2>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+8>>2]|0)+(c[(c[u>>2]|0)+84>>2]|0)>>16,b[(c[n>>2]|0)+4>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+8>>2]|0)+(c[(c[u>>2]|0)+84>>2]|0)&65535,b[(c[n>>2]|0)+4>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+12>>2]|0)+(c[(c[u>>2]|0)+80>>2]|0)>>16,b[(c[n>>2]|0)+6>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+12>>2]|0)+(c[(c[u>>2]|0)+80>>2]|0)&65535,b[(c[n>>2]|0)+6>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+16>>2]|0)+(c[(c[u>>2]|0)+76>>2]|0)>>16,b[(c[n>>2]|0)+8>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+16>>2]|0)+(c[(c[u>>2]|0)+76>>2]|0)&65535,b[(c[n>>2]|0)+8>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+20>>2]|0)+(c[(c[u>>2]|0)+72>>2]|0)>>16,b[(c[n>>2]|0)+10>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+20>>2]|0)+(c[(c[u>>2]|0)+72>>2]|0)&65535,b[(c[n>>2]|0)+10>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+24>>2]|0)+(c[(c[u>>2]|0)+68>>2]|0)>>16,b[(c[n>>2]|0)+12>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+24>>2]|0)+(c[(c[u>>2]|0)+68>>2]|0)&65535,b[(c[n>>2]|0)+12>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+28>>2]|0)+(c[(c[u>>2]|0)+64>>2]|0)>>16,b[(c[n>>2]|0)+14>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+28>>2]|0)+(c[(c[u>>2]|0)+64>>2]|0)&65535,b[(c[n>>2]|0)+14>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+32>>2]|0)+(c[(c[u>>2]|0)+60>>2]|0)>>16,b[(c[n>>2]|0)+16>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+32>>2]|0)+(c[(c[u>>2]|0)+60>>2]|0)&65535,b[(c[n>>2]|0)+16>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+36>>2]|0)+(c[(c[u>>2]|0)+56>>2]|0)>>16,b[(c[n>>2]|0)+18>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+36>>2]|0)+(c[(c[u>>2]|0)+56>>2]|0)&65535,b[(c[n>>2]|0)+18>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+40>>2]|0)+(c[(c[u>>2]|0)+52>>2]|0)>>16,b[(c[n>>2]|0)+20>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+40>>2]|0)+(c[(c[u>>2]|0)+52>>2]|0)&65535,b[(c[n>>2]|0)+20>>1]|0)|0)>>16));x=_((c[(c[u>>2]|0)+44>>2]|0)+(c[(c[u>>2]|0)+48>>2]|0)>>16,b[(c[n>>2]|0)+22>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(x+((_((c[(c[u>>2]|0)+44>>2]|0)+(c[(c[u>>2]|0)+48>>2]|0)&65535,b[(c[n>>2]|0)+22>>1]|0)|0)>>16));if(((c[t>>2]>>5)+1>>1|0)<=32767)if(((c[t>>2]>>5)+1>>1|0)<-32768)z=-32768;else z=(c[t>>2]>>5)+1>>1;else z=32767;x=c[l>>2]|0;c[l>>2]=x+2;b[x>>1]=z;c[s>>2]=(c[s>>2]|0)+(c[r>>2]|0)}y=c[l>>2]|0;i=k;return y|0}else if((j|0)==36){c[s>>2]=0;while(1){if((c[s>>2]|0)>=(c[q>>2]|0))break;c[u>>2]=(c[m>>2]|0)+(c[s>>2]>>16<<2);j=_((c[c[u>>2]>>2]|0)+(c[(c[u>>2]|0)+140>>2]|0)>>16,b[c[n>>2]>>1]|0)|0;c[t>>2]=j+((_((c[c[u>>2]>>2]|0)+(c[(c[u>>2]|0)+140>>2]|0)&65535,b[c[n>>2]>>1]|0)|0)>>16);j=_((c[(c[u>>2]|0)+4>>2]|0)+(c[(c[u>>2]|0)+136>>2]|0)>>16,b[(c[n>>2]|0)+2>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+4>>2]|0)+(c[(c[u>>2]|0)+136>>2]|0)&65535,b[(c[n>>2]|0)+2>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+8>>2]|0)+(c[(c[u>>2]|0)+132>>2]|0)>>16,b[(c[n>>2]|0)+4>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+8>>2]|0)+(c[(c[u>>2]|0)+132>>2]|0)&65535,b[(c[n>>2]|0)+4>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+12>>2]|0)+(c[(c[u>>2]|0)+128>>2]|0)>>16,b[(c[n>>2]|0)+6>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+12>>2]|0)+(c[(c[u>>2]|0)+128>>2]|0)&65535,b[(c[n>>2]|0)+6>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+16>>2]|0)+(c[(c[u>>2]|0)+124>>2]|0)>>16,b[(c[n>>2]|0)+8>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+16>>2]|0)+(c[(c[u>>2]|0)+124>>2]|0)&65535,b[(c[n>>2]|0)+8>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+20>>2]|0)+(c[(c[u>>2]|0)+120>>2]|0)>>16,b[(c[n>>2]|0)+10>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+20>>2]|0)+(c[(c[u>>2]|0)+120>>2]|0)&65535,b[(c[n>>2]|0)+10>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+24>>2]|0)+(c[(c[u>>2]|0)+116>>2]|0)>>16,b[(c[n>>2]|0)+12>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+24>>2]|0)+(c[(c[u>>2]|0)+116>>2]|0)&65535,b[(c[n>>2]|0)+12>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+28>>2]|0)+(c[(c[u>>2]|0)+112>>2]|0)>>16,b[(c[n>>2]|0)+14>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+28>>2]|0)+(c[(c[u>>2]|0)+112>>2]|0)&65535,b[(c[n>>2]|0)+14>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+32>>2]|0)+(c[(c[u>>2]|0)+108>>2]|0)>>16,b[(c[n>>2]|0)+16>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+32>>2]|0)+(c[(c[u>>2]|0)+108>>2]|0)&65535,b[(c[n>>2]|0)+16>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+36>>2]|0)+(c[(c[u>>2]|0)+104>>2]|0)>>16,b[(c[n>>2]|0)+18>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+36>>2]|0)+(c[(c[u>>2]|0)+104>>2]|0)&65535,b[(c[n>>2]|0)+18>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+40>>2]|0)+(c[(c[u>>2]|0)+100>>2]|0)>>16,b[(c[n>>2]|0)+20>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+40>>2]|0)+(c[(c[u>>2]|0)+100>>2]|0)&65535,b[(c[n>>2]|0)+20>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+44>>2]|0)+(c[(c[u>>2]|0)+96>>2]|0)>>16,b[(c[n>>2]|0)+22>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+44>>2]|0)+(c[(c[u>>2]|0)+96>>2]|0)&65535,b[(c[n>>2]|0)+22>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+48>>2]|0)+(c[(c[u>>2]|0)+92>>2]|0)>>16,b[(c[n>>2]|0)+24>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+48>>2]|0)+(c[(c[u>>2]|0)+92>>2]|0)&65535,b[(c[n>>2]|0)+24>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+52>>2]|0)+(c[(c[u>>2]|0)+88>>2]|0)>>16,b[(c[n>>2]|0)+26>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+52>>2]|0)+(c[(c[u>>2]|0)+88>>2]|0)&65535,b[(c[n>>2]|0)+26>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+56>>2]|0)+(c[(c[u>>2]|0)+84>>2]|0)>>16,b[(c[n>>2]|0)+28>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+56>>2]|0)+(c[(c[u>>2]|0)+84>>2]|0)&65535,b[(c[n>>2]|0)+28>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+60>>2]|0)+(c[(c[u>>2]|0)+80>>2]|0)>>16,b[(c[n>>2]|0)+30>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+60>>2]|0)+(c[(c[u>>2]|0)+80>>2]|0)&65535,b[(c[n>>2]|0)+30>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+64>>2]|0)+(c[(c[u>>2]|0)+76>>2]|0)>>16,b[(c[n>>2]|0)+32>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+64>>2]|0)+(c[(c[u>>2]|0)+76>>2]|0)&65535,b[(c[n>>2]|0)+32>>1]|0)|0)>>16));j=_((c[(c[u>>2]|0)+68>>2]|0)+(c[(c[u>>2]|0)+72>>2]|0)>>16,b[(c[n>>2]|0)+34>>1]|0)|0;c[t>>2]=(c[t>>2]|0)+(j+((_((c[(c[u>>2]|0)+68>>2]|0)+(c[(c[u>>2]|0)+72>>2]|0)&65535,b[(c[n>>2]|0)+34>>1]|0)|0)>>16));if(((c[t>>2]>>5)+1>>1|0)<=32767)if(((c[t>>2]>>5)+1>>1|0)<-32768)A=-32768;else A=(c[t>>2]>>5)+1>>1;else A=32767;j=c[l>>2]|0;c[l>>2]=j+2;b[j>>1]=A;c[s>>2]=(c[s>>2]|0)+(c[r>>2]|0)}y=c[l>>2]|0;i=k;return y|0}else{y=c[l>>2]|0;i=k;return y|0}return 0}function Wd(a,d,e,f){a=a|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;g=i;i=i+32|0;h=g+4|0;j=g+16|0;k=g+8|0;l=g+20|0;m=g+28|0;n=g;o=g+12|0;p=g+24|0;c[h>>2]=a;c[j>>2]=d;c[k>>2]=e;c[l>>2]=f;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break;c[p>>2]=(((c[m>>2]&65535)>>16)*12|0)+((c[m>>2]&65535)*12>>16);c[o>>2]=(c[j>>2]|0)+(c[m>>2]>>16<<1);c[n>>2]=_(b[c[o>>2]>>1]|0,b[2280+(c[p>>2]<<3)>>1]|0)|0;c[n>>2]=(c[n>>2]|0)+(_(b[(c[o>>2]|0)+2>>1]|0,b[2280+(c[p>>2]<<3)+2>>1]|0)|0);c[n>>2]=(c[n>>2]|0)+(_(b[(c[o>>2]|0)+4>>1]|0,b[2280+(c[p>>2]<<3)+4>>1]|0)|0);c[n>>2]=(c[n>>2]|0)+(_(b[(c[o>>2]|0)+6>>1]|0,b[2280+(c[p>>2]<<3)+6>>1]|0)|0);c[n>>2]=(c[n>>2]|0)+(_(b[(c[o>>2]|0)+8>>1]|0,b[2280+(11-(c[p>>2]|0)<<3)+6>>1]|0)|0);c[n>>2]=(c[n>>2]|0)+(_(b[(c[o>>2]|0)+10>>1]|0,b[2280+(11-(c[p>>2]|0)<<3)+4>>1]|0)|0);c[n>>2]=(c[n>>2]|0)+(_(b[(c[o>>2]|0)+12>>1]|0,b[2280+(11-(c[p>>2]|0)<<3)+2>>1]|0)|0);c[n>>2]=(c[n>>2]|0)+(_(b[(c[o>>2]|0)+14>>1]|0,b[2280+(11-(c[p>>2]|0)<<3)>>1]|0)|0);if(((c[n>>2]>>14)+1>>1|0)<=32767)if(((c[n>>2]>>14)+1>>1|0)<-32768)q=-32768;else q=(c[n>>2]>>14)+1>>1;else q=32767;f=c[h>>2]|0;c[h>>2]=f+2;b[f>>1]=q;c[m>>2]=(c[m>>2]|0)+(c[l>>2]|0)}i=g;return c[h>>2]|0}function Xd(a,e,f){a=a|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0;g=i;i=i+16|0;h=g+12|0;j=g+8|0;k=g+4|0;l=g;c[j>>2]=a;c[k>>2]=e;c[l>>2]=f;if((c[k>>2]|0)<1){b[c[l>>2]>>1]=-1;c[h>>2]=-1;m=c[h>>2]|0;i=g;return m|0}if((d[c[j>>2]>>0]|0|0)<252){b[c[l>>2]>>1]=d[c[j>>2]>>0]|0;c[h>>2]=1;m=c[h>>2]|0;i=g;return m|0}if((c[k>>2]|0)<2){b[c[l>>2]>>1]=-1;c[h>>2]=-1;m=c[h>>2]|0;i=g;return m|0}else{b[c[l>>2]>>1]=((d[(c[j>>2]|0)+1>>0]|0)<<2)+(d[c[j>>2]>>0]|0);c[h>>2]=2;m=c[h>>2]|0;i=g;return m|0}return 0}function Yd(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;i=b;return (c[d>>2]|0)+4-1&-4|0}function Zd(d,e,f,h,j,k){d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0;l=i;i=i+320|0;m=l;n=l+72|0;o=l+48|0;p=l+40|0;q=l+24|0;r=l+8|0;s=l+16|0;t=l+56|0;u=l+80|0;v=l+64|0;w=l+32|0;x=l+100|0;y=l+96|0;z=l+88|0;A=l+84|0;B=l+256|0;C=l+252|0;D=l+220|0;E=l+200|0;F=l+192|0;G=l+172|0;H=l+168|0;I=l+160|0;J=l+112|0;K=l+272|0;L=l+284|0;M=l+292|0;N=l+300|0;O=l+304|0;P=l+180|0;Q=l+184|0;R=l+280|0;S=l+288|0;T=l+296|0;U=l+248|0;V=l+216|0;W=l+204|0;Y=l+208|0;Z=l+212|0;$=l+188|0;aa=l+228|0;ba=l+232|0;ca=l+276|0;da=l+164|0;ea=l+236|0;fa=l+240|0;ga=l+244|0;ha=l+92|0;ia=l+104|0;ja=l+260|0;la=l+308|0;ma=l+196|0;na=l+268|0;oa=l+224|0;pa=l+312|0;qa=l+108|0;ra=l+176|0;sa=l+264|0;c[y>>2]=d;c[z>>2]=e;c[A>>2]=f;c[B>>2]=h;c[C>>2]=j;c[D>>2]=k;c[H>>2]=0;c[I>>2]=0;c[O>>2]=0;c[S>>2]=0;c[U>>2]=0;c[V>>2]=0;c[W>>2]=0;c[da>>2]=0;c[E>>2]=(c[y>>2]|0)+(c[(c[y>>2]|0)+4>>2]|0);c[F>>2]=(c[y>>2]|0)+(c[c[y>>2]>>2]|0);c[ba>>2]=(c[(c[y>>2]|0)+12>>2]|0)/50|0;c[aa>>2]=c[ba>>2]>>1;c[$>>2]=c[aa>>2]>>1;c[Z>>2]=c[$>>2]>>1;if((c[C>>2]|0)<(c[Z>>2]|0)){c[x>>2]=-2;ta=c[x>>2]|0;i=l;return ta|0}if((c[C>>2]|0)<(((c[(c[y>>2]|0)+12>>2]|0)/25|0)*3|0))va=c[C>>2]|0;else va=((c[(c[y>>2]|0)+12>>2]|0)/25|0)*3|0;c[C>>2]=va;if((c[A>>2]|0)<=1){c[z>>2]=0;if((c[C>>2]|0)<(c[(c[y>>2]|0)+60>>2]|0))wa=c[C>>2]|0;else wa=c[(c[y>>2]|0)+60>>2]|0;c[C>>2]=wa}do if(!(c[z>>2]|0)){c[Q>>2]=c[C>>2];c[R>>2]=c[(c[y>>2]|0)+56>>2];if(!(c[R>>2]|0)){c[G>>2]=0;while(1){if((c[G>>2]|0)>=(_(c[Q>>2]|0,c[(c[y>>2]|0)+8>>2]|0)|0))break;g[(c[B>>2]|0)+(c[G>>2]<<2)>>2]=0.0;c[G>>2]=(c[G>>2]|0)+1}c[x>>2]=c[Q>>2];ta=c[x>>2]|0;i=l;return ta|0}if((c[Q>>2]|0)>(c[ba>>2]|0)){while(1){c[fa>>2]=Zd(c[y>>2]|0,0,0,c[B>>2]|0,(c[Q>>2]|0)<(c[ba>>2]|0)?c[Q>>2]|0:c[ba>>2]|0,0)|0;xa=c[fa>>2]|0;if((c[fa>>2]|0)<0){ya=20;break}wa=_(xa,c[(c[y>>2]|0)+8>>2]|0)|0;c[B>>2]=(c[B>>2]|0)+(wa<<2);c[Q>>2]=(c[Q>>2]|0)-(c[fa>>2]|0);if((c[Q>>2]|0)<=0){ya=22;break}}if((ya|0)==20){c[x>>2]=xa;ta=c[x>>2]|0;i=l;return ta|0}else if((ya|0)==22){c[x>>2]=c[C>>2];ta=c[x>>2]|0;i=l;return ta|0}}if((c[Q>>2]|0)<(c[ba>>2]|0)){if((c[Q>>2]|0)>(c[aa>>2]|0)){c[Q>>2]=c[aa>>2];break}if(((c[R>>2]|0)!=1e3?(c[Q>>2]|0)>(c[$>>2]|0):0)?(c[Q>>2]|0)<(c[aa>>2]|0):0)c[Q>>2]=c[$>>2]}}else{c[Q>>2]=c[(c[y>>2]|0)+60>>2];c[R>>2]=c[(c[y>>2]|0)+52>>2];eb(J,c[z>>2]|0,c[A>>2]|0)}while(0);c[ea>>2]=0;c[M>>2]=1;c[N>>2]=1;do if((c[z>>2]|0)!=0?(c[(c[y>>2]|0)+56>>2]|0)>0:0){if(!(((c[R>>2]|0)==1002?(c[(c[y>>2]|0)+56>>2]|0)!=1002:0)?(c[(c[y>>2]|0)+64>>2]|0)==0:0)){if((c[R>>2]|0)==1002)break;if((c[(c[y>>2]|0)+56>>2]|0)!=1002)break}c[S>>2]=1;ya=_(c[$>>2]|0,c[(c[y>>2]|0)+8>>2]|0)|0;if((c[R>>2]|0)==1002){c[N>>2]=ya;break}else{c[M>>2]=ya;break}}while(0);ya=c[N>>2]|0;c[ga>>2]=ua()|0;N=i;i=i+((1*(ya<<2)|0)+15&-16)|0;if((c[S>>2]|0)!=0&(c[R>>2]|0)==1002){c[O>>2]=N;Zd(c[y>>2]|0,0,0,c[O>>2]|0,(c[$>>2]|0)<(c[Q>>2]|0)?c[$>>2]|0:c[Q>>2]|0,0)|0}a:do if((c[Q>>2]|0)>(c[C>>2]|0)){c[x>>2]=-1;c[ha>>2]=1}else{c[C>>2]=c[Q>>2];if((c[R>>2]|0)==1002|(c[ea>>2]|0)!=0)za=1;else za=_((c[aa>>2]|0)>(c[C>>2]|0)?c[aa>>2]|0:c[C>>2]|0,c[(c[y>>2]|0)+8>>2]|0)|0;c[L>>2]=za;N=i;i=i+((1*(c[L>>2]<<1)|0)+15&-16)|0;b:do if((c[R>>2]|0)!=1002){c[la>>2]=N;if((c[(c[y>>2]|0)+56>>2]|0)==1002)Vb(c[E>>2]|0)|0;if(10>(((c[Q>>2]|0)*1e3|0)/(c[(c[y>>2]|0)+12>>2]|0)|0|0))Aa=10;else Aa=((c[Q>>2]|0)*1e3|0)/(c[(c[y>>2]|0)+12>>2]|0)|0;c[(c[y>>2]|0)+16+16>>2]=Aa;do if(c[z>>2]|0){c[(c[y>>2]|0)+16+4>>2]=c[(c[y>>2]|0)+44>>2];ya=c[y>>2]|0;if((c[R>>2]|0)!=1e3){c[ya+16+12>>2]=16e3;break}xa=c[y>>2]|0;if((c[ya+48>>2]|0)==1101){c[xa+16+12>>2]=8e3;break}if((c[xa+48>>2]|0)==1102){c[(c[y>>2]|0)+16+12>>2]=12e3;break}else{c[(c[y>>2]|0)+16+12>>2]=16e3;break}}while(0);c[ia>>2]=(c[z>>2]|0)==0?1:c[D>>2]<<1;c[ja>>2]=0;c:while(1){c[ma>>2]=(c[ja>>2]|0)==0&1;c[H>>2]=Wb(c[E>>2]|0,(c[y>>2]|0)+16|0,c[ia>>2]|0,c[ma>>2]|0,J,c[la>>2]|0,K)|0;d:do if(c[H>>2]|0){if(!(c[ia>>2]|0))break c;c[K>>2]=c[C>>2];c[G>>2]=0;while(1){if((c[G>>2]|0)>=(_(c[C>>2]|0,c[(c[y>>2]|0)+8>>2]|0)|0))break d;b[(c[la>>2]|0)+(c[G>>2]<<1)>>1]=0;c[G>>2]=(c[G>>2]|0)+1}}while(0);xa=_(c[K>>2]|0,c[(c[y>>2]|0)+8>>2]|0)|0;c[la>>2]=(c[la>>2]|0)+(xa<<1);c[ja>>2]=(c[ja>>2]|0)+(c[K>>2]|0);if((c[ja>>2]|0)>=(c[C>>2]|0))break b}c[x>>2]=-3;c[ha>>2]=1;break a}while(0);c[T>>2]=0;if((c[D>>2]|0)==0&(c[R>>2]|0)!=1002&(c[z>>2]|0)!=0?(xa=(ge(J)|0)+17|0,(xa+(((c[(c[y>>2]|0)+52>>2]|0)==1001&1)*20|0)|0)<=(c[A>>2]<<3|0)):0){if((c[R>>2]|0)==1001)c[U>>2]=ib(J,12)|0;else c[U>>2]=1;if(c[U>>2]|0){c[W>>2]=ib(J,1)|0;if((c[R>>2]|0)==1001)Ba=(kb(J,256)|0)+2|0;else{xa=c[A>>2]|0;Ba=xa-((ge(J)|0)+7>>3)|0}c[V>>2]=Ba;c[A>>2]=(c[A>>2]|0)-(c[V>>2]|0);xa=c[A>>2]<<3;if((xa|0)<(ge(J)|0)){c[A>>2]=0;c[V>>2]=0;c[U>>2]=0}xa=J+4|0;c[xa>>2]=(c[xa>>2]|0)-(c[V>>2]|0)}}if((c[R>>2]|0)!=1002)c[T>>2]=17;c[na>>2]=21;switch(c[(c[y>>2]|0)+48>>2]|0){case 1101:{c[na>>2]=13;break}case 1103:case 1102:{c[na>>2]=17;break}case 1104:{c[na>>2]=19;break}case 1105:{c[na>>2]=21;break}default:{}}xa=c[F>>2]|0;c[w>>2]=c[na>>2];ab(xa,10012,w)|0;xa=c[F>>2]|0;c[v>>2]=c[(c[y>>2]|0)+44>>2];ab(xa,10008,v)|0;if(c[U>>2]|0){c[S>>2]=0;c[M>>2]=1}xa=i;i=i+((1*(c[M>>2]<<2)|0)+15&-16)|0;if((c[S>>2]|0)!=0&(c[R>>2]|0)!=1002){c[O>>2]=xa;Zd(c[y>>2]|0,0,0,c[O>>2]|0,(c[$>>2]|0)<(c[Q>>2]|0)?c[$>>2]|0:c[Q>>2]|0,0)|0}if(c[U>>2]|0)Ca=_(c[$>>2]|0,c[(c[y>>2]|0)+8>>2]|0)|0;else Ca=1;c[P>>2]=Ca;xa=i;i=i+((1*(c[P>>2]<<2)|0)+15&-16)|0;if((c[U>>2]|0)!=0&(c[W>>2]|0)!=0){ya=c[F>>2]|0;c[u>>2]=0;ab(ya,10010,u)|0;$a(c[F>>2]|0,(c[z>>2]|0)+(c[A>>2]|0)|0,c[V>>2]|0,xa,c[$>>2]|0,0,0)|0;ya=c[F>>2]|0;c[t>>2]=da+(((da-da|0)/4|0)<<2);ab(ya,4031,t)|0}ya=c[F>>2]|0;c[s>>2]=c[T>>2];ab(ya,10010,s)|0;do if((c[R>>2]|0)==1e3){a[pa>>0]=a[5184]|0;a[pa+1>>0]=a[5185]|0;e:do if(!(c[ea>>2]|0)){c[G>>2]=0;while(1){if((c[G>>2]|0)>=(_(c[C>>2]|0,c[(c[y>>2]|0)+8>>2]|0)|0))break e;g[(c[B>>2]|0)+(c[G>>2]<<2)>>2]=0.0;c[G>>2]=(c[G>>2]|0)+1}}while(0);if((c[(c[y>>2]|0)+56>>2]|0)==1001){if((c[U>>2]|0)!=0&(c[W>>2]|0)!=0?(c[(c[y>>2]|0)+64>>2]|0)!=0:0)break;ya=c[F>>2]|0;c[q>>2]=0;ab(ya,10010,q)|0;$a(c[F>>2]|0,pa,2,c[B>>2]|0,c[Z>>2]|0,0,c[ea>>2]|0)|0}}else{c[oa>>2]=(c[ba>>2]|0)<(c[C>>2]|0)?c[ba>>2]|0:c[C>>2]|0;do if((c[R>>2]|0)!=(c[(c[y>>2]|0)+56>>2]|0)){if((c[(c[y>>2]|0)+56>>2]|0)<=0)break;if(c[(c[y>>2]|0)+64>>2]|0)break;ab(c[F>>2]|0,4028,r)|0}while(0);c[I>>2]=$a(c[F>>2]|0,(c[D>>2]|0)!=0?0:c[z>>2]|0,c[A>>2]|0,c[B>>2]|0,c[oa>>2]|0,J,c[ea>>2]|0)|0}while(0);f:do if(!((c[R>>2]|0)==1002|(c[ea>>2]|0)!=0)){c[G>>2]=0;while(1){if((c[G>>2]|0)>=(_(c[C>>2]|0,c[(c[y>>2]|0)+8>>2]|0)|0))break f;g[(c[B>>2]|0)+(c[G>>2]<<2)>>2]=+g[(c[B>>2]|0)+(c[G>>2]<<2)>>2]+ +(b[N+(c[G>>2]<<1)>>1]|0)*.000030517578125;c[G>>2]=(c[G>>2]|0)+1}}while(0);N=c[F>>2]|0;c[p>>2]=qa+(((qa-qa|0)/4|0)<<2);ab(N,10015,p)|0;c[ca>>2]=c[(c[qa>>2]|0)+60>>2];if(!((c[U>>2]|0)==0|(c[W>>2]|0)!=0)){ab(c[F>>2]|0,4028,o)|0;N=c[F>>2]|0;c[n>>2]=0;ab(N,10010,n)|0;$a(c[F>>2]|0,(c[z>>2]|0)+(c[A>>2]|0)|0,c[V>>2]|0,xa,c[$>>2]|0,0,0)|0;N=c[F>>2]|0;c[m>>2]=da+(((da-da|0)/4|0)<<2);ab(N,4031,m)|0;N=(c[B>>2]|0)+((_(c[(c[y>>2]|0)+8>>2]|0,(c[C>>2]|0)-(c[Z>>2]|0)|0)|0)<<2)|0;ya=xa+((_(c[(c[y>>2]|0)+8>>2]|0,c[Z>>2]|0)|0)<<2)|0;fa=(c[B>>2]|0)+((_(c[(c[y>>2]|0)+8>>2]|0,(c[C>>2]|0)-(c[Z>>2]|0)|0)|0)<<2)|0;he(N,ya,fa,c[Z>>2]|0,c[(c[y>>2]|0)+8>>2]|0,c[ca>>2]|0,c[(c[y>>2]|0)+12>>2]|0)}if((c[U>>2]|0)!=0&(c[W>>2]|0)!=0){c[Y>>2]=0;while(1){if((c[Y>>2]|0)>=(c[(c[y>>2]|0)+8>>2]|0))break;c[G>>2]=0;while(1){if((c[G>>2]|0)>=(c[Z>>2]|0))break;fa=_(c[(c[y>>2]|0)+8>>2]|0,c[G>>2]|0)|0;ya=_(c[(c[y>>2]|0)+8>>2]|0,c[G>>2]|0)|0;g[(c[B>>2]|0)+(ya+(c[Y>>2]|0)<<2)>>2]=+g[xa+(fa+(c[Y>>2]|0)<<2)>>2];c[G>>2]=(c[G>>2]|0)+1}c[Y>>2]=(c[Y>>2]|0)+1}fa=xa+((_(c[(c[y>>2]|0)+8>>2]|0,c[Z>>2]|0)|0)<<2)|0;ya=(c[B>>2]|0)+((_(c[(c[y>>2]|0)+8>>2]|0,c[Z>>2]|0)|0)<<2)|0;N=(c[B>>2]|0)+((_(c[(c[y>>2]|0)+8>>2]|0,c[Z>>2]|0)|0)<<2)|0;he(fa,ya,N,c[Z>>2]|0,c[(c[y>>2]|0)+8>>2]|0,c[ca>>2]|0,c[(c[y>>2]|0)+12>>2]|0)}do if(c[S>>2]|0){if((c[Q>>2]|0)<(c[$>>2]|0)){he(c[O>>2]|0,c[B>>2]|0,c[B>>2]|0,c[Z>>2]|0,c[(c[y>>2]|0)+8>>2]|0,c[ca>>2]|0,c[(c[y>>2]|0)+12>>2]|0);break}c[G>>2]=0;while(1){if((c[G>>2]|0)>=(_(c[(c[y>>2]|0)+8>>2]|0,c[Z>>2]|0)|0))break;g[(c[B>>2]|0)+(c[G>>2]<<2)>>2]=+g[(c[O>>2]|0)+(c[G>>2]<<2)>>2];c[G>>2]=(c[G>>2]|0)+1}N=(c[O>>2]|0)+((_(c[(c[y>>2]|0)+8>>2]|0,c[Z>>2]|0)|0)<<2)|0;ya=(c[B>>2]|0)+((_(c[(c[y>>2]|0)+8>>2]|0,c[Z>>2]|0)|0)<<2)|0;fa=(c[B>>2]|0)+((_(c[(c[y>>2]|0)+8>>2]|0,c[Z>>2]|0)|0)<<2)|0;he(N,ya,fa,c[Z>>2]|0,c[(c[y>>2]|0)+8>>2]|0,c[ca>>2]|0,c[(c[y>>2]|0)+12>>2]|0)}while(0);g:do if(c[(c[y>>2]|0)+40>>2]|0){g[ra>>2]=+X(+(+(c[(c[y>>2]|0)+40>>2]|0)*6.488140788860619e-04*.6931471805599453));c[G>>2]=0;while(1){if((c[G>>2]|0)>=(_(c[C>>2]|0,c[(c[y>>2]|0)+8>>2]|0)|0))break g;g[sa>>2]=+g[(c[B>>2]|0)+(c[G>>2]<<2)>>2]*+g[ra>>2];g[(c[B>>2]|0)+(c[G>>2]<<2)>>2]=+g[sa>>2];c[G>>2]=(c[G>>2]|0)+1}}while(0);if((c[A>>2]|0)<=1)c[(c[y>>2]|0)+80>>2]=0;else c[(c[y>>2]|0)+80>>2]=c[J+28>>2]^c[da>>2];c[(c[y>>2]|0)+56>>2]=c[R>>2];if(c[U>>2]|0)Da=(c[W>>2]|0)!=0^1;else Da=0;c[(c[y>>2]|0)+64>>2]=Da&1;if((c[I>>2]|0)>=0)_d()|0;c[x>>2]=(c[I>>2]|0)<0?c[I>>2]|0:c[Q>>2]|0;c[ha>>2]=1}while(0);ka(c[ga>>2]|0);ta=c[x>>2]|0;i=l;return ta|0}function _d(){return 0}function $d(a){a=a|0;var b=0,e=0,f=0;b=i;i=i+16|0;e=b+4|0;f=b;c[e>>2]=a;do if(!((d[c[e>>2]>>0]|0)&128))if(((d[c[e>>2]>>0]|0)&96|0)==96){c[f>>2]=1001;break}else{c[f>>2]=1e3;break}else c[f>>2]=1002;while(0);i=b;return c[f>>2]|0}function ae(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;i=b;return (c[d>>2]|0)+4-1&-4|0}function be(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;a=Ze(c[d>>2]|0)|0;i=b;return a|0}function ce(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;_e(c[d>>2]|0);i=b;return}function de(a,b,e,f,g,h,j,k){a=a|0;b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0;l=i;i=i+112|0;m=l;n=l+72|0;o=l+56|0;p=l+12|0;q=l+4|0;r=l+16|0;s=l+20|0;t=l+24|0;u=l+28|0;v=l+32|0;w=l+36|0;x=l+40|0;y=l+44|0;z=l+48|0;A=l+52|0;B=l+8|0;C=l+60|0;D=l+64|0;E=l+68|0;F=l+76|0;G=l+80|0;H=l+84|0;I=l+88|0;J=l+92|0;K=l+96|0;L=l+100|0;M=l+104|0;c[o>>2]=a;c[p>>2]=b;c[q>>2]=e;c[r>>2]=f;c[s>>2]=g;c[t>>2]=h;c[u>>2]=j;c[v>>2]=k;c[C>>2]=0;k=c[o>>2]|0;c[m>>2]=w+(((w-w|0)/4|0)<<2);Qc(k,4029,m)|0;if((c[t>>2]|0)<(((c[w>>2]|0)/25|0)*3|0))N=c[t>>2]|0;else N=((c[w>>2]|0)/25|0)*3|0;c[t>>2]=N;N=c[t>>2]<<1;c[D>>2]=ua()|0;m=i;i=i+((1*(N<<2)|0)+15&-16)|0;N=c[o>>2]|0;c[B>>2]=N+(ae(268)|0);c[x>>2]=Ac(2)|0;c[y>>2]=Ac(1)|0;if(!(c[q>>2]|0))c[C>>2]=1;if((c[q>>2]|0)<0){c[n>>2]=-1;c[E>>2]=1;O=c[D>>2]|0;ka(O|0);P=c[n>>2]|0;i=l;return P|0}if((c[C>>2]|0)==0?(c[q>>2]|0)<((c[(c[o>>2]|0)+4>>2]<<1)-1|0):0){c[n>>2]=-4;c[E>>2]=1;O=c[D>>2]|0;ka(O|0);P=c[n>>2]|0;i=l;return P|0}if(!(c[C>>2]|0)){c[F>>2]=fe(c[p>>2]|0,c[q>>2]|0,c[(c[o>>2]|0)+4>>2]|0,c[w>>2]|0)|0;w=c[F>>2]|0;if((c[F>>2]|0)<0){c[n>>2]=w;c[E>>2]=1;O=c[D>>2]|0;ka(O|0);P=c[n>>2]|0;i=l;return P|0}if((w|0)>(c[t>>2]|0)){c[n>>2]=-2;c[E>>2]=1;O=c[D>>2]|0;ka(O|0);P=c[n>>2]|0;i=l;return P|0}}c[z>>2]=0;while(1){if((c[z>>2]|0)>=(c[(c[o>>2]|0)+4>>2]|0)){Q=36;break}c[G>>2]=c[B>>2];if((c[z>>2]|0)<(c[(c[o>>2]|0)+8>>2]|0))R=ae(c[x>>2]|0)|0;else R=ae(c[y>>2]|0)|0;c[B>>2]=(c[B>>2]|0)+R;if((c[C>>2]|0)==0&(c[q>>2]|0)<=0){Q=22;break}c[H>>2]=0;c[I>>2]=Cc(c[G>>2]|0,c[p>>2]|0,c[q>>2]|0,m,c[t>>2]|0,c[u>>2]|0,(c[z>>2]|0)!=((c[(c[o>>2]|0)+4>>2]|0)-1|0)&1,H,c[v>>2]|0)|0;c[p>>2]=(c[p>>2]|0)+(c[H>>2]|0);c[q>>2]=(c[q>>2]|0)-(c[H>>2]|0);S=c[I>>2]|0;if((c[I>>2]|0)<=0){Q=24;break}c[t>>2]=S;a:do if((c[z>>2]|0)<(c[(c[o>>2]|0)+8>>2]|0)){c[K>>2]=-1;while(1){w=Jc(c[o>>2]|0,c[z>>2]|0,c[K>>2]|0)|0;c[J>>2]=w;if((w|0)==-1)break;Ha[c[s>>2]&1](c[r>>2]|0,c[c[o>>2]>>2]|0,c[J>>2]|0,m,2,c[t>>2]|0);c[K>>2]=c[J>>2]}c[K>>2]=-1;while(1){w=Kc(c[o>>2]|0,c[z>>2]|0,c[K>>2]|0)|0;c[J>>2]=w;if((w|0)==-1)break a;Ha[c[s>>2]&1](c[r>>2]|0,c[c[o>>2]>>2]|0,c[J>>2]|0,m+4|0,2,c[t>>2]|0);c[K>>2]=c[J>>2]}}else{c[M>>2]=-1;while(1){w=Lc(c[o>>2]|0,c[z>>2]|0,c[M>>2]|0)|0;c[L>>2]=w;if((w|0)==-1)break a;Ha[c[s>>2]&1](c[r>>2]|0,c[c[o>>2]>>2]|0,c[L>>2]|0,m,1,c[t>>2]|0);c[M>>2]=c[L>>2]}}while(0);c[z>>2]=(c[z>>2]|0)+1}if((Q|0)==22){c[n>>2]=-3;c[E>>2]=1;O=c[D>>2]|0;ka(O|0);P=c[n>>2]|0;i=l;return P|0}else if((Q|0)==24){c[n>>2]=S;c[E>>2]=1;O=c[D>>2]|0;ka(O|0);P=c[n>>2]|0;i=l;return P|0}else if((Q|0)==36){c[A>>2]=0;while(1){if((c[A>>2]|0)>=(c[c[o>>2]>>2]|0))break;if((d[(c[o>>2]|0)+12+(c[A>>2]|0)>>0]|0|0)==255)Ha[c[s>>2]&1](c[r>>2]|0,c[c[o>>2]>>2]|0,c[A>>2]|0,0,0,c[t>>2]|0);c[A>>2]=(c[A>>2]|0)+1}c[n>>2]=c[t>>2];c[E>>2]=1;O=c[D>>2]|0;ka(O|0);P=c[n>>2]|0;i=l;return P|0}return 0}function ee(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;j=i;i=i+32|0;k=j+4|0;l=j+16|0;m=j+8|0;n=j+20|0;o=j+28|0;p=j;q=j+12|0;r=j+24|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;c[q>>2]=c[k>>2];k=(c[n>>2]|0)!=0;c[r>>2]=0;if(k){while(1){if((c[r>>2]|0)>=(c[p>>2]|0))break;k=_(c[r>>2]|0,c[o>>2]|0)|0;h=_(c[r>>2]|0,c[l>>2]|0)|0;g[(c[q>>2]|0)+(h+(c[m>>2]|0)<<2)>>2]=+g[(c[n>>2]|0)+(k<<2)>>2];c[r>>2]=(c[r>>2]|0)+1}i=j;return}else{while(1){if((c[r>>2]|0)>=(c[p>>2]|0))break;n=_(c[r>>2]|0,c[l>>2]|0)|0;g[(c[q>>2]|0)+(n+(c[m>>2]|0)<<2)>>2]=0.0;c[r>>2]=(c[r>>2]|0)+1}i=j;return}}function fe(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;f=i;i=i+144|0;g=f+12|0;h=f+16|0;j=f+4|0;k=f+8|0;l=f+32|0;m=f;n=f+36|0;o=f+136|0;p=f+40|0;q=f+28|0;r=f+20|0;s=f+24|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[q>>2]=0;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0)){t=11;break}if((c[j>>2]|0)<=0){t=4;break}c[n>>2]=zc(c[h>>2]|0,c[j>>2]|0,(c[m>>2]|0)!=((c[k>>2]|0)-1|0)&1,o,0,p,0,r)|0;if((c[n>>2]|0)<0){t=6;break}c[s>>2]=Hc(c[h>>2]|0,c[r>>2]|0,c[l>>2]|0)|0;if((c[m>>2]|0)!=0?(c[q>>2]|0)!=(c[s>>2]|0):0){t=9;break}c[q>>2]=c[s>>2];c[h>>2]=(c[h>>2]|0)+(c[r>>2]|0);c[j>>2]=(c[j>>2]|0)-(c[r>>2]|0);c[m>>2]=(c[m>>2]|0)+1}if((t|0)==4){c[g>>2]=-4;u=c[g>>2]|0;i=f;return u|0}else if((t|0)==6){c[g>>2]=c[n>>2];u=c[g>>2]|0;i=f;return u|0}else if((t|0)==9){c[g>>2]=-4;u=c[g>>2]|0;i=f;return u|0}else if((t|0)==11){c[g>>2]=c[q>>2];u=c[g>>2]|0;i=f;return u|0}return 0}function ge(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;a=(c[(c[d>>2]|0)+20>>2]|0)-(32-(aa(c[(c[d>>2]|0)+28>>2]|0)|0))|0;i=b;return a|0}function he(a,b,d,e,f,h,j){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;k=i;i=i+48|0;l=k+36|0;m=k+16|0;n=k;o=k+28|0;p=k+32|0;q=k+40|0;r=k+12|0;s=k+24|0;t=k+20|0;u=k+8|0;v=k+4|0;c[l>>2]=a;c[m>>2]=b;c[n>>2]=d;c[o>>2]=e;c[p>>2]=f;c[q>>2]=h;c[r>>2]=j;c[u>>2]=48e3/(c[r>>2]|0)|0;c[t>>2]=0;while(1){if((c[t>>2]|0)>=(c[p>>2]|0))break;c[s>>2]=0;while(1){if((c[s>>2]|0)>=(c[o>>2]|0))break;r=_(c[s>>2]|0,c[u>>2]|0)|0;j=_(c[s>>2]|0,c[u>>2]|0)|0;g[v>>2]=+g[(c[q>>2]|0)+(r<<2)>>2]*+g[(c[q>>2]|0)+(j<<2)>>2];j=_(c[s>>2]|0,c[p>>2]|0)|0;r=_(c[s>>2]|0,c[p>>2]|0)|0;h=_(c[s>>2]|0,c[p>>2]|0)|0;g[(c[n>>2]|0)+(h+(c[t>>2]|0)<<2)>>2]=+g[v>>2]*+g[(c[m>>2]|0)+(j+(c[t>>2]|0)<<2)>>2]+(1.0-+g[v>>2])*+g[(c[l>>2]|0)+(r+(c[t>>2]|0)<<2)>>2];c[s>>2]=(c[s>>2]|0)+1}c[t>>2]=(c[t>>2]|0)+1}i=k;return}function ie(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b;c[d>>2]=a;if(!(c[d>>2]|0)){e=32;i=b;return e|0}e=32-(32-(aa(c[d>>2]|0)|0))|0;i=b;return e|0}function je(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;d=i;i=i+48|0;e=d+28|0;f=d+16|0;g=d+4|0;h=d+8|0;j=d+32|0;k=d;l=d+12|0;m=d+24|0;n=d+20|0;c[f>>2]=a;c[g>>2]=b;b=c[f>>2]|0;c[h>>2]=(ie((c[f>>2]|0)>0?b:0-b|0)|0)-1;c[l>>2]=c[f>>2]<<c[h>>2];c[k>>2]=536870911/(c[l>>2]>>16|0)|0;c[n>>2]=c[k>>2]<<16;f=_(c[l>>2]>>16,(c[k>>2]&65535)<<16>>16)|0;c[m>>2]=536870912-(f+((_(c[l>>2]&65535,(c[k>>2]&65535)<<16>>16)|0)>>16))<<3;l=_(c[m>>2]>>16,(c[k>>2]&65535)<<16>>16)|0;f=(c[n>>2]|0)+(l+((_(c[m>>2]&65535,(c[k>>2]&65535)<<16>>16)|0)>>16))|0;c[n>>2]=f+(_(c[m>>2]|0,(c[k>>2]>>15)+1>>1)|0);c[j>>2]=61-(c[h>>2]|0)-(c[g>>2]|0);g=c[j>>2]|0;if((c[j>>2]|0)>0)if((g|0)<32){c[e>>2]=c[n>>2]>>c[j>>2];o=c[e>>2]|0;i=d;return o|0}else{c[e>>2]=0;o=c[e>>2]|0;i=d;return o|0}h=c[n>>2]|0;k=0-(c[j>>2]|0)|0;do if((-2147483648>>0-g|0)>(2147483647>>0-(c[j>>2]|0)|0)){if((h|0)>(-2147483648>>k|0)){p=-2147483648>>0-(c[j>>2]|0);break}if((c[n>>2]|0)<(2147483647>>0-(c[j>>2]|0)|0)){p=2147483647>>0-(c[j>>2]|0);break}else{p=c[n>>2]|0;break}}else{if((h|0)>(2147483647>>k|0)){p=2147483647>>0-(c[j>>2]|0);break}if((c[n>>2]|0)<(-2147483648>>0-(c[j>>2]|0)|0)){p=-2147483648>>0-(c[j>>2]|0);break}else{p=c[n>>2]|0;break}}while(0);c[e>>2]=p<<0-(c[j>>2]|0);o=c[e>>2]|0;i=d;return o|0}function ke(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;e=i;i=i+16|0;f=e+12|0;g=e+8|0;h=e+4|0;j=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[j>>2]=Ld(c[f>>2]|0)|0;c[c[g>>2]>>2]=c[j>>2];g=(le(c[f>>2]|0,24-(c[j>>2]|0)|0)|0)&127;c[c[h>>2]>>2]=g;i=e;return}function le(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;d=i;i=i+32|0;e=d+20|0;f=d+16|0;g=d+12|0;h=d+8|0;j=d+4|0;k=d;c[f>>2]=a;c[g>>2]=b;c[h>>2]=c[f>>2];c[j>>2]=c[g>>2];c[k>>2]=0-(c[g>>2]|0);if(!(c[g>>2]|0)){c[e>>2]=c[f>>2];l=c[e>>2]|0;i=d;return l|0}f=c[h>>2]|0;if((c[g>>2]|0)<0){c[e>>2]=f<<c[k>>2]|(c[h>>2]|0)>>>(32-(c[k>>2]|0)|0);l=c[e>>2]|0;i=d;return l|0}else{c[e>>2]=f<<32-(c[j>>2]|0)|(c[h>>2]|0)>>>(c[j>>2]|0);l=c[e>>2]|0;i=d;return l|0}return 0}function me(a,d,e,f,g,h,j,k){a=a|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;var l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0;l=i;i=i+48|0;m=l+4|0;n=l+16|0;o=l+36|0;p=l;q=l+32|0;r=l+40|0;s=l+44|0;t=l+24|0;u=l+20|0;v=l+8|0;w=l+12|0;x=l+28|0;c[m>>2]=a;c[n>>2]=d;c[o>>2]=e;c[p>>2]=f;c[q>>2]=g;c[r>>2]=h;c[s>>2]=j;c[t>>2]=k;k=c[s>>2]<<1;c[x>>2]=ua()|0;j=i;i=i+((1*(k<<1)|0)+15&-16)|0;c[w>>2]=j;c[v>>2]=0;while(1){if((c[v>>2]|0)>=2)break;c[u>>2]=0;while(1){if((c[u>>2]|0)>=(c[s>>2]|0))break;k=(c[u>>2]|0)+(_((c[v>>2]|0)+(c[t>>2]|0)-2|0,c[s>>2]|0)|0)|0;h=_(c[(c[q>>2]|0)+(k<<2)>>2]>>16,(c[(c[r>>2]|0)+(c[v>>2]<<2)>>2]&65535)<<16>>16)|0;k=(c[u>>2]|0)+(_((c[v>>2]|0)+(c[t>>2]|0)-2|0,c[s>>2]|0)|0)|0;g=h+((_(c[(c[q>>2]|0)+(k<<2)>>2]&65535,(c[(c[r>>2]|0)+(c[v>>2]<<2)>>2]&65535)<<16>>16)|0)>>16)|0;k=(c[u>>2]|0)+(_((c[v>>2]|0)+(c[t>>2]|0)-2|0,c[s>>2]|0)|0)|0;if((g+(_(c[(c[q>>2]|0)+(k<<2)>>2]|0,(c[(c[r>>2]|0)+(c[v>>2]<<2)>>2]>>15)+1>>1)|0)>>8|0)<=32767){k=(c[u>>2]|0)+(_((c[v>>2]|0)+(c[t>>2]|0)-2|0,c[s>>2]|0)|0)|0;g=_(c[(c[q>>2]|0)+(k<<2)>>2]>>16,(c[(c[r>>2]|0)+(c[v>>2]<<2)>>2]&65535)<<16>>16)|0;k=(c[u>>2]|0)+(_((c[v>>2]|0)+(c[t>>2]|0)-2|0,c[s>>2]|0)|0)|0;h=g+((_(c[(c[q>>2]|0)+(k<<2)>>2]&65535,(c[(c[r>>2]|0)+(c[v>>2]<<2)>>2]&65535)<<16>>16)|0)>>16)|0;k=(c[u>>2]|0)+(_((c[v>>2]|0)+(c[t>>2]|0)-2|0,c[s>>2]|0)|0)|0;if((h+(_(c[(c[q>>2]|0)+(k<<2)>>2]|0,(c[(c[r>>2]|0)+(c[v>>2]<<2)>>2]>>15)+1>>1)|0)>>8|0)<-32768)y=-32768;else{k=(c[u>>2]|0)+(_((c[v>>2]|0)+(c[t>>2]|0)-2|0,c[s>>2]|0)|0)|0;h=_(c[(c[q>>2]|0)+(k<<2)>>2]>>16,(c[(c[r>>2]|0)+(c[v>>2]<<2)>>2]&65535)<<16>>16)|0;k=(c[u>>2]|0)+(_((c[v>>2]|0)+(c[t>>2]|0)-2|0,c[s>>2]|0)|0)|0;g=h+((_(c[(c[q>>2]|0)+(k<<2)>>2]&65535,(c[(c[r>>2]|0)+(c[v>>2]<<2)>>2]&65535)<<16>>16)|0)>>16)|0;k=(c[u>>2]|0)+(_((c[v>>2]|0)+(c[t>>2]|0)-2|0,c[s>>2]|0)|0)|0;y=g+(_(c[(c[q>>2]|0)+(k<<2)>>2]|0,(c[(c[r>>2]|0)+(c[v>>2]<<2)>>2]>>15)+1>>1)|0)>>8}}else y=32767;b[(c[w>>2]|0)+(c[u>>2]<<1)>>1]=y;c[u>>2]=(c[u>>2]|0)+1}c[w>>2]=(c[w>>2]|0)+(c[s>>2]<<1);c[v>>2]=(c[v>>2]|0)+1}uc(c[m>>2]|0,c[n>>2]|0,j,c[s>>2]|0);uc(c[o>>2]|0,c[p>>2]|0,j+(c[s>>2]<<1)|0,c[s>>2]|0);ka(c[x>>2]|0);i=l;return}function ne(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}function oe(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)<(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}function pe(a,c){a=a|0;c=c|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+2|0;f=d;b[e>>1]=a;b[f>>1]=c;i=d;return ((b[e>>1]|0)>(b[f>>1]|0)?b[e>>1]|0:b[f>>1]|0)&65535|0}function qe(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)<(c[f>>2]|0)?c[e>>2]|0:c[f>>2]|0)|0}function re(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;d=i;i=i+48|0;e=d+28|0;f=d+16|0;g=d+4|0;h=d+8|0;j=d+32|0;k=d;l=d+12|0;m=d+24|0;n=d+20|0;c[f>>2]=a;c[g>>2]=b;b=c[f>>2]|0;c[h>>2]=(Ld((c[f>>2]|0)>0?b:0-b|0)|0)-1;c[l>>2]=c[f>>2]<<c[h>>2];c[k>>2]=536870911/(c[l>>2]>>16|0)|0;c[n>>2]=c[k>>2]<<16;f=_(c[l>>2]>>16,(c[k>>2]&65535)<<16>>16)|0;c[m>>2]=536870912-(f+((_(c[l>>2]&65535,(c[k>>2]&65535)<<16>>16)|0)>>16))<<3;l=_(c[m>>2]>>16,(c[k>>2]&65535)<<16>>16)|0;f=(c[n>>2]|0)+(l+((_(c[m>>2]&65535,(c[k>>2]&65535)<<16>>16)|0)>>16))|0;c[n>>2]=f+(_(c[m>>2]|0,(c[k>>2]>>15)+1>>1)|0);c[j>>2]=61-(c[h>>2]|0)-(c[g>>2]|0);g=c[j>>2]|0;if((c[j>>2]|0)>0)if((g|0)<32){c[e>>2]=c[n>>2]>>c[j>>2];o=c[e>>2]|0;i=d;return o|0}else{c[e>>2]=0;o=c[e>>2]|0;i=d;return o|0}h=c[n>>2]|0;k=0-(c[j>>2]|0)|0;do if((-2147483648>>0-g|0)>(2147483647>>0-(c[j>>2]|0)|0)){if((h|0)>(-2147483648>>k|0)){p=-2147483648>>0-(c[j>>2]|0);break}if((c[n>>2]|0)<(2147483647>>0-(c[j>>2]|0)|0)){p=2147483647>>0-(c[j>>2]|0);break}else{p=c[n>>2]|0;break}}else{if((h|0)>(2147483647>>k|0)){p=2147483647>>0-(c[j>>2]|0);break}if((c[n>>2]|0)<(-2147483648>>0-(c[j>>2]|0)|0)){p=-2147483648>>0-(c[j>>2]|0);break}else{p=c[n>>2]|0;break}}while(0);c[e>>2]=p<<0-(c[j>>2]|0);o=c[e>>2]|0;i=d;return o|0}function se(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;e=i;i=i+16|0;f=e+12|0;g=e+8|0;h=e+4|0;j=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[j>>2]=te(c[f>>2]|0)|0;c[c[g>>2]>>2]=c[j>>2];g=(ue(c[f>>2]|0,24-(c[j>>2]|0)|0)|0)&127;c[c[h>>2]>>2]=g;i=e;return}function te(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b;c[d>>2]=a;if(!(c[d>>2]|0)){e=32;i=b;return e|0}e=32-(32-(aa(c[d>>2]|0)|0))|0;i=b;return e|0}function ue(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;d=i;i=i+32|0;e=d+20|0;f=d+16|0;g=d+12|0;h=d+8|0;j=d+4|0;k=d;c[f>>2]=a;c[g>>2]=b;c[h>>2]=c[f>>2];c[j>>2]=c[g>>2];c[k>>2]=0-(c[g>>2]|0);if(!(c[g>>2]|0)){c[e>>2]=c[f>>2];l=c[e>>2]|0;i=d;return l|0}f=c[h>>2]|0;if((c[g>>2]|0)<0){c[e>>2]=f<<c[k>>2]|(c[h>>2]|0)>>>(32-(c[k>>2]|0)|0);l=c[e>>2]|0;i=d;return l|0}else{c[e>>2]=f<<32-(c[j>>2]|0)|(c[h>>2]|0)>>>(c[j>>2]|0);l=c[e>>2]|0;i=d;return l|0}return 0}function ve(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b;c[d>>2]=a;if(!(c[d>>2]|0)){e=32;i=b;return e|0}e=32-(32-(aa(c[d>>2]|0)|0))|0;i=b;return e|0}function we(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>>>0)/((c[f>>2]|0)>>>0)|0|0}function xe(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=+e;f=+f;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;h=i;i=i+48|0;j=h+4|0;k=h+16|0;l=h+36|0;m=h;n=h+32|0;o=h+40|0;p=h+44|0;q=h+24|0;r=h+20|0;s=h+8|0;t=h+12|0;u=h+28|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;g[m>>2]=e;g[n>>2]=f;c[q>>2]=c[j>>2];g[p>>2]=-+g[n>>2];c[o>>2]=0;while(1){if((c[o>>2]|0)>=((c[k>>2]|0)-(c[l>>2]|0)|0))break;g[r>>2]=+g[c[q>>2]>>2];g[s>>2]=+g[(c[q>>2]|0)+(c[l>>2]<<2)>>2];g[(c[q>>2]|0)+(c[l>>2]<<2)>>2]=+g[m>>2]*+g[s>>2]+ +g[n>>2]*+g[r>>2];f=+g[m>>2]*+g[r>>2]+ +g[p>>2]*+g[s>>2];d=c[q>>2]|0;c[q>>2]=d+4;g[d>>2]=f;c[o>>2]=(c[o>>2]|0)+1}c[q>>2]=(c[j>>2]|0)+((c[k>>2]|0)-(c[l>>2]<<1)-1<<2);c[o>>2]=(c[k>>2]|0)-(c[l>>2]<<1)-1;while(1){if((c[o>>2]|0)<0)break;g[t>>2]=+g[c[q>>2]>>2];g[u>>2]=+g[(c[q>>2]|0)+(c[l>>2]<<2)>>2];g[(c[q>>2]|0)+(c[l>>2]<<2)>>2]=+g[m>>2]*+g[u>>2]+ +g[n>>2]*+g[t>>2];f=+g[m>>2]*+g[t>>2]+ +g[p>>2]*+g[u>>2];k=c[q>>2]|0;c[q>>2]=k+-4;g[k>>2]=f;c[o>>2]=(c[o>>2]|0)+-1}i=h;return}function ye(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;i=d;return ((c[e>>2]|0)>>>0)/((c[f>>2]|0)>>>0)|0|0}function ze(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[g>>2]=b;c[h>>2]=d;if(((c[(c[g>>2]|0)+24>>2]|0)+(c[(c[g>>2]|0)+8>>2]|0)|0)>>>0>=(c[(c[g>>2]|0)+4>>2]|0)>>>0){c[f>>2]=-1;j=c[f>>2]|0;i=e;return j|0}else{d=c[h>>2]&255;h=(c[g>>2]|0)+24|0;b=c[h>>2]|0;c[h>>2]=b+1;a[(c[c[g>>2]>>2]|0)+b>>0]=d;c[f>>2]=0;j=c[f>>2]|0;i=e;return j|0}return 0}function Ae(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+4112|0;f=e+4108|0;g=e+4104|0;h=e+4100|0;j=e+4096|0;k=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;vb(c[f>>2]|0,k,2048,c[g>>2]|0,c[h>>2]|0);xb(k+1440|0,k,1328,620,j,c[h>>2]|0);c[j>>2]=720-(c[j>>2]|0);i=e;return c[j>>2]|0}function Be(){return 0}function Ce(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;h=i;i=i+48|0;j=h+4|0;k=h+16|0;l=h+36|0;m=h;n=h+32|0;o=h+40|0;p=h+44|0;q=h+24|0;r=h+20|0;s=h+8|0;t=h+12|0;u=h+28|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;c[o>>2]=((c[c[j>>2]>>2]|0)!=0^1)&1;c[r>>2]=c[k>>2];c[s>>2]=c[c[j>>2]>>2];c[t>>2]=c[(c[j>>2]|0)+24>>2];c[q>>2]=(c[l>>2]|0)!=0&1;c[p>>2]=0;do{c[u>>2]=0;if((c[(c[j>>2]|0)+28>>2]|0)>=8){if(c[s>>2]|0){c[u>>2]=+g[c[r>>2]>>2]<0.0&1;pb(c[t>>2]|0,c[u>>2]|0,1)}else c[u>>2]=lb(c[t>>2]|0,1)|0;f=(c[j>>2]|0)+28|0;c[f>>2]=(c[f>>2]|0)-8;c[m>>2]=(c[m>>2]|0)-8}if(c[o>>2]|0)g[c[r>>2]>>2]=(c[u>>2]|0)!=0?-1.0:1.0;c[r>>2]=c[l>>2];f=(c[p>>2]|0)+1|0;c[p>>2]=f}while((f|0)<(1+(c[q>>2]|0)|0));if(!(c[n>>2]|0)){i=h;return 1}g[c[n>>2]>>2]=+g[c[k>>2]>>2];i=h;return 1}function De(a,d,e,f,h,j,k,l,m,n,o){a=a|0;d=d|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;m=m|0;n=n|0;o=o|0;var p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0;p=i;i=i+160|0;q=p+72|0;r=p+56|0;s=p+4|0;t=p+52|0;u=p+140|0;v=p+68|0;w=p+20|0;x=p+24|0;y=p+28|0;z=p+32|0;A=p+36|0;B=p+40|0;C=p+44|0;D=p+48|0;E=p+112|0;F=p+120|0;G=p+128|0;H=p+136|0;I=p+144|0;J=p+148|0;K=p+76|0;L=p+80|0;M=p+84|0;N=p+88|0;O=p+92|0;P=p+96|0;Q=p+100|0;R=p+104|0;S=p+12|0;T=p;U=p+8|0;V=p+108|0;W=p+116|0;X=p+60|0;Y=p+124|0;Z=p+16|0;$=p+64|0;aa=p+132|0;c[q>>2]=a;c[r>>2]=d;c[s>>2]=e;c[t>>2]=f;c[u>>2]=h;c[v>>2]=j;c[w>>2]=k;c[x>>2]=l;c[y>>2]=m;c[z>>2]=n;c[A>>2]=o;c[C>>2]=0;c[K>>2]=0;c[L>>2]=c[c[q>>2]>>2];c[M>>2]=c[(c[q>>2]|0)+4>>2];c[N>>2]=c[(c[q>>2]|0)+8>>2];c[O>>2]=c[(c[q>>2]|0)+12>>2];c[P>>2]=c[(c[q>>2]|0)+24>>2];c[Q>>2]=c[(c[q>>2]|0)+32>>2];c[H>>2]=(b[(c[(c[M>>2]|0)+56>>2]|0)+(c[N>>2]<<1)>>1]|0)+(c[y>>2]<<3);c[I>>2]=(c[H>>2]>>1)-(((c[z>>2]|0)!=0?(c[u>>2]|0)==2:0)?16:4);c[B>>2]=Ge(c[u>>2]|0,c[c[v>>2]>>2]|0,c[I>>2]|0,c[H>>2]|0,c[z>>2]|0)|0;if((c[z>>2]|0)!=0?(c[N>>2]|0)>=(c[O>>2]|0):0)c[B>>2]=1;if(c[L>>2]|0)c[C>>2]=Jb(c[s>>2]|0,c[t>>2]|0,c[z>>2]|0,c[u>>2]|0)|0;c[J>>2]=db(c[P>>2]|0)|0;do if((c[B>>2]|0)!=1){if(c[L>>2]|0)c[C>>2]=(_(c[C>>2]|0,c[B>>2]|0)|0)+8192>>14;do if((c[z>>2]|0)!=0&(c[u>>2]|0)>2){c[R>>2]=3;c[S>>2]=c[C>>2];c[T>>2]=(c[B>>2]|0)/2|0;O=_(c[R>>2]|0,(c[T>>2]|0)+1|0)|0;c[U>>2]=O+(c[T>>2]|0);O=c[P>>2]|0;if(c[L>>2]|0){if((c[S>>2]|0)<=(c[T>>2]|0))ba=_(c[R>>2]|0,c[S>>2]|0)|0;else ba=(c[S>>2]|0)-1-(c[T>>2]|0)+(_((c[T>>2]|0)+1|0,c[R>>2]|0)|0)|0;if((c[S>>2]|0)<=(c[T>>2]|0))ca=_(c[R>>2]|0,(c[S>>2]|0)+1|0)|0;else ca=(c[S>>2]|0)-(c[T>>2]|0)+(_((c[T>>2]|0)+1|0,c[R>>2]|0)|0)|0;mb(O,ba,ca,c[U>>2]|0);break}c[V>>2]=fb(O,c[U>>2]|0)|0;if((c[V>>2]|0)<(_((c[T>>2]|0)+1|0,c[R>>2]|0)|0))c[S>>2]=(c[V>>2]|0)/(c[R>>2]|0)|0;else c[S>>2]=(c[T>>2]|0)+1+((c[V>>2]|0)-(_((c[T>>2]|0)+1|0,c[R>>2]|0)|0));if((c[S>>2]|0)<=(c[T>>2]|0))da=_(c[R>>2]|0,c[S>>2]|0)|0;else da=(c[S>>2]|0)-1-(c[T>>2]|0)+(_((c[T>>2]|0)+1|0,c[R>>2]|0)|0)|0;if((c[S>>2]|0)<=(c[T>>2]|0))ea=_(c[R>>2]|0,(c[S>>2]|0)+1|0)|0;else ea=(c[S>>2]|0)-(c[T>>2]|0)+(_((c[T>>2]|0)+1|0,c[R>>2]|0)|0)|0;hb(c[P>>2]|0,da,ea,c[U>>2]|0);c[C>>2]=c[S>>2]}else{if((c[x>>2]|0)>1|(c[z>>2]|0)!=0){O=c[P>>2]|0;if(c[L>>2]|0){ob(O,c[C>>2]|0,(c[B>>2]|0)+1|0);break}else{c[C>>2]=kb(O,(c[B>>2]|0)+1|0)|0;break}}c[W>>2]=1;c[X>>2]=_((c[B>>2]>>1)+1|0,(c[B>>2]>>1)+1|0)|0;if(!(c[L>>2]|0)){c[Z>>2]=0;c[$>>2]=fb(c[P>>2]|0,c[X>>2]|0)|0;if((c[$>>2]|0)<((_(c[B>>2]>>1,(c[B>>2]>>1)+1|0)|0)>>1|0)){c[C>>2]=((sb((c[$>>2]<<3)+1|0)|0)-1|0)>>>1;c[W>>2]=(c[C>>2]|0)+1;c[Z>>2]=(_(c[C>>2]|0,(c[C>>2]|0)+1|0)|0)>>1}else{O=(c[B>>2]|0)+1<<1;c[C>>2]=(O-(sb(((c[X>>2]|0)-(c[$>>2]|0)-1<<3)+1|0)|0)|0)>>>1;c[W>>2]=(c[B>>2]|0)+1-(c[C>>2]|0);c[Z>>2]=(c[X>>2]|0)-((_((c[B>>2]|0)+1-(c[C>>2]|0)|0,(c[B>>2]|0)+2-(c[C>>2]|0)|0)|0)>>1)}hb(c[P>>2]|0,c[Z>>2]|0,(c[Z>>2]|0)+(c[W>>2]|0)|0,c[X>>2]|0);break}if((c[C>>2]|0)<=(c[B>>2]>>1|0))fa=(c[C>>2]|0)+1|0;else fa=(c[B>>2]|0)+1-(c[C>>2]|0)|0;c[W>>2]=fa;if((c[C>>2]|0)<=(c[B>>2]>>1|0))ga=(_(c[C>>2]|0,(c[C>>2]|0)+1|0)|0)>>1;else ga=(c[X>>2]|0)-((_((c[B>>2]|0)+1-(c[C>>2]|0)|0,(c[B>>2]|0)+2-(c[C>>2]|0)|0)|0)>>1)|0;c[Y>>2]=ga;mb(c[P>>2]|0,c[Y>>2]|0,(c[Y>>2]|0)+(c[W>>2]|0)|0,c[X>>2]|0)}while(0);c[C>>2]=Rc(c[C>>2]<<14,c[B>>2]|0)|0;if((c[L>>2]|0)!=0&(c[z>>2]|0)!=0)if(!(c[C>>2]|0)){He(c[M>>2]|0,c[s>>2]|0,c[t>>2]|0,c[Q>>2]|0,c[N>>2]|0,c[u>>2]|0);break}else{Ie(c[s>>2]|0,c[t>>2]|0,c[u>>2]|0);break}}else if(c[z>>2]|0){if(c[L>>2]|0){c[K>>2]=(c[C>>2]|0)>8192&1;a:do if(c[K>>2]|0){c[aa>>2]=0;while(1){if((c[aa>>2]|0)>=(c[u>>2]|0))break a;g[(c[t>>2]|0)+(c[aa>>2]<<2)>>2]=-+g[(c[t>>2]|0)+(c[aa>>2]<<2)>>2];c[aa>>2]=(c[aa>>2]|0)+1}}while(0);He(c[M>>2]|0,c[s>>2]|0,c[t>>2]|0,c[Q>>2]|0,c[N>>2]|0,c[u>>2]|0)}do if((c[c[v>>2]>>2]|0)>16?(c[(c[q>>2]|0)+28>>2]|0)>16:0){O=c[P>>2]|0;if(c[L>>2]|0){nb(O,c[K>>2]|0,2);break}else{c[K>>2]=ib(O,2)|0;break}}else ha=60;while(0);if((ha|0)==60)c[K>>2]=0;c[C>>2]=0}while(0);ha=db(c[P>>2]|0)|0;c[G>>2]=ha-(c[J>>2]|0);J=c[v>>2]|0;c[J>>2]=(c[J>>2]|0)-(c[G>>2]|0);if(!(c[C>>2]|0)){c[E>>2]=32767;c[F>>2]=0;J=c[A>>2]|0;c[J>>2]=c[J>>2]&(1<<c[w>>2])-1;c[D>>2]=-16384;ia=c[K>>2]|0;ja=c[r>>2]|0;c[ja>>2]=ia;ka=c[E>>2]|0;la=c[r>>2]|0;ma=la+4|0;c[ma>>2]=ka;na=c[F>>2]|0;oa=c[r>>2]|0;pa=oa+8|0;c[pa>>2]=na;qa=c[D>>2]|0;ra=c[r>>2]|0;sa=ra+12|0;c[sa>>2]=qa;ta=c[C>>2]|0;ua=c[r>>2]|0;va=ua+16|0;c[va>>2]=ta;wa=c[G>>2]|0;xa=c[r>>2]|0;ya=xa+20|0;c[ya>>2]=wa;i=p;return}if((c[C>>2]|0)==16384){c[E>>2]=0;c[F>>2]=32767;J=c[A>>2]|0;c[J>>2]=c[J>>2]&(1<<c[w>>2])-1<<c[w>>2];c[D>>2]=16384;ia=c[K>>2]|0;ja=c[r>>2]|0;c[ja>>2]=ia;ka=c[E>>2]|0;la=c[r>>2]|0;ma=la+4|0;c[ma>>2]=ka;na=c[F>>2]|0;oa=c[r>>2]|0;pa=oa+8|0;c[pa>>2]=na;qa=c[D>>2]|0;ra=c[r>>2]|0;sa=ra+12|0;c[sa>>2]=qa;ta=c[C>>2]|0;ua=c[r>>2]|0;va=ua+16|0;c[va>>2]=ta;wa=c[G>>2]|0;xa=c[r>>2]|0;ya=xa+20|0;c[ya>>2]=wa;i=p;return}else{c[E>>2]=(Je(c[C>>2]&65535)|0)<<16>>16;c[F>>2]=(Je(16384-(c[C>>2]|0)&65535)|0)<<16>>16;w=((c[u>>2]|0)-1<<7&65535)<<16>>16;c[D>>2]=16384+(_(w,((Ke(c[F>>2]|0,c[E>>2]|0)|0)&65535)<<16>>16)|0)>>15;ia=c[K>>2]|0;ja=c[r>>2]|0;c[ja>>2]=ia;ka=c[E>>2]|0;la=c[r>>2]|0;ma=la+4|0;c[ma>>2]=ka;na=c[F>>2]|0;oa=c[r>>2]|0;pa=oa+8|0;c[pa>>2]=na;qa=c[D>>2]|0;ra=c[r>>2]|0;sa=ra+12|0;c[sa>>2]=qa;ta=c[C>>2]|0;ua=c[r>>2]|0;va=ua+16|0;c[va>>2]=ta;wa=c[G>>2]|0;xa=c[r>>2]|0;ya=xa+20|0;c[ya>>2]=wa;i=p;return}}function Ee(a,b,d,e){a=a|0;b=b|0;d=+d;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;f=i;i=i+64|0;h=f+52|0;j=f+44|0;k=f+24|0;l=f+20|0;m=f+12|0;n=f+40|0;o=f+48|0;p=f+56|0;q=f+28|0;r=f+8|0;s=f+4|0;t=f+32|0;u=f;v=f+16|0;w=f+36|0;c[h>>2]=a;c[j>>2]=b;g[k>>2]=d;c[l>>2]=e;g[n>>2]=0.0;g[o>>2]=0.0;Fe(c[j>>2]|0,c[h>>2]|0,c[j>>2]|0,c[l>>2]|0,n,o);g[n>>2]=+g[k>>2]*+g[n>>2];g[r>>2]=+g[k>>2];g[p>>2]=+g[r>>2]*+g[r>>2]+ +g[o>>2]-+g[n>>2]*2.0;g[q>>2]=+g[r>>2]*+g[r>>2]+ +g[o>>2]+ +g[n>>2]*2.0;if(+g[q>>2]<6.000000284984708e-04|+g[p>>2]<6.000000284984708e-04){df(c[j>>2]|0,c[h>>2]|0,(c[l>>2]<<2)+0|0)|0;i=f;return}g[s>>2]=+g[p>>2];g[t>>2]=1.0/+O(+(+g[s>>2]));g[s>>2]=+g[q>>2];g[u>>2]=1.0/+O(+(+g[s>>2]));c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[l>>2]|0))break;g[w>>2]=+g[k>>2]*+g[(c[h>>2]|0)+(c[m>>2]<<2)>>2];g[v>>2]=+g[(c[j>>2]|0)+(c[m>>2]<<2)>>2];g[(c[h>>2]|0)+(c[m>>2]<<2)>>2]=+g[t>>2]*(+g[w>>2]-+g[v>>2]);g[(c[j>>2]|0)+(c[m>>2]<<2)>>2]=+g[u>>2]*(+g[w>>2]+ +g[v>>2]);c[m>>2]=(c[m>>2]|0)+1}i=f;return}function Fe(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0.0;j=i;i=i+48|0;k=j+28|0;l=j+16|0;m=j+4|0;n=j+8|0;o=j+32|0;p=j;q=j+12|0;r=j+24|0;s=j+20|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;g[r>>2]=0.0;g[s>>2]=0.0;c[q>>2]=0;while(1){t=+g[r>>2];if((c[q>>2]|0)>=(c[n>>2]|0))break;g[r>>2]=t+ +g[(c[k>>2]|0)+(c[q>>2]<<2)>>2]*+g[(c[l>>2]|0)+(c[q>>2]<<2)>>2];g[s>>2]=+g[s>>2]+ +g[(c[k>>2]|0)+(c[q>>2]<<2)>>2]*+g[(c[m>>2]|0)+(c[q>>2]<<2)>>2];c[q>>2]=(c[q>>2]|0)+1}g[c[o>>2]>>2]=t;g[c[p>>2]>>2]=+g[s>>2];i=j;return}function Ge(a,d,e,f,g){a=a|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;h=i;i=i+32|0;j=h+4|0;k=h+16|0;l=h+8|0;m=h+20|0;n=h+28|0;o=h;p=h+12|0;q=h+24|0;c[j>>2]=a;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[q>>2]=(c[j>>2]<<1)-1;if((c[n>>2]|0)!=0&(c[j>>2]|0)==2)c[q>>2]=(c[q>>2]|0)+-1;j=(c[k>>2]|0)+(_(c[q>>2]|0,c[l>>2]|0)|0)|0;c[p>>2]=Sc(j,c[q>>2]|0)|0;if(((c[k>>2]|0)-(c[m>>2]|0)-32|0)<(c[p>>2]|0))r=(c[k>>2]|0)-(c[m>>2]|0)-32|0;else r=c[p>>2]|0;c[p>>2]=r;c[p>>2]=64<(c[p>>2]|0)?64:c[p>>2]|0;if((c[p>>2]|0)<4){c[o>>2]=1;s=c[o>>2]|0;i=h;return s|0}else{c[o>>2]=b[25080+((c[p>>2]&7)<<1)>>1]>>14-(c[p>>2]>>3);c[o>>2]=(c[o>>2]|0)+1>>1<<1;s=c[o>>2]|0;i=h;return s|0}return 0}function He(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0;j=i;i=i+64|0;k=j+52|0;l=j+44|0;m=j+24|0;n=j+20|0;o=j+12|0;p=j+40|0;q=j+48|0;r=j+56|0;s=j+28|0;t=j+8|0;u=j+4|0;v=j+32|0;w=j;x=j+16|0;y=j+36|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=d;c[n>>2]=e;c[o>>2]=f;c[p>>2]=h;c[q>>2]=c[o>>2];g[u>>2]=+g[(c[n>>2]|0)+(c[q>>2]<<2)>>2];g[v>>2]=+g[(c[n>>2]|0)+((c[q>>2]|0)+(c[(c[k>>2]|0)+8>>2]|0)<<2)>>2];g[w>>2]=+O(+(+g[u>>2]*+g[u>>2]+1.0000000036274937e-15+ +g[v>>2]*+g[v>>2]))+1.0000000036274937e-15;g[s>>2]=+g[u>>2]/+g[w>>2];g[t>>2]=+g[v>>2]/+g[w>>2];c[r>>2]=0;while(1){if((c[r>>2]|0)>=(c[p>>2]|0))break;g[y>>2]=+g[(c[l>>2]|0)+(c[r>>2]<<2)>>2];g[x>>2]=+g[(c[m>>2]|0)+(c[r>>2]<<2)>>2];g[(c[l>>2]|0)+(c[r>>2]<<2)>>2]=+g[s>>2]*+g[y>>2]+ +g[t>>2]*+g[x>>2];c[r>>2]=(c[r>>2]|0)+1}i=j;return}function Ie(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0;e=i;i=i+32|0;f=e+20|0;h=e+16|0;j=e+12|0;k=e+8|0;l=e+4|0;m=e;c[f>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=0;while(1){if((c[k>>2]|0)>=(c[j>>2]|0))break;g[m>>2]=+g[(c[f>>2]|0)+(c[k>>2]<<2)>>2]*.7071067690849304;g[l>>2]=+g[(c[h>>2]|0)+(c[k>>2]<<2)>>2]*.7071067690849304;g[(c[f>>2]|0)+(c[k>>2]<<2)>>2]=+g[m>>2]+ +g[l>>2];g[(c[h>>2]|0)+(c[k>>2]<<2)>>2]=+g[l>>2]-+g[m>>2];c[k>>2]=(c[k>>2]|0)+1}i=e;return}function Je(a){a=a|0;var d=0,e=0,f=0,g=0;d=i;i=i+16|0;e=d+6|0;f=d;g=d+4|0;b[e>>1]=a;c[f>>2]=4096+(_(b[e>>1]|0,b[e>>1]|0)|0)>>13;b[g>>1]=c[f>>2];b[g>>1]=32767-(b[g>>1]|0)+(16384+(_(b[g>>1]|0,((16384+(_(b[g>>1]|0,(8277+(16384+(_(-626,b[g>>1]|0)|0)>>15)&65535)<<16>>16)|0)>>15)+-7651&65535)<<16>>16)|0)>>15);i=d;return 1+(b[g>>1]|0)&65535|0}function Ke(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[e>>2]=a;c[f>>2]=b;c[g>>2]=32-(aa(c[f>>2]|0)|0);c[h>>2]=32-(aa(c[e>>2]|0)|0);c[f>>2]=c[f>>2]<<15-(c[g>>2]|0);c[e>>2]=c[e>>2]<<15-(c[h>>2]|0);b=((c[h>>2]|0)-(c[g>>2]|0)<<11)+(16384+(_((c[e>>2]&65535)<<16>>16,((16384+(_((c[e>>2]&65535)<<16>>16,-2597)|0)>>15)+7932&65535)<<16>>16)|0)>>15)|0;e=b-(16384+(_((c[f>>2]&65535)<<16>>16,((16384+(_((c[f>>2]&65535)<<16>>16,-2597)|0)>>15)+7932&65535)<<16>>16)|0)>>15)|0;i=d;return e|0}function Le(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0;f=i;i=i+48|0;h=f+28|0;j=f+16|0;k=f+4|0;l=f+8|0;m=f+32|0;n=f;o=f+12|0;p=f+24|0;q=f+20|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[o>>2]=_(c[j>>2]|0,c[k>>2]|0)|0;e=c[o>>2]|0;c[p>>2]=ua()|0;d=i;i=i+((1*(e<<2)|0)+15&-16)|0;if(c[l>>2]|0){c[q>>2]=25128+(c[k>>2]<<2)+-8;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break;c[n>>2]=0;while(1){if((c[n>>2]|0)>=(c[j>>2]|0))break;l=_(c[n>>2]|0,c[k>>2]|0)|0;e=_(c[(c[q>>2]|0)+(c[m>>2]<<2)>>2]|0,c[j>>2]|0)|0;g[d+(e+(c[n>>2]|0)<<2)>>2]=+g[(c[h>>2]|0)+(l+(c[m>>2]|0)<<2)>>2];c[n>>2]=(c[n>>2]|0)+1}c[m>>2]=(c[m>>2]|0)+1}r=c[h>>2]|0;s=c[o>>2]|0;t=s<<2;u=c[h>>2]|0;v=u;w=d;x=v-w|0;y=(x|0)/4|0;z=0;A=t+z|0;df(r|0,d|0,A|0)|0;B=c[p>>2]|0;ka(B|0);i=f;return}else{c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break;c[n>>2]=0;while(1){if((c[n>>2]|0)>=(c[j>>2]|0))break;q=_(c[n>>2]|0,c[k>>2]|0)|0;l=_(c[m>>2]|0,c[j>>2]|0)|0;g[d+(l+(c[n>>2]|0)<<2)>>2]=+g[(c[h>>2]|0)+(q+(c[m>>2]|0)<<2)>>2];c[n>>2]=(c[n>>2]|0)+1}c[m>>2]=(c[m>>2]|0)+1}r=c[h>>2]|0;s=c[o>>2]|0;t=s<<2;u=c[h>>2]|0;v=u;w=d;x=v-w|0;y=(x|0)/4|0;z=0;A=t+z|0;df(r|0,d|0,A|0)|0;B=c[p>>2]|0;ka(B|0);i=f;return}}function Me(a,e,f,h,j,k,l,m,n){a=a|0;e=e|0;f=f|0;h=h|0;j=j|0;k=k|0;l=l|0;m=+m;n=n|0;var o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0;o=i;i=i+176|0;p=o+160|0;q=o+128|0;r=o+4|0;s=o+56|0;t=o+68|0;u=o+152|0;v=o+20|0;w=o+24|0;x=o+28|0;y=o+32|0;z=o+36|0;A=o+40|0;B=o+44|0;C=o+48|0;D=o+132|0;E=o+140|0;F=o+148|0;G=o+156|0;H=o+164|0;I=o+72|0;J=o+76|0;K=o+80|0;L=o+84|0;M=o+88|0;N=o+92|0;O=o+96|0;P=o+100|0;Q=o+12|0;R=o;S=o+8|0;T=o+104|0;U=o+52|0;V=o+136|0;W=o+60|0;X=o+144|0;Y=o+16|0;Z=o+64|0;c[p>>2]=a;c[q>>2]=e;c[r>>2]=f;c[s>>2]=h;c[t>>2]=j;c[u>>2]=k;c[v>>2]=l;g[w>>2]=m;c[x>>2]=n;c[B>>2]=0;c[C>>2]=0;c[D>>2]=c[t>>2];g[E>>2]=0.0;g[F>>2]=0.0;c[G>>2]=0;c[H>>2]=((c[c[p>>2]>>2]|0)!=0^1)&1;c[I>>2]=0;c[J>>2]=c[c[p>>2]>>2];c[K>>2]=c[(c[p>>2]|0)+4>>2];c[L>>2]=c[(c[p>>2]|0)+8>>2];c[M>>2]=c[(c[p>>2]|0)+16>>2];c[N>>2]=c[(c[p>>2]|0)+24>>2];n=_((c[v>>2]|0)+1|0,c[(c[K>>2]|0)+8>>2]|0)|0;c[y>>2]=(c[(c[K>>2]|0)+92+8>>2]|0)+(b[(c[(c[K>>2]|0)+92+4>>2]|0)+(n+(c[L>>2]|0)<<1)>>1]|0);if((c[v>>2]|0)!=-1?((c[r>>2]|0)>2?(c[s>>2]|0)>((d[(c[y>>2]|0)+(d[c[y>>2]>>0]|0)>>0]|0)+12|0):0):0){c[U>>2]=0;c[r>>2]=c[r>>2]>>1;c[I>>2]=(c[q>>2]|0)+(c[r>>2]<<2);c[v>>2]=(c[v>>2]|0)-1;if((c[t>>2]|0)==1)c[x>>2]=c[x>>2]&1|c[x>>2]<<1;c[t>>2]=(c[t>>2]|0)+1>>1;De(c[p>>2]|0,T,c[q>>2]|0,c[I>>2]|0,c[r>>2]|0,s,c[t>>2]|0,c[D>>2]|0,c[v>>2]|0,0,x);c[B>>2]=c[T+4>>2];c[C>>2]=c[T+8>>2];c[Q>>2]=c[T+12>>2];c[R>>2]=c[T+16>>2];c[S>>2]=c[T+20>>2];g[E>>2]=+(c[B>>2]|0)*.000030517578125;g[F>>2]=+(c[C>>2]|0)*.000030517578125;do if((c[D>>2]|0)>1?(c[R>>2]&16383|0)!=0:0){C=c[Q>>2]|0;if((c[R>>2]|0)>8192){c[Q>>2]=(c[Q>>2]|0)-(C>>4-(c[v>>2]|0));break}if(0<(C+(c[r>>2]<<3>>5-(c[v>>2]|0))|0))$=0;else $=(c[Q>>2]|0)+(c[r>>2]<<3>>5-(c[v>>2]|0))|0;c[Q>>2]=$}while(0);$=c[s>>2]|0;if((c[s>>2]|0)<(((c[s>>2]|0)-(c[Q>>2]|0)|0)/2|0|0))aa=$;else aa=($-(c[Q>>2]|0)|0)/2|0;if(0<=(aa|0)){aa=c[s>>2]|0;if((c[s>>2]|0)<(((c[s>>2]|0)-(c[Q>>2]|0)|0)/2|0|0))ba=aa;else ba=(aa-(c[Q>>2]|0)|0)/2|0}else ba=0;c[O>>2]=ba;c[P>>2]=(c[s>>2]|0)-(c[O>>2]|0);ba=(c[p>>2]|0)+28|0;c[ba>>2]=(c[ba>>2]|0)-(c[S>>2]|0);if(c[u>>2]|0)c[U>>2]=(c[u>>2]|0)+(c[r>>2]<<2);c[V>>2]=c[(c[p>>2]|0)+28>>2];S=c[p>>2]|0;if((c[O>>2]|0)>=(c[P>>2]|0)){c[G>>2]=Me(S,c[q>>2]|0,c[r>>2]|0,c[O>>2]|0,c[t>>2]|0,c[u>>2]|0,c[v>>2]|0,+g[w>>2]*+g[E>>2],c[x>>2]|0)|0;c[V>>2]=(c[O>>2]|0)-((c[V>>2]|0)-(c[(c[p>>2]|0)+28>>2]|0));if((c[V>>2]|0)>24&(c[R>>2]|0)!=0)c[P>>2]=(c[P>>2]|0)+((c[V>>2]|0)-24);ba=Me(c[p>>2]|0,c[I>>2]|0,c[r>>2]|0,c[P>>2]|0,c[t>>2]|0,c[U>>2]|0,c[v>>2]|0,+g[w>>2]*+g[F>>2],c[x>>2]>>c[t>>2])|0;c[G>>2]=c[G>>2]|ba<<(c[D>>2]>>1);ca=c[G>>2]|0;i=o;return ca|0}else{ba=Me(S,c[I>>2]|0,c[r>>2]|0,c[P>>2]|0,c[t>>2]|0,c[U>>2]|0,c[v>>2]|0,+g[w>>2]*+g[F>>2],c[x>>2]>>c[t>>2])|0;c[G>>2]=ba<<(c[D>>2]>>1);c[V>>2]=(c[P>>2]|0)-((c[V>>2]|0)-(c[(c[p>>2]|0)+28>>2]|0));if((c[V>>2]|0)>24&(c[R>>2]|0)!=16384)c[O>>2]=(c[O>>2]|0)+((c[V>>2]|0)-24);V=Me(c[p>>2]|0,c[q>>2]|0,c[r>>2]|0,c[O>>2]|0,c[t>>2]|0,c[u>>2]|0,c[v>>2]|0,+g[w>>2]*+g[E>>2],c[x>>2]|0)|0;c[G>>2]=c[G>>2]|V;ca=c[G>>2]|0;i=o;return ca|0}}c[z>>2]=Oe(c[K>>2]|0,c[L>>2]|0,c[v>>2]|0,c[s>>2]|0)|0;c[A>>2]=Pe(c[K>>2]|0,c[L>>2]|0,c[v>>2]|0,c[z>>2]|0)|0;s=(c[p>>2]|0)+28|0;c[s>>2]=(c[s>>2]|0)-(c[A>>2]|0);while(1){if(!((c[(c[p>>2]|0)+28>>2]|0)<0?(c[z>>2]|0)>0:0))break;s=(c[p>>2]|0)+28|0;c[s>>2]=(c[s>>2]|0)+(c[A>>2]|0);c[z>>2]=(c[z>>2]|0)+-1;c[A>>2]=Pe(c[K>>2]|0,c[L>>2]|0,c[v>>2]|0,c[z>>2]|0)|0;s=(c[p>>2]|0)+28|0;c[s>>2]=(c[s>>2]|0)-(c[A>>2]|0)}if(c[z>>2]|0){c[W>>2]=Qe(c[z>>2]|0)|0;z=c[q>>2]|0;A=c[r>>2]|0;v=c[W>>2]|0;W=c[M>>2]|0;M=c[t>>2]|0;L=c[N>>2]|0;if(c[J>>2]|0){c[G>>2]=Gb(z,A,v,W,M,L)|0;ca=c[G>>2]|0;i=o;return ca|0}else{c[G>>2]=Hb(z,A,v,W,M,L,+g[w>>2])|0;ca=c[G>>2]|0;i=o;return ca|0}}if(!(c[H>>2]|0)){ca=c[G>>2]|0;i=o;return ca|0}c[Y>>2]=(1<<c[t>>2])-1;c[x>>2]=c[x>>2]&c[Y>>2];if(!(c[x>>2]|0)){bf(c[q>>2]|0,0,c[r>>2]<<2|0)|0;ca=c[G>>2]|0;i=o;return ca|0}t=(c[u>>2]|0)==0;c[X>>2]=0;if(t){while(1){if((c[X>>2]|0)>=(c[r>>2]|0))break;t=Ra(c[(c[p>>2]|0)+36>>2]|0)|0;c[(c[p>>2]|0)+36>>2]=t;g[(c[q>>2]|0)+(c[X>>2]<<2)>>2]=+(c[(c[p>>2]|0)+36>>2]>>20|0);c[X>>2]=(c[X>>2]|0)+1}c[G>>2]=c[Y>>2]}else{while(1){if((c[X>>2]|0)>=(c[r>>2]|0))break;Y=Ra(c[(c[p>>2]|0)+36>>2]|0)|0;c[(c[p>>2]|0)+36>>2]=Y;g[Z>>2]=.00390625;m=+g[Z>>2];g[Z>>2]=(c[(c[p>>2]|0)+36>>2]&32768|0)!=0?m:-m;g[(c[q>>2]|0)+(c[X>>2]<<2)>>2]=+g[(c[u>>2]|0)+(c[X>>2]<<2)>>2]+ +g[Z>>2];c[X>>2]=(c[X>>2]|0)+1}c[G>>2]=c[x>>2]}Ib(c[q>>2]|0,c[r>>2]|0,+g[w>>2]);ca=c[G>>2]|0;i=o;return ca|0}function Ne(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0;f=i;i=i+48|0;h=f+28|0;j=f+16|0;k=f+4|0;l=f+8|0;m=f+32|0;n=f;o=f+12|0;p=f+24|0;q=f+20|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[o>>2]=_(c[j>>2]|0,c[k>>2]|0)|0;e=c[o>>2]|0;c[p>>2]=ua()|0;d=i;i=i+((1*(e<<2)|0)+15&-16)|0;if(c[l>>2]|0){c[q>>2]=25128+(c[k>>2]<<2)+-8;c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break;c[n>>2]=0;while(1){r=c[m>>2]|0;if((c[n>>2]|0)>=(c[j>>2]|0))break;l=_(c[(c[q>>2]|0)+(r<<2)>>2]|0,c[j>>2]|0)|0;e=_(c[n>>2]|0,c[k>>2]|0)|0;g[d+(e+(c[m>>2]|0)<<2)>>2]=+g[(c[h>>2]|0)+(l+(c[n>>2]|0)<<2)>>2];c[n>>2]=(c[n>>2]|0)+1}c[m>>2]=r+1}s=c[h>>2]|0;t=c[o>>2]|0;u=t<<2;v=c[h>>2]|0;w=v;x=d;y=w-x|0;z=(y|0)/4|0;A=0;B=u+A|0;df(s|0,d|0,B|0)|0;C=c[p>>2]|0;ka(C|0);i=f;return}else{c[m>>2]=0;while(1){if((c[m>>2]|0)>=(c[k>>2]|0))break;c[n>>2]=0;while(1){D=c[m>>2]|0;if((c[n>>2]|0)>=(c[j>>2]|0))break;r=_(D,c[j>>2]|0)|0;q=_(c[n>>2]|0,c[k>>2]|0)|0;g[d+(q+(c[m>>2]|0)<<2)>>2]=+g[(c[h>>2]|0)+(r+(c[n>>2]|0)<<2)>>2];c[n>>2]=(c[n>>2]|0)+1}c[m>>2]=D+1}s=c[h>>2]|0;t=c[o>>2]|0;u=t<<2;v=c[h>>2]|0;w=v;x=d;y=w-x|0;z=(y|0)/4|0;A=0;B=u+A|0;df(s|0,d|0,B|0)|0;C=c[p>>2]|0;ka(C|0);i=f;return}}function Oe(a,e,f,g){a=a|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;h=i;i=i+48|0;j=h;k=h+16|0;l=h+28|0;m=h+4|0;n=h+32|0;o=h+36|0;p=h+12|0;q=h+24|0;r=h+20|0;s=h+8|0;c[k>>2]=a;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[m>>2]=(c[m>>2]|0)+1;g=_(c[m>>2]|0,c[(c[k>>2]|0)+8>>2]|0)|0;c[r>>2]=(c[(c[k>>2]|0)+92+8>>2]|0)+(b[(c[(c[k>>2]|0)+92+4>>2]|0)+(g+(c[l>>2]|0)<<1)>>1]|0);c[p>>2]=0;c[q>>2]=d[c[r>>2]>>0];c[n>>2]=(c[n>>2]|0)+-1;c[o>>2]=0;while(1){if((c[o>>2]|0)>=6)break;c[s>>2]=(c[p>>2]|0)+(c[q>>2]|0)+1>>1;l=c[s>>2]|0;if((d[(c[r>>2]|0)+(c[s>>2]|0)>>0]|0)>=(c[n>>2]|0))c[q>>2]=l;else c[p>>2]=l;c[o>>2]=(c[o>>2]|0)+1}if(!(c[p>>2]|0))t=-1;else t=d[(c[r>>2]|0)+(c[p>>2]|0)>>0]|0;if(((c[n>>2]|0)-t|0)<=((d[(c[r>>2]|0)+(c[q>>2]|0)>>0]|0)-(c[n>>2]|0)|0)){c[j>>2]=c[p>>2];u=c[j>>2]|0;i=h;return u|0}else{c[j>>2]=c[q>>2];u=c[j>>2]|0;i=h;return u|0}return 0}function Pe(a,e,f,g){a=a|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0;h=i;i=i+32|0;j=h+16|0;k=h+12|0;l=h+8|0;m=h+4|0;n=h;c[j>>2]=a;c[k>>2]=e;c[l>>2]=f;c[m>>2]=g;c[l>>2]=(c[l>>2]|0)+1;g=_(c[l>>2]|0,c[(c[j>>2]|0)+8>>2]|0)|0;c[n>>2]=(c[(c[j>>2]|0)+92+8>>2]|0)+(b[(c[(c[j>>2]|0)+92+4>>2]|0)+(g+(c[k>>2]|0)<<1)>>1]|0);if(!(c[m>>2]|0)){o=0;i=h;return o|0}o=(d[(c[n>>2]|0)+(c[m>>2]|0)>>0]|0)+1|0;i=h;return o|0}function Qe(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b;c[d>>2]=a;a=c[d>>2]|0;if((c[d>>2]|0)<8){e=a;i=b;return e|0}e=8+(a&7)<<(c[d>>2]>>3)-1;i=b;return e|0}function Re(){return}function Se(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,j=0.0;d=i;i=i+48|0;e=d+32|0;f=d;Ve(f,a,b);b=c[6312]|0;if((b|0)==1){c[6312]=2;h=1;i=d;return h|0}else if(!b){b=Xe(f,25264,25272,25280,25288,25296)|0;c[6314]=b;if(!b){h=0;i=d;return h|0}c[6312]=1;j=+g[6322];if(j!=0.0){c[e>>2]=~~j;Qc(b,4034,e)|0}c[6312]=1;h=1;i=d;return h|0}else{pa(c[6318]|0,48e3);h=1;i=d;return h|0}return 0}function Te(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;d=i;i=i+16|0;e=d;f=Ze((c[6318]|0)*23040|0)|0;g=Pc(c[6314]|0,a,b,f,5760,0)|0;if((g|0)<0){c[e>>2]=g;va(25304,e|0)|0;h=0;_e(f);i=d;return h|0}e=c[6320]|0;if((g|0)>(e|0)){b=g-e|0;a=c[6318]|0;j=Ze(_(b<<2,a)|0)|0;k=Ze(a<<2)|0;if((a|0)>0){l=0;do{m=_(l,b)|0;c[k+(l<<2)>>2]=j+(m<<2);n=e;do{c[j+(m+(n-e)<<2)>>2]=c[f+((_(a,n)|0)+l<<2)>>2];n=n+1|0}while((n|0)!=(g|0));l=l+1|0}while((l|0)<(a|0))}wa(k|0,a|0,b|0);_e(k);_e(j);o=c[6320]|0;p=e}else{o=e;p=g}c[6320]=o-p;h=1;_e(f);i=d;return h|0}function Ue(){return}function Ve(a,b,d){a=a|0;b=b|0;d=d|0;c[a>>2]=b;c[a+4>>2]=d;d=a+8|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;c[d+16>>2]=0;c[d+20>>2]=0;return}function We(b,e,f){b=b|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;g=i;i=i+16|0;h=g;a[h+8>>0]=0;if((e|0)<19){i=g;return 0}j=b;k=j;l=j+4|0;j=d[l>>0]|d[l+1>>0]<<8|d[l+2>>0]<<16|d[l+3>>0]<<24;l=h;c[l>>2]=d[k>>0]|d[k+1>>0]<<8|d[k+2>>0]<<16|d[k+3>>0]<<24;c[l+4>>2]=j;if(Ye(h,25336,8)|0){i=g;return 0}h=e+-1|0;if((e|0)<9){i=g;return 0}j=d[b+8>>0]|0;c[f>>2]=j;if((e|0)<10|(j&240|0)!=0){i=g;return 0}l=a[b+9>>0]|0;k=f+4|0;c[k>>2]=l&255;if(!(l<<24>>24)){i=g;return 0}m=e+-2|0;if((m|0)<=9){i=g;return 0}c[f+8>>2]=(d[b+11>>0]|0)<<8|(d[b+10>>0]|0);n=f+12|0;if((e+-4|0)<12){i=g;return 0}o=d[b+12>>0]|0;c[n>>2]=o;p=(d[b+13>>0]|0)<<8|o;c[n>>2]=p;o=(d[b+14>>0]|0)<<16|p;c[n>>2]=o;c[n>>2]=(d[b+15>>0]|0)<<24|o;if((m|0)<16){i=g;return 0}c[f+16>>2]=((d[b+17>>0]|0)<<8|(d[b+16>>0]|0))<<16>>16;if((e|0)<19){i=g;return 0}m=a[b+18>>0]|0;c[f+20>>2]=m&255;if(!(m<<24>>24)){if((l&255)>2){i=g;return 0}c[f+24>>2]=1;c[f+28>>2]=(l&255)>1&1;a[f+32>>0]=0;a[f+33>>0]=1;q=j;r=19;s=q>>>0>1;t=(r|0)==(e|0);u=t|s;v=u&1;i=g;return v|0}if((h|0)<=18){i=g;return 0}j=a[b+19>>0]|0;if(!(j<<24>>24)){i=g;return 0}l=j&255;m=f+24|0;c[m>>2]=l;if((h|0)<=19){i=g;return 0}o=a[b+20>>0]|0;n=o&255;if((o&255)>(j&255)|(n+l|0)>255){i=g;return 0}l=f+28|0;c[l>>2]=n;n=21;j=0;while(1){if((n|0)>(h|0)){w=23;break}o=a[b+n>>0]|0;a[f+32+j>>0]=o;p=n+1|0;j=j+1|0;if(!(o<<24>>24==-1?1:(o&255|0)<=((c[l>>2]|0)+(c[m>>2]|0)|0))){w=23;break}if((j|0)>=(c[k>>2]|0)){x=p;w=21;break}else n=p}if((w|0)==21){q=c[f>>2]|0;r=x;s=q>>>0>1;t=(r|0)==(e|0);u=t|s;v=u&1;i=g;return v|0}else if((w|0)==23){i=g;return 0}return 0}function Xe(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var j=0,k=0,l=0,m=0,n=0;j=i;i=i+304|0;k=j;l=j+296|0;m=j+8|0;if(!(We(c[a>>2]|0,c[a+4>>2]|0,m)|0)){n=0;i=j;return n|0}c[b>>2]=c[m+20>>2];b=c[m+4>>2]|0;c[d>>2]=b;c[e>>2]=c[m+8>>2];e=m+24|0;d=Oc(48e3,b,c[e>>2]|0,c[m+28>>2]|0,m+32|0,l)|0;if((d|0)==0|(c[l>>2]|0)!=0){n=0;i=j;return n|0}c[h>>2]=c[e>>2];e=m+16|0;m=c[e>>2]|0;do if(m){c[k>>2]=m;h=Qc(d,4034,k)|0;c[l>>2]=h;if(!h)break;else if((h|0)==-5){g[f>>2]=+P(10.0,+(+(c[e>>2]|0)/5120.0));break}else{n=0;i=j;return n|0}}while(0);n=d;i=j;return n|0}function Ye(b,c,d){b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0;if(!d){e=0;return e|0}else{f=d;g=b;h=c}while(1){c=a[g>>0]|0;b=a[h>>0]|0;if(c<<24>>24!=b<<24>>24){i=c;j=b;break}f=f+-1|0;if(!f){e=0;k=5;break}else{g=g+1|0;h=h+1|0}}if((k|0)==5)return e|0;e=(i&255)-(j&255)|0;return e|0}function Ze(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,pa=0,qa=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,Aa=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0,Oa=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Va=0,Wa=0,Xa=0;do if(a>>>0<245){b=a>>>0<11?16:a+11&-8;d=b>>>3;e=c[6338]|0;f=e>>>d;if(f&3){g=(f&1^1)+d|0;h=g<<1;i=25392+(h<<2)|0;j=25392+(h+2<<2)|0;h=c[j>>2]|0;k=h+8|0;l=c[k>>2]|0;do if((i|0)!=(l|0)){if(l>>>0<(c[6342]|0)>>>0)za();m=l+12|0;if((c[m>>2]|0)==(h|0)){c[m>>2]=i;c[j>>2]=l;break}else za()}else c[6338]=e&~(1<<g);while(0);l=g<<3;c[h+4>>2]=l|3;j=h+(l|4)|0;c[j>>2]=c[j>>2]|1;n=k;return n|0}j=c[6340]|0;if(b>>>0>j>>>0){if(f){l=2<<d;i=f<<d&(l|0-l);l=(i&0-i)+-1|0;i=l>>>12&16;m=l>>>i;l=m>>>5&8;o=m>>>l;m=o>>>2&4;p=o>>>m;o=p>>>1&2;q=p>>>o;p=q>>>1&1;r=(l|i|m|o|p)+(q>>>p)|0;p=r<<1;q=25392+(p<<2)|0;o=25392+(p+2<<2)|0;p=c[o>>2]|0;m=p+8|0;i=c[m>>2]|0;do if((q|0)!=(i|0)){if(i>>>0<(c[6342]|0)>>>0)za();l=i+12|0;if((c[l>>2]|0)==(p|0)){c[l>>2]=q;c[o>>2]=i;s=c[6340]|0;break}else za()}else{c[6338]=e&~(1<<r);s=j}while(0);j=r<<3;e=j-b|0;c[p+4>>2]=b|3;i=p+b|0;c[p+(b|4)>>2]=e|1;c[p+j>>2]=e;if(s){j=c[6343]|0;o=s>>>3;q=o<<1;d=25392+(q<<2)|0;f=c[6338]|0;k=1<<o;if(f&k){o=25392+(q+2<<2)|0;h=c[o>>2]|0;if(h>>>0<(c[6342]|0)>>>0)za();else{t=o;u=h}}else{c[6338]=f|k;t=25392+(q+2<<2)|0;u=d}c[t>>2]=j;c[u+12>>2]=j;c[j+8>>2]=u;c[j+12>>2]=d}c[6340]=e;c[6343]=i;n=m;return n|0}i=c[6339]|0;if(i){e=(i&0-i)+-1|0;i=e>>>12&16;d=e>>>i;e=d>>>5&8;j=d>>>e;d=j>>>2&4;q=j>>>d;j=q>>>1&2;k=q>>>j;q=k>>>1&1;f=c[25656+((e|i|d|j|q)+(k>>>q)<<2)>>2]|0;q=(c[f+4>>2]&-8)-b|0;k=f;j=f;while(1){f=c[k+16>>2]|0;if(!f){d=c[k+20>>2]|0;if(!d){v=q;w=j;break}else x=d}else x=f;f=(c[x+4>>2]&-8)-b|0;d=f>>>0<q>>>0;q=d?f:q;k=x;j=d?x:j}j=c[6342]|0;if(w>>>0<j>>>0)za();k=w+b|0;if(w>>>0>=k>>>0)za();q=c[w+24>>2]|0;m=c[w+12>>2]|0;do if((m|0)==(w|0)){p=w+20|0;r=c[p>>2]|0;if(!r){d=w+16|0;f=c[d>>2]|0;if(!f){y=0;break}else{z=f;A=d}}else{z=r;A=p}while(1){p=z+20|0;r=c[p>>2]|0;if(r){z=r;A=p;continue}p=z+16|0;r=c[p>>2]|0;if(!r){B=z;C=A;break}else{z=r;A=p}}if(C>>>0<j>>>0)za();else{c[C>>2]=0;y=B;break}}else{p=c[w+8>>2]|0;if(p>>>0<j>>>0)za();r=p+12|0;if((c[r>>2]|0)!=(w|0))za();d=m+8|0;if((c[d>>2]|0)==(w|0)){c[r>>2]=m;c[d>>2]=p;y=m;break}else za()}while(0);do if(q){m=c[w+28>>2]|0;j=25656+(m<<2)|0;if((w|0)==(c[j>>2]|0)){c[j>>2]=y;if(!y){c[6339]=c[6339]&~(1<<m);break}}else{if(q>>>0<(c[6342]|0)>>>0)za();m=q+16|0;if((c[m>>2]|0)==(w|0))c[m>>2]=y;else c[q+20>>2]=y;if(!y)break}m=c[6342]|0;if(y>>>0<m>>>0)za();c[y+24>>2]=q;j=c[w+16>>2]|0;do if(j)if(j>>>0<m>>>0)za();else{c[y+16>>2]=j;c[j+24>>2]=y;break}while(0);j=c[w+20>>2]|0;if(j)if(j>>>0<(c[6342]|0)>>>0)za();else{c[y+20>>2]=j;c[j+24>>2]=y;break}}while(0);if(v>>>0<16){q=v+b|0;c[w+4>>2]=q|3;j=w+(q+4)|0;c[j>>2]=c[j>>2]|1}else{c[w+4>>2]=b|3;c[w+(b|4)>>2]=v|1;c[w+(v+b)>>2]=v;j=c[6340]|0;if(j){q=c[6343]|0;m=j>>>3;j=m<<1;p=25392+(j<<2)|0;d=c[6338]|0;r=1<<m;if(d&r){m=25392+(j+2<<2)|0;f=c[m>>2]|0;if(f>>>0<(c[6342]|0)>>>0)za();else{D=m;E=f}}else{c[6338]=d|r;D=25392+(j+2<<2)|0;E=p}c[D>>2]=q;c[E+12>>2]=q;c[q+8>>2]=E;c[q+12>>2]=p}c[6340]=v;c[6343]=k}n=w+8|0;return n|0}else F=b}else F=b}else if(a>>>0<=4294967231){p=a+11|0;q=p&-8;j=c[6339]|0;if(j){r=0-q|0;d=p>>>8;if(d)if(q>>>0>16777215)G=31;else{p=(d+1048320|0)>>>16&8;f=d<<p;d=(f+520192|0)>>>16&4;m=f<<d;f=(m+245760|0)>>>16&2;i=14-(d|p|f)+(m<<f>>>15)|0;G=q>>>(i+7|0)&1|i<<1}else G=0;i=c[25656+(G<<2)>>2]|0;a:do if(!i){H=r;I=0;J=0;K=86}else{f=r;m=0;p=q<<((G|0)==31?0:25-(G>>>1)|0);d=i;e=0;while(1){h=c[d+4>>2]&-8;o=h-q|0;if(o>>>0<f>>>0)if((h|0)==(q|0)){L=o;M=d;N=d;K=90;break a}else{O=o;P=d}else{O=f;P=e}o=c[d+20>>2]|0;d=c[d+16+(p>>>31<<2)>>2]|0;h=(o|0)==0|(o|0)==(d|0)?m:o;if(!d){H=O;I=h;J=P;K=86;break}else{f=O;m=h;p=p<<1;e=P}}}while(0);if((K|0)==86){if((I|0)==0&(J|0)==0){i=2<<G;r=j&(i|0-i);if(!r){F=q;break}i=(r&0-r)+-1|0;r=i>>>12&16;b=i>>>r;i=b>>>5&8;k=b>>>i;b=k>>>2&4;e=k>>>b;k=e>>>1&2;p=e>>>k;e=p>>>1&1;Q=c[25656+((i|r|b|k|e)+(p>>>e)<<2)>>2]|0;R=0}else{Q=I;R=J}if(!Q){S=H;T=R}else{L=H;M=Q;N=R;K=90}}if((K|0)==90)while(1){K=0;e=(c[M+4>>2]&-8)-q|0;p=e>>>0<L>>>0;k=p?e:L;e=p?M:N;p=c[M+16>>2]|0;if(p){L=k;M=p;N=e;K=90;continue}M=c[M+20>>2]|0;if(!M){S=k;T=e;break}else{L=k;N=e;K=90}}if((T|0)!=0?S>>>0<((c[6340]|0)-q|0)>>>0:0){j=c[6342]|0;if(T>>>0<j>>>0)za();e=T+q|0;if(T>>>0>=e>>>0)za();k=c[T+24>>2]|0;p=c[T+12>>2]|0;do if((p|0)==(T|0)){b=T+20|0;r=c[b>>2]|0;if(!r){i=T+16|0;m=c[i>>2]|0;if(!m){U=0;break}else{V=m;W=i}}else{V=r;W=b}while(1){b=V+20|0;r=c[b>>2]|0;if(r){V=r;W=b;continue}b=V+16|0;r=c[b>>2]|0;if(!r){X=V;Y=W;break}else{V=r;W=b}}if(Y>>>0<j>>>0)za();else{c[Y>>2]=0;U=X;break}}else{b=c[T+8>>2]|0;if(b>>>0<j>>>0)za();r=b+12|0;if((c[r>>2]|0)!=(T|0))za();i=p+8|0;if((c[i>>2]|0)==(T|0)){c[r>>2]=p;c[i>>2]=b;U=p;break}else za()}while(0);do if(k){p=c[T+28>>2]|0;j=25656+(p<<2)|0;if((T|0)==(c[j>>2]|0)){c[j>>2]=U;if(!U){c[6339]=c[6339]&~(1<<p);break}}else{if(k>>>0<(c[6342]|0)>>>0)za();p=k+16|0;if((c[p>>2]|0)==(T|0))c[p>>2]=U;else c[k+20>>2]=U;if(!U)break}p=c[6342]|0;if(U>>>0<p>>>0)za();c[U+24>>2]=k;j=c[T+16>>2]|0;do if(j)if(j>>>0<p>>>0)za();else{c[U+16>>2]=j;c[j+24>>2]=U;break}while(0);j=c[T+20>>2]|0;if(j)if(j>>>0<(c[6342]|0)>>>0)za();else{c[U+20>>2]=j;c[j+24>>2]=U;break}}while(0);b:do if(S>>>0>=16){c[T+4>>2]=q|3;c[T+(q|4)>>2]=S|1;c[T+(S+q)>>2]=S;k=S>>>3;if(S>>>0<256){j=k<<1;p=25392+(j<<2)|0;b=c[6338]|0;i=1<<k;if(b&i){k=25392+(j+2<<2)|0;r=c[k>>2]|0;if(r>>>0<(c[6342]|0)>>>0)za();else{Z=k;_=r}}else{c[6338]=b|i;Z=25392+(j+2<<2)|0;_=p}c[Z>>2]=e;c[_+12>>2]=e;c[T+(q+8)>>2]=_;c[T+(q+12)>>2]=p;break}p=S>>>8;if(p)if(S>>>0>16777215)$=31;else{j=(p+1048320|0)>>>16&8;i=p<<j;p=(i+520192|0)>>>16&4;b=i<<p;i=(b+245760|0)>>>16&2;r=14-(p|j|i)+(b<<i>>>15)|0;$=S>>>(r+7|0)&1|r<<1}else $=0;r=25656+($<<2)|0;c[T+(q+28)>>2]=$;c[T+(q+20)>>2]=0;c[T+(q+16)>>2]=0;i=c[6339]|0;b=1<<$;if(!(i&b)){c[6339]=i|b;c[r>>2]=e;c[T+(q+24)>>2]=r;c[T+(q+12)>>2]=e;c[T+(q+8)>>2]=e;break}b=c[r>>2]|0;c:do if((c[b+4>>2]&-8|0)!=(S|0)){r=S<<(($|0)==31?0:25-($>>>1)|0);i=b;while(1){j=i+16+(r>>>31<<2)|0;p=c[j>>2]|0;if(!p){aa=j;ba=i;break}if((c[p+4>>2]&-8|0)==(S|0)){ca=p;break c}else{r=r<<1;i=p}}if(aa>>>0<(c[6342]|0)>>>0)za();else{c[aa>>2]=e;c[T+(q+24)>>2]=ba;c[T+(q+12)>>2]=e;c[T+(q+8)>>2]=e;break b}}else ca=b;while(0);b=ca+8|0;i=c[b>>2]|0;r=c[6342]|0;if(i>>>0>=r>>>0&ca>>>0>=r>>>0){c[i+12>>2]=e;c[b>>2]=e;c[T+(q+8)>>2]=i;c[T+(q+12)>>2]=ca;c[T+(q+24)>>2]=0;break}else za()}else{i=S+q|0;c[T+4>>2]=i|3;b=T+(i+4)|0;c[b>>2]=c[b>>2]|1}while(0);n=T+8|0;return n|0}else F=q}else F=q}else F=-1;while(0);T=c[6340]|0;if(T>>>0>=F>>>0){S=T-F|0;ca=c[6343]|0;if(S>>>0>15){c[6343]=ca+F;c[6340]=S;c[ca+(F+4)>>2]=S|1;c[ca+T>>2]=S;c[ca+4>>2]=F|3}else{c[6340]=0;c[6343]=0;c[ca+4>>2]=T|3;S=ca+(T+4)|0;c[S>>2]=c[S>>2]|1}n=ca+8|0;return n|0}ca=c[6341]|0;if(ca>>>0>F>>>0){S=ca-F|0;c[6341]=S;ca=c[6344]|0;c[6344]=ca+F;c[ca+(F+4)>>2]=S|1;c[ca+4>>2]=F|3;n=ca+8|0;return n|0}do if(!(c[6456]|0)){ca=ra(30)|0;if(!(ca+-1&ca)){c[6458]=ca;c[6457]=ca;c[6459]=-1;c[6460]=-1;c[6461]=0;c[6449]=0;c[6456]=(Ba(0)|0)&-16^1431655768;break}else za()}while(0);ca=F+48|0;S=c[6458]|0;T=F+47|0;ba=S+T|0;aa=0-S|0;S=ba&aa;if(S>>>0<=F>>>0){n=0;return n|0}$=c[6448]|0;if(($|0)!=0?(_=c[6446]|0,Z=_+S|0,Z>>>0<=_>>>0|Z>>>0>$>>>0):0){n=0;return n|0}d:do if(!(c[6449]&4)){$=c[6344]|0;e:do if($){Z=25800;while(1){_=c[Z>>2]|0;if(_>>>0<=$>>>0?(U=Z+4|0,(_+(c[U>>2]|0)|0)>>>0>$>>>0):0){da=Z;ea=U;break}Z=c[Z+8>>2]|0;if(!Z){K=174;break e}}Z=ba-(c[6341]|0)&aa;if(Z>>>0<2147483647){U=oa(Z|0)|0;_=(U|0)==((c[da>>2]|0)+(c[ea>>2]|0)|0);X=_?Z:0;if(_)if((U|0)==(-1|0))fa=X;else{ga=U;ha=X;K=194;break d}else{ia=U;ja=Z;ka=X;K=184}}else fa=0}else K=174;while(0);do if((K|0)==174){$=oa(0)|0;if(($|0)!=(-1|0)){q=$;X=c[6457]|0;Z=X+-1|0;if(!(Z&q))la=S;else la=S-q+(Z+q&0-X)|0;X=c[6446]|0;q=X+la|0;if(la>>>0>F>>>0&la>>>0<2147483647){Z=c[6448]|0;if((Z|0)!=0?q>>>0<=X>>>0|q>>>0>Z>>>0:0){fa=0;break}Z=oa(la|0)|0;q=(Z|0)==($|0);X=q?la:0;if(q){ga=$;ha=X;K=194;break d}else{ia=Z;ja=la;ka=X;K=184}}else fa=0}else fa=0}while(0);f:do if((K|0)==184){X=0-ja|0;do if(ca>>>0>ja>>>0&(ja>>>0<2147483647&(ia|0)!=(-1|0))?(Z=c[6458]|0,$=T-ja+Z&0-Z,$>>>0<2147483647):0)if((oa($|0)|0)==(-1|0)){oa(X|0)|0;fa=ka;break f}else{ma=$+ja|0;break}else ma=ja;while(0);if((ia|0)==(-1|0))fa=ka;else{ga=ia;ha=ma;K=194;break d}}while(0);c[6449]=c[6449]|4;na=fa;K=191}else{na=0;K=191}while(0);if((((K|0)==191?S>>>0<2147483647:0)?(fa=oa(S|0)|0,S=oa(0)|0,fa>>>0<S>>>0&((fa|0)!=(-1|0)&(S|0)!=(-1|0))):0)?(ma=S-fa|0,S=ma>>>0>(F+40|0)>>>0,S):0){ga=fa;ha=S?ma:na;K=194}if((K|0)==194){na=(c[6446]|0)+ha|0;c[6446]=na;if(na>>>0>(c[6447]|0)>>>0)c[6447]=na;na=c[6344]|0;g:do if(na){ma=25800;do{S=c[ma>>2]|0;fa=ma+4|0;ia=c[fa>>2]|0;if((ga|0)==(S+ia|0)){pa=S;qa=fa;sa=ia;ta=ma;K=204;break}ma=c[ma+8>>2]|0}while((ma|0)!=0);if(((K|0)==204?(c[ta+12>>2]&8|0)==0:0)?na>>>0<ga>>>0&na>>>0>=pa>>>0:0){c[qa>>2]=sa+ha;ma=(c[6341]|0)+ha|0;ia=na+8|0;fa=(ia&7|0)==0?0:0-ia&7;ia=ma-fa|0;c[6344]=na+fa;c[6341]=ia;c[na+(fa+4)>>2]=ia|1;c[na+(ma+4)>>2]=40;c[6345]=c[6460];break}ma=c[6342]|0;if(ga>>>0<ma>>>0){c[6342]=ga;ua=ga}else ua=ma;ma=ga+ha|0;ia=25800;while(1){if((c[ia>>2]|0)==(ma|0)){va=ia;wa=ia;K=212;break}ia=c[ia+8>>2]|0;if(!ia){xa=25800;break}}if((K|0)==212)if(!(c[wa+12>>2]&8)){c[va>>2]=ga;ia=wa+4|0;c[ia>>2]=(c[ia>>2]|0)+ha;ia=ga+8|0;ma=(ia&7|0)==0?0:0-ia&7;ia=ga+(ha+8)|0;fa=(ia&7|0)==0?0:0-ia&7;ia=ga+(fa+ha)|0;S=ma+F|0;ka=ga+S|0;ja=ia-(ga+ma)-F|0;c[ga+(ma+4)>>2]=F|3;h:do if((ia|0)!=(na|0)){if((ia|0)==(c[6343]|0)){T=(c[6340]|0)+ja|0;c[6340]=T;c[6343]=ka;c[ga+(S+4)>>2]=T|1;c[ga+(T+S)>>2]=T;break}T=ha+4|0;ca=c[ga+(T+fa)>>2]|0;if((ca&3|0)==1){la=ca&-8;ea=ca>>>3;i:do if(ca>>>0>=256){da=c[ga+((fa|24)+ha)>>2]|0;aa=c[ga+(ha+12+fa)>>2]|0;do if((aa|0)==(ia|0)){ba=fa|16;X=ga+(T+ba)|0;$=c[X>>2]|0;if(!$){Z=ga+(ba+ha)|0;ba=c[Z>>2]|0;if(!ba){Aa=0;break}else{Ca=ba;Da=Z}}else{Ca=$;Da=X}while(1){X=Ca+20|0;$=c[X>>2]|0;if($){Ca=$;Da=X;continue}X=Ca+16|0;$=c[X>>2]|0;if(!$){Ea=Ca;Fa=Da;break}else{Ca=$;Da=X}}if(Fa>>>0<ua>>>0)za();else{c[Fa>>2]=0;Aa=Ea;break}}else{X=c[ga+((fa|8)+ha)>>2]|0;if(X>>>0<ua>>>0)za();$=X+12|0;if((c[$>>2]|0)!=(ia|0))za();Z=aa+8|0;if((c[Z>>2]|0)==(ia|0)){c[$>>2]=aa;c[Z>>2]=X;Aa=aa;break}else za()}while(0);if(!da)break;aa=c[ga+(ha+28+fa)>>2]|0;X=25656+(aa<<2)|0;do if((ia|0)!=(c[X>>2]|0)){if(da>>>0<(c[6342]|0)>>>0)za();Z=da+16|0;if((c[Z>>2]|0)==(ia|0))c[Z>>2]=Aa;else c[da+20>>2]=Aa;if(!Aa)break i}else{c[X>>2]=Aa;if(Aa)break;c[6339]=c[6339]&~(1<<aa);break i}while(0);aa=c[6342]|0;if(Aa>>>0<aa>>>0)za();c[Aa+24>>2]=da;X=fa|16;Z=c[ga+(X+ha)>>2]|0;do if(Z)if(Z>>>0<aa>>>0)za();else{c[Aa+16>>2]=Z;c[Z+24>>2]=Aa;break}while(0);Z=c[ga+(T+X)>>2]|0;if(!Z)break;if(Z>>>0<(c[6342]|0)>>>0)za();else{c[Aa+20>>2]=Z;c[Z+24>>2]=Aa;break}}else{Z=c[ga+((fa|8)+ha)>>2]|0;aa=c[ga+(ha+12+fa)>>2]|0;da=25392+(ea<<1<<2)|0;do if((Z|0)!=(da|0)){if(Z>>>0<ua>>>0)za();if((c[Z+12>>2]|0)==(ia|0))break;za()}while(0);if((aa|0)==(Z|0)){c[6338]=c[6338]&~(1<<ea);break}do if((aa|0)==(da|0))Ga=aa+8|0;else{if(aa>>>0<ua>>>0)za();X=aa+8|0;if((c[X>>2]|0)==(ia|0)){Ga=X;break}za()}while(0);c[Z+12>>2]=aa;c[Ga>>2]=Z}while(0);Ha=ga+((la|fa)+ha)|0;Ia=la+ja|0}else{Ha=ia;Ia=ja}ea=Ha+4|0;c[ea>>2]=c[ea>>2]&-2;c[ga+(S+4)>>2]=Ia|1;c[ga+(Ia+S)>>2]=Ia;ea=Ia>>>3;if(Ia>>>0<256){T=ea<<1;ca=25392+(T<<2)|0;da=c[6338]|0;X=1<<ea;do if(!(da&X)){c[6338]=da|X;Ja=25392+(T+2<<2)|0;Ka=ca}else{ea=25392+(T+2<<2)|0;$=c[ea>>2]|0;if($>>>0>=(c[6342]|0)>>>0){Ja=ea;Ka=$;break}za()}while(0);c[Ja>>2]=ka;c[Ka+12>>2]=ka;c[ga+(S+8)>>2]=Ka;c[ga+(S+12)>>2]=ca;break}T=Ia>>>8;do if(!T)La=0;else{if(Ia>>>0>16777215){La=31;break}X=(T+1048320|0)>>>16&8;da=T<<X;la=(da+520192|0)>>>16&4;$=da<<la;da=($+245760|0)>>>16&2;ea=14-(la|X|da)+($<<da>>>15)|0;La=Ia>>>(ea+7|0)&1|ea<<1}while(0);T=25656+(La<<2)|0;c[ga+(S+28)>>2]=La;c[ga+(S+20)>>2]=0;c[ga+(S+16)>>2]=0;ca=c[6339]|0;ea=1<<La;if(!(ca&ea)){c[6339]=ca|ea;c[T>>2]=ka;c[ga+(S+24)>>2]=T;c[ga+(S+12)>>2]=ka;c[ga+(S+8)>>2]=ka;break}ea=c[T>>2]|0;j:do if((c[ea+4>>2]&-8|0)!=(Ia|0)){T=Ia<<((La|0)==31?0:25-(La>>>1)|0);ca=ea;while(1){da=ca+16+(T>>>31<<2)|0;$=c[da>>2]|0;if(!$){Ma=da;Na=ca;break}if((c[$+4>>2]&-8|0)==(Ia|0)){Oa=$;break j}else{T=T<<1;ca=$}}if(Ma>>>0<(c[6342]|0)>>>0)za();else{c[Ma>>2]=ka;c[ga+(S+24)>>2]=Na;c[ga+(S+12)>>2]=ka;c[ga+(S+8)>>2]=ka;break h}}else Oa=ea;while(0);ea=Oa+8|0;ca=c[ea>>2]|0;T=c[6342]|0;if(ca>>>0>=T>>>0&Oa>>>0>=T>>>0){c[ca+12>>2]=ka;c[ea>>2]=ka;c[ga+(S+8)>>2]=ca;c[ga+(S+12)>>2]=Oa;c[ga+(S+24)>>2]=0;break}else za()}else{ca=(c[6341]|0)+ja|0;c[6341]=ca;c[6344]=ka;c[ga+(S+4)>>2]=ca|1}while(0);n=ga+(ma|8)|0;return n|0}else xa=25800;while(1){S=c[xa>>2]|0;if(S>>>0<=na>>>0?(ka=c[xa+4>>2]|0,ja=S+ka|0,ja>>>0>na>>>0):0){Pa=S;Qa=ka;Ra=ja;break}xa=c[xa+8>>2]|0}ma=Pa+(Qa+-39)|0;ja=Pa+(Qa+-47+((ma&7|0)==0?0:0-ma&7))|0;ma=na+16|0;ka=ja>>>0<ma>>>0?na:ja;ja=ka+8|0;S=ga+8|0;ia=(S&7|0)==0?0:0-S&7;S=ha+-40-ia|0;c[6344]=ga+ia;c[6341]=S;c[ga+(ia+4)>>2]=S|1;c[ga+(ha+-36)>>2]=40;c[6345]=c[6460];S=ka+4|0;c[S>>2]=27;c[ja>>2]=c[6450];c[ja+4>>2]=c[6451];c[ja+8>>2]=c[6452];c[ja+12>>2]=c[6453];c[6450]=ga;c[6451]=ha;c[6453]=0;c[6452]=ja;ja=ka+28|0;c[ja>>2]=7;if((ka+32|0)>>>0<Ra>>>0){ia=ja;do{ja=ia;ia=ia+4|0;c[ia>>2]=7}while((ja+8|0)>>>0<Ra>>>0)}if((ka|0)!=(na|0)){ia=ka-na|0;c[S>>2]=c[S>>2]&-2;c[na+4>>2]=ia|1;c[ka>>2]=ia;ja=ia>>>3;if(ia>>>0<256){fa=ja<<1;ca=25392+(fa<<2)|0;ea=c[6338]|0;T=1<<ja;if(ea&T){ja=25392+(fa+2<<2)|0;Z=c[ja>>2]|0;if(Z>>>0<(c[6342]|0)>>>0)za();else{Sa=ja;Ta=Z}}else{c[6338]=ea|T;Sa=25392+(fa+2<<2)|0;Ta=ca}c[Sa>>2]=na;c[Ta+12>>2]=na;c[na+8>>2]=Ta;c[na+12>>2]=ca;break}ca=ia>>>8;if(ca)if(ia>>>0>16777215)Ua=31;else{fa=(ca+1048320|0)>>>16&8;T=ca<<fa;ca=(T+520192|0)>>>16&4;ea=T<<ca;T=(ea+245760|0)>>>16&2;Z=14-(ca|fa|T)+(ea<<T>>>15)|0;Ua=ia>>>(Z+7|0)&1|Z<<1}else Ua=0;Z=25656+(Ua<<2)|0;c[na+28>>2]=Ua;c[na+20>>2]=0;c[ma>>2]=0;T=c[6339]|0;ea=1<<Ua;if(!(T&ea)){c[6339]=T|ea;c[Z>>2]=na;c[na+24>>2]=Z;c[na+12>>2]=na;c[na+8>>2]=na;break}ea=c[Z>>2]|0;k:do if((c[ea+4>>2]&-8|0)!=(ia|0)){Z=ia<<((Ua|0)==31?0:25-(Ua>>>1)|0);T=ea;while(1){fa=T+16+(Z>>>31<<2)|0;ca=c[fa>>2]|0;if(!ca){Va=fa;Wa=T;break}if((c[ca+4>>2]&-8|0)==(ia|0)){Xa=ca;break k}else{Z=Z<<1;T=ca}}if(Va>>>0<(c[6342]|0)>>>0)za();else{c[Va>>2]=na;c[na+24>>2]=Wa;c[na+12>>2]=na;c[na+8>>2]=na;break g}}else Xa=ea;while(0);ea=Xa+8|0;ia=c[ea>>2]|0;ma=c[6342]|0;if(ia>>>0>=ma>>>0&Xa>>>0>=ma>>>0){c[ia+12>>2]=na;c[ea>>2]=na;c[na+8>>2]=ia;c[na+12>>2]=Xa;c[na+24>>2]=0;break}else za()}}else{ia=c[6342]|0;if((ia|0)==0|ga>>>0<ia>>>0)c[6342]=ga;c[6450]=ga;c[6451]=ha;c[6453]=0;c[6347]=c[6456];c[6346]=-1;ia=0;do{ea=ia<<1;ma=25392+(ea<<2)|0;c[25392+(ea+3<<2)>>2]=ma;c[25392+(ea+2<<2)>>2]=ma;ia=ia+1|0}while((ia|0)!=32);ia=ga+8|0;ma=(ia&7|0)==0?0:0-ia&7;ia=ha+-40-ma|0;c[6344]=ga+ma;c[6341]=ia;c[ga+(ma+4)>>2]=ia|1;c[ga+(ha+-36)>>2]=40;c[6345]=c[6460]}while(0);ha=c[6341]|0;if(ha>>>0>F>>>0){ga=ha-F|0;c[6341]=ga;ha=c[6344]|0;c[6344]=ha+F;c[ha+(F+4)>>2]=ga|1;c[ha+4>>2]=F|3;n=ha+8|0;return n|0}}c[(ya()|0)>>2]=12;n=0;return n|0}function _e(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;if(!a)return;b=a+-8|0;d=c[6342]|0;if(b>>>0<d>>>0)za();e=c[a+-4>>2]|0;f=e&3;if((f|0)==1)za();g=e&-8;h=a+(g+-8)|0;do if(!(e&1)){i=c[b>>2]|0;if(!f)return;j=-8-i|0;k=a+j|0;l=i+g|0;if(k>>>0<d>>>0)za();if((k|0)==(c[6343]|0)){m=a+(g+-4)|0;n=c[m>>2]|0;if((n&3|0)!=3){o=k;p=l;break}c[6340]=l;c[m>>2]=n&-2;c[a+(j+4)>>2]=l|1;c[h>>2]=l;return}n=i>>>3;if(i>>>0<256){i=c[a+(j+8)>>2]|0;m=c[a+(j+12)>>2]|0;q=25392+(n<<1<<2)|0;if((i|0)!=(q|0)){if(i>>>0<d>>>0)za();if((c[i+12>>2]|0)!=(k|0))za()}if((m|0)==(i|0)){c[6338]=c[6338]&~(1<<n);o=k;p=l;break}if((m|0)!=(q|0)){if(m>>>0<d>>>0)za();q=m+8|0;if((c[q>>2]|0)==(k|0))r=q;else za()}else r=m+8|0;c[i+12>>2]=m;c[r>>2]=i;o=k;p=l;break}i=c[a+(j+24)>>2]|0;m=c[a+(j+12)>>2]|0;do if((m|0)==(k|0)){q=a+(j+20)|0;n=c[q>>2]|0;if(!n){s=a+(j+16)|0;t=c[s>>2]|0;if(!t){u=0;break}else{v=t;w=s}}else{v=n;w=q}while(1){q=v+20|0;n=c[q>>2]|0;if(n){v=n;w=q;continue}q=v+16|0;n=c[q>>2]|0;if(!n){x=v;y=w;break}else{v=n;w=q}}if(y>>>0<d>>>0)za();else{c[y>>2]=0;u=x;break}}else{q=c[a+(j+8)>>2]|0;if(q>>>0<d>>>0)za();n=q+12|0;if((c[n>>2]|0)!=(k|0))za();s=m+8|0;if((c[s>>2]|0)==(k|0)){c[n>>2]=m;c[s>>2]=q;u=m;break}else za()}while(0);if(i){m=c[a+(j+28)>>2]|0;q=25656+(m<<2)|0;if((k|0)==(c[q>>2]|0)){c[q>>2]=u;if(!u){c[6339]=c[6339]&~(1<<m);o=k;p=l;break}}else{if(i>>>0<(c[6342]|0)>>>0)za();m=i+16|0;if((c[m>>2]|0)==(k|0))c[m>>2]=u;else c[i+20>>2]=u;if(!u){o=k;p=l;break}}m=c[6342]|0;if(u>>>0<m>>>0)za();c[u+24>>2]=i;q=c[a+(j+16)>>2]|0;do if(q)if(q>>>0<m>>>0)za();else{c[u+16>>2]=q;c[q+24>>2]=u;break}while(0);q=c[a+(j+20)>>2]|0;if(q)if(q>>>0<(c[6342]|0)>>>0)za();else{c[u+20>>2]=q;c[q+24>>2]=u;o=k;p=l;break}else{o=k;p=l}}else{o=k;p=l}}else{o=b;p=g}while(0);if(o>>>0>=h>>>0)za();b=a+(g+-4)|0;u=c[b>>2]|0;if(!(u&1))za();if(!(u&2)){if((h|0)==(c[6344]|0)){d=(c[6341]|0)+p|0;c[6341]=d;c[6344]=o;c[o+4>>2]=d|1;if((o|0)!=(c[6343]|0))return;c[6343]=0;c[6340]=0;return}if((h|0)==(c[6343]|0)){d=(c[6340]|0)+p|0;c[6340]=d;c[6343]=o;c[o+4>>2]=d|1;c[o+d>>2]=d;return}d=(u&-8)+p|0;x=u>>>3;do if(u>>>0>=256){y=c[a+(g+16)>>2]|0;w=c[a+(g|4)>>2]|0;do if((w|0)==(h|0)){v=a+(g+12)|0;r=c[v>>2]|0;if(!r){f=a+(g+8)|0;e=c[f>>2]|0;if(!e){z=0;break}else{A=e;B=f}}else{A=r;B=v}while(1){v=A+20|0;r=c[v>>2]|0;if(r){A=r;B=v;continue}v=A+16|0;r=c[v>>2]|0;if(!r){C=A;D=B;break}else{A=r;B=v}}if(D>>>0<(c[6342]|0)>>>0)za();else{c[D>>2]=0;z=C;break}}else{v=c[a+g>>2]|0;if(v>>>0<(c[6342]|0)>>>0)za();r=v+12|0;if((c[r>>2]|0)!=(h|0))za();f=w+8|0;if((c[f>>2]|0)==(h|0)){c[r>>2]=w;c[f>>2]=v;z=w;break}else za()}while(0);if(y){w=c[a+(g+20)>>2]|0;l=25656+(w<<2)|0;if((h|0)==(c[l>>2]|0)){c[l>>2]=z;if(!z){c[6339]=c[6339]&~(1<<w);break}}else{if(y>>>0<(c[6342]|0)>>>0)za();w=y+16|0;if((c[w>>2]|0)==(h|0))c[w>>2]=z;else c[y+20>>2]=z;if(!z)break}w=c[6342]|0;if(z>>>0<w>>>0)za();c[z+24>>2]=y;l=c[a+(g+8)>>2]|0;do if(l)if(l>>>0<w>>>0)za();else{c[z+16>>2]=l;c[l+24>>2]=z;break}while(0);l=c[a+(g+12)>>2]|0;if(l)if(l>>>0<(c[6342]|0)>>>0)za();else{c[z+20>>2]=l;c[l+24>>2]=z;break}}}else{l=c[a+g>>2]|0;w=c[a+(g|4)>>2]|0;y=25392+(x<<1<<2)|0;if((l|0)!=(y|0)){if(l>>>0<(c[6342]|0)>>>0)za();if((c[l+12>>2]|0)!=(h|0))za()}if((w|0)==(l|0)){c[6338]=c[6338]&~(1<<x);break}if((w|0)!=(y|0)){if(w>>>0<(c[6342]|0)>>>0)za();y=w+8|0;if((c[y>>2]|0)==(h|0))E=y;else za()}else E=w+8|0;c[l+12>>2]=w;c[E>>2]=l}while(0);c[o+4>>2]=d|1;c[o+d>>2]=d;if((o|0)==(c[6343]|0)){c[6340]=d;return}else F=d}else{c[b>>2]=u&-2;c[o+4>>2]=p|1;c[o+p>>2]=p;F=p}p=F>>>3;if(F>>>0<256){u=p<<1;b=25392+(u<<2)|0;d=c[6338]|0;E=1<<p;if(d&E){p=25392+(u+2<<2)|0;h=c[p>>2]|0;if(h>>>0<(c[6342]|0)>>>0)za();else{G=p;H=h}}else{c[6338]=d|E;G=25392+(u+2<<2)|0;H=b}c[G>>2]=o;c[H+12>>2]=o;c[o+8>>2]=H;c[o+12>>2]=b;return}b=F>>>8;if(b)if(F>>>0>16777215)I=31;else{H=(b+1048320|0)>>>16&8;G=b<<H;b=(G+520192|0)>>>16&4;u=G<<b;G=(u+245760|0)>>>16&2;E=14-(b|H|G)+(u<<G>>>15)|0;I=F>>>(E+7|0)&1|E<<1}else I=0;E=25656+(I<<2)|0;c[o+28>>2]=I;c[o+20>>2]=0;c[o+16>>2]=0;G=c[6339]|0;u=1<<I;a:do if(G&u){H=c[E>>2]|0;b:do if((c[H+4>>2]&-8|0)!=(F|0)){b=F<<((I|0)==31?0:25-(I>>>1)|0);d=H;while(1){h=d+16+(b>>>31<<2)|0;p=c[h>>2]|0;if(!p){J=h;K=d;break}if((c[p+4>>2]&-8|0)==(F|0)){L=p;break b}else{b=b<<1;d=p}}if(J>>>0<(c[6342]|0)>>>0)za();else{c[J>>2]=o;c[o+24>>2]=K;c[o+12>>2]=o;c[o+8>>2]=o;break a}}else L=H;while(0);H=L+8|0;d=c[H>>2]|0;b=c[6342]|0;if(d>>>0>=b>>>0&L>>>0>=b>>>0){c[d+12>>2]=o;c[H>>2]=o;c[o+8>>2]=d;c[o+12>>2]=L;c[o+24>>2]=0;break}else za()}else{c[6339]=G|u;c[E>>2]=o;c[o+24>>2]=E;c[o+12>>2]=o;c[o+8>>2]=o}while(0);o=(c[6346]|0)+-1|0;c[6346]=o;if(!o)M=25808;else return;while(1){o=c[M>>2]|0;if(!o)break;else M=o+8|0}c[6346]=-1;return}function $e(){}function af(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>c;return a>>>c|(b&(1<<c)-1)<<32-c}C=(b|0)<0?-1:0;return b>>c-32|0}function bf(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;g=b&3;h=d|d<<8|d<<16|d<<24;i=f&~3;if(g){g=b+4-g|0;while((b|0)<(g|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(i|0)){c[b>>2]=h;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function cf(b){b=b|0;var c=0;c=b;while(a[c>>0]|0)c=c+1|0;return c-b|0}function df(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return sa(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function ef(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=a+c>>>0;return (C=b+d+(e>>>0<a>>>0|0)>>>0,e|0)|0}function ff(b,c,d){b=b|0;c=c|0;d=d|0;var e=0;if((c|0)<(b|0)&(b|0)<(c+d|0)){e=b;c=c+d|0;b=b+d|0;while((d|0)>0){b=b-1|0;c=c-1|0;d=d-1|0;a[b>>0]=a[c>>0]|0}b=e}else df(b,c,d)|0;return b|0}function gf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=b-d>>>0;e=b-d-(c>>>0>a>>>0|0)>>>0;return (C=e,a-c>>>0|0)|0}function hf(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<<c|(a&(1<<c)-1<<32-c)>>>32-c;return a<<c}C=a<<c-32;return 0}function jf(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<<c)-1)<<32-c}C=0;return b>>>c-32|0}function kf(b){b=b|0;var c=0;c=a[m+(b&255)>>0]|0;if((c|0)<8)return c|0;c=a[m+(b>>8&255)>>0]|0;if((c|0)<8)return c+8|0;c=a[m+(b>>16&255)>>0]|0;if((c|0)<8)return c+16|0;return (a[m+(b>>>24)>>0]|0)+24|0}function lf(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;c=a&65535;d=b&65535;e=_(d,c)|0;f=a>>>16;a=(e>>>16)+(_(d,f)|0)|0;d=b>>>16;b=_(d,c)|0;return (C=(a>>>16)+(_(d,f)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|e&65535|0)|0}function mf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b>>31|((b|0)<0?-1:0)<<1;f=((b|0)<0?-1:0)>>31|((b|0)<0?-1:0)<<1;g=d>>31|((d|0)<0?-1:0)<<1;h=((d|0)<0?-1:0)>>31|((d|0)<0?-1:0)<<1;i=gf(e^a,f^b,e,f)|0;b=C;a=g^e;e=h^f;return gf((rf(i,b,gf(g^c,h^d,g,h)|0,C,0)|0)^a,C^e,a,e)|0}function nf(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+8|0;g=f|0;h=b>>31|((b|0)<0?-1:0)<<1;j=((b|0)<0?-1:0)>>31|((b|0)<0?-1:0)<<1;k=e>>31|((e|0)<0?-1:0)<<1;l=((e|0)<0?-1:0)>>31|((e|0)<0?-1:0)<<1;m=gf(h^a,j^b,h,j)|0;b=C;rf(m,b,gf(k^d,l^e,k,l)|0,C,g)|0;l=gf(c[g>>2]^h,c[g+4>>2]^j,h,j)|0;j=C;i=f;return (C=j,l)|0}function of(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;a=c;c=lf(e,a)|0;f=C;return (C=(_(b,a)|0)+(_(d,e)|0)+f|f&0,c|0|0)|0}function pf(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return rf(a,b,c,d,0)|0}function qf(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+8|0;g=f|0;rf(a,b,d,e,g)|0;i=f;return (C=c[g+4>>2]|0,c[g>>2]|0)|0}function rf(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0;g=a;h=b;i=h;j=d;k=e;l=k;if(!i){m=(f|0)!=0;if(!l){if(m){c[f>>2]=(g>>>0)%(j>>>0);c[f+4>>2]=0}n=0;o=(g>>>0)/(j>>>0)>>>0;return (C=n,o)|0}else{if(!m){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=b&0;n=0;o=0;return (C=n,o)|0}}m=(l|0)==0;do if(j){if(!m){p=(aa(l|0)|0)-(aa(i|0)|0)|0;if(p>>>0<=31){q=p+1|0;r=31-p|0;s=p-31>>31;t=q;u=g>>>(q>>>0)&s|i<<r;v=i>>>(q>>>0)&s;w=0;x=g<<r;break}if(!f){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=h|b&0;n=0;o=0;return (C=n,o)|0}r=j-1|0;if(r&j){s=(aa(j|0)|0)+33-(aa(i|0)|0)|0;q=64-s|0;p=32-s|0;y=p>>31;z=s-32|0;A=z>>31;t=s;u=p-1>>31&i>>>(z>>>0)|(i<<p|g>>>(s>>>0))&A;v=A&i>>>(s>>>0);w=g<<q&y;x=(i<<q|g>>>(z>>>0))&y|g<<p&s-33>>31;break}if(f){c[f>>2]=r&g;c[f+4>>2]=0}if((j|0)==1){n=h|b&0;o=a|0|0;return (C=n,o)|0}else{r=kf(j|0)|0;n=i>>>(r>>>0)|0;o=i<<32-r|g>>>(r>>>0)|0;return (C=n,o)|0}}else{if(m){if(f){c[f>>2]=(i>>>0)%(j>>>0);c[f+4>>2]=0}n=0;o=(i>>>0)/(j>>>0)>>>0;return (C=n,o)|0}if(!g){if(f){c[f>>2]=0;c[f+4>>2]=(i>>>0)%(l>>>0)}n=0;o=(i>>>0)/(l>>>0)>>>0;return (C=n,o)|0}r=l-1|0;if(!(r&l)){if(f){c[f>>2]=a|0;c[f+4>>2]=r&i|b&0}n=0;o=i>>>((kf(l|0)|0)>>>0);return (C=n,o)|0}r=(aa(l|0)|0)-(aa(i|0)|0)|0;if(r>>>0<=30){s=r+1|0;p=31-r|0;t=s;u=i<<p|g>>>(s>>>0);v=i>>>(s>>>0);w=0;x=g<<p;break}if(!f){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=h|b&0;n=0;o=0;return (C=n,o)|0}while(0);if(!t){B=x;D=w;E=v;F=u;G=0;H=0}else{b=d|0|0;d=k|e&0;e=ef(b|0,d|0,-1,-1)|0;k=C;h=x;x=w;w=v;v=u;u=t;t=0;do{a=h;h=x>>>31|h<<1;x=t|x<<1;g=v<<1|a>>>31|0;a=v>>>31|w<<1|0;gf(e,k,g,a)|0;i=C;l=i>>31|((i|0)<0?-1:0)<<1;t=l&1;v=gf(g,a,l&b,(((i|0)<0?-1:0)>>31|((i|0)<0?-1:0)<<1)&d)|0;w=C;u=u-1|0}while((u|0)!=0);B=h;D=x;E=w;F=v;G=0;H=t}t=D;D=0;if(f){c[f>>2]=F;c[f+4>>2]=E}n=(t|0)>>>31|(B|D)<<1|(D<<1|t>>>31)&0|G;o=(t<<1|0>>>31)&-2|H;return (C=n,o)|0}function sf(a,b,c,d,e,f,g){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;Ha[a&1](b|0,c|0,d|0,e|0,f|0,g|0)}function tf(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;ba(0)}
+
+// EMSCRIPTEN_END_FUNCS
+var Ha=[tf,ee];return{_strlen:cf,_free:_e,_ogv_audio_decoder_destroy:Ue,_ogv_audio_decoder_init:Re,_i64Add:ef,_memmove:ff,_bitshift64Ashr:af,_memset:bf,_ogv_audio_decoder_process_header:Se,_malloc:Ze,_memcpy:df,_ogv_audio_decoder_process_audio:Te,runPostSets:$e,stackAlloc:Ia,stackSave:Ja,stackRestore:Ka,establishStackSpace:La,setThrew:Ma,setTempRet0:Pa,getTempRet0:Qa,dynCall_viiiiii:sf}})
+
+
+// EMSCRIPTEN_END_ASM
+(Module.asmGlobalArg,Module.asmLibraryArg,buffer);var _strlen=Module["_strlen"]=asm["_strlen"];var _free=Module["_free"]=asm["_free"];var runPostSets=Module["runPostSets"]=asm["runPostSets"];var _ogv_audio_decoder_destroy=Module["_ogv_audio_decoder_destroy"]=asm["_ogv_audio_decoder_destroy"];var _ogv_audio_decoder_init=Module["_ogv_audio_decoder_init"]=asm["_ogv_audio_decoder_init"];var _i64Add=Module["_i64Add"]=asm["_i64Add"];var _memmove=Module["_memmove"]=asm["_memmove"];var _bitshift64Ashr=Module["_bitshift64Ashr"]=asm["_bitshift64Ashr"];var _memset=Module["_memset"]=asm["_memset"];var _ogv_audio_decoder_process_header=Module["_ogv_audio_decoder_process_header"]=asm["_ogv_audio_decoder_process_header"];var _malloc=Module["_malloc"]=asm["_malloc"];var _memcpy=Module["_memcpy"]=asm["_memcpy"];var _ogv_audio_decoder_process_audio=Module["_ogv_audio_decoder_process_audio"]=asm["_ogv_audio_decoder_process_audio"];var dynCall_viiiiii=Module["dynCall_viiiiii"]=asm["dynCall_viiiiii"];Runtime.stackAlloc=asm["stackAlloc"];Runtime.stackSave=asm["stackSave"];Runtime.stackRestore=asm["stackRestore"];Runtime.establishStackSpace=asm["establishStackSpace"];Runtime.setTempRet0=asm["setTempRet0"];Runtime.getTempRet0=asm["getTempRet0"];var i64Math=(function(){var goog={math:{}};goog.math.Long=(function(low,high){this.low_=low|0;this.high_=high|0});goog.math.Long.IntCache_={};goog.math.Long.fromInt=(function(value){if(-128<=value&&value<128){var cachedObj=goog.math.Long.IntCache_[value];if(cachedObj){return cachedObj}}var obj=new goog.math.Long(value|0,value<0?-1:0);if(-128<=value&&value<128){goog.math.Long.IntCache_[value]=obj}return obj});goog.math.Long.fromNumber=(function(value){if(isNaN(value)||!isFinite(value)){return goog.math.Long.ZERO}else if(value<=-goog.math.Long.TWO_PWR_63_DBL_){return goog.math.Long.MIN_VALUE}else if(value+1>=goog.math.Long.TWO_PWR_63_DBL_){return goog.math.Long.MAX_VALUE}else if(value<0){return goog.math.Long.fromNumber(-value).negate()}else{return new goog.math.Long(value%goog.math.Long.TWO_PWR_32_DBL_|0,value/goog.math.Long.TWO_PWR_32_DBL_|0)}});goog.math.Long.fromBits=(function(lowBits,highBits){return new goog.math.Long(lowBits,highBits)});goog.math.Long.fromString=(function(str,opt_radix){if(str.length==0){throw Error("number format error: empty string")}var radix=opt_radix||10;if(radix<2||36<radix){throw Error("radix out of range: "+radix)}if(str.charAt(0)=="-"){return goog.math.Long.fromString(str.substring(1),radix).negate()}else if(str.indexOf("-")>=0){throw Error('number format error: interior "-" character: '+str)}var radixToPower=goog.math.Long.fromNumber(Math.pow(radix,8));var result=goog.math.Long.ZERO;for(var i=0;i<str.length;i+=8){var size=Math.min(8,str.length-i);var value=parseInt(str.substring(i,i+size),radix);if(size<8){var power=goog.math.Long.fromNumber(Math.pow(radix,size));result=result.multiply(power).add(goog.math.Long.fromNumber(value))}else{result=result.multiply(radixToPower);result=result.add(goog.math.Long.fromNumber(value))}}return result});goog.math.Long.TWO_PWR_16_DBL_=1<<16;goog.math.Long.TWO_PWR_24_DBL_=1<<24;goog.math.Long.TWO_PWR_32_DBL_=goog.math.Long.TWO_PWR_16_DBL_*goog.math.Long.TWO_PWR_16_DBL_;goog.math.Long.TWO_PWR_31_DBL_=goog.math.Long.TWO_PWR_32_DBL_/2;goog.math.Long.TWO_PWR_48_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_16_DBL_;goog.math.Long.TWO_PWR_64_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_32_DBL_;goog.math.Long.TWO_PWR_63_DBL_=goog.math.Long.TWO_PWR_64_DBL_/2;goog.math.Long.ZERO=goog.math.Long.fromInt(0);goog.math.Long.ONE=goog.math.Long.fromInt(1);goog.math.Long.NEG_ONE=goog.math.Long.fromInt(-1);goog.math.Long.MAX_VALUE=goog.math.Long.fromBits(4294967295|0,2147483647|0);goog.math.Long.MIN_VALUE=goog.math.Long.fromBits(0,2147483648|0);goog.math.Long.TWO_PWR_24_=goog.math.Long.fromInt(1<<24);goog.math.Long.prototype.toInt=(function(){return this.low_});goog.math.Long.prototype.toNumber=(function(){return this.high_*goog.math.Long.TWO_PWR_32_DBL_+this.getLowBitsUnsigned()});goog.math.Long.prototype.toString=(function(opt_radix){var radix=opt_radix||10;if(radix<2||36<radix){throw Error("radix out of range: "+radix)}if(this.isZero()){return"0"}if(this.isNegative()){if(this.equals(goog.math.Long.MIN_VALUE)){var radixLong=goog.math.Long.fromNumber(radix);var div=this.div(radixLong);var rem=div.multiply(radixLong).subtract(this);return div.toString(radix)+rem.toInt().toString(radix)}else{return"-"+this.negate().toString(radix)}}var radixToPower=goog.math.Long.fromNumber(Math.pow(radix,6));var rem=this;var result="";while(true){var remDiv=rem.div(radixToPower);var intval=rem.subtract(remDiv.multiply(radixToPower)).toInt();var digits=intval.toString(radix);rem=remDiv;if(rem.isZero()){return digits+result}else{while(digits.length<6){digits="0"+digits}result=""+digits+result}}});goog.math.Long.prototype.getHighBits=(function(){return this.high_});goog.math.Long.prototype.getLowBits=(function(){return this.low_});goog.math.Long.prototype.getLowBitsUnsigned=(function(){return this.low_>=0?this.low_:goog.math.Long.TWO_PWR_32_DBL_+this.low_});goog.math.Long.prototype.getNumBitsAbs=(function(){if(this.isNegative()){if(this.equals(goog.math.Long.MIN_VALUE)){return 64}else{return this.negate().getNumBitsAbs()}}else{var val=this.high_!=0?this.high_:this.low_;for(var bit=31;bit>0;bit--){if((val&1<<bit)!=0){break}}return this.high_!=0?bit+33:bit+1}});goog.math.Long.prototype.isZero=(function(){return this.high_==0&&this.low_==0});goog.math.Long.prototype.isNegative=(function(){return this.high_<0});goog.math.Long.prototype.isOdd=(function(){return(this.low_&1)==1});goog.math.Long.prototype.equals=(function(other){return this.high_==other.high_&&this.low_==other.low_});goog.math.Long.prototype.notEquals=(function(other){return this.high_!=other.high_||this.low_!=other.low_});goog.math.Long.prototype.lessThan=(function(other){return this.compare(other)<0});goog.math.Long.prototype.lessThanOrEqual=(function(other){return this.compare(other)<=0});goog.math.Long.prototype.greaterThan=(function(other){return this.compare(other)>0});goog.math.Long.prototype.greaterThanOrEqual=(function(other){return this.compare(other)>=0});goog.math.Long.prototype.compare=(function(other){if(this.equals(other)){return 0}var thisNeg=this.isNegative();var otherNeg=other.isNegative();if(thisNeg&&!otherNeg){return-1}if(!thisNeg&&otherNeg){return 1}if(this.subtract(other).isNegative()){return-1}else{return 1}});goog.math.Long.prototype.negate=(function(){if(this.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.MIN_VALUE}else{return this.not().add(goog.math.Long.ONE)}});goog.math.Long.prototype.add=(function(other){var a48=this.high_>>>16;var a32=this.high_&65535;var a16=this.low_>>>16;var a00=this.low_&65535;var b48=other.high_>>>16;var b32=other.high_&65535;var b16=other.low_>>>16;var b00=other.low_&65535;var c48=0,c32=0,c16=0,c00=0;c00+=a00+b00;c16+=c00>>>16;c00&=65535;c16+=a16+b16;c32+=c16>>>16;c16&=65535;c32+=a32+b32;c48+=c32>>>16;c32&=65535;c48+=a48+b48;c48&=65535;return goog.math.Long.fromBits(c16<<16|c00,c48<<16|c32)});goog.math.Long.prototype.subtract=(function(other){return this.add(other.negate())});goog.math.Long.prototype.multiply=(function(other){if(this.isZero()){return goog.math.Long.ZERO}else if(other.isZero()){return goog.math.Long.ZERO}if(this.equals(goog.math.Long.MIN_VALUE)){return other.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO}else if(other.equals(goog.math.Long.MIN_VALUE)){return this.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO}if(this.isNegative()){if(other.isNegative()){return this.negate().multiply(other.negate())}else{return this.negate().multiply(other).negate()}}else if(other.isNegative()){return this.multiply(other.negate()).negate()}if(this.lessThan(goog.math.Long.TWO_PWR_24_)&&other.lessThan(goog.math.Long.TWO_PWR_24_)){return goog.math.Long.fromNumber(this.toNumber()*other.toNumber())}var a48=this.high_>>>16;var a32=this.high_&65535;var a16=this.low_>>>16;var a00=this.low_&65535;var b48=other.high_>>>16;var b32=other.high_&65535;var b16=other.low_>>>16;var b00=other.low_&65535;var c48=0,c32=0,c16=0,c00=0;c00+=a00*b00;c16+=c00>>>16;c00&=65535;c16+=a16*b00;c32+=c16>>>16;c16&=65535;c16+=a00*b16;c32+=c16>>>16;c16&=65535;c32+=a32*b00;c48+=c32>>>16;c32&=65535;c32+=a16*b16;c48+=c32>>>16;c32&=65535;c32+=a00*b32;c48+=c32>>>16;c32&=65535;c48+=a48*b00+a32*b16+a16*b32+a00*b48;c48&=65535;return goog.math.Long.fromBits(c16<<16|c00,c48<<16|c32)});goog.math.Long.prototype.div=(function(other){if(other.isZero()){throw Error("division by zero")}else if(this.isZero()){return goog.math.Long.ZERO}if(this.equals(goog.math.Long.MIN_VALUE)){if(other.equals(goog.math.Long.ONE)||other.equals(goog.math.Long.NEG_ONE)){return goog.math.Long.MIN_VALUE}else if(other.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.ONE}else{var halfThis=this.shiftRight(1);var approx=halfThis.div(other).shiftLeft(1);if(approx.equals(goog.math.Long.ZERO)){return other.isNegative()?goog.math.Long.ONE:goog.math.Long.NEG_ONE}else{var rem=this.subtract(other.multiply(approx));var result=approx.add(rem.div(other));return result}}}else if(other.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.ZERO}if(this.isNegative()){if(other.isNegative()){return this.negate().div(other.negate())}else{return this.negate().div(other).negate()}}else if(other.isNegative()){return this.div(other.negate()).negate()}var res=goog.math.Long.ZERO;var rem=this;while(rem.greaterThanOrEqual(other)){var approx=Math.max(1,Math.floor(rem.toNumber()/other.toNumber()));var log2=Math.ceil(Math.log(approx)/Math.LN2);var delta=log2<=48?1:Math.pow(2,log2-48);var approxRes=goog.math.Long.fromNumber(approx);var approxRem=approxRes.multiply(other);while(approxRem.isNegative()||approxRem.greaterThan(rem)){approx-=delta;approxRes=goog.math.Long.fromNumber(approx);approxRem=approxRes.multiply(other)}if(approxRes.isZero()){approxRes=goog.math.Long.ONE}res=res.add(approxRes);rem=rem.subtract(approxRem)}return res});goog.math.Long.prototype.modulo=(function(other){return this.subtract(this.div(other).multiply(other))});goog.math.Long.prototype.not=(function(){return goog.math.Long.fromBits(~this.low_,~this.high_)});goog.math.Long.prototype.and=(function(other){return goog.math.Long.fromBits(this.low_&other.low_,this.high_&other.high_)});goog.math.Long.prototype.or=(function(other){return goog.math.Long.fromBits(this.low_|other.low_,this.high_|other.high_)});goog.math.Long.prototype.xor=(function(other){return goog.math.Long.fromBits(this.low_^other.low_,this.high_^other.high_)});goog.math.Long.prototype.shiftLeft=(function(numBits){numBits&=63;if(numBits==0){return this}else{var low=this.low_;if(numBits<32){var high=this.high_;return goog.math.Long.fromBits(low<<numBits,high<<numBits|low>>>32-numBits)}else{return goog.math.Long.fromBits(0,low<<numBits-32)}}});goog.math.Long.prototype.shiftRight=(function(numBits){numBits&=63;if(numBits==0){return this}else{var high=this.high_;if(numBits<32){var low=this.low_;return goog.math.Long.fromBits(low>>>numBits|high<<32-numBits,high>>numBits)}else{return goog.math.Long.fromBits(high>>numBits-32,high>=0?0:-1)}}});goog.math.Long.prototype.shiftRightUnsigned=(function(numBits){numBits&=63;if(numBits==0){return this}else{var high=this.high_;if(numBits<32){var low=this.low_;return goog.math.Long.fromBits(low>>>numBits|high<<32-numBits,high>>>numBits)}else if(numBits==32){return goog.math.Long.fromBits(high,0)}else{return goog.math.Long.fromBits(high>>>numBits-32,0)}}});var navigator={appName:"Modern Browser"};var dbits;var canary=0xdeadbeefcafe;var j_lm=(canary&16777215)==15715070;function BigInteger(a,b,c){if(a!=null)if("number"==typeof a)this.fromNumber(a,b,c);else if(b==null&&"string"!=typeof a)this.fromString(a,256);else this.fromString(a,b)}function nbi(){return new BigInteger(null)}function am1(i,x,w,j,c,n){while(--n>=0){var v=x*this[i++]+w[j]+c;c=Math.floor(v/67108864);w[j++]=v&67108863}return c}function am2(i,x,w,j,c,n){var xl=x&32767,xh=x>>15;while(--n>=0){var l=this[i]&32767;var h=this[i++]>>15;var m=xh*l+h*xl;l=xl*l+((m&32767)<<15)+w[j]+(c&1073741823);c=(l>>>30)+(m>>>15)+xh*h+(c>>>30);w[j++]=l&1073741823}return c}function am3(i,x,w,j,c,n){var xl=x&16383,xh=x>>14;while(--n>=0){var l=this[i]&16383;var h=this[i++]>>14;var m=xh*l+h*xl;l=xl*l+((m&16383)<<14)+w[j]+c;c=(l>>28)+(m>>14)+xh*h;w[j++]=l&268435455}return c}if(j_lm&&navigator.appName=="Microsoft Internet Explorer"){BigInteger.prototype.am=am2;dbits=30}else if(j_lm&&navigator.appName!="Netscape"){BigInteger.prototype.am=am1;dbits=26}else{BigInteger.prototype.am=am3;dbits=28}BigInteger.prototype.DB=dbits;BigInteger.prototype.DM=(1<<dbits)-1;BigInteger.prototype.DV=1<<dbits;var BI_FP=52;BigInteger.prototype.FV=Math.pow(2,BI_FP);BigInteger.prototype.F1=BI_FP-dbits;BigInteger.prototype.F2=2*dbits-BI_FP;var BI_RM="0123456789abcdefghijklmnopqrstuvwxyz";var BI_RC=new Array;var rr,vv;rr="0".charCodeAt(0);for(vv=0;vv<=9;++vv)BI_RC[rr++]=vv;rr="a".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;rr="A".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;function int2char(n){return BI_RM.charAt(n)}function intAt(s,i){var c=BI_RC[s.charCodeAt(i)];return c==null?-1:c}function bnpCopyTo(r){for(var i=this.t-1;i>=0;--i)r[i]=this[i];r.t=this.t;r.s=this.s}function bnpFromInt(x){this.t=1;this.s=x<0?-1:0;if(x>0)this[0]=x;else if(x<-1)this[0]=x+DV;else this.t=0}function nbv(i){var r=nbi();r.fromInt(i);return r}function bnpFromString(s,b){var k;if(b==16)k=4;else if(b==8)k=3;else if(b==256)k=8;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else{this.fromRadix(s,b);return}this.t=0;this.s=0;var i=s.length,mi=false,sh=0;while(--i>=0){var x=k==8?s[i]&255:intAt(s,i);if(x<0){if(s.charAt(i)=="-")mi=true;continue}mi=false;if(sh==0)this[this.t++]=x;else if(sh+k>this.DB){this[this.t-1]|=(x&(1<<this.DB-sh)-1)<<sh;this[this.t++]=x>>this.DB-sh}else this[this.t-1]|=x<<sh;sh+=k;if(sh>=this.DB)sh-=this.DB}if(k==8&&(s[0]&128)!=0){this.s=-1;if(sh>0)this[this.t-1]|=(1<<this.DB-sh)-1<<sh}this.clamp();if(mi)BigInteger.ZERO.subTo(this,this)}function bnpClamp(){var c=this.s&this.DM;while(this.t>0&&this[this.t-1]==c)--this.t}function bnToString(b){if(this.s<0)return"-"+this.negate().toString(b);var k;if(b==16)k=4;else if(b==8)k=3;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else return this.toRadix(b);var km=(1<<k)-1,d,m=false,r="",i=this.t;var p=this.DB-i*this.DB%k;if(i-->0){if(p<this.DB&&(d=this[i]>>p)>0){m=true;r=int2char(d)}while(i>=0){if(p<k){d=(this[i]&(1<<p)-1)<<k-p;d|=this[--i]>>(p+=this.DB-k)}else{d=this[i]>>(p-=k)&km;if(p<=0){p+=this.DB;--i}}if(d>0)m=true;if(m)r+=int2char(d)}}return m?r:"0"}function bnNegate(){var r=nbi();BigInteger.ZERO.subTo(this,r);return r}function bnAbs(){return this.s<0?this.negate():this}function bnCompareTo(a){var r=this.s-a.s;if(r!=0)return r;var i=this.t;r=i-a.t;if(r!=0)return this.s<0?-r:r;while(--i>=0)if((r=this[i]-a[i])!=0)return r;return 0}function nbits(x){var r=1,t;if((t=x>>>16)!=0){x=t;r+=16}if((t=x>>8)!=0){x=t;r+=8}if((t=x>>4)!=0){x=t;r+=4}if((t=x>>2)!=0){x=t;r+=2}if((t=x>>1)!=0){x=t;r+=1}return r}function bnBitLength(){if(this.t<=0)return 0;return this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)}function bnpDLShiftTo(n,r){var i;for(i=this.t-1;i>=0;--i)r[i+n]=this[i];for(i=n-1;i>=0;--i)r[i]=0;r.t=this.t+n;r.s=this.s}function bnpDRShiftTo(n,r){for(var i=n;i<this.t;++i)r[i-n]=this[i];r.t=Math.max(this.t-n,0);r.s=this.s}function bnpLShiftTo(n,r){var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<cbs)-1;var ds=Math.floor(n/this.DB),c=this.s<<bs&this.DM,i;for(i=this.t-1;i>=0;--i){r[i+ds+1]=this[i]>>cbs|c;c=(this[i]&bm)<<bs}for(i=ds-1;i>=0;--i)r[i]=0;r[ds]=c;r.t=this.t+ds+1;r.s=this.s;r.clamp()}function bnpRShiftTo(n,r){r.s=this.s;var ds=Math.floor(n/this.DB);if(ds>=this.t){r.t=0;return}var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<bs)-1;r[0]=this[ds]>>bs;for(var i=ds+1;i<this.t;++i){r[i-ds-1]|=(this[i]&bm)<<cbs;r[i-ds]=this[i]>>bs}if(bs>0)r[this.t-ds-1]|=(this.s&bm)<<cbs;r.t=this.t-ds;r.clamp()}function bnpSubTo(a,r){var i=0,c=0,m=Math.min(a.t,this.t);while(i<m){c+=this[i]-a[i];r[i++]=c&this.DM;c>>=this.DB}if(a.t<this.t){c-=a.s;while(i<this.t){c+=this[i];r[i++]=c&this.DM;c>>=this.DB}c+=this.s}else{c+=this.s;while(i<a.t){c-=a[i];r[i++]=c&this.DM;c>>=this.DB}c-=a.s}r.s=c<0?-1:0;if(c<-1)r[i++]=this.DV+c;else if(c>0)r[i++]=c;r.t=i;r.clamp()}function bnpMultiplyTo(a,r){var x=this.abs(),y=a.abs();var i=x.t;r.t=i+y.t;while(--i>=0)r[i]=0;for(i=0;i<y.t;++i)r[i+x.t]=x.am(0,y[i],r,i,0,x.t);r.s=0;r.clamp();if(this.s!=a.s)BigInteger.ZERO.subTo(r,r)}function bnpSquareTo(r){var x=this.abs();var i=r.t=2*x.t;while(--i>=0)r[i]=0;for(i=0;i<x.t-1;++i){var c=x.am(i,x[i],r,2*i,0,1);if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1))>=x.DV){r[i+x.t]-=x.DV;r[i+x.t+1]=1}}if(r.t>0)r[r.t-1]+=x.am(i,x[i],r,2*i,0,1);r.s=0;r.clamp()}function bnpDivRemTo(m,q,r){var pm=m.abs();if(pm.t<=0)return;var pt=this.abs();if(pt.t<pm.t){if(q!=null)q.fromInt(0);if(r!=null)this.copyTo(r);return}if(r==null)r=nbi();var y=nbi(),ts=this.s,ms=m.s;var nsh=this.DB-nbits(pm[pm.t-1]);if(nsh>0){pm.lShiftTo(nsh,y);pt.lShiftTo(nsh,r)}else{pm.copyTo(y);pt.copyTo(r)}var ys=y.t;var y0=y[ys-1];if(y0==0)return;var yt=y0*(1<<this.F1)+(ys>1?y[ys-2]>>this.F2:0);var d1=this.FV/yt,d2=(1<<this.F1)/yt,e=1<<this.F2;var i=r.t,j=i-ys,t=q==null?nbi():q;y.dlShiftTo(j,t);if(r.compareTo(t)>=0){r[r.t++]=1;r.subTo(t,r)}BigInteger.ONE.dlShiftTo(ys,t);t.subTo(y,y);while(y.t<ys)y[y.t++]=0;while(--j>=0){var qd=r[--i]==y0?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);if((r[i]+=y.am(0,qd,r,j,0,ys))<qd){y.dlShiftTo(j,t);r.subTo(t,r);while(r[i]<--qd)r.subTo(t,r)}}if(q!=null){r.drShiftTo(ys,q);if(ts!=ms)BigInteger.ZERO.subTo(q,q)}r.t=ys;r.clamp();if(nsh>0)r.rShiftTo(nsh,r);if(ts<0)BigInteger.ZERO.subTo(r,r)}function bnMod(a){var r=nbi();this.abs().divRemTo(a,null,r);if(this.s<0&&r.compareTo(BigInteger.ZERO)>0)a.subTo(r,r);return r}function Classic(m){this.m=m}function cConvert(x){if(x.s<0||x.compareTo(this.m)>=0)return x.mod(this.m);else return x}function cRevert(x){return x}function cReduce(x){x.divRemTo(this.m,null,x)}function cMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r)}function cSqrTo(x,r){x.squareTo(r);this.reduce(r)}Classic.prototype.convert=cConvert;Classic.prototype.revert=cRevert;Classic.prototype.reduce=cReduce;Classic.prototype.mulTo=cMulTo;Classic.prototype.sqrTo=cSqrTo;function bnpInvDigit(){if(this.t<1)return 0;var x=this[0];if((x&1)==0)return 0;var y=x&3;y=y*(2-(x&15)*y)&15;y=y*(2-(x&255)*y)&255;y=y*(2-((x&65535)*y&65535))&65535;y=y*(2-x*y%this.DV)%this.DV;return y>0?this.DV-y:-y}function Montgomery(m){this.m=m;this.mp=m.invDigit();this.mpl=this.mp&32767;this.mph=this.mp>>15;this.um=(1<<m.DB-15)-1;this.mt2=2*m.t}function montConvert(x){var r=nbi();x.abs().dlShiftTo(this.m.t,r);r.divRemTo(this.m,null,r);if(x.s<0&&r.compareTo(BigInteger.ZERO)>0)this.m.subTo(r,r);return r}function montRevert(x){var r=nbi();x.copyTo(r);this.reduce(r);return r}function montReduce(x){while(x.t<=this.mt2)x[x.t++]=0;for(var i=0;i<this.m.t;++i){var j=x[i]&32767;var u0=j*this.mpl+((j*this.mph+(x[i]>>15)*this.mpl&this.um)<<15)&x.DM;j=i+this.m.t;x[j]+=this.m.am(0,u0,x,i,0,this.m.t);while(x[j]>=x.DV){x[j]-=x.DV;x[++j]++}}x.clamp();x.drShiftTo(this.m.t,x);if(x.compareTo(this.m)>=0)x.subTo(this.m,x)}function montSqrTo(x,r){x.squareTo(r);this.reduce(r)}function montMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r)}Montgomery.prototype.convert=montConvert;Montgomery.prototype.revert=montRevert;Montgomery.prototype.reduce=montReduce;Montgomery.prototype.mulTo=montMulTo;Montgomery.prototype.sqrTo=montSqrTo;function bnpIsEven(){return(this.t>0?this[0]&1:this.s)==0}function bnpExp(e,z){if(e>4294967295||e<1)return BigInteger.ONE;var r=nbi(),r2=nbi(),g=z.convert(this),i=nbits(e)-1;g.copyTo(r);while(--i>=0){z.sqrTo(r,r2);if((e&1<<i)>0)z.mulTo(r2,g,r);else{var t=r;r=r2;r2=t}}return z.revert(r)}function bnModPowInt(e,m){var z;if(e<256||m.isEven())z=new Classic(m);else z=new Montgomery(m);return this.exp(e,z)}BigInteger.prototype.copyTo=bnpCopyTo;BigInteger.prototype.fromInt=bnpFromInt;BigInteger.prototype.fromString=bnpFromString;BigInteger.prototype.clamp=bnpClamp;BigInteger.prototype.dlShiftTo=bnpDLShiftTo;BigInteger.prototype.drShiftTo=bnpDRShiftTo;BigInteger.prototype.lShiftTo=bnpLShiftTo;BigInteger.prototype.rShiftTo=bnpRShiftTo;BigInteger.prototype.subTo=bnpSubTo;BigInteger.prototype.multiplyTo=bnpMultiplyTo;BigInteger.prototype.squareTo=bnpSquareTo;BigInteger.prototype.divRemTo=bnpDivRemTo;BigInteger.prototype.invDigit=bnpInvDigit;BigInteger.prototype.isEven=bnpIsEven;BigInteger.prototype.exp=bnpExp;BigInteger.prototype.toString=bnToString;BigInteger.prototype.negate=bnNegate;BigInteger.prototype.abs=bnAbs;BigInteger.prototype.compareTo=bnCompareTo;BigInteger.prototype.bitLength=bnBitLength;BigInteger.prototype.mod=bnMod;BigInteger.prototype.modPowInt=bnModPowInt;BigInteger.ZERO=nbv(0);BigInteger.ONE=nbv(1);function bnpFromRadix(s,b){this.fromInt(0);if(b==null)b=10;var cs=this.chunkSize(b);var d=Math.pow(b,cs),mi=false,j=0,w=0;for(var i=0;i<s.length;++i){var x=intAt(s,i);if(x<0){if(s.charAt(i)=="-"&&this.signum()==0)mi=true;continue}w=b*w+x;if(++j>=cs){this.dMultiply(d);this.dAddOffset(w,0);j=0;w=0}}if(j>0){this.dMultiply(Math.pow(b,j));this.dAddOffset(w,0)}if(mi)BigInteger.ZERO.subTo(this,this)}function bnpChunkSize(r){return Math.floor(Math.LN2*this.DB/Math.log(r))}function bnSigNum(){if(this.s<0)return-1;else if(this.t<=0||this.t==1&&this[0]<=0)return 0;else return 1}function bnpDMultiply(n){this[this.t]=this.am(0,n-1,this,0,0,this.t);++this.t;this.clamp()}function bnpDAddOffset(n,w){if(n==0)return;while(this.t<=w)this[this.t++]=0;this[w]+=n;while(this[w]>=this.DV){this[w]-=this.DV;if(++w>=this.t)this[this.t++]=0;++this[w]}}function bnpToRadix(b){if(b==null)b=10;if(this.signum()==0||b<2||b>36)return"0";var cs=this.chunkSize(b);var a=Math.pow(b,cs);var d=nbv(a),y=nbi(),z=nbi(),r="";this.divRemTo(d,y,z);while(y.signum()>0){r=(a+z.intValue()).toString(b).substr(1)+r;y.divRemTo(d,y,z)}return z.intValue().toString(b)+r}function bnIntValue(){if(this.s<0){if(this.t==1)return this[0]-this.DV;else if(this.t==0)return-1}else if(this.t==1)return this[0];else if(this.t==0)return 0;return(this[1]&(1<<32-this.DB)-1)<<this.DB|this[0]}function bnpAddTo(a,r){var i=0,c=0,m=Math.min(a.t,this.t);while(i<m){c+=this[i]+a[i];r[i++]=c&this.DM;c>>=this.DB}if(a.t<this.t){c+=a.s;while(i<this.t){c+=this[i];r[i++]=c&this.DM;c>>=this.DB}c+=this.s}else{c+=this.s;while(i<a.t){c+=a[i];r[i++]=c&this.DM;c>>=this.DB}c+=a.s}r.s=c<0?-1:0;if(c>0)r[i++]=c;else if(c<-1)r[i++]=this.DV+c;r.t=i;r.clamp()}BigInteger.prototype.fromRadix=bnpFromRadix;BigInteger.prototype.chunkSize=bnpChunkSize;BigInteger.prototype.signum=bnSigNum;BigInteger.prototype.dMultiply=bnpDMultiply;BigInteger.prototype.dAddOffset=bnpDAddOffset;BigInteger.prototype.toRadix=bnpToRadix;BigInteger.prototype.intValue=bnIntValue;BigInteger.prototype.addTo=bnpAddTo;var Wrapper={abs:(function(l,h){var x=new goog.math.Long(l,h);var ret;if(x.isNegative()){ret=x.negate()}else{ret=x}HEAP32[tempDoublePtr>>2]=ret.low_;HEAP32[tempDoublePtr+4>>2]=ret.high_}),ensureTemps:(function(){if(Wrapper.ensuredTemps)return;Wrapper.ensuredTemps=true;Wrapper.two32=new BigInteger;Wrapper.two32.fromString("4294967296",10);Wrapper.two64=new BigInteger;Wrapper.two64.fromString("18446744073709551616",10);Wrapper.temp1=new BigInteger;Wrapper.temp2=new BigInteger}),lh2bignum:(function(l,h){var a=new BigInteger;a.fromString(h.toString(),10);var b=new BigInteger;a.multiplyTo(Wrapper.two32,b);var c=new BigInteger;c.fromString(l.toString(),10);var d=new BigInteger;c.addTo(b,d);return d}),stringify:(function(l,h,unsigned){var ret=(new goog.math.Long(l,h)).toString();if(unsigned&&ret[0]=="-"){Wrapper.ensureTemps();var bignum=new BigInteger;bignum.fromString(ret,10);ret=new BigInteger;Wrapper.two64.addTo(bignum,ret);ret=ret.toString(10)}return ret}),fromString:(function(str,base,min,max,unsigned){Wrapper.ensureTemps();var bignum=new BigInteger;bignum.fromString(str,base);var bigmin=new BigInteger;bigmin.fromString(min,10);var bigmax=new BigInteger;bigmax.fromString(max,10);if(unsigned&&bignum.compareTo(BigInteger.ZERO)<0){var temp=new BigInteger;bignum.addTo(Wrapper.two64,temp);bignum=temp}var error=false;if(bignum.compareTo(bigmin)<0){bignum=bigmin;error=true}else if(bignum.compareTo(bigmax)>0){bignum=bigmax;error=true}var ret=goog.math.Long.fromString(bignum.toString());HEAP32[tempDoublePtr>>2]=ret.low_;HEAP32[tempDoublePtr+4>>2]=ret.high_;if(error)throw"range error"})};return Wrapper})();function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;var initialStackTop;var preloadStartTime=null;var calledMain=false;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};Module["callMain"]=Module.callMain=function callMain(args){assert(runDependencies==0,"cannot call main when async dependencies remain! (listen on __ATMAIN__)");assert(__ATPRERUN__.length==0,"cannot call main when preRun functions remain to be called");args=args||[];ensureInitRuntime();var argc=args.length+1;function pad(){for(var i=0;i<4-1;i++){argv.push(0)}}var argv=[allocate(intArrayFromString(Module["thisProgram"]),"i8",ALLOC_NORMAL)];pad();for(var i=0;i<argc-1;i=i+1){argv.push(allocate(intArrayFromString(args[i]),"i8",ALLOC_NORMAL));pad()}argv.push(0);argv=allocate(argv,"i32",ALLOC_NORMAL);initialStackTop=STACKTOP;try{var ret=Module["_main"](argc,argv,0);exit(ret,true)}catch(e){if(e instanceof ExitStatus){return}else if(e=="SimulateInfiniteLoop"){Module["noExitRuntime"]=true;return}else{if(e&&typeof e==="object"&&e.stack)Module.printErr("exception thrown: "+[e,e.stack]);throw e}}finally{calledMain=true}};function run(args){args=args||Module["arguments"];if(preloadStartTime===null)preloadStartTime=Date.now();if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(ENVIRONMENT_IS_WEB&&preloadStartTime!==null){Module.printErr("pre-main prep time: "+(Date.now()-preloadStartTime)+" ms")}if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(Module["_main"]&&shouldRunNow)Module["callMain"](args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=Module.run=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["stdout"]["once"]("drain",(function(){process["exit"](status)}));console.log(" ");setTimeout((function(){process["exit"](status)}),500)}else if(ENVIRONMENT_IS_SHELL&&typeof quit==="function"){quit(status)}throw new ExitStatus(status)}Module["exit"]=Module.exit=exit;var abortDecorators=[];function abort(what){if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;var extra="\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.";var output="abort("+what+") at "+stackTrace()+extra;if(abortDecorators){abortDecorators.forEach((function(decorator){output=decorator(output,what)}))}throw output}Module["abort"]=Module.abort=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=false;if(Module["noInitialRun"]){shouldRunNow=false}Module["noExitRuntime"]=true;run();var inputBuffer,inputBufferSize;function reallocInputBuffer(size){if(inputBuffer&&inputBufferSize>=size){return inputBuffer}if(inputBuffer){Module._free(inputBuffer)}inputBufferSize=size;inputBuffer=Module._malloc(inputBufferSize);return inputBuffer}Module.loadedMetadata=!!options.audioFormat;Module.audioFormat=options.audioFormat||null;Module.audioBuffer=null;Object.defineProperty(Module,"processing",{get:function getProcessing(){return false}});Module.init=(function(callback){Module._ogv_audio_decoder_init();callback()});Module.processHeader=(function(data,callback){var len=data.byteLength;var buffer=reallocInputBuffer(len);Module.HEAPU8.set(new Uint8Array(data),buffer);var ret=Module._ogv_audio_decoder_process_header(buffer,len);callback(ret)});Module.processAudio=(function(data,callback){var len=data.byteLength;var buffer=reallocInputBuffer(len);Module.HEAPU8.set(new Uint8Array(data),buffer);var ret=Module._ogv_audio_decoder_process_audio(buffer,len);callback(ret)})
+
+
+
+
+
+ return Module;
+};
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-audio-vorbis.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-audio-vorbis.js
new file mode 100644
index 00000000..7815d228
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-audio-vorbis.js
@@ -0,0 +1,23 @@
+var OGVDecoderAudioVorbis = function(Module) {
+ Module = Module || {};
+
+var options=Module;Module={print:(function(str){console.log(str)})};var Module;if(!Module)Module=(typeof OGVDecoderAudioVorbis!=="undefined"?OGVDecoderAudioVorbis:null)||{};var moduleOverrides={};for(var key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var ENVIRONMENT_IS_WEB=typeof window==="object";var ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB;var ENVIRONMENT_IS_WORKER=typeof importScripts==="function";var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){if(!Module["print"])Module["print"]=function print(x){process["stdout"].write(x+"\n")};if(!Module["printErr"])Module["printErr"]=function printErr(x){process["stderr"].write(x+"\n")};var nodeFS=require("fs");var nodePath=require("path");Module["read"]=function read(filename,binary){filename=nodePath["normalize"](filename);var ret=nodeFS["readFileSync"](filename);if(!ret&&filename!=nodePath["resolve"](filename)){filename=path.join(__dirname,"..","src",filename);ret=nodeFS["readFileSync"](filename)}if(ret&&!binary)ret=ret.toString();return ret};Module["readBinary"]=function readBinary(filename){return Module["read"](filename,true)};Module["load"]=function load(f){globalEval(read(f))};if(!Module["thisProgram"]){if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}else{Module["thisProgram"]="unknown-program"}}Module["arguments"]=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(!Module["print"])Module["print"]=print;if(typeof printErr!="undefined")Module["printErr"]=printErr;if(typeof read!="undefined"){Module["read"]=read}else{Module["read"]=function read(){throw"no read() available (jsc?)"}}Module["readBinary"]=function readBinary(f){if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}var data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof console!=="undefined"){if(!Module["print"])Module["print"]=function print(x){console.log(x)};if(!Module["printErr"])Module["printErr"]=function printErr(x){console.log(x)}}else{var TRY_USE_DUMP=false;if(!Module["print"])Module["print"]=TRY_USE_DUMP&&typeof dump!=="undefined"?(function(x){dump(x)}):(function(x){})}if(ENVIRONMENT_IS_WORKER){Module["load"]=importScripts}if(typeof Module["setWindowTitle"]==="undefined"){Module["setWindowTitle"]=(function(title){document.title=title})}}else{throw"Unknown runtime environment. Where are we?"}function globalEval(x){eval.call(null,x)}if(!Module["load"]&&Module["read"]){Module["load"]=function load(f){globalEval(Module["read"](f))}}if(!Module["print"]){Module["print"]=(function(){})}if(!Module["printErr"]){Module["printErr"]=Module["print"]}if(!Module["arguments"]){Module["arguments"]=[]}if(!Module["thisProgram"]){Module["thisProgram"]="./this.program"}Module.print=Module["print"];Module.printErr=Module["printErr"];Module["preRun"]=[];Module["postRun"]=[];for(var key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}var Runtime={setTempRet0:(function(value){tempRet0=value}),getTempRet0:(function(){return tempRet0}),stackSave:(function(){return STACKTOP}),stackRestore:(function(stackTop){STACKTOP=stackTop}),getNativeTypeSize:(function(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return Runtime.QUANTUM_SIZE}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0);return bits/8}else{return 0}}}}),getNativeFieldSize:(function(type){return Math.max(Runtime.getNativeTypeSize(type),Runtime.QUANTUM_SIZE)}),STACK_ALIGN:16,prepVararg:(function(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){assert((ptr&7)===4);ptr+=4}}else{assert((ptr&3)===0)}return ptr}),getAlignSize:(function(type,size,vararg){if(!vararg&&(type=="i64"||type=="double"))return 8;if(!type)return Math.min(size,8);return Math.min(size||(type?Runtime.getNativeFieldSize(type):0),Runtime.QUANTUM_SIZE)}),dynCall:(function(sig,ptr,args){if(args&&args.length){if(!args.splice)args=Array.prototype.slice.call(args);args.splice(0,0,ptr);return Module["dynCall_"+sig].apply(null,args)}else{return Module["dynCall_"+sig].call(null,ptr)}}),functionPointers:[],addFunction:(function(func){for(var i=0;i<Runtime.functionPointers.length;i++){if(!Runtime.functionPointers[i]){Runtime.functionPointers[i]=func;return 2*(1+i)}}throw"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS."}),removeFunction:(function(index){Runtime.functionPointers[(index-2)/2]=null}),warnOnce:(function(text){if(!Runtime.warnOnce.shown)Runtime.warnOnce.shown={};if(!Runtime.warnOnce.shown[text]){Runtime.warnOnce.shown[text]=1;Module.printErr(text)}}),funcWrappers:{},getFuncWrapper:(function(func,sig){assert(sig);if(!Runtime.funcWrappers[sig]){Runtime.funcWrappers[sig]={}}var sigCache=Runtime.funcWrappers[sig];if(!sigCache[func]){sigCache[func]=function dynCall_wrapper(){return Runtime.dynCall(sig,func,arguments)}}return sigCache[func]}),getCompilerSetting:(function(name){throw"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work"}),stackAlloc:(function(size){var ret=STACKTOP;STACKTOP=STACKTOP+size|0;STACKTOP=STACKTOP+15&-16;return ret}),staticAlloc:(function(size){var ret=STATICTOP;STATICTOP=STATICTOP+size|0;STATICTOP=STATICTOP+15&-16;return ret}),dynamicAlloc:(function(size){var ret=DYNAMICTOP;DYNAMICTOP=DYNAMICTOP+size|0;DYNAMICTOP=DYNAMICTOP+15&-16;if(DYNAMICTOP>=TOTAL_MEMORY){var success=enlargeMemory();if(!success){DYNAMICTOP=ret;return 0}}return ret}),alignMemory:(function(size,quantum){var ret=size=Math.ceil(size/(quantum?quantum:16))*(quantum?quantum:16);return ret}),makeBigInt:(function(low,high,unsigned){var ret=unsigned?+(low>>>0)+ +(high>>>0)*+4294967296:+(low>>>0)+ +(high|0)*+4294967296;return ret}),GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module["Runtime"]=Runtime;var __THREW__=0;var ABORT=false;var EXITSTATUS=0;var undef=0;var tempValue,tempInt,tempBigInt,tempInt2,tempBigInt2,tempPair,tempBigIntI,tempBigIntR,tempBigIntS,tempBigIntP,tempBigIntD,tempDouble,tempFloat;var tempI64,tempI64b;var tempRet0,tempRet1,tempRet2,tempRet3,tempRet4,tempRet5,tempRet6,tempRet7,tempRet8,tempRet9;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var globalScope=this;function getCFunc(ident){var func=Module["_"+ident];if(!func){try{func=eval("_"+ident)}catch(e){}}assert(func,"Cannot call unknown function "+ident+" (perhaps LLVM optimizations or closure removed it?)");return func}var cwrap,ccall;((function(){var JSfuncs={"stackSave":(function(){Runtime.stackSave()}),"stackRestore":(function(){Runtime.stackRestore()}),"arrayToC":(function(arr){var ret=Runtime.stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}),"stringToC":(function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=Runtime.stackAlloc((str.length<<2)+1);writeStringToMemory(str,ret)}return ret})};var toC={"string":JSfuncs["stringToC"],"array":JSfuncs["arrayToC"]};ccall=function ccallFunc(ident,returnType,argTypes,args,opts){var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=Runtime.stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func.apply(null,cArgs);if(returnType==="string")ret=Pointer_stringify(ret);if(stack!==0){if(opts&&opts.async){EmterpreterAsync.asyncFinalizers.push((function(){Runtime.stackRestore(stack)}));return}Runtime.stackRestore(stack)}return ret};var sourceRegex=/^function\s*\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;function parseJSFunc(jsfunc){var parsed=jsfunc.toString().match(sourceRegex).slice(1);return{arguments:parsed[0],body:parsed[1],returnValue:parsed[2]}}var JSsource={};for(var fun in JSfuncs){if(JSfuncs.hasOwnProperty(fun)){JSsource[fun]=parseJSFunc(JSfuncs[fun])}}cwrap=function cwrap(ident,returnType,argTypes){argTypes=argTypes||[];var cfunc=getCFunc(ident);var numericArgs=argTypes.every((function(type){return type==="number"}));var numericRet=returnType!=="string";if(numericRet&&numericArgs){return cfunc}var argNames=argTypes.map((function(x,i){return"$"+i}));var funcstr="(function("+argNames.join(",")+") {";var nargs=argTypes.length;if(!numericArgs){funcstr+="var stack = "+JSsource["stackSave"].body+";";for(var i=0;i<nargs;i++){var arg=argNames[i],type=argTypes[i];if(type==="number")continue;var convertCode=JSsource[type+"ToC"];funcstr+="var "+convertCode.arguments+" = "+arg+";";funcstr+=convertCode.body+";";funcstr+=arg+"="+convertCode.returnValue+";"}}var cfuncname=parseJSFunc((function(){return cfunc})).returnValue;funcstr+="var ret = "+cfuncname+"("+argNames.join(",")+");";if(!numericRet){var strgfy=parseJSFunc((function(){return Pointer_stringify})).returnValue;funcstr+="ret = "+strgfy+"(ret);"}if(!numericArgs){funcstr+=JSsource["stackRestore"].body.replace("()","(stack)")+";"}funcstr+="return ret})";return eval(funcstr)}}))();Module["cwrap"]=cwrap;Module["ccall"]=ccall;function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=+1?tempDouble>+0?(Math_min(+Math_floor(tempDouble/+4294967296),+4294967295)|0)>>>0:~~+Math_ceil((tempDouble- +(~~tempDouble>>>0))/+4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}Module["setValue"]=setValue;function getValue(ptr,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP32[ptr>>2];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];default:abort("invalid type for setValue: "+type)}return null}Module["getValue"]=getValue;var ALLOC_NORMAL=0;var ALLOC_STACK=1;var ALLOC_STATIC=2;var ALLOC_DYNAMIC=3;var ALLOC_NONE=4;Module["ALLOC_NORMAL"]=ALLOC_NORMAL;Module["ALLOC_STACK"]=ALLOC_STACK;Module["ALLOC_STATIC"]=ALLOC_STATIC;Module["ALLOC_DYNAMIC"]=ALLOC_DYNAMIC;Module["ALLOC_NONE"]=ALLOC_NONE;function allocate(slab,types,allocator,ptr){var zeroinit,size;if(typeof slab==="number"){zeroinit=true;size=slab}else{zeroinit=false;size=slab.length}var singleType=typeof types==="string"?types:null;var ret;if(allocator==ALLOC_NONE){ret=ptr}else{ret=[_malloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][allocator===undefined?ALLOC_STATIC:allocator](Math.max(size,singleType?1:types.length))}if(zeroinit){var ptr=ret,stop;assert((ret&3)==0);stop=ret+(size&~3);for(;ptr<stop;ptr+=4){HEAP32[ptr>>2]=0}stop=ret+size;while(ptr<stop){HEAP8[ptr++>>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i<size){var curr=slab[i];if(typeof curr==="function"){curr=Runtime.getFunctionIndex(curr)}type=singleType||types[i];if(type===0){i++;continue}if(type=="i64")type="i32";setValue(ret+i,curr,type);if(previousType!==type){typeSize=Runtime.getNativeTypeSize(type);previousType=type}i+=typeSize}return ret}Module["allocate"]=allocate;function getMemory(size){if(!staticSealed)return Runtime.staticAlloc(size);if(typeof _sbrk!=="undefined"&&!_sbrk.called||!runtimeInitialized)return Runtime.dynamicAlloc(size);return _malloc(size)}Module["getMemory"]=getMemory;function Pointer_stringify(ptr,length){if(length===0||!ptr)return"";var hasUtf=0;var t;var i=0;while(1){t=HEAPU8[ptr+i>>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return Module["UTF8ToString"](ptr)}Module["Pointer_stringify"]=Pointer_stringify;function AsciiToString(ptr){var str="";while(1){var ch=HEAP8[ptr++>>0];if(!ch)return str;str+=String.fromCharCode(ch)}}Module["AsciiToString"]=AsciiToString;function stringToAscii(str,outPtr){return writeAsciiToMemory(str,outPtr,false)}Module["stringToAscii"]=stringToAscii;function UTF8ArrayToString(u8Array,idx){var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}Module["UTF8ArrayToString"]=UTF8ArrayToString;function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}Module["UTF8ToString"]=UTF8ToString;function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=2097151){if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=67108863){if(outIdx+4>=endIdx)break;outU8Array[outIdx++]=248|u>>24;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+5>=endIdx)break;outU8Array[outIdx++]=252|u>>30;outU8Array[outIdx++]=128|u>>24&63;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}Module["stringToUTF8Array"]=stringToUTF8Array;function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}Module["stringToUTF8"]=stringToUTF8;function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){++len}else if(u<=2047){len+=2}else if(u<=65535){len+=3}else if(u<=2097151){len+=4}else if(u<=67108863){len+=5}else{len+=6}}return len}Module["lengthBytesUTF8"]=lengthBytesUTF8;function UTF16ToString(ptr){var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)return str;++i;str+=String.fromCharCode(codeUnit)}}Module["UTF16ToString"]=UTF16ToString;function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite<str.length*2?maxBytesToWrite/2:str.length;for(var i=0;i<numCharsToWrite;++i){var codeUnit=str.charCodeAt(i);HEAP16[outPtr>>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}Module["stringToUTF16"]=stringToUTF16;function lengthBytesUTF16(str){return str.length*2}Module["lengthBytesUTF16"]=lengthBytesUTF16;function UTF32ToString(ptr){var i=0;var str="";while(1){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)return str;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}}Module["UTF32ToString"]=UTF32ToString;function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i<str.length;++i){var codeUnit=str.charCodeAt(i);if(codeUnit>=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}Module["stringToUTF32"]=stringToUTF32;function lengthBytesUTF32(str){var len=0;for(var i=0;i<str.length;++i){var codeUnit=str.charCodeAt(i);if(codeUnit>=55296&&codeUnit<=57343)++i;len+=4}return len}Module["lengthBytesUTF32"]=lengthBytesUTF32;function demangle(func){var hasLibcxxabi=!!Module["___cxa_demangle"];if(hasLibcxxabi){try{var buf=_malloc(func.length);writeStringToMemory(func.substr(1),buf);var status=_malloc(4);var ret=Module["___cxa_demangle"](buf,0,0,status);if(getValue(status,"i32")===0&&ret){return Pointer_stringify(ret)}}catch(e){}finally{if(buf)_free(buf);if(status)_free(status);if(ret)_free(ret)}}var i=3;var basicTypes={"v":"void","b":"bool","c":"char","s":"short","i":"int","l":"long","f":"float","d":"double","w":"wchar_t","a":"signed char","h":"unsigned char","t":"unsigned short","j":"unsigned int","m":"unsigned long","x":"long long","y":"unsigned long long","z":"..."};var subs=[];var first=true;function dump(x){if(x)Module.print(x);Module.print(func);var pre="";for(var a=0;a<i;a++)pre+=" ";Module.print(pre+"^")}function parseNested(){i++;if(func[i]==="K")i++;var parts=[];while(func[i]!=="E"){if(func[i]==="S"){i++;var next=func.indexOf("_",i);var num=func.substring(i,next)||0;parts.push(subs[num]||"?");i=next+1;continue}if(func[i]==="C"){parts.push(parts[parts.length-1]);i+=2;continue}var size=parseInt(func.substr(i));var pre=size.toString().length;if(!size||!pre){i--;break}var curr=func.substr(i+pre,size);parts.push(curr);subs.push(curr);i+=pre+size}i++;return parts}function parse(rawList,limit,allowVoid){limit=limit||Infinity;var ret="",list=[];function flushList(){return"("+list.join(", ")+")"}var name;if(func[i]==="N"){name=parseNested().join("::");limit--;if(limit===0)return rawList?[name]:name}else{if(func[i]==="K"||first&&func[i]==="L")i++;var size=parseInt(func.substr(i));if(size){var pre=size.toString().length;name=func.substr(i+pre,size);i+=pre+size}}first=false;if(func[i]==="I"){i++;var iList=parse(true);var iRet=parse(true,1,true);ret+=iRet[0]+" "+name+"<"+iList.join(", ")+">"}else{ret=name}paramLoop:while(i<func.length&&limit-->0){var c=func[i++];if(c in basicTypes){list.push(basicTypes[c])}else{switch(c){case"P":list.push(parse(true,1,true)[0]+"*");break;case"R":list.push(parse(true,1,true)[0]+"&");break;case"L":{i++;var end=func.indexOf("E",i);var size=end-i;list.push(func.substr(i,size));i+=size+2;break};case"A":{var size=parseInt(func.substr(i));i+=size.toString().length;if(func[i]!=="_")throw"?";i++;list.push(parse(true,1,true)[0]+" ["+size+"]");break};case"E":break paramLoop;default:ret+="?"+c;break paramLoop}}}if(!allowVoid&&list.length===1&&list[0]==="void")list=[];if(rawList){if(ret){list.push(ret+"?")}return list}else{return ret+flushList()}}var parsed=func;try{if(func=="Object._main"||func=="_main"){return"main()"}if(typeof func==="number")func=Pointer_stringify(func);if(func[0]!=="_")return func;if(func[1]!=="_")return func;if(func[2]!=="Z")return func;switch(func[3]){case"n":return"operator new()";case"d":return"operator delete()"}parsed=parse()}catch(e){parsed+="?"}if(parsed.indexOf("?")>=0&&!hasLibcxxabi){Runtime.warnOnce("warning: a problem occurred in builtin C++ name demangling; build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling")}return parsed}function demangleAll(text){return text.replace(/__Z[\w\d_]+/g,(function(x){var y=demangle(x);return x===y?x:x+" ["+y+"]"}))}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error(0)}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){return demangleAll(jsStackTrace())}Module["stackTrace"]=stackTrace;var PAGE_SIZE=4096;function alignMemoryPage(x){if(x%4096>0){x+=4096-x%4096}return x}var HEAP;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;var STATIC_BASE=0,STATICTOP=0,staticSealed=false;var STACK_BASE=0,STACKTOP=0,STACK_MAX=0;var DYNAMIC_BASE=0,DYNAMICTOP=0;function enlargeMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.")}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;var totalMemory=64*1024;while(totalMemory<TOTAL_MEMORY||totalMemory<2*TOTAL_STACK){if(totalMemory<16*1024*1024){totalMemory*=2}else{totalMemory+=16*1024*1024}}if(totalMemory!==TOTAL_MEMORY){Module.printErr("increasing TOTAL_MEMORY to "+totalMemory+" to be compliant with the asm.js spec (and given that TOTAL_STACK="+TOTAL_STACK+")");TOTAL_MEMORY=totalMemory}assert(typeof Int32Array!=="undefined"&&typeof Float64Array!=="undefined"&&!!(new Int32Array(1))["subarray"]&&!!(new Int32Array(1))["set"],"JS engine does not provide full typed array support");var buffer;buffer=new ArrayBuffer(TOTAL_MEMORY);HEAP8=new Int8Array(buffer);HEAP16=new Int16Array(buffer);HEAP32=new Int32Array(buffer);HEAPU8=new Uint8Array(buffer);HEAPU16=new Uint16Array(buffer);HEAPU32=new Uint32Array(buffer);HEAPF32=new Float32Array(buffer);HEAPF64=new Float64Array(buffer);HEAP32[0]=255;assert(HEAPU8[0]===255&&HEAPU8[3]===0,"Typed arrays 2 must be run on a little-endian system");Module["HEAP"]=HEAP;Module["buffer"]=buffer;Module["HEAP8"]=HEAP8;Module["HEAP16"]=HEAP16;Module["HEAP32"]=HEAP32;Module["HEAPU8"]=HEAPU8;Module["HEAPU16"]=HEAPU16;Module["HEAPU32"]=HEAPU32;Module["HEAPF32"]=HEAPF32;Module["HEAPF64"]=HEAPF64;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Runtime.dynCall("v",func)}else{Runtime.dynCall("vi",func,[callback.arg])}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}Module["addOnPreRun"]=Module.addOnPreRun=addOnPreRun;function addOnInit(cb){__ATINIT__.unshift(cb)}Module["addOnInit"]=Module.addOnInit=addOnInit;function addOnPreMain(cb){__ATMAIN__.unshift(cb)}Module["addOnPreMain"]=Module.addOnPreMain=addOnPreMain;function addOnExit(cb){__ATEXIT__.unshift(cb)}Module["addOnExit"]=Module.addOnExit=addOnExit;function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}Module["addOnPostRun"]=Module.addOnPostRun=addOnPostRun;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["intArrayFromString"]=intArrayFromString;function intArrayToString(array){var ret=[];for(var i=0;i<array.length;i++){var chr=array[i];if(chr>255){chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}Module["intArrayToString"]=intArrayToString;function writeStringToMemory(string,buffer,dontAddNull){var array=intArrayFromString(string,dontAddNull);var i=0;while(i<array.length){var chr=array[i];HEAP8[buffer+i>>0]=chr;i=i+1}}Module["writeStringToMemory"]=writeStringToMemory;function writeArrayToMemory(array,buffer){for(var i=0;i<array.length;i++){HEAP8[buffer++>>0]=array[i]}}Module["writeArrayToMemory"]=writeArrayToMemory;function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i<str.length;++i){HEAP8[buffer++>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}Module["writeAsciiToMemory"]=writeAsciiToMemory;function unSign(value,bits,ignore){if(value>=0){return value}return bits<=32?2*Math.abs(1<<bits-1)+value:Math.pow(2,bits)+value}function reSign(value,bits,ignore){if(value<=0){return value}var half=bits<=32?Math.abs(1<<bits-1):Math.pow(2,bits-1);if(value>=half&&(bits<=32||value>half)){value=-2*half+value}return value}if(!Math["imul"]||Math["imul"](4294967295,5)!==-5)Math["imul"]=function imul(a,b){var ah=a>>>16;var al=a&65535;var bh=b>>>16;var bl=b&65535;return al*bl+(ah*bl+al*bh<<16)|0};Math.imul=Math["imul"];if(!Math["clz32"])Math["clz32"]=(function(x){x=x>>>0;for(var i=0;i<32;i++){if(x&1<<31-i)return i}return 32});Math.clz32=Math["clz32"];var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_min=Math.min;var Math_clz32=Math.clz32;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}Module["addRunDependency"]=addRunDependency;function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["removeRunDependency"]=removeRunDependency;Module["preloadedImages"]={};Module["preloadedAudios"]={};var memoryInitializer=null;var ASM_CONSTS=[];STATIC_BASE=8;STATICTOP=STATIC_BASE+58272;__ATINIT__.push();allocate([0,0,0,0,1,0,0,0,3,0,0,0,7,0,0,0,15,0,0,0,31,0,0,0,63,0,0,0,127,0,0,0,255,0,0,0,255,1,0,0,255,3,0,0,255,7,0,0,255,15,0,0,255,31,0,0,255,63,0,0,255,127,0,0,255,255,0,0,255,255,1,0,255,255,3,0,255,255,7,0,255,255,15,0,255,255,31,0,255,255,63,0,255,255,127,0,255,255,255,0,255,255,255,1,255,255,255,3,255,255,255,7,255,255,255,15,255,255,255,31,255,255,255,63,255,255,255,127,255,255,255,255,0,0,0,0,1,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5,0,0,0,3,0,0,0,4,0,0,0,6,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,8,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,7,0,0,0,8,0,0,0,5,0,0,0,6,0,0,0,2,0,0,0,1,0,0,0,3,0,0,0,2,0,0,0,7,0,0,0,8,0,0,0,5,0,0,0,6,0,0,0,4,0,0,0,2,0,0,0,5,0,0,0,1,0,0,0,9,0,0,0,7,0,0,0,1,0,0,0,10,0,0,0,0,0,0,0,176,0,0,0,144,0,0,0,208,0,0,0,240,0,0,0,16,1,0,0,0,0,0,0,48,1,0,0,0,0,0,0,4,0,0,0,2,0,0,0,3,0,0,0,5,0,0,0,144,3,0,0,16,4,0,0,16,5,0,0,16,7,0,0,16,11,0,0,16,19,0,0,16,35,0,0,16,67,0,0,0,0,76,194,0,0,80,194,0,0,84,194,0,0,88,194,0,0,92,194,0,0,96,194,0,0,100,194,0,0,104,194,0,0,108,194,0,0,112,194,0,0,116,194,0,0,120,194,0,0,124,194,0,0,128,194,0,0,130,194,0,0,132,194,0,0,134,194,0,0,136,194,0,0,138,194,0,0,140,194,0,0,142,194,0,0,144,194,0,0,146,194,0,0,148,194,0,0,150,194,0,0,152,194,0,0,154,194,0,0,156,194,0,0,160,194,0,0,162,194,0,0,164,194,0,0,166,194,0,0,168,194,0,0,170,194,0,0,172,194,0,0,174,194,0,0,176,194,0,0,176,194,0,0,178,194,0,0,178,194,0,0,180,194,0,0,182,194,0,0,182,194,0,0,184,194,0,0,186,194,0,0,188,194,0,0,190,194,0,0,192,194,0,0,192,194,0,0,194,194,0,0,196,194,0,0,196,194,0,0,198,194,0,0,198,194,0,0,200,194,0,0,200,194,0,0,202,194,0,0,204,194,0,0,206,194,0,0,208,194,0,0,212,194,0,0,214,194,0,0,214,194,0,0,214,194,0,0,214,194,0,0,210,194,0,0,206,194,0,0,204,194,0,0,202,194,0,0,198,194,0,0,196,194,0,0,192,194,0,0,190,194,0,0,190,194,0,0,192,194,0,0,194,194,0,0,192,194,0,0,190,194,0,0,186,194,0,0,180,194,0,0,160,194,0,0,140,194,0,0,72,194,0,0,32,194,0,0,240,193,0,0,240,193,0,0,240,193,0,0,240,193,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,63,0,0,0,0,0,0,240,63,0,0,0,0,0,0,248,63,0,0,0,0,0,0,4,64,0,0,0,0,0,0,18,64,0,0,0,0,0,0,33,64,0,0,0,0,0,128,48,64,0,0,0,4,107,244,52,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,63,0,0,0,0,0,0,240,63,0,0,0,0,0,0,248,63,0,0,0,0,0,0,0,64,0,0,0,0,0,0,4,64,0,0,0,0,0,0,18,64,0,0,0,0,0,0,33,64,0,0,0,4,107,244,52,66,118,111,114,98,105,115,0,0,24,0,120,58,76,70,11,60,242,204,192,60,116,252,59,61,86,73,154,61,241,93,228,61,248,163,29,62,180,231,78,62,54,157,130,62,78,220,159,62,193,174,190,62,65,132,222,62,173,194,254,62,186,101,15,63,248,0,31,63,29,233,45,63,249,219,59,63,45,162,72,63,160,17,84,63,38,15,94,63,46,143,102,63,112,149,109,63,174,51,115,63,159,135,119,63,66,184,122,63,196,242,124,63,75,103,126,63,196,69,127,63,241,186,127,63,217,237,127,63,162,253,127,63,248,255,127,63,168,9,120,57,17,119,11,59,135,139,193,59,74,113,61,60,148,82,156,60,94,8,233,60,42,83,34,61,74,118,87,61,138,227,137,61,7,140,171,61,34,154,208,61,108,239,248,61,164,52,18,62,100,112,41,62,65,21,66,62,67,11,92,62,47,56,119,62,197,191,137,62,92,97,152,62,135,112,167,62,4,220,182,62,188,145,198,62,231,126,214,62,48,144,230,62,227,177,246,62,13,104,3,63,121,107,11,63,98,89,19,63,42,40,27,63,137,206,34,63,166,67,42,63,49,127,49,63,126,121,56,63,153,43,63,63,92,143,69,63,127,159,75,63,165,87,81,63,104,180,86,63,89,179,91,63,8,83,96,63,252,146,100,63,177,115,104,63,138,246,107,63,198,29,111,63,109,236,113,63,62,102,116,63,154,143,118,63,104,109,120,63,3,5,122,63,26,92,123,63,153,120,124,63,143,96,125,63,17,26,126,63,39,171,126,63,176,25,127,63,74,107,127,63,68,165,127,63,132,204,127,63,123,229,127,63,17,244,127,63,158,251,127,63,219,254,127,63,218,255,127,63,0,0,128,63,5,12,120,56,50,131,11,58,118,186,193,58,226,203,61,59,38,207,156,59,139,32,234,59,245,102,35,60,63,100,89,60,184,127,139,60,59,23,174,60,239,114,212,60,96,140,254,60,45,46,22,61,114,237,46,61,155,127,73,61,220,223,101,61,123,4,130,61,159,250,145,61,71,207,162,61,38,127,180,61,173,6,199,61,16,98,218,61,63,141,238,61,244,193,1,62,185,160,12,62,128,224,23,62,182,126,35,62,166,120,47,62,116,203,59,62,34,116,72,62,141,111,85,62,107,186,98,62,83,81,112,62,180,48,126,62,110,42,134,62,252,92,141,62,9,174,148,62,138,27,156,62,100,163,163,62,112,67,171,62,119,249,178,62,54,195,186,62,93,158,194,62,147,136,202,62,118,127,210,62,154,128,218,62,142,137,226,62,217,151,234,62,2,169,242,62,139,186,250,62,251,100,1,63,99,106,5,63,65,108,9,63,89,105,13,63,116,96,17,63,94,80,21,63,231,55,25,63,231,21,29,63,58,233,32,63,197,176,36,63,116,107,40,63,62,24,44,63,35,182,47,63,43,68,51,63,109,193,54,63,10,45,58,63,48,134,61,63,26,204,64,63,17,254,67,63,107,27,71,63,142,35,74,63,238,21,77,63,15,242,79,63,132,183,82,63,239,101,85,63,3,253,87,63,129,124,90,63,60,228,92,63,21,52,95,63,254,107,97,63,246,139,99,63,14,148,101,63,98,132,103,63,33,93,105,63,133,30,107,63,213,200,108,63,103,92,110,63,155,217,111,63,224,64,113,63,172,146,114,63,131,207,115,63,241,247,116,63,139,12,118,63,239,13,119,63,193,252,119,63,172,217,120,63,99,165,121,63,155,96,122,63,15,12,123,63,124,168,123,63,163,54,124,63,71,183,124,63,41,43,125,63,13,147,125,63,183,239,125,63,229,65,126,63,89,138,126,63,205,201,126,63,251,0,127,63,150,48,127,63,78,89,127,63,205,123,127,63,182,152,127,63,167,176,127,63,53,196,127,63,239,211,127,63,91,224,127,63,245,233,127,63,51,241,127,63,127,246,127,63,59,250,127,63,190,252,127,63,84,254,127,63,64,255,127,63,186,255,127,63,238,255,127,63,254,255,127,63,0,0,128,63,169,12,120,55,54,134,11,57,38,198,193,57,94,226,61,58,234,237,156,58,85,101,234,58,56,170,35,59,207,219,89,59,169,226,139,59,42,178,174,59,13,91,213,59,204,219,255,59,91,25,23,60,250,46,48,60,194,45,75,60,156,20,104,60,46,113,131,60,225,202,147,60,185,22,165,60,1,84,183,60,245,129,202,60,198,159,222,60,155,172,243,60,199,211,4,61,213,71,16,61,250,49,28,61,174,145,40,61,101,102,53,61,141,175,66,61,140,108,80,61,193,156,94,61,133,63,109,61,41,84,124,61,252,236,133,61,26,232,141,61,13,27,150,61,110,133,158,61,212,38,167,61,210,254,175,61,245,12,185,61,200,80,194,61,209,201,203,61,146,119,213,61,139,89,223,61,51,111,233,61,2,184,243,61,105,51,254,61,106,112,4,62,214,223,9,62,171,103,15,62,153,7,21,62,77,191,26,62,116,142,32,62,181,116,38,62,184,113,44,62,34,133,50,62,149,174,56,62,178,237,62,62,21,66,69,62,92,171,75,62,30,41,82,62,243,186,88,62,112,96,95,62,40,25,102,62,170,228,108,62,132,194,115,62,68,178,122,62,185,217,128,62,203,98,132,62,26,244,135,62,105,141,139,62,120,46,143,62,6,215,146,62,211,134,150,62,156,61,154,62,29,251,157,62,19,191,161,62,57,137,165,62,71,89,169,62,249,46,173,62,5,10,177,62,36,234,180,62,13,207,184,62,117,184,188,62,18,166,192,62,153,151,196,62,190,140,200,62,52,133,204,62,175,128,208,62,225,126,212,62,125,127,216,62,52,130,220,62,184,134,224,62,185,140,228,62,233,147,232,62,248,155,236,62,150,164,240,62,117,173,244,62,67,182,248,62,178,190,252,62,57,99,0,63,153,102,2,63,82,105,4,63,60,107,6,63,48,108,8,63,6,108,10,63,151,106,12,63,188,103,14,63,78,99,16,63,39,93,18,63,33,85,20,63,21,75,22,63,222,62,24,63,87,48,26,63,92,31,28,63,199,11,30,63,117,245,31,63,66,220,33,63,12,192,35,63,176,160,37,63,12,126,39,63,254,87,41,63,104,46,43,63,39,1,45,63,29,208,46,63,43,155,48,63,51,98,50,63,23,37,52,63,188,227,53,63,4,158,55,63,214,83,57,63,23,5,59,63,173,177,60,63,128,89,62,63,120,252,63,63,126,154,65,63,124,51,67,63,93,199,68,63,12,86,70,63,119,223,71,63,138,99,73,63,54,226,74,63,104,91,76,63,17,207,77,63,35,61,79,63,145,165,80,63,76,8,82,63,75,101,83,63,130,188,84,63,231,13,86,63,114,89,87,63,26,159,88,63,218,222,89,63,172,24,91,63,138,76,92,63,113,122,93,63,93,162,94,63,78,196,95,63,67,224,96,63,58,246,97,63,54,6,99,63,56,16,100,63,67,20,101,63,92,18,102,63,133,10,103,63,198,252,103,63,37,233,104,63,168,207,105,63,89,176,106,63,64,139,107,63,102,96,108,63,216,47,109,63,159,249,109,63,201,189,110,63,97,124,111,63,118,53,112,63,23,233,112,63,81,151,113,63,53,64,114,63,212,227,114,63,61,130,115,63,131,27,116,63,184,175,116,63,238,62,117,63,56,201,117,63,171,78,118,63,90,207,118,63,90,75,119,63,192,194,119,63,162,53,120,63,21,164,120,63,48,14,121,63,8,116,121,63,182,213,121,63,79,51,122,63,235,140,122,63,162,226,122,63,139,52,123,63,191,130,123,63,85,205,123,63,102,20,124,63,9,88,124,63,88,152,124,63,106,213,124,63,88,15,125,63,58,70,125,63,41,122,125,63,62,171,125,63,143,217,125,63,54,5,126,63,75,46,126,63,228,84,126,63,27,121,126,63,7,155,126,63,190,186,126,63,88,216,126,63,236,243,126,63,144,13,127,63,91,37,127,63,99,59,127,63,188,79,127,63,125,98,127,63,185,115,127,63,135,131,127,63,249,145,127,63,36,159,127,63,26,171,127,63,238,181,127,63,179,191,127,63,122,200,127,63,85,208,127,63,84,215,127,63,136,221,127,63,0,227,127,63,204,231,127,63,249,235,127,63,150,239,127,63,177,242,127,63,85,245,127,63,144,247,127,63,109,249,127,63,246,250,127,63,54,252,127,63,55,253,127,63,1,254,127,63,156,254,127,63,18,255,127,63,103,255,127,63,163,255,127,63,204,255,127,63,229,255,127,63,244,255,127,63,252,255,127,63,255,255,127,63,0,0,128,63,0,0,128,63,60,12,120,54,253,134,11,56,19,201,193,56,248,231,61,57,148,245,156,57,115,118,234,57,238,186,35,58,113,249,89,58,32,251,139,58,96,216,174,58,34,148,213,58,3,23,0,59,209,82,23,59,65,125,48,59,21,150,75,59,8,157,104,59,233,200,131,59,20,58,148,59,218,161,165,59,16,0,184,59,136,84,203,59,16,159,223,59,118,223,244,59,194,138,5,60,128,32,17,60,217,48,29,60,172,187,41,60,219,192,54,60,67,64,68,60,194,57,82,60,52,173,96,60,115,154,111,60,88,1,127,60,222,112,135,60,186,157,143,60,42,7,152,60,25,173,160,60,112,143,169,60,23,174,178,60,246,8,188,60,243,159,197,60,245,114,207,60,225,129,217,60,156,204,227,60,10,83,238,60,14,21,249,60,70,9,2,61,177,165,7,61,187,95,13,61,81,55,19,61,102,44,25,61,230,62,31,61,195,110,37,61,233,187,43,61,71,38,50,61,202,173,56,61,97,82,63,61,247,19,70,61,121,242,76,61,210,237,83,61,240,5,91,61,187,58,98,61,32,140,105,61,8,250,112,61,93,132,120,61,132,21,128,61,249,246,131,61,130,230,135,61,19,228,139,61,159,239,143,61,26,9,148,61,119,48,152,61,169,101,156,61,163,168,160,61,88,249,164,61,186,87,169,61,186,195,173,61,76,61,178,61,95,196,182,61,230,88,187,61,209,250,191,61,18,170,196,61,152,102,201,61,85,48,206,61,56,7,211,61,48,235,215,61,47,220,220,61,34,218,225,61,248,228,230,61,161,252,235,61,11,33,241,61,35,82,246,61,217,143,251,61,13,109,0,62,105,24,3,62,247,201,5,62,174,129,8,62,133,63,11,62,113,3,14,62,104,205,16,62,96,157,19,62,79,115,22,62,42,79,25,62,232,48,28,62,124,24,31,62,221,5,34,62,255,248,36,62,215,241,39,62,90,240,42,62,125,244,45,62,51,254,48,62,114,13,52,62,45,34,55,62,88,60,58,62,232,91,61,62,208,128,64,62,3,171,67,62,118,218,70,62,26,15,74,62,229,72,77,62,199,135,80,62,181,203,83,62,162,20,87,62,127,98,90,62,63,181,93,62,213,12,97,62,50,105,100,62,73,202,103,62,12,48,107,62,108,154,110,62,92,9,114,62,203,124,117,62,173,244,120,62,241,112,124,62,138,241,127,62,52,187,129,62,190,127,131,62,91,70,133,62,4,15,135,62,176,217,136,62,89,166,138,62,245,116,140,62,126,69,142,62,234,23,144,62,50,236,145,62,78,194,147,62,54,154,149,62,224,115,151,62,70,79,153,62,93,44,155,62,31,11,157,62,130,235,158,62,127,205,160,62,11,177,162,62,31,150,164,62,177,124,166,62,186,100,168,62,47,78,170,62,9,57,172,62,62,37,174,62,198,18,176,62,150,1,178,62,167,241,179,62,238,226,181,62,100,213,183,62,254,200,185,62,179,189,187,62,122,179,189,62,74,170,191,62,25,162,193,62,221,154,195,62,142,148,197,62,34,143,199,62,142,138,201,62,203,134,203,62,205,131,205,62,140,129,207,62,253,127,209,62,24,127,211,62,210,126,213,62,33,127,215,62,252,127,217,62,88,129,219,62,45,131,221,62,112,133,223,62,23,136,225,62,25,139,227,62,108,142,229,62,5,146,231,62,219,149,233,62,228,153,235,62,21,158,237,62,102,162,239,62,203,166,241,62,59,171,243,62,173,175,245,62,21,180,247,62,107,184,249,62,164,188,251,62,181,192,253,62,150,196,255,62,30,228,0,63,207,229,1,63,88,231,2,63,182,232,3,63,226,233,4,63,215,234,5,63,146,235,6,63,12,236,7,63,66,236,8,63,45,236,9,63,202,235,10,63,19,235,11,63,4,234,12,63,151,232,13,63,200,230,14,63,145,228,15,63,239,225,16,63,220,222,17,63,84,219,18,63,81,215,19,63,208,210,20,63,202,205,21,63,61,200,22,63,34,194,23,63,117,187,24,63,50,180,25,63,85,172,26,63,215,163,27,63,182,154,28,63,236,144,29,63,117,134,30,63,77,123,31,63,110,111,32,63,214,98,33,63,126,85,34,63,100,71,35,63,130,56,36,63,212,40,37,63,87,24,38,63,5,7,39,63,219,244,39,63,213,225,40,63,239,205,41,63,36,185,42,63,113,163,43,63,209,140,44,63,64,117,45,63,188,92,46,63,63,67,47,63,199,40,48,63,78,13,49,63,211,240,49,63,80,211,50,63,195,180,51,63,39,149,52,63,122,116,53,63,184,82,54,63,220,47,55,63,229,11,56,63,206,230,56,63,149,192,57,63,54,153,58,63,174,112,59,63,249,70,60,63,21,28,61,63,255,239,61,63,179,194,62,63,48,148,63,63,113,100,64,63,116,51,65,63,55,1,66,63,182,205,66,63,239,152,67,63,224,98,68,63,134,43,69,63,222,242,69,63,230,184,70,63,156,125,71,63,253,64,72,63,7,3,73,63,184,195,73,63,14,131,74,63,6,65,75,63,159,253,75,63,215,184,76,63,172,114,77,63,28,43,78,63,38,226,78,63,199,151,79,63,253,75,80,63,201,254,80,63,39,176,81,63,22,96,82,63,150,14,83,63,164,187,83,63,63,103,84,63,103,17,85,63,26,186,85,63,86,97,86,63,28,7,87,63,105,171,87,63,62,78,88,63,152,239,88,63,120,143,89,63,221,45,90,63,198,202,90,63,50,102,91,63,33,0,92,63,147,152,92,63,134,47,93,63,251,196,93,63,242,88,94,63,105,235,94,63,98,124,95,63,219,11,96,63,213,153,96,63,80,38,97,63,76,177,97,63,201,58,98,63,199,194,98,63,70,73,99,63,71,206,99,63,202,81,100,63,208,211,100,63,88,84,101,63,100,211,101,63,244,80,102,63,9,205,102,63,163,71,103,63,195,192,103,63,107,56,104,63,154,174,104,63,82,35,105,63,147,150,105,63,96,8,106,63,184,120,106,63,157,231,106,63,16,85,107,63,19,193,107,63,166,43,108,63,203,148,108,63,132,252,108,63,209,98,109,63,180,199,109,63,48,43,110,63,68,141,110,63,244,237,110,63,64,77,111,63,42,171,111,63,181,7,112,63,225,98,112,63,177,188,112,63,38,21,113,63,67,108,113,63,10,194,113,63,123,22,114,63,155,105,114,63,106,187,114,63,234,11,115,63,31,91,115,63,9,169,115,63,172,245,115,63,9,65,116,63,35,139,116,63,252,211,116,63,151,27,117,63,245,97,117,63,26,167,117,63,8,235,117,63,193,45,118,63,72,111,118,63,159,175,118,63,202,238,118,63,201,44,119,63,161,105,119,63,84,165,119,63,228,223,119,63,85,25,120,63,168,81,120,63,226,136,120,63,3,191,120,63,16,244,120,63,11,40,121,63,247,90,121,63,215,140,121,63,173,189,121,63,125,237,121,63,73,28,122,63,20,74,122,63,226,118,122,63,181,162,122,63,144,205,122,63,118,247,122,63,107,32,123,63,112,72,123,63,138,111,123,63,186,149,123,63,5,187,123,63,109,223,123,63,245,2,124,63,160,37,124,63,113,71,124,63,108,104,124,63,147,136,124,63,233,167,124,63,114,198,124,63,48,228,124,63,38,1,125,63,89,29,125,63,201,56,125,63,124,83,125,63,115,109,125,63,178,134,125,63,60,159,125,63,19,183,125,63,60,206,125,63,184,228,125,63,139,250,125,63,184,15,126,63,66,36,126,63,44,56,126,63,120,75,126,63,43,94,126,63,70,112,126,63,204,129,126,63,194,146,126,63,41,163,126,63,4,179,126,63,86,194,126,63,35,209,126,63,109,223,126,63,55,237,126,63,131,250,126,63,85,7,127,63,175,19,127,63,148,31,127,63,7,43,127,63,10,54,127,63,160,64,127,63,205,74,127,63,146,84,127,63,242,93,127,63,239,102,127,63,141,111,127,63,206,119,127,63,181,127,127,63,67,135,127,63,124,142,127,63,98,149,127,63,247,155,127,63,61,162,127,63,56,168,127,63,233,173,127,63,83,179,127,63,120,184,127,63,90,189,127,63,252,193,127,63,95,198,127,63,134,202,127,63,116,206,127,63,41,210,127,63,168,213,127,63,244,216,127,63,13,220,127,63,247,222,127,63,179,225,127,63,67,228,127,63,168,230,127,63,229,232,127,63,252,234,127,63,237,236,127,63,188,238,127,63,105,240,127,63,246,241,127,63,101,243,127,63,183,244,127,63,238,245,127,63,11,247,127,63,16,248,127,63,254,248,127,63,214,249,127,63,155,250,127,63,76,251,127,63,236,251,127,63,124,252,127,63,252,252,127,63,110,253,127,63,211,253,127,63,44,254,127,63,121,254,127,63,189,254,127,63,247,254,127,63,42,255,127,63,84,255,127,63,120,255,127,63,150,255,127,63,175,255,127,63,195,255,127,63,211,255,127,63,224,255,127,63,234,255,127,63,241,255,127,63,246,255,127,63,250,255,127,63,253,255,127,63,254,255,127,63,255,255,127,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,171,15,120,53,24,135,11,55,225,201,193,55,107,233,61,56,128,247,156,56,187,122,234,56,24,191,35,57,213,0,90,57,56,1,140,57,229,225,174,57,88,162,213,57,60,33,0,58,24,97,23,58,175,144,48,58,243,175,75,58,212,190,104,58,159,222,131,58,143,85,148,58,48,196,165,58,119,42,184,58,90,136,203,58,204,221,223,58,191,42,245,58,148,183,5,59,124,85,17,59,16,111,29,59,73,4,42,59,31,21,55,59,138,161,68,59,129,169,82,59,252,44,97,59,241,43,112,59,88,166,127,59,19,206,135,59,169,6,144,59,233,124,152,59,204,48,161,59,79,34,170,59,106,81,179,59,26,190,188,59,86,104,198,59,26,80,208,59,95,117,218,59,31,216,228,59,83,120,239,59,244,85,250,59,126,184,2,60,177,100,8,60,145,47,14,60,25,25,20,60,70,33,26,60,19,72,32,60,126,141,38,60,129,241,44,60,25,116,51,60,65,21,58,60,246,212,64,60,50,179,71,60,243,175,78,60,50,203,85,60,235,4,93,60,26,93,100,60,186,211,107,60,198,104,115,60,58,28,123,60,7,119,129,60,33,111,133,60,102,118,137,60,212,140,141,60,105,178,145,60,33,231,149,60,251,42,154,60,243,125,158,60,6,224,162,60,50,81,167,60,115,209,171,60,199,96,176,60,43,255,180,60,154,172,185,60,19,105,190,60,146,52,195,60,20,15,200,60,149,248,204,60,19,241,209,60,137,248,214,60,245,14,220,60,83,52,225,60,160,104,230,60,215,171,235,60,246,253,240,60,249,94,246,60,220,206,251,60,205,166,0,61,153,109,3,61,207,59,6,61,109,17,9,61,114,238,11,61,220,210,14,61,167,190,17,61,211,177,20,61,94,172,23,61,68,174,26,61,133,183,29,61,30,200,32,61,12,224,35,61,78,255,38,61,225,37,42,61,196,83,45,61,243,136,48,61,109,197,51,61,47,9,55,61,55,84,58,61,130,166,61,61,15,0,65,61,218,96,68,61,226,200,71,61,35,56,75,61,156,174,78,61,73,44,82,61,40,177,85,61,55,61,89,61,115,208,92,61,217,106,96,61,103,12,100,61,25,181,103,61,238,100,107,61,227,27,111,61,244,217,114,61,30,159,118,61,96,107,122,61,182,62,126,61,143,12,129,61,73,253,130,61,138,241,132,61,79,233,134,61,150,228,136,61,94,227,138,61,167,229,140,61,109,235,142,61,175,244,144,61,109,1,147,61,164,17,149,61,83,37,151,61,120,60,153,61,17,87,155,61,30,117,157,61,155,150,159,61,136,187,161,61,226,227,163,61,169,15,166,61,218,62,168,61,116,113,170,61,116,167,172,61,218,224,174,61,162,29,177,61,205,93,179,61,87,161,181,61,62,232,183,61,130,50,186,61,32,128,188,61,22,209,190,61,98,37,193,61,2,125,195,61,245,215,197,61,57,54,200,61,203,151,202,61,169,252,204,61,211,100,207,61,68,208,209,61,252,62,212,61,249,176,214,61,56,38,217,61,184,158,219,61,117,26,222,61,111,153,224,61,163,27,227,61,14,161,229,61,175,41,232,61,132,181,234,61,138,68,237,61,191,214,239,61,33,108,242,61,174,4,245,61,99,160,247,61,62,63,250,61,61,225,252,61,93,134,255,61,78,23,1,62,252,108,2,62,56,196,3,62,255,28,5,62,81,119,6,62,45,211,7,62,145,48,9,62,125,143,10,62,238,239,11,62,228,81,13,62,94,181,14,62,89,26,16,62,214,128,17,62,210,232,18,62,77,82,20,62,69,189,21,62,184,41,23,62,166,151,24,62,13,7,26,62,236,119,27,62,65,234,28,62,11,94,30,62,73,211,31,62,250,73,33,62,28,194,34,62,173,59,36,62,172,182,37,62,24,51,39,62,240,176,40,62,50,48,42,62,220,176,43,62,238,50,45,62,101,182,46,62,64,59,48,62,126,193,49,62,30,73,51,62,29,210,52,62,123,92,54,62,54,232,55,62,76,117,57,62,187,3,59,62,131,147,60,62,162,36,62,62,22,183,63,62,222,74,65,62,248,223,66,62,98,118,68,62,28,14,70,62,35,167,71,62,117,65,73,62,18,221,74,62,247,121,76,62,35,24,78,62,149,183,79,62,74,88,81,62,66,250,82,62,121,157,84,62,240,65,86,62,163,231,87,62,146,142,89,62,186,54,91,62,26,224,92,62,177,138,94,62,124,54,96,62,122,227,97,62,169,145,99,62,7,65,101,62,147,241,102,62,75,163,104,62,44,86,106,62,54,10,108,62,102,191,109,62,187,117,111,62,51,45,113,62,204,229,114,62,132,159,116,62,90,90,118,62,75,22,120,62,85,211,121,62,120,145,123,62,176,80,125,62,253,16,127,62,46,105,128,62,101,74,129,62,36,44,130,62,105,14,131,62,52,241,131,62,130,212,132,62,84,184,133,62,169,156,134,62,127,129,135,62,213,102,136,62,171,76,137,62,255,50,138,62,209,25,139,62,32,1,140,62,233,232,140,62,46,209,141,62,236,185,142,62,34,163,143,62,208,140,144,62,244,118,145,62,142,97,146,62,156,76,147,62,29,56,148,62,17,36,149,62,118,16,150,62,76,253,150,62,144,234,151,62,67,216,152,62,99,198,153,62,239,180,154,62,230,163,155,62,71,147,156,62,17,131,157,62,67,115,158,62,219,99,159,62,218,84,160,62,60,70,161,62,3,56,162,62,43,42,163,62,181,28,164,62,160,15,165,62,233,2,166,62,145,246,166,62,149,234,167,62,245,222,168,62,176,211,169,62,197,200,170,62,50,190,171,62,246,179,172,62,17,170,173,62,129,160,174,62,69,151,175,62,91,142,176,62,196,133,177,62,125,125,178,62,133,117,179,62,220,109,180,62,128,102,181,62,112,95,182,62,171,88,183,62,47,82,184,62,252,75,185,62,17,70,186,62,108,64,187,62,11,59,188,62,239,53,189,62,22,49,190,62,126,44,191,62,38,40,192,62,13,36,193,62,51,32,194,62,150,28,195,62,52,25,196,62,12,22,197,62,30,19,198,62,104,16,199,62,233,13,200,62,159,11,201,62,138,9,202,62,169,7,203,62,249,5,204,62,123,4,205,62,44,3,206,62,11,2,207,62,24,1,208,62,81,0,209,62,181,255,209,62,66,255,210,62,248,254,211,62,213,254,212,62,216,254,213,62,255,254,214,62,75,255,215,62,184,255,216,62,71,0,218,62,245,0,219,62,195,1,220,62,173,2,221,62,180,3,222,62,214,4,223,62,17,6,224,62,101,7,225,62,208,8,226,62,81,10,227,62,231,11,228,62,144,13,229,62,76,15,230,62,25,17,231,62,245,18,232,62,224,20,233,62,217,22,234,62,221,24,235,62,236,26,236,62,5,29,237,62,39,31,238,62,79,33,239,62,125,35,240,62,176,37,241,62,230,39,242,62,31,42,243,62,88,44,244,62,145,46,245,62,200,48,246,62,253,50,247,62,45,53,248,62,88,55,249,62,124,57,250,62,153,59,251,62,172,61,252,62,181,63,253,62,179,65,254,62,163,67,255,62,195,34,0,63,173,163,0,63,142,36,1,63,102,165,1,63,53,38,2,63,250,166,2,63,180,39,3,63,99,168,3,63,5,41,4,63,155,169,4,63,36,42,5,63,159,170,5,63,12,43,6,63,105,171,6,63,183,43,7,63,244,171,7,63,32,44,8,63,59,172,8,63,68,44,9,63,58,172,9,63,28,44,10,63,235,171,10,63,164,43,11,63,73,171,11,63,216,42,12,63,80,170,12,63,177,41,13,63,251,168,13,63,44,40,14,63,69,167,14,63,68,38,15,63,41,165,15,63,243,35,16,63,162,162,16,63,53,33,17,63,172,159,17,63,5,30,18,63,65,156,18,63,95,26,19,63,94,152,19,63,61,22,20,63,252,147,20,63,155,17,21,63,24,143,21,63,116,12,22,63,173,137,22,63,195,6,23,63,182,131,23,63,133,0,24,63,46,125,24,63,179,249,24,63,18,118,25,63,74,242,25,63,91,110,26,63,69,234,26,63,6,102,27,63,159,225,27,63,14,93,28,63,84,216,28,63,111,83,29,63,95,206,29,63,36,73,30,63,188,195,30,63,40,62,31,63,102,184,31,63,119,50,32,63,90,172,32,63,14,38,33,63,146,159,33,63,230,24,34,63,10,146,34,63,253,10,35,63,190,131,35,63,77,252,35,63,169,116,36,63,211,236,36,63,200,100,37,63,138,220,37,63,22,84,38,63,110,203,38,63,143,66,39,63,122,185,39,63,47,48,40,63,172,166,40,63,241,28,41,63,254,146,41,63,210,8,42,63,108,126,42,63,205,243,42,63,243,104,43,63,223,221,43,63,143,82,44,63,3,199,44,63,59,59,45,63,54,175,45,63,244,34,46,63,116,150,46,63,182,9,47,63,185,124,47,63,125,239,47,63,1,98,48,63,69,212,48,63,72,70,49,63,10,184,49,63,139,41,50,63,202,154,50,63,198,11,51,63,127,124,51,63,246,236,51,63,40,93,52,63,22,205,52,63,191,60,53,63,36,172,53,63,66,27,54,63,27,138,54,63,174,248,54,63,249,102,55,63,254,212,55,63,187,66,56,63,47,176,56,63,91,29,57,63,63,138,57,63,217,246,57,63,41,99,58,63,48,207,58,63,236,58,59,63,93,166,59,63,130,17,60,63,93,124,60,63,235,230,60,63,44,81,61,63,33,187,61,63,201,36,62,63,35,142,62,63,48,247,62,63,238,95,63,63,94,200,63,63,126,48,64,63,80,152,64,63,209,255,64,63,3,103,65,63,228,205,65,63,117,52,66,63,181,154,66,63,163,0,67,63,64,102,67,63,139,203,67,63,131,48,68,63,41,149,68,63,124,249,68,63,123,93,69,63,39,193,69,63,127,36,70,63,132,135,70,63,51,234,70,63,142,76,71,63,148,174,71,63,68,16,72,63,159,113,72,63,164,210,72,63,83,51,73,63,172,147,73,63,174,243,73,63,89,83,74,63,173,178,74,63,169,17,75,63,77,112,75,63,154,206,75,63,143,44,76,63,43,138,76,63,110,231,76,63,89,68,77,63,234,160,77,63,34,253,77,63,0,89,78,63,133,180,78,63,176,15,79,63,128,106,79,63,246,196,79,63,18,31,80,63,210,120,80,63,56,210,80,63,66,43,81,63,242,131,81,63,69,220,81,63,61,52,82,63,217,139,82,63,24,227,82,63,252,57,83,63,131,144,83,63,174,230,83,63,123,60,84,63,236,145,84,63,0,231,84,63,183,59,85,63,16,144,85,63,12,228,85,63,170,55,86,63,235,138,86,63,206,221,86,63,83,48,87,63,121,130,87,63,66,212,87,63,172,37,88,63,184,118,88,63,101,199,88,63,180,23,89,63,164,103,89,63,53,183,89,63,104,6,90,63,59,85,90,63,175,163,90,63,197,241,90,63,123,63,91,63,210,140,91,63,201,217,91,63,97,38,92,63,154,114,92,63,115,190,92,63,237,9,93,63,7,85,93,63,194,159,93,63,29,234,93,63,24,52,94,63,179,125,94,63,239,198,94,63,203,15,95,63,72,88,95,63,100,160,95,63,33,232,95,63,126,47,96,63,123,118,96,63,24,189,96,63,85,3,97,63,51,73,97,63,177,142,97,63,207,211,97,63,141,24,98,63,236,92,98,63,235,160,98,63,138,228,98,63,202,39,99,63,170,106,99,63,42,173,99,63,75,239,99,63,13,49,100,63,111,114,100,63,114,179,100,63,21,244,100,63,90,52,101,63,63,116,101,63,197,179,101,63,236,242,101,63,180,49,102,63,29,112,102,63,39,174,102,63,211,235,102,63,32,41,103,63,15,102,103,63,159,162,103,63,209,222,103,63,164,26,104,63,26,86,104,63,49,145,104,63,235,203,104,63,71,6,105,63,69,64,105,63,230,121,105,63,42,179,105,63,16,236,105,63,153,36,106,63,197,92,106,63,148,148,106,63,7,204,106,63,29,3,107,63,214,57,107,63,52,112,107,63,53,166,107,63,218,219,107,63,36,17,108,63,18,70,108,63,164,122,108,63,220,174,108,63,184,226,108,63,57,22,109,63,96,73,109,63,44,124,109,63,157,174,109,63,181,224,109,63,115,18,110,63,214,67,110,63,225,116,110,63,146,165,110,63,233,213,110,63,232,5,111,63,142,53,111,63,219,100,111,63,209,147,111,63,110,194,111,63,179,240,111,63,160,30,112,63,54,76,112,63,117,121,112,63,93,166,112,63,239,210,112,63,41,255,112,63,14,43,113,63,156,86,113,63,213,129,113,63,184,172,113,63,70,215,113,63,127,1,114,63,99,43,114,63,243,84,114,63,46,126,114,63,21,167,114,63,169,207,114,63,233,247,114,63,214,31,115,63,113,71,115,63,184,110,115,63,173,149,115,63,80,188,115,63,162,226,115,63,161,8,116,63,80,46,116,63,174,83,116,63,187,120,116,63,119,157,116,63,228,193,116,63,1,230,116,63,206,9,117,63,76,45,117,63,123,80,117,63,92,115,117,63,238,149,117,63,51,184,117,63,42,218,117,63,211,251,117,63,48,29,118,63,64,62,118,63,3,95,118,63,122,127,118,63,166,159,118,63,134,191,118,63,27,223,118,63,101,254,118,63,101,29,119,63,27,60,119,63,135,90,119,63,169,120,119,63,131,150,119,63,19,180,119,63,91,209,119,63,91,238,119,63,20,11,120,63,132,39,120,63,174,67,120,63,145,95,120,63,46,123,120,63,132,150,120,63,149,177,120,63,96,204,120,63,231,230,120,63,41,1,121,63,38,27,121,63,223,52,121,63,85,78,121,63,136,103,121,63,120,128,121,63,37,153,121,63,144,177,121,63,185,201,121,63,161,225,121,63,72,249,121,63,174,16,122,63,212,39,122,63,185,62,122,63,96,85,122,63,198,107,122,63,238,129,122,63,216,151,122,63,131,173,122,63,241,194,122,63,33,216,122,63,20,237,122,63,202,1,123,63,68,22,123,63,130,42,123,63,133,62,123,63,77,82,123,63,217,101,123,63,43,121,123,63,68,140,123,63,34,159,123,63,200,177,123,63,52,196,123,63,104,214,123,63,99,232,123,63,39,250,123,63,180,11,124,63,9,29,124,63,40,46,124,63,17,63,124,63,196,79,124,63,65,96,124,63,137,112,124,63,156,128,124,63,124,144,124,63,39,160,124,63,158,175,124,63,226,190,124,63,244,205,124,63,211,220,124,63,128,235,124,63,251,249,124,63,69,8,125,63,94,22,125,63,71,36,125,63,255,49,125,63,136,63,125,63,225,76,125,63,11,90,125,63,7,103,125,63,212,115,125,63,115,128,125,63,229,140,125,63,42,153,125,63,66,165,125,63,46,177,125,63,238,188,125,63,130,200,125,63,235,211,125,63,41,223,125,63,61,234,125,63,38,245,125,63,230,255,125,63,124,10,126,63,234,20,126,63,47,31,126,63,75,41,126,63,64,51,126,63,13,61,126,63,180,70,126,63,51,80,126,63,140,89,126,63,191,98,126,63,205,107,126,63,181,116,126,63,120,125,126,63,23,134,126,63,146,142,126,63,233,150,126,63,28,159,126,63,44,167,126,63,26,175,126,63,229,182,126,63,142,190,126,63,22,198,126,63,124,205,126,63,194,212,126,63,231,219,126,63,235,226,126,63,208,233,126,63,149,240,126,63,59,247,126,63,195,253,126,63,44,4,127,63,118,10,127,63,163,16,127,63,179,22,127,63,165,28,127,63,123,34,127,63,52,40,127,63,210,45,127,63,83,51,127,63,186,56,127,63,5,62,127,63,53,67,127,63,75,72,127,63,72,77,127,63,42,82,127,63,243,86,127,63,163,91,127,63,58,96,127,63,185,100,127,63,32,105,127,63,111,109,127,63,166,113,127,63,199,117,127,63,208,121,127,63,196,125,127,63,161,129,127,63,104,133,127,63,25,137,127,63,182,140,127,63,61,144,127,63,176,147,127,63,14,151,127,63,89,154,127,63,143,157,127,63,179,160,127,63,195,163,127,63,192,166,127,63,171,169,127,63,132,172,127,63,74,175,127,63,255,177,127,63,163,180,127,63,53,183,127,63,183,185,127,63,40,188,127,63,137,190,127,63,217,192,127,63,26,195,127,63,76,197,127,63,111,199,127,63,130,201,127,63,135,203,127,63,126,205,127,63,102,207,127,63,65,209,127,63,14,211,127,63,205,212,127,63,128,214,127,63,38,216,127,63,191,217,127,63,76,219,127,63,204,220,127,63,65,222,127,63,170,223,127,63,8,225,127,63,91,226,127,63,163,227,127,63,224,228,127,63,19,230,127,63,59,231,127,63,90,232,127,63,110,233,127,63,122,234,127,63,124,235,127,63,116,236,127,63,100,237,127,63,75,238,127,63,42,239,127,63,1,240,127,63,207,240,127,63,149,241,127,63,84,242,127,63,12,243,127,63,188,243,127,63,101,244,127,63,7,245,127,63,162,245,127,63,55,246,127,63,198,246,127,63,78,247,127,63,209,247,127,63,77,248,127,63,196,248,127,63,54,249,127,63,162,249,127,63,9,250,127,63,108,250,127,63,201,250,127,63,34,251,127,63,118,251,127,63,198,251,127,63,18,252,127,63,89,252,127,63,157,252,127,63,221,252,127,63,26,253,127,63,83,253,127,63,136,253,127,63,187,253,127,63,234,253,127,63,22,254,127,63,64,254,127,63,103,254,127,63,139,254,127,63,173,254,127,63,204,254,127,63,234,254,127,63,5,255,127,63,30,255,127,63,53,255,127,63,74,255,127,63,94,255,127,63,112,255,127,63,128,255,127,63,143,255,127,63,157,255,127,63,169,255,127,63,180,255,127,63,191,255,127,63,200,255,127,63,208,255,127,63,215,255,127,63,221,255,127,63,227,255,127,63,232,255,127,63,236,255,127,63,239,255,127,63,243,255,127,63,245,255,127,63,248,255,127,63,249,255,127,63,251,255,127,63,252,255,127,63,253,255,127,63,254,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,204,8,120,52,171,134,11,54,79,202,193,54,190,233,61,55,238,247,156,55,192,123,234,55,43,192,35,56,161,2,90,56,189,2,140,56,76,228,174,56,227,165,213,56,199,35,0,57,168,100,23,57,134,149,48,57,104,182,75,57,64,199,104,57,7,228,131,57,105,92,148,57,191,204,165,57,6,53,184,57,65,149,203,57,105,237,223,57,120,61,245,57,184,194,5,58,166,98,17,58,134,126,29,58,81,22,42,58,9,42,55,58,172,185,68,58,54,197,82,58,165,76,97,58,250,79,112,58,47,207,127,58,34,229,135,58,154,32,144,58,255,153,152,58,80,81,161,58,139,70,170,58,174,121,179,58,186,234,188,58,171,153,198,58,129,134,208,58,58,177,218,58,212,25,229,58,79,192,239,58,167,164,250,58,109,227,2,59,117,147,8,59,105,98,14,59,73,80,20,59,19,93,26,59,199,136,32,59,100,211,38,59,232,60,45,59,83,197,51,59,164,108,58,59,218,50,65,59,243,23,72,59,239,27,79,59,204,62,86,59,138,128,93,59,38,225,100,59,161,96,108,59,249,254,115,59,45,188,123,59,29,204,129,59,145,201,133,59,113,214,137,59,188,242,141,59,113,30,146,59,145,89,150,59,26,164,154,59,12,254,158,59,102,103,163,59,40,224,167,59,80,104,172,59,222,255,176,59,209,166,181,59,40,93,186,59,228,34,191,59,2,248,195,59,131,220,200,59,101,208,205,59,168,211,210,59,74,230,215,59,76,8,221,59,172,57,226,59,105,122,231,59,131,202,236,59,249,41,242,59,202,152,247,59,245,22,253,59,60,82,1,60,170,32,4,60,196,246,6,60,137,212,9,60,249,185,12,60,19,167,15,60,216,155,18,60,69,152,21,60,92,156,24,60,26,168,27,60,129,187,30,60,143,214,33,60,69,249,36,60,160,35,40,60,162,85,43,60,73,143,46,60,149,208,49,60,133,25,53,60,26,106,56,60,81,194,59,60,44,34,63,60,168,137,66,60,199,248,69,60,134,111,73,60,230,237,76,60,231,115,80,60,134,1,84,60,197,150,87,60,162,51,91,60,28,216,94,60,52,132,98,60,232,55,102,60,56,243,105,60,35,182,109,60,170,128,113,60,202,82,117,60,131,44,121,60,214,13,125,60,96,123,128,60,161,115,130,60,174,111,132,60,134,111,134,60,40,115,136,60,149,122,138,60,205,133,140,60,206,148,142,60,152,167,144,60,44,190,146,60,136,216,148,60,173,246,150,60,154,24,153,60,78,62,155,60,202,103,157,60,13,149,159,60,23,198,161,60,231,250,163,60,125,51,166,60,217,111,168,60,249,175,170,60,223,243,172,60,137,59,175,60,247,134,177,60,40,214,179,60,29,41,182,60,213,127,184,60,80,218,186,60,140,56,189,60,138,154,191,60,74,0,194,60,202,105,196,60,11,215,198,60,12,72,201,60,205,188,203,60,77,53,206,60,140,177,208,60,137,49,211,60,69,181,213,60,189,60,216,60,243,199,218,60,230,86,221,60,149,233,223,60,0,128,226,60,39,26,229,60,8,184,231,60,164,89,234,60,250,254,236,60,9,168,239,60,210,84,242,60,83,5,245,60,141,185,247,60,126,113,250,60,39,45,253,60,134,236,255,60,206,87,1,61,52,187,2,61,117,32,4,61,144,135,5,61,133,240,6,61,84,91,8,61,253,199,9,61,128,54,11,61,219,166,12,61,16,25,14,61,29,141,15,61,3,3,17,61,193,122,18,61,87,244,19,61,197,111,21,61,10,237,22,61,39,108,24,61,26,237,25,61,228,111,27,61,132,244,28,61,251,122,30,61,71,3,32,61,105,141,33,61,96,25,35,61,45,167,36,61,206,54,38,61,67,200,39,61,141,91,41,61,171,240,42,61,156,135,44,61,96,32,46,61,248,186,47,61,99,87,49,61,160,245,50,61,175,149,52,61,144,55,54,61,67,219,55,61,199,128,57,61,28,40,59,61,65,209,60,61,56,124,62,61,254,40,64,61,148,215,65,61,250,135,67,61,47,58,69,61,51,238,70,61,5,164,72,61,166,91,74,61,20,21,76,61,80,208,77,61,90,141,79,61,49,76,81,61,212,12,83,61,68,207,84,61,128,147,86,61,135,89,88,61,90,33,90,61,248,234,91,61,97,182,93,61,148,131,95,61,145,82,97,61,88,35,99,61,232,245,100,61,65,202,102,61,100,160,104,61,78,120,106,61,1,82,108,61,123,45,110,61,188,10,112,61,197,233,113,61,148,202,115,61,41,173,117,61,133,145,119,61,166,119,121,61,140,95,123,61,55,73,125,61,166,52,127,61,237,144,128,61,105,136,129,61,198,128,130,61,5,122,131,61,37,116,132,61,39,111,133,61,9,107,134,61,204,103,135,61,112,101,136,61,244,99,137,61,88,99,138,61,157,99,139,61,193,100,140,61,196,102,141,61,167,105,142,61,106,109,143,61,11,114,144,61,139,119,145,61,234,125,146,61,40,133,147,61,67,141,148,61,61,150,149,61,20,160,150,61,201,170,151,61,92,182,152,61,203,194,153,61,24,208,154,61,66,222,155,61,72,237,156,61,42,253,157,61,233,13,159,61,132,31,160,61,250,49,161,61,76,69,162,61,122,89,163,61,130,110,164,61,101,132,165,61,35,155,166,61,188,178,167,61,47,203,168,61,124,228,169,61,162,254,170,61,163,25,172,61,124,53,173,61,47,82,174,61,187,111,175,61,31,142,176,61,92,173,177,61,113,205,178,61,94,238,179,61,35,16,181,61,192,50,182,61,52,86,183,61,127,122,184,61,160,159,185,61,153,197,186,61],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE);allocate([104,236,187,61,13,20,189,61,136,60,190,61,217,101,191,61,255,143,192,61,250,186,193,61,202,230,194,61,111,19,196,61,233,64,197,61,55,111,198,61,89,158,199,61,78,206,200,61,23,255,201,61,179,48,203,61,35,99,204,61,101,150,205,61,121,202,206,61,96,255,207,61,25,53,209,61,164,107,210,61,0,163,211,61,45,219,212,61,44,20,214,61,251,77,215,61,154,136,216,61,10,196,217,61,74,0,219,61,89,61,220,61,56,123,221,61,230,185,222,61,99,249,223,61,174,57,225,61,200,122,226,61,176,188,227,61,102,255,228,61,233,66,230,61,58,135,231,61,88,204,232,61,66,18,234,61,249,88,235,61,124,160,236,61,203,232,237,61,230,49,239,61,204,123,240,61,125,198,241,61,249,17,243,61,63,94,244,61,79,171,245,61,42,249,246,61,206,71,248,61,60,151,249,61,114,231,250,61,114,56,252,61,58,138,253,61,202,220,254,61,17,24,0,62,33,194,0,62,149,108,1,62,108,23,2,62,166,194,2,62,68,110,3,62,69,26,4,62,168,198,4,62,111,115,5,62,152,32,6,62,35,206,6,62,17,124,7,62,98,42,8,62,20,217,8,62,40,136,9,62,157,55,10,62,117,231,10,62,173,151,11,62,71,72,12,62,66,249,12,62,158,170,13,62,91,92,14,62,120,14,15,62,246,192,15,62,213,115,16,62,19,39,17,62,177,218,17,62,175,142,18,62,13,67,19,62,202,247,19,62,231,172,20,62,99,98,21,62,62,24,22,62,120,206,22,62,16,133,23,62,7,60,24,62,92,243,24,62,16,171,25,62,33,99,26,62,145,27,27,62,94,212,27,62,137,141,28,62,17,71,29,62,246,0,30,62,56,187,30,62,215,117,31,62,211,48,32,62,43,236,32,62,224,167,33,62,241,99,34,62,93,32,35,62,38,221,35,62,74,154,36,62,202,87,37,62,165,21,38,62,219,211,38,62,108,146,39,62,88,81,40,62,159,16,41,62,64,208,41,62,59,144,42,62,144,80,43,62,63,17,44,62,72,210,44,62,170,147,45,62,102,85,46,62,122,23,47,62,232,217,47,62,175,156,48,62,206,95,49,62,69,35,50,62,21,231,50,62,61,171,51,62,189,111,52,62,148,52,53,62,195,249,53,62,73,191,54,62,38,133,55,62,91,75,56,62,230,17,57,62,199,216,57,62,255,159,58,62,141,103,59,62,113,47,60,62,171,247,60,62,59,192,61,62,31,137,62,62,89,82,63,62,232,27,64,62,204,229,64,62,5,176,65,62,146,122,66,62,115,69,67,62,168,16,68,62,49,220,68,62,14,168,69,62,62,116,70,62,194,64,71,62,152,13,72,62,193,218,72,62,61,168,73,62,12,118,74,62,44,68,75,62,159,18,76,62,100,225,76,62,122,176,77,62,225,127,78,62,154,79,79,62,164,31,80,62,255,239,80,62,170,192,81,62,166,145,82,62,242,98,83,62,141,52,84,62,121,6,85,62,180,216,85,62,63,171,86,62,25,126,87,62,65,81,88,62,185,36,89,62,126,248,89,62,147,204,90,62,245,160,91,62,165,117,92,62,163,74,93,62,238,31,94,62,135,245,94,62,109,203,95,62,159,161,96,62,30,120,97,62,233,78,98,62,1,38,99,62,100,253,99,62,19,213,100,62,14,173,101,62,84,133,102,62,229,93,103,62,193,54,104,62,231,15,105,62,88,233,105,62,19,195,106,62,24,157,107,62,103,119,108,62,255,81,109,62,224,44,110,62,11,8,111,62,126,227,111,62,58,191,112,62,62,155,113,62,139,119,114,62,31,84,115,62,251,48,116,62,31,14,117,62,138,235,117,62,59,201,118,62,52,167,119,62,115,133,120,62,248,99,121,62,196,66,122,62,213,33,123,62,44,1,124,62,200,224,124,62,170,192,125,62,208,160,126,62,59,129,127,62,245,48,128,62,111,161,128,62,11,18,129,62,201,130,129,62,168,243,129,62,169,100,130,62,204,213,130,62,15,71,131,62,117,184,131,62,251,41,132,62,162,155,132,62,107,13,133,62,84,127,133,62,93,241,133,62,136,99,134,62,210,213,134,62,61,72,135,62,200,186,135,62,116,45,136,62,63,160,136,62,42,19,137,62,52,134,137,62,94,249,137,62,168,108,138,62,17,224,138,62,153,83,139,62,64,199,139,62,6,59,140,62,235,174,140,62,239,34,141,62,17,151,141,62,82,11,142,62,177,127,142,62,46,244,142,62,201,104,143,62,130,221,143,62,89,82,144,62,78,199,144,62,96,60,145,62,143,177,145,62,220,38,146,62,70,156,146,62,205,17,147,62,113,135,147,62,50,253,147,62,16,115,148,62,9,233,148,62,32,95,149,62,82,213,149,62,161,75,150,62,12,194,150,62,146,56,151,62,53,175,151,62,243,37,152,62,204,156,152,62,193,19,153,62,209,138,153,62,252,1,154,62,66,121,154,62,163,240,154,62,31,104,155,62,181,223,155,62,101,87,156,62,48,207,156,62,21,71,157,62,20,191,157,62,45,55,158,62,96,175,158,62,172,39,159,62,18,160,159,62,145,24,160,62,41,145,160,62,218,9,161,62,165,130,161,62,136,251,161,62,132,116,162,62,152,237,162,62,197,102,163,62,10,224,163,62,103,89,164,62,220,210,164,62,105,76,165,62,14,198,165,62,202,63,166,62,158,185,166,62,137,51,167,62,139,173,167,62,164,39,168,62,213,161,168,62,27,28,169,62,121,150,169,62,237,16,170,62,119,139,170,62,24,6,171,62,206,128,171,62,155,251,171,62,125,118,172,62,117,241,172,62,130,108,173,62,165,231,173,62,221,98,174,62,42,222,174,62,140,89,175,62,2,213,175,62,142,80,176,62,46,204,176,62,226,71,177,62,170,195,177,62,135,63,178,62,119,187,178,62,124,55,179,62,148,179,179,62,191,47,180,62,254,171,180,62,80,40,181,62,181,164,181,62,45,33,182,62,184,157,182,62,85,26,183,62,5,151,183,62,199,19,184,62,156,144,184,62,130,13,185,62,123,138,185,62,133,7,186,62,161,132,186,62,206,1,187,62,13,127,187,62,93,252,187,62,190,121,188,62,48,247,188,62,178,116,189,62,70,242,189,62,233,111,190,62,157,237,190,62,98,107,191,62,54,233,191,62,26,103,192,62,14,229,192,62,17,99,193,62,36,225,193,62,70,95,194,62,119,221,194,62,184,91,195,62,7,218,195,62,100,88,196,62,209,214,196,62,75,85,197,62,212,211,197,62,107,82,198,62,16,209,198,62,195,79,199,62,132,206,199,62,82,77,200,62,45,204,200,62,21,75,201,62,11,202,201,62,13,73,202,62,29,200,202,62,56,71,203,62,97,198,203,62,149,69,204,62,214,196,204,62,34,68,205,62,123,195,205,62,223,66,206,62,79,194,206,62,202,65,207,62,81,193,207,62,226,64,208,62,127,192,208,62,38,64,209,62,216,191,209,62,148,63,210,62,91,191,210,62,44,63,211,62,7,191,211,62,235,62,212,62,218,190,212,62,210,62,213,62,211,190,213,62,222,62,214,62,242,190,214,62,15,63,215,62,53,191,215,62,99,63,216,62,154,191,216,62,217,63,217,62,32,192,217,62,112,64,218,62,199,192,218,62,38,65,219,62,140,193,219,62,250,65,220,62,112,194,220,62,236,66,221,62,112,195,221,62,250,67,222,62,139,196,222,62,34,69,223,62,192,197,223,62,100,70,224,62,14,199,224,62,189,71,225,62,115,200,225,62,46,73,226,62,239,201,226,62,181,74,227,62,127,203,227,62,79,76,228,62,36,205,228,62,253,77,229,62,219,206,229,62,190,79,230,62,164,208,230,62,142,81,231,62,125,210,231,62,111,83,232,62,100,212,232,62,93,85,233,62,89,214,233,62,89,87,234,62,91,216,234,62,96,89,235,62,104,218,235,62,114,91,236,62,126,220,236,62,141,93,237,62,158,222,237,62,176,95,238,62,196,224,238,62,218,97,239,62,241,226,239,62,10,100,240,62,35,229,240,62,62,102,241,62,89,231,241,62,116,104,242,62,145,233,242,62,173,106,243,62,202,235,243,62,230,108,244,62,3,238,244,62,31,111,245,62,59,240,245,62,86,113,246,62,112,242,246,62,137,115,247,62,161,244,247,62,184,117,248,62,206,246,248,62,226,119,249,62,244,248,249,62,4,122,250,62,18,251,250,62,30,124,251,62,40,253,251,62,47,126,252,62,52,255,252,62,54,128,253,62,52,1,254,62,48,130,254,62,40,3,255,62,29,132,255,62,135,2,0,63,254,66,0,63,115,131,0,63,230,195,0,63,86,4,1,63,197,68,1,63,49,133,1,63,155,197,1,63,3,6,2,63,103,70,2,63,202,134,2,63,42,199,2,63,135,7,3,63,225,71,3,63,56,136,3,63,141,200,3,63,222,8,4,63,44,73,4,63,119,137,4,63,191,201,4,63,3,10,5,63,68,74,5,63,130,138,5,63,188,202,5,63,242,10,6,63,36,75,6,63,83,139,6,63,126,203,6,63,165,11,7,63,199,75,7,63,230,139,7,63,1,204,7,63,23,12,8,63,41,76,8,63,54,140,8,63,63,204,8,63,67,12,9,63,67,76,9,63,62,140,9,63,52,204,9,63,37,12,10,63,18,76,10,63,249,139,10,63,219,203,10,63,184,11,11,63,144,75,11,63,98,139,11,63,47,203,11,63,246,10,12,63,184,74,12,63,116,138,12,63,43,202,12,63,219,9,13,63,134,73,13,63,43,137,13,63,202,200,13,63,98,8,14,63,245,71,14,63,129,135,14,63,7,199,14,63,135,6,15,63,0,70,15,63,114,133,15,63,222,196,15,63,67,4,16,63,161,67,16,63,249,130,16,63,73,194,16,63,147,1,17,63,213,64,17,63,17,128,17,63,69,191,17,63,114,254,17,63,151,61,18,63,181,124,18,63,203,187,18,63,218,250,18,63,225,57,19,63,225,120,19,63,216,183,19,63,200,246,19,63,176,53,20,63,143,116,20,63,103,179,20,63,54,242,20,63,253,48,21,63,188,111,21,63,114,174,21,63,32,237,21,63,197,43,22,63,98,106,22,63,246,168,22,63,129,231,22,63,3,38,23,63,125,100,23,63,237,162,23,63,84,225,23,63,178,31,24,63,7,94,24,63,83,156,24,63,149,218,24,63,206,24,25,63,253,86,25,63,35,149,25,63,63,211,25,63,82,17,26,63,90,79,26,63,89,141,26,63,78,203,26,63,57,9,27,63,25,71,27,63,240,132,27,63,188,194,27,63,126,0,28,63,54,62,28,63,227,123,28,63,134,185,28,63,30,247,28,63,172,52,29,63,47,114,29,63,167,175,29,63,20,237,29,63,118,42,30,63,206,103,30,63,26,165,30,63,91,226,30,63,145,31,31,63,188,92,31,63,219,153,31,63,239,214,31,63,247,19,32,63,244,80,32,63,230,141,32,63,203,202,32,63,165,7,33,63,115,68,33,63,53,129,33,63,235,189,33,63,150,250,33,63,52,55,34,63,198,115,34,63,75,176,34,63,197,236,34,63,50,41,35,63,146,101,35,63,230,161,35,63,46,222,35,63,105,26,36,63,151,86,36,63,185,146,36,63,205,206,36,63,213,10,37,63,208,70,37,63,190,130,37,63,158,190,37,63,114,250,37,63,56,54,38,63,241,113,38,63,157,173,38,63,59,233,38,63,204,36,39,63,79,96,39,63,197,155,39,63,45,215,39,63,135,18,40,63,211,77,40,63,18,137,40,63,66,196,40,63,101,255,40,63,121,58,41,63,128,117,41,63,120,176,41,63,98,235,41,63,62,38,42,63,11,97,42,63,202,155,42,63,122,214,42,63,28,17,43,63,175,75,43,63,52,134,43,63,170,192,43,63,16,251,43,63,105,53,44,63,178,111,44,63,236,169,44,63,23,228,44,63,51,30,45,63,64,88,45,63,61,146,45,63,43,204,45,63,10,6,46,63,218,63,46,63,154,121,46,63,74,179,46,63,235,236,46,63,124,38,47,63,254,95,47,63,112,153,47,63,210,210,47,63,36,12,48,63,102,69,48,63,152,126,48,63,186,183,48,63,204,240,48,63,205,41,49,63,191,98,49,63,160,155,49,63,113,212,49,63,49,13,50,63,225,69,50,63,128,126,50,63,15,183,50,63,141,239,50,63,251,39,51,63,87,96,51,63,163,152,51,63,222,208,51,63,8,9,52,63,34,65,52,63,42,121,52,63,33,177,52,63,7,233,52,63,219,32,53,63,159,88,53,63,81,144,53,63,242,199,53,63,129,255,53,63,255,54,54,63,108,110,54,63,198,165,54,63,16,221,54,63,71,20,55,63,109,75,55,63,129,130,55,63,131,185,55,63,116,240,55,63,82,39,56,63,30,94,56,63,217,148,56,63,129,203,56,63,23,2,57,63,155,56,57,63,13,111,57,63,108,165,57,63,185,219,57,63,244,17,58,63,28,72,58,63,50,126,58,63,53,180,58,63,38,234,58,63,4,32,59,63,207,85,59,63,135,139,59,63,45,193,59,63,192,246,59,63,64,44,60,63,173,97,60,63,7,151,60,63,78,204,60,63,130,1,61,63,163,54,61,63,177,107,61,63,171,160,61,63,146,213,61,63,102,10,62,63,39,63,62,63,212,115,62,63,110,168,62,63,244,220,62,63,103,17,63,63,198,69,63,63,17,122,63,63,73,174,63,63,109,226,63,63,126,22,64,63,122,74,64,63,99,126,64,63,56,178,64,63,248,229,64,63,165,25,65,63,62,77,65,63,195,128,65,63,52,180,65,63,144,231,65,63,216,26,66,63,13,78,66,63,44,129,66,63,56,180,66,63,47,231,66,63,18,26,67,63,224,76,67,63,154,127,67,63,64,178,67,63,208,228,67,63,77,23,68,63,180,73,68,63,7,124,68,63,69,174,68,63,111,224,68,63,131,18,69,63,131,68,69,63,110,118,69,63,68,168,69,63,5,218,69,63,177,11,70,63,72,61,70,63,202,110,70,63,55,160,70,63,143,209,70,63,210,2,71,63,255,51,71,63,23,101,71,63,26,150,71,63,8,199,71,63,224,247,71,63,163,40,72,63,81,89,72,63,233,137,72,63,107,186,72,63,216,234,72,63,48,27,73,63,114,75,73,63,158,123,73,63,181,171,73,63,181,219,73,63,161,11,74,63,118,59,74,63,54,107,74,63,224,154,74,63,116,202,74,63,242,249,74,63,90,41,75,63,173,88,75,63,233,135,75,63,15,183,75,63,32,230,75,63,26,21,76,63,254,67,76,63,204,114,76,63,132,161,76,63,38,208,76,63,177,254,76,63,38,45,77,63,133,91,77,63,206,137,77,63,0,184,77,63,28,230,77,63,34,20,78,63,17,66,78,63,234,111,78,63,172,157,78,63,88,203,78,63,238,248,78,63,108,38,79,63,213,83,79,63,38,129,79,63,97,174,79,63,134,219,79,63,147,8,80,63,138,53,80,63,107,98,80,63,52,143,80,63,231,187,80,63,131,232,80,63,8,21,81,63,119,65,81,63,206,109,81,63,15,154,81,63,57,198,81,63,76,242,81,63,71,30,82,63,44,74,82,63,250,117,82,63,177,161,82,63,81,205,82,63,218,248,82,63,76,36,83,63,166,79,83,63,234,122,83,63,22,166,83,63,44,209,83,63,42,252,83,63,17,39,84,63,224,81,84,63,153,124,84,63,58,167,84,63,196,209,84,63,54,252,84,63,146,38,85,63,214,80,85,63,2,123,85,63,24,165,85,63,22,207,85,63,252,248,85,63,204,34,86,63,131,76,86,63,36,118,86,63,172,159,86,63,30,201,86,63,120,242,86,63,186,27,87,63,229,68,87,63,248,109,87,63,244,150,87,63,216,191,87,63,165,232,87,63,90,17,88,63,248,57,88,63,126,98,88,63,236,138,88,63,67,179,88,63,130,219,88,63,169,3,89,63,185,43,89,63,177,83,89,63,145,123,89,63,90,163,89,63,11,203,89,63,164,242,89,63,37,26,90,63,143,65,90,63,225,104,90,63,27,144,90,63,62,183,90,63,72,222,90,63,59,5,91,63,22,44,91,63,217,82,91,63,133,121,91,63,24,160,91,63,148,198,91,63,248,236,91,63,68,19,92,63,120,57,92,63,149,95,92,63,153,133,92,63,134,171,92,63,91,209,92,63,24,247,92,63,189,28,93,63,74,66,93,63,191,103,93,63,28,141,93,63,98,178,93,63,143,215,93,63,165,252,93,63,162,33,94,63,136,70,94,63,86,107,94,63,11,144,94,63,169,180,94,63,47,217,94,63,157,253,94,63,243,33,95,63,49,70,95,63,88,106,95,63,102,142,95,63,92,178,95,63,59,214,95,63,1,250,95,63,175,29,96,63,70,65,96,63,196,100,96,63,43,136,96,63,122,171,96,63,176,206,96,63,207,241,96,63,214,20,97,63,197,55,97,63,155,90,97,63,90,125,97,63,1,160,97,63,144,194,97,63,8,229,97,63,103,7,98,63,174,41,98,63,221,75,98,63,245,109,98,63,244,143,98,63,220,177,98,63,171,211,98,63,99,245,98,63,3,23,99,63,139,56,99,63,251,89,99,63,83,123,99,63,147,156,99,63,188,189,99,63,204,222,99,63,197,255,99,63,166,32,100,63,110,65,100,63,32,98,100,63,185,130,100,63,58,163,100,63,164,195,100,63,245,227,100,63,47,4,101,63,82,36,101,63,92,68,101,63,78,100,101,63,41,132,101,63,236,163,101,63,151,195,101,63,43,227,101,63,167,2,102,63,11,34,102,63,87,65,102,63,139,96,102,63,168,127,102,63,174,158,102,63,155,189,102,63,113,220,102,63,47,251,102,63,214,25,103,63,101,56,103,63,220,86,103,63,59,117,103,63,132,147,103,63,180,177,103,63,205,207,103,63,206,237,103,63,184,11,104,63,138,41,104,63,69,71,104,63,233,100,104,63,116,130,104,63,233,159,104,63,69,189,104,63,139,218,104,63,185,247,104,63,207,20,105,63,207,49,105,63,182,78,105,63,135,107,105,63,64,136,105,63,225,164,105,63,108,193,105,63,223,221,105,63,59,250,105,63,127,22,106,63,172,50,106,63,195,78,106,63,193,106,106,63,169,134,106,63,121,162,106,63,51,190,106,63,213,217,106,63,96,245,106,63,212,16,107,63,48,44,107,63,118,71,107,63,165,98,107,63,188,125,107,63,189,152,107,63,167,179,107,63,121,206,107,63,53,233,107,63,218,3,108,63,104,30,108,63,223,56,108,63,63,83,108,63,136,109,108,63,187,135,108,63,214,161,108,63,219,187,108,63,201,213,108,63,161,239,108,63,97,9,109,63,11,35,109,63,159,60,109,63,27,86,109,63,129,111,109,63,209,136,109,63,9,162,109,63,44,187,109,63,56,212,109,63,45,237,109,63,12,6,110,63,212,30,110,63,134,55,110,63,33,80,110,63,166,104,110,63,21,129,110,63,110,153,110,63,176,177,110,63,220,201,110,63,241,225,110,63,241,249,110,63,218,17,111,63,173,41,111,63,106,65,111,63,16,89,111,63,161,112,111,63,28,136,111,63,128,159,111,63,207,182,111,63,7,206,111,63,42,229,111,63,54,252,111,63,45,19,112,63,14,42,112,63,217,64,112,63,142,87,112,63,46,110,112,63,184,132,112,63,43,155,112,63,138,177,112,63,210,199,112,63,5,222,112,63,35,244,112,63,42,10,113,63,29,32,113,63,249,53,113,63,193,75,113,63,114,97,113,63,15,119,113,63,150,140,113,63,7,162,113,63,99,183,113,63,170,204,113,63,220,225,113,63,249,246,113,63,0,12,114,63,242,32,114,63,207,53,114,63,151,74,114,63,73,95,114,63,231,115,114,63,112,136,114,63,227,156,114,63,66,177,114,63,140,197,114,63,193,217,114,63,225,237,114,63,236,1,115,63,227,21,115,63,197,41,115,63,146,61,115,63,74,81,115,63,238,100,115,63,125,120,115,63,248,139,115,63,94,159,115,63,175,178,115,63,236,197,115,63,21,217,115,63,41,236,115,63,41,255,115,63,21,18,116,63,236,36,116,63,175,55,116,63,94,74,116,63,248,92,116,63,127,111,116,63,241,129,116,63,80,148,116,63,154,166,116,63,208,184,116,63,242,202,116,63,1,221,116,63,251,238,116,63,226,0,117,63,181,18,117,63,116,36,117,63,31,54,117,63,183,71,117,63,59,89,117,63,171,106,117,63,8,124,117,63,81,141,117,63,135,158,117,63,169,175,117,63,184,192,117,63,179,209,117,63,155,226,117,63,112,243,117,63,50,4,118,63,224,20,118,63,123,37,118,63,3,54,118,63,120,70,118,63,217,86,118,63,40,103,118,63,100,119,118,63,140,135,118,63,162,151,118,63,165,167,118,63,149,183,118,63,114,199,118,63,61,215,118,63,245,230,118,63,154,246,118,63,44,6,119,63,172,21,119,63,26,37,119,63,117,52,119,63,189,67,119,63,243,82,119,63,22,98,119,63,40,113,119,63,39,128,119,63,19,143,119,63,238,157,119,63,182,172,119,63,108,187,119,63,16,202,119,63,162,216,119,63,34,231,119,63,144,245,119,63,236,3,120,63,55,18,120,63,111,32,120,63,150,46,120,63,170,60,120,63,174,74,120,63,159,88,120,63,127,102,120,63,77,116,120,63,10,130,120,63,181,143,120,63,79,157,120,63,215,170,120,63,78,184,120,63,180,197,120,63,8,211,120,63,76,224,120,63,126,237,120,63,158,250,120,63,174,7,121,63,173,20,121,63,155,33,121,63,119,46,121,63,67,59,121,63,254,71,121,63,168,84,121,63,66,97,121,63,202,109,121,63,66,122,121,63,169,134,121,63,0,147,121,63,70,159,121,63,124,171,121,63,161,183,121,63,181,195,121,63,186,207,121,63,173,219,121,63,145,231,121,63,100,243,121,63,40,255,121,63,219,10,122,63,126,22,122,63,16,34,122,63,147,45,122,63,6,57,122,63,105,68,122,63,188,79,122,63,255,90,122,63,51,102,122,63,86,113,122,63,106,124,122,63,111,135,122,63,99,146,122,63,72,157,122,63,30,168,122,63,228,178,122,63,155,189,122,63,66,200,122,63,218,210,122,63,99,221,122,63,221,231,122,63,71,242,122,63,162,252,122,63,238,6,123,63,43,17,123,63,89,27,123,63,120,37,123,63,137,47,123,63,138,57,123,63,124,67,123,63,96,77,123,63,53,87,123,63,252,96,123,63,179,106,123,63,92,116,123,63,247,125,123,63,131,135,123,63,1,145,123,63,112,154,123,63,209,163,123,63,36,173,123,63,104,182,123,63,158,191,123,63,198,200,123,63,224,209,123,63,236,218,123,63,234,227,123,63,218,236,123,63,188,245,123,63,144,254,123,63,86,7,124,63,14,16,124,63,185,24,124,63,86,33,124,63,230,41,124,63,104,50,124,63,220,58,124,63,67,67,124,63,156,75,124,63,232,83,124,63,39,92,124,63,88,100,124,63,124,108,124,63,147,116,124,63,157,124,124,63,153,132,124,63,137,140,124,63,107,148,124,63,65,156,124,63,9,164,124,63,197,171,124,63,116,179,124,63,22,187,124,63,172,194,124,63,52,202,124,63,176,209,124,63,32,217,124,63,131,224,124,63,217,231,124,63,35,239,124,63,97,246,124,63,146,253,124,63,183,4,125,63,208,11,125,63,221,18,125,63,221,25,125,63,209,32,125,63,185,39,125,63,150,46,125,63,102,53,125,63,42,60,125,63,227,66,125,63,143,73,125,63,48,80,125,63,197,86,125,63,78,93,125,63,204,99,125,63,62,106,125,63,165,112,125,63,0,119,125,63,80,125,125,63,148,131,125,63,205,137,125,63,251,143,125,63,29,150,125,63,52,156,125,63,64,162,125,63,65,168,125,63,55,174,125,63,34,180,125,63,2,186,125,63,215,191,125,63,161,197,125,63,96,203,125,63,21,209,125,63,190,214,125,63,93,220,125,63,242,225,125,63,124,231,125,63,251,236,125,63,112,242,125,63,218,247,125,63,58,253,125,63,143,2,126,63,219,7,126,63,28,13,126,63,82,18,126,63,127,23,126,63,161,28,126,63,186,33,126,63,200,38,126,63,204,43,126,63,199,48,126,63,183,53,126,63,158,58,126,63,123,63,126,63,78,68,126,63,23,73,126,63,215,77,126,63,141,82,126,63,58,87,126,63,221,91,126,63,118,96,126,63,6,101,126,63,141,105,126,63,10,110,126,63,126,114,126,63,233,118,126,63,75,123,126,63,164,127,126,63,243,131,126,63,57,136,126,63,119,140,126,63,171,144,126,63,214,148,126,63,249,152,126,63,18,157,126,63,35,161,126,63,44,165,126,63,43,169,126,63,34,173,126,63,16,177,126,63,246,180,126,63,211,184,126,63,167,188,126,63,115,192,126,63,55,196,126,63,243,199,126,63,166,203,126,63,81,207,126,63,243,210,126,63,142,214,126,63,32,218,126,63,171,221,126,63,45,225,126,63,167,228,126,63,26,232,126,63,132,235,126,63,231,238,126,63,66,242,126,63,149,245,126,63,224,248,126,63,36,252,126,63,96,255,126,63,148,2,127,63,193,5,127,63,230,8,127,63,4,12,127,63,27,15,127,63,42,18,127,63,50,21,127,63,50,24,127,63,43,27,127,63,29,30,127,63,8,33,127,63,236,35,127,63,201,38,127,63,158,41,127,63,109,44,127,63,53,47,127,63,246,49,127,63,175,52,127,63,99,55,127,63,15,58,127,63,181,60,127,63,83,63,127,63,236,65,127,63,125,68,127,63,8,71,127,63,141,73,127,63,11,76,127,63,131,78,127,63,244,80,127,63,95,83,127,63,195,85,127,63,33,88,127,63,121,90,127,63,203,92,127,63,23,95,127,63,92,97,127,63,155,99,127,63,213,101,127,63,8,104,127,63,54,106,127,63,93,108,127,63,127,110,127,63,155,112,127,63,177,114,127,63,193,116,127,63,203,118,127,63,208,120,127,63,207,122,127,63,201,124,127,63,189,126,127,63,171,128,127,63,148,130,127,63,120,132,127,63,86,134,127,63,47,136,127,63,2,138,127,63,209,139,127,63,153,141,127,63,93,143,127,63,28,145,127,63,213,146,127,63,137,148,127,63,57,150,127,63,227,151,127,63,136,153,127,63,40,155,127,63,196,156,127,63,90,158,127,63,236,159,127,63,121,161,127,63,1,163,127,63,132,164,127,63,3,166,127,63,125,167,127,63,242,168,127,63,99,170,127,63,207,171,127,63,55,173,127,63,154,174,127,63,249,175,127,63,84,177,127,63,170,178,127,63,251,179,127,63,73,181,127,63,146,182,127,63,215,183,127,63,24,185,127,63,85,186,127,63,141,187,127,63,193,188,127,63,242,189,127,63,30,191,127,63,71,192,127,63,107,193,127,63,140,194,127,63,168,195,127,63,193,196,127,63,214,197,127,63,231,198,127,63,245,199,127,63,255,200,127,63,5,202,127,63,7,203,127,63,6,204,127,63,1,205,127,63,249,205,127,63,237,206,127,63,222,207,127,63,203,208,127,63,181,209,127,63,156,210,127,63,127,211,127,63,95,212,127,63,59,213,127,63,20,214,127,63,234,214,127,63,189,215,127,63,141,216,127,63,90,217,127,63,35,218,127,63,233,218,127,63,173,219,127,63,109,220,127,63,43,221,127,63,229,221,127,63,156,222,127,63,81,223,127,63,3,224,127,63,178,224,127,63,94,225,127,63,7,226,127,63,174,226,127,63,82,227,127,63,243,227,127,63,146,228,127,63,46,229,127,63,199,229,127,63,94,230,127,63,242,230,127,63,132,231,127,63,19,232,127,63,160,232,127,63,42,233,127,63,178,233,127,63,56,234,127,63,187,234,127,63,60,235,127,63,187,235,127,63,55,236,127,63,177,236,127,63,41,237,127,63,159,237,127,63,18,238,127,63,132,238,127,63,243,238,127,63,96,239,127,63,204,239,127,63,53,240,127,63,156,240,127,63,1,241,127,63,101,241,127,63,198,241,127,63,37,242,127,63,131,242,127,63,222,242,127,63,56,243,127,63,144,243,127,63,231,243,127,63,59,244,127,63,142,244,127,63,223,244,127,63,46,245,127,63,124,245,127,63,200,245,127,63,19,246,127,63,91,246,127,63,163,246,127,63,233,246,127,63,45,247,127,63,111,247,127,63,177,247,127,63,240,247,127,63,47,248,127,63,108,248,127,63,167,248,127,63,225,248,127,63,26,249,127,63,82,249,127,63,136,249,127,63,188,249,127,63,240,249,127,63,34,250,127,63,83,250,127,63,131,250,127,63,178,250,127,63,224,250,127,63,12,251,127,63,55,251,127,63,97,251,127,63,138,251,127,63,178,251,127,63,217,251,127,63,255,251,127,63,36,252,127,63,72,252,127,63,107,252,127,63,141,252,127,63,173,252,127,63,205,252,127,63,237,252,127,63,11,253,127,63,40,253,127,63,69,253,127,63,96,253,127,63,123,253,127,63,149,253,127,63,174,253,127,63,199,253,127,63,222,253,127,63,245,253,127,63,12,254,127,63,33,254,127,63,54,254,127,63,74,254,127,63,93,254,127,63,112,254,127,63,130,254,127,63,148,254,127,63,165,254,127,63,181,254,127,63,197,254,127,63,212,254,127,63,227,254,127,63,241,254,127,63,254,254,127,63,11,255,127,63,24,255,127,63,36,255,127,63,47,255,127,63,59,255,127,63,69,255,127,63,79,255,127,63,89,255,127,63,99,255,127,63,108,255,127,63,116,255,127,63,124,255,127,63,132,255,127,63,140,255,127,63,147,255,127,63,154,255,127,63,160,255,127,63,166,255,127,63,172,255,127,63,178,255,127,63,183,255,127,63,188,255,127,63,193,255,127,63,197,255,127,63,202,255,127,63,206,255,127,63,209,255,127,63,213,255,127,63,216,255,127,63,220,255,127,63,223,255,127,63,225,255,127,63,228,255,127,63,230,255,127,63,233,255,127,63,235,255,127,63,237,255,127,63,239,255,127,63,240,255,127,63,242,255,127,63,243,255,127,63,245,255,127,63,246,255,127,63,247,255,127,63,248,255,127,63,249,255,127,63,250,255,127,63,251,255,127,63,251,255,127,63,252,255,127,63,252,255,127,63,253,255,127,63,253,255,127,63,254,255,127,63,254,255,127,63,254,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,198,63,120,51,98,136,11,53,151,200,193,53,80,233,61,54,183,247,156,54,46,124,234,54,153,192,35,55,244,2,90,55,56,3,140,55,227,228,174,55,177,166,213,55,108,36,0,56,146,101,23,56,201,150,48,56,18,184,75,56,81,201,104,56,94,229,131,56,29,94,148,56,229,206,165,56,167,55,184,56,128,152,203,56,85,241,223,56,36,66,245,56,126,197,5,57,238,101,17,57,99,130,29,57,207,26,42,57,63,47,55,57,179,191,68,57,30,204,82,57,141,84,97,57,243,88,112,57,94,217,127,57,227,234,135,57,18,39,144,57,64,161,152,57,105,89,161,57,146,79,170,57,181,131,179,57,215,245,188,57,245,165,198,57,14,148,208,57,34,192,218,57,46,42,229,57,57,210,239,57,60,184,250,57,27,238,2,58,22,159,8,58,13,111,14,58,0,94,20,58,239,107,26,58,218,152,32,58,192,228,38,58,161,79,45,58,124,217,51,58,83,130,58,58,37,74,65,58,240,48,72,58,182,54,79,58,116,91,86,58,45,159,93,58,222,1,101,58,136,131,108,58,42,36,116,58,196,227,123,58,44,225,129,58,241,223,133,58,49,238,137,58,238,11,142,58,37,57,146,58,215,117,150,58,5,194,154,58,174,29,159,58,209,136,163,58,110,3,168,58,134,141,172,58,24,39,177,58,36,208,181,58,169,136,186,58,169,80,191,58,33,40,196,58,19,15,201,58,126,5,206,58,98,11,211,58,191,32,216,58,148,69,221,58,225,121,226,58,166,189,231,58,227,16,237,58,152,115,242,58,196,229,247,58,103,103,253,58,65,124,1,59,137,76,4,59,141,36,7,59,76,4,10,59,198,235,12,59,251,218,15,59,235,209,18,59,149,208,21,59,251,214,24,59,26,229,27,59,244,250,30,59,136,24,34,59,215,61,37,59,223,106,40,59,161,159,43,59,29,220,46,59,83,32,50,59,66,108,53,59,234,191,56,59,76,27,60,59,103,126,63,59,59,233,66,59,199,91,70,59,12,214,73,59,10,88,77,59,193,225,80,59,48,115,84,59,86,12,88,59,53,173,91,59,204,85,95,59,26,6,99,59,32,190,102,59,222,125,106,59,82,69,110,59,127,20,114,59,97,235,117,59,251,201,121,59,76,176,125,59,41,207,128,59,8,202,130,59,194,200,132,59,87,203,134,59,198,209,136,59,17,220,138,59,55,234,140,59,55,252,142,59,18,18,145,59,199,43,147,59,87,73,149,59,194,106,151,59,6,144,153,59,37,185,155,59,30,230,157,59,241,22,160,59,158,75,162,59,37,132,164,59,134,192,166,59,192,0,169,59,212,68,171,59,193,140,173,59,137,216,175,59,41,40,178,59,163,123,180,59,245,210,182,59,33,46,185,59,38,141,187,59,4,240,189,59,186,86,192,59,73,193,194,59,177,47,197,59,242,161,199,59,10,24,202,59,251,145,204,59,196,15,207,59,102,145,209,59,223,22,212,59,49,160,214,59,90,45,217,59,91,190,219,59,51,83,222,59,227,235,224,59,107,136,227,59,201,40,230,59,255,204,232,59,12,117,235,59,240,32,238,59,171,208,240,59,61,132,243,59,165,59,246,59,228,246,248,59,250,181,251,59,229,120,254,59,212,159,0,60,32,5,2,60,87,108,3,60,121,213,4,60,134,64,6,60,126,173,7,60,96,28,9,60,45,141,10,60,229,255,11,60,136,116,13,60,21,235,14,60,141,99,16,60,239,221,17,60,59,90,19,60,114,216,20,60,147,88,22,60,158,218,23,60,147,94,25,60,115,228,26,60,60,108,28,60,240,245,29,60,141,129,31,60,20,15,33,60,133,158,34,60,224,47,36,60,36,195,37,60,82,88,39,60,105,239,40,60,106,136,42,60,84,35,44,60,40,192,45,60,229,94,47,60,139,255,48,60,26,162,50,60,146,70,52,60,243,236,53,60,61,149,55,60,112,63,57,60,140,235,58,60,145,153,60,60,126,73,62,60,84,251,63,60,18,175,65,60,185,100,67,60,72,28,69,60,192,213,70,60,31,145,72,60,103,78,74,60,151,13,76,60,175,206,77,60,176,145,79,60,152,86,81,60,103,29,83,60,31,230,84,60,190,176,86,60,69,125,88,60,179,75,90,60,9,28,92,60,71,238,93,60,107,194,95,60,119,152,97,60,106,112,99,60,68,74,101,60,5,38,103,60,173,3,105,60,60,227,106,60,178,196,108,60,14,168,110,60,81,141,112,60,123,116,114,60,139,93,116,60,130,72,118,60,95,53,120,60,34,36,122,60,203,20,124,60,90,7,126,60,208,251,127,60,22,249,128,60,54,245,129,60,74,242,130,60,80,240,131,60,73,239,132,60,53,239,133,60,19,240,134,60,229,241,135,60,169,244,136,60,95,248,137,60,8,253,138,60,164,2,140,60,50,9,141,60,178,16,142,60,37,25,143,60,139,34,144,60,226,44,145,60,44,56,146,60,104,68,147,60,150,81,148,60,182,95,149,60,201,110,150,60,205,126,151,60,196,143,152,60,172,161,153,60,135,180,154,60,83,200,155,60,17,221,156,60,193,242,157,60,98,9,159,60,245,32,160,60,122,57,161,60,241,82,162,60,89,109,163,60,178,136,164,60,253,164,165,60,57,194,166,60,103,224,167,60,134,255,168,60,151,31,170,60,152,64,171,60,139,98,172,60,111,133,173,60,68,169,174,60,10,206,175,60,193,243,176,60,105,26,178,60,2,66,179,60,139,106,180,60,6,148,181,60,113,190,182,60,205,233,183,60,26,22,185,60,87,67,186,60,133,113,187,60,163,160,188,60,177,208,189,60,177,1,191,60,160,51,192,60,128,102,193,60,80,154,194,60,16,207,195,60,193,4,197,60,97,59,198,60,242,114,199,60,114,171,200,60,227,228,201,60,67,31,203,60,147,90,204,60,211,150,205,60,3,212,206,60,34,18,208,60,49,81,209,60,48,145,210,60,30,210,211,60,252,19,213,60,201,86,214,60,133,154,215,60,49,223,216,60,204,36,218,60,86,107,219,60,208,178,220,60,56,251,221,60,144,68,223,60,214,142,224,60,12,218,225,60,48,38,227,60,67,115,228,60,69,193,229,60,54,16,231,60,21,96,232,60,227,176,233,60,160,2,235,60,75,85,236,60,228,168,237,60,108,253,238,60,226,82,240,60,70,169,241,60,153,0,243,60,218,88,244,60,8,178,245,60,37,12,247,60,48,103,248,60,41,195,249,60,15,32,251,60,228,125,252,60,166,220,253,60,85,60,255,60,121,78,0,61,63,255,0,61,123,176,1,61,46,98,2,61,88,20,3,61,248,198,3,61,15,122,4,61,156,45,5,61,161,225,5,61,27,150,6,61,12,75,7,61,116,0,8,61,82,182,8,61,167,108,9,61,113,35,10,61,179,218,10,61,106,146,11,61,152,74,12,61,60,3,13,61,87,188,13,61,231,117,14,61,238,47,15,61,107,234,15,61,94,165,16,61,199,96,17,61,166,28,18,61,251,216,18,61,198,149,19,61,7,83,20,61,190,16,21,61,234,206,21,61,141,141,22,61,165,76,23,61,52,12,24,61,56,204,24,61,177,140,25,61,161,77,26,61,6,15,27,61,224,208,27,61,48,147,28,61,246,85,29,61,49,25,30,61,226,220,30,61,8,161,31,61,164,101,32,61,181,42,33,61,59,240,33,61,55,182,34,61,168,124,35,61,142,67,36,61,233,10,37,61,186,210,37,61,255,154,38,61,186,99,39,61,234,44,40,61,143,246,40,61,168,192,41,61,55,139,42,61,59,86,43,61,180,33,44,61,161,237,44,61,4,186,45,61,219,134,46,61,38,84,47,61,231,33,48,61,28,240,48,61,198,190,49,61,229,141,50,61,120,93,51,61,127,45,52,61,251,253,52,61,236,206,53,61,81,160,54,61,42,114,55,61,120,68,56,61,58,23,57,61,112,234,57,61,27,190,58,61,58,146,59,61,204,102,60,61,211,59,61,61,79,17,62,61,62,231,62,61,161,189,63,61,120,148,64,61,195,107,65,61,130,67,66,61,181,27,67,61,92,244,67,61,118,205,68,61,4,167,69,61,6,129,70,61,124,91,71,61,101,54,72,61,194,17,73,61,146,237,73,61,214,201,74,61,141,166,75,61,184,131,76,61,86,97,77,61,104,63,78,61,236,29,79,61,229,252,79,61,80,220,80,61,46,188,81,61,128,156,82,61,69,125,83,61,125,94,84,61,40,64,85,61,69,34,86,61,214,4,87,61,218,231,87,61,81,203,88,61,58,175,89,61,150,147,90,61,101,120,91,61,167,93,92,61,91,67,93,61,130,41,94,61,28,16,95,61,40,247,95,61,167,222,96,61,152,198,97,61,251,174,98,61,209,151,99,61,25,129,100,61,212,106,101,61,0,85,102,61,159,63,103,61,176,42,104,61,51,22,105,61,41,2,106,61,144,238,106,61,105,219,107,61,180,200,108,61,113,182,109,61,160,164,110,61,65,147,111,61,84,130,112,61,216,113,113,61,206,97,114,61,54,82,115,61,15,67,116,61,89,52,117,61,22,38,118,61,67,24,119,61,226,10,120,61,243,253,120,61,117,241,121,61,104,229,122,61,204,217,123,61,162,206,124,61,232,195,125,61,160,185,126,61,201,175,127,61,49,83,128,61,183,206,128,61,117,74,129,61,107,198,129,61,154,66,130,61,1,191,130,61,160,59,131,61,120,184,131,61,136,53,132,61,209,178,132,61,81,48,133,61,10,174,133,61,251,43,134,61,37,170,134,61,134,40,135,61,32,167,135,61,242,37,136,61,252,164,136,61,62,36,137,61,184,163,137,61,106,35,138,61,84,163,138,61,118,35,139,61,209,163,139,61,99,36,140,61,45,165,140,61,46,38,141,61,104,167,141,61,218,40,142,61,131,170,142,61,100,44,143,61,125,174,143,61,206,48,144,61,86,179,144,61,23,54,145,61,14,185,145,61,62,60,146,61,165,191,146,61,67,67,147,61,26,199,147,61,39,75,148,61,109,207,148,61,234,83,149,61,158,216,149,61,138,93,150,61,173,226,150,61,7,104,151,61,153,237,151,61,98,115,152,61,99,249,152,61,155,127,153,61,10,6,154,61,176,140,154,61,142,19,155,61,163,154,155,61,239,33,156,61,114,169,156,61,44,49,157,61,29,185,157,61,69,65,158,61,165,201,158,61,59,82,159,61,8,219,159,61,13,100,160,61,72,237,160,61,186,118,161,61,99,0,162,61,67,138,162,61,90,20,163,61,167,158,163,61,43,41,164,61,230,179,164,61,216,62,165,61,0,202,165,61,95,85,166,61,245,224,166,61,193,108,167,61,196,248,167,61,254,132,168,61,110,17,169,61,20,158,169,61,241,42,170,61,4,184,170,61,78,69,171,61,206,210,171,61,133,96,172,61,113,238,172,61,149,124,173,61,238,10,174,61,126,153,174,61,67,40,175,61,63,183,175,61,114,70,176,61,218,213,176,61,120,101,177,61,77,245,177,61,88,133,178,61,152,21,179,61,15,166,179,61,187,54,180,61,158,199,180,61,182,88,181,61,4,234,181,61,137,123,182,61,67,13,183,61,50,159,183,61,88,49,184,61,179,195,184,61,68,86,185,61,11,233,185,61,7,124,186,61,57,15,187,61,160,162,187,61,61,54,188,61,16,202,188,61,24,94,189,61,85,242,189,61,200,134,190,61,112,27,191,61,78,176,191,61,97,69,192,61,170,218,192,61,39,112,193,61,218,5,194,61,194,155,194,61,224,49,195,61,50,200,195,61,186,94,196,61,119,245,196,61,104,140,197,61,143,35,198,61,235,186,198,61,124,82,199,61,66,234,199,61,61,130,200,61,108,26,201,61,209,178,201,61,106,75,202,61,57,228,202,61,59,125,203,61,115,22,204,61,224,175,204,61,129,73,205,61,86,227,205,61,97,125,206,61,159,23,207,61,19,178,207,61,187,76,208,61,151,231,208,61,168,130,209,61,237,29,210,61,103,185,210,61,21,85,211,61,248,240,211,61,14,141,212,61,89,41,213,61,216,197,213,61,140,98,214,61,115,255,214,61,143,156,215,61,223,57,216,61,99,215,216,61,27,117,217,61,7,19,218,61,38,177,218,61,122,79,219,61,2,238,219,61,189,140,220,61,173,43,221,61,208,202,221,61,39,106,222,61,178,9,223,61,112,169,223,61,98,73,224,61,136,233,224,61,226,137,225,61,111,42,226,61,47,203,226,61,35,108,227,61,74,13,228,61,165,174,228,61,52,80,229,61,245,241,229,61,234,147,230,61,19,54,231,61,110,216,231,61,253,122,232,61,191,29,233,61,180,192,233,61,221,99,234,61,56,7,235,61,199,170,235,61,136,78,236,61,125,242,236,61,164,150,237,61,255,58,238,61,140,223,238,61,76,132,239,61,63,41,240,61,101,206,240,61,189,115,241,61,73,25,242,61,7,191,242,61,247,100,243,61,26,11,244,61,112,177,244,61,248,87,245,61,179,254,245,61,160,165,246,61,192,76,247,61,18,244,247,61,151,155,248,61,77,67,249,61,55,235,249,61,82,147,250,61,159,59,251,61,31,228,251,61,209,140,252,61,181,53,253,61,203,222,253,61,19,136,254,61,141,49,255,61,57,219,255,61,140,66,0,62,148,151,0,62,181,236,0,62,238,65,1,62,65,151,1,62,173,236,1,62,49,66,2,62,206,151,2,62,132,237,2,62,83,67,3,62,59,153,3,62,59,239,3,62,84,69,4,62,134,155,4,62,209,241,4,62,52,72,5,62,176,158,5,62,68,245,5,62,242,75,6,62,183,162,6,62,150,249,6,62,141,80,7,62,156,167,7,62,196,254,7,62,5,86,8,62,94,173,8,62,207,4,9,62,89,92,9,62,252,179,9,62,183,11,10,62,138,99,10,62,118,187,10,62,122,19,11,62,150,107,11,62,203,195,11,62,24,28,12,62,125,116,12,62,250,204,12,62,144,37,13,62,62,126,13,62,4,215,13,62,227,47,14,62,217,136,14,62,232,225,14,62,15,59,15,62,78,148,15,62,165,237,15,62,20,71,16,62,155,160,16,62,58,250,16,62,241,83,17,62,193,173,17,62,168,7,18,62,167,97,18,62,190,187,18,62,237,21,19,62,51,112,19,62,146,202,19,62,9,37,20,62,151,127,20,62,61,218,20,62,251,52,21,62,209,143,21,62,190,234,21,62,195,69,22,62,224,160,22,62,21,252,22,62,97,87,23,62,197,178,23,62,64,14,24,62,211,105,24,62,126,197,24,62,64,33,25,62,26,125,25,62,11,217,25,62,20,53,26,62,52,145,26,62,108,237,26,62,187,73,27,62,34,166,27,62,160,2,28,62,53,95,28,62,226,187,28,62],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE+10240);allocate([166,24,29,62,129,117,29,62,116,210,29,62,126,47,30,62,159,140,30,62,215,233,30,62,39,71,31,62,141,164,31,62,11,2,32,62,160,95,32,62,76,189,32,62,16,27,33,62,234,120,33,62,219,214,33,62,228,52,34,62,3,147,34,62,58,241,34,62,135,79,35,62,235,173,35,62,103,12,36,62,249,106,36,62,162,201,36,62,98,40,37,62,56,135,37,62,38,230,37,62,42,69,38,62,69,164,38,62,119,3,39,62,192,98,39,62,31,194,39,62,149,33,40,62,33,129,40,62,197,224,40,62,126,64,41,62,79,160,41,62,54,0,42,62,51,96,42,62,72,192,42,62,114,32,43,62,179,128,43,62,11,225,43,62,121,65,44,62,253,161,44,62,152,2,45,62,73,99,45,62,16,196,45,62,238,36,46,62,226,133,46,62,237,230,46,62,13,72,47,62,68,169,47,62,145,10,48,62,245,107,48,62,110,205,48,62,254,46,49,62,163,144,49,62,95,242,49,62,49,84,50,62,25,182,50,62,23,24,51,62,43,122,51,62,85,220,51,62,148,62,52,62,234,160,52,62,86,3,53,62,216,101,53,62,111,200,53,62,28,43,54,62,223,141,54,62,184,240,54,62,167,83,55,62,171,182,55,62,197,25,56,62,245,124,56,62,59,224,56,62,150,67,57,62,7,167,57,62,141,10,58,62,41,110,58,62,219,209,58,62,162,53,59,62,126,153,59,62,112,253,59,62,120,97,60,62,149,197,60,62,199,41,61,62,15,142,61,62,108,242,61,62,222,86,62,62,102,187,62,62,3,32,63,62,181,132,63,62,125,233,63,62,90,78,64,62,75,179,64,62,83,24,65,62,111,125,65,62,160,226,65,62,231,71,66,62,66,173,66,62,179,18,67,62,57,120,67,62,211,221,67,62,131,67,68,62,71,169,68,62,33,15,69,62,15,117,69,62,18,219,69,62,42,65,70,62,87,167,70,62,153,13,71,62,240,115,71,62,91,218,71,62,219,64,72,62,111,167,72,62,25,14,73,62,215,116,73,62,169,219,73,62,144,66,74,62,140,169,74,62,157,16,75,62,193,119,75,62,251,222,75,62,73,70,76,62,171,173,76,62,34,21,77,62,173,124,77,62,76,228,77,62,0,76,78,62,200,179,78,62,164,27,79,62,149,131,79,62,154,235,79,62,179,83,80,62,225,187,80,62,34,36,81,62,120,140,81,62,225,244,81,62,95,93,82,62,241,197,82,62,151,46,83,62,81,151,83,62,31,0,84,62,1,105,84,62,247,209,84,62,0,59,85,62,30,164,85,62,79,13,86,62,149,118,86,62,238,223,86,62,91,73,87,62,219,178,87,62,112,28,88,62,24,134,88,62,211,239,88,62,163,89,89,62,134,195,89,62,124,45,90,62,134,151,90,62,164,1,91,62,213,107,91,62,26,214,91,62,114,64,92,62,221,170,92,62,92,21,93,62,239,127,93,62,148,234,93,62,77,85,94,62,26,192,94,62,249,42,95,62,236,149,95,62,242,0,96,62,11,108,96,62,55,215,96,62,119,66,97,62,202,173,97,62,47,25,98,62,168,132,98,62,52,240,98,62,210,91,99,62,132,199,99,62,73,51,100,62,32,159,100,62,11,11,101,62,8,119,101,62,24,227,101,62,59,79,102,62,113,187,102,62,186,39,103,62,21,148,103,62,131,0,104,62,3,109,104,62,151,217,104,62,60,70,105,62,245,178,105,62,192,31,106,62,157,140,106,62,141,249,106,62,144,102,107,62,165,211,107,62,204,64,108,62,6,174,108,62,82,27,109,62,176,136,109,62,33,246,109,62,164,99,110,62,57,209,110,62,225,62,111,62,154,172,111,62,102,26,112,62,68,136,112,62,52,246,112,62,55,100,113,62,75,210,113,62,113,64,114,62,169,174,114,62,243,28,115,62,80,139,115,62,190,249,115,62,61,104,116,62,207,214,116,62,115,69,117,62,40,180,117,62,239,34,118,62,200,145,118,62,179,0,119,62,175,111,119,62,189,222,119,62,221,77,120,62,14,189,120,62,80,44,121,62,165,155,121,62,10,11,122,62,130,122,122,62,10,234,122,62,164,89,123,62,80,201,123,62,13,57,124,62,219,168,124,62,186,24,125,62,171,136,125,62,173,248,125,62,192,104,126,62,228,216,126,62,26,73,127,62,96,185,127,62,220,20,128,62,16,77,128,62,77,133,128,62,147,189,128,62,225,245,128,62,55,46,129,62,150,102,129,62,253,158,129,62,109,215,129,62,229,15,130,62,102,72,130,62,238,128,130,62,128,185,130,62,25,242,130,62,187,42,131,62,102,99,131,62,24,156,131,62,211,212,131,62,150,13,132,62,98,70,132,62,53,127,132,62,17,184,132,62,245,240,132,62,226,41,133,62,214,98,133,62,211,155,133,62,216,212,133,62,229,13,134,62,250,70,134,62,23,128,134,62,61,185,134,62,106,242,134,62,160,43,135,62,221,100,135,62,35,158,135,62,112,215,135,62,198,16,136,62,35,74,136,62,137,131,136,62,247,188,136,62,108,246,136,62,233,47,137,62,111,105,137,62,252,162,137,62,145,220,137,62,46,22,138,62,211,79,138,62,127,137,138,62,52,195,138,62,240,252,138,62,180,54,139,62,128,112,139,62,84,170,139,62,47,228,139,62,18,30,140,62,253,87,140,62,239,145,140,62,233,203,140,62,235,5,141,62,245,63,141,62,6,122,141,62,31,180,141,62,63,238,141,62,103,40,142,62,150,98,142,62,205,156,142,62,12,215,142,62,82,17,143,62,159,75,143,62,245,133,143,62,81,192,143,62,181,250,143,62,33,53,144,62,147,111,144,62,14,170,144,62,143,228,144,62,25,31,145,62,169,89,145,62,65,148,145,62,224,206,145,62,134,9,146,62,52,68,146,62,233,126,146,62,165,185,146,62,105,244,146,62,52,47,147,62,6,106,147,62,223,164,147,62,191,223,147,62,167,26,148,62,150,85,148,62,139,144,148,62,136,203,148,62,140,6,149,62,152,65,149,62,170,124,149,62,195,183,149,62,227,242,149,62,11,46,150,62,57,105,150,62,111,164,150,62,171,223,150,62,238,26,151,62,56,86,151,62,138,145,151,62,226,204,151,62,65,8,152,62,167,67,152,62,19,127,152,62,135,186,152,62,1,246,152,62,130,49,153,62,10,109,153,62,153,168,153,62,47,228,153,62,203,31,154,62,110,91,154,62,24,151,154,62,200,210,154,62,127,14,155,62,61,74,155,62,2,134,155,62,205,193,155,62,158,253,155,62,119,57,156,62,85,117,156,62,59,177,156,62,39,237,156,62,25,41,157,62,18,101,157,62,18,161,157,62,24,221,157,62,36,25,158,62,55,85,158,62,80,145,158,62,112,205,158,62,150,9,159,62,195,69,159,62,246,129,159,62,47,190,159,62,111,250,159,62,180,54,160,62,1,115,160,62,83,175,160,62,172,235,160,62,11,40,161,62,112,100,161,62,219,160,161,62,77,221,161,62,196,25,162,62,66,86,162,62,198,146,162,62,81,207,162,62,225,11,163,62,119,72,163,62,20,133,163,62,182,193,163,62,95,254,163,62,13,59,164,62,194,119,164,62,125,180,164,62,61,241,164,62,4,46,165,62,208,106,165,62,162,167,165,62,123,228,165,62,89,33,166,62,61,94,166,62,39,155,166,62,23,216,166,62,12,21,167,62,7,82,167,62,8,143,167,62,15,204,167,62,28,9,168,62,46,70,168,62,70,131,168,62,100,192,168,62,136,253,168,62,177,58,169,62,223,119,169,62,20,181,169,62,78,242,169,62,141,47,170,62,211,108,170,62,29,170,170,62,109,231,170,62,195,36,171,62,31,98,171,62,127,159,171,62,230,220,171,62,81,26,172,62,194,87,172,62,57,149,172,62,181,210,172,62,54,16,173,62,189,77,173,62,73,139,173,62,218,200,173,62,113,6,174,62,13,68,174,62,174,129,174,62,85,191,174,62,0,253,174,62,177,58,175,62,103,120,175,62,35,182,175,62,227,243,175,62,169,49,176,62,116,111,176,62,68,173,176,62,25,235,176,62,243,40,177,62,210,102,177,62,182,164,177,62,160,226,177,62,142,32,178,62,129,94,178,62,121,156,178,62,119,218,178,62,121,24,179,62,128,86,179,62,140,148,179,62,157,210,179,62,178,16,180,62,205,78,180,62,236,140,180,62,16,203,180,62,57,9,181,62,103,71,181,62,154,133,181,62,209,195,181,62,13,2,182,62,78,64,182,62,147,126,182,62,221,188,182,62,44,251,182,62,127,57,183,62,215,119,183,62,52,182,183,62,149,244,183,62,251,50,184,62,101,113,184,62,212,175,184,62,71,238,184,62,191,44,185,62,59,107,185,62,188,169,185,62,65,232,185,62,202,38,186,62,88,101,186,62,235,163,186,62,129,226,186,62,28,33,187,62,188,95,187,62,95,158,187,62,7,221,187,62,180,27,188,62,100,90,188,62,25,153,188,62,210,215,188,62,143,22,189,62,80,85,189,62,22,148,189,62,223,210,189,62,173,17,190,62,127,80,190,62,85,143,190,62,47,206,190,62,13,13,191,62,239,75,191,62,213,138,191,62,191,201,191,62,173,8,192,62,159,71,192,62,149,134,192,62,143,197,192,62,141,4,193,62,143,67,193,62,148,130,193,62,158,193,193,62,171,0,194,62,188,63,194,62,209,126,194,62,234,189,194,62,6,253,194,62,38,60,195,62,74,123,195,62,113,186,195,62,157,249,195,62,204,56,196,62,254,119,196,62,52,183,196,62,110,246,196,62,171,53,197,62,236,116,197,62,49,180,197,62,121,243,197,62,196,50,198,62,19,114,198,62,102,177,198,62,188,240,198,62,21,48,199,62,114,111,199,62,210,174,199,62,54,238,199,62,157,45,200,62,7,109,200,62,117,172,200,62,230,235,200,62,90,43,201,62,209,106,201,62,76,170,201,62,202,233,201,62,75,41,202,62,208,104,202,62,88,168,202,62,226,231,202,62,112,39,203,62,1,103,203,62,149,166,203,62,45,230,203,62,199,37,204,62,100,101,204,62,4,165,204,62,168,228,204,62,78,36,205,62,248,99,205,62,164,163,205,62,83,227,205,62,5,35,206,62,186,98,206,62,114,162,206,62,45,226,206,62,234,33,207,62,171,97,207,62,110,161,207,62,52,225,207,62,253,32,208,62,200,96,208,62,150,160,208,62,103,224,208,62,59,32,209,62,17,96,209,62,234,159,209,62,198,223,209,62,164,31,210,62,133,95,210,62,104,159,210,62,78,223,210,62,55,31,211,62,33,95,211,62,15,159,211,62,255,222,211,62,241,30,212,62,230,94,212,62,221,158,212,62,215,222,212,62,211,30,213,62,209,94,213,62,210,158,213,62,213,222,213,62,219,30,214,62,226,94,214,62,236,158,214,62,248,222,214,62,7,31,215,62,24,95,215,62,42,159,215,62,63,223,215,62,87,31,216,62,112,95,216,62,139,159,216,62,169,223,216,62,200,31,217,62,234,95,217,62,14,160,217,62,51,224,217,62,91,32,218,62,133,96,218,62,176,160,218,62,222,224,218,62,13,33,219,62,63,97,219,62,114,161,219,62,167,225,219,62,222,33,220,62,23,98,220,62,82,162,220,62,142,226,220,62,204,34,221,62,12,99,221,62,78,163,221,62,146,227,221,62,215,35,222,62,29,100,222,62,102,164,222,62,176,228,222,62,252,36,223,62,73,101,223,62,152,165,223,62,232,229,223,62,58,38,224,62,142,102,224,62,227,166,224,62,57,231,224,62,145,39,225,62,234,103,225,62,69,168,225,62,161,232,225,62,255,40,226,62,94,105,226,62,190,169,226,62,32,234,226,62,131,42,227,62,231,106,227,62,76,171,227,62,179,235,227,62,27,44,228,62,132,108,228,62,238,172,228,62,90,237,228,62,199,45,229,62,52,110,229,62,163,174,229,62,19,239,229,62,133,47,230,62,247,111,230,62,106,176,230,62,222,240,230,62,83,49,231,62,202,113,231,62,65,178,231,62,185,242,231,62,50,51,232,62,172,115,232,62,38,180,232,62,162,244,232,62,31,53,233,62,156,117,233,62,26,182,233,62,153,246,233,62,25,55,234,62,153,119,234,62,26,184,234,62,156,248,234,62,31,57,235,62,162,121,235,62,38,186,235,62,170,250,235,62,47,59,236,62,181,123,236,62,59,188,236,62,194,252,236,62,73,61,237,62,209,125,237,62,89,190,237,62,226,254,237,62,107,63,238,62,245,127,238,62,127,192,238,62,10,1,239,62,149,65,239,62,32,130,239,62,171,194,239,62,55,3,240,62,196,67,240,62,80,132,240,62,221,196,240,62,106,5,241,62,247,69,241,62,132,134,241,62,18,199,241,62,160,7,242,62,45,72,242,62,187,136,242,62,74,201,242,62,216,9,243,62,102,74,243,62,244,138,243,62,131,203,243,62,17,12,244,62,159,76,244,62,46,141,244,62,188,205,244,62,74,14,245,62,216,78,245,62,102,143,245,62,244,207,245,62,129,16,246,62,15,81,246,62,156,145,246,62,41,210,246,62,182,18,247,62,67,83,247,62,207,147,247,62,91,212,247,62,231,20,248,62,115,85,248,62,254,149,248,62,136,214,248,62,19,23,249,62,157,87,249,62,38,152,249,62,175,216,249,62,56,25,250,62,192,89,250,62,72,154,250,62,207,218,250,62,86,27,251,62,220,91,251,62,97,156,251,62,230,220,251,62,106,29,252,62,238,93,252,62,113,158,252,62,243,222,252,62,117,31,253,62,245,95,253,62,118,160,253,62,245,224,253,62,116,33,254,62,241,97,254,62,110,162,254,62,235,226,254,62,102,35,255,62,224,99,255,62,90,164,255,62,211,228,255,62,165,18,0,63,225,50,0,63,27,83,0,63,86,115,0,63,144,147,0,63,201,179,0,63,2,212,0,63,58,244,0,63,114,20,1,63,169,52,1,63,224,84,1,63,22,117,1,63,76,149,1,63,129,181,1,63,181,213,1,63,233,245,1,63,28,22,2,63,78,54,2,63,128,86,2,63,178,118,2,63,226,150,2,63,18,183,2,63,65,215,2,63,112,247,2,63,157,23,3,63,203,55,3,63,247,87,3,63,35,120,3,63,78,152,3,63,120,184,3,63,161,216,3,63,202,248,3,63,242,24,4,63,25,57,4,63,63,89,4,63,101,121,4,63,137,153,4,63,173,185,4,63,208,217,4,63,243,249,4,63,20,26,5,63,52,58,5,63,84,90,5,63,115,122,5,63,145,154,5,63,173,186,5,63,202,218,5,63,229,250,5,63,255,26,6,63,24,59,6,63,48,91,6,63,72,123,6,63,94,155,6,63,116,187,6,63,136,219,6,63,155,251,6,63,174,27,7,63,191,59,7,63,208,91,7,63,223,123,7,63,237,155,7,63,250,187,7,63,7,220,7,63,18,252,7,63,28,28,8,63,37,60,8,63,44,92,8,63,51,124,8,63,57,156,8,63,61,188,8,63,64,220,8,63,67,252,8,63,68,28,9,63,68,60,9,63,66,92,9,63,64,124,9,63,60,156,9,63,55,188,9,63,49,220,9,63,41,252,9,63,33,28,10,63,23,60,10,63,12,92,10,63,255,123,10,63,242,155,10,63,227,187,10,63,211,219,10,63,193,251,10,63,174,27,11,63,154,59,11,63,133,91,11,63,110,123,11,63,86,155,11,63,60,187,11,63,33,219,11,63,5,251,11,63,231,26,12,63,200,58,12,63,168,90,12,63,134,122,12,63,98,154,12,63,62,186,12,63,23,218,12,63,240,249,12,63,199,25,13,63,156,57,13,63,112,89,13,63,66,121,13,63,19,153,13,63,227,184,13,63,176,216,13,63,125,248,13,63,72,24,14,63,17,56,14,63,216,87,14,63,159,119,14,63,99,151,14,63,38,183,14,63,232,214,14,63,167,246,14,63,101,22,15,63,34,54,15,63,221,85,15,63,150,117,15,63,78,149,15,63,4,181,15,63,184,212,15,63,106,244,15,63,27,20,16,63,202,51,16,63,120,83,16,63,36,115,16,63,206,146,16,63,118,178,16,63,28,210,16,63,193,241,16,63,100,17,17,63,6,49,17,63,165,80,17,63,67,112,17,63,223,143,17,63,121,175,17,63,17,207,17,63,167,238,17,63,60,14,18,63,206,45,18,63,95,77,18,63,238,108,18,63,123,140,18,63,7,172,18,63,144,203,18,63,23,235,18,63,157,10,19,63,32,42,19,63,162,73,19,63,34,105,19,63,159,136,19,63,27,168,19,63,149,199,19,63,13,231,19,63,131,6,20,63,247,37,20,63,104,69,20,63,216,100,20,63,70,132,20,63,178,163,20,63,27,195,20,63,131,226,20,63,233,1,21,63,76,33,21,63,174,64,21,63,13,96,21,63,106,127,21,63,197,158,21,63,31,190,21,63,117,221,21,63,202,252,21,63,29,28,22,63,109,59,22,63,188,90,22,63,8,122,22,63,82,153,22,63,153,184,22,63,223,215,22,63,34,247,22,63,100,22,23,63,162,53,23,63,223,84,23,63,26,116,23,63,82,147,23,63,136,178,23,63,187,209,23,63,237,240,23,63,28,16,24,63,73,47,24,63,115,78,24,63,155,109,24,63,193,140,24,63,228,171,24,63,6,203,24,63,36,234,24,63,65,9,25,63,91,40,25,63,115,71,25,63,136,102,25,63,155,133,25,63,171,164,25,63,185,195,25,63,197,226,25,63,206,1,26,63,213,32,26,63,217,63,26,63,219,94,26,63,218,125,26,63,215,156,26,63,210,187,26,63,202,218,26,63,191,249,26,63,178,24,27,63,162,55,27,63,144,86,27,63,123,117,27,63,100,148,27,63,74,179,27,63,46,210,27,63,15,241,27,63,237,15,28,63,201,46,28,63,162,77,28,63,121,108,28,63,77,139,28,63,31,170,28,63,237,200,28,63,185,231,28,63,131,6,29,63,74,37,29,63,14,68,29,63,207,98,29,63,142,129,29,63,74,160,29,63,3,191,29,63,186,221,29,63,110,252,29,63,31,27,30,63,205,57,30,63,121,88,30,63,34,119,30,63,200,149,30,63,107,180,30,63,12,211,30,63,170,241,30,63,69,16,31,63,221,46,31,63,114,77,31,63,5,108,31,63,148,138,31,63,33,169,31,63,171,199,31,63,50,230,31,63,182,4,32,63,56,35,32,63,182,65,32,63,50,96,32,63,170,126,32,63,32,157,32,63,147,187,32,63,3,218,32,63,112,248,32,63,218,22,33,63,65,53,33,63,165,83,33,63,6,114,33,63,100,144,33,63,191,174,33,63,23,205,33,63,108,235,33,63,190,9,34,63,13,40,34,63,89,70,34,63,162,100,34,63,232,130,34,63,43,161,34,63,107,191,34,63,167,221,34,63,225,251,34,63,24,26,35,63,75,56,35,63,123,86,35,63,168,116,35,63,211,146,35,63,249,176,35,63,29,207,35,63,62,237,35,63,91,11,36,63,118,41,36,63,141,71,36,63,161,101,36,63,177,131,36,63,191,161,36,63,201,191,36,63,208,221,36,63,212,251,36,63,213,25,37,63,210,55,37,63,204,85,37,63,195,115,37,63,183,145,37,63,167,175,37,63,148,205,37,63,126,235,37,63,101,9,38,63,72,39,38,63,40,69,38,63,4,99,38,63,221,128,38,63,179,158,38,63,134,188,38,63,85,218,38,63,33,248,38,63,233,21,39,63,174,51,39,63,112,81,39,63,46,111,39,63,233,140,39,63,160,170,39,63,84,200,39,63,4,230,39,63,178,3,40,63,91,33,40,63,1,63,40,63,164,92,40,63,67,122,40,63,223,151,40,63,120,181,40,63,12,211,40,63,158,240,40,63,43,14,41,63,182,43,41,63,60,73,41,63,192,102,41,63,63,132,41,63,187,161,41,63,52,191,41,63,169,220,41,63,26,250,41,63,136,23,42,63,242,52,42,63,89,82,42,63,188,111,42,63,28,141,42,63,119,170,42,63,208,199,42,63,36,229,42,63,117,2,43,63,194,31,43,63,12,61,43,63,82,90,43,63,148,119,43,63,211,148,43,63,14,178,43,63,69,207,43,63,120,236,43,63,168,9,44,63,212,38,44,63,252,67,44,63,33,97,44,63,66,126,44,63,95,155,44,63,120,184,44,63,142,213,44,63,159,242,44,63,173,15,45,63,184,44,45,63,190,73,45,63,193,102,45,63,191,131,45,63,186,160,45,63,177,189,45,63,165,218,45,63,148,247,45,63,128,20,46,63,103,49,46,63,75,78,46,63,43,107,46,63,7,136,46,63,224,164,46,63,180,193,46,63,132,222,46,63,81,251,46,63,26,24,47,63,222,52,47,63,159,81,47,63,92,110,47,63,21,139,47,63,202,167,47,63,123,196,47,63,40,225,47,63,209,253,47,63,118,26,48,63,23,55,48,63,180,83,48,63,77,112,48,63,226,140,48,63,115,169,48,63,0,198,48,63,137,226,48,63,14,255,48,63,142,27,49,63,11,56,49,63,132,84,49,63,248,112,49,63,105,141,49,63,214,169,49,63,62,198,49,63,162,226,49,63,2,255,49,63,95,27,50,63,182,55,50,63,10,84,50,63,90,112,50,63,166,140,50,63,237,168,50,63,48,197,50,63,111,225,50,63,170,253,50,63,225,25,51,63,19,54,51,63,66,82,51,63,108,110,51,63,146,138,51,63,180,166,51,63,209,194,51,63,234,222,51,63,0,251,51,63,16,23,52,63,29,51,52,63,37,79,52,63,41,107,52,63,41,135,52,63,37,163,52,63,28,191,52,63,15,219,52,63,253,246,52,63,232,18,53,63,206,46,53,63,176,74,53,63,141,102,53,63,102,130,53,63,59,158,53,63,11,186,53,63,215,213,53,63,159,241,53,63,98,13,54,63,33,41,54,63,220,68,54,63,146,96,54,63,68,124,54,63,241,151,54,63,154,179,54,63,63,207,54,63,223,234,54,63,123,6,55,63,18,34,55,63,165,61,55,63,52,89,55,63,190,116,55,63,67,144,55,63,196,171,55,63,65,199,55,63,185,226,55,63,45,254,55,63,156,25,56,63,7,53,56,63,109,80,56,63,207,107,56,63,44,135,56,63,133,162,56,63,217,189,56,63,40,217,56,63,115,244,56,63,186,15,57,63,252,42,57,63,57,70,57,63,114,97,57,63,166,124,57,63,214,151,57,63,1,179,57,63,40,206,57,63,74,233,57,63,103,4,58,63,128,31,58,63,148,58,58,63,163,85,58,63,174,112,58,63,180,139,58,63,182,166,58,63,179,193,58,63,171,220,58,63,159,247,58,63,142,18,59,63,120,45,59,63,94,72,59,63,63,99,59,63,27,126,59,63,243,152,59,63,197,179,59,63,148,206,59,63,93,233,59,63,34,4,60,63,226,30,60,63,157,57,60,63,84,84,60,63,5,111,60,63,178,137,60,63,91,164,60,63,254,190,60,63,157,217,60,63,55,244,60,63,204,14,61,63,93,41,61,63,232,67,61,63,111,94,61,63,241,120,61,63,110,147,61,63,231,173,61,63,91,200,61,63,201,226,61,63,51,253,61,63,152,23,62,63,249,49,62,63,84,76,62,63,171,102,62,63,252,128,62,63,73,155,62,63,145,181,62,63,212,207,62,63,19,234,62,63,76,4,63,63,128,30,63,63,176,56,63,63,219,82,63,63,0,109,63,63,33,135,63,63,61,161,63,63,84,187,63,63,102,213,63,63,115,239,63,63,123,9,64,63,127,35,64,63,125,61,64,63,118,87,64,63,106,113,64,63,90,139,64,63,68,165,64,63,42,191,64,63,10,217,64,63,229,242,64,63,188,12,65,63,141,38,65,63,90,64,65,63,33,90,65,63,228,115,65,63,161,141,65,63,89,167,65,63,13,193,65,63,187,218,65,63,100,244,65,63,8,14,66,63,167,39,66,63,65,65,66,63,214,90,66,63,102,116,66,63,241,141,66,63,119,167,66,63,248,192,66,63,115,218,66,63,234,243,66,63,91,13,67,63,199,38,67,63,47,64,67,63,145,89,67,63,238,114,67,63,69,140,67,63,152,165,67,63,230,190,67,63,46,216,67,63,113,241,67,63,175,10,68,63,232,35,68,63,28,61,68,63,75,86,68,63,116,111,68,63,153,136,68,63,184,161,68,63,210,186,68,63,230,211,68,63,246,236,68,63,0,6,69,63,5,31,69,63,5,56,69,63,0,81,69,63,245,105,69,63,230,130,69,63,209,155,69,63,182,180,69,63,151,205,69,63,114,230,69,63,72,255,69,63,25,24,70,63,229,48,70,63,171,73,70,63,108,98,70,63,40,123,70,63,222,147,70,63,143,172,70,63,59,197,70,63,226,221,70,63,131,246,70,63,31,15,71,63,182,39,71,63,71,64,71,63,211,88,71,63,90,113,71,63,220,137,71,63,88,162,71,63,207,186,71,63,64,211,71,63,172,235,71,63,19,4,72,63,116,28,72,63,209,52,72,63,39,77,72,63,121,101,72,63,197,125,72,63,11,150,72,63,77,174,72,63,137,198,72,63,191,222,72,63,240,246,72,63,28,15,73,63,66,39,73,63,99,63,73,63,127,87,73,63,149,111,73,63,166,135,73,63,177,159,73,63,183,183,73,63,183,207,73,63,178,231,73,63,168,255,73,63,152,23,74,63,131,47,74,63,104,71,74,63,72,95,74,63,34,119,74,63,247,142,74,63,199,166,74,63,145,190,74,63,85,214,74,63,20,238,74,63,206,5,75,63,130,29,75,63,49,53,75,63,218,76,75,63,126,100,75,63,28,124,75,63,181,147,75,63,72,171,75,63,213,194,75,63,93,218,75,63,224,241,75,63,93,9,76,63,213,32,76,63,71,56,76,63,179,79,76,63,26,103,76,63,124,126,76,63,216,149,76,63,46,173,76,63,127,196,76,63,202,219,76,63,16,243,76,63,80,10,77,63,139,33,77,63,192,56,77,63,240,79,77,63,26,103,77,63,62,126,77,63,93,149,77,63,118,172,77,63,137,195,77,63,151,218,77,63,160,241,77,63,163,8,78,63,160,31,78,63,151,54,78,63,137,77,78,63,118,100,78,63,93,123,78,63,62,146,78,63,25,169,78,63,239,191,78,63,192,214,78,63,138,237,78,63,79,4,79,63,15,27,79,63,201,49,79,63,125,72,79,63,43,95,79,63,212,117,79,63,119,140,79,63,21,163,79,63,172,185,79,63,63,208,79,63,203,230,79,63,82,253,79,63,211,19,80,63,79,42,80,63,197,64,80,63,53,87,80,63,159,109,80,63,4,132,80,63,99,154,80,63,189,176,80,63,16,199,80,63,94,221,80,63,167,243,80,63,233,9,81,63,38,32,81,63,93,54,81,63,143,76,81,63,187,98,81,63,225,120,81,63,1,143,81,63,28,165,81,63,48,187,81,63,64,209,81,63,73,231,81,63,77,253,81,63,75,19,82,63,67,41,82,63,53,63,82,63,34,85,82,63,9,107,82,63,234,128,82,63,198,150,82,63,155,172,82,63,107,194,82,63,53,216,82,63,250,237,82,63,185,3,83,63,113,25,83,63,37,47,83,63,210,68,83,63,121,90,83,63,27,112,83,63,183,133,83,63,77,155,83,63,222,176,83,63,104,198,83,63,237,219,83,63,108,241,83,63,230,6,84,63,89,28,84,63,199,49,84,63,46,71,84,63,145,92,84,63,237,113,84,63,67,135,84,63,148,156,84,63,223,177,84,63,35,199,84,63,99,220,84,63,156,241,84,63,207,6,85,63,253,27,85,63,37,49,85,63,71,70,85,63,99,91,85,63,121,112,85,63,138,133,85,63,149,154,85,63,153,175,85,63,152,196,85,63,146,217,85,63,133,238,85,63,114,3,86,63,90,24,86,63,60,45,86,63,24,66,86,63,238,86,86,63,190,107,86,63,136,128,86,63,76,149,86,63,11,170,86,63,196,190,86,63,118,211,86,63,35,232,86,63,203,252,86,63,108,17,87,63,7,38,87,63,156,58,87,63,44,79,87,63,182,99,87,63,58,120,87,63,183,140,87,63,47,161,87,63,162,181,87,63,14,202,87,63,116,222,87,63,213,242,87,63,47,7,88,63,132,27,88,63,211,47,88,63,28,68,88,63,95,88,88,63,156,108,88,63,211,128,88,63,4,149,88,63,47,169,88,63,85,189,88,63,116,209,88,63,142,229,88,63,162,249,88,63,175,13,89,63,183,33,89,63,185,53,89,63,181,73,89,63,171,93,89,63,155,113,89,63,134,133,89,63,106,153,89,63,72,173,89,63,33,193,89,63,243,212,89,63,192,232,89,63,135,252,89,63,71,16,90,63,2,36,90,63,183,55,90,63,102,75,90,63,15,95,90,63,178,114,90,63,79,134,90,63,230,153,90,63,119,173,90,63,3,193,90,63,136,212,90,63,7,232,90,63,129,251,90,63,244,14,91,63,98,34,91,63,201,53,91,63,43,73,91,63,135,92,91,63,220,111,91,63,44,131,91,63,118,150,91,63,186,169,91,63,248,188,91,63,47,208,91,63,97,227,91,63,141,246,91,63,179,9,92,63,212,28,92,63,238,47,92,63,2,67,92,63,16,86,92,63,24,105,92,63,26,124,92,63,23,143,92,63,13,162,92,63,253,180,92,63,232,199,92,63,204,218,92,63,171,237,92,63,131,0,93,63,86,19,93,63,34,38,93,63,233,56,93,63,169,75,93,63,100,94,93,63,24,113,93,63,199,131,93,63,112,150,93,63,18,169,93,63,175,187,93,63,70,206,93,63,215,224,93,63,97,243,93,63,230,5,94,63,101,24,94,63,222,42,94,63,81,61,94,63,190,79,94,63,36,98,94,63,133,116,94,63,224,134,94,63,53,153,94,63,132,171,94,63,205,189,94,63,16,208,94,63,77,226,94,63,132,244,94,63,181,6,95,63,224,24,95,63,5,43,95,63,36,61,95,63,61,79,95,63,80,97,95,63,93,115,95,63,101,133,95,63,102,151,95,63,97,169,95,63,86,187,95,63,69,205,95,63,46,223,95,63,18,241,95,63,239,2,96,63,198,20,96,63,151,38,96,63,98,56,96,63,40,74,96,63,231,91,96,63,160,109,96,63,84,127,96,63,1,145,96,63,168,162,96,63,73,180,96,63,229,197,96,63,122,215,96,63,10,233,96,63,147,250,96,63,22,12,97,63,148,29,97,63,11,47,97,63,125,64,97,63,232,81,97,63,77,99,97,63,173,116,97,63,6,134,97,63,90,151,97,63,167,168,97,63,239,185,97,63,48,203,97,63,108,220,97,63,162,237,97,63,209,254,97,63,251,15,98,63,30,33,98,63,60,50,98,63,84,67,98,63,101,84,98,63,113,101,98,63,119,118,98,63,119,135,98,63,112,152,98,63,100,169,98,63,82,186,98,63,58,203,98,63,28,220,98,63,247,236,98,63,205,253,98,63,157,14,99,63,103,31,99,63,43,48,99,63,233,64,99,63,161,81,99,63,83,98,99,63,255,114,99,63,165,131,99,63,69,148,99,63,224,164,99,63,116,181,99,63,2,198,99,63,138,214,99,63,13,231,99,63,137,247,99,63,255,7,100,63,112,24,100,63,218,40,100,63,62,57,100,63,157,73,100,63,246,89,100,63,72,106,100,63,149,122,100,63,219,138,100,63,28,155,100,63,87,171,100,63,140,187,100,63,186,203,100,63,227,219,100,63,6,236,100,63,35,252,100,63,58,12,101,63,75,28,101,63,86,44,101,63,91,60,101,63,91,76,101,63,84,92,101,63,71,108,101,63,53,124,101,63,28,140,101,63,254,155,101,63,217,171,101,63,175,187,101,63,126,203,101,63,72,219,101,63,12,235,101,63,202,250,101,63,130,10,102,63,52,26,102,63,224,41,102,63,134,57,102,63,38,73,102,63,193,88,102,63,85,104,102,63,227,119,102,63,108,135,102,63,238,150,102,63,107,166,102,63,226,181,102,63,83,197,102,63,190,212,102,63,35,228,102,63,130,243,102,63,219,2,103,63,46,18,103,63,124,33,103,63,195,48,103,63,5,64,103,63,64,79,103,63,118,94,103,63,166,109,103,63,208,124,103,63,244,139,103,63,18,155,103,63,42,170,103,63,61,185,103,63,73,200,103,63,80,215,103,63,80,230,103,63,75,245,103,63,64,4,104,63,47,19,104,63,24,34,104,63,251,48,104,63,217,63,104,63,176,78,104,63,130,93,104,63,78,108,104,63,20,123,104,63,212,137,104,63,142,152,104,63,66,167,104,63,240,181,104,63,153,196,104,63,60,211,104,63,217,225,104,63,112,240,104,63,1,255,104,63,140,13,105,63,17,28,105,63,145,42,105,63,11,57,105,63,127,71,105,63,237,85,105,63,85,100,105,63,183,114,105,63,20,129,105,63,106,143,105,63,187,157,105,63,6,172,105,63,75,186,105,63,139,200,105,63,196,214,105,63,248,228,105,63,38,243,105,63,78,1,106,63,112,15,106,63,141,29,106,63,163,43,106,63,180,57,106,63,191,71,106,63,196,85,106,63,196,99,106,63,189,113,106,63,177,127,106,63,159,141,106,63,135,155,106,63,106,169,106,63,70,183,106,63,29,197,106,63,238,210,106,63,186,224,106,63,127,238,106,63,63,252,106,63,249,9,107,63,173,23,107,63,91,37,107,63,4,51,107,63,167,64,107,63,68,78,107,63,219,91,107,63,109,105,107,63,249,118,107,63,127,132,107,63,255,145,107,63,122,159,107,63,238,172,107,63,94,186,107,63,199,199,107,63,42,213,107,63,136,226,107,63,224,239,107,63,51,253,107,63,128,10,108,63,198,23,108,63,8,37,108,63,67,50,108,63,121,63,108,63,169,76,108,63,211,89,108,63,248,102,108,63,23,116,108,63,48,129,108,63,68,142,108,63,82,155,108,63,90,168,108,63,92,181,108,63,89,194,108,63,80,207,108,63,65,220,108,63,45,233,108,63,19,246,108,63,243,2,109,63,206,15,109,63,163,28,109,63,114,41,109,63,60,54,109,63,0,67,109,63,190,79,109,63,119,92,109,63,42,105,109,63,215,117,109,63,127,130,109,63,33,143,109,63,189,155,109,63,84,168,109,63,229,180,109,63,113,193,109,63,247,205,109,63,119,218,109,63,242,230,109,63,103,243,109,63,214,255,109,63,64,12,110,63,164,24,110,63,3,37,110,63,91,49,110,63,175,61,110,63,253,73,110,63,69,86,110,63,135,98,110,63,196,110,110,63,252,122,110,63,45,135,110,63,90,147,110,63,128,159,110,63,161,171,110,63,189,183,110,63,211,195,110,63,227,207,110,63,238,219,110,63,243,231,110,63,243,243,110,63,237,255,110,63,226,11,111,63,209,23,111,63,186,35,111,63,158,47,111,63,125,59,111,63,85,71,111,63,41,83,111,63,247,94,111,63,191,106,111,63,130,118,111,63,63,130,111,63,247,141,111,63,169,153,111,63,86,165,111,63,253,176,111,63,159,188,111,63,59,200,111,63,210,211,111,63,99,223,111,63,239,234,111,63,117,246,111,63,246,1,112,63,114,13,112,63,231,24,112,63,88,36,112,63,195,47,112,63,40,59,112,63,137,70,112,63,227,81,112,63,56,93,112,63,136,104,112,63,210,115,112,63,23,127,112,63,87,138,112,63,145,149,112,63,197,160,112,63,244,171,112,63,30,183,112,63,66,194,112,63,97,205,112,63,123,216,112,63,143,227,112,63,157,238,112,63,167,249,112,63,171,4,113,63,169,15,113,63,162,26,113,63,150,37,113,63,132,48,113,63,109,59,113,63,81,70,113,63,47,81,113,63,8,92,113,63,219,102,113,63,170,113,113,63,114,124,113,63,54,135,113,63,244,145,113,63,173,156,113,63,96,167,113,63,14,178,113,63,183,188,113,63,91,199,113,63,249,209,113,63,146,220,113,63,37,231,113,63,179,241,113,63,60,252,113,63,192,6,114,63,62,17,114,63,183,27,114,63,43,38,114,63,154,48,114,63,3,59,114,63,103,69,114,63,197,79,114,63,31,90,114,63,115,100,114,63,194,110,114,63,11,121,114,63,79,131,114,63,143,141,114,63,200,151,114,63,253,161,114,63,44,172,114,63,87,182,114,63,123,192,114,63,155,202,114,63,182,212,114,63,203,222,114,63,219,232,114,63,230,242,114,63,235,252,114,63,236,6,115,63,231,16,115,63,221,26,115,63,206,36,115,63,186,46,115,63,160,56,115,63,130,66,115,63,94,76,115,63,53,86,115,63,7,96,115,63,212,105,115,63,155,115,115,63,94,125,115,63,27,135,115,63,211,144,115,63,134,154,115,63,52,164,115,63,221,173,115,63,128,183,115,63,31,193,115,63,184,202,115,63,77,212,115,63,220,221,115,63,102,231,115,63,235,240,115,63,107,250,115,63,230,3,116,63,92,13,116,63,204,22,116,63,56,32,116,63,159,41,116,63,0,51,116,63,93,60,116,63,180,69,116,63,6,79,116,63,84,88,116,63,156,97,116,63,223,106,116,63,29,116,116,63,87,125,116,63,139,134,116,63,186,143,116,63,228,152,116,63,9,162,116,63,41,171,116,63,68,180,116,63,91,189,116,63,108,198,116,63,120,207,116,63,127,216,116,63,129,225,116,63,127,234,116,63,119,243,116,63,106,252,116,63,89,5,117,63,66,14,117,63,38,23,117,63,6,32,117,63,225,40,117,63,182,49,117,63,135,58,117,63,83,67,117,63,26,76,117,63,220,84,117,63,153,93,117,63,81,102,117,63,4,111,117,63,179,119,117,63,92,128,117,63,1,137,117,63,160,145,117,63,59,154,117,63,209,162,117,63,98,171,117,63,239,179,117,63,118,188,117,63,249,196,117,63,118,205,117,63,239,213,117,63,99,222,117,63,210,230,117,63,61,239,117,63,162,247,117,63,3,0,118,63,95,8,118,63,182,16,118,63,8,25,118,63,86,33,118,63,159,41,118,63,227,49,118,63,34,58,118,63,92,66,118,63,146,74,118,63,195,82,118,63,239,90,118,63,22,99,118,63,57,107,118,63,86,115,118,63,112,123,118,63,132,131,118,63,148,139,118,63,158,147,118,63,165,155,118,63,166,163,118,63,163,171,118,63,155,179,118,63,142,187,118,63,125,195,118,63,103,203,118,63,76,211,118,63,45,219,118,63,9,227,118,63,224,234,118,63,178,242,118,63,128,250,118,63,74,2,119,63,14,10,119,63,206,17,119,63,137,25,119,63,64,33,119,63,242,40,119,63,160,48,119,63,72,56,119,63,237,63,119,63,140,71,119,63,39,79,119,63,190,86,119,63,79,94,119,63,220,101,119,63,101,109,119,63,233,116,119,63,105,124,119,63,228,131,119,63,90,139,119,63,204,146,119,63,57,154,119,63,162,161,119,63,6,169,119,63,101,176,119,63,192,183,119,63,23,191,119,63,105,198,119,63,182,205,119,63,255,212,119,63,68,220,119,63,132,227,119,63,191,234,119,63,246,241,119,63,41,249,119,63,87,0,120,63,129,7,120,63,166,14,120,63,198,21,120,63,227,28,120,63,250,35,120,63,14,43,120,63,28,50,120,63,39,57,120,63,45,64,120,63,46,71,120,63,44,78,120,63,36,85,120,63,25,92,120,63,9,99,120,63,244,105,120,63,219,112,120,63,190,119,120,63,156,126,120,63,118,133,120,63,76,140,120,63,29,147,120,63,234,153,120,63,179,160,120,63,119,167,120,63,55,174,120,63,242,180,120,63,169,187,120,63,92,194,120,63,11,201,120,63,181,207,120,63,91,214,120,63,252,220,120,63,154,227,120,63,51,234,120,63,199,240,120,63,88,247,120,63,228,253,120,63,108,4,121,63,240,10,121,63,111,17,121,63,234,23,121,63,97,30,121,63,211,36,121,63,66,43,121,63,172,49,121,63,18,56,121,63,116,62,121,63,209,68,121,63,42,75,121,63,127,81,121,63,208,87,121,63,29,94,121,63,101,100,121,63,170,106,121,63,234,112,121,63,38,119,121,63,93,125,121,63,145,131,121,63,193,137,121,63,236,143,121,63,19,150,121,63,54,156,121,63,85,162,121,63,112,168,121,63,134,174,121,63,153,180,121,63,167,186,121,63,178,192,121,63,184,198,121,63,186,204,121,63,184,210,121,63,178,216,121,63,168,222,121,63,154,228,121,63,135,234,121,63,113,240,121,63,87,246,121,63,56,252,121,63,22,2,122,63,239,7,122,63,197,13,122,63,150,19,122,63,100,25,122,63,45,31,122,63,243,36,122,63,180,42,122,63,113,48,122,63,43,54,122,63,224,59,122,63,146,65,122,63,63,71,122,63,233,76,122,63,142,82,122,63,48,88,122,63,206,93,122,63,103,99,122,63,253,104,122,63,143,110,122,63,29,116,122,63,167,121,122,63,45,127,122,63,175,132,122,63,45,138,122,63,168,143,122,63,30,149,122,63,145,154,122,63,255,159,122,63,106,165,122,63,209,170,122,63,52,176,122,63,147,181,122,63,239,186,122,63,70,192,122,63,154,197,122,63,234,202,122,63,54,208,122,63,126,213,122,63,194,218,122,63,3,224,122,63,64,229,122,63,121,234,122,63,174,239,122,63,223,244,122,63,13,250,122,63,55,255,122,63,93,4,123,63,127,9,123,63,157,14,123,63,184,19,123,63,207,24,123,63,227,29,123,63,242,34,123,63,254,39,123,63,6,45,123,63,10,50,123,63,11,55,123,63,8,60,123,63,1,65,123,63,247,69,123,63,233,74,123,63,215,79,123,63,193,84,123,63,168,89,123,63,139,94,123,63,107,99,123,63,71,104,123,63,31,109,123,63,243,113,123,63,196,118,123,63,146,123,123,63,91,128,123,63,33,133,123,63,228,137,123,63,163,142,123,63,94,147,123,63,22,152,123,63,202,156,123,63,122,161,123,63,39,166,123,63,208,170,123,63,118,175,123,63,24,180,123,63,183,184,123,63,82,189,123,63,233,193,123,63,125,198,123,63,14,203,123,63,155,207,123,63,36,212,123,63,170,216,123,63,45,221,123,63,172,225,123,63,39,230,123,63,159,234,123,63,19,239,123,63,132,243,123,63,242,247,123,63,92,252,123,63,195,0,124,63,38,5,124,63,133,9,124,63,226,13,124,63,58,18,124,63,144,22,124,63,226,26,124,63,48,31,124,63,123,35,124,63,195,39,124,63,7,44,124,63,72,48,124,63,134,52,124,63,192,56,124,63,247,60,124,63,42,65,124,63,90,69,124,63,135,73,124,63,176,77,124,63,214,81,124,63,249,85,124,63,24,90,124,63,52,94,124,63,77,98,124,63,98,102,124,63,116,106,124,63,131,110,124,63,142,114,124,63,150,118,124,63,155,122,124,63,157,126,124,63,155,130,124,63,150,134,124,63,142,138,124,63,130,142,124,63,116,146,124,63,98,150,124,63,77,154,124,63,52,158,124,63,24,162,124,63,249,165,124,63,215,169,124,63,178,173,124,63,137,177,124,63,94,181,124,63,47,185,124,63,253,188,124,63,199,192,124,63,143,196,124,63,83,200,124,63,20,204,124,63,211,207,124,63,141,211,124,63,69,215,124,63,250,218,124,63,171,222,124,63,90,226,124,63,5,230,124,63,173,233,124,63,82,237,124,63,244,240,124,63,147,244,124,63,46,248,124,63,199,251,124,63,93,255,124,63,239,2,125,63,127,6,125,63,11,10,125,63,148,13,125,63,27,17,125,63,158,20,125,63,30,24,125,63,155,27,125,63,21,31,125,63,140,34,125,63,0,38,125,63,114,41,125,63,224,44,125,63,75,48,125,63,179,51,125,63,24,55,125,63,122,58,125,63,217,61,125,63,54,65,125,63,143,68,125,63,229,71,125,63,56,75,125,63,137,78,125,63,214,81,125,63,33,85,125,63,104,88,125,63,173,91,125,63,239,94,125,63,46,98,125,63,106,101,125,63,163,104,125,63,217,107,125,63,12,111,125,63,61,114,125,63,106,117,125,63,149,120,125,63,189,123,125,63,226,126,125,63,4,130,125,63,36,133,125,63,64,136,125,63,90,139,125,63,112,142,125,63,133,145,125,63,150,148,125,63,164,151,125,63,176,154,125,63,185,157,125,63,191,160,125,63,194,163,125,63,194,166,125,63,192,169,125,63,187,172,125,63,179,175,125,63,168,178,125,63,155,181,125,63,139,184,125,63,120,187,125,63,99,190,125,63,74,193,125,63,48,196,125,63,18,199,125,63,241,201,125,63,206,204,125,63,169,207,125,63,128,210,125,63,85,213,125,63,39,216,125,63,247,218,125,63,196,221,125,63,142,224,125,63,85,227,125,63,26,230,125,63,220,232,125,63,156,235,125,63,89,238,125,63,19,241,125,63,203,243,125,63,128,246,125,63,51,249,125,63,227,251,125,63,144,254,125,63,59,1,126,63,227,3,126,63,137,6,126,63,44,9,126,63,204,11,126,63,106,14,126,63,6,17,126,63,158,19,126,63,53,22,126,63,200,24,126,63,90,27,126,63,232,29,126,63,116,32,126,63,254,34,126,63,133,37,126,63,10,40,126,63,140,42,126,63,12,45,126,63,137,47,126,63,4,50,126,63,124,52,126,63,242,54,126,63,101,57,126,63,214,59,126,63,68,62,126,63,176,64,126,63,26,67,126,63,129,69,126,63,230,71,126,63,72,74,126,63,168,76,126,63,5,79,126,63,96,81,126,63,185,83,126,63,15,86,126,63,99,88,126,63,181,90,126,63,4,93,126,63,81,95,126,63,155,97,126,63],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE+20480);allocate([227,99,126,63,41,102,126,63,108,104,126,63,173,106,126,63,236,108,126,63,40,111,126,63,98,113,126,63,154,115,126,63,208,117,126,63,3,120,126,63,51,122,126,63,98,124,126,63,142,126,126,63,184,128,126,63,224,130,126,63,5,133,126,63,40,135,126,63,73,137,126,63,104,139,126,63,132,141,126,63,159,143,126,63,183,145,126,63,204,147,126,63,224,149,126,63,241,151,126,63,0,154,126,63,13,156,126,63,24,158,126,63,32,160,126,63,38,162,126,63,42,164,126,63,44,166,126,63,44,168,126,63,41,170,126,63,37,172,126,63,30,174,126,63,21,176,126,63,10,178,126,63,253,179,126,63,238,181,126,63,220,183,126,63,201,185,126,63,179,187,126,63,155,189,126,63,129,191,126,63,101,193,126,63,71,195,126,63,39,197,126,63,5,199,126,63,224,200,126,63,186,202,126,63,145,204,126,63,103,206,126,63,58,208,126,63,12,210,126,63,219,211,126,63,168,213,126,63,115,215,126,63,61,217,126,63,4,219,126,63,201,220,126,63,140,222,126,63,77,224,126,63,12,226,126,63,202,227,126,63,133,229,126,63,62,231,126,63,245,232,126,63,170,234,126,63,94,236,126,63,15,238,126,63,190,239,126,63,108,241,126,63,23,243,126,63,193,244,126,63,104,246,126,63,14,248,126,63,178,249,126,63,84,251,126,63,243,252,126,63,145,254,126,63,46,0,127,63,200,1,127,63,96,3,127,63,247,4,127,63,139,6,127,63,30,8,127,63,175,9,127,63,62,11,127,63,203,12,127,63,86,14,127,63,223,15,127,63,103,17,127,63,237,18,127,63,112,20,127,63,242,21,127,63,115,23,127,63,241,24,127,63,110,26,127,63,233,27,127,63,98,29,127,63,217,30,127,63,78,32,127,63,194,33,127,63,52,35,127,63,164,36,127,63,18,38,127,63,127,39,127,63,234,40,127,63,83,42,127,63,186,43,127,63,32,45,127,63,131,46,127,63,230,47,127,63,70,49,127,63,165,50,127,63,2,52,127,63,93,53,127,63,182,54,127,63,14,56,127,63,100,57,127,63,185,58,127,63,12,60,127,63,93,61,127,63,172,62,127,63,250,63,127,63,70,65,127,63,145,66,127,63,217,67,127,63,33,69,127,63,102,70,127,63,170,71,127,63,236,72,127,63,45,74,127,63,108,75,127,63,169,76,127,63,229,77,127,63,31,79,127,63,88,80,127,63,143,81,127,63,196,82,127,63,248,83,127,63,42,85,127,63,91,86,127,63,138,87,127,63,184,88,127,63,228,89,127,63,14,91,127,63,55,92,127,63,94,93,127,63,132,94,127,63,169,95,127,63,203,96,127,63,237,97,127,63,12,99,127,63,42,100,127,63,71,101,127,63,98,102,127,63,124,103,127,63,148,104,127,63,171,105,127,63,192,106,127,63,212,107,127,63,230,108,127,63,247,109,127,63,6,111,127,63,20,112,127,63,33,113,127,63,44,114,127,63,53,115,127,63,61,116,127,63,68,117,127,63,73,118,127,63,77,119,127,63,79,120,127,63,80,121,127,63,80,122,127,63,78,123,127,63,75,124,127,63,70,125,127,63,64,126,127,63,57,127,127,63,48,128,127,63,38,129,127,63,27,130,127,63,14,131,127,63,0,132,127,63,240,132,127,63,223,133,127,63,205,134,127,63,185,135,127,63,164,136,127,63,142,137,127,63,118,138,127,63,93,139,127,63,67,140,127,63,40,141,127,63,11,142,127,63,237,142,127,63,205,143,127,63,173,144,127,63,139,145,127,63,103,146,127,63,67,147,127,63,29,148,127,63,246,148,127,63,205,149,127,63,164,150,127,63,121,151,127,63,77,152,127,63,31,153,127,63,241,153,127,63,193,154,127,63,144,155,127,63,93,156,127,63,42,157,127,63,245,157,127,63,191,158,127,63,136,159,127,63,79,160,127,63,22,161,127,63,219,161,127,63,159,162,127,63,98,163,127,63,36,164,127,63,228,164,127,63,163,165,127,63,98,166,127,63,31,167,127,63,219,167,127,63,149,168,127,63,79,169,127,63,7,170,127,63,190,170,127,63,117,171,127,63,42,172,127,63,221,172,127,63,144,173,127,63,66,174,127,63,242,174,127,63,162,175,127,63,80,176,127,63,253,176,127,63,169,177,127,63,85,178,127,63,254,178,127,63,167,179,127,63,79,180,127,63,246,180,127,63,156,181,127,63,64,182,127,63,228,182,127,63,134,183,127,63,40,184,127,63,200,184,127,63,103,185,127,63,6,186,127,63,163,186,127,63,63,187,127,63,219,187,127,63,117,188,127,63,14,189,127,63,166,189,127,63,61,190,127,63,212,190,127,63,105,191,127,63,253,191,127,63,144,192,127,63,34,193,127,63,180,193,127,63,68,194,127,63,211,194,127,63,98,195,127,63,239,195,127,63,123,196,127,63,7,197,127,63,145,197,127,63,27,198,127,63,163,198,127,63,43,199,127,63,178,199,127,63,56,200,127,63,189,200,127,63,65,201,127,63,196,201,127,63,70,202,127,63,199,202,127,63,71,203,127,63,199,203,127,63,69,204,127,63,195,204,127,63,64,205,127,63,187,205,127,63,54,206,127,63,177,206,127,63,42,207,127,63,162,207,127,63,26,208,127,63,144,208,127,63,6,209,127,63,123,209,127,63,239,209,127,63,98,210,127,63,213,210,127,63,70,211,127,63,183,211,127,63,39,212,127,63,150,212,127,63,4,213,127,63,114,213,127,63,222,213,127,63,74,214,127,63,181,214,127,63,32,215,127,63,137,215,127,63,242,215,127,63,89,216,127,63,192,216,127,63,39,217,127,63,140,217,127,63,241,217,127,63,85,218,127,63,184,218,127,63,27,219,127,63,124,219,127,63,221,219,127,63,61,220,127,63,157,220,127,63,251,220,127,63,89,221,127,63,183,221,127,63,19,222,127,63,111,222,127,63,202,222,127,63,36,223,127,63,126,223,127,63,215,223,127,63,47,224,127,63,134,224,127,63,221,224,127,63,51,225,127,63,137,225,127,63,221,225,127,63,49,226,127,63,133,226,127,63,215,226,127,63,41,227,127,63,122,227,127,63,203,227,127,63,27,228,127,63,106,228,127,63,185,228,127,63,7,229,127,63,84,229,127,63,161,229,127,63,237,229,127,63,56,230,127,63,131,230,127,63,205,230,127,63,23,231,127,63,96,231,127,63,168,231,127,63,239,231,127,63,54,232,127,63,125,232,127,63,195,232,127,63,8,233,127,63,76,233,127,63,144,233,127,63,212,233,127,63,23,234,127,63,89,234,127,63,154,234,127,63,219,234,127,63,28,235,127,63,92,235,127,63,155,235,127,63,218,235,127,63,24,236,127,63,86,236,127,63,147,236,127,63,207,236,127,63,11,237,127,63,71,237,127,63,130,237,127,63,188,237,127,63,246,237,127,63,47,238,127,63,104,238,127,63,160,238,127,63,216,238,127,63,15,239,127,63,69,239,127,63,123,239,127,63,177,239,127,63,230,239,127,63,27,240,127,63,79,240,127,63,130,240,127,63,182,240,127,63,232,240,127,63,26,241,127,63,76,241,127,63,125,241,127,63,174,241,127,63,222,241,127,63,14,242,127,63,61,242,127,63,108,242,127,63,154,242,127,63,200,242,127,63,245,242,127,63,34,243,127,63,79,243,127,63,123,243,127,63,166,243,127,63,209,243,127,63,252,243,127,63,38,244,127,63,80,244,127,63,121,244,127,63,162,244,127,63,203,244,127,63,243,244,127,63,27,245,127,63,66,245,127,63,105,245,127,63,143,245,127,63,181,245,127,63,219,245,127,63,0,246,127,63,37,246,127,63,73,246,127,63,109,246,127,63,145,246,127,63,180,246,127,63,215,246,127,63,250,246,127,63,28,247,127,63,62,247,127,63,95,247,127,63,128,247,127,63,160,247,127,63,193,247,127,63,225,247,127,63,0,248,127,63,31,248,127,63,62,248,127,63,93,248,127,63,123,248,127,63,152,248,127,63,182,248,127,63,211,248,127,63,240,248,127,63,12,249,127,63,40,249,127,63,68,249,127,63,95,249,127,63,122,249,127,63,149,249,127,63,175,249,127,63,202,249,127,63,227,249,127,63,253,249,127,63,22,250,127,63,47,250,127,63,71,250,127,63,96,250,127,63,120,250,127,63,143,250,127,63,166,250,127,63,190,250,127,63,212,250,127,63,235,250,127,63,1,251,127,63,23,251,127,63,44,251,127,63,66,251,127,63,87,251,127,63,108,251,127,63,128,251,127,63,148,251,127,63,168,251,127,63,188,251,127,63,208,251,127,63,227,251,127,63,246,251,127,63,8,252,127,63,27,252,127,63,45,252,127,63,63,252,127,63,81,252,127,63,98,252,127,63,115,252,127,63,132,252,127,63,149,252,127,63,165,252,127,63,182,252,127,63,198,252,127,63,213,252,127,63,229,252,127,63,244,252,127,63,3,253,127,63,18,253,127,63,33,253,127,63,47,253,127,63,62,253,127,63,76,253,127,63,89,253,127,63,103,253,127,63,116,253,127,63,130,253,127,63,143,253,127,63,155,253,127,63,168,253,127,63,181,253,127,63,193,253,127,63,205,253,127,63,217,253,127,63,228,253,127,63,240,253,127,63,251,253,127,63,6,254,127,63,17,254,127,63,28,254,127,63,38,254,127,63,49,254,127,63,59,254,127,63,69,254,127,63,79,254,127,63,89,254,127,63,98,254,127,63,108,254,127,63,117,254,127,63,126,254,127,63,135,254,127,63,144,254,127,63,152,254,127,63,161,254,127,63,169,254,127,63,177,254,127,63,185,254,127,63,193,254,127,63,201,254,127,63,208,254,127,63,216,254,127,63,223,254,127,63,230,254,127,63,237,254,127,63,244,254,127,63,251,254,127,63,2,255,127,63,8,255,127,63,14,255,127,63,21,255,127,63,27,255,127,63,33,255,127,63,39,255,127,63,45,255,127,63,50,255,127,63,56,255,127,63,61,255,127,63,67,255,127,63,72,255,127,63,77,255,127,63,82,255,127,63,87,255,127,63,92,255,127,63,96,255,127,63,101,255,127,63,105,255,127,63,110,255,127,63,114,255,127,63,118,255,127,63,122,255,127,63,126,255,127,63,130,255,127,63,134,255,127,63,138,255,127,63,142,255,127,63,145,255,127,63,149,255,127,63,152,255,127,63,155,255,127,63,159,255,127,63,162,255,127,63,165,255,127,63,168,255,127,63,171,255,127,63,174,255,127,63,176,255,127,63,179,255,127,63,182,255,127,63,184,255,127,63,187,255,127,63,189,255,127,63,192,255,127,63,194,255,127,63,196,255,127,63,198,255,127,63,201,255,127,63,203,255,127,63,205,255,127,63,207,255,127,63,209,255,127,63,210,255,127,63,212,255,127,63,214,255,127,63,216,255,127,63,217,255,127,63,219,255,127,63,220,255,127,63,222,255,127,63,223,255,127,63,225,255,127,63,226,255,127,63,227,255,127,63,229,255,127,63,230,255,127,63,231,255,127,63,232,255,127,63,233,255,127,63,234,255,127,63,235,255,127,63,236,255,127,63,237,255,127,63,238,255,127,63,239,255,127,63,240,255,127,63,241,255,127,63,241,255,127,63,242,255,127,63,243,255,127,63,244,255,127,63,244,255,127,63,245,255,127,63,246,255,127,63,246,255,127,63,247,255,127,63,247,255,127,63,248,255,127,63,248,255,127,63,249,255,127,63,249,255,127,63,250,255,127,63,250,255,127,63,250,255,127,63,251,255,127,63,251,255,127,63,251,255,127,63,252,255,127,63,252,255,127,63,252,255,127,63,253,255,127,63,253,255,127,63,253,255,127,63,253,255,127,63,254,255,127,63,254,255,127,63,254,255,127,63,254,255,127,63,254,255,127,63,254,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,255,255,127,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,128,63,0,0,112,194,0,0,112,194,0,0,112,194,0,0,112,194,0,0,112,194,0,0,112,194,0,0,112,194,0,0,112,194,0,0,112,194,0,0,112,194,0,0,112,194,0,0,112,194,0,0,120,194,0,0,120,194,0,0,130,194,0,0,146,194,0,0,138,194,0,0,136,194,0,0,136,194,0,0,134,194,0,0,140,194,0,0,140,194,0,0,144,194,0,0,148,194,0,0,150,194,0,0,158,194,0,0,158,194,0,0,160,194,0,0,166,194,0,0,176,194,0,0,186,194,0,0,200,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,84,194,0,0,116,194,0,0,132,194,0,0,132,194,0,0,136,194,0,0,134,194,0,0,140,194,0,0,152,194,0,0,152,194,0,0,144,194,0,0,146,194,0,0,150,194,0,0,152,194,0,0,156,194,0,0,158,194,0,0,166,194,0,0,176,194,0,0,186,194,0,0,200,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,20,194,0,0,20,194,0,0,20,194,0,0,20,194,0,0,20,194,0,0,20,194,0,0,20,194,0,0,20,194,0,0,24,194,0,0,32,194,0,0,40,194,0,0,56,194,0,0,64,194,0,0,84,194,0,0,92,194,0,0,120,194,0,0,130,194,0,0,104,194,0,0,96,194,0,0,96,194,0,0,116,194,0,0,112,194,0,0,130,194,0,0,134,194,0,0,138,194,0,0,142,194,0,0,154,194,0,0,154,194,0,0,156,194,0,0,160,194,0,0,164,194,0,0,168,194,0,0,176,194,0,0,186,194,0,0,196,194,0,0,212,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,200,193,0,0,200,193,0,0,200,193,0,0,200,193,0,0,200,193,0,0,200,193,0,0,200,193,0,0,200,193,0,0,200,193,0,0,208,193,0,0,216,193,0,0,232,193,0,0,0,194,0,0,24,194,0,0,64,194,0,0,80,194,0,0,80,194,0,0,72,194,0,0,64,194,0,0,64,194,0,0,76,194,0,0,80,194,0,0,88,194,0,0,112,194,0,0,134,194,0,0,134,194,0,0,132,194,0,0,136,194,0,0,138,194,0,0,146,194,0,0,146,194,0,0,152,194,0,0,160,194,0,0,162,194,0,0,162,194,0,0,170,194,0,0,170,194,0,0,172,194,0,0,176,194,0,0,186,194,0,0,200,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,128,193,0,0,128,193,0,0,128,193,0,0,128,193,0,0,128,193,0,0,128,193,0,0,128,193,0,0,128,193,0,0,136,193,0,0,152,193,0,0,160,193,0,0,176,193,0,0,208,193,0,0,224,193,0,0,248,193,0,0,32,194,0,0,60,194,0,0,28,194,0,0,28,194,0,0,32,194,0,0,40,194,0,0,44,194,0,0,60,194,0,0,76,194,0,0,100,194,0,0,80,194,0,0,92,194,0,0,92,194,0,0,112,194,0,0,104,194,0,0,120,194,0,0,124,194,0,0,140,194,0,0,134,194,0,0,138,194,0,0,144,194,0,0,146,194,0,0,154,194,0,0,160,194,0,0,164,194,0,0,166,194,0,0,174,194,0,0,180,194,0,0,188,194,0,0,196,194,0,0,208,194,0,0,230,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,0,193,0,0,0,193,0,0,0,193,0,0,0,193,0,0,0,193,0,0,0,193,0,0,0,193,0,0,0,193,0,0,0,193,0,0,0,193,0,0,32,193,0,0,48,193,0,0,112,193,0,0,152,193,0,0,200,193,0,0,240,193,0,0,8,194,0,0,248,193,0,0,240,193,0,0,248,193,0,0,232,193,0,0,0,194,0,0,12,194,0,0,40,194,0,0,64,194,0,0,40,194,0,0,48,194,0,0,56,194,0,0,72,194,0,0,72,194,0,0,76,194,0,0,80,194,0,0,108,194,0,0,88,194,0,0,92,194,0,0,92,194,0,0,104,194,0,0,120,194,0,0,124,194,0,0,132,194,0,0,144,194,0,0,146,194,0,0,152,194,0,0,150,194,0,0,156,194,0,0,160,194,0,0,160,194,0,0,162,194,0,0,168,194,0,0,176,194,0,0,180,194,0,0,188,194,0,0,196,194,0,0,202,194,0,0,212,194,0,0,220,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,134,194,0,0,134,194,0,0,134,194,0,0,152,194,0,0,144,194,0,0,142,194,0,0,148,194,0,0,152,194,0,0,152,194,0,0,150,194,0,0,156,194,0,0,158,194,0,0,158,194,0,0,162,194,0,0,166,194,0,0,172,194,0,0,178,194,0,0,186,194,0,0,194,194,0,0,200,194,0,0,210,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,60,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,64,194,0,0,76,194,0,0,92,194,0,0,108,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,134,194,0,0,132,194,0,0,136,194,0,0,138,194,0,0,140,194,0,0,148,194,0,0,158,194,0,0,154,194,0,0,154,194,0,0,156,194,0,0,160,194,0,0,162,194,0,0,164,194,0,0,168,194,0,0,172,194,0,0,176,194,0,0,182,194,0,0,190,194,0,0,200,194,0,0,216,194,0,0,232,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,20,194,0,0,20,194,0,0,36,194,0,0,48,194,0,0,64,194,0,0,76,194,0,0,104,194,0,0,120,194,0,0,112,194,0,0,100,194,0,0,108,194,0,0,108,194,0,0,112,194,0,0,124,194,0,0,130,194,0,0,144,194,0,0,142,194,0,0,140,194,0,0,144,194,0,0,148,194,0,0,154,194,0,0,152,194,0,0,156,194,0,0,162,194,0,0,162,194,0,0,160,194,0,0,166,194,0,0,172,194,0,0,182,194,0,0,192,194,0,0,200,194,0,0,210,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,224,193,0,0,224,193,0,0,224,193,0,0,224,193,0,0,224,193,0,0,224,193,0,0,224,193,0,0,224,193,0,0,224,193,0,0,240,193,0,0,0,194,0,0,0,194,0,0,4,194,0,0,12,194,0,0,36,194,0,0,68,194,0,0,72,194,0,0,68,194,0,0,60,194,0,0,64,194,0,0,64,194,0,0,80,194,0,0,76,194,0,0,100,194,0,0,130,194,0,0,116,194,0,0,108,194,0,0,116,194,0,0,128,194,0,0,138,194,0,0,140,194,0,0,148,194,0,0,154,194,0,0,154,194,0,0,156,194,0,0,162,194,0,0,168,194,0,0,170,194,0,0,174,194,0,0,180,194,0,0,184,194,0,0,192,194,0,0,200,194,0,0,214,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,152,193,0,0,152,193,0,0,152,193,0,0,152,193,0,0,152,193,0,0,152,193,0,0,152,193,0,0,152,193,0,0,160,193,0,0,168,193,0,0,184,193,0,0,216,193,0,0,240,193,0,0,12,194,0,0,16,194,0,0,36,194,0,0,56,194,0,0,48,194,0,0,40,194,0,0,32,194,0,0,36,194,0,0,36,194,0,0,44,194,0,0,64,194,0,0,92,194,0,0,84,194,0,0,80,194,0,0,84,194,0,0,96,194,0,0,108,194,0,0,104,194,0,0,112,194,0,0,134,194,0,0,132,194,0,0,138,194,0,0,142,194,0,0,144,194,0,0,150,194,0,0,158,194,0,0,162,194,0,0,168,194,0,0,174,194,0,0,180,194,0,0,186,194,0,0,194,194,0,0,202,194,0,0,214,194,0,0,228,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,16,193,0,0,16,193,0,0,16,193,0,0,16,193,0,0,16,193,0,0,16,193,0,0,16,193,0,0,16,193,0,0,48,193,0,0,64,193,0,0,64,193,0,0,112,193,0,0,128,193,0,0,160,193,0,0,184,193,0,0,240,193,0,0,20,194,0,0,8,194,0,0,4,194,0,0,8,194,0,0,248,193,0,0,0,194,0,0,0,194,0,0,24,194,0,0,60,194,0,0,48,194,0,0,36,194,0,0,32,194,0,0,60,194,0,0,68,194,0,0,56,194,0,0,56,194,0,0,104,194,0,0,72,194,0,0,72,194,0,0,88,194,0,0,104,194,0,0,120,194,0,0,128,194,0,0,134,194,0,0,134,194,0,0,140,194,0,0,144,194,0,0,152,194,0,0,158,194,0,0,166,194,0,0,174,194,0,0,182,194,0,0,192,194,0,0,200,194,0,0,208,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,120,194,0,0,120,194,0,0,120,194,0,0,120,194,0,0,120,194,0,0,120,194,0,0,120,194,0,0,120,194,0,0,120,194,0,0,120,194,0,0,124,194,0,0,128,194,0,0,132,194,0,0,134,194,0,0,132,194,0,0,136,194,0,0,150,194,0,0,144,194,0,0,152,194,0,0,150,194,0,0,152,194,0,0,156,194,0,0,158,194,0,0,164,194,0,0,168,194,0,0,170,194,0,0,180,194,0,0,188,194,0,0,202,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,108,194,0,0,108,194,0,0,108,194,0,0,108,194,0,0,108,194,0,0,108,194,0,0,108,194,0,0,108,194,0,0,108,194,0,0,108,194,0,0,108,194,0,0,112,194,0,0,112,194,0,0,116,194,0,0,124,194,0,0,132,194,0,0,142,194,0,0,136,194,0,0,140,194,0,0,140,194,0,0,142,194,0,0,144,194,0,0,144,194,0,0,150,194,0,0,162,194,0,0,156,194,0,0,158,194,0,0,164,194,0,0,166,194,0,0,172,194,0,0,180,194,0,0,194,194,0,0,206,194,0,0,226,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,84,194,0,0,84,194,0,0,84,194,0,0,84,194,0,0,84,194,0,0,84,194,0,0,84,194,0,0,84,194,0,0,84,194,0,0,88,194,0,0,92,194,0,0,100,194,0,0,96,194,0,0,100,194,0,0,92,194,0,0,116,194,0,0,130,194,0,0,112,194,0,0,112,194,0,0,120,194,0,0,124,194,0,0,124,194,0,0,132,194,0,0,136,194,0,0,148,194,0,0,146,194,0,0,150,194,0,0,150,194,0,0,156,194,0,0,160,194,0,0,160,194,0,0,164,194,0,0,170,194,0,0,180,194,0,0,192,194,0,0,202,194,0,0,216,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,56,194,0,0,56,194,0,0,56,194,0,0,56,194,0,0,56,194,0,0,56,194,0,0,56,194,0,0,56,194,0,0,56,194,0,0,56,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,60,194,0,0,64,194,0,0,76,194,0,0,100,194,0,0,76,194,0,0,68,194,0,0,72,194,0,0,76,194,0,0,84,194,0,0,88,194,0,0,108,194,0,0,132,194,0,0,112,194,0,0,120,194,0,0,134,194,0,0,134,194,0,0,140,194,0,0,144,194,0,0,150,194,0,0,152,194,0,0,156,194,0,0,162,194,0,0,170,194,0,0,176,194,0,0,188,194,0,0,194,194,0,0,208,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,16,194,0,0,28,194,0,0,36,194,0,0,40,194,0,0,40,194,0,0,28,194,0,0,24,194,0,0,36,194,0,0,44,194,0,0,80,194,0,0,48,194,0,0,32,194,0,0,28,194,0,0,20,194,0,0,20,194,0,0,32,194,0,0,60,194,0,0,88,194,0,0,72,194,0,0,64,194,0,0,72,194,0,0,92,194,0,0,116,194,0,0,108,194,0,0,120,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,138,194,0,0,138,194,0,0,146,194,0,0,148,194,0,0,148,194,0,0,150,194,0,0,154,194,0,0,158,194,0,0,164,194,0,0,174,194,0,0,182,194,0,0,190,194,0,0,200,194,0,0,216,194,0,0,230,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,224,193,0,0,208,193,0,0,192,193,0,0,176,193,0,0,160,193,0,0,160,193,0,0,184,193,0,0,232,193,0,0,240,193,0,0,248,193,0,0,224,193,0,0,216,193,0,0,224,193,0,0,224,193,0,0,224,193,0,0,12,194,0,0,32,194,0,0,4,194,0,0,0,194,0,0,232,193,0,0,240,193,0,0,240,193,0,0,240,193,0,0,20,194,0,0,52,194,0,0,36,194,0,0,20,194,0,0,24,194,0,0,52,194,0,0,60,194,0,0,60,194,0,0,64,194,0,0,84,194,0,0,68,194,0,0,64,194,0,0,72,194,0,0,68,194,0,0,68,194,0,0,76,194,0,0,80,194,0,0,104,194,0,0,96,194,0,0,100,194,0,0,96,194,0,0,112,194,0,0,116,194,0,0,120,194,0,0,140,194,0,0,144,194,0,0,148,194,0,0,156,194,0,0,166,194,0,0,176,194,0,0,186,194,0,0,200,194,0,0,212,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,210,194,0,0,200,194,0,0,190,194,0,0,182,194,0,0,174,194,0,0,166,194,0,0,160,194,0,0,156,194,0,0,152,194,0,0,156,194,0,0,156,194,0,0,162,194,0,0,166,194,0,0,170,194,0,0,172,194,0,0,170,194,0,0,172,194,0,0,174,194,0,0,180,194,0,0,194,194,0,0,214,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,210,194,0,0,200,194,0,0,190,194,0,0,180,194,0,0,170,194,0,0,162,194,0,0,154,194,0,0,146,194,0,0,140,194,0,0,134,194,0,0,134,194,0,0,136,194,0,0,150,194,0,0,146,194,0,0,140,194,0,0,138,194,0,0,140,194,0,0,144,194,0,0,150,194,0,0,158,194,0,0,168,194,0,0,166,194,0,0,168,194,0,0,172,194,0,0,176,194,0,0,178,194,0,0,178,194,0,0,186,194,0,0,196,194,0,0,210,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,200,194,0,0,190,194,0,0,180,194,0,0,170,194,0,0,160,194,0,0,152,194,0,0,142,194,0,0,136,194,0,0,136,194,0,0,130,194,0,0,124,194,0,0,124,194,0,0,120,194,0,0,120,194,0,0,128,194,0,0,130,194,0,0,128,194,0,0,116,194,0,0,120,194,0,0,124,194,0,0,128,194,0,0,132,194,0,0,136,194,0,0,146,194,0,0,146,194,0,0,148,194,0,0,150,194,0,0,152,194,0,0,162,194,0,0,166,194,0,0,170,194,0,0,176,194,0,0,178,194,0,0,184,194,0,0,190,194,0,0,200,194,0,0,216,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,160,194,0,0,150,194,0,0,142,194,0,0,136,194,0,0,130,194,0,0,124,194,0,0,120,194,0,0,116,194,0,0,116,194,0,0,116,194,0,0,116,194,0,0,108,194,0,0,96,194,0,0,100,194,0,0,84,194,0,0,72,194,0,0,104,194,0,0,80,194,0,0,72,194,0,0,72,194,0,0,80,194,0,0,84,194,0,0,88,194,0,0,104,194,0,0,134,194,0,0,124,194,0,0,134,194,0,0,136,194,0,0,144,194,0,0,150,194,0,0,156,194,0,0,160,194,0,0,162,194,0,0,162,194,0,0,164,194,0,0,170,194,0,0,178,194,0,0,180,194,0,0,186,194,0,0,194,194,0,0,202,194,0,0,214,194,0,0,228,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,130,194,0,0,116,194,0,0,108,194,0,0,100,194,0,0,96,194,0,0,92,194,0,0,92,194,0,0,96,194,0,0,96,194,0,0,100,194,0,0,92,194,0,0,84,194,0,0,80,194,0,0,60,194,0,0,48,194,0,0,48,194,0,0,72,194,0,0,48,194,0,0,36,194,0,0,28,194,0,0,28,194,0,0,40,194,0,0,32,194,0,0,56,194,0,0,76,194,0,0,68,194,0,0,72,194,0,0,84,194,0,0,88,194,0,0,124,194,0,0,112,194,0,0,116,194,0,0,120,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,140,194,0,0,146,194,0,0,148,194,0,0,150,194,0,0,152,194,0,0,150,194,0,0,158,194,0,0,170,194,0,0,178,194,0,0,182,194,0,0,192,194,0,0,204,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,80,194,0,0,72,194,0,0,68,194,0,0,68,194,0,0,64,194,0,0,64,194,0,0,64,194,0,0,68,194,0,0,72,194,0,0,72,194,0,0,68,194,0,0,56,194,0,0,44,194,0,0,28,194,0,0,12,194,0,0,4,194,0,0,24,194,0,0,16,194,0,0,0,194,0,0,232,193,0,0,0,194,0,0,0,194,0,0,0,194,0,0,12,194,0,0,48,194,0,0,28,194,0,0,24,194,0,0,24,194,0,0,56,194,0,0,72,194,0,0,52,194,0,0,56,194,0,0,84,194,0,0,72,194,0,0,72,194,0,0,72,194,0,0,88,194,0,0,88,194,0,0,84,194,0,0,84,194,0,0,96,194,0,0,100,194,0,0,108,194,0,0,132,194,0,0,140,194,0,0,144,194,0,0,148,194,0,0,158,194,0,0,166,194,0,0,170,194,0,0,180,194,0,0,194,194,0,0,228,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,210,194,0,0,200,194,0,0,190,194,0,0,180,194,0,0,172,194,0,0,160,194,0,0,150,194,0,0,150,194,0,0,158,194,0,0,160,194,0,0,158,194,0,0,160,194,0,0,162,194,0,0,164,194,0,0,176,194,0,0,190,194,0,0,206,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,216,194,0,0,206,194,0,0,196,194,0,0,186,194,0,0,176,194,0,0,166,194,0,0,158,194,0,0,156,194,0,0,150,194,0,0,142,194,0,0,134,194,0,0,136,194,0,0,146,194,0,0,146,194,0,0,144,194,0,0,146,194,0,0,150,194,0,0,154,194,0,0,160,194,0,0,164,194,0,0,176,194,0,0,186,194,0,0,200,194,0,0,214,194,0,0,228,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,210,194,0,0,202,194,0,0,192,194,0,0,180,194,0,0,172,194,0,0,162,194,0,0,154,194,0,0,146,194,0,0,138,194,0,0,132,194,0,0,116,194,0,0,120,194,0,0,132,194,0,0,128,194,0,0,120,194,0,0,130,194,0,0,132,194,0,0,140,194,0,0,144,194,0,0,152,194,0,0,162,194,0,0,160,194,0,0,168,194,0,0,180,194,0,0,190,194,0,0,204,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,214,194,0,0,206,194,0,0,194,194,0,0,184,194,0,0,176,194,0,0,166,194,0,0,158,194,0,0,148,194,0,0,140,194,0,0,132,194,0,0,108,194,0,0,84,194,0,0,104,194,0,0,120,194,0,0,92,194,0,0,88,194,0,0,88,194,0,0,88,194,0,0,104,194,0,0,116,194,0,0,120,194,0,0,144,194,0,0,140,194,0,0,144,194,0,0,150,194,0,0,156,194,0,0,160,194,0,0,162,194,0,0,160,194,0,0,166,194,0,0,166,194,0,0,176,194,0,0,186,194,0,0,200,194,0,0,214,194,0,0,230,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,200,194,0,0,190,194,0,0,180,194,0,0,170,194,0,0,160,194,0,0,150,194,0,0,140,194,0,0,132,194,0,0,120,194,0,0,96,194,0,0,64,194,0,0,48,194,0,0,64,194,0,0,56,194,0,0,56,194,0,0,44,194,0,0,56,194,0,0,64,194,0,0,64,194,0,0,76,194,0,0,104,194,0,0,104,194,0,0,108,194,0,0,112,194,0,0,120,194,0,0,120,194,0,0,116,194,0,0,116,194,0,0,130,194,0,0,128,194,0,0,130,194,0,0,136,194,0,0,140,194,0,0,148,194,0,0,150,194,0,0,156,194,0,0,162,194,0,0,172,194,0,0,190,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,200,194,0,0,190,194,0,0,180,194,0,0,170,194,0,0,160,194,0,0,150,194,0,0,140,194,0,0,130,194,0,0,116,194,0,0,92,194,0,0,68,194,0,0,28,194,0,0,4,194,0,0,32,194,0,0,12,194,0,0,0,194,0,0,24,194,0,0,32,194,0,0,4,194,0,0,12,194,0,0,20,194,0,0,56,194,0,0,36,194,0,0,52,194,0,0,48,194,0,0,56,194,0,0,40,194,0,0,52,194,0,0,56,194,0,0,80,194,0,0,72,194,0,0,72,194,0,0,72,194,0,0,88,194,0,0,88,194,0,0,92,194,0,0,100,194,0,0,120,194,0,0,128,194,0,0,132,194,0,0,136,194,0,0,140,194,0,0,152,194,0,0,162,194,0,0,180,194,0,0,200,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,196,194,0,0,180,194,0,0,170,194,0,0,164,194,0,0,166,194,0,0,160,194,0,0,156,194,0,0,168,194,0,0,158,194,0,0,160,194,0,0,166,194,0,0,174,194,0,0,178,194,0,0,182,194,0,0,186,194,0,0,198,194,0,0,212,194,0,0,234,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,196,194,0,0,180,194,0,0,170,194,0,0,160,194,0,0,150,194,0,0,140,194,0,0,136,194,0,0,148,194,0,0,144,194,0,0,148,194,0,0,154,194,0,0,160,194,0,0,164,194,0,0,170,194,0,0,174,194,0,0,184,194,0,0,178,194,0,0,182,194,0,0,190,194,0,0,200,194,0,0,212,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,196,194,0,0,180,194,0,0,166,194,0,0,150,194,0,0,142,194,0,0,124,194,0,0,128,194,0,0,134,194,0,0,120,194,0,0,128,194,0,0,134,194,0,0,140,194,0,0,146,194,0,0,154,194,0,0,162,194,0,0,168,194,0,0,166,194,0,0,170,194,0,0,178,194,0,0,180,194,0,0,186,194,0,0,196,194,0,0,208,194,0,0,218,194,0,0,228,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE+30720);allocate([0,192,121,196,0,192,121,196,0,0,206,194,0,0,192,194,0,0,176,194,0,0,162,194,0,0,150,194,0,0,136,194,0,0,104,194,0,0,88,194,0,0,96,194,0,0,88,194,0,0,96,194,0,0,96,194,0,0,104,194,0,0,112,194,0,0,124,194,0,0,132,194,0,0,148,194,0,0,138,194,0,0,144,194,0,0,144,194,0,0,150,194,0,0,148,194,0,0,154,194,0,0,162,194,0,0,162,194,0,0,164,194,0,0,168,194,0,0,174,194,0,0,186,194,0,0,192,194,0,0,198,194,0,0,208,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,216,194,0,0,204,194,0,0,192,194,0,0,182,194,0,0,170,194,0,0,160,194,0,0,148,194,0,0,136,194,0,0,112,194,0,0,76,194,0,0,56,194,0,0,64,194,0,0,56,194,0,0,44,194,0,0,52,194,0,0,60,194,0,0,60,194,0,0,68,194,0,0,64,194,0,0,96,194,0,0,84,194,0,0,92,194,0,0,104,194,0,0,100,194,0,0,124,194,0,0,104,194,0,0,112,194,0,0,132,194,0,0,128,194,0,0,134,194,0,0,140,194,0,0,140,194,0,0,148,194,0,0,154,194,0,0,168,194,0,0,172,194,0,0,178,194,0,0,182,194,0,0,186,194,0,0,188,194,0,0,202,194,0,0,218,194,0,0,236,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,216,194,0,0,206,194,0,0,196,194,0,0,186,194,0,0,176,194,0,0,166,194,0,0,156,194,0,0,146,194,0,0,136,194,0,0,112,194,0,0,84,194,0,0,48,194,0,0,12,194,0,0,24,194,0,0,24,194,0,0,8,194,0,0,8,194,0,0,16,194,0,0,32,194,0,0,36,194,0,0,48,194,0,0,76,194,0,0,52,194,0,0,56,194,0,0,60,194,0,0,56,194,0,0,88,194,0,0,72,194,0,0,68,194,0,0,72,194,0,0,72,194,0,0,72,194,0,0,76,194,0,0,88,194,0,0,100,194,0,0,104,194,0,0,112,194,0,0,132,194,0,0,132,194,0,0,132,194,0,0,128,194,0,0,130,194,0,0,136,194,0,0,154,194,0,0,164,194,0,0,174,194,0,0,190,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,214,194,0,0,204,194,0,0,194,194,0,0,184,194,0,0,174,194,0,0,166,194,0,0,156,194,0,0,150,194,0,0,164,194,0,0,158,194,0,0,166,194,0,0,170,194,0,0,178,194,0,0,184,194,0,0,190,194,0,0,196,194,0,0,202,194,0,0,210,194,0,0,218,194,0,0,226,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,212,194,0,0,200,194,0,0,190,194,0,0,180,194,0,0,172,194,0,0,162,194,0,0,156,194,0,0,148,194,0,0,138,194,0,0,148,194,0,0,148,194,0,0,152,194,0,0,158,194,0,0,166,194,0,0,168,194,0,0,172,194,0,0,178,194,0,0,184,194,0,0,194,194,0,0,186,194,0,0,200,194,0,0,206,194,0,0,214,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,212,194,0,0,200,194,0,0,190,194,0,0,180,194,0,0,174,194,0,0,166,194,0,0,160,194,0,0,150,194,0,0,138,194,0,0,112,194,0,0,132,194,0,0,132,194,0,0,136,194,0,0,140,194,0,0,148,194,0,0,156,194,0,0,158,194,0,0,162,194,0,0,162,194,0,0,166,194,0,0,168,194,0,0,174,194,0,0,186,194,0,0,192,194,0,0,198,194,0,0,206,194,0,0,214,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,216,194,0,0,206,194,0,0,196,194,0,0,186,194,0,0,178,194,0,0,170,194,0,0,164,194,0,0,156,194,0,0,142,194,0,0,120,194,0,0,92,194,0,0,104,194,0,0,104,194,0,0,88,194,0,0,88,194,0,0,92,194,0,0,108,194,0,0,116,194,0,0,120,194,0,0,140,194,0,0,132,194,0,0,132,194,0,0,134,194,0,0,140,194,0,0,144,194,0,0,150,194,0,0,156,194,0,0,168,194,0,0,168,194,0,0,168,194,0,0,176,194,0,0,182,194,0,0,180,194,0,0,190,194,0,0,196,194,0,0,204,194,0,0,206,194,0,0,212,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,216,194,0,0,206,194,0,0,196,194,0,0,188,194,0,0,180,194,0,0,174,194,0,0,164,194,0,0,158,194,0,0,146,194,0,0,134,194,0,0,104,194,0,0,60,194,0,0,72,194,0,0,52,194,0,0,36,194,0,0,52,194,0,0,64,194,0,0,48,194,0,0,48,194,0,0,68,194,0,0,88,194,0,0,76,194,0,0,64,194,0,0,60,194,0,0,68,194,0,0,72,194,0,0,76,194,0,0,100,194,0,0,104,194,0,0,112,194,0,0,124,194,0,0,138,194,0,0,140,194,0,0,138,194,0,0,142,194,0,0,148,194,0,0,156,194,0,0,164,194,0,0,180,194,0,0,190,194,0,0,202,194,0,0,210,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,202,194,0,0,194,194,0,0,186,194,0,0,180,194,0,0,170,194,0,0,160,194,0,0,154,194,0,0,144,194,0,0,130,194,0,0,96,194,0,0,64,194,0,0,20,194,0,0,32,194,0,0,16,194,0,0,8,194,0,0,32,194,0,0,72,194,0,0,60,194,0,0,24,194,0,0,36,194,0,0,60,194,0,0,24,194,0,0,12,194,0,0,28,194,0,0,24,194,0,0,44,194,0,0,32,194,0,0,52,194,0,0,72,194,0,0,52,194,0,0,48,194,0,0,60,194,0,0,72,194,0,0,92,194,0,0,64,194,0,0,64,194,0,0,80,194,0,0,132,194,0,0,140,194,0,0,152,194,0,0,164,194,0,0,180,194,0,0,194,194,0,0,210,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,216,194,0,0,206,194,0,0,196,194,0,0,186,194,0,0,172,194,0,0,158,194,0,0,152,194,0,0,166,194,0,0,162,194,0,0,170,194,0,0,174,194,0,0,178,194,0,0,186,194,0,0,196,194,0,0,204,194,0,0,214,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,216,194,0,0,206,194,0,0,196,194,0,0,186,194,0,0,172,194,0,0,158,194,0,0,142,194,0,0,154,194,0,0,148,194,0,0,154,194,0,0,158,194,0,0,162,194,0,0,168,194,0,0,170,194,0,0,180,194,0,0,184,194,0,0,186,194,0,0,184,194,0,0,196,194,0,0,202,194,0,0,216,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,216,194,0,0,206,194,0,0,196,194,0,0,186,194,0,0,174,194,0,0,156,194,0,0,136,194,0,0,130,194,0,0,132,194,0,0,120,194,0,0,130,194,0,0,134,194,0,0,140,194,0,0,146,194,0,0,150,194,0,0,156,194,0,0,164,194,0,0,164,194,0,0,166,194,0,0,168,194,0,0,182,194,0,0,186,194,0,0,196,194,0,0,204,194,0,0,212,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,200,194,0,0,190,194,0,0,180,194,0,0,164,194,0,0,148,194,0,0,120,194,0,0,100,194,0,0,104,194,0,0,96,194,0,0,76,194,0,0,80,194,0,0,80,194,0,0,88,194,0,0,88,194,0,0,104,194,0,0,132,194,0,0,108,194,0,0,112,194,0,0,124,194,0,0,132,194,0,0,138,194,0,0,146,194,0,0,158,194,0,0,166,194,0,0,168,194,0,0,160,194,0,0,162,194,0,0,162,194,0,0,164,194,0,0,176,194,0,0,184,194,0,0,196,194,0,0,210,194,0,0,226,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,214,194,0,0,204,194,0,0,194,194,0,0,184,194,0,0,168,194,0,0,158,194,0,0,138,194,0,0,100,194,0,0,60,194,0,0,80,194,0,0,60,194,0,0,48,194,0,0,52,194,0,0,72,194,0,0,80,194,0,0,40,194,0,0,40,194,0,0,84,194,0,0,44,194,0,0,44,194,0,0,64,194,0,0,76,194,0,0,96,194,0,0,92,194,0,0,80,194,0,0,100,194,0,0,108,194,0,0,116,194,0,0,120,194,0,0,134,194,0,0,142,194,0,0,156,194,0,0,166,194,0,0,172,194,0,0,188,194,0,0,196,194,0,0,206,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,200,194,0,0,190,194,0,0,180,194,0,0,168,194,0,0,156,194,0,0,140,194,0,0,116,194,0,0,76,194,0,0,36,194,0,0,32,194,0,0,24,194,0,0,32,194,0,0,56,194,0,0,80,194,0,0,76,194,0,0,36,194,0,0,32,194,0,0,56,194,0,0,32,194,0,0,24,194,0,0,24,194,0,0,36,194,0,0,56,194,0,0,36,194,0,0,56,194,0,0,60,194,0,0,44,194,0,0,44,194,0,0,52,194,0,0,36,194,0,0,52,194,0,0,96,194,0,0,134,194,0,0,136,194,0,0,166,194,0,0,174,194,0,0,180,194,0,0,190,194,0,0,204,194,0,0,214,194,0,0,226,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,218,194,0,0,210,194,0,0,202,194,0,0,192,194,0,0,182,194,0,0,168,194,0,0,154,194,0,0,164,194,0,0,164,194,0,0,170,194,0,0,178,194,0,0,188,194,0,0,200,194,0,0,212,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,212,194,0,0,206,194,0,0,196,194,0,0,184,194,0,0,170,194,0,0,160,194,0,0,142,194,0,0,150,194,0,0,144,194,0,0,152,194,0,0,160,194,0,0,168,194,0,0,172,194,0,0,178,194,0,0,186,194,0,0,200,194,0,0,214,194,0,0,226,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,214,194,0,0,208,194,0,0,202,194,0,0,194,194,0,0,184,194,0,0,176,194,0,0,168,194,0,0,160,194,0,0,128,194,0,0,132,194,0,0,124,194,0,0,128,194,0,0,132,194,0,0,138,194,0,0,146,194,0,0,154,194,0,0,166,194,0,0,166,194,0,0,172,194,0,0,182,194,0,0,196,194,0,0,208,194,0,0,222,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,214,194,0,0,208,194,0,0,202,194,0,0,194,194,0,0,184,194,0,0,180,194,0,0,168,194,0,0,148,194,0,0,100,194,0,0,104,194,0,0,80,194,0,0,92,194,0,0,88,194,0,0,72,194,0,0,80,194,0,0,72,194,0,0,80,194,0,0,124,194,0,0,120,194,0,0,138,194,0,0,152,194,0,0,154,194,0,0,156,194,0,0,156,194,0,0,158,194,0,0,164,194,0,0,176,194,0,0,188,194,0,0,200,194,0,0,212,194,0,0,222,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,212,194,0,0,204,194,0,0,196,194,0,0,190,194,0,0,180,194,0,0,170,194,0,0,166,194,0,0,156,194,0,0,140,194,0,0,72,194,0,0,72,194,0,0,36,194,0,0,48,194,0,0,68,194,0,0,60,194,0,0,72,194,0,0,72,194,0,0,48,194,0,0,92,194,0,0,56,194,0,0,60,194,0,0,64,194,0,0,64,194,0,0,88,194,0,0,68,194,0,0,68,194,0,0,104,194,0,0,120,194,0,0,142,194,0,0,162,194,0,0,174,194,0,0,184,194,0,0,194,194,0,0,204,194,0,0,216,194,0,0,228,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,212,194,0,0,204,194,0,0,196,194,0,0,190,194,0,0,180,194,0,0,170,194,0,0,166,194,0,0,156,194,0,0,140,194,0,0,52,194,0,0,44,194,0,0,36,194,0,0,60,194,0,0,72,194,0,0,76,194,0,0,72,194,0,0,68,194,0,0,52,194,0,0,60,194,0,0,36,194,0,0,48,194,0,0,36,194,0,0,28,194,0,0,44,194,0,0,24,194,0,0,20,194,0,0,32,194,0,0,36,194,0,0,48,194,0,0,72,194,0,0,104,194,0,0,130,194,0,0,146,194,0,0,158,194,0,0,170,194,0,0,184,194,0,0,194,194,0,0,202,194,0,0,210,194,0,0,218,194,0,0,226,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,214,194,0,0,200,194,0,0,190,194,0,0,174,194,0,0,162,194,0,0,170,194,0,0,166,194,0,0,176,194,0,0,186,194,0,0,200,194,0,0,214,194,0,0,228,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,214,194,0,0,202,194,0,0,190,194,0,0,176,194,0,0,166,194,0,0,152,194,0,0,146,194,0,0,144,194,0,0,158,194,0,0,168,194,0,0,180,194,0,0,190,194,0,0,200,194,0,0,210,194,0,0,220,194,0,0,230,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,208,194,0,0,196,194,0,0,184,194,0,0,174,194,0,0,162,194,0,0,140,194,0,0,130,194,0,0,120,194,0,0,134,194,0,0,142,194,0,0,148,194,0,0,160,194,0,0,170,194,0,0,182,194,0,0,190,194,0,0,198,194,0,0,206,194,0,0,216,194,0,0,222,194,0,0,228,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,206,194,0,0,194,194,0,0,180,194,0,0,170,194,0,0,152,194,0,0,112,194,0,0,96,194,0,0,88,194,0,0,112,194,0,0,120,194,0,0,116,194,0,0,96,194,0,0,124,194,0,0,130,194,0,0,146,194,0,0,148,194,0,0,154,194,0,0,150,194,0,0,156,194,0,0,162,194,0,0,172,194,0,0,174,194,0,0,176,194,0,0,182,194,0,0,188,194,0,0,196,194,0,0,206,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,200,194,0,0,194,194,0,0,184,194,0,0,172,194,0,0,162,194,0,0,158,194,0,0,140,194,0,0,100,194,0,0,76,194,0,0,60,194,0,0,76,194,0,0,104,194,0,0,112,194,0,0,96,194,0,0,84,194,0,0,72,194,0,0,104,194,0,0,80,194,0,0,72,194,0,0,72,194,0,0,84,194,0,0,92,194,0,0,128,194,0,0,138,194,0,0,142,194,0,0,170,194,0,0,164,194,0,0,156,194,0,0,162,194,0,0,170,194,0,0,190,194,0,0,204,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,200,194,0,0,194,194,0,0,184,194,0,0,170,194,0,0,166,194,0,0,158,194,0,0,144,194,0,0,68,194,0,0,32,194,0,0,44,194,0,0,44,194,0,0,88,194,0,0,96,194,0,0,76,194,0,0,72,194,0,0,32,194,0,0,44,194,0,0,24,194,0,0,16,194,0,0,12,194,0,0,20,194,0,0,24,194,0,0,20,194,0,0,48,194,0,0,88,194,0,0,112,194,0,0,100,194,0,0,112,194,0,0,140,194,0,0,150,194,0,0,168,194,0,0,184,194,0,0,206,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,204,194,0,0,190,194,0,0,178,194,0,0,164,194,0,0,166,194,0,0,168,194,0,0,180,194,0,0,184,194,0,0,198,194,0,0,214,194,0,0,226,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,214,194,0,0,202,194,0,0,190,194,0,0,178,194,0,0,166,194,0,0,144,194,0,0,148,194,0,0,156,194,0,0,170,194,0,0,176,194,0,0,176,194,0,0,180,194,0,0,184,194,0,0,196,194,0,0,210,194,0,0,222,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,218,194,0,0,206,194,0,0,194,194,0,0,186,194,0,0,174,194,0,0,162,194,0,0,140,194,0,0,140,194,0,0,134,194,0,0,150,194,0,0,146,194,0,0,152,194,0,0,158,194,0,0,162,194,0,0,166,194,0,0,176,194,0,0,178,194,0,0,194,194,0,0,206,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,214,194,0,0,200,194,0,0,188,194,0,0,176,194,0,0,166,194,0,0,150,194,0,0,124,194,0,0,108,194,0,0,108,194,0,0,124,194,0,0,132,194,0,0,112,194,0,0,120,194,0,0,134,194,0,0,134,194,0,0,154,194,0,0,152,194,0,0,162,194,0,0,176,194,0,0,172,194,0,0,184,194,0,0,192,194,0,0,204,194,0,0,218,194,0,0,232,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,196,194,0,0,184,194,0,0,172,194,0,0,162,194,0,0,146,194,0,0,96,194,0,0,80,194,0,0,60,194,0,0,92,194,0,0,112,194,0,0,104,194,0,0,80,194,0,0,76,194,0,0,52,194,0,0,68,194,0,0,72,194,0,0,84,194,0,0,88,194,0,0,116,194,0,0,142,194,0,0,140,194,0,0,138,194,0,0,156,194,0,0,158,194,0,0,174,194,0,0,180,194,0,0,192,194,0,0,208,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,206,194,0,0,192,194,0,0,180,194,0,0,172,194,0,0,156,194,0,0,140,194,0,0,76,194,0,0,40,194,0,0,60,194,0,0,64,194,0,0,92,194,0,0,88,194,0,0,88,194,0,0,84,194,0,0,40,194,0,0,12,194,0,0,224,193,0,0,4,194,0,0,24,194,0,0,20,194,0,0,48,194,0,0,60,194,0,0,68,194,0,0,88,194,0,0,124,194,0,0,136,194,0,0,156,194,0,0,164,194,0,0,178,194,0,0,188,194,0,0,198,194,0,0,208,194,0,0,218,194,0,0,228,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,200,194,0,0,180,194,0,0,158,194,0,0,170,194,0,0,162,194,0,0,164,194,0,0,164,194,0,0,178,194,0,0,188,194,0,0,198,194,0,0,206,194,0,0,218,194,0,0,230,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,194,194,0,0,170,194,0,0,144,194,0,0,148,194,0,0,140,194,0,0,140,194,0,0,140,194,0,0,152,194,0,0,170,194,0,0,182,194,0,0,186,194,0,0,194,194,0,0,206,194,0,0,218,194,0,0,230,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,224,194,0,0,186,194,0,0,162,194,0,0,136,194,0,0,120,194,0,0,112,194,0,0,112,194,0,0,100,194,0,0,124,194,0,0,140,194,0,0,154,194,0,0,164,194,0,0,180,194,0,0,186,194,0,0,196,194,0,0,208,194,0,0,218,194,0,0,226,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,226,194,0,0,200,194,0,0,186,194,0,0,168,194,0,0,124,194,0,0,104,194,0,0,64,194,0,0,84,194,0,0,88,194,0,0,80,194,0,0,80,194,0,0,100,194,0,0,128,194,0,0,132,194,0,0,152,194,0,0,166,194,0,0,162,194,0,0,170,194,0,0,170,194,0,0,180,194,0,0,190,194,0,0,196,194,0,0,202,194,0,0,206,194,0,0,212,194,0,0,216,194,0,0,222,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,210,194,0,0,190,194,0,0,172,194,0,0,148,194,0,0,84,194,0,0,72,194,0,0,24,194,0,0,44,194,0,0,68,194,0,0,44,194,0,0,40,194,0,0,28,194,0,0,28,194,0,0,56,194,0,0,80,194,0,0,100,194,0,0,96,194,0,0,144,194,0,0,138,194,0,0,148,194,0,0,162,194,0,0,174,194,0,0,184,194,0,0,188,194,0,0,194,194,0,0,198,194,0,0,204,194,0,0,210,194,0,0,216,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,216,194,0,0,198,194,0,0,180,194,0,0,152,194,0,0,132,194,0,0,52,194,0,0,44,194,0,0,36,194,0,0,48,194,0,0,60,194,0,0,44,194,0,0,60,194,0,0,32,194,0,0,240,193,0,0,248,193,0,0,248,193,0,0,28,194,0,0,4,194,0,0,32,194,0,0,36,194,0,0,44,194,0,0,84,194,0,0,108,194,0,0,140,194,0,0,146,194,0,0,154,194,0,0,158,194,0,0,164,194,0,0,168,194,0,0,174,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,182,194,0,0,152,194,0,0,150,194,0,0,170,194,0,0,186,194,0,0,196,194,0,0,208,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,182,194,0,0,140,194,0,0,140,194,0,0,150,194,0,0,172,194,0,0,178,194,0,0,188,194,0,0,196,194,0,0,202,194,0,0,212,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,190,194,0,0,160,194,0,0,112,194,0,0,130,194,0,0,128,194,0,0,148,194,0,0,166,194,0,0,176,194,0,0,182,194,0,0,190,194,0,0,198,194,0,0,206,194,0,0,214,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,190,194,0,0,160,194,0,0,104,194,0,0,92,194,0,0,68,194,0,0,132,194,0,0,136,194,0,0,142,194,0,0,156,194,0,0,156,194,0,0,160,194,0,0,176,194,0,0,170,194,0,0,178,194,0,0,194,194,0,0,200,194,0,0,210,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,190,194,0,0,160,194,0,0,84,194,0,0,80,194,0,0,36,194,0,0,108,194,0,0,108,194,0,0,68,194,0,0,104,194,0,0,96,194,0,0,124,194,0,0,172,194,0,0,158,194,0,0,180,194,0,0,186,194,0,0,196,194,0,0,206,194,0,0,214,194,0,0,224,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,194,194,0,0,182,194,0,0,146,194,0,0,52,194,0,0,32,194,0,0,4,194,0,0,84,194,0,0,116,194,0,0,68,194,0,0,88,194,0,0,72,194,0,0,72,194,0,0,112,194,0,0,80,194,0,0,134,194,0,0,148,194,0,0,162,194,0,0,184,194,0,0,192,194,0,0,200,194,0,0,210,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,226,194,0,0,212,194,0,0,198,194,0,0,184,194,0,0,154,194,0,0,160,194,0,0,176,194,0,0,194,194,0,0,212,194,0,0,230,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE+40960);allocate([0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,232,194,0,0,218,194,0,0,204,194,0,0,190,194,0,0,178,194,0,0,148,194,0,0,144,194,0,0,176,194,0,0,174,194,0,0,190,194,0,0,204,194,0,0,218,194,0,0,232,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,232,194,0,0,218,194,0,0,204,194,0,0,190,194,0,0,178,194,0,0,150,194,0,0,132,194,0,0,148,194,0,0,154,194,0,0,156,194,0,0,172,194,0,0,174,194,0,0,180,194,0,0,192,194,0,0,210,194,0,0,230,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,230,194,0,0,216,194,0,0,202,194,0,0,188,194,0,0,176,194,0,0,132,194,0,0,96,194,0,0,116,194,0,0,140,194,0,0,130,194,0,0,156,194,0,0,144,194,0,0,166,194,0,0,168,194,0,0,186,194,0,0,196,194,0,0,210,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,210,194,0,0,190,194,0,0,178,194,0,0,164,194,0,0,100,194,0,0,80,194,0,0,80,194,0,0,108,194,0,0,96,194,0,0,108,194,0,0,104,194,0,0,138,194,0,0,134,194,0,0,176,194,0,0,164,194,0,0,164,194,0,0,178,194,0,0,188,194,0,0,200,194,0,0,216,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,202,194,0,0,192,194,0,0,180,194,0,0,166,194,0,0,154,194,0,0,88,194,0,0,44,194,0,0,24,194,0,0,72,194,0,0,64,194,0,0,80,194,0,0,64,194,0,0,40,194,0,0,40,194,0,0,76,194,0,0,80,194,0,0,84,194,0,0,108,194,0,0,130,194,0,0,142,194,0,0,156,194,0,0,170,194,0,0,190,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,240,194,0,0,210,194,0,0,172,194,0,0,136,194,0,0,156,194,0,0,158,194,0,0,180,194,0,0,200,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,240,194,0,0,210,194,0,0,172,194,0,0,132,194,0,0,146,194,0,0,154,194,0,0,176,194,0,0,192,194,0,0,210,194,0,0,230,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,240,194,0,0,210,194,0,0,184,194,0,0,160,194,0,0,116,194,0,0,128,194,0,0,136,194,0,0,160,194,0,0,174,194,0,0,184,194,0,0,200,194,0,0,220,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,240,194,0,0,208,194,0,0,182,194,0,0,158,194,0,0,80,194,0,0,112,194,0,0,88,194,0,0,128,194,0,0,138,194,0,0,154,194,0,0,160,194,0,0,164,194,0,0,168,194,0,0,170,194,0,0,174,194,0,0,176,194,0,0,180,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,236,194,0,0,200,194,0,0,174,194,0,0,154,194,0,0,68,194,0,0,72,194,0,0,48,194,0,0,104,194,0,0,116,194,0,0,116,194,0,0,134,194,0,0,130,194,0,0,120,194,0,0,120,194,0,0,120,194,0,0,130,194,0,0,136,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,230,194,0,0,196,194,0,0,168,194,0,0,120,194,0,0,68,194,0,0,48,194,0,0,24,194,0,0,56,194,0,0,68,194,0,0,68,194,0,0,56,194,0,0,28,194,0,0,20,194,0,0,28,194,0,0,32,194,0,0,40,194,0,0,44,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,176,194,0,0,148,194,0,0,154,194,0,0,164,194,0,0,164,194,0,0,170,194,0,0,180,194,0,0,188,194,0,0,198,194,0,0,208,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,176,194,0,0,132,194,0,0,140,194,0,0,162,194,0,0,160,194,0,0,162,194,0,0,168,194,0,0,176,194,0,0,182,194,0,0,186,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,176,194,0,0,116,194,0,0,124,194,0,0,140,194,0,0,142,194,0,0,148,194,0,0,154,194,0,0,160,194,0,0,166,194,0,0,170,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,172,194,0,0,120,194,0,0,124,194,0,0,120,194,0,0,120,194,0,0,104,194,0,0,80,194,0,0,72,194,0,0,72,194,0,0,80,194,0,0,88,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,236,194,0,0,216,194,0,0,168,194,0,0,84,194,0,0,72,194,0,0,72,194,0,0,72,194,0,0,92,194,0,0,60,194,0,0,52,194,0,0,32,194,0,0,32,194,0,0,32,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,236,194,0,0,200,194,0,0,146,194,0,0,44,194,0,0,20,194,0,0,40,194,0,0,44,194,0,0,84,194,0,0,24,194,0,0,20,194,0,0,12,194,0,0,12,194,0,0,24,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,200,194,0,0,182,194,0,0,168,194,0,0,148,194,0,0,160,194,0,0,160,194,0,0,160,194,0,0,160,194,0,0,160,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,200,194,0,0,182,194,0,0,168,194,0,0,148,194,0,0,136,194,0,0,136,194,0,0,136,194,0,0,136,194,0,0,136,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,200,194,0,0,172,194,0,0,156,194,0,0,140,194,0,0,112,194,0,0,52,194,0,0,240,193,0,0,168,193,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,200,194,0,0,174,194,0,0,156,194,0,0,134,194,0,0,64,194,0,0,24,194,0,0,232,193,0,0,168,193,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,200,194,0,0,172,194,0,0,138,194,0,0,96,194,0,0,52,194,0,0,12,194,0,0,4,194,0,0,232,193,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,0,220,194,0,0,200,194,0,0,166,194,0,0,142,194,0,0,64,194,0,0,216,193,0,0,24,194,0,0,20,194,0,0,8,194,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,0,192,121,196,62,180,228,51,9,145,243,51,139,178,1,52,60,32,10,52,35,26,19,52,96,169,28,52,167,215,38,52,75,175,49,52,80,59,61,52,112,135,73,52,35,160,86,52,184,146,100,52,85,109,115,52,136,159,129,52,252,11,138,52,147,4,147,52,105,146,156,52,50,191,166,52,63,149,177,52,147,31,189,52,228,105,201,52,173,128,214,52,54,113,228,52,166,73,243,52,136,140,1,53,192,247,9,53,6,239,18,53,118,123,28,53,192,166,38,53,55,123,49,53,218,3,61,53,94,76,73,53,59,97,86,53,185,79,100,53,252,37,115,53,138,121,129,53,134,227,137,53,124,217,146,53,133,100,156,53,82,142,166,53,51,97,177,53,37,232,188,53,220,46,201,53,206,65,214,53,65,46,228,53,87,2,243,53,143,102,1,54,79,207,9,54,245,195,18,54,152,77,28,54,232,117,38,54,50,71,49,54,116,204,60,54,94,17,73,54,101,34,86,54,206,12,100,54,184,222,114,54,151,83,129,54,28,187,137,54,114,174,146,54,175,54,156,54,129,93,166,54,53,45,177,54,199,176,188,54,228,243,200,54,1,3,214,54,96,235,227,54,30,187,242,54,162,64,1,55,235,166,9,55,241,152,18,55,201,31,28,55,30,69,38,55,61,19,49,55,30,149,60,55,111,214,72,55,162,227,85,55,247,201,99,55,137,151,114,55,175,45,129,55,190,146,137,55,116,131,146,55,230,8,156,55,190,44,166,55,71,249,176,55,121,121,188,55,254,184,200,55,71,196,213,55,146,168,227,55,248,115,242,55,192,26,1,56,147,126,9,56,249,109,18,56,6,242,27,56,98,20,38,56,86,223,48,56,216,93,60,56,146,155,72,56,242,164,85,56,51,135,99,56,110,80,114,56,211,7,129,56,107,106,137,56,130,88,146,56,42,219,155,56,9,252,165,56,104,197,176,56,59,66,188,56,41,126,200,56,160,133,213,56,217,101,227,56,232,44,242,56,233,244,0,57,70,86,9,57,14,67,18,57,81,196,27,57,181,227,37,57,127,171,48,57,162,38,60,57,197,96,72,57,83,102,85,57,131,68,99,57,104,9,114,57,1,226,128,57,36,66,137,57,157,45,146,57,123,173,155,57,99,203,165,57,153,145,176,57,13,11,188,57,102,67,200,57,11,71,213,57,50,35,227,57,237,229,241,57,29,207,0,58,5,46,9,58,48,24,18,58,169,150,27,58,21,179,37,58,183,119,48,58,124,239,59,58,10,38,72,58,199,39,85,58,230,1,99,58,120,194,113,58,59,188,128,58,233,25,137,58,198,2,146,58,219,127,155,58,203,154,165,58,216,93,176,58,239,211,187,58,179,8,200,58,136,8,213,58,159,224,226,58,7,159,241,58,92,169,0,59,208,5,9,59,94,237,17,59,15,105,27,59,132,130,37,59,253,67,48,59,103,184,59,59,97,235,71,59,77,233,84,59,93,191,98,59,156,123,113,59,127,150,128,59,186,241,136,59,249,215,145,59,71,82,155,59,65,106,165,59,39,42,176,59,226,156,187,59,18,206,199,59,23,202,212,59,32,158,226,59,53,88,241,59,166,131,0,60,167,221,8,60,152,194,17,60,130,59,27,60,1,82,37,60,84,16,48,60,97,129,59,60,200,176,71,60,229,170,84,60,232,124,98,60,212,52,113,60,207,112,128,60,150,201,136,60,58,173,145,60,192,36,155,60,197,57,165,60,133,246,175,60,229,101,187,60,130,147,199,60,185,139,212,60,180,91,226,60,121,17,241,60,251,93,0,61,137,181,8,61,223,151,17,61,2,14,27,61,141,33,37,61,185,220,47,61,109,74,59,61,64,118,71,61,145,108,84,61,133,58,98,61,34,238,112,61,42,75,128,61,127,161,136,61,136,130,145,61,72,247,154,61,88,9,165,61,242,194,175,61,248,46,187,61,3,89,199,61,109,77,212,61,92,25,226,61,209,202,240,61,91,56,0,62,119,141,8,62,51,109,17,62,144,224,26,62,39,241,36,62,46,169,47,62,135,19,59,62,202,59,71,62,77,46,84,62,55,248,97,62,132,167,112,62,143,37,128,62,115,121,136,62,226,87,145,62,220,201,154,62,249,216,164,62,109,143,175,62,27,248,186,62,149,30,199,62,51,15,212,62,23,215,225,62,61,132,240,62,198,18,0,63,114,101,8,63,147,66,17,63,43,179,26,63,206,192,36,63,177,117,47,63,178,220,58,63,101,1,71,63,29,240,83,63,251,181,97,63,251,96,112,63,0,0,128,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,73,110,118,97,108,105,100,32,118,111,114,98,105,115,32,104,101,97,100,101,114,63,0,0,86,111,114,98,105,115,32,100,101,99,111,100,101,114,32,102,97,105,108,101,100,32,109,121,115,116,101,114,105,111,117,115,108,121,63,32,37,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE+51200);var tempDoublePtr=Runtime.alignMemory(allocate(12,"i8",ALLOC_STATIC),8);assert(tempDoublePtr%8==0);function copyTempFloat(ptr){HEAP8[tempDoublePtr]=HEAP8[ptr];HEAP8[tempDoublePtr+1]=HEAP8[ptr+1];HEAP8[tempDoublePtr+2]=HEAP8[ptr+2];HEAP8[tempDoublePtr+3]=HEAP8[ptr+3]}function copyTempDouble(ptr){HEAP8[tempDoublePtr]=HEAP8[ptr];HEAP8[tempDoublePtr+1]=HEAP8[ptr+1];HEAP8[tempDoublePtr+2]=HEAP8[ptr+2];HEAP8[tempDoublePtr+3]=HEAP8[ptr+3];HEAP8[tempDoublePtr+4]=HEAP8[ptr+4];HEAP8[tempDoublePtr+5]=HEAP8[ptr+5];HEAP8[tempDoublePtr+6]=HEAP8[ptr+6];HEAP8[tempDoublePtr+7]=HEAP8[ptr+7]}var _cosf=Math_cos;Module["_i64Subtract"]=_i64Subtract;var _fabsf=Math_abs;var ___errno_state=0;function ___setErrNo(value){HEAP32[___errno_state>>2]=value;return value}var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};function _sysconf(name){switch(name){case 30:return PAGE_SIZE;case 85:return totalMemory/PAGE_SIZE;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:return 200809;case 79:return 0;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1e3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:{if(typeof navigator==="object")return navigator["hardwareConcurrency"]||1;return 1}}___setErrNo(ERRNO_CODES.EINVAL);return-1}Module["_memset"]=_memset;var _BDtoILow=true;Module["_bitshift64Shl"]=_bitshift64Shl;function _abort(){Module["abort"]()}var FS=undefined;var SOCKFS=undefined;function _send(fd,buf,len,flags){var sock=SOCKFS.getSocket(fd);if(!sock){___setErrNo(ERRNO_CODES.EBADF);return-1}return _write(fd,buf,len)}function _pwrite(fildes,buf,nbyte,offset){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{var slab=HEAP8;return FS.write(stream,slab,buf,nbyte,offset)}catch(e){FS.handleFSError(e);return-1}}function _write(fildes,buf,nbyte){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{var slab=HEAP8;return FS.write(stream,slab,buf,nbyte)}catch(e){FS.handleFSError(e);return-1}}function _fileno(stream){stream=FS.getStreamFromPtr(stream);if(!stream)return-1;return stream.fd}function _fwrite(ptr,size,nitems,stream){var bytesToWrite=nitems*size;if(bytesToWrite==0)return 0;var fd=_fileno(stream);var bytesWritten=_write(fd,ptr,bytesToWrite);if(bytesWritten==-1){var streamObj=FS.getStreamFromPtr(stream);if(streamObj)streamObj.error=true;return 0}else{return bytesWritten/size|0}}Module["_strlen"]=_strlen;function __reallyNegative(x){return x<0||x===0&&1/x===-Infinity}function __formatString(format,varargs){assert((varargs&3)===0);var textIndex=format;var argIndex=0;function getNextArg(type){var ret;argIndex=Runtime.prepVararg(argIndex,type);if(type==="double"){ret=(HEAP32[tempDoublePtr>>2]=HEAP32[varargs+argIndex>>2],HEAP32[tempDoublePtr+4>>2]=HEAP32[varargs+(argIndex+4)>>2],+HEAPF64[tempDoublePtr>>3]);argIndex+=8}else if(type=="i64"){ret=[HEAP32[varargs+argIndex>>2],HEAP32[varargs+(argIndex+4)>>2]];argIndex+=8}else{assert((argIndex&3)===0);type="i32";ret=HEAP32[varargs+argIndex>>2];argIndex+=4}return ret}var ret=[];var curr,next,currArg;while(1){var startTextIndex=textIndex;curr=HEAP8[textIndex>>0];if(curr===0)break;next=HEAP8[textIndex+1>>0];if(curr==37){var flagAlwaysSigned=false;var flagLeftAlign=false;var flagAlternative=false;var flagZeroPad=false;var flagPadSign=false;flagsLoop:while(1){switch(next){case 43:flagAlwaysSigned=true;break;case 45:flagLeftAlign=true;break;case 35:flagAlternative=true;break;case 48:if(flagZeroPad){break flagsLoop}else{flagZeroPad=true;break};case 32:flagPadSign=true;break;default:break flagsLoop}textIndex++;next=HEAP8[textIndex+1>>0]}var width=0;if(next==42){width=getNextArg("i32");textIndex++;next=HEAP8[textIndex+1>>0]}else{while(next>=48&&next<=57){width=width*10+(next-48);textIndex++;next=HEAP8[textIndex+1>>0]}}var precisionSet=false,precision=-1;if(next==46){precision=0;precisionSet=true;textIndex++;next=HEAP8[textIndex+1>>0];if(next==42){precision=getNextArg("i32");textIndex++}else{while(1){var precisionChr=HEAP8[textIndex+1>>0];if(precisionChr<48||precisionChr>57)break;precision=precision*10+(precisionChr-48);textIndex++}}next=HEAP8[textIndex+1>>0]}if(precision<0){precision=6;precisionSet=false}var argSize;switch(String.fromCharCode(next)){case"h":var nextNext=HEAP8[textIndex+2>>0];if(nextNext==104){textIndex++;argSize=1}else{argSize=2}break;case"l":var nextNext=HEAP8[textIndex+2>>0];if(nextNext==108){textIndex++;argSize=8}else{argSize=4}break;case"L":case"q":case"j":argSize=8;break;case"z":case"t":case"I":argSize=4;break;default:argSize=null}if(argSize)textIndex++;next=HEAP8[textIndex+1>>0];switch(String.fromCharCode(next)){case"d":case"i":case"u":case"o":case"x":case"X":case"p":{var signed=next==100||next==105;argSize=argSize||4;var currArg=getNextArg("i"+argSize*8);var origArg=currArg;var argText;if(argSize==8){currArg=Runtime.makeBigInt(currArg[0],currArg[1],next==117)}if(argSize<=4){var limit=Math.pow(256,argSize)-1;currArg=(signed?reSign:unSign)(currArg&limit,argSize*8)}var currAbsArg=Math.abs(currArg);var prefix="";if(next==100||next==105){if(argSize==8&&i64Math)argText=i64Math.stringify(origArg[0],origArg[1],null);else argText=reSign(currArg,8*argSize,1).toString(10)}else if(next==117){if(argSize==8&&i64Math)argText=i64Math.stringify(origArg[0],origArg[1],true);else argText=unSign(currArg,8*argSize,1).toString(10);currArg=Math.abs(currArg)}else if(next==111){argText=(flagAlternative?"0":"")+currAbsArg.toString(8)}else if(next==120||next==88){prefix=flagAlternative&&currArg!=0?"0x":"";if(argSize==8&&i64Math){if(origArg[1]){argText=(origArg[1]>>>0).toString(16);var lower=(origArg[0]>>>0).toString(16);while(lower.length<8)lower="0"+lower;argText+=lower}else{argText=(origArg[0]>>>0).toString(16)}}else if(currArg<0){currArg=-currArg;argText=(currAbsArg-1).toString(16);var buffer=[];for(var i=0;i<argText.length;i++){buffer.push((15-parseInt(argText[i],16)).toString(16))}argText=buffer.join("");while(argText.length<argSize*2)argText="f"+argText}else{argText=currAbsArg.toString(16)}if(next==88){prefix=prefix.toUpperCase();argText=argText.toUpperCase()}}else if(next==112){if(currAbsArg===0){argText="(nil)"}else{prefix="0x";argText=currAbsArg.toString(16)}}if(precisionSet){while(argText.length<precision){argText="0"+argText}}if(currArg>=0){if(flagAlwaysSigned){prefix="+"+prefix}else if(flagPadSign){prefix=" "+prefix}}if(argText.charAt(0)=="-"){prefix="-"+prefix;argText=argText.substr(1)}while(prefix.length+argText.length<width){if(flagLeftAlign){argText+=" "}else{if(flagZeroPad){argText="0"+argText}else{prefix=" "+prefix}}}argText=prefix+argText;argText.split("").forEach((function(chr){ret.push(chr.charCodeAt(0))}));break};case"f":case"F":case"e":case"E":case"g":case"G":{var currArg=getNextArg("double");var argText;if(isNaN(currArg)){argText="nan";flagZeroPad=false}else if(!isFinite(currArg)){argText=(currArg<0?"-":"")+"inf";flagZeroPad=false}else{var isGeneral=false;var effectivePrecision=Math.min(precision,20);if(next==103||next==71){isGeneral=true;precision=precision||1;var exponent=parseInt(currArg.toExponential(effectivePrecision).split("e")[1],10);if(precision>exponent&&exponent>=-4){next=(next==103?"f":"F").charCodeAt(0);precision-=exponent+1}else{next=(next==103?"e":"E").charCodeAt(0);precision--}effectivePrecision=Math.min(precision,20)}if(next==101||next==69){argText=currArg.toExponential(effectivePrecision);if(/[eE][-+]\d$/.test(argText)){argText=argText.slice(0,-1)+"0"+argText.slice(-1)}}else if(next==102||next==70){argText=currArg.toFixed(effectivePrecision);if(currArg===0&&__reallyNegative(currArg)){argText="-"+argText}}var parts=argText.split("e");if(isGeneral&&!flagAlternative){while(parts[0].length>1&&parts[0].indexOf(".")!=-1&&(parts[0].slice(-1)=="0"||parts[0].slice(-1)==".")){parts[0]=parts[0].slice(0,-1)}}else{if(flagAlternative&&argText.indexOf(".")==-1)parts[0]+=".";while(precision>effectivePrecision++)parts[0]+="0"}argText=parts[0]+(parts.length>1?"e"+parts[1]:"");if(next==69)argText=argText.toUpperCase();if(currArg>=0){if(flagAlwaysSigned){argText="+"+argText}else if(flagPadSign){argText=" "+argText}}}while(argText.length<width){if(flagLeftAlign){argText+=" "}else{if(flagZeroPad&&(argText[0]=="-"||argText[0]=="+")){argText=argText[0]+"0"+argText.slice(1)}else{argText=(flagZeroPad?"0":" ")+argText}}}if(next<97)argText=argText.toUpperCase();argText.split("").forEach((function(chr){ret.push(chr.charCodeAt(0))}));break};case"s":{var arg=getNextArg("i8*");var argLength=arg?_strlen(arg):"(null)".length;if(precisionSet)argLength=Math.min(argLength,precision);if(!flagLeftAlign){while(argLength<width--){ret.push(32)}}if(arg){for(var i=0;i<argLength;i++){ret.push(HEAPU8[arg++>>0])}}else{ret=ret.concat(intArrayFromString("(null)".substr(0,argLength),true))}if(flagLeftAlign){while(argLength<width--){ret.push(32)}}break};case"c":{if(flagLeftAlign)ret.push(getNextArg("i8"));while(--width>0){ret.push(32)}if(!flagLeftAlign)ret.push(getNextArg("i8"));break};case"n":{var ptr=getNextArg("i32*");HEAP32[ptr>>2]=ret.length;break};case"%":{ret.push(curr);break};default:{for(var i=startTextIndex;i<textIndex+2;i++){ret.push(HEAP8[i>>0])}}}textIndex+=2}else{ret.push(curr);textIndex+=1}}return ret}function _fprintf(stream,format,varargs){var result=__formatString(format,varargs);var stack=Runtime.stackSave();var ret=_fwrite(allocate(result,"i8",ALLOC_STACK),1,result.length,stream);Runtime.stackRestore(stack);return ret}function _printf(format,varargs){var result=__formatString(format,varargs);var string=intArrayToString(result);if(string[string.length-1]==="\n")string=string.substr(0,string.length-1);Module.print(string);return result.length}Module["_i64Add"]=_i64Add;function _fputs(s,stream){var fd=_fileno(stream);return _write(fd,s,_strlen(s))}function _fputc(c,stream){var chr=unSign(c&255);HEAP8[_fputc.ret>>0]=chr;var fd=_fileno(stream);var ret=_write(fd,_fputc.ret,1);if(ret==-1){var streamObj=FS.getStreamFromPtr(stream);if(streamObj)streamObj.error=true;return-1}else{return chr}}var _stdout=allocate(1,"i32*",ALLOC_STATIC);function _puts(s){var result=Pointer_stringify(s);var string=result.substr(0);if(string[string.length-1]==="\n")string=string.substr(0,string.length-1);Module.print(string);return result.length}var _floor=Math_floor;function _ogvjs_callback_init_audio(channels,rate){Module.audioFormat={channels:channels,rate:rate};Module.loadedMetadata=true}var _llvm_sqrt_f64=Math_sqrt;function __exit(status){Module["exit"](status)}function _exit(status){__exit(status)}var _sin=Math_sin;var _atan=Math_atan;var _BDtoIHigh=true;var _ceil=Math_ceil;var _sinf=Math_sin;function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest);return dest}Module["_memcpy"]=_memcpy;var _log=Math_log;var _cos=Math_cos;var _llvm_pow_f64=Math_pow;function _ogvjs_callback_audio(buffers,channels,sampleCount){var HEAPU32=Module.HEAPU32;var HEAPF32=Module.HEAPF32;var outputBuffers=[];if(buffers!==0){var inPtr,inArray,outArray,i;for(var channel=0;channel<channels;channel++){inPtr=HEAPU32[buffers/4+channel];inArray=HEAPF32.subarray(inPtr/4,inPtr/4+sampleCount);outArray=new Float32Array(inArray);outputBuffers.push(outArray)}}Module.audioBuffer=outputBuffers}function ___errno_location(){return ___errno_state}var _BItoD=true;function _sbrk(bytes){var self=_sbrk;if(!self.called){DYNAMICTOP=alignMemoryPage(DYNAMICTOP);self.called=true;assert(Runtime.dynamicAlloc);self.alloc=Runtime.dynamicAlloc;Runtime.dynamicAlloc=(function(){abort("cannot dynamically allocate, sbrk now has control")})}var ret=DYNAMICTOP;if(bytes!=0){var success=self.alloc(bytes);if(!success)return-1>>>0}return ret}var _exp=Math_exp;function _time(ptr){var ret=Date.now()/1e3|0;if(ptr){HEAP32[ptr>>2]=ret}return ret}___errno_state=Runtime.staticAlloc(4);HEAP32[___errno_state>>2]=0;_fputc.ret=allocate([0],"i8",ALLOC_STATIC);STACK_BASE=STACKTOP=Runtime.alignMemory(STATICTOP);staticSealed=true;STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=DYNAMICTOP=Runtime.alignMemory(STACK_MAX);assert(DYNAMIC_BASE<TOTAL_MEMORY,"TOTAL_MEMORY not big enough for stack");var cttz_i8=allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0],"i8",ALLOC_DYNAMIC);function invoke_iiiii(index,a1,a2,a3,a4){try{return Module["dynCall_iiiii"](index,a1,a2,a3,a4)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_vi(index,a1){try{Module["dynCall_vi"](index,a1)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_vii(index,a1,a2){try{Module["dynCall_vii"](index,a1,a2)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_ii(index,a1){try{return Module["dynCall_ii"](index,a1)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_viii(index,a1,a2,a3){try{Module["dynCall_viii"](index,a1,a2,a3)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_iiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8){try{return Module["dynCall_iiiiiiiii"](index,a1,a2,a3,a4,a5,a6,a7,a8)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_iii(index,a1,a2){try{return Module["dynCall_iii"](index,a1,a2)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){try{return Module["dynCall_iiiiii"](index,a1,a2,a3,a4,a5)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}Module.asmGlobalArg={"Math":Math,"Int8Array":Int8Array,"Int16Array":Int16Array,"Int32Array":Int32Array,"Uint8Array":Uint8Array,"Uint16Array":Uint16Array,"Uint32Array":Uint32Array,"Float32Array":Float32Array,"Float64Array":Float64Array,"NaN":NaN,"Infinity":Infinity};Module.asmLibraryArg={"abort":abort,"assert":assert,"invoke_iiiii":invoke_iiiii,"invoke_vi":invoke_vi,"invoke_vii":invoke_vii,"invoke_ii":invoke_ii,"invoke_viii":invoke_viii,"invoke_iiiiiiiii":invoke_iiiiiiiii,"invoke_iii":invoke_iii,"invoke_iiiiii":invoke_iiiiii,"_sin":_sin,"_exp":_exp,"_cosf":_cosf,"_send":_send,"___setErrNo":___setErrNo,"_floor":_floor,"_pwrite":_pwrite,"_llvm_sqrt_f64":_llvm_sqrt_f64,"_llvm_pow_f64":_llvm_pow_f64,"__reallyNegative":__reallyNegative,"_fabsf":_fabsf,"_sbrk":_sbrk,"_atan":_atan,"_sinf":_sinf,"_fileno":_fileno,"_sysconf":_sysconf,"_ogvjs_callback_init_audio":_ogvjs_callback_init_audio,"_cos":_cos,"_puts":_puts,"_printf":_printf,"_ogvjs_callback_audio":_ogvjs_callback_audio,"_log":_log,"_write":_write,"_emscripten_memcpy_big":_emscripten_memcpy_big,"___errno_location":___errno_location,"_fputc":_fputc,"__exit":__exit,"_abort":_abort,"_fwrite":_fwrite,"_time":_time,"_fprintf":_fprintf,"_ceil":_ceil,"__formatString":__formatString,"_fputs":_fputs,"_exit":_exit,"STACKTOP":STACKTOP,"STACK_MAX":STACK_MAX,"tempDoublePtr":tempDoublePtr,"ABORT":ABORT,"cttz_i8":cttz_i8};// EMSCRIPTEN_START_ASM
+var asm=(function(global,env,buffer) {
+"use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.tempDoublePtr|0;var l=env.ABORT|0;var m=env.cttz_i8|0;var n=0;var o=0;var p=0;var q=0;var r=global.NaN,s=global.Infinity;var t=0,u=0,v=0,w=0,x=0.0,y=0,z=0,A=0,B=0.0;var C=0;var D=0;var E=0;var F=0;var G=0;var H=0;var I=0;var J=0;var K=0;var L=0;var M=global.Math.floor;var N=global.Math.abs;var O=global.Math.sqrt;var P=global.Math.pow;var Q=global.Math.cos;var R=global.Math.sin;var S=global.Math.tan;var T=global.Math.acos;var U=global.Math.asin;var V=global.Math.atan;var W=global.Math.atan2;var X=global.Math.exp;var Y=global.Math.log;var Z=global.Math.ceil;var _=global.Math.imul;var $=global.Math.min;var aa=global.Math.clz32;var ba=env.abort;var ca=env.assert;var da=env.invoke_iiiii;var ea=env.invoke_vi;var fa=env.invoke_vii;var ga=env.invoke_ii;var ha=env.invoke_viii;var ia=env.invoke_iiiiiiiii;var ja=env.invoke_iii;var ka=env.invoke_iiiiii;var la=env._sin;var ma=env._exp;var na=env._cosf;var oa=env._send;var pa=env.___setErrNo;var qa=env._floor;var ra=env._pwrite;var sa=env._llvm_sqrt_f64;var ta=env._llvm_pow_f64;var ua=env.__reallyNegative;var va=env._fabsf;var wa=env._sbrk;var xa=env._atan;var ya=env._sinf;var za=env._fileno;var Aa=env._sysconf;var Ba=env._ogvjs_callback_init_audio;var Ca=env._cos;var Da=env._puts;var Ea=env._printf;var Fa=env._ogvjs_callback_audio;var Ga=env._log;var Ha=env._write;var Ia=env._emscripten_memcpy_big;var Ja=env.___errno_location;var Ka=env._fputc;var La=env.__exit;var Ma=env._abort;var Na=env._fwrite;var Oa=env._time;var Pa=env._fprintf;var Qa=env._ceil;var Ra=env.__formatString;var Sa=env._fputs;var Ta=env._exit;var Ua=0.0;
+// EMSCRIPTEN_START_FUNCS
+function bb(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function cb(){return i|0}function db(a){a=a|0;i=a}function eb(a,b){a=a|0;b=b|0;i=a;j=b}function fb(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function gb(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0]}function hb(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0];a[k+4>>0]=a[b+4>>0];a[k+5>>0]=a[b+5>>0];a[k+6>>0]=a[b+6>>0];a[k+7>>0]=a[b+7>>0]}function ib(a){a=a|0;C=a}function jb(){return C|0}function kb(b){b=b|0;var d=0;c[b>>2]=0;c[b+4>>2]=0;c[b+8>>2]=0;c[b+12>>2]=0;d=xd(256)|0;c[b+8>>2]=d;c[b+12>>2]=d;a[d>>0]=0;c[b+16>>2]=256;return}function lb(b,e,f){b=b|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0;do if(f>>>0<=32){g=b+16|0;h=c[g>>2]|0;i=b+12|0;j=c[i>>2]|0;if((c[b>>2]|0)<(h+-4|0))k=j;else{if(!j)return;if((h|0)>2147483391)break;j=b+8|0;l=Ad(c[j>>2]|0,h+256|0)|0;if(!l)break;c[j>>2]=l;c[g>>2]=(c[g>>2]|0)+256;g=l+(c[b>>2]|0)|0;c[i>>2]=g;k=g}g=c[8+(f<<2)>>2]&e;l=b+4|0;j=c[l>>2]|0;h=j+f|0;a[k>>0]=d[k>>0]|0|g<<j;do if((((h|0)>7?(a[(c[i>>2]|0)+1>>0]=g>>>(8-(c[l>>2]|0)|0),(h|0)>15):0)?(a[(c[i>>2]|0)+2>>0]=g>>>(16-(c[l>>2]|0)|0),(h|0)>23):0)?(a[(c[i>>2]|0)+3>>0]=g>>>(24-(c[l>>2]|0)|0),(h|0)>31):0){j=c[l>>2]|0;if(!j){a[(c[i>>2]|0)+4>>0]=0;break}else{a[(c[i>>2]|0)+4>>0]=g>>>(32-j|0);break}}while(0);g=(h|0)/8|0;c[b>>2]=(c[b>>2]|0)+g;c[i>>2]=(c[i>>2]|0)+g;c[l>>2]=h&7;return}while(0);k=c[b+8>>2]|0;if(k)yd(k);c[b>>2]=0;c[b+4>>2]=0;c[b+8>>2]=0;c[b+12>>2]=0;c[b+16>>2]=0;return}function mb(a){a=a|0;var b=0;b=c[a+8>>2]|0;if(b)yd(b);c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+16>>2]=0;return}function nb(a,b,d){a=a|0;b=b|0;d=d|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+12>>2]=b;c[a+8>>2]=b;c[a+16>>2]=d;return}function ob(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;if(b>>>0>32){e=-1;return e|0}f=c[8+(b<<2)>>2]|0;g=c[a+4>>2]|0;h=g+b|0;b=c[a>>2]|0;i=c[a+16>>2]|0;if((b|0)>=(i+-4|0)){if((b|0)>(i-(h+7>>3)|0)){e=-1;return e|0}if(!h){e=0;return e|0}}i=c[a+12>>2]|0;a=(d[i>>0]|0)>>>g;if((h|0)>8){b=(d[i+1>>0]|0)<<8-g|a;if((h|0)>16){j=(d[i+2>>0]|0)<<16-g|b;if((h|0)>24){k=(d[i+3>>0]|0)<<24-g|j;if((h|0)<33|(g|0)==0)l=k;else l=(d[i+4>>0]|0)<<32-g|k}else l=j}else l=b}else l=a;e=l&f;return e|0}function pb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=a+4|0;e=(c[d>>2]|0)+b|0;b=c[a>>2]|0;f=c[a+16>>2]|0;if((b|0)>(f-(e+7>>3)|0)){c[a+12>>2]=0;c[a>>2]=f;g=1;c[d>>2]=g;return}else{f=(e|0)/8|0;h=a+12|0;c[h>>2]=(c[h>>2]|0)+f;c[a>>2]=b+f;g=e&7;c[d>>2]=g;return}}function qb(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;do if(b>>>0>32){e=a;f=a+4|0;g=c[a+16>>2]|0}else{h=c[8+(b<<2)>>2]|0;i=a+4|0;j=c[i>>2]|0;k=j+b|0;l=c[a>>2]|0;m=c[a+16>>2]|0;if((l|0)>=(m+-4|0)){if((l|0)>(m-(k+7>>3)|0)){e=a;f=i;g=m;break}if(!k){n=0;return n|0}}m=a+12|0;o=c[m>>2]|0;p=(d[o>>0]|0)>>>j;if((k|0)>8){q=(d[o+1>>0]|0)<<8-j|p;if((k|0)>16){r=(d[o+2>>0]|0)<<16-j|q;if((k|0)>24){s=(d[o+3>>0]|0)<<24-j|r;if((k|0)<33|(j|0)==0)t=s;else t=(d[o+4>>0]|0)<<32-j|s}else t=r}else t=q}else t=p;p=(k|0)/8|0;c[m>>2]=o+p;c[a>>2]=l+p;c[i>>2]=k&7;n=t&h;return n|0}while(0);c[a+12>>2]=0;c[e>>2]=g;c[f>>2]=1;n=-1;return n|0}function rb(a){a=a|0;return (((c[a+4>>2]|0)+7|0)/8|0)+(c[a>>2]|0)|0}function sb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,i=0.0,j=0,k=0.0,l=0,m=0.0,n=0.0,o=0,p=0.0,q=0,r=0,s=0,t=0;d=(b|0)/4|0;e=xd(d<<2)|0;f=xd(d+b<<2)|0;h=b>>1;i=+(b|0);j=~~+td(+Y(+i)*1.4426950408889634);c[a+4>>2]=j;c[a>>2]=b;c[a+8>>2]=f;c[a+12>>2]=e;if((b|0)<=3){k=4.0/i;l=a+16|0;g[l>>2]=k;return}m=3.141592653589793/+(b|0);n=3.141592653589793/+(b<<1|0);o=0;do{p=m*+(o<<2|0);q=o<<1;g[f+(q<<2)>>2]=+Q(+p);r=q|1;g[f+(r<<2)>>2]=-+R(+p);p=n*+(r|0);r=q+h|0;g[f+(r<<2)>>2]=+Q(+p);g[f+(r+1<<2)>>2]=+R(+p);o=o+1|0}while((o|0)<(d|0));d=(b|0)/8|0;o=(b|0)>7;if(!o){k=4.0/i;l=a+16|0;g[l>>2]=k;return}n=3.141592653589793/+(b|0);h=0;do{m=n*+(h<<2|2|0);r=(h<<1)+b|0;g[f+(r<<2)>>2]=+Q(+m)*.5;g[f+(r+1<<2)>>2]=+R(+m)*-.5;h=h+1|0}while((h|0)<(d|0));h=(1<<j+-1)+-1|0;f=1<<j+-2;if(o)s=0;else{k=4.0/i;l=a+16|0;g[l>>2]=k;return}do{o=f;j=0;b=0;while(1){r=((o&s|0)==0?0:1<<b)|j;b=b+1|0;o=f>>b;if(!o){t=r;break}else j=r}j=s<<1;c[e+(j<<2)>>2]=(h&~t)+-1;c[e+((j|1)<<2)>>2]=t;s=s+1|0}while((s|0)<(d|0));k=4.0/i;l=a+16|0;g[l>>2]=k;return}function tb(a){a=a|0;var b=0;if(!a)return;b=c[a+8>>2]|0;if(b)yd(b);b=c[a+12>>2]|0;if(b)yd(b);c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+16>>2]=0;return}function ub(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0.0,t=0,u=0;e=c[a>>2]|0;f=e>>1;h=e>>2;e=d+(f+h<<2)|0;i=a+8|0;j=c[i>>2]|0;k=j+(h<<2)|0;l=k;m=b+(f+-7<<2)|0;n=e;while(1){o=n;n=n+-16|0;p=m+8|0;q=l+12|0;r=l+8|0;g[n>>2]=-(+g[p>>2]*+g[q>>2])-+g[r>>2]*+g[m>>2];g[o+-12>>2]=+g[q>>2]*+g[m>>2]-+g[r>>2]*+g[p>>2];p=m+24|0;r=l+4|0;q=m+16|0;g[o+-8>>2]=-(+g[p>>2]*+g[r>>2])-+g[l>>2]*+g[q>>2];g[o+-4>>2]=+g[r>>2]*+g[q>>2]-+g[l>>2]*+g[p>>2];m=m+-32|0;if(m>>>0<b>>>0)break;else l=l+16|0}l=d+(f<<2)|0;m=k;k=b+(f+-8<<2)|0;n=e;while(1){p=k+16|0;q=m+-4|0;r=k+24|0;o=m+-8|0;g[n>>2]=+g[o>>2]*+g[r>>2]+ +g[q>>2]*+g[p>>2];g[n+4>>2]=+g[o>>2]*+g[p>>2]-+g[q>>2]*+g[r>>2];r=m+-12|0;m=m+-16|0;q=k+8|0;g[n+8>>2]=+g[m>>2]*+g[q>>2]+ +g[r>>2]*+g[k>>2];g[n+12>>2]=+g[m>>2]*+g[k>>2]-+g[r>>2]*+g[q>>2];k=k+-32|0;if(k>>>0<b>>>0)break;else n=n+16|0}Ec(c[a+4>>2]|0,j,l,f);Fc(c[a>>2]|0,c[i>>2]|0,c[a+12>>2]|0,d);a=(c[i>>2]|0)+(f<<2)|0;f=d;i=e;j=e;while(1){n=a+4|0;b=f+4|0;g[i+-4>>2]=+g[n>>2]*+g[f>>2]-+g[a>>2]*+g[b>>2];g[j>>2]=-(+g[a>>2]*+g[f>>2]+ +g[n>>2]*+g[b>>2]);b=f+8|0;n=a+12|0;k=f+12|0;m=a+8|0;g[i+-8>>2]=+g[n>>2]*+g[b>>2]-+g[m>>2]*+g[k>>2];g[j+4>>2]=-(+g[m>>2]*+g[b>>2]+ +g[n>>2]*+g[k>>2]);k=f+16|0;n=a+20|0;b=f+20|0;m=a+16|0;g[i+-12>>2]=+g[n>>2]*+g[k>>2]-+g[m>>2]*+g[b>>2];i=i+-16|0;g[j+8>>2]=-(+g[m>>2]*+g[k>>2]+ +g[n>>2]*+g[b>>2]);b=f+24|0;n=a+28|0;k=f+28|0;m=a+24|0;g[i>>2]=+g[n>>2]*+g[b>>2]-+g[m>>2]*+g[k>>2];g[j+12>>2]=-(+g[m>>2]*+g[b>>2]+ +g[n>>2]*+g[k>>2]);f=f+32|0;if(f>>>0>=i>>>0)break;else{a=a+32|0;j=j+16|0}}j=d+(h<<2)|0;h=e;d=j;a=j;do{j=d;d=d+-16|0;s=+g[h+-4>>2];g[j+-4>>2]=s;g[a>>2]=-s;s=+g[h+-8>>2];g[j+-8>>2]=s;g[a+4>>2]=-s;s=+g[h+-12>>2];h=h+-16|0;g[j+-12>>2]=s;g[a+8>>2]=-s;s=+g[h>>2];g[d>>2]=s;g[a+12>>2]=-s;a=a+16|0}while(a>>>0<h>>>0);t=e;u=e;while(1){e=u;u=u+-16|0;c[u>>2]=c[t+12>>2];c[e+-12>>2]=c[t+8>>2];c[e+-8>>2]=c[t+4>>2];c[e+-4>>2]=c[t>>2];if(u>>>0<=l>>>0)break;else t=t+16|0}return}function vb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0.0,B=0.0,C=0,D=0,E=0,F=0,G=0,H=0,I=0;e=i;f=c[a>>2]|0;h=f>>1;j=f>>2;k=f>>3;l=i;i=i+((1*(f<<2)|0)+15&-16)|0;m=l+(h<<2)|0;n=h+j|0;o=b+(n<<2)|0;p=a+8|0;q=c[p>>2]|0;r=q+(h<<2)|0;if((k|0)>0){s=(k+-1|0)>>>1;t=s<<1;u=h+-2-t|0;v=n+-4-(s<<2)|0;s=r;w=0;x=o;y=b+(n+1<<2)|0;while(1){n=x;x=x+-16|0;z=s;s=s+-8|0;A=+g[y>>2]+ +g[n+-8>>2];B=+g[y+8>>2]+ +g[x>>2];n=z+-4|0;g[l+(w+h<<2)>>2]=+g[s>>2]*A+B*+g[n>>2];g[l+((w|1)+h<<2)>>2]=+g[s>>2]*B-+g[n>>2]*A;w=w+2|0;if((w|0)>=(k|0))break;else y=y+16|0}C=u;D=q+(u<<2)|0;E=t+2|0;F=b+(v<<2)|0}else{C=h;D=r;E=0;F=o}o=b+4|0;r=h-k|0;if((E|0)<(r|0)){v=(h+-1-E-k|0)>>>1;k=v<<1;t=E+k|0;u=(v<<2)+5|0;v=-2-k|0;k=D;y=E;w=F;F=o;while(1){s=k;k=k+-8|0;A=+g[w+-8>>2]-+g[F>>2];w=w+-16|0;B=+g[w>>2]-+g[F+8>>2];x=s+-4|0;g[l+(y+h<<2)>>2]=+g[k>>2]*A+B*+g[x>>2];g[l+((y|1)+h<<2)>>2]=+g[k>>2]*B-+g[x>>2]*A;y=y+2|0;if((y|0)>=(r|0))break;else F=F+16|0}G=q+(C+v<<2)|0;H=t+2|0;I=b+(u<<2)|0}else{G=D;H=E;I=o}if((H|0)<(h|0)){o=G;G=H;H=b+(f<<2)|0;f=I;while(1){I=o;o=o+-8|0;A=-+g[H+-8>>2]-+g[f>>2];H=H+-16|0;B=-+g[H>>2]-+g[f+8>>2];b=I+-4|0;g[l+(G+h<<2)>>2]=+g[o>>2]*A+B*+g[b>>2];g[l+((G|1)+h<<2)>>2]=+g[o>>2]*B-+g[b>>2]*A;G=G+2|0;if((G|0)>=(h|0))break;else f=f+16|0}}Ec(c[a+4>>2]|0,q,m,h);Fc(c[a>>2]|0,c[p>>2]|0,c[a+12>>2]|0,l);if((j|0)<=0){i=e;return}m=a+16|0;a=(c[p>>2]|0)+(h<<2)|0;p=0;q=l;l=d+(h<<2)|0;while(1){l=l+-4|0;h=q+4|0;f=a+4|0;g[d+(p<<2)>>2]=(+g[f>>2]*+g[h>>2]+ +g[a>>2]*+g[q>>2])*+g[m>>2];g[l>>2]=(+g[f>>2]*+g[q>>2]-+g[a>>2]*+g[h>>2])*+g[m>>2];p=p+1|0;if((p|0)==(j|0))break;else{a=a+8|0;q=q+8|0}}i=e;return}function wb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;d=c[a>>2]|0;if((d|0)==1)return;e=c[a+4>>2]|0;f=c[a+8>>2]|0;a=c[f+4>>2]|0;if((a|0)<=0)return;g=a+1|0;h=d+-1|0;i=d;j=0;k=d;l=1;while(1){m=c[f+(g-j<<2)>>2]|0;n=(d|0)/(k|0)|0;k=(k|0)/(m|0)|0;o=_(n,k)|0;i=i-(_(n,m+-1|0)|0)|0;p=1-l|0;do if((m|0)==4){q=i+n|0;r=e+(h+i<<2)|0;s=e+(h+q<<2)|0;t=e+(h+n+q<<2)|0;if(!p){Gc(n,k,b,e,r,s,t);u=0;break}else{Gc(n,k,e,b,r,s,t);u=p;break}}else if((m|0)==2){t=e+(h+i<<2)|0;if(!p){Hc(n,k,b,e,t);u=0;break}else{Hc(n,k,e,b,t);u=p;break}}else{t=e+(h+i<<2)|0;if(!(((n|0)==1?l:p)|0)){Ic(n,m,k,o,b,b,b,e,e,t);u=1;break}else{Ic(n,m,k,o,e,e,e,b,b,t);u=0;break}}while(0);j=j+1|0;if((j|0)==(a|0)){v=u;break}else l=u}if((d|0)>0&(v|0)!=1)w=0;else return;do{c[b+(w<<2)>>2]=c[e+(w<<2)>>2];w=w+1|0}while((w|0)!=(d|0));return}function xb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0.0,x=0.0,y=0.0,z=0.0,A=0;c[a>>2]=b;d=zd(b*3|0,4)|0;c[a+4>>2]=d;e=zd(32,4)|0;c[a+8>>2]=e;if((b|0)==1)return;a=e+8|0;f=-1;h=0;i=b;j=0;a:while(1){k=f+1|0;if((k|0)<4)l=c[360+(k<<2)>>2]|0;else l=j+2|0;m=(l|0)!=2;n=h;o=i;while(1){p=n+1|0;q=o;o=(o|0)/(l|0)|0;if((q|0)!=(_(o,l)|0)){f=k;h=n;i=q;j=l;continue a}c[e+(n+2<<2)>>2]=l;q=(n|0)==0;if(!(m|q)){if((n|0)>=1){r=1;do{s=p-r|0;c[e+(s+2<<2)>>2]=c[e+(s+1<<2)>>2];r=r+1|0}while((r|0)!=(p|0))}c[a>>2]=2}if((o|0)==1){t=q;u=p;v=n;break a}else n=p}}c[e>>2]=b;c[e+4>>2]=u;w=6.2831854820251465/+(b|0);if(!((v|0)>0&(t^1)))return;t=b+1|0;u=0;a=0;l=1;while(1){j=c[e+(a+2<<2)>>2]|0;i=l;l=_(j,l)|0;h=(b|0)/(l|0)|0;if((j|0)>1){f=(h|0)>2;n=j+-1|0;j=u;o=0;m=0;while(1){m=m+i|0;x=+(m|0)*w;if(f){y=0.0;k=j;r=2;while(1){y=y+1.0;z=x*y;g[d+(k+b<<2)>>2]=+Q(+z);g[d+(t+k<<2)>>2]=+R(+z);r=r+2|0;if((r|0)>=(h|0))break;else k=k+2|0}}o=o+1|0;if((o|0)==(n|0))break;else j=j+h|0}A=(_(h,n)|0)+u|0}else A=u;a=a+1|0;if((a|0)==(v|0))break;else u=A}return}function yb(a){a=a|0;var b=0;if(!a)return;b=c[a+4>>2]|0;if(b)yd(b);b=c[a+8>>2]|0;if(b)yd(b);c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;return}function zb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=b;e=d+112|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));c[b+64>>2]=a;c[b+76>>2]=0;c[b+68>>2]=0;if(!(c[a>>2]|0))return 0;a=zd(1,72)|0;c[b+104>>2]=a;g[a+4>>2]=-9999.0;d=b+4|0;b=a+12|0;e=a+40|0;a=0;while(1)if((a|0)!=7){f=zd(1,20)|0;c[b+(a<<2)>>2]=f;kb(f);f=a+1|0;if((f|0)==15)break;else{a=f;continue}}else{c[e>>2]=d;kb(d);a=8;continue}return 0}function Ab(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;d=b+7&-8;b=a+72|0;e=c[b>>2]|0;f=a+76|0;g=a+68|0;h=c[g>>2]|0;if((e+d|0)<=(c[f>>2]|0)){i=h;j=e;k=i+j|0;l=j+d|0;c[b>>2]=l;return k|0}if(h){m=xd(8)|0;n=a+80|0;c[n>>2]=(c[n>>2]|0)+e;e=a+84|0;c[m+4>>2]=c[e>>2];c[m>>2]=h;c[e>>2]=m}c[f>>2]=d;f=xd(d)|0;c[g>>2]=f;c[b>>2]=0;i=f;j=0;k=i+j|0;l=j+d|0;c[b>>2]=l;return k|0}function Bb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=a+84|0;d=c[b>>2]|0;if(d){e=d;do{d=e;e=c[e+4>>2]|0;yd(c[d>>2]|0);yd(d)}while((e|0)!=0)}e=a+80|0;d=c[e>>2]|0;if(!d){f=a+72|0;c[f>>2]=0;c[b>>2]=0;return}g=a+68|0;h=a+76|0;c[g>>2]=Ad(c[g>>2]|0,(c[h>>2]|0)+d|0)|0;c[h>>2]=(c[h>>2]|0)+(c[e>>2]|0);c[e>>2]=0;f=a+72|0;c[f>>2]=0;c[b>>2]=0;return}function Cb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;b=c[a+104>>2]|0;d=a+84|0;e=c[d>>2]|0;if(e){f=e;do{e=f;f=c[f+4>>2]|0;yd(c[e>>2]|0);yd(e)}while((f|0)!=0)}f=a+80|0;e=c[f>>2]|0;g=a+68|0;h=c[g>>2]|0;if(!e)i=h;else{j=a+76|0;k=Ad(h,(c[j>>2]|0)+e|0)|0;c[g>>2]=k;c[j>>2]=(c[j>>2]|0)+(c[f>>2]|0);c[f>>2]=0;i=k}c[a+72>>2]=0;c[d>>2]=0;if(i)yd(i);if(!b){l=a;m=l+112|0;do{c[l>>2]=0;l=l+4|0}while((l|0)<(m|0));return 0}else n=0;while(1){i=b+12+(n<<2)|0;mb(c[i>>2]|0);if((n|0)==7){n=8;continue}yd(c[i>>2]|0);n=n+1|0;if((n|0)==15)break}yd(b);l=a;m=l+112|0;do{c[l>>2]=0;l=l+4|0}while((l|0)<(m|0));return 0}function Db(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;if(!a)return;b=c[a+4>>2]|0;d=(b|0)!=0;if(d)e=c[b+28>>2]|0;else e=0;f=c[a+104>>2]|0;g=(f|0)!=0;if(g){h=c[f>>2]|0;if(h){Ib(h);yd(c[f>>2]|0)}h=f+12|0;i=c[h>>2]|0;if(i){tb(c[i>>2]|0);yd(c[c[h>>2]>>2]|0);yd(c[h>>2]|0)}h=f+16|0;i=c[h>>2]|0;if(i){tb(c[i>>2]|0);yd(c[c[h>>2]>>2]|0);yd(c[h>>2]|0)}h=f+48|0;i=c[h>>2]|0;if(i){if((e|0)!=0?(j=e+16|0,(c[j>>2]|0)>0):0){k=e+800|0;Wa[c[(c[328+(c[k>>2]<<2)>>2]|0)+16>>2]&7](c[i>>2]|0);if((c[j>>2]|0)>1){l=1;do{Wa[c[(c[328+(c[k+(l<<2)>>2]<<2)>>2]|0)+16>>2]&7](c[(c[h>>2]|0)+(l<<2)>>2]|0);l=l+1|0}while((l|0)<(c[j>>2]|0))}m=c[h>>2]|0}else m=i;yd(m)}m=f+52|0;i=c[m>>2]|0;if(i){if((e|0)!=0?(h=e+20|0,(c[h>>2]|0)>0):0){j=e+1312|0;Wa[c[(c[336+(c[j>>2]<<2)>>2]|0)+16>>2]&7](c[i>>2]|0);if((c[h>>2]|0)>1){l=1;do{Wa[c[(c[336+(c[j+(l<<2)>>2]<<2)>>2]|0)+16>>2]&7](c[(c[m>>2]|0)+(l<<2)>>2]|0);l=l+1|0}while((l|0)<(c[h>>2]|0))}n=c[m>>2]|0}else n=i;yd(n)}n=f+56|0;i=c[n>>2]|0;if(i){if((e|0)!=0?(m=e+28|0,(c[m>>2]|0)>0):0){Qb(i);if((c[m>>2]|0)>1){e=1;do{Qb((c[n>>2]|0)+(e*52|0)|0);e=e+1|0}while((e|0)<(c[m>>2]|0))}o=c[n>>2]|0}else o=i;yd(o)}o=c[f+60>>2]|0;if(o)Nb(o);Cc(f+80|0);yb(f+20|0);yb(f+32|0)}o=a+8|0;i=c[o>>2]|0;if(i){if(d?(d=b+4|0,b=c[d>>2]|0,(b|0)>0):0){n=i;m=b;b=0;while(1){e=c[n+(b<<2)>>2]|0;if(!e)p=m;else{yd(e);p=c[d>>2]|0}e=b+1|0;if((e|0)>=(p|0))break;n=c[o>>2]|0;m=p;b=e}q=c[o>>2]|0}else q=i;yd(q);q=c[a+12>>2]|0;if(q)yd(q)}if(g){g=c[f+64>>2]|0;if(g)yd(g);g=c[f+68>>2]|0;if(g)yd(g);g=c[f+72>>2]|0;if(g)yd(g);yd(f)}f=a;a=f+112|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(a|0));return}function Eb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;if(Jc(a,b,0)|0){Db(a);d=1;return d|0}b=c[a+4>>2]|0;e=c[a+104>>2]|0;if((b|0)==0|(e|0)==0){d=0;return d|0}f=c[b+28>>2]|0;if(!f){d=0;return d|0}b=c[f+3656>>2]|0;g=c[f+4>>2]>>b+1;c[a+48>>2]=g;c[a+20>>2]=g>>b;c[a+24>>2]=-1;b=a+56|0;c[b>>2]=-1;c[b+4>>2]=-1;c[b+8>>2]=-1;c[b+12>>2]=-1;c[a+32>>2]=0;a=e+128|0;c[a>>2]=-1;c[a+4>>2]=-1;d=0;return d|0}function Fb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0;d=c[a+4>>2]|0;e=c[d+28>>2]|0;f=c[a+104>>2]|0;h=c[e+3656>>2]|0;if(!b){i=-131;return i|0}j=a+20|0;k=c[j>>2]|0;l=a+24|0;m=c[l>>2]|0;if(!((k|0)<=(m|0)|(m|0)==-1)){i=-131;return i|0}n=a+40|0;o=c[n>>2]|0;p=a+36|0;c[p>>2]=o;q=c[b+28>>2]|0;c[n>>2]=q;c[a+44>>2]=-1;r=a+64|0;s=r;t=c[s>>2]|0;u=c[s+4>>2]|0;if(!((t|0)==-1&(u|0)==-1)){s=Id(t|0,u|0,1,0)|0;u=C;t=b+56|0;v=c[t>>2]|0;w=c[t+4>>2]|0;if((s|0)==(v|0)&(u|0)==(w|0)){x=s;y=u}else{z=v;A=w;B=6}}else{w=b+56|0;z=c[w>>2]|0;A=c[w+4>>2]|0;B=6}if((B|0)==6){B=a+56|0;c[B>>2]=-1;c[B+4>>2]=-1;B=f+128|0;c[B>>2]=-1;c[B+4>>2]=-1;x=z;y=A}A=r;c[A>>2]=x;c[A+4>>2]=y;do if(c[b>>2]|0){y=h+1|0;A=c[e+(q<<2)>>2]>>y;x=c[e>>2]>>y;r=c[e+4>>2]>>y;y=c[b+88>>2]|0;z=a+72|0;B=z;w=Id(c[B>>2]|0,c[B+4>>2]|0,y|0,((y|0)<0)<<31>>31|0)|0;y=z;c[y>>2]=w;c[y+4>>2]=C;y=c[b+92>>2]|0;w=a+80|0;z=w;B=Id(c[z>>2]|0,c[z+4>>2]|0,y|0,((y|0)<0)<<31>>31|0)|0;y=w;c[y>>2]=B;c[y+4>>2]=C;y=c[b+96>>2]|0;B=a+88|0;w=B;z=Id(c[w>>2]|0,c[w+4>>2]|0,y|0,((y|0)<0)<<31>>31|0)|0;y=B;c[y>>2]=z;c[y+4>>2]=C;y=c[b+100>>2]|0;z=a+96|0;B=z;w=Id(c[B>>2]|0,c[B+4>>2]|0,y|0,((y|0)<0)<<31>>31|0)|0;y=z;c[y>>2]=w;c[y+4>>2]=C;y=a+48|0;w=c[y>>2]|0;z=(w|0)==0;B=z?r:0;v=z?0:r;z=d+4|0;if((c[z>>2]|0)>0){u=f+4|0;s=a+8|0;t=(r|0)/2|0;D=(x|0)/2|0;E=t-D|0;F=(x|0)>0;G=D+t|0;D=x+-1|0;H=(A|0)>0;I=f+8|0;J=(r|0)>0;K=r+-1|0;L=t+B+((x|0)/-2|0)|0;t=o;M=q;N=0;while(1){O=(M|0)!=0;a:do if(!t){P=Jb((c[u>>2]|0)-h|0)|0;Q=c[(c[s>>2]|0)+(N<<2)>>2]|0;R=c[(c[b>>2]|0)+(N<<2)>>2]|0;if(!O){if(F)S=0;else{T=R;U=Q;break}while(1){V=Q+(S+B<<2)|0;g[V>>2]=+g[P+(S<<2)>>2]*+g[R+(S<<2)>>2]+ +g[P+(D-S<<2)>>2]*+g[V>>2];S=S+1|0;if((S|0)==(x|0)){T=R;U=Q;break a}}}if(F){V=0;do{W=Q+(V+B<<2)|0;g[W>>2]=+g[P+(V<<2)>>2]*+g[R+(V+E<<2)>>2]+ +g[P+(D-V<<2)>>2]*+g[W>>2];V=V+1|0}while((V|0)!=(x|0));X=x}else X=0;if((X|0)<(G|0)){V=X;do{c[Q+(V+B<<2)>>2]=c[R+(V+E<<2)>>2];V=V+1|0}while((V|0)!=(G|0));T=R;U=Q}else{T=R;U=Q}}else if(O){V=Jb((c[I>>2]|0)-h|0)|0;P=c[(c[s>>2]|0)+(N<<2)>>2]|0;W=c[(c[b>>2]|0)+(N<<2)>>2]|0;if(J)Y=0;else{T=W;U=P;break}do{Z=P+(Y+B<<2)|0;g[Z>>2]=+g[V+(Y<<2)>>2]*+g[W+(Y<<2)>>2]+ +g[V+(K-Y<<2)>>2]*+g[Z>>2];Y=Y+1|0}while((Y|0)!=(r|0));T=W;U=P}else{P=Jb((c[u>>2]|0)-h|0)|0;W=c[(c[s>>2]|0)+(N<<2)>>2]|0;V=c[(c[b>>2]|0)+(N<<2)>>2]|0;if(F)_=0;else{T=V;U=W;break}do{Q=W+(L+_<<2)|0;g[Q>>2]=+g[P+(_<<2)>>2]*+g[V+(_<<2)>>2]+ +g[P+(D-_<<2)>>2]*+g[Q>>2];_=_+1|0}while((_|0)!=(x|0));T=V;U=W}while(0);if(H){O=0;do{c[U+(O+v<<2)>>2]=c[T+(O+A<<2)>>2];O=O+1|0}while((O|0)!=(A|0))}O=N+1|0;if((O|0)>=(c[z>>2]|0))break;t=c[p>>2]|0;M=c[n>>2]|0;N=O}$=c[y>>2]|0;aa=c[l>>2]|0}else{$=w;aa=m}c[y>>2]=($|0)==0?r:0;if((aa|0)==-1){c[l>>2]=v;c[j>>2]=v;ba=v;ca=v;break}else{c[l>>2]=B;N=(((c[e+(c[n>>2]<<2)>>2]|0)/4|0)+((c[e+(c[p>>2]<<2)>>2]|0)/4|0)>>h)+B|0;c[j>>2]=N;ba=N;ca=B;break}}else{ba=k;ca=m}while(0);m=f+128|0;f=m;k=c[f>>2]|0;aa=c[f+4>>2]|0;if((k|0)==-1&(aa|0)==-1){da=0;ea=0}else{f=((c[e+(c[n>>2]<<2)>>2]|0)/4|0)+((c[e+(c[p>>2]<<2)>>2]|0)/4|0)|0;$=Id(f|0,((f|0)<0)<<31>>31|0,k|0,aa|0)|0;da=$;ea=C}$=m;c[$>>2]=da;c[$+4>>2]=ea;$=a+56|0;m=$;aa=c[m>>2]|0;k=c[m+4>>2]|0;do if((aa|0)==-1&(k|0)==-1){m=b+48|0;f=c[m>>2]|0;T=c[m+4>>2]|0;if(!((f|0)==-1&(T|0)==-1)?(m=$,c[m>>2]=f,c[m+4>>2]=T,(ea|0)>(T|0)|(ea|0)==(T|0)&da>>>0>f>>>0):0){m=Ed(da|0,ea|0,f|0,T|0)|0;T=(m|0)<0?0:m;if(!(c[b+44>>2]|0)){m=ca+(T>>h)|0;c[l>>2]=(m|0)>(ba|0)?ba:m;break}else{m=ba-ca<<h;c[j>>2]=ba-(((T|0)>(m|0)?m:T)>>h);break}}}else{T=((c[e+(c[n>>2]<<2)>>2]|0)/4|0)+((c[e+(c[p>>2]<<2)>>2]|0)/4|0)|0;m=Id(T|0,((T|0)<0)<<31>>31|0,aa|0,k|0)|0;T=C;f=$;c[f>>2]=m;c[f+4>>2]=T;f=b+48|0;U=c[f>>2]|0;_=c[f+4>>2]|0;if(!((U|0)==-1&(_|0)==-1|(m|0)==(U|0)&(T|0)==(_|0))){if(((T|0)>(_|0)|(T|0)==(_|0)&m>>>0>U>>>0?(f=Ed(m|0,T|0,U|0,_|0)|0,(f|0)!=0):0)?(c[b+44>>2]|0)!=0:0){T=ba-ca<<h;m=(f|0)>(T|0)?T:f;c[j>>2]=ba-(((m|0)<0?0:m)>>h)}m=$;c[m>>2]=U;c[m+4>>2]=_}}while(0);if(!(c[b+44>>2]|0)){i=0;return i|0}c[a+32>>2]=1;i=0;return i|0}function Gb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;d=c[a+24>>2]|0;if((d|0)<=-1){e=0;return e|0}f=c[a+20>>2]|0;if((f|0)<=(d|0)){e=0;return e|0}if(b){g=c[(c[a+4>>2]|0)+4>>2]|0;if((g|0)>0){h=a+8|0;i=a+12|0;j=0;do{c[(c[i>>2]|0)+(j<<2)>>2]=(c[(c[h>>2]|0)+(j<<2)>>2]|0)+(d<<2);j=j+1|0}while((j|0)<(g|0));k=i}else k=a+12|0;c[b>>2]=c[k>>2]}e=f-d|0;return e|0}function Hb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=a+24|0;e=c[d>>2]|0;if((b|0)!=0?(e+b|0)>(c[a+20>>2]|0):0){f=-131;return f|0}c[d>>2]=e+b;f=0;return f|0}function Ib(a){a=a|0;tb(a+16|0);yd(c[a+48>>2]|0);yd(c[a+64>>2]|0);yd(c[a+80>>2]|0);yd(c[a+96>>2]|0);yd(c[a+112>>2]|0);yd(c[a+128>>2]|0);yd(c[a+144>>2]|0);yd(c[a+36>>2]|0);yd(c[a+152>>2]|0);yd(c[a+160>>2]|0);Fd(a|0,0,180)|0;return}function Jb(a){a=a|0;return c[376+(a<<2)>>2]|0}function Kb(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;i=(f|0)!=0;j=i?e:0;e=i?h:0;h=c[376+(c[b+(j<<2)>>2]<<2)>>2]|0;i=c[376+(c[b+(e<<2)>>2]<<2)>>2]|0;b=c[d+(f<<2)>>2]|0;f=c[d+(j<<2)>>2]|0;j=c[d+(e<<2)>>2]|0;e=(b|0)/4|0;d=(f|0)/4|0;k=e-d|0;l=(f|0)/2|0;f=((b|0)/2|0)+e+((j|0)/-4|0)|0;m=(j|0)/2|0;n=f+m|0;if((k|0)>0){Fd(a|0,0,e-d<<2|0)|0;o=k}else o=0;if((o|0)<(k+l|0)){k=e+l-o-d|0;d=o;o=0;while(1){l=a+(d<<2)|0;g[l>>2]=+g[l>>2]*+g[h+(o<<2)>>2];o=o+1|0;if((o|0)==(k|0))break;else d=d+1|0}}if((j|0)>1){j=f+1|0;d=(n|0)>(j|0);k=f;o=m;do{o=o+-1|0;m=a+(k<<2)|0;g[m>>2]=+g[m>>2]*+g[i+(o<<2)>>2];k=k+1|0}while((k|0)<(n|0));p=d?n:j}else p=f;if((b|0)<=(p|0))return;Fd(a+(p<<2)|0,0,b-p<<2|0)|0;return}function Lb(a,b,d,e,f,h,i,j){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=+i;j=+j;var k=0.0,l=0,m=0.0,n=0,o=0.0,p=0.0,q=0.0,r=0,s=0,t=0,u=0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0;k=3.141592653589793/+(e|0);if((h|0)>0){e=0;do{l=f+(e<<2)|0;g[l>>2]=+Q(+(+g[l>>2]))*2.0;e=e+1|0}while((e|0)!=(h|0))}if((d|0)<=0)return;m=i;i=j;if((h|0)<=1){e=(h|0)==1;l=0;while(1){n=c[b+(l<<2)>>2]|0;j=+Q(+(+(n|0)*k))*2.0;if(e){o=(j-+g[f>>2])*.5;p=4.0-j*j;q=o*o}else{p=2.0-j;q=(j+2.0)*.25}j=+X(+((m/+O(+(q+p*.25))-i)*.1151292473077774));r=a+(l<<2)|0;g[r>>2]=+g[r>>2]*j;r=l+1|0;if((c[b+(r<<2)>>2]|0)==(n|0)){s=r;while(1){t=a+(s<<2)|0;g[t>>2]=+g[t>>2]*j;t=s+1|0;if((c[b+(t<<2)>>2]|0)==(n|0))s=t;else{u=t;break}}}else u=r;if((u|0)<(d|0))l=u;else break}return}u=((h+-2&-2)+3|0)==(h|0);l=f+(h+-1<<2)|0;e=0;while(1){s=c[b+(e<<2)>>2]|0;p=+Q(+(+(s|0)*k))*2.0;n=1;q=.5;j=.5;while(1){o=(p-+g[f+(n+-1<<2)>>2])*j;v=(p-+g[f+(n<<2)>>2])*q;n=n+2|0;if((n|0)>=(h|0)){w=o;x=v;break}else{q=v;j=o}}if(u){j=(p-+g[l>>2])*w;y=x*x*(4.0-p*p);z=j*j}else{y=x*x*(2.0-p);z=w*w*(p+2.0)}j=+X(+((m/+O(+(z+y))-i)*.1151292473077774));n=a+(e<<2)|0;g[n>>2]=+g[n>>2]*j;n=e+1|0;if((c[b+(n<<2)>>2]|0)==(s|0)){r=n;while(1){t=a+(r<<2)|0;g[t>>2]=+g[t>>2]*j;t=r+1|0;if((c[b+(t<<2)>>2]|0)==(s|0))r=t;else{A=t;break}}}else A=n;if((A|0)<(d|0))e=A;else break}return}function Mb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0;d=(a|0)!=0;if(d?(e=c[a+64>>2]|0,(e|0)!=0):0){f=c[e+104>>2]|0;g=c[e+4>>2]|0;if(!g){h=f;i=1;j=0;k=0;l=0}else{h=f;i=1;j=1;k=c[g+28>>2]|0;l=g}}else{h=0;i=0;j=0;k=0;l=0}g=d?a+4|0:0;if(!(d&((k|0)!=0&(j&(i&(h|0)!=0))))){m=-136;return m|0}Bb(a);nb(g,c[b>>2]|0,c[b+4>>2]|0);if(qb(g,1)|0){m=-135;return m|0}i=qb(g,c[h+44>>2]|0)|0;if((i|0)==-1){m=-136;return m|0}c[a+40>>2]=i;h=k+32+(i<<2)|0;i=c[h>>2]|0;if(!i){m=-136;return m|0}j=c[i>>2]|0;i=a+28|0;c[i>>2]=j;do if(j){c[a+24>>2]=qb(g,1)|0;d=qb(g,1)|0;c[a+32>>2]=d;if((d|0)==-1){m=-136;return m|0}else{n=c[i>>2]|0;break}}else{c[a+24>>2]=0;c[a+32>>2]=0;n=0}while(0);i=b+16|0;g=c[i+4>>2]|0;j=a+48|0;c[j>>2]=c[i>>2];c[j+4>>2]=g;g=b+24|0;j=c[g+4>>2]|0;i=a+56|0;c[i>>2]=c[g>>2];c[i+4>>2]=j;c[a+44>>2]=c[b+12>>2];b=a+36|0;c[b>>2]=c[k+(n<<2)>>2];n=l+4|0;c[a>>2]=Ab(a,c[n>>2]<<2)|0;if((c[n>>2]|0)>0){l=0;do{j=Ab(a,c[b>>2]<<2)|0;c[(c[a>>2]|0)+(l<<2)>>2]=j;l=l+1|0}while((l|0)<(c[n>>2]|0))}n=c[(c[h>>2]|0)+12>>2]|0;m=$a[c[(c[352+(c[k+288+(n<<2)>>2]<<2)>>2]|0)+16>>2]&15](a,c[k+544+(n<<2)>>2]|0)|0;return m|0}function Nb(a){a=a|0;if(!a)return;yd(a);return}function Ob(a){a=a|0;if(a)yd(a);return}function Pb(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0.0,k=0.0,l=0.0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0.0,B=0.0,C=0.0,D=0,E=0,F=0.0,G=0;h=a;i=h+48|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(i|0));h=c[d>>2]|0;c[a+36>>2]=h;d=~~(+td(+Y(+(+(h|0)*8.0))*1.4426950408889634)+-1.0);i=a+32|0;c[i>>2]=d;j=+(f|0);k=+(e|0);l=+(1<<d+1|0);d=~~(l*(+Y(+(j*.25*.5/k))*1.4426950216293335+-5.965784072875977)-+(h|0));c[a+28>>2]=d;c[a+40>>2]=1-d+~~(l*(+Y(+((+(e|0)+.25)*j*.5/k))*1.4426950216293335+-5.965784072875977)+.5);d=e<<2;h=xd(d)|0;c[a+16>>2]=h;m=xd(d)|0;c[a+20>>2]=m;n=xd(d)|0;c[a+24>>2]=n;o=a+4|0;c[o>>2]=b;c[a>>2]=e;c[a+44>>2]=f;p=a+48|0;g[p>>2]=1.0;do if((f|0)>=26e3){if((f|0)<38e3){g[p>>2]=.9399999976158142;break}if((f|0)>46e3)g[p>>2]=1.274999976158142}else g[p>>2]=0.0;while(0);j=k*2.0;l=+(f|0);p=(e|0)>0;q=0;r=0;a:while(1){s=p^1;t=q;while(1){u=t;t=t+1|0;v=~~+td(j*+X(+(+(t|0)*.08664337545633316+2.7488713472395148))/l);if(!((v|0)<=(r|0)|s)){w=t;x=v;y=u;break}if((t|0)>=87){z=r;break a}}A=+g[408+(y<<2)>>2];B=(+g[408+(w<<2)>>2]-A)/+(x-r|0);t=r-x|0;s=r-e|0;u=r-(t>>>0>s>>>0?t:s)|0;C=A;s=r;while(1){g[h+(s<<2)>>2]=C+100.0;s=s+1|0;if((s|0)==(u|0))break;else C=C+B}if((w|0)<87){p=(u|0)<(e|0);q=w;r=u}else{z=u;break}}if((z|0)<(e|0)){r=z;do{c[h+(r<<2)>>2]=c[h+(r+-1<<2)>>2];r=r+1|0}while((r|0)!=(e|0))}r=(e|0)>0;if(r){h=(f|0)/(e<<1|0)|0;f=c[b+120>>2]|0;z=b+124|0;w=b+116|0;q=b+112|0;p=1;x=0;y=-99;while(1){s=_(h,x)|0;B=+(s|0);C=+V(+(+(_(s,s)|0)*1.8499999754340024e-08))*2.240000009536743+ +V(+(B*7.399999885819852e-04))*13.100000381469727+B*9.999999747378752e-05;b:do if((f+y|0)<(x|0)){B=C-+g[q>>2];s=y;while(1){t=_(s,h)|0;A=+(t|0);if(!(+V(+(A*7.399999885819852e-04))*13.100000381469727+A*9.999999747378752e-05+ +V(+(+(_(t,t)|0)*1.8499999754340024e-08))*2.240000009536743<B)){D=s;break b}t=s+1|0;if((f+t|0)<(x|0))s=t;else{D=t;break}}}else D=y;while(0);c:do if((p|0)>(e|0))E=p;else{u=(c[z>>2]|0)+x|0;s=p;while(1){if((s|0)>=(u|0)?(t=_(s,h)|0,B=+(t|0),A=+V(+(B*7.399999885819852e-04))*13.100000381469727+B*9.999999747378752e-05+ +V(+(+(_(t,t)|0)*1.8499999754340024e-08))*2.240000009536743,!(A<+g[w>>2]+C)):0){E=s;break c}t=s+1|0;if((s|0)<(e|0))s=t;else{E=t;break}}}while(0);c[n+(x<<2)>>2]=(D<<16)+-65537+E;x=x+1|0;if((x|0)==(e|0))break;else{p=E;y=D}}if(r){C=l*.5;A=+(1<<(c[i>>2]|0)+1|0);i=0;do{c[m+(i<<2)>>2]=~~(A*(+Y(+(C*(+(i|0)+.25)/k))*1.4426950216293335+-5.965784072875977)+.5);i=i+1|0}while((i|0)!=(e|0));F=C}else G=19}else G=19;if((G|0)==19)F=l*.5;c[a+8>>2]=Kc(b+36|0,F/k,e,+g[b+24>>2],+g[b+28>>2])|0;b=xd(12)|0;c[a+12>>2]=b;c[b>>2]=xd(d)|0;c[b+4>>2]=xd(d)|0;c[b+8>>2]=xd(d)|0;if(!r)return;r=c[o>>2]|0;o=c[b>>2]|0;d=c[b+4>>2]|0;a=c[b+8>>2]|0;b=0;do{k=+Y(+((+(b|0)+.5)*l/j))*2.885390043258667+-11.931568145751953;F=k<0.0?0.0:k;k=F>=16.0?16.0:F;G=~~k;F=k-+(G|0);k=1.0-F;i=G+1|0;g[o+(b<<2)>>2]=+g[r+132+(i<<2)>>2]*F+ +g[r+132+(G<<2)>>2]*k;g[d+(b<<2)>>2]=+g[r+200+(i<<2)>>2]*F+ +g[r+200+(G<<2)>>2]*k;g[a+(b<<2)>>2]=+g[r+268+(i<<2)>>2]*F+ +g[r+268+(G<<2)>>2]*k;b=b+1|0}while((b|0)!=(e|0));return}function Qb(a){a=a|0;var b=0,d=0,e=0,f=0;if(!a)return;b=c[a+16>>2]|0;if(b)yd(b);b=c[a+20>>2]|0;if(b)yd(b);b=c[a+24>>2]|0;if(b)yd(b);b=a+8|0;d=c[b>>2]|0;if(d){e=d;d=0;while(1){yd(c[c[e+(d<<2)>>2]>>2]|0);yd(c[(c[(c[b>>2]|0)+(d<<2)>>2]|0)+4>>2]|0);yd(c[(c[(c[b>>2]|0)+(d<<2)>>2]|0)+8>>2]|0);yd(c[(c[(c[b>>2]|0)+(d<<2)>>2]|0)+12>>2]|0);yd(c[(c[(c[b>>2]|0)+(d<<2)>>2]|0)+16>>2]|0);yd(c[(c[(c[b>>2]|0)+(d<<2)>>2]|0)+20>>2]|0);yd(c[(c[(c[b>>2]|0)+(d<<2)>>2]|0)+24>>2]|0);yd(c[(c[(c[b>>2]|0)+(d<<2)>>2]|0)+28>>2]|0);yd(c[(c[b>>2]|0)+(d<<2)>>2]|0);f=d+1|0;if((f|0)==17)break;e=c[b>>2]|0;d=f}yd(c[b>>2]|0)}b=a+12|0;d=c[b>>2]|0;if(d){yd(c[d>>2]|0);yd(c[(c[b>>2]|0)+4>>2]|0);yd(c[(c[b>>2]|0)+8>>2]|0);yd(c[b>>2]|0)}b=a;a=b+52|0;do{c[b>>2]=0;b=b+4|0}while((b|0)<(a|0));return}function Rb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0;e=i;f=c[a>>2]|0;h=i;i=i+((1*(f<<2)|0)+15&-16)|0;j=a+24|0;Lc(f,c[j>>2]|0,b,d,140.0,-1);k=(f|0)>0;if(k){l=0;do{g[h+(l<<2)>>2]=+g[b+(l<<2)>>2]-+g[d+(l<<2)>>2];l=l+1|0}while((l|0)!=(f|0))}l=a+4|0;Lc(f,c[j>>2]|0,h,d,0.0,c[(c[l>>2]|0)+128>>2]|0);if(k)m=0;else{i=e;return}do{j=h+(m<<2)|0;g[j>>2]=+g[b+(m<<2)>>2]-+g[j>>2];m=m+1|0}while((m|0)!=(f|0));if(!k){i=e;return}k=c[l>>2]|0;l=0;do{m=d+(l<<2)|0;b=~~(+g[m>>2]+.5);j=(b|0)>39?39:b;g[m>>2]=+g[k+336+(((j|0)<0?0:j)<<2)>>2]+ +g[h+(l<<2)>>2];l=l+1|0}while((l|0)!=(f|0));i=e;return}function Sb(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=+e;f=+f;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0.0,q=0,r=0.0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0.0,E=0,F=0,G=0,H=0,I=0,J=0,K=0.0,L=0.0,M=0,N=0,O=0,P=0;h=i;j=c[a>>2]|0;k=a+40|0;l=c[k>>2]|0;m=i;i=i+((1*(l<<2)|0)+15&-16)|0;n=a+4|0;o=c[n>>2]|0;p=+g[o+4>>2]+f;if((l|0)>0){q=0;do{g[m+(q<<2)>>2]=-9999.0;q=q+1|0}while((q|0)<(l|0))}f=+g[o+8>>2];r=p<f?f:p;q=(j|0)>0;if(q){s=c[a+16>>2]|0;t=0;do{g[d+(t<<2)>>2]=+g[s+(t<<2)>>2]+r;t=t+1|0}while((t|0)!=(j|0));t=c[a+8>>2]|0;r=+g[o+496>>2]-e;if(q){q=c[a+20>>2]|0;o=a+32|0;s=a+36|0;u=a+28|0;v=0;while(1){w=c[q+(v<<2)>>2]|0;x=v;e=+g[b+(v<<2)>>2];a:while(1){y=x;while(1){z=y+1|0;if((z|0)>=(j|0)){A=0;B=z;C=y;D=e;break a}if((c[q+(z<<2)>>2]|0)!=(w|0)){A=1;B=z;C=y;D=e;break a}p=+g[b+(z<<2)>>2];if(p>e){x=z;e=p;continue a}else y=z}}if(D+6.0>+g[d+(C<<2)>>2]?(x=w>>c[o>>2],y=(x|0)>16?16:x,x=c[s>>2]|0,z=~~((r+D+-30.0)*.10000000149011612),E=(z|0)<0?0:z,z=c[(c[t+(((y|0)<0?0:y)<<2)>>2]|0)+(((E|0)>7?7:E)<<2)>>2]|0,E=~~+g[z+4>>2],e=+g[z>>2],y=~~e,(y|0)<(E|0)):0){F=y;y=~~((e+-16.0)*+(x|0)-+(x>>1|0)+ +((c[q+(C<<2)>>2]|0)-(c[u>>2]|0)|0));do{if((y|0)>0?(e=+g[z+(F+2<<2)>>2]+D,G=m+(y<<2)|0,+g[G>>2]<e):0)g[G>>2]=e;y=y+x|0;F=F+1|0}while((F|0)<(E|0)&(y|0)<(l|0))}if(A)v=B;else{H=s;break}}}else I=7}else I=7;if((I|0)==7)H=a+36|0;I=c[H>>2]|0;Mc(m,I,l);l=c[a>>2]|0;b:do if((l|0)>1){H=c[a+20>>2]|0;s=c[H>>2]|0;B=c[a+28>>2]|0;v=(c[n>>2]|0)+32|0;A=1;u=s;C=0;q=s-(I>>1)-B|0;while(1){D=+g[m+(q<<2)>>2];s=((c[H+(A<<2)>>2]|0)+u>>1)-B|0;r=+g[v>>2];e=D>r?r:D;c:do if((q|0)<(s|0)){t=q;D=e;while(1){o=D==-9999.0;b=t;while(1){j=b+1|0;r=+g[m+(j<<2)>>2];if(r>-9999.0){if(o|r<D){J=j;K=r;break}}else if(o){J=j;K=r;break}if((j|0)<(s|0))b=j;else{L=D;M=j;break c}}if((J|0)<(s|0)){t=J;D=K}else{L=K;M=J;break}}}else{L=e;M=q}while(0);s=M+B|0;d:do if((C|0)>=(l|0)|(u|0)>(s|0))N=C;else{t=C;while(1){b=d+(t<<2)|0;if(+g[b>>2]<L)g[b>>2]=L;b=t+1|0;if((b|0)>=(l|0)){N=b;break d}if((c[H+(b<<2)>>2]|0)>(s|0)){N=b;break}else t=b}}while(0);s=N+1|0;if((s|0)>=(l|0)){O=N;break b}A=s;u=c[H+(N<<2)>>2]|0;C=N;q=M}}else O=0;while(0);L=+g[m+((c[k>>2]|0)+-1<<2)>>2];if((O|0)<(l|0))P=O;else{i=h;return}do{O=d+(P<<2)|0;if(+g[O>>2]<L)g[O>>2]=L;P=P+1|0}while((P|0)!=(l|0));i=h;return}function Tb(a,b,d,e,f,h,i){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;var j=0,k=0,l=0.0,m=0,n=0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0;j=c[a>>2]|0;k=c[a+4>>2]|0;l=+g[k+12+(e<<2)>>2];if((j|0)<=0)return;m=c[(c[a+12>>2]|0)+(e<<2)>>2]|0;n=k+108|0;k=(e|0)==1;o=+g[a+48>>2];p=o*.005;q=o*.0003;a=0;do{o=+g[m+(a<<2)>>2]+ +g[b+(a<<2)>>2];r=+g[n>>2];s=o>r?r:o;o=+g[d+(a<<2)>>2]+l;g[f+(a<<2)>>2]=s<o?o:s;if(k){o=s-+g[i+(a<<2)>>2];s=o+17.200000762939453;if(o>-17.200000762939453){o=1.0-p*s;if(o<0.0)t=9.999999747378752e-05;else t=o}else t=1.0-q*s;e=h+(a<<2)|0;g[e>>2]=+g[e>>2]*t}a=a+1|0}while((a|0)!=(j|0));return}function Ub(a,b,d,e,f,j,k,l,m){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;j=j|0;k=k|0;l=l|0;m=m|0;var n=0,o=0,p=0,q=0,r=0,s=0.0,t=0,u=0,v=0,w=0,x=0,y=0,z=0.0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,O=0,P=0,Q=0,R=0,S=0.0,T=0,U=0.0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0.0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0;n=i;o=c[d>>2]|0;p=d+4|0;d=c[p>>2]|0;if(!(c[d+500>>2]|0))q=16;else q=c[d+508>>2]|0;r=c[b+132+((c[d>>2]|0)*60|0)+(a<<2)>>2]|0;s=+h[760+(c[b+252+(a<<2)>>2]<<3)>>3];d=m<<2;t=i;i=i+((1*d|0)+15&-16)|0;u=i;i=i+((1*d|0)+15&-16)|0;v=i;i=i+((1*d|0)+15&-16)|0;w=i;i=i+((1*d|0)+15&-16)|0;x=i;i=i+((1*d|0)+15&-16)|0;y=e+1156|0;z=+h[((o|0)>1e3?832:760)+(c[b+312+(a<<2)>>2]<<3)>>3];a=_(d,q)|0;b=i;i=i+((1*a|0)+15&-16)|0;c[t>>2]=b;A=i;i=i+((1*a|0)+15&-16)|0;c[u>>2]=A;B=i;i=i+((1*a|0)+15&-16)|0;c[v>>2]=B;C=i;i=i+((1*a|0)+15&-16)|0;c[w>>2]=C;if((m|0)>1?(c[t+4>>2]=b+(q<<2),c[u+4>>2]=A+(q<<2),c[v+4>>2]=B+(q<<2),c[w+4>>2]=C+(q<<2),(m|0)!=2):0){C=2;do{B=c[u>>2]|0;A=c[v>>2]|0;b=c[w>>2]|0;D=_(C,q)|0;c[t+(C<<2)>>2]=(c[t>>2]|0)+(D<<2);c[u+(C<<2)>>2]=B+(D<<2);c[v+(C<<2)>>2]=A+(D<<2);c[w+(C<<2)>>2]=b+(D<<2);C=C+1|0}while((C|0)!=(m|0))}C=c[y>>2]|0;if((o|0)>0){D=c[w>>2]|0;b=(m|0)>0;A=~q;B=0;E=~o;while(1){F=~((E|0)>(A|0)?E:A);G=o-B|0;H=(q|0)>(G|0)?G:q;Jd(x|0,k|0,d|0)|0;Fd(D|0,0,a|0)|0;if(b){G=(H|0)>0;I=r-B|0;J=0;do{K=c[j+(J<<2)>>2]|0;L=K+(B<<2)|0;if(!(c[x+(J<<2)>>2]|0)){if(G){M=c[v+(J<<2)>>2]|0;O=c[t+(J<<2)>>2]|0;P=c[u+(J<<2)>>2]|0;Q=c[w+(J<<2)>>2]|0;R=0;do{g[M+(R<<2)>>2]=1.000000013351432e-10;g[O+(R<<2)>>2]=0.0;g[P+(R<<2)>>2]=0.0;c[Q+(R<<2)>>2]=0;c[K+(R+B<<2)>>2]=0;R=R+1|0}while((R|0)!=(F|0))}}else{R=c[v+(J<<2)>>2]|0;if(G){Q=0;do{c[R+(Q<<2)>>2]=c[56400+(c[K+(Q+B<<2)>>2]<<2)>>2];Q=Q+1|0}while((Q|0)!=(F|0));Q=c[f+(J<<2)>>2]|0;K=c[w+(J<<2)>>2]|0;if(G){P=0;do{S=+N(+(+g[Q+(P+B<<2)>>2]));c[K+(P<<2)>>2]=!(S/+g[R+(P<<2)>>2]<((P|0)>=(I|0)?z:s))&1;P=P+1|0}while((P|0)!=(H|0));if(G){P=c[t+(J<<2)>>2]|0;K=u+(J<<2)|0;O=c[K>>2]|0;M=0;do{T=Q+(M+B<<2)|0;S=+g[T>>2];U=S*S;V=P+(M<<2)|0;g[V>>2]=U;g[O+(M<<2)>>2]=U;if(+g[T>>2]<0.0)g[V>>2]=-+g[V>>2];V=R+(M<<2)|0;U=+g[V>>2];g[V>>2]=U*U;M=M+1|0}while((M|0)!=(F|0));W=K;X=P}else Y=21}else Y=21}else Y=21;if((Y|0)==21){Y=0;W=u+(J<<2)|0;X=c[t+(J<<2)>>2]|0}+Nc(c[p>>2]|0,r,X,c[W>>2]|0,R,0,B,H,L)}J=J+1|0}while((J|0)!=(m|0))}J=c[y>>2]|0;if((J|0)>0){G=(H|0)>0;I=l-B|0;P=r-B|0;K=J;M=0;while(1){O=c[e+1160+(M<<2)>>2]|0;Q=c[e+2184+(M<<2)>>2]|0;V=c[j+(O<<2)>>2]|0;T=V+(B<<2)|0;Z=c[j+(Q<<2)>>2]|0;$=c[t+(O<<2)>>2]|0;aa=c[t+(Q<<2)>>2]|0;ba=c[u+(O<<2)>>2]|0;ca=c[u+(Q<<2)>>2]|0;da=c[v+(O<<2)>>2]|0;ea=c[v+(Q<<2)>>2]|0;fa=c[w+(O<<2)>>2]|0;ga=c[w+(Q<<2)>>2]|0;ha=x+(O<<2)|0;O=x+(Q<<2)|0;if((c[ha>>2]|0)==0?(c[O>>2]|0)==0:0)ia=K;else{c[O>>2]=1;c[ha>>2]=1;if(G){ha=0;do{do if((ha|0)<(I|0)){O=fa+(ha<<2)|0;Q=ga+(ha<<2)|0;if((c[O>>2]|0)==0?(c[Q>>2]|0)==0:0){do if((ha|0)>=(P|0)){ja=$+(ha<<2)|0;U=+g[ja>>2];ka=aa+(ha<<2)|0;S=+g[ka>>2];la=+N(+S)+ +N(+U);g[ba+(ha<<2)>>2]=la;if(S+U<0.0){g[ja>>2]=-la;ma=ka;break}else{g[ja>>2]=la;ma=ka;break}}else{ka=aa+(ha<<2)|0;ja=$+(ha<<2)|0;la=+g[ja>>2]+ +g[ka>>2];g[ja>>2]=la;g[ba+(ha<<2)>>2]=+N(+la);ma=ka}while(0);g[ca+(ha<<2)>>2]=0.0;g[ma>>2]=0.0;c[Q>>2]=1;c[Z+(ha+B<<2)>>2]=0;break}ka=$+(ha<<2)|0;la=+N(+(+g[ka>>2]));g[ka>>2]=+N(+(+g[aa+(ha<<2)>>2]))+la;ka=ba+(ha<<2)|0;g[ka>>2]=+g[ca+(ha<<2)>>2]+ +g[ka>>2];c[Q>>2]=1;c[O>>2]=1;ka=ha+B|0;ja=V+(ka<<2)|0;na=c[ja>>2]|0;oa=Z+(ka<<2)|0;ka=c[oa>>2]|0;if((((na|0)>-1?na:0-na|0)|0)>(((ka|0)>-1?ka:0-ka|0)|0)){pa=(na|0)>0?na-ka|0:ka-na|0;c[oa>>2]=pa;qa=c[ja>>2]|0;ra=pa}else{c[oa>>2]=(ka|0)>0?na-ka|0:ka-na|0;c[ja>>2]=ka;qa=ka;ra=c[oa>>2]|0}if((ra|0)>=(((qa|0)>-1?qa:0-qa|0)<<1|0)){c[oa>>2]=0-ra;c[ja>>2]=0-(c[ja>>2]|0)}}while(0);ja=da+(ha<<2)|0;oa=ea+(ha<<2)|0;la=+g[oa>>2]+ +g[ja>>2];g[oa>>2]=la;g[ja>>2]=la;ha=ha+1|0}while((ha|0)!=(F|0))}+Nc(c[p>>2]|0,r,$,ba,da,fa,B,H,T);ia=c[y>>2]|0}M=M+1|0;if((M|0)>=(ia|0)){sa=ia;break}else K=ia}}else sa=J;B=B+q|0;if((o|0)<=(B|0)){ta=sa;break}else E=E+q|0}}else ta=C;if((ta|0)>0){ua=ta;va=0}else{i=n;return}while(1){ta=k+(c[e+1160+(va<<2)>>2]<<2)|0;C=e+2184+(va<<2)|0;if((c[ta>>2]|0)==0?(c[k+(c[C>>2]<<2)>>2]|0)==0:0)wa=ua;else{c[ta>>2]=1;c[k+(c[C>>2]<<2)>>2]=1;wa=c[y>>2]|0}va=va+1|0;if((va|0)>=(wa|0))break;else ua=wa}i=n;return}function Vb(a){a=a|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;return}function Wb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0;if(!a)return;b=c[a>>2]|0;if(b){d=a+8|0;e=c[d>>2]|0;if((e|0)>0){f=e;e=b;g=0;while(1){h=c[e+(g<<2)>>2]|0;if(!h)i=f;else{yd(h);i=c[d>>2]|0}h=g+1|0;if((h|0)>=(i|0))break;f=i;e=c[a>>2]|0;g=h}j=c[a>>2]|0}else j=b;yd(j)}j=c[a+4>>2]|0;if(j)yd(j);j=c[a+12>>2]|0;if(j)yd(j);c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;return}function Xb(a){a=a|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+16>>2]=0;c[a+20>>2]=0;c[a+24>>2]=0;c[a+28>>2]=zd(1,3664)|0;return}function Yb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;b=c[a+28>>2]|0;if(!b){c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+16>>2]=0;c[a+20>>2]=0;c[a+24>>2]=0;c[a+28>>2]=0;return}d=b+8|0;e=c[d>>2]|0;if((e|0)>0){f=e;e=0;while(1){g=c[b+32+(e<<2)>>2]|0;if(!g)h=f;else{yd(g);h=c[d>>2]|0}e=e+1|0;if((e|0)>=(h|0))break;else f=h}}h=b+12|0;f=c[h>>2]|0;if((f|0)>0){e=f;f=0;while(1){d=c[b+544+(f<<2)>>2]|0;if(!d)i=e;else{Wa[c[(c[352+(c[b+288+(f<<2)>>2]<<2)>>2]|0)+8>>2]&7](d);i=c[h>>2]|0}f=f+1|0;if((f|0)>=(i|0))break;else e=i}}i=b+16|0;e=c[i>>2]|0;if((e|0)>0){f=e;e=0;while(1){h=c[b+1056+(e<<2)>>2]|0;if(!h)j=f;else{Wa[c[(c[328+(c[b+800+(e<<2)>>2]<<2)>>2]|0)+12>>2]&7](h);j=c[i>>2]|0}e=e+1|0;if((e|0)>=(j|0))break;else f=j}}j=b+20|0;f=c[j>>2]|0;if((f|0)>0){e=f;f=0;while(1){i=c[b+1568+(f<<2)>>2]|0;if(!i)k=e;else{Wa[c[(c[336+(c[b+1312+(f<<2)>>2]<<2)>>2]|0)+12>>2]&7](i);k=c[j>>2]|0}f=f+1|0;if((f|0)>=(k|0))break;else e=k}}k=b+24|0;e=b+2848|0;if((c[k>>2]|0)>0){f=0;do{j=c[b+1824+(f<<2)>>2]|0;if(j)yc(j);j=c[e>>2]|0;if(j)zc(j+(f*56|0)|0);f=f+1|0}while((f|0)<(c[k>>2]|0))}k=c[e>>2]|0;if(k)yd(k);k=b+28|0;if((c[k>>2]|0)>0){e=0;do{Ob(c[b+2852+(e<<2)>>2]|0);e=e+1|0}while((e|0)<(c[k>>2]|0))}yd(b);c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+16>>2]=0;c[a+20>>2]=0;c[a+24>>2]=0;c[a+28>>2]=0;return}function Zb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;f=i;i=i+32|0;g=f;h=f+20|0;if(!e){j=-133;i=f;return j|0}nb(g,c[e>>2]|0,c[e+4>>2]|0);k=qb(g,8)|0;a[h>>0]=0;a[h+1>>0]=0;a[h+2>>0]=0;a[h+3>>0]=0;a[h+4>>0]=0;a[h>>0]=qb(g,8)|0;a[h+1>>0]=qb(g,8)|0;a[h+2>>0]=qb(g,8)|0;a[h+3>>0]=qb(g,8)|0;a[h+4>>0]=qb(g,8)|0;a[h+5>>0]=qb(g,8)|0;if(wd(h,904,6)|0){j=-132;i=f;return j|0}if((k|0)==5){if(!(c[b+8>>2]|0)){j=-133;i=f;return j|0}if(!(c[d+12>>2]|0)){j=-133;i=f;return j|0}h=c[b+28>>2]|0;if(!h){j=-129;i=f;return j|0}l=qb(g,8)|0;m=h+24|0;c[m>>2]=l+1;a:do if((l|0)>=0){n=0;do{o=nc(g)|0;c[h+1824+(n<<2)>>2]=o;n=n+1|0;if(!o)break a}while((n|0)<(c[m>>2]|0));n=qb(g,6)|0;if((n|0)>=0){o=0;while(1){if(qb(g,16)|0)break a;if((o|0)<(n|0))o=o+1|0;else break}o=qb(g,6)|0;n=h+16|0;c[n>>2]=o+1;if((o|0)>=0){o=0;do{p=qb(g,16)|0;c[h+800+(o<<2)>>2]=p;if(p>>>0>1)break a;q=$a[c[(c[328+(p<<2)>>2]|0)+4>>2]&15](b,g)|0;c[h+1056+(o<<2)>>2]=q;o=o+1|0;if(!q)break a}while((o|0)<(c[n>>2]|0));n=qb(g,6)|0;o=h+20|0;c[o>>2]=n+1;if((n|0)>=0){n=0;do{q=qb(g,16)|0;c[h+1312+(n<<2)>>2]=q;if(q>>>0>2)break a;p=$a[c[(c[336+(q<<2)>>2]|0)+4>>2]&15](b,g)|0;c[h+1568+(n<<2)>>2]=p;n=n+1|0;if(!p)break a}while((n|0)<(c[o>>2]|0));o=qb(g,6)|0;n=h+12|0;c[n>>2]=o+1;if((o|0)>=0){o=(c[88]|0)+4|0;p=0;do{q=qb(g,16)|0;c[h+288+(p<<2)>>2]=q;if(q)break a;q=$a[c[o>>2]&15](b,g)|0;c[h+544+(p<<2)>>2]=q;p=p+1|0;if(!q)break a}while((p|0)<(c[n>>2]|0));p=qb(g,6)|0;o=h+8|0;c[o>>2]=p+1;if((p|0)>=0){p=0;do{q=h+32+(p<<2)|0;c[q>>2]=zd(1,16)|0;r=qb(g,1)|0;c[c[q>>2]>>2]=r;r=qb(g,16)|0;c[(c[q>>2]|0)+4>>2]=r;r=qb(g,16)|0;c[(c[q>>2]|0)+8>>2]=r;r=qb(g,8)|0;s=c[q>>2]|0;c[s+12>>2]=r;if((c[s+4>>2]|0)>0)break a;if((c[s+8>>2]|0)>0)break a;p=p+1|0;if((r|0)<0?1:(r|0)>=(c[n>>2]|0))break a}while((p|0)<(c[o>>2]|0));if((qb(g,1)|0)==1){j=0;i=f;return j|0}}}}}}}while(0);Yb(b);j=-133;i=f;return j|0}else if((k|0)==1){if(!(c[e+8>>2]|0)){j=-133;i=f;return j|0}e=b+8|0;if(c[e>>2]|0){j=-133;i=f;return j|0}h=c[b+28>>2]|0;if(!h){j=-129;i=f;return j|0}m=qb(g,32)|0;c[b>>2]=m;if(m){j=-134;i=f;return j|0}m=b+4|0;c[m>>2]=qb(g,8)|0;c[e>>2]=qb(g,32)|0;c[b+12>>2]=qb(g,32)|0;c[b+16>>2]=qb(g,32)|0;c[b+20>>2]=qb(g,32)|0;c[h>>2]=1<<(qb(g,4)|0);l=1<<(qb(g,4)|0);c[h+4>>2]=l;if((((c[e>>2]|0)>=1?(c[m>>2]|0)>=1:0)?(m=c[h>>2]|0,!((l|0)>8192|((m|0)<64|(l|0)<(m|0)))):0)?(qb(g,1)|0)==1:0){j=0;i=f;return j|0}Yb(b);j=-133;i=f;return j|0}else if((k|0)==3){if(!(c[b+8>>2]|0)){j=-133;i=f;return j|0}b=qb(g,32)|0;b:do if((b|0)>=0?(k=g+16|0,(b|0)<=((c[k>>2]|0)+-8|0)):0){m=zd(b+1|0,1)|0;c[d+12>>2]=m;if(b){l=m;m=b;while(1){m=m+-1|0;a[l>>0]=qb(g,8)|0;if(!m)break;else l=l+1|0}}l=qb(g,32)|0;if((l|0)>=0?(m=c[k>>2]|0,(l|0)<=(m-(rb(g)|0)>>2|0)):0){m=d+8|0;c[m>>2]=l;h=l+1|0;c[d>>2]=zd(h,4)|0;e=d+4|0;c[e>>2]=zd(h,4)|0;if((l|0)>0){l=0;do{h=qb(g,32)|0;if((h|0)<0){t=d;break b}o=c[k>>2]|0;if((h|0)>(o-(rb(g)|0)|0)){t=d;break b}c[(c[e>>2]|0)+(l<<2)>>2]=h;o=zd(h+1|0,1)|0;c[(c[d>>2]|0)+(l<<2)>>2]=o;if(h){o=c[(c[d>>2]|0)+(l<<2)>>2]|0;p=h;while(1){p=p+-1|0;a[o>>0]=qb(g,8)|0;if(!p)break;else o=o+1|0}}l=l+1|0}while((l|0)<(c[m>>2]|0))}if((qb(g,1)|0)==1){j=0;i=f;return j|0}else t=d}else u=28}else u=28;while(0);do if((u|0)==28)if(!d){j=-133;i=f;return j|0}else{t=d;break}while(0);u=c[t>>2]|0;if(u){g=d+8|0;b=c[g>>2]|0;if((b|0)>0){m=u;l=b;b=0;while(1){e=c[m+(b<<2)>>2]|0;if(!e)v=l;else{yd(e);v=c[g>>2]|0}e=b+1|0;if((e|0)>=(v|0))break;m=c[t>>2]|0;l=v;b=e}w=c[d>>2]|0}else w=u;yd(w)}w=c[d+4>>2]|0;if(w)yd(w);w=c[d+12>>2]|0;if(w)yd(w);c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;j=-133;i=f;return j|0}else{j=-133;i=f;return j|0}return 0}function _b(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0.0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0,Oa=0,Pa=0,Qa=0,Ra=0,Sa=0,Ua=0,Va=0,Wa=0,Xa=0,Ya=0,Za=0,_a=0.0,$a=0.0,ab=0,bb=0,cb=0.0,db=0,eb=0,fb=0,gb=0,hb=0,ib=0;f=i;i=i+4912|0;h=f+264|0;j=f+3856|0;k=f+4388|0;l=f;m=f+4128|0;n=f+4648|0;o=f+4908|0;p=f+4120|0;q=f+4116|0;r=f+3848|0;s=f+3852|0;t=f+4124|0;u=c[b+1296>>2]|0;v=c[b+1288>>2]|0;w=c[b+1284>>2]|0;x=(w|0)>0;if(x){y=0;do{c[j+(y<<2)>>2]=-200;y=y+1|0}while((y|0)!=(w|0));if(x){y=0;do{c[k+(y<<2)>>2]=-200;y=y+1|0}while((y|0)!=(w|0));if(x){Fd(l|0,0,w<<2|0)|0;y=0;do{c[m+(y<<2)>>2]=1;y=y+1|0}while((y|0)!=(w|0));if(x){Fd(n|0,-1,w<<2|0)|0;if((w|0)<=1){z=0;i=f;return z|0}x=v+-1|0;y=u+1112|0;A=w+-1|0;B=c[b>>2]|0;C=0;D=0;while(1){E=C;C=C+1|0;F=B;B=c[b+(C<<2)>>2]|0;G=h+(E*56|0)|0;H=G;I=H+56|0;do{c[H>>2]=0;H=H+4|0}while((H|0)<(I|0));c[G>>2]=F;c[h+(E*56|0)+4>>2]=B;J=(B|0)<(v|0)?B:x;if((J|0)<(F|0)){K=0;L=0;M=0;N=0;O=0;P=0;Q=0;R=0;S=0;T=0;U=0;V=0}else{W=F;X=0;Y=0;Z=0;$=0;aa=0;ba=0;ca=0;da=0;ea=0;fa=0;ga=0;ha=0;while(1){ia=+g[e+(W<<2)>>2];ja=~~(ia*7.314285755157471+1023.5);ka=(ja|0)>1023?1023:(ja|0)<0?0:ja;do if(ka)if(!(+g[y>>2]+ +g[d+(W<<2)>>2]>=ia)){la=X;ma=Y+1|0;na=Z;oa=(_(W,W)|0)+$|0;pa=aa;qa=W+ba|0;ra=ca;sa=(_(ka,W)|0)+da|0;ta=ea;ua=(_(ka,ka)|0)+fa|0;va=ga;wa=ka+ha|0;break}else{la=X+1|0;ma=Y;na=(_(W,W)|0)+Z|0;oa=$;pa=W+aa|0;qa=ba;ra=(_(ka,W)|0)+ca|0;sa=da;ta=(_(ka,ka)|0)+ea|0;ua=fa;va=ka+ga|0;wa=ha;break}else{la=X;ma=Y;na=Z;oa=$;pa=aa;qa=ba;ra=ca;sa=da;ta=ea;ua=fa;va=ga;wa=ha}while(0);if((W|0)<(J|0)){W=W+1|0;X=la;Y=ma;Z=na;$=oa;aa=pa;ba=qa;ca=ra;da=sa;ea=ta;fa=ua;ga=va;ha=wa}else{K=la;L=ma;M=na;N=oa;O=pa;P=qa;Q=ra;R=sa;S=ta;T=ua;U=va;V=wa;break}}}c[h+(E*56|0)+8>>2]=O;c[h+(E*56|0)+12>>2]=U;c[h+(E*56|0)+16>>2]=M;c[h+(E*56|0)+20>>2]=S;c[h+(E*56|0)+24>>2]=Q;c[h+(E*56|0)+28>>2]=K;c[h+(E*56|0)+32>>2]=P;c[h+(E*56|0)+36>>2]=V;c[h+(E*56|0)+40>>2]=N;c[h+(E*56|0)+44>>2]=T;c[h+(E*56|0)+48>>2]=R;c[h+(E*56|0)+52>>2]=L;ha=K+D|0;if((C|0)==(A|0)){xa=ha;break}else D=ha}}else ya=9}else ya=9}else ya=9}else ya=9;if((ya|0)==9){if(w){z=0;i=f;return z|0}D=h+4|0;H=h;I=H+56|0;do{c[H>>2]=0;H=H+4|0}while((H|0)<(I|0));c[D>>2]=v;if((v|0)<1){za=0;Aa=0;Ba=0;Ca=0;Da=0;Ea=0;Fa=0;Ga=0;Ha=0;Ia=0;Ja=0;Ka=0}else{D=u+1112|0;H=0;I=0;A=0;C=0;K=0;L=0;R=0;T=0;N=0;V=0;P=0;Q=0;S=0;while(1){ia=+g[e+(H<<2)>>2];M=~~(ia*7.314285755157471+1023.5);U=(M|0)>1023?1023:(M|0)<0?0:M;do if(U)if(!(+g[D>>2]+ +g[d+(H<<2)>>2]>=ia)){La=I;Ma=A+1|0;Na=C;Oa=(_(H,H)|0)+K|0;Pa=L;Qa=H+R|0;Ra=T;Sa=(_(U,H)|0)+N|0;Ua=V;Va=(_(U,U)|0)+P|0;Wa=Q;Xa=U+S|0;break}else{La=I+1|0;Ma=A;Na=(_(H,H)|0)+C|0;Oa=K;Pa=H+L|0;Qa=R;Ra=(_(U,H)|0)+T|0;Sa=N;Ua=(_(U,U)|0)+V|0;Va=P;Wa=U+Q|0;Xa=S;break}else{La=I;Ma=A;Na=C;Oa=K;Pa=L;Qa=R;Ra=T;Sa=N;Ua=V;Va=P;Wa=Q;Xa=S}while(0);H=H+1|0;if((H|0)==(v|0)){za=La;Aa=Ma;Ba=Na;Ca=Oa;Da=Pa;Ea=Qa;Fa=Ra;Ga=Sa;Ha=Ua;Ia=Va;Ja=Wa;Ka=Xa;break}else{I=La;A=Ma;C=Na;K=Oa;L=Pa;R=Qa;T=Ra;N=Sa;V=Ua;P=Va;Q=Wa;S=Xa}}}c[h+8>>2]=Da;c[h+12>>2]=Ja;c[h+16>>2]=Ba;c[h+20>>2]=Ha;c[h+24>>2]=Fa;c[h+28>>2]=za;c[h+32>>2]=Ea;c[h+36>>2]=Ka;c[h+40>>2]=Ca;c[h+44>>2]=Ia;c[h+48>>2]=Ga;c[h+52>>2]=Aa;xa=za}if(!xa){z=0;i=f;return z|0}c[o>>2]=-200;c[p>>2]=-200;Oc(h,w+-1|0,o,p,u)|0;xa=c[o>>2]|0;c[j>>2]=xa;c[k>>2]=xa;o=c[p>>2]|0;p=k+4|0;c[p>>2]=o;za=j+4|0;c[za>>2]=o;o=(w|0)>2;do if(o){Aa=u+1112|0;Ga=u+1096|0;Ia=u+1100|0;Ca=u+1104|0;Ka=2;a:while(1){Ea=c[b+520+(Ka<<2)>>2]|0;Fa=c[l+(Ea<<2)>>2]|0;Ha=c[m+(Ea<<2)>>2]|0;Ba=n+(Fa<<2)|0;b:do if((c[Ba>>2]|0)!=(Ha|0)){Ja=c[b+520+(Fa<<2)>>2]|0;Da=c[b+520+(Ha<<2)>>2]|0;c[Ba>>2]=Ha;Xa=c[u+836+(Fa<<2)>>2]|0;S=c[u+836+(Ha<<2)>>2]|0;Wa=c[j+(Fa<<2)>>2]|0;Q=k+(Fa<<2)|0;Va=c[Q>>2]|0;if((Wa|0)>=0)if((Va|0)<0)Ya=Wa;else Ya=Va+Wa>>1;else Ya=Va;Va=j+(Ha<<2)|0;Wa=c[Va>>2]|0;P=c[k+(Ha<<2)>>2]|0;if((Wa|0)>=0)if((P|0)<0)Za=Wa;else Za=P+Wa>>1;else Za=P;if((Ya|0)==-1|(Za|0)==-1){ya=38;break a}P=Za-Ya|0;Wa=S-Xa|0;Ua=(P|0)/(Wa|0)|0;V=P>>31|1;ia=+g[e+(Xa<<2)>>2];Sa=~~(ia*7.314285755157471+1023.5);N=(Sa|0)>1023?1023:(Sa|0)<0?0:Sa;Sa=_(Ua,Wa)|0;Ra=((P|0)>-1?P:0-P|0)-((Sa|0)>-1?Sa:0-Sa|0)|0;Sa=Ya-N|0;P=_(Sa,Sa)|0;_a=+g[Aa>>2];if(_a+ +g[d+(Xa<<2)>>2]>=ia){ia=+(Ya|0);$a=+(N|0);if(!(+g[Ga>>2]+ia<$a)?!(ia-+g[Ia>>2]>$a):0)ya=42}else ya=42;c:do if((ya|0)==42){ya=0;N=Xa+1|0;if((N|0)<(S|0)){Sa=N;N=0;T=P;Qa=1;R=Ya;while(1){Pa=N+Ra|0;L=(Pa|0)<(Wa|0);N=Pa-(L?0:Wa)|0;R=R+Ua+(L?0:V)|0;$a=+g[e+(Sa<<2)>>2];L=~~($a*7.314285755157471+1023.5);Pa=(L|0)>1023?1023:(L|0)<0?0:L;L=R-Pa|0;Oa=(_(L,L)|0)+T|0;L=Qa+1|0;if((Pa|0)!=0?+g[d+(Sa<<2)>>2]+_a>=$a:0){$a=+(R|0);ia=+(Pa|0);if(+g[Ga>>2]+$a<ia)break c;if($a-+g[Ia>>2]>ia)break c}Sa=Sa+1|0;if((Sa|0)>=(S|0)){ab=Oa;bb=L;break}else{T=Oa;Qa=L}}}else{ab=P;bb=1}ia=+g[Ga>>2];$a=+(bb|0);cb=+g[Ca>>2];if((!(ia*ia/$a>cb)?(ia=+g[Ia>>2],!(ia*ia/$a>cb)):0)?+((ab|0)/(bb|0)|0|0)>cb:0)break;c[j+(Ka<<2)>>2]=-200;c[k+(Ka<<2)>>2]=-200;break b}while(0);c[q>>2]=-200;c[r>>2]=-200;c[s>>2]=-200;c[t>>2]=-200;P=Oc(h+(Ja*56|0)|0,Ea-Ja|0,q,r,u)|0;S=Oc(h+(Ea*56|0)|0,Da-Ea|0,s,t,u)|0;V=(P|0)!=0;if(V){c[q>>2]=Ya;c[r>>2]=c[s>>2]}if((S|0)!=0?(c[s>>2]=c[r>>2],c[t>>2]=Za,V):0){c[j+(Ka<<2)>>2]=-200;c[k+(Ka<<2)>>2]=-200;break}V=c[q>>2]|0;c[Q>>2]=V;if(!Fa)c[j>>2]=V;V=c[r>>2]|0;c[j+(Ka<<2)>>2]=V;S=c[s>>2]|0;c[k+(Ka<<2)>>2]=S;P=c[t>>2]|0;c[Va>>2]=P;if((Ha|0)==1)c[p>>2]=P;if((S&V|0)>-1){d:do if((Ea|0)>0){V=Ea;do{S=V;V=V+-1|0;P=m+(V<<2)|0;if((c[P>>2]|0)!=(Ha|0))break d;c[P>>2]=Ka}while((S|0)>1)}while(0);Va=Ea+1|0;if((Va|0)<(w|0)){Q=Va;do{Va=l+(Q<<2)|0;if((c[Va>>2]|0)!=(Fa|0))break b;c[Va>>2]=Ka;Q=Q+1|0}while((Q|0)<(w|0))}}}while(0);Ka=Ka+1|0;if((Ka|0)>=(w|0)){ya=68;break}}if((ya|0)==38)Ta(1);else if((ya|0)==68){db=c[j>>2]|0;eb=c[k>>2]|0;break}}else{db=xa;eb=xa}while(0);xa=Ab(a,w<<2)|0;if((db|0)>=0)if((eb|0)<0)fb=db;else fb=eb+db>>1;else fb=eb;c[xa>>2]=fb;fb=c[za>>2]|0;za=c[p>>2]|0;if((fb|0)>=0)if((za|0)<0)gb=fb;else gb=za+fb>>1;else gb=za;c[xa+4>>2]=gb;if(o)hb=2;else{z=xa;i=f;return z|0}do{o=hb+-2|0;gb=c[b+1032+(o<<2)>>2]|0;za=c[b+780+(o<<2)>>2]|0;o=c[u+836+(gb<<2)>>2]|0;fb=c[xa+(gb<<2)>>2]&32767;gb=(c[xa+(za<<2)>>2]&32767)-fb|0;p=(_((gb|0)>-1?gb:0-gb|0,(c[u+836+(hb<<2)>>2]|0)-o|0)|0)/((c[u+836+(za<<2)>>2]|0)-o|0)|0;o=((gb|0)<0?0-p|0:p)+fb|0;fb=c[j+(hb<<2)>>2]|0;p=c[k+(hb<<2)>>2]|0;if((fb|0)>=0)if((p|0)<0)ib=fb;else ib=p+fb>>1;else ib=p;c[xa+(hb<<2)>>2]=(ib|0)<0|(o|0)==(ib|0)?o|32768:ib;hb=hb+1|0}while((hb|0)!=(w|0));z=xa;i=f;return z|0}function $b(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0;g=c[b+1284>>2]|0;if(!((d|0)!=0&(e|0)!=0)){h=0;return h|0}b=Ab(a,g<<2)|0;if((g|0)<=0){h=b;return h|0}a=65536-f|0;i=0;do{j=d+(i<<2)|0;k=_(c[j>>2]&32767,a)|0;l=e+(i<<2)|0;m=k+32768+(_(c[l>>2]&32767,f)|0)>>16;k=b+(i<<2)|0;c[k>>2]=m;if((c[j>>2]&32768|0)!=0?(c[l>>2]&32768|0)!=0:0)c[k>>2]=m|32768;i=i+1|0}while((i|0)!=(g|0));h=b;return h|0}function ac(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0;g=i;i=i+336|0;h=g+64|0;j=g+32|0;k=g;l=c[d+1296>>2]|0;m=d+1284|0;n=c[m>>2]|0;o=c[(c[(c[b+64>>2]|0)+4>>2]|0)+28>>2]|0;p=c[o+2848>>2]|0;if(!e){lb(a,0,1);Fd(f|0,0,((c[b+36>>2]|0)/2|0)<<2|0)|0;q=0;i=g;return q|0}if((n|0)>0){r=l+832|0;s=0;do{t=e+(s<<2)|0;u=c[t>>2]|0;v=u&32767;w=c[r>>2]|0;if((w|0)==3)x=(v>>>0)/12|0;else if((w|0)==4)x=v>>>4;else if((w|0)==1)x=v>>>2;else if((w|0)==2)x=v>>>3;else x=v;c[t>>2]=u&32768|x;s=s+1|0}while((s|0)!=(n|0))}c[h>>2]=c[e>>2];s=h+4|0;c[s>>2]=c[e+4>>2];x=d+1292|0;if((n|0)>2){r=2;do{u=r+-2|0;t=c[d+1032+(u<<2)>>2]|0;v=c[d+780+(u<<2)>>2]|0;u=c[l+836+(t<<2)>>2]|0;w=e+(t<<2)|0;t=e+(v<<2)|0;y=c[w>>2]&32767;z=(c[t>>2]&32767)-y|0;A=(_((z|0)>-1?z:0-z|0,(c[l+836+(r<<2)>>2]|0)-u|0)|0)/((c[l+836+(v<<2)>>2]|0)-u|0)|0;u=((z|0)<0?0-A|0:A)+y|0;A=e+(r<<2)|0;z=c[A>>2]|0;if((z&32768|0)!=0|(z|0)==(u|0)){c[A>>2]=u|32768;c[h+(r<<2)>>2]=0}else{A=(c[x>>2]|0)-u|0;v=(A|0)<(u|0)?A:u;A=z-u|0;do if((A|0)<0)if((A|0)<(0-v|0)){B=v+~A|0;break}else{B=~(A<<1);break}else if((v|0)>(A|0)){B=A<<1;break}else{B=v+A|0;break}while(0);c[h+(r<<2)>>2]=B;c[w>>2]=y;c[t>>2]=c[t>>2]&32767}r=r+1|0}while((r|0)!=(n|0))}lb(a,1,1);n=d+1308|0;c[n>>2]=(c[n>>2]|0)+1;n=(c[x>>2]|0)+-1|0;r=(n|0)==0;if(!r){B=n;A=0;while(1){v=A+1|0;B=B>>>1;if(!B){C=v;break}else A=v}A=d+1304|0;c[A>>2]=(c[A>>2]|0)+(C<<1);C=c[h>>2]|0;if(r){D=C;E=A;F=0}else{r=n;n=0;while(1){B=n+1|0;r=r>>>1;if(!r){D=C;E=A;F=B;break}else n=B}}}else{D=c[h>>2]|0;E=d+1304|0;F=0}lb(a,D,F);F=c[s>>2]|0;s=(c[x>>2]|0)+-1|0;if(!s)G=0;else{x=s;s=0;while(1){D=s+1|0;x=x>>>1;if(!x){G=D;break}else s=D}}lb(a,F,G);if((c[l>>2]|0)>0){G=d+1300|0;F=0;s=2;while(1){x=c[l+4+(F<<2)>>2]|0;D=c[l+128+(x<<2)>>2]|0;n=c[l+192+(x<<2)>>2]|0;A=1<<n;c[j>>2]=0;c[j+4>>2]=0;c[j+8>>2]=0;c[j+12>>2]=0;c[j+16>>2]=0;c[j+20>>2]=0;c[j+24>>2]=0;c[j+28>>2]=0;if(n){C=(n|0)==31;if(!C){r=0;do{B=c[l+320+(x<<5)+(r<<2)>>2]|0;if((B|0)<0)H=1;else H=c[(c[o+1824+(B<<2)>>2]|0)+4>>2]|0;c[k+(r<<2)>>2]=H;r=r+1|0}while((r|0)<(A|0))}a:do if((D|0)>0){if(C){r=0;t=0;y=0;while(1){w=c[j+(y<<2)>>2]<<r|t;y=y+1|0;if((y|0)==(D|0)){I=w;break a}else{r=r+31|0;t=w}}}else{J=0;K=0;L=0}while(1){t=c[h+(L+s<<2)>>2]|0;r=0;while(1){if((t|0)<(c[k+(r<<2)>>2]|0)){M=r;N=37;break}r=r+1|0;if((r|0)>=(A|0)){N=39;break}}if((N|0)==37){N=0;c[j+(L<<2)>>2]=M;O=M}else if((N|0)==39){N=0;O=c[j+(L<<2)>>2]|0}r=O<<J|K;L=L+1|0;if((L|0)==(D|0)){I=r;break}else{J=J+n|0;K=r}}}else I=0;while(0);n=oc(p+((c[l+256+(x<<2)>>2]|0)*56|0)|0,I,a)|0;c[G>>2]=(c[G>>2]|0)+n}if((D|0)>0){n=0;do{A=c[l+320+(x<<5)+(c[j+(n<<2)>>2]<<2)>>2]|0;if((A|0)>-1?(C=c[h+(n+s<<2)>>2]|0,(C|0)<(c[p+(A*56|0)+4>>2]|0)):0){r=oc(p+(A*56|0)|0,C,a)|0;c[E>>2]=(c[E>>2]|0)+r}n=n+1|0}while((n|0)!=(D|0))}F=F+1|0;if((F|0)>=(c[l>>2]|0))break;else s=D+s|0}}s=l+832|0;F=_(c[s>>2]|0,c[e>>2]|0)|0;E=(c[o+(c[b+28>>2]<<2)>>2]|0)/2|0;if((c[m>>2]|0)>1){o=0;a=1;p=0;h=F;while(1){j=c[d+260+(a<<2)>>2]|0;G=c[e+(j<<2)>>2]|0;if((G&32767|0)==(G|0)){I=_(c[s>>2]|0,G)|0;G=c[l+836+(j<<2)>>2]|0;j=I-h|0;K=G-p|0;J=(j|0)/(K|0)|0;L=j>>31|1;O=_(J,K)|0;N=((j|0)>-1?j:0-j|0)-((O|0)>-1?O:0-O|0)|0;O=(E|0)>(G|0)?G:E;if((O|0)>(p|0))c[f+(p<<2)>>2]=h;j=p+1|0;if((j|0)<(O|0)){M=j;j=0;k=h;while(1){H=j+N|0;n=(H|0)<(K|0);k=k+J+(n?0:L)|0;c[f+(M<<2)>>2]=k;M=M+1|0;if((M|0)==(O|0)){P=G;Q=G;R=I;break}else j=H-(n?0:K)|0}}else{P=G;Q=G;R=I}}else{P=o;Q=p;R=h}a=a+1|0;if((a|0)>=(c[m>>2]|0)){S=P;T=R;break}else{o=P;p=Q;h=R}}}else{S=0;T=F}F=b+36|0;if((S|0)<((c[F>>2]|0)/2|0|0))U=S;else{q=1;i=g;return q|0}do{c[f+(U<<2)>>2]=T;U=U+1|0}while((U|0)<((c[F>>2]|0)/2|0|0));q=1;i=g;return q|0}function bc(a){a=a|0;if(a)yd(a);return}function cc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;if(!a)return;b=a+4|0;d=c[b>>2]|0;e=a+20|0;if((d|0)>0){f=d;d=0;while(1){g=c[(c[e>>2]|0)+(d<<2)>>2]|0;if(!g)h=f;else{yd(g);h=c[b>>2]|0}d=d+1|0;if((d|0)>=(h|0))break;else f=h}}yd(c[e>>2]|0);e=a+24|0;h=a+28|0;if((c[e>>2]|0)>0){f=0;do{yd(c[(c[h>>2]|0)+(f<<2)>>2]|0);f=f+1|0}while((f|0)<(c[e>>2]|0))}yd(c[h>>2]|0);yd(a);return}function dc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;lb(b,c[a>>2]|0,24);lb(b,c[a+4>>2]|0,24);lb(b,(c[a+8>>2]|0)+-1|0,24);d=a+12|0;lb(b,(c[d>>2]|0)+-1|0,6);lb(b,c[a+20>>2]|0,8);if((c[d>>2]|0)<=0)return;e=a+24|0;f=0;g=0;while(1){h=e+(g<<2)|0;i=c[h>>2]|0;if(i){j=i;k=0;while(1){j=j>>>1;if(!j){l=k;break}else k=k+1|0}if((l|0)>2){lb(b,i,3);lb(b,1,1);lb(b,c[h>>2]>>3,5)}else m=9}else m=9;if((m|0)==9){m=0;lb(b,i,4)}k=c[h>>2]|0;if(!k)n=0;else{j=k;k=0;while(1){o=(j&1)+k|0;j=j>>>1;if(!j){n=o;break}else k=o}}k=n+f|0;g=g+1|0;if((g|0)>=(c[d>>2]|0)){p=k;break}else f=k}if((p|0)<=0)return;f=a+280|0;a=0;do{lb(b,c[f+(a<<2)>>2]|0,8);a=a+1|0}while((a|0)!=(p|0));return}function ec(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;d=zd(1,2840)|0;e=c[a+28>>2]|0;c[d>>2]=qb(b,24)|0;c[d+4>>2]=qb(b,24)|0;c[d+8>>2]=(qb(b,24)|0)+1;a=qb(b,6)|0;f=d+12|0;c[f>>2]=a+1;g=qb(b,8)|0;h=d+20|0;c[h>>2]=g;a:do if((g|0)>=0){if((a|0)>-1){i=d+24|0;j=0;k=0;while(1){l=qb(b,3)|0;m=qb(b,1)|0;if((m|0)<0){n=26;break a}if(!m)o=l;else{m=qb(b,5)|0;if((m|0)<0){n=26;break a}o=m<<3|l}c[i+(k<<2)>>2]=o;if(!o)p=0;else{l=o;m=0;while(1){q=(l&1)+m|0;l=l>>>1;if(!l){p=q;break}else m=q}}m=p+j|0;k=k+1|0;if((k|0)>=(c[f>>2]|0)){r=m;break}else j=m}j=(r|0)>0;if(j){k=d+280|0;i=0;while(1){m=qb(b,8)|0;if((m|0)<0)break a;c[k+(i<<2)>>2]=m;i=i+1|0;if((i|0)>=(r|0)){s=j;t=r;break}}}else{s=0;t=r}}else{s=0;t=0}j=c[h>>2]|0;i=c[e+24>>2]|0;if((j|0)<(i|0)){if(s){k=d+280|0;m=0;do{l=c[k+(m<<2)>>2]|0;if((l|0)>=(i|0))break a;m=m+1|0;if(!(c[(c[e+1824+(l<<2)>>2]|0)+12>>2]|0))break a}while((m|0)<(t|0))}m=c[e+1824+(j<<2)>>2]|0;i=c[m+4>>2]|0;k=c[m>>2]|0;if((k|0)>=1){m=c[f>>2]|0;l=k;k=1;while(1){q=_(m,k)|0;if((q|0)>(i|0))break a;if((l|0)>1){l=l+-1|0;k=q}else{u=q;break}}c[d+16>>2]=u;v=d;return v|0}}}else n=26;while(0);if((n|0)==26?(d|0)==0:0){v=0;return v|0}yd(d);v=0;return v|0}function fc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;d=zd(1,44)|0;e=c[(c[a+4>>2]|0)+28>>2]|0;c[d>>2]=b;a=c[b+12>>2]|0;c[d+4>>2]=a;f=e+2848|0;e=c[f>>2]|0;c[d+12>>2]=e;g=e+((c[b+20>>2]|0)*56|0)|0;c[d+16>>2]=g;e=c[g>>2]|0;g=zd(a,4)|0;c[d+20>>2]=g;if((a|0)>0){h=b+24|0;i=b+280|0;b=0;j=0;k=0;while(1){l=c[h+(j<<2)>>2]|0;if(l){m=l;n=0;while(1){o=n+1|0;m=m>>>1;if(!m){p=o;q=n;break}else n=o}if(p){n=(p|0)>(k|0)?p:k;c[g+(j<<2)>>2]=zd(p,4)|0;if((q|0)>-1){m=g+(j<<2)|0;o=b;r=0;while(1){if(!(l&1<<r))s=o;else{c[(c[m>>2]|0)+(r<<2)>>2]=(c[f>>2]|0)+((c[i+(o<<2)>>2]|0)*56|0);s=o+1|0}r=r+1|0;if((r|0)>=(p|0)){t=s;u=n;break}else o=s}}else{t=b;u=n}}else{t=b;u=k}}else{t=b;u=k}j=j+1|0;if((j|0)>=(a|0)){v=u;break}else{b=t;k=u}}}else v=0;u=d+24|0;c[u>>2]=1;k=(e|0)>0;if(k){t=1;b=0;while(1){j=_(t,a)|0;b=b+1|0;if((b|0)==(e|0)){w=j;break}else t=j}c[u>>2]=w;x=w}else x=1;c[d+8>>2]=v;v=xd(x<<2)|0;w=d+28|0;c[w>>2]=v;if((x|0)<=0)return d|0;u=e<<2;if(!k){k=0;do{c[v+(k<<2)>>2]=xd(u)|0;k=k+1|0}while((k|0)<(x|0));return d|0}k=c[w>>2]|0;w=0;do{c[v+(w<<2)>>2]=xd(u)|0;t=c[k+(w<<2)>>2]|0;b=x;j=0;s=w;do{b=(b|0)/(a|0)|0;p=(s|0)/(b|0)|0;s=s-(_(p,b)|0)|0;c[t+(j<<2)>>2]=p;j=j+1|0}while((j|0)!=(e|0));w=w+1|0}while((w|0)<(x|0));return d|0}function gc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0;if((f|0)>0){g=0;h=0}else return 0;while(1){if(!(c[e+(g<<2)>>2]|0))i=h;else{c[d+(h<<2)>>2]=c[d+(g<<2)>>2];i=h+1|0}g=g+1|0;if((g|0)==(f|0)){j=i;break}else h=i}if(!j)return 0;Pc(a,b,d,j,3);return 0}function hc(a,b,d,e,f,g,h,i){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;var j=0,k=0,l=0,m=0;if((g|0)>0){j=0;k=0}else return 0;while(1){if(!(c[f+(j<<2)>>2]|0))l=k;else{c[e+(k<<2)>>2]=c[e+(j<<2)>>2];l=k+1|0}j=j+1|0;if((j|0)==(g|0)){m=l;break}else k=l}if(!m)return 0;Qc(a,d,e,m,h);return 0}function ic(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0.0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;if((f|0)>0){g=0;h=0}else{i=0;return i|0}while(1){if(!(c[e+(g<<2)>>2]|0))j=h;else{c[d+(h<<2)>>2]=c[d+(g<<2)>>2];j=h+1|0}g=g+1|0;if((g|0)==(f|0)){k=j;break}else h=j}if(!k){i=0;return i|0}j=c[b>>2]|0;h=c[j+8>>2]|0;f=c[j+12>>2]|0;g=((c[j+4>>2]|0)-(c[j>>2]|0)|0)/(h|0)|0;e=Ab(a,k<<2)|0;l=100.0/+(h|0);m=(k|0)>0;if(m){n=g<<2;o=0;do{p=Ab(a,n)|0;c[e+(o<<2)>>2]=p;Fd(p|0,0,n|0)|0;o=o+1|0}while((o|0)!=(k|0))}if((g|0)>0){o=(h|0)>0;n=f+-1|0;a=(f|0)>1;f=0;do{p=_(f,h)|0;q=(c[j>>2]|0)+p|0;if(m){p=0;do{if(o){r=c[d+(p<<2)>>2]|0;s=0;t=0;u=0;while(1){v=c[r+(q+t<<2)>>2]|0;w=(v|0)>-1?v:0-v|0;v=(w|0)>(u|0)?w:u;x=w+s|0;t=t+1|0;if((t|0)==(h|0)){y=x;z=v;break}else{s=x;u=v}}}else{y=0;z=0}u=~~(+(y|0)*l);a:do if(a){s=0;while(1){if((z|0)<=(c[j+2328+(s<<2)>>2]|0)?(t=c[j+2584+(s<<2)>>2]|0,(t|0)<0|(u|0)<(t|0)):0){A=s;break a}t=s+1|0;if((t|0)<(n|0))s=t;else{A=t;break}}}else A=0;while(0);c[(c[e+(p<<2)>>2]|0)+(f<<2)>>2]=A;p=p+1|0}while((p|0)!=(k|0))}f=f+1|0}while((f|0)!=(g|0))}g=b+40|0;c[g>>2]=(c[g>>2]|0)+1;i=e;return i|0}function jc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0;if((f|0)>0){g=0;h=0}else return 0;while(1){if(!(c[e+(g<<2)>>2]|0))i=h;else{c[d+(h<<2)>>2]=c[d+(g<<2)>>2];i=h+1|0}g=g+1|0;if((g|0)==(f|0)){j=i;break}else h=i}if(!j)return 0;Pc(a,b,d,j,4);return 0}function kc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0;if((f|0)>0){g=0;h=0}else{i=0;return i|0}while(1){j=((c[e+(g<<2)>>2]|0)!=0&1)+h|0;g=g+1|0;if((g|0)==(f|0)){k=j;break}else h=j}if(!k){i=0;return i|0}k=c[b>>2]|0;h=c[k+8>>2]|0;g=c[k+12>>2]|0;e=((c[k+4>>2]|0)-(c[k>>2]|0)|0)/(h|0)|0;j=Ab(a,4)|0;l=e<<2;m=Ab(a,l)|0;c[j>>2]=m;Fd(m|0,0,l|0)|0;if((e|0)>0){l=(h|0)>0;m=g+-1|0;a=(g|0)>1;g=c[j>>2]|0;n=(f|0)>1;o=0;p=(c[k>>2]|0)/(f|0)|0;while(1){if(l){q=c[d>>2]|0;r=0;s=0;t=p;u=0;while(1){v=c[q+(t<<2)>>2]|0;w=(v|0)>-1?v:0-v|0;v=(w|0)>(u|0)?w:u;if(n){w=r;x=1;while(1){y=c[(c[d+(x<<2)>>2]|0)+(t<<2)>>2]|0;z=(y|0)>-1?y:0-y|0;y=(z|0)>(w|0)?z:w;x=x+1|0;if((x|0)==(f|0)){A=y;break}else w=y}}else A=r;w=t+1|0;s=s+f|0;if((s|0)>=(h|0)){B=A;C=w;D=v;break}else{r=A;t=w;u=v}}}else{B=0;C=p;D=0}a:do if(a){u=0;while(1){if((D|0)<=(c[k+2328+(u<<2)>>2]|0)?(B|0)<=(c[k+2584+(u<<2)>>2]|0):0){E=u;break a}t=u+1|0;if((t|0)<(m|0))u=t;else{E=t;break}}}else E=0;while(0);c[g+(o<<2)>>2]=E;o=o+1|0;if((o|0)==(e|0))break;else p=C}}C=b+40|0;c[C>>2]=(c[C>>2]|0)+1;i=j;return i|0}function lc(a,b,d,e,f,g,h,j){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;j=i;i=i+16|0;k=j;l=c[b+36>>2]|0;m=(l|0)/2|0;n=Ab(b,_(g<<2,m)|0)|0;c[k>>2]=n;if((g|0)<=0){i=j;return 0}b=(l|0)>1;l=0;o=0;while(1){p=c[e+(l<<2)>>2]|0;q=((c[f+(l<<2)>>2]|0)!=0&1)+o|0;if(b){r=0;s=l;while(1){c[n+(s<<2)>>2]=c[p+(r<<2)>>2];r=r+1|0;if((r|0)>=(m|0))break;else s=s+g|0}}l=l+1|0;if((l|0)==(g|0)){t=q;break}else o=q}if(!t){i=j;return 0}Qc(a,d,k,1,h);i=j;return 0}function mc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0;g=c[b>>2]|0;h=c[g+8>>2]|0;i=b+16|0;j=c[c[i>>2]>>2]|0;k=(_(c[a+36>>2]|0,f)|0)>>1;l=c[g+4>>2]|0;m=((l|0)<(k|0)?l:k)-(c[g>>2]|0)|0;if((m|0)<=0)return 0;k=(m|0)/(h|0)|0;m=Ab(a,((j+-1+k|0)/(j|0)|0)<<2)|0;a:do if((f|0)>0){l=0;while(1){if(c[e+(l<<2)>>2]|0){n=l;break a}o=l+1|0;if((o|0)<(f|0))l=o;else{n=o;break}}}else n=0;while(0);if((n|0)==(f|0))return 0;n=b+8|0;e=c[n>>2]|0;if((e|0)<=0)return 0;l=(k|0)>0;o=a+4|0;a=g+16|0;p=b+28|0;q=(j|0)>0;r=b+20|0;b=e;e=0;b:while(1){if(l){s=(e|0)==0;t=1<<e;u=0;v=0;while(1){if(s){w=pc(c[i>>2]|0,o)|0;if((w|0)==-1){x=23;break b}if((w|0)>=(c[a>>2]|0)){x=23;break b}y=c[(c[p>>2]|0)+(w<<2)>>2]|0;c[m+(v<<2)>>2]=y;if(!y){x=23;break b}}if(q&(u|0)<(k|0)){y=m+(v<<2)|0;w=u;z=0;while(1){A=c[(c[y>>2]|0)+(z<<2)>>2]|0;if(((c[g+24+(A<<2)>>2]&t|0)!=0?(B=c[(c[(c[r>>2]|0)+(A<<2)>>2]|0)+(e<<2)>>2]|0,(B|0)!=0):0)?(A=_(w,h)|0,(tc(B,d,(c[g>>2]|0)+A|0,f,o,h)|0)==-1):0){x=23;break b}z=z+1|0;A=w+1|0;if(!((z|0)<(j|0)&(A|0)<(k|0))){C=A;break}else w=A}}else C=u;if((C|0)<(k|0)){u=C;v=v+1|0}else break}D=c[n>>2]|0}else D=b;e=e+1|0;if((e|0)>=(D|0)){x=23;break}else b=D}if((x|0)==23)return 0;return 0}function nc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;b=zd(1,40)|0;c[b+36>>2]=1;a:do if(((qb(a,24)|0)==5653314?(c[b>>2]=qb(a,16)|0,d=qb(a,24)|0,e=b+4|0,c[e>>2]=d,(d|0)!=-1):0)?(d=uc(c[b>>2]|0)|0,((uc(c[e>>2]|0)|0)+d|0)<=24):0){d=qb(a,1)|0;b:do if(!d){f=qb(a,1)|0;g=(f|0)!=0;f=(_(g?1:5,c[e>>2]|0)|0)+7>>3;h=c[a+16>>2]|0;if((f|0)>(h-(rb(a)|0)|0))break a;h=c[e>>2]|0;f=b+8|0;c[f>>2]=xd(h<<2)|0;i=(h|0)>0;if(!g){if(i)j=0;else break;while(1){g=qb(a,5)|0;if((g|0)==-1)break a;c[(c[f>>2]|0)+(j<<2)>>2]=g+1;j=j+1|0;if((j|0)>=(c[e>>2]|0))break b}}if(i){g=0;do{if(!(qb(a,1)|0))c[(c[f>>2]|0)+(g<<2)>>2]=0;else{h=qb(a,5)|0;if((h|0)==-1)break a;c[(c[f>>2]|0)+(g<<2)>>2]=h+1}g=g+1|0}while((g|0)<(c[e>>2]|0))}}else if((d|0)==1){g=(qb(a,5)|0)+1|0;if(!g)break a;f=c[e>>2]|0;i=b+8|0;c[i>>2]=xd(f<<2)|0;if((f|0)>0){h=f;f=0;k=g;while(1){g=qb(a,uc(h-f|0)|0)|0;if((k|0)>32|(g|0)==-1)break a;l=c[e>>2]|0;if((g|0)>(l-f|0))break a;if((g|0)>0){if((g+-1>>k+-1|0)>1)break a;m=c[i>>2]|0;n=f;o=0;while(1){c[m+(n<<2)>>2]=k;o=o+1|0;if((o|0)==(g|0))break;else n=n+1|0}p=c[e>>2]|0;q=g+f|0}else{p=l;q=f}if((p|0)>(q|0)){h=p;f=q;k=k+1|0}else break}}}else break a;while(0);d=qb(a,4)|0;k=b+12|0;c[k>>2]=d;if(!d){r=b;return r|0}else if(!((d|0)==2|(d|0)==1))break;c[b+16>>2]=qb(a,32)|0;c[b+20>>2]=qb(a,32)|0;d=b+24|0;c[d>>2]=(qb(a,4)|0)+1;f=qb(a,1)|0;c[b+28>>2]=f;if((f|0)!=-1){f=c[k>>2]|0;if((f|0)==1)if(!(c[b>>2]|0))s=0;else s=wc(b)|0;else if((f|0)==2)s=_(c[b>>2]|0,c[e>>2]|0)|0;else s=0;f=(_(c[d>>2]|0,s)|0)+7>>3;k=c[a+16>>2]|0;if((f|0)<=(k-(rb(a)|0)|0)){k=xd(s<<2)|0;f=b+32|0;c[f>>2]=k;if((s|0)>0){h=0;do{i=qb(a,c[d>>2]|0)|0;n=c[f>>2]|0;c[n+(h<<2)>>2]=i;h=h+1|0}while((h|0)!=(s|0));t=n}else t=k;if(!s){r=b;return r|0}if((c[t+(s+-1<<2)>>2]|0)!=-1){r=b;return r|0}}}}while(0);yc(b);r=0;return r|0}function oc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0;if((b|0)<0){e=0;return e|0}f=a+12|0;g=c[f>>2]|0;if((c[g+4>>2]|0)<=(b|0)){e=0;return e|0}lb(d,c[(c[a+20>>2]|0)+(b<<2)>>2]|0,c[(c[g+8>>2]|0)+(b<<2)>>2]|0);e=c[(c[(c[f>>2]|0)+8>>2]|0)+(b<<2)>>2]|0;return e|0}function pc(a,b){a=a|0;b=b|0;var d=0,e=0;if((c[a+8>>2]|0)<=0){d=-1;return d|0}e=Rc(a,b)|0;if((e|0)<=-1){d=-1;return d|0}d=c[(c[a+24>>2]|0)+(e<<2)>>2]|0;return d|0}function qc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;f=i;if((c[a+8>>2]|0)<=0){h=0;i=f;return h|0}j=c[a>>2]|0;k=(e|0)/(j|0)|0;e=i;i=i+((1*(k<<2)|0)+15&-16)|0;l=(k|0)>0;a:do if(l){m=a+16|0;n=0;while(1){o=Rc(a,d)|0;if((o|0)==-1){h=-1;break}p=c[a>>2]|0;c[e+(n<<2)>>2]=(c[m>>2]|0)+((_(p,o)|0)<<2);n=n+1|0;if((n|0)>=(k|0)){q=p;break a}}i=f;return h|0}else q=j;while(0);if((q|0)<1|l^1){h=0;i=f;return h|0}else{r=0;s=0}while(1){l=0;do{j=b+(l+s<<2)|0;g[j>>2]=+g[j>>2]+ +g[(c[e+(l<<2)>>2]|0)+(r<<2)>>2];l=l+1|0}while((l|0)!=(k|0));r=r+1|0;if((r|0)>=(q|0)){h=0;break}else s=s+k|0}i=f;return h|0}function rc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0;if((c[a+8>>2]|0)<=0){f=0;return f|0}if((c[a>>2]|0)>8){if((e|0)<=0){f=0;return f|0}h=a+16|0;i=0;while(1){j=Rc(a,d)|0;if((j|0)==-1){f=-1;k=29;break}l=c[h>>2]|0;m=c[a>>2]|0;n=_(m,j)|0;if((m|0)>0){j=(m|0)>1?m:1;o=i;p=0;while(1){q=b+(o<<2)|0;g[q>>2]=+g[q>>2]+ +g[l+(p+n<<2)>>2];p=p+1|0;if((p|0)>=(m|0))break;else o=o+1|0}r=i+j|0}else r=i;if((r|0)<(e|0))i=r;else{f=0;k=29;break}}if((k|0)==29)return f|0}r=a+16|0;if((e|0)>0)s=0;else{f=0;return f|0}a:while(1){b:while(1){i=Rc(a,d)|0;if((i|0)==-1){f=-1;k=29;break a}h=c[r>>2]|0;switch(c[a>>2]|0){case 6:{t=i;u=h;k=15;break b;break}case 5:{v=i;w=h;k=17;break b;break}case 4:{x=i;y=h;k=19;break b;break}case 1:{z=i;A=h;B=s;C=0;break b;break}case 7:{D=i;E=h;k=13;break b;break}case 2:{F=i;G=h;k=23;break b;break}case 8:{H=h;I=i;k=12;break b;break}case 3:{J=i;K=h;k=21;break b;break}default:{}}}if((k|0)==12){k=0;j=I<<3;h=b+(s<<2)|0;g[h>>2]=+g[h>>2]+ +g[H+(j<<2)>>2];L=j;M=H;N=s+1|0;O=1;k=14}else if((k|0)==13){k=0;L=D*7|0;M=E;N=s;O=0;k=14}else if((k|0)==15){k=0;P=t*6|0;Q=u;R=s;S=0;k=16}else if((k|0)==17){k=0;T=v*5|0;U=w;V=s;W=0;k=18}else if((k|0)==19){k=0;X=x<<2;Y=y;Z=s;$=0;k=20}else if((k|0)==21){k=0;aa=J*3|0;ba=K;ca=s;da=0;k=22}else if((k|0)==23){k=0;ea=F<<1;fa=G;ga=s;ha=0;k=24}if((k|0)==14){k=0;j=b+(N<<2)|0;g[j>>2]=+g[j>>2]+ +g[M+(O+L<<2)>>2];P=L;Q=M;R=N+1|0;S=O+1|0;k=16}if((k|0)==16){k=0;j=b+(R<<2)|0;g[j>>2]=+g[j>>2]+ +g[Q+(S+P<<2)>>2];T=P;U=Q;V=R+1|0;W=S+1|0;k=18}if((k|0)==18){k=0;j=b+(V<<2)|0;g[j>>2]=+g[j>>2]+ +g[U+(W+T<<2)>>2];X=T;Y=U;Z=V+1|0;$=W+1|0;k=20}if((k|0)==20){k=0;j=b+(Z<<2)|0;g[j>>2]=+g[j>>2]+ +g[Y+($+X<<2)>>2];aa=X;ba=Y;ca=Z+1|0;da=$+1|0;k=22}if((k|0)==22){k=0;j=b+(ca<<2)|0;g[j>>2]=+g[j>>2]+ +g[ba+(da+aa<<2)>>2];ea=aa;fa=ba;ga=ca+1|0;ha=da+1|0;k=24}if((k|0)==24){k=0;j=b+(ga<<2)|0;g[j>>2]=+g[j>>2]+ +g[fa+(ha+ea<<2)>>2];z=ea;A=fa;B=ga+1|0;C=ha+1|0}s=B+1|0;j=b+(B<<2)|0;g[j>>2]=+g[j>>2]+ +g[A+(C+z<<2)>>2];if((s|0)>=(e|0)){f=0;k=29;break}}if((k|0)==29)return f|0;return 0}function sc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;f=(e|0)>0;if((c[a+8>>2]|0)<=0){if(!f){g=0;return g|0}Fd(b|0,0,e<<2|0)|0;g=0;return g|0}if(!f){g=0;return g|0}f=a+16|0;h=0;while(1){i=Rc(a,d)|0;if((i|0)==-1){g=-1;j=11;break}k=c[f>>2]|0;l=c[a>>2]|0;m=_(l,i)|0;a:do if((h|0)<(e|0)){i=h;n=0;while(1){if((n|0)>=(l|0)){o=i;break a}p=i+1|0;c[b+(i<<2)>>2]=c[k+(n+m<<2)>>2];if((p|0)<(e|0)){i=p;n=n+1|0}else{o=p;break}}}else o=h;while(0);if((o|0)<(e|0))h=o;else{g=0;j=11;break}}if((j|0)==11)return g|0;return 0}function tc(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;if((c[a+8>>2]|0)<=0){i=0;return i|0}j=(d|0)/(e|0)|0;k=(h+d|0)/(e|0)|0;if((j|0)>=(k|0)){i=0;return i|0}d=a+16|0;h=0;l=j;while(1){j=Rc(a,f)|0;if((j|0)==-1){i=-1;m=8;break}n=c[d>>2]|0;o=c[a>>2]|0;p=_(o,j)|0;if((o|0)>0){j=h;q=l;r=0;while(1){s=j+1|0;t=(c[b+(j<<2)>>2]|0)+(q<<2)|0;g[t>>2]=+g[t>>2]+ +g[n+(r+p<<2)>>2];t=(s|0)==(e|0);u=(t&1)+q|0;v=t?0:s;r=r+1|0;if((r|0)>=(o|0)){w=v;x=u;break}else{j=v;q=u}}}else{w=h;x=l}if((x|0)<(k|0)){h=w;l=x}else{i=0;m=8;break}}if((m|0)==8)return i|0;return 0}function uc(a){a=a|0;var b=0,c=0,d=0;if(!a)b=0;else{c=a;a=0;while(1){d=a+1|0;c=c>>>1;if(!c){b=d;break}else a=d}}return b|0}function vc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0;e=i;i=i+144|0;f=e;g=(d|0)!=0;h=xd((g?d:b)<<2)|0;Fd(f|0,0,132)|0;j=(b|0)>0;a:do if(j){k=f+4|0;l=(d|0)==0&1;m=0;n=0;b:while(1){o=c[a+(n<<2)>>2]|0;c:do if((o|0)>0){p=c[f+(o<<2)>>2]|0;if(!((o|0)>31|(p>>>o|0)==0))break b;c[h+(m<<2)>>2]=p;q=f+(o<<2)|0;d:do if(!(p&1)){r=p;s=q;t=o;while(1){c[s>>2]=r+1;u=t+-1|0;if((t|0)<=1)break d;r=c[f+(u<<2)>>2]|0;v=f+(u<<2)|0;if(r&1){w=v;x=u;y=8;break}else{s=v;t=u}}}else{w=q;x=o;y=8}while(0);do if((y|0)==8){y=0;if((x|0)==1){c[k>>2]=(c[k>>2]|0)+1;break}else{c[w>>2]=c[f+(x+-1<<2)>>2]<<1;break}}while(0);q=o+1|0;if((q|0)<33){t=p;s=o;r=q;while(1){q=f+(r<<2)|0;u=t;t=c[q>>2]|0;if((t>>>1|0)!=(u|0)){z=1;break c}c[q>>2]=c[f+(s<<2)>>2]<<1;q=r+1|0;if((q|0)>=33){z=1;break}else{u=r;r=q;s=u}}}else z=1}else z=l;while(0);n=n+1|0;if((n|0)>=(b|0))break a;else m=m+z|0}yd(h);A=0;i=e;return A|0}while(0);e:do if((d|0)!=1){z=1;while(1){if(c[f+(z<<2)>>2]&-1>>>(32-z|0))break;z=z+1|0;if((z|0)>=33)break e}yd(h);A=0;i=e;return A|0}while(0);if(!j){A=h;i=e;return A|0}if(g){B=0;C=0}else{g=0;j=0;while(1){f=c[a+(j<<2)>>2]|0;if((f|0)>0){d=c[h+(g<<2)>>2]|0;z=0;x=0;while(1){w=d>>>z&1|x<<1;z=z+1|0;if((z|0)>=(f|0)){D=w;break}else x=w}}else D=0;c[h+(g<<2)>>2]=D;j=j+1|0;if((j|0)==(b|0)){A=h;break}else g=g+1|0}i=e;return A|0}while(1){g=c[a+(C<<2)>>2]|0;if((g|0)>0){j=c[h+(B<<2)>>2]|0;D=0;x=0;while(1){f=j>>>D&1|x<<1;D=D+1|0;if((D|0)>=(g|0)){E=f;break}else x=f}}else E=0;if(!g)F=B;else{c[h+(B<<2)>>2]=E;F=B+1|0}C=C+1|0;if((C|0)==(b|0)){A=h;break}else B=F}i=e;return A|0}function wc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;b=c[a+4>>2]|0;d=c[a>>2]|0;if((d|0)<=0)while(1){}a=~~+M(+(+P(+(+(b|0)),+(1.0/+(d|0)))));while(1){e=a+1|0;f=1;g=1;h=0;while(1){i=_(f,a)|0;j=_(g,e)|0;h=h+1|0;if((h|0)>=(d|0)){k=i;l=j;break}else{f=i;g=j}}if((k|0)<=(b|0)&(l|0)>(b|0)){m=a;break}a=a+((k|0)>(b|0)?-1:1)|0}return m|0}function xc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,i=0.0,j=0.0,k=0.0,l=0,m=0,n=0,o=0,p=0.0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0.0,C=0.0,D=0,E=0,F=0,G=0,H=0;e=c[a+12>>2]|0;if((e+-1|0)>>>0>=2){f=0;return f|0}h=c[a+16>>2]|0;i=+(h&2097151|0);j=+qd((h|0)<0?-i:i,(h>>>21&1023)+-788|0);h=c[a+20>>2]|0;i=+(h&2097151|0);k=+qd((h|0)<0?-i:i,(h>>>21&1023)+-788|0);h=c[a>>2]|0;l=zd(_(h,b)|0,4)|0;if((e|0)==2){b=c[a+4>>2]|0;if((b|0)<=0){f=l;return f|0}m=(d|0)!=0;n=a+8|0;o=a+32|0;i=k;p=j;q=a+28|0;r=(h|0)>0;s=0;t=0;while(1){if(m?(c[(c[n>>2]|0)+(t<<2)>>2]|0)==0:0)u=s;else{if(r){v=c[o>>2]|0;w=(c[q>>2]|0)==0;x=d+(s<<2)|0;y=_(h,t)|0;z=_(h,s)|0;A=0;B=0.0;while(1){C=B+p+ +N(+(+(c[v+(y+A<<2)>>2]|0)))*i;if(m)g[l+((_(c[x>>2]|0,h)|0)+A<<2)>>2]=C;else g[l+(z+A<<2)>>2]=C;A=A+1|0;if((A|0)>=(h|0))break;else B=w?B:C}}u=s+1|0}t=t+1|0;if((t|0)>=(b|0)){f=l;break}else s=u}return f|0}else if((e|0)==1){e=c[a+4>>2]|0;if((h|0)<=0)while(1){}u=~~+M(+(+P(+(+(e|0)),+(1.0/+(h|0)))));while(1){s=u+1|0;b=1;t=1;m=0;while(1){q=_(b,u)|0;o=_(t,s)|0;m=m+1|0;if((m|0)==(h|0)){D=q;E=o;break}else{b=q;t=o}}if((E|0)>(e|0)&(D|0)<=(e|0)){F=u;break}u=((D|0)>(e|0)?-1:1)+u|0}if((e|0)<=0){f=l;return f|0}u=(d|0)==0;D=a+8|0;E=a+32|0;i=k;k=j;t=a+28|0;a=0;b=0;while(1){if(u){m=c[E>>2]|0;s=_(h,a)|0;if(!(c[t>>2]|0)){o=1;q=0;do{g[l+(s+q<<2)>>2]=k+ +N(+(+(c[m+((((b|0)/(o|0)|0|0)%(F|0)|0)<<2)>>2]|0)))*i;o=_(o,F)|0;q=q+1|0}while((q|0)<(h|0));G=21}else{q=1;o=0;j=0.0;do{j=j+k+ +N(+(+(c[m+((((b|0)/(q|0)|0|0)%(F|0)|0)<<2)>>2]|0)))*i;g[l+(s+o<<2)>>2]=j;q=_(q,F)|0;o=o+1|0}while((o|0)<(h|0));G=21}}else if(!(c[(c[D>>2]|0)+(b<<2)>>2]|0))H=a;else{o=c[E>>2]|0;q=(c[t>>2]|0)==0;s=_(c[d+(a<<2)>>2]|0,h)|0;m=1;r=0;j=0.0;while(1){p=j+k+ +N(+(+(c[o+((((b|0)/(m|0)|0|0)%(F|0)|0)<<2)>>2]|0)))*i;g[l+(s+r<<2)>>2]=p;m=_(m,F)|0;r=r+1|0;if((r|0)>=(h|0)){G=21;break}else j=q?j:p}}if((G|0)==21){G=0;H=a+1|0}b=b+1|0;if((b|0)>=(e|0)){f=l;break}else a=H}return f|0}else{f=l;return f|0}return 0}function yc(a){a=a|0;var b=0;if(!(c[a+36>>2]|0))return;b=c[a+32>>2]|0;if(b)yd(b);b=c[a+8>>2]|0;if(b)yd(b);yd(a);return}function zc(a){a=a|0;var b=0;b=c[a+16>>2]|0;if(b)yd(b);b=c[a+20>>2]|0;if(b)yd(b);b=c[a+24>>2]|0;if(b)yd(b);b=c[a+28>>2]|0;if(b)yd(b);b=c[a+32>>2]|0;if(b)yd(b);b=a;a=b+56|0;do{c[b>>2]=0;b=b+4|0}while((b|0)<(a|0));return}function Ac(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0.0;d=a;e=d+56|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));c[a+12>>2]=b;d=b+4|0;e=c[d>>2]|0;c[a+4>>2]=e;c[a+8>>2]=e;c[a>>2]=c[b>>2];c[a+20>>2]=vc(c[b+8>>2]|0,e,0)|0;e=c[d>>2]|0;d=c[b>>2]|0;if((d|0)<=0)while(1){}f=~~+M(+(+P(+(+(e|0)),+(1.0/+(d|0)))));while(1){g=f+1|0;h=1;i=1;j=0;while(1){k=_(h,f)|0;l=_(i,g)|0;j=j+1|0;if((j|0)==(d|0)){m=k;n=l;break}else{h=k;i=l}}if((n|0)>(e|0)&(m|0)<=(e|0)){o=f;break}f=((m|0)>(e|0)?-1:1)+f|0}c[a+44>>2]=o;o=c[b+16>>2]|0;p=+(o&2097151|0);c[a+48>>2]=~~+ud(+qd((o|0)<0?-p:p,(o>>>21&1023)+-788|0));o=c[b+20>>2]|0;p=+(o&2097151|0);c[a+52>>2]=~~+ud(+qd((o|0)<0?-p:p,(o>>>21&1023)+-788|0));return 0}function Bc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;e=i;f=b;g=f+56|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(g|0));h=d+4|0;j=c[h>>2]|0;if((j|0)>0){k=c[d+8>>2]|0;l=0;m=0;while(1){n=((c[k+(l<<2)>>2]|0)>0&1)+m|0;l=l+1|0;if((l|0)>=(j|0)){o=n;break}else m=n}}else o=0;c[b+4>>2]=j;m=b+8|0;c[m>>2]=o;c[b>>2]=c[d>>2];if((o|0)<=0){p=0;i=e;return p|0}l=d+8|0;k=vc(c[l>>2]|0,j,o)|0;j=o<<2;n=i;i=i+((1*j|0)+15&-16)|0;if(!k){q=c[b+16>>2]|0;if(q)yd(q);q=c[b+20>>2]|0;if(q)yd(q);q=c[b+24>>2]|0;if(q)yd(q);q=c[b+28>>2]|0;if(q)yd(q);q=c[b+32>>2]|0;if(q)yd(q);f=b;g=f+56|0;do{c[f>>2]=0;f=f+4|0}while((f|0)<(g|0));p=-1;i=e;return p|0}else r=0;do{f=k+(r<<2)|0;g=c[f>>2]|0;q=g>>>16|g<<16;g=q>>>8&16711935|q<<8&-16711936;q=g>>>4&252645135|g<<4&-252645136;g=q>>>2&858993459|q<<2&-858993460;c[f>>2]=g>>>1&1431655765|g<<1&-1431655766;c[n+(r<<2)>>2]=f;r=r+1|0}while((r|0)!=(o|0));rd(n,o,4,11);r=i;i=i+((1*j|0)+15&-16)|0;f=xd(j)|0;g=b+20|0;c[g>>2]=f;q=k;s=0;do{c[r+((c[n+(s<<2)>>2]|0)-q>>2<<2)>>2]=s;s=s+1|0}while((s|0)!=(o|0));t=0;do{c[f+(c[r+(t<<2)>>2]<<2)>>2]=c[k+(t<<2)>>2];t=t+1|0}while((t|0)!=(o|0));yd(k);c[b+16>>2]=xc(d,o,r)|0;o=xd(j)|0;c[b+24>>2]=o;j=c[h>>2]|0;d=(j|0)>0;if(d){k=c[l>>2]|0;t=0;f=0;while(1){if((c[k+(t<<2)>>2]|0)>0){c[o+(c[r+(f<<2)>>2]<<2)>>2]=t;u=f+1|0}else u=f;t=t+1|0;if((t|0)>=(j|0)){v=u;break}else f=u}u=b+28|0;c[u>>2]=xd(v)|0;if(d){d=j;j=0;v=0;while(1){f=c[(c[l>>2]|0)+(j<<2)>>2]|0;if((f|0)>0){a[(c[u>>2]|0)+(c[r+(v<<2)>>2]|0)>>0]=f;w=c[h>>2]|0;x=v+1|0}else{w=d;x=v}j=j+1|0;if((j|0)>=(w|0)){y=u;z=x;break}else{d=w;v=x}}}else{y=u;z=0}}else{u=b+28|0;c[u>>2]=xd(0)|0;y=u;z=0}u=c[m>>2]|0;if(!u)A=-4;else{m=u;u=0;while(1){m=m>>>1;if(!m){B=u;break}else u=u+1|0}A=B+-3|0}B=b+36|0;u=(A|0)<5?5:A;A=(u|0)>8?8:u;c[B>>2]=A;u=1<<A;m=zd(u,4)|0;c[b+32>>2]=m;x=b+40|0;c[x>>2]=0;a:do if((z|0)>0){b=c[y>>2]|0;v=0;w=A;d=0;while(1){j=b+d|0;h=a[j>>0]|0;r=h<<24>>24;if((v|0)<(r|0)){c[x>>2]=r;C=a[j>>0]|0}else C=h;h=C<<24>>24;if((w|0)>=(h|0)?(r=c[(c[g>>2]|0)+(d<<2)>>2]|0,l=r>>>16|r<<16,r=l>>>8&16711935|l<<8&-16711936,l=r>>>4&252645135|r<<4&-252645136,r=l>>>2&858993459|l<<2&-858993460,l=r>>>1&1431655765|r<<1&-1431655766,(w-h|0)!=31):0){r=d+1|0;f=h;h=0;do{c[m+((l|h<<f)<<2)>>2]=r;h=h+1|0;t=c[B>>2]|0;f=a[j>>0]|0}while((h|0)<(1<<t-f|0));D=t}else D=w;f=d+1|0;if((f|0)==(z|0)){E=D;break a}v=c[x>>2]|0;w=D;d=f}}else E=A;while(0);D=-2<<31-E;if((A|0)==31){p=0;i=e;return p|0}else{F=E;G=0;H=0;I=0}while(1){E=H<<32-F;A=E>>>16|E<<16;x=A>>>8&16711935|A<<8&-16711936;A=x>>>4&252645135|x<<4&-252645136;x=A>>>2&858993459|A<<2&-858993460;A=m+((x>>>1&1431655765|x<<1&-1431655766)<<2)|0;if(!(c[A>>2]|0)){x=I;while(1){C=x+1|0;if((C|0)>=(z|0)){J=x;break}if((c[(c[g>>2]|0)+(C<<2)>>2]|0)>>>0>E>>>0){J=x;break}else x=C}b:do if((z|0)>(G|0)){x=c[g>>2]|0;C=G;while(1){if(E>>>0<(c[x+(C<<2)>>2]&D)>>>0){K=C;break b}y=C+1|0;if((z|0)>(y|0))C=y;else{K=y;break}}}else K=G;while(0);E=z-K|0;c[A>>2]=(J>>>0>32767?-1073774592:J<<15|-2147483648)|(E>>>0>32767?32767:E);L=K;M=J}else{L=G;M=I}E=H+1|0;if((E|0)>=(u|0)){p=0;break}F=c[B>>2]|0;G=L;H=E;I=M}i=e;return p|0}function Cc(a){a=a|0;var b=0;b=a;a=b+48|0;do{c[b>>2]=0;b=b+4|0}while((b|0)<(a|0));return}function Dc(a){a=a|0;return (c[(c[(c[a+64>>2]|0)+104>>2]|0)+80>>2]|0)!=0|0}function Ec(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,h=0,i=0,j=0.0,k=0,l=0.0,m=0.0,n=0,o=0.0,p=0,q=0.0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0.0,I=0.0,J=0.0,K=0,L=0.0,M=0.0,N=0,O=0,P=0,Q=0,R=0.0,S=0.0,T=0,U=0,V=0,W=0.0,X=0.0,Y=0.0,Z=0.0,$=0.0,aa=0.0,ba=0.0,ca=0.0,da=0.0;e=a+-6|0;if((a|0)>6){a=b;f=c+(d+-8<<2)|0;h=c+((d>>1)+-8<<2)|0;while(1){i=f+24|0;j=+g[i>>2];k=h+24|0;l=+g[k>>2];m=j-l;n=f+28|0;o=+g[n>>2];p=h+28|0;q=o-+g[p>>2];g[i>>2]=l+j;g[n>>2]=+g[p>>2]+o;n=a+4|0;g[k>>2]=+g[a>>2]*m+ +g[n>>2]*q;g[p>>2]=+g[a>>2]*q-+g[n>>2]*m;n=f+16|0;m=+g[n>>2];p=h+16|0;q=+g[p>>2];o=m-q;k=f+20|0;j=+g[k>>2];i=h+20|0;l=j-+g[i>>2];g[n>>2]=q+m;g[k>>2]=+g[i>>2]+j;k=a+20|0;n=a+16|0;g[p>>2]=+g[n>>2]*o+ +g[k>>2]*l;g[i>>2]=+g[n>>2]*l-+g[k>>2]*o;k=f+8|0;o=+g[k>>2];n=h+8|0;l=+g[n>>2];j=o-l;i=f+12|0;m=+g[i>>2];p=h+12|0;q=m-+g[p>>2];g[k>>2]=l+o;g[i>>2]=+g[p>>2]+m;i=a+36|0;k=a+32|0;g[n>>2]=+g[k>>2]*j+ +g[i>>2]*q;g[p>>2]=+g[k>>2]*q-+g[i>>2]*j;j=+g[f>>2];q=+g[h>>2];m=j-q;i=f+4|0;o=+g[i>>2];k=h+4|0;l=o-+g[k>>2];g[f>>2]=q+j;g[i>>2]=+g[k>>2]+o;i=a+52|0;p=a+48|0;g[h>>2]=+g[p>>2]*m+ +g[i>>2]*l;g[k>>2]=+g[p>>2]*l-+g[i>>2]*m;h=h+-32|0;if(h>>>0<c>>>0)break;else{a=a+64|0;f=f+-32|0}}}if((e|0)>1){f=1;do{a=1<<f;if((f|0)!=31){h=d>>f;i=4<<f;p=h+-8|0;k=(h>>1)+-8|0;n=i+1|0;r=i<<1;s=r|1;t=i*3|0;u=t+1|0;v=i<<2;w=0;do{x=_(w,h)|0;y=c+(x<<2)|0;z=b;A=c+(p+x<<2)|0;B=c+(k+x<<2)|0;while(1){x=A+24|0;m=+g[x>>2];C=B+24|0;l=+g[C>>2];o=m-l;D=A+28|0;j=+g[D>>2];E=B+28|0;q=j-+g[E>>2];g[x>>2]=l+m;g[D>>2]=+g[E>>2]+j;D=z+4|0;g[C>>2]=+g[z>>2]*o+ +g[D>>2]*q;g[E>>2]=+g[z>>2]*q-+g[D>>2]*o;D=z+(i<<2)|0;E=A+16|0;o=+g[E>>2];C=B+16|0;q=+g[C>>2];j=o-q;x=A+20|0;m=+g[x>>2];F=B+20|0;l=m-+g[F>>2];g[E>>2]=q+o;g[x>>2]=+g[F>>2]+m;x=z+(n<<2)|0;g[C>>2]=+g[D>>2]*j+ +g[x>>2]*l;g[F>>2]=+g[D>>2]*l-+g[x>>2]*j;x=z+(r<<2)|0;D=A+8|0;j=+g[D>>2];F=B+8|0;l=+g[F>>2];m=j-l;C=A+12|0;o=+g[C>>2];E=B+12|0;q=o-+g[E>>2];g[D>>2]=l+j;g[C>>2]=+g[E>>2]+o;C=z+(s<<2)|0;g[F>>2]=+g[x>>2]*m+ +g[C>>2]*q;g[E>>2]=+g[x>>2]*q-+g[C>>2]*m;C=z+(t<<2)|0;m=+g[A>>2];q=+g[B>>2];o=m-q;x=A+4|0;j=+g[x>>2];E=B+4|0;l=j-+g[E>>2];g[A>>2]=q+m;g[x>>2]=+g[E>>2]+j;x=z+(u<<2)|0;g[B>>2]=+g[C>>2]*o+ +g[x>>2]*l;g[E>>2]=+g[C>>2]*l-+g[x>>2]*o;B=B+-32|0;if(B>>>0<y>>>0)break;else{z=z+(v<<2)|0;A=A+-32|0}}w=w+1|0}while((w|0)<(a|0))}f=f+1|0}while((f|0)!=(e|0))}if((d|0)>0)G=0;else return;do{e=c+(G<<2)|0;f=c+((G|30)<<2)|0;o=+g[f>>2];b=c+((G|14)<<2)|0;l=+g[b>>2];a=c+((G|31)<<2)|0;j=+g[a>>2];w=c+((G|15)<<2)|0;m=+g[w>>2];g[f>>2]=l+o;g[a>>2]=m+j;g[b>>2]=o-l;g[w>>2]=j-m;v=c+((G|28)<<2)|0;m=+g[v>>2];u=c+((G|12)<<2)|0;j=+g[u>>2];l=m-j;t=c+((G|29)<<2)|0;o=+g[t>>2];s=c+((G|13)<<2)|0;q=+g[s>>2];H=o-q;g[v>>2]=j+m;g[t>>2]=q+o;g[u>>2]=l*.9238795042037964-H*.3826834261417389;g[s>>2]=H*.9238795042037964+l*.3826834261417389;r=c+((G|26)<<2)|0;l=+g[r>>2];n=c+((G|10)<<2)|0;H=+g[n>>2];o=l-H;i=c+((G|27)<<2)|0;q=+g[i>>2];k=c+((G|11)<<2)|0;m=+g[k>>2];j=q-m;g[r>>2]=H+l;g[i>>2]=m+q;g[n>>2]=(o-j)*.7071067690849304;g[k>>2]=(j+o)*.7071067690849304;p=c+((G|24)<<2)|0;o=+g[p>>2];h=c+((G|8)<<2)|0;j=+g[h>>2];q=o-j;A=c+((G|25)<<2)|0;m=+g[A>>2];z=c+((G|9)<<2)|0;l=+g[z>>2];H=m-l;g[p>>2]=j+o;g[A>>2]=l+m;m=q*.3826834261417389-H*.9238795042037964;l=H*.3826834261417389+q*.9238795042037964;y=c+((G|22)<<2)|0;q=+g[y>>2];B=c+((G|6)<<2)|0;H=+g[B>>2];o=q-H;x=c+((G|7)<<2)|0;j=+g[x>>2];C=c+((G|23)<<2)|0;I=+g[C>>2];J=j-I;g[y>>2]=H+q;g[C>>2]=I+j;g[B>>2]=J;g[x>>2]=o;E=c+((G|4)<<2)|0;j=+g[E>>2];F=c+((G|20)<<2)|0;I=+g[F>>2];q=j-I;D=c+((G|5)<<2)|0;H=+g[D>>2];K=c+((G|21)<<2)|0;L=+g[K>>2];M=H-L;g[F>>2]=I+j;g[K>>2]=L+H;H=M*.9238795042037964+q*.3826834261417389;L=M*.3826834261417389-q*.9238795042037964;N=c+((G|2)<<2)|0;q=+g[N>>2];O=c+((G|18)<<2)|0;M=+g[O>>2];j=q-M;P=c+((G|3)<<2)|0;I=+g[P>>2];Q=c+((G|19)<<2)|0;R=+g[Q>>2];S=I-R;g[O>>2]=M+q;g[Q>>2]=R+I;I=(S+j)*.7071067690849304;R=(S-j)*.7071067690849304;j=+g[e>>2];T=c+((G|16)<<2)|0;S=+g[T>>2];q=j-S;U=c+((G|1)<<2)|0;M=+g[U>>2];V=c+((G|17)<<2)|0;W=+g[V>>2];X=M-W;Y=S+j;g[T>>2]=Y;j=W+M;g[V>>2]=j;M=X*.3826834261417389+q*.9238795042037964;W=X*.9238795042037964-q*.3826834261417389;q=W-l;X=M-m;S=M+m;m=W+l;l=X+q;W=q-X;X=+g[k>>2];q=R-X;M=+g[n>>2];Z=M-I;$=M+I;I=X+R;R=+g[u>>2];X=R-H;M=+g[s>>2];aa=M-L;ba=R+H;H=M+L;L=X-aa;M=aa+X;X=+g[b>>2];aa=X-J;R=+g[w>>2];ca=R-o;da=J+X;X=o+R;R=aa+q;o=aa-q;q=(L+l)*.7071067690849304;aa=(L-l)*.7071067690849304;g[B>>2]=q+R;g[E>>2]=R-q;q=(M-W)*.7071067690849304;R=ca-Z;g[e>>2]=q+o;g[N>>2]=o-q;q=(M+W)*.7071067690849304;W=ca+Z;g[P>>2]=R+aa;g[U>>2]=R-aa;g[x>>2]=W+q;g[D>>2]=W-q;q=da+$;W=da-$;$=S+ba;da=ba-S;g[b>>2]=q+$;g[u>>2]=q-$;$=H-m;q=X-I;g[h>>2]=W+$;g[n>>2]=W-$;$=H+m;m=X+I;g[k>>2]=q+da;g[z>>2]=q-da;g[w>>2]=m+$;g[s>>2]=m-$;$=+g[A>>2];m=j-$;da=+g[p>>2];q=Y-da;I=da+Y;Y=$+j;j=q+m;$=m-q;q=+g[Q>>2];m=+g[i>>2];da=q-m;X=+g[r>>2];H=+g[O>>2];W=X-H;S=H+X;X=m+q;q=+g[v>>2];m=+g[F>>2];H=q-m;ba=+g[t>>2];aa=+g[K>>2];R=ba-aa;Z=m+q;q=aa+ba;ba=H-R;aa=R+H;H=+g[f>>2];R=+g[y>>2];m=H-R;ca=+g[a>>2];M=+g[C>>2];o=ca-M;l=R+H;H=M+ca;ca=m+da;M=m-da;da=(ba+j)*.7071067690849304;m=(ba-j)*.7071067690849304;g[y>>2]=da+ca;g[F>>2]=ca-da;da=(aa-$)*.7071067690849304;ca=o-W;g[T>>2]=da+M;g[O>>2]=M-da;da=(aa+$)*.7071067690849304;$=o+W;g[Q>>2]=ca+m;g[V>>2]=ca-m;g[C>>2]=$+da;g[K>>2]=$-da;da=l+S;$=l-S;S=Z+I;l=Z-I;g[f>>2]=da+S;g[v>>2]=da-S;S=q-Y;da=H-X;g[p>>2]=$+S;g[r>>2]=$-S;S=q+Y;Y=H+X;g[i>>2]=da+l;g[A>>2]=da-l;g[a>>2]=Y+S;g[t>>2]=Y-S;G=G+32|0}while((G|0)<(d|0));return}function Fc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0.0,q=0.0,r=0.0,s=0.0,t=0.0,u=0;f=a>>1;h=b+(a<<2)|0;a=d;d=e;b=e+(f<<2)|0;while(1){i=(c[a>>2]|0)+f|0;j=(c[a+4>>2]|0)+f|0;k=+g[e+(i+1<<2)>>2];l=+g[e+(j+1<<2)>>2];m=k-l;n=+g[e+(i<<2)>>2];o=+g[e+(j<<2)>>2];p=o+n;q=+g[h>>2];r=+g[h+4>>2];s=r*m+p*q;t=r*p-q*m;j=b;b=b+-16|0;m=(l+k)*.5;k=(n-o)*.5;g[d>>2]=s+m;g[j+-8>>2]=m-s;g[d+4>>2]=t+k;g[j+-4>>2]=t-k;i=(c[a+8>>2]|0)+f|0;u=(c[a+12>>2]|0)+f|0;k=+g[e+(i+1<<2)>>2];t=+g[e+(u+1<<2)>>2];s=k-t;m=+g[e+(i<<2)>>2];o=+g[e+(u<<2)>>2];n=o+m;l=+g[h+8>>2];q=+g[h+12>>2];p=q*s+n*l;r=q*n-l*s;s=(t+k)*.5;k=(m-o)*.5;g[d+8>>2]=p+s;g[b>>2]=s-p;g[d+12>>2]=r+k;g[j+-12>>2]=r-k;d=d+16|0;if(d>>>0>=b>>>0)break;else{h=h+16|0;a=a+16|0}}return}function Gc(a,b,c,d,e,f,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;h=h|0;var i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0.0,v=0,w=0,x=0.0,y=0,z=0,A=0.0,B=0.0,C=0.0,D=0.0,E=0,F=0.0,G=0.0,H=0.0,I=0.0;i=_(b,a)|0;j=i<<1;k=(b|0)>0;if(k){l=(a<<2)+-1|0;m=a<<1;n=0;o=i;p=i*3|0;q=0;r=j;while(1){s=c+(o<<2)|0;t=c+(p<<2)|0;u=+g[t>>2]+ +g[s>>2];v=c+(q<<2)|0;w=c+(r<<2)|0;x=+g[w>>2]+ +g[v>>2];y=q<<2;g[d+(y<<2)>>2]=x+u;g[d+(l+y<<2)>>2]=x-u;z=y+m|0;g[d+(z+-1<<2)>>2]=+g[v>>2]-+g[w>>2];g[d+(z<<2)>>2]=+g[t>>2]-+g[s>>2];n=n+1|0;if((n|0)==(b|0))break;else{o=o+a|0;p=p+a|0;q=q+a|0;r=r+a|0}}}if((a|0)<2)return;if((a|0)!=2){if(k){r=a<<1;q=0;p=0;while(1){o=p<<2;n=2;m=p;l=o;s=o+r|0;do{o=m;m=m+2|0;t=l;l=l+2|0;z=s;s=s+-2|0;w=m+i|0;v=n+-2|0;u=+g[e+(v<<2)>>2];x=+g[c+(w+-1<<2)>>2];y=n+-1|0;A=+g[e+(y<<2)>>2];B=+g[c+(w<<2)>>2];C=B*A+x*u;D=B*u-A*x;E=w+i|0;x=+g[f+(v<<2)>>2];A=+g[c+(E+-1<<2)>>2];u=+g[f+(y<<2)>>2];B=+g[c+(E<<2)>>2];F=B*u+A*x;G=B*x-u*A;w=E+i|0;A=+g[h+(v<<2)>>2];u=+g[c+(w+-1<<2)>>2];x=+g[h+(y<<2)>>2];B=+g[c+(w<<2)>>2];H=B*x+u*A;I=B*A-x*u;u=H+C;x=H-C;C=I+D;H=D-I;I=+g[c+(m<<2)>>2];D=I+G;A=I-G;G=+g[c+(o+1<<2)>>2];I=G+F;B=G-F;g[d+((t|1)<<2)>>2]=u+I;g[d+(l<<2)>>2]=C+D;g[d+(z+-3<<2)>>2]=B-H;g[d+(s<<2)>>2]=x-A;z=l+r|0;g[d+(z+-1<<2)>>2]=H+B;g[d+(z<<2)>>2]=x+A;z=s+r|0;g[d+(z+-1<<2)>>2]=I-u;g[d+(z<<2)>>2]=C-D;n=n+2|0}while((n|0)<(a|0));q=q+1|0;if((q|0)==(b|0))break;else p=p+a|0}}if(a&1)return}p=a+-1+i|0;q=a<<2;r=a<<1;if(!k)return;k=0;h=p;f=p+j|0;j=a;p=a;while(1){D=+g[c+(h<<2)>>2];C=+g[c+(f<<2)>>2];u=(C+D)*-.7071067690849304;I=(D-C)*.7071067690849304;e=c+(p+-1<<2)|0;g[d+(j+-1<<2)>>2]=I+ +g[e>>2];n=j+r|0;g[d+(n+-1<<2)>>2]=+g[e>>2]-I;e=c+(h+i<<2)|0;g[d+(j<<2)>>2]=u-+g[e>>2];g[d+(n<<2)>>2]=+g[e>>2]+u;k=k+1|0;if((k|0)==(b|0))break;else{h=h+a|0;f=f+a|0;j=j+q|0;p=p+a|0}}return}function Hc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0;h=_(b,a)|0;i=a<<1;j=(b|0)>0;if(j){k=i+-1|0;l=0;m=0;n=h;while(1){o=d+(m<<2)|0;p=d+(n<<2)|0;q=m<<1;g[e+(q<<2)>>2]=+g[p>>2]+ +g[o>>2];g[e+(k+q<<2)>>2]=+g[o>>2]-+g[p>>2];l=l+1|0;if((l|0)==(b|0))break;else{m=m+a|0;n=n+a|0}}}if((a|0)<2)return;if((a|0)!=2){if(j){n=0;m=0;l=h;while(1){k=m<<1;p=2;o=l;q=k+i|0;r=m;s=k;do{k=o;o=o+2|0;t=q;q=q+-2|0;u=r;r=r+2|0;v=s;s=s+2|0;w=+g[f+(p+-2<<2)>>2];x=+g[d+(k+1<<2)>>2];y=+g[f+(p+-1<<2)>>2];z=+g[d+(o<<2)>>2];A=z*y+x*w;B=z*w-y*x;k=d+(r<<2)|0;g[e+(s<<2)>>2]=B+ +g[k>>2];g[e+(q<<2)>>2]=B-+g[k>>2];k=d+(u+1<<2)|0;g[e+((v|1)<<2)>>2]=+g[k>>2]+A;g[e+(t+-3<<2)>>2]=+g[k>>2]-A;p=p+2|0}while((p|0)<(a|0));n=n+1|0;if((n|0)==(b|0))break;else{m=m+a|0;l=l+a|0}}}if(((a|0)%2|0|0)==1)return}l=a+-1|0;if(!j)return;j=0;m=a;n=h+l|0;h=l;while(1){g[e+(m<<2)>>2]=-+g[d+(n<<2)>>2];c[e+(m+-1<<2)>>2]=c[d+(h<<2)>>2];j=j+1|0;if((j|0)==(b|0))break;else{m=m+i|0;n=n+a|0;h=h+a|0}}return}function Ic(a,b,d,e,f,h,i,j,k,l){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;h=h|0;i=i|0;j=j|0;k=k|0;l=l|0;var m=0.0,n=0.0,o=0.0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0.0,N=0.0,O=0.0,P=0.0;m=6.2831854820251465/+(b|0);n=+Q(+m);o=+R(+m);p=b+1>>1;q=a+-1>>1;r=_(d,a)|0;s=_(b,a)|0;t=(a|0)==1;a:do if(!t){if((e|0)>0){u=0;do{c[k+(u<<2)>>2]=c[i+(u<<2)>>2];u=u+1|0}while((u|0)!=(e|0))}u=(b|0)>1;if(u){v=(d|0)>0;w=1;x=0;do{x=x+r|0;if(v){y=0;z=x;while(1){c[j+(z<<2)>>2]=c[h+(z<<2)>>2];y=y+1|0;if((y|0)==(d|0))break;else z=z+a|0}}w=w+1|0}while((w|0)!=(b|0))}w=0-a|0;if((q|0)>(d|0)){if(u){x=(d|0)>0;v=(a|0)>2;z=w;y=1;A=0;do{A=A+r|0;z=z+a|0;if(x){B=z+-1|0;C=0;D=A-a|0;do{D=D+a|0;if(v){E=2;F=B;G=D;do{H=F;F=F+2|0;I=l+(H+1<<2)|0;H=G+1|0;G=G+2|0;J=h+(H<<2)|0;K=l+(F<<2)|0;L=h+(G<<2)|0;g[j+(H<<2)>>2]=+g[L>>2]*+g[K>>2]+ +g[J>>2]*+g[I>>2];g[j+(G<<2)>>2]=+g[L>>2]*+g[I>>2]-+g[J>>2]*+g[K>>2];E=E+2|0}while((E|0)<(a|0))}C=C+1|0}while((C|0)!=(d|0))}y=y+1|0}while((y|0)!=(b|0))}}else if(u){y=(a|0)>2;v=(d|0)>0;A=w;z=1;x=0;do{A=A+a|0;x=x+r|0;if(y){C=2;D=A+-1|0;B=x;do{E=D;D=D+2|0;B=B+2|0;if(v){G=l+(E+1<<2)|0;E=l+(D<<2)|0;F=0;K=B;while(1){J=K+-1|0;I=h+(J<<2)|0;L=h+(K<<2)|0;g[j+(J<<2)>>2]=+g[L>>2]*+g[E>>2]+ +g[I>>2]*+g[G>>2];g[j+(K<<2)>>2]=+g[L>>2]*+g[G>>2]-+g[I>>2]*+g[E>>2];F=F+1|0;if((F|0)==(d|0))break;else K=K+a|0}}C=C+2|0}while((C|0)<(a|0))}z=z+1|0}while((z|0)!=(b|0))}z=_(r,b)|0;v=(p|0)>1;if((q|0)>=(d|0)){if(!v)break;x=(d|0)>0;A=(a|0)>2;y=1;w=0;u=z;while(1){w=w+r|0;u=u-r|0;if(x){C=0;B=w;D=u;while(1){if(A){K=2;F=B;E=D;do{G=F;F=F+2|0;I=G+1|0;G=j+(I<<2)|0;L=E+1|0;E=E+2|0;J=j+(L<<2)|0;g[h+(I<<2)>>2]=+g[J>>2]+ +g[G>>2];I=j+(F<<2)|0;H=j+(E<<2)|0;g[h+(L<<2)>>2]=+g[I>>2]-+g[H>>2];g[h+(F<<2)>>2]=+g[H>>2]+ +g[I>>2];g[h+(E<<2)>>2]=+g[J>>2]-+g[G>>2];K=K+2|0}while((K|0)<(a|0))}C=C+1|0;if((C|0)==(d|0))break;else{B=B+a|0;D=D+a|0}}}y=y+1|0;if((y|0)==(p|0))break a}}if(v){y=(a|0)>2;A=(d|0)>0;u=1;w=0;x=z;do{w=w+r|0;x=x-r|0;if(y){D=2;B=w;C=x;do{B=B+2|0;C=C+2|0;if(A){K=0;E=B-a|0;F=C-a|0;do{E=E+a|0;F=F+a|0;G=E+-1|0;J=j+(G<<2)|0;I=F+-1|0;H=j+(I<<2)|0;g[h+(G<<2)>>2]=+g[H>>2]+ +g[J>>2];G=j+(E<<2)|0;L=j+(F<<2)|0;g[h+(I<<2)>>2]=+g[G>>2]-+g[L>>2];g[h+(E<<2)>>2]=+g[L>>2]+ +g[G>>2];g[h+(F<<2)>>2]=+g[H>>2]-+g[J>>2];K=K+1|0}while((K|0)!=(d|0))}D=D+2|0}while((D|0)<(a|0))}u=u+1|0}while((u|0)!=(p|0))}}while(0);l=(e|0)>0;if(l){u=0;do{c[i+(u<<2)>>2]=c[k+(u<<2)>>2];u=u+1|0}while((u|0)!=(e|0))}u=_(e,b)|0;A=(p|0)>1;if(A){x=(d|0)>0;w=1;y=0;z=u;do{y=y+r|0;z=z-r|0;if(x){v=0;D=y-a|0;C=z-a|0;do{D=D+a|0;C=C+a|0;B=j+(D<<2)|0;K=j+(C<<2)|0;g[h+(D<<2)>>2]=+g[K>>2]+ +g[B>>2];g[h+(C<<2)>>2]=+g[K>>2]-+g[B>>2];v=v+1|0}while((v|0)!=(d|0))}w=w+1|0}while((w|0)!=(p|0));w=_(b+-1|0,e)|0;if(A){h=(p|0)>2;m=0.0;M=1.0;z=1;y=0;x=u;do{y=y+e|0;x=x-e|0;N=M;M=M*n-m*o;m=N*o+m*n;if(l){u=0;v=y;C=x;D=w;B=e;while(1){g[k+(v<<2)>>2]=+g[i+(B<<2)>>2]*M+ +g[i+(u<<2)>>2];g[k+(C<<2)>>2]=+g[i+(D<<2)>>2]*m;u=u+1|0;if((u|0)==(e|0))break;else{v=v+1|0;C=C+1|0;D=D+1|0;B=B+1|0}}}if(h){N=m;O=M;B=2;D=e;C=w;do{D=D+e|0;C=C-e|0;P=O;O=O*M-N*m;N=P*m+N*M;if(l){v=0;u=y;K=x;F=D;E=C;while(1){J=k+(u<<2)|0;g[J>>2]=+g[J>>2]+ +g[i+(F<<2)>>2]*O;J=k+(K<<2)|0;g[J>>2]=+g[J>>2]+ +g[i+(E<<2)>>2]*N;v=v+1|0;if((v|0)==(e|0))break;else{u=u+1|0;K=K+1|0;F=F+1|0;E=E+1|0}}}B=B+1|0}while((B|0)!=(p|0))}z=z+1|0}while((z|0)!=(p|0));if(A){z=1;x=0;do{x=x+e|0;if(l){y=0;w=x;while(1){h=k+(y<<2)|0;g[h>>2]=+g[h>>2]+ +g[i+(w<<2)>>2];y=y+1|0;if((y|0)==(e|0))break;else w=w+1|0}}z=z+1|0}while((z|0)!=(p|0))}}}if((a|0)<(d|0)){if((a|0)>0){z=(d|0)>0;e=0;do{if(z){i=0;k=e;x=e;while(1){c[f+(x<<2)>>2]=c[j+(k<<2)>>2];i=i+1|0;if((i|0)==(d|0))break;else{k=k+a|0;x=x+s|0}}}e=e+1|0}while((e|0)!=(a|0))}}else if((d|0)>0){e=(a|0)>0;z=0;x=0;k=0;while(1){if(e){i=0;l=x;w=k;while(1){c[f+(w<<2)>>2]=c[j+(l<<2)>>2];i=i+1|0;if((i|0)==(a|0))break;else{l=l+1|0;w=w+1|0}}}z=z+1|0;if((z|0)==(d|0))break;else{x=x+a|0;k=k+s|0}}}k=a<<1;x=_(r,b)|0;if(A){b=(d|0)>0;z=1;e=0;w=0;l=x;do{e=e+k|0;w=w+r|0;l=l-r|0;if(b){i=0;y=e;h=w;B=l;while(1){c[f+(y+-1<<2)>>2]=c[j+(h<<2)>>2];c[f+(y<<2)>>2]=c[j+(B<<2)>>2];i=i+1|0;if((i|0)==(d|0))break;else{y=y+s|0;h=h+a|0;B=B+a|0}}}z=z+1|0}while((z|0)!=(p|0))}if(t)return;t=0-a|0;if((q|0)>=(d|0)){if(!A)return;q=(d|0)<1|(a|0)<3;z=1;l=t;w=0;e=0;b=x;do{l=l+k|0;w=w+k|0;e=e+r|0;b=b-r|0;if(!q){B=0;h=l;y=w;i=e;C=b;while(1){D=2;do{E=D+i|0;F=j+(E+-1<<2)|0;K=D+C|0;u=j+(K+-1<<2)|0;v=D+y|0;g[f+(v+-1<<2)>>2]=+g[u>>2]+ +g[F>>2];J=a-D+h|0;g[f+(J+-1<<2)>>2]=+g[F>>2]-+g[u>>2];u=j+(E<<2)|0;E=j+(K<<2)|0;g[f+(v<<2)>>2]=+g[E>>2]+ +g[u>>2];g[f+(J<<2)>>2]=+g[E>>2]-+g[u>>2];D=D+2|0}while((D|0)<(a|0));B=B+1|0;if((B|0)==(d|0))break;else{h=h+s|0;y=y+s|0;i=i+a|0;C=C+a|0}}}z=z+1|0}while((z|0)!=(p|0));return}if(!A)return;A=(a|0)>2;z=(d|0)>0;b=1;e=t;t=0;w=0;l=x;do{e=e+k|0;t=t+k|0;w=w+r|0;l=l-r|0;if(A?(x=e+a|0,z):0){q=2;do{C=0;i=x-q|0;y=q+t|0;h=q+w|0;B=q+l|0;while(1){D=j+(h+-1<<2)|0;u=j+(B+-1<<2)|0;g[f+(y+-1<<2)>>2]=+g[u>>2]+ +g[D>>2];g[f+(i+-1<<2)>>2]=+g[D>>2]-+g[u>>2];u=j+(h<<2)|0;D=j+(B<<2)|0;g[f+(y<<2)>>2]=+g[D>>2]+ +g[u>>2];g[f+(i<<2)>>2]=+g[D>>2]-+g[u>>2];C=C+1|0;if((C|0)==(d|0))break;else{i=i+s|0;y=y+s|0;h=h+a|0;B=B+a|0}}q=q+2|0}while((q|0)<(a|0))}b=b+1|0}while((b|0)!=(p|0));return}function Jc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;e=c[b+28>>2]|0;if(!e){f=1;return f|0}g=c[e+3656>>2]|0;h=a;i=h+112|0;do{c[h>>2]=0;h=h+4|0}while((h|0)<(i|0));h=zd(1,136)|0;c[a+104>>2]=h;c[a+4>>2]=b;i=c[e+8>>2]|0;j=i+-1|0;if((i|0)==0|(j|0)==0)k=0;else{i=j;j=0;while(1){l=j+1|0;i=i>>>1;if(!i){k=l;break}else j=l}}c[h+44>>2]=k;k=zd(1,4)|0;c[h+12>>2]=k;j=zd(1,4)|0;i=h+16|0;c[i>>2]=j;l=zd(1,20)|0;c[k>>2]=l;c[j>>2]=zd(1,20)|0;sb(l,c[e>>2]>>g);l=e+4|0;sb(c[c[i>>2]>>2]|0,c[l>>2]>>g);g=c[e>>2]|0;i=g+-1|0;if((g|0)==0|(i|0)==0)m=0;else{j=i;i=0;while(1){k=i+1|0;j=j>>>1;if(!j){m=k;break}else i=k}}c[h+4>>2]=m+-6;m=c[l>>2]|0;i=m+-1|0;if((m|0)==0|(i|0)==0)n=0;else{m=i;i=0;while(1){j=i+1|0;m=m>>>1;if(!m){n=j;break}else i=j}}c[h+8>>2]=n+-6;a:do if(!d){n=e+2848|0;if((c[n>>2]|0)==0?(i=e+24|0,c[n>>2]=zd(c[i>>2]|0,56)|0,m=c[i>>2]|0,(m|0)>0):0){j=m;m=0;while(1){k=e+1824+(m<<2)|0;o=c[k>>2]|0;if(!o){p=j;break}if(Bc((c[n>>2]|0)+(m*56|0)|0,o)|0){q=23;break}yc(c[k>>2]|0);c[k>>2]=0;m=m+1|0;j=c[i>>2]|0;if((m|0)>=(j|0))break a}if((q|0)==23)p=c[i>>2]|0;if((p|0)>0){j=p;m=0;while(1){n=e+1824+(m<<2)|0;k=c[n>>2]|0;if(!k)r=j;else{yc(k);c[n>>2]=0;r=c[i>>2]|0}m=m+1|0;if((m|0)>=(r|0))break;else j=r}}Db(a);f=-1;return f|0}}else{xb(h+20|0,g);xb(h+32|0,c[l>>2]|0);j=e+2848|0;if(((c[j>>2]|0)==0?(m=e+24|0,i=zd(c[m>>2]|0,56)|0,c[j>>2]=i,(c[m>>2]|0)>0):0)?(Ac(i,c[e+1824>>2]|0)|0,(c[m>>2]|0)>1):0){i=1;do{Ac((c[j>>2]|0)+(i*56|0)|0,c[e+1824+(i<<2)>>2]|0)|0;i=i+1|0}while((i|0)<(c[m>>2]|0))}m=e+28|0;i=zd(c[m>>2]|0,52)|0;j=h+56|0;c[j>>2]=i;b:do if((c[m>>2]|0)>0){n=e+2868|0;k=b+8|0;o=i;s=0;while(1){t=c[e+2852+(s<<2)>>2]|0;Pb(o+(s*52|0)|0,t,n,(c[e+(c[t>>2]<<2)>>2]|0)/2|0,c[k>>2]|0);t=s+1|0;if((t|0)>=(c[m>>2]|0))break b;o=c[j>>2]|0;s=t}}while(0);c[a>>2]=1}while(0);g=c[l>>2]|0;c[a+16>>2]=g;r=c[b+4>>2]|0;b=r<<2;p=xd(b)|0;q=a+8|0;c[q>>2]=p;c[a+12>>2]=xd(b)|0;if((r|0)>0?(c[p>>2]=zd(g,4)|0,(r|0)>1):0){p=1;do{b=c[q>>2]|0;c[b+(p<<2)>>2]=zd(g,4)|0;p=p+1|0}while((p|0)<(r|0))}c[a+36>>2]=0;c[a+40>>2]=0;r=(c[l>>2]|0)/2|0;c[a+48>>2]=r;c[a+20>>2]=r;r=e+16|0;l=h+48|0;c[l>>2]=zd(c[r>>2]|0,4)|0;p=e+20|0;g=h+52|0;c[g>>2]=zd(c[p>>2]|0,4)|0;if((c[r>>2]|0)>0){h=0;do{q=$a[c[(c[328+(c[e+800+(h<<2)>>2]<<2)>>2]|0)+8>>2]&15](a,c[e+1056+(h<<2)>>2]|0)|0;c[(c[l>>2]|0)+(h<<2)>>2]=q;h=h+1|0}while((h|0)<(c[r>>2]|0))}if((c[p>>2]|0)>0)u=0;else{f=0;return f|0}do{r=$a[c[(c[336+(c[e+1312+(u<<2)>>2]<<2)>>2]|0)+8>>2]&15](a,c[e+1568+(u<<2)>>2]|0)|0;c[(c[g>>2]|0)+(u<<2)>>2]=r;u=u+1|0}while((u|0)<(c[p>>2]|0));f=0;return f|0}function Kc(a,b,d,e,f){a=a|0;b=+b;d=d|0;e=+e;f=+f;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0.0,v=0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,N=0,O=0.0,P=0;h=i;i=i+32480|0;j=h+32256|0;k=h+1792|0;l=h;m=i;i=i+((1*(d<<2)|0)+15&-16)|0;n=xd(68)|0;Fd(k|0,0,30464)|0;o=e>0.0;p=e<0.0;q=0;do{r=q<<2;s=0;do{t=s+r|0;if((t|0)<88)u=+g[408+(t<<2)>>2];else u=-30.0;v=t+1|0;if((v|0)<88){w=+g[408+(v<<2)>>2];if(u>w)x=w;else x=u}else if(u>-30.0)x=-30.0;else x=u;v=t+2|0;if((v|0)<88){w=+g[408+(v<<2)>>2];if(x>w)y=w;else y=x}else if(x>-30.0)y=-30.0;else y=x;v=t+3|0;if((v|0)<88){w=+g[408+(v<<2)>>2];if(y>w)z=w;else z=y}else if(y>-30.0)z=-30.0;else z=y;g[j+(s<<2)>>2]=z;s=s+1|0}while((s|0)!=56);s=33552+(q*1344|0)|0;Jd(k+(q*1792|0)+448|0,s|0,224)|0;Jd(k+(q*1792|0)+672|0,33552+(q*1344|0)+224|0,224)|0;Jd(k+(q*1792|0)+896|0,33552+(q*1344|0)+448|0,224)|0;Jd(k+(q*1792|0)+1120|0,33552+(q*1344|0)+672|0,224)|0;Jd(k+(q*1792|0)+1344|0,33552+(q*1344|0)+896|0,224)|0;Jd(k+(q*1792|0)+1568|0,33552+(q*1344|0)+1120|0,224)|0;Jd(k+(q*1792|0)|0,s|0,224)|0;Jd(k+(q*1792|0)+224|0,s|0,224)|0;if(o){s=0;do{if(p){r=0;do{v=16-r|0;w=+(((v|0)>-1?v:0-v|0)|0)*f+e;A=w<0.0?0.0:w;v=k+(q*1792|0)+(s*224|0)+(r<<2)|0;g[v>>2]=+g[v>>2]+(A>0.0?0.0:A);r=r+1|0}while((r|0)!=56)}else{r=0;do{v=16-r|0;A=+(((v|0)>-1?v:0-v|0)|0)*f+e;v=k+(q*1792|0)+(s*224|0)+(r<<2)|0;g[v>>2]=+g[v>>2]+(A<0.0?0.0:A);r=r+1|0}while((r|0)!=56)}s=s+1|0}while((s|0)!=8)}else{s=0;do{if(p){r=0;do{v=16-r|0;A=+(((v|0)>-1?v:0-v|0)|0)*f+e;v=k+(q*1792|0)+(s*224|0)+(r<<2)|0;g[v>>2]=+g[v>>2]+(A>0.0?0.0:A);r=r+1|0}while((r|0)!=56)}else{r=0;do{v=16-r|0;t=k+(q*1792|0)+(s*224|0)+(r<<2)|0;g[t>>2]=+g[t>>2]+(+(((v|0)>-1?v:0-v|0)|0)*f+e);r=r+1|0}while((r|0)!=56)}s=s+1|0}while((s|0)!=8)}A=+g[a+(q<<2)>>2];s=0;do{w=((s|0)<2?50.0:70.0-+(s|0)*10.0)+A;r=0;do{v=k+(q*1792|0)+(s*224|0)+(r<<2)|0;g[v>>2]=+g[v>>2]+w;r=r+1|0}while((r|0)!=56);Jd(l+(s*224|0)|0,j|0,224)|0;w=70.0-+(s|0)*10.0;r=0;do{v=l+(s*224|0)+(r<<2)|0;g[v>>2]=w+ +g[v>>2];r=r+1|0}while((r|0)!=56);B=0;do{w=+g[k+(q*1792|0)+(s*224|0)+(B<<2)>>2];r=l+(s*224|0)+(B<<2)|0;if(w>+g[r>>2])g[r>>2]=w;B=B+1|0}while((B|0)!=56);s=s+1|0}while((s|0)!=8);C=1;do{s=C+-1|0;r=0;do{A=+g[l+(s*224|0)+(r<<2)>>2];v=l+(C*224|0)+(r<<2)|0;if(A<+g[v>>2])g[v>>2]=A;r=r+1|0}while((r|0)!=56);D=0;do{A=+g[l+(C*224|0)+(D<<2)>>2];r=k+(q*1792|0)+(C*224|0)+(D<<2)|0;if(A<+g[r>>2])g[r>>2]=A;D=D+1|0}while((D|0)!=56);C=C+1|0}while((C|0)!=8);q=q+1|0}while((q|0)!=17);e=b;q=(d|0)>0;C=~d;D=0;do{l=xd(32)|0;c[n+(D<<2)>>2]=l;f=+(D|0);z=f*.5;B=~~+M(+(+X(+(f*.34657350182533264+4.135165354540845))/e));j=~~+Z(+(+Y(+(+(B|0)*b+1.0))*2.885390043258667+-11.931568145751953));a=~~+M(+(+Y(+(+(B+1|0)*b))*2.885390043258667+-11.931568145751953));B=(j|0)>(D|0)?D:j;j=(B|0)<0?0:B;B=(a|0)>16?16:a;a=(j|0)>(B|0);D=D+1|0;p=(D|0)<17;f=z+3.9657840728759766;o=0;do{r=xd(232)|0;c[l+(o<<2)>>2]=r;if(q){s=0;do{g[m+(s<<2)>>2]=999.0;s=s+1|0}while((s|0)!=(d|0))}if(!a){s=j;while(1){y=+(s|0)*.5;v=0;t=0;while(1){x=+(v|0)*.125+y;E=~~(+X(+((x+3.9032840728759766)*.6931470036506653))/e);F=~~(+X(+((x+4.028284072875977)*.6931470036506653))/e+1.0);G=(E|0)<0?0:E;H=(G|0)>(d|0)?d:G;G=(H|0)<(t|0)?H:t;H=(F|0)<0?0:F;if((G|0)<(d|0)?(G|0)<(((H|0)>(d|0)?d:H)|0):0){x=+g[k+(s*1792|0)+(o*224|0)+(v<<2)>>2];H=~((t|0)<(d|0)?t:d);I=(E|0)>0?~E:-1;E=(I|0)<(H|0)?H:I;I=(F|0)>0?~F:-1;F=((I|0)<(C|0)?C:I)-E|0;I=~(E+d);H=~E-(F>>>0>I>>>0?F:I)|0;I=G;do{F=m+(I<<2)|0;if(+g[F>>2]>x)g[F>>2]=x;I=I+1|0}while((I|0)!=(H|0));J=H}else J=G;v=v+1|0;if((v|0)==56){K=J;break}else t=J}if((K|0)<(d|0)){y=+g[k+(s*1792|0)+(o*224|0)+220>>2];t=K;do{v=m+(t<<2)|0;if(+g[v>>2]>y)g[v>>2]=y;t=t+1|0}while((t|0)!=(d|0))}if((s|0)<(B|0))s=s+1|0;else break}}if(p){s=0;t=0;while(1){y=+(s|0)*.125+z;v=~~(+X(+((y+3.9032840728759766)*.6931470036506653))/e);H=~~(+X(+((y+4.028284072875977)*.6931470036506653))/e+1.0);I=(v|0)<0?0:v;F=(I|0)>(d|0)?d:I;I=(F|0)<(t|0)?F:t;F=(H|0)<0?0:H;if((I|0)<(d|0)?(I|0)<(((F|0)>(d|0)?d:F)|0):0){y=+g[k+(D*1792|0)+(o*224|0)+(s<<2)>>2];F=~((t|0)<(d|0)?t:d);E=(v|0)>0?~v:-1;v=(E|0)<(F|0)?F:E;E=(H|0)>0?~H:-1;H=((E|0)<(C|0)?C:E)-v|0;E=~(v+d);F=~v-(H>>>0>E>>>0?H:E)|0;E=I;do{H=m+(E<<2)|0;if(+g[H>>2]>y)g[H>>2]=y;E=E+1|0}while((E|0)!=(F|0));L=F}else L=I;s=s+1|0;if((s|0)==56){N=L;break}else t=L}if((N|0)<(d|0)){y=+g[k+(D*1792|0)+(o*224|0)+220>>2];t=N;do{s=m+(t<<2)|0;if(+g[s>>2]>y)g[s>>2]=y;t=t+1|0}while((t|0)!=(d|0))}}t=l+(o<<2)|0;s=l+(o<<2)|0;F=l+(o<<2)|0;E=0;do{H=~~(+X(+((f+ +(E|0)*.125)*.6931470036506653))/e);do if((H|0)>=0)if((H|0)<(d|0)){c[(c[s>>2]|0)+(E+2<<2)>>2]=c[m+(H<<2)>>2];break}else{g[(c[F>>2]|0)+(E+2<<2)>>2]=-999.0;break}else g[(c[t>>2]|0)+(E+2<<2)>>2]=-999.0;while(0);E=E+1|0}while((E|0)!=56);do if(!(+g[r+8>>2]>-200.0))if(!(+g[r+12>>2]>-200.0))if(!(+g[r+16>>2]>-200.0))if(!(+g[r+20>>2]>-200.0))if(!(+g[r+24>>2]>-200.0))if(!(+g[r+28>>2]>-200.0))if(!(+g[r+32>>2]>-200.0))if(!(+g[r+36>>2]>-200.0))if(!(+g[r+40>>2]>-200.0))if(!(+g[r+44>>2]>-200.0))if(!(+g[r+48>>2]>-200.0))if(!(+g[r+52>>2]>-200.0))if(!(+g[r+56>>2]>-200.0))if(+g[r+60>>2]>-200.0)O=13.0;else{if(+g[r+64>>2]>-200.0){O=14.0;break}if(+g[r+68>>2]>-200.0){O=15.0;break}O=16.0}else O=12.0;else O=11.0;else O=10.0;else O=9.0;else O=8.0;else O=7.0;else O=6.0;else O=5.0;else O=4.0;else O=3.0;else O=2.0;else O=1.0;else O=0.0;while(0);g[r>>2]=O;E=55;while(1){if(+g[r+(E+2<<2)>>2]>-200.0){P=E;break}t=E+-1|0;if((t|0)>17)E=t;else{P=t;break}}g[r+4>>2]=+(P|0);o=o+1|0}while((o|0)!=8)}while((D|0)!=17);i=h;return n|0}function Lc(a,b,d,e,f,h){a=a|0;b=b|0;d=d|0;e=e|0;f=+f;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0.0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0,A=0.0,B=0.0,C=0.0,D=0,E=0.0,F=0,G=0,H=0,I=0.0,J=0.0,K=0.0,L=0,M=0.0,N=0.0,O=0.0,P=0.0,Q=0,R=0.0,S=0.0,T=0.0,U=0.0,V=0,W=0.0,X=0,Y=0.0;j=i;k=a<<2;l=i;i=i+((1*k|0)+15&-16)|0;m=i;i=i+((1*k|0)+15&-16)|0;n=i;i=i+((1*k|0)+15&-16)|0;o=i;i=i+((1*k|0)+15&-16)|0;p=i;i=i+((1*k|0)+15&-16)|0;q=+g[d>>2]+f;r=q<1.0?1.0:q;q=r*r*.5;s=q*r;g[l>>2]=q;g[m>>2]=q;g[n>>2]=0.0;g[o>>2]=s;g[p>>2]=0.0;if((a|0)>1){k=1;r=q;t=q;q=0.0;u=0.0;v=s;s=1.0;while(1){w=+g[d+(k<<2)>>2]+f;x=w<1.0?1.0:w;w=x*x;r=w+r;y=w*s;t=y+t;q=y*s+q;v=w*x+v;u=y*x+u;g[l+(k<<2)>>2]=r;g[m+(k<<2)>>2]=t;g[n+(k<<2)>>2]=q;g[o+(k<<2)>>2]=v;g[p+(k<<2)>>2]=u;k=k+1|0;if((k|0)==(a|0))break;else s=s+1.0}}k=c[b>>2]|0;d=k>>16;if((d|0)>-1){z=k;A=0.0;B=0.0;C=1.0;D=0;E=0.0}else{F=k;k=d;d=0;s=0.0;while(1){G=F&65535;H=0-k|0;u=+g[l+(H<<2)>>2]+ +g[l+(G<<2)>>2];v=+g[m+(G<<2)>>2]-+g[m+(H<<2)>>2];q=+g[n+(H<<2)>>2]+ +g[n+(G<<2)>>2];t=+g[o+(H<<2)>>2]+ +g[o+(G<<2)>>2];r=+g[p+(G<<2)>>2]-+g[p+(H<<2)>>2];x=t*q-r*v;y=r*u-t*v;t=q*u-v*v;v=(y*s+x)/t;g[e+(d<<2)>>2]=(v<0.0?0.0:v)-f;H=d+1|0;v=s+1.0;G=c[b+(H<<2)>>2]|0;k=G>>16;if((k|0)>-1){z=G;A=x;B=y;C=t;D=H;E=v;break}else{F=G;d=H;s=v}}}d=z&65535;if((d|0)<(a|0)){F=z;z=d;d=D;s=E;while(1){k=F>>16;v=+g[l+(z<<2)>>2]-+g[l+(k<<2)>>2];t=+g[m+(z<<2)>>2]-+g[m+(k<<2)>>2];y=+g[n+(z<<2)>>2]-+g[n+(k<<2)>>2];x=+g[o+(z<<2)>>2]-+g[o+(k<<2)>>2];u=+g[p+(z<<2)>>2]-+g[p+(k<<2)>>2];q=x*y-u*t;r=u*v-x*t;x=y*v-t*t;t=(r*s+q)/x;g[e+(d<<2)>>2]=(t<0.0?0.0:t)-f;k=d+1|0;t=s+1.0;F=c[b+(k<<2)>>2]|0;z=F&65535;if((z|0)>=(a|0)){I=q;J=r;K=x;L=k;M=t;break}else{d=k;s=t}}}else{I=A;J=B;K=C;L=D;M=E}if((L|0)<(a|0)){D=L;E=M;while(1){M=(E*J+I)/K;g[e+(D<<2)>>2]=(M<0.0?0.0:M)-f;D=D+1|0;if((D|0)==(a|0))break;else E=E+1.0}}if((h|0)<1){i=j;return}D=(h|0)/2|0;L=D-h|0;if((L|0)>-1){N=I;O=J;P=K;Q=0;R=0.0}else{d=h-D|0;z=D;F=L;L=0;K=0.0;while(1){b=0-F|0;J=+g[l+(b<<2)>>2]+ +g[l+(z<<2)>>2];I=+g[m+(z<<2)>>2]-+g[m+(b<<2)>>2];E=+g[n+(b<<2)>>2]+ +g[n+(z<<2)>>2];M=+g[o+(b<<2)>>2]+ +g[o+(z<<2)>>2];C=+g[p+(z<<2)>>2]-+g[p+(b<<2)>>2];B=M*E-C*I;A=C*J-M*I;M=E*J-I*I;I=(A*K+B)/M-f;b=e+(L<<2)|0;if(I<+g[b>>2])g[b>>2]=I;L=L+1|0;I=K+1.0;b=D+L|0;if((L|0)==(d|0)){N=B;O=A;P=M;Q=d;R=I;break}else{z=b;F=b-h|0;K=I}}}F=Q+D|0;if((F|0)<(a|0)){z=a-D|0;d=F;F=Q;K=R;while(1){L=d-h|0;I=+g[l+(d<<2)>>2]-+g[l+(L<<2)>>2];M=+g[m+(d<<2)>>2]-+g[m+(L<<2)>>2];A=+g[n+(d<<2)>>2]-+g[n+(L<<2)>>2];B=+g[o+(d<<2)>>2]-+g[o+(L<<2)>>2];J=+g[p+(d<<2)>>2]-+g[p+(L<<2)>>2];E=B*A-J*M;C=J*I-B*M;B=A*I-M*M;M=(C*K+E)/B-f;L=e+(F<<2)|0;if(M<+g[L>>2])g[L>>2]=M;L=F+1|0;M=K+1.0;if((L|0)==(z|0)){S=E;T=C;U=B;V=z;W=M;break}else{d=L+D|0;F=L;K=M}}}else{S=N;T=O;U=P;V=Q;W=R}if((V|0)<(a|0)){X=V;Y=W}else{i=j;return}while(1){W=(Y*T+S)/U-f;V=e+(X<<2)|0;if(W<+g[V>>2])g[V>>2]=W;X=X+1|0;if((X|0)==(a|0))break;else Y=Y+1.0}i=j;return}function Mc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,h=0,j=0,k=0,l=0,m=0.0,n=0,o=0.0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;e=i;f=d<<2;h=i;i=i+((1*f|0)+15&-16)|0;j=i;i=i+((1*f|0)+15&-16)|0;if((d|0)>0){k=0;l=0}else{i=e;return}while(1){do if((l|0)>=2){m=+g[a+(k<<2)>>2];f=l;while(1){n=f+-1|0;o=+g[j+(n<<2)>>2];if(m<o){p=f;q=8;break}if(!((f|0)>1?(k|0)<((c[h+(n<<2)>>2]|0)+b|0):0)){r=f;q=12;break}s=f+-2|0;if(!(o<=+g[j+(s<<2)>>2])){r=f;q=12;break}if((k|0)<((c[h+(s<<2)>>2]|0)+b|0))f=n;else{r=f;q=12;break}}if((q|0)==8){q=0;c[h+(p<<2)>>2]=k;g[j+(p<<2)>>2]=m;t=p;break}else if((q|0)==12){q=0;c[h+(r<<2)>>2]=k;g[j+(r<<2)>>2]=m;t=r;break}}else{c[h+(l<<2)>>2]=k;c[j+(l<<2)>>2]=c[a+(k<<2)>>2];t=l}while(0);f=t+1|0;k=k+1|0;if((k|0)==(d|0)){u=t;v=f;break}else l=f}if((u|0)<=-1){i=e;return}l=b+1|0;b=0;t=0;while(1){if((b|0)<(u|0)?(k=b+1|0,+g[j+(k<<2)>>2]>+g[j+(b<<2)>>2]):0)w=c[h+(k<<2)>>2]|0;else w=l+(c[h+(b<<2)>>2]|0)|0;if((t|0)<(((w|0)>(d|0)?d:w)|0)){k=c[j+(b<<2)>>2]|0;r=(w|0)<(d|0)?w:d;q=t;do{c[a+(q<<2)>>2]=k;q=q+1|0}while((q|0)!=(r|0));x=r}else x=t;b=b+1|0;if((b|0)==(v|0))break;else t=x}i=e;return}function Nc(a,b,d,e,f,j,l,m,n){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;j=j|0;l=l|0;m=m|0;n=n|0;var o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0.0,w=0,x=0.0,y=0.0,z=0,A=0.0,B=0.0,C=0,D=0.0,E=0,F=0.0,G=0,H=0.0;o=i;p=i;i=i+((1*(m<<2)|0)+15&-16)|0;if(!(c[a+500>>2]|0))q=m;else q=(c[a+504>>2]|0)-l|0;if((((q|0)>(m|0)?m:q)|0)>0){r=(j|0)==0;s=(q|0)<(m|0)?q:m;q=0;do{if(!(!r?(c[j+(q<<2)>>2]|0)!=0:0))t=9;do if((t|0)==9){t=0;u=+g[d+(q<<2)>>2]<0.0;v=+td(+O(+(+g[e+(q<<2)>>2]/+g[f+(q<<2)>>2])));if(u){c[n+(q<<2)>>2]=~~-v;break}else{c[n+(q<<2)>>2]=~~v;break}}while(0);q=q+1|0}while((q|0)!=(s|0));w=s}else w=0;if((w|0)>=(m|0)){x=0.0;i=o;return +x}s=(j|0)!=0;q=b-l|0;v=0.0;l=0;b=w;while(1){if(s?(c[j+(b<<2)>>2]|0)!=0:0){y=v;z=l}else t=15;do if((t|0)==15){t=0;w=e+(b<<2)|0;r=f+(b<<2)|0;A=+g[w>>2]/+g[r>>2];if(!(A<.25)|s&(b|0)<(q|0)){u=+g[d+(b<<2)>>2]<0.0;B=+td(+O(+A));C=~~(u?-B:B);c[n+(b<<2)>>2]=C;B=+(_(C,C)|0);g[w>>2]=B*+g[r>>2];y=v;z=l;break}else{c[p+(l<<2)>>2]=w;y=A+v;z=l+1|0;break}}while(0);b=b+1|0;if((b|0)==(m|0)){D=y;E=z;break}else{v=y;l=z}}if(!E){x=D;i=o;return +x}rd(p,E,4,12);if((E|0)<=0){x=D;i=o;return +x}z=e;y=+h[a+512>>3];v=D;a=0;while(1){e=c[p+(a<<2)>>2]|0;l=e-z>>2;if(!(v>=y)){F=v;G=0;H=0.0}else{F=v+-1.0;G=~~(c[k>>2]=c[d+(l<<2)>>2]&-2147483648|1065353216,+g[k>>2]);H=+g[f+(l<<2)>>2]}c[n+(l<<2)>>2]=G;g[e>>2]=H;a=a+1|0;if((a|0)==(E|0)){x=F;break}else v=F}i=o;return +x}function Oc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var h=0,i=0,j=0.0,k=0.0,l=0.0,m=0.0,n=0.0,o=0.0,p=0,q=0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0,w=0.0,x=0.0,y=0.0,z=0.0,A=0.0,B=0.0,C=0.0,D=0.0,E=0.0,F=0.0,G=0.0,H=0.0,I=0.0,J=0.0,K=0.0,L=0.0,M=0,N=0,O=0,P=0,Q=0,R=0;h=c[a>>2]|0;i=c[a+((b+-1|0)*56|0)+4>>2]|0;if((b|0)>0){j=+g[f+1108>>2];k=0.0;f=0;l=0.0;m=0.0;n=0.0;o=0.0;while(1){p=c[a+(f*56|0)+52>>2]|0;q=c[a+(f*56|0)+28>>2]|0;r=+(q+p|0)*j/+(q+1|0)+1.0;s=+(c[a+(f*56|0)+32>>2]|0)+m+ +(c[a+(f*56|0)+8>>2]|0)*r;t=+(c[a+(f*56|0)+36>>2]|0)+o+ +(c[a+(f*56|0)+12>>2]|0)*r;u=+(c[a+(f*56|0)+40>>2]|0)+l+ +(c[a+(f*56|0)+16>>2]|0)*r;v=+(c[a+(f*56|0)+48>>2]|0)+n+ +(c[a+(f*56|0)+24>>2]|0)*r;w=+(p|0)+k+r*+(q|0);f=f+1|0;if((f|0)==(b|0)){x=w;y=u;z=s;A=v;B=t;break}else{k=w;l=u;m=s;n=v;o=t}}}else{x=0.0;y=0.0;z=0.0;A=0.0;B=0.0}b=c[d>>2]|0;if((b|0)>-1){C=x+1.0;D=y+ +(_(h,h)|0);E=z+ +(h|0);F=+(_(b,h)|0)+A;G=+(b|0)+B}else{C=x;D=y;E=z;F=A;G=B}b=c[e>>2]|0;if((b|0)>-1){H=C+1.0;I=D+ +(_(i,i)|0);J=E+ +(i|0);K=+(_(b,i)|0)+F;L=+(b|0)+G}else{H=C;I=D;J=E;K=F;L=G}G=I*H-J*J;if(!(G>0.0)){c[d>>2]=0;c[e>>2]=0;M=1;return M|0}F=(L*I-J*K)/G;I=(K*H-J*L)/G;c[d>>2]=~~+td(I*+(h|0)+F);h=~~+td(I*+(i|0)+F);c[e>>2]=h;i=c[d>>2]|0;if((i|0)>1023){c[d>>2]=1023;N=c[e>>2]|0;O=1023}else{N=h;O=i}if((N|0)>1023){c[e>>2]=1023;P=c[d>>2]|0;Q=1023}else{P=O;Q=N}if((P|0)<0){c[d>>2]=0;R=c[e>>2]|0}else R=Q;if((R|0)>=0){M=0;return M|0}c[e>>2]=0;M=0;return M|0}function Pc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0;g=i;h=c[b>>2]|0;j=c[h+8>>2]|0;k=b+16|0;l=c[c[k>>2]>>2]|0;m=c[a+36>>2]>>1;n=c[h+4>>2]|0;o=((n|0)<(m|0)?n:m)-(c[h>>2]|0)|0;if((o|0)<=0){i=g;return}m=(o|0)/(j|0)|0;o=i;i=i+((1*(e<<2)|0)+15&-16)|0;n=(e|0)>0;if(n){p=((l+-1+m|0)/(l|0)|0)<<2;q=0;do{c[o+(q<<2)>>2]=Ab(a,p)|0;q=q+1|0}while((q|0)!=(e|0))}q=b+8|0;if((c[q>>2]|0)<=0){i=g;return}p=(m|0)>0;r=a+4|0;a=h+16|0;s=b+28|0;t=(l|0)>0;u=b+20|0;b=n^1;v=0;a:while(1){if(p){w=1<<v;x=(v|0)!=0|b;y=0;z=0;while(1){if(!x){A=0;do{B=pc(c[k>>2]|0,r)|0;if((B|0)==-1){C=25;break a}if((B|0)>=(c[a>>2]|0)){C=25;break a}D=c[(c[s>>2]|0)+(B<<2)>>2]|0;c[(c[o+(A<<2)>>2]|0)+(z<<2)>>2]=D;A=A+1|0;if(!D){C=25;break a}}while((A|0)<(e|0))}b:do if(t&(y|0)<(m|0)){if(n){E=y;F=0}else{A=y;D=0;while(1){D=D+1|0;B=A+1|0;if(!((D|0)<(l|0)&(B|0)<(m|0))){G=B;break b}else A=B}}while(1){A=_(E,j)|0;D=0;do{B=(c[h>>2]|0)+A|0;H=c[(c[(c[o+(D<<2)>>2]|0)+(z<<2)>>2]|0)+(F<<2)>>2]|0;if(((c[h+24+(H<<2)>>2]&w|0)!=0?(I=c[(c[(c[u>>2]|0)+(H<<2)>>2]|0)+(v<<2)>>2]|0,(I|0)!=0):0)?(Va[f&7](I,(c[d+(D<<2)>>2]|0)+(B<<2)|0,r,j)|0)==-1:0){C=25;break a}D=D+1|0}while((D|0)<(e|0));F=F+1|0;D=E+1|0;if(!((F|0)<(l|0)&(D|0)<(m|0))){G=D;break}else E=D}}else G=y;while(0);if((G|0)<(m|0)){y=G;z=z+1|0}else break}}v=v+1|0;if((v|0)>=(c[q>>2]|0)){C=25;break}}if((C|0)==25){i=g;return}}function Qc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0;g=i;i=i+1088|0;h=g+1056|0;j=g+1024|0;k=g+512|0;l=g;m=c[b>>2]|0;n=c[m+8>>2]|0;o=c[m+12>>2]|0;p=b+16|0;q=c[c[p>>2]>>2]|0;r=((c[m+4>>2]|0)-(c[m>>2]|0)|0)/(n|0)|0;Fd(k|0,0,512)|0;Fd(l|0,0,512)|0;s=b+8|0;t=c[s>>2]|0;if((t|0)<=0){i=g;return}u=(r|0)>0;v=(e|0)>0;w=(q|0)>1;x=b+36|0;y=(q|0)>0;z=b+20|0;A=b+32|0;b=0-q|0;B=t;t=0;while(1){if(u){C=(t|0)==0;D=1<<t;E=C&v;F=0;while(1){a:do if(E){if(w)G=0;else{H=0;while(1){I=c[(c[f+(H<<2)>>2]|0)+(F<<2)>>2]|0;J=c[p>>2]|0;if((I|0)<(c[J+4>>2]|0)){K=oc(J,I,a)|0;c[x>>2]=(c[x>>2]|0)+K}H=H+1|0;if((H|0)==(e|0))break a}}do{H=c[f+(G<<2)>>2]|0;K=1;I=c[H+(F<<2)>>2]|0;while(1){J=_(I,o)|0;L=K+F|0;if((L|0)<(r|0))M=(c[H+(L<<2)>>2]|0)+J|0;else M=J;K=K+1|0;if((K|0)==(q|0)){N=M;break}else I=M}I=c[p>>2]|0;if((N|0)<(c[I+4>>2]|0)){K=oc(I,N,a)|0;c[x>>2]=(c[x>>2]|0)+K}G=G+1|0}while((G|0)!=(e|0))}while(0);if(y&(F|0)<(r|0)){K=F-r|0;I=K>>>0<b>>>0?b:K;K=0-I|0;H=F;J=0;while(1){L=_(H,n)|0;O=(c[m>>2]|0)+L|0;if(v){L=0;do{P=f+(L<<2)|0;Q=c[P>>2]|0;R=c[Q+(H<<2)>>2]|0;if(C){S=l+(R<<2)|0;c[S>>2]=(c[S>>2]|0)+n}if((c[m+24+(R<<2)>>2]&D|0)!=0?(S=c[(c[(c[z>>2]|0)+(R<<2)>>2]|0)+(t<<2)>>2]|0,(S|0)!=0):0){R=c[d+(L<<2)>>2]|0;T=c[S>>2]|0;U=(n|0)/(T|0)|0;if((U|0)>0){V=S+48|0;W=S+52|0;X=S+44|0;Y=S+12|0;Z=S+4|0;$=T;aa=0;ba=0;while(1){ca=(_(ba,T)|0)+O|0;da=R+(ca<<2)|0;ea=c[V>>2]|0;fa=c[W>>2]|0;ga=c[X>>2]|0;ha=ga>>1;c[h>>2]=0;c[h+4>>2]=0;c[h+8>>2]=0;c[h+12>>2]=0;c[h+16>>2]=0;c[h+20>>2]=0;c[h+24>>2]=0;c[h+28>>2]=0;ia=($|0)>0;do if((fa|0)==1){if(!ia){ja=0;break}ka=ga+-1|0;la=0;ma=0;na=$;while(1){na=na+-1|0;oa=c[R+(ca+na<<2)>>2]|0;pa=oa-ea|0;if((pa|0)<(ha|0))qa=(ha-pa<<1)+-1|0;else qa=pa-ha<<1;pa=_(ma,ga)|0;ra=((qa|0)<0?0:(qa|0)>=(ga|0)?ka:qa)+pa|0;c[h+(na<<2)>>2]=oa;la=la+1|0;if((la|0)==($|0)){ja=ra;break}else ma=ra}}else{if(!ia){ja=0;break}ma=(fa>>1)-ea|0;la=ga+-1|0;na=0;ka=0;ra=$;while(1){ra=ra+-1|0;oa=(ma+(c[R+(ca+ra<<2)>>2]|0)|0)/(fa|0)|0;if((oa|0)<(ha|0))sa=(ha-oa<<1)+-1|0;else sa=oa-ha<<1;pa=_(ka,ga)|0;ta=((sa|0)<0?0:(sa|0)>=(ga|0)?la:sa)+pa|0;c[h+(ra<<2)>>2]=(_(oa,fa)|0)+ea;na=na+1|0;if((na|0)==($|0)){ja=ta;break}else ka=ta}}while(0);ha=c[(c[Y>>2]|0)+8>>2]|0;do if((c[ha+(ja<<2)>>2]|0)<1){c[j>>2]=0;c[j+4>>2]=0;c[j+8>>2]=0;c[j+12>>2]=0;c[j+16>>2]=0;c[j+20>>2]=0;c[j+24>>2]=0;c[j+28>>2]=0;ka=(_(ga+-1|0,fa)|0)+ea|0;na=c[Z>>2]|0;if((na|0)>0){ua=-1;va=0;wa=ja}else{xa=ja;break}while(1){do if((c[ha+(va<<2)>>2]|0)>0){if(ia){ra=0;la=0;while(1){ma=(c[j+(ra<<2)>>2]|0)-(c[R+(ca+ra<<2)>>2]|0)|0;ta=(_(ma,ma)|0)+la|0;ra=ra+1|0;if((ra|0)==($|0)){ya=ta;break}else la=ta}}else ya=0;if(!((ua|0)==-1|(ya|0)<(ua|0))){za=ua;Aa=wa;break};c[h>>2]=c[j>>2];c[h+4>>2]=c[j+4>>2];c[h+8>>2]=c[j+8>>2];c[h+12>>2]=c[j+12>>2];c[h+16>>2]=c[j+16>>2];c[h+20>>2]=c[j+20>>2];c[h+24>>2]=c[j+24>>2];c[h+28>>2]=c[j+28>>2];za=ya;Aa=va}else{za=ua;Aa=wa}while(0);la=c[j>>2]|0;if((la|0)<(ka|0)){Ba=j;Ca=la}else{la=j;ra=0;while(1){ra=ra+1|0;c[la>>2]=0;ta=j+(ra<<2)|0;ma=c[ta>>2]|0;if((ma|0)<(ka|0)){Ba=ta;Ca=ma;break}else la=ta}}if((Ca|0)>-1){la=Ca+fa|0;c[Ba>>2]=la;Da=la}else Da=Ca;c[Ba>>2]=0-Da;va=va+1|0;if((va|0)==(na|0)){xa=Aa;break}else{ua=za;wa=Aa}}}else xa=ja;while(0);if(ia&(xa|0)>-1){fa=da;ca=0;while(1){c[fa>>2]=(c[fa>>2]|0)-(c[h+(ca<<2)>>2]|0);ca=ca+1|0;if((ca|0)==($|0))break;else fa=fa+4|0}}fa=(oc(S,xa,a)|0)+aa|0;ca=ba+1|0;if((ca|0)==(U|0)){Ea=fa;break}$=c[S>>2]|0;aa=fa;ba=ca}Fa=c[P>>2]|0;Ga=Ea}else{Fa=Q;Ga=0}c[A>>2]=(c[A>>2]|0)+Ga;ba=k+(c[Fa+(H<<2)>>2]<<2)|0;c[ba>>2]=(c[ba>>2]|0)+Ga}L=L+1|0}while((L|0)!=(e|0))}J=J+1|0;if((J|0)==(K|0))break;else H=H+1|0}Ha=F-I|0}else Ha=F;if((Ha|0)<(r|0))F=Ha;else break}Ia=c[s>>2]|0}else Ia=B;t=t+1|0;if((t|0)>=(Ia|0))break;else B=Ia}i=g;return}function Rc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;e=c[b+40>>2]|0;f=ob(d,c[b+36>>2]|0)|0;do if((f|0)>-1){g=c[(c[b+32>>2]|0)+(f<<2)>>2]|0;if((g|0)<0){h=(c[b+8>>2]|0)-(g&32767)|0;i=g>>>15&32767;break}j=g+-1|0;pb(d,a[(c[b+28>>2]|0)+j>>0]|0);k=j;return k|0}else{h=c[b+8>>2]|0;i=0}while(0);f=ob(d,e)|0;j=(f|0)<0;if(j&(e|0)>1){g=e;while(1){l=g+-1|0;m=ob(d,l)|0;n=(m|0)<0;if(n&(l|0)>1)g=l;else{o=n;p=m;q=l;break}}}else{o=j;p=f;q=e}if(o){k=-1;return k|0}o=p>>>16|p<<16;p=o>>>8&16711935|o<<8&-16711936;o=p>>>4&252645135|p<<4&-252645136;p=o>>>2&858993459|o<<2&-858993460;o=p>>>1&1431655765|p<<1&-1431655766;p=h-i|0;if((p|0)>1){e=c[b+20>>2]|0;f=p;p=h;h=i;while(1){j=f>>1;g=(c[e+(j+h<<2)>>2]|0)>>>0>o>>>0;l=(g?0:j)+h|0;p=p-(g?j:0)|0;f=p-l|0;if((f|0)<=1){r=l;break}else h=l}}else r=i;i=a[(c[b+28>>2]|0)+r>>0]|0;if((i|0)>(q|0)){pb(d,q);k=-1;return k|0}else{pb(d,i);k=r;return k|0}return 0}function Sc(a,b){a=a|0;b=b|0;var d=0;d=c[c[a>>2]>>2]|0;a=c[c[b>>2]>>2]|0;return (d>>>0>a>>>0&1)-(d>>>0<a>>>0&1)|0}function Tc(a,b){a=a|0;b=b|0;var d=0.0,e=0.0;d=+g[c[a>>2]>>2];e=+g[c[b>>2]>>2];return (d<e&1)-(d>e&1)|0}function Uc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;d=a+836|0;e=c[a+840>>2]|0;lb(b,c[a>>2]|0,5);if((c[a>>2]|0)>0){f=a+4|0;g=0;h=-1;while(1){i=f+(g<<2)|0;lb(b,c[i>>2]|0,4);j=c[i>>2]|0;i=(h|0)<(j|0)?j:h;g=g+1|0;if((g|0)>=(c[a>>2]|0)){k=i;break}else h=i}if((k|0)>-1){h=a+128|0;g=a+192|0;f=a+256|0;i=a+320|0;j=0;while(1){lb(b,(c[h+(j<<2)>>2]|0)+-1|0,3);l=g+(j<<2)|0;lb(b,c[l>>2]|0,2);if(!((c[l>>2]|0)!=0?(lb(b,c[f+(j<<2)>>2]|0,8),(c[l>>2]|0)==31):0)){m=0;n=8}if((n|0)==8)while(1){n=0;lb(b,(c[i+(j<<5)+(m<<2)>>2]|0)+1|0,8);m=m+1|0;if((m|0)>=(1<<c[l>>2]|0))break;else n=8}if((j|0)==(k|0))break;else j=j+1|0}}}lb(b,(c[a+832>>2]|0)+-1|0,2);j=e+-1|0;if((e|0)==0|(j|0)==0){lb(b,0,4);o=0}else{e=j;k=0;while(1){n=k+1|0;e=e>>>1;if(!e){p=n;break}else k=n}lb(b,p,4);p=j;j=0;while(1){k=j+1|0;p=p>>>1;if(!p){o=k;break}else j=k}}j=c[a>>2]|0;if((j|0)<=0)return;p=a+4|0;k=a+128|0;e=j;j=0;n=0;m=0;while(1){j=(c[k+(c[p+(n<<2)>>2]<<2)>>2]|0)+j|0;if((m|0)<(j|0)){i=m;do{lb(b,c[d+(i+2<<2)>>2]|0,o);i=i+1|0}while((i|0)!=(j|0));q=c[a>>2]|0;r=j}else{q=e;r=m}n=n+1|0;if((n|0)>=(q|0))break;else{e=q;m=r}}return}function Vc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;d=i;i=i+272|0;e=d;f=c[a+28>>2]|0;a=zd(1,1120)|0;g=qb(b,5)|0;c[a>>2]=g;a:do if((g|0)>0){h=a+4|0;j=0;k=-1;while(1){l=qb(b,4)|0;c[h+(j<<2)>>2]=l;if((l|0)<0)break a;m=(k|0)<(l|0)?l:k;j=j+1|0;if((j|0)>=(c[a>>2]|0)){n=m;break}else k=m}if((n|0)>-1){k=a+128|0;j=a+192|0;h=a+256|0;m=f+24|0;l=a+320|0;o=0;while(1){c[k+(o<<2)>>2]=(qb(b,3)|0)+1;p=qb(b,2)|0;q=j+(o<<2)|0;c[q>>2]=p;if((p|0)<0)break a;if(!p)r=c[h+(o<<2)>>2]|0;else{p=qb(b,8)|0;c[h+(o<<2)>>2]=p;r=p}if((r|0)<0)break a;if((r|0)>=(c[m>>2]|0))break a;if((c[q>>2]|0)!=31){p=0;do{s=qb(b,8)|0;c[l+(o<<5)+(p<<2)>>2]=s+-1;if((s|0)<0)break a;p=p+1|0;if((s|0)>(c[m>>2]|0))break a}while((p|0)<(1<<c[q>>2]|0))}if((o|0)<(n|0))o=o+1|0;else{t=18;break}}}else t=18}else t=18;while(0);b:do if((t|0)==18?(c[a+832>>2]=(qb(b,2)|0)+1,n=qb(b,4)|0,(n|0)>=0):0){r=c[a>>2]|0;if((r|0)>0){f=a+4|0;g=a+128|0;o=a+836|0;m=1<<n;l=r;r=0;h=0;j=0;while(1){k=(c[g+(c[f+(h<<2)>>2]<<2)>>2]|0)+r|0;if((k|0)>63)break b;if((j|0)<(k|0)){q=j;while(1){p=qb(b,n)|0;c[o+(q+2<<2)>>2]=p;if(!((p|0)>-1&(p|0)<(m|0)))break b;p=q+1|0;if((p|0)<(k|0))q=p;else{u=p;break}}v=c[a>>2]|0;w=u}else{v=l;w=j}h=h+1|0;if((h|0)>=(v|0)){x=o;y=m;z=k;break}else{l=v;r=k;j=w}}}else{x=a+836|0;y=1<<n;z=0}c[x>>2]=0;c[a+840>>2]=y;j=z+2|0;if((z|0)>-2){r=0;do{c[e+(r<<2)>>2]=x+(r<<2);r=r+1|0}while((r|0)<(j|0))}rd(e,j,4,13);c:do if((j|0)>1){r=c[c[e>>2]>>2]|0;n=1;while(1){l=r;r=c[c[e+(n<<2)>>2]>>2]|0;n=n+1|0;if((l|0)==(r|0))break;if((n|0)>=(j|0))break c}if(!a)A=0;else break b;i=d;return A|0}while(0);A=a;i=d;return A|0}while(0);yd(a);A=0;i=d;return A|0}function Wc(a,b){a=a|0;b=b|0;return (c[c[a>>2]>>2]|0)-(c[c[b>>2]>>2]|0)|0}function Xc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;a=i;i=i+272|0;d=a;e=zd(1,1312)|0;c[e+1296>>2]=b;f=b+836|0;g=e+1288|0;c[g>>2]=c[b+840>>2];h=c[b>>2]|0;if((h|0)>0){j=b+4|0;k=b+128|0;l=0;m=0;while(1){n=(c[k+(c[j+(l<<2)>>2]<<2)>>2]|0)+m|0;l=l+1|0;if((l|0)>=(h|0)){o=n;break}else m=n}m=o+2|0;c[e+1284>>2]=m;if((o|0)>-2){p=m;q=o;r=7}else{rd(d,m,4,13);s=o}}else{c[e+1284>>2]=2;p=2;q=0;r=7}if((r|0)==7){r=0;do{c[d+(r<<2)>>2]=f+(r<<2);r=r+1|0}while((r|0)<(p|0));rd(d,p,4,13);r=f;o=e+260|0;m=0;do{c[o+(m<<2)>>2]=(c[d+(m<<2)>>2]|0)-r>>2;m=m+1|0}while((m|0)<(p|0));m=e+260|0;r=e+520|0;d=0;do{c[r+(c[m+(d<<2)>>2]<<2)>>2]=d;d=d+1|0}while((d|0)<(p|0));d=e+260|0;m=0;do{c[e+(m<<2)>>2]=c[f+(c[d+(m<<2)>>2]<<2)>>2];m=m+1|0}while((m|0)<(p|0));s=q}q=c[b+832>>2]|0;if((q|0)==2)c[e+1292>>2]=128;else if((q|0)==1)c[e+1292>>2]=256;else if((q|0)==3)c[e+1292>>2]=86;else if((q|0)==4)c[e+1292>>2]=64;if((s|0)<=0){i=a;return e|0}q=e+1032|0;b=e+780|0;p=0;do{m=p+2|0;d=c[f+(m<<2)>>2]|0;r=1;o=c[g>>2]|0;h=0;l=0;j=0;while(1){k=c[f+(h<<2)>>2]|0;n=(k|0)>(j|0)&(k|0)<(d|0);t=n?h:l;u=(k|0)<(o|0)&(k|0)>(d|0);v=u?h:r;h=h+1|0;if((h|0)>=(m|0)){w=v;x=t;break}else{r=v;o=u?k:o;l=t;j=n?k:j}}c[q+(p<<2)>>2]=x;c[b+(p<<2)>>2]=w;p=p+1|0}while((p|0)!=(s|0));i=a;return e|0}function Yc(a){a=a|0;if(a)yd(a);return}function Zc(a){a=a|0;if(a)yd(a);return}function _c(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;d=c[b+1296>>2]|0;e=c[(c[(c[(c[a+64>>2]|0)+4>>2]|0)+28>>2]|0)+2848>>2]|0;f=a+4|0;if((qb(f,1)|0)!=1){g=0;return g|0}h=b+1284|0;i=Ab(a,c[h>>2]<<2)|0;a=b+1292|0;j=(c[a>>2]|0)+-1|0;if(!j)k=0;else{l=j;j=0;while(1){m=j+1|0;l=l>>>1;if(!l){k=m;break}else j=m}}c[i>>2]=qb(f,k)|0;k=(c[a>>2]|0)+-1|0;if(!k)n=0;else{j=k;k=0;while(1){l=k+1|0;j=j>>>1;if(!j){n=l;break}else k=l}}c[i+4>>2]=qb(f,n)|0;a:do if((c[d>>2]|0)>0){n=0;k=2;b:while(1){j=c[d+4+(n<<2)>>2]|0;l=c[d+128+(j<<2)>>2]|0;m=c[d+192+(j<<2)>>2]|0;o=1<<m;if(m){p=pc(e+((c[d+256+(j<<2)>>2]|0)*56|0)|0,f)|0;if((p|0)==-1){g=0;q=29;break}else r=p}else r=0;if((l|0)>0){p=o+-1|0;o=r;s=0;do{t=c[d+320+(j<<5)+((o&p)<<2)>>2]|0;o=o>>m;if((t|0)>-1){u=pc(e+(t*56|0)|0,f)|0;c[i+(s+k<<2)>>2]=u;if((u|0)==-1){g=0;q=29;break b}}else c[i+(s+k<<2)>>2]=0;s=s+1|0}while((s|0)<(l|0))}n=n+1|0;if((n|0)>=(c[d>>2]|0))break a;else k=l+k|0}if((q|0)==29)return g|0}while(0);if((c[h>>2]|0)<=2){g=i;return g|0}q=b+1032|0;f=b+780|0;b=2;do{e=b+-2|0;r=q+(e<<2)|0;k=c[r>>2]|0;n=c[d+836+(k<<2)>>2]|0;s=f+(e<<2)|0;e=c[s>>2]|0;m=c[i+(k<<2)>>2]&32767;k=(c[i+(e<<2)>>2]&32767)-m|0;o=(_((k|0)>-1?k:0-k|0,(c[d+836+(b<<2)>>2]|0)-n|0)|0)/((c[d+836+(e<<2)>>2]|0)-n|0)|0;n=((k|0)<0?0-o|0:o)+m|0;m=(c[a>>2]|0)-n|0;o=i+(b<<2)|0;k=c[o>>2]|0;if(!k)c[o>>2]=n|32768;else{do if((k|0)<(((m|0)<(n|0)?m:n)<<1|0))if(!(k&1)){v=k>>1;break}else{v=0-(k+1>>1)|0;break}else if((m|0)>(n|0)){v=k-n|0;break}else{v=~(k-m);break}while(0);c[o>>2]=v+n&32767;m=i+(c[r>>2]<<2)|0;c[m>>2]=c[m>>2]&32767;m=i+(c[s>>2]<<2)|0;c[m>>2]=c[m>>2]&32767}b=b+1|0}while((b|0)<(c[h>>2]|0));g=i;return g|0}function $c(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0.0;f=c[b+1296>>2]|0;h=(c[(c[(c[(c[a+64>>2]|0)+4>>2]|0)+28>>2]|0)+(c[a+28>>2]<<2)>>2]|0)/2|0;if(!d){Fd(e|0,0,h<<2|0)|0;i=0;return i|0}a=c[f+832>>2]|0;j=_(a,c[d>>2]|0)|0;k=(j|0)<0?0:(j|0)>255?255:j;j=c[b+1284>>2]|0;if((j|0)>1){l=b+260|0;b=0;m=1;n=0;o=k;while(1){p=c[l+(m<<2)>>2]|0;q=c[d+(p<<2)>>2]|0;if((q&32767|0)==(q|0)){r=c[f+836+(p<<2)>>2]|0;p=_(a,q)|0;q=(p|0)<0?0:(p|0)>255?255:p;p=q-o|0;s=r-n|0;t=(p|0)/(s|0)|0;u=p>>31|1;v=_(t,s)|0;w=((p|0)>-1?p:0-p|0)-((v|0)>-1?v:0-v|0)|0;v=(h|0)>(r|0)?r:h;if((v|0)>(n|0)){p=e+(n<<2)|0;g[p>>2]=+g[p>>2]*+g[56400+(o<<2)>>2]}p=n+1|0;if((p|0)<(v|0)){x=p;p=0;y=o;while(1){z=p+w|0;A=(z|0)<(s|0);y=y+t+(A?0:u)|0;B=e+(x<<2)|0;g[B>>2]=+g[B>>2]*+g[56400+(y<<2)>>2];x=x+1|0;if((x|0)==(v|0)){C=r;D=r;E=q;break}else p=z-(A?0:s)|0}}else{C=r;D=r;E=q}}else{C=b;D=n;E=o}m=m+1|0;if((m|0)>=(j|0)){F=C;G=E;break}else{b=C;n=D;o=E}}}else{F=0;G=k}if((F|0)>=(h|0)){i=1;return i|0}H=+g[56400+(G<<2)>>2];G=F;do{F=e+(G<<2)|0;g[F>>2]=+g[F>>2]*H;G=G+1|0}while((G|0)!=(h|0));i=1;return i|0}function ad(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;d=c[a+28>>2]|0;a=xd(96)|0;e=qb(b,8)|0;c[a>>2]=e;f=qb(b,16)|0;c[a+4>>2]=f;g=qb(b,16)|0;c[a+8>>2]=g;c[a+12>>2]=qb(b,6)|0;c[a+16>>2]=qb(b,8)|0;h=qb(b,4)|0;i=a+20|0;c[i>>2]=h+1;a:do if((e|0)<1){if(!a){j=0;return j|0}}else if((f|0)>=1?!((h|0)<0|(g|0)<1):0){if((h|0)<=-1){j=a;return j|0}k=a+24|0;l=d+24|0;m=0;while(1){n=qb(b,8)|0;c[k+(m<<2)>>2]=n;if((n|0)<0)break a;if((n|0)>=(c[l>>2]|0))break a;o=c[d+1824+(n<<2)>>2]|0;if(!(c[o+12>>2]|0))break a;m=m+1|0;if((c[o>>2]|0)<1)break a;if((m|0)>=(c[i>>2]|0)){j=a;break}}return j|0}while(0);yd(a);j=0;return j|0}function bd(a,b){a=a|0;b=b|0;a=zd(1,32)|0;c[a+4>>2]=c[b>>2];c[a>>2]=c[b+8>>2];c[a+20>>2]=b;c[a+8>>2]=zd(2,4)|0;return a|0}function cd(a){a=a|0;if(a)yd(a);return}function dd(a){a=a|0;var b=0,d=0,e=0,f=0,g=0;if(!a)return;b=a+8|0;d=c[b>>2]|0;if(d){e=c[d>>2]|0;if(!e)f=d;else{yd(e);f=c[b>>2]|0}e=c[f+4>>2]|0;if(!e)g=f;else{yd(e);g=c[b>>2]|0}yd(g)}yd(a);return}function ed(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,i=0,j=0.0,k=0.0,l=0,m=0,n=0;d=c[b+20>>2]|0;e=a+4|0;f=d+12|0;h=qb(e,c[f>>2]|0)|0;if((h|0)<=0){i=0;return i|0}j=+(c[d+16>>2]|0)*(+(h|0)/+((1<<c[f>>2])+-1|0));f=d+20|0;h=qb(e,uc(c[f>>2]|0)|0)|0;if((h|0)==-1){i=0;return i|0}if((h|0)>=(c[f>>2]|0)){i=0;return i|0}f=(c[(c[(c[(c[a+64>>2]|0)+4>>2]|0)+28>>2]|0)+2848>>2]|0)+((c[d+24+(h<<2)>>2]|0)*56|0)|0;h=b+4|0;b=Ab(a,((c[f>>2]|0)+(c[h>>2]|0)<<2)+4|0)|0;if((sc(f,b,e,c[h>>2]|0)|0)==-1){i=0;return i|0}e=c[h>>2]|0;if((e|0)>0){h=0;k=0.0;while(1){a:do if((h|0)<(e|0)){a=c[f>>2]|0;d=h;l=0;while(1){if((l|0)>=(a|0)){m=d;break a}n=b+(d<<2)|0;g[n>>2]=+g[n>>2]+k;n=d+1|0;if((n|0)<(e|0)){d=n;l=l+1|0}else{m=n;break}}}else m=h;while(0);if((m|0)<(e|0)){h=m;k=+g[b+(m+-1<<2)>>2]}else break}}g[b+(e<<2)>>2]=j;i=b;return i|0}function fd(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,h=0,i=0,j=0,k=0,l=0,m=0.0,n=0.0,o=0.0,p=0,q=0,r=0,s=0;f=c[b+20>>2]|0;h=c[a+28>>2]|0;i=b+8|0;j=(c[i>>2]|0)+(h<<2)|0;if(!(c[j>>2]|0)){k=c[(c[(c[(c[a+64>>2]|0)+4>>2]|0)+28>>2]|0)+(h<<2)>>2]|0;a=(k|0)/2|0;l=c[b>>2]|0;m=+(c[f+4>>2]|0);c[j>>2]=xd((a<<2)+4|0)|0;if((k|0)>1){n=m*.5/+(a|0);o=+(l|0)/(+V(+(m*m*4.624999938585006e-09))*2.240000009536743+m*4.999999873689376e-05+ +V(+(m*3.699999942909926e-04))*13.100000381469727);k=c[(c[i>>2]|0)+(h<<2)>>2]|0;j=l;l=0;while(1){m=+(l|0)*n;p=~~+M(+((+V(+(m*m*1.8499999754340024e-08))*2.240000009536743+ +V(+(m*7.399999885819852e-04))*13.100000381469727+m*9.999999747378752e-05)*o));c[k+(l<<2)>>2]=(p|0)<(j|0)?p:j+-1|0;p=l+1|0;if((p|0)>=(a|0))break;j=c[b>>2]|0;l=p}q=k;r=(a|0)>1?a:1}else{q=c[(c[i>>2]|0)+(h<<2)>>2]|0;r=0}c[q+(r<<2)>>2]=-1;c[b+12+(h<<2)>>2]=a}if(!d){Fd(e|0,0,c[b+12+(h<<2)>>2]<<2|0)|0;s=0;return s|0}else{a=c[b+4>>2]|0;Lb(e,c[(c[i>>2]|0)+(h<<2)>>2]|0,c[b+12+(h<<2)>>2]|0,c[b>>2]|0,d,a,+g[d+(a<<2)>>2],+(c[f+16>>2]|0));s=1;return s|0}return 0}
+function gd(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;if((c[b>>2]|0)>1){lb(d,1,1);lb(d,(c[b>>2]|0)+-1|0,4)}else lb(d,0,1);e=b+1156|0;if((c[e>>2]|0)>0){lb(d,1,1);lb(d,(c[e>>2]|0)+-1|0,8);if((c[e>>2]|0)>0){f=b+1160|0;g=a+4|0;h=b+2184|0;i=0;do{j=c[f+(i<<2)>>2]|0;k=c[g>>2]|0;l=k+-1|0;if((k|0)==0|(l|0)==0)m=0;else{k=l;l=0;while(1){n=l+1|0;k=k>>>1;if(!k){m=n;break}else l=n}}lb(d,j,m);l=c[h+(i<<2)>>2]|0;k=c[g>>2]|0;n=k+-1|0;if((k|0)==0|(n|0)==0)o=0;else{k=n;n=0;while(1){p=n+1|0;k=k>>>1;if(!k){o=p;break}else n=p}}lb(d,l,o);i=i+1|0}while((i|0)<(c[e>>2]|0))}}else lb(d,0,1);lb(d,0,2);e=c[b>>2]|0;if((e|0)>1){i=a+4|0;if((c[i>>2]|0)>0){a=b+4|0;o=0;do{lb(d,c[a+(o<<2)>>2]|0,4);o=o+1|0}while((o|0)<(c[i>>2]|0));q=c[b>>2]|0;r=17}}else{q=e;r=17}if((r|0)==17?(q|0)<=0:0)return;q=b+1028|0;r=b+1092|0;e=0;do{lb(d,0,8);lb(d,c[q+(e<<2)>>2]|0,8);lb(d,c[r+(e<<2)>>2]|0,8);e=e+1|0}while((e|0)<(c[b>>2]|0));return}function hd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;d=zd(1,3208)|0;e=c[a+28>>2]|0;Fd(d|0,0,3208)|0;f=qb(b,1)|0;a:do if((f|0)<0){if(!d){g=0;return g|0}}else{if(f){h=qb(b,4)|0;c[d>>2]=h+1;if((h|0)<0)break}else c[d>>2]=1;h=qb(b,1)|0;if((h|0)>=0){if(h){h=qb(b,8)|0;i=d+1156|0;c[i>>2]=h+1;if((h|0)<0)break;h=a+4|0;j=d+1160|0;k=d+2184|0;l=c[h>>2]|0;m=0;do{n=l+-1|0;if((l|0)==0|(n|0)==0)o=0;else{p=n;n=0;while(1){q=n+1|0;p=p>>>1;if(!p){o=q;break}else n=q}}n=qb(b,o)|0;c[j+(m<<2)>>2]=n;p=c[h>>2]|0;q=p+-1|0;if((p|0)==0|(q|0)==0)r=0;else{p=q;q=0;while(1){s=q+1|0;p=p>>>1;if(!p){r=s;break}else q=s}}q=qb(b,r)|0;c[k+(m<<2)>>2]=q;if((n|0)==(q|0)|(q|n|0)<0)break a;l=c[h>>2]|0;m=m+1|0;if(!((n|0)<(l|0)&(q|0)<(l|0)))break a}while((m|0)<(c[i>>2]|0))}if(!(qb(b,2)|0)){i=c[d>>2]|0;if((i|0)>1){m=a+4|0;if((c[m>>2]|0)>0){l=d+4|0;h=0;while(1){k=qb(b,4)|0;c[l+(h<<2)>>2]=k;j=c[d>>2]|0;h=h+1|0;if((k|0)<0|(k|0)>=(j|0))break a;if((h|0)>=(c[m>>2]|0)){t=j;u=20;break}}}}else{t=i;u=20}if((u|0)==20?(t|0)<=0:0){g=d;return g|0}m=d+1028|0;h=e+16|0;l=d+1092|0;j=e+20|0;k=0;while(1){qb(b,8)|0;q=qb(b,8)|0;c[m+(k<<2)>>2]=q;if((q|0)<0?1:(q|0)>=(c[h>>2]|0))break a;q=qb(b,8)|0;c[l+(k<<2)>>2]=q;k=k+1|0;if((q|0)<0?1:(q|0)>=(c[j>>2]|0))break a;if((k|0)>=(c[d>>2]|0)){g=d;break}}return g|0}}}while(0);yd(d);g=0;return g|0}function id(a){a=a|0;if(a)yd(a);return}function jd(a){a=a|0;var b=0,d=0,e=0,f=0,h=0,j=0,l=0,m=0,n=0,o=0,p=0,q=0.0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0.0,A=0,B=0,C=0,D=0.0,E=0,F=0,G=0.0,H=0,I=0,J=0,K=0.0,L=0.0,M=0,N=0.0,O=0,P=0.0,Q=0.0,R=0.0,S=0.0,T=0.0,U=0,V=0,W=0.0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0;b=i;d=c[a+64>>2]|0;e=c[d+4>>2]|0;f=c[e+28>>2]|0;h=c[d+104>>2]|0;d=c[a+104>>2]|0;j=c[a+36>>2]|0;l=e+4|0;e=c[l>>2]<<2;m=i;i=i+((1*e|0)+15&-16)|0;n=Ab(a,e)|0;e=Ab(a,c[l>>2]<<2)|0;o=Ab(a,c[l>>2]<<2)|0;p=d+4|0;q=+g[p>>2];r=c[l>>2]|0;s=i;i=i+((1*(r<<2)|0)+15&-16)|0;t=a+28|0;u=c[t>>2]|0;v=c[f+544+(u<<2)>>2]|0;w=(c[h+56>>2]|0)+((((u|0)!=0?2:0)+(c[d+8>>2]|0)|0)*52|0)|0;x=a+40|0;c[x>>2]=u;if((r|0)>0){r=(j|0)/2|0;y=r<<2;z=+(((g[k>>2]=4.0/+(j|0),c[k>>2]|0)&2147483647)>>>0)*7.177114298428933e-07+-764.6162109375+.345;A=h+4|0;B=a+24|0;C=a+32|0;D=z+-764.6162109375;E=j+-1|0;F=(E|0)>1;G=z+-382.30810546875;z=q;H=0;while(1){I=c[(c[a>>2]|0)+(H<<2)>>2]|0;c[e+(H<<2)>>2]=Ab(a,y)|0;J=n+(H<<2)|0;c[J>>2]=Ab(a,y)|0;Kb(I,A,f,c[B>>2]|0,c[t>>2]|0,c[C>>2]|0);vb(c[c[h+12+(c[t>>2]<<2)>>2]>>2]|0,I,c[J>>2]|0);wb(h+20+((c[t>>2]|0)*12|0)|0,I);K=D+ +((c[I>>2]&2147483647)>>>0)*7.177114298428933e-07+.345;g[I>>2]=K;J=s+(H<<2)|0;g[J>>2]=K;if(F){L=K;M=1;while(1){N=+g[I+(M<<2)>>2];O=M+1|0;P=+g[I+(O<<2)>>2];Q=G+ +(((g[k>>2]=P*P+N*N,c[k>>2]|0)&2147483647)>>>0)*3.5885571492144663e-07+.345;g[I+(O>>1<<2)>>2]=Q;if(Q>L){g[J>>2]=Q;R=Q}else R=L;M=M+2|0;if((M|0)>=(E|0)){S=R;break}else L=R}}else S=K;if(S>0.0){g[J>>2]=0.0;T=0.0}else T=S;L=T>z?T:z;H=H+1|0;if((H|0)>=(c[l>>2]|0)){U=y;V=r;W=L;break}else z=L}}else{r=(j|0)/2|0;U=r<<2;V=r;W=q}r=Ab(a,U)|0;y=Ab(a,U)|0;U=c[l>>2]|0;a:do if((U|0)>0){H=h+48|0;if((j|0)>1)X=0;else{E=0;while(1){F=c[v+4+(E<<2)>>2]|0;C=c[n+(E<<2)>>2]|0;B=c[(c[a>>2]|0)+(E<<2)>>2]|0;A=B+(V<<2)|0;c[x>>2]=u;M=Ab(a,60)|0;I=o+(E<<2)|0;c[I>>2]=M;Y=M;Z=Y+60|0;do{c[Y>>2]=0;Y=Y+4|0}while((Y|0)<(Z|0));Rb(w,A,r);Sb(w,B,y,W,+g[s+(E<<2)>>2]);Tb(w,r,y,1,B,C,A);M=v+1028+(F<<2)|0;O=c[M>>2]|0;if((c[f+800+(O<<2)>>2]|0)!=1){_=-1;break}$=_b(a,c[(c[H>>2]|0)+(O<<2)>>2]|0,A,B)|0;c[(c[I>>2]|0)+28>>2]=$;if((Dc(a)|0)!=0?(c[(c[I>>2]|0)+28>>2]|0)!=0:0){Tb(w,r,y,2,B,C,A);$=_b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,A,B)|0;c[(c[I>>2]|0)+56>>2]=$;Tb(w,r,y,0,B,C,A);$=_b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,A,B)|0;c[c[I>>2]>>2]=$;$=c[I>>2]|0;O=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[$>>2]|0,c[$+28>>2]|0,9362)|0;c[(c[I>>2]|0)+4>>2]=O;O=c[I>>2]|0;$=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[O>>2]|0,c[O+28>>2]|0,18724)|0;c[(c[I>>2]|0)+8>>2]=$;$=c[I>>2]|0;O=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[$>>2]|0,c[$+28>>2]|0,28086)|0;c[(c[I>>2]|0)+12>>2]=O;O=c[I>>2]|0;$=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[O>>2]|0,c[O+28>>2]|0,37449)|0;c[(c[I>>2]|0)+16>>2]=$;$=c[I>>2]|0;O=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[$>>2]|0,c[$+28>>2]|0,46811)|0;c[(c[I>>2]|0)+20>>2]=O;O=c[I>>2]|0;$=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[O>>2]|0,c[O+28>>2]|0,56173)|0;c[(c[I>>2]|0)+24>>2]=$;$=c[I>>2]|0;O=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[$+28>>2]|0,c[$+56>>2]|0,9362)|0;c[(c[I>>2]|0)+32>>2]=O;O=c[I>>2]|0;$=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[O+28>>2]|0,c[O+56>>2]|0,18724)|0;c[(c[I>>2]|0)+36>>2]=$;$=c[I>>2]|0;O=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[$+28>>2]|0,c[$+56>>2]|0,28086)|0;c[(c[I>>2]|0)+40>>2]=O;O=c[I>>2]|0;$=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[O+28>>2]|0,c[O+56>>2]|0,37449)|0;c[(c[I>>2]|0)+44>>2]=$;$=c[I>>2]|0;O=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[$+28>>2]|0,c[$+56>>2]|0,46811)|0;c[(c[I>>2]|0)+48>>2]=O;O=c[I>>2]|0;$=$b(a,c[(c[H>>2]|0)+(c[M>>2]<<2)>>2]|0,c[O+28>>2]|0,c[O+56>>2]|0,56173)|0;c[(c[I>>2]|0)+52>>2]=$}E=E+1|0;$=c[l>>2]|0;if((E|0)>=($|0)){aa=H;ba=$;break a}}i=b;return _|0}while(1){E=c[v+4+(X<<2)>>2]|0;J=c[n+(X<<2)>>2]|0;$=c[(c[a>>2]|0)+(X<<2)>>2]|0;O=$+(V<<2)|0;c[x>>2]=u;M=Ab(a,60)|0;ca=o+(X<<2)|0;c[ca>>2]=M;Y=M;Z=Y+60|0;do{c[Y>>2]=0;Y=Y+4|0}while((Y|0)<(Z|0));I=0;do{g[$+(I+V<<2)>>2]=+((c[J+(I<<2)>>2]&2147483647)>>>0)*7.177114298428933e-07+-764.6162109375+.345;I=I+1|0}while((I|0)<(V|0));Rb(w,O,r);Sb(w,$,y,W,+g[s+(X<<2)>>2]);Tb(w,r,y,1,$,J,O);I=v+1028+(E<<2)|0;B=c[I>>2]|0;if((c[f+800+(B<<2)>>2]|0)!=1){_=-1;break}A=_b(a,c[(c[H>>2]|0)+(B<<2)>>2]|0,O,$)|0;c[(c[ca>>2]|0)+28>>2]=A;if((Dc(a)|0)!=0?(c[(c[ca>>2]|0)+28>>2]|0)!=0:0){Tb(w,r,y,2,$,J,O);A=_b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,O,$)|0;c[(c[ca>>2]|0)+56>>2]=A;Tb(w,r,y,0,$,J,O);A=_b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,O,$)|0;c[c[ca>>2]>>2]=A;A=c[ca>>2]|0;B=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[A>>2]|0,c[A+28>>2]|0,9362)|0;c[(c[ca>>2]|0)+4>>2]=B;B=c[ca>>2]|0;A=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[B>>2]|0,c[B+28>>2]|0,18724)|0;c[(c[ca>>2]|0)+8>>2]=A;A=c[ca>>2]|0;B=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[A>>2]|0,c[A+28>>2]|0,28086)|0;c[(c[ca>>2]|0)+12>>2]=B;B=c[ca>>2]|0;A=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[B>>2]|0,c[B+28>>2]|0,37449)|0;c[(c[ca>>2]|0)+16>>2]=A;A=c[ca>>2]|0;B=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[A>>2]|0,c[A+28>>2]|0,46811)|0;c[(c[ca>>2]|0)+20>>2]=B;B=c[ca>>2]|0;A=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[B>>2]|0,c[B+28>>2]|0,56173)|0;c[(c[ca>>2]|0)+24>>2]=A;A=c[ca>>2]|0;B=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[A+28>>2]|0,c[A+56>>2]|0,9362)|0;c[(c[ca>>2]|0)+32>>2]=B;B=c[ca>>2]|0;A=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[B+28>>2]|0,c[B+56>>2]|0,18724)|0;c[(c[ca>>2]|0)+36>>2]=A;A=c[ca>>2]|0;B=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[A+28>>2]|0,c[A+56>>2]|0,28086)|0;c[(c[ca>>2]|0)+40>>2]=B;B=c[ca>>2]|0;A=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[B+28>>2]|0,c[B+56>>2]|0,37449)|0;c[(c[ca>>2]|0)+44>>2]=A;A=c[ca>>2]|0;B=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[A+28>>2]|0,c[A+56>>2]|0,46811)|0;c[(c[ca>>2]|0)+48>>2]=B;B=c[ca>>2]|0;A=$b(a,c[(c[H>>2]|0)+(c[I>>2]<<2)>>2]|0,c[B+28>>2]|0,c[B+56>>2]|0,56173)|0;c[(c[ca>>2]|0)+52>>2]=A}X=X+1|0;A=c[l>>2]|0;if((X|0)>=(A|0)){aa=H;ba=A;break a}}i=b;return _|0}else{aa=h+48|0;ba=U}while(0);g[p>>2]=W;p=ba<<2;ba=i;i=i+((1*p|0)+15&-16)|0;U=i;i=i+((1*p|0)+15&-16)|0;p=(Dc(a)|0)!=0;X=h+44|0;y=a+24|0;r=a+32|0;s=f+2868|0;V=h+52|0;h=p?0:7;while(1){p=c[d+12+(h<<2)>>2]|0;lb(p,0,1);lb(p,u,c[X>>2]|0);if(c[t>>2]|0){lb(p,c[y>>2]|0,1);lb(p,c[r>>2]|0,1)}Y=c[l>>2]|0;if((Y|0)>0){Z=0;do{c[m+(Z<<2)>>2]=ac(p,a,c[(c[aa>>2]|0)+(c[v+1028+(c[v+4+(Z<<2)>>2]<<2)>>2]<<2)>>2]|0,c[(c[o+(Z<<2)>>2]|0)+(h<<2)>>2]|0,c[e+(Z<<2)>>2]|0)|0;Z=Z+1|0;x=c[l>>2]|0}while((Z|0)<(x|0));da=x}else da=Y;Ub(h,s,w,v,n,e,m,c[f+3240+((c[t>>2]|0)*60|0)+(h<<2)>>2]|0,da);if((c[v>>2]|0)>0){Z=0;do{x=c[v+1092+(Z<<2)>>2]|0;j=c[l>>2]|0;if((j|0)>0){H=j;j=0;A=0;while(1){if((c[v+4+(A<<2)>>2]|0)==(Z|0)){c[U+(j<<2)>>2]=(c[m+(A<<2)>>2]|0)!=0&1;c[ba+(j<<2)>>2]=c[e+(A<<2)>>2];ea=c[l>>2]|0;fa=j+1|0}else{ea=H;fa=j}A=A+1|0;if((A|0)>=(ea|0)){ga=fa;break}else{H=ea;j=fa}}}else ga=0;j=f+1312+(x<<2)|0;H=ab[c[(c[336+(c[j>>2]<<2)>>2]|0)+20>>2]&7](a,c[(c[V>>2]|0)+(x<<2)>>2]|0,ba,U,ga)|0;A=c[l>>2]|0;if((A|0)>0){ca=0;$=0;while(1){if((c[v+4+($<<2)>>2]|0)==(Z|0)){c[ba+(ca<<2)>>2]=c[e+($<<2)>>2];ha=ca+1|0}else ha=ca;$=$+1|0;if(($|0)>=(A|0)){ia=ha;break}else ca=ha}}else ia=0;_a[c[(c[336+(c[j>>2]<<2)>>2]|0)+24>>2]&3](p,a,c[(c[V>>2]|0)+(x<<2)>>2]|0,ba,U,ia,H,Z)|0;Z=Z+1|0}while((Z|0)<(c[v>>2]|0))}Z=(Dc(a)|0)!=0;if((h|0)<((Z?14:7)|0))h=h+1|0;else{_=0;break}}i=b;return _|0}function kd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0.0,E=0.0,F=0;d=i;e=c[a+64>>2]|0;f=c[e+4>>2]|0;h=c[f+28>>2]|0;j=c[e+104>>2]|0;e=a+28|0;k=c[h+(c[e>>2]<<2)>>2]|0;c[a+36>>2]=k;l=f+4|0;f=c[l>>2]<<2;m=i;i=i+((1*f|0)+15&-16)|0;n=i;i=i+((1*f|0)+15&-16)|0;o=i;i=i+((1*f|0)+15&-16)|0;p=i;i=i+((1*f|0)+15&-16)|0;f=c[l>>2]|0;if((f|0)>0){q=b+4|0;r=b+1028|0;s=j+48|0;t=k<<1&2147483646;u=0;do{v=c[r+(c[q+(u<<2)>>2]<<2)>>2]|0;w=$a[c[(c[328+(c[h+800+(v<<2)>>2]<<2)>>2]|0)+20>>2]&15](a,c[(c[s>>2]|0)+(v<<2)>>2]|0)|0;c[p+(u<<2)>>2]=w;c[o+(u<<2)>>2]=(w|0)!=0&1;Fd(c[(c[a>>2]|0)+(u<<2)>>2]|0,0,t|0)|0;u=u+1|0;w=c[l>>2]|0}while((u|0)<(w|0));x=w}else x=f;f=b+1156|0;u=c[f>>2]|0;if((u|0)>0){t=b+1160|0;s=b+2184|0;q=0;do{r=o+(c[t+(q<<2)>>2]<<2)|0;w=c[s+(q<<2)>>2]|0;if(!((c[r>>2]|0)==0?(c[o+(w<<2)>>2]|0)==0:0)){c[r>>2]=1;c[o+(w<<2)>>2]=1}q=q+1|0}while((q|0)<(u|0))}if((c[b>>2]|0)>0){q=b+1092|0;s=j+52|0;t=b+4|0;w=x;x=0;while(1){if((w|0)>0){r=w;v=0;y=0;while(1){if((c[t+(y<<2)>>2]|0)==(x|0)){c[n+(v<<2)>>2]=(c[o+(y<<2)>>2]|0)!=0&1;c[m+(v<<2)>>2]=c[(c[a>>2]|0)+(y<<2)>>2];z=c[l>>2]|0;A=v+1|0}else{z=r;A=v}y=y+1|0;if((y|0)>=(z|0)){B=A;break}else{r=z;v=A}}}else B=0;v=c[q+(x<<2)>>2]|0;ab[c[(c[336+(c[h+1312+(v<<2)>>2]<<2)>>2]|0)+28>>2]&7](a,c[(c[s>>2]|0)+(v<<2)>>2]|0,m,n,B)|0;v=x+1|0;if((v|0)>=(c[b>>2]|0))break;w=c[l>>2]|0;x=v}C=c[f>>2]|0}else C=u;if((C|0)>0){u=b+1160|0;f=c[a>>2]|0;x=b+2184|0;w=(k|0)/2|0;B=(k|0)>1;k=C;do{C=k;k=k+-1|0;n=c[f+(c[u+(k<<2)>>2]<<2)>>2]|0;m=c[f+(c[x+(k<<2)>>2]<<2)>>2]|0;if(B){s=0;do{q=n+(s<<2)|0;D=+g[q>>2];A=m+(s<<2)|0;E=+g[A>>2];z=E>0.0;do if(D>0.0)if(z){g[q>>2]=D;g[A>>2]=D-E;break}else{g[A>>2]=D;g[q>>2]=E+D;break}else if(z){g[q>>2]=D;g[A>>2]=E+D;break}else{g[A>>2]=D;g[q>>2]=D-E;break}while(0);s=s+1|0}while((s|0)<(w|0))}}while((C|0)>1)}if((c[l>>2]|0)<=0){i=d;return 0}w=b+4|0;B=b+1028|0;b=j+48|0;k=0;do{x=c[B+(c[w+(k<<2)>>2]<<2)>>2]|0;Va[c[(c[328+(c[h+800+(x<<2)>>2]<<2)>>2]|0)+24>>2]&7](a,c[(c[b>>2]|0)+(x<<2)>>2]|0,c[p+(k<<2)>>2]|0,c[(c[a>>2]|0)+(k<<2)>>2]|0)|0;k=k+1|0;x=c[l>>2]|0}while((k|0)<(x|0));F=x;if((F|0)<=0){i=d;return 0}F=0;do{k=c[(c[a>>2]|0)+(F<<2)>>2]|0;ub(c[c[j+12+(c[e>>2]<<2)>>2]>>2]|0,k,k);F=F+1|0}while((F|0)<(c[l>>2]|0));i=d;return 0}function ld(){Xb(57432);Vb(57464);return}function md(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+32|0;e=d;pd(e,a,b);if(!(c[14356]|0))c[e+8>>2]=1;if(Zb(57432,57464,e)|0){Da(57704)|0;f=0;i=d;return f|0}e=(c[14356]|0)+1|0;c[14356]=e;if((e|0)<3){f=1;i=d;return f|0}Eb(57480,57432)|0;zb(57480,57592)|0;Ba(c[14359]|0,c[14360]|0);f=1;i=d;return f|0}function nd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+48|0;e=d+32|0;f=d;g=d+36|0;pd(f,a,b);b=Mb(57592,f)|0;if(!b){Fb(57480,57592)|0;f=Gb(57480,g)|0;Fa(c[g>>2]|0,c[14359]|0,f|0);Hb(57480,f)|0;h=1;i=d;return h|0}else{c[e>>2]=b;Ea(57728,e|0)|0;h=0;i=d;return h|0}return 0}function od(){if(!(c[14356]|0))return;Yb(57432);Db(57480);Cb(57592)|0;Wb(57464);return}function pd(a,b,d){a=a|0;b=b|0;d=d|0;c[a>>2]=b;c[a+4>>2]=d;d=a+8|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;c[d+16>>2]=0;c[d+20>>2]=0;return}function qd(a,b){a=+a;b=b|0;return +(+vd(a,b))}function rd(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0;f=i;i=i+688|0;g=f+424|0;h=f+192|0;j=f;k=_(d,b)|0;if(!k){i=f;return}b=k-d|0;c[j+4>>2]=d;c[j>>2]=d;l=d;m=d;n=2;while(1){o=l+d+m|0;c[j+(n<<2)>>2]=o;if(o>>>0<k>>>0){p=m;m=o;n=n+1|0;l=p}else break}l=0-d|0;n=a+b|0;if((b|0)>0){b=(d|0)==0;m=n;k=1;p=0;o=a;q=1;while(1){do if((k&3|0)!=3){r=q+-1|0;if((c[j+(r<<2)>>2]|0)>>>0<(m-o|0)>>>0){c[h>>2]=o;a:do if((q|0)>1){s=q;t=o;u=o;v=1;while(1){w=t+l|0;x=s+-2|0;y=t+(0-((c[j+(x<<2)>>2]|0)+d))|0;if(($a[e&15](u,y)|0)>-1?($a[e&15](u,w)|0)>-1:0){z=v;break}A=v+1|0;B=h+(v<<2)|0;if(($a[e&15](y,w)|0)>-1){c[B>>2]=y;C=y;D=s+-1|0}else{c[B>>2]=w;C=w;D=x}if((D|0)<=1){z=A;break}s=D;t=C;u=c[h>>2]|0;v=A}if((z|0)>=2?(v=h+(z<<2)|0,c[v>>2]=g,!b):0){u=d;t=g;while(1){s=u>>>0>256?256:u;A=c[h>>2]|0;Jd(t|0,A|0,s|0)|0;x=A;A=0;do{w=A;A=A+1|0;B=x;x=c[h+(A<<2)>>2]|0;Jd(B|0,x|0,s|0)|0;c[h+(w<<2)>>2]=B+s}while((A|0)!=(z|0));if((u|0)==(s|0))break a;u=u-s|0;t=c[v>>2]|0}}}while(0)}else sd(o,d,e,k,p,q,0,j);if((q|0)==1){E=k<<1;F=k>>>31|p<<1;G=0;break}else{v=r>>>0>31;t=v?0:k;u=v?q+-33|0:r;E=t<<u;F=t>>>(32-u|0)|(v?k:p)<<u;G=1;break}}else{c[h>>2]=o;b:do if((q|0)>1){u=q;v=o;t=o;A=1;while(1){x=v+l|0;B=u+-2|0;w=v+(0-((c[j+(B<<2)>>2]|0)+d))|0;if(($a[e&15](t,w)|0)>-1?($a[e&15](t,x)|0)>-1:0){H=A;break}y=A+1|0;I=h+(A<<2)|0;if(($a[e&15](w,x)|0)>-1){c[I>>2]=w;J=w;K=u+-1|0}else{c[I>>2]=x;J=x;K=B}if((K|0)<=1){H=y;break}u=K;v=J;t=c[h>>2]|0;A=y}if((H|0)>=2?(A=h+(H<<2)|0,c[A>>2]=g,!b):0){t=d;v=g;while(1){u=t>>>0>256?256:t;y=c[h>>2]|0;Jd(v|0,y|0,u|0)|0;B=y;y=0;do{x=y;y=y+1|0;I=B;B=c[h+(y<<2)>>2]|0;Jd(I|0,B|0,u|0)|0;c[h+(x<<2)>>2]=I+u}while((y|0)!=(H|0));if((t|0)==(u|0))break b;t=t-u|0;v=c[A>>2]|0}}}while(0);E=k>>>2|p<<30;F=p>>>2;G=q+2|0}while(0);r=E|1;A=o+d|0;if(A>>>0<n>>>0){k=r;p=F;o=A;q=G}else{L=F;M=r;N=A;O=G;break}}}else{L=0;M=1;N=a;O=1}sd(N,d,e,M,L,O,0,j);if((L|0)==0&((M|0)==1&(O|0)==1)){i=f;return}else{P=M;Q=L;R=N;S=O}while(1){if((S|0)>=2){O=P>>>30;N=S+-2|0;L=(P<<1&2147483646|O<<31)^3;M=(O|Q<<2)>>>1;sd(R+(0-((c[j+(N<<2)>>2]|0)+d))|0,d,e,L,M,S+-1|0,1,j);a=M<<1|O&1;O=L<<1|1;L=R+l|0;sd(L,d,e,O,a,N,1,j);P=O;Q=a;R=L;S=N;continue}N=P+-1|0;do if(N){if(!(N&1)){L=N;a=0;while(1){O=a+1|0;L=L>>>1;if(L&1){T=O;break}else a=O}if(T)U=T;else V=51}else V=51;if((V|0)==51){V=0;if(!Q){W=64;V=56;break}if(!(Q&1)){X=Q;Y=0}else{Z=0;$=P;aa=Q;ba=0;break}while(1){a=Y+1|0;X=X>>>1;if(X&1){ca=a;da=Y;break}else Y=a}if(!ca){Z=0;$=P;aa=Q;ba=0;break}else U=da+33|0}if(U>>>0>31){W=U;V=56}else{Z=U;$=P;aa=Q;ba=U}}else{W=32;V=56}while(0);if((V|0)==56){V=0;Z=W+-32|0;$=Q;aa=0;ba=W}P=aa<<32-Z|$>>>Z;Q=aa>>>Z;S=ba+S|0;if((Q|0)==0&((P|0)==1&(S|0)==1))break;else R=R+l|0}i=f;return}function sd(a,b,d,e,f,g,h,j){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0;k=i;i=i+720|0;l=k+456|0;m=k+228|0;n=k;c[n>>2]=a;o=0-b|0;a:do if((f|0)!=0|(e|0)!=1?(p=a+(0-(c[j+(g<<2)>>2]|0))|0,($a[d&15](p,a)|0)>=1):0){q=a;r=g;s=h;t=p;p=f;u=1;v=e;while(1){if((s|0)==0&(r|0)>1){w=c[j+(r+-2<<2)>>2]|0;if(($a[d&15](q+o|0,t)|0)>-1){x=q;y=r;z=u;break a}if(($a[d&15](q+(0-(w+b))|0,t)|0)>-1){x=q;y=r;z=u;break a}}w=u+1|0;c[n+(u<<2)>>2]=t;A=v+-1|0;do if(A){if(!(A&1)){B=A;C=0;while(1){D=C+1|0;B=B>>>1;if(B&1){E=D;break}else C=D}if(E)F=E;else G=10}else G=10;if((G|0)==10){G=0;if(!p){H=64;G=15;break}if(!(p&1)){I=p;J=0}else{K=0;L=v;M=p;N=0;break}while(1){C=J+1|0;I=I>>>1;if(I&1){O=C;P=J;break}else J=C}if(!O){K=0;L=v;M=p;N=0;break}else F=P+33|0}if(F>>>0>31){H=F;G=15}else{K=F;L=v;M=p;N=F}}else{H=32;G=15}while(0);if((G|0)==15){G=0;K=H+-32|0;L=p;M=0;N=H}v=M<<32-K|L>>>K;p=M>>>K;A=N+r|0;if(!((p|0)!=0|(v|0)!=1)){x=t;y=A;z=w;break a}C=t+(0-(c[j+(A<<2)>>2]|0))|0;if(($a[d&15](C,c[n>>2]|0)|0)<1){Q=t;R=A;S=0;T=w;G=18;break}else{B=t;r=A;s=0;t=C;u=w;q=B}}}else{Q=a;R=g;S=h;T=1;G=18}while(0);if((G|0)==18)if(!S){x=Q;y=R;z=T}else{i=k;return}b:do if((z|0)>=2?(T=n+(z<<2)|0,c[T>>2]=l,(b|0)!=0):0){R=b;Q=l;while(1){S=R>>>0>256?256:R;G=c[n>>2]|0;Jd(Q|0,G|0,S|0)|0;h=G;G=0;do{g=G;G=G+1|0;a=h;h=c[n+(G<<2)>>2]|0;Jd(a|0,h|0,S|0)|0;c[n+(g<<2)>>2]=a+S}while((G|0)!=(z|0));if((R|0)==(S|0))break b;R=R-S|0;Q=c[T>>2]|0}}while(0);c[m>>2]=x;c:do if((y|0)>1){z=y;n=x;T=x;Q=1;while(1){R=n+o|0;G=z+-2|0;h=n+(0-((c[j+(G<<2)>>2]|0)+b))|0;if(($a[d&15](T,h)|0)>-1?($a[d&15](T,R)|0)>-1:0){U=Q;break}w=Q+1|0;a=m+(Q<<2)|0;if(($a[d&15](h,R)|0)>-1){c[a>>2]=h;V=h;W=z+-1|0}else{c[a>>2]=R;V=R;W=G}if((W|0)<=1){U=w;break}z=W;n=V;T=c[m>>2]|0;Q=w}if((U|0)>=2?(Q=m+(U<<2)|0,c[Q>>2]=l,(b|0)!=0):0){T=b;n=l;while(1){z=T>>>0>256?256:T;w=c[m>>2]|0;Jd(n|0,w|0,z|0)|0;G=w;w=0;do{R=w;w=w+1|0;a=G;G=c[m+(w<<2)>>2]|0;Jd(a|0,G|0,z|0)|0;c[m+(R<<2)>>2]=a+z}while((w|0)!=(U|0));if((T|0)==(z|0)){X=l;break c}T=T-z|0;n=c[Q>>2]|0}}else X=l}else X=l;while(0);i=k;return}function td(a){a=+a;var b=0,d=0,e=0.0,f=0.0;h[k>>3]=a;b=c[k+4>>2]|0;d=b&2146435072;if(d>>>0>1126170624|(d|0)==1126170624&0>0){e=a;return +e}d=(b|0)<0;f=d?a+-4503599627370496.0+4503599627370496.0:a+4503599627370496.0+-4503599627370496.0;if(!(f==0.0)){e=f;return +e}e=d?-0.0:0.0;return +e}function ud(a){a=+a;var b=0,d=0.0,e=0,f=0.0;b=(g[k>>2]=a,c[k>>2]|0);if((b&2130706432)>>>0>1249902592){d=a;return +d}e=(b|0)<0;f=e?a+-8388608.0+8388608.0:a+8388608.0+-8388608.0;if(!(f==0.0)){d=f;return +d}d=e?-0.0:0.0;return +d}function vd(a,b){a=+a;b=b|0;var d=0.0,e=0,f=0,g=0,i=0.0;if((b|0)>1023){d=a*8988465674311579538646525.0e283;e=b+-1023|0;if((e|0)>1023){f=b+-2046|0;g=(f|0)>1023?1023:f;i=d*8988465674311579538646525.0e283}else{g=e;i=d}}else if((b|0)<-1022){d=a*2.2250738585072014e-308;e=b+1022|0;if((e|0)<-1022){f=b+2044|0;g=(f|0)<-1022?-1022:f;i=d*2.2250738585072014e-308}else{g=e;i=d}}else{g=b;i=a}b=Gd(g+1023|0,0,52)|0;g=C;c[k>>2]=b;c[k+4>>2]=g;return +(i*+h[k>>3])}function wd(b,c,d){b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0;if(!d){e=0;return e|0}else{f=d;g=b;h=c}while(1){c=a[g>>0]|0;b=a[h>>0]|0;if(c<<24>>24!=b<<24>>24){i=c;j=b;break}f=f+-1|0;if(!f){e=0;k=5;break}else{g=g+1|0;h=h+1|0}}if((k|0)==5)return e|0;e=(i&255)-(j&255)|0;return e|0}function xd(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,xa=0,ya=0,za=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ka=0,La=0,Na=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Va=0,Wa=0,Xa=0;do if(a>>>0<245){b=a>>>0<11?16:a+11&-8;d=b>>>3;e=c[14442]|0;f=e>>>d;if(f&3){g=(f&1^1)+d|0;h=g<<1;i=57808+(h<<2)|0;j=57808+(h+2<<2)|0;h=c[j>>2]|0;k=h+8|0;l=c[k>>2]|0;do if((i|0)!=(l|0)){if(l>>>0<(c[14446]|0)>>>0)Ma();m=l+12|0;if((c[m>>2]|0)==(h|0)){c[m>>2]=i;c[j>>2]=l;break}else Ma()}else c[14442]=e&~(1<<g);while(0);l=g<<3;c[h+4>>2]=l|3;j=h+(l|4)|0;c[j>>2]=c[j>>2]|1;n=k;return n|0}j=c[14444]|0;if(b>>>0>j>>>0){if(f){l=2<<d;i=f<<d&(l|0-l);l=(i&0-i)+-1|0;i=l>>>12&16;m=l>>>i;l=m>>>5&8;o=m>>>l;m=o>>>2&4;p=o>>>m;o=p>>>1&2;q=p>>>o;p=q>>>1&1;r=(l|i|m|o|p)+(q>>>p)|0;p=r<<1;q=57808+(p<<2)|0;o=57808+(p+2<<2)|0;p=c[o>>2]|0;m=p+8|0;i=c[m>>2]|0;do if((q|0)!=(i|0)){if(i>>>0<(c[14446]|0)>>>0)Ma();l=i+12|0;if((c[l>>2]|0)==(p|0)){c[l>>2]=q;c[o>>2]=i;s=c[14444]|0;break}else Ma()}else{c[14442]=e&~(1<<r);s=j}while(0);j=r<<3;e=j-b|0;c[p+4>>2]=b|3;i=p+b|0;c[p+(b|4)>>2]=e|1;c[p+j>>2]=e;if(s){j=c[14447]|0;o=s>>>3;q=o<<1;d=57808+(q<<2)|0;f=c[14442]|0;k=1<<o;if(f&k){o=57808+(q+2<<2)|0;h=c[o>>2]|0;if(h>>>0<(c[14446]|0)>>>0)Ma();else{t=o;u=h}}else{c[14442]=f|k;t=57808+(q+2<<2)|0;u=d}c[t>>2]=j;c[u+12>>2]=j;c[j+8>>2]=u;c[j+12>>2]=d}c[14444]=e;c[14447]=i;n=m;return n|0}i=c[14443]|0;if(i){e=(i&0-i)+-1|0;i=e>>>12&16;d=e>>>i;e=d>>>5&8;j=d>>>e;d=j>>>2&4;q=j>>>d;j=q>>>1&2;k=q>>>j;q=k>>>1&1;f=c[58072+((e|i|d|j|q)+(k>>>q)<<2)>>2]|0;q=(c[f+4>>2]&-8)-b|0;k=f;j=f;while(1){f=c[k+16>>2]|0;if(!f){d=c[k+20>>2]|0;if(!d){v=q;w=j;break}else x=d}else x=f;f=(c[x+4>>2]&-8)-b|0;d=f>>>0<q>>>0;q=d?f:q;k=x;j=d?x:j}j=c[14446]|0;if(w>>>0<j>>>0)Ma();k=w+b|0;if(w>>>0>=k>>>0)Ma();q=c[w+24>>2]|0;m=c[w+12>>2]|0;do if((m|0)==(w|0)){p=w+20|0;r=c[p>>2]|0;if(!r){d=w+16|0;f=c[d>>2]|0;if(!f){y=0;break}else{z=f;A=d}}else{z=r;A=p}while(1){p=z+20|0;r=c[p>>2]|0;if(r){z=r;A=p;continue}p=z+16|0;r=c[p>>2]|0;if(!r){B=z;C=A;break}else{z=r;A=p}}if(C>>>0<j>>>0)Ma();else{c[C>>2]=0;y=B;break}}else{p=c[w+8>>2]|0;if(p>>>0<j>>>0)Ma();r=p+12|0;if((c[r>>2]|0)!=(w|0))Ma();d=m+8|0;if((c[d>>2]|0)==(w|0)){c[r>>2]=m;c[d>>2]=p;y=m;break}else Ma()}while(0);do if(q){m=c[w+28>>2]|0;j=58072+(m<<2)|0;if((w|0)==(c[j>>2]|0)){c[j>>2]=y;if(!y){c[14443]=c[14443]&~(1<<m);break}}else{if(q>>>0<(c[14446]|0)>>>0)Ma();m=q+16|0;if((c[m>>2]|0)==(w|0))c[m>>2]=y;else c[q+20>>2]=y;if(!y)break}m=c[14446]|0;if(y>>>0<m>>>0)Ma();c[y+24>>2]=q;j=c[w+16>>2]|0;do if(j)if(j>>>0<m>>>0)Ma();else{c[y+16>>2]=j;c[j+24>>2]=y;break}while(0);j=c[w+20>>2]|0;if(j)if(j>>>0<(c[14446]|0)>>>0)Ma();else{c[y+20>>2]=j;c[j+24>>2]=y;break}}while(0);if(v>>>0<16){q=v+b|0;c[w+4>>2]=q|3;j=w+(q+4)|0;c[j>>2]=c[j>>2]|1}else{c[w+4>>2]=b|3;c[w+(b|4)>>2]=v|1;c[w+(v+b)>>2]=v;j=c[14444]|0;if(j){q=c[14447]|0;m=j>>>3;j=m<<1;p=57808+(j<<2)|0;d=c[14442]|0;r=1<<m;if(d&r){m=57808+(j+2<<2)|0;f=c[m>>2]|0;if(f>>>0<(c[14446]|0)>>>0)Ma();else{D=m;E=f}}else{c[14442]=d|r;D=57808+(j+2<<2)|0;E=p}c[D>>2]=q;c[E+12>>2]=q;c[q+8>>2]=E;c[q+12>>2]=p}c[14444]=v;c[14447]=k}n=w+8|0;return n|0}else F=b}else F=b}else if(a>>>0<=4294967231){p=a+11|0;q=p&-8;j=c[14443]|0;if(j){r=0-q|0;d=p>>>8;if(d)if(q>>>0>16777215)G=31;else{p=(d+1048320|0)>>>16&8;f=d<<p;d=(f+520192|0)>>>16&4;m=f<<d;f=(m+245760|0)>>>16&2;i=14-(d|p|f)+(m<<f>>>15)|0;G=q>>>(i+7|0)&1|i<<1}else G=0;i=c[58072+(G<<2)>>2]|0;a:do if(!i){H=r;I=0;J=0;K=86}else{f=r;m=0;p=q<<((G|0)==31?0:25-(G>>>1)|0);d=i;e=0;while(1){h=c[d+4>>2]&-8;o=h-q|0;if(o>>>0<f>>>0)if((h|0)==(q|0)){L=o;M=d;N=d;K=90;break a}else{O=o;P=d}else{O=f;P=e}o=c[d+20>>2]|0;d=c[d+16+(p>>>31<<2)>>2]|0;h=(o|0)==0|(o|0)==(d|0)?m:o;if(!d){H=O;I=h;J=P;K=86;break}else{f=O;m=h;p=p<<1;e=P}}}while(0);if((K|0)==86){if((I|0)==0&(J|0)==0){i=2<<G;r=j&(i|0-i);if(!r){F=q;break}i=(r&0-r)+-1|0;r=i>>>12&16;b=i>>>r;i=b>>>5&8;k=b>>>i;b=k>>>2&4;e=k>>>b;k=e>>>1&2;p=e>>>k;e=p>>>1&1;Q=c[58072+((i|r|b|k|e)+(p>>>e)<<2)>>2]|0;R=0}else{Q=I;R=J}if(!Q){S=H;T=R}else{L=H;M=Q;N=R;K=90}}if((K|0)==90)while(1){K=0;e=(c[M+4>>2]&-8)-q|0;p=e>>>0<L>>>0;k=p?e:L;e=p?M:N;p=c[M+16>>2]|0;if(p){L=k;M=p;N=e;K=90;continue}M=c[M+20>>2]|0;if(!M){S=k;T=e;break}else{L=k;N=e;K=90}}if((T|0)!=0?S>>>0<((c[14444]|0)-q|0)>>>0:0){j=c[14446]|0;if(T>>>0<j>>>0)Ma();e=T+q|0;if(T>>>0>=e>>>0)Ma();k=c[T+24>>2]|0;p=c[T+12>>2]|0;do if((p|0)==(T|0)){b=T+20|0;r=c[b>>2]|0;if(!r){i=T+16|0;m=c[i>>2]|0;if(!m){U=0;break}else{V=m;W=i}}else{V=r;W=b}while(1){b=V+20|0;r=c[b>>2]|0;if(r){V=r;W=b;continue}b=V+16|0;r=c[b>>2]|0;if(!r){X=V;Y=W;break}else{V=r;W=b}}if(Y>>>0<j>>>0)Ma();else{c[Y>>2]=0;U=X;break}}else{b=c[T+8>>2]|0;if(b>>>0<j>>>0)Ma();r=b+12|0;if((c[r>>2]|0)!=(T|0))Ma();i=p+8|0;if((c[i>>2]|0)==(T|0)){c[r>>2]=p;c[i>>2]=b;U=p;break}else Ma()}while(0);do if(k){p=c[T+28>>2]|0;j=58072+(p<<2)|0;if((T|0)==(c[j>>2]|0)){c[j>>2]=U;if(!U){c[14443]=c[14443]&~(1<<p);break}}else{if(k>>>0<(c[14446]|0)>>>0)Ma();p=k+16|0;if((c[p>>2]|0)==(T|0))c[p>>2]=U;else c[k+20>>2]=U;if(!U)break}p=c[14446]|0;if(U>>>0<p>>>0)Ma();c[U+24>>2]=k;j=c[T+16>>2]|0;do if(j)if(j>>>0<p>>>0)Ma();else{c[U+16>>2]=j;c[j+24>>2]=U;break}while(0);j=c[T+20>>2]|0;if(j)if(j>>>0<(c[14446]|0)>>>0)Ma();else{c[U+20>>2]=j;c[j+24>>2]=U;break}}while(0);b:do if(S>>>0>=16){c[T+4>>2]=q|3;c[T+(q|4)>>2]=S|1;c[T+(S+q)>>2]=S;k=S>>>3;if(S>>>0<256){j=k<<1;p=57808+(j<<2)|0;b=c[14442]|0;i=1<<k;if(b&i){k=57808+(j+2<<2)|0;r=c[k>>2]|0;if(r>>>0<(c[14446]|0)>>>0)Ma();else{Z=k;_=r}}else{c[14442]=b|i;Z=57808+(j+2<<2)|0;_=p}c[Z>>2]=e;c[_+12>>2]=e;c[T+(q+8)>>2]=_;c[T+(q+12)>>2]=p;break}p=S>>>8;if(p)if(S>>>0>16777215)$=31;else{j=(p+1048320|0)>>>16&8;i=p<<j;p=(i+520192|0)>>>16&4;b=i<<p;i=(b+245760|0)>>>16&2;r=14-(p|j|i)+(b<<i>>>15)|0;$=S>>>(r+7|0)&1|r<<1}else $=0;r=58072+($<<2)|0;c[T+(q+28)>>2]=$;c[T+(q+20)>>2]=0;c[T+(q+16)>>2]=0;i=c[14443]|0;b=1<<$;if(!(i&b)){c[14443]=i|b;c[r>>2]=e;c[T+(q+24)>>2]=r;c[T+(q+12)>>2]=e;c[T+(q+8)>>2]=e;break}b=c[r>>2]|0;c:do if((c[b+4>>2]&-8|0)!=(S|0)){r=S<<(($|0)==31?0:25-($>>>1)|0);i=b;while(1){j=i+16+(r>>>31<<2)|0;p=c[j>>2]|0;if(!p){aa=j;ba=i;break}if((c[p+4>>2]&-8|0)==(S|0)){ca=p;break c}else{r=r<<1;i=p}}if(aa>>>0<(c[14446]|0)>>>0)Ma();else{c[aa>>2]=e;c[T+(q+24)>>2]=ba;c[T+(q+12)>>2]=e;c[T+(q+8)>>2]=e;break b}}else ca=b;while(0);b=ca+8|0;i=c[b>>2]|0;r=c[14446]|0;if(i>>>0>=r>>>0&ca>>>0>=r>>>0){c[i+12>>2]=e;c[b>>2]=e;c[T+(q+8)>>2]=i;c[T+(q+12)>>2]=ca;c[T+(q+24)>>2]=0;break}else Ma()}else{i=S+q|0;c[T+4>>2]=i|3;b=T+(i+4)|0;c[b>>2]=c[b>>2]|1}while(0);n=T+8|0;return n|0}else F=q}else F=q}else F=-1;while(0);T=c[14444]|0;if(T>>>0>=F>>>0){S=T-F|0;ca=c[14447]|0;if(S>>>0>15){c[14447]=ca+F;c[14444]=S;c[ca+(F+4)>>2]=S|1;c[ca+T>>2]=S;c[ca+4>>2]=F|3}else{c[14444]=0;c[14447]=0;c[ca+4>>2]=T|3;S=ca+(T+4)|0;c[S>>2]=c[S>>2]|1}n=ca+8|0;return n|0}ca=c[14445]|0;if(ca>>>0>F>>>0){S=ca-F|0;c[14445]=S;ca=c[14448]|0;c[14448]=ca+F;c[ca+(F+4)>>2]=S|1;c[ca+4>>2]=F|3;n=ca+8|0;return n|0}do if(!(c[14560]|0)){ca=Aa(30)|0;if(!(ca+-1&ca)){c[14562]=ca;c[14561]=ca;c[14563]=-1;c[14564]=-1;c[14565]=0;c[14553]=0;c[14560]=(Oa(0)|0)&-16^1431655768;break}else Ma()}while(0);ca=F+48|0;S=c[14562]|0;T=F+47|0;ba=S+T|0;aa=0-S|0;S=ba&aa;if(S>>>0<=F>>>0){n=0;return n|0}$=c[14552]|0;if(($|0)!=0?(_=c[14550]|0,Z=_+S|0,Z>>>0<=_>>>0|Z>>>0>$>>>0):0){n=0;return n|0}d:do if(!(c[14553]&4)){$=c[14448]|0;e:do if($){Z=58216;while(1){_=c[Z>>2]|0;if(_>>>0<=$>>>0?(U=Z+4|0,(_+(c[U>>2]|0)|0)>>>0>$>>>0):0){da=Z;ea=U;break}Z=c[Z+8>>2]|0;if(!Z){K=174;break e}}Z=ba-(c[14445]|0)&aa;if(Z>>>0<2147483647){U=wa(Z|0)|0;_=(U|0)==((c[da>>2]|0)+(c[ea>>2]|0)|0);X=_?Z:0;if(_)if((U|0)==(-1|0))fa=X;else{ga=U;ha=X;K=194;break d}else{ia=U;ja=Z;ka=X;K=184}}else fa=0}else K=174;while(0);do if((K|0)==174){$=wa(0)|0;if(($|0)!=(-1|0)){q=$;X=c[14561]|0;Z=X+-1|0;if(!(Z&q))la=S;else la=S-q+(Z+q&0-X)|0;X=c[14550]|0;q=X+la|0;if(la>>>0>F>>>0&la>>>0<2147483647){Z=c[14552]|0;if((Z|0)!=0?q>>>0<=X>>>0|q>>>0>Z>>>0:0){fa=0;break}Z=wa(la|0)|0;q=(Z|0)==($|0);X=q?la:0;if(q){ga=$;ha=X;K=194;break d}else{ia=Z;ja=la;ka=X;K=184}}else fa=0}else fa=0}while(0);f:do if((K|0)==184){X=0-ja|0;do if(ca>>>0>ja>>>0&(ja>>>0<2147483647&(ia|0)!=(-1|0))?(Z=c[14562]|0,$=T-ja+Z&0-Z,$>>>0<2147483647):0)if((wa($|0)|0)==(-1|0)){wa(X|0)|0;fa=ka;break f}else{ma=$+ja|0;break}else ma=ja;while(0);if((ia|0)==(-1|0))fa=ka;else{ga=ia;ha=ma;K=194;break d}}while(0);c[14553]=c[14553]|4;na=fa;K=191}else{na=0;K=191}while(0);if((((K|0)==191?S>>>0<2147483647:0)?(fa=wa(S|0)|0,S=wa(0)|0,fa>>>0<S>>>0&((fa|0)!=(-1|0)&(S|0)!=(-1|0))):0)?(ma=S-fa|0,S=ma>>>0>(F+40|0)>>>0,S):0){ga=fa;ha=S?ma:na;K=194}if((K|0)==194){na=(c[14550]|0)+ha|0;c[14550]=na;if(na>>>0>(c[14551]|0)>>>0)c[14551]=na;na=c[14448]|0;g:do if(na){ma=58216;do{S=c[ma>>2]|0;fa=ma+4|0;ia=c[fa>>2]|0;if((ga|0)==(S+ia|0)){oa=S;pa=fa;qa=ia;ra=ma;K=204;break}ma=c[ma+8>>2]|0}while((ma|0)!=0);if(((K|0)==204?(c[ra+12>>2]&8|0)==0:0)?na>>>0<ga>>>0&na>>>0>=oa>>>0:0){c[pa>>2]=qa+ha;ma=(c[14445]|0)+ha|0;ia=na+8|0;fa=(ia&7|0)==0?0:0-ia&7;ia=ma-fa|0;c[14448]=na+fa;c[14445]=ia;c[na+(fa+4)>>2]=ia|1;c[na+(ma+4)>>2]=40;c[14449]=c[14564];break}ma=c[14446]|0;if(ga>>>0<ma>>>0){c[14446]=ga;sa=ga}else sa=ma;ma=ga+ha|0;ia=58216;while(1){if((c[ia>>2]|0)==(ma|0)){ta=ia;ua=ia;K=212;break}ia=c[ia+8>>2]|0;if(!ia){va=58216;break}}if((K|0)==212)if(!(c[ua+12>>2]&8)){c[ta>>2]=ga;ia=ua+4|0;c[ia>>2]=(c[ia>>2]|0)+ha;ia=ga+8|0;ma=(ia&7|0)==0?0:0-ia&7;ia=ga+(ha+8)|0;fa=(ia&7|0)==0?0:0-ia&7;ia=ga+(fa+ha)|0;S=ma+F|0;ka=ga+S|0;ja=ia-(ga+ma)-F|0;c[ga+(ma+4)>>2]=F|3;h:do if((ia|0)!=(na|0)){if((ia|0)==(c[14447]|0)){T=(c[14444]|0)+ja|0;c[14444]=T;c[14447]=ka;c[ga+(S+4)>>2]=T|1;c[ga+(T+S)>>2]=T;break}T=ha+4|0;ca=c[ga+(T+fa)>>2]|0;if((ca&3|0)==1){la=ca&-8;ea=ca>>>3;i:do if(ca>>>0>=256){da=c[ga+((fa|24)+ha)>>2]|0;aa=c[ga+(ha+12+fa)>>2]|0;do if((aa|0)==(ia|0)){ba=fa|16;X=ga+(T+ba)|0;$=c[X>>2]|0;if(!$){Z=ga+(ba+ha)|0;ba=c[Z>>2]|0;if(!ba){xa=0;break}else{ya=ba;za=Z}}else{ya=$;za=X}while(1){X=ya+20|0;$=c[X>>2]|0;if($){ya=$;za=X;continue}X=ya+16|0;$=c[X>>2]|0;if(!$){Ba=ya;Ca=za;break}else{ya=$;za=X}}if(Ca>>>0<sa>>>0)Ma();else{c[Ca>>2]=0;xa=Ba;break}}else{X=c[ga+((fa|8)+ha)>>2]|0;if(X>>>0<sa>>>0)Ma();$=X+12|0;if((c[$>>2]|0)!=(ia|0))Ma();Z=aa+8|0;if((c[Z>>2]|0)==(ia|0)){c[$>>2]=aa;c[Z>>2]=X;xa=aa;break}else Ma()}while(0);if(!da)break;aa=c[ga+(ha+28+fa)>>2]|0;X=58072+(aa<<2)|0;do if((ia|0)!=(c[X>>2]|0)){if(da>>>0<(c[14446]|0)>>>0)Ma();Z=da+16|0;if((c[Z>>2]|0)==(ia|0))c[Z>>2]=xa;else c[da+20>>2]=xa;if(!xa)break i}else{c[X>>2]=xa;if(xa)break;c[14443]=c[14443]&~(1<<aa);break i}while(0);aa=c[14446]|0;if(xa>>>0<aa>>>0)Ma();c[xa+24>>2]=da;X=fa|16;Z=c[ga+(X+ha)>>2]|0;do if(Z)if(Z>>>0<aa>>>0)Ma();else{c[xa+16>>2]=Z;c[Z+24>>2]=xa;break}while(0);Z=c[ga+(T+X)>>2]|0;if(!Z)break;if(Z>>>0<(c[14446]|0)>>>0)Ma();else{c[xa+20>>2]=Z;c[Z+24>>2]=xa;break}}else{Z=c[ga+((fa|8)+ha)>>2]|0;aa=c[ga+(ha+12+fa)>>2]|0;da=57808+(ea<<1<<2)|0;do if((Z|0)!=(da|0)){if(Z>>>0<sa>>>0)Ma();if((c[Z+12>>2]|0)==(ia|0))break;Ma()}while(0);if((aa|0)==(Z|0)){c[14442]=c[14442]&~(1<<ea);break}do if((aa|0)==(da|0))Da=aa+8|0;else{if(aa>>>0<sa>>>0)Ma();X=aa+8|0;if((c[X>>2]|0)==(ia|0)){Da=X;break}Ma()}while(0);c[Z+12>>2]=aa;c[Da>>2]=Z}while(0);Ea=ga+((la|fa)+ha)|0;Fa=la+ja|0}else{Ea=ia;Fa=ja}ea=Ea+4|0;c[ea>>2]=c[ea>>2]&-2;c[ga+(S+4)>>2]=Fa|1;c[ga+(Fa+S)>>2]=Fa;ea=Fa>>>3;if(Fa>>>0<256){T=ea<<1;ca=57808+(T<<2)|0;da=c[14442]|0;X=1<<ea;do if(!(da&X)){c[14442]=da|X;Ga=57808+(T+2<<2)|0;Ha=ca}else{ea=57808+(T+2<<2)|0;$=c[ea>>2]|0;if($>>>0>=(c[14446]|0)>>>0){Ga=ea;Ha=$;break}Ma()}while(0);c[Ga>>2]=ka;c[Ha+12>>2]=ka;c[ga+(S+8)>>2]=Ha;c[ga+(S+12)>>2]=ca;break}T=Fa>>>8;do if(!T)Ia=0;else{if(Fa>>>0>16777215){Ia=31;break}X=(T+1048320|0)>>>16&8;da=T<<X;la=(da+520192|0)>>>16&4;$=da<<la;da=($+245760|0)>>>16&2;ea=14-(la|X|da)+($<<da>>>15)|0;Ia=Fa>>>(ea+7|0)&1|ea<<1}while(0);T=58072+(Ia<<2)|0;c[ga+(S+28)>>2]=Ia;c[ga+(S+20)>>2]=0;c[ga+(S+16)>>2]=0;ca=c[14443]|0;ea=1<<Ia;if(!(ca&ea)){c[14443]=ca|ea;c[T>>2]=ka;c[ga+(S+24)>>2]=T;c[ga+(S+12)>>2]=ka;c[ga+(S+8)>>2]=ka;break}ea=c[T>>2]|0;j:do if((c[ea+4>>2]&-8|0)!=(Fa|0)){T=Fa<<((Ia|0)==31?0:25-(Ia>>>1)|0);ca=ea;while(1){da=ca+16+(T>>>31<<2)|0;$=c[da>>2]|0;if(!$){Ka=da;La=ca;break}if((c[$+4>>2]&-8|0)==(Fa|0)){Na=$;break j}else{T=T<<1;ca=$}}if(Ka>>>0<(c[14446]|0)>>>0)Ma();else{c[Ka>>2]=ka;c[ga+(S+24)>>2]=La;c[ga+(S+12)>>2]=ka;c[ga+(S+8)>>2]=ka;break h}}else Na=ea;while(0);ea=Na+8|0;ca=c[ea>>2]|0;T=c[14446]|0;if(ca>>>0>=T>>>0&Na>>>0>=T>>>0){c[ca+12>>2]=ka;c[ea>>2]=ka;c[ga+(S+8)>>2]=ca;c[ga+(S+12)>>2]=Na;c[ga+(S+24)>>2]=0;break}else Ma()}else{ca=(c[14445]|0)+ja|0;c[14445]=ca;c[14448]=ka;c[ga+(S+4)>>2]=ca|1}while(0);n=ga+(ma|8)|0;return n|0}else va=58216;while(1){S=c[va>>2]|0;if(S>>>0<=na>>>0?(ka=c[va+4>>2]|0,ja=S+ka|0,ja>>>0>na>>>0):0){Pa=S;Qa=ka;Ra=ja;break}va=c[va+8>>2]|0}ma=Pa+(Qa+-39)|0;ja=Pa+(Qa+-47+((ma&7|0)==0?0:0-ma&7))|0;ma=na+16|0;ka=ja>>>0<ma>>>0?na:ja;ja=ka+8|0;S=ga+8|0;ia=(S&7|0)==0?0:0-S&7;S=ha+-40-ia|0;c[14448]=ga+ia;c[14445]=S;c[ga+(ia+4)>>2]=S|1;c[ga+(ha+-36)>>2]=40;c[14449]=c[14564];S=ka+4|0;c[S>>2]=27;c[ja>>2]=c[14554];c[ja+4>>2]=c[14555];c[ja+8>>2]=c[14556];c[ja+12>>2]=c[14557];c[14554]=ga;c[14555]=ha;c[14557]=0;c[14556]=ja;ja=ka+28|0;c[ja>>2]=7;if((ka+32|0)>>>0<Ra>>>0){ia=ja;do{ja=ia;ia=ia+4|0;c[ia>>2]=7}while((ja+8|0)>>>0<Ra>>>0)}if((ka|0)!=(na|0)){ia=ka-na|0;c[S>>2]=c[S>>2]&-2;c[na+4>>2]=ia|1;c[ka>>2]=ia;ja=ia>>>3;if(ia>>>0<256){fa=ja<<1;ca=57808+(fa<<2)|0;ea=c[14442]|0;T=1<<ja;if(ea&T){ja=57808+(fa+2<<2)|0;Z=c[ja>>2]|0;if(Z>>>0<(c[14446]|0)>>>0)Ma();else{Sa=ja;Ta=Z}}else{c[14442]=ea|T;Sa=57808+(fa+2<<2)|0;Ta=ca}c[Sa>>2]=na;c[Ta+12>>2]=na;c[na+8>>2]=Ta;c[na+12>>2]=ca;break}ca=ia>>>8;if(ca)if(ia>>>0>16777215)Ua=31;else{fa=(ca+1048320|0)>>>16&8;T=ca<<fa;ca=(T+520192|0)>>>16&4;ea=T<<ca;T=(ea+245760|0)>>>16&2;Z=14-(ca|fa|T)+(ea<<T>>>15)|0;Ua=ia>>>(Z+7|0)&1|Z<<1}else Ua=0;Z=58072+(Ua<<2)|0;c[na+28>>2]=Ua;c[na+20>>2]=0;c[ma>>2]=0;T=c[14443]|0;ea=1<<Ua;if(!(T&ea)){c[14443]=T|ea;c[Z>>2]=na;c[na+24>>2]=Z;c[na+12>>2]=na;c[na+8>>2]=na;break}ea=c[Z>>2]|0;k:do if((c[ea+4>>2]&-8|0)!=(ia|0)){Z=ia<<((Ua|0)==31?0:25-(Ua>>>1)|0);T=ea;while(1){fa=T+16+(Z>>>31<<2)|0;ca=c[fa>>2]|0;if(!ca){Va=fa;Wa=T;break}if((c[ca+4>>2]&-8|0)==(ia|0)){Xa=ca;break k}else{Z=Z<<1;T=ca}}if(Va>>>0<(c[14446]|0)>>>0)Ma();else{c[Va>>2]=na;c[na+24>>2]=Wa;c[na+12>>2]=na;c[na+8>>2]=na;break g}}else Xa=ea;while(0);ea=Xa+8|0;ia=c[ea>>2]|0;ma=c[14446]|0;if(ia>>>0>=ma>>>0&Xa>>>0>=ma>>>0){c[ia+12>>2]=na;c[ea>>2]=na;c[na+8>>2]=ia;c[na+12>>2]=Xa;c[na+24>>2]=0;break}else Ma()}}else{ia=c[14446]|0;if((ia|0)==0|ga>>>0<ia>>>0)c[14446]=ga;c[14554]=ga;c[14555]=ha;c[14557]=0;c[14451]=c[14560];c[14450]=-1;ia=0;do{ea=ia<<1;ma=57808+(ea<<2)|0;c[57808+(ea+3<<2)>>2]=ma;c[57808+(ea+2<<2)>>2]=ma;ia=ia+1|0}while((ia|0)!=32);ia=ga+8|0;ma=(ia&7|0)==0?0:0-ia&7;ia=ha+-40-ma|0;c[14448]=ga+ma;c[14445]=ia;c[ga+(ma+4)>>2]=ia|1;c[ga+(ha+-36)>>2]=40;c[14449]=c[14564]}while(0);ha=c[14445]|0;if(ha>>>0>F>>>0){ga=ha-F|0;c[14445]=ga;ha=c[14448]|0;c[14448]=ha+F;c[ha+(F+4)>>2]=ga|1;c[ha+4>>2]=F|3;n=ha+8|0;return n|0}}c[(Ja()|0)>>2]=12;n=0;return n|0}function yd(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;if(!a)return;b=a+-8|0;d=c[14446]|0;if(b>>>0<d>>>0)Ma();e=c[a+-4>>2]|0;f=e&3;if((f|0)==1)Ma();g=e&-8;h=a+(g+-8)|0;do if(!(e&1)){i=c[b>>2]|0;if(!f)return;j=-8-i|0;k=a+j|0;l=i+g|0;if(k>>>0<d>>>0)Ma();if((k|0)==(c[14447]|0)){m=a+(g+-4)|0;n=c[m>>2]|0;if((n&3|0)!=3){o=k;p=l;break}c[14444]=l;c[m>>2]=n&-2;c[a+(j+4)>>2]=l|1;c[h>>2]=l;return}n=i>>>3;if(i>>>0<256){i=c[a+(j+8)>>2]|0;m=c[a+(j+12)>>2]|0;q=57808+(n<<1<<2)|0;if((i|0)!=(q|0)){if(i>>>0<d>>>0)Ma();if((c[i+12>>2]|0)!=(k|0))Ma()}if((m|0)==(i|0)){c[14442]=c[14442]&~(1<<n);o=k;p=l;break}if((m|0)!=(q|0)){if(m>>>0<d>>>0)Ma();q=m+8|0;if((c[q>>2]|0)==(k|0))r=q;else Ma()}else r=m+8|0;c[i+12>>2]=m;c[r>>2]=i;o=k;p=l;break}i=c[a+(j+24)>>2]|0;m=c[a+(j+12)>>2]|0;do if((m|0)==(k|0)){q=a+(j+20)|0;n=c[q>>2]|0;if(!n){s=a+(j+16)|0;t=c[s>>2]|0;if(!t){u=0;break}else{v=t;w=s}}else{v=n;w=q}while(1){q=v+20|0;n=c[q>>2]|0;if(n){v=n;w=q;continue}q=v+16|0;n=c[q>>2]|0;if(!n){x=v;y=w;break}else{v=n;w=q}}if(y>>>0<d>>>0)Ma();else{c[y>>2]=0;u=x;break}}else{q=c[a+(j+8)>>2]|0;if(q>>>0<d>>>0)Ma();n=q+12|0;if((c[n>>2]|0)!=(k|0))Ma();s=m+8|0;if((c[s>>2]|0)==(k|0)){c[n>>2]=m;c[s>>2]=q;u=m;break}else Ma()}while(0);if(i){m=c[a+(j+28)>>2]|0;q=58072+(m<<2)|0;if((k|0)==(c[q>>2]|0)){c[q>>2]=u;if(!u){c[14443]=c[14443]&~(1<<m);o=k;p=l;break}}else{if(i>>>0<(c[14446]|0)>>>0)Ma();m=i+16|0;if((c[m>>2]|0)==(k|0))c[m>>2]=u;else c[i+20>>2]=u;if(!u){o=k;p=l;break}}m=c[14446]|0;if(u>>>0<m>>>0)Ma();c[u+24>>2]=i;q=c[a+(j+16)>>2]|0;do if(q)if(q>>>0<m>>>0)Ma();else{c[u+16>>2]=q;c[q+24>>2]=u;break}while(0);q=c[a+(j+20)>>2]|0;if(q)if(q>>>0<(c[14446]|0)>>>0)Ma();else{c[u+20>>2]=q;c[q+24>>2]=u;o=k;p=l;break}else{o=k;p=l}}else{o=k;p=l}}else{o=b;p=g}while(0);if(o>>>0>=h>>>0)Ma();b=a+(g+-4)|0;u=c[b>>2]|0;if(!(u&1))Ma();if(!(u&2)){if((h|0)==(c[14448]|0)){d=(c[14445]|0)+p|0;c[14445]=d;c[14448]=o;c[o+4>>2]=d|1;if((o|0)!=(c[14447]|0))return;c[14447]=0;c[14444]=0;return}if((h|0)==(c[14447]|0)){d=(c[14444]|0)+p|0;c[14444]=d;c[14447]=o;c[o+4>>2]=d|1;c[o+d>>2]=d;return}d=(u&-8)+p|0;x=u>>>3;do if(u>>>0>=256){y=c[a+(g+16)>>2]|0;w=c[a+(g|4)>>2]|0;do if((w|0)==(h|0)){v=a+(g+12)|0;r=c[v>>2]|0;if(!r){f=a+(g+8)|0;e=c[f>>2]|0;if(!e){z=0;break}else{A=e;B=f}}else{A=r;B=v}while(1){v=A+20|0;r=c[v>>2]|0;if(r){A=r;B=v;continue}v=A+16|0;r=c[v>>2]|0;if(!r){C=A;D=B;break}else{A=r;B=v}}if(D>>>0<(c[14446]|0)>>>0)Ma();else{c[D>>2]=0;z=C;break}}else{v=c[a+g>>2]|0;if(v>>>0<(c[14446]|0)>>>0)Ma();r=v+12|0;if((c[r>>2]|0)!=(h|0))Ma();f=w+8|0;if((c[f>>2]|0)==(h|0)){c[r>>2]=w;c[f>>2]=v;z=w;break}else Ma()}while(0);if(y){w=c[a+(g+20)>>2]|0;l=58072+(w<<2)|0;if((h|0)==(c[l>>2]|0)){c[l>>2]=z;if(!z){c[14443]=c[14443]&~(1<<w);break}}else{if(y>>>0<(c[14446]|0)>>>0)Ma();w=y+16|0;if((c[w>>2]|0)==(h|0))c[w>>2]=z;else c[y+20>>2]=z;if(!z)break}w=c[14446]|0;if(z>>>0<w>>>0)Ma();c[z+24>>2]=y;l=c[a+(g+8)>>2]|0;do if(l)if(l>>>0<w>>>0)Ma();else{c[z+16>>2]=l;c[l+24>>2]=z;break}while(0);l=c[a+(g+12)>>2]|0;if(l)if(l>>>0<(c[14446]|0)>>>0)Ma();else{c[z+20>>2]=l;c[l+24>>2]=z;break}}}else{l=c[a+g>>2]|0;w=c[a+(g|4)>>2]|0;y=57808+(x<<1<<2)|0;if((l|0)!=(y|0)){if(l>>>0<(c[14446]|0)>>>0)Ma();if((c[l+12>>2]|0)!=(h|0))Ma()}if((w|0)==(l|0)){c[14442]=c[14442]&~(1<<x);break}if((w|0)!=(y|0)){if(w>>>0<(c[14446]|0)>>>0)Ma();y=w+8|0;if((c[y>>2]|0)==(h|0))E=y;else Ma()}else E=w+8|0;c[l+12>>2]=w;c[E>>2]=l}while(0);c[o+4>>2]=d|1;c[o+d>>2]=d;if((o|0)==(c[14447]|0)){c[14444]=d;return}else F=d}else{c[b>>2]=u&-2;c[o+4>>2]=p|1;c[o+p>>2]=p;F=p}p=F>>>3;if(F>>>0<256){u=p<<1;b=57808+(u<<2)|0;d=c[14442]|0;E=1<<p;if(d&E){p=57808+(u+2<<2)|0;h=c[p>>2]|0;if(h>>>0<(c[14446]|0)>>>0)Ma();else{G=p;H=h}}else{c[14442]=d|E;G=57808+(u+2<<2)|0;H=b}c[G>>2]=o;c[H+12>>2]=o;c[o+8>>2]=H;c[o+12>>2]=b;return}b=F>>>8;if(b)if(F>>>0>16777215)I=31;else{H=(b+1048320|0)>>>16&8;G=b<<H;b=(G+520192|0)>>>16&4;u=G<<b;G=(u+245760|0)>>>16&2;E=14-(b|H|G)+(u<<G>>>15)|0;I=F>>>(E+7|0)&1|E<<1}else I=0;E=58072+(I<<2)|0;c[o+28>>2]=I;c[o+20>>2]=0;c[o+16>>2]=0;G=c[14443]|0;u=1<<I;a:do if(G&u){H=c[E>>2]|0;b:do if((c[H+4>>2]&-8|0)!=(F|0)){b=F<<((I|0)==31?0:25-(I>>>1)|0);d=H;while(1){h=d+16+(b>>>31<<2)|0;p=c[h>>2]|0;if(!p){J=h;K=d;break}if((c[p+4>>2]&-8|0)==(F|0)){L=p;break b}else{b=b<<1;d=p}}if(J>>>0<(c[14446]|0)>>>0)Ma();else{c[J>>2]=o;c[o+24>>2]=K;c[o+12>>2]=o;c[o+8>>2]=o;break a}}else L=H;while(0);H=L+8|0;d=c[H>>2]|0;b=c[14446]|0;if(d>>>0>=b>>>0&L>>>0>=b>>>0){c[d+12>>2]=o;c[H>>2]=o;c[o+8>>2]=d;c[o+12>>2]=L;c[o+24>>2]=0;break}else Ma()}else{c[14443]=G|u;c[E>>2]=o;c[o+24>>2]=E;c[o+12>>2]=o;c[o+8>>2]=o}while(0);o=(c[14450]|0)+-1|0;c[14450]=o;if(!o)M=58224;else return;while(1){o=c[M>>2]|0;if(!o)break;else M=o+8|0}c[14450]=-1;return}function zd(a,b){a=a|0;b=b|0;var d=0,e=0;if(a){d=_(b,a)|0;if((b|a)>>>0>65535)e=((d>>>0)/(a>>>0)|0|0)==(b|0)?d:-1;else e=d}else e=0;d=xd(e)|0;if(!d)return d|0;if(!(c[d+-4>>2]&3))return d|0;Fd(d|0,0,e|0)|0;return d|0}function Ad(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;if(!a){d=xd(b)|0;return d|0}if(b>>>0>4294967231){c[(Ja()|0)>>2]=12;d=0;return d|0}e=Bd(a+-8|0,b>>>0<11?16:b+11&-8)|0;if(e){d=e+8|0;return d|0}e=xd(b)|0;if(!e){d=0;return d|0}f=c[a+-4>>2]|0;g=(f&-8)-((f&3|0)==0?8:4)|0;Jd(e|0,a|0,(g>>>0<b>>>0?g:b)|0)|0;yd(a);d=e;return d|0}function Bd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0;d=a+4|0;e=c[d>>2]|0;f=e&-8;g=a+f|0;h=c[14446]|0;i=e&3;if(!((i|0)!=1&a>>>0>=h>>>0&a>>>0<g>>>0))Ma();j=a+(f|4)|0;k=c[j>>2]|0;if(!(k&1))Ma();if(!i){if(b>>>0<256){l=0;return l|0}if(f>>>0>=(b+4|0)>>>0?(f-b|0)>>>0<=c[14562]<<1>>>0:0){l=a;return l|0}l=0;return l|0}if(f>>>0>=b>>>0){i=f-b|0;if(i>>>0<=15){l=a;return l|0}c[d>>2]=e&1|b|2;c[a+(b+4)>>2]=i|3;c[j>>2]=c[j>>2]|1;Cd(a+b|0,i);l=a;return l|0}if((g|0)==(c[14448]|0)){i=(c[14445]|0)+f|0;if(i>>>0<=b>>>0){l=0;return l|0}j=i-b|0;c[d>>2]=e&1|b|2;c[a+(b+4)>>2]=j|1;c[14448]=a+b;c[14445]=j;l=a;return l|0}if((g|0)==(c[14447]|0)){j=(c[14444]|0)+f|0;if(j>>>0<b>>>0){l=0;return l|0}i=j-b|0;if(i>>>0>15){c[d>>2]=e&1|b|2;c[a+(b+4)>>2]=i|1;c[a+j>>2]=i;m=a+(j+4)|0;c[m>>2]=c[m>>2]&-2;n=a+b|0;o=i}else{c[d>>2]=e&1|j|2;i=a+(j+4)|0;c[i>>2]=c[i>>2]|1;n=0;o=0}c[14444]=o;c[14447]=n;l=a;return l|0}if(k&2){l=0;return l|0}n=(k&-8)+f|0;if(n>>>0<b>>>0){l=0;return l|0}o=n-b|0;i=k>>>3;do if(k>>>0>=256){j=c[a+(f+24)>>2]|0;m=c[a+(f+12)>>2]|0;do if((m|0)==(g|0)){p=a+(f+20)|0;q=c[p>>2]|0;if(!q){r=a+(f+16)|0;s=c[r>>2]|0;if(!s){t=0;break}else{u=s;v=r}}else{u=q;v=p}while(1){p=u+20|0;q=c[p>>2]|0;if(q){u=q;v=p;continue}p=u+16|0;q=c[p>>2]|0;if(!q){w=u;x=v;break}else{u=q;v=p}}if(x>>>0<h>>>0)Ma();else{c[x>>2]=0;t=w;break}}else{p=c[a+(f+8)>>2]|0;if(p>>>0<h>>>0)Ma();q=p+12|0;if((c[q>>2]|0)!=(g|0))Ma();r=m+8|0;if((c[r>>2]|0)==(g|0)){c[q>>2]=m;c[r>>2]=p;t=m;break}else Ma()}while(0);if(j){m=c[a+(f+28)>>2]|0;p=58072+(m<<2)|0;if((g|0)==(c[p>>2]|0)){c[p>>2]=t;if(!t){c[14443]=c[14443]&~(1<<m);break}}else{if(j>>>0<(c[14446]|0)>>>0)Ma();m=j+16|0;if((c[m>>2]|0)==(g|0))c[m>>2]=t;else c[j+20>>2]=t;if(!t)break}m=c[14446]|0;if(t>>>0<m>>>0)Ma();c[t+24>>2]=j;p=c[a+(f+16)>>2]|0;do if(p)if(p>>>0<m>>>0)Ma();else{c[t+16>>2]=p;c[p+24>>2]=t;break}while(0);p=c[a+(f+20)>>2]|0;if(p)if(p>>>0<(c[14446]|0)>>>0)Ma();else{c[t+20>>2]=p;c[p+24>>2]=t;break}}}else{p=c[a+(f+8)>>2]|0;m=c[a+(f+12)>>2]|0;j=57808+(i<<1<<2)|0;if((p|0)!=(j|0)){if(p>>>0<h>>>0)Ma();if((c[p+12>>2]|0)!=(g|0))Ma()}if((m|0)==(p|0)){c[14442]=c[14442]&~(1<<i);break}if((m|0)!=(j|0)){if(m>>>0<h>>>0)Ma();j=m+8|0;if((c[j>>2]|0)==(g|0))y=j;else Ma()}else y=m+8|0;c[p+12>>2]=m;c[y>>2]=p}while(0);if(o>>>0<16){c[d>>2]=n|e&1|2;y=a+(n|4)|0;c[y>>2]=c[y>>2]|1;l=a;return l|0}else{c[d>>2]=e&1|b|2;c[a+(b+4)>>2]=o|3;e=a+(n|4)|0;c[e>>2]=c[e>>2]|1;Cd(a+b|0,o);l=a;return l|0}return 0}function Cd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;d=a+b|0;e=c[a+4>>2]|0;do if(!(e&1)){f=c[a>>2]|0;if(!(e&3))return;g=a+(0-f)|0;h=f+b|0;i=c[14446]|0;if(g>>>0<i>>>0)Ma();if((g|0)==(c[14447]|0)){j=a+(b+4)|0;k=c[j>>2]|0;if((k&3|0)!=3){l=g;m=h;break}c[14444]=h;c[j>>2]=k&-2;c[a+(4-f)>>2]=h|1;c[d>>2]=h;return}k=f>>>3;if(f>>>0<256){j=c[a+(8-f)>>2]|0;n=c[a+(12-f)>>2]|0;o=57808+(k<<1<<2)|0;if((j|0)!=(o|0)){if(j>>>0<i>>>0)Ma();if((c[j+12>>2]|0)!=(g|0))Ma()}if((n|0)==(j|0)){c[14442]=c[14442]&~(1<<k);l=g;m=h;break}if((n|0)!=(o|0)){if(n>>>0<i>>>0)Ma();o=n+8|0;if((c[o>>2]|0)==(g|0))p=o;else Ma()}else p=n+8|0;c[j+12>>2]=n;c[p>>2]=j;l=g;m=h;break}j=c[a+(24-f)>>2]|0;n=c[a+(12-f)>>2]|0;do if((n|0)==(g|0)){o=16-f|0;k=a+(o+4)|0;q=c[k>>2]|0;if(!q){r=a+o|0;o=c[r>>2]|0;if(!o){s=0;break}else{t=o;u=r}}else{t=q;u=k}while(1){k=t+20|0;q=c[k>>2]|0;if(q){t=q;u=k;continue}k=t+16|0;q=c[k>>2]|0;if(!q){v=t;w=u;break}else{t=q;u=k}}if(w>>>0<i>>>0)Ma();else{c[w>>2]=0;s=v;break}}else{k=c[a+(8-f)>>2]|0;if(k>>>0<i>>>0)Ma();q=k+12|0;if((c[q>>2]|0)!=(g|0))Ma();r=n+8|0;if((c[r>>2]|0)==(g|0)){c[q>>2]=n;c[r>>2]=k;s=n;break}else Ma()}while(0);if(j){n=c[a+(28-f)>>2]|0;i=58072+(n<<2)|0;if((g|0)==(c[i>>2]|0)){c[i>>2]=s;if(!s){c[14443]=c[14443]&~(1<<n);l=g;m=h;break}}else{if(j>>>0<(c[14446]|0)>>>0)Ma();n=j+16|0;if((c[n>>2]|0)==(g|0))c[n>>2]=s;else c[j+20>>2]=s;if(!s){l=g;m=h;break}}n=c[14446]|0;if(s>>>0<n>>>0)Ma();c[s+24>>2]=j;i=16-f|0;k=c[a+i>>2]|0;do if(k)if(k>>>0<n>>>0)Ma();else{c[s+16>>2]=k;c[k+24>>2]=s;break}while(0);k=c[a+(i+4)>>2]|0;if(k)if(k>>>0<(c[14446]|0)>>>0)Ma();else{c[s+20>>2]=k;c[k+24>>2]=s;l=g;m=h;break}else{l=g;m=h}}else{l=g;m=h}}else{l=a;m=b}while(0);s=c[14446]|0;if(d>>>0<s>>>0)Ma();v=a+(b+4)|0;w=c[v>>2]|0;if(!(w&2)){if((d|0)==(c[14448]|0)){u=(c[14445]|0)+m|0;c[14445]=u;c[14448]=l;c[l+4>>2]=u|1;if((l|0)!=(c[14447]|0))return;c[14447]=0;c[14444]=0;return}if((d|0)==(c[14447]|0)){u=(c[14444]|0)+m|0;c[14444]=u;c[14447]=l;c[l+4>>2]=u|1;c[l+u>>2]=u;return}u=(w&-8)+m|0;t=w>>>3;do if(w>>>0>=256){p=c[a+(b+24)>>2]|0;e=c[a+(b+12)>>2]|0;do if((e|0)==(d|0)){k=a+(b+20)|0;n=c[k>>2]|0;if(!n){f=a+(b+16)|0;j=c[f>>2]|0;if(!j){x=0;break}else{y=j;z=f}}else{y=n;z=k}while(1){k=y+20|0;n=c[k>>2]|0;if(n){y=n;z=k;continue}k=y+16|0;n=c[k>>2]|0;if(!n){A=y;B=z;break}else{y=n;z=k}}if(B>>>0<s>>>0)Ma();else{c[B>>2]=0;x=A;break}}else{k=c[a+(b+8)>>2]|0;if(k>>>0<s>>>0)Ma();n=k+12|0;if((c[n>>2]|0)!=(d|0))Ma();f=e+8|0;if((c[f>>2]|0)==(d|0)){c[n>>2]=e;c[f>>2]=k;x=e;break}else Ma()}while(0);if(p){e=c[a+(b+28)>>2]|0;h=58072+(e<<2)|0;if((d|0)==(c[h>>2]|0)){c[h>>2]=x;if(!x){c[14443]=c[14443]&~(1<<e);break}}else{if(p>>>0<(c[14446]|0)>>>0)Ma();e=p+16|0;if((c[e>>2]|0)==(d|0))c[e>>2]=x;else c[p+20>>2]=x;if(!x)break}e=c[14446]|0;if(x>>>0<e>>>0)Ma();c[x+24>>2]=p;h=c[a+(b+16)>>2]|0;do if(h)if(h>>>0<e>>>0)Ma();else{c[x+16>>2]=h;c[h+24>>2]=x;break}while(0);h=c[a+(b+20)>>2]|0;if(h)if(h>>>0<(c[14446]|0)>>>0)Ma();else{c[x+20>>2]=h;c[h+24>>2]=x;break}}}else{h=c[a+(b+8)>>2]|0;e=c[a+(b+12)>>2]|0;p=57808+(t<<1<<2)|0;if((h|0)!=(p|0)){if(h>>>0<s>>>0)Ma();if((c[h+12>>2]|0)!=(d|0))Ma()}if((e|0)==(h|0)){c[14442]=c[14442]&~(1<<t);break}if((e|0)!=(p|0)){if(e>>>0<s>>>0)Ma();p=e+8|0;if((c[p>>2]|0)==(d|0))C=p;else Ma()}else C=e+8|0;c[h+12>>2]=e;c[C>>2]=h}while(0);c[l+4>>2]=u|1;c[l+u>>2]=u;if((l|0)==(c[14447]|0)){c[14444]=u;return}else D=u}else{c[v>>2]=w&-2;c[l+4>>2]=m|1;c[l+m>>2]=m;D=m}m=D>>>3;if(D>>>0<256){w=m<<1;v=57808+(w<<2)|0;u=c[14442]|0;C=1<<m;if(u&C){m=57808+(w+2<<2)|0;d=c[m>>2]|0;if(d>>>0<(c[14446]|0)>>>0)Ma();else{E=m;F=d}}else{c[14442]=u|C;E=57808+(w+2<<2)|0;F=v}c[E>>2]=l;c[F+12>>2]=l;c[l+8>>2]=F;c[l+12>>2]=v;return}v=D>>>8;if(v)if(D>>>0>16777215)G=31;else{F=(v+1048320|0)>>>16&8;E=v<<F;v=(E+520192|0)>>>16&4;w=E<<v;E=(w+245760|0)>>>16&2;C=14-(v|F|E)+(w<<E>>>15)|0;G=D>>>(C+7|0)&1|C<<1}else G=0;C=58072+(G<<2)|0;c[l+28>>2]=G;c[l+20>>2]=0;c[l+16>>2]=0;E=c[14443]|0;w=1<<G;if(!(E&w)){c[14443]=E|w;c[C>>2]=l;c[l+24>>2]=C;c[l+12>>2]=l;c[l+8>>2]=l;return}w=c[C>>2]|0;a:do if((c[w+4>>2]&-8|0)==(D|0))H=w;else{C=D<<((G|0)==31?0:25-(G>>>1)|0);E=w;while(1){F=E+16+(C>>>31<<2)|0;v=c[F>>2]|0;if(!v){I=F;J=E;break}if((c[v+4>>2]&-8|0)==(D|0)){H=v;break a}else{C=C<<1;E=v}}if(I>>>0<(c[14446]|0)>>>0)Ma();c[I>>2]=l;c[l+24>>2]=J;c[l+12>>2]=l;c[l+8>>2]=l;return}while(0);J=H+8|0;I=c[J>>2]|0;D=c[14446]|0;if(!(I>>>0>=D>>>0&H>>>0>=D>>>0))Ma();c[I+12>>2]=l;c[J>>2]=l;c[l+8>>2]=I;c[l+12>>2]=H;c[l+24>>2]=0;return}function Dd(){}function Ed(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=b-d>>>0;e=b-d-(c>>>0>a>>>0|0)>>>0;return (C=e,a-c>>>0|0)|0}function Fd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;g=b&3;h=d|d<<8|d<<16|d<<24;i=f&~3;if(g){g=b+4-g|0;while((b|0)<(g|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(i|0)){c[b>>2]=h;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function Gd(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<<c|(a&(1<<c)-1<<32-c)>>>32-c;return a<<c}C=a<<c-32;return 0}function Hd(b){b=b|0;var c=0;c=b;while(a[c>>0]|0)c=c+1|0;return c-b|0}function Id(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=a+c>>>0;return (C=b+d+(e>>>0<a>>>0|0)>>>0,e|0)|0}function Jd(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return Ia(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function Kd(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<<c)-1)<<32-c}C=0;return b>>>c-32|0}function Ld(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>c;return a>>>c|(b&(1<<c)-1)<<32-c}C=(b|0)<0?-1:0;return b>>c-32|0}function Md(b){b=b|0;var c=0;c=a[m+(b&255)>>0]|0;if((c|0)<8)return c|0;c=a[m+(b>>8&255)>>0]|0;if((c|0)<8)return c+8|0;c=a[m+(b>>16&255)>>0]|0;if((c|0)<8)return c+16|0;return (a[m+(b>>>24)>>0]|0)+24|0}function Nd(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;c=a&65535;d=b&65535;e=_(d,c)|0;f=a>>>16;a=(e>>>16)+(_(d,f)|0)|0;d=b>>>16;b=_(d,c)|0;return (C=(a>>>16)+(_(d,f)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|e&65535|0)|0}function Od(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b>>31|((b|0)<0?-1:0)<<1;f=((b|0)<0?-1:0)>>31|((b|0)<0?-1:0)<<1;g=d>>31|((d|0)<0?-1:0)<<1;h=((d|0)<0?-1:0)>>31|((d|0)<0?-1:0)<<1;i=Ed(e^a,f^b,e,f)|0;b=C;a=g^e;e=h^f;return Ed((Td(i,b,Ed(g^c,h^d,g,h)|0,C,0)|0)^a,C^e,a,e)|0}function Pd(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+8|0;g=f|0;h=b>>31|((b|0)<0?-1:0)<<1;j=((b|0)<0?-1:0)>>31|((b|0)<0?-1:0)<<1;k=e>>31|((e|0)<0?-1:0)<<1;l=((e|0)<0?-1:0)>>31|((e|0)<0?-1:0)<<1;m=Ed(h^a,j^b,h,j)|0;b=C;Td(m,b,Ed(k^d,l^e,k,l)|0,C,g)|0;l=Ed(c[g>>2]^h,c[g+4>>2]^j,h,j)|0;j=C;i=f;return (C=j,l)|0}function Qd(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;a=c;c=Nd(e,a)|0;f=C;return (C=(_(b,a)|0)+(_(d,e)|0)+f|f&0,c|0|0)|0}function Rd(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return Td(a,b,c,d,0)|0}function Sd(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+8|0;g=f|0;Td(a,b,d,e,g)|0;i=f;return (C=c[g+4>>2]|0,c[g>>2]|0)|0}function Td(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0;g=a;h=b;i=h;j=d;k=e;l=k;if(!i){m=(f|0)!=0;if(!l){if(m){c[f>>2]=(g>>>0)%(j>>>0);c[f+4>>2]=0}n=0;o=(g>>>0)/(j>>>0)>>>0;return (C=n,o)|0}else{if(!m){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=b&0;n=0;o=0;return (C=n,o)|0}}m=(l|0)==0;do if(j){if(!m){p=(aa(l|0)|0)-(aa(i|0)|0)|0;if(p>>>0<=31){q=p+1|0;r=31-p|0;s=p-31>>31;t=q;u=g>>>(q>>>0)&s|i<<r;v=i>>>(q>>>0)&s;w=0;x=g<<r;break}if(!f){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=h|b&0;n=0;o=0;return (C=n,o)|0}r=j-1|0;if(r&j){s=(aa(j|0)|0)+33-(aa(i|0)|0)|0;q=64-s|0;p=32-s|0;y=p>>31;z=s-32|0;A=z>>31;t=s;u=p-1>>31&i>>>(z>>>0)|(i<<p|g>>>(s>>>0))&A;v=A&i>>>(s>>>0);w=g<<q&y;x=(i<<q|g>>>(z>>>0))&y|g<<p&s-33>>31;break}if(f){c[f>>2]=r&g;c[f+4>>2]=0}if((j|0)==1){n=h|b&0;o=a|0|0;return (C=n,o)|0}else{r=Md(j|0)|0;n=i>>>(r>>>0)|0;o=i<<32-r|g>>>(r>>>0)|0;return (C=n,o)|0}}else{if(m){if(f){c[f>>2]=(i>>>0)%(j>>>0);c[f+4>>2]=0}n=0;o=(i>>>0)/(j>>>0)>>>0;return (C=n,o)|0}if(!g){if(f){c[f>>2]=0;c[f+4>>2]=(i>>>0)%(l>>>0)}n=0;o=(i>>>0)/(l>>>0)>>>0;return (C=n,o)|0}r=l-1|0;if(!(r&l)){if(f){c[f>>2]=a|0;c[f+4>>2]=r&i|b&0}n=0;o=i>>>((Md(l|0)|0)>>>0);return (C=n,o)|0}r=(aa(l|0)|0)-(aa(i|0)|0)|0;if(r>>>0<=30){s=r+1|0;p=31-r|0;t=s;u=i<<p|g>>>(s>>>0);v=i>>>(s>>>0);w=0;x=g<<p;break}if(!f){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=h|b&0;n=0;o=0;return (C=n,o)|0}while(0);if(!t){B=x;D=w;E=v;F=u;G=0;H=0}else{b=d|0|0;d=k|e&0;e=Id(b|0,d|0,-1,-1)|0;k=C;h=x;x=w;w=v;v=u;u=t;t=0;do{a=h;h=x>>>31|h<<1;x=t|x<<1;g=v<<1|a>>>31|0;a=v>>>31|w<<1|0;Ed(e,k,g,a)|0;i=C;l=i>>31|((i|0)<0?-1:0)<<1;t=l&1;v=Ed(g,a,l&b,(((i|0)<0?-1:0)>>31|((i|0)<0?-1:0)<<1)&d)|0;w=C;u=u-1|0}while((u|0)!=0);B=h;D=x;E=w;F=v;G=0;H=t}t=D;D=0;if(f){c[f>>2]=F;c[f+4>>2]=E}n=(t|0)>>>31|(B|D)<<1|(D<<1|t>>>31)&0|G;o=(t<<1|0>>>31)&-2|H;return (C=n,o)|0}function Ud(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Va[a&7](b|0,c|0,d|0,e|0)|0}function Vd(a,b){a=a|0;b=b|0;Wa[a&7](b|0)}function Wd(a,b,c){a=a|0;b=b|0;c=c|0;Xa[a&3](b|0,c|0)}function Xd(a,b){a=a|0;b=b|0;return Ya[a&1](b|0)|0}function Yd(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;Za[a&1](b|0,c|0,d|0)}function Zd(a,b,c,d,e,f,g,h,i){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;return _a[a&3](b|0,c|0,d|0,e|0,f|0,g|0,h|0,i|0)|0}function _d(a,b,c){a=a|0;b=b|0;c=c|0;return $a[a&15](b|0,c|0)|0}function $d(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return ab[a&7](b|0,c|0,d|0,e|0,f|0)|0}function ae(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;ba(0);return 0}function be(a){a=a|0;ba(1)}function ce(a,b){a=a|0;b=b|0;ba(2)}function de(a){a=a|0;ba(3);return 0}function ee(a,b,c){a=a|0;b=b|0;c=c|0;ba(4)}function fe(a,b,c,d,e,f,g,h){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;ba(5);return 0}function ge(a,b){a=a|0;b=b|0;ba(6);return 0}function he(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;ba(7);return 0}
+
+// EMSCRIPTEN_END_FUNCS
+var Va=[ae,$c,fd,qc,rc,ae,ae,ae];var Wa=[be,Yc,Zc,cd,dd,bc,cc,id];var Xa=[ce,Uc,dc,ce];var Ya=[de,jd];var Za=[ee,gd];var _a=[fe,hc,lc,fe];var $a=[ge,Vc,Xc,_c,ad,bd,ed,ec,fc,hd,kd,Sc,Tc,Wc,ge,ge];var ab=[he,gc,ic,jc,kc,mc,he,he];return{_i64Subtract:Ed,_free:yd,_ogv_audio_decoder_destroy:od,_ogv_audio_decoder_init:ld,_i64Add:Id,_strlen:Hd,_ogv_audio_decoder_process_header:md,_memset:Fd,_malloc:xd,_memcpy:Jd,_ogv_audio_decoder_process_audio:nd,_bitshift64Shl:Gd,runPostSets:Dd,stackAlloc:bb,stackSave:cb,stackRestore:db,establishStackSpace:eb,setThrew:fb,setTempRet0:ib,getTempRet0:jb,dynCall_iiiii:Ud,dynCall_vi:Vd,dynCall_vii:Wd,dynCall_ii:Xd,dynCall_viii:Yd,dynCall_iiiiiiiii:Zd,dynCall_iii:_d,dynCall_iiiiii:$d}})
+
+
+// EMSCRIPTEN_END_ASM
+(Module.asmGlobalArg,Module.asmLibraryArg,buffer);var _i64Subtract=Module["_i64Subtract"]=asm["_i64Subtract"];var _free=Module["_free"]=asm["_free"];var runPostSets=Module["runPostSets"]=asm["runPostSets"];var _ogv_audio_decoder_destroy=Module["_ogv_audio_decoder_destroy"]=asm["_ogv_audio_decoder_destroy"];var _ogv_audio_decoder_init=Module["_ogv_audio_decoder_init"]=asm["_ogv_audio_decoder_init"];var _i64Add=Module["_i64Add"]=asm["_i64Add"];var _strlen=Module["_strlen"]=asm["_strlen"];var _ogv_audio_decoder_process_header=Module["_ogv_audio_decoder_process_header"]=asm["_ogv_audio_decoder_process_header"];var _memset=Module["_memset"]=asm["_memset"];var _malloc=Module["_malloc"]=asm["_malloc"];var _memcpy=Module["_memcpy"]=asm["_memcpy"];var _ogv_audio_decoder_process_audio=Module["_ogv_audio_decoder_process_audio"]=asm["_ogv_audio_decoder_process_audio"];var _bitshift64Shl=Module["_bitshift64Shl"]=asm["_bitshift64Shl"];var dynCall_iiiii=Module["dynCall_iiiii"]=asm["dynCall_iiiii"];var dynCall_vi=Module["dynCall_vi"]=asm["dynCall_vi"];var dynCall_vii=Module["dynCall_vii"]=asm["dynCall_vii"];var dynCall_ii=Module["dynCall_ii"]=asm["dynCall_ii"];var dynCall_viii=Module["dynCall_viii"]=asm["dynCall_viii"];var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=asm["dynCall_iiiiiiiii"];var dynCall_iii=Module["dynCall_iii"]=asm["dynCall_iii"];var dynCall_iiiiii=Module["dynCall_iiiiii"]=asm["dynCall_iiiiii"];Runtime.stackAlloc=asm["stackAlloc"];Runtime.stackSave=asm["stackSave"];Runtime.stackRestore=asm["stackRestore"];Runtime.establishStackSpace=asm["establishStackSpace"];Runtime.setTempRet0=asm["setTempRet0"];Runtime.getTempRet0=asm["getTempRet0"];var i64Math=(function(){var goog={math:{}};goog.math.Long=(function(low,high){this.low_=low|0;this.high_=high|0});goog.math.Long.IntCache_={};goog.math.Long.fromInt=(function(value){if(-128<=value&&value<128){var cachedObj=goog.math.Long.IntCache_[value];if(cachedObj){return cachedObj}}var obj=new goog.math.Long(value|0,value<0?-1:0);if(-128<=value&&value<128){goog.math.Long.IntCache_[value]=obj}return obj});goog.math.Long.fromNumber=(function(value){if(isNaN(value)||!isFinite(value)){return goog.math.Long.ZERO}else if(value<=-goog.math.Long.TWO_PWR_63_DBL_){return goog.math.Long.MIN_VALUE}else if(value+1>=goog.math.Long.TWO_PWR_63_DBL_){return goog.math.Long.MAX_VALUE}else if(value<0){return goog.math.Long.fromNumber(-value).negate()}else{return new goog.math.Long(value%goog.math.Long.TWO_PWR_32_DBL_|0,value/goog.math.Long.TWO_PWR_32_DBL_|0)}});goog.math.Long.fromBits=(function(lowBits,highBits){return new goog.math.Long(lowBits,highBits)});goog.math.Long.fromString=(function(str,opt_radix){if(str.length==0){throw Error("number format error: empty string")}var radix=opt_radix||10;if(radix<2||36<radix){throw Error("radix out of range: "+radix)}if(str.charAt(0)=="-"){return goog.math.Long.fromString(str.substring(1),radix).negate()}else if(str.indexOf("-")>=0){throw Error('number format error: interior "-" character: '+str)}var radixToPower=goog.math.Long.fromNumber(Math.pow(radix,8));var result=goog.math.Long.ZERO;for(var i=0;i<str.length;i+=8){var size=Math.min(8,str.length-i);var value=parseInt(str.substring(i,i+size),radix);if(size<8){var power=goog.math.Long.fromNumber(Math.pow(radix,size));result=result.multiply(power).add(goog.math.Long.fromNumber(value))}else{result=result.multiply(radixToPower);result=result.add(goog.math.Long.fromNumber(value))}}return result});goog.math.Long.TWO_PWR_16_DBL_=1<<16;goog.math.Long.TWO_PWR_24_DBL_=1<<24;goog.math.Long.TWO_PWR_32_DBL_=goog.math.Long.TWO_PWR_16_DBL_*goog.math.Long.TWO_PWR_16_DBL_;goog.math.Long.TWO_PWR_31_DBL_=goog.math.Long.TWO_PWR_32_DBL_/2;goog.math.Long.TWO_PWR_48_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_16_DBL_;goog.math.Long.TWO_PWR_64_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_32_DBL_;goog.math.Long.TWO_PWR_63_DBL_=goog.math.Long.TWO_PWR_64_DBL_/2;goog.math.Long.ZERO=goog.math.Long.fromInt(0);goog.math.Long.ONE=goog.math.Long.fromInt(1);goog.math.Long.NEG_ONE=goog.math.Long.fromInt(-1);goog.math.Long.MAX_VALUE=goog.math.Long.fromBits(4294967295|0,2147483647|0);goog.math.Long.MIN_VALUE=goog.math.Long.fromBits(0,2147483648|0);goog.math.Long.TWO_PWR_24_=goog.math.Long.fromInt(1<<24);goog.math.Long.prototype.toInt=(function(){return this.low_});goog.math.Long.prototype.toNumber=(function(){return this.high_*goog.math.Long.TWO_PWR_32_DBL_+this.getLowBitsUnsigned()});goog.math.Long.prototype.toString=(function(opt_radix){var radix=opt_radix||10;if(radix<2||36<radix){throw Error("radix out of range: "+radix)}if(this.isZero()){return"0"}if(this.isNegative()){if(this.equals(goog.math.Long.MIN_VALUE)){var radixLong=goog.math.Long.fromNumber(radix);var div=this.div(radixLong);var rem=div.multiply(radixLong).subtract(this);return div.toString(radix)+rem.toInt().toString(radix)}else{return"-"+this.negate().toString(radix)}}var radixToPower=goog.math.Long.fromNumber(Math.pow(radix,6));var rem=this;var result="";while(true){var remDiv=rem.div(radixToPower);var intval=rem.subtract(remDiv.multiply(radixToPower)).toInt();var digits=intval.toString(radix);rem=remDiv;if(rem.isZero()){return digits+result}else{while(digits.length<6){digits="0"+digits}result=""+digits+result}}});goog.math.Long.prototype.getHighBits=(function(){return this.high_});goog.math.Long.prototype.getLowBits=(function(){return this.low_});goog.math.Long.prototype.getLowBitsUnsigned=(function(){return this.low_>=0?this.low_:goog.math.Long.TWO_PWR_32_DBL_+this.low_});goog.math.Long.prototype.getNumBitsAbs=(function(){if(this.isNegative()){if(this.equals(goog.math.Long.MIN_VALUE)){return 64}else{return this.negate().getNumBitsAbs()}}else{var val=this.high_!=0?this.high_:this.low_;for(var bit=31;bit>0;bit--){if((val&1<<bit)!=0){break}}return this.high_!=0?bit+33:bit+1}});goog.math.Long.prototype.isZero=(function(){return this.high_==0&&this.low_==0});goog.math.Long.prototype.isNegative=(function(){return this.high_<0});goog.math.Long.prototype.isOdd=(function(){return(this.low_&1)==1});goog.math.Long.prototype.equals=(function(other){return this.high_==other.high_&&this.low_==other.low_});goog.math.Long.prototype.notEquals=(function(other){return this.high_!=other.high_||this.low_!=other.low_});goog.math.Long.prototype.lessThan=(function(other){return this.compare(other)<0});goog.math.Long.prototype.lessThanOrEqual=(function(other){return this.compare(other)<=0});goog.math.Long.prototype.greaterThan=(function(other){return this.compare(other)>0});goog.math.Long.prototype.greaterThanOrEqual=(function(other){return this.compare(other)>=0});goog.math.Long.prototype.compare=(function(other){if(this.equals(other)){return 0}var thisNeg=this.isNegative();var otherNeg=other.isNegative();if(thisNeg&&!otherNeg){return-1}if(!thisNeg&&otherNeg){return 1}if(this.subtract(other).isNegative()){return-1}else{return 1}});goog.math.Long.prototype.negate=(function(){if(this.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.MIN_VALUE}else{return this.not().add(goog.math.Long.ONE)}});goog.math.Long.prototype.add=(function(other){var a48=this.high_>>>16;var a32=this.high_&65535;var a16=this.low_>>>16;var a00=this.low_&65535;var b48=other.high_>>>16;var b32=other.high_&65535;var b16=other.low_>>>16;var b00=other.low_&65535;var c48=0,c32=0,c16=0,c00=0;c00+=a00+b00;c16+=c00>>>16;c00&=65535;c16+=a16+b16;c32+=c16>>>16;c16&=65535;c32+=a32+b32;c48+=c32>>>16;c32&=65535;c48+=a48+b48;c48&=65535;return goog.math.Long.fromBits(c16<<16|c00,c48<<16|c32)});goog.math.Long.prototype.subtract=(function(other){return this.add(other.negate())});goog.math.Long.prototype.multiply=(function(other){if(this.isZero()){return goog.math.Long.ZERO}else if(other.isZero()){return goog.math.Long.ZERO}if(this.equals(goog.math.Long.MIN_VALUE)){return other.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO}else if(other.equals(goog.math.Long.MIN_VALUE)){return this.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO}if(this.isNegative()){if(other.isNegative()){return this.negate().multiply(other.negate())}else{return this.negate().multiply(other).negate()}}else if(other.isNegative()){return this.multiply(other.negate()).negate()}if(this.lessThan(goog.math.Long.TWO_PWR_24_)&&other.lessThan(goog.math.Long.TWO_PWR_24_)){return goog.math.Long.fromNumber(this.toNumber()*other.toNumber())}var a48=this.high_>>>16;var a32=this.high_&65535;var a16=this.low_>>>16;var a00=this.low_&65535;var b48=other.high_>>>16;var b32=other.high_&65535;var b16=other.low_>>>16;var b00=other.low_&65535;var c48=0,c32=0,c16=0,c00=0;c00+=a00*b00;c16+=c00>>>16;c00&=65535;c16+=a16*b00;c32+=c16>>>16;c16&=65535;c16+=a00*b16;c32+=c16>>>16;c16&=65535;c32+=a32*b00;c48+=c32>>>16;c32&=65535;c32+=a16*b16;c48+=c32>>>16;c32&=65535;c32+=a00*b32;c48+=c32>>>16;c32&=65535;c48+=a48*b00+a32*b16+a16*b32+a00*b48;c48&=65535;return goog.math.Long.fromBits(c16<<16|c00,c48<<16|c32)});goog.math.Long.prototype.div=(function(other){if(other.isZero()){throw Error("division by zero")}else if(this.isZero()){return goog.math.Long.ZERO}if(this.equals(goog.math.Long.MIN_VALUE)){if(other.equals(goog.math.Long.ONE)||other.equals(goog.math.Long.NEG_ONE)){return goog.math.Long.MIN_VALUE}else if(other.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.ONE}else{var halfThis=this.shiftRight(1);var approx=halfThis.div(other).shiftLeft(1);if(approx.equals(goog.math.Long.ZERO)){return other.isNegative()?goog.math.Long.ONE:goog.math.Long.NEG_ONE}else{var rem=this.subtract(other.multiply(approx));var result=approx.add(rem.div(other));return result}}}else if(other.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.ZERO}if(this.isNegative()){if(other.isNegative()){return this.negate().div(other.negate())}else{return this.negate().div(other).negate()}}else if(other.isNegative()){return this.div(other.negate()).negate()}var res=goog.math.Long.ZERO;var rem=this;while(rem.greaterThanOrEqual(other)){var approx=Math.max(1,Math.floor(rem.toNumber()/other.toNumber()));var log2=Math.ceil(Math.log(approx)/Math.LN2);var delta=log2<=48?1:Math.pow(2,log2-48);var approxRes=goog.math.Long.fromNumber(approx);var approxRem=approxRes.multiply(other);while(approxRem.isNegative()||approxRem.greaterThan(rem)){approx-=delta;approxRes=goog.math.Long.fromNumber(approx);approxRem=approxRes.multiply(other)}if(approxRes.isZero()){approxRes=goog.math.Long.ONE}res=res.add(approxRes);rem=rem.subtract(approxRem)}return res});goog.math.Long.prototype.modulo=(function(other){return this.subtract(this.div(other).multiply(other))});goog.math.Long.prototype.not=(function(){return goog.math.Long.fromBits(~this.low_,~this.high_)});goog.math.Long.prototype.and=(function(other){return goog.math.Long.fromBits(this.low_&other.low_,this.high_&other.high_)});goog.math.Long.prototype.or=(function(other){return goog.math.Long.fromBits(this.low_|other.low_,this.high_|other.high_)});goog.math.Long.prototype.xor=(function(other){return goog.math.Long.fromBits(this.low_^other.low_,this.high_^other.high_)});goog.math.Long.prototype.shiftLeft=(function(numBits){numBits&=63;if(numBits==0){return this}else{var low=this.low_;if(numBits<32){var high=this.high_;return goog.math.Long.fromBits(low<<numBits,high<<numBits|low>>>32-numBits)}else{return goog.math.Long.fromBits(0,low<<numBits-32)}}});goog.math.Long.prototype.shiftRight=(function(numBits){numBits&=63;if(numBits==0){return this}else{var high=this.high_;if(numBits<32){var low=this.low_;return goog.math.Long.fromBits(low>>>numBits|high<<32-numBits,high>>numBits)}else{return goog.math.Long.fromBits(high>>numBits-32,high>=0?0:-1)}}});goog.math.Long.prototype.shiftRightUnsigned=(function(numBits){numBits&=63;if(numBits==0){return this}else{var high=this.high_;if(numBits<32){var low=this.low_;return goog.math.Long.fromBits(low>>>numBits|high<<32-numBits,high>>>numBits)}else if(numBits==32){return goog.math.Long.fromBits(high,0)}else{return goog.math.Long.fromBits(high>>>numBits-32,0)}}});var navigator={appName:"Modern Browser"};var dbits;var canary=0xdeadbeefcafe;var j_lm=(canary&16777215)==15715070;function BigInteger(a,b,c){if(a!=null)if("number"==typeof a)this.fromNumber(a,b,c);else if(b==null&&"string"!=typeof a)this.fromString(a,256);else this.fromString(a,b)}function nbi(){return new BigInteger(null)}function am1(i,x,w,j,c,n){while(--n>=0){var v=x*this[i++]+w[j]+c;c=Math.floor(v/67108864);w[j++]=v&67108863}return c}function am2(i,x,w,j,c,n){var xl=x&32767,xh=x>>15;while(--n>=0){var l=this[i]&32767;var h=this[i++]>>15;var m=xh*l+h*xl;l=xl*l+((m&32767)<<15)+w[j]+(c&1073741823);c=(l>>>30)+(m>>>15)+xh*h+(c>>>30);w[j++]=l&1073741823}return c}function am3(i,x,w,j,c,n){var xl=x&16383,xh=x>>14;while(--n>=0){var l=this[i]&16383;var h=this[i++]>>14;var m=xh*l+h*xl;l=xl*l+((m&16383)<<14)+w[j]+c;c=(l>>28)+(m>>14)+xh*h;w[j++]=l&268435455}return c}if(j_lm&&navigator.appName=="Microsoft Internet Explorer"){BigInteger.prototype.am=am2;dbits=30}else if(j_lm&&navigator.appName!="Netscape"){BigInteger.prototype.am=am1;dbits=26}else{BigInteger.prototype.am=am3;dbits=28}BigInteger.prototype.DB=dbits;BigInteger.prototype.DM=(1<<dbits)-1;BigInteger.prototype.DV=1<<dbits;var BI_FP=52;BigInteger.prototype.FV=Math.pow(2,BI_FP);BigInteger.prototype.F1=BI_FP-dbits;BigInteger.prototype.F2=2*dbits-BI_FP;var BI_RM="0123456789abcdefghijklmnopqrstuvwxyz";var BI_RC=new Array;var rr,vv;rr="0".charCodeAt(0);for(vv=0;vv<=9;++vv)BI_RC[rr++]=vv;rr="a".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;rr="A".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;function int2char(n){return BI_RM.charAt(n)}function intAt(s,i){var c=BI_RC[s.charCodeAt(i)];return c==null?-1:c}function bnpCopyTo(r){for(var i=this.t-1;i>=0;--i)r[i]=this[i];r.t=this.t;r.s=this.s}function bnpFromInt(x){this.t=1;this.s=x<0?-1:0;if(x>0)this[0]=x;else if(x<-1)this[0]=x+DV;else this.t=0}function nbv(i){var r=nbi();r.fromInt(i);return r}function bnpFromString(s,b){var k;if(b==16)k=4;else if(b==8)k=3;else if(b==256)k=8;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else{this.fromRadix(s,b);return}this.t=0;this.s=0;var i=s.length,mi=false,sh=0;while(--i>=0){var x=k==8?s[i]&255:intAt(s,i);if(x<0){if(s.charAt(i)=="-")mi=true;continue}mi=false;if(sh==0)this[this.t++]=x;else if(sh+k>this.DB){this[this.t-1]|=(x&(1<<this.DB-sh)-1)<<sh;this[this.t++]=x>>this.DB-sh}else this[this.t-1]|=x<<sh;sh+=k;if(sh>=this.DB)sh-=this.DB}if(k==8&&(s[0]&128)!=0){this.s=-1;if(sh>0)this[this.t-1]|=(1<<this.DB-sh)-1<<sh}this.clamp();if(mi)BigInteger.ZERO.subTo(this,this)}function bnpClamp(){var c=this.s&this.DM;while(this.t>0&&this[this.t-1]==c)--this.t}function bnToString(b){if(this.s<0)return"-"+this.negate().toString(b);var k;if(b==16)k=4;else if(b==8)k=3;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else return this.toRadix(b);var km=(1<<k)-1,d,m=false,r="",i=this.t;var p=this.DB-i*this.DB%k;if(i-->0){if(p<this.DB&&(d=this[i]>>p)>0){m=true;r=int2char(d)}while(i>=0){if(p<k){d=(this[i]&(1<<p)-1)<<k-p;d|=this[--i]>>(p+=this.DB-k)}else{d=this[i]>>(p-=k)&km;if(p<=0){p+=this.DB;--i}}if(d>0)m=true;if(m)r+=int2char(d)}}return m?r:"0"}function bnNegate(){var r=nbi();BigInteger.ZERO.subTo(this,r);return r}function bnAbs(){return this.s<0?this.negate():this}function bnCompareTo(a){var r=this.s-a.s;if(r!=0)return r;var i=this.t;r=i-a.t;if(r!=0)return this.s<0?-r:r;while(--i>=0)if((r=this[i]-a[i])!=0)return r;return 0}function nbits(x){var r=1,t;if((t=x>>>16)!=0){x=t;r+=16}if((t=x>>8)!=0){x=t;r+=8}if((t=x>>4)!=0){x=t;r+=4}if((t=x>>2)!=0){x=t;r+=2}if((t=x>>1)!=0){x=t;r+=1}return r}function bnBitLength(){if(this.t<=0)return 0;return this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)}function bnpDLShiftTo(n,r){var i;for(i=this.t-1;i>=0;--i)r[i+n]=this[i];for(i=n-1;i>=0;--i)r[i]=0;r.t=this.t+n;r.s=this.s}function bnpDRShiftTo(n,r){for(var i=n;i<this.t;++i)r[i-n]=this[i];r.t=Math.max(this.t-n,0);r.s=this.s}function bnpLShiftTo(n,r){var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<cbs)-1;var ds=Math.floor(n/this.DB),c=this.s<<bs&this.DM,i;for(i=this.t-1;i>=0;--i){r[i+ds+1]=this[i]>>cbs|c;c=(this[i]&bm)<<bs}for(i=ds-1;i>=0;--i)r[i]=0;r[ds]=c;r.t=this.t+ds+1;r.s=this.s;r.clamp()}function bnpRShiftTo(n,r){r.s=this.s;var ds=Math.floor(n/this.DB);if(ds>=this.t){r.t=0;return}var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<bs)-1;r[0]=this[ds]>>bs;for(var i=ds+1;i<this.t;++i){r[i-ds-1]|=(this[i]&bm)<<cbs;r[i-ds]=this[i]>>bs}if(bs>0)r[this.t-ds-1]|=(this.s&bm)<<cbs;r.t=this.t-ds;r.clamp()}function bnpSubTo(a,r){var i=0,c=0,m=Math.min(a.t,this.t);while(i<m){c+=this[i]-a[i];r[i++]=c&this.DM;c>>=this.DB}if(a.t<this.t){c-=a.s;while(i<this.t){c+=this[i];r[i++]=c&this.DM;c>>=this.DB}c+=this.s}else{c+=this.s;while(i<a.t){c-=a[i];r[i++]=c&this.DM;c>>=this.DB}c-=a.s}r.s=c<0?-1:0;if(c<-1)r[i++]=this.DV+c;else if(c>0)r[i++]=c;r.t=i;r.clamp()}function bnpMultiplyTo(a,r){var x=this.abs(),y=a.abs();var i=x.t;r.t=i+y.t;while(--i>=0)r[i]=0;for(i=0;i<y.t;++i)r[i+x.t]=x.am(0,y[i],r,i,0,x.t);r.s=0;r.clamp();if(this.s!=a.s)BigInteger.ZERO.subTo(r,r)}function bnpSquareTo(r){var x=this.abs();var i=r.t=2*x.t;while(--i>=0)r[i]=0;for(i=0;i<x.t-1;++i){var c=x.am(i,x[i],r,2*i,0,1);if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1))>=x.DV){r[i+x.t]-=x.DV;r[i+x.t+1]=1}}if(r.t>0)r[r.t-1]+=x.am(i,x[i],r,2*i,0,1);r.s=0;r.clamp()}function bnpDivRemTo(m,q,r){var pm=m.abs();if(pm.t<=0)return;var pt=this.abs();if(pt.t<pm.t){if(q!=null)q.fromInt(0);if(r!=null)this.copyTo(r);return}if(r==null)r=nbi();var y=nbi(),ts=this.s,ms=m.s;var nsh=this.DB-nbits(pm[pm.t-1]);if(nsh>0){pm.lShiftTo(nsh,y);pt.lShiftTo(nsh,r)}else{pm.copyTo(y);pt.copyTo(r)}var ys=y.t;var y0=y[ys-1];if(y0==0)return;var yt=y0*(1<<this.F1)+(ys>1?y[ys-2]>>this.F2:0);var d1=this.FV/yt,d2=(1<<this.F1)/yt,e=1<<this.F2;var i=r.t,j=i-ys,t=q==null?nbi():q;y.dlShiftTo(j,t);if(r.compareTo(t)>=0){r[r.t++]=1;r.subTo(t,r)}BigInteger.ONE.dlShiftTo(ys,t);t.subTo(y,y);while(y.t<ys)y[y.t++]=0;while(--j>=0){var qd=r[--i]==y0?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);if((r[i]+=y.am(0,qd,r,j,0,ys))<qd){y.dlShiftTo(j,t);r.subTo(t,r);while(r[i]<--qd)r.subTo(t,r)}}if(q!=null){r.drShiftTo(ys,q);if(ts!=ms)BigInteger.ZERO.subTo(q,q)}r.t=ys;r.clamp();if(nsh>0)r.rShiftTo(nsh,r);if(ts<0)BigInteger.ZERO.subTo(r,r)}function bnMod(a){var r=nbi();this.abs().divRemTo(a,null,r);if(this.s<0&&r.compareTo(BigInteger.ZERO)>0)a.subTo(r,r);return r}function Classic(m){this.m=m}function cConvert(x){if(x.s<0||x.compareTo(this.m)>=0)return x.mod(this.m);else return x}function cRevert(x){return x}function cReduce(x){x.divRemTo(this.m,null,x)}function cMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r)}function cSqrTo(x,r){x.squareTo(r);this.reduce(r)}Classic.prototype.convert=cConvert;Classic.prototype.revert=cRevert;Classic.prototype.reduce=cReduce;Classic.prototype.mulTo=cMulTo;Classic.prototype.sqrTo=cSqrTo;function bnpInvDigit(){if(this.t<1)return 0;var x=this[0];if((x&1)==0)return 0;var y=x&3;y=y*(2-(x&15)*y)&15;y=y*(2-(x&255)*y)&255;y=y*(2-((x&65535)*y&65535))&65535;y=y*(2-x*y%this.DV)%this.DV;return y>0?this.DV-y:-y}function Montgomery(m){this.m=m;this.mp=m.invDigit();this.mpl=this.mp&32767;this.mph=this.mp>>15;this.um=(1<<m.DB-15)-1;this.mt2=2*m.t}function montConvert(x){var r=nbi();x.abs().dlShiftTo(this.m.t,r);r.divRemTo(this.m,null,r);if(x.s<0&&r.compareTo(BigInteger.ZERO)>0)this.m.subTo(r,r);return r}function montRevert(x){var r=nbi();x.copyTo(r);this.reduce(r);return r}function montReduce(x){while(x.t<=this.mt2)x[x.t++]=0;for(var i=0;i<this.m.t;++i){var j=x[i]&32767;var u0=j*this.mpl+((j*this.mph+(x[i]>>15)*this.mpl&this.um)<<15)&x.DM;j=i+this.m.t;x[j]+=this.m.am(0,u0,x,i,0,this.m.t);while(x[j]>=x.DV){x[j]-=x.DV;x[++j]++}}x.clamp();x.drShiftTo(this.m.t,x);if(x.compareTo(this.m)>=0)x.subTo(this.m,x)}function montSqrTo(x,r){x.squareTo(r);this.reduce(r)}function montMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r)}Montgomery.prototype.convert=montConvert;Montgomery.prototype.revert=montRevert;Montgomery.prototype.reduce=montReduce;Montgomery.prototype.mulTo=montMulTo;Montgomery.prototype.sqrTo=montSqrTo;function bnpIsEven(){return(this.t>0?this[0]&1:this.s)==0}function bnpExp(e,z){if(e>4294967295||e<1)return BigInteger.ONE;var r=nbi(),r2=nbi(),g=z.convert(this),i=nbits(e)-1;g.copyTo(r);while(--i>=0){z.sqrTo(r,r2);if((e&1<<i)>0)z.mulTo(r2,g,r);else{var t=r;r=r2;r2=t}}return z.revert(r)}function bnModPowInt(e,m){var z;if(e<256||m.isEven())z=new Classic(m);else z=new Montgomery(m);return this.exp(e,z)}BigInteger.prototype.copyTo=bnpCopyTo;BigInteger.prototype.fromInt=bnpFromInt;BigInteger.prototype.fromString=bnpFromString;BigInteger.prototype.clamp=bnpClamp;BigInteger.prototype.dlShiftTo=bnpDLShiftTo;BigInteger.prototype.drShiftTo=bnpDRShiftTo;BigInteger.prototype.lShiftTo=bnpLShiftTo;BigInteger.prototype.rShiftTo=bnpRShiftTo;BigInteger.prototype.subTo=bnpSubTo;BigInteger.prototype.multiplyTo=bnpMultiplyTo;BigInteger.prototype.squareTo=bnpSquareTo;BigInteger.prototype.divRemTo=bnpDivRemTo;BigInteger.prototype.invDigit=bnpInvDigit;BigInteger.prototype.isEven=bnpIsEven;BigInteger.prototype.exp=bnpExp;BigInteger.prototype.toString=bnToString;BigInteger.prototype.negate=bnNegate;BigInteger.prototype.abs=bnAbs;BigInteger.prototype.compareTo=bnCompareTo;BigInteger.prototype.bitLength=bnBitLength;BigInteger.prototype.mod=bnMod;BigInteger.prototype.modPowInt=bnModPowInt;BigInteger.ZERO=nbv(0);BigInteger.ONE=nbv(1);function bnpFromRadix(s,b){this.fromInt(0);if(b==null)b=10;var cs=this.chunkSize(b);var d=Math.pow(b,cs),mi=false,j=0,w=0;for(var i=0;i<s.length;++i){var x=intAt(s,i);if(x<0){if(s.charAt(i)=="-"&&this.signum()==0)mi=true;continue}w=b*w+x;if(++j>=cs){this.dMultiply(d);this.dAddOffset(w,0);j=0;w=0}}if(j>0){this.dMultiply(Math.pow(b,j));this.dAddOffset(w,0)}if(mi)BigInteger.ZERO.subTo(this,this)}function bnpChunkSize(r){return Math.floor(Math.LN2*this.DB/Math.log(r))}function bnSigNum(){if(this.s<0)return-1;else if(this.t<=0||this.t==1&&this[0]<=0)return 0;else return 1}function bnpDMultiply(n){this[this.t]=this.am(0,n-1,this,0,0,this.t);++this.t;this.clamp()}function bnpDAddOffset(n,w){if(n==0)return;while(this.t<=w)this[this.t++]=0;this[w]+=n;while(this[w]>=this.DV){this[w]-=this.DV;if(++w>=this.t)this[this.t++]=0;++this[w]}}function bnpToRadix(b){if(b==null)b=10;if(this.signum()==0||b<2||b>36)return"0";var cs=this.chunkSize(b);var a=Math.pow(b,cs);var d=nbv(a),y=nbi(),z=nbi(),r="";this.divRemTo(d,y,z);while(y.signum()>0){r=(a+z.intValue()).toString(b).substr(1)+r;y.divRemTo(d,y,z)}return z.intValue().toString(b)+r}function bnIntValue(){if(this.s<0){if(this.t==1)return this[0]-this.DV;else if(this.t==0)return-1}else if(this.t==1)return this[0];else if(this.t==0)return 0;return(this[1]&(1<<32-this.DB)-1)<<this.DB|this[0]}function bnpAddTo(a,r){var i=0,c=0,m=Math.min(a.t,this.t);while(i<m){c+=this[i]+a[i];r[i++]=c&this.DM;c>>=this.DB}if(a.t<this.t){c+=a.s;while(i<this.t){c+=this[i];r[i++]=c&this.DM;c>>=this.DB}c+=this.s}else{c+=this.s;while(i<a.t){c+=a[i];r[i++]=c&this.DM;c>>=this.DB}c+=a.s}r.s=c<0?-1:0;if(c>0)r[i++]=c;else if(c<-1)r[i++]=this.DV+c;r.t=i;r.clamp()}BigInteger.prototype.fromRadix=bnpFromRadix;BigInteger.prototype.chunkSize=bnpChunkSize;BigInteger.prototype.signum=bnSigNum;BigInteger.prototype.dMultiply=bnpDMultiply;BigInteger.prototype.dAddOffset=bnpDAddOffset;BigInteger.prototype.toRadix=bnpToRadix;BigInteger.prototype.intValue=bnIntValue;BigInteger.prototype.addTo=bnpAddTo;var Wrapper={abs:(function(l,h){var x=new goog.math.Long(l,h);var ret;if(x.isNegative()){ret=x.negate()}else{ret=x}HEAP32[tempDoublePtr>>2]=ret.low_;HEAP32[tempDoublePtr+4>>2]=ret.high_}),ensureTemps:(function(){if(Wrapper.ensuredTemps)return;Wrapper.ensuredTemps=true;Wrapper.two32=new BigInteger;Wrapper.two32.fromString("4294967296",10);Wrapper.two64=new BigInteger;Wrapper.two64.fromString("18446744073709551616",10);Wrapper.temp1=new BigInteger;Wrapper.temp2=new BigInteger}),lh2bignum:(function(l,h){var a=new BigInteger;a.fromString(h.toString(),10);var b=new BigInteger;a.multiplyTo(Wrapper.two32,b);var c=new BigInteger;c.fromString(l.toString(),10);var d=new BigInteger;c.addTo(b,d);return d}),stringify:(function(l,h,unsigned){var ret=(new goog.math.Long(l,h)).toString();if(unsigned&&ret[0]=="-"){Wrapper.ensureTemps();var bignum=new BigInteger;bignum.fromString(ret,10);ret=new BigInteger;Wrapper.two64.addTo(bignum,ret);ret=ret.toString(10)}return ret}),fromString:(function(str,base,min,max,unsigned){Wrapper.ensureTemps();var bignum=new BigInteger;bignum.fromString(str,base);var bigmin=new BigInteger;bigmin.fromString(min,10);var bigmax=new BigInteger;bigmax.fromString(max,10);if(unsigned&&bignum.compareTo(BigInteger.ZERO)<0){var temp=new BigInteger;bignum.addTo(Wrapper.two64,temp);bignum=temp}var error=false;if(bignum.compareTo(bigmin)<0){bignum=bigmin;error=true}else if(bignum.compareTo(bigmax)>0){bignum=bigmax;error=true}var ret=goog.math.Long.fromString(bignum.toString());HEAP32[tempDoublePtr>>2]=ret.low_;HEAP32[tempDoublePtr+4>>2]=ret.high_;if(error)throw"range error"})};return Wrapper})();function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;var initialStackTop;var preloadStartTime=null;var calledMain=false;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};Module["callMain"]=Module.callMain=function callMain(args){assert(runDependencies==0,"cannot call main when async dependencies remain! (listen on __ATMAIN__)");assert(__ATPRERUN__.length==0,"cannot call main when preRun functions remain to be called");args=args||[];ensureInitRuntime();var argc=args.length+1;function pad(){for(var i=0;i<4-1;i++){argv.push(0)}}var argv=[allocate(intArrayFromString(Module["thisProgram"]),"i8",ALLOC_NORMAL)];pad();for(var i=0;i<argc-1;i=i+1){argv.push(allocate(intArrayFromString(args[i]),"i8",ALLOC_NORMAL));pad()}argv.push(0);argv=allocate(argv,"i32",ALLOC_NORMAL);initialStackTop=STACKTOP;try{var ret=Module["_main"](argc,argv,0);exit(ret,true)}catch(e){if(e instanceof ExitStatus){return}else if(e=="SimulateInfiniteLoop"){Module["noExitRuntime"]=true;return}else{if(e&&typeof e==="object"&&e.stack)Module.printErr("exception thrown: "+[e,e.stack]);throw e}}finally{calledMain=true}};function run(args){args=args||Module["arguments"];if(preloadStartTime===null)preloadStartTime=Date.now();if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(ENVIRONMENT_IS_WEB&&preloadStartTime!==null){Module.printErr("pre-main prep time: "+(Date.now()-preloadStartTime)+" ms")}if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(Module["_main"]&&shouldRunNow)Module["callMain"](args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=Module.run=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["stdout"]["once"]("drain",(function(){process["exit"](status)}));console.log(" ");setTimeout((function(){process["exit"](status)}),500)}else if(ENVIRONMENT_IS_SHELL&&typeof quit==="function"){quit(status)}throw new ExitStatus(status)}Module["exit"]=Module.exit=exit;var abortDecorators=[];function abort(what){if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;var extra="\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.";var output="abort("+what+") at "+stackTrace()+extra;if(abortDecorators){abortDecorators.forEach((function(decorator){output=decorator(output,what)}))}throw output}Module["abort"]=Module.abort=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=false;if(Module["noInitialRun"]){shouldRunNow=false}Module["noExitRuntime"]=true;run();var inputBuffer,inputBufferSize;function reallocInputBuffer(size){if(inputBuffer&&inputBufferSize>=size){return inputBuffer}if(inputBuffer){Module._free(inputBuffer)}inputBufferSize=size;inputBuffer=Module._malloc(inputBufferSize);return inputBuffer}Module.loadedMetadata=!!options.audioFormat;Module.audioFormat=options.audioFormat||null;Module.audioBuffer=null;Object.defineProperty(Module,"processing",{get:function getProcessing(){return false}});Module.init=(function(callback){Module._ogv_audio_decoder_init();callback()});Module.processHeader=(function(data,callback){var len=data.byteLength;var buffer=reallocInputBuffer(len);Module.HEAPU8.set(new Uint8Array(data),buffer);var ret=Module._ogv_audio_decoder_process_header(buffer,len);callback(ret)});Module.processAudio=(function(data,callback){var len=data.byteLength;var buffer=reallocInputBuffer(len);Module.HEAPU8.set(new Uint8Array(data),buffer);var ret=Module._ogv_audio_decoder_process_audio(buffer,len);callback(ret)})
+
+
+
+
+
+ return Module;
+};
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-video-theora.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-video-theora.js
new file mode 100644
index 00000000..3421de39
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-decoder-video-theora.js
@@ -0,0 +1,22 @@
+var OGVDecoderVideoTheora = function(Module) {
+ Module = Module || {};
+
+var options=Module;Module={print:(function(str){console.log(str)})};var Module;if(!Module)Module=(typeof OGVDecoderVideoTheora!=="undefined"?OGVDecoderVideoTheora:null)||{};var moduleOverrides={};for(var key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var ENVIRONMENT_IS_WEB=typeof window==="object";var ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB;var ENVIRONMENT_IS_WORKER=typeof importScripts==="function";var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){if(!Module["print"])Module["print"]=function print(x){process["stdout"].write(x+"\n")};if(!Module["printErr"])Module["printErr"]=function printErr(x){process["stderr"].write(x+"\n")};var nodeFS=require("fs");var nodePath=require("path");Module["read"]=function read(filename,binary){filename=nodePath["normalize"](filename);var ret=nodeFS["readFileSync"](filename);if(!ret&&filename!=nodePath["resolve"](filename)){filename=path.join(__dirname,"..","src",filename);ret=nodeFS["readFileSync"](filename)}if(ret&&!binary)ret=ret.toString();return ret};Module["readBinary"]=function readBinary(filename){return Module["read"](filename,true)};Module["load"]=function load(f){globalEval(read(f))};if(!Module["thisProgram"]){if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}else{Module["thisProgram"]="unknown-program"}}Module["arguments"]=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(!Module["print"])Module["print"]=print;if(typeof printErr!="undefined")Module["printErr"]=printErr;if(typeof read!="undefined"){Module["read"]=read}else{Module["read"]=function read(){throw"no read() available (jsc?)"}}Module["readBinary"]=function readBinary(f){if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}var data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof console!=="undefined"){if(!Module["print"])Module["print"]=function print(x){console.log(x)};if(!Module["printErr"])Module["printErr"]=function printErr(x){console.log(x)}}else{var TRY_USE_DUMP=false;if(!Module["print"])Module["print"]=TRY_USE_DUMP&&typeof dump!=="undefined"?(function(x){dump(x)}):(function(x){})}if(ENVIRONMENT_IS_WORKER){Module["load"]=importScripts}if(typeof Module["setWindowTitle"]==="undefined"){Module["setWindowTitle"]=(function(title){document.title=title})}}else{throw"Unknown runtime environment. Where are we?"}function globalEval(x){eval.call(null,x)}if(!Module["load"]&&Module["read"]){Module["load"]=function load(f){globalEval(Module["read"](f))}}if(!Module["print"]){Module["print"]=(function(){})}if(!Module["printErr"]){Module["printErr"]=Module["print"]}if(!Module["arguments"]){Module["arguments"]=[]}if(!Module["thisProgram"]){Module["thisProgram"]="./this.program"}Module.print=Module["print"];Module.printErr=Module["printErr"];Module["preRun"]=[];Module["postRun"]=[];for(var key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}var Runtime={setTempRet0:(function(value){tempRet0=value}),getTempRet0:(function(){return tempRet0}),stackSave:(function(){return STACKTOP}),stackRestore:(function(stackTop){STACKTOP=stackTop}),getNativeTypeSize:(function(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return Runtime.QUANTUM_SIZE}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0);return bits/8}else{return 0}}}}),getNativeFieldSize:(function(type){return Math.max(Runtime.getNativeTypeSize(type),Runtime.QUANTUM_SIZE)}),STACK_ALIGN:16,prepVararg:(function(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){assert((ptr&7)===4);ptr+=4}}else{assert((ptr&3)===0)}return ptr}),getAlignSize:(function(type,size,vararg){if(!vararg&&(type=="i64"||type=="double"))return 8;if(!type)return Math.min(size,8);return Math.min(size||(type?Runtime.getNativeFieldSize(type):0),Runtime.QUANTUM_SIZE)}),dynCall:(function(sig,ptr,args){if(args&&args.length){if(!args.splice)args=Array.prototype.slice.call(args);args.splice(0,0,ptr);return Module["dynCall_"+sig].apply(null,args)}else{return Module["dynCall_"+sig].call(null,ptr)}}),functionPointers:[],addFunction:(function(func){for(var i=0;i<Runtime.functionPointers.length;i++){if(!Runtime.functionPointers[i]){Runtime.functionPointers[i]=func;return 2*(1+i)}}throw"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS."}),removeFunction:(function(index){Runtime.functionPointers[(index-2)/2]=null}),warnOnce:(function(text){if(!Runtime.warnOnce.shown)Runtime.warnOnce.shown={};if(!Runtime.warnOnce.shown[text]){Runtime.warnOnce.shown[text]=1;Module.printErr(text)}}),funcWrappers:{},getFuncWrapper:(function(func,sig){assert(sig);if(!Runtime.funcWrappers[sig]){Runtime.funcWrappers[sig]={}}var sigCache=Runtime.funcWrappers[sig];if(!sigCache[func]){sigCache[func]=function dynCall_wrapper(){return Runtime.dynCall(sig,func,arguments)}}return sigCache[func]}),getCompilerSetting:(function(name){throw"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work"}),stackAlloc:(function(size){var ret=STACKTOP;STACKTOP=STACKTOP+size|0;STACKTOP=STACKTOP+15&-16;return ret}),staticAlloc:(function(size){var ret=STATICTOP;STATICTOP=STATICTOP+size|0;STATICTOP=STATICTOP+15&-16;return ret}),dynamicAlloc:(function(size){var ret=DYNAMICTOP;DYNAMICTOP=DYNAMICTOP+size|0;DYNAMICTOP=DYNAMICTOP+15&-16;if(DYNAMICTOP>=TOTAL_MEMORY){var success=enlargeMemory();if(!success){DYNAMICTOP=ret;return 0}}return ret}),alignMemory:(function(size,quantum){var ret=size=Math.ceil(size/(quantum?quantum:16))*(quantum?quantum:16);return ret}),makeBigInt:(function(low,high,unsigned){var ret=unsigned?+(low>>>0)+ +(high>>>0)*+4294967296:+(low>>>0)+ +(high|0)*+4294967296;return ret}),GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module["Runtime"]=Runtime;var __THREW__=0;var ABORT=false;var EXITSTATUS=0;var undef=0;var tempValue,tempInt,tempBigInt,tempInt2,tempBigInt2,tempPair,tempBigIntI,tempBigIntR,tempBigIntS,tempBigIntP,tempBigIntD,tempDouble,tempFloat;var tempI64,tempI64b;var tempRet0,tempRet1,tempRet2,tempRet3,tempRet4,tempRet5,tempRet6,tempRet7,tempRet8,tempRet9;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var globalScope=this;function getCFunc(ident){var func=Module["_"+ident];if(!func){try{func=eval("_"+ident)}catch(e){}}assert(func,"Cannot call unknown function "+ident+" (perhaps LLVM optimizations or closure removed it?)");return func}var cwrap,ccall;((function(){var JSfuncs={"stackSave":(function(){Runtime.stackSave()}),"stackRestore":(function(){Runtime.stackRestore()}),"arrayToC":(function(arr){var ret=Runtime.stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}),"stringToC":(function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=Runtime.stackAlloc((str.length<<2)+1);writeStringToMemory(str,ret)}return ret})};var toC={"string":JSfuncs["stringToC"],"array":JSfuncs["arrayToC"]};ccall=function ccallFunc(ident,returnType,argTypes,args,opts){var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=Runtime.stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func.apply(null,cArgs);if(returnType==="string")ret=Pointer_stringify(ret);if(stack!==0){if(opts&&opts.async){EmterpreterAsync.asyncFinalizers.push((function(){Runtime.stackRestore(stack)}));return}Runtime.stackRestore(stack)}return ret};var sourceRegex=/^function\s*\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;function parseJSFunc(jsfunc){var parsed=jsfunc.toString().match(sourceRegex).slice(1);return{arguments:parsed[0],body:parsed[1],returnValue:parsed[2]}}var JSsource={};for(var fun in JSfuncs){if(JSfuncs.hasOwnProperty(fun)){JSsource[fun]=parseJSFunc(JSfuncs[fun])}}cwrap=function cwrap(ident,returnType,argTypes){argTypes=argTypes||[];var cfunc=getCFunc(ident);var numericArgs=argTypes.every((function(type){return type==="number"}));var numericRet=returnType!=="string";if(numericRet&&numericArgs){return cfunc}var argNames=argTypes.map((function(x,i){return"$"+i}));var funcstr="(function("+argNames.join(",")+") {";var nargs=argTypes.length;if(!numericArgs){funcstr+="var stack = "+JSsource["stackSave"].body+";";for(var i=0;i<nargs;i++){var arg=argNames[i],type=argTypes[i];if(type==="number")continue;var convertCode=JSsource[type+"ToC"];funcstr+="var "+convertCode.arguments+" = "+arg+";";funcstr+=convertCode.body+";";funcstr+=arg+"="+convertCode.returnValue+";"}}var cfuncname=parseJSFunc((function(){return cfunc})).returnValue;funcstr+="var ret = "+cfuncname+"("+argNames.join(",")+");";if(!numericRet){var strgfy=parseJSFunc((function(){return Pointer_stringify})).returnValue;funcstr+="ret = "+strgfy+"(ret);"}if(!numericArgs){funcstr+=JSsource["stackRestore"].body.replace("()","(stack)")+";"}funcstr+="return ret})";return eval(funcstr)}}))();Module["cwrap"]=cwrap;Module["ccall"]=ccall;function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=+1?tempDouble>+0?(Math_min(+Math_floor(tempDouble/+4294967296),+4294967295)|0)>>>0:~~+Math_ceil((tempDouble- +(~~tempDouble>>>0))/+4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}Module["setValue"]=setValue;function getValue(ptr,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP32[ptr>>2];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];default:abort("invalid type for setValue: "+type)}return null}Module["getValue"]=getValue;var ALLOC_NORMAL=0;var ALLOC_STACK=1;var ALLOC_STATIC=2;var ALLOC_DYNAMIC=3;var ALLOC_NONE=4;Module["ALLOC_NORMAL"]=ALLOC_NORMAL;Module["ALLOC_STACK"]=ALLOC_STACK;Module["ALLOC_STATIC"]=ALLOC_STATIC;Module["ALLOC_DYNAMIC"]=ALLOC_DYNAMIC;Module["ALLOC_NONE"]=ALLOC_NONE;function allocate(slab,types,allocator,ptr){var zeroinit,size;if(typeof slab==="number"){zeroinit=true;size=slab}else{zeroinit=false;size=slab.length}var singleType=typeof types==="string"?types:null;var ret;if(allocator==ALLOC_NONE){ret=ptr}else{ret=[_malloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][allocator===undefined?ALLOC_STATIC:allocator](Math.max(size,singleType?1:types.length))}if(zeroinit){var ptr=ret,stop;assert((ret&3)==0);stop=ret+(size&~3);for(;ptr<stop;ptr+=4){HEAP32[ptr>>2]=0}stop=ret+size;while(ptr<stop){HEAP8[ptr++>>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i<size){var curr=slab[i];if(typeof curr==="function"){curr=Runtime.getFunctionIndex(curr)}type=singleType||types[i];if(type===0){i++;continue}if(type=="i64")type="i32";setValue(ret+i,curr,type);if(previousType!==type){typeSize=Runtime.getNativeTypeSize(type);previousType=type}i+=typeSize}return ret}Module["allocate"]=allocate;function getMemory(size){if(!staticSealed)return Runtime.staticAlloc(size);if(typeof _sbrk!=="undefined"&&!_sbrk.called||!runtimeInitialized)return Runtime.dynamicAlloc(size);return _malloc(size)}Module["getMemory"]=getMemory;function Pointer_stringify(ptr,length){if(length===0||!ptr)return"";var hasUtf=0;var t;var i=0;while(1){t=HEAPU8[ptr+i>>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return Module["UTF8ToString"](ptr)}Module["Pointer_stringify"]=Pointer_stringify;function AsciiToString(ptr){var str="";while(1){var ch=HEAP8[ptr++>>0];if(!ch)return str;str+=String.fromCharCode(ch)}}Module["AsciiToString"]=AsciiToString;function stringToAscii(str,outPtr){return writeAsciiToMemory(str,outPtr,false)}Module["stringToAscii"]=stringToAscii;function UTF8ArrayToString(u8Array,idx){var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}Module["UTF8ArrayToString"]=UTF8ArrayToString;function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}Module["UTF8ToString"]=UTF8ToString;function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=2097151){if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=67108863){if(outIdx+4>=endIdx)break;outU8Array[outIdx++]=248|u>>24;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+5>=endIdx)break;outU8Array[outIdx++]=252|u>>30;outU8Array[outIdx++]=128|u>>24&63;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}Module["stringToUTF8Array"]=stringToUTF8Array;function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}Module["stringToUTF8"]=stringToUTF8;function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){++len}else if(u<=2047){len+=2}else if(u<=65535){len+=3}else if(u<=2097151){len+=4}else if(u<=67108863){len+=5}else{len+=6}}return len}Module["lengthBytesUTF8"]=lengthBytesUTF8;function UTF16ToString(ptr){var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)return str;++i;str+=String.fromCharCode(codeUnit)}}Module["UTF16ToString"]=UTF16ToString;function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite<str.length*2?maxBytesToWrite/2:str.length;for(var i=0;i<numCharsToWrite;++i){var codeUnit=str.charCodeAt(i);HEAP16[outPtr>>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}Module["stringToUTF16"]=stringToUTF16;function lengthBytesUTF16(str){return str.length*2}Module["lengthBytesUTF16"]=lengthBytesUTF16;function UTF32ToString(ptr){var i=0;var str="";while(1){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)return str;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}}Module["UTF32ToString"]=UTF32ToString;function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i<str.length;++i){var codeUnit=str.charCodeAt(i);if(codeUnit>=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}Module["stringToUTF32"]=stringToUTF32;function lengthBytesUTF32(str){var len=0;for(var i=0;i<str.length;++i){var codeUnit=str.charCodeAt(i);if(codeUnit>=55296&&codeUnit<=57343)++i;len+=4}return len}Module["lengthBytesUTF32"]=lengthBytesUTF32;function demangle(func){var hasLibcxxabi=!!Module["___cxa_demangle"];if(hasLibcxxabi){try{var buf=_malloc(func.length);writeStringToMemory(func.substr(1),buf);var status=_malloc(4);var ret=Module["___cxa_demangle"](buf,0,0,status);if(getValue(status,"i32")===0&&ret){return Pointer_stringify(ret)}}catch(e){}finally{if(buf)_free(buf);if(status)_free(status);if(ret)_free(ret)}}var i=3;var basicTypes={"v":"void","b":"bool","c":"char","s":"short","i":"int","l":"long","f":"float","d":"double","w":"wchar_t","a":"signed char","h":"unsigned char","t":"unsigned short","j":"unsigned int","m":"unsigned long","x":"long long","y":"unsigned long long","z":"..."};var subs=[];var first=true;function dump(x){if(x)Module.print(x);Module.print(func);var pre="";for(var a=0;a<i;a++)pre+=" ";Module.print(pre+"^")}function parseNested(){i++;if(func[i]==="K")i++;var parts=[];while(func[i]!=="E"){if(func[i]==="S"){i++;var next=func.indexOf("_",i);var num=func.substring(i,next)||0;parts.push(subs[num]||"?");i=next+1;continue}if(func[i]==="C"){parts.push(parts[parts.length-1]);i+=2;continue}var size=parseInt(func.substr(i));var pre=size.toString().length;if(!size||!pre){i--;break}var curr=func.substr(i+pre,size);parts.push(curr);subs.push(curr);i+=pre+size}i++;return parts}function parse(rawList,limit,allowVoid){limit=limit||Infinity;var ret="",list=[];function flushList(){return"("+list.join(", ")+")"}var name;if(func[i]==="N"){name=parseNested().join("::");limit--;if(limit===0)return rawList?[name]:name}else{if(func[i]==="K"||first&&func[i]==="L")i++;var size=parseInt(func.substr(i));if(size){var pre=size.toString().length;name=func.substr(i+pre,size);i+=pre+size}}first=false;if(func[i]==="I"){i++;var iList=parse(true);var iRet=parse(true,1,true);ret+=iRet[0]+" "+name+"<"+iList.join(", ")+">"}else{ret=name}paramLoop:while(i<func.length&&limit-->0){var c=func[i++];if(c in basicTypes){list.push(basicTypes[c])}else{switch(c){case"P":list.push(parse(true,1,true)[0]+"*");break;case"R":list.push(parse(true,1,true)[0]+"&");break;case"L":{i++;var end=func.indexOf("E",i);var size=end-i;list.push(func.substr(i,size));i+=size+2;break};case"A":{var size=parseInt(func.substr(i));i+=size.toString().length;if(func[i]!=="_")throw"?";i++;list.push(parse(true,1,true)[0]+" ["+size+"]");break};case"E":break paramLoop;default:ret+="?"+c;break paramLoop}}}if(!allowVoid&&list.length===1&&list[0]==="void")list=[];if(rawList){if(ret){list.push(ret+"?")}return list}else{return ret+flushList()}}var parsed=func;try{if(func=="Object._main"||func=="_main"){return"main()"}if(typeof func==="number")func=Pointer_stringify(func);if(func[0]!=="_")return func;if(func[1]!=="_")return func;if(func[2]!=="Z")return func;switch(func[3]){case"n":return"operator new()";case"d":return"operator delete()"}parsed=parse()}catch(e){parsed+="?"}if(parsed.indexOf("?")>=0&&!hasLibcxxabi){Runtime.warnOnce("warning: a problem occurred in builtin C++ name demangling; build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling")}return parsed}function demangleAll(text){return text.replace(/__Z[\w\d_]+/g,(function(x){var y=demangle(x);return x===y?x:x+" ["+y+"]"}))}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error(0)}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){return demangleAll(jsStackTrace())}Module["stackTrace"]=stackTrace;var PAGE_SIZE=4096;function alignMemoryPage(x){if(x%4096>0){x+=4096-x%4096}return x}var HEAP;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;var STATIC_BASE=0,STATICTOP=0,staticSealed=false;var STACK_BASE=0,STACKTOP=0,STACK_MAX=0;var DYNAMIC_BASE=0,DYNAMICTOP=0;function enlargeMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.")}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||33554432;var totalMemory=64*1024;while(totalMemory<TOTAL_MEMORY||totalMemory<2*TOTAL_STACK){if(totalMemory<16*1024*1024){totalMemory*=2}else{totalMemory+=16*1024*1024}}if(totalMemory!==TOTAL_MEMORY){Module.printErr("increasing TOTAL_MEMORY to "+totalMemory+" to be compliant with the asm.js spec (and given that TOTAL_STACK="+TOTAL_STACK+")");TOTAL_MEMORY=totalMemory}assert(typeof Int32Array!=="undefined"&&typeof Float64Array!=="undefined"&&!!(new Int32Array(1))["subarray"]&&!!(new Int32Array(1))["set"],"JS engine does not provide full typed array support");var buffer;buffer=new ArrayBuffer(TOTAL_MEMORY);HEAP8=new Int8Array(buffer);HEAP16=new Int16Array(buffer);HEAP32=new Int32Array(buffer);HEAPU8=new Uint8Array(buffer);HEAPU16=new Uint16Array(buffer);HEAPU32=new Uint32Array(buffer);HEAPF32=new Float32Array(buffer);HEAPF64=new Float64Array(buffer);HEAP32[0]=255;assert(HEAPU8[0]===255&&HEAPU8[3]===0,"Typed arrays 2 must be run on a little-endian system");Module["HEAP"]=HEAP;Module["buffer"]=buffer;Module["HEAP8"]=HEAP8;Module["HEAP16"]=HEAP16;Module["HEAP32"]=HEAP32;Module["HEAPU8"]=HEAPU8;Module["HEAPU16"]=HEAPU16;Module["HEAPU32"]=HEAPU32;Module["HEAPF32"]=HEAPF32;Module["HEAPF64"]=HEAPF64;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Runtime.dynCall("v",func)}else{Runtime.dynCall("vi",func,[callback.arg])}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}Module["addOnPreRun"]=Module.addOnPreRun=addOnPreRun;function addOnInit(cb){__ATINIT__.unshift(cb)}Module["addOnInit"]=Module.addOnInit=addOnInit;function addOnPreMain(cb){__ATMAIN__.unshift(cb)}Module["addOnPreMain"]=Module.addOnPreMain=addOnPreMain;function addOnExit(cb){__ATEXIT__.unshift(cb)}Module["addOnExit"]=Module.addOnExit=addOnExit;function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}Module["addOnPostRun"]=Module.addOnPostRun=addOnPostRun;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["intArrayFromString"]=intArrayFromString;function intArrayToString(array){var ret=[];for(var i=0;i<array.length;i++){var chr=array[i];if(chr>255){chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}Module["intArrayToString"]=intArrayToString;function writeStringToMemory(string,buffer,dontAddNull){var array=intArrayFromString(string,dontAddNull);var i=0;while(i<array.length){var chr=array[i];HEAP8[buffer+i>>0]=chr;i=i+1}}Module["writeStringToMemory"]=writeStringToMemory;function writeArrayToMemory(array,buffer){for(var i=0;i<array.length;i++){HEAP8[buffer++>>0]=array[i]}}Module["writeArrayToMemory"]=writeArrayToMemory;function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i<str.length;++i){HEAP8[buffer++>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}Module["writeAsciiToMemory"]=writeAsciiToMemory;function unSign(value,bits,ignore){if(value>=0){return value}return bits<=32?2*Math.abs(1<<bits-1)+value:Math.pow(2,bits)+value}function reSign(value,bits,ignore){if(value<=0){return value}var half=bits<=32?Math.abs(1<<bits-1):Math.pow(2,bits-1);if(value>=half&&(bits<=32||value>half)){value=-2*half+value}return value}if(!Math["imul"]||Math["imul"](4294967295,5)!==-5)Math["imul"]=function imul(a,b){var ah=a>>>16;var al=a&65535;var bh=b>>>16;var bl=b&65535;return al*bl+(ah*bl+al*bh<<16)|0};Math.imul=Math["imul"];if(!Math["clz32"])Math["clz32"]=(function(x){x=x>>>0;for(var i=0;i<32;i++){if(x&1<<31-i)return i}return 32});Math.clz32=Math["clz32"];var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_min=Math.min;var Math_clz32=Math.clz32;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}Module["addRunDependency"]=addRunDependency;function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["removeRunDependency"]=removeRunDependency;Module["preloadedImages"]={};Module["preloadedAudios"]={};var memoryInitializer=null;var ASM_CONSTS=[];STATIC_BASE=8;STATICTOP=STATIC_BASE+2448;__ATINIT__.push();allocate([0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,3,1,2,0,0,0,0,0,1,2,3,4,8,0,0,0,0,0,0,0,1,2,3,4,5,8,9,0,0,0,0,0,1,2,3,4,6,8,10,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,6,8,8,12,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,116,104,101,111,114,97,0,0,4,0,255,254,255,254,255,254,255,254,255,254,255,254,255,254,255,254,254,252,254,252,253,252,253,252,252,251,251,251,224,251,17,0,2,0,220,253,216,253,180,253,36,253,0,0,0,0,5,0,255,253,255,253,255,253,255,253,255,253,255,253,255,253,255,253,254,253,254,253,254,253,254,253,254,253,254,253,254,253,254,253,253,252,253,252,253,252,253,252,252,252,252,252,252,252,252,252,251,251,251,251,250,251,250,251,33,0,36,0,39,0,44,0,1,0,249,254,248,254,1,0,247,254,246,254,2,0,245,253,244,253,243,253,242,253,4,0,241,251,240,251,239,251,238,251,237,251,236,251,235,251,234,251,233,251,232,251,231,251,230,251,229,251,228,251,227,251,226,251,0,0,0,0,0,0,3,4,2,0,1,5,6,7,3,4,0,2,1,5,6,7,3,2,4,0,1,5,6,7,3,2,0,4,1,5,6,7,0,3,4,2,1,5,6,7,0,5,3,4,2,1,6,7,0,1,2,3,4,5,6,7,3,0,0,253,255,252,254,252,253,252,252,252,251,252,250,252,249,252,0,0,0,0,0,0,4,0,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,255,253,255,253,255,253,255,253,254,252,254,252,253,251,17,0,3,0,252,254,252,254,252,254,252,254,251,253,251,253,250,252,249,252,0,0,0,0,6,0,224,249,224,249,223,249,225,249,222,249,226,249,221,249,227,249,220,249,228,249,219,249,229,249,218,249,230,249,217,249,231,249,216,249,232,249,215,249,233,249,214,249,234,249,213,249,235,249,212,249,236,249,211,249,237,249,210,249,238,249,209,249,239,249,208,249,240,249,207,249,241,249,206,249,242,249,205,249,243,249,204,249,244,249,203,249,245,249,202,249,246,249,201,249,247,249,200,249,248,249,199,249,249,249,198,249,250,249,197,249,251,249,196,249,252,249,195,249,253,249,194,249,254,249,193,249,255,249,0,0,0,0,0,0,5,0,224,252,224,252,224,252,224,252,223,252,223,252,223,252,223,252,225,252,225,252,225,252,225,252,222,251,222,251,226,251,226,251,221,251,221,251,227,251,227,251,33,0,36,0,39,0,42,0,45,0,50,0,55,0,60,0,65,0,74,0,83,0,92,0,1,0,220,254,228,254,1,0,219,254,229,254,1,0,218,254,230,254,1,0,217,254,231,254,2,0,216,253,232,253,215,253,233,253,2,0,214,253,234,253,213,253,235,253,2,0,212,253,236,253,211,253,237,253,2,0,210,253,238,253,209,253,239,253,3,0,208,252,240,252,207,252,241,252,206,252,242,252,205,252,243,252,3,0,204,252,244,252,203,252,245,252,202,252,246,252,201,252,247,252,3,0,200,252,248,252,199,252,249,252,198,252,250,252,197,252,251,252,3,0,196,252,252,252,195,252,253,252,194,252,254,252,193,252,255,252,0,0,0,0,0,0,12,4,3,3,4,4,5,5,8,8,8,8,3,3,6,0,0,0,0,0,0,16,0,0,0,0,160,1,0,0,144,1,0,0,160,2,0,0,144,2,0,0,160,4,0,0,144,4,0,0,160,8,0,0,160,40,0,0,144,8,0,0,144,40,10,0,32,0,10,0,224,255,0,0,240,255,0,1,0,0,0,2,0,0,0,3,0,0,1,0,32,0,1,0,224,255,2,0,32,0,2,0,224,255,3,0,32,0,3,0,224,255,4,0,32,0,4,0,224,255,5,0,32,0,5,0,224,255,1,0,64,0,1,0,96,0,1,0,192,255,1,0,160,255,6,0,32,0,7,0,32,0,8,0,32,0,9,0,32,0,6,0,224,255,7,0,224,255,8,0,224,255,9,0,224,255,2,0,64,0,3,0,64,0,2,0,96,0,3,0,96,0,2,0,192,255,3,0,192,255,2,0,160,255,3,0,160,255,0,0,240,255,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,5,0,0,0,6,0,0,0,7,0,0,0,0,0,32,0,0,0,224,255,0,0,64,0,0,0,192,255,0,0,96,0,0,0,160,255,0,0,128,0,0,0,128,255,0,0,160,0,0,0,96,255,0,0,192,0,0,0,64,255,0,0,224,0,0,0,0,1,0,0,32,255,0,0,0,255,0,0,32,1,0,0,64,1,0,0,96,1,0,0,128,1,0,0,224,254,0,0,192,254,0,0,160,254,0,0,128,254,0,8,0,0,0,9,0,0,0,10,0,0,0,11,0,0,0,12,0,0,0,13,0,0,0,14,0,0,0,15,0,0,0,4,0,0,0,5,0,0,0,6,0,0,0,7,0,0,1,6,15,28,64,0,0,0,0,0,0,2,3,0,0,3,0,0,0,0,0,1,1,1,1,2,3,1,1,1,2,1,1,1,1,1,3,1,2,3,15,16,17,88,80,1,0,48,14,56,57,58,59,60,62,64,66,68,72,2,4,6,8,18,20,22,24,26,32,12,28,40,16,0,0,0,32,0,0,0,8,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,3,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,2,0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,255,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,0,249,249,249,249,250,250,250,250,251,251,251,251,252,252,252,252,253,253,253,253,254,254,254,254,255,255,255,255,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,255,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,255,255,255,0,255,255,255,0,255,255,255,0,255,255,255,0,255,255,255,0,255,255,255,0,255,255,255,0,255,255,255,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,24,32,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,69,114,114,111,114,32,112,97,114,115,105,110,103,32,116,104,101,111,114,97,32,104,101,97,100,101,114,115,58,32,37,100,46,10,0,0,0,0,0,0,84,104,101,111,114,97,32,100,101,99,111,100,101,114,32,102,97,105,108,101,100,32,109,121,115,116,101,114,105,111,117,115,108,121,63,32,37,100,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE);var tempDoublePtr=Runtime.alignMemory(allocate(12,"i8",ALLOC_STATIC),8);assert(tempDoublePtr%8==0);function copyTempFloat(ptr){HEAP8[tempDoublePtr]=HEAP8[ptr];HEAP8[tempDoublePtr+1]=HEAP8[ptr+1];HEAP8[tempDoublePtr+2]=HEAP8[ptr+2];HEAP8[tempDoublePtr+3]=HEAP8[ptr+3]}function copyTempDouble(ptr){HEAP8[tempDoublePtr]=HEAP8[ptr];HEAP8[tempDoublePtr+1]=HEAP8[ptr+1];HEAP8[tempDoublePtr+2]=HEAP8[ptr+2];HEAP8[tempDoublePtr+3]=HEAP8[ptr+3];HEAP8[tempDoublePtr+4]=HEAP8[ptr+4];HEAP8[tempDoublePtr+5]=HEAP8[ptr+5];HEAP8[tempDoublePtr+6]=HEAP8[ptr+6];HEAP8[tempDoublePtr+7]=HEAP8[ptr+7]}Module["_i64Subtract"]=_i64Subtract;Module["_i64Add"]=_i64Add;Module["_memset"]=_memset;Module["_bitshift64Shl"]=_bitshift64Shl;function _abort(){Module["abort"]()}function _ogvjs_callback_frame(bufferY,strideY,bufferCb,strideCb,bufferCr,strideCr,width,height,hdec,vdec){var HEAPU8=Module.HEAPU8,widthColor=width>>hdec,heightColor=height>>vdec,countBytesY=strideY*height,countBytesCb=strideCb*heightColor,countBytesCr=strideCr*heightColor,bytesY=HEAPU8.subarray(bufferY,bufferY+countBytesY),bytesCb=HEAPU8.subarray(bufferCb,bufferCb+countBytesCb),bytesCr=HEAPU8.subarray(bufferCr,bufferCr+countBytesCr);Module.frameBuffer={bytesY:bytesY,bytesCb:bytesCb,bytesCr:bytesCr,strideY:strideY,strideCb:strideCb,strideCr:strideCr,width:width,height:height,hdec:hdec,vdec:vdec}}var FS=undefined;var ___errno_state=0;function ___setErrNo(value){HEAP32[___errno_state>>2]=value;return value}var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};var SOCKFS=undefined;function _send(fd,buf,len,flags){var sock=SOCKFS.getSocket(fd);if(!sock){___setErrNo(ERRNO_CODES.EBADF);return-1}return _write(fd,buf,len)}function _pwrite(fildes,buf,nbyte,offset){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{var slab=HEAP8;return FS.write(stream,slab,buf,nbyte,offset)}catch(e){FS.handleFSError(e);return-1}}function _write(fildes,buf,nbyte){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{var slab=HEAP8;return FS.write(stream,slab,buf,nbyte)}catch(e){FS.handleFSError(e);return-1}}function _fileno(stream){stream=FS.getStreamFromPtr(stream);if(!stream)return-1;return stream.fd}function _fwrite(ptr,size,nitems,stream){var bytesToWrite=nitems*size;if(bytesToWrite==0)return 0;var fd=_fileno(stream);var bytesWritten=_write(fd,ptr,bytesToWrite);if(bytesWritten==-1){var streamObj=FS.getStreamFromPtr(stream);if(streamObj)streamObj.error=true;return 0}else{return bytesWritten/size|0}}Module["_strlen"]=_strlen;function __reallyNegative(x){return x<0||x===0&&1/x===-Infinity}function __formatString(format,varargs){assert((varargs&3)===0);var textIndex=format;var argIndex=0;function getNextArg(type){var ret;argIndex=Runtime.prepVararg(argIndex,type);if(type==="double"){ret=(HEAP32[tempDoublePtr>>2]=HEAP32[varargs+argIndex>>2],HEAP32[tempDoublePtr+4>>2]=HEAP32[varargs+(argIndex+4)>>2],+HEAPF64[tempDoublePtr>>3]);argIndex+=8}else if(type=="i64"){ret=[HEAP32[varargs+argIndex>>2],HEAP32[varargs+(argIndex+4)>>2]];argIndex+=8}else{assert((argIndex&3)===0);type="i32";ret=HEAP32[varargs+argIndex>>2];argIndex+=4}return ret}var ret=[];var curr,next,currArg;while(1){var startTextIndex=textIndex;curr=HEAP8[textIndex>>0];if(curr===0)break;next=HEAP8[textIndex+1>>0];if(curr==37){var flagAlwaysSigned=false;var flagLeftAlign=false;var flagAlternative=false;var flagZeroPad=false;var flagPadSign=false;flagsLoop:while(1){switch(next){case 43:flagAlwaysSigned=true;break;case 45:flagLeftAlign=true;break;case 35:flagAlternative=true;break;case 48:if(flagZeroPad){break flagsLoop}else{flagZeroPad=true;break};case 32:flagPadSign=true;break;default:break flagsLoop}textIndex++;next=HEAP8[textIndex+1>>0]}var width=0;if(next==42){width=getNextArg("i32");textIndex++;next=HEAP8[textIndex+1>>0]}else{while(next>=48&&next<=57){width=width*10+(next-48);textIndex++;next=HEAP8[textIndex+1>>0]}}var precisionSet=false,precision=-1;if(next==46){precision=0;precisionSet=true;textIndex++;next=HEAP8[textIndex+1>>0];if(next==42){precision=getNextArg("i32");textIndex++}else{while(1){var precisionChr=HEAP8[textIndex+1>>0];if(precisionChr<48||precisionChr>57)break;precision=precision*10+(precisionChr-48);textIndex++}}next=HEAP8[textIndex+1>>0]}if(precision<0){precision=6;precisionSet=false}var argSize;switch(String.fromCharCode(next)){case"h":var nextNext=HEAP8[textIndex+2>>0];if(nextNext==104){textIndex++;argSize=1}else{argSize=2}break;case"l":var nextNext=HEAP8[textIndex+2>>0];if(nextNext==108){textIndex++;argSize=8}else{argSize=4}break;case"L":case"q":case"j":argSize=8;break;case"z":case"t":case"I":argSize=4;break;default:argSize=null}if(argSize)textIndex++;next=HEAP8[textIndex+1>>0];switch(String.fromCharCode(next)){case"d":case"i":case"u":case"o":case"x":case"X":case"p":{var signed=next==100||next==105;argSize=argSize||4;var currArg=getNextArg("i"+argSize*8);var origArg=currArg;var argText;if(argSize==8){currArg=Runtime.makeBigInt(currArg[0],currArg[1],next==117)}if(argSize<=4){var limit=Math.pow(256,argSize)-1;currArg=(signed?reSign:unSign)(currArg&limit,argSize*8)}var currAbsArg=Math.abs(currArg);var prefix="";if(next==100||next==105){if(argSize==8&&i64Math)argText=i64Math.stringify(origArg[0],origArg[1],null);else argText=reSign(currArg,8*argSize,1).toString(10)}else if(next==117){if(argSize==8&&i64Math)argText=i64Math.stringify(origArg[0],origArg[1],true);else argText=unSign(currArg,8*argSize,1).toString(10);currArg=Math.abs(currArg)}else if(next==111){argText=(flagAlternative?"0":"")+currAbsArg.toString(8)}else if(next==120||next==88){prefix=flagAlternative&&currArg!=0?"0x":"";if(argSize==8&&i64Math){if(origArg[1]){argText=(origArg[1]>>>0).toString(16);var lower=(origArg[0]>>>0).toString(16);while(lower.length<8)lower="0"+lower;argText+=lower}else{argText=(origArg[0]>>>0).toString(16)}}else if(currArg<0){currArg=-currArg;argText=(currAbsArg-1).toString(16);var buffer=[];for(var i=0;i<argText.length;i++){buffer.push((15-parseInt(argText[i],16)).toString(16))}argText=buffer.join("");while(argText.length<argSize*2)argText="f"+argText}else{argText=currAbsArg.toString(16)}if(next==88){prefix=prefix.toUpperCase();argText=argText.toUpperCase()}}else if(next==112){if(currAbsArg===0){argText="(nil)"}else{prefix="0x";argText=currAbsArg.toString(16)}}if(precisionSet){while(argText.length<precision){argText="0"+argText}}if(currArg>=0){if(flagAlwaysSigned){prefix="+"+prefix}else if(flagPadSign){prefix=" "+prefix}}if(argText.charAt(0)=="-"){prefix="-"+prefix;argText=argText.substr(1)}while(prefix.length+argText.length<width){if(flagLeftAlign){argText+=" "}else{if(flagZeroPad){argText="0"+argText}else{prefix=" "+prefix}}}argText=prefix+argText;argText.split("").forEach((function(chr){ret.push(chr.charCodeAt(0))}));break};case"f":case"F":case"e":case"E":case"g":case"G":{var currArg=getNextArg("double");var argText;if(isNaN(currArg)){argText="nan";flagZeroPad=false}else if(!isFinite(currArg)){argText=(currArg<0?"-":"")+"inf";flagZeroPad=false}else{var isGeneral=false;var effectivePrecision=Math.min(precision,20);if(next==103||next==71){isGeneral=true;precision=precision||1;var exponent=parseInt(currArg.toExponential(effectivePrecision).split("e")[1],10);if(precision>exponent&&exponent>=-4){next=(next==103?"f":"F").charCodeAt(0);precision-=exponent+1}else{next=(next==103?"e":"E").charCodeAt(0);precision--}effectivePrecision=Math.min(precision,20)}if(next==101||next==69){argText=currArg.toExponential(effectivePrecision);if(/[eE][-+]\d$/.test(argText)){argText=argText.slice(0,-1)+"0"+argText.slice(-1)}}else if(next==102||next==70){argText=currArg.toFixed(effectivePrecision);if(currArg===0&&__reallyNegative(currArg)){argText="-"+argText}}var parts=argText.split("e");if(isGeneral&&!flagAlternative){while(parts[0].length>1&&parts[0].indexOf(".")!=-1&&(parts[0].slice(-1)=="0"||parts[0].slice(-1)==".")){parts[0]=parts[0].slice(0,-1)}}else{if(flagAlternative&&argText.indexOf(".")==-1)parts[0]+=".";while(precision>effectivePrecision++)parts[0]+="0"}argText=parts[0]+(parts.length>1?"e"+parts[1]:"");if(next==69)argText=argText.toUpperCase();if(currArg>=0){if(flagAlwaysSigned){argText="+"+argText}else if(flagPadSign){argText=" "+argText}}}while(argText.length<width){if(flagLeftAlign){argText+=" "}else{if(flagZeroPad&&(argText[0]=="-"||argText[0]=="+")){argText=argText[0]+"0"+argText.slice(1)}else{argText=(flagZeroPad?"0":" ")+argText}}}if(next<97)argText=argText.toUpperCase();argText.split("").forEach((function(chr){ret.push(chr.charCodeAt(0))}));break};case"s":{var arg=getNextArg("i8*");var argLength=arg?_strlen(arg):"(null)".length;if(precisionSet)argLength=Math.min(argLength,precision);if(!flagLeftAlign){while(argLength<width--){ret.push(32)}}if(arg){for(var i=0;i<argLength;i++){ret.push(HEAPU8[arg++>>0])}}else{ret=ret.concat(intArrayFromString("(null)".substr(0,argLength),true))}if(flagLeftAlign){while(argLength<width--){ret.push(32)}}break};case"c":{if(flagLeftAlign)ret.push(getNextArg("i8"));while(--width>0){ret.push(32)}if(!flagLeftAlign)ret.push(getNextArg("i8"));break};case"n":{var ptr=getNextArg("i32*");HEAP32[ptr>>2]=ret.length;break};case"%":{ret.push(curr);break};default:{for(var i=startTextIndex;i<textIndex+2;i++){ret.push(HEAP8[i>>0])}}}textIndex+=2}else{ret.push(curr);textIndex+=1}}return ret}function _fprintf(stream,format,varargs){var result=__formatString(format,varargs);var stack=Runtime.stackSave();var ret=_fwrite(allocate(result,"i8",ALLOC_STACK),1,result.length,stream);Runtime.stackRestore(stack);return ret}function _printf(format,varargs){var result=__formatString(format,varargs);var string=intArrayToString(result);if(string[string.length-1]==="\n")string=string.substr(0,string.length-1);Module.print(string);return result.length}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest);return dest}Module["_memcpy"]=_memcpy;function _sysconf(name){switch(name){case 30:return PAGE_SIZE;case 85:return totalMemory/PAGE_SIZE;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:return 200809;case 79:return 0;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1e3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:{if(typeof navigator==="object")return navigator["hardwareConcurrency"]||1;return 1}}___setErrNo(ERRNO_CODES.EINVAL);return-1}function _sbrk(bytes){var self=_sbrk;if(!self.called){DYNAMICTOP=alignMemoryPage(DYNAMICTOP);self.called=true;assert(Runtime.dynamicAlloc);self.alloc=Runtime.dynamicAlloc;Runtime.dynamicAlloc=(function(){abort("cannot dynamically allocate, sbrk now has control")})}var ret=DYNAMICTOP;if(bytes!=0){var success=self.alloc(bytes);if(!success)return-1>>>0}return ret}function ___errno_location(){return ___errno_state}function _ogvjs_callback_init_video(frameWidth,frameHeight,hdec,vdec,fps,picWidth,picHeight,picX,picY,displayWidth,displayHeight){Module.videoFormat={frameWidth:frameWidth,frameHeight:frameHeight,hdec:hdec,vdec:vdec,fps:fps,picWidth:picWidth,picHeight:picHeight,picX:picX,picY:picY,displayWidth:displayWidth,displayHeight:displayHeight};Module.loadedMetadata=true}function _time(ptr){var ret=Date.now()/1e3|0;if(ptr){HEAP32[ptr>>2]=ret}return ret}___errno_state=Runtime.staticAlloc(4);HEAP32[___errno_state>>2]=0;STACK_BASE=STACKTOP=Runtime.alignMemory(STATICTOP);staticSealed=true;STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=DYNAMICTOP=Runtime.alignMemory(STACK_MAX);assert(DYNAMIC_BASE<TOTAL_MEMORY,"TOTAL_MEMORY not big enough for stack");var cttz_i8=allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0],"i8",ALLOC_DYNAMIC);function invoke_vii(index,a1,a2){try{Module["dynCall_vii"](index,a1,a2)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_viiii(index,a1,a2,a3,a4){try{Module["dynCall_viiii"](index,a1,a2,a3,a4)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}Module.asmGlobalArg={"Math":Math,"Int8Array":Int8Array,"Int16Array":Int16Array,"Int32Array":Int32Array,"Uint8Array":Uint8Array,"Uint16Array":Uint16Array,"Uint32Array":Uint32Array,"Float32Array":Float32Array,"Float64Array":Float64Array,"NaN":NaN,"Infinity":Infinity};Module.asmLibraryArg={"abort":abort,"assert":assert,"invoke_vii":invoke_vii,"invoke_viiii":invoke_viiii,"_ogvjs_callback_init_video":_ogvjs_callback_init_video,"__formatString":__formatString,"_ogvjs_callback_frame":_ogvjs_callback_frame,"_send":_send,"_pwrite":_pwrite,"_abort":_abort,"___setErrNo":___setErrNo,"_fwrite":_fwrite,"_sbrk":_sbrk,"_printf":_printf,"_fprintf":_fprintf,"__reallyNegative":__reallyNegative,"_emscripten_memcpy_big":_emscripten_memcpy_big,"_fileno":_fileno,"_write":_write,"_time":_time,"_sysconf":_sysconf,"___errno_location":___errno_location,"STACKTOP":STACKTOP,"STACK_MAX":STACK_MAX,"tempDoublePtr":tempDoublePtr,"ABORT":ABORT,"cttz_i8":cttz_i8};// EMSCRIPTEN_START_ASM
+var asm=(function(global,env,buffer) {
+"use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.tempDoublePtr|0;var l=env.ABORT|0;var m=env.cttz_i8|0;var n=0;var o=0;var p=0;var q=0;var r=global.NaN,s=global.Infinity;var t=0,u=0,v=0,w=0,x=0.0,y=0,z=0,A=0,B=0.0;var C=0;var D=0;var E=0;var F=0;var G=0;var H=0;var I=0;var J=0;var K=0;var L=0;var M=global.Math.floor;var N=global.Math.abs;var O=global.Math.sqrt;var P=global.Math.pow;var Q=global.Math.cos;var R=global.Math.sin;var S=global.Math.tan;var T=global.Math.acos;var U=global.Math.asin;var V=global.Math.atan;var W=global.Math.atan2;var X=global.Math.exp;var Y=global.Math.log;var Z=global.Math.ceil;var _=global.Math.imul;var $=global.Math.min;var aa=global.Math.clz32;var ba=env.abort;var ca=env.assert;var da=env.invoke_vii;var ea=env.invoke_viiii;var fa=env._ogvjs_callback_init_video;var ga=env.__formatString;var ha=env._ogvjs_callback_frame;var ia=env._send;var ja=env._pwrite;var ka=env._abort;var la=env.___setErrNo;var ma=env._fwrite;var na=env._sbrk;var oa=env._printf;var pa=env._fprintf;var qa=env.__reallyNegative;var ra=env._emscripten_memcpy_big;var sa=env._fileno;var ta=env._write;var ua=env._time;var va=env._sysconf;var wa=env.___errno_location;var xa=0.0;
+// EMSCRIPTEN_START_FUNCS
+function Aa(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function Ba(){return i|0}function Ca(a){a=a|0;i=a}function Da(a,b){a=a|0;b=b|0;i=a;j=b}function Ea(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Fa(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0]}function Ga(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0];a[k+4>>0]=a[b+4>>0];a[k+5>>0]=a[b+5>>0];a[k+6>>0]=a[b+6>>0];a[k+7>>0]=a[b+7>>0]}function Ha(a){a=a|0;C=a}function Ia(){return C|0}function Ja(a,b,d){a=a|0;b=b|0;d=d|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+16>>2]=0;c[a+4>>2]=b;c[a>>2]=b+d;return}function Ka(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0;e=a+8|0;f=a+12|0;g=c[f>>2]|0;if(!b){h=0;return h|0}i=c[e>>2]|0;if((g|0)<(b|0)){j=c[a>>2]|0;k=a+4|0;l=c[k>>2]|0;m=32-g|0;n=l>>>0<j>>>0;if(m>>>0>7&n){o=l-j|0;p=(24-g|0)>>>3;q=~p;r=o>>>0>q>>>0?o:q;q=l+(0-r)|0;s=~p;p=0-(o>>>0>s>>>0?o:s)|0;s=l;o=m;t=i;while(1){o=o+-8|0;u=s;s=s+1|0;v=(d[u>>0]|0)<<o|t;if((s|0)==(q|0)){w=v;break}else t=v}x=(l+p|0)>>>0<j>>>0;y=q;z=m+(r<<3)|0;A=w}else{x=n;y=l;z=m;A=i}c[k>>2]=y;k=32-z|0;do if((k|0)<(b|0))if(x){B=k;C=(d[y>>0]|0)>>>(k&7)|A;break}else{c[a+16>>2]=1;B=1073741824;C=A;break}else{B=k;C=A}while(0);c[f>>2]=B;D=B;E=C}else{D=g;E=i}c[e>>2]=E<<1<<b+-1;c[f>>2]=D-b;h=E>>>(32-b|0);return h|0}function La(a){a=a|0;var b=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0;b=a+8|0;e=c[b>>2]|0;f=a+12|0;g=c[f>>2]|0;if((g|0)>=1){h=g;i=e;j=i>>>31;k=h+-1|0;l=i<<1;c[b>>2]=l;c[f>>2]=k;return j|0}m=c[a>>2]|0;n=a+4|0;o=c[n>>2]|0;p=32-g|0;q=o>>>0<m>>>0;if(p>>>0>7&q){r=o-m|0;s=(24-g|0)>>>3;g=~s;t=r>>>0>g>>>0?r:g;g=o+(0-t)|0;u=~s;s=0-(r>>>0>u>>>0?r:u)|0;u=o;r=p;v=e;while(1){r=r+-8|0;w=u;u=u+1|0;x=(d[w>>0]|0)<<r|v;if((u|0)==(g|0)){y=x;break}else v=x}z=(o+s|0)>>>0<m>>>0;A=g;B=p+(t<<3)|0;C=y}else{z=q;A=o;B=p;C=e}c[n>>2]=A;n=32-B|0;do if((n|0)<1)if(z){D=n;E=(d[A>>0]|0)>>>(n&7)|C;break}else{c[a+16>>2]=1;D=1073741824;E=C;break}else{D=n;E=C}while(0);c[f>>2]=D;h=D;i=E;j=i>>>31;k=h+-1|0;l=i<<1;c[b>>2]=l;c[f>>2]=k;return j|0}function Ma(a){a=a|0;var b=0;if(c[a+16>>2]|0){b=-1;return b|0}b=(c[a>>2]|0)-(c[a+4>>2]|0)+(c[a+12>>2]>>3)|0;return b|0}function Na(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0;h=i;i=i+32|0;j=h+20|0;k=h;if(!g){l=-20;i=h;return l|0}if(!b){l=-1;i=h;return l|0}Ja(k,c[g>>2]|0,c[g+4>>2]|0);m=Ka(k,8)|0;if((((m&128|0)==0?(c[b+4>>2]|0)!=0:0)?(c[e+12>>2]|0)!=0:0)?(c[f>>2]|0)!=0:0)n=0;else o=7;a:do if((o|0)==7){a[j>>0]=Ka(k,8)|0;a[j+1>>0]=Ka(k,8)|0;a[j+2>>0]=Ka(k,8)|0;a[j+3>>0]=Ka(k,8)|0;a[j+4>>0]=Ka(k,8)|0;a[j+5>>0]=Ka(k,8)|0;if(!(Nb(j,216,6)|0))if((m|0)==128){if(!(c[g+8>>2]|0)){n=-20;break}p=b+4|0;if(c[p>>2]|0){n=-20;break}a[b>>0]=Ka(k,8)|0;q=b+1|0;a[q>>0]=Ka(k,8)|0;a[b+2>>0]=Ka(k,8)|0;r=a[b>>0]|0;do if((r&255)<=3){if(r<<24>>24==3?(d[q>>0]|0)>2:0){s=-22;break}c[p>>2]=(Ka(k,16)|0)<<4;t=b+8|0;c[t>>2]=(Ka(k,16)|0)<<4;u=b+12|0;c[u>>2]=Ka(k,24)|0;v=b+16|0;c[v>>2]=Ka(k,24)|0;w=b+20|0;c[w>>2]=Ka(k,8)|0;x=b+24|0;c[x>>2]=Ka(k,8)|0;y=b+28|0;c[y>>2]=Ka(k,32)|0;z=Ka(k,32)|0;c[b+32>>2]=z;A=c[p>>2]|0;if(((((((A|0)!=0?(B=c[t>>2]|0,(B|0)!=0):0)?((c[w>>2]|0)+(c[u>>2]|0)|0)>>>0<=A>>>0:0)?(A=c[v>>2]|0,v=c[x>>2]|0,(v+A|0)>>>0<=B>>>0):0)?!((z|0)==0|(c[y>>2]|0)==0):0)?(c[x>>2]=B-A-v,c[b+36>>2]=Ka(k,24)|0,c[b+40>>2]=Ka(k,24)|0,c[b+44>>2]=Ka(k,8)|0,c[b+52>>2]=Ka(k,24)|0,c[b+56>>2]=Ka(k,6)|0,c[b+60>>2]=Ka(k,5)|0,v=Ka(k,2)|0,c[b+48>>2]=v,(v|0)!=1):0)?(Ka(k,3)|0)==0:0){v=(Ma(k)|0)>>31&-20;if((v|0)<0)s=v;else{n=3;break a}}else s=-20}else s=-22;while(0);eb(b);n=s;break}else if((m|0)==129){if(!e){n=-1;break}if(!(c[b+4>>2]|0)){n=-20;break}p=e+12|0;if(c[p>>2]|0){n=-20;break}q=Ka(k,8)|0;r=Ka(k,8)|0;v=Ka(k,8)|0;A=r<<8|q|v<<16|(Ka(k,8)|0)<<24;b:do if((A|0)>=0?(A|0)<=(Ma(k)|0):0){v=Ob(A+1|0)|0;c[p>>2]=v;if(!v)C=-1;else{if(!A)D=v;else{q=A;r=v;while(1){q=q+-1|0;a[r>>0]=Ka(k,8)|0;if(!q)break;else r=r+1|0}D=c[p>>2]|0}a[D+A>>0]=0;r=Ka(k,8)|0;q=Ka(k,8)|0;v=Ka(k,8)|0;B=q<<8|r|v<<16|(Ka(k,8)|0)<<24;v=e+8|0;c[v>>2]=B;if(B>>>0<=536870911?(B<<2|0)<=(Ma(k)|0):0){B=c[v>>2]|0;r=B<<2;q=Ob(r)|0;x=e+4|0;c[x>>2]=q;y=Ob(r)|0;c[e>>2]=y;if((q|0)==0|(y|0)==0){c[v>>2]=0;C=-1;break}c:do if((B|0)>0){y=0;while(1){q=Ka(k,8)|0;r=Ka(k,8)|0;z=Ka(k,8)|0;u=r<<8|q|z<<16|(Ka(k,8)|0)<<24;if((u|0)<0){E=y;o=40;break}if((u|0)>(Ma(k)|0)){E=y;o=40;break}c[(c[x>>2]|0)+(y<<2)>>2]=u;z=Ob(u+1|0)|0;c[(c[e>>2]|0)+(y<<2)>>2]=z;z=c[(c[e>>2]|0)+(y<<2)>>2]|0;if(!z){F=y;o=42;break}if(!u)G=z;else{q=u;r=z;while(1){q=q+-1|0;a[r>>0]=Ka(k,8)|0;if(!q)break;else r=r+1|0}G=c[(c[e>>2]|0)+(y<<2)>>2]|0}a[G+u>>0]=0;y=y+1|0;if((y|0)>=(c[v>>2]|0))break c}if((o|0)==40){c[v>>2]=E;C=-20;break b}else if((o|0)==42){c[v>>2]=F;C=-1;break b}}while(0);x=(Ma(k)|0)>>31&-20;if((x|0)<0){C=x;break}else{n=2;break a}}c[v>>2]=0;C=-20}}else C=-20;while(0);gb(e);n=C;break}else if((m|0)==130){if((e|0)==0|(f|0)==0){n=-1;break}if(!(c[b+4>>2]|0)){n=-20;break}if(!(c[e+12>>2]|0)){n=-20;break}if(c[f>>2]|0){n=-20;break}A=Qb(1,712)|0;if(!A){n=-1;break}p=A+320|0;x=Ta(k,p)|0;if((x|0)>=0){B=_a(k,A)|0;if((B|0)<0)H=B;else{c[f>>2]=A;n=1;break}}else H=x;Ua(p);ab(A);Pb(A);n=H;break}else{n=-20;break}else n=-21}while(0);l=n;i=h;return l|0}function Oa(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0;e=c[b+2936+(d<<2)>>2]|0;f=c[b+2948+(d<<2)>>2]|0;g=c[a+72+(d<<5)>>2]|0;h=c[a+168>>2]|0;if((f|0)<=(e|0)){i=0;j=b+2840+(d<<2)|0;c[j>>2]=i;k=f-e|0;l=_(k,g)|0;m=l-i|0;n=b+2852+(d<<2)|0;c[n>>2]=m;return}o=(g|0)>0;p=1-g|0;q=~g;r=(c[a+72+(d<<5)+8>>2]|0)+(_(g,e)|0)|0;a=e;s=0;while(1){if(!a)if(o){t=r;u=0;v=s;while(1){w=h+(t<<2)|0;x=c[w>>2]|0;if(!(x&1))y=v;else{z=b+2960+(d<<4)+((x>>>6&3)<<2)|0;A=(c[z>>2]<<16)+x|0;c[w>>2]=A;c[z>>2]=A>>16;y=v+1|0}u=u+1|0;if((u|0)==(g|0)){B=y;break}else{t=t+1|0;v=y}}C=g+r|0;D=B}else{C=r;D=s}else if(o){v=r;t=0;u=-1;A=s;z=(c[h+(r-g<<2)>>2]|0)>>>6&3;w=-1;while(1){t=t+1|0;if((t|0)<(g|0))E=(c[h+(p+v<<2)>>2]|0)>>>6&3;else E=-1;x=h+(v<<2)|0;F=c[x>>2]|0;if(!(F&1)){G=-1;H=A}else{I=F>>>6&3;do switch(((w|0)==(I|0)&1)<<1|(u|0)==(I|0)|((z|0)==(I|0)&1)<<2|((E|0)==(I|0)&1)<<3|0){case 13:case 11:case 9:{J=(((c[h+(p+v<<2)>>2]>>16)*53|0)+((c[h+(v+-1<<2)>>2]>>16)*75|0)|0)/128|0;break}case 5:{J=((c[h+(v-g<<2)>>2]>>16)+(c[h+(v+-1<<2)>>2]>>16)|0)/2|0;break}case 12:case 6:case 4:{J=c[h+(v-g<<2)>>2]>>16;break}case 10:{J=((c[h+(p+v<<2)>>2]>>16)+(c[h+(v+q<<2)>>2]>>16)|0)/2|0;break}case 14:{J=((((c[h+(p+v<<2)>>2]>>16)+(c[h+(v+q<<2)>>2]>>16)|0)*3|0)+((c[h+(v-g<<2)>>2]>>16)*10|0)|0)/16|0;break}case 15:case 7:{K=v+-1|0;L=c[h+(K<<2)>>2]>>16;M=c[h+(K-g<<2)>>2]>>16;K=c[h+(v-g<<2)>>2]>>16;N=(((K+L|0)*29|0)+(_(M,-26)|0)|0)/32|0;O=N-K|0;if((((O|0)>-1?O:0-O|0)|0)<=128){O=N-L|0;if((((O|0)>-1?O:0-O|0)|0)>128)J=L;else{L=N-M|0;J=(((L|0)>-1?L:0-L|0)|0)>128?M:N}}else J=K;break}case 8:{J=c[h+(p+v<<2)>>2]>>16;break}case 3:case 1:{J=c[h+(v+-1<<2)>>2]>>16;break}case 2:{J=c[h+(v+q<<2)>>2]>>16;break}default:J=c[b+2960+(d<<4)+(I<<2)>>2]|0}while(0);K=F+(J<<16)|0;c[x>>2]=K;c[b+2960+(d<<4)+(I<<2)>>2]=K>>16;G=I;H=A+1|0}if((t|0)==(g|0)){P=H;break}else{K=z;v=v+1|0;u=G;A=H;z=E;w=K}}C=g+r|0;D=P}else{C=r;D=s}a=a+1|0;if((a|0)==(f|0)){i=D;break}else{r=C;s=D}}j=b+2840+(d<<2)|0;c[j>>2]=i;k=f-e|0;l=_(k,g)|0;m=l-i|0;n=b+2852+(d<<2)|0;c[n>>2]=m;return}function Pa(b,d){b=b|0;d=d|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;if((b|0)==0|(d|0)==0){f=0;return f|0}g=ib(57136,16)|0;do if((g|0)!=0?(mb(g,b,3)|0)>=0:0){h=g+51656|0;if(($a(h,d)|0)<0){nb(g);break}i=Ob((c[g+180>>2]|0)*129|0)|0;c[g+53512>>2]=i;if(!i){ab(h);nb(g);break}else j=0;do{c[g+880+(j*24|0)>>2]=g+2416+(j*768|0);c[g+880+(j*24|0)+4>>2]=g+2416+(j*768|0)+128;c[g+880+(j*24|0)+8>>2]=g+2416+(j*768|0)+256;c[g+880+(j*24|0)+12>>2]=g+2416+(j*768|0)+384;c[g+880+(j*24|0)+16>>2]=g+2416+(j*768|0)+512;c[g+880+(j*24|0)+20>>2]=g+2416+(j*768|0)+640;j=j+1|0}while((j|0)!=64);lb(g+880|0,g+53528|0,d+320|0);h=0;do{i=c[g+880+(h*24|0)>>2]|0;k=c[g+880+(h*24|0)+8>>2]|0;l=c[g+880+(h*24|0)+16>>2]|0;m=c[g+880+(h*24|0)+4>>2]|0;n=c[g+880+(h*24|0)+12>>2]|0;o=c[g+880+(h*24|0)+20>>2]|0;c[g+53784+(h<<2)>>2]=0-((e[k+34>>1]|0)+(e[k+24>>1]|0)+(e[k+36>>1]|0)+(e[k+48>>1]|0)+(e[l+24>>1]|0)+(e[l+34>>1]|0)+(e[l+36>>1]|0)+(e[l+48>>1]|0)+(e[n+24>>1]|0)+(e[n+34>>1]|0)+(e[n+36>>1]|0)+(e[n+48>>1]|0)+(e[o+24>>1]|0)+(e[o+34>>1]|0)+(e[o+36>>1]|0)+(e[o+48>>1]|0)+((e[i+34>>1]|0)+(e[i+24>>1]|0)+(e[i+36>>1]|0)+(e[i+48>>1]|0)+(e[m+24>>1]|0)+(e[m+34>>1]|0)+(e[m+36>>1]|0)+(e[m+48>>1]|0)<<1)>>11);h=h+1|0}while((h|0)!=64);h=g+51568|0;m=d+576|0;i=h+64|0;do{a[h>>0]=a[m>>0]|0;h=h+1|0;m=m+1|0}while((h|0)<(i|0));c[g+53524>>2]=0;c[g+54040>>2]=0;c[g+54044>>2]=0;c[g+54048>>2]=0;c[g+54104>>2]=0;c[g+54108>>2]=0;m=g+856|0;c[m>>2]=0;c[m+4>>2]=0;f=g;return f|0}while(0);jb(g);f=0;return f|0}function Qa(a){a=a|0;if(!a)return;Pb(c[a+54048>>2]|0);Pb(c[a+54044>>2]|0);Pb(c[a+54040>>2]|0);Pb(c[a+53512>>2]|0);ab(a+51656|0);nb(a);jb(a);return}function Ra(f,g,h){f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ma=0,Na=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Wa=0,Xa=0,Ya=0,Za=0,_a=0,$a=0,ab=0,cb=0,db=0,eb=0,fb=0,gb=0,hb=0,ib=0,jb=0,lb=0,mb=0,nb=0,wb=0,xb=0,yb=0,zb=0,Ab=0,Bb=0,Cb=0,Db=0,Eb=0,Fb=0,Gb=0,Hb=0,Ib=0,Jb=0,Kb=0,Lb=0,Mb=0,Nb=0,Qb=0,Rb=0,Wb=0,Yb=0,Zb=0,_b=0,$b=0,ac=0,bc=0,cc=0,dc=0,ec=0,fc=0,gc=0,hc=0,ic=0,jc=0,kc=0,lc=0,mc=0,nc=0,oc=0,pc=0,qc=0,rc=0,sc=0,tc=0,uc=0,vc=0,wc=0,xc=0,yc=0,zc=0,Ac=0,Bc=0,Cc=0,Dc=0,Ec=0,Fc=0,Gc=0,Hc=0,Ic=0,Jc=0,Kc=0,Lc=0,Mc=0,Nc=0,Oc=0,Pc=0,Qc=0,Rc=0,Sc=0,Tc=0,Uc=0,Vc=0,Wc=0,Xc=0,Yc=0,Zc=0,_c=0,$c=0,ad=0,bd=0,cd=0,dd=0,ed=0,fd=0,gd=0,hd=0,id=0,jd=0,kd=0,ld=0,md=0,nd=0,od=0,pd=0,qd=0,rd=0,sd=0,td=0,ud=0,vd=0,wd=0,xd=0,yd=0,zd=0,Ad=0,Bd=0,Cd=0,Dd=0,Ed=0,Fd=0,Gd=0,Hd=0,Id=0,Jd=0,Kd=0,Ld=0,Md=0,Nd=0,Od=0,Pd=0,Qd=0,Rd=0,Sd=0,Td=0,Ud=0;j=i;i=i+1088|0;k=j;l=j+312|0;m=j+304|0;n=j+256|0;if((f|0)==0|(g|0)==0){o=-1;i=j;return o|0}p=c[g+4>>2]|0;do if(!p){q=f+872|0;a[q>>0]=1;c[f+232>>2]=0;r=q;s=0}else{q=f+51636|0;Ja(q,c[g>>2]|0,p);if(La(q)|0){o=-24;i=j;return o|0}t=f+872|0;a[t>>0]=La(q)|0;a[f+875>>0]=Ka(q,6)|0;do if(La(q)|0){a[f+876>>0]=Ka(q,6)|0;if(!(La(q)|0)){a[f+874>>0]=2;break}else{a[f+877>>0]=Ka(q,6)|0;a[f+874>>0]=3;break}}else a[f+874>>0]=1;while(0);if(!(a[t>>0]|0)){if(Ka(q,3)|0){o=-23;i=j;return o|0}if(!(a[t>>0]|0)){u=c[f+216>>2]|0;v=c[f+184>>2]|0;w=c[f+188>>2]|0;x=c[f+168>>2]|0;y=0;z=0;A=0;B=0;while(1){y=(c[f+72+(z<<5)+28>>2]|0)+y|0;if(B>>>0<y>>>0){D=A;E=B;while(1){F=w+E|0;G=D;H=0;while(1){if((d[F>>0]|0)>>>2&15&1<<H){I=c[v+(E<<6)+(H<<4)>>2]|0;if((I|0)>-1){J=x+(I<<2)|0;c[J>>2]=c[J>>2]&-1986|385;c[u+(G<<2)>>2]=I;K=G+1|0}else K=G;I=c[v+(E<<6)+(H<<4)+4>>2]|0;if((I|0)>-1){J=x+(I<<2)|0;c[J>>2]=c[J>>2]&-1986|385;c[u+(K<<2)>>2]=I;L=K+1|0}else L=K;I=c[v+(E<<6)+(H<<4)+8>>2]|0;if((I|0)>-1){J=x+(I<<2)|0;c[J>>2]=c[J>>2]&-1986|385;c[u+(L<<2)>>2]=I;M=L+1|0}else M=L;I=c[v+(E<<6)+(H<<4)+12>>2]|0;if((I|0)>-1){J=x+(I<<2)|0;c[J>>2]=c[J>>2]&-1986|385;c[u+(M<<2)>>2]=I;N=M+1|0}else N=M}else N=G;H=H+1|0;if((H|0)==4){O=N;break}else G=N}E=E+1|0;if((E|0)==(y|0)){P=O;Q=y;break}else D=O}}else{P=A;Q=B}c[f+220+(z<<2)>>2]=P-A;z=z+1|0;if((z|0)==3){R=P;break}else{A=P;B=Q}}c[f+232>>2]=R;r=t;s=R;break}}B=La(q)|0;A=f+188|0;z=c[A>>2]|0;y=f+192|0;u=c[y>>2]|0;if(u){x=B;B=0;v=0;while(1){w=bb(q,224)|0;if((w|0)>15){D=w&31;S=D+6+(Ka(q,w-D>>4)|0)|0}else S=w;w=(x&255)<<1&2;D=0-S|0;E=v+1|0;G=v-(u>>>0>E>>>0?u:E)|0;E=G>>>0<D>>>0?D:G;G=v;v=v-E|0;do{D=z+G|0;a[D>>0]=a[D>>0]&-4|w;G=G+1|0}while((G|0)!=(v|0));G=_(E,x)|0;w=v>>>0<u>>>0;D=B-G|0;if(S>>>0>4128&w)T=La(q)|0;else T=(x|0)==0&1;if(!w){U=G;V=D;W=B;break}else{x=T;B=D}}B=c[y>>2]|0;a:do if(V>>>0<B>>>0){x=c[A>>2]|0;u=0;while(1)if(!(a[x+u>>0]&2)){X=u;break}else u=u+1|0;u=La(q)|0;E=X;while(1){v=bb(q,224)|0;if((v|0)>15){z=v&31;Y=z+6+(Ka(q,v-z>>4)|0)|0}else Y=v;if(E>>>0>=B>>>0)break a;v=u&1;z=Y;D=E;while(1){G=x+D|0;w=a[G>>0]|0;if(!(w&2)){if(!z){Z=D;break}a[G>>0]=w&-2|v;$=z+-1|0}else $=z;D=D+1|0;if(D>>>0>=B>>>0)break a;else z=$}if(Y>>>0<4129){u=(u|0)==0&1;E=Z;continue}else{u=La(q)|0;E=Z;continue}}}while(0);if((W|0)!=(U|0))aa=(La(q)|0)==0&1;else aa=0}else aa=0;B=c[f+184>>2]|0;y=c[A>>2]|0;E=c[f+200>>2]|0;u=c[f+168>>2]|0;x=c[f+216>>2]|0;z=c[f+180>>2]|0;D=aa;v=0;w=0;G=0;H=0;F=0;I=0;while(1){w=(c[f+72+(H<<5)+28>>2]|0)+w|0;if(I>>>0<w>>>0){J=(H|0)==0;ba=D;ca=v;da=G;ea=F;fa=I;while(1){ga=y+fa|0;ha=fa<<2;if(J){ia=ba;ja=ca;ka=da;la=0;ma=ea;while(1){if(!((d[ga>>0]|0)>>>2&15&1<<la)){na=ia;oa=ja;pa=ka;qa=ma}else{ra=0;sa=ia;ta=ja;ua=ka;va=0;wa=ma;while(1){xa=c[B+(fa<<6)+(la<<4)+(ra<<2)>>2]|0;if((xa|0)>-1){Aa=a[ga>>0]|0;do if(!(Aa&1)){if(Aa&2){if((wa|0)<1){Ba=(sa|0)==0&1;Ca=bb(q,272)|0}else{Ba=sa;Ca=wa}Da=Ca+-1|0;if(!Ba){Ea=0;Fa=Da}else{Ga=Ba;Ha=Ba;Ia=Da;Ma=67;break}}else{Ea=sa;Fa=wa}c[x+(z+~ua<<2)>>2]=xa;Na=0;Pa=Ea;Qa=ta;Ra=ua+1|0;Sa=Fa}else{Ga=1;Ha=sa;Ia=wa;Ma=67}while(0);if((Ma|0)==67){Ma=0;c[x+(ta<<2)>>2]=xa;Na=Ga;Pa=Ha;Qa=ta+1|0;Ra=ua;Sa=Ia}Aa=u+(xa<<2)|0;c[Aa>>2]=Na&1|c[Aa>>2]&-194|192;Ta=Pa;Ua=Qa;Wa=Ra;Xa=Na|va;Ya=Sa}else{Ta=sa;Ua=ta;Wa=ua;Xa=va;Ya=wa}ra=ra+1|0;if((ra|0)==4){Za=Ta;_a=Ua;$a=Wa;ab=Xa;cb=Ya;break}else{sa=Ta;ta=Ua;ua=Wa;va=Xa;wa=Ya}}a[E+(la|ha)>>0]=ab;na=Za;oa=_a;pa=$a;qa=cb}la=la+1|0;if((la|0)==4){db=na;eb=oa;fb=pa;gb=qa;break}else{ia=na;ja=oa;ka=pa;ma=qa}}}else{ma=ba;ka=ca;ja=da;ia=0;la=ea;while(1){if(!((d[ga>>0]|0)>>>2&15&1<<ia)){hb=ma;ib=ka;jb=ja;lb=la}else{ha=0;wa=ma;va=ka;ua=ja;ta=la;while(1){sa=c[B+(fa<<6)+(ia<<4)+(ha<<2)>>2]|0;if((sa|0)>-1){ra=a[ga>>0]|0;do if(!(ra&1)){if(ra&2){if((ta|0)<1){mb=(wa|0)==0&1;nb=bb(q,272)|0}else{mb=wa;nb=ta}Aa=nb+-1|0;if(!mb){wb=0;xb=Aa}else{yb=mb;zb=mb;Ab=Aa;Ma=79;break}}else{wb=wa;xb=ta}c[x+(z+~ua<<2)>>2]=sa;Bb=0;Cb=wb;Db=va;Eb=ua+1|0;Fb=xb}else{yb=1;zb=wa;Ab=ta;Ma=79}while(0);if((Ma|0)==79){Ma=0;c[x+(va<<2)>>2]=sa;Bb=yb;Cb=zb;Db=va+1|0;Eb=ua;Fb=Ab}ra=u+(sa<<2)|0;c[ra>>2]=Bb&1|c[ra>>2]&-194|192;Gb=Cb;Hb=Db;Ib=Eb;Jb=Fb}else{Gb=wa;Hb=va;Ib=ua;Jb=ta}ha=ha+1|0;if((ha|0)==4){hb=Gb;ib=Hb;jb=Ib;lb=Jb;break}else{wa=Gb;va=Hb;ua=Ib;ta=Jb}}}ia=ia+1|0;if((ia|0)==4){db=hb;eb=ib;fb=jb;gb=lb;break}else{ma=hb;ka=ib;ja=jb;la=lb}}}fa=fa+1|0;if((fa|0)==(w|0)){Kb=db;Lb=eb;Mb=fb;Nb=gb;Qb=w;break}else{ba=db;ca=eb;da=fb;ea=gb}}}else{Kb=D;Lb=v;Mb=G;Nb=F;Qb=I}c[f+220+(H<<2)>>2]=Lb-v;H=H+1|0;if((H|0)==3){Rb=Lb;break}else{D=Kb;v=Lb;G=Mb;F=Nb;I=Qb}}c[f+232>>2]=Rb;r=t;s=Rb}while(0);do if(!(a[r>>0]|0))Wb=s;else{Rb=f+524|0;Qb=f+528|0;if((c[Rb>>2]|0)>=0?(c[Qb>>2]|0)>=0:0){Wb=s;break}c[Rb>>2]=0;c[Qb>>2]=0;c[f+532>>2]=0;Qb=c[f+248>>2]|0;c[f+556>>2]=Qb;c[f+552>>2]=Qb;c[f+548>>2]=Qb;Yb=f+54056|0;Zb=f+236|0;_b=Yb+48|0;do{c[Yb>>2]=c[Zb>>2];Yb=Yb+4|0;Zb=Zb+4|0}while((Yb|0)<(_b|0));t=c[f+576>>2]|0;Rb=(t|0)>-1?t:0-t|0;t=c[f+8>>2]|0;Nb=t+32|0;Mb=c[f+580>>2]|0;Ub(Qb+(-16-(_(Rb,t+15|0)|0))|0,-128,(_(Rb,Nb)|0)+16+(_(((Mb|0)>-1?Mb:0-Mb|0)<<1,Nb>>((c[f+48>>2]|0)>>>1&1^1))|0)|0)|0;Wb=c[f+232>>2]|0}while(0);s=f+232|0;if((Wb|0)<1){Wb=f+848|0;Nb=c[Wb>>2]|0;Mb=c[Wb+4>>2]|0;Wb=Tb(d[f+873>>0]|0,0,Nb|0,Mb|0)|0;Rb=Vb(Wb|0,C|0,c[f+60>>2]|0)|0;Wb=C;t=f+856|0;Lb=t;Kb=c[Lb>>2]|0;gb=c[Lb+4>>2]|0;Lb=Sb(Kb|0,gb|0,Nb|0,Mb|0)|0;Mb=Tb(Lb|0,C|0,Rb|0,Wb|0)|0;Wb=C;Rb=f+864|0;c[Rb>>2]=Mb;c[Rb+4>>2]=Wb;Rb=Tb(Kb|0,gb|0,1,0)|0;gb=t;c[gb>>2]=Rb;c[gb+4>>2]=C;if(!h){o=1;i=j;return o|0}gb=h;c[gb>>2]=Mb;c[gb+4>>2]=Wb;o=1;i=j;return o|0}Wb=f+528|0;gb=f+524|0;Mb=c[gb>>2]|0;Rb=c[Wb>>2]|0;t=0;while(1)if((t|0)==(Mb|0)|(t|0)==(Rb|0))t=t+1|0;else{$b=t;break}t=f+532|0;c[t>>2]=$b;Rb=f+548|0;Mb=f+556|0;c[Mb>>2]=c[f+236+($b*48|0)+12>>2];if(a[r>>0]|0){Kb=f+51636|0;Lb=Ka(Kb,3)|0;if(!Lb){Nb=k;c[Nb>>2]=0;c[Nb+4>>2]=0;a[k+(Ka(Kb,3)|0)>>0]=0;a[k+(Ka(Kb,3)|0)>>0]=1;a[k+(Ka(Kb,3)|0)>>0]=2;a[k+(Ka(Kb,3)|0)>>0]=3;a[k+(Ka(Kb,3)|0)>>0]=4;a[k+(Ka(Kb,3)|0)>>0]=5;a[k+(Ka(Kb,3)|0)>>0]=6;a[k+(Ka(Kb,3)|0)>>0]=7;ac=k}else ac=400+(Lb+-1<<3)|0;Nb=(Lb|0)==7?456:480;Lb=f+200|0;fb=c[Lb>>2]|0;eb=f+212|0;db=c[eb>>2]|0;if(db){lb=0;do{jb=fb+lb|0;if((a[jb>>0]|0)>0)a[jb>>0]=a[ac+(bb(Kb,Nb)|0)>>0]|0;lb=lb+1|0}while((lb|0)!=(db|0))}db=f+48|0;lb=c[200+(c[db>>2]<<2)>>2]|0;Nb=(La(Kb)|0)!=0;ac=Nb?536:672;Nb=c[db>>2]|0;db=a[192+Nb>>0]|0;fb=db&255;jb=c[f+168>>2]|0;ib=c[f+176>>2]|0;hb=c[f+196>>2]|0;Jb=c[Lb>>2]|0;Lb=c[eb>>2]|0;if(Lb){eb=(db&255)>4;db=l+2|0;Ib=l+4|0;Hb=l+6|0;Gb=0;Fb=0;Eb=0;while(1){Db=a[Jb+Fb>>0]|0;Cb=Db<<24>>24;if(Db<<24>>24==7){Bb=c[hb+(Fb*48|0)>>2]|0;Ab=jb+(Bb<<2)|0;zb=c[Ab>>2]|0;if(!(zb&1)){b[l>>1]=0;bc=Gb}else{c[Ab>>2]=zb&-1985|1856;zb=(bb(Kb,ac)|0)+224|0;Ab=(((bb(Kb,ac)|0)<<8)+57344|zb&255)&65535;b[l>>1]=Ab;b[ib+(Bb<<1)>>1]=Ab;bc=Ab}Ab=c[hb+(Fb*48|0)+4>>2]|0;Bb=jb+(Ab<<2)|0;zb=c[Bb>>2]|0;if(!(zb&1)){b[db>>1]=0;cc=bc}else{c[Bb>>2]=zb&-1985|1856;zb=(bb(Kb,ac)|0)+224|0;Bb=(((bb(Kb,ac)|0)<<8)+57344|zb&255)&65535;b[db>>1]=Bb;b[ib+(Ab<<1)>>1]=Bb;cc=Bb}Bb=c[hb+(Fb*48|0)+8>>2]|0;Ab=jb+(Bb<<2)|0;zb=c[Ab>>2]|0;if(!(zb&1)){b[Ib>>1]=0;dc=cc}else{c[Ab>>2]=zb&-1985|1856;zb=(bb(Kb,ac)|0)+224|0;Ab=(((bb(Kb,ac)|0)<<8)+57344|zb&255)&65535;b[Ib>>1]=Ab;b[ib+(Bb<<1)>>1]=Ab;dc=Ab}Ab=c[hb+(Fb*48|0)+12>>2]|0;Bb=jb+(Ab<<2)|0;zb=c[Bb>>2]|0;if(!(zb&1)){b[Hb>>1]=0;ec=dc}else{c[Bb>>2]=zb&-1985|1856;zb=(bb(Kb,ac)|0)+224|0;Bb=(((bb(Kb,ac)|0)<<8)+57344|zb&255)&65535;b[Hb>>1]=Bb;b[ib+(Ab<<1)>>1]=Bb;ec=Bb}ya[lb&7](k,l);if(eb){Bb=4;do{Ab=d[144+(Nb*12|0)+Bb>>0]|0;zb=Ab&3;yb=c[hb+(Fb*48|0)+(Ab>>>2<<4)+(zb<<2)>>2]|0;Ab=jb+(yb<<2)|0;xb=c[Ab>>2]|0;if(xb&1){c[Ab>>2]=xb&-1985|1856;b[ib+(yb<<1)>>1]=b[k+(zb<<1)>>1]|0}Bb=Bb+1|0}while((Bb|0)<(fb|0));fc=ec;gc=Gb}else{fc=ec;gc=Gb}}else if(Db<<24>>24==-1){fc=Gb;gc=Eb}else{if((Cb|0)==2){Bb=(bb(Kb,ac)|0)+224|0;Qb=(((bb(Kb,ac)|0)<<8)+57344|Bb&255)&65535;hc=Qb;ic=Qb;jc=Gb}else if((Cb|0)==4){hc=Eb;ic=Eb;jc=Gb}else if((Cb|0)==6){Qb=(bb(Kb,ac)|0)+224|0;hc=Gb;ic=(((bb(Kb,ac)|0)<<8)+57344|Qb&255)&65535;jc=Eb}else if((Cb|0)==3){hc=Gb;ic=Gb;jc=Eb}else{hc=Gb;ic=0;jc=Eb}Qb=268505377>>>(Cb<<2)<<6&192|Cb<<8&1792;Bb=0;do{zb=d[144+(Nb*12|0)+Bb>>0]|0;yb=c[hb+(Fb*48|0)+(zb>>>2<<4)+((zb&3)<<2)>>2]|0;zb=jb+(yb<<2)|0;xb=c[zb>>2]|0;if(xb&1){c[zb>>2]=Qb|xb&-1985;b[ib+(yb<<1)>>1]=ic}Bb=Bb+1|0}while((Bb|0)<(fb|0));fc=hc;gc=jc}Fb=Fb+1|0;if((Fb|0)==(Lb|0))break;else{Gb=fc;Eb=gc}}}}else{gc=f+856|0;Eb=c[gc+4>>2]|0;fc=f+848|0;c[fc>>2]=c[gc>>2];c[fc+4>>2]=Eb}Eb=c[s>>2]|0;b:do if((Eb|0)>=1){s=c[f+168>>2]|0;fc=c[f+216>>2]|0;gc=f+874|0;if((a[gc>>0]|0)==1){Gb=0;while(1){Lb=s+(c[fc+(Gb<<2)>>2]<<2)|0;c[Lb>>2]=c[Lb>>2]&-61;Gb=Gb+1|0;if((Gb|0)==(Eb|0))break b}}Gb=f+51636|0;Lb=La(Gb)|0;Fb=0;jc=0;while(1){hc=bb(Gb,224)|0;if((hc|0)>15){fb=hc&31;kc=fb+6+(Ka(Gb,hc-fb>>4)|0)|0}else kc=hc;hc=(kc|0)>4128;fb=Lb<<2&60;ic=Fb;ib=jc;jb=kc;while(1){hb=ic+1|0;Nb=s+(c[fc+(ic<<2)>>2]<<2)|0;c[Nb>>2]=c[Nb>>2]&-61|fb;Nb=ib+Lb|0;if((jb|0)<=1){lc=hb;mc=Nb;break}if((hb|0)<(Eb|0)){ic=hb;ib=Nb;jb=jb+-1|0}else{lc=hb;mc=Nb;break}}jb=(lc|0)<(Eb|0);if(hc&jb)nc=La(Gb)|0;else nc=(Lb|0)==0&1;if(jb){Lb=nc;Fb=lc;jc=mc}else{oc=mc;break}}if((oc|0)>0&(a[gc>>0]|0)==3){jc=0;while(1)if(!(c[s+(c[fc+(jc<<2)>>2]<<2)>>2]&60))jc=jc+1|0;else{pc=jc;break}jc=La(Gb)|0;gc=pc;while(1){Fb=bb(Gb,224)|0;if((Fb|0)>15){Lb=Fb&31;qc=Lb+6+(Ka(Gb,Fb-Lb>>4)|0)|0}else qc=Fb;if((gc|0)<(Eb|0)){rc=gc;sc=qc}else break b;while(1){Fb=s+(c[fc+(rc<<2)>>2]<<2)|0;Lb=c[Fb>>2]|0;jb=Lb>>>2;if(!(jb&15))tc=sc;else{if((sc|0)<1){uc=rc;break}c[Fb>>2]=jb+jc<<2&60|Lb&-61;tc=sc+-1|0}rc=rc+1|0;if((rc|0)>=(Eb|0))break b;else sc=tc}if((qc|0)<4129){jc=(jc|0)==0&1;gc=uc;continue}else{jc=La(Gb)|0;gc=uc;continue}}}}while(0);uc=f+220|0;qc=c[uc>>2]|0;tc=0;do{c[l+(tc<<2)>>2]=qc;tc=tc+1|0}while((tc|0)!=64);tc=f+224|0;qc=c[tc>>2]|0;sc=0;do{c[l+256+(sc<<2)>>2]=qc;sc=sc+1|0}while((sc|0)!=64);sc=f+228|0;qc=c[sc>>2]|0;Eb=0;do{c[l+512+(Eb<<2)>>2]=qc;Eb=Eb+1|0}while((Eb|0)!=64);Eb=f+51636|0;c[m>>2]=Ka(Eb,4)|0;qc=m+4|0;c[qc>>2]=Ka(Eb,4)|0;c[f+52744>>2]=0;rc=f+53512|0;pc=c[rc>>2]|0;oc=f+168|0;mc=c[oc>>2]|0;lc=f+216|0;nc=c[lc>>2]|0;kc=k+252|0;gc=0;Gb=0;jc=0;fc=0;s=0;while(1){hc=c[f+220+(fc<<2)>>2]|0;Lb=jc;jc=hc+jc|0;Ub(k|0,0,256)|0;c[f+52744+(fc<<8)>>2]=gc;c[f+51976+(fc<<8)>>2]=s;jb=jc-Gb|0;Fb=(jb|0)<(gc|0)?jb:gc;jb=gc-Fb|0;if((Fb|0)>0){ib=Gb+~Lb-hc|0;ic=~gc;fb=(ib|0)>(ic|0)?ib:ic;ic=Fb;ib=Gb;while(1){Nb=mc+(c[nc+(ib<<2)>>2]<<2)|0;c[Nb>>2]=c[Nb>>2]&65535;if((ic|0)>1){ic=ic+-1|0;ib=ib+1|0}else break}vc=Gb+1-fb+((fb|0)>-2?fb:-2)|0}else vc=Gb;c:do if((jc|0)>(vc|0)){ib=~Lb-hc|0;ic=f+51656+(c[m+(fc+1>>1<<2)>>2]<<2)|0;Nb=Fb;hb=vc;ac=s;while(1){Kb=hb;ec=ac;while(1){eb=bb(Eb,c[ic>>2]|0)|0;lb=ec+1|0;a[pc+ec>>0]=eb;if((eb|0)<15){Hb=Ka(Eb,d[880+eb>>0]|0)|0;dc=ec+2|0;a[pc+lb>>0]=Hb;if(!eb){a[pc+dc>>0]=Hb>>>8;wc=ec+3|0}else wc=dc;xc=Hb<<((eb|0)<2?-13:0)+((eb|0)<12?21:0);yc=wc}else{xc=0;yc=lb}lb=(c[896+(eb<<2)>>2]|0)+xc|0;eb=(lb|0)==0?2147483647:lb>>>8&4095;if(eb){zc=eb;Ac=Kb;Bc=yc;break}eb=lb&255;Hb=k+(eb<<2)|0;c[Hb>>2]=(c[Hb>>2]|0)+1;Hb=Kb+1|0;dc=mc+(c[nc+(Kb<<2)>>2]<<2)|0;c[dc>>2]=c[dc>>2]&65535|((eb|0)!=0?0:(lb^0-(lb&1048576))>>21<<16);if((jc|0)>(Hb|0)){Kb=Hb;ec=yc}else{Cc=Nb;Dc=0;Ec=Hb;Fc=yc;break c}}ec=jc-Ac|0;Kb=(ec|0)<(zc|0)?ec-zc|0:0;ec=Kb+zc|0;Hb=ec+Nb|0;if((ec|0)>0){lb=Ac+ib|0;eb=~zc;dc=(lb|0)>(eb|0)?lb:eb;eb=ec;ec=Ac;while(1){lb=mc+(c[nc+(ec<<2)>>2]<<2)|0;c[lb>>2]=c[lb>>2]&65535;if((eb|0)>1){eb=eb+-1|0;ec=ec+1|0}else break}Gc=Ac+1-dc+((dc|0)>-2?dc:-2)|0}else Gc=Ac;if((jc|0)>(Gc|0)){Nb=Hb;hb=Gc;ac=Bc}else{Hc=Kb;Ic=Hb;Jc=Gc;Kc=Bc;break}}Cc=Ic;Dc=0-Hc|0;Ec=Jc;Fc=Kc}else{Cc=Fb;Dc=jb;Ec=vc;Fc=s}while(0);jb=(c[kc>>2]|0)+Cc|0;c[kc>>2]=jb;Fb=62;hc=jb;while(1){jb=k+(Fb<<2)|0;hc=(c[jb>>2]|0)+hc|0;c[jb>>2]=hc;if((Fb|0)<=0){Lc=63;break}else Fb=Fb+-1|0}while(1){Fb=l+(fc<<8)+(Lc<<2)|0;c[Fb>>2]=(c[Fb>>2]|0)-(c[k+(Lc<<2)>>2]|0);if((Lc|0)>0)Lc=Lc+-1|0;else break}fc=fc+1|0;if((fc|0)==3){Mc=Dc;Nc=Fc;break}else{gc=Dc;Gb=Ec;s=Fc}}Fc=f+53520|0;c[Fc>>2]=Nc;Nc=Ka(Eb,4)|0;c[m>>2]=Nc;s=Ka(Eb,4)|0;c[qc>>2]=s;Ec=Nc;Nc=s;s=Mc;Mc=1;Gb=1;while(1){Ec=Ec+16|0;c[m>>2]=Ec;Nc=Nc+16|0;c[qc>>2]=Nc;Dc=d[1264+Mc>>0]|0;if((Gb|0)<(Dc|0)){gc=Gb+1|0;fc=c[Fc>>2]|0;Lc=s;Cc=Gb;while(1){vc=c[rc>>2]|0;Kc=64-Cc|0;Jc=(Kc|0)>0;Hc=Lc;Ic=0;Bc=fc;while(1){c[f+52744+(Ic<<8)+(Cc<<2)>>2]=Hc;c[f+51976+(Ic<<8)+(Cc<<2)>>2]=Bc;Gc=c[l+(Ic<<8)+(Cc<<2)>>2]|0;Ub(k|0,0,256)|0;if(Hc>>>0<Gc>>>0){jc=f+51656+(c[m+(Ic+1>>1<<2)>>2]<<2)|0;Ac=Hc;nc=Hc;mc=0;zc=Bc;while(1){yc=mc+Ac|0;xc=bb(Eb,c[jc>>2]|0)|0;wc=zc+1|0;a[vc+zc>>0]=xc;if((xc|0)<15){pc=Ka(Eb,d[880+xc>>0]|0)|0;Fb=zc+2|0;a[vc+wc>>0]=pc;if(!xc){a[vc+Fb>>0]=pc>>>8;Oc=zc+3|0}else Oc=Fb;Pc=pc<<((xc|0)<2?-13:0)+((xc|0)<12?21:0);Qc=Oc}else{Pc=0;Qc=wc}wc=(c[896+(xc<<2)>>2]|0)+Pc|0;xc=(wc|0)==0?2147483647:wc>>>8&4095;if(!xc){pc=k+((wc&255)<<2)|0;c[pc>>2]=(c[pc>>2]|0)+1;Rc=0;Sc=nc+1|0}else{Rc=xc;Sc=nc}nc=Rc+Sc|0;if(nc>>>0>=Gc>>>0){Tc=Rc;Uc=yc;Vc=Sc;Wc=Qc;break}else{Ac=Rc;mc=yc;zc=Qc}}Xc=Tc;Yc=c[kc>>2]|0;Zc=Uc;_c=Vc;$c=Wc}else{Xc=Hc;Yc=0;Zc=0;_c=0;$c=Bc}zc=Gc-_c|0;mc=Zc+Yc+zc|0;c[kc>>2]=mc;Ac=62;nc=mc;while(1){mc=k+(Ac<<2)|0;nc=(c[mc>>2]|0)+nc|0;c[mc>>2]=nc;if((Ac|0)<=0)break;else Ac=Ac+-1|0}Ac=Xc-zc|0;if(Jc){nc=Kc;do{Gc=nc;nc=nc+-1|0;mc=l+(Ic<<8)+(nc+Cc<<2)|0;c[mc>>2]=(c[mc>>2]|0)-(c[k+(nc<<2)>>2]|0)}while((Gc|0)>1)}Ic=Ic+1|0;if((Ic|0)==3){ad=Ac;bd=$c;break}else{Hc=Ac;Bc=$c}}c[Fc>>2]=bd;Bc=Cc+1|0;if((Bc|0)==(Dc|0)){cd=ad;break}else{fc=bd;Lc=ad;Cc=Bc}}dd=cd;ed=(gc|0)>(Dc|0)?gc:Dc}else{dd=s;ed=Gb}Mc=Mc+1|0;if((Mc|0)==5)break;else{s=dd;Gb=ed}}ed=f+848|0;Gb=c[ed>>2]|0;dd=c[ed+4>>2]|0;ed=Tb(d[f+873>>0]|0,0,Gb|0,dd|0)|0;s=Vb(ed|0,C|0,c[f+60>>2]|0)|0;ed=C;Mc=f+856|0;cd=Mc;ad=c[cd>>2]|0;bd=c[cd+4>>2]|0;cd=Sb(ad|0,bd|0,Gb|0,dd|0)|0;dd=Tb(cd|0,C|0,s|0,ed|0)|0;ed=C;s=f+864|0;c[s>>2]=dd;c[s+4>>2]=ed;s=Tb(ad|0,bd|0,1,0)|0;bd=Mc;c[bd>>2]=s;c[bd+4>>2]=C;if(h){bd=h;c[bd>>2]=dd;c[bd+4>>2]=ed}ed=f+54112|0;bd=f+48|0;dd=f+57120|0;c[dd>>2]=4<<((c[bd>>2]|0)>>>1&1^1);Xb(f+54624|0,f+51976|0,768)|0;Xb(f+56160|0,f+52744|0,768)|0;h=c[lc>>2]|0;s=f+180|0;Mc=c[s>>2]|0;c[f+56928>>2]=h;c[f+56940>>2]=h+(Mc<<2);ad=c[uc>>2]|0;cd=ad-(c[f+84>>2]|0)+Mc|0;c[f+56932>>2]=h+(ad<<2);c[f+56944>>2]=h+(cd<<2);Mc=c[tc>>2]|0;Gb=h+(Mc-(c[f+116>>2]|0)+cd<<2)|0;c[f+56936>>2]=h+(Mc+ad<<2);c[f+56948>>2]=Gb;Gb=a[f+874>>0]|0;if(Gb<<24>>24){ad=Gb&255;Gb=0;do{Mc=f+875+Gb|0;c[f+56976+(Gb<<3)>>2]=c[f+880+((d[Mc>>0]|0)*24|0)>>2];c[f+56976+(Gb<<3)+4>>2]=c[f+880+((d[Mc>>0]|0)*24|0)+4>>2];Gb=Gb+1|0}while((Gb|0)!=(ad|0));fd=0;do{Gb=f+875+fd|0;c[f+57e3+(fd<<3)>>2]=c[f+880+((d[Gb>>0]|0)*24|0)+8>>2];c[f+57e3+(fd<<3)+4>>2]=c[f+880+((d[Gb>>0]|0)*24|0)+12>>2];fd=fd+1|0}while((fd|0)!=(ad|0));gd=0;do{fd=f+875+gd|0;c[f+57024+(gd<<3)>>2]=c[f+880+((d[fd>>0]|0)*24|0)+16>>2];c[f+57024+(gd<<3)+4>>2]=c[f+880+((d[fd>>0]|0)*24|0)+20>>2];gd=gd+1|0}while((gd|0)!=(ad|0))}Yb=f+57072|0;_b=Yb+48|0;do{c[Yb>>2]=0;Yb=Yb+4|0}while((Yb|0)<(_b|0));ad=f+875|0;gd=a[(d[ad>>0]|0)+(f+51568)>>0]|0;fd=gd<<24>>24!=0;Gb=f+57124|0;c[Gb>>2]=fd&1;if(fd)rb(f+54368|0,gd&255);gd=f+53524|0;fd=c[gd>>2]|0;Mc=f+54040|0;h=c[Mc>>2]|0;cd=(h|0)==0;d:do if((fd|0)<1)if(cd)Ma=245;else{Pb(h);c[Mc>>2]=0;Fc=f+54044|0;Pb(c[Fc>>2]|0);c[Fc>>2]=0;Fc=f+54048|0;Pb(c[Fc>>2]|0);c[Fc>>2]=0;Ma=245}else{if(!cd){Fc=c[lc>>2]|0;$c=(c[tc>>2]|0)+(c[uc>>2]|0)+(c[sc>>2]|0)|0;l=a[ad>>0]|0;if(($c|0)>0){Xc=0;do{a[h+(c[Fc+(Xc<<2)>>2]|0)>>0]=l;Xc=Xc+1|0}while((Xc|0)!=($c|0));hd=c[gd>>2]|0}else hd=fd}else{if(a[r>>0]|0){Ma=245;break}$c=c[s>>2]|0;Xc=Ob($c)|0;c[Mc>>2]=Xc;if(!Xc){Ma=245;break}Ub(Xc|0,a[ad>>0]|0,$c|0)|0;hd=fd}$c=f+54044|0;Xc=c[$c>>2]|0;l=(Xc|0)==0;if((hd|0)<2){if(l){Ma=245;break}Pb(Xc);c[$c>>2]=0;Xc=f+54048|0;Pb(c[Xc>>2]|0);c[Xc>>2]=0;Ma=245;break}do if(l){Xc=c[f+4>>2]|0;Fc=c[f+8>>2]|0;Dc=_(Fc,Xc)|0;gc=c[bd>>2]|0;kc=Ob((_(Xc>>>(gc&1^1)<<1,Fc>>>(gc>>>1&1^1))|0)+Dc|0)|0;Dc=f+54048|0;c[Dc>>2]=kc;gc=Ob(c[s>>2]<<2)|0;c[$c>>2]=gc;if((kc|0)==0|(gc|0)==0){Pb(kc);c[Dc>>2]=0;Pb(c[$c>>2]|0);c[$c>>2]=0;Ma=245;break d}else{Dc=f+54052|0;c[Dc>>2]=0;id=Dc;jd=Xc;kd=Fc;Ma=238;break}}else{Fc=f+54052|0;if((c[Fc>>2]|0)==(((hd|0)>4?2:1)|0))ld=hd;else{id=Fc;jd=c[f+4>>2]|0;kd=c[f+8>>2]|0;Ma=238}}while(0);if((Ma|0)==238){if((hd|0)<5){c[f+54056>>2]=jd;c[f+54060>>2]=kd;l=0-jd|0;c[f+54064>>2]=l;c[f+54068>>2]=(c[f+54048>>2]|0)+(_(1-kd|0,l)|0);md=hd}else{l=_(jd,kd)|0;Fc=c[bd>>2]|0;Xc=jd>>>(Fc&1^1);Dc=kd>>>(Fc>>>1&1^1);Fc=_(Dc,Xc)|0;kc=f+54056|0;c[kc>>2]=jd;c[f+54060>>2]=kd;c[f+54064>>2]=jd;gc=c[f+54048>>2]|0;c[f+54068>>2]=gc;c[f+54072>>2]=Xc;c[f+54076>>2]=Dc;c[f+54080>>2]=Xc;Yc=gc;c[f+54084>>2]=Yc+l;c[f+54088>>2]=Xc;c[f+54092>>2]=Dc;c[f+54096>>2]=Xc;c[f+54100>>2]=Yc+(Fc+l);kb(kc,kc);md=c[gd>>2]|0}c[id>>2]=(md|0)>4?2:1;ld=md}if((ld|0)<5){kc=f+54072|0;l=f+236+((c[t>>2]|0)*48|0)+16|0;c[kc>>2]=c[l>>2];c[kc+4>>2]=c[l+4>>2];c[kc+8>>2]=c[l+8>>2];c[kc+12>>2]=c[l+12>>2];c[kc+16>>2]=c[l+16>>2];c[kc+20>>2]=c[l+20>>2];c[kc+24>>2]=c[l+24>>2];c[kc+28>>2]=c[l+28>>2]}l=f+57128|0;c[l>>2]=c[gd>>2];nd=l;od=$c}while(0);if((Ma|0)==245){ld=f+57128|0;c[ld>>2]=0;Yb=f+54056|0;Zb=f+236+((c[t>>2]|0)*48|0)|0;_b=Yb+48|0;do{c[Yb>>2]=c[Zb>>2];Yb=Yb+4|0;Zb=Zb+4|0}while((Yb|0)<(_b|0));nd=ld;od=f+54044|0}Yb=ed;_b=Yb+128|0;do{b[Yb>>1]=0;Yb=Yb+2|0}while((Yb|0)<(_b|0));kb(n,f+54056|0);Yb=f+76|0;_b=f+64|0;ld=k+2|0;Zb=f+552|0;md=f+172|0;id=f+54368|0;jd=f+54108|0;kd=f+54104|0;hd=c[dd>>2]|0;s=0;fd=0;while(1){ad=c[Yb>>2]|0;h=(hd+fd|0)<(ad|0);sc=h&1;uc=ad;tc=ad;ad=0;while(1){lc=(ad|0)!=0;if(lc)pd=(c[bd>>2]&2|0)==0;else pd=0;cd=pd&1;l=fd>>cd;kc=f+57048+(ad<<2)|0;c[kc>>2]=l;Fc=f+72+(ad<<5)+4|0;Yc=c[Fc>>2]|0;Xc=(c[dd>>2]>>cd)+l|0;l=f+57060+(ad<<2)|0;c[l>>2]=(Xc|0)<(Yc|0)?Xc:Yc;Oa(f,ed,ad);Yc=c[rc>>2]|0;Xc=c[_b>>2]|0;Dc=c[oc>>2]|0;gc=f+56928+(ad<<2)|0;Zc=c[gc>>2]|0;_c=c[f+56952+(ad<<2)>>2]|0;b[k>>1]=b[c[f+56976+(ad*24|0)>>2]>>1]|0;b[ld>>1]=b[c[f+56976+(ad*24|0)+4>>2]>>1]|0;if((_c|0)>0){Wc=0;do{Vc=c[Zc+(Wc<<2)>>2]|0;Uc=Dc+(Vc<<2)|0;Tc=c[Uc>>2]|0;Qc=(Tc&1792|0)!=256&1;Rc=c[f+56976+(ad*24|0)+((Tc>>>2&15)<<3)+(Qc<<2)>>2]|0;Tc=0;while(1){Sc=f+56160+(ad<<8)+(Tc<<2)|0;Pc=c[Sc>>2]|0;if(Pc){qd=Sc;rd=Pc;sd=Tc;Ma=257;break}Pc=f+54624+(ad<<8)+(Tc<<2)|0;Oc=c[Pc>>2]|0;Eb=Oc+1|0;m=a[Yc+Oc>>0]|0;Nc=c[896+((m&255)<<2)>>2]|0;do if((m&255)<15){qc=Oc+2|0;Ec=(d[Yc+Eb>>0]<<((m&255)<2?-13:0)+((m&255)<12?21:0))+Nc|0;Cc=Ec>>>8&4095;if(m<<24>>24){td=Ec;ud=Cc;vd=qc;break}Lc=(d[Yc+qc>>0]<<8)+Cc|0;td=Ec;ud=(Lc|0)==0?2147483647:Lc;vd=Oc+3|0}else{td=Nc;ud=Nc>>>8&4095;vd=Eb}while(0);c[Sc>>2]=ud;c[Pc>>2]=vd;Eb=(td&255)+Tc|0;Nc=(_(e[Rc+(Eb<<1)>>1]|0,(td^0-(td&1048576))>>21)|0)&65535;b[f+54112+(d[Xc+Eb>>0]<<1)>>1]=Nc;Nc=((ud|0)==0&1)+Eb|0;if((Nc|0)<64)Tc=Nc;else{wd=Tc;break}}if((Ma|0)==257){Ma=0;c[qd>>2]=rd+-1;wd=sd}b[ed>>1]=(c[Uc>>2]|0)>>>16;qb(f,Vc,ad,ed,wd,b[k+(Qc<<1)>>1]|0);Wc=Wc+1|0}while((Wc|0)!=(_c|0));xd=c[gc>>2]|0}else xd=Zc;c[gc>>2]=xd+(_c<<2);Wc=c[f+56964+(ad<<2)>>2]|0;if((Wc|0)>0){Xc=f+56940+(ad<<2)|0;Yc=(c[Xc>>2]|0)+(0-Wc<<2)|0;c[Xc>>2]=Yc;Va(c[Mb>>2]|0,c[Zb>>2]|0,c[f+576+(ad<<2)>>2]|0,Yc,Wc,c[md>>2]|0)}if(!(c[Gb>>2]|0)){yd=0;zd=0}else{sb(f,id,2,ad,(c[kc>>2]|0)-s|0,(c[l>>2]|0)-sc|0);yd=sc;zd=s}ob(f,$b,ad,((c[kc>>2]|0)-zd<<3)-(zd<<1)|0,((c[l>>2]|0)-yd<<3)-(yd<<1)|0);Wc=lc?3:0;do if((c[nd>>2]|0)<(Wc+2|0))if(!(c[Gb>>2]|0)){Ad=yd;Bd=zd}else{Ad=yd+sc|0;Bd=zd+s|0}else{Yc=zd+s|0;Xc=yd+sc|0;Dc=(c[kc>>2]|0)-Yc|0;Tc=c[l>>2]|0;Rc=Tc-Xc|0;Ac=f+72+(ad<<5)|0;Nc=c[Ac>>2]|0;Eb=f+72+(ad<<5)+8|0;Oc=c[Eb>>2]|0;m=_(Nc,Dc)|0;Lc=Oc+m|0;Ec=c[od>>2]|0;Cc=Ec+(Lc<<2)|0;qc=c[Mc>>2]|0;fc=qc+Lc|0;Bc=(Dc|0)>0;Hc=(c[Fc>>2]|0)>(Rc|0);Ic=Hc&1;Ub(Ec+(Lc+(Bc?Nc:0)<<2)|0,0,_(Nc<<2,Rc-Dc+(Bc<<31>>31)+Ic|0)|0)|0;Lc=(Bc&1)<<2|Dc<<3;Dc=f+54056+(ad<<4)+8|0;Bc=c[Dc>>2]|0;Kc=c[f+236+($b*48|0)+(ad<<4)+8>>2]|0;Jc=f+54056+(ad<<4)+12|0;vc=c[Jc>>2]|0;nc=_(Bc,Lc)|0;zc=vc+nc|0;Gc=c[f+236+($b*48|0)+(ad<<4)+12>>2]|0;mc=_(Kc,Lc)|0;jc=Gc+mc|0;Hb=f+54056+(ad<<4)|0;Kb=c[Hb>>2]|0;if((Lc|0)<4){dc=Kc<<2;yc=zc;xc=jc;pc=Lc;while(1){Xb(yc|0,xc|0,Kb|0)|0;pc=pc+1|0;if((pc|0)==4)break;else{yc=yc+Bc|0;xc=xc+Kc|0}}xc=Bc<<2;Cd=dc;Dd=xc;Ed=vc+xc|0;Fd=Gc+dc|0;Gd=4}else{Cd=mc;Dd=nc;Ed=zc;Fd=jc;Gd=Lc}xc=Ic^1;yc=Rc-xc<<3;if((Gd|0)<(yc|0)){pc=0-Kc|0;Qc=Bc<<3;Vc=Kc<<3;Uc=Nc+1|0;wc=-4-(Bc<<2)|0;if((Kb|0)>8){Fb=(Kb+-9|0)>>>3;hc=Fb+2|0;jb=(Rc<<3)+-1-(xc<<3)-Gd|0;Lb=Oc+Fb+m|0;fb=((Tc-xc-Xc<<3)+-1-Gd|0)>>>3;ac=Ec+(Lb+2<<2)+(_(fb,(Fb<<2)+8|0)|0)|0;Fb=Lb+(_(fb,hc)|0)|0;fb=fc;Lb=Ed;hb=Fd;Nb=Cc;ib=Gd;while(1){ic=c[f+53528+(d[fb>>0]<<2)>>2]|0;tb(Lb,Bc,hb+pc|0,Kc,ic,ic*3>>2,Nb,Nb+(Nc<<2)|0);ic=fb;ec=Nb;eb=8;do{lb=ec;ec=ec+4|0;ic=ic+1|0;Ib=c[f+53528+(d[ic>>0]<<2)>>2]|0;cc=Ib*3>>2;tb(Lb+eb|0,Bc,hb+(eb-Kc)|0,Kc,Ib,cc,ec,lb+(Uc<<2)|0);ub(Lb+(wc+eb)|0,Bc,Ib,cc,lb);eb=eb+8|0}while((eb|0)<(Kb|0));ib=ib+8|0;if((ib|0)>=(yc|0))break;else{fb=fb+hc|0;Lb=Lb+Qc|0;hb=hb+Vc|0;Nb=Nb+(hc<<2)|0}}Hd=Fb+2|0;Id=jb&-8;Jd=ac}else{hc=((Rc<<3)+-1-(xc<<3)-Gd|0)>>>3;Nb=Oc+1+m+hc|0;hb=fc;Lb=Ed;fb=Fd;ib=Cc;wc=Gd;while(1){Uc=c[f+53528+(d[hb>>0]<<2)>>2]|0;tb(Lb,Bc,fb+pc|0,Kc,Uc,Uc*3>>2,ib,ib+(Nc<<2)|0);wc=wc+8|0;if((wc|0)>=(yc|0))break;else{hb=hb+1|0;Lb=Lb+Qc|0;fb=fb+Vc|0;ib=ib+4|0}}Hd=Nb;Id=hc<<3;Jd=Ec+(Nb<<2)|0}ib=Id+8|0;Kd=qc+Hd|0;Ld=vc+((_(ib,Bc)|0)+Dd)|0;Md=Gc+((_(ib,Kc)|0)+Cd)|0;Nd=Jd;Od=Gd+8+Id|0}else{Kd=fc;Ld=Ed;Md=Fd;Nd=Cc;Od=Gd}do if(!Hc){ib=c[f+54056+(ad<<4)+4>>2]|0;if((ib|0)>(Od|0)){Vc=ib-Od|0;fb=Ld;Qc=Md;Lb=Od;while(1){Xb(fb|0,Qc|0,Kb|0)|0;Lb=Lb+1|0;if((Lb|0)==(ib|0))break;else{fb=fb+Bc|0;Qc=Qc+Kc|0}}Pd=Ld+(_(Vc,Bc)|0)|0}else Pd=Ld;if((Kb|0)<=8)break;Qc=-4-(Bc<<3)|0;fb=Kd;ib=Nd;Lb=8;while(1){fb=fb+1|0;hb=c[f+53528+(d[fb>>0]<<2)>>2]|0;ub(Pd+(Qc+Lb)|0,Bc,hb,hb*3>>2,ib);Lb=Lb+8|0;if((Lb|0)>=(Kb|0))break;else ib=ib+4|0}}while(0);if((c[nd>>2]|0)<(Wc+3|0)){Ad=Xc;Bd=Yc;break}Kb=Yc+s|0;Bc=Xc+sc|0;Kc=(c[kc>>2]|0)-Kb|0;Hc=c[Ac>>2]|0;Cc=(c[Eb>>2]|0)+(_(Hc,Kc)|0)|0;fc=(c[gd>>2]|0)>=((lc?7:4)|0);Gc=lc?3840:1920;vc=Kc<<3;Kc=c[Dc>>2]|0;qc=(c[l>>2]|0)-Bc<<3;Nb=c[Hb>>2]|0;Ec=c[f+54056+(ad<<4)+4>>2]|0;if((vc|0)>=(qc|0)){Ad=Bc;Bd=Kb;break}hc=(c[Jc>>2]|0)+(_(Kc,vc)|0)|0;ib=(Nb|0)>0;Lb=Kc<<3;Qc=0-Hc|0;fb=((Nb+-1|0)>>>3)+1|0;Vc=(c[oc>>2]|0)+(Cc<<2)|0;hb=hc;hc=(c[od>>2]|0)+(Cc<<2)|0;Cc=vc;while(1){if(ib){vc=(Cc|0)<1;yc=Cc+8|0;wc=(yc|0)>=(Ec|0);Nc=(wc&1)<<3|(vc&1)<<2;pc=Vc;m=hc;Oc=0;while(1){xc=d[((c[pc>>2]|0)>>>2&15)+(f+875)>>0]|0;Rc=c[m>>2]|0;ac=(Oc|0)<1;jb=Oc;Oc=Oc+8|0;Fb=(Oc|0)>=(Nb|0);Uc=Nc|ac&1|(Fb&1)<<1;e:do if(fc&(Rc|0)>(Gc|0)){Tc=hb+jb|0;Ic=f+53528+(xc<<2)|0;Lc=f+53784+(xc<<2)|0;vb(Tc,Kc,Uc,c[Ic>>2]|0,c[Lc>>2]|0,1);do if(!lc){if(!ac?(c[m+-4>>2]|0)>3840:0)break;if(!Fb?(c[m+4>>2]|0)>3840:0)break;if(!vc?(c[m+(Qc<<2)>>2]|0)>3840:0)break;if(wc)break e;if((c[m+(Hc<<2)>>2]|0)<=3840)break e}while(0);vb(Tc,Kc,Uc,c[Ic>>2]|0,c[Lc>>2]|0,1);vb(Tc,Kc,Uc,c[Ic>>2]|0,c[Lc>>2]|0,1)}else{if((Rc|0)>1536){vb(hb+jb|0,Kc,Uc,c[f+53528+(xc<<2)>>2]|0,c[f+53784+(xc<<2)>>2]|0,1);break}if((Rc|0)<=384)break;vb(hb+jb|0,Kc,Uc,c[f+53528+(xc<<2)>>2]|0,c[f+53784+(xc<<2)>>2]|0,0)}while(0);if((Oc|0)>=(Nb|0))break;else{pc=pc+4|0;m=m+4|0}}Qd=yc;Rd=Vc+(fb<<2)|0;Sd=hc+(fb<<2)|0}else{Qd=Cc+8|0;Rd=Vc;Sd=hc}if((Qd|0)<(qc|0)){Vc=Rd;hb=hb+Lb|0;hc=Sd;Cc=Qd}else{Ad=Bc;Bd=Kb;break}}}while(0);lc=(c[kc>>2]|0)-Bd<<cd;Wc=(lc|0)<(uc|0)?lc:uc;lc=(c[l>>2]|0)-Ad<<cd;Fc=(lc|0)<(tc|0)?lc:tc;ad=ad+1|0;if((ad|0)==3){Td=Wc;Ud=Fc;break}else{uc=Wc;tc=Fc}}tc=c[jd>>2]|0;if(tc){uc=c[Yb>>2]|0;za[tc&7](c[kd>>2]|0,n,uc-Ud|0,uc-Td|0)}uc=c[dd>>2]|0;if(h){hd=uc;s=1;fd=uc+fd|0}else break}pb(f,$b,0);pb(f,$b,1);pb(f,$b,2);$b=(a[r>>0]|0)==0;r=c[t>>2]|0;c[Wb>>2]=r;if($b){c[gb>>2]=r;r=c[Mb>>2]|0;c[Zb>>2]=r;c[Rb>>2]=r}else c[Zb>>2]=c[Mb>>2];o=0;i=j;return o|0}function Sa(a,b){a=a|0;b=b|0;var c=0;if((a|0)==0|(b|0)==0){c=-1;return c|0}kb(b,a+54056|0);c=0;return c|0}function Ta(d,e){d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0;f=i;i=i+512|0;g=f+256|0;h=f;j=Ka(d,3)|0;k=0;do{a[e+256+k>>0]=Ka(d,j)|0;k=k+1|0}while((k|0)!=64);k=(Ka(d,4)|0)+1|0;j=0;do{b[e+128+(j<<1)>>1]=Ka(d,k)|0;j=j+1|0}while((j|0)!=64);j=(Ka(d,4)|0)+1|0;k=0;do{b[e+(k<<1)>>1]=Ka(d,j)|0;k=k+1|0}while((k|0)!=64);k=Ka(d,9)|0;j=k+1|0;l=Ob(j<<6)|0;if(!l){m=-1;i=f;return m|0}if((k|0)>-1){n=0;do{o=0;do{a[l+(n<<6)+o>>0]=Ka(d,8)|0;o=o+1|0}while((o|0)!=64);n=n+1|0}while((n|0)<(j|0))}n=hb(k)|0;k=0;a:while(1){o=(k|0)/3|0;p=(k|0)%3|0;q=e+320+(o*36|0)+(p*12|0)|0;if((k|0)>0?(La(d)|0)==0:0){do if((k|0)>2)if(!(La(d)|0)){r=k+-1|0;s=(r|0)%3|0;t=(r|0)/3|0;break}else{s=p;t=o+-1|0;break}else{r=k+-1|0;s=(r|0)%3|0;t=(r|0)/3|0}while(0);r=e+320+(t*36|0)+(s*12|0)|0;c[q>>2]=c[r>>2];c[q+4>>2]=c[r+4>>2];c[q+8>>2]=c[r+8>>2]}else u=21;b:do if((u|0)==21){u=0;c[h>>2]=Ka(d,n)|0;r=0;v=0;while(1){w=(Ka(d,hb(62-r|0)|0)|0)+1|0;c[g+(v<<2)>>2]=w;x=w+r|0;w=Ka(d,n)|0;y=v+1|0;c[h+(y<<2)>>2]=w;if((x|0)<63){r=x;v=y}else{z=x;A=w;B=y;break}}if((z|0)>63){u=24;break a}c[q>>2]=B;v=B<<2;r=Ob(v)|0;c[e+320+(o*36|0)+(p*12|0)+4>>2]=r;if(!r){u=26;break a}Xb(r|0,g|0,v|0)|0;v=Ob((B<<6)+64|0)|0;if(!v){u=28;break a}c[e+320+(o*36|0)+(p*12|0)+8>>2]=v;if((A|0)<(j|0)){C=A;D=B}else{u=30;break a}while(1){r=v+(D<<6)|0;y=l+(C<<6)|0;w=r+64|0;do{a[r>>0]=a[y>>0]|0;r=r+1|0;y=y+1|0}while((r|0)<(w|0));if((D|0)<=0)break b;D=D+-1|0;C=c[h+(D<<2)>>2]|0;if((C|0)>=(j|0)){u=30;break a}}}while(0);k=k+1|0;if((k|0)>=6){u=34;break}}if((u|0)==24){Pb(l);m=-20;i=f;return m|0}else if((u|0)==26){Pb(l);m=-1;i=f;return m|0}else if((u|0)==28){Pb(l);m=-1;i=f;return m|0}else if((u|0)==30){Pb(l);m=-20;i=f;return m|0}else if((u|0)==34){Pb(l);m=0;i=f;return m|0}return 0}function Ua(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0;b=5;d=6;while(1){e=(b|0)/3|0;f=(b|0)%3|0;if((d|0)>1){g=d+-2|0;h=(g|0)/3|0;i=(g|0)%3|0;g=a+320+(e*36|0)+(f*12|0)+4|0;if((c[g>>2]|0)==(c[a+320+(h*36|0)+(i*12|0)+4>>2]|0))c[g>>2]=0;g=a+320+(e*36|0)+(f*12|0)+8|0;if((c[g>>2]|0)==(c[a+320+(h*36|0)+(i*12|0)+8>>2]|0))c[g>>2]=0}if((b|0)>2){g=a+356+(f*12|0)+4|0;if((c[g>>2]|0)==(c[a+320+(f*12|0)+4>>2]|0))c[g>>2]=0;g=a+356+(f*12|0)+8|0;if((c[g>>2]|0)==(c[a+320+(f*12|0)+8>>2]|0))c[g>>2]=0}Pb(c[a+320+(e*36|0)+(f*12|0)+4>>2]|0);Pb(c[a+320+(e*36|0)+(f*12|0)+8>>2]|0);if((b|0)>0){f=b;b=b+-1|0;d=f}else break}return}function Va(b,e,f,g,h,i){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;if((h|0)<=0)return;j=f<<1;k=f*3|0;l=f<<2;m=f*5|0;n=f*6|0;o=f*7|0;p=0;do{q=c[i+(c[g+(p<<2)>>2]<<2)>>2]|0;r=e+q|0;s=r;t=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=r+4|0;r=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=b+q|0;u=s;a[u>>0]=t;a[u+1>>0]=t>>8;a[u+2>>0]=t>>16;a[u+3>>0]=t>>24;t=s+4|0;a[t>>0]=r;a[t+1>>0]=r>>8;a[t+2>>0]=r>>16;a[t+3>>0]=r>>24;r=q+f|0;t=e+r|0;s=t;u=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=t+4|0;t=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=b+r|0;r=s;a[r>>0]=u;a[r+1>>0]=u>>8;a[r+2>>0]=u>>16;a[r+3>>0]=u>>24;u=s+4|0;a[u>>0]=t;a[u+1>>0]=t>>8;a[u+2>>0]=t>>16;a[u+3>>0]=t>>24;t=q+j|0;u=e+t|0;s=u;r=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=u+4|0;u=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=b+t|0;t=s;a[t>>0]=r;a[t+1>>0]=r>>8;a[t+2>>0]=r>>16;a[t+3>>0]=r>>24;r=s+4|0;a[r>>0]=u;a[r+1>>0]=u>>8;a[r+2>>0]=u>>16;a[r+3>>0]=u>>24;u=q+k|0;r=e+u|0;s=r;t=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=r+4|0;r=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=b+u|0;u=s;a[u>>0]=t;a[u+1>>0]=t>>8;a[u+2>>0]=t>>16;a[u+3>>0]=t>>24;t=s+4|0;a[t>>0]=r;a[t+1>>0]=r>>8;a[t+2>>0]=r>>16;a[t+3>>0]=r>>24;r=q+l|0;t=e+r|0;s=t;u=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=t+4|0;t=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=b+r|0;r=s;a[r>>0]=u;a[r+1>>0]=u>>8;a[r+2>>0]=u>>16;a[r+3>>0]=u>>24;u=s+4|0;a[u>>0]=t;a[u+1>>0]=t>>8;a[u+2>>0]=t>>16;a[u+3>>0]=t>>24;t=q+m|0;u=e+t|0;s=u;r=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=u+4|0;u=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=b+t|0;t=s;a[t>>0]=r;a[t+1>>0]=r>>8;a[t+2>>0]=r>>16;a[t+3>>0]=r>>24;r=s+4|0;a[r>>0]=u;a[r+1>>0]=u>>8;a[r+2>>0]=u>>16;a[r+3>>0]=u>>24;u=q+n|0;r=e+u|0;s=r;t=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=r+4|0;r=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;s=b+u|0;u=s;a[u>>0]=t;a[u+1>>0]=t>>8;a[u+2>>0]=t>>16;a[u+3>>0]=t>>24;t=s+4|0;a[t>>0]=r;a[t+1>>0]=r>>8;a[t+2>>0]=r>>16;a[t+3>>0]=r>>24;r=q+o|0;q=e+r|0;t=q;s=d[t>>0]|d[t+1>>0]<<8|d[t+2>>0]<<16|d[t+3>>0]<<24;t=q+4|0;q=d[t>>0]|d[t+1>>0]<<8|d[t+2>>0]<<16|d[t+3>>0]<<24;t=b+r|0;r=t;a[r>>0]=s;a[r+1>>0]=s>>8;a[r+2>>0]=s>>16;a[r+3>>0]=s>>24;s=t+4|0;a[s>>0]=q;a[s+1>>0]=q>>8;a[s+2>>0]=q>>16;a[s+3>>0]=q>>24;p=p+1|0}while((p|0)!=(h|0));return}function Wa(c,d,e){c=c|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=c;c=0;while(1){g=c<<3;h=b[e+(g<<1)>>1]|0;i=(h<<16>>16)+128|0;a[f>>0]=h<<16>>16>-129?((i|0)>255?-1:i&255):0;i=b[e+((g|1)<<1)>>1]|0;h=(i<<16>>16)+128|0;a[f+1>>0]=i<<16>>16>-129?((h|0)>255?-1:h&255):0;h=b[e+((g|2)<<1)>>1]|0;i=(h<<16>>16)+128|0;a[f+2>>0]=h<<16>>16>-129?((i|0)>255?-1:i&255):0;i=b[e+((g|3)<<1)>>1]|0;h=(i<<16>>16)+128|0;a[f+3>>0]=i<<16>>16>-129?((h|0)>255?-1:h&255):0;h=b[e+((g|4)<<1)>>1]|0;i=(h<<16>>16)+128|0;a[f+4>>0]=h<<16>>16>-129?((i|0)>255?-1:i&255):0;i=b[e+((g|5)<<1)>>1]|0;h=(i<<16>>16)+128|0;a[f+5>>0]=i<<16>>16>-129?((h|0)>255?-1:h&255):0;h=b[e+((g|6)<<1)>>1]|0;i=(h<<16>>16)+128|0;a[f+6>>0]=h<<16>>16>-129?((i|0)>255?-1:i&255):0;i=b[e+((g|7)<<1)>>1]|0;g=(i<<16>>16)+128|0;a[f+7>>0]=i<<16>>16>-129?((g|0)>255?-1:g&255):0;c=c+1|0;if((c|0)==8)break;else f=f+d|0}return}function Xa(c,e,f,g){c=c|0;e=e|0;f=f|0;g=g|0;var h=0,i=0,j=0;h=e;e=c;c=0;while(1){i=c<<3;j=(d[h>>0]|0)+(b[g+(i<<1)>>1]|0)|0;a[e>>0]=(j>>>31)+255&((j|0)>255?255:j);j=(d[h+1>>0]|0)+(b[g+((i|1)<<1)>>1]|0)|0;a[e+1>>0]=(j>>>31)+255&((j|0)>255?255:j);j=(d[h+2>>0]|0)+(b[g+((i|2)<<1)>>1]|0)|0;a[e+2>>0]=(j>>>31)+255&((j|0)>255?255:j);j=(d[h+3>>0]|0)+(b[g+((i|3)<<1)>>1]|0)|0;a[e+3>>0]=(j>>>31)+255&((j|0)>255?255:j);j=(d[h+4>>0]|0)+(b[g+((i|4)<<1)>>1]|0)|0;a[e+4>>0]=(j>>>31)+255&((j|0)>255?255:j);j=(d[h+5>>0]|0)+(b[g+((i|5)<<1)>>1]|0)|0;a[e+5>>0]=(j>>>31)+255&((j|0)>255?255:j);j=(d[h+6>>0]|0)+(b[g+((i|6)<<1)>>1]|0)|0;a[e+6>>0]=(j>>>31)+255&((j|0)>255?255:j);j=(d[h+7>>0]|0)+(b[g+((i|7)<<1)>>1]|0)|0;a[e+7>>0]=(j>>>31)+255&((j|0)>255?255:j);c=c+1|0;if((c|0)==8)break;else{h=h+f|0;e=e+f|0}}return}function Ya(c,e,f,g,h){c=c|0;e=e|0;f=f|0;g=g|0;h=h|0;var i=0,j=0,k=0,l=0;i=e;e=f;f=c;c=0;while(1){j=c<<3;k=0;do{l=(((d[e+k>>0]|0)+(d[i+k>>0]|0)|0)>>>1)+(b[h+(k+j<<1)>>1]|0)|0;a[f+k>>0]=(l>>>31)+255&((l|0)>255?255:l);k=k+1|0}while((k|0)!=8);c=c+1|0;if((c|0)==8)break;else{i=i+g|0;e=e+g|0;f=f+g|0}}return}function Za(b,c){b=b|0;c=c|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;e=0;f=0;g=0;h=0;a:while(1){i=f;while(1){j=La(b)|0;if((Ma(b)|0)<0){k=-20;l=12;break a}if(j){m=i;break}if((i|0)>31){k=-20;l=12;break a}else i=i+1|0}if((g|0)>31){k=-20;l=12;break}g=g+1|0;i=Ka(b,5)|0;j=d[1272+i>>0]|0;n=1<<j;o=j+m&255;j=h+2|0;p=(n|0)<1?~n:-2;q=n;r=h;s=d[1304+i>>0]|0;while(1){a[c+(r<<1)>>0]=s;a[c+(r<<1)+1>>0]=o;if((q|0)>1){q=q+-1|0;r=r+1|0;s=s+1|0}else break}s=j+n+p|0;r=-2147483648>>>(m+-1|0);if((m|0)<1|(r&e|0)==0){t=e;u=r;v=m}else{q=e;o=r;r=m;while(1){i=o^q;w=o<<1;x=r+-1|0;if((r|0)<2|(w&i|0)==0){t=i;u=w;v=x;break}else{q=i;o=w;r=x}}}if((v|0)<1){k=s;l=12;break}else{e=u|t;f=v;h=s}}if((l|0)==12)return k|0;return 0}function _a(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0;d=i;i=i+512|0;e=d;f=0;while(1){g=Za(a,e)|0;if((g|0)<0){h=g;break}j=wb(0,e,g)|0;if(j>>>0>32767){h=-23;break}k=Ob(j<<1)|0;if(!k){h=-1;break}wb(k,e,g)|0;c[b+(f<<2)>>2]=k;f=f+1|0;if((f|0)>=80){l=0;m=7;break}}if((m|0)==7){i=d;return l|0}l=h;i=d;return l|0}function $a(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;d=0;while(1){e=b+(d<<2)|0;f=(xb(c[e>>2]|0,0)|0)<<1;g=Ob(f)|0;c[a+(d<<2)>>2]=g;if(!g){h=d;break}Xb(g|0,c[e>>2]|0,f|0)|0;d=d+1|0;if((d|0)>=80){i=0;j=6;break}}if((j|0)==6)return i|0;if((h|0)>0)k=h;else{i=-1;return i|0}do{h=k;k=k+-1|0;Pb(c[a+(k<<2)>>2]|0)}while((h|0)>1);i=-1;return i|0}function ab(a){a=a|0;var b=0;b=0;do{Pb(c[a+(b<<2)>>2]|0);b=b+1|0}while((b|0)!=80);return}function bb(a,e){a=a|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0;f=a+4|0;g=a+8|0;h=c[a>>2]|0;i=a+12|0;a=c[i>>2]|0;j=0;k=c[f>>2]|0;l=c[g>>2]|0;while(1){m=b[e+(j<<1)>>1]|0;if((m|0)>(a|0)){n=k;o=32-a|0;p=l;while(1){if(n>>>0>=h>>>0){q=n;r=-1073741824;s=p;break}t=o+-8|0;u=n+1|0;v=d[n>>0]<<t|p;if(t>>>0>7){n=u;o=t;p=v}else{q=u;r=t;s=v;break}}w=32-r|0;x=q;y=s}else{w=a;x=k;y=l}p=b[e+(j+1+(y>>>(32-m|0))<<1)>>1]|0;o=p<<16>>16;if(p<<16>>16<1){z=o;A=w;B=x;C=y;break}a=w-m|0;j=o;k=x;l=y<<m}y=0-z|0;z=y>>8;c[f>>2]=B;c[g>>2]=C<<z;c[i>>2]=A-z;return y&255|0}function cb(a,c,d){a=a|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;e=i;i=i+128|0;f=e;if((d|0)<4){g=c+2|0;h=(b[c>>1]|0)*46341>>16;j=b[g>>1]|0;k=j*12785>>16;l=j*64277>>16;j=k*46341>>16;m=l*46341>>16;n=m+j|0;o=m-j|0;b[f>>1]=l+h;b[f+16>>1]=n+h;b[f+32>>1]=o+h;b[f+48>>1]=k+h;b[f+64>>1]=h-k;b[f+80>>1]=h-o;b[f+96>>1]=h-n;b[f+112>>1]=h-l;l=c+16|0;h=((b[l>>1]|0)*46341|0)>>>16&65535;b[f+114>>1]=h;b[f+98>>1]=h;b[f+82>>1]=h;b[f+66>>1]=h;b[f+50>>1]=h;b[f+34>>1]=h;b[f+18>>1]=h;b[f+2>>1]=h;h=0;do{n=h<<3;o=(b[f+(n<<1)>>1]|0)*46341>>16;k=b[f+((n|1)<<1)>>1]|0;n=k*12785>>16;j=k*64277>>16;k=n*46341>>16;m=j*46341>>16;p=m+k|0;q=m-k|0;b[a+(h<<1)>>1]=j+o;b[a+(h+8<<1)>>1]=p+o;b[a+(h+16<<1)>>1]=q+o;b[a+(h+24<<1)>>1]=n+o;b[a+(h+32<<1)>>1]=o-n;b[a+(h+40<<1)>>1]=o-q;b[a+(h+48<<1)>>1]=o-p;b[a+(h+56<<1)>>1]=o-j;h=h+1|0}while((h|0)!=8);r=0;do{h=a+(r<<1)|0;b[h>>1]=((b[h>>1]|0)+8|0)>>>4;r=r+1|0}while((r|0)!=64);b[l>>1]=0;b[g>>1]=0;b[c>>1]=0;i=e;return}if((d|0)>=11){yb(f,c);yb(f+2|0,c+16|0);yb(f+4|0,c+32|0);yb(f+6|0,c+48|0);yb(f+8|0,c+64|0);yb(f+10|0,c+80|0);yb(f+12|0,c+96|0);yb(f+14|0,c+112|0);yb(a,f);yb(a+2|0,f+16|0);yb(a+4|0,f+32|0);yb(a+6|0,f+48|0);yb(a+8|0,f+64|0);yb(a+10|0,f+80|0);yb(a+12|0,f+96|0);yb(a+14|0,f+112|0);d=0;do{g=a+(d<<1)|0;b[g>>1]=((b[g>>1]|0)+8|0)>>>4;d=d+1|0}while((d|0)!=64);d=c;g=d+128|0;do{b[d>>1]=0;d=d+2|0}while((d|0)<(g|0));i=e;return}d=(b[c>>1]|0)*46341>>16;g=b[c+4>>1]|0;l=g*25080>>16;r=g*60547>>16;g=b[c+2>>1]|0;h=g*12785>>16;j=b[c+6>>1]|0;o=j*36410>>16;p=j*54491>>16;j=g*64277>>16;g=h-o|0;q=(o+h<<16>>16)*46341>>16;h=p+j|0;o=(j-p<<16>>16)*46341>>16;p=l+d|0;j=d-l|0;l=r+d|0;n=d-r|0;r=o+q|0;d=o-q|0;b[f>>1]=h+l;b[f+16>>1]=r+p;b[f+32>>1]=d+j;b[f+48>>1]=g+n;b[f+64>>1]=n-g;b[f+80>>1]=j-d;b[f+96>>1]=p-r;b[f+112>>1]=l-h;h=c+16|0;l=c+18|0;r=c+20|0;p=(b[h>>1]|0)*46341>>16;d=b[r>>1]|0;j=d*25080>>16;g=d*60547>>16;d=b[l>>1]|0;n=d*12785>>16;q=d*64277>>16;d=n*46341>>16;o=q*46341>>16;k=j+p|0;m=p-j|0;j=g+p|0;s=p-g|0;g=o+d|0;p=o-d|0;b[f+2>>1]=j+q;b[f+18>>1]=g+k;b[f+34>>1]=p+m;b[f+50>>1]=s+n;b[f+66>>1]=s-n;b[f+82>>1]=m-p;b[f+98>>1]=k-g;b[f+114>>1]=j-q;q=c+32|0;j=c+34|0;g=(b[q>>1]|0)*46341>>16;k=b[j>>1]|0;p=k*12785>>16;m=k*64277>>16;k=p*46341>>16;n=m*46341>>16;s=n+k|0;d=n-k|0;b[f+4>>1]=m+g;b[f+20>>1]=s+g;b[f+36>>1]=d+g;b[f+52>>1]=p+g;b[f+68>>1]=g-p;b[f+84>>1]=g-d;b[f+100>>1]=g-s;b[f+116>>1]=g-m;m=c+48|0;g=((b[m>>1]|0)*46341|0)>>>16&65535;b[f+118>>1]=g;b[f+102>>1]=g;b[f+86>>1]=g;b[f+70>>1]=g;b[f+54>>1]=g;b[f+38>>1]=g;b[f+22>>1]=g;b[f+6>>1]=g;g=0;do{s=g<<3;d=(b[f+(s<<1)>>1]|0)*46341>>16;p=b[f+((s|2)<<1)>>1]|0;k=p*25080>>16;n=p*60547>>16;p=b[f+((s|1)<<1)>>1]|0;o=p*12785>>16;t=b[f+((s|3)<<1)>>1]|0;s=t*36410>>16;u=t*54491>>16;t=p*64277>>16;p=o-s|0;v=(s+o<<16>>16)*46341>>16;o=u+t|0;s=(t-u<<16>>16)*46341>>16;u=k+d|0;t=d-k|0;k=n+d|0;w=d-n|0;n=s+v|0;d=s-v|0;b[a+(g<<1)>>1]=o+k;b[a+(g+8<<1)>>1]=n+u;b[a+(g+16<<1)>>1]=d+t;b[a+(g+24<<1)>>1]=p+w;b[a+(g+32<<1)>>1]=w-p;b[a+(g+40<<1)>>1]=t-d;b[a+(g+48<<1)>>1]=u-n;b[a+(g+56<<1)>>1]=k-o;g=g+1|0}while((g|0)!=8);x=0;do{g=a+(x<<1)|0;b[g>>1]=((b[g>>1]|0)+8|0)>>>4;x=x+1|0}while((x|0)!=64);b[m>>1]=0;b[j>>1]=0;b[q>>1]=0;b[r>>1]=0;b[l>>1]=0;b[h>>1]=0;h=c;c=h;b[c>>1]=0;b[c+2>>1]=0>>>16;c=h+4|0;b[c>>1]=0;b[c+2>>1]=0>>>16;i=e;return}function db(b){b=b|0;var d=0,e=0;d=b;e=d+60|0;do{c[d>>2]=0;d=d+4|0}while((d|0)<(e|0));a[b>>0]=3;a[b+1>>0]=2;a[b+2>>0]=1;c[b+60>>2]=6;return}function eb(a){a=a|0;var b=0;b=a;a=b+64|0;do{c[b>>2]=0;b=b+4|0}while((b|0)<(a|0));return}function fb(a){a=a|0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;return}function gb(a){a=a|0;var b=0,d=0;if(!a)return;b=a+8|0;if((c[b>>2]|0)>0){d=0;do{Pb(c[(c[a>>2]|0)+(d<<2)>>2]|0);d=d+1|0}while((d|0)<(c[b>>2]|0))}Pb(c[a>>2]|0);Pb(c[a+4>>2]|0);Pb(c[a+12>>2]|0);c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;return}function hb(a){a=a|0;var b=0,c=0,d=0;if(!a)b=0;else{c=a;a=0;while(1){c=c>>>1;d=a+1|0;if(!c){b=d;break}else a=d}}return b|0}function ib(b,c){b=b|0;c=c|0;var d=0,e=0,f=0;d=c+-1|0;if(b>>>0>~c>>>0|(d&(c|-256)|0)!=0){e=0;return e|0}f=Ob(c+b|0)|0;if(!f){e=0;return e|0}b=f+-1&d;a[f+b>>0]=b;e=f+(b+1)|0;return e|0}function jb(a){a=a|0;if(!a)return;Pb(a+~(d[a+-1>>0]|0)|0);return}function kb(a,b){a=a|0;b=b|0;var d=0,e=0;c[a>>2]=c[b>>2];d=c[b+4>>2]|0;c[a+4>>2]=d;e=0-(c[b+8>>2]|0)|0;c[a+8>>2]=e;c[a+12>>2]=(c[b+12>>2]|0)+(_(1-d|0,e)|0);c[a+16>>2]=c[b+16>>2];e=c[b+20>>2]|0;c[a+20>>2]=e;d=0-(c[b+24>>2]|0)|0;c[a+24>>2]=d;c[a+28>>2]=(c[b+28>>2]|0)+(_(1-e|0,d)|0);c[a+32>>2]=c[b+32>>2];d=c[b+36>>2]|0;c[a+36>>2]=d;e=0-(c[b+40>>2]|0)|0;c[a+40>>2]=e;c[a+44>>2]=(c[b+44>>2]|0)+(_(1-d|0,e)|0);return}function lb(f,g,h){f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0;j=i;i=i+64|0;k=j;l=(g|0)==0;m=0;while(1){n=1336+(m<<2)|0;o=1344+(m<<2)|0;p=0;while(1){q=h+320+(m*36|0)+(p*12|0)|0;r=c[q>>2]|0;if((r|0)>=0){s=h+320+(m*36|0)+(p*12|0)+8|0;t=c[n>>2]|0;u=c[o>>2]|0;v=h+320+(m*36|0)+(p*12|0)+4|0;w=r;r=0;x=0;while(1){y=k;z=(c[s>>2]|0)+(x<<6)|0;A=y+64|0;do{a[y>>0]=a[z>>0]|0;y=y+1|0;z=z+1|0}while((y|0)<(A|0));if((x|0)==(w|0))B=r+1|0;else B=(c[(c[v>>2]|0)+(x<<2)>>2]|0)+r|0;z=x;x=x+1|0;a:do if(l){y=r;b:while(1){A=(((_(d[k>>0]|0,e[h+(y<<1)>>1]|0)|0)>>>0)/100|0)<<2;C=A>>>0>4096?4096:A;A=f+(y*24|0)+(p<<3)+(m<<2)|0;D=c[A>>2]|0;b[D>>1]=t-(t>>>0<C>>>0?t-C|0:0);C=h+128+(y<<1)|0;E=1;do{F=(((_(d[k+(d[8+E>>0]|0)>>0]|0,e[C>>1]|0)|0)>>>0)/100|0)<<2;G=F>>>0>4096?4096:F;b[D+(E<<1)>>1]=u-(u>>>0<G>>>0?u-G|0:0);E=E+1|0}while((E|0)!=64);H=0;c:while(1){E=(H|0)<(m|0);C=E?3:p;if((C|0)>0){G=0;do{F=c[f+(y*24|0)+(G<<3)+(H<<2)>>2]|0;if(!(Nb(D,F,128)|0)){I=F;J=13;break c}G=G+1|0}while((G|0)<(C|0))}if(E)H=H+1|0;else break}if((J|0)==13){J=0;c[A>>2]=I}D=y+1|0;if((B|0)<=(D|0)){K=D;L=w;break a}C=B-D|0;G=c[s>>2]|0;F=D-r|0;M=c[(c[v>>2]|0)+(z<<2)>>2]|0;N=M<<1;O=0;while(1){P=_(d[G+(z<<6)+O>>0]|0,C)|0;a[k+O>>0]=(((_(d[G+(x<<6)+O>>0]|0,F)|0)+P<<1)+M|0)/(N|0)|0;P=O+1|0;if((P|0)==64){y=D;continue b}else O=P}}}else{y=r;d:while(1){O=_(d[k>>0]|0,e[h+(y<<1)>>1]|0)|0;c[g+(y<<2)>>2]=(O>>>0)/160|0;D=((O>>>0)/100|0)<<2;O=D>>>0>4096?4096:D;D=f+(y*24|0)+(p<<3)+(m<<2)|0;N=c[D>>2]|0;b[N>>1]=t-(t>>>0<O>>>0?t-O|0:0);O=h+128+(y<<1)|0;M=1;do{F=(((_(d[k+(d[8+M>>0]|0)>>0]|0,e[O>>1]|0)|0)>>>0)/100|0)<<2;G=F>>>0>4096?4096:F;b[N+(M<<1)>>1]=u-(u>>>0<G>>>0?u-G|0:0);M=M+1|0}while((M|0)!=64);Q=0;e:while(1){M=(Q|0)<(m|0);O=M?3:p;if((O|0)>0){G=0;do{F=c[f+(y*24|0)+(G<<3)+(Q<<2)>>2]|0;if(!(Nb(N,F,128)|0)){R=F;J=25;break e}G=G+1|0}while((G|0)<(O|0))}if(M)Q=Q+1|0;else break}if((J|0)==25){J=0;c[D>>2]=R}N=y+1|0;if((B|0)<=(N|0)){S=N;break}O=B-N|0;G=c[s>>2]|0;E=N-r|0;F=c[(c[v>>2]|0)+(z<<2)>>2]|0;C=F<<1;A=0;while(1){P=_(d[G+(z<<6)+A>>0]|0,O)|0;a[k+A>>0]=(((_(d[G+(x<<6)+A>>0]|0,E)|0)+P<<1)+F|0)/(C|0)|0;P=A+1|0;if((P|0)==64){y=N;continue d}else A=P}}K=S;L=c[q>>2]|0}while(0);if((z|0)>=(L|0))break;else{w=L;r=K}}}p=p+1|0;if((p|0)==3)break}m=m+1|0;if((m|0)==2)break}i=j;return}function mb(b,e,f){b=b|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,ua=0,va=0,wa=0,xa=0,ya=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0,Oa=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Va=0,Wa=0,Xa=0,Ya=0,Za=0,_a=0,$a=0,ab=0,bb=0,cb=0,db=0,eb=0,fb=0,gb=0,hb=0,lb=0,mb=0,nb=0,ob=0,pb=0,qb=0,rb=0,sb=0,tb=0,ub=0,vb=0,wb=0,xb=0,yb=0,zb=0,Ab=0,Bb=0,Cb=0,Db=0;if(!e){g=-1;return g|0}h=c[e+4>>2]|0;if(h&15){g=-10;return g|0}i=e+8|0;j=c[i>>2]|0;if((j+-1|0)>>>0>1048574|((h+-1|0)>>>0>1048574|(j&15|0)!=0)){g=-10;return g|0}k=c[e+20>>2]|0;if(((c[e+12>>2]|0)+k|0)>>>0>h>>>0){g=-10;return g|0}h=e+24|0;l=c[h>>2]|0;m=e+16|0;n=c[m>>2]|0;if(k>>>0>255|(n+l|0)>>>0>j>>>0){g=-10;return g|0}if((j-l-n|0)>>>0>255){g=-10;return g|0}if((c[e+44>>2]|0)>>>0>2){g=-10;return g|0}if((c[e+48>>2]|0)>>>0>3){g=-10;return g|0}if(!(c[e+28>>2]|0)){g=-10;return g|0}if(!(c[e+32>>2]|0)){g=-10;return g|0}Ub(b|0,0,51632)|0;n=b;l=e;j=n+64|0;do{c[n>>2]=c[l>>2];n=n+4|0;l=l+4|0}while((n|0)<(j|0));k=b+24|0;c[k>>2]=(c[i>>2]|0)-(c[m>>2]|0)-(c[h>>2]|0);a[b+872>>0]=-1;c[b+68>>2]=0;c[b+64>>2]=8;h=b+4|0;m=(c[h>>2]|0)>>>3;i=b+8|0;o=(c[i>>2]|0)>>>3;p=b+48|0;q=c[p>>2]|0;r=q&1^1;s=q>>>1&1^1;q=(r+m|0)>>>r;r=(s+o|0)>>>s;s=_(o,m)|0;t=_(r,q)|0;u=t<<1;v=u+s|0;w=(m+3|0)>>>2;x=(o+3|0)>>>2;y=q+3>>2;z=r+3>>2;A=_(x,w)|0;B=_(z,y)|0;D=B<<1;E=D+A|0;F=A<<2;do if(!((t|0)<0|(u|0)<(t|0))?(A&1073741823|0)==(A|0)&((E>>>0<A>>>0|(D>>>0<B>>>0?1:((A>>>0)/(w>>>0)|0|0)!=(x|0)))^1):0){G=b+72|0;c[G>>2]=m;H=b+76|0;c[H>>2]=o;I=b+80|0;c[I>>2]=0;J=b+84|0;c[J>>2]=s;c[b+88>>2]=w;c[b+92>>2]=x;c[b+96>>2]=0;c[b+100>>2]=A;K=b+136|0;c[K>>2]=q;L=b+104|0;c[L>>2]=q;c[b+140>>2]=r;c[b+108>>2]=r;M=b+112|0;c[M>>2]=s;N=b+144|0;c[N>>2]=t+s;O=b+148|0;c[O>>2]=t;P=b+116|0;c[P>>2]=t;c[b+152>>2]=y;c[b+120>>2]=y;c[b+156>>2]=z;c[b+124>>2]=z;c[b+128>>2]=A;c[b+160>>2]=B+A;c[b+164>>2]=B;c[b+132>>2]=B;Q=b+180|0;c[Q>>2]=v;R=Qb(v,4)|0;S=b+168|0;c[S>>2]=R;T=Ob(v<<1)|0;c[b+176>>2]=T;c[b+192>>2]=E;U=Ob(E<<6)|0;V=b+184|0;c[V>>2]=U;W=Qb(E,1)|0;X=b+188|0;c[X>>2]=W;c[b+204>>2]=w<<1;c[b+208>>2]=x<<1;c[b+212>>2]=F;Y=Qb(F,48)|0;Z=b+196|0;c[Z>>2]=Y;$=Qb(F,1)|0;aa=b+200|0;c[aa>>2]=$;ba=Ob(v<<2)|0;c[b+216>>2]=ba;if(!((R|0)==0|(T|0)==0|(U|0)==0|(W|0)==0|(Y|0)==0)?!(($|0)==0|(ba|0)==0):0){ba=o;$=W;W=U;U=0;Y=0;T=0;while(1){R=c[b+72+(T<<5)>>2]|0;ca=R<<2;da=0;ea=0;fa=Y;while(1){ga=ba-ea|0;if((ga|0)<=4)if((ga|0)<1)break;else ha=ga;else ha=4;ga=da;ia=0;while(1){ja=R-ia|0;if((ja|0)<=4)if((ja|0)<1){ka=ga;break}else la=ja;else la=4;ja=ga+U|0;n=W+(ja<<6)|0;j=n+64|0;do{c[n>>2]=-1;n=n+4|0}while((n|0)<(j|0));ma=0;na=ia+fa|0;while(1){oa=0;do{c[W+(ja<<6)+(c[1352+(ma<<5)+(oa<<3)>>2]<<4)+(c[1352+(ma<<5)+(oa<<3)+4>>2]<<2)>>2]=oa+na;oa=oa+1|0}while((oa|0)!=(la|0));ma=ma+1|0;if((ma|0)==(ha|0))break;else na=na+R|0}na=$+ja|0;ma=a[na>>0]|0;oa=ma&-61;pa=(((ma&255)>>>2&255|(c[W+(ja<<6)>>2]|0)>>>31^1)&255)<<2&60|oa;a[na>>0]=pa;ma=(((pa&255)>>>2&255|(c[W+(ja<<6)+16>>2]|0)>>>31<<1^2)&255)<<2&60|oa;a[na>>0]=ma;pa=(((ma&255)>>>2&255|(c[W+(ja<<6)+32>>2]|0)>>>31<<2^4)&255)<<2&60|oa;a[na>>0]=pa;a[na>>0]=(((pa&255)>>>2&255|(c[W+(ja<<6)+56>>2]|0)>>>31<<3^8)&255)<<2&60|oa;ga=ga+1|0;ia=ia+4|0}da=ka;ea=ea+4|0;fa=fa+ca|0}ca=T+1|0;if((ca|0)==3)break;ba=c[b+72+(ca<<5)+4>>2]|0;$=c[X>>2]|0;W=c[V>>2]|0;U=c[b+72+(ca<<5)+24>>2]|0;Y=c[b+72+(ca<<5)+8>>2]|0;T=ca}T=c[Z>>2]|0;Y=c[aa>>2]|0;U=c[1480+(c[p>>2]<<2)>>2]|0;V=c[H>>2]|0;if((V|0)>0){W=c[G>>2]|0;X=V;V=0;$=0;while(1){if((W|0)>0){ba=V;ca=0;while(1){fa=ba<<2;ea=ca|1;da=ca|2;R=ca|3;ia=0;do{ga=ia<<1|$;oa=ga|1;pa=d[136+(ia<<1)>>0]|fa;na=T+(pa*48|0)|0;n=na;j=n+48|0;do{c[n>>2]=-1;n=n+4|0}while((n|0)<(j|0));ja=c[G>>2]|0;do if((ca|0)<(ja|0)){if((ga|0)>=(c[H>>2]|0)){qa=36;break}c[na>>2]=(_(ja,ga)|0)+ca;c[T+(pa*48|0)+4>>2]=(_(c[G>>2]|0,ga)|0)+ea;c[T+(pa*48|0)+8>>2]=(_(c[G>>2]|0,oa)|0)+ca;c[T+(pa*48|0)+12>>2]=(_(c[G>>2]|0,oa)|0)+ea;za[U&7](na,G,ca,ga)}else qa=36;while(0);if((qa|0)==36){qa=0;a[Y+pa>>0]=-1}na=d[136+(ia<<1)+1>>0]|fa;ja=T+(na*48|0)|0;n=ja;j=n+48|0;do{c[n>>2]=-1;n=n+4|0}while((n|0)<(j|0));pa=c[G>>2]|0;do if((da|0)<(pa|0)){if((ga|0)>=(c[H>>2]|0)){qa=43;break}c[ja>>2]=(_(pa,ga)|0)+da;c[T+(na*48|0)+4>>2]=(_(c[G>>2]|0,ga)|0)+R;c[T+(na*48|0)+8>>2]=(_(c[G>>2]|0,oa)|0)+da;c[T+(na*48|0)+12>>2]=(_(c[G>>2]|0,oa)|0)+R;za[U&7](ja,G,da,ga)}else qa=43;while(0);if((qa|0)==43){qa=0;a[Y+na>>0]=-1}ia=ia+1|0}while((ia|0)!=2);ca=ca+4|0;ia=ba+1|0;da=c[G>>2]|0;if((ca|0)>=(da|0)){ra=ia;sa=da;break}else ba=ia}ta=c[H>>2]|0;ua=sa;va=ra}else{ta=X;ua=W;va=V}$=$+4|0;if(($|0)>=(ta|0))break;else{W=ua;X=ta;V=va}}}V=b+588|0;c[V>>2]=0;X=c[S>>2]|0;W=b+20|0;$=b+12|0;H=b+16|0;G=X;Y=0;U=X;while(1){X=c[W>>2]|0;T=(c[$>>2]|0)+X|0;aa=c[k>>2]|0;Z=(c[H>>2]|0)+aa|0;do if((Y|0)>0){ba=c[p>>2]|0;if(!(ba&1)){wa=X>>1;xa=T+1>>1}else{wa=X;xa=T}if(ba&2){ya=wa;Aa=xa;Ba=aa;Ca=Z;break}ya=wa;Aa=xa;Ba=aa>>1;Ca=Z+1>>1}else{ya=X;Aa=T;Ba=aa;Ca=Z}while(0);U=U+(c[b+72+(Y<<5)+12>>2]<<2)|0;if(G>>>0<U>>>0){Z=b+72+(Y<<5)|0;aa=(ya|0)<(Aa|0);T=(Ba|0)<(Ca|0);X=G;ba=0;while(1){ca=c[Z>>2]|0;ia=X+(ca<<2)|0;if((ca|0)>0){ca=ba+8|0;da=(ca|0)>(Ba|0);R=(Ca|0)>(ba|0);fa=(ba|0)<(Ba|0)&da;ea=R&(Ca|0)<(ca|0);ga=X+4|0;ja=(ia>>>0>ga>>>0?ia:ga)+~X|0;ga=T&(aa&(R&da))^1;da=X;R=0;do{oa=R;R=R+8|0;do if((Aa|0)<=(oa|0)|(R|0)<=(ya|0)|ga)c[da>>2]=c[da>>2]|2;else{pa=(oa|0)<(ya|0);if(!(ea|(fa|(pa|(Aa|0)<(R|0))))){c[da>>2]=c[da>>2]|63488;break}ma=oa|1;Da=oa|2;Ea=oa|3;Fa=oa|4;Ga=oa|5;Ha=oa|6;Ia=oa|7;Ja=(ma|0)>=(Aa|0)|(ma|0)<(ya|0);ma=(Da|0)>=(Aa|0)|(Da|0)<(ya|0);Da=(Ea|0)>=(Aa|0)|(Ea|0)<(ya|0);Ea=(Fa|0)>=(Aa|0)|(Fa|0)<(ya|0);Fa=(Ga|0)>=(Aa|0)|(Ga|0)<(ya|0);Ga=(Ha|0)>=(Aa|0)|(Ha|0)<(ya|0);Ha=(Ia|0)>=(Aa|0)|(Ia|0)<(ya|0);Ia=0;Ka=0;La=0;Ma=0;while(1){Na=La+ba|0;Oa=La<<3;Pa=(Na|0)>=(Ca|0)|(Na|0)<(Ba|0);if(pa|Pa){Qa=Ia;Ra=Ka;Sa=Ma}else{Na=Vb(1,0,Oa|0)|0;Qa=Na|Ia;Ra=C|Ka;Sa=Ma+1|0}if(Ja|Pa){Ta=Qa;Ua=Ra;Va=Sa}else{Na=Vb(1,0,Oa|1|0)|0;Ta=Qa|Na;Ua=Ra|C;Va=Sa+1|0}if(ma|Pa){Wa=Ta;Xa=Ua;Ya=Va}else{Na=Vb(1,0,Oa|2|0)|0;Wa=Ta|Na;Xa=Ua|C;Ya=Va+1|0}if(Da|Pa){Za=Wa;_a=Xa;$a=Ya}else{Na=Vb(1,0,Oa|3|0)|0;Za=Wa|Na;_a=Xa|C;$a=Ya+1|0}if(Ea|Pa){ab=Za;bb=_a;cb=$a}else{Na=Vb(1,0,Oa|4|0)|0;ab=Za|Na;bb=_a|C;cb=$a+1|0}if(Fa|Pa){db=ab;eb=bb;fb=cb}else{Na=Vb(1,0,Oa|5|0)|0;db=ab|Na;eb=bb|C;fb=cb+1|0}if(Ga|Pa){gb=db;hb=eb;lb=fb}else{Na=Vb(1,0,Oa|6|0)|0;gb=db|Na;hb=eb|C;lb=fb+1|0}if(Ha|Pa){mb=gb;nb=hb;ob=lb}else{Pa=Vb(1,0,Oa|7|0)|0;mb=gb|Pa;nb=hb|C;ob=lb+1|0}La=La+1|0;if((La|0)==8){pb=mb;qb=nb;rb=ob;break}else{Ia=mb;Ka=nb;Ma=ob}}Ma=c[V>>2]|0;a:do if((Ma|0)>0){Ka=0;while(1){Ia=b+592+(Ka<<4)|0;if((c[Ia>>2]|0)==(pb|0)?(c[Ia+4>>2]|0)==(qb|0):0){sb=Ka;break a}Ia=Ka+1|0;if((Ia|0)<(Ma|0))Ka=Ia;else{tb=Ia;qa=65;break}}}else{tb=0;qa=65}while(0);if((qa|0)==65){qa=0;c[V>>2]=Ma+1;Ka=b+592+(tb<<4)|0;c[Ka>>2]=pb;c[Ka+4>>2]=qb;c[b+592+(tb<<4)+8>>2]=rb;sb=tb}c[da>>2]=c[da>>2]&-63489|sb<<11&63488}while(0);da=da+4|0}while(da>>>0<ia>>>0);ub=ca;vb=X+((ja>>>2)+1<<2)|0}else{ub=ba+8|0;vb=X}if(vb>>>0<U>>>0){X=vb;ba=ub}else{wb=vb;break}}}else wb=G;Y=Y+1|0;if((Y|0)==3)break;else G=wb}if((f+-3|0)>>>0<=3){G=c[p>>2]|0;Y=G&1^1;U=G>>>1&1^1;G=c[h>>2]|0;V=G+32|0;H=(c[i>>2]|0)+32|0;$=(V>>Y)+15&-16;W=_(H,V)|0;S=_($,H>>U)|0;ba=(V<<4)+16|0;X=(_($,16>>>U)|0)+(16>>>Y)|0;aa=0-X&15;T=S<<1;Z=W+16+T|0;ia=_(Z,f)|0;if(!(Z>>>0<W>>>0|((T|16)>>>0<S>>>0?1:((W>>>0)/(V>>>0)|0|0)!=(H|0)))?((ia>>>0)/(f>>>0)|0|0)==(Z|0):0){Z=ib(ia,16)|0;ia=Ob(c[Q>>2]<<2)|0;c[b+172>>2]=ia;if((Z|0)==0|(ia|0)==0){Pb(ia);jb(Z);xb=-1;break}H=c[h>>2]|0;T=b+236|0;c[T>>2]=H;da=c[i>>2]|0;c[b+240>>2]=da;R=b+244|0;c[R>>2]=V;V=H>>>Y;c[b+268>>2]=V;c[b+252>>2]=V;V=da>>>U;c[b+272>>2]=V;c[b+256>>2]=V;V=b+276|0;c[V>>2]=$;U=b+260|0;c[U>>2]=$;if((f|0)>1){da=1;do{n=b+236+(da*48|0)|0;l=T;j=n+48|0;do{c[n>>2]=c[l>>2];n=n+4|0;l=l+4|0}while((n|0)<(j|0));da=da+1|0}while((da|0)!=(f|0))}c[b+572>>2]=Z;if((f|0)>0){da=aa+W|0;T=da+X|0;Q=da+S|0;da=Q+X|0;Y=S+16-aa+Q|0;Q=Z;H=0;while(1){fa=b+236+(H*48|0)|0;c[b+236+(H*48|0)+12>>2]=Q+ba;c[b+236+(H*48|0)+28>>2]=Q+T;c[b+236+(H*48|0)+44>>2]=Q+da;kb(fa,fa);H=H+1|0;if((H|0)==(f|0))break;else Q=Q+Y|0}}c[b+576>>2]=-32-G;Y=0-$|0;c[b+584>>2]=Y;c[b+580>>2]=Y;Y=c[b+248>>2]|0;Q=Y;H=(c[J>>2]|0)+(c[I>>2]|0)|0;da=c[b+72>>2]|0;if((H|0)>0){T=c[R>>2]<<3;ba=(da|0)>0;Z=0;aa=Y;while(1){Y=Z+da|0;if(ba){S=Z+1|0;X=Z;W=aa;while(1){c[ia+(X<<2)>>2]=W-Q;X=X+1|0;if((X|0)>=(Y|0))break;else W=W+8|0}yb=(Y|0)>(S|0)?Y:S}else yb=Z;if((yb|0)<(H|0)){Z=yb;aa=aa+T|0}else{zb=yb;break}}}else zb=0;T=(c[P>>2]|0)+(c[M>>2]|0)|0;aa=c[L>>2]|0;if((zb|0)<(T|0)){Z=c[U>>2]<<3;H=(aa|0)>0;ba=zb;da=c[b+264>>2]|0;while(1){R=ba+aa|0;if(H){I=ba+1|0;J=ba;$=da;while(1){c[ia+(J<<2)>>2]=$-Q;J=J+1|0;if((J|0)>=(R|0))break;else $=$+8|0}Ab=(R|0)>(I|0)?R:I}else Ab=ba;if((Ab|0)<(T|0)){ba=Ab;da=da+Z|0}else{Bb=Ab;break}}}else Bb=zb;Z=(c[O>>2]|0)+(c[N>>2]|0)|0;da=c[K>>2]|0;if((Bb|0)<(Z|0)){ba=c[V>>2]<<3;T=(da|0)>0;H=Bb;aa=c[b+280>>2]|0;while(1){U=H+da|0;if(T){L=H+1|0;M=H;P=aa;while(1){c[ia+(M<<2)>>2]=P-Q;M=M+1|0;if((M|0)>=(U|0))break;else P=P+8|0}Cb=(U|0)>(L|0)?U:L}else Cb=H;if((Cb|0)<(Z|0)){H=Cb;aa=aa+ba|0}else break}}ba=b+524|0;c[ba>>2]=-1;c[ba+4>>2]=-1;c[ba+8>>2]=-1;c[ba+12>>2]=-1;c[ba+16>>2]=-1;c[ba+20>>2]=-1;ba=b+548|0;c[ba>>2]=0;c[ba+4>>2]=0;c[ba+8>>2]=0;c[ba+12>>2]=0;c[ba+16>>2]=0;c[ba+20>>2]=0;if((c[e+60>>2]|0)>>>0>31)c[b+60>>2]=31;ba=b+848|0;c[ba>>2]=0;c[ba+4>>2]=0;ba=b+856|0;c[ba>>2]=-1;c[ba+4>>2]=-1;ba=a[e>>0]|0;do if((ba&255)>3)Db=1;else{if(ba<<24>>24!=3){Db=0;break}aa=a[e+1>>0]|0;if((aa&255)>2){Db=1;break}if(aa<<24>>24!=2){Db=0;break}Db=(a[e+2>>0]|0)!=0&1}while(0);a[b+873>>0]=Db;g=0;return g|0}else xb=-23}else xb=-10}else xb=-1}else xb=-23;while(0);Pb(c[b+216>>2]|0);Pb(c[b+200>>2]|0);Pb(c[b+196>>2]|0);Pb(c[b+188>>2]|0);Pb(c[b+184>>2]|0);Pb(c[b+176>>2]|0);Pb(c[b+168>>2]|0);g=xb;return g|0}function nb(a){a=a|0;Pb(c[a+172>>2]|0);jb(c[a+572>>2]|0);Pb(c[a+216>>2]|0);Pb(c[a+200>>2]|0);Pb(c[a+196>>2]|0);Pb(c[a+188>>2]|0);Pb(c[a+184>>2]|0);Pb(c[a+176>>2]|0);Pb(c[a+168>>2]|0);return}function ob(b,d,e,f,g){b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,i=0,j=0,k=0,l=0,m=0;if(!e)h=0;else h=(c[b+48>>2]&1|0)==0;i=16>>>(h&1);h=c[b+236+(d*48|0)+(e<<4)+8>>2]|0;j=c[b+236+(d*48|0)+(e<<4)+12>>2]|0;k=_(h,f)|0;f=_(h,g)|0;g=j+f|0;if((k|0)==(f|0))return;f=0-i|0;l=j+k|0;m=j+(k+-1+(c[b+236+(d*48|0)+(e<<4)>>2]|0))|0;while(1){Ub(l+f|0,a[l>>0]|0,i|0)|0;Ub(m+1|0,a[m>>0]|0,i|0)|0;l=l+h|0;if((l|0)==(g|0))break;else m=m+h|0}return}function pb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;if(!d){e=16;f=0}else{g=c[a+48>>2]|0;e=16>>>(g&1^1);f=(g&2|0)==0}g=c[a+236+(b*48|0)+(d<<4)+8>>2]|0;h=(c[a+236+(b*48|0)+(d<<4)>>2]|0)+(e<<1)|0;i=c[a+236+(b*48|0)+(d<<4)+12>>2]|0;j=0-e|0;k=0-(e+(_(16>>>(f&1),g)|0))|0;f=i+k|0;if((j|0)==(k|0))return;k=0-g|0;l=i+j|0;j=i+((_((c[a+236+(b*48|0)+(d<<4)+4>>2]|0)+-1|0,g)|0)-e)|0;do{e=l;l=l+k|0;Xb(l|0,e|0,h|0)|0;e=j;j=j+g|0;Xb(j|0,e|0,h|0)|0}while((l|0)!=(f|0));return}function qb(d,e,f,g,h,i){d=d|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;var j=0,k=0,l=0,m=0,n=0,o=0;j=_(b[g>>1]|0,i&65535)|0;if((h|0)<2){i=(j+15|0)>>>5&65535;k=0;do{b[g+(k+64<<1)>>1]=i;k=k+1|0}while((k|0)!=64)}else{b[g>>1]=j;cb(g+128|0,g,h)}h=c[(c[d+172>>2]|0)+(e<<2)>>2]|0;j=(c[(c[d+168>>2]|0)+(e<<2)>>2]|0)>>>6&3;k=c[d+576+(f<<2)>>2]|0;i=(c[d+556>>2]|0)+h|0;if((j|0)==2){Wa(i,k,g+128|0);return}l=c[d+548+(j<<2)>>2]|0;j=b[(c[d+176>>2]|0)+(e<<1)>>1]|0;e=(f|0)!=0;if(e)m=(c[d+48>>2]&2|0)==0;else m=0;f=m&1;m=(j<<16>>16>>8)+31|0;n=a[1624+(f<<6)+m>>0]|0;if(e)o=(c[d+48>>2]&1|0)==0;else o=0;d=o&1;o=((j&65535)<<24>>24)+31|0;j=a[1624+(d<<6)+o>>0]|0;e=(a[1496+(d<<6)+o>>0]|0)+(_(a[1496+(f<<6)+m>>0]|0,k)|0)|0;if(!((j|n)<<24>>24)){Xa(i,l+(e+h)|0,k,g+128|0);return}else{Ya(i,l+(e+h)|0,l+((_(n<<24>>24,k)|0)+h+e+(j<<24>>24))|0,k,g+128|0);return}}function rb(b,c){b=b|0;c=c|0;var d=0,e=0,f=0;Ub(b|0,0,256)|0;if((c|0)>0)d=0;else return;do{e=127-d|0;f=e-c|0;if((f|0)>-1)a[b+f>>0]=d-c;a[b+e>>0]=0-d;e=d+127|0;a[b+e>>0]=d;f=e+c|0;if((f|0)<256)a[b+f>>0]=c-d;d=d+1|0}while((d|0)!=(c|0));return}function sb(b,e,f,g,h,i){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;i=i|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0;j=c[b+72+(g<<5)>>2]|0;k=c[b+72+(g<<5)+8>>2]|0;l=(c[b+72+(g<<5)+12>>2]|0)+k|0;m=k+(_(j,h)|0)|0;h=k+(_(j,i)|0)|0;i=c[b+576+(g<<2)>>2]|0;g=c[b+168>>2]|0;n=c[b+172>>2]|0;o=c[b+548+(f<<2)>>2]|0;if((m|0)>=(h|0))return;f=i<<1;b=i<<3;p=(j|0)>0;q=m;do{m=q;q=q+j|0;if(p){r=(m|0)>(k|0);s=m;while(1){if(c[g+(s<<2)>>2]&1){t=c[n+(s<<2)>>2]|0;if((s|0)>(m|0)){u=o+(t+-2)|0;v=0;while(1){w=u+2|0;x=d[w>>0]|0;y=u+1|0;z=d[y>>0]|0;A=a[e+(((d[u>>0]|0)+4-(d[u+3>>0]|0)+((x-z|0)*3|0)>>3)+127)>>0]|0;B=A+z|0;a[y>>0]=(B>>>31)+255&((B|0)>255?255:B);B=x-A|0;a[w>>0]=(B>>>31)+255&((B|0)>255?255:B);v=v+1|0;if((v|0)==8)break;else u=u+i|0}}if(r){u=t-f|0;v=t+i|0;B=t-i|0;w=0;do{A=o+(w+t)|0;x=o+(B+w)|0;y=d[x>>0]|0;z=a[e+(((d[o+(u+w)>>0]|0)+4-(d[o+(v+w)>>0]|0)+(((d[A>>0]|0)-y|0)*3|0)>>3)+127)>>0]|0;C=z+y|0;a[x>>0]=(C>>>31)+255&((C|0)>255?255:C);C=(d[A>>0]|0)-z|0;a[A>>0]=(C>>>31)+255&((C|0)>255?255:C);w=w+1|0}while((w|0)!=8)}w=s+1|0;if((w|0)<(q|0)?(c[g+(w<<2)>>2]&1|0)==0:0){v=o+(t+6)|0;u=0;while(1){B=v+2|0;C=d[B>>0]|0;A=v+1|0;z=d[A>>0]|0;x=a[e+(((d[v>>0]|0)+4-(d[v+3>>0]|0)+((C-z|0)*3|0)>>3)+127)>>0]|0;y=x+z|0;a[A>>0]=(y>>>31)+255&((y|0)>255?255:y);y=C-x|0;a[B>>0]=(y>>>31)+255&((y|0)>255?255:y);u=u+1|0;if((u|0)==8)break;else v=v+i|0}}v=s+j|0;if((v|0)<(l|0)?(c[g+(v<<2)>>2]&1|0)==0:0){v=t+b|0;u=v-f|0;y=v+i|0;B=v-i|0;x=0;do{C=o+(x+v)|0;A=o+(B+x)|0;z=d[A>>0]|0;D=a[e+(((d[o+(u+x)>>0]|0)+4-(d[o+(y+x)>>0]|0)+(((d[C>>0]|0)-z|0)*3|0)>>3)+127)>>0]|0;E=D+z|0;a[A>>0]=(E>>>31)+255&((E|0)>255?255:E);E=(d[C>>0]|0)-D|0;a[C>>0]=(E>>>31)+255&((E|0)>255?255:E);x=x+1|0}while((x|0)!=8);F=w}else F=w}else F=s+1|0;if((F|0)<(q|0))s=F;else break}}}while((q|0)<(h|0));return}function tb(b,e,f,g,h,j,k,l){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;k=k|0;l=l|0;var m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0;m=i;i=i+48|0;n=m;o=n+20|0;p=n+16|0;q=n+4|0;r=n+8|0;s=n+12|0;t=e<<1;u=n+24|0;v=n+28|0;w=n+32|0;x=n+36|0;y=g<<1;z=g*3|0;A=g<<2;B=g*5|0;C=g*6|0;D=g*7|0;E=g<<3;F=g*9|0;G=e*3|0;H=e<<2;I=e*5|0;J=e<<1;K=e*3|0;L=e<<2;M=e*5|0;N=e*6|0;O=e*7|0;P=0;Q=b+(e*6|0)|0;R=b+(e*5|0)|0;S=b;b=f;while(1){f=d[b>>0]|0;c[n>>2]=f;T=a[b+g>>0]|0;U=T&255;c[q>>2]=U;V=d[b+y>>0]|0;c[r>>2]=V;W=d[b+z>>0]|0;c[s>>2]=W;X=d[b+A>>0]|0;c[p>>2]=X;Y=d[b+B>>0]|0;c[o>>2]=Y;Z=d[b+C>>0]|0;c[u>>2]=Z;_=d[b+D>>0]|0;c[v>>2]=_;$=d[b+E>>0]|0;c[w>>2]=$;aa=d[b+F>>0]|0;c[x>>2]=aa;ba=U-f|0;ca=Y-Z|0;da=V-U|0;ea=Z-_|0;Z=W-V|0;fa=_-$|0;_=X-W|0;ga=((_|0)>-1?_:0-_|0)+(((Z|0)>-1?Z:0-Z|0)+(((da|0)>-1?da:0-da|0)+((ba|0)>-1?ba:0-ba|0)))|0;ba=$-aa|0;aa=((ba|0)>-1?ba:0-ba|0)+(((fa|0)>-1?fa:0-fa|0)+(((ea|0)>-1?ea:0-ea|0)+((ca|0)>-1?ca:0-ca|0)))|0;c[k>>2]=(c[k>>2]|0)+((ga|0)<255?ga:255);c[l>>2]=(c[l>>2]|0)+((aa|0)<255?aa:255);if((ga|0)<(j|0)&(aa|0)<(j|0)?(Y-X|0)<(h|0)&(X-Y|0)<(h|0):0){a[S>>0]=(X+4+(f*3|0)+(U<<1)+V+W|0)>>>3;a[S+e>>0]=((c[q>>2]|0)+4+(c[s>>2]|0)+(c[p>>2]|0)+(c[o>>2]|0)+((c[r>>2]|0)+(c[n>>2]|0)<<1)|0)>>>3;a[S+t>>0]=((c[n>>2]|0)+4+(c[q>>2]|0)+(c[r>>2]|0)+(c[s>>2]<<1)+(c[p>>2]|0)+(c[o>>2]|0)+(c[u>>2]|0)|0)>>>3;a[S+G>>0]=((c[q>>2]|0)+4+(c[r>>2]|0)+(c[s>>2]|0)+(c[p>>2]<<1)+(c[o>>2]|0)+(c[u>>2]|0)+(c[v>>2]|0)|0)>>>3;a[S+H>>0]=((c[r>>2]|0)+4+(c[s>>2]|0)+(c[p>>2]|0)+(c[o>>2]<<1)+(c[u>>2]|0)+(c[v>>2]|0)+(c[w>>2]|0)|0)>>>3;a[S+I>>0]=((c[s>>2]|0)+4+(c[p>>2]|0)+(c[o>>2]|0)+(c[u>>2]<<1)+(c[v>>2]|0)+(c[w>>2]|0)+(c[x>>2]|0)|0)>>>3;a[Q>>0]=((c[p>>2]|0)+4+(c[o>>2]|0)+(c[u>>2]|0)+(c[w>>2]|0)+((c[x>>2]|0)+(c[v>>2]|0)<<1)|0)>>>3;a[R+t>>0]=((c[o>>2]|0)+4+(c[u>>2]|0)+(c[v>>2]|0)+(c[w>>2]<<1)+((c[x>>2]|0)*3|0)|0)>>>3}else{a[S>>0]=T;a[S+e>>0]=c[r>>2];a[S+J>>0]=c[s>>2];a[S+K>>0]=c[p>>2];a[S+L>>0]=c[o>>2];a[S+M>>0]=c[u>>2];a[S+N>>0]=c[v>>2];a[S+O>>0]=c[w>>2]}P=P+1|0;if((P|0)==8)break;else{Q=Q+1|0;R=R+1|0;S=S+1|0;b=b+1|0}}i=m;return}function ub(b,e,f,g,h){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0;j=i;i=i+48|0;k=j;l=h+4|0;m=k+20|0;n=k+16|0;o=k+4|0;p=k+8|0;q=k+12|0;r=k+24|0;s=k+28|0;t=k+32|0;u=k+36|0;v=0;w=b;x=b+6|0;y=b+5|0;while(1){b=d[w+-1>>0]|0;c[k>>2]=b;z=d[w>>0]|0;c[o>>2]=z;A=d[w+1>>0]|0;c[p>>2]=A;B=d[w+2>>0]|0;c[q>>2]=B;C=d[w+3>>0]|0;c[n>>2]=C;D=d[w+4>>0]|0;c[m>>2]=D;E=d[w+5>>0]|0;c[r>>2]=E;F=d[w+6>>0]|0;c[s>>2]=F;G=d[w+7>>0]|0;c[t>>2]=G;H=d[w+8>>0]|0;c[u>>2]=H;I=z-b|0;J=D-E|0;K=A-z|0;L=E-F|0;E=B-A|0;M=F-G|0;F=C-B|0;N=((F|0)>-1?F:0-F|0)+(((E|0)>-1?E:0-E|0)+(((K|0)>-1?K:0-K|0)+((I|0)>-1?I:0-I|0)))|0;I=G-H|0;H=((I|0)>-1?I:0-I|0)+(((M|0)>-1?M:0-M|0)+(((L|0)>-1?L:0-L|0)+((J|0)>-1?J:0-J|0)))|0;c[h>>2]=(c[h>>2]|0)+((N|0)<255?N:255);c[l>>2]=(c[l>>2]|0)+((H|0)<255?H:255);if((N|0)<(g|0)&(H|0)<(g|0)?(D-C|0)<(f|0)&(C-D|0)<(f|0):0){a[w>>0]=(C+4+(b*3|0)+(z<<1)+A+B|0)>>>3;a[w+1>>0]=((c[o>>2]|0)+4+(c[q>>2]|0)+(c[n>>2]|0)+(c[m>>2]|0)+((c[p>>2]|0)+(c[k>>2]|0)<<1)|0)>>>3;a[w+2>>0]=((c[k>>2]|0)+4+(c[o>>2]|0)+(c[p>>2]|0)+(c[q>>2]<<1)+(c[n>>2]|0)+(c[m>>2]|0)+(c[r>>2]|0)|0)>>>3;a[w+3>>0]=((c[o>>2]|0)+4+(c[p>>2]|0)+(c[q>>2]|0)+(c[n>>2]<<1)+(c[m>>2]|0)+(c[r>>2]|0)+(c[s>>2]|0)|0)>>>3;a[w+4>>0]=((c[p>>2]|0)+4+(c[q>>2]|0)+(c[n>>2]|0)+(c[m>>2]<<1)+(c[r>>2]|0)+(c[s>>2]|0)+(c[t>>2]|0)|0)>>>3;a[w+5>>0]=((c[q>>2]|0)+4+(c[n>>2]|0)+(c[m>>2]|0)+(c[r>>2]<<1)+(c[s>>2]|0)+(c[t>>2]|0)+(c[u>>2]|0)|0)>>>3;a[x>>0]=((c[n>>2]|0)+4+(c[m>>2]|0)+(c[r>>2]|0)+(c[t>>2]|0)+((c[u>>2]|0)+(c[s>>2]|0)<<1)|0)>>>3;a[y+2>>0]=((c[m>>2]|0)+4+(c[r>>2]|0)+(c[s>>2]|0)+(c[t>>2]<<1)+((c[u>>2]|0)*3|0)|0)>>>3}v=v+1|0;if((v|0)==8)break;else{w=w+e|0;x=x+e|0;y=y+e|0}}i=j;return}function vb(b,e,f,g,h,j){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0;k=i;i=i+576|0;l=k+288|0;m=k;n=g*3|0;o=d[1752+j>>0]|0;p=(o|0)<(n|0)?o:n;n=b+(0-(0-(f>>>2&1^1)&e))|0;o=g+32|0;g=d[1760+j>>0]|0;j=f>>>3&1^1;q=0;r=n;s=b;while(1){t=q<<3;u=0;do{v=(d[s+u>>0]|0)-(d[r+u>>0]|0)|0;w=o-(((v|0)>-1?v:0-v|0)<<g)|0;if((w|0)<-64)x=h;else{v=(p|0)<(w|0)?p:w;x=(v|0)>0?v:0}c[l+(u+t<<2)>>2]=x;u=u+1|0}while((u|0)!=8);u=s+(0-((q|0)<7|j)&e)|0;q=q+1|0;if((q|0)==9)break;else{t=s;s=u;r=t}}r=0-(f&1^1)|0;s=f>>>1&1;f=s^1;q=0;x=b;t=b+r|0;while(1){u=q<<3;v=0;w=t;y=x;while(1){z=(d[y>>0]|0)-(d[w>>0]|0)|0;A=o-(((z|0)>-1?z:0-z|0)<<g)|0;if((A|0)<-64)B=h;else{z=(p|0)<(A|0)?p:A;B=(z|0)>0?z:0}c[m+(v+u<<2)>>2]=B;v=v+1|0;if((v|0)==8)break;else{w=w+e|0;y=y+e|0}}y=x+((q|0)<7|f)|0;q=q+1|0;if((q|0)==9)break;else{w=x;x=y;t=w}}t=8-s|0;s=0;x=b;q=b+e|0;f=n;n=b;while(1){b=c[m+(s<<2)>>2]|0;B=(_(d[n+r>>0]|0,b)|0)+64|0;p=s<<3;h=c[l+(p<<2)>>2]|0;g=B+(_(d[f>>0]|0,h)|0)|0;B=s;s=s+1|0;o=s<<3;w=c[l+(o<<2)>>2]|0;y=g+(_(d[q>>0]|0,w)|0)|0;g=c[m+(B+8<<2)>>2]|0;v=y+(_(d[n+1>>0]|0,g)|0)|0;y=v+(_(d[n>>0]|0,128-b-h-w-g|0)|0)>>7;a[x>>0]=(y>>>31)+255&((y|0)>255?255:y);y=1;do{g=c[m+((y<<3)+B<<2)>>2]|0;w=(_(d[n+(y+-1)>>0]|0,g)|0)+64|0;h=c[l+(y+p<<2)>>2]|0;b=w+(_(d[f+y>>0]|0,h)|0)|0;w=c[l+(y+o<<2)>>2]|0;v=b+(_(d[q+y>>0]|0,w)|0)|0;b=y;y=y+1|0;u=c[m+((y<<3)+B<<2)>>2]|0;z=v+(_(d[n+y>>0]|0,u)|0)|0;v=z+(_(d[n+b>>0]|0,128-g-h-w-u|0)|0)>>7;a[x+b>>0]=(v>>>31)+255&((v|0)>255?255:v)}while((y|0)!=7);y=c[m+(B+56<<2)>>2]|0;v=(_(d[n+6>>0]|0,y)|0)+64|0;b=c[l+((p|7)<<2)>>2]|0;u=v+(_(d[f+7>>0]|0,b)|0)|0;v=c[l+((o|7)<<2)>>2]|0;w=u+(_(d[q+7>>0]|0,v)|0)|0;u=c[m+(B+64<<2)>>2]|0;h=w+(_(d[n+t>>0]|0,u)|0)|0;w=h+(_(d[n+7>>0]|0,128-y-b-v-u|0)|0)>>7;a[x+7>>0]=(w>>>31)+255&((w|0)>255?255:w);w=q+(0-((B|0)<6|j)&e)|0;if((s|0)==8)break;else{u=q;v=n;x=x+e|0;q=w;n=u;f=v}}i=k;return}function wb(c,e,f){c=c|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,$=0;g=i;i=i+144|0;h=g;j=g+102|0;k=g+68|0;a[j>>0]=0;l=f+255&255;a[k>>0]=l;f=(c|0)!=0;m=l;l=0;n=0;o=0;p=0;while(1){q=1-p+(m&255)|0;r=l&255;s=l<<24>>24!=0?2:7;a:do if((q|0)>0){t=0;u=1;v=1;w=2;while(1){x=(u|0)==0;y=v+1|0;z=y+r|0;A=0;B=0;C=0;while(1){D=C+p|0;E=e+(D<<1)|0;F=d[e+(D<<1)+1>>0]|0;do if((F|0)>=(z|0))if((F|0)==(z|0)){G=1;H=C+1|0;break}else{G=A;H=(Hb(E,z)|0)+C|0;break}else{G=A;H=C+1|0}while(0);E=B+1|0;if((H|0)<(q|0)){A=G;B=E;C=H}else{I=E;J=G;K=B;break}}B=x?t:v;if((K|0)<(w|0)){L=B;break a}if((_(I,s)|0)<(1<<y|0)){L=B;break}else{t=B;u=J;v=y;w=I}}}else L=1;while(0);s=o&65535;q=h+(n<<1)|0;b[q>>1]=s;r=o+1+(1<<L)|0;if(f){b[q>>1]=s+1<<16>>16;b[c+(o<<16>>16<<1)>>1]=L;M=m;N=l;O=n;P=L;Q=p}else{M=m;N=l;O=n;P=L;Q=p}while(1){s=M&255;b:do if((Q|0)>(s|0))R=Q;else{q=N&255;w=q+P|0;v=h+(O<<1)|0;if(f)S=Q;else{u=Q;while(1){if((w|0)<(d[e+(u<<1)+1>>0]|0|0)){R=u;break b}t=u+1|0;if((u|0)<(s|0))u=t;else{R=t;break b}}}while(1){u=d[e+(S<<1)+1>>0]|0;if((w|0)<(u|0)){R=S;break b}y=w-u|0;x=0-(d[e+(S<<1)>>0]|0|u-q<<8)&65535;if((y|0)!=31){u=1<<y;y=b[v>>1]|0;t=u+1+((u|0)<1?u^65535:65534)&65535;B=y;C=u;while(1){b[c+(B<<16>>16<<1)>>1]=x;if((C|0)>1){B=B+1<<16>>16;C=C+-1|0}else break}b[v>>1]=(y+1<<16>>16)+t<<16>>16}C=S+1|0;if((S|0)<(s|0))S=C;else{R=C;break}}}while(0);if((R|0)<=(s|0)){T=N;U=O;V=P;W=R;X=25;break}v=O+-1|0;if((O|0)<=0){Y=v;Z=R;break}q=a[j+v>>0]|0;w=(N&255)-(q&255)|0;M=a[k+v>>0]|0;N=q;O=v;P=w;Q=R}if((X|0)==25){X=0;w=(T&255)+V|0;v=U+1|0;a[j+v>>0]=w;if(f){q=h+(U<<1)|0;C=b[q>>1]|0;b[q>>1]=C+1<<16>>16;b[c+(C<<16>>16<<1)>>1]=r}a[k+v>>0]=W+255+(Hb(e+(W<<1)|0,w&255)|0);Y=v;Z=W}if((Y|0)<=-1){$=r;break}m=a[k+Y>>0]|0;l=a[j+Y>>0]|0;n=Y;o=r;p=Z}i=g;return $|0}function xb(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0;d=b[a+(c<<1)>>1]|0;e=1<<d;f=c+1|0;c=0;g=e+1|0;while(1){h=b[a+(f+c<<1)>>1]|0;i=h<<16>>16;if(h<<16>>16<1){j=1<<d-(0-i>>8);k=g}else{j=1;k=(xb(a,i)|0)+g|0}c=j+c|0;if((c|0)>=(e|0)){l=k;break}else g=k}return l|0}function yb(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0;d=b[c>>1]|0;e=b[c+8>>1]|0;f=(e+d<<16>>16)*46341>>16;g=(d-e<<16>>16)*46341>>16;e=b[c+4>>1]|0;d=b[c+12>>1]|0;h=(e*25080>>16)-(d*60547>>16)|0;i=(d*25080>>16)+(e*60547>>16)|0;e=b[c+2>>1]|0;d=b[c+14>>1]|0;j=(e*12785>>16)-(d*64277>>16)|0;k=b[c+10>>1]|0;l=b[c+6>>1]|0;c=(k*54491>>16)-(l*36410>>16)|0;m=(l*54491>>16)+(k*36410>>16)|0;k=(d*12785>>16)+(e*64277>>16)|0;e=c+j|0;d=(j-c<<16>>16)*46341>>16;c=m+k|0;j=(k-m<<16>>16)*46341>>16;m=f+i|0;k=f-i|0;i=g+h|0;f=g-h|0;h=j+d|0;g=j-d|0;b[a>>1]=c+m;b[a+16>>1]=h+i;b[a+32>>1]=g+f;b[a+48>>1]=e+k;b[a+64>>1]=k-e;b[a+80>>1]=f-g;b[a+96>>1]=i-h;b[a+112>>1]=m-c;return}function zb(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0,h=0;d=b[c>>1]|0;e=b[c+2>>1]|0;f=b[c+4>>1]|0;g=b[c+6>>1]|0;c=((e&65535)<<24>>24)+((d&65535)<<24>>24)+((f&65535)<<24>>24)+((g&65535)<<24>>24)|0;h=(e<<16>>16>>8)+(d<<16>>16>>8)+(f<<16>>16>>8)+(g<<16>>16>>8)|0;b[a>>1]=(c+2+(c>>31)|0)>>>2&255|(h+2+(h>>31)|0)>>>2<<8;return}function Ab(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0;d=b[c>>1]|0;e=b[c+4>>1]|0;f=((e&65535)<<24>>24)+((d&65535)<<24>>24)|0;g=(e<<16>>16>>8)+(d<<16>>16>>8)|0;b[a>>1]=(f+1+(f>>31)|0)>>>1&255|(g+1+(g>>31)|0)>>>1<<8;g=b[c+2>>1]|0;f=b[c+6>>1]|0;c=((f&65535)<<24>>24)+((g&65535)<<24>>24)|0;d=(f<<16>>16>>8)+(g<<16>>16>>8)|0;b[a+2>>1]=(c+1+(c>>31)|0)>>>1&255|(d+1+(d>>31)|0)>>>1<<8;return}function Bb(a,c){a=a|0;c=c|0;var d=0,e=0,f=0,g=0;d=b[c>>1]|0;e=b[c+2>>1]|0;f=((e&65535)<<24>>24)+((d&65535)<<24>>24)|0;g=(e<<16>>16>>8)+(d<<16>>16>>8)|0;b[a>>1]=(f+1+(f>>31)|0)>>>1&255|(g+1+(g>>31)|0)>>>1<<8;g=b[c+4>>1]|0;f=b[c+6>>1]|0;c=((f&65535)<<24>>24)+((g&65535)<<24>>24)|0;d=(f<<16>>16>>8)+(g<<16>>16>>8)|0;b[a+4>>1]=(c+1+(c>>31)|0)>>>1&255|(d+1+(d>>31)|0)>>>1<<8;return}function Cb(a,c){a=a|0;c=c|0;b[a>>1]=b[c>>1]|0;b[a+2>>1]=b[c+2>>1]|0;b[a+4>>1]=b[c+4>>1]|0;b[a+6>>1]=b[c+6>>1]|0;return}function Db(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;f=(_(c[b+32>>2]|0,e>>1)|0)+(d>>1)|0;c[a+16>>2]=f+(c[b+40>>2]|0);c[a+32>>2]=f+(c[b+72>>2]|0);return}function Eb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0;f=(_(c[b+32>>2]|0,e>>1)|0)+d|0;d=b+40|0;e=b+72|0;c[a+16>>2]=(c[d>>2]|0)+f;c[a+32>>2]=(c[e>>2]|0)+f;b=f+1|0;c[a+20>>2]=(c[d>>2]|0)+b;c[a+36>>2]=(c[e>>2]|0)+b;return}function Fb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;f=b+32|0;g=(_(c[f>>2]|0,e)|0)+(d>>1)|0;d=b+40|0;e=b+72|0;c[a+16>>2]=(c[d>>2]|0)+g;c[a+32>>2]=(c[e>>2]|0)+g;b=(c[f>>2]|0)+g|0;c[a+24>>2]=(c[d>>2]|0)+b;c[a+40>>2]=(c[e>>2]|0)+b;return}function Gb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;e=b+40|0;d=b+72|0;b=c[a>>2]|0;c[a+16>>2]=(c[e>>2]|0)+b;c[a+32>>2]=(c[d>>2]|0)+b;b=c[a+4>>2]|0;c[a+20>>2]=(c[e>>2]|0)+b;c[a+36>>2]=(c[d>>2]|0)+b;b=c[a+8>>2]|0;c[a+24>>2]=(c[e>>2]|0)+b;c[a+40>>2]=(c[d>>2]|0)+b;b=c[a+12>>2]|0;c[a+28>>2]=(c[e>>2]|0)+b;c[a+44>>2]=(c[d>>2]|0)+b;return}function Hb(a,b){a=a|0;b=b|0;var c=0,e=0,f=0,g=0,h=0,i=0,j=0;c=b+31|0;e=0;f=0;while(1){g=(d[a+(f<<1)+1>>0]|0)-b|0;if((g|0)<32){h=-2147483648>>>g;i=f+1|0}else{h=1;i=(Hb(a+(f<<1)|0,c)|0)+f|0}e=h+e|0;if((e|0)<=-1){j=i;break}else f=i}return j|0}function Ib(){fb(1776);db(1792);return}function Jb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;d=i;i=i+48|0;e=d+32|0;f=d;Mb(f,a,b);g=c[442]|0;if(!g)c[f+8>>2]=256;c[442]=g+1;g=Na(1792,1776,1856,f)|0;if(!g){c[466]=Pa(1792,c[464]|0)|0;f=c[460]|0;h=c[451]|0;j=c[452]|0;k=c[457]|0;l=c[458]|0;if((k|0)!=0&(l|0)!=0)m=((_(k,h)|0)>>>0)/(l>>>0)|0;else m=h;fa(c[449]|0,c[450]|0,f&1^1|0,f>>>1&1^1|0,+(+((c[455]|0)>>>0)/+((c[456]|0)>>>0)),h|0,j|0,c[453]|0,c[454]|0,m|0,j|0);n=Kb(a,b)|0;i=d;return n|0}else{if((g|0)>0){n=1;i=d;return n|0}c[e>>2]=g;oa(1872,e|0)|0;n=0;i=d;return n|0}return 0}function Kb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+96|0;e=d+32|0;f=d;g=d+40|0;Mb(f,a,b);b=Ra(c[466]|0,f,0)|0;if(b>>>0<2){Sa(c[466]|0,g)|0;f=c[460]|0;ha(c[g+12>>2]|0,c[g+8>>2]|0,c[g+28>>2]|0,c[g+24>>2]|0,c[g+44>>2]|0,c[g+40>>2]|0,c[449]|0,c[450]|0,f&1^1|0,f>>>1&1^1|0);h=1;i=d;return h|0}else{c[e>>2]=b;oa(1912,e|0)|0;h=0;i=d;return h|0}return 0}function Lb(){var a=0;a=c[466]|0;if(a){Qa(a);c[466]=0}gb(1776);eb(1792);return}function Mb(a,b,d){a=a|0;b=b|0;d=d|0;c[a>>2]=b;c[a+4>>2]=d;d=a+8|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;c[d+16>>2]=0;c[d+20>>2]=0;return}function Nb(b,c,d){b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0;if(!d){e=0;return e|0}else{f=d;g=b;h=c}while(1){c=a[g>>0]|0;b=a[h>>0]|0;if(c<<24>>24!=b<<24>>24){i=c;j=b;break}f=f+-1|0;if(!f){e=0;k=5;break}else{g=g+1|0;h=h+1|0}}if((k|0)==5)return e|0;e=(i&255)-(j&255)|0;return e|0}function Ob(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,la=0,ma=0,oa=0,pa=0,qa=0,ra=0,sa=0,ta=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Da=0,Ea=0,Fa=0,Ga=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0,Oa=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Va=0,Wa=0,Xa=0;do if(a>>>0<245){b=a>>>0<11?16:a+11&-8;d=b>>>3;e=c[488]|0;f=e>>>d;if(f&3){g=(f&1^1)+d|0;h=g<<1;i=1992+(h<<2)|0;j=1992+(h+2<<2)|0;h=c[j>>2]|0;k=h+8|0;l=c[k>>2]|0;do if((i|0)!=(l|0)){if(l>>>0<(c[492]|0)>>>0)ka();m=l+12|0;if((c[m>>2]|0)==(h|0)){c[m>>2]=i;c[j>>2]=l;break}else ka()}else c[488]=e&~(1<<g);while(0);l=g<<3;c[h+4>>2]=l|3;j=h+(l|4)|0;c[j>>2]=c[j>>2]|1;n=k;return n|0}j=c[490]|0;if(b>>>0>j>>>0){if(f){l=2<<d;i=f<<d&(l|0-l);l=(i&0-i)+-1|0;i=l>>>12&16;m=l>>>i;l=m>>>5&8;o=m>>>l;m=o>>>2&4;p=o>>>m;o=p>>>1&2;q=p>>>o;p=q>>>1&1;r=(l|i|m|o|p)+(q>>>p)|0;p=r<<1;q=1992+(p<<2)|0;o=1992+(p+2<<2)|0;p=c[o>>2]|0;m=p+8|0;i=c[m>>2]|0;do if((q|0)!=(i|0)){if(i>>>0<(c[492]|0)>>>0)ka();l=i+12|0;if((c[l>>2]|0)==(p|0)){c[l>>2]=q;c[o>>2]=i;s=c[490]|0;break}else ka()}else{c[488]=e&~(1<<r);s=j}while(0);j=r<<3;e=j-b|0;c[p+4>>2]=b|3;i=p+b|0;c[p+(b|4)>>2]=e|1;c[p+j>>2]=e;if(s){j=c[493]|0;o=s>>>3;q=o<<1;d=1992+(q<<2)|0;f=c[488]|0;k=1<<o;if(f&k){o=1992+(q+2<<2)|0;h=c[o>>2]|0;if(h>>>0<(c[492]|0)>>>0)ka();else{t=o;u=h}}else{c[488]=f|k;t=1992+(q+2<<2)|0;u=d}c[t>>2]=j;c[u+12>>2]=j;c[j+8>>2]=u;c[j+12>>2]=d}c[490]=e;c[493]=i;n=m;return n|0}i=c[489]|0;if(i){e=(i&0-i)+-1|0;i=e>>>12&16;d=e>>>i;e=d>>>5&8;j=d>>>e;d=j>>>2&4;q=j>>>d;j=q>>>1&2;k=q>>>j;q=k>>>1&1;f=c[2256+((e|i|d|j|q)+(k>>>q)<<2)>>2]|0;q=(c[f+4>>2]&-8)-b|0;k=f;j=f;while(1){f=c[k+16>>2]|0;if(!f){d=c[k+20>>2]|0;if(!d){v=q;w=j;break}else x=d}else x=f;f=(c[x+4>>2]&-8)-b|0;d=f>>>0<q>>>0;q=d?f:q;k=x;j=d?x:j}j=c[492]|0;if(w>>>0<j>>>0)ka();k=w+b|0;if(w>>>0>=k>>>0)ka();q=c[w+24>>2]|0;m=c[w+12>>2]|0;do if((m|0)==(w|0)){p=w+20|0;r=c[p>>2]|0;if(!r){d=w+16|0;f=c[d>>2]|0;if(!f){y=0;break}else{z=f;A=d}}else{z=r;A=p}while(1){p=z+20|0;r=c[p>>2]|0;if(r){z=r;A=p;continue}p=z+16|0;r=c[p>>2]|0;if(!r){B=z;C=A;break}else{z=r;A=p}}if(C>>>0<j>>>0)ka();else{c[C>>2]=0;y=B;break}}else{p=c[w+8>>2]|0;if(p>>>0<j>>>0)ka();r=p+12|0;if((c[r>>2]|0)!=(w|0))ka();d=m+8|0;if((c[d>>2]|0)==(w|0)){c[r>>2]=m;c[d>>2]=p;y=m;break}else ka()}while(0);do if(q){m=c[w+28>>2]|0;j=2256+(m<<2)|0;if((w|0)==(c[j>>2]|0)){c[j>>2]=y;if(!y){c[489]=c[489]&~(1<<m);break}}else{if(q>>>0<(c[492]|0)>>>0)ka();m=q+16|0;if((c[m>>2]|0)==(w|0))c[m>>2]=y;else c[q+20>>2]=y;if(!y)break}m=c[492]|0;if(y>>>0<m>>>0)ka();c[y+24>>2]=q;j=c[w+16>>2]|0;do if(j)if(j>>>0<m>>>0)ka();else{c[y+16>>2]=j;c[j+24>>2]=y;break}while(0);j=c[w+20>>2]|0;if(j)if(j>>>0<(c[492]|0)>>>0)ka();else{c[y+20>>2]=j;c[j+24>>2]=y;break}}while(0);if(v>>>0<16){q=v+b|0;c[w+4>>2]=q|3;j=w+(q+4)|0;c[j>>2]=c[j>>2]|1}else{c[w+4>>2]=b|3;c[w+(b|4)>>2]=v|1;c[w+(v+b)>>2]=v;j=c[490]|0;if(j){q=c[493]|0;m=j>>>3;j=m<<1;p=1992+(j<<2)|0;d=c[488]|0;r=1<<m;if(d&r){m=1992+(j+2<<2)|0;f=c[m>>2]|0;if(f>>>0<(c[492]|0)>>>0)ka();else{D=m;E=f}}else{c[488]=d|r;D=1992+(j+2<<2)|0;E=p}c[D>>2]=q;c[E+12>>2]=q;c[q+8>>2]=E;c[q+12>>2]=p}c[490]=v;c[493]=k}n=w+8|0;return n|0}else F=b}else F=b}else if(a>>>0<=4294967231){p=a+11|0;q=p&-8;j=c[489]|0;if(j){r=0-q|0;d=p>>>8;if(d)if(q>>>0>16777215)G=31;else{p=(d+1048320|0)>>>16&8;f=d<<p;d=(f+520192|0)>>>16&4;m=f<<d;f=(m+245760|0)>>>16&2;i=14-(d|p|f)+(m<<f>>>15)|0;G=q>>>(i+7|0)&1|i<<1}else G=0;i=c[2256+(G<<2)>>2]|0;a:do if(!i){H=r;I=0;J=0;K=86}else{f=r;m=0;p=q<<((G|0)==31?0:25-(G>>>1)|0);d=i;e=0;while(1){h=c[d+4>>2]&-8;o=h-q|0;if(o>>>0<f>>>0)if((h|0)==(q|0)){L=o;M=d;N=d;K=90;break a}else{O=o;P=d}else{O=f;P=e}o=c[d+20>>2]|0;d=c[d+16+(p>>>31<<2)>>2]|0;h=(o|0)==0|(o|0)==(d|0)?m:o;if(!d){H=O;I=h;J=P;K=86;break}else{f=O;m=h;p=p<<1;e=P}}}while(0);if((K|0)==86){if((I|0)==0&(J|0)==0){i=2<<G;r=j&(i|0-i);if(!r){F=q;break}i=(r&0-r)+-1|0;r=i>>>12&16;b=i>>>r;i=b>>>5&8;k=b>>>i;b=k>>>2&4;e=k>>>b;k=e>>>1&2;p=e>>>k;e=p>>>1&1;Q=c[2256+((i|r|b|k|e)+(p>>>e)<<2)>>2]|0;R=0}else{Q=I;R=J}if(!Q){S=H;T=R}else{L=H;M=Q;N=R;K=90}}if((K|0)==90)while(1){K=0;e=(c[M+4>>2]&-8)-q|0;p=e>>>0<L>>>0;k=p?e:L;e=p?M:N;p=c[M+16>>2]|0;if(p){L=k;M=p;N=e;K=90;continue}M=c[M+20>>2]|0;if(!M){S=k;T=e;break}else{L=k;N=e;K=90}}if((T|0)!=0?S>>>0<((c[490]|0)-q|0)>>>0:0){j=c[492]|0;if(T>>>0<j>>>0)ka();e=T+q|0;if(T>>>0>=e>>>0)ka();k=c[T+24>>2]|0;p=c[T+12>>2]|0;do if((p|0)==(T|0)){b=T+20|0;r=c[b>>2]|0;if(!r){i=T+16|0;m=c[i>>2]|0;if(!m){U=0;break}else{V=m;W=i}}else{V=r;W=b}while(1){b=V+20|0;r=c[b>>2]|0;if(r){V=r;W=b;continue}b=V+16|0;r=c[b>>2]|0;if(!r){X=V;Y=W;break}else{V=r;W=b}}if(Y>>>0<j>>>0)ka();else{c[Y>>2]=0;U=X;break}}else{b=c[T+8>>2]|0;if(b>>>0<j>>>0)ka();r=b+12|0;if((c[r>>2]|0)!=(T|0))ka();i=p+8|0;if((c[i>>2]|0)==(T|0)){c[r>>2]=p;c[i>>2]=b;U=p;break}else ka()}while(0);do if(k){p=c[T+28>>2]|0;j=2256+(p<<2)|0;if((T|0)==(c[j>>2]|0)){c[j>>2]=U;if(!U){c[489]=c[489]&~(1<<p);break}}else{if(k>>>0<(c[492]|0)>>>0)ka();p=k+16|0;if((c[p>>2]|0)==(T|0))c[p>>2]=U;else c[k+20>>2]=U;if(!U)break}p=c[492]|0;if(U>>>0<p>>>0)ka();c[U+24>>2]=k;j=c[T+16>>2]|0;do if(j)if(j>>>0<p>>>0)ka();else{c[U+16>>2]=j;c[j+24>>2]=U;break}while(0);j=c[T+20>>2]|0;if(j)if(j>>>0<(c[492]|0)>>>0)ka();else{c[U+20>>2]=j;c[j+24>>2]=U;break}}while(0);b:do if(S>>>0>=16){c[T+4>>2]=q|3;c[T+(q|4)>>2]=S|1;c[T+(S+q)>>2]=S;k=S>>>3;if(S>>>0<256){j=k<<1;p=1992+(j<<2)|0;b=c[488]|0;i=1<<k;if(b&i){k=1992+(j+2<<2)|0;r=c[k>>2]|0;if(r>>>0<(c[492]|0)>>>0)ka();else{Z=k;_=r}}else{c[488]=b|i;Z=1992+(j+2<<2)|0;_=p}c[Z>>2]=e;c[_+12>>2]=e;c[T+(q+8)>>2]=_;c[T+(q+12)>>2]=p;break}p=S>>>8;if(p)if(S>>>0>16777215)$=31;else{j=(p+1048320|0)>>>16&8;i=p<<j;p=(i+520192|0)>>>16&4;b=i<<p;i=(b+245760|0)>>>16&2;r=14-(p|j|i)+(b<<i>>>15)|0;$=S>>>(r+7|0)&1|r<<1}else $=0;r=2256+($<<2)|0;c[T+(q+28)>>2]=$;c[T+(q+20)>>2]=0;c[T+(q+16)>>2]=0;i=c[489]|0;b=1<<$;if(!(i&b)){c[489]=i|b;c[r>>2]=e;c[T+(q+24)>>2]=r;c[T+(q+12)>>2]=e;c[T+(q+8)>>2]=e;break}b=c[r>>2]|0;c:do if((c[b+4>>2]&-8|0)!=(S|0)){r=S<<(($|0)==31?0:25-($>>>1)|0);i=b;while(1){j=i+16+(r>>>31<<2)|0;p=c[j>>2]|0;if(!p){aa=j;ba=i;break}if((c[p+4>>2]&-8|0)==(S|0)){ca=p;break c}else{r=r<<1;i=p}}if(aa>>>0<(c[492]|0)>>>0)ka();else{c[aa>>2]=e;c[T+(q+24)>>2]=ba;c[T+(q+12)>>2]=e;c[T+(q+8)>>2]=e;break b}}else ca=b;while(0);b=ca+8|0;i=c[b>>2]|0;r=c[492]|0;if(i>>>0>=r>>>0&ca>>>0>=r>>>0){c[i+12>>2]=e;c[b>>2]=e;c[T+(q+8)>>2]=i;c[T+(q+12)>>2]=ca;c[T+(q+24)>>2]=0;break}else ka()}else{i=S+q|0;c[T+4>>2]=i|3;b=T+(i+4)|0;c[b>>2]=c[b>>2]|1}while(0);n=T+8|0;return n|0}else F=q}else F=q}else F=-1;while(0);T=c[490]|0;if(T>>>0>=F>>>0){S=T-F|0;ca=c[493]|0;if(S>>>0>15){c[493]=ca+F;c[490]=S;c[ca+(F+4)>>2]=S|1;c[ca+T>>2]=S;c[ca+4>>2]=F|3}else{c[490]=0;c[493]=0;c[ca+4>>2]=T|3;S=ca+(T+4)|0;c[S>>2]=c[S>>2]|1}n=ca+8|0;return n|0}ca=c[491]|0;if(ca>>>0>F>>>0){S=ca-F|0;c[491]=S;ca=c[494]|0;c[494]=ca+F;c[ca+(F+4)>>2]=S|1;c[ca+4>>2]=F|3;n=ca+8|0;return n|0}do if(!(c[606]|0)){ca=va(30)|0;if(!(ca+-1&ca)){c[608]=ca;c[607]=ca;c[609]=-1;c[610]=-1;c[611]=0;c[599]=0;c[606]=(ua(0)|0)&-16^1431655768;break}else ka()}while(0);ca=F+48|0;S=c[608]|0;T=F+47|0;ba=S+T|0;aa=0-S|0;S=ba&aa;if(S>>>0<=F>>>0){n=0;return n|0}$=c[598]|0;if(($|0)!=0?(_=c[596]|0,Z=_+S|0,Z>>>0<=_>>>0|Z>>>0>$>>>0):0){n=0;return n|0}d:do if(!(c[599]&4)){$=c[494]|0;e:do if($){Z=2400;while(1){_=c[Z>>2]|0;if(_>>>0<=$>>>0?(U=Z+4|0,(_+(c[U>>2]|0)|0)>>>0>$>>>0):0){da=Z;ea=U;break}Z=c[Z+8>>2]|0;if(!Z){K=174;break e}}Z=ba-(c[491]|0)&aa;if(Z>>>0<2147483647){U=na(Z|0)|0;_=(U|0)==((c[da>>2]|0)+(c[ea>>2]|0)|0);X=_?Z:0;if(_)if((U|0)==(-1|0))fa=X;else{ga=U;ha=X;K=194;break d}else{ia=U;ja=Z;la=X;K=184}}else fa=0}else K=174;while(0);do if((K|0)==174){$=na(0)|0;if(($|0)!=(-1|0)){q=$;X=c[607]|0;Z=X+-1|0;if(!(Z&q))ma=S;else ma=S-q+(Z+q&0-X)|0;X=c[596]|0;q=X+ma|0;if(ma>>>0>F>>>0&ma>>>0<2147483647){Z=c[598]|0;if((Z|0)!=0?q>>>0<=X>>>0|q>>>0>Z>>>0:0){fa=0;break}Z=na(ma|0)|0;q=(Z|0)==($|0);X=q?ma:0;if(q){ga=$;ha=X;K=194;break d}else{ia=Z;ja=ma;la=X;K=184}}else fa=0}else fa=0}while(0);f:do if((K|0)==184){X=0-ja|0;do if(ca>>>0>ja>>>0&(ja>>>0<2147483647&(ia|0)!=(-1|0))?(Z=c[608]|0,$=T-ja+Z&0-Z,$>>>0<2147483647):0)if((na($|0)|0)==(-1|0)){na(X|0)|0;fa=la;break f}else{oa=$+ja|0;break}else oa=ja;while(0);if((ia|0)==(-1|0))fa=la;else{ga=ia;ha=oa;K=194;break d}}while(0);c[599]=c[599]|4;pa=fa;K=191}else{pa=0;K=191}while(0);if((((K|0)==191?S>>>0<2147483647:0)?(fa=na(S|0)|0,S=na(0)|0,fa>>>0<S>>>0&((fa|0)!=(-1|0)&(S|0)!=(-1|0))):0)?(oa=S-fa|0,S=oa>>>0>(F+40|0)>>>0,S):0){ga=fa;ha=S?oa:pa;K=194}if((K|0)==194){pa=(c[596]|0)+ha|0;c[596]=pa;if(pa>>>0>(c[597]|0)>>>0)c[597]=pa;pa=c[494]|0;g:do if(pa){oa=2400;do{S=c[oa>>2]|0;fa=oa+4|0;ia=c[fa>>2]|0;if((ga|0)==(S+ia|0)){qa=S;ra=fa;sa=ia;ta=oa;K=204;break}oa=c[oa+8>>2]|0}while((oa|0)!=0);if(((K|0)==204?(c[ta+12>>2]&8|0)==0:0)?pa>>>0<ga>>>0&pa>>>0>=qa>>>0:0){c[ra>>2]=sa+ha;oa=(c[491]|0)+ha|0;ia=pa+8|0;fa=(ia&7|0)==0?0:0-ia&7;ia=oa-fa|0;c[494]=pa+fa;c[491]=ia;c[pa+(fa+4)>>2]=ia|1;c[pa+(oa+4)>>2]=40;c[495]=c[610];break}oa=c[492]|0;if(ga>>>0<oa>>>0){c[492]=ga;xa=ga}else xa=oa;oa=ga+ha|0;ia=2400;while(1){if((c[ia>>2]|0)==(oa|0)){ya=ia;za=ia;K=212;break}ia=c[ia+8>>2]|0;if(!ia){Aa=2400;break}}if((K|0)==212)if(!(c[za+12>>2]&8)){c[ya>>2]=ga;ia=za+4|0;c[ia>>2]=(c[ia>>2]|0)+ha;ia=ga+8|0;oa=(ia&7|0)==0?0:0-ia&7;ia=ga+(ha+8)|0;fa=(ia&7|0)==0?0:0-ia&7;ia=ga+(fa+ha)|0;S=oa+F|0;la=ga+S|0;ja=ia-(ga+oa)-F|0;c[ga+(oa+4)>>2]=F|3;h:do if((ia|0)!=(pa|0)){if((ia|0)==(c[493]|0)){T=(c[490]|0)+ja|0;c[490]=T;c[493]=la;c[ga+(S+4)>>2]=T|1;c[ga+(T+S)>>2]=T;break}T=ha+4|0;ca=c[ga+(T+fa)>>2]|0;if((ca&3|0)==1){ma=ca&-8;ea=ca>>>3;i:do if(ca>>>0>=256){da=c[ga+((fa|24)+ha)>>2]|0;aa=c[ga+(ha+12+fa)>>2]|0;do if((aa|0)==(ia|0)){ba=fa|16;X=ga+(T+ba)|0;$=c[X>>2]|0;if(!$){Z=ga+(ba+ha)|0;ba=c[Z>>2]|0;if(!ba){Ba=0;break}else{Ca=ba;Da=Z}}else{Ca=$;Da=X}while(1){X=Ca+20|0;$=c[X>>2]|0;if($){Ca=$;Da=X;continue}X=Ca+16|0;$=c[X>>2]|0;if(!$){Ea=Ca;Fa=Da;break}else{Ca=$;Da=X}}if(Fa>>>0<xa>>>0)ka();else{c[Fa>>2]=0;Ba=Ea;break}}else{X=c[ga+((fa|8)+ha)>>2]|0;if(X>>>0<xa>>>0)ka();$=X+12|0;if((c[$>>2]|0)!=(ia|0))ka();Z=aa+8|0;if((c[Z>>2]|0)==(ia|0)){c[$>>2]=aa;c[Z>>2]=X;Ba=aa;break}else ka()}while(0);if(!da)break;aa=c[ga+(ha+28+fa)>>2]|0;X=2256+(aa<<2)|0;do if((ia|0)!=(c[X>>2]|0)){if(da>>>0<(c[492]|0)>>>0)ka();Z=da+16|0;if((c[Z>>2]|0)==(ia|0))c[Z>>2]=Ba;else c[da+20>>2]=Ba;if(!Ba)break i}else{c[X>>2]=Ba;if(Ba)break;c[489]=c[489]&~(1<<aa);break i}while(0);aa=c[492]|0;if(Ba>>>0<aa>>>0)ka();c[Ba+24>>2]=da;X=fa|16;Z=c[ga+(X+ha)>>2]|0;do if(Z)if(Z>>>0<aa>>>0)ka();else{c[Ba+16>>2]=Z;c[Z+24>>2]=Ba;break}while(0);Z=c[ga+(T+X)>>2]|0;if(!Z)break;if(Z>>>0<(c[492]|0)>>>0)ka();else{c[Ba+20>>2]=Z;c[Z+24>>2]=Ba;break}}else{Z=c[ga+((fa|8)+ha)>>2]|0;aa=c[ga+(ha+12+fa)>>2]|0;da=1992+(ea<<1<<2)|0;do if((Z|0)!=(da|0)){if(Z>>>0<xa>>>0)ka();if((c[Z+12>>2]|0)==(ia|0))break;ka()}while(0);if((aa|0)==(Z|0)){c[488]=c[488]&~(1<<ea);break}do if((aa|0)==(da|0))Ga=aa+8|0;else{if(aa>>>0<xa>>>0)ka();X=aa+8|0;if((c[X>>2]|0)==(ia|0)){Ga=X;break}ka()}while(0);c[Z+12>>2]=aa;c[Ga>>2]=Z}while(0);Ha=ga+((ma|fa)+ha)|0;Ia=ma+ja|0}else{Ha=ia;Ia=ja}ea=Ha+4|0;c[ea>>2]=c[ea>>2]&-2;c[ga+(S+4)>>2]=Ia|1;c[ga+(Ia+S)>>2]=Ia;ea=Ia>>>3;if(Ia>>>0<256){T=ea<<1;ca=1992+(T<<2)|0;da=c[488]|0;X=1<<ea;do if(!(da&X)){c[488]=da|X;Ja=1992+(T+2<<2)|0;Ka=ca}else{ea=1992+(T+2<<2)|0;$=c[ea>>2]|0;if($>>>0>=(c[492]|0)>>>0){Ja=ea;Ka=$;break}ka()}while(0);c[Ja>>2]=la;c[Ka+12>>2]=la;c[ga+(S+8)>>2]=Ka;c[ga+(S+12)>>2]=ca;break}T=Ia>>>8;do if(!T)La=0;else{if(Ia>>>0>16777215){La=31;break}X=(T+1048320|0)>>>16&8;da=T<<X;ma=(da+520192|0)>>>16&4;$=da<<ma;da=($+245760|0)>>>16&2;ea=14-(ma|X|da)+($<<da>>>15)|0;La=Ia>>>(ea+7|0)&1|ea<<1}while(0);T=2256+(La<<2)|0;c[ga+(S+28)>>2]=La;c[ga+(S+20)>>2]=0;c[ga+(S+16)>>2]=0;ca=c[489]|0;ea=1<<La;if(!(ca&ea)){c[489]=ca|ea;c[T>>2]=la;c[ga+(S+24)>>2]=T;c[ga+(S+12)>>2]=la;c[ga+(S+8)>>2]=la;break}ea=c[T>>2]|0;j:do if((c[ea+4>>2]&-8|0)!=(Ia|0)){T=Ia<<((La|0)==31?0:25-(La>>>1)|0);ca=ea;while(1){da=ca+16+(T>>>31<<2)|0;$=c[da>>2]|0;if(!$){Ma=da;Na=ca;break}if((c[$+4>>2]&-8|0)==(Ia|0)){Oa=$;break j}else{T=T<<1;ca=$}}if(Ma>>>0<(c[492]|0)>>>0)ka();else{c[Ma>>2]=la;c[ga+(S+24)>>2]=Na;c[ga+(S+12)>>2]=la;c[ga+(S+8)>>2]=la;break h}}else Oa=ea;while(0);ea=Oa+8|0;ca=c[ea>>2]|0;T=c[492]|0;if(ca>>>0>=T>>>0&Oa>>>0>=T>>>0){c[ca+12>>2]=la;c[ea>>2]=la;c[ga+(S+8)>>2]=ca;c[ga+(S+12)>>2]=Oa;c[ga+(S+24)>>2]=0;break}else ka()}else{ca=(c[491]|0)+ja|0;c[491]=ca;c[494]=la;c[ga+(S+4)>>2]=ca|1}while(0);n=ga+(oa|8)|0;return n|0}else Aa=2400;while(1){S=c[Aa>>2]|0;if(S>>>0<=pa>>>0?(la=c[Aa+4>>2]|0,ja=S+la|0,ja>>>0>pa>>>0):0){Pa=S;Qa=la;Ra=ja;break}Aa=c[Aa+8>>2]|0}oa=Pa+(Qa+-39)|0;ja=Pa+(Qa+-47+((oa&7|0)==0?0:0-oa&7))|0;oa=pa+16|0;la=ja>>>0<oa>>>0?pa:ja;ja=la+8|0;S=ga+8|0;ia=(S&7|0)==0?0:0-S&7;S=ha+-40-ia|0;c[494]=ga+ia;c[491]=S;c[ga+(ia+4)>>2]=S|1;c[ga+(ha+-36)>>2]=40;c[495]=c[610];S=la+4|0;c[S>>2]=27;c[ja>>2]=c[600];c[ja+4>>2]=c[601];c[ja+8>>2]=c[602];c[ja+12>>2]=c[603];c[600]=ga;c[601]=ha;c[603]=0;c[602]=ja;ja=la+28|0;c[ja>>2]=7;if((la+32|0)>>>0<Ra>>>0){ia=ja;do{ja=ia;ia=ia+4|0;c[ia>>2]=7}while((ja+8|0)>>>0<Ra>>>0)}if((la|0)!=(pa|0)){ia=la-pa|0;c[S>>2]=c[S>>2]&-2;c[pa+4>>2]=ia|1;c[la>>2]=ia;ja=ia>>>3;if(ia>>>0<256){fa=ja<<1;ca=1992+(fa<<2)|0;ea=c[488]|0;T=1<<ja;if(ea&T){ja=1992+(fa+2<<2)|0;Z=c[ja>>2]|0;if(Z>>>0<(c[492]|0)>>>0)ka();else{Sa=ja;Ta=Z}}else{c[488]=ea|T;Sa=1992+(fa+2<<2)|0;Ta=ca}c[Sa>>2]=pa;c[Ta+12>>2]=pa;c[pa+8>>2]=Ta;c[pa+12>>2]=ca;break}ca=ia>>>8;if(ca)if(ia>>>0>16777215)Ua=31;else{fa=(ca+1048320|0)>>>16&8;T=ca<<fa;ca=(T+520192|0)>>>16&4;ea=T<<ca;T=(ea+245760|0)>>>16&2;Z=14-(ca|fa|T)+(ea<<T>>>15)|0;Ua=ia>>>(Z+7|0)&1|Z<<1}else Ua=0;Z=2256+(Ua<<2)|0;c[pa+28>>2]=Ua;c[pa+20>>2]=0;c[oa>>2]=0;T=c[489]|0;ea=1<<Ua;if(!(T&ea)){c[489]=T|ea;c[Z>>2]=pa;c[pa+24>>2]=Z;c[pa+12>>2]=pa;c[pa+8>>2]=pa;break}ea=c[Z>>2]|0;k:do if((c[ea+4>>2]&-8|0)!=(ia|0)){Z=ia<<((Ua|0)==31?0:25-(Ua>>>1)|0);T=ea;while(1){fa=T+16+(Z>>>31<<2)|0;ca=c[fa>>2]|0;if(!ca){Va=fa;Wa=T;break}if((c[ca+4>>2]&-8|0)==(ia|0)){Xa=ca;break k}else{Z=Z<<1;T=ca}}if(Va>>>0<(c[492]|0)>>>0)ka();else{c[Va>>2]=pa;c[pa+24>>2]=Wa;c[pa+12>>2]=pa;c[pa+8>>2]=pa;break g}}else Xa=ea;while(0);ea=Xa+8|0;ia=c[ea>>2]|0;oa=c[492]|0;if(ia>>>0>=oa>>>0&Xa>>>0>=oa>>>0){c[ia+12>>2]=pa;c[ea>>2]=pa;c[pa+8>>2]=ia;c[pa+12>>2]=Xa;c[pa+24>>2]=0;break}else ka()}}else{ia=c[492]|0;if((ia|0)==0|ga>>>0<ia>>>0)c[492]=ga;c[600]=ga;c[601]=ha;c[603]=0;c[497]=c[606];c[496]=-1;ia=0;do{ea=ia<<1;oa=1992+(ea<<2)|0;c[1992+(ea+3<<2)>>2]=oa;c[1992+(ea+2<<2)>>2]=oa;ia=ia+1|0}while((ia|0)!=32);ia=ga+8|0;oa=(ia&7|0)==0?0:0-ia&7;ia=ha+-40-oa|0;c[494]=ga+oa;c[491]=ia;c[ga+(oa+4)>>2]=ia|1;c[ga+(ha+-36)>>2]=40;c[495]=c[610]}while(0);ha=c[491]|0;if(ha>>>0>F>>>0){ga=ha-F|0;c[491]=ga;ha=c[494]|0;c[494]=ha+F;c[ha+(F+4)>>2]=ga|1;c[ha+4>>2]=F|3;n=ha+8|0;return n|0}}c[(wa()|0)>>2]=12;n=0;return n|0}function Pb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;if(!a)return;b=a+-8|0;d=c[492]|0;if(b>>>0<d>>>0)ka();e=c[a+-4>>2]|0;f=e&3;if((f|0)==1)ka();g=e&-8;h=a+(g+-8)|0;do if(!(e&1)){i=c[b>>2]|0;if(!f)return;j=-8-i|0;k=a+j|0;l=i+g|0;if(k>>>0<d>>>0)ka();if((k|0)==(c[493]|0)){m=a+(g+-4)|0;n=c[m>>2]|0;if((n&3|0)!=3){o=k;p=l;break}c[490]=l;c[m>>2]=n&-2;c[a+(j+4)>>2]=l|1;c[h>>2]=l;return}n=i>>>3;if(i>>>0<256){i=c[a+(j+8)>>2]|0;m=c[a+(j+12)>>2]|0;q=1992+(n<<1<<2)|0;if((i|0)!=(q|0)){if(i>>>0<d>>>0)ka();if((c[i+12>>2]|0)!=(k|0))ka()}if((m|0)==(i|0)){c[488]=c[488]&~(1<<n);o=k;p=l;break}if((m|0)!=(q|0)){if(m>>>0<d>>>0)ka();q=m+8|0;if((c[q>>2]|0)==(k|0))r=q;else ka()}else r=m+8|0;c[i+12>>2]=m;c[r>>2]=i;o=k;p=l;break}i=c[a+(j+24)>>2]|0;m=c[a+(j+12)>>2]|0;do if((m|0)==(k|0)){q=a+(j+20)|0;n=c[q>>2]|0;if(!n){s=a+(j+16)|0;t=c[s>>2]|0;if(!t){u=0;break}else{v=t;w=s}}else{v=n;w=q}while(1){q=v+20|0;n=c[q>>2]|0;if(n){v=n;w=q;continue}q=v+16|0;n=c[q>>2]|0;if(!n){x=v;y=w;break}else{v=n;w=q}}if(y>>>0<d>>>0)ka();else{c[y>>2]=0;u=x;break}}else{q=c[a+(j+8)>>2]|0;if(q>>>0<d>>>0)ka();n=q+12|0;if((c[n>>2]|0)!=(k|0))ka();s=m+8|0;if((c[s>>2]|0)==(k|0)){c[n>>2]=m;c[s>>2]=q;u=m;break}else ka()}while(0);if(i){m=c[a+(j+28)>>2]|0;q=2256+(m<<2)|0;if((k|0)==(c[q>>2]|0)){c[q>>2]=u;if(!u){c[489]=c[489]&~(1<<m);o=k;p=l;break}}else{if(i>>>0<(c[492]|0)>>>0)ka();m=i+16|0;if((c[m>>2]|0)==(k|0))c[m>>2]=u;else c[i+20>>2]=u;if(!u){o=k;p=l;break}}m=c[492]|0;if(u>>>0<m>>>0)ka();c[u+24>>2]=i;q=c[a+(j+16)>>2]|0;do if(q)if(q>>>0<m>>>0)ka();else{c[u+16>>2]=q;c[q+24>>2]=u;break}while(0);q=c[a+(j+20)>>2]|0;if(q)if(q>>>0<(c[492]|0)>>>0)ka();else{c[u+20>>2]=q;c[q+24>>2]=u;o=k;p=l;break}else{o=k;p=l}}else{o=k;p=l}}else{o=b;p=g}while(0);if(o>>>0>=h>>>0)ka();b=a+(g+-4)|0;u=c[b>>2]|0;if(!(u&1))ka();if(!(u&2)){if((h|0)==(c[494]|0)){d=(c[491]|0)+p|0;c[491]=d;c[494]=o;c[o+4>>2]=d|1;if((o|0)!=(c[493]|0))return;c[493]=0;c[490]=0;return}if((h|0)==(c[493]|0)){d=(c[490]|0)+p|0;c[490]=d;c[493]=o;c[o+4>>2]=d|1;c[o+d>>2]=d;return}d=(u&-8)+p|0;x=u>>>3;do if(u>>>0>=256){y=c[a+(g+16)>>2]|0;w=c[a+(g|4)>>2]|0;do if((w|0)==(h|0)){v=a+(g+12)|0;r=c[v>>2]|0;if(!r){f=a+(g+8)|0;e=c[f>>2]|0;if(!e){z=0;break}else{A=e;B=f}}else{A=r;B=v}while(1){v=A+20|0;r=c[v>>2]|0;if(r){A=r;B=v;continue}v=A+16|0;r=c[v>>2]|0;if(!r){C=A;D=B;break}else{A=r;B=v}}if(D>>>0<(c[492]|0)>>>0)ka();else{c[D>>2]=0;z=C;break}}else{v=c[a+g>>2]|0;if(v>>>0<(c[492]|0)>>>0)ka();r=v+12|0;if((c[r>>2]|0)!=(h|0))ka();f=w+8|0;if((c[f>>2]|0)==(h|0)){c[r>>2]=w;c[f>>2]=v;z=w;break}else ka()}while(0);if(y){w=c[a+(g+20)>>2]|0;l=2256+(w<<2)|0;if((h|0)==(c[l>>2]|0)){c[l>>2]=z;if(!z){c[489]=c[489]&~(1<<w);break}}else{if(y>>>0<(c[492]|0)>>>0)ka();w=y+16|0;if((c[w>>2]|0)==(h|0))c[w>>2]=z;else c[y+20>>2]=z;if(!z)break}w=c[492]|0;if(z>>>0<w>>>0)ka();c[z+24>>2]=y;l=c[a+(g+8)>>2]|0;do if(l)if(l>>>0<w>>>0)ka();else{c[z+16>>2]=l;c[l+24>>2]=z;break}while(0);l=c[a+(g+12)>>2]|0;if(l)if(l>>>0<(c[492]|0)>>>0)ka();else{c[z+20>>2]=l;c[l+24>>2]=z;break}}}else{l=c[a+g>>2]|0;w=c[a+(g|4)>>2]|0;y=1992+(x<<1<<2)|0;if((l|0)!=(y|0)){if(l>>>0<(c[492]|0)>>>0)ka();if((c[l+12>>2]|0)!=(h|0))ka()}if((w|0)==(l|0)){c[488]=c[488]&~(1<<x);break}if((w|0)!=(y|0)){if(w>>>0<(c[492]|0)>>>0)ka();y=w+8|0;if((c[y>>2]|0)==(h|0))E=y;else ka()}else E=w+8|0;c[l+12>>2]=w;c[E>>2]=l}while(0);c[o+4>>2]=d|1;c[o+d>>2]=d;if((o|0)==(c[493]|0)){c[490]=d;return}else F=d}else{c[b>>2]=u&-2;c[o+4>>2]=p|1;c[o+p>>2]=p;F=p}p=F>>>3;if(F>>>0<256){u=p<<1;b=1992+(u<<2)|0;d=c[488]|0;E=1<<p;if(d&E){p=1992+(u+2<<2)|0;h=c[p>>2]|0;if(h>>>0<(c[492]|0)>>>0)ka();else{G=p;H=h}}else{c[488]=d|E;G=1992+(u+2<<2)|0;H=b}c[G>>2]=o;c[H+12>>2]=o;c[o+8>>2]=H;c[o+12>>2]=b;return}b=F>>>8;if(b)if(F>>>0>16777215)I=31;else{H=(b+1048320|0)>>>16&8;G=b<<H;b=(G+520192|0)>>>16&4;u=G<<b;G=(u+245760|0)>>>16&2;E=14-(b|H|G)+(u<<G>>>15)|0;I=F>>>(E+7|0)&1|E<<1}else I=0;E=2256+(I<<2)|0;c[o+28>>2]=I;c[o+20>>2]=0;c[o+16>>2]=0;G=c[489]|0;u=1<<I;a:do if(G&u){H=c[E>>2]|0;b:do if((c[H+4>>2]&-8|0)!=(F|0)){b=F<<((I|0)==31?0:25-(I>>>1)|0);d=H;while(1){h=d+16+(b>>>31<<2)|0;p=c[h>>2]|0;if(!p){J=h;K=d;break}if((c[p+4>>2]&-8|0)==(F|0)){L=p;break b}else{b=b<<1;d=p}}if(J>>>0<(c[492]|0)>>>0)ka();else{c[J>>2]=o;c[o+24>>2]=K;c[o+12>>2]=o;c[o+8>>2]=o;break a}}else L=H;while(0);H=L+8|0;d=c[H>>2]|0;b=c[492]|0;if(d>>>0>=b>>>0&L>>>0>=b>>>0){c[d+12>>2]=o;c[H>>2]=o;c[o+8>>2]=d;c[o+12>>2]=L;c[o+24>>2]=0;break}else ka()}else{c[489]=G|u;c[E>>2]=o;c[o+24>>2]=E;c[o+12>>2]=o;c[o+8>>2]=o}while(0);o=(c[496]|0)+-1|0;c[496]=o;if(!o)M=2408;else return;while(1){o=c[M>>2]|0;if(!o)break;else M=o+8|0}c[496]=-1;return}function Qb(a,b){a=a|0;b=b|0;var d=0,e=0;if(a){d=_(b,a)|0;if((b|a)>>>0>65535)e=((d>>>0)/(a>>>0)|0|0)==(b|0)?d:-1;else e=d}else e=0;d=Ob(e)|0;if(!d)return d|0;if(!(c[d+-4>>2]&3))return d|0;Ub(d|0,0,e|0)|0;return d|0}function Rb(){}function Sb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=b-d>>>0;e=b-d-(c>>>0>a>>>0|0)>>>0;return (C=e,a-c>>>0|0)|0}function Tb(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=a+c>>>0;return (C=b+d+(e>>>0<a>>>0|0)>>>0,e|0)|0}function Ub(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;g=b&3;h=d|d<<8|d<<16|d<<24;i=f&~3;if(g){g=b+4-g|0;while((b|0)<(g|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(i|0)){c[b>>2]=h;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function Vb(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<<c|(a&(1<<c)-1<<32-c)>>>32-c;return a<<c}C=a<<c-32;return 0}function Wb(b){b=b|0;var c=0;c=b;while(a[c>>0]|0)c=c+1|0;return c-b|0}function Xb(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return ra(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function Yb(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<<c)-1)<<32-c}C=0;return b>>>c-32|0}function Zb(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>c;return a>>>c|(b&(1<<c)-1)<<32-c}C=(b|0)<0?-1:0;return b>>c-32|0}function _b(b){b=b|0;var c=0;c=a[m+(b&255)>>0]|0;if((c|0)<8)return c|0;c=a[m+(b>>8&255)>>0]|0;if((c|0)<8)return c+8|0;c=a[m+(b>>16&255)>>0]|0;if((c|0)<8)return c+16|0;return (a[m+(b>>>24)>>0]|0)+24|0}function $b(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;c=a&65535;d=b&65535;e=_(d,c)|0;f=a>>>16;a=(e>>>16)+(_(d,f)|0)|0;d=b>>>16;b=_(d,c)|0;return (C=(a>>>16)+(_(d,f)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|e&65535|0)|0}function ac(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b>>31|((b|0)<0?-1:0)<<1;f=((b|0)<0?-1:0)>>31|((b|0)<0?-1:0)<<1;g=d>>31|((d|0)<0?-1:0)<<1;h=((d|0)<0?-1:0)>>31|((d|0)<0?-1:0)<<1;i=Sb(e^a,f^b,e,f)|0;b=C;a=g^e;e=h^f;return Sb((fc(i,b,Sb(g^c,h^d,g,h)|0,C,0)|0)^a,C^e,a,e)|0}function bc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+8|0;g=f|0;h=b>>31|((b|0)<0?-1:0)<<1;j=((b|0)<0?-1:0)>>31|((b|0)<0?-1:0)<<1;k=e>>31|((e|0)<0?-1:0)<<1;l=((e|0)<0?-1:0)>>31|((e|0)<0?-1:0)<<1;m=Sb(h^a,j^b,h,j)|0;b=C;fc(m,b,Sb(k^d,l^e,k,l)|0,C,g)|0;l=Sb(c[g>>2]^h,c[g+4>>2]^j,h,j)|0;j=C;i=f;return (C=j,l)|0}function cc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;a=c;c=$b(e,a)|0;f=C;return (C=(_(b,a)|0)+(_(d,e)|0)+f|f&0,c|0|0)|0}function dc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return fc(a,b,c,d,0)|0}function ec(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+8|0;g=f|0;fc(a,b,d,e,g)|0;i=f;return (C=c[g+4>>2]|0,c[g>>2]|0)|0}function fc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0;g=a;h=b;i=h;j=d;k=e;l=k;if(!i){m=(f|0)!=0;if(!l){if(m){c[f>>2]=(g>>>0)%(j>>>0);c[f+4>>2]=0}n=0;o=(g>>>0)/(j>>>0)>>>0;return (C=n,o)|0}else{if(!m){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=b&0;n=0;o=0;return (C=n,o)|0}}m=(l|0)==0;do if(j){if(!m){p=(aa(l|0)|0)-(aa(i|0)|0)|0;if(p>>>0<=31){q=p+1|0;r=31-p|0;s=p-31>>31;t=q;u=g>>>(q>>>0)&s|i<<r;v=i>>>(q>>>0)&s;w=0;x=g<<r;break}if(!f){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=h|b&0;n=0;o=0;return (C=n,o)|0}r=j-1|0;if(r&j){s=(aa(j|0)|0)+33-(aa(i|0)|0)|0;q=64-s|0;p=32-s|0;y=p>>31;z=s-32|0;A=z>>31;t=s;u=p-1>>31&i>>>(z>>>0)|(i<<p|g>>>(s>>>0))&A;v=A&i>>>(s>>>0);w=g<<q&y;x=(i<<q|g>>>(z>>>0))&y|g<<p&s-33>>31;break}if(f){c[f>>2]=r&g;c[f+4>>2]=0}if((j|0)==1){n=h|b&0;o=a|0|0;return (C=n,o)|0}else{r=_b(j|0)|0;n=i>>>(r>>>0)|0;o=i<<32-r|g>>>(r>>>0)|0;return (C=n,o)|0}}else{if(m){if(f){c[f>>2]=(i>>>0)%(j>>>0);c[f+4>>2]=0}n=0;o=(i>>>0)/(j>>>0)>>>0;return (C=n,o)|0}if(!g){if(f){c[f>>2]=0;c[f+4>>2]=(i>>>0)%(l>>>0)}n=0;o=(i>>>0)/(l>>>0)>>>0;return (C=n,o)|0}r=l-1|0;if(!(r&l)){if(f){c[f>>2]=a|0;c[f+4>>2]=r&i|b&0}n=0;o=i>>>((_b(l|0)|0)>>>0);return (C=n,o)|0}r=(aa(l|0)|0)-(aa(i|0)|0)|0;if(r>>>0<=30){s=r+1|0;p=31-r|0;t=s;u=i<<p|g>>>(s>>>0);v=i>>>(s>>>0);w=0;x=g<<p;break}if(!f){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=h|b&0;n=0;o=0;return (C=n,o)|0}while(0);if(!t){B=x;D=w;E=v;F=u;G=0;H=0}else{b=d|0|0;d=k|e&0;e=Tb(b|0,d|0,-1,-1)|0;k=C;h=x;x=w;w=v;v=u;u=t;t=0;do{a=h;h=x>>>31|h<<1;x=t|x<<1;g=v<<1|a>>>31|0;a=v>>>31|w<<1|0;Sb(e,k,g,a)|0;i=C;l=i>>31|((i|0)<0?-1:0)<<1;t=l&1;v=Sb(g,a,l&b,(((i|0)<0?-1:0)>>31|((i|0)<0?-1:0)<<1)&d)|0;w=C;u=u-1|0}while((u|0)!=0);B=h;D=x;E=w;F=v;G=0;H=t}t=D;D=0;if(f){c[f>>2]=F;c[f+4>>2]=E}n=(t|0)>>>31|(B|D)<<1|(D<<1|t>>>31)&0|G;o=(t<<1|0>>>31)&-2|H;return (C=n,o)|0}function gc(a,b,c){a=a|0;b=b|0;c=c|0;ya[a&7](b|0,c|0)}function hc(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;za[a&7](b|0,c|0,d|0,e|0)}function ic(a,b){a=a|0;b=b|0;ba(0)}function jc(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;ba(1)}
+
+// EMSCRIPTEN_END_FUNCS
+var ya=[ic,zb,Ab,Bb,Cb,ic,ic,ic];var za=[jc,Db,Eb,Fb,Gb,jc,jc,jc];return{_ogv_video_decoder_init:Ib,_free:Pb,_ogv_video_decoder_process_header:Jb,_i64Add:Tb,_ogv_video_decoder_destroy:Lb,_i64Subtract:Sb,_memset:Ub,_malloc:Ob,_memcpy:Xb,_strlen:Wb,_ogv_video_decoder_process_frame:Kb,_bitshift64Shl:Vb,runPostSets:Rb,stackAlloc:Aa,stackSave:Ba,stackRestore:Ca,establishStackSpace:Da,setThrew:Ea,setTempRet0:Ha,getTempRet0:Ia,dynCall_vii:gc,dynCall_viiii:hc}})
+
+
+// EMSCRIPTEN_END_ASM
+(Module.asmGlobalArg,Module.asmLibraryArg,buffer);var _ogv_video_decoder_init=Module["_ogv_video_decoder_init"]=asm["_ogv_video_decoder_init"];var _free=Module["_free"]=asm["_free"];var runPostSets=Module["runPostSets"]=asm["runPostSets"];var _ogv_video_decoder_process_header=Module["_ogv_video_decoder_process_header"]=asm["_ogv_video_decoder_process_header"];var _i64Add=Module["_i64Add"]=asm["_i64Add"];var _ogv_video_decoder_destroy=Module["_ogv_video_decoder_destroy"]=asm["_ogv_video_decoder_destroy"];var _i64Subtract=Module["_i64Subtract"]=asm["_i64Subtract"];var _memset=Module["_memset"]=asm["_memset"];var _malloc=Module["_malloc"]=asm["_malloc"];var _memcpy=Module["_memcpy"]=asm["_memcpy"];var _strlen=Module["_strlen"]=asm["_strlen"];var _ogv_video_decoder_process_frame=Module["_ogv_video_decoder_process_frame"]=asm["_ogv_video_decoder_process_frame"];var _bitshift64Shl=Module["_bitshift64Shl"]=asm["_bitshift64Shl"];var dynCall_vii=Module["dynCall_vii"]=asm["dynCall_vii"];var dynCall_viiii=Module["dynCall_viiii"]=asm["dynCall_viiii"];Runtime.stackAlloc=asm["stackAlloc"];Runtime.stackSave=asm["stackSave"];Runtime.stackRestore=asm["stackRestore"];Runtime.establishStackSpace=asm["establishStackSpace"];Runtime.setTempRet0=asm["setTempRet0"];Runtime.getTempRet0=asm["getTempRet0"];var i64Math=(function(){var goog={math:{}};goog.math.Long=(function(low,high){this.low_=low|0;this.high_=high|0});goog.math.Long.IntCache_={};goog.math.Long.fromInt=(function(value){if(-128<=value&&value<128){var cachedObj=goog.math.Long.IntCache_[value];if(cachedObj){return cachedObj}}var obj=new goog.math.Long(value|0,value<0?-1:0);if(-128<=value&&value<128){goog.math.Long.IntCache_[value]=obj}return obj});goog.math.Long.fromNumber=(function(value){if(isNaN(value)||!isFinite(value)){return goog.math.Long.ZERO}else if(value<=-goog.math.Long.TWO_PWR_63_DBL_){return goog.math.Long.MIN_VALUE}else if(value+1>=goog.math.Long.TWO_PWR_63_DBL_){return goog.math.Long.MAX_VALUE}else if(value<0){return goog.math.Long.fromNumber(-value).negate()}else{return new goog.math.Long(value%goog.math.Long.TWO_PWR_32_DBL_|0,value/goog.math.Long.TWO_PWR_32_DBL_|0)}});goog.math.Long.fromBits=(function(lowBits,highBits){return new goog.math.Long(lowBits,highBits)});goog.math.Long.fromString=(function(str,opt_radix){if(str.length==0){throw Error("number format error: empty string")}var radix=opt_radix||10;if(radix<2||36<radix){throw Error("radix out of range: "+radix)}if(str.charAt(0)=="-"){return goog.math.Long.fromString(str.substring(1),radix).negate()}else if(str.indexOf("-")>=0){throw Error('number format error: interior "-" character: '+str)}var radixToPower=goog.math.Long.fromNumber(Math.pow(radix,8));var result=goog.math.Long.ZERO;for(var i=0;i<str.length;i+=8){var size=Math.min(8,str.length-i);var value=parseInt(str.substring(i,i+size),radix);if(size<8){var power=goog.math.Long.fromNumber(Math.pow(radix,size));result=result.multiply(power).add(goog.math.Long.fromNumber(value))}else{result=result.multiply(radixToPower);result=result.add(goog.math.Long.fromNumber(value))}}return result});goog.math.Long.TWO_PWR_16_DBL_=1<<16;goog.math.Long.TWO_PWR_24_DBL_=1<<24;goog.math.Long.TWO_PWR_32_DBL_=goog.math.Long.TWO_PWR_16_DBL_*goog.math.Long.TWO_PWR_16_DBL_;goog.math.Long.TWO_PWR_31_DBL_=goog.math.Long.TWO_PWR_32_DBL_/2;goog.math.Long.TWO_PWR_48_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_16_DBL_;goog.math.Long.TWO_PWR_64_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_32_DBL_;goog.math.Long.TWO_PWR_63_DBL_=goog.math.Long.TWO_PWR_64_DBL_/2;goog.math.Long.ZERO=goog.math.Long.fromInt(0);goog.math.Long.ONE=goog.math.Long.fromInt(1);goog.math.Long.NEG_ONE=goog.math.Long.fromInt(-1);goog.math.Long.MAX_VALUE=goog.math.Long.fromBits(4294967295|0,2147483647|0);goog.math.Long.MIN_VALUE=goog.math.Long.fromBits(0,2147483648|0);goog.math.Long.TWO_PWR_24_=goog.math.Long.fromInt(1<<24);goog.math.Long.prototype.toInt=(function(){return this.low_});goog.math.Long.prototype.toNumber=(function(){return this.high_*goog.math.Long.TWO_PWR_32_DBL_+this.getLowBitsUnsigned()});goog.math.Long.prototype.toString=(function(opt_radix){var radix=opt_radix||10;if(radix<2||36<radix){throw Error("radix out of range: "+radix)}if(this.isZero()){return"0"}if(this.isNegative()){if(this.equals(goog.math.Long.MIN_VALUE)){var radixLong=goog.math.Long.fromNumber(radix);var div=this.div(radixLong);var rem=div.multiply(radixLong).subtract(this);return div.toString(radix)+rem.toInt().toString(radix)}else{return"-"+this.negate().toString(radix)}}var radixToPower=goog.math.Long.fromNumber(Math.pow(radix,6));var rem=this;var result="";while(true){var remDiv=rem.div(radixToPower);var intval=rem.subtract(remDiv.multiply(radixToPower)).toInt();var digits=intval.toString(radix);rem=remDiv;if(rem.isZero()){return digits+result}else{while(digits.length<6){digits="0"+digits}result=""+digits+result}}});goog.math.Long.prototype.getHighBits=(function(){return this.high_});goog.math.Long.prototype.getLowBits=(function(){return this.low_});goog.math.Long.prototype.getLowBitsUnsigned=(function(){return this.low_>=0?this.low_:goog.math.Long.TWO_PWR_32_DBL_+this.low_});goog.math.Long.prototype.getNumBitsAbs=(function(){if(this.isNegative()){if(this.equals(goog.math.Long.MIN_VALUE)){return 64}else{return this.negate().getNumBitsAbs()}}else{var val=this.high_!=0?this.high_:this.low_;for(var bit=31;bit>0;bit--){if((val&1<<bit)!=0){break}}return this.high_!=0?bit+33:bit+1}});goog.math.Long.prototype.isZero=(function(){return this.high_==0&&this.low_==0});goog.math.Long.prototype.isNegative=(function(){return this.high_<0});goog.math.Long.prototype.isOdd=(function(){return(this.low_&1)==1});goog.math.Long.prototype.equals=(function(other){return this.high_==other.high_&&this.low_==other.low_});goog.math.Long.prototype.notEquals=(function(other){return this.high_!=other.high_||this.low_!=other.low_});goog.math.Long.prototype.lessThan=(function(other){return this.compare(other)<0});goog.math.Long.prototype.lessThanOrEqual=(function(other){return this.compare(other)<=0});goog.math.Long.prototype.greaterThan=(function(other){return this.compare(other)>0});goog.math.Long.prototype.greaterThanOrEqual=(function(other){return this.compare(other)>=0});goog.math.Long.prototype.compare=(function(other){if(this.equals(other)){return 0}var thisNeg=this.isNegative();var otherNeg=other.isNegative();if(thisNeg&&!otherNeg){return-1}if(!thisNeg&&otherNeg){return 1}if(this.subtract(other).isNegative()){return-1}else{return 1}});goog.math.Long.prototype.negate=(function(){if(this.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.MIN_VALUE}else{return this.not().add(goog.math.Long.ONE)}});goog.math.Long.prototype.add=(function(other){var a48=this.high_>>>16;var a32=this.high_&65535;var a16=this.low_>>>16;var a00=this.low_&65535;var b48=other.high_>>>16;var b32=other.high_&65535;var b16=other.low_>>>16;var b00=other.low_&65535;var c48=0,c32=0,c16=0,c00=0;c00+=a00+b00;c16+=c00>>>16;c00&=65535;c16+=a16+b16;c32+=c16>>>16;c16&=65535;c32+=a32+b32;c48+=c32>>>16;c32&=65535;c48+=a48+b48;c48&=65535;return goog.math.Long.fromBits(c16<<16|c00,c48<<16|c32)});goog.math.Long.prototype.subtract=(function(other){return this.add(other.negate())});goog.math.Long.prototype.multiply=(function(other){if(this.isZero()){return goog.math.Long.ZERO}else if(other.isZero()){return goog.math.Long.ZERO}if(this.equals(goog.math.Long.MIN_VALUE)){return other.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO}else if(other.equals(goog.math.Long.MIN_VALUE)){return this.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO}if(this.isNegative()){if(other.isNegative()){return this.negate().multiply(other.negate())}else{return this.negate().multiply(other).negate()}}else if(other.isNegative()){return this.multiply(other.negate()).negate()}if(this.lessThan(goog.math.Long.TWO_PWR_24_)&&other.lessThan(goog.math.Long.TWO_PWR_24_)){return goog.math.Long.fromNumber(this.toNumber()*other.toNumber())}var a48=this.high_>>>16;var a32=this.high_&65535;var a16=this.low_>>>16;var a00=this.low_&65535;var b48=other.high_>>>16;var b32=other.high_&65535;var b16=other.low_>>>16;var b00=other.low_&65535;var c48=0,c32=0,c16=0,c00=0;c00+=a00*b00;c16+=c00>>>16;c00&=65535;c16+=a16*b00;c32+=c16>>>16;c16&=65535;c16+=a00*b16;c32+=c16>>>16;c16&=65535;c32+=a32*b00;c48+=c32>>>16;c32&=65535;c32+=a16*b16;c48+=c32>>>16;c32&=65535;c32+=a00*b32;c48+=c32>>>16;c32&=65535;c48+=a48*b00+a32*b16+a16*b32+a00*b48;c48&=65535;return goog.math.Long.fromBits(c16<<16|c00,c48<<16|c32)});goog.math.Long.prototype.div=(function(other){if(other.isZero()){throw Error("division by zero")}else if(this.isZero()){return goog.math.Long.ZERO}if(this.equals(goog.math.Long.MIN_VALUE)){if(other.equals(goog.math.Long.ONE)||other.equals(goog.math.Long.NEG_ONE)){return goog.math.Long.MIN_VALUE}else if(other.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.ONE}else{var halfThis=this.shiftRight(1);var approx=halfThis.div(other).shiftLeft(1);if(approx.equals(goog.math.Long.ZERO)){return other.isNegative()?goog.math.Long.ONE:goog.math.Long.NEG_ONE}else{var rem=this.subtract(other.multiply(approx));var result=approx.add(rem.div(other));return result}}}else if(other.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.ZERO}if(this.isNegative()){if(other.isNegative()){return this.negate().div(other.negate())}else{return this.negate().div(other).negate()}}else if(other.isNegative()){return this.div(other.negate()).negate()}var res=goog.math.Long.ZERO;var rem=this;while(rem.greaterThanOrEqual(other)){var approx=Math.max(1,Math.floor(rem.toNumber()/other.toNumber()));var log2=Math.ceil(Math.log(approx)/Math.LN2);var delta=log2<=48?1:Math.pow(2,log2-48);var approxRes=goog.math.Long.fromNumber(approx);var approxRem=approxRes.multiply(other);while(approxRem.isNegative()||approxRem.greaterThan(rem)){approx-=delta;approxRes=goog.math.Long.fromNumber(approx);approxRem=approxRes.multiply(other)}if(approxRes.isZero()){approxRes=goog.math.Long.ONE}res=res.add(approxRes);rem=rem.subtract(approxRem)}return res});goog.math.Long.prototype.modulo=(function(other){return this.subtract(this.div(other).multiply(other))});goog.math.Long.prototype.not=(function(){return goog.math.Long.fromBits(~this.low_,~this.high_)});goog.math.Long.prototype.and=(function(other){return goog.math.Long.fromBits(this.low_&other.low_,this.high_&other.high_)});goog.math.Long.prototype.or=(function(other){return goog.math.Long.fromBits(this.low_|other.low_,this.high_|other.high_)});goog.math.Long.prototype.xor=(function(other){return goog.math.Long.fromBits(this.low_^other.low_,this.high_^other.high_)});goog.math.Long.prototype.shiftLeft=(function(numBits){numBits&=63;if(numBits==0){return this}else{var low=this.low_;if(numBits<32){var high=this.high_;return goog.math.Long.fromBits(low<<numBits,high<<numBits|low>>>32-numBits)}else{return goog.math.Long.fromBits(0,low<<numBits-32)}}});goog.math.Long.prototype.shiftRight=(function(numBits){numBits&=63;if(numBits==0){return this}else{var high=this.high_;if(numBits<32){var low=this.low_;return goog.math.Long.fromBits(low>>>numBits|high<<32-numBits,high>>numBits)}else{return goog.math.Long.fromBits(high>>numBits-32,high>=0?0:-1)}}});goog.math.Long.prototype.shiftRightUnsigned=(function(numBits){numBits&=63;if(numBits==0){return this}else{var high=this.high_;if(numBits<32){var low=this.low_;return goog.math.Long.fromBits(low>>>numBits|high<<32-numBits,high>>>numBits)}else if(numBits==32){return goog.math.Long.fromBits(high,0)}else{return goog.math.Long.fromBits(high>>>numBits-32,0)}}});var navigator={appName:"Modern Browser"};var dbits;var canary=0xdeadbeefcafe;var j_lm=(canary&16777215)==15715070;function BigInteger(a,b,c){if(a!=null)if("number"==typeof a)this.fromNumber(a,b,c);else if(b==null&&"string"!=typeof a)this.fromString(a,256);else this.fromString(a,b)}function nbi(){return new BigInteger(null)}function am1(i,x,w,j,c,n){while(--n>=0){var v=x*this[i++]+w[j]+c;c=Math.floor(v/67108864);w[j++]=v&67108863}return c}function am2(i,x,w,j,c,n){var xl=x&32767,xh=x>>15;while(--n>=0){var l=this[i]&32767;var h=this[i++]>>15;var m=xh*l+h*xl;l=xl*l+((m&32767)<<15)+w[j]+(c&1073741823);c=(l>>>30)+(m>>>15)+xh*h+(c>>>30);w[j++]=l&1073741823}return c}function am3(i,x,w,j,c,n){var xl=x&16383,xh=x>>14;while(--n>=0){var l=this[i]&16383;var h=this[i++]>>14;var m=xh*l+h*xl;l=xl*l+((m&16383)<<14)+w[j]+c;c=(l>>28)+(m>>14)+xh*h;w[j++]=l&268435455}return c}if(j_lm&&navigator.appName=="Microsoft Internet Explorer"){BigInteger.prototype.am=am2;dbits=30}else if(j_lm&&navigator.appName!="Netscape"){BigInteger.prototype.am=am1;dbits=26}else{BigInteger.prototype.am=am3;dbits=28}BigInteger.prototype.DB=dbits;BigInteger.prototype.DM=(1<<dbits)-1;BigInteger.prototype.DV=1<<dbits;var BI_FP=52;BigInteger.prototype.FV=Math.pow(2,BI_FP);BigInteger.prototype.F1=BI_FP-dbits;BigInteger.prototype.F2=2*dbits-BI_FP;var BI_RM="0123456789abcdefghijklmnopqrstuvwxyz";var BI_RC=new Array;var rr,vv;rr="0".charCodeAt(0);for(vv=0;vv<=9;++vv)BI_RC[rr++]=vv;rr="a".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;rr="A".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;function int2char(n){return BI_RM.charAt(n)}function intAt(s,i){var c=BI_RC[s.charCodeAt(i)];return c==null?-1:c}function bnpCopyTo(r){for(var i=this.t-1;i>=0;--i)r[i]=this[i];r.t=this.t;r.s=this.s}function bnpFromInt(x){this.t=1;this.s=x<0?-1:0;if(x>0)this[0]=x;else if(x<-1)this[0]=x+DV;else this.t=0}function nbv(i){var r=nbi();r.fromInt(i);return r}function bnpFromString(s,b){var k;if(b==16)k=4;else if(b==8)k=3;else if(b==256)k=8;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else{this.fromRadix(s,b);return}this.t=0;this.s=0;var i=s.length,mi=false,sh=0;while(--i>=0){var x=k==8?s[i]&255:intAt(s,i);if(x<0){if(s.charAt(i)=="-")mi=true;continue}mi=false;if(sh==0)this[this.t++]=x;else if(sh+k>this.DB){this[this.t-1]|=(x&(1<<this.DB-sh)-1)<<sh;this[this.t++]=x>>this.DB-sh}else this[this.t-1]|=x<<sh;sh+=k;if(sh>=this.DB)sh-=this.DB}if(k==8&&(s[0]&128)!=0){this.s=-1;if(sh>0)this[this.t-1]|=(1<<this.DB-sh)-1<<sh}this.clamp();if(mi)BigInteger.ZERO.subTo(this,this)}function bnpClamp(){var c=this.s&this.DM;while(this.t>0&&this[this.t-1]==c)--this.t}function bnToString(b){if(this.s<0)return"-"+this.negate().toString(b);var k;if(b==16)k=4;else if(b==8)k=3;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else return this.toRadix(b);var km=(1<<k)-1,d,m=false,r="",i=this.t;var p=this.DB-i*this.DB%k;if(i-->0){if(p<this.DB&&(d=this[i]>>p)>0){m=true;r=int2char(d)}while(i>=0){if(p<k){d=(this[i]&(1<<p)-1)<<k-p;d|=this[--i]>>(p+=this.DB-k)}else{d=this[i]>>(p-=k)&km;if(p<=0){p+=this.DB;--i}}if(d>0)m=true;if(m)r+=int2char(d)}}return m?r:"0"}function bnNegate(){var r=nbi();BigInteger.ZERO.subTo(this,r);return r}function bnAbs(){return this.s<0?this.negate():this}function bnCompareTo(a){var r=this.s-a.s;if(r!=0)return r;var i=this.t;r=i-a.t;if(r!=0)return this.s<0?-r:r;while(--i>=0)if((r=this[i]-a[i])!=0)return r;return 0}function nbits(x){var r=1,t;if((t=x>>>16)!=0){x=t;r+=16}if((t=x>>8)!=0){x=t;r+=8}if((t=x>>4)!=0){x=t;r+=4}if((t=x>>2)!=0){x=t;r+=2}if((t=x>>1)!=0){x=t;r+=1}return r}function bnBitLength(){if(this.t<=0)return 0;return this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)}function bnpDLShiftTo(n,r){var i;for(i=this.t-1;i>=0;--i)r[i+n]=this[i];for(i=n-1;i>=0;--i)r[i]=0;r.t=this.t+n;r.s=this.s}function bnpDRShiftTo(n,r){for(var i=n;i<this.t;++i)r[i-n]=this[i];r.t=Math.max(this.t-n,0);r.s=this.s}function bnpLShiftTo(n,r){var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<cbs)-1;var ds=Math.floor(n/this.DB),c=this.s<<bs&this.DM,i;for(i=this.t-1;i>=0;--i){r[i+ds+1]=this[i]>>cbs|c;c=(this[i]&bm)<<bs}for(i=ds-1;i>=0;--i)r[i]=0;r[ds]=c;r.t=this.t+ds+1;r.s=this.s;r.clamp()}function bnpRShiftTo(n,r){r.s=this.s;var ds=Math.floor(n/this.DB);if(ds>=this.t){r.t=0;return}var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<bs)-1;r[0]=this[ds]>>bs;for(var i=ds+1;i<this.t;++i){r[i-ds-1]|=(this[i]&bm)<<cbs;r[i-ds]=this[i]>>bs}if(bs>0)r[this.t-ds-1]|=(this.s&bm)<<cbs;r.t=this.t-ds;r.clamp()}function bnpSubTo(a,r){var i=0,c=0,m=Math.min(a.t,this.t);while(i<m){c+=this[i]-a[i];r[i++]=c&this.DM;c>>=this.DB}if(a.t<this.t){c-=a.s;while(i<this.t){c+=this[i];r[i++]=c&this.DM;c>>=this.DB}c+=this.s}else{c+=this.s;while(i<a.t){c-=a[i];r[i++]=c&this.DM;c>>=this.DB}c-=a.s}r.s=c<0?-1:0;if(c<-1)r[i++]=this.DV+c;else if(c>0)r[i++]=c;r.t=i;r.clamp()}function bnpMultiplyTo(a,r){var x=this.abs(),y=a.abs();var i=x.t;r.t=i+y.t;while(--i>=0)r[i]=0;for(i=0;i<y.t;++i)r[i+x.t]=x.am(0,y[i],r,i,0,x.t);r.s=0;r.clamp();if(this.s!=a.s)BigInteger.ZERO.subTo(r,r)}function bnpSquareTo(r){var x=this.abs();var i=r.t=2*x.t;while(--i>=0)r[i]=0;for(i=0;i<x.t-1;++i){var c=x.am(i,x[i],r,2*i,0,1);if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1))>=x.DV){r[i+x.t]-=x.DV;r[i+x.t+1]=1}}if(r.t>0)r[r.t-1]+=x.am(i,x[i],r,2*i,0,1);r.s=0;r.clamp()}function bnpDivRemTo(m,q,r){var pm=m.abs();if(pm.t<=0)return;var pt=this.abs();if(pt.t<pm.t){if(q!=null)q.fromInt(0);if(r!=null)this.copyTo(r);return}if(r==null)r=nbi();var y=nbi(),ts=this.s,ms=m.s;var nsh=this.DB-nbits(pm[pm.t-1]);if(nsh>0){pm.lShiftTo(nsh,y);pt.lShiftTo(nsh,r)}else{pm.copyTo(y);pt.copyTo(r)}var ys=y.t;var y0=y[ys-1];if(y0==0)return;var yt=y0*(1<<this.F1)+(ys>1?y[ys-2]>>this.F2:0);var d1=this.FV/yt,d2=(1<<this.F1)/yt,e=1<<this.F2;var i=r.t,j=i-ys,t=q==null?nbi():q;y.dlShiftTo(j,t);if(r.compareTo(t)>=0){r[r.t++]=1;r.subTo(t,r)}BigInteger.ONE.dlShiftTo(ys,t);t.subTo(y,y);while(y.t<ys)y[y.t++]=0;while(--j>=0){var qd=r[--i]==y0?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);if((r[i]+=y.am(0,qd,r,j,0,ys))<qd){y.dlShiftTo(j,t);r.subTo(t,r);while(r[i]<--qd)r.subTo(t,r)}}if(q!=null){r.drShiftTo(ys,q);if(ts!=ms)BigInteger.ZERO.subTo(q,q)}r.t=ys;r.clamp();if(nsh>0)r.rShiftTo(nsh,r);if(ts<0)BigInteger.ZERO.subTo(r,r)}function bnMod(a){var r=nbi();this.abs().divRemTo(a,null,r);if(this.s<0&&r.compareTo(BigInteger.ZERO)>0)a.subTo(r,r);return r}function Classic(m){this.m=m}function cConvert(x){if(x.s<0||x.compareTo(this.m)>=0)return x.mod(this.m);else return x}function cRevert(x){return x}function cReduce(x){x.divRemTo(this.m,null,x)}function cMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r)}function cSqrTo(x,r){x.squareTo(r);this.reduce(r)}Classic.prototype.convert=cConvert;Classic.prototype.revert=cRevert;Classic.prototype.reduce=cReduce;Classic.prototype.mulTo=cMulTo;Classic.prototype.sqrTo=cSqrTo;function bnpInvDigit(){if(this.t<1)return 0;var x=this[0];if((x&1)==0)return 0;var y=x&3;y=y*(2-(x&15)*y)&15;y=y*(2-(x&255)*y)&255;y=y*(2-((x&65535)*y&65535))&65535;y=y*(2-x*y%this.DV)%this.DV;return y>0?this.DV-y:-y}function Montgomery(m){this.m=m;this.mp=m.invDigit();this.mpl=this.mp&32767;this.mph=this.mp>>15;this.um=(1<<m.DB-15)-1;this.mt2=2*m.t}function montConvert(x){var r=nbi();x.abs().dlShiftTo(this.m.t,r);r.divRemTo(this.m,null,r);if(x.s<0&&r.compareTo(BigInteger.ZERO)>0)this.m.subTo(r,r);return r}function montRevert(x){var r=nbi();x.copyTo(r);this.reduce(r);return r}function montReduce(x){while(x.t<=this.mt2)x[x.t++]=0;for(var i=0;i<this.m.t;++i){var j=x[i]&32767;var u0=j*this.mpl+((j*this.mph+(x[i]>>15)*this.mpl&this.um)<<15)&x.DM;j=i+this.m.t;x[j]+=this.m.am(0,u0,x,i,0,this.m.t);while(x[j]>=x.DV){x[j]-=x.DV;x[++j]++}}x.clamp();x.drShiftTo(this.m.t,x);if(x.compareTo(this.m)>=0)x.subTo(this.m,x)}function montSqrTo(x,r){x.squareTo(r);this.reduce(r)}function montMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r)}Montgomery.prototype.convert=montConvert;Montgomery.prototype.revert=montRevert;Montgomery.prototype.reduce=montReduce;Montgomery.prototype.mulTo=montMulTo;Montgomery.prototype.sqrTo=montSqrTo;function bnpIsEven(){return(this.t>0?this[0]&1:this.s)==0}function bnpExp(e,z){if(e>4294967295||e<1)return BigInteger.ONE;var r=nbi(),r2=nbi(),g=z.convert(this),i=nbits(e)-1;g.copyTo(r);while(--i>=0){z.sqrTo(r,r2);if((e&1<<i)>0)z.mulTo(r2,g,r);else{var t=r;r=r2;r2=t}}return z.revert(r)}function bnModPowInt(e,m){var z;if(e<256||m.isEven())z=new Classic(m);else z=new Montgomery(m);return this.exp(e,z)}BigInteger.prototype.copyTo=bnpCopyTo;BigInteger.prototype.fromInt=bnpFromInt;BigInteger.prototype.fromString=bnpFromString;BigInteger.prototype.clamp=bnpClamp;BigInteger.prototype.dlShiftTo=bnpDLShiftTo;BigInteger.prototype.drShiftTo=bnpDRShiftTo;BigInteger.prototype.lShiftTo=bnpLShiftTo;BigInteger.prototype.rShiftTo=bnpRShiftTo;BigInteger.prototype.subTo=bnpSubTo;BigInteger.prototype.multiplyTo=bnpMultiplyTo;BigInteger.prototype.squareTo=bnpSquareTo;BigInteger.prototype.divRemTo=bnpDivRemTo;BigInteger.prototype.invDigit=bnpInvDigit;BigInteger.prototype.isEven=bnpIsEven;BigInteger.prototype.exp=bnpExp;BigInteger.prototype.toString=bnToString;BigInteger.prototype.negate=bnNegate;BigInteger.prototype.abs=bnAbs;BigInteger.prototype.compareTo=bnCompareTo;BigInteger.prototype.bitLength=bnBitLength;BigInteger.prototype.mod=bnMod;BigInteger.prototype.modPowInt=bnModPowInt;BigInteger.ZERO=nbv(0);BigInteger.ONE=nbv(1);function bnpFromRadix(s,b){this.fromInt(0);if(b==null)b=10;var cs=this.chunkSize(b);var d=Math.pow(b,cs),mi=false,j=0,w=0;for(var i=0;i<s.length;++i){var x=intAt(s,i);if(x<0){if(s.charAt(i)=="-"&&this.signum()==0)mi=true;continue}w=b*w+x;if(++j>=cs){this.dMultiply(d);this.dAddOffset(w,0);j=0;w=0}}if(j>0){this.dMultiply(Math.pow(b,j));this.dAddOffset(w,0)}if(mi)BigInteger.ZERO.subTo(this,this)}function bnpChunkSize(r){return Math.floor(Math.LN2*this.DB/Math.log(r))}function bnSigNum(){if(this.s<0)return-1;else if(this.t<=0||this.t==1&&this[0]<=0)return 0;else return 1}function bnpDMultiply(n){this[this.t]=this.am(0,n-1,this,0,0,this.t);++this.t;this.clamp()}function bnpDAddOffset(n,w){if(n==0)return;while(this.t<=w)this[this.t++]=0;this[w]+=n;while(this[w]>=this.DV){this[w]-=this.DV;if(++w>=this.t)this[this.t++]=0;++this[w]}}function bnpToRadix(b){if(b==null)b=10;if(this.signum()==0||b<2||b>36)return"0";var cs=this.chunkSize(b);var a=Math.pow(b,cs);var d=nbv(a),y=nbi(),z=nbi(),r="";this.divRemTo(d,y,z);while(y.signum()>0){r=(a+z.intValue()).toString(b).substr(1)+r;y.divRemTo(d,y,z)}return z.intValue().toString(b)+r}function bnIntValue(){if(this.s<0){if(this.t==1)return this[0]-this.DV;else if(this.t==0)return-1}else if(this.t==1)return this[0];else if(this.t==0)return 0;return(this[1]&(1<<32-this.DB)-1)<<this.DB|this[0]}function bnpAddTo(a,r){var i=0,c=0,m=Math.min(a.t,this.t);while(i<m){c+=this[i]+a[i];r[i++]=c&this.DM;c>>=this.DB}if(a.t<this.t){c+=a.s;while(i<this.t){c+=this[i];r[i++]=c&this.DM;c>>=this.DB}c+=this.s}else{c+=this.s;while(i<a.t){c+=a[i];r[i++]=c&this.DM;c>>=this.DB}c+=a.s}r.s=c<0?-1:0;if(c>0)r[i++]=c;else if(c<-1)r[i++]=this.DV+c;r.t=i;r.clamp()}BigInteger.prototype.fromRadix=bnpFromRadix;BigInteger.prototype.chunkSize=bnpChunkSize;BigInteger.prototype.signum=bnSigNum;BigInteger.prototype.dMultiply=bnpDMultiply;BigInteger.prototype.dAddOffset=bnpDAddOffset;BigInteger.prototype.toRadix=bnpToRadix;BigInteger.prototype.intValue=bnIntValue;BigInteger.prototype.addTo=bnpAddTo;var Wrapper={abs:(function(l,h){var x=new goog.math.Long(l,h);var ret;if(x.isNegative()){ret=x.negate()}else{ret=x}HEAP32[tempDoublePtr>>2]=ret.low_;HEAP32[tempDoublePtr+4>>2]=ret.high_}),ensureTemps:(function(){if(Wrapper.ensuredTemps)return;Wrapper.ensuredTemps=true;Wrapper.two32=new BigInteger;Wrapper.two32.fromString("4294967296",10);Wrapper.two64=new BigInteger;Wrapper.two64.fromString("18446744073709551616",10);Wrapper.temp1=new BigInteger;Wrapper.temp2=new BigInteger}),lh2bignum:(function(l,h){var a=new BigInteger;a.fromString(h.toString(),10);var b=new BigInteger;a.multiplyTo(Wrapper.two32,b);var c=new BigInteger;c.fromString(l.toString(),10);var d=new BigInteger;c.addTo(b,d);return d}),stringify:(function(l,h,unsigned){var ret=(new goog.math.Long(l,h)).toString();if(unsigned&&ret[0]=="-"){Wrapper.ensureTemps();var bignum=new BigInteger;bignum.fromString(ret,10);ret=new BigInteger;Wrapper.two64.addTo(bignum,ret);ret=ret.toString(10)}return ret}),fromString:(function(str,base,min,max,unsigned){Wrapper.ensureTemps();var bignum=new BigInteger;bignum.fromString(str,base);var bigmin=new BigInteger;bigmin.fromString(min,10);var bigmax=new BigInteger;bigmax.fromString(max,10);if(unsigned&&bignum.compareTo(BigInteger.ZERO)<0){var temp=new BigInteger;bignum.addTo(Wrapper.two64,temp);bignum=temp}var error=false;if(bignum.compareTo(bigmin)<0){bignum=bigmin;error=true}else if(bignum.compareTo(bigmax)>0){bignum=bigmax;error=true}var ret=goog.math.Long.fromString(bignum.toString());HEAP32[tempDoublePtr>>2]=ret.low_;HEAP32[tempDoublePtr+4>>2]=ret.high_;if(error)throw"range error"})};return Wrapper})();function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;var initialStackTop;var preloadStartTime=null;var calledMain=false;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};Module["callMain"]=Module.callMain=function callMain(args){assert(runDependencies==0,"cannot call main when async dependencies remain! (listen on __ATMAIN__)");assert(__ATPRERUN__.length==0,"cannot call main when preRun functions remain to be called");args=args||[];ensureInitRuntime();var argc=args.length+1;function pad(){for(var i=0;i<4-1;i++){argv.push(0)}}var argv=[allocate(intArrayFromString(Module["thisProgram"]),"i8",ALLOC_NORMAL)];pad();for(var i=0;i<argc-1;i=i+1){argv.push(allocate(intArrayFromString(args[i]),"i8",ALLOC_NORMAL));pad()}argv.push(0);argv=allocate(argv,"i32",ALLOC_NORMAL);initialStackTop=STACKTOP;try{var ret=Module["_main"](argc,argv,0);exit(ret,true)}catch(e){if(e instanceof ExitStatus){return}else if(e=="SimulateInfiniteLoop"){Module["noExitRuntime"]=true;return}else{if(e&&typeof e==="object"&&e.stack)Module.printErr("exception thrown: "+[e,e.stack]);throw e}}finally{calledMain=true}};function run(args){args=args||Module["arguments"];if(preloadStartTime===null)preloadStartTime=Date.now();if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(ENVIRONMENT_IS_WEB&&preloadStartTime!==null){Module.printErr("pre-main prep time: "+(Date.now()-preloadStartTime)+" ms")}if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(Module["_main"]&&shouldRunNow)Module["callMain"](args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=Module.run=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["stdout"]["once"]("drain",(function(){process["exit"](status)}));console.log(" ");setTimeout((function(){process["exit"](status)}),500)}else if(ENVIRONMENT_IS_SHELL&&typeof quit==="function"){quit(status)}throw new ExitStatus(status)}Module["exit"]=Module.exit=exit;var abortDecorators=[];function abort(what){if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;var extra="\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.";var output="abort("+what+") at "+stackTrace()+extra;if(abortDecorators){abortDecorators.forEach((function(decorator){output=decorator(output,what)}))}throw output}Module["abort"]=Module.abort=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=false;if(Module["noInitialRun"]){shouldRunNow=false}Module["noExitRuntime"]=true;run();var inputBuffer,inputBufferSize;function reallocInputBuffer(size){if(inputBuffer&&inputBufferSize>=size){return inputBuffer}if(inputBuffer){Module._free(inputBuffer)}inputBufferSize=size;inputBuffer=Module._malloc(inputBufferSize);return inputBuffer}Module.loadedMetadata=!!options.videoFormat;Module.videoFormat=options.videoFormat||null;Module.frameBuffer=null;Object.defineProperty(Module,"processing",{get:function getProcessing(){return false}});Module.init=(function(callback){Module._ogv_video_decoder_init();callback()});Module.processHeader=(function(data,callback){var len=data.byteLength;var buffer=reallocInputBuffer(len);Module.HEAPU8.set(new Uint8Array(data),buffer);var ret=Module._ogv_video_decoder_process_header(buffer,len);callback(ret)});Module.processFrame=(function(data,callback){var len=data.byteLength;var buffer=reallocInputBuffer(len);Module.HEAPU8.set(new Uint8Array(data),buffer);var ret=Module._ogv_video_decoder_process_frame(buffer,len);callback(ret)})
+
+
+
+
+
+ return Module;
+};
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-demuxer-ogg.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-demuxer-ogg.js
new file mode 100644
index 00000000..13c6c731
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-demuxer-ogg.js
@@ -0,0 +1,23 @@
+var OGVDemuxerOgg = function(Module) {
+ Module = Module || {};
+
+var options=Module;Module={print:(function(str){console.log(str)})};var Module;if(!Module)Module=(typeof OGVDemuxerOgg!=="undefined"?OGVDemuxerOgg:null)||{};var moduleOverrides={};for(var key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var ENVIRONMENT_IS_WEB=typeof window==="object";var ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB;var ENVIRONMENT_IS_WORKER=typeof importScripts==="function";var ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(ENVIRONMENT_IS_NODE){if(!Module["print"])Module["print"]=function print(x){process["stdout"].write(x+"\n")};if(!Module["printErr"])Module["printErr"]=function printErr(x){process["stderr"].write(x+"\n")};var nodeFS=require("fs");var nodePath=require("path");Module["read"]=function read(filename,binary){filename=nodePath["normalize"](filename);var ret=nodeFS["readFileSync"](filename);if(!ret&&filename!=nodePath["resolve"](filename)){filename=path.join(__dirname,"..","src",filename);ret=nodeFS["readFileSync"](filename)}if(ret&&!binary)ret=ret.toString();return ret};Module["readBinary"]=function readBinary(filename){return Module["read"](filename,true)};Module["load"]=function load(f){globalEval(read(f))};if(!Module["thisProgram"]){if(process["argv"].length>1){Module["thisProgram"]=process["argv"][1].replace(/\\/g,"/")}else{Module["thisProgram"]="unknown-program"}}Module["arguments"]=process["argv"].slice(2);if(typeof module!=="undefined"){module["exports"]=Module}process["on"]("uncaughtException",(function(ex){if(!(ex instanceof ExitStatus)){throw ex}}));Module["inspect"]=(function(){return"[Emscripten Module object]"})}else if(ENVIRONMENT_IS_SHELL){if(!Module["print"])Module["print"]=print;if(typeof printErr!="undefined")Module["printErr"]=printErr;if(typeof read!="undefined"){Module["read"]=read}else{Module["read"]=function read(){throw"no read() available (jsc?)"}}Module["readBinary"]=function readBinary(f){if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}var data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){Module["arguments"]=scriptArgs}else if(typeof arguments!="undefined"){Module["arguments"]=arguments}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){Module["read"]=function read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(typeof arguments!="undefined"){Module["arguments"]=arguments}if(typeof console!=="undefined"){if(!Module["print"])Module["print"]=function print(x){console.log(x)};if(!Module["printErr"])Module["printErr"]=function printErr(x){console.log(x)}}else{var TRY_USE_DUMP=false;if(!Module["print"])Module["print"]=TRY_USE_DUMP&&typeof dump!=="undefined"?(function(x){dump(x)}):(function(x){})}if(ENVIRONMENT_IS_WORKER){Module["load"]=importScripts}if(typeof Module["setWindowTitle"]==="undefined"){Module["setWindowTitle"]=(function(title){document.title=title})}}else{throw"Unknown runtime environment. Where are we?"}function globalEval(x){eval.call(null,x)}if(!Module["load"]&&Module["read"]){Module["load"]=function load(f){globalEval(Module["read"](f))}}if(!Module["print"]){Module["print"]=(function(){})}if(!Module["printErr"]){Module["printErr"]=Module["print"]}if(!Module["arguments"]){Module["arguments"]=[]}if(!Module["thisProgram"]){Module["thisProgram"]="./this.program"}Module.print=Module["print"];Module.printErr=Module["printErr"];Module["preRun"]=[];Module["postRun"]=[];for(var key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}var Runtime={setTempRet0:(function(value){tempRet0=value}),getTempRet0:(function(){return tempRet0}),stackSave:(function(){return STACKTOP}),stackRestore:(function(stackTop){STACKTOP=stackTop}),getNativeTypeSize:(function(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return Runtime.QUANTUM_SIZE}else if(type[0]==="i"){var bits=parseInt(type.substr(1));assert(bits%8===0);return bits/8}else{return 0}}}}),getNativeFieldSize:(function(type){return Math.max(Runtime.getNativeTypeSize(type),Runtime.QUANTUM_SIZE)}),STACK_ALIGN:16,prepVararg:(function(ptr,type){if(type==="double"||type==="i64"){if(ptr&7){assert((ptr&7)===4);ptr+=4}}else{assert((ptr&3)===0)}return ptr}),getAlignSize:(function(type,size,vararg){if(!vararg&&(type=="i64"||type=="double"))return 8;if(!type)return Math.min(size,8);return Math.min(size||(type?Runtime.getNativeFieldSize(type):0),Runtime.QUANTUM_SIZE)}),dynCall:(function(sig,ptr,args){if(args&&args.length){if(!args.splice)args=Array.prototype.slice.call(args);args.splice(0,0,ptr);return Module["dynCall_"+sig].apply(null,args)}else{return Module["dynCall_"+sig].call(null,ptr)}}),functionPointers:[],addFunction:(function(func){for(var i=0;i<Runtime.functionPointers.length;i++){if(!Runtime.functionPointers[i]){Runtime.functionPointers[i]=func;return 2*(1+i)}}throw"Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS."}),removeFunction:(function(index){Runtime.functionPointers[(index-2)/2]=null}),warnOnce:(function(text){if(!Runtime.warnOnce.shown)Runtime.warnOnce.shown={};if(!Runtime.warnOnce.shown[text]){Runtime.warnOnce.shown[text]=1;Module.printErr(text)}}),funcWrappers:{},getFuncWrapper:(function(func,sig){assert(sig);if(!Runtime.funcWrappers[sig]){Runtime.funcWrappers[sig]={}}var sigCache=Runtime.funcWrappers[sig];if(!sigCache[func]){sigCache[func]=function dynCall_wrapper(){return Runtime.dynCall(sig,func,arguments)}}return sigCache[func]}),getCompilerSetting:(function(name){throw"You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work"}),stackAlloc:(function(size){var ret=STACKTOP;STACKTOP=STACKTOP+size|0;STACKTOP=STACKTOP+15&-16;return ret}),staticAlloc:(function(size){var ret=STATICTOP;STATICTOP=STATICTOP+size|0;STATICTOP=STATICTOP+15&-16;return ret}),dynamicAlloc:(function(size){var ret=DYNAMICTOP;DYNAMICTOP=DYNAMICTOP+size|0;DYNAMICTOP=DYNAMICTOP+15&-16;if(DYNAMICTOP>=TOTAL_MEMORY){var success=enlargeMemory();if(!success){DYNAMICTOP=ret;return 0}}return ret}),alignMemory:(function(size,quantum){var ret=size=Math.ceil(size/(quantum?quantum:16))*(quantum?quantum:16);return ret}),makeBigInt:(function(low,high,unsigned){var ret=unsigned?+(low>>>0)+ +(high>>>0)*+4294967296:+(low>>>0)+ +(high|0)*+4294967296;return ret}),GLOBAL_BASE:8,QUANTUM_SIZE:4,__dummy__:0};Module["Runtime"]=Runtime;var __THREW__=0;var ABORT=false;var EXITSTATUS=0;var undef=0;var tempValue,tempInt,tempBigInt,tempInt2,tempBigInt2,tempPair,tempBigIntI,tempBigIntR,tempBigIntS,tempBigIntP,tempBigIntD,tempDouble,tempFloat;var tempI64,tempI64b;var tempRet0,tempRet1,tempRet2,tempRet3,tempRet4,tempRet5,tempRet6,tempRet7,tempRet8,tempRet9;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}var globalScope=this;function getCFunc(ident){var func=Module["_"+ident];if(!func){try{func=eval("_"+ident)}catch(e){}}assert(func,"Cannot call unknown function "+ident+" (perhaps LLVM optimizations or closure removed it?)");return func}var cwrap,ccall;((function(){var JSfuncs={"stackSave":(function(){Runtime.stackSave()}),"stackRestore":(function(){Runtime.stackRestore()}),"arrayToC":(function(arr){var ret=Runtime.stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}),"stringToC":(function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=Runtime.stackAlloc((str.length<<2)+1);writeStringToMemory(str,ret)}return ret})};var toC={"string":JSfuncs["stringToC"],"array":JSfuncs["arrayToC"]};ccall=function ccallFunc(ident,returnType,argTypes,args,opts){var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=Runtime.stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func.apply(null,cArgs);if(returnType==="string")ret=Pointer_stringify(ret);if(stack!==0){if(opts&&opts.async){EmterpreterAsync.asyncFinalizers.push((function(){Runtime.stackRestore(stack)}));return}Runtime.stackRestore(stack)}return ret};var sourceRegex=/^function\s*\(([^)]*)\)\s*{\s*([^*]*?)[\s;]*(?:return\s*(.*?)[;\s]*)?}$/;function parseJSFunc(jsfunc){var parsed=jsfunc.toString().match(sourceRegex).slice(1);return{arguments:parsed[0],body:parsed[1],returnValue:parsed[2]}}var JSsource={};for(var fun in JSfuncs){if(JSfuncs.hasOwnProperty(fun)){JSsource[fun]=parseJSFunc(JSfuncs[fun])}}cwrap=function cwrap(ident,returnType,argTypes){argTypes=argTypes||[];var cfunc=getCFunc(ident);var numericArgs=argTypes.every((function(type){return type==="number"}));var numericRet=returnType!=="string";if(numericRet&&numericArgs){return cfunc}var argNames=argTypes.map((function(x,i){return"$"+i}));var funcstr="(function("+argNames.join(",")+") {";var nargs=argTypes.length;if(!numericArgs){funcstr+="var stack = "+JSsource["stackSave"].body+";";for(var i=0;i<nargs;i++){var arg=argNames[i],type=argTypes[i];if(type==="number")continue;var convertCode=JSsource[type+"ToC"];funcstr+="var "+convertCode.arguments+" = "+arg+";";funcstr+=convertCode.body+";";funcstr+=arg+"="+convertCode.returnValue+";"}}var cfuncname=parseJSFunc((function(){return cfunc})).returnValue;funcstr+="var ret = "+cfuncname+"("+argNames.join(",")+");";if(!numericRet){var strgfy=parseJSFunc((function(){return Pointer_stringify})).returnValue;funcstr+="ret = "+strgfy+"(ret);"}if(!numericArgs){funcstr+=JSsource["stackRestore"].body.replace("()","(stack)")+";"}funcstr+="return ret})";return eval(funcstr)}}))();Module["cwrap"]=cwrap;Module["ccall"]=ccall;function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=+1?tempDouble>+0?(Math_min(+Math_floor(tempDouble/+4294967296),+4294967295)|0)>>>0:~~+Math_ceil((tempDouble- +(~~tempDouble>>>0))/+4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}Module["setValue"]=setValue;function getValue(ptr,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP32[ptr>>2];case"float":return HEAPF32[ptr>>2];case"double":return HEAPF64[ptr>>3];default:abort("invalid type for setValue: "+type)}return null}Module["getValue"]=getValue;var ALLOC_NORMAL=0;var ALLOC_STACK=1;var ALLOC_STATIC=2;var ALLOC_DYNAMIC=3;var ALLOC_NONE=4;Module["ALLOC_NORMAL"]=ALLOC_NORMAL;Module["ALLOC_STACK"]=ALLOC_STACK;Module["ALLOC_STATIC"]=ALLOC_STATIC;Module["ALLOC_DYNAMIC"]=ALLOC_DYNAMIC;Module["ALLOC_NONE"]=ALLOC_NONE;function allocate(slab,types,allocator,ptr){var zeroinit,size;if(typeof slab==="number"){zeroinit=true;size=slab}else{zeroinit=false;size=slab.length}var singleType=typeof types==="string"?types:null;var ret;if(allocator==ALLOC_NONE){ret=ptr}else{ret=[_malloc,Runtime.stackAlloc,Runtime.staticAlloc,Runtime.dynamicAlloc][allocator===undefined?ALLOC_STATIC:allocator](Math.max(size,singleType?1:types.length))}if(zeroinit){var ptr=ret,stop;assert((ret&3)==0);stop=ret+(size&~3);for(;ptr<stop;ptr+=4){HEAP32[ptr>>2]=0}stop=ret+size;while(ptr<stop){HEAP8[ptr++>>0]=0}return ret}if(singleType==="i8"){if(slab.subarray||slab.slice){HEAPU8.set(slab,ret)}else{HEAPU8.set(new Uint8Array(slab),ret)}return ret}var i=0,type,typeSize,previousType;while(i<size){var curr=slab[i];if(typeof curr==="function"){curr=Runtime.getFunctionIndex(curr)}type=singleType||types[i];if(type===0){i++;continue}if(type=="i64")type="i32";setValue(ret+i,curr,type);if(previousType!==type){typeSize=Runtime.getNativeTypeSize(type);previousType=type}i+=typeSize}return ret}Module["allocate"]=allocate;function getMemory(size){if(!staticSealed)return Runtime.staticAlloc(size);if(typeof _sbrk!=="undefined"&&!_sbrk.called||!runtimeInitialized)return Runtime.dynamicAlloc(size);return _malloc(size)}Module["getMemory"]=getMemory;function Pointer_stringify(ptr,length){if(length===0||!ptr)return"";var hasUtf=0;var t;var i=0;while(1){t=HEAPU8[ptr+i>>0];hasUtf|=t;if(t==0&&!length)break;i++;if(length&&i==length)break}if(!length)length=i;var ret="";if(hasUtf<128){var MAX_CHUNK=1024;var curr;while(length>0){curr=String.fromCharCode.apply(String,HEAPU8.subarray(ptr,ptr+Math.min(length,MAX_CHUNK)));ret=ret?ret+curr:curr;ptr+=MAX_CHUNK;length-=MAX_CHUNK}return ret}return Module["UTF8ToString"](ptr)}Module["Pointer_stringify"]=Pointer_stringify;function AsciiToString(ptr){var str="";while(1){var ch=HEAP8[ptr++>>0];if(!ch)return str;str+=String.fromCharCode(ch)}}Module["AsciiToString"]=AsciiToString;function stringToAscii(str,outPtr){return writeAsciiToMemory(str,outPtr,false)}Module["stringToAscii"]=stringToAscii;function UTF8ArrayToString(u8Array,idx){var u0,u1,u2,u3,u4,u5;var str="";while(1){u0=u8Array[idx++];if(!u0)return str;if(!(u0&128)){str+=String.fromCharCode(u0);continue}u1=u8Array[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}u2=u8Array[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u3=u8Array[idx++]&63;if((u0&248)==240){u0=(u0&7)<<18|u1<<12|u2<<6|u3}else{u4=u8Array[idx++]&63;if((u0&252)==248){u0=(u0&3)<<24|u1<<18|u2<<12|u3<<6|u4}else{u5=u8Array[idx++]&63;u0=(u0&1)<<30|u1<<24|u2<<18|u3<<12|u4<<6|u5}}}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}Module["UTF8ArrayToString"]=UTF8ArrayToString;function UTF8ToString(ptr){return UTF8ArrayToString(HEAPU8,ptr)}Module["UTF8ToString"]=UTF8ToString;function stringToUTF8Array(str,outU8Array,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){if(outIdx>=endIdx)break;outU8Array[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;outU8Array[outIdx++]=192|u>>6;outU8Array[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;outU8Array[outIdx++]=224|u>>12;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=2097151){if(outIdx+3>=endIdx)break;outU8Array[outIdx++]=240|u>>18;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else if(u<=67108863){if(outIdx+4>=endIdx)break;outU8Array[outIdx++]=248|u>>24;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}else{if(outIdx+5>=endIdx)break;outU8Array[outIdx++]=252|u>>30;outU8Array[outIdx++]=128|u>>24&63;outU8Array[outIdx++]=128|u>>18&63;outU8Array[outIdx++]=128|u>>12&63;outU8Array[outIdx++]=128|u>>6&63;outU8Array[outIdx++]=128|u&63}}outU8Array[outIdx]=0;return outIdx-startIdx}Module["stringToUTF8Array"]=stringToUTF8Array;function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}Module["stringToUTF8"]=stringToUTF8;function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127){++len}else if(u<=2047){len+=2}else if(u<=65535){len+=3}else if(u<=2097151){len+=4}else if(u<=67108863){len+=5}else{len+=6}}return len}Module["lengthBytesUTF8"]=lengthBytesUTF8;function UTF16ToString(ptr){var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0)return str;++i;str+=String.fromCharCode(codeUnit)}}Module["UTF16ToString"]=UTF16ToString;function stringToUTF16(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite<str.length*2?maxBytesToWrite/2:str.length;for(var i=0;i<numCharsToWrite;++i){var codeUnit=str.charCodeAt(i);HEAP16[outPtr>>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}Module["stringToUTF16"]=stringToUTF16;function lengthBytesUTF16(str){return str.length*2}Module["lengthBytesUTF16"]=lengthBytesUTF16;function UTF32ToString(ptr){var i=0;var str="";while(1){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)return str;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}}Module["UTF32ToString"]=UTF32ToString;function stringToUTF32(str,outPtr,maxBytesToWrite){if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i<str.length;++i){var codeUnit=str.charCodeAt(i);if(codeUnit>=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}Module["stringToUTF32"]=stringToUTF32;function lengthBytesUTF32(str){var len=0;for(var i=0;i<str.length;++i){var codeUnit=str.charCodeAt(i);if(codeUnit>=55296&&codeUnit<=57343)++i;len+=4}return len}Module["lengthBytesUTF32"]=lengthBytesUTF32;function demangle(func){var hasLibcxxabi=!!Module["___cxa_demangle"];if(hasLibcxxabi){try{var buf=_malloc(func.length);writeStringToMemory(func.substr(1),buf);var status=_malloc(4);var ret=Module["___cxa_demangle"](buf,0,0,status);if(getValue(status,"i32")===0&&ret){return Pointer_stringify(ret)}}catch(e){}finally{if(buf)_free(buf);if(status)_free(status);if(ret)_free(ret)}}var i=3;var basicTypes={"v":"void","b":"bool","c":"char","s":"short","i":"int","l":"long","f":"float","d":"double","w":"wchar_t","a":"signed char","h":"unsigned char","t":"unsigned short","j":"unsigned int","m":"unsigned long","x":"long long","y":"unsigned long long","z":"..."};var subs=[];var first=true;function dump(x){if(x)Module.print(x);Module.print(func);var pre="";for(var a=0;a<i;a++)pre+=" ";Module.print(pre+"^")}function parseNested(){i++;if(func[i]==="K")i++;var parts=[];while(func[i]!=="E"){if(func[i]==="S"){i++;var next=func.indexOf("_",i);var num=func.substring(i,next)||0;parts.push(subs[num]||"?");i=next+1;continue}if(func[i]==="C"){parts.push(parts[parts.length-1]);i+=2;continue}var size=parseInt(func.substr(i));var pre=size.toString().length;if(!size||!pre){i--;break}var curr=func.substr(i+pre,size);parts.push(curr);subs.push(curr);i+=pre+size}i++;return parts}function parse(rawList,limit,allowVoid){limit=limit||Infinity;var ret="",list=[];function flushList(){return"("+list.join(", ")+")"}var name;if(func[i]==="N"){name=parseNested().join("::");limit--;if(limit===0)return rawList?[name]:name}else{if(func[i]==="K"||first&&func[i]==="L")i++;var size=parseInt(func.substr(i));if(size){var pre=size.toString().length;name=func.substr(i+pre,size);i+=pre+size}}first=false;if(func[i]==="I"){i++;var iList=parse(true);var iRet=parse(true,1,true);ret+=iRet[0]+" "+name+"<"+iList.join(", ")+">"}else{ret=name}paramLoop:while(i<func.length&&limit-->0){var c=func[i++];if(c in basicTypes){list.push(basicTypes[c])}else{switch(c){case"P":list.push(parse(true,1,true)[0]+"*");break;case"R":list.push(parse(true,1,true)[0]+"&");break;case"L":{i++;var end=func.indexOf("E",i);var size=end-i;list.push(func.substr(i,size));i+=size+2;break};case"A":{var size=parseInt(func.substr(i));i+=size.toString().length;if(func[i]!=="_")throw"?";i++;list.push(parse(true,1,true)[0]+" ["+size+"]");break};case"E":break paramLoop;default:ret+="?"+c;break paramLoop}}}if(!allowVoid&&list.length===1&&list[0]==="void")list=[];if(rawList){if(ret){list.push(ret+"?")}return list}else{return ret+flushList()}}var parsed=func;try{if(func=="Object._main"||func=="_main"){return"main()"}if(typeof func==="number")func=Pointer_stringify(func);if(func[0]!=="_")return func;if(func[1]!=="_")return func;if(func[2]!=="Z")return func;switch(func[3]){case"n":return"operator new()";case"d":return"operator delete()"}parsed=parse()}catch(e){parsed+="?"}if(parsed.indexOf("?")>=0&&!hasLibcxxabi){Runtime.warnOnce("warning: a problem occurred in builtin C++ name demangling; build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling")}return parsed}function demangleAll(text){return text.replace(/__Z[\w\d_]+/g,(function(x){var y=demangle(x);return x===y?x:x+" ["+y+"]"}))}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error(0)}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){return demangleAll(jsStackTrace())}Module["stackTrace"]=stackTrace;var PAGE_SIZE=4096;function alignMemoryPage(x){if(x%4096>0){x+=4096-x%4096}return x}var HEAP;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;var STATIC_BASE=0,STATICTOP=0,staticSealed=false;var STACK_BASE=0,STACKTOP=0,STACK_MAX=0;var DYNAMIC_BASE=0,DYNAMICTOP=0;function enlargeMemory(){abort("Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value "+TOTAL_MEMORY+", (2) compile with ALLOW_MEMORY_GROWTH which adjusts the size at runtime but prevents some optimizations, or (3) set Module.TOTAL_MEMORY before the program runs.")}var TOTAL_STACK=Module["TOTAL_STACK"]||5242880;var TOTAL_MEMORY=Module["TOTAL_MEMORY"]||16777216;var totalMemory=64*1024;while(totalMemory<TOTAL_MEMORY||totalMemory<2*TOTAL_STACK){if(totalMemory<16*1024*1024){totalMemory*=2}else{totalMemory+=16*1024*1024}}if(totalMemory!==TOTAL_MEMORY){Module.printErr("increasing TOTAL_MEMORY to "+totalMemory+" to be compliant with the asm.js spec (and given that TOTAL_STACK="+TOTAL_STACK+")");TOTAL_MEMORY=totalMemory}assert(typeof Int32Array!=="undefined"&&typeof Float64Array!=="undefined"&&!!(new Int32Array(1))["subarray"]&&!!(new Int32Array(1))["set"],"JS engine does not provide full typed array support");var buffer;buffer=new ArrayBuffer(TOTAL_MEMORY);HEAP8=new Int8Array(buffer);HEAP16=new Int16Array(buffer);HEAP32=new Int32Array(buffer);HEAPU8=new Uint8Array(buffer);HEAPU16=new Uint16Array(buffer);HEAPU32=new Uint32Array(buffer);HEAPF32=new Float32Array(buffer);HEAPF64=new Float64Array(buffer);HEAP32[0]=255;assert(HEAPU8[0]===255&&HEAPU8[3]===0,"Typed arrays 2 must be run on a little-endian system");Module["HEAP"]=HEAP;Module["buffer"]=buffer;Module["HEAP8"]=HEAP8;Module["HEAP16"]=HEAP16;Module["HEAP32"]=HEAP32;Module["HEAPU8"]=HEAPU8;Module["HEAPU16"]=HEAPU16;Module["HEAPU32"]=HEAPU32;Module["HEAPF32"]=HEAPF32;Module["HEAPF64"]=HEAPF64;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback();continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Runtime.dynCall("v",func)}else{Runtime.dynCall("vi",func,[callback.arg])}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function ensureInitRuntime(){if(runtimeInitialized)return;runtimeInitialized=true;callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){callRuntimeCallbacks(__ATEXIT__);runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}Module["addOnPreRun"]=Module.addOnPreRun=addOnPreRun;function addOnInit(cb){__ATINIT__.unshift(cb)}Module["addOnInit"]=Module.addOnInit=addOnInit;function addOnPreMain(cb){__ATMAIN__.unshift(cb)}Module["addOnPreMain"]=Module.addOnPreMain=addOnPreMain;function addOnExit(cb){__ATEXIT__.unshift(cb)}Module["addOnExit"]=Module.addOnExit=addOnExit;function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}Module["addOnPostRun"]=Module.addOnPostRun=addOnPostRun;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}Module["intArrayFromString"]=intArrayFromString;function intArrayToString(array){var ret=[];for(var i=0;i<array.length;i++){var chr=array[i];if(chr>255){chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}Module["intArrayToString"]=intArrayToString;function writeStringToMemory(string,buffer,dontAddNull){var array=intArrayFromString(string,dontAddNull);var i=0;while(i<array.length){var chr=array[i];HEAP8[buffer+i>>0]=chr;i=i+1}}Module["writeStringToMemory"]=writeStringToMemory;function writeArrayToMemory(array,buffer){for(var i=0;i<array.length;i++){HEAP8[buffer++>>0]=array[i]}}Module["writeArrayToMemory"]=writeArrayToMemory;function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i<str.length;++i){HEAP8[buffer++>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}Module["writeAsciiToMemory"]=writeAsciiToMemory;function unSign(value,bits,ignore){if(value>=0){return value}return bits<=32?2*Math.abs(1<<bits-1)+value:Math.pow(2,bits)+value}function reSign(value,bits,ignore){if(value<=0){return value}var half=bits<=32?Math.abs(1<<bits-1):Math.pow(2,bits-1);if(value>=half&&(bits<=32||value>half)){value=-2*half+value}return value}if(!Math["imul"]||Math["imul"](4294967295,5)!==-5)Math["imul"]=function imul(a,b){var ah=a>>>16;var al=a&65535;var bh=b>>>16;var bl=b&65535;return al*bl+(ah*bl+al*bh<<16)|0};Math.imul=Math["imul"];if(!Math["clz32"])Math["clz32"]=(function(x){x=x>>>0;for(var i=0;i<32;i++){if(x&1<<31-i)return i}return 32});Math.clz32=Math["clz32"];var Math_abs=Math.abs;var Math_cos=Math.cos;var Math_sin=Math.sin;var Math_tan=Math.tan;var Math_acos=Math.acos;var Math_asin=Math.asin;var Math_atan=Math.atan;var Math_atan2=Math.atan2;var Math_exp=Math.exp;var Math_log=Math.log;var Math_sqrt=Math.sqrt;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_pow=Math.pow;var Math_imul=Math.imul;var Math_fround=Math.fround;var Math_min=Math.min;var Math_clz32=Math.clz32;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}Module["addRunDependency"]=addRunDependency;function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["removeRunDependency"]=removeRunDependency;Module["preloadedImages"]={};Module["preloadedAudios"]={};var memoryInitializer=null;var ASM_CONSTS=[];STATIC_BASE=8;STATICTOP=STATIC_BASE+3392;__ATINIT__.push();allocate([0,0,0,0,183,29,193,4,110,59,130,9,217,38,67,13,220,118,4,19,107,107,197,23,178,77,134,26,5,80,71,30,184,237,8,38,15,240,201,34,214,214,138,47,97,203,75,43,100,155,12,53,211,134,205,49,10,160,142,60,189,189,79,56,112,219,17,76,199,198,208,72,30,224,147,69,169,253,82,65,172,173,21,95,27,176,212,91,194,150,151,86,117,139,86,82,200,54,25,106,127,43,216,110,166,13,155,99,17,16,90,103,20,64,29,121,163,93,220,125,122,123,159,112,205,102,94,116,224,182,35,152,87,171,226,156,142,141,161,145,57,144,96,149,60,192,39,139,139,221,230,143,82,251,165,130,229,230,100,134,88,91,43,190,239,70,234,186,54,96,169,183,129,125,104,179,132,45,47,173,51,48,238,169,234,22,173,164,93,11,108,160,144,109,50,212,39,112,243,208,254,86,176,221,73,75,113,217,76,27,54,199,251,6,247,195,34,32,180,206,149,61,117,202,40,128,58,242,159,157,251,246,70,187,184,251,241,166,121,255,244,246,62,225,67,235,255,229,154,205,188,232,45,208,125,236,119,112,134,52,192,109,71,48,25,75,4,61,174,86,197,57,171,6,130,39,28,27,67,35,197,61,0,46,114,32,193,42,207,157,142,18,120,128,79,22,161,166,12,27,22,187,205,31,19,235,138,1,164,246,75,5,125,208,8,8,202,205,201,12,7,171,151,120,176,182,86,124,105,144,21,113,222,141,212,117,219,221,147,107,108,192,82,111,181,230,17,98,2,251,208,102,191,70,159,94,8,91,94,90,209,125,29,87,102,96,220,83,99,48,155,77,212,45,90,73,13,11,25,68,186,22,216,64,151,198,165,172,32,219,100,168,249,253,39,165,78,224,230,161,75,176,161,191,252,173,96,187,37,139,35,182,146,150,226,178,47,43,173,138,152,54,108,142,65,16,47,131,246,13,238,135,243,93,169,153,68,64,104,157,157,102,43,144,42,123,234,148,231,29,180,224,80,0,117,228,137,38,54,233,62,59,247,237,59,107,176,243,140,118,113,247,85,80,50,250,226,77,243,254,95,240,188,198,232,237,125,194,49,203,62,207,134,214,255,203,131,134,184,213,52,155,121,209,237,189,58,220,90,160,251,216,238,224,12,105,89,253,205,109,128,219,142,96,55,198,79,100,50,150,8,122,133,139,201,126,92,173,138,115,235,176,75,119,86,13,4,79,225,16,197,75,56,54,134,70,143,43,71,66,138,123,0,92,61,102,193,88,228,64,130,85,83,93,67,81,158,59,29,37,41,38,220,33,240,0,159,44,71,29,94,40,66,77,25,54,245,80,216,50,44,118,155,63,155,107,90,59,38,214,21,3,145,203,212,7,72,237,151,10,255,240,86,14,250,160,17,16,77,189,208,20,148,155,147,25,35,134,82,29,14,86,47,241,185,75,238,245,96,109,173,248,215,112,108,252,210,32,43,226,101,61,234,230,188,27,169,235,11,6,104,239,182,187,39,215,1,166,230,211,216,128,165,222,111,157,100,218,106,205,35,196,221,208,226,192,4,246,161,205,179,235,96,201,126,141,62,189,201,144,255,185,16,182,188,180,167,171,125,176,162,251,58,174,21,230,251,170,204,192,184,167,123,221,121,163,198,96,54,155,113,125,247,159,168,91,180,146,31,70,117,150,26,22,50,136,173,11,243,140,116,45,176,129,195,48,113,133,153,144,138,93,46,141,75,89,247,171,8,84,64,182,201,80,69,230,142,78,242,251,79,74,43,221,12,71,156,192,205,67,33,125,130,123,150,96,67,127,79,70,0,114,248,91,193,118,253,11,134,104,74,22,71,108,147,48,4,97,36,45,197,101,233,75,155,17,94,86,90,21,135,112,25,24,48,109,216,28,53,61,159,2,130,32,94,6,91,6,29,11,236,27,220,15,81,166,147,55,230,187,82,51,63,157,17,62,136,128,208,58,141,208,151,36,58,205,86,32,227,235,21,45,84,246,212,41,121,38,169,197,206,59,104,193,23,29,43,204,160,0,234,200,165,80,173,214,18,77,108,210,203,107,47,223,124,118,238,219,193,203,161,227,118,214,96,231,175,240,35,234,24,237,226,238,29,189,165,240,170,160,100,244,115,134,39,249,196,155,230,253,9,253,184,137,190,224,121,141,103,198,58,128,208,219,251,132,213,139,188,154,98,150,125,158,187,176,62,147,12,173,255,151,177,16,176,175,6,13,113,171,223,43,50,166,104,54,243,162,109,102,180,188,218,123,117,184,3,93,54,181,180,64,247,177,79,103,103,83,0,0,0,0,184,8,0,0,7,0,0,0,192,8,0,0,1,0,0,0,1,0,0,0,2,0,0,0,200,8,0,0,7,0,0,0,208,8,0,0,3,0,0,0,2,0,0,0,4,0,0,0,216,8,0,0,5,0,0,0,216,8,0,0,5,0,0,0,3,0,0,0,0,0,0,0,224,8,0,0,8,0,0,0,240,8,0,0,6,0,0,0,0,0,0,0,0,0,0,0,248,8,0,0,8,0,0,0,8,9,0,0,7,0,0,0,0,0,0,0,0,0,0,0,16,9,0,0,7,0,0,0,16,9,0,0,8,0,0,0,0,0,0,0,0,0,0,0,24,9,0,0,7,0,0,0,32,9,0,0,9,0,0,0,0,0,0,0,0,0,0,0,48,9,0,0,4,0,0,0,56,9,0,0,10,0,0,0,4,0,0,0,0,0,0,0,64,9,0,0,5,0,0,0,72,9,0,0,11,0,0,0,4,0,0,0,0,0,0,0,80,9,0,0,7,0,0,0,80,9,0,0,12,0,0,0,0,0,0,0,0,0,0,0,88,9,0,0,8,0,0,0,104,9,0,0,13,0,0,0,5,0,0,0,0,0,0,0,112,9,0,0,8,0,0,0,128,9,0,0,14,0,0,0,0,0,0,0,0,0,0,0,136,9,0,0,5,0,0,0,144,9,0,0,15,0,0,0,0,0,0,0,0,0,0,0,152,9,0,0,8,0,0,0,168,9,0,0,16,0,0,0,6,0,0,0,17,0,0,0,176,9,0,0,5,0,0,0,184,9,0,0,18,0,0,0,7,0,0,0,0,0,0,0,192,9,0,0,0,0,0,0,200,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,118,111,114,98,105,115,0,129,116,104,101,111,114,97,0,129,107,97,116,101,0,0,0,0,0,0,0,0,0,0,0,79,112,117,115,84,97,103,115,0,0,0,0,0,0,0,0,79,86,80,56,48,2,32,0,128,2,0,0,204,1,0,0,24,0,0,0,1,0,0,0,176,0,0,0,120,0,0,0,96,1,0,0,240,0,0,0,96,1,0,0,32,1,0,0,192,2,0,0,224,1,0,0,192,2,0,0,64,2,0,0,208,2,0,0,224,1,0,0,208,2,0,0,64,2,0,0,0,5,0,0,208,2,0,0,0,5,0,0,208,2,0,0,128,7,0,0,56,4,0,0,128,7,0,0,56,4,0,0,128,7,0,0,56,4,0,0,128,7,0,0,56,4,0,0,0,8,0,0,56,4,0,0,0,16,0,0,112,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,9,0,0,0,10,0,0,0,9,0,0,0,10,0,0,0,9,0,0,0,10,0,0,0,4,0,0,0,3,0,0,0,7,0,0,0,6,0,0,0,4,0,0,0,3,0,0,0,7,0,0,0,6,0,0,0,2,0,0,0,2,0,0,0,7,0,0,0,6,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,192,93,0,0,233,3,0,0,24,0,0,0,1,0,0,0,25,0,0,0,1,0,0,0,48,117,0,0,233,3,0,0,30,0,0,0,1,0,0,0,50,0,0,0,1,0,0,0,96,234,0,0,233,3,0,0,60,0,0,0,1,0,0,0,152,58,0,0,233,3,0,0,25,0,0,0,2,0,0,0,224,1,0,0,192,3,0,0,128,7,0,0,64,11,0,0,224,1,0,0,192,3,0,0,128,7,0,0,64,11,0,0,224,1,0,0,192,3,0,0,128,7,0,0,64,11,0,0,224,1,0,0,192,3,0,0,224,1,0,0,192,3,0,0,120,0,0,0,240,0,0,0,224,1,0,0,192,3,0,0,120,0,0,0,240,0,0,0,224,1,0,0,192,3,0,0,120,0,0,0,240,0,0,0,224,1,0,0,192,3,0,0,120,0,0,0,240,0,0,0,224,1,0,0,192,3,0,0,0,0,0,0,1,0,0,0,3,0,0,0,7,0,0,0,15,0,0,0,31,0,0,0,63,0,0,0,127,0,0,0,255,0,0,0,255,1,0,0,255,3,0,0,255,7,0,0,255,15,0,0,255,31,0,0,255,63,0,0,255,127,0,0,255,255,0,0,255,255,1,0,255,255,3,0,255,255,7,0,255,255,15,0,255,255,31,0,255,255,63,0,255,255,127,0,255,255,255,0,255,255,255,1,255,255,255,3,255,255,255,7,255,255,255,15,255,255,255,31,255,255,255,63,255,255,255,127,255,255,255,255,0,0,0,0,128,116,104,101,111,114,97,0,84,104,101,111,114,97,0,0,1,118,111,114,98,105,115,0,86,111,114,98,105,115,0,0,83,112,101,101,120,0,0,0,80,67,77,32,32,32,32,32,0,0,0,0,0,0,0,0,80,67,77,0,0,0,0,0,67,77,77,76,0,0,0,0,0,0,0,0,0,0,0,0,67,77,77,76,0,0,0,0,65,110,110,111,100,101,120,0,102,105,115,104,101,97,100,0,83,107,101,108,101,116,111,110,0,0,0,0,0,0,0,0,102,76,97,67,0,0,0,0,70,108,97,99,48,0,0,0,127,70,76,65,67,0,0,0,70,108,97,99,0,0,0,0,65,110,120,68,97,116,97,0,67,69,76,84,32,32,32,32,0,0,0,0,0,0,0,0,67,69,76,84,0,0,0,0,128,107,97,116,101,0,0,0,0,0,0,0,0,0,0,0,75,97,116,101,0,0,0,0,66,66,67,68,0,0,0,0,68,105,114,97,99,0,0,0,79,112,117,115,72,101,97,100,0,0,0,0,0,0,0,0,79,112,117,115,0,0,0,0,79,86,80,56,48,0,0,0,86,80,56,0,0,0,0,0,0,0,0,0,0,0,0,0,85,110,107,110,111,119,110,0,86,80,56,48,0,0,0,0,102,105,115,104,101,97,100,0,0,0,0,0,0,0,0,0,102,105,115,98,111,110,101,0,0,0,0,0,0,0,0,0,105,110,100,101,120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,69,114,114,111,114,32,37,100,32,102,114,111,109,32,111,103,103,122,95,114,101,97,100,95,105,110,112,117,116,10,0,0,69,120,112,101,99,116,101,100,32,116,111,32,114,101,97,100,32,37,100,32,102,114,111,109,32,111,103,103,122,95,114,101,97,100,95,105,110,112,117,116,32,98,117,116,32,103,97,118,101,32,37,100,10,0,0,0,116,104,101,111,114,97,0,0,118,111,114,98,105,115,0,0,111,112,117,115,0,0,0,0,73,110,118,97,108,105,100,32,111,103,103,32,115,107,101,108,101,116,111,110,32,116,114,97,99,107,32,100,97,116,97,63,32,37,100,10,0,0,0,0,73,110,118,97,108,105,100,32,115,116,97,116,101,32,105,110,32,79,103,103,32,114,101,97,100,80,97,99,107,101,116,67,97,108,108,98,97,99,107,0,69,114,114,111,114,32,112,114,111,99,101,115,115,105,110,103,32,115,107,101,108,101,116,111,110,32,112,97,99,107,101,116,58,32,37,100,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"i8",ALLOC_NONE,Runtime.GLOBAL_BASE);var tempDoublePtr=Runtime.alignMemory(allocate(12,"i8",ALLOC_STATIC),8);assert(tempDoublePtr%8==0);function copyTempFloat(ptr){HEAP8[tempDoublePtr]=HEAP8[ptr];HEAP8[tempDoublePtr+1]=HEAP8[ptr+1];HEAP8[tempDoublePtr+2]=HEAP8[ptr+2];HEAP8[tempDoublePtr+3]=HEAP8[ptr+3]}function copyTempDouble(ptr){HEAP8[tempDoublePtr]=HEAP8[ptr];HEAP8[tempDoublePtr+1]=HEAP8[ptr+1];HEAP8[tempDoublePtr+2]=HEAP8[ptr+2];HEAP8[tempDoublePtr+3]=HEAP8[ptr+3];HEAP8[tempDoublePtr+4]=HEAP8[ptr+4];HEAP8[tempDoublePtr+5]=HEAP8[ptr+5];HEAP8[tempDoublePtr+6]=HEAP8[ptr+6];HEAP8[tempDoublePtr+7]=HEAP8[ptr+7]}function _ogvjs_callback_loaded_metadata(videoCodecStr,audioCodecStr){if(videoCodecStr){Module.videoCodec=Module.Pointer_stringify(videoCodecStr)}if(audioCodecStr){Module.audioCodec=Module.Pointer_stringify(audioCodecStr)}var len=Module._ogv_demuxer_media_duration();if(len>=0){Module.duration=len}else{Module.duration=NaN}Module.loadedMetadata=true}Module["_bitshift64Ashr"]=_bitshift64Ashr;function _ogvjs_callback_video_packet(buffer,len,frameTimestamp,keyframeTimestamp){Module.videoPackets.push({data:Module.HEAPU8.buffer.slice?Module.HEAPU8.buffer.slice(buffer,buffer+len):(new Uint8Array(new Uint8Array(Module.HEAPU8.buffer,buffer,len))).buffer,timestamp:frameTimestamp,keyframeTimestamp:keyframeTimestamp})}Module["_i64Subtract"]=_i64Subtract;var ___errno_state=0;function ___setErrNo(value){HEAP32[___errno_state>>2]=value;return value}var ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};function _sysconf(name){switch(name){case 30:return PAGE_SIZE;case 85:return totalMemory/PAGE_SIZE;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:return 200809;case 79:return 0;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1e3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:{if(typeof navigator==="object")return navigator["hardwareConcurrency"]||1;return 1}}___setErrNo(ERRNO_CODES.EINVAL);return-1}var _SItoD=true;var _SItoF=true;Module["_memset"]=_memset;var FS=undefined;function _close(fildes){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{FS.close(stream);return 0}catch(e){FS.handleFSError(e);return-1}}function _fileno(stream){stream=FS.getStreamFromPtr(stream);if(!stream)return-1;return stream.fd}function _fclose(stream){var fd=_fileno(stream);return _close(fd)}Module["_bitshift64Shl"]=_bitshift64Shl;function _abort(){Module["abort"]()}var SOCKFS=undefined;function _send(fd,buf,len,flags){var sock=SOCKFS.getSocket(fd);if(!sock){___setErrNo(ERRNO_CODES.EBADF);return-1}return _write(fd,buf,len)}function _pwrite(fildes,buf,nbyte,offset){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{var slab=HEAP8;return FS.write(stream,slab,buf,nbyte,offset)}catch(e){FS.handleFSError(e);return-1}}function _write(fildes,buf,nbyte){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{var slab=HEAP8;return FS.write(stream,slab,buf,nbyte)}catch(e){FS.handleFSError(e);return-1}}function _fwrite(ptr,size,nitems,stream){var bytesToWrite=nitems*size;if(bytesToWrite==0)return 0;var fd=_fileno(stream);var bytesWritten=_write(fd,ptr,bytesToWrite);if(bytesWritten==-1){var streamObj=FS.getStreamFromPtr(stream);if(streamObj)streamObj.error=true;return 0}else{return bytesWritten/size|0}}Module["_strlen"]=_strlen;function __reallyNegative(x){return x<0||x===0&&1/x===-Infinity}function __formatString(format,varargs){assert((varargs&3)===0);var textIndex=format;var argIndex=0;function getNextArg(type){var ret;argIndex=Runtime.prepVararg(argIndex,type);if(type==="double"){ret=(HEAP32[tempDoublePtr>>2]=HEAP32[varargs+argIndex>>2],HEAP32[tempDoublePtr+4>>2]=HEAP32[varargs+(argIndex+4)>>2],+HEAPF64[tempDoublePtr>>3]);argIndex+=8}else if(type=="i64"){ret=[HEAP32[varargs+argIndex>>2],HEAP32[varargs+(argIndex+4)>>2]];argIndex+=8}else{assert((argIndex&3)===0);type="i32";ret=HEAP32[varargs+argIndex>>2];argIndex+=4}return ret}var ret=[];var curr,next,currArg;while(1){var startTextIndex=textIndex;curr=HEAP8[textIndex>>0];if(curr===0)break;next=HEAP8[textIndex+1>>0];if(curr==37){var flagAlwaysSigned=false;var flagLeftAlign=false;var flagAlternative=false;var flagZeroPad=false;var flagPadSign=false;flagsLoop:while(1){switch(next){case 43:flagAlwaysSigned=true;break;case 45:flagLeftAlign=true;break;case 35:flagAlternative=true;break;case 48:if(flagZeroPad){break flagsLoop}else{flagZeroPad=true;break};case 32:flagPadSign=true;break;default:break flagsLoop}textIndex++;next=HEAP8[textIndex+1>>0]}var width=0;if(next==42){width=getNextArg("i32");textIndex++;next=HEAP8[textIndex+1>>0]}else{while(next>=48&&next<=57){width=width*10+(next-48);textIndex++;next=HEAP8[textIndex+1>>0]}}var precisionSet=false,precision=-1;if(next==46){precision=0;precisionSet=true;textIndex++;next=HEAP8[textIndex+1>>0];if(next==42){precision=getNextArg("i32");textIndex++}else{while(1){var precisionChr=HEAP8[textIndex+1>>0];if(precisionChr<48||precisionChr>57)break;precision=precision*10+(precisionChr-48);textIndex++}}next=HEAP8[textIndex+1>>0]}if(precision<0){precision=6;precisionSet=false}var argSize;switch(String.fromCharCode(next)){case"h":var nextNext=HEAP8[textIndex+2>>0];if(nextNext==104){textIndex++;argSize=1}else{argSize=2}break;case"l":var nextNext=HEAP8[textIndex+2>>0];if(nextNext==108){textIndex++;argSize=8}else{argSize=4}break;case"L":case"q":case"j":argSize=8;break;case"z":case"t":case"I":argSize=4;break;default:argSize=null}if(argSize)textIndex++;next=HEAP8[textIndex+1>>0];switch(String.fromCharCode(next)){case"d":case"i":case"u":case"o":case"x":case"X":case"p":{var signed=next==100||next==105;argSize=argSize||4;var currArg=getNextArg("i"+argSize*8);var origArg=currArg;var argText;if(argSize==8){currArg=Runtime.makeBigInt(currArg[0],currArg[1],next==117)}if(argSize<=4){var limit=Math.pow(256,argSize)-1;currArg=(signed?reSign:unSign)(currArg&limit,argSize*8)}var currAbsArg=Math.abs(currArg);var prefix="";if(next==100||next==105){if(argSize==8&&i64Math)argText=i64Math.stringify(origArg[0],origArg[1],null);else argText=reSign(currArg,8*argSize,1).toString(10)}else if(next==117){if(argSize==8&&i64Math)argText=i64Math.stringify(origArg[0],origArg[1],true);else argText=unSign(currArg,8*argSize,1).toString(10);currArg=Math.abs(currArg)}else if(next==111){argText=(flagAlternative?"0":"")+currAbsArg.toString(8)}else if(next==120||next==88){prefix=flagAlternative&&currArg!=0?"0x":"";if(argSize==8&&i64Math){if(origArg[1]){argText=(origArg[1]>>>0).toString(16);var lower=(origArg[0]>>>0).toString(16);while(lower.length<8)lower="0"+lower;argText+=lower}else{argText=(origArg[0]>>>0).toString(16)}}else if(currArg<0){currArg=-currArg;argText=(currAbsArg-1).toString(16);var buffer=[];for(var i=0;i<argText.length;i++){buffer.push((15-parseInt(argText[i],16)).toString(16))}argText=buffer.join("");while(argText.length<argSize*2)argText="f"+argText}else{argText=currAbsArg.toString(16)}if(next==88){prefix=prefix.toUpperCase();argText=argText.toUpperCase()}}else if(next==112){if(currAbsArg===0){argText="(nil)"}else{prefix="0x";argText=currAbsArg.toString(16)}}if(precisionSet){while(argText.length<precision){argText="0"+argText}}if(currArg>=0){if(flagAlwaysSigned){prefix="+"+prefix}else if(flagPadSign){prefix=" "+prefix}}if(argText.charAt(0)=="-"){prefix="-"+prefix;argText=argText.substr(1)}while(prefix.length+argText.length<width){if(flagLeftAlign){argText+=" "}else{if(flagZeroPad){argText="0"+argText}else{prefix=" "+prefix}}}argText=prefix+argText;argText.split("").forEach((function(chr){ret.push(chr.charCodeAt(0))}));break};case"f":case"F":case"e":case"E":case"g":case"G":{var currArg=getNextArg("double");var argText;if(isNaN(currArg)){argText="nan";flagZeroPad=false}else if(!isFinite(currArg)){argText=(currArg<0?"-":"")+"inf";flagZeroPad=false}else{var isGeneral=false;var effectivePrecision=Math.min(precision,20);if(next==103||next==71){isGeneral=true;precision=precision||1;var exponent=parseInt(currArg.toExponential(effectivePrecision).split("e")[1],10);if(precision>exponent&&exponent>=-4){next=(next==103?"f":"F").charCodeAt(0);precision-=exponent+1}else{next=(next==103?"e":"E").charCodeAt(0);precision--}effectivePrecision=Math.min(precision,20)}if(next==101||next==69){argText=currArg.toExponential(effectivePrecision);if(/[eE][-+]\d$/.test(argText)){argText=argText.slice(0,-1)+"0"+argText.slice(-1)}}else if(next==102||next==70){argText=currArg.toFixed(effectivePrecision);if(currArg===0&&__reallyNegative(currArg)){argText="-"+argText}}var parts=argText.split("e");if(isGeneral&&!flagAlternative){while(parts[0].length>1&&parts[0].indexOf(".")!=-1&&(parts[0].slice(-1)=="0"||parts[0].slice(-1)==".")){parts[0]=parts[0].slice(0,-1)}}else{if(flagAlternative&&argText.indexOf(".")==-1)parts[0]+=".";while(precision>effectivePrecision++)parts[0]+="0"}argText=parts[0]+(parts.length>1?"e"+parts[1]:"");if(next==69)argText=argText.toUpperCase();if(currArg>=0){if(flagAlwaysSigned){argText="+"+argText}else if(flagPadSign){argText=" "+argText}}}while(argText.length<width){if(flagLeftAlign){argText+=" "}else{if(flagZeroPad&&(argText[0]=="-"||argText[0]=="+")){argText=argText[0]+"0"+argText.slice(1)}else{argText=(flagZeroPad?"0":" ")+argText}}}if(next<97)argText=argText.toUpperCase();argText.split("").forEach((function(chr){ret.push(chr.charCodeAt(0))}));break};case"s":{var arg=getNextArg("i8*");var argLength=arg?_strlen(arg):"(null)".length;if(precisionSet)argLength=Math.min(argLength,precision);if(!flagLeftAlign){while(argLength<width--){ret.push(32)}}if(arg){for(var i=0;i<argLength;i++){ret.push(HEAPU8[arg++>>0])}}else{ret=ret.concat(intArrayFromString("(null)".substr(0,argLength),true))}if(flagLeftAlign){while(argLength<width--){ret.push(32)}}break};case"c":{if(flagLeftAlign)ret.push(getNextArg("i8"));while(--width>0){ret.push(32)}if(!flagLeftAlign)ret.push(getNextArg("i8"));break};case"n":{var ptr=getNextArg("i32*");HEAP32[ptr>>2]=ret.length;break};case"%":{ret.push(curr);break};default:{for(var i=startTextIndex;i<textIndex+2;i++){ret.push(HEAP8[i>>0])}}}textIndex+=2}else{ret.push(curr);textIndex+=1}}return ret}function _fprintf(stream,format,varargs){var result=__formatString(format,varargs);var stack=Runtime.stackSave();var ret=_fwrite(allocate(result,"i8",ALLOC_STACK),1,result.length,stream);Runtime.stackRestore(stack);return ret}function _printf(format,varargs){var result=__formatString(format,varargs);var string=intArrayToString(result);if(string[string.length-1]==="\n")string=string.substr(0,string.length-1);Module.print(string);return result.length}function _ogvjs_callback_frame_ready(){return Module.videoPackets.length>0?1:0}function _fflush(stream){}function _emscripten_memcpy_big(dest,src,num){HEAPU8.set(HEAPU8.subarray(src,src+num),dest);return dest}Module["_memcpy"]=_memcpy;Module["_strncpy"]=_strncpy;Module["_i64Add"]=_i64Add;function _ogvjs_callback_audio_packet(buffer,len,audioTimestamp){Module.audioPackets.push({data:Module.HEAPU8.buffer.slice?Module.HEAPU8.buffer.slice(buffer,buffer+len):(new Uint8Array(new Uint8Array(Module.HEAPU8.buffer,buffer,len))).buffer,timestamp:audioTimestamp})}Module["_memmove"]=_memmove;function _ogvjs_callback_audio_ready(){return Module.audioPackets.length>0?1:0}function _lseek(fildes,offset,whence){var stream=FS.getStream(fildes);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}try{return FS.llseek(stream,offset,whence)}catch(e){FS.handleFSError(e);return-1}}function _fseek(stream,offset,whence){var fd=_fileno(stream);var ret=_lseek(fd,offset,whence);if(ret==-1){return-1}stream=FS.getStreamFromPtr(stream);stream.eof=false;return 0}function ___errno_location(){return ___errno_state}function _ftell(stream){stream=FS.getStreamFromPtr(stream);if(!stream){___setErrNo(ERRNO_CODES.EBADF);return-1}if(FS.isChrdev(stream.node.mode)){___setErrNo(ERRNO_CODES.ESPIPE);return-1}else{return stream.position}}Module["_strcpy"]=_strcpy;function _sbrk(bytes){var self=_sbrk;if(!self.called){DYNAMICTOP=alignMemoryPage(DYNAMICTOP);self.called=true;assert(Runtime.dynamicAlloc);self.alloc=Runtime.dynamicAlloc;Runtime.dynamicAlloc=(function(){abort("cannot dynamically allocate, sbrk now has control")})}var ret=DYNAMICTOP;if(bytes!=0){var success=self.alloc(bytes);if(!success)return-1>>>0}return ret}function _time(ptr){var ret=Date.now()/1e3|0;if(ptr){HEAP32[ptr>>2]=ret}return ret}___errno_state=Runtime.staticAlloc(4);HEAP32[___errno_state>>2]=0;STACK_BASE=STACKTOP=Runtime.alignMemory(STATICTOP);staticSealed=true;STACK_MAX=STACK_BASE+TOTAL_STACK;DYNAMIC_BASE=DYNAMICTOP=Runtime.alignMemory(STACK_MAX);assert(DYNAMIC_BASE<TOTAL_MEMORY,"TOTAL_MEMORY not big enough for stack");var cttz_i8=allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0],"i8",ALLOC_DYNAMIC);function invoke_iiii(index,a1,a2,a3){try{return Module["dynCall_iiii"](index,a1,a2,a3)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_vi(index,a1){try{Module["dynCall_vi"](index,a1)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_ii(index,a1){try{return Module["dynCall_ii"](index,a1)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){try{return Module["dynCall_iiiii"](index,a1,a2,a3,a4)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_iii(index,a1,a2){try{return Module["dynCall_iii"](index,a1,a2)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){try{return Module["dynCall_iiiiii"](index,a1,a2,a3,a4,a5)}catch(e){if(typeof e!=="number"&&e!=="longjmp")throw e;asm["setThrew"](1,0)}}Module.asmGlobalArg={"Math":Math,"Int8Array":Int8Array,"Int16Array":Int16Array,"Int32Array":Int32Array,"Uint8Array":Uint8Array,"Uint16Array":Uint16Array,"Uint32Array":Uint32Array,"Float32Array":Float32Array,"Float64Array":Float64Array,"NaN":NaN,"Infinity":Infinity};Module.asmLibraryArg={"abort":abort,"assert":assert,"invoke_iiii":invoke_iiii,"invoke_vi":invoke_vi,"invoke_ii":invoke_ii,"invoke_iiiii":invoke_iiiii,"invoke_iii":invoke_iii,"invoke_iiiiii":invoke_iiiiii,"_send":_send,"_lseek":_lseek,"___setErrNo":___setErrNo,"_ogvjs_callback_audio_packet":_ogvjs_callback_audio_packet,"_ogvjs_callback_loaded_metadata":_ogvjs_callback_loaded_metadata,"_fflush":_fflush,"_pwrite":_pwrite,"__reallyNegative":__reallyNegative,"_sbrk":_sbrk,"_emscripten_memcpy_big":_emscripten_memcpy_big,"_fileno":_fileno,"_ogvjs_callback_frame_ready":_ogvjs_callback_frame_ready,"_sysconf":_sysconf,"_close":_close,"_ogvjs_callback_video_packet":_ogvjs_callback_video_packet,"_fseek":_fseek,"_printf":_printf,"_fclose":_fclose,"_write":_write,"_ftell":_ftell,"___errno_location":___errno_location,"_abort":_abort,"_fwrite":_fwrite,"_time":_time,"_fprintf":_fprintf,"__formatString":__formatString,"_ogvjs_callback_audio_ready":_ogvjs_callback_audio_ready,"STACKTOP":STACKTOP,"STACK_MAX":STACK_MAX,"tempDoublePtr":tempDoublePtr,"ABORT":ABORT,"cttz_i8":cttz_i8};// EMSCRIPTEN_START_ASM
+var asm=(function(global,env,buffer) {
+"use asm";var a=new global.Int8Array(buffer);var b=new global.Int16Array(buffer);var c=new global.Int32Array(buffer);var d=new global.Uint8Array(buffer);var e=new global.Uint16Array(buffer);var f=new global.Uint32Array(buffer);var g=new global.Float32Array(buffer);var h=new global.Float64Array(buffer);var i=env.STACKTOP|0;var j=env.STACK_MAX|0;var k=env.tempDoublePtr|0;var l=env.ABORT|0;var m=env.cttz_i8|0;var n=0;var o=0;var p=0;var q=0;var r=global.NaN,s=global.Infinity;var t=0,u=0,v=0,w=0,x=0.0,y=0,z=0,A=0,B=0.0;var C=0;var D=0;var E=0;var F=0;var G=0;var H=0;var I=0;var J=0;var K=0;var L=0;var M=global.Math.floor;var N=global.Math.abs;var O=global.Math.sqrt;var P=global.Math.pow;var Q=global.Math.cos;var R=global.Math.sin;var S=global.Math.tan;var T=global.Math.acos;var U=global.Math.asin;var V=global.Math.atan;var W=global.Math.atan2;var X=global.Math.exp;var Y=global.Math.log;var Z=global.Math.ceil;var _=global.Math.imul;var $=global.Math.min;var aa=global.Math.clz32;var ba=env.abort;var ca=env.assert;var da=env.invoke_iiii;var ea=env.invoke_vi;var fa=env.invoke_ii;var ga=env.invoke_iiiii;var ha=env.invoke_iii;var ia=env.invoke_iiiiii;var ja=env._send;var ka=env._lseek;var la=env.___setErrNo;var ma=env._ogvjs_callback_audio_packet;var na=env._ogvjs_callback_loaded_metadata;var oa=env._fflush;var pa=env._pwrite;var qa=env.__reallyNegative;var ra=env._sbrk;var sa=env._emscripten_memcpy_big;var ta=env._fileno;var ua=env._ogvjs_callback_frame_ready;var va=env._sysconf;var wa=env._close;var xa=env._ogvjs_callback_video_packet;var ya=env._fseek;var za=env._printf;var Aa=env._fclose;var Ba=env._write;var Ca=env._ftell;var Da=env.___errno_location;var Ea=env._abort;var Fa=env._fwrite;var Ga=env._time;var Ha=env._fprintf;var Ia=env.__formatString;var Ja=env._ogvjs_callback_audio_ready;var Ka=0.0;
+// EMSCRIPTEN_START_FUNCS
+function Ra(a){a=a|0;var b=0;b=i;i=i+a|0;i=i+15&-16;return b|0}function Sa(){return i|0}function Ta(a){a=a|0;i=a}function Ua(a,b){a=a|0;b=b|0;i=a;j=b}function Va(a,b){a=a|0;b=b|0;if(!n){n=a;o=b}}function Wa(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0]}function Xa(b){b=b|0;a[k>>0]=a[b>>0];a[k+1>>0]=a[b+1>>0];a[k+2>>0]=a[b+2>>0];a[k+3>>0]=a[b+3>>0];a[k+4>>0]=a[b+4>>0];a[k+5>>0]=a[b+5>>0];a[k+6>>0]=a[b+6>>0];a[k+7>>0]=a[b+7>>0]}function Ya(a){a=a|0;C=a}function Za(){return C|0}function _a(a){a=a|0;return (d[(c[a>>2]|0)+5>>0]|0)&1|0}function $a(a){a=a|0;return (d[(c[a>>2]|0)+5>>0]|0)&2|0}function ab(a){a=a|0;var b=0,e=0;b=c[a>>2]|0;a=Ie(d[b+13>>0]|0|0,0,8)|0;e=Ie(a|(d[b+12>>0]|0)|0,C|0,8)|0;a=Ie(e|(d[b+11>>0]|0)|0,C|0,8)|0;e=Ie(a|(d[b+10>>0]|0)|0,C|0,8)|0;a=Ie(e|(d[b+9>>0]|0)|0,C|0,8)|0;e=Ie(a|(d[b+8>>0]|0)|0,C|0,8)|0;a=Ie(e|(d[b+7>>0]|0)|0,C|0,8)|0;return a|(d[b+6>>0]|0)|0}function bb(a){a=a|0;var b=0;b=c[a>>2]|0;return (d[b+15>>0]|0)<<8|(d[b+14>>0]|0)|(d[b+16>>0]|0)<<16|(d[b+17>>0]|0)<<24|0}function cb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0;if(!a){d=-1;return d|0}He(a|0,0,360)|0;c[a+4>>2]=16384;c[a+24>>2]=1024;e=ye(16384)|0;c[a>>2]=e;f=ye(4096)|0;g=a+16|0;c[g>>2]=f;h=ye(8192)|0;i=a+20|0;c[i>>2]=h;do if(!e)j=f;else{if((h|0)==0|(f|0)==0){ze(e);j=c[g>>2]|0;break}c[a+336>>2]=b;d=0;return d|0}while(0);if(j)ze(j);j=c[i>>2]|0;if(j)ze(j);He(a|0,0,360)|0;d=-1;return d|0}function db(a){a=a|0;var b=0;if(!a)return 0;b=c[a>>2]|0;if(b)ze(b);b=c[a+16>>2]|0;if(b)ze(b);b=c[a+20>>2]|0;if(b)ze(b);He(a|0,0,360)|0;return 0}function eb(a){a=a|0;if(!a)return 0;c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+16>>2]=0;c[a+20>>2]=0;c[a+24>>2]=0;return 0}function fb(a){a=a|0;var b=0;if(!a)return 0;b=c[a>>2]|0;if(b)ze(b);c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+16>>2]=0;c[a+20>>2]=0;c[a+24>>2]=0;return 0}function gb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;d=a+4|0;e=c[d>>2]|0;if((e|0)<=-1){f=0;return f|0}g=a+12|0;h=c[g>>2]|0;i=a+8|0;if(!h)j=e;else{k=(c[i>>2]|0)-h|0;c[i>>2]=k;if((k|0)>0){l=c[a>>2]|0;Ne(l|0,l+h|0,k|0)|0;m=c[d>>2]|0}else m=e;c[g>>2]=0;j=m}m=c[i>>2]|0;do if((j-m|0)<(b|0)){g=b+4096+m|0;e=c[a>>2]|0;if(!e)n=ye(g)|0;else n=Be(e,g)|0;if(n){c[a>>2]=n;c[d>>2]=g;o=n;p=c[i>>2]|0;break}g=c[a>>2]|0;if(g)ze(g);c[a>>2]=0;c[a+4>>2]=0;c[a+8>>2]=0;c[a+12>>2]=0;c[a+16>>2]=0;c[a+20>>2]=0;c[a+24>>2]=0;f=0;return f|0}else{o=c[a>>2]|0;p=m}while(0);f=o+p|0;return f|0}function hb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=c[a+4>>2]|0;if((d|0)<=-1){e=-1;return e|0}f=a+8|0;a=(c[f>>2]|0)+b|0;if((a|0)>(d|0)){e=-1;return e|0}c[f>>2]=a;e=0;return e|0}function ib(b,e){b=b|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0;f=i;i=i+16|0;g=f;h=c[b>>2]|0;j=b+12|0;k=c[j>>2]|0;l=h+k|0;m=b+8|0;n=(c[m>>2]|0)-k|0;if((c[b+4>>2]|0)<=-1){o=0;i=f;return o|0}p=b+20|0;q=c[p>>2]|0;do if(!q){if((n|0)<27){o=0;i=f;return o|0}if(ve(l,1032,4)|0){r=b+24|0;break}s=h+(k+26)|0;t=a[s>>0]|0;u=(t&255)+27|0;if((n|0)<(u|0)){o=0;i=f;return o|0}if(t<<24>>24){t=k+27|0;v=b+24|0;w=c[v>>2]|0;x=0;do{w=w+(d[h+(t+x)>>0]|0)|0;c[v>>2]=w;x=x+1|0}while((x|0)<(d[s>>0]|0|0))}c[p>>2]=u;y=u;z=11}else{y=q;z=11}while(0);do if((z|0)==11){q=b+24|0;if((y+(c[q>>2]|0)|0)>(n|0)){o=0;i=f;return o|0}s=h+(k+22)|0;x=d[s>>0]|d[s+1>>0]<<8|d[s+2>>0]<<16|d[s+3>>0]<<24;c[g>>2]=x;a[s>>0]=0;a[s+1>>0]=0;a[s+2>>0]=0;a[s+3>>0]=0;w=c[p>>2]|0;v=w+k|0;t=c[q>>2]|0;a[s>>0]=0;A=h+(k+23)|0;a[A>>0]=0;B=h+(k+24)|0;a[B>>0]=0;C=h+(k+25)|0;a[C>>0]=0;if((w|0)>0){D=0;E=0;while(1){F=c[8+(((d[h+(E+k)>>0]|0)^D>>>24)<<2)>>2]^D<<8;E=E+1|0;if((E|0)==(w|0)){G=F;break}else D=F}}else G=0;if((t|0)>0){D=G;w=0;while(1){E=c[8+(((d[h+(v+w)>>0]|0)^D>>>24)<<2)>>2]^D<<8;w=w+1|0;if((w|0)==(t|0)){H=E;break}else D=E}}else H=G;a[s>>0]=H;a[A>>0]=H>>>8;a[B>>0]=H>>>16;a[C>>0]=H>>>24;if(ve(g,s,4)|0){a[s>>0]=x;a[s+1>>0]=x>>8;a[s+2>>0]=x>>16;a[s+3>>0]=x>>24;r=q;break}D=c[b>>2]|0;t=c[j>>2]|0;if(!e){I=c[q>>2]|0;J=c[p>>2]|0}else{c[e>>2]=D+t;w=c[p>>2]|0;c[e+4>>2]=w;c[e+8>>2]=D+(w+t);D=c[q>>2]|0;c[e+12>>2]=D;I=D;J=w}c[b+16>>2]=0;w=I+J|0;c[j>>2]=t+w;c[p>>2]=0;c[q>>2]=0;o=w;i=f;return o|0}while(0);c[p>>2]=0;c[r>>2]=0;r=ue(h+(k+1)|0,79,n+-1|0)|0;n=c[b>>2]|0;if(!r)K=n+(c[m>>2]|0)|0;else K=r;r=K;c[j>>2]=r-n;o=l-r|0;i=f;return o|0}function jb(b,e){b=b|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0;f=c[e>>2]|0;g=c[e+8>>2]|0;h=c[e+12>>2]|0;e=a[f+4>>0]|0;i=d[f+5>>0]|0;j=i&1;k=i&2;l=i&4;i=Ie(d[f+13>>0]|0|0,0,8)|0;m=Ie(i|(d[f+12>>0]|0)|0,C|0,8)|0;i=Ie(m|(d[f+11>>0]|0)|0,C|0,8)|0;m=Ie(i|(d[f+10>>0]|0)|0,C|0,8)|0;i=Ie(m|(d[f+9>>0]|0)|0,C|0,8)|0;m=Ie(i|(d[f+8>>0]|0)|0,C|0,8)|0;i=Ie(m|(d[f+7>>0]|0)|0,C|0,8)|0;m=C;n=i|(d[f+6>>0]|0);i=(d[f+15>>0]|0)<<8|(d[f+14>>0]|0)|(d[f+16>>0]|0)<<16|(d[f+17>>0]|0)<<24;o=(d[f+19>>0]|0)<<8|(d[f+18>>0]|0)|(d[f+20>>0]|0)<<16|(d[f+21>>0]|0)<<24;p=d[f+26>>0]|0;if(!b){q=-1;return q|0}r=c[b>>2]|0;if(!r){q=-1;return q|0}s=b+36|0;t=c[s>>2]|0;u=b+12|0;v=c[u>>2]|0;if(v){w=b+8|0;x=c[w>>2]|0;y=x-v|0;c[w>>2]=y;if((x|0)!=(v|0))Ne(r|0,r+v|0,y|0)|0;c[u>>2]=0}if(t){u=b+28|0;y=c[u>>2]|0;if((y|0)==(t|0))z=t;else{v=c[b+16>>2]|0;Ne(v|0,v+(t<<2)|0,y-t<<2|0)|0;y=c[b+20>>2]|0;Ne(y|0,y+(t<<3)|0,(c[u>>2]|0)-t<<3|0)|0;z=c[u>>2]|0}c[u>>2]=z-t;z=b+32|0;c[z>>2]=(c[z>>2]|0)-t;c[s>>2]=0}if(e<<24>>24!=0?1:(i|0)!=(c[b+336>>2]|0)){q=-1;return q|0}if(nb(b,p+1|0)|0){q=-1;return q|0}i=b+340|0;e=c[i>>2]|0;if((o|0)!=(e|0)){s=b+32|0;t=c[s>>2]|0;z=b+28|0;u=c[z>>2]|0;if((t|0)<(u|0)){y=c[b+16>>2]|0;v=b+8|0;r=c[v>>2]|0;x=t;while(1){w=r-(c[y+(x<<2)>>2]&255)|0;x=x+1|0;if((x|0)>=(u|0)){A=w;break}else r=w}c[v>>2]=A}c[z>>2]=t;if((e|0)!=-1){e=t+1|0;c[z>>2]=e;c[(c[b+16>>2]|0)+(t<<2)>>2]=1024;c[s>>2]=e}}a:do if(!j){B=g;D=h;E=k;F=0}else{e=c[b+28>>2]|0;if((e|0)>=1?(c[(c[b+16>>2]|0)+(e+-1<<2)>>2]|0)!=1024:0){B=g;D=h;E=k;F=0;break}else{G=g;H=h;I=0}while(1){if((I|0)>=(p|0)){B=G;D=H;E=0;F=I;break a}e=a[f+(I+27)>>0]|0;s=e&255;t=G+s|0;z=H-s|0;s=I+1|0;if(e<<24>>24==-1){G=t;H=z;I=s}else{B=t;D=z;E=0;F=s;break}}}while(0);if(D){I=b+4|0;H=c[I>>2]|0;G=b+8|0;h=c[G>>2]|0;do if((H-D|0)>(h|0)){J=c[b>>2]|0;K=h}else{if((H|0)>(2147483647-D|0)){g=c[b>>2]|0;if(g)ze(g);g=c[b+16>>2]|0;if(g)ze(g);g=c[b+20>>2]|0;if(g)ze(g);He(b|0,0,360)|0;q=-1;return q|0}g=H+D|0;k=(g|0)<2147482623?g+1024|0:g;g=Be(c[b>>2]|0,k)|0;if(g){c[I>>2]=k;c[b>>2]=g;J=g;K=c[G>>2]|0;break}g=c[b>>2]|0;if(g)ze(g);g=c[b+16>>2]|0;if(g)ze(g);g=c[b+20>>2]|0;if(g)ze(g);He(b|0,0,360)|0;q=-1;return q|0}while(0);Ke(J+K|0,B|0,D|0)|0;c[G>>2]=(c[G>>2]|0)+D}if((F|0)<(p|0)){D=b+28|0;G=b+32|0;B=c[b+16>>2]|0;K=c[b+20>>2]|0;J=c[D>>2]|0;I=E;E=-1;H=F;b:while(1){F=J;h=I;g=H;while(1){k=a[f+(g+27)>>0]|0;j=k&255;s=B+(F<<2)|0;c[s>>2]=j;z=K+(F<<3)|0;c[z>>2]=-1;c[z+4>>2]=-1;if(h)c[s>>2]=j|256;j=F;F=F+1|0;c[D>>2]=F;g=g+1|0;if(k<<24>>24!=-1){L=j;M=F;N=g;break}if((g|0)>=(p|0)){O=E;break b}else h=0}c[G>>2]=M;if((N|0)<(p|0)){J=M;I=0;E=L;H=N}else{O=L;break}}if((O|0)!=-1){L=(c[b+20>>2]|0)+(O<<3)|0;c[L>>2]=n;c[L+4>>2]=m}}if((l|0)!=0?(c[b+328>>2]=1,l=c[b+28>>2]|0,(l|0)>0):0){m=(c[b+16>>2]|0)+(l+-1<<2)|0;c[m>>2]=c[m>>2]|512}c[i>>2]=o+1;q=0;return q|0}function kb(a){a=a|0;var b=0,d=0;if((c[a+4>>2]|0)<=-1){b=-1;return b|0}d=a+8|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;c[d+16>>2]=0;b=0;return b|0}function lb(a){a=a|0;var b=0,d=0;if(!a){b=-1;return b|0}if(!(c[a>>2]|0)){b=-1;return b|0}c[a+8>>2]=0;c[a+12>>2]=0;c[a+28>>2]=0;c[a+32>>2]=0;c[a+36>>2]=0;c[a+324>>2]=0;c[a+328>>2]=0;c[a+332>>2]=0;c[a+340>>2]=-1;d=a+344|0;c[d>>2]=0;c[d+4>>2]=0;c[d+8>>2]=0;c[d+12>>2]=0;b=0;return b|0}function mb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;if(!a){d=0;return d|0}e=c[a>>2]|0;if(!e){d=0;return d|0}f=a+36|0;g=c[f>>2]|0;if((c[a+32>>2]|0)<=(g|0)){d=0;return d|0}h=c[a+16>>2]|0;i=c[h+(g<<2)>>2]|0;if(i&1024){c[f>>2]=g+1;j=a+344|0;k=j;l=Me(c[k>>2]|0,c[k+4>>2]|0,1,0)|0;k=j;c[k>>2]=l;c[k+4>>2]=C;d=-1;return d|0}k=(b|0)==0;l=i&255;j=i&512;m=i&256;if((l|0)==255){i=255;n=j;o=g;while(1){p=o+1|0;q=c[h+(p<<2)>>2]|0;r=q&255;s=(q&512|0)==0?n:512;q=r+i|0;if((r|0)==255){i=q;n=s;o=p}else{t=q;u=s;v=p;break}}}else{t=l;u=j;v=g}if(k){k=a+12|0;g=a+344|0;j=g;w=g;x=k;y=c[k>>2]|0;z=c[j>>2]|0;A=c[j+4>>2]|0}else{c[b+12>>2]=u;c[b+8>>2]=m;m=a+12|0;u=c[m>>2]|0;c[b>>2]=e+u;e=a+344|0;j=e;k=c[j>>2]|0;g=c[j+4>>2]|0;j=b+24|0;c[j>>2]=k;c[j+4>>2]=g;j=(c[a+20>>2]|0)+(v<<3)|0;a=c[j+4>>2]|0;l=b+16|0;c[l>>2]=c[j>>2];c[l+4>>2]=a;c[b+4>>2]=t;w=e;x=m;y=u;z=k;A=g}c[x>>2]=y+t;c[f>>2]=v+1;v=Me(z|0,A|0,1,0)|0;A=w;c[A>>2]=v;c[A+4>>2]=C;d=1;return d|0}function nb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=a+24|0;e=c[d>>2]|0;if((e-b|0)>(c[a+28>>2]|0)){f=0;return f|0}if((e|0)>(2147483647-b|0)){g=c[a>>2]|0;if(g)ze(g);g=c[a+16>>2]|0;if(g)ze(g);g=c[a+20>>2]|0;if(g)ze(g);He(a|0,0,360)|0;f=-1;return f|0}g=e+b|0;b=(g|0)<2147483615?g+32|0:g;g=a+16|0;e=Be(c[g>>2]|0,b<<2)|0;if(!e){h=c[a>>2]|0;if(h)ze(h);h=c[g>>2]|0;if(h)ze(h);h=c[a+20>>2]|0;if(h)ze(h);He(a|0,0,360)|0;f=-1;return f|0}c[g>>2]=e;e=a+20|0;h=Be(c[e>>2]|0,b<<3)|0;if(h){c[e>>2]=h;c[d>>2]=b;f=0;return f|0}b=c[a>>2]|0;if(b)ze(b);b=c[g>>2]|0;if(b)ze(b);b=c[e>>2]|0;if(b)ze(b);He(a|0,0,360)|0;f=-1;return f|0}function ob(a){a=a|0;var b=0,d=0,e=0,f=0,g=0;b=i;i=i+16|0;d=b+8|0;e=b+4|0;f=b;c[e>>2]=a;if(sc(c[e>>2]|0)|0){c[d>>2]=0;g=c[d>>2]|0;i=b;return g|0}c[f>>2]=ye(568)|0;if(!(c[f>>2]|0)){c[d>>2]=0;g=c[d>>2]|0;i=b;return g|0}c[c[f>>2]>>2]=c[e>>2];c[(c[f>>2]|0)+4>>2]=0;c[(c[f>>2]|0)+8>>2]=0;c[(c[f>>2]|0)+64>>2]=0;c[(c[f>>2]|0)+68>>2]=0;c[(c[f>>2]|0)+72>>2]=1024;c[(c[f>>2]|0)+76>>2]=0;e=_b()|0;c[(c[f>>2]|0)+80>>2]=e;do if(c[(c[f>>2]|0)+80>>2]|0){c[(c[f>>2]|0)+84>>2]=0;c[(c[f>>2]|0)+88>>2]=0;c[(c[f>>2]|0)+92>>2]=0;c[(c[f>>2]|0)+96>>2]=0;c[(c[f>>2]|0)+100>>2]=0;c[(c[f>>2]|0)+104>>2]=0;e=gc()|0;c[(c[f>>2]|0)+560>>2]=e;e=c[f>>2]|0;if(!(c[(c[f>>2]|0)+560>>2]|0)){ze(c[e+80>>2]|0);break}Eb(e)|0;c[d>>2]=c[f>>2];g=c[d>>2]|0;i=b;return g|0}while(0);ze(c[f>>2]|0);c[d>>2]=0;g=c[d>>2]|0;i=b;return g|0}function pb(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;d=b+4|0;e=b;c[e>>2]=a;if(!(c[e>>2]|0)){c[d>>2]=-2;f=c[d>>2]|0;i=b;return f|0}Fb(c[e>>2]|0)|0;dc(c[(c[e>>2]|0)+80>>2]|0,1)|0;$b(c[(c[e>>2]|0)+80>>2]|0);lc(c[(c[e>>2]|0)+560>>2]|0,2)|0;hc(c[(c[e>>2]|0)+560>>2]|0);if(c[(c[e>>2]|0)+96>>2]|0)ze(c[(c[e>>2]|0)+92>>2]|0);if((c[(c[e>>2]|0)+4>>2]|0)!=0?(Aa(c[(c[e>>2]|0)+4>>2]|0)|0)==-1:0){c[d>>2]=-10;f=c[d>>2]|0;i=b;return f|0}if(c[(c[e>>2]|0)+8>>2]|0){Db(c[e>>2]|0)|0;ze(c[(c[e>>2]|0)+8>>2]|0)}ze(c[e>>2]|0);c[d>>2]=0;f=c[d>>2]|0;i=b;return f|0}function qb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=i;i=i+16|0;d=b;e=b+12|0;f=b+8|0;c[e>>2]=a;do if(c[e>>2]|0)if(c[c[e>>2]>>2]&1){a=d;c[a>>2]=-3;c[a+4>>2]=-1;break}else{c[f>>2]=(c[e>>2]|0)+112;a=(c[f>>2]|0)+416|0;g=c[a+4>>2]|0;h=d;c[h>>2]=c[a>>2];c[h+4>>2]=g;break}else{g=d;c[g>>2]=-2;c[g+4>>2]=-1}while(0);f=d;C=c[f+4>>2]|0;i=b;return c[f>>2]|0}function rb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0;b=i;i=i+16|0;d=b;e=b+8|0;c[e>>2]=a;do if(c[e>>2]|0)if(c[c[e>>2]>>2]&1){a=d;c[a>>2]=-3;c[a+4>>2]=-1;break}else{a=(c[e>>2]|0)+112+424|0;f=c[a+4>>2]|0;g=d;c[g>>2]=c[a>>2];c[g+4>>2]=f;break}else{f=d;c[f>>2]=-2;c[f+4>>2]=-1}while(0);e=d;C=c[e+4>>2]|0;i=b;return c[e>>2]|0}function sb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[f>>2]=a;c[g>>2]=b;if((c[g>>2]|0)==-1){c[e>>2]=0;h=c[e>>2]|0;i=d;return h|0}else{c[e>>2]=cc(c[(c[f>>2]|0)+80>>2]|0,1,c[g>>2]|0)|0;h=c[e>>2]|0;i=d;return h|0}return 0}function tb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;c[h>>2]=ye(512)|0;if(!(c[h>>2]|0)){c[e>>2]=0;j=c[e>>2]|0;i=d;return j|0}cb(c[h>>2]|0,c[g>>2]|0)|0;g=(yb(c[h>>2]|0)|0)==-1;b=c[h>>2]|0;if(g){ze(b);c[e>>2]=0;j=c[e>>2]|0;i=d;return j|0}else{c[b+360>>2]=15;c[(c[h>>2]|0)+364>>2]=3;c[(c[h>>2]|0)+368>>2]=0;b=(c[h>>2]|0)+376|0;c[b>>2]=1;c[b+4>>2]=0;b=(c[h>>2]|0)+384|0;c[b>>2]=1;c[b+4>>2]=0;b=(c[h>>2]|0)+392|0;c[b>>2]=0;c[b+4>>2]=0;b=(c[h>>2]|0)+400|0;c[b>>2]=0;c[b+4>>2]=0;c[(c[h>>2]|0)+408>>2]=0;c[(c[h>>2]|0)+420>>2]=0;c[(c[h>>2]|0)+424>>2]=1;c[(c[h>>2]|0)+428>>2]=0;b=(c[h>>2]|0)+432|0;c[b>>2]=0;c[b+4>>2]=0;b=(c[h>>2]|0)+440|0;c[b>>2]=-1;c[b+4>>2]=-1;c[(c[h>>2]|0)+448>>2]=0;c[(c[h>>2]|0)+452>>2]=0;c[(c[h>>2]|0)+456>>2]=0;c[(c[h>>2]|0)+460>>2]=0;c[(c[h>>2]|0)+464>>2]=0;c[(c[h>>2]|0)+468>>2]=0;c[(c[h>>2]|0)+472>>2]=0;c[(c[h>>2]|0)+476>>2]=0;c[(c[h>>2]|0)+480>>2]=0;c[(c[h>>2]|0)+504>>2]=0;ec(c[(c[f>>2]|0)+80>>2]|0,c[h>>2]|0)|0;c[e>>2]=c[h>>2];j=c[e>>2]|0;i=d;return j|0}return 0}function ub(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=i;i=i+32|0;h=g+8|0;j=g+16|0;k=g+20|0;l=g+24|0;m=g+4|0;n=g;o=g+12|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;if(!(c[j>>2]|0)){c[h>>2]=-2;p=c[h>>2]|0;i=g;return p|0}f=c[j>>2]|0;if((c[k>>2]|0)==-1){if((c[f+96>>2]|0)!=0?(c[(c[j>>2]|0)+92>>2]|0)!=0:0)ze(c[(c[j>>2]|0)+92>>2]|0);c[(c[j>>2]|0)+88>>2]=c[l>>2];c[(c[j>>2]|0)+92>>2]=c[m>>2];c[(c[j>>2]|0)+96>>2]=c[n>>2]}else{c[o>>2]=sb(f,c[k>>2]|0)|0;if(!(c[o>>2]|0)){c[h>>2]=-20;p=c[h>>2]|0;i=g;return p|0}if((c[(c[o>>2]|0)+456>>2]|0)!=0?(c[(c[o>>2]|0)+452>>2]|0)!=0:0)ze(c[(c[o>>2]|0)+452>>2]|0);c[(c[o>>2]|0)+448>>2]=c[l>>2];c[(c[o>>2]|0)+452>>2]=c[m>>2];c[(c[o>>2]|0)+456>>2]=c[n>>2]}c[h>>2]=0;p=c[h>>2]|0;i=g;return p|0}function vb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;do if(!(c[(c[f>>2]|0)+88>>2]|0)){c[h>>2]=sb(c[f>>2]|0,c[g>>2]|0)|0;if(!(c[h>>2]|0)){c[e>>2]=-20;break}if(c[(c[h>>2]|0)+448>>2]|0){c[e>>2]=1;break}else{c[e>>2]=0;break}}else c[e>>2]=1;while(0);i=d;return c[e>>2]|0}function wb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;f=i;i=i+32|0;g=f+8|0;h=f+24|0;j=f+20|0;k=f;l=f+16|0;c[h>>2]=a;c[j>>2]=b;b=k;c[b>>2]=d;c[b+4>>2]=e;do if(!(c[h>>2]|0)){e=g;c[e>>2]=-2;c[e+4>>2]=-1}else{e=k;if((c[e>>2]|0)==-1?(c[e+4>>2]|0)==-1:0){e=g;c[e>>2]=-1;c[e+4>>2]=-1;break}e=c[h>>2]|0;if((c[j>>2]|0)==-1){if(c[e+88>>2]|0){b=k;d=Qa[c[(c[h>>2]|0)+88>>2]&31](c[h>>2]|0,c[j>>2]|0,c[b>>2]|0,c[b+4>>2]|0,c[(c[h>>2]|0)+92>>2]|0)|0;b=g;c[b>>2]=d;c[b+4>>2]=C;break}}else{c[l>>2]=sb(e,c[j>>2]|0)|0;if(!(c[l>>2]|0)){e=g;c[e>>2]=-1;c[e+4>>2]=-1;break}if(c[(c[l>>2]|0)+448>>2]|0){e=k;b=Qa[c[(c[l>>2]|0)+448>>2]&31](c[h>>2]|0,c[j>>2]|0,c[e>>2]|0,c[e+4>>2]|0,c[(c[l>>2]|0)+452>>2]|0)|0;e=g;c[e>>2]=b;c[e+4>>2]=C;break}if(c[(c[h>>2]|0)+88>>2]|0){e=k;b=Qa[c[(c[h>>2]|0)+88>>2]&31](c[h>>2]|0,c[j>>2]|0,c[e>>2]|0,c[e+4>>2]|0,c[(c[h>>2]|0)+92>>2]|0)|0;e=g;c[e>>2]=b;c[e+4>>2]=C;break}}e=g;c[e>>2]=-1;c[e+4>>2]=-1}while(0);h=g;C=c[h+4>>2]|0;i=f;return c[h>>2]|0}function xb(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[e>>2]=a;a=c[e>>2]|0;if((a|0)==1)c[d>>2]=-14;else if((a|0)==-1)c[d>>2]=-15;else if(!a)c[d>>2]=0;else c[d>>2]=c[e>>2];i=b;return c[d>>2]|0}function yb(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;d=b+4|0;e=b;c[e>>2]=a;c[(c[e>>2]|0)+412>>2]=0;a=_b()|0;c[(c[e>>2]|0)+416>>2]=a;if(!(c[(c[e>>2]|0)+416>>2]|0)){c[d>>2]=-1;f=c[d>>2]|0;i=b;return f|0}else{fc(c[(c[e>>2]|0)+416>>2]|0,1,0)|0;c[d>>2]=0;f=c[d>>2]|0;i=b;return f|0}return 0}function zb(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;d=b;c[d>>2]=a;dc(c[(c[d>>2]|0)+416>>2]|0,1)|0;$b(c[(c[d>>2]|0)+416>>2]|0);c[(c[d>>2]|0)+416>>2]=0;if(!(c[(c[d>>2]|0)+412>>2]|0)){e=c[d>>2]|0;f=e+412|0;c[f>>2]=0;i=b;return 0}ze(c[(c[d>>2]|0)+412>>2]|0);e=c[d>>2]|0;f=e+412|0;c[f>>2]=0;i=b;return 0}function Ab(b,d,e,f){b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0;g=i;i=i+64|0;h=g+52|0;j=g+44|0;k=g+24|0;l=g+20|0;m=g+12|0;n=g+40|0;o=g+48|0;p=g+56|0;q=g+28|0;r=g+8|0;s=g+4|0;t=g+32|0;u=g;v=g+16|0;w=g+36|0;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[m>>2]=f;c[o>>2]=c[l>>2];c[w>>2]=0;if((c[m>>2]|0)<8){c[h>>2]=-1;x=c[h>>2]|0;i=g;return x|0}c[t>>2]=(c[o>>2]|0)+(c[m>>2]|0);c[s>>2]=a[(c[o>>2]|0)+3>>0]<<24&-16777216|a[(c[o>>2]|0)+2>>0]<<16&16711680|a[(c[o>>2]|0)+1>>0]<<8&65280|a[c[o>>2]>>0]&255;c[o>>2]=(c[o>>2]|0)+4;if((c[s>>2]|0)>>>0>((c[t>>2]|0)-(c[o>>2]|0)|0)>>>0){c[h>>2]=-1;x=c[h>>2]|0;i=g;return x|0}c[n>>2]=sb(c[j>>2]|0,c[k>>2]|0)|0;if(!(c[n>>2]|0)){c[h>>2]=-20;x=c[h>>2]|0;i=g;return x|0}if((c[s>>2]|0)>>>0>0){m=yc(c[o>>2]|0,c[s>>2]|0)|0;c[w>>2]=m;if(!m){c[h>>2]=-18;x=c[h>>2]|0;i=g;return x|0}m=(zc(c[j>>2]|0,c[k>>2]|0,c[w>>2]|0)|0)==-18;ze(c[w>>2]|0);if(m){c[h>>2]=-18;x=c[h>>2]|0;i=g;return x|0}}c[o>>2]=(c[o>>2]|0)+(c[s>>2]|0);if(((c[o>>2]|0)+4|0)>>>0>(c[t>>2]|0)>>>0){c[h>>2]=-1;x=c[h>>2]|0;i=g;return x|0}c[q>>2]=a[(c[o>>2]|0)+3>>0]<<24&-16777216|a[(c[o>>2]|0)+2>>0]<<16&16711680|a[(c[o>>2]|0)+1>>0]<<8&65280|a[c[o>>2]>>0]&255;c[o>>2]=(c[o>>2]|0)+4;c[p>>2]=0;while(1){if((c[p>>2]|0)>=(c[q>>2]|0)){y=34;break}if(((c[o>>2]|0)+4|0)>>>0>(c[t>>2]|0)>>>0){y=17;break}c[s>>2]=a[(c[o>>2]|0)+3>>0]<<24&-16777216|a[(c[o>>2]|0)+2>>0]<<16&16711680|a[(c[o>>2]|0)+1>>0]<<8&65280|a[c[o>>2]>>0]&255;c[o>>2]=(c[o>>2]|0)+4;if((c[s>>2]|0)>>>0>((c[t>>2]|0)-(c[o>>2]|0)|0)>>>0){y=19;break}c[r>>2]=0;c[u>>2]=c[o>>2];c[v>>2]=Ac(c[o>>2]|0,61,c[s>>2]|0)|0;if(c[v>>2]|0){a[c[v>>2]>>0]=0;c[v>>2]=(c[v>>2]|0)+1;c[r>>2]=(c[o>>2]|0)+(c[s>>2]|0)-(c[v>>2]|0)}if(c[r>>2]|0){m=yc(c[v>>2]|0,c[r>>2]|0)|0;c[w>>2]=m;if(!m){y=24;break}m=(Bc(c[n>>2]|0,c[u>>2]|0,c[w>>2]|0)|0)==0;ze(c[w>>2]|0);if(m){y=26;break}}else{m=yc(c[u>>2]|0,c[s>>2]|0)|0;c[w>>2]=m;if(!m){y=28;break}m=(Bc(c[n>>2]|0,c[w>>2]|0,0)|0)==0;ze(c[w>>2]|0);if(m){y=30;break}}if(c[v>>2]|0)a[(c[v>>2]|0)+-1>>0]=61;c[o>>2]=(c[o>>2]|0)+(c[s>>2]|0);c[p>>2]=(c[p>>2]|0)+1}if((y|0)==17){c[h>>2]=-1;x=c[h>>2]|0;i=g;return x|0}else if((y|0)==19){c[h>>2]=-1;x=c[h>>2]|0;i=g;return x|0}else if((y|0)==24){c[h>>2]=-18;x=c[h>>2]|0;i=g;return x|0}else if((y|0)==26){c[h>>2]=-18;x=c[h>>2]|0;i=g;return x|0}else if((y|0)==28){c[h>>2]=-18;x=c[h>>2]|0;i=g;return x|0}else if((y|0)==30){c[h>>2]=-18;x=c[h>>2]|0;i=g;return x|0}else if((y|0)==34){c[h>>2]=0;x=c[h>>2]|0;i=g;return x|0}return 0}function Bb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;d=c[g>>2]|0;do if(c[(c[g>>2]|0)+4>>2]|0)if((ya(c[d+4>>2]|0,c[h>>2]|0,c[j>>2]|0)|0)==-1)c[f>>2]=-10;else l=10;else{b=c[d+8>>2]|0;c[k>>2]=b;if(!b){c[f>>2]=-3;break}if(!(c[(c[k>>2]|0)+16>>2]|0)){c[f>>2]=-1;break}if((La[c[(c[k>>2]|0)+16>>2]&1](c[(c[k>>2]|0)+20>>2]|0,c[h>>2]|0,c[j>>2]|0)|0)==-1)c[f>>2]=-1;else l=10}while(0);if((l|0)==10)c[f>>2]=0;i=e;return c[f>>2]|0}function Cb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0;b=i;i=i+16|0;d=b+12|0;e=b+8|0;f=b+4|0;g=b;c[e>>2]=a;a=c[e>>2]|0;do if(c[(c[e>>2]|0)+4>>2]|0){h=Ca(c[a+4>>2]|0)|0;c[g>>2]=h;if((h|0)==-1)c[d>>2]=-1;else j=10}else{h=c[a+8>>2]|0;c[f>>2]=h;if(!h){c[d>>2]=-3;break}if(!(c[(c[f>>2]|0)+24>>2]|0)){c[d>>2]=-1;break}h=Na[c[(c[f>>2]|0)+24>>2]&7](c[(c[f>>2]|0)+28>>2]|0)|0;c[g>>2]=h;if((h|0)==-1)c[d>>2]=-1;else j=10}while(0);if((j|0)==10)c[d>>2]=c[g>>2];i=b;return c[d>>2]|0}function Db(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=i;i=i+16|0;d=b+8|0;e=b+4|0;f=b;c[e>>2]=a;a=c[e>>2]|0;do if(c[(c[e>>2]|0)+4>>2]|0)if((oa(c[a+4>>2]|0)|0)==-1)c[d>>2]=-10;else g=10;else{h=c[a+8>>2]|0;c[f>>2]=h;if(!h){c[d>>2]=-3;break}if(!(c[(c[f>>2]|0)+32>>2]|0)){c[d>>2]=-3;break}if((Na[c[(c[f>>2]|0)+32>>2]&7](c[(c[f>>2]|0)+36>>2]|0)|0)==-1)c[d>>2]=-1;else g=10}while(0);if((g|0)==10)c[d>>2]=0;i=b;return c[d>>2]|0}function Eb(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;c[e>>2]=(c[d>>2]|0)+112;eb(c[e>>2]|0)|0;cb((c[e>>2]|0)+32|0,-1)|0;c[(c[e>>2]|0)+392>>2]=-1;c[(c[e>>2]|0)+396>>2]=0;c[(c[e>>2]|0)+400>>2]=0;c[(c[e>>2]|0)+404>>2]=0;c[(c[e>>2]|0)+408>>2]=0;a=(c[e>>2]|0)+416|0;c[a>>2]=0;c[a+4>>2]=0;c[(c[e>>2]|0)+432>>2]=0;c[(c[e>>2]|0)+436>>2]=0;c[(c[e>>2]|0)+440>>2]=0;i=b;return c[d>>2]|0}function Fb(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;c[e>>2]=(c[d>>2]|0)+112;db((c[e>>2]|0)+32|0)|0;fb(c[e>>2]|0)|0;i=b;return c[d>>2]|0}function Gb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;f=i;i=i+32|0;g=f+8|0;h=f+16|0;j=f+20|0;k=f+24|0;l=f+4|0;m=f;n=f+12|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;if(!(c[h>>2]|0)){c[g>>2]=-2;o=c[g>>2]|0;i=f;return o|0}c[m>>2]=(c[h>>2]|0)+112;if(c[c[h>>2]>>2]&1){c[g>>2]=-3;o=c[g>>2]|0;i=f;return o|0}do if((c[j>>2]|0)==-1){c[(c[m>>2]|0)+396>>2]=c[k>>2];c[(c[m>>2]|0)+400>>2]=c[l>>2]}else{c[n>>2]=sb(c[h>>2]|0,c[j>>2]|0)|0;if(!(c[n>>2]|0))c[n>>2]=tb(c[h>>2]|0,c[j>>2]|0)|0;if(c[n>>2]|0){c[(c[n>>2]|0)+468>>2]=c[k>>2];c[(c[n>>2]|0)+472>>2]=c[l>>2];break}c[g>>2]=-18;o=c[g>>2]|0;i=f;return o|0}while(0);c[g>>2]=0;o=c[g>>2]|0;i=f;return o|0}function Hb(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;g=i;i=i+32|0;h=g+4|0;j=g+16|0;k=g+8|0;l=g+20|0;m=g+28|0;n=g;o=g+12|0;p=g+24|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[n>>2]=f;c[p>>2]=c[k>>2];f=ye(72)|0;c[o>>2]=f;if(!f){c[h>>2]=0;q=c[h>>2]|0;i=g;return q|0}f=c[o>>2]|0;e=c[k>>2]|0;k=f+56|0;do{c[f>>2]=c[e>>2];f=f+4|0;e=e+4|0}while((f|0)<(k|0));e=ye(c[(c[p>>2]|0)+4>>2]|0)|0;c[c[o>>2]>>2]=e;f=c[o>>2]|0;if(!e){ze(f);c[h>>2]=0;q=c[h>>2]|0;i=g;return q|0}else{Ke(c[f>>2]|0,c[c[p>>2]>>2]|0,c[(c[p>>2]|0)+4>>2]|0)|0;c[(c[o>>2]|0)+56>>2]=c[m>>2];c[(c[o>>2]|0)+68>>2]=c[l>>2];c[(c[o>>2]|0)+60>>2]=c[n>>2];c[(c[o>>2]|0)+64>>2]=c[j>>2];c[h>>2]=c[o>>2];q=c[h>>2]|0;i=g;return q|0}return 0}function Ib(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;ze(c[c[d>>2]>>2]|0);ze(c[d>>2]|0);i=b;return}function Jb(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;c[e>>2]=c[d>>2];Ib(c[e>>2]|0);i=b;return 1}function Kb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0;b=i;i=i+16|0;d=b+12|0;e=b+8|0;f=b+4|0;g=b;c[e>>2]=a;c[f>>2]=c[e>>2];e=(c[f>>2]|0)+32|0;do if(((c[e>>2]|0)==-1?(c[e+4>>2]|0)==-1:0)?(a=(c[(c[f>>2]|0)+56>>2]|0)+488|0,(c[a>>2]|0)!=-1?1:(c[a+4>>2]|0)!=-1):0){c[g>>2]=Xb(c[(c[f>>2]|0)+64>>2]|0,c[(c[f>>2]|0)+68>>2]|0)|0;if(!((c[g>>2]|0)<0|(c[g>>2]|0)>=15)){a=(c[(c[f>>2]|0)+56>>2]|0)+488|0;h=Ub(c[g>>2]|0,c[a>>2]|0,c[a+4>>2]|0,c[(c[f>>2]|0)+56>>2]|0,c[f>>2]|0,c[(c[(c[f>>2]|0)+56>>2]|0)+508>>2]|0)|0;a=(c[f>>2]|0)+32|0;c[a>>2]=h;c[a+4>>2]=C;a=(c[f>>2]|0)+32|0;h=c[a+4>>2]|0;j=(c[(c[f>>2]|0)+56>>2]|0)+488|0;c[j>>2]=c[a>>2];c[j+4>>2]=h;c[(c[(c[f>>2]|0)+56>>2]|0)+508>>2]=c[f>>2];break}c[d>>2]=0;k=c[d>>2]|0;i=b;return k|0}while(0);c[d>>2]=1;k=c[d>>2]|0;i=b;return k|0}function Lb(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;b=i;i=i+32|0;d=b+28|0;e=b+24|0;f=b+20|0;g=b+8|0;h=b;j=b+16|0;c[e>>2]=a;c[f>>2]=c[e>>2];e=(c[f>>2]|0)+32|0;if((c[e>>2]|0)==-1?(c[e+4>>2]|0)==-1:0){c[d>>2]=0;k=c[d>>2]|0;i=b;return k|0}e=(c[(c[f>>2]|0)+60>>2]|0)+424|0;a=c[e+4>>2]|0;l=g;c[l>>2]=c[e>>2];c[l+4>>2]=a;a=(c[(c[f>>2]|0)+60>>2]|0)+416|0;l=c[a+4>>2]|0;e=h;c[e>>2]=c[a>>2];c[e+4>>2]=l;l=(c[f>>2]|0)+32|0;e=c[l+4>>2]|0;a=(c[(c[f>>2]|0)+60>>2]|0)+424|0;c[a>>2]=c[l>>2];c[a+4>>2]=e;e=(c[f>>2]|0)+32|0;a=wb(c[(c[f>>2]|0)+64>>2]|0,c[(c[f>>2]|0)+68>>2]|0,c[e>>2]|0,c[e+4>>2]|0)|0;e=(c[(c[f>>2]|0)+60>>2]|0)+416|0;c[e>>2]=a;c[e+4>>2]=C;e=c[f>>2]|0;if(c[(c[(c[f>>2]|0)+56>>2]|0)+468>>2]|0){a=Oa[c[(c[e+56>>2]|0)+468>>2]&15](c[(c[f>>2]|0)+64>>2]|0,c[f>>2]|0,c[(c[f>>2]|0)+68>>2]|0,c[(c[(c[f>>2]|0)+56>>2]|0)+472>>2]|0)|0;c[j>>2]=a;if((a|0)<0?(c[(c[(c[f>>2]|0)+64>>2]|0)+76>>2]=c[j>>2],(c[j>>2]|0)==-1):0){c[d>>2]=-1;k=c[d>>2]|0;i=b;return k|0}}else if(((c[(c[e+60>>2]|0)+396>>2]|0)!=0?(e=Oa[c[(c[(c[f>>2]|0)+60>>2]|0)+396>>2]&15](c[(c[f>>2]|0)+64>>2]|0,c[f>>2]|0,c[(c[f>>2]|0)+68>>2]|0,c[(c[(c[f>>2]|0)+60>>2]|0)+400>>2]|0)|0,c[j>>2]=e,(e|0)<0):0)?(c[(c[(c[f>>2]|0)+64>>2]|0)+76>>2]=c[j>>2],(c[j>>2]|0)==-1):0){c[d>>2]=-1;k=c[d>>2]|0;i=b;return k|0}j=g;g=c[j+4>>2]|0;e=(c[(c[f>>2]|0)+60>>2]|0)+424|0;c[e>>2]=c[j>>2];c[e+4>>2]=g;g=h;h=c[g+4>>2]|0;e=(c[(c[f>>2]|0)+60>>2]|0)+416|0;c[e>>2]=c[g>>2];c[e+4>>2]=h;Ib(c[f>>2]|0);c[d>>2]=1;k=c[d>>2]|0;i=b;return k|0}function Mb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;e=i;i=i+48|0;f=e;g=e+16|0;h=e+28|0;j=e+4|0;k=e+32|0;l=e+36|0;m=e+12|0;n=e+24|0;o=e+20|0;p=e+8|0;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[n>>2]=c[j>>2];c[o>>2]=0;c[p>>2]=0;if(!(c[g>>2]|0)){c[f>>2]=-2;q=c[f>>2]|0;i=e;return q|0}if(c[c[g>>2]>>2]&1){c[f>>2]=-3;q=c[f>>2]|0;i=e;return q|0}j=c[(c[g>>2]|0)+76>>2]|0;c[p>>2]=j;d=c[g>>2]|0;if(j){c[d+76>>2]=0;c[f>>2]=xb(c[p>>2]|0)|0;q=c[f>>2]|0;i=e;return q|0}c[k>>2]=d+112;c[p>>2]=Dc(c[g>>2]|0)|0;if((c[p>>2]|0)==-18){c[f>>2]=c[p>>2];q=c[f>>2]|0;i=e;return q|0}while(1){if(!((c[p>>2]|0)!=-1&(c[p>>2]|0)!=1&(c[n>>2]|0)>0))break;c[m>>2]=(c[n>>2]|0)<4096?c[n>>2]|0:4096;c[l>>2]=gb(c[k>>2]|0,c[m>>2]|0)|0;Ke(c[l>>2]|0,c[h>>2]|0,c[m>>2]|0)|0;hb(c[k>>2]|0,c[m>>2]|0)|0;c[h>>2]=(c[h>>2]|0)+(c[m>>2]|0);c[n>>2]=(c[n>>2]|0)-(c[m>>2]|0);c[o>>2]=(c[o>>2]|0)+(c[m>>2]|0);c[p>>2]=Dc(c[g>>2]|0)|0;if((c[p>>2]|0)==-18){r=11;break}}if((r|0)==11){c[f>>2]=c[p>>2];q=c[f>>2]|0;i=e;return q|0}if((c[p>>2]|0)==-1)Ob(c[g>>2]|0)|0;r=(c[p>>2]|0)==-404;if(c[o>>2]|0){if(r)c[p>>2]=0;c[(c[g>>2]|0)+76>>2]=c[p>>2];c[f>>2]=c[o>>2];q=c[f>>2]|0;i=e;return q|0}if(r){c[f>>2]=-14;q=c[f>>2]|0;i=e;return q|0}else{c[f>>2]=xb(c[p>>2]|0)|0;q=c[f>>2]|0;i=e;return q|0}return 0}function Nb(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;a=(c[d>>2]|0)+488|0;c[a>>2]=-1;c[a+4>>2]=-1;i=b;return 0}function Ob(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[e>>2]=a;do if(!(c[e>>2]|0))c[d>>2]=-2;else{if(c[c[e>>2]>>2]&1){c[d>>2]=-3;break}Ec(c[e>>2]|0);if((c[(c[e>>2]|0)+4>>2]|0)!=0?(Fc(c[e>>2]|0,c[(c[e>>2]|0)+64>>2]|0,-1,-1,0)|0)<0:0){c[d>>2]=-10;break}c[d>>2]=0}while(0);i=b;return c[d>>2]|0}function Pb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0;e=i;i=i+32|0;f=e+24|0;g=e+20|0;h=e+16|0;j=e+12|0;k=e+8|0;l=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;d=l;c[d>>2]=-1;c[d+4>>2]=-1;if(!(c[g>>2]|0)){c[f>>2]=-1;m=c[f>>2]|0;i=e;return m|0}if(c[c[g>>2]>>2]&1){c[f>>2]=-1;m=c[f>>2]|0;i=e;return m|0}if((c[h>>2]|0)==0&(c[j>>2]|0)==0){d=l;c[d>>2]=0;c[d+4>>2]=0}c[k>>2]=(c[g>>2]|0)+112;if(!((c[h>>2]|0)==0&(c[j>>2]|0)==1)){d=(c[k>>2]|0)+416|0;c[d>>2]=-1;c[d+4>>2]=-1}d=l;c[f>>2]=Fc(c[g>>2]|0,c[h>>2]|0,c[d>>2]|0,c[d+4>>2]|0,c[j>>2]|0)|0;m=c[f>>2]|0;i=e;return m|0}function Qb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;d=Hc(c[f>>2]|0,c[h>>2]|0,c[(c[g>>2]|0)+8>>2]|0,c[(c[g>>2]|0)+12>>2]|0)|0;i=e;return d|0}function Rb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;i=i+32|0;g=f+20|0;h=f+16|0;j=f+12|0;k=f+8|0;l=f+4|0;m=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[m>>2]=0;c[m>>2]=Xb(c[h>>2]|0,c[k>>2]|0)|0;if((c[m>>2]|0)<0|(c[m>>2]|0)>=15){c[g>>2]=0;n=c[g>>2]|0;i=f;return n|0}if((c[m>>2]|0)==6?($a(c[j>>2]|0)|0)==0:0){c[g>>2]=Ic(c[h>>2]|0,c[k>>2]|0,c[(c[j>>2]|0)+8>>2]|0,c[(c[j>>2]|0)+12>>2]|0,c[l>>2]|0)|0;n=c[g>>2]|0;i=f;return n|0}c[g>>2]=Qa[c[1040+((c[m>>2]|0)*24|0)+12>>2]&31](c[h>>2]|0,c[k>>2]|0,c[(c[j>>2]|0)+8>>2]|0,c[(c[j>>2]|0)+12>>2]|0,c[l>>2]|0)|0;n=c[g>>2]|0;i=f;return n|0}function Sb(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;i=i+32|0;g=f+20|0;h=f+16|0;j=f+12|0;k=f+8|0;l=f+4|0;m=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[m>>2]=0;c[m>>2]=Xb(c[h>>2]|0,c[k>>2]|0)|0;if((c[m>>2]|0)<0|(c[m>>2]|0)>=15){c[g>>2]=0;n=c[g>>2]|0;i=f;return n|0}if((c[m>>2]|0)==6?(c[(c[j>>2]|0)+8>>2]|0)==0:0){c[g>>2]=Ic(c[h>>2]|0,c[k>>2]|0,c[c[j>>2]>>2]|0,c[(c[j>>2]|0)+4>>2]|0,c[l>>2]|0)|0;n=c[g>>2]|0;i=f;return n|0}c[g>>2]=Qa[c[1040+((c[m>>2]|0)*24|0)+12>>2]&31](c[h>>2]|0,c[k>>2]|0,c[c[j>>2]>>2]|0,c[(c[j>>2]|0)+4>>2]|0,c[l>>2]|0)|0;n=c[g>>2]|0;i=f;return n|0}function Tb(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;g=i;i=i+48|0;h=g+16|0;j=g+32|0;k=g+8|0;l=g+28|0;m=g+24|0;n=g;c[j>>2]=a;a=k;c[a>>2]=b;c[a+4>>2]=d;c[l>>2]=e;c[m>>2]=f;if(c[1040+((c[j>>2]|0)*24|0)+16>>2]|0){f=k;e=Oa[c[1040+((c[j>>2]|0)*24|0)+16>>2]&15](c[f>>2]|0,c[f+4>>2]|0,c[l>>2]|0,c[m>>2]|0)|0;m=n;c[m>>2]=e;c[m+4>>2]=C;m=n;n=c[m+4>>2]|0;e=h;c[e>>2]=c[m>>2];c[e+4>>2]=n;o=h;p=o;q=c[p>>2]|0;r=o+4|0;s=r;t=c[s>>2]|0;C=t;i=g;return q|0}else{n=k;k=c[n+4>>2]|0;e=h;c[e>>2]=c[n>>2];c[e+4>>2]=k;o=h;p=o;q=c[p>>2]|0;r=o+4|0;s=r;t=c[s>>2]|0;C=t;i=g;return q|0}return 0}function Ub(a,b,d,e,f,g){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;h=i;i=i+32|0;j=h+8|0;k=h+28|0;l=h;m=h+24|0;n=h+20|0;o=h+16|0;c[k>>2]=a;a=l;c[a>>2]=b;c[a+4>>2]=d;c[m>>2]=e;c[n>>2]=f;c[o>>2]=g;if(c[1040+((c[k>>2]|0)*24|0)+20>>2]|0){g=l;l=Qa[c[1040+((c[k>>2]|0)*24|0)+20>>2]&31](c[g>>2]|0,c[g+4>>2]|0,c[m>>2]|0,c[n>>2]|0,c[o>>2]|0)|0;o=j;c[o>>2]=l;c[o+4>>2]=C;p=j;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=h;return r|0}else{o=j;c[o>>2]=0;c[o+4>>2]=0;p=j;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=h;return r|0}return 0}function Vb(a,b,e,f){a=a|0;b=b|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0;g=i;i=i+32|0;h=g+20|0;j=g+16|0;k=g+12|0;l=g+8|0;m=g+4|0;n=g;c[h>>2]=a;c[j>>2]=b;c[k>>2]=e;c[l>>2]=f;c[m>>2]=-1;c[n>>2]=-1;switch(c[(c[j>>2]|0)+360>>2]|0){case 3:case 2:{c[m>>2]=0;break}case 14:{if((c[(c[l>>2]|0)+4>>2]|0)>7?(ve(c[c[l>>2]>>2]|0,1472,7)|0)==0:0)c[m>>2]=7;break}case 8:{if((c[(c[l>>2]|0)+4>>2]|0)>4?((d[c[c[l>>2]>>2]>>0]|0)&7|0)==4:0){c[n>>2]=((d[(c[c[l>>2]>>2]|0)+1>>0]|0)<<16)+((d[(c[c[l>>2]>>2]|0)+2>>0]|0)<<8)+(d[(c[c[l>>2]>>2]|0)+3>>0]|0);c[m>>2]=4}break}case 11:{if((c[(c[l>>2]|0)+4>>2]|0)>9?(ve(c[c[l>>2]>>2]|0,1440,8)|0)==0:0)c[m>>2]=9;break}case 0:{if((c[(c[l>>2]|0)+4>>2]|0)>7?(ve(c[c[l>>2]>>2]|0,1432,7)|0)==0:0)c[m>>2]=7;break}case 13:{if((c[(c[l>>2]|0)+4>>2]|0)>8?(ve(c[c[l>>2]>>2]|0,1456,8)|0)==0:0)c[m>>2]=8;break}case 1:{if((c[(c[l>>2]|0)+4>>2]|0)>7?(ve(c[c[l>>2]>>2]|0,1424,7)|0)==0:0)c[m>>2]=7;break}default:{}}if((c[n>>2]|0)==-1)c[n>>2]=(c[(c[l>>2]|0)+4>>2]|0)-(c[m>>2]|0);if((c[m>>2]|0)<0){i=g;return 0}Ab(c[h>>2]|0,c[k>>2]|0,(c[c[l>>2]>>2]|0)+(c[m>>2]|0)|0,c[n>>2]|0)|0;i=g;return 0}function Wb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=sb(c[g>>2]|0,c[h>>2]|0)|0;if(!(c[k>>2]|0)){c[f>>2]=-20;l=c[f>>2]|0;i=e;return l|0}else{c[(c[k>>2]|0)+360>>2]=c[j>>2];c[f>>2]=0;l=c[f>>2]|0;i=e;return l|0}return 0}function Xb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;do if(c[f>>2]|0){c[h>>2]=sb(c[f>>2]|0,c[g>>2]|0)|0;if(!(c[h>>2]|0)){c[e>>2]=-20;break}else{c[e>>2]=c[(c[h>>2]|0)+360>>2];break}}else c[e>>2]=-2;while(0);i=d;return c[e>>2]|0}function Yb(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;do if(c[f>>2]|0){c[h>>2]=sb(c[f>>2]|0,c[g>>2]|0)|0;if(!(c[h>>2]|0)){c[e>>2]=-20;break}else{c[e>>2]=c[(c[h>>2]|0)+364>>2];break}}else c[e>>2]=-2;while(0);i=d;return c[e>>2]|0}function Zb(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;if(!(c[g>>2]|0)){c[f>>2]=-2;l=c[f>>2]|0;i=e;return l|0}c[k>>2]=sb(c[g>>2]|0,c[h>>2]|0)|0;if(!(c[k>>2]|0)){c[f>>2]=-20;l=c[f>>2]|0;i=e;return l|0}else{c[(c[k>>2]|0)+368>>2]=c[j>>2];c[f>>2]=0;l=c[f>>2]|0;i=e;return l|0}return 0}function _b(){var a=0,b=0,d=0,e=0;a=i;i=i+16|0;b=a+4|0;d=a;c[d>>2]=ye(20)|0;if(!(c[d>>2]|0)){c[b>>2]=0;e=c[b>>2]|0;i=a;return e|0}else{c[c[d>>2]>>2]=0;c[(c[d>>2]|0)+4>>2]=0;c[(c[d>>2]|0)+8>>2]=0;c[(c[d>>2]|0)+12>>2]=0;c[(c[d>>2]|0)+16>>2]=0;c[b>>2]=c[d>>2];e=c[b>>2]|0;i=a;return e|0}return 0}function $b(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;Jc(c[d>>2]|0);ze(c[d>>2]|0);i=b;return}function ac(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[e>>2]=a;if(!(c[e>>2]|0))c[d>>2]=0;else c[d>>2]=c[(c[e>>2]|0)+4>>2];i=b;return c[d>>2]|0}function bc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[f>>2]=a;c[g>>2]=b;do if(c[f>>2]|0)if((c[g>>2]|0)>=(c[(c[f>>2]|0)+4>>2]|0)){c[e>>2]=0;break}else{c[e>>2]=c[(c[(c[f>>2]|0)+8>>2]|0)+(c[g>>2]<<2)>>2];break}else c[e>>2]=0;while(0);i=d;return c[e>>2]|0}function cc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;e=i;i=i+32|0;f=e+20|0;g=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[l>>2]=0;while(1){if((c[l>>2]|0)>=(c[(c[g>>2]|0)+4>>2]|0)){m=6;break}c[k>>2]=c[(c[(c[g>>2]|0)+8>>2]|0)+(c[l>>2]<<2)>>2];if(Pa[c[h>>2]&1](c[k>>2]|0,c[j>>2]|0)|0){m=4;break}c[l>>2]=(c[l>>2]|0)+1}if((m|0)==4){c[f>>2]=c[k>>2];n=c[f>>2]|0;i=e;return n|0}else if((m|0)==6){c[f>>2]=0;n=c[f>>2]|0;i=e;return n|0}return 0}function dc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[e>>2]=a;c[f>>2]=b;c[g>>2]=0;while(1){if((c[g>>2]|0)>=(c[(c[e>>2]|0)+4>>2]|0))break;Na[c[f>>2]&7](c[(c[(c[e>>2]|0)+8>>2]|0)+(c[g>>2]<<2)>>2]|0)|0;c[g>>2]=(c[g>>2]|0)+1}i=d;return 0}function ec(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[f>>2]=a;c[g>>2]=b;if(!(Kc(c[f>>2]|0)|0)){c[e>>2]=0;h=c[e>>2]|0;i=d;return h|0}else{c[(c[(c[f>>2]|0)+8>>2]|0)+((c[(c[f>>2]|0)+4>>2]|0)-1<<2)>>2]=c[g>>2];Lc(c[f>>2]|0);c[e>>2]=c[g>>2];h=c[e>>2]|0;i=d;return h|0}return 0}function fc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[(c[f>>2]|0)+12>>2]=c[g>>2];c[(c[f>>2]|0)+16>>2]=c[h>>2];if(!(c[g>>2]|0)){i=e;return 0}Mc(c[f>>2]|0,0,(c[(c[f>>2]|0)+4>>2]|0)-1|0);i=e;return 0}function gc(){var a=0,b=0,d=0,e=0,f=0,g=0;a=i;i=i+16|0;b=a+12|0;d=a+8|0;e=a+4|0;f=a;c[d>>2]=ye(8)|0;if(!(c[d>>2]|0)){c[b>>2]=0;g=c[b>>2]|0;i=a;return g|0}c[e>>2]=ye(12)|0;if(!(c[e>>2]|0)){ze(c[d>>2]|0);c[b>>2]=0;g=c[b>>2]|0;i=a;return g|0}c[f>>2]=ye(12)|0;if(!(c[f>>2]|0)){ze(c[e>>2]|0);ze(c[d>>2]|0);c[b>>2]=0;g=c[b>>2]|0;i=a;return g|0}else{c[c[e>>2]>>2]=c[f>>2];c[(c[e>>2]|0)+4>>2]=0;c[(c[f>>2]|0)+4>>2]=c[e>>2];c[c[f>>2]>>2]=0;c[c[d>>2]>>2]=c[e>>2];c[(c[d>>2]|0)+4>>2]=c[f>>2];c[b>>2]=c[d>>2];g=c[b>>2]|0;i=a;return g|0}return 0}function hc(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;c[e>>2]=c[c[c[d>>2]>>2]>>2];while(1){if(!(c[e>>2]|0))break;ze(c[(c[e>>2]|0)+4>>2]|0);c[e>>2]=c[c[e>>2]>>2]}ze(c[(c[d>>2]|0)+4>>2]|0);ze(c[d>>2]|0);i=b;return}function ic(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;i=b;return (c[c[c[d>>2]>>2]>>2]|0)==(c[(c[d>>2]|0)+4>>2]|0)|0}function jc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;if(!(c[f>>2]|0)){c[e>>2]=-1;j=c[e>>2]|0;i=d;return j|0}c[h>>2]=ye(12)|0;if(!(c[h>>2]|0)){c[e>>2]=-1;j=c[e>>2]|0;i=d;return j|0}else{c[(c[h>>2]|0)+8>>2]=c[g>>2];c[c[h>>2]>>2]=c[(c[f>>2]|0)+4>>2];c[(c[h>>2]|0)+4>>2]=c[(c[(c[f>>2]|0)+4>>2]|0)+4>>2];c[c[(c[h>>2]|0)+4>>2]>>2]=c[h>>2];c[(c[c[h>>2]>>2]|0)+4>>2]=c[h>>2];c[e>>2]=0;j=c[e>>2]|0;i=d;return j|0}return 0}function kc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[e>>2]=a;c[f>>2]=b;c[g>>2]=c[(c[(c[e>>2]|0)+4>>2]|0)+4>>2];while(1){if((c[g>>2]|0)==(c[c[e>>2]>>2]|0)){h=5;break}if(!(Na[c[f>>2]&7](c[(c[g>>2]|0)+8>>2]|0)|0)){h=5;break}c[g>>2]=c[(c[g>>2]|0)+4>>2]}if((h|0)==5){i=d;return}}function lc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;d=i;i=i+32|0;e=d+20|0;f=d+16|0;g=d+12|0;h=d+8|0;j=d+4|0;k=d;c[e>>2]=a;c[f>>2]=b;c[j>>2]=0;c[g>>2]=c[c[c[e>>2]>>2]>>2];while(1){if((c[g>>2]|0)==(c[(c[e>>2]|0)+4>>2]|0)){l=7;break}c[k>>2]=Na[c[f>>2]&7](c[(c[g>>2]|0)+8>>2]|0)|0;if((c[k>>2]|0)==-1)c[j>>2]=-1;if(!(c[k>>2]|0)){l=7;break}c[h>>2]=c[c[g>>2]>>2];c[c[(c[g>>2]|0)+4>>2]>>2]=c[c[g>>2]>>2];c[(c[c[g>>2]>>2]|0)+4>>2]=c[(c[g>>2]|0)+4>>2];ze(c[g>>2]|0);c[g>>2]=c[h>>2]}if((l|0)==7){i=d;return c[j>>2]|0}return 0}function mc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;if(!(c[g>>2]|0)){c[f>>2]=-2;l=c[f>>2]|0;i=e;return l|0}c[k>>2]=sb(c[g>>2]|0,c[h>>2]|0)|0;if(!(c[k>>2]|0)){c[f>>2]=-20;l=c[f>>2]|0;i=e;return l|0}else{c[(c[k>>2]|0)+408>>2]=c[j>>2];c[f>>2]=Nc(c[g>>2]|0,c[h>>2]|0)|0;l=c[f>>2]|0;i=e;return l|0}return 0}function nc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;do if(c[f>>2]|0){c[h>>2]=sb(c[f>>2]|0,c[g>>2]|0)|0;if(!(c[h>>2]|0)){c[e>>2]=-20;break}else{c[e>>2]=c[(c[h>>2]|0)+408>>2];break}}else c[e>>2]=-2;while(0);i=d;return c[e>>2]|0}function oc(a,b,d,e,f,g){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;h=i;i=i+32|0;j=h+28|0;k=h+24|0;l=h+20|0;m=h+8|0;n=h;o=h+16|0;c[k>>2]=a;c[l>>2]=b;b=m;c[b>>2]=d;c[b+4>>2]=e;e=n;c[e>>2]=f;c[e+4>>2]=g;if(!(c[k>>2]|0)){c[j>>2]=-2;p=c[j>>2]|0;i=h;return p|0}c[o>>2]=sb(c[k>>2]|0,c[l>>2]|0)|0;if(!(c[o>>2]|0)){c[j>>2]=-20;p=c[j>>2]|0;i=h;return p|0}else{g=m;m=c[g+4>>2]|0;e=(c[o>>2]|0)+376|0;c[e>>2]=c[g>>2];c[e+4>>2]=m;m=n;n=c[m+4>>2]|0;e=(c[o>>2]|0)+384|0;c[e>>2]=c[m>>2];c[e+4>>2]=n;c[j>>2]=Nc(c[k>>2]|0,c[l>>2]|0)|0;p=c[j>>2]|0;i=h;return p|0}return 0}function pc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;i=i+32|0;g=f+20|0;h=f+16|0;j=f+12|0;k=f+8|0;l=f+4|0;m=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;if(!(c[h>>2]|0)){c[g>>2]=-2;n=c[g>>2]|0;i=f;return n|0}c[m>>2]=sb(c[h>>2]|0,c[j>>2]|0)|0;if(!(c[m>>2]|0)){c[g>>2]=-20;n=c[g>>2]|0;i=f;return n|0}else{j=(c[m>>2]|0)+376|0;h=c[j+4>>2]|0;e=c[k>>2]|0;c[e>>2]=c[j>>2];c[e+4>>2]=h;h=(c[m>>2]|0)+384|0;m=Ve(c[h>>2]|0,c[h+4>>2]|0,1e3,0)|0;h=c[l>>2]|0;c[h>>2]=m;c[h+4>>2]=C;c[g>>2]=0;n=c[g>>2]|0;i=f;return n|0}return 0}function qc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+32|0;g=f+20|0;h=f+16|0;j=f+12|0;k=f;l=f+8|0;c[h>>2]=a;c[j>>2]=b;b=k;c[b>>2]=d;c[b+4>>2]=e;if(!(c[h>>2]|0)){c[g>>2]=-2;m=c[g>>2]|0;i=f;return m|0}c[l>>2]=sb(c[h>>2]|0,c[j>>2]|0)|0;if(!(c[l>>2]|0)){c[g>>2]=-20;m=c[g>>2]|0;i=f;return m|0}else{e=k;k=c[e+4>>2]|0;b=(c[l>>2]|0)+392|0;c[b>>2]=c[e>>2];c[b+4>>2]=k;c[g>>2]=Nc(c[h>>2]|0,c[j>>2]|0)|0;m=c[g>>2]|0;i=f;return m|0}return 0}function rc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;e=i;i=i+48|0;f=e+4|0;g=e+16|0;h=e+8|0;j=e+20|0;k=e+32|0;l=e;m=e+12|0;n=e+24|0;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;Oc(k,c[h>>2]|0,c[j>>2]|0);Pc(k,104);j=Qc(k)|0;c[c[g>>2]>>2]=j;j=Qc(k)|0;c[(c[g>>2]|0)+4>>2]=j;j=Qc(k)|0;c[(c[g>>2]|0)+8>>2]=j;j=Qc(k)|0;c[(c[g>>2]|0)+12>>2]=j;j=Qc(k)|0;c[l>>2]=j;c[(c[g>>2]|0)+20>>2]=j;if((c[l>>2]|0)>>>0>=17){c[f>>2]=-1;o=c[f>>2]|0;i=e;return o|0}c[(c[g>>2]|0)+24>>2]=c[1480+(c[l>>2]<<3)>>2];c[(c[g>>2]|0)+28>>2]=c[1480+(c[l>>2]<<3)+4>>2];if(Rc(k)|0){j=Qc(k)|0;c[(c[g>>2]|0)+24>>2]=j;j=Qc(k)|0;c[(c[g>>2]|0)+28>>2]=j}if(Rc(k)|0){j=Qc(k)|0;c[(c[g>>2]|0)+16>>2]=j}do if(Rc(k)|0){c[m>>2]=Qc(k)|0;if((c[m>>2]|0)<2){c[(c[g>>2]|0)+40>>2]=c[m>>2];break}else{c[(c[g>>2]|0)+40>>2]=0;break}}else c[(c[g>>2]|0)+40>>2]=c[1616+(c[l>>2]<<2)>>2];while(0);c[(c[g>>2]|0)+44>>2]=c[1704+(c[l>>2]<<2)>>2];c[(c[g>>2]|0)+32>>2]=c[1880+(c[1792+(c[l>>2]<<2)>>2]<<3)>>2];c[(c[g>>2]|0)+36>>2]=c[1880+(c[1792+(c[l>>2]<<2)>>2]<<3)+4>>2];if((Rc(k)|0)!=0?(c[n>>2]=Qc(k)|0,c[(c[g>>2]|0)+32>>2]=c[1880+(c[n>>2]<<3)>>2],c[(c[g>>2]|0)+36>>2]=c[1880+(c[n>>2]<<3)+4>>2],(c[n>>2]|0)==0):0){n=Qc(k)|0;c[(c[g>>2]|0)+32>>2]=n;n=Qc(k)|0;c[(c[g>>2]|0)+36>>2]=n}c[f>>2]=0;o=c[f>>2]|0;i=e;return o|0}function sc(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[e>>2]=a;if(c[e>>2]&1)c[d>>2]=-11;else c[d>>2]=0;i=b;return c[d>>2]|0}function tc(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;c[e>>2]=c[d>>2];zb(c[e>>2]|0)|0;if((c[(c[e>>2]|0)+336>>2]|0)!=-1)db(c[e>>2]|0)|0;if(c[(c[e>>2]|0)+456>>2]|0)ze(c[(c[e>>2]|0)+452>>2]|0);if(!(c[(c[e>>2]|0)+504>>2]|0)){f=c[e>>2]|0;ze(f);i=b;return 0}ze(c[(c[e>>2]|0)+504>>2]|0);f=c[e>>2]|0;ze(f);i=b;return 0}function uc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[e>>2]=a;c[f>>2]=b;c[g>>2]=c[e>>2];i=d;return (c[(c[g>>2]|0)+336>>2]|0)==(c[f>>2]|0)|0}function vc(b){b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;i=i+16|0;e=d+8|0;f=d+4|0;g=d;c[f>>2]=b;if(!(c[f>>2]|0)){c[e>>2]=0;h=c[e>>2]|0;i=d;return h|0}c[g>>2]=c[f>>2];while(1){if(!(a[c[g>>2]>>0]|0)){j=10;break}if((a[c[g>>2]>>0]|0)<32){j=8;break}if((a[c[g>>2]>>0]|0)>125){j=8;break}if((a[c[g>>2]>>0]|0)==61){j=8;break}c[g>>2]=(c[g>>2]|0)+1}if((j|0)==8){c[e>>2]=0;h=c[e>>2]|0;i=d;return h|0}else if((j|0)==10){c[e>>2]=1;h=c[e>>2]|0;i=d;return h|0}return 0}function wc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e+12|0;g=e+8|0;h=e+4|0;c[g>>2]=a;c[h>>2]=b;c[e>>2]=d;do if((c[g>>2]|0)!=(c[h>>2]|0)){if(!((c[g>>2]|0)!=0&(c[h>>2]|0)!=0)){c[f>>2]=0;break}if(we(c[c[g>>2]>>2]|0,c[c[h>>2]>>2]|0)|0){c[f>>2]=0;break}if(xe(c[(c[g>>2]|0)+4>>2]|0,c[(c[h>>2]|0)+4>>2]|0)|0){c[f>>2]=0;break}else{c[f>>2]=1;break}}else c[f>>2]=1;while(0);i=e;return c[f>>2]|0}function xc(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;if(!(c[d>>2]|0)){i=b;return}if(c[c[d>>2]>>2]|0)ze(c[c[d>>2]>>2]|0);if(c[(c[d>>2]|0)+4>>2]|0)ze(c[(c[d>>2]|0)+4>>2]|0);ze(c[d>>2]|0);i=b;return}function yc(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;e=i;i=i+16|0;f=e+12|0;g=e+8|0;h=e+4|0;j=e;c[g>>2]=b;c[h>>2]=d;do if(c[g>>2]|0){if(!(c[h>>2]|0)){c[f>>2]=0;break}c[h>>2]=(c[h>>2]|0)>>>0<4294967294?c[h>>2]|0:-2;c[j>>2]=ye((c[h>>2]|0)+1|0)|0;if(!(c[j>>2]|0)){c[f>>2]=0;break}if(!(Le(c[j>>2]|0,c[g>>2]|0,c[h>>2]|0)|0)){ze(c[j>>2]|0);c[f>>2]=0;break}else{a[(c[j>>2]|0)+(c[h>>2]|0)>>0]=0;c[f>>2]=c[j>>2];break}}else c[f>>2]=0;while(0);i=e;return c[f>>2]|0}function zc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;if(!(c[g>>2]|0)){c[f>>2]=-2;l=c[f>>2]|0;i=e;return l|0}c[k>>2]=sb(c[g>>2]|0,c[h>>2]|0)|0;if(!(c[k>>2]|0)){c[f>>2]=-20;l=c[f>>2]|0;i=e;return l|0}if(c[(c[k>>2]|0)+412>>2]|0)ze(c[(c[k>>2]|0)+412>>2]|0);h=Sc(c[j>>2]|0)|0;c[(c[k>>2]|0)+412>>2]=h;if(!h){c[f>>2]=-18;l=c[f>>2]|0;i=e;return l|0}else{c[f>>2]=0;l=c[f>>2]|0;i=e;return l|0}return 0}function Ac(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;i=i+32|0;g=f+12|0;h=f+8|0;j=f+16|0;k=f+4|0;l=f;c[h>>2]=b;a[j>>0]=d;c[k>>2]=e;c[l>>2]=0;while(1){if(!(a[c[h>>2]>>0]|0)){m=7;break}if((c[l>>2]|0)>=(c[k>>2]|0)){m=7;break}if((a[c[h>>2]>>0]|0)==(a[j>>0]|0)){m=5;break}c[l>>2]=(c[l>>2]|0)+1;c[h>>2]=(c[h>>2]|0)+1}if((m|0)==5){c[g>>2]=c[h>>2];n=c[g>>2]|0;i=f;return n|0}else if((m|0)==7){c[g>>2]=0;n=c[g>>2]|0;i=f;return n|0}return 0}function Bc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0;e=i;i=i+32|0;f=e+8|0;g=e+16|0;h=e+20|0;j=e+24|0;k=e+4|0;l=e;m=e+12|0;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[m>>2]=0;a:while(1){d=c[m>>2]|0;if((d|0)>=(ac(c[(c[g>>2]|0)+416>>2]|0)|0)){n=14;break}c[k>>2]=bc(c[(c[g>>2]|0)+416>>2]|0,c[m>>2]|0)|0;do if((c[c[k>>2]>>2]|0)!=0?(we(c[h>>2]|0,c[c[k>>2]>>2]|0)|0)==0:0){d=c[j>>2]|0;if(!(c[(c[k>>2]|0)+4>>2]|0))if(!d){n=7;break a}else break;if((d|0)!=0?(xe(c[j>>2]|0,c[(c[k>>2]|0)+4>>2]|0)|0)==0:0){n=12;break a}if((c[j>>2]|0)==0?(c[(c[k>>2]|0)+4>>2]|0)==0:0){n=12;break a}}while(0);c[m>>2]=(c[m>>2]|0)+1}if((n|0)==7){c[f>>2]=c[k>>2];o=c[f>>2]|0;i=e;return o|0}else if((n|0)==12){c[f>>2]=c[k>>2];o=c[f>>2]|0;i=e;return o|0}else if((n|0)==14){n=Tc(c[h>>2]|0,c[j>>2]|0)|0;c[l>>2]=n;if(!n){c[f>>2]=0;o=c[f>>2]|0;i=e;return o|0}else{c[f>>2]=ec(c[(c[g>>2]|0)+416>>2]|0,c[l>>2]|0)|0;o=c[f>>2]|0;i=e;return o|0}}return 0}function Cc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0;b=i;i=i+16|0;d=b+8|0;e=b+4|0;f=b;c[e>>2]=a;if(!(c[e>>2]|0)){c[d>>2]=0;g=c[d>>2]|0;i=b;return g|0}else{c[f>>2]=Je(c[e>>2]|0)|0;c[d>>2]=(c[f>>2]|0)>>>0<4294967294?c[f>>2]|0:-2;g=c[d>>2]|0;i=b;return g|0}return 0}function Dc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;b=i;i=i+160|0;d=b+120|0;e=b+124|0;f=b+112|0;g=b+88|0;h=b+108|0;j=b+116|0;k=b+100|0;l=b+96|0;m=b+16|0;n=b+136|0;o=b+128|0;p=b;q=b+84|0;r=b+104|0;s=b+92|0;t=b+8|0;u=b+80|0;v=b+72|0;c[e>>2]=a;c[f>>2]=(c[e>>2]|0)+112;c[o>>2]=0;c[j>>2]=m;c[k>>2]=m+32;a:while(1){if(c[o>>2]|0){w=75;break}b:do if((c[o>>2]|0)==0?(c[(c[f>>2]|0)+392>>2]|0)!=-1:0)do{c[l>>2]=c[(c[f>>2]|0)+392>>2];c[g>>2]=sb(c[e>>2]|0,c[l>>2]|0)|0;if((c[g>>2]|0)==0?(a=tb(c[e>>2]|0,c[l>>2]|0)|0,c[g>>2]=a,(a|0)==0):0){w=7;break a}c[h>>2]=c[g>>2];c[q>>2]=mb(c[h>>2]|0,c[j>>2]|0)|0;if((c[q>>2]|0)==-1){a=(c[g>>2]|0)+440|0;x=c[a+4>>2]|0;y=(c[(c[g>>2]|0)+364>>2]|0)-1|0;z=((y|0)<0)<<31>>31;if((x|0)<(z|0)|((x|0)==(z|0)?(c[a>>2]|0)>>>0<y>>>0:0)){w=10;break a}c[q>>2]=mb(c[h>>2]|0,c[j>>2]|0)|0;if((c[q>>2]|0)==-1){w=12;break a}c[(c[f>>2]|0)+440>>2]=1;c[(c[f>>2]|0)+436>>2]=c[(c[e>>2]|0)+64>>2];c[(c[f>>2]|0)+444>>2]=1}if((c[q>>2]|0)<=0)break b;y=(c[g>>2]|0)+440|0;a=y;z=Me(c[a>>2]|0,c[a+4>>2]|0,1,0)|0;a=y;c[a>>2]=z;c[a+4>>2]=C;a=(c[j>>2]|0)+16|0;z=c[a+4>>2]|0;y=p;c[y>>2]=c[a>>2];c[y+4>>2]=z;c[r>>2]=Xb(c[e>>2]|0,c[l>>2]|0)|0;do if(!((c[r>>2]|0)<0|(c[r>>2]|0)>=15)){if(((c[r>>2]|0)==6?1:(c[(c[g>>2]|0)+448>>2]|0)==0)?(c[c[e>>2]>>2]&32|0)!=0:0)Sb(c[e>>2]|0,c[j>>2]|0,c[l>>2]|0,0)|0;if(!(c[c[e>>2]>>2]&32)){z=p;y=c[z+4>>2]|0;a=(c[f>>2]|0)+424|0;c[a>>2]=c[z>>2];c[a+4>>2]=y;break}y=p;a=Tb(c[r>>2]|0,c[y>>2]|0,c[y+4>>2]|0,c[g>>2]|0,c[j>>2]|0)|0;y=(c[f>>2]|0)+424|0;c[y>>2]=a;c[y+4>>2]=C;y=p;if(((c[y>>2]|0)!=-1?1:(c[y+4>>2]|0)!=-1)?(y=(c[f>>2]|0)+424|0,a=c[y+4>>2]|0,z=p,x=c[z+4>>2]|0,(a|0)<(x|0)|((a|0)==(x|0)?(c[y>>2]|0)>>>0<(c[z>>2]|0)>>>0:0)):0){z=p;y=c[z+4>>2]|0;x=(c[f>>2]|0)+424|0;c[x>>2]=c[z>>2];c[x+4>>2]=y}}else{y=p;x=c[y+4>>2]|0;z=(c[f>>2]|0)+424|0;c[z>>2]=c[y>>2];c[z+4>>2]=x}while(0);x=(c[f>>2]|0)+424|0;z=c[x+4>>2]|0;y=(c[g>>2]|0)+488|0;c[y>>2]=c[x>>2];c[y+4>>2]=z;if(!((c[(c[e>>2]|0)+88>>2]|0)==0?(c[(c[g>>2]|0)+448>>2]|0)==0:0))w=27;if((w|0)==27?(w=0,z=(c[f>>2]|0)+424|0,(c[z>>2]|0)!=-1?1:(c[z+4>>2]|0)!=-1):0){z=(c[f>>2]|0)+424|0;y=wb(c[e>>2]|0,c[l>>2]|0,c[z>>2]|0,c[z+4>>2]|0)|0;z=(c[f>>2]|0)+416|0;c[z>>2]=y;c[z+4>>2]=C}z=(c[g>>2]|0)+440|0;if((c[z>>2]|0)==1&(c[z+4>>2]|0)==0)Vb(c[e>>2]|0,c[g>>2]|0,c[l>>2]|0,c[j>>2]|0)|0;z=(c[f>>2]|0)+424|0;y=c[z+4>>2]|0;x=c[k>>2]|0;c[x>>2]=c[z>>2];c[x+4>>2]=y;c[(c[k>>2]|0)+8>>2]=c[(c[f>>2]|0)+436>>2];c[(c[k>>2]|0)+12>>2]=c[(c[e>>2]|0)+64>>2];c[(c[k>>2]|0)+16>>2]=c[(c[f>>2]|0)+440>>2];c[(c[k>>2]|0)+20>>2]=c[(c[f>>2]|0)+444>>2];do if(c[c[e>>2]>>2]&32){y=(c[f>>2]|0)+424|0;x=c[e>>2]|0;if((c[y>>2]|0)==-1?(c[y+4>>2]|0)==-1:0){c[s>>2]=Hb(x,m,c[l>>2]|0,c[g>>2]|0,c[f>>2]|0)|0;jc(c[(c[e>>2]|0)+560>>2]|0,c[s>>2]|0)|0;w=45;break}if(!(ic(c[x+560>>2]|0)|0)){x=(c[g>>2]|0)+488|0;y=c[x+4>>2]|0;z=t;c[z>>2]=c[x>>2];c[z+4>>2]=y;c[(c[g>>2]|0)+508>>2]=c[j>>2];kc(c[(c[e>>2]|0)+560>>2]|0,3);c[(c[e>>2]|0)+76>>2]=0;if((lc(c[(c[e>>2]|0)+560>>2]|0,4)|0)==-1){w=36;break a}y=(c[e>>2]|0)+76|0;if((c[(c[e>>2]|0)+76>>2]|0)>0){c[o>>2]=c[y>>2];c[(c[e>>2]|0)+76>>2]=0;break}c[y>>2]=0;y=t;z=c[y+4>>2]|0;x=(c[g>>2]|0)+488|0;c[x>>2]=c[y>>2];c[x+4>>2]=z;if(!(ic(c[(c[e>>2]|0)+560>>2]|0)|0)){c[u>>2]=Hb(c[e>>2]|0,m,c[l>>2]|0,c[g>>2]|0,c[f>>2]|0)|0;jc(c[(c[e>>2]|0)+560>>2]|0,c[u>>2]|0)|0;w=45}else w=41}else w=41}else w=41;while(0);do if((w|0)==41){w=0;if(c[(c[g>>2]|0)+468>>2]|0){c[o>>2]=Oa[c[(c[g>>2]|0)+468>>2]&15](c[e>>2]|0,m,c[l>>2]|0,c[(c[g>>2]|0)+472>>2]|0)|0;w=45;break}if(c[(c[f>>2]|0)+396>>2]|0){c[o>>2]=Oa[c[(c[f>>2]|0)+396>>2]&15](c[e>>2]|0,m,c[l>>2]|0,c[(c[f>>2]|0)+400>>2]|0)|0;w=45}else w=45}while(0);if((w|0)==45){w=0;if((c[(c[f>>2]|0)+436>>2]|0)==(c[(c[e>>2]|0)+64>>2]|0)){z=(c[f>>2]|0)+444|0;c[z>>2]=(c[z>>2]|0)+1}else{c[(c[f>>2]|0)+436>>2]=c[(c[e>>2]|0)+64>>2];c[(c[f>>2]|0)+444>>2]=1}c[(c[f>>2]|0)+440>>2]=1;if(!(c[(c[j>>2]|0)+8>>2]|0))c[(c[g>>2]|0)+420>>2]=1}}while((c[o>>2]|0)==0);while(0);if((c[o>>2]|0)==1|(c[o>>2]|0)==-1|(c[o>>2]|0)==-17){w=51;break}if((Uc(c[e>>2]|0,n)|0)<0){w=53;break}c[l>>2]=bb(n)|0;c[(c[f>>2]|0)+392>>2]=c[l>>2];c[g>>2]=sb(c[e>>2]|0,c[l>>2]|0)|0;z=c[e>>2]|0;x=c[l>>2]|0;if(!(c[g>>2]|0)){y=tb(z,x)|0;c[g>>2]=y;if(!y){w=56;break}Qb(c[e>>2]|0,n,c[l>>2]|0)|0;if(c[c[e>>2]>>2]&32)Rb(c[e>>2]|0,n,c[l>>2]|0,0)|0}else if((Xb(z,x)|0)==9)Qb(c[e>>2]|0,n,c[l>>2]|0)|0;c[h>>2]=c[g>>2];x=ab(n)|0;z=v;c[z>>2]=x;c[z+4>>2]=C;z=v;x=c[z+4>>2]|0;y=(c[g>>2]|0)+496|0;c[y>>2]=c[z>>2];c[y+4>>2]=x;if(c[(c[e>>2]|0)+88>>2]|0){x=v;if((c[x>>2]|0)!=-1?1:(c[x+4>>2]|0)!=-1)w=64;else w=65}else{x=v;if((c[(c[g>>2]|0)+448>>2]|0)!=0&((c[x>>2]|0)!=-1?1:(c[x+4>>2]|0)!=-1))w=64;else w=65}if((w|0)==64){w=0;x=v;y=wb(c[e>>2]|0,c[l>>2]|0,c[x>>2]|0,c[x+4>>2]|0)|0;x=(c[f>>2]|0)+416|0;c[x>>2]=y;c[x+4>>2]=C}else if((w|0)==65?(w=0,x=v,(c[x>>2]|0)==0&(c[x+4>>2]|0)==0):0){x=(c[f>>2]|0)+416|0;c[x>>2]=0;c[x+4>>2]=0}if(!(c[(c[g>>2]|0)+476>>2]|0)){if(c[(c[f>>2]|0)+404>>2]|0)c[o>>2]=Oa[c[(c[f>>2]|0)+404>>2]&15](c[e>>2]|0,n,c[l>>2]|0,c[(c[f>>2]|0)+408>>2]|0)|0}else c[o>>2]=Oa[c[(c[g>>2]|0)+476>>2]&15](c[e>>2]|0,n,c[l>>2]|0,c[(c[g>>2]|0)+480>>2]|0)|0;jb(c[h>>2]|0,n)|0;x=(_a(n)|0)!=0;y=(c[f>>2]|0)+440|0;if(!x){c[y>>2]=1;c[(c[f>>2]|0)+436>>2]=c[(c[e>>2]|0)+64>>2];c[(c[f>>2]|0)+444>>2]=0;continue}if((c[y>>2]|0)==-1)continue;y=(c[f>>2]|0)+440|0;c[y>>2]=(c[y>>2]|0)+1}if((w|0)==7){c[d>>2]=-18;A=c[d>>2]|0;i=b;return A|0}else if((w|0)==10){c[d>>2]=-17;A=c[d>>2]|0;i=b;return A|0}else if((w|0)==12){c[d>>2]=-17;A=c[d>>2]|0;i=b;return A|0}else if((w|0)==36){c[d>>2]=-17;A=c[d>>2]|0;i=b;return A|0}else if((w|0)==51){c[d>>2]=c[o>>2];A=c[d>>2]|0;i=b;return A|0}else if((w|0)==53){c[d>>2]=-404;A=c[d>>2]|0;i=b;return A|0}else if((w|0)==56){c[d>>2]=-18;A=c[d>>2]|0;i=b;return A|0}else if((w|0)==75){c[d>>2]=c[o>>2];A=c[d>>2]|0;i=b;return A|0}return 0}function Ec(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;dc(c[(c[d>>2]|0)+80>>2]|0,5)|0;i=b;return}function Fc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0;g=i;i=i+32|0;h=g+16|0;j=g+12|0;k=g;l=g+8|0;c[h>>2]=a;c[j>>2]=b;b=k;c[b>>2]=d;c[b+4>>2]=e;c[l>>2]=f;Ec(c[h>>2]|0);f=k;k=Wc(c[h>>2]|0,c[j>>2]|0,c[f>>2]|0,c[f+4>>2]|0,c[l>>2]|0)|0;i=g;return k|0}function Gc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0;e=i;i=i+32|0;f=e+20|0;g=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=(c[g>>2]|0)+112;if((Bb(c[g>>2]|0,c[h>>2]|0,c[j>>2]|0)|0)==-1){c[f>>2]=-1;m=c[f>>2]|0;i=e;return m|0}else{c[l>>2]=Cb(c[g>>2]|0)|0;c[(c[g>>2]|0)+64>>2]=c[l>>2];kb(c[k>>2]|0)|0;dc(c[(c[g>>2]|0)+80>>2]|0,6)|0;c[f>>2]=c[l>>2];m=c[f>>2]|0;i=e;return m|0}return 0}function Hc(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;f=i;i=i+32|0;g=f+8|0;h=f+16|0;j=f+20|0;k=f+24|0;l=f+4|0;m=f;n=f+12|0;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=e;c[m>>2]=0;while(1){if((c[m>>2]|0)>=15){o=7;break}c[n>>2]=1040+((c[m>>2]|0)*24|0);if((c[l>>2]|0)>=(c[(c[n>>2]|0)+4>>2]|0)?(ve(c[k>>2]|0,c[c[n>>2]>>2]|0,c[(c[n>>2]|0)+4>>2]|0)|0)==0:0){o=5;break}c[m>>2]=(c[m>>2]|0)+1}if((o|0)==5){Wb(c[h>>2]|0,c[j>>2]|0,c[m>>2]|0)|0;c[g>>2]=1;p=c[g>>2]|0;i=f;return p|0}else if((o|0)==7){Wb(c[h>>2]|0,c[j>>2]|0,15)|0;c[g>>2]=0;p=c[g>>2]|0;i=f;return p|0}return 0}function Ic(a,b,e,f,g){a=a|0;b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;h=i;i=i+64|0;j=h+20|0;k=h+40|0;l=h+44|0;m=h+36|0;n=h+32|0;o=h+52|0;p=h+16|0;q=h;r=h+8|0;s=h+28|0;t=h+24|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=e;c[n>>2]=f;c[h+48>>2]=g;c[o>>2]=c[m>>2];m=q;c[m>>2]=0;c[m+4>>2]=0;m=r;c[m>>2]=0;c[m+4>>2]=0;if((c[n>>2]|0)<48){c[j>>2]=0;u=c[j>>2]|0;i=h;return u|0}c[p>>2]=bd((c[o>>2]|0)+12|0)|0;if(vb(c[k>>2]|0,c[p>>2]|0)|0){c[j>>2]=1;u=c[j>>2]|0;i=h;return u|0}else{n=id((c[o>>2]|0)+20|0)|0;m=q;c[m>>2]=n;c[m+4>>2]=C;m=id((c[o>>2]|0)+28|0)|0;n=r;c[n>>2]=m;c[n+4>>2]=C;c[s>>2]=d[(c[o>>2]|0)+48>>0];o=c[k>>2]|0;n=c[p>>2]|0;m=q;q=c[m>>2]|0;g=c[m+4>>2]|0;m=r;r=Ue(1e3,0,c[m>>2]|0,c[m+4>>2]|0)|0;oc(o,n,q,g,r,C)|0;mc(c[k>>2]|0,c[p>>2]|0,c[s>>2]|0)|0;c[t>>2]=Yb(c[k>>2]|0,c[l>>2]|0)|0;Zc(c[k>>2]|0,c[l>>2]|0,(c[t>>2]|0)+1|0)|0;c[j>>2]=1;u=c[j>>2]|0;i=h;return u|0}return 0}function Jc(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;if(c[(c[d>>2]|0)+8>>2]|0){ze(c[(c[d>>2]|0)+8>>2]|0);c[(c[d>>2]|0)+8>>2]=0}c[(c[d>>2]|0)+4>>2]=0;c[c[d>>2]>>2]=0;i=b;return}function Kc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0;b=i;i=i+16|0;d=b+12|0;e=b+8|0;f=b+4|0;g=b;c[e>>2]=a;a=(c[e>>2]|0)+4|0;c[a>>2]=(c[a>>2]|0)+1;do if((c[(c[e>>2]|0)+4>>2]|0)>(c[c[e>>2]>>2]|0)){if(!(c[c[e>>2]>>2]|0))c[g>>2]=1;else c[g>>2]=c[c[e>>2]>>2]<<1;c[f>>2]=Be(c[(c[e>>2]|0)+8>>2]|0,c[g>>2]<<2)|0;if(c[f>>2]|0){c[c[e>>2]>>2]=c[g>>2];c[(c[e>>2]|0)+8>>2]=c[f>>2];break}a=(c[e>>2]|0)+4|0;c[a>>2]=(c[a>>2]|0)+-1;c[d>>2]=0;h=c[d>>2]|0;i=b;return h|0}while(0);c[d>>2]=c[e>>2];h=c[d>>2]|0;i=b;return h|0}function Lc(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;if(!(c[(c[d>>2]|0)+12>>2]|0)){i=b;return}c[e>>2]=(c[(c[d>>2]|0)+4>>2]|0)-1;while(1){if((c[e>>2]|0)<=0){f=6;break}if((La[c[(c[d>>2]|0)+12>>2]&1](c[(c[(c[d>>2]|0)+8>>2]|0)+((c[e>>2]|0)-1<<2)>>2]|0,c[(c[(c[d>>2]|0)+8>>2]|0)+(c[e>>2]<<2)>>2]|0,c[(c[d>>2]|0)+16>>2]|0)|0)<=0){f=6;break}Bd(c[(c[d>>2]|0)+8>>2]|0,c[e>>2]|0,(c[e>>2]|0)-1|0);c[e>>2]=(c[e>>2]|0)+-1}if((f|0)==6){i=b;return}}function Mc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+20|0;g=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[l>>2]=c[(c[f>>2]|0)+8>>2];if((c[g>>2]|0)>=(c[h>>2]|0)){i=e;return}Bd(c[l>>2]|0,c[g>>2]|0,((c[g>>2]|0)+(c[h>>2]|0)|0)/2|0);c[k>>2]=c[g>>2];c[j>>2]=(c[g>>2]|0)+1;while(1){if((c[j>>2]|0)>(c[h>>2]|0))break;if((La[c[(c[f>>2]|0)+12>>2]&1](c[(c[l>>2]|0)+(c[j>>2]<<2)>>2]|0,c[(c[l>>2]|0)+(c[g>>2]<<2)>>2]|0,c[(c[f>>2]|0)+16>>2]|0)|0)<0){d=c[l>>2]|0;b=(c[k>>2]|0)+1|0;c[k>>2]=b;Bd(d,b,c[j>>2]|0)}c[j>>2]=(c[j>>2]|0)+1}Bd(c[l>>2]|0,c[g>>2]|0,c[k>>2]|0);Mc(c[f>>2]|0,c[g>>2]|0,(c[k>>2]|0)-1|0);Mc(c[f>>2]|0,(c[k>>2]|0)+1|0,c[h>>2]|0);i=e;return}function Nc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;if(!(c[f>>2]|0)){c[e>>2]=-2;j=c[e>>2]|0;i=d;return j|0}c[h>>2]=sb(c[f>>2]|0,c[g>>2]|0)|0;if(!(c[h>>2]|0)){c[e>>2]=-20;j=c[e>>2]|0;i=d;return j|0}b=(c[h>>2]|0)+376|0;if((c[b>>2]|0)==0&(c[b+4>>2]|0)==0){b=(c[h>>2]|0)+376|0;c[b>>2]=1;c[b+4>>2]=0;b=(c[h>>2]|0)+384|0;c[b>>2]=0;c[b+4>>2]=0}b=c[f>>2]|0;a=c[g>>2]|0;if(!(c[(c[h>>2]|0)+408>>2]|0)){c[e>>2]=ub(b,a,19,0,1)|0;j=c[e>>2]|0;i=d;return j|0}h=(Xb(b,a)|0)==12;a=c[f>>2]|0;b=c[g>>2]|0;if(h){c[e>>2]=ub(a,b,20,0,1)|0;j=c[e>>2]|0;i=d;return j|0}h=(Xb(a,b)|0)==14;b=c[f>>2]|0;f=c[g>>2]|0;if(h){c[e>>2]=ub(b,f,21,0,1)|0;j=c[e>>2]|0;i=d;return j|0}else{c[e>>2]=ub(b,f,22,0,1)|0;j=c[e>>2]|0;i=d;return j|0}return 0}function Oc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[c[f>>2]>>2]=c[g>>2];c[(c[f>>2]|0)+4>>2]=c[g>>2];c[(c[f>>2]|0)+8>>2]=(c[(c[f>>2]|0)+4>>2]|0)+(c[h>>2]|0);c[(c[f>>2]|0)+12>>2]=8;i=e;return}function Pc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0;d=i;i=i+16|0;e=d+4|0;f=d;c[e>>2]=a;c[f>>2]=b;b=(c[e>>2]|0)+12|0;c[b>>2]=(c[b>>2]|0)-(c[f>>2]|0);while(1){if((c[(c[e>>2]|0)+12>>2]|0)>0)break;f=(c[e>>2]|0)+4|0;c[f>>2]=(c[f>>2]|0)+1;f=(c[e>>2]|0)+12|0;c[f>>2]=(c[f>>2]|0)+8}i=d;return}function Qc(a){a=a|0;var b=0,d=0,e=0,f=0,g=0;b=i;i=i+16|0;d=b+8|0;e=b+4|0;f=b;c[d>>2]=a;c[e>>2]=0;c[f>>2]=0;while(1){a=(Gd(c[d>>2]|0,1)|0)!=0^1;g=c[e>>2]|0;if(!a)break;c[e>>2]=g+1;c[f>>2]=c[f>>2]<<1;a=Gd(c[d>>2]|0,1)|0;c[f>>2]=c[f>>2]|a}i=b;return (1<<g)-1+(c[f>>2]|0)|0}function Rc(a){a=a|0;var b=0,d=0;b=i;i=i+16|0;d=b;c[d>>2]=a;a=Gd(c[d>>2]|0,1)|0;i=b;return a|0}function Sc(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;d=b+8|0;e=b+4|0;f=b;c[e>>2]=a;do if(c[e>>2]|0){c[f>>2]=ye((Cc(c[e>>2]|0)|0)+1|0)|0;if(!(c[f>>2]|0)){c[d>>2]=0;break}else{c[d>>2]=Oe(c[f>>2]|0,c[e>>2]|0)|0;break}}else c[d>>2]=0;while(0);i=b;return c[d>>2]|0}function Tc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;if(!(vc(c[f>>2]|0)|0)){c[e>>2]=0;j=c[e>>2]|0;i=d;return j|0}c[h>>2]=ye(8)|0;if(!(c[h>>2]|0)){c[e>>2]=0;j=c[e>>2]|0;i=d;return j|0}b=Sc(c[f>>2]|0)|0;c[c[h>>2]>>2]=b;if(!(c[c[h>>2]>>2]|0)){ze(c[h>>2]|0);c[e>>2]=0;j=c[e>>2]|0;i=d;return j|0}if(c[g>>2]|0){b=Sc(c[g>>2]|0)|0;c[(c[h>>2]|0)+4>>2]=b;if(!(c[(c[h>>2]|0)+4>>2]|0)){ze(c[c[h>>2]>>2]|0);ze(c[h>>2]|0);c[e>>2]=0;j=c[e>>2]|0;i=d;return j|0}}else c[(c[h>>2]|0)+4>>2]=0;c[e>>2]=c[h>>2];j=c[e>>2]|0;i=d;return j|0}function Uc(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0;d=i;i=i+32|0;e=d+20|0;f=d+16|0;g=d+12|0;h=d+8|0;j=d+4|0;k=d;c[f>>2]=a;c[g>>2]=b;c[h>>2]=(c[f>>2]|0)+112;c[k>>2]=0;b=(c[f>>2]|0)+64|0;c[b>>2]=(c[b>>2]|0)+(c[(c[h>>2]|0)+432>>2]|0);while(1){c[j>>2]=ib(c[h>>2]|0,c[g>>2]|0)|0;if(!(c[j>>2]|0)){l=3;break}b=c[j>>2]|0;if((c[j>>2]|0)<0){a=(c[f>>2]|0)+64|0;c[a>>2]=(c[a>>2]|0)+(0-b)}else{c[(c[h>>2]|0)+432>>2]=b;c[k>>2]=1}if(!((c[k>>2]|0)!=0^1)){l=8;break}}if((l|0)==3){c[e>>2]=-2;m=c[e>>2]|0;i=d;return m|0}else if((l|0)==8){c[e>>2]=c[(c[f>>2]|0)+64>>2];m=c[e>>2]|0;i=d;return m|0}return 0}function Vc(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;c[e>>2]=c[d>>2];if((c[(c[e>>2]|0)+336>>2]|0)==-1){i=b;return 0}lb(c[e>>2]|0)|0;i=b;return 0}function Wc(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=i;i=i+32|0;h=g+28|0;j=g+20|0;k=g+24|0;l=g;m=g+16|0;n=g+12|0;o=g+8|0;c[j>>2]=a;c[k>>2]=b;b=l;c[b>>2]=d;c[b+4>>2]=e;c[m>>2]=f;c[n>>2]=(c[j>>2]|0)+112;c[o>>2]=Gc(c[j>>2]|0,c[k>>2]|0,c[m>>2]|0)|0;if((c[o>>2]|0)==-1){c[h>>2]=-1;p=c[h>>2]|0;i=g;return p|0}c[(c[j>>2]|0)+64>>2]=c[o>>2];j=l;if((c[j>>2]|0)!=-1?1:(c[j+4>>2]|0)!=-1){j=l;l=c[j+4>>2]|0;m=(c[n>>2]|0)+416|0;c[m>>2]=c[j>>2];c[m+4>>2]=l}c[h>>2]=c[o>>2];p=c[h>>2]|0;i=g;return p|0}function Xc(b,e,f,g,h){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;j=i;i=i+48|0;k=j+12|0;l=j+16|0;m=j+28|0;n=j+4|0;o=j+32|0;p=j+40|0;q=j+24|0;r=j+20|0;s=j+8|0;t=j+44|0;u=j;c[l>>2]=b;c[m>>2]=e;c[n>>2]=f;c[o>>2]=g;c[j+36>>2]=h;c[p>>2]=c[n>>2];a[t>>0]=0;if((c[o>>2]|0)<41){c[k>>2]=0;v=c[k>>2]|0;i=j;return v|0}c[q>>2]=(d[(c[p>>2]|0)+7>>0]<<16)+(d[(c[p>>2]|0)+8>>0]<<8)+(d[(c[p>>2]|0)+9>>0]|0);c[r>>2]=Yc((c[p>>2]|0)+22|0)|0;c[s>>2]=Yc((c[p>>2]|0)+26|0)|0;if(!(c[r>>2]|0))c[r>>2]=1;a[t>>0]=(d[(c[p>>2]|0)+40>>0]&3)<<3;a[t>>0]=a[t>>0]|(d[(c[p>>2]|0)+41>>0]&224)>>5;c[u>>2]=a[t>>0];t=c[l>>2]|0;p=c[m>>2]|0;o=c[r>>2]|0;r=c[s>>2]|0;s=Ue(1e3,0,r|0,((r|0)<0)<<31>>31|0)|0;oc(t,p,o,((o|0)<0)<<31>>31,s,C)|0;mc(c[l>>2]|0,c[m>>2]|0,c[u>>2]|0)|0;if((c[q>>2]|0)<197120)qc(c[l>>2]|0,c[m>>2]|0,-1,-1)|0;Zc(c[l>>2]|0,c[m>>2]|0,3)|0;c[k>>2]=1;v=c[k>>2]|0;i=j;return v|0}function Yc(a){a=a|0;var b=0,e=0;b=i;i=i+16|0;e=b;c[e>>2]=a;i=b;return (d[c[e>>2]>>0]|0)<<24|(d[(c[e>>2]|0)+1>>0]|0)<<16|(d[(c[e>>2]|0)+2>>0]|0)<<8|(d[(c[e>>2]|0)+3>>0]|0)|0}function Zc(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;if(!(c[g>>2]|0)){c[f>>2]=-2;l=c[f>>2]|0;i=e;return l|0}c[k>>2]=sb(c[g>>2]|0,c[h>>2]|0)|0;if(!(c[k>>2]|0)){c[f>>2]=-20;l=c[f>>2]|0;i=e;return l|0}else{c[(c[k>>2]|0)+364>>2]=c[j>>2];c[f>>2]=0;l=c[f>>2]|0;i=e;return l|0}return 0}function _c(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;h=i;i=i+48|0;j=h+8|0;k=h;l=h+28|0;m=h+24|0;n=h+20|0;o=h+16|0;p=h+36|0;q=h+32|0;r=k;c[r>>2]=b;c[r+4>>2]=e;c[l>>2]=f;c[m>>2]=g;if(!(c[(c[m>>2]|0)+4>>2]|0))s=64;else s=d[c[c[m>>2]>>2]>>0]|0;a[p>>0]=s;c[q>>2]=c[(c[l>>2]|0)+504>>2];a:do if(!((d[p>>0]|0)&128)){s=k;m=c[s+4>>2]|0;if((m|0)>-1|(m|0)==-1&(c[s>>2]|0)>>>0>4294967295){c[c[q>>2]>>2]=1;s=k;m=c[s+4>>2]|0;g=j;c[g>>2]=c[s>>2];c[g+4>>2]=m;break}m=(c[l>>2]|0)+488|0;g=c[q>>2]|0;if((c[m>>2]|0)==-1?(c[m+4>>2]|0)==-1:0){c[g>>2]=1;m=j;c[m>>2]=-1;c[m+4>>2]=-1;break}if(!(c[g>>2]|0)){c[c[q>>2]>>2]=1;g=j;c[g>>2]=-1;c[g+4>>2]=-1;break}g=c[l>>2]|0;if((d[p>>0]|0)&64){m=g+488|0;s=Me(c[m>>2]|0,c[m+4>>2]|0,1,0)|0;m=j;c[m>>2]=s;c[m+4>>2]=C;break}else{c[o>>2]=c[g+408>>2];g=(c[l>>2]|0)+488|0;m=Fe(c[g>>2]|0,c[g+4>>2]|0,c[o>>2]|0)|0;c[n>>2]=m;m=(c[l>>2]|0)+488|0;g=(1<<c[o>>2])-1|0;s=Me(c[m>>2]&g|0,c[m+4>>2]&((g|0)<0)<<31>>31|0,1,0)|0;g=c[n>>2]|0;m=Me(g|0,((g|0)<0)<<31>>31|0,s|0,C|0)|0;c[n>>2]=m;m=c[n>>2]|0;s=Ie(m|0,((m|0)<0)<<31>>31|0,c[o>>2]|0)|0;m=j;c[m>>2]=s;c[m+4>>2]=C;break}}else{do if(!(c[q>>2]|0)){m=ye(4)|0;c[(c[l>>2]|0)+504>>2]=m;if(!(c[(c[l>>2]|0)+504>>2]|0)){m=j;c[m>>2]=-1;c[m+4>>2]=-1;break a}else{c[q>>2]=c[(c[l>>2]|0)+504>>2];break}}while(0);c[c[q>>2]>>2]=0;m=j;c[m>>2]=0;c[m+4>>2]=0}while(0);q=j;C=c[q+4>>2]|0;i=h;return c[q>>2]|0}function $c(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;g=i;i=i+48|0;h=g;j=g+8|0;k=g+28|0;l=g+16|0;m=g+24|0;n=j;c[n>>2]=a;c[n+4>>2]=b;c[k>>2]=d;c[g+32>>2]=e;c[g+20>>2]=f;f=j;e=Fe(c[f>>2]|0,c[f+4>>2]|0,c[(c[k>>2]|0)+408>>2]|0)|0;c[l>>2]=e;e=j;j=c[l>>2]<<c[(c[k>>2]|0)+408>>2];f=Ge(c[e>>2]|0,c[e+4>>2]|0,j|0,((j|0)<0)<<31>>31|0)|0;c[m>>2]=f;f=c[l>>2]|0;if(!(c[m>>2]|0)){l=(f-60<<c[(c[k>>2]|0)+408>>2])+59|0;j=h;c[j>>2]=l;c[j+4>>2]=((l|0)<0)<<31>>31;o=h;p=o;q=c[p>>2]|0;r=o+4|0;s=r;t=c[s>>2]|0;C=t;i=g;return q|0}else{l=Ie(f|0,((f|0)<0)<<31>>31|0,c[(c[k>>2]|0)+408>>2]|0)|0;k=(c[m>>2]|0)-1|0;m=Me(l|0,C|0,k|0,((k|0)<0)<<31>>31|0)|0;k=h;c[k>>2]=m;c[k+4>>2]=C;o=h;p=o;q=c[p>>2]|0;r=o+4|0;s=r;t=c[s>>2]|0;C=t;i=g;return q|0}return 0}function ad(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=i;i=i+48|0;h=g+28|0;j=g+12|0;k=g+24|0;l=g+20|0;m=g+32|0;n=g+16|0;o=g;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[g+8>>2]=f;c[n>>2]=c[l>>2];l=o;c[l>>2]=0;c[l+4>>2]=0;if((c[m>>2]|0)<30){c[h>>2]=0;p=c[h>>2]|0;i=g;return p|0}else{m=bd((c[n>>2]|0)+12|0)|0;n=o;c[n>>2]=m;c[n+4>>2]=((m|0)<0)<<31>>31;m=o;oc(c[j>>2]|0,c[k>>2]|0,c[m>>2]|0,c[m+4>>2]|0,1e3,0)|0;Zb(c[j>>2]|0,c[k>>2]|0,2)|0;Zc(c[j>>2]|0,c[k>>2]|0,3)|0;c[h>>2]=1;p=c[h>>2]|0;i=g;return p|0}return 0}function bd(a){a=a|0;var b=0,e=0;b=i;i=i+16|0;e=b;c[e>>2]=a;i=b;return d[c[e>>2]>>0]|0|(d[(c[e>>2]|0)+1>>0]|0)<<8|(d[(c[e>>2]|0)+2>>0]|0)<<16|(d[(c[e>>2]|0)+3>>0]|0)<<24|0}function cd(a,b,e,f){a=a|0;b=b|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0;g=i;i=i+80|0;h=g+8|0;j=g+24|0;k=g+40|0;l=g+16|0;m=g+20|0;n=g+28|0;o=g+36|0;p=g+32|0;q=g+44|0;r=g+48|0;s=g+52|0;t=g+56|0;u=g+60|0;v=g+64|0;w=g;c[w>>2]=a;c[w+4>>2]=b;c[j>>2]=e;c[k>>2]=f;f=c[c[k>>2]>>2]|0;if(!(c[(c[j>>2]|0)+504>>2]|0)){c[o>>2]=1<<((d[f+28>>0]|0)>>4);c[n>>2]=1<<((d[(c[c[k>>2]>>2]|0)+28>>0]|0)&15);e=ye(44)|0;c[(c[j>>2]|0)+504>>2]=e;if(!(c[(c[j>>2]|0)+504>>2]|0)){e=h;c[e>>2]=-1;c[e+4>>2]=-1;x=h;y=x;z=c[y>>2]|0;A=x+4|0;B=A;D=c[B>>2]|0;C=D;i=g;return z|0}else{c[l>>2]=c[(c[j>>2]|0)+504>>2];c[(c[l>>2]|0)+12>>2]=c[o>>2]>>1;c[(c[l>>2]|0)+8>>2]=((c[o>>2]>>2)*3|0)-(c[n>>2]>>2);c[(c[l>>2]|0)+4>>2]=(c[o>>2]>>2)+(c[n>>2]>>2);c[c[l>>2]>>2]=c[(c[l>>2]|0)+12>>2];c[(c[l>>2]|0)+20>>2]=c[n>>2];c[(c[l>>2]|0)+24>>2]=c[o>>2];c[(c[l>>2]|0)+16>>2]=c[n>>2]>>1;c[(c[l>>2]|0)+28>>2]=0;n=h;c[n>>2]=0;c[n+4>>2]=0;x=h;y=x;z=c[y>>2]|0;A=x+4|0;B=A;D=c[B>>2]|0;C=D;i=g;return z|0}}if(!((d[f>>0]|0)&1)){c[l>>2]=c[(c[j>>2]|0)+504>>2];f=h;c[f>>2]=-1;c[f+4>>2]=-1;x=h;y=x;z=c[y>>2]|0;A=x+4|0;B=A;D=c[B>>2]|0;C=D;i=g;return z|0}a:do if((d[c[c[k>>2]>>2]>>0]|0|0)==5){c[p>>2]=(c[c[k>>2]>>2]|0)+((c[(c[k>>2]|0)+4>>2]|0)-1);c[r>>2]=0;c[q>>2]=8;while(1){f=(c[q>>2]|0)+-1|0;c[q>>2]=f;if(!((1<<f&(d[c[p>>2]>>0]|0)|0)!=0^1))break;if(c[q>>2]|0)continue;c[q>>2]=8;c[p>>2]=(c[p>>2]|0)+-1}while(1){c[q>>2]=((c[q>>2]|0)+7|0)%8|0;if((c[q>>2]|0)==7)c[p>>2]=(c[p>>2]|0)+-1;if((d[(c[p>>2]|0)+-5>>0]|0)&~((1<<(c[q>>2]|0)+1)-1))break;if(d[(c[p>>2]|0)+-4>>0]|0)break;if(d[(c[p>>2]|0)+-3>>0]|0)break;if(d[(c[p>>2]|0)+-2>>0]|0)break;if((d[(c[p>>2]|0)+-1>>0]|0)&(1<<(c[q>>2]|0)+1)-1)break;c[r>>2]=(c[r>>2]|0)+1;c[p>>2]=(c[p>>2]|0)+-5}c[m>>2]=0;while(1){if((c[m>>2]|0)>=2)break;f=d[c[p>>2]>>0]|0;n=c[q>>2]|0;if((c[q>>2]|0)>4)c[s>>2]=f>>n-5&63;else{c[s>>2]=f&(1<<n+1)-1;c[s>>2]=c[s>>2]<<5-(c[q>>2]|0);c[s>>2]=c[s>>2]|((d[(c[p>>2]|0)+-1>>0]|0)&~((1<<(c[q>>2]|0)+3)-1))>>(c[q>>2]|0)+3}c[s>>2]=(c[s>>2]|0)+1;if((c[s>>2]|0)==(c[r>>2]|0))break;c[q>>2]=((c[q>>2]|0)+1|0)%8|0;if(!(c[q>>2]|0))c[p>>2]=(c[p>>2]|0)+1;c[p>>2]=(c[p>>2]|0)+5;c[r>>2]=(c[r>>2]|0)-1;c[m>>2]=(c[m>>2]|0)+1}c[v>>2]=44+((c[r>>2]|0)-1<<2);if((c[v>>2]|0)>>>0<44){n=h;c[n>>2]=-1;c[n+4>>2]=-1;x=h;y=x;z=c[y>>2]|0;A=x+4|0;B=A;D=c[B>>2]|0;C=D;i=g;return z|0}c[l>>2]=Be(c[(c[j>>2]|0)+504>>2]|0,c[v>>2]|0)|0;if(!(c[l>>2]|0)){n=h;c[n>>2]=-1;c[n+4>>2]=-1;x=h;y=x;z=c[y>>2]|0;A=x+4|0;B=A;D=c[B>>2]|0;C=D;i=g;return z|0}c[(c[j>>2]|0)+504>>2]=c[l>>2];c[u>>2]=-1;do{n=(c[u>>2]|0)+1|0;c[u>>2]=n}while((1<<n|0)<(c[r>>2]|0));c[(c[l>>2]|0)+36>>2]=c[u>>2];c[t>>2]=(c[l>>2]|0)+40;c[u>>2]=0;while(1){if((c[u>>2]|0)>=(c[r>>2]|0))break a;c[q>>2]=((c[q>>2]|0)+1|0)%8|0;if(!(c[q>>2]|0))c[p>>2]=(c[p>>2]|0)+1;n=(d[c[p>>2]>>0]|0)>>c[q>>2]&1;f=c[t>>2]|0;c[t>>2]=f+4;c[f>>2]=n;c[p>>2]=(c[p>>2]|0)+5;c[u>>2]=(c[u>>2]|0)+1}}while(0);u=h;c[u>>2]=0;c[u+4>>2]=0;x=h;y=x;z=c[y>>2]|0;A=x+4|0;B=A;D=c[B>>2]|0;C=D;i=g;return z|0}function dd(a,b,e,f,g){a=a|0;b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0;h=i;i=i+64|0;j=h+16|0;k=h;l=h+36|0;m=h+32|0;n=h+40|0;o=h+44|0;p=h+48|0;q=h+28|0;r=h+24|0;s=h+8|0;t=k;c[t>>2]=a;c[t+4>>2]=b;c[l>>2]=e;c[m>>2]=f;c[n>>2]=g;c[o>>2]=c[(c[l>>2]|0)+504>>2];c[p>>2]=(d[c[c[m>>2]>>2]>>0]|0)>>1&(1<<c[(c[o>>2]|0)+36>>2])-1;m=c[o>>2]|0;if(c[(c[o>>2]|0)+40+(c[p>>2]<<2)>>2]|0)u=c[m+24>>2]|0;else u=c[m+20>>2]|0;c[q>>2]=u;c[p>>2]=(d[c[c[n>>2]>>2]>>0]|0)>>1&(1<<c[(c[o>>2]|0)+36>>2])-1;n=c[o>>2]|0;if(c[(c[o>>2]|0)+40+(c[p>>2]<<2)>>2]|0)v=c[n+24>>2]|0;else v=c[n+20>>2]|0;c[r>>2]=v;v=k;k=((c[q>>2]|0)+(c[r>>2]|0)|0)/4|0;r=Ge(c[v>>2]|0,c[v+4>>2]|0,k|0,((k|0)<0)<<31>>31|0)|0;k=s;c[k>>2]=r;c[k+4>>2]=C;if((c[s+4>>2]|0)<0){k=j;c[k>>2]=0;c[k+4>>2]=0;w=j;x=w;y=c[x>>2]|0;z=w+4|0;A=z;B=c[A>>2]|0;C=B;i=h;return y|0}else{k=s;s=c[k+4>>2]|0;r=j;c[r>>2]=c[k>>2];c[r+4>>2]=s;w=j;x=w;y=c[x>>2]|0;z=w+4|0;A=z;B=c[A>>2]|0;C=B;i=h;return y|0}return 0}function ed(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;g=i;i=i+48|0;h=g+32|0;j=g+12|0;k=g+28|0;l=g+24|0;m=g+36|0;n=g+16|0;o=g;p=g+20|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[g+8>>2]=f;c[n>>2]=c[l>>2];l=o;c[l>>2]=0;c[l+4>>2]=0;if((c[m>>2]|0)<68){c[h>>2]=0;q=c[h>>2]|0;i=g;return q|0}else{m=bd((c[n>>2]|0)+36|0)|0;l=o;c[l>>2]=m;c[l+4>>2]=((m|0)<0)<<31>>31;m=o;oc(c[j>>2]|0,c[k>>2]|0,c[m>>2]|0,c[m+4>>2]|0,1e3,0)|0;Zb(c[j>>2]|0,c[k>>2]|0,3)|0;m=bd((c[n>>2]|0)+68|0)|0;n=Me(m|0,((m|0)<0)<<31>>31|0,2,0)|0;c[p>>2]=n;Zc(c[j>>2]|0,c[k>>2]|0,c[p>>2]|0)|0;c[h>>2]=1;q=c[h>>2]|0;i=g;return q|0}return 0}function fd(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+32|0;g=f+8|0;h=f;j=f+24|0;k=f+20|0;l=f+16|0;m=h;c[m>>2]=a;c[m+4>>2]=b;c[j>>2]=d;c[k>>2]=e;c[l>>2]=c[(c[j>>2]|0)+504>>2];do if(!(c[(c[j>>2]|0)+504>>2]|0)){e=ye(12)|0;c[(c[j>>2]|0)+504>>2]=e;if(!(c[(c[j>>2]|0)+504>>2]|0)){e=g;c[e>>2]=-1;c[e+4>>2]=-1;break}else{c[l>>2]=c[(c[j>>2]|0)+504>>2];c[(c[l>>2]|0)+8>>2]=0;e=_(c[(c[c[k>>2]>>2]|0)+64>>2]|0,c[(c[c[k>>2]>>2]|0)+56>>2]|0)|0;c[(c[l>>2]|0)+4>>2]=e;c[c[l>>2]>>2]=1;e=g;c[e>>2]=0;c[e+4>>2]=0;break}}else{e=c[l>>2]|0;if((c[c[l>>2]>>2]|0)<2)c[e>>2]=(c[e>>2]|0)+1;else c[e+8>>2]=1;e=h;d=c[e+4>>2]|0;if((d|0)>-1|(d|0)==-1&(c[e>>2]|0)>>>0>4294967295){e=h;d=c[e+4>>2]|0;b=g;c[b>>2]=c[e>>2];c[b+4>>2]=d;break}if(!(c[(c[l>>2]|0)+8>>2]|0)){d=g;c[d>>2]=0;c[d+4>>2]=0;break}d=(c[j>>2]|0)+488|0;b=c[d+4>>2]|0;if((b|0)>0|(b|0)==0&(c[d>>2]|0)>>>0>0){d=(c[j>>2]|0)+488|0;b=c[(c[l>>2]|0)+4>>2]|0;e=Me(c[d>>2]|0,c[d+4>>2]|0,b|0,((b|0)<0)<<31>>31|0)|0;b=g;c[b>>2]=e;c[b+4>>2]=C;break}else{b=g;c[b>>2]=-1;c[b+4>>2]=-1;break}}while(0);l=g;C=c[l+4>>2]|0;i=f;return c[l>>2]|0}function gd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=i;i=i+48|0;h=g+28|0;j=g+12|0;k=g+24|0;l=g+20|0;m=g+32|0;n=g+16|0;o=g;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[g+8>>2]=f;c[n>>2]=c[l>>2];if((c[m>>2]|0)<28){c[h>>2]=0;p=c[h>>2]|0;i=g;return p|0}else{m=Yc((c[n>>2]|0)+16|0)|0;n=o;c[n>>2]=m;c[n+4>>2]=((m|0)<0)<<31>>31;m=o;oc(c[j>>2]|0,c[k>>2]|0,c[m>>2]|0,c[m+4>>2]|0,1e3,0)|0;Zc(c[j>>2]|0,c[k>>2]|0,3)|0;c[h>>2]=1;p=c[h>>2]|0;i=g;return p|0}return 0}function hd(a,b,e,f,g){a=a|0;b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0;h=i;i=i+48|0;j=h+24|0;k=h+28|0;l=h+32|0;m=h+36|0;n=h+40|0;o=h+20|0;p=h;q=h+8|0;r=h+16|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=e;c[n>>2]=f;c[h+44>>2]=g;c[o>>2]=c[m>>2];m=p;c[m>>2]=0;c[m+4>>2]=0;m=q;c[m>>2]=0;c[m+4>>2]=0;if((c[n>>2]|0)<28){c[j>>2]=0;s=c[j>>2]|0;i=h;return s|0}m=id((c[o>>2]|0)+12|0)|0;g=p;c[g>>2]=m;c[g+4>>2]=C;g=id((c[o>>2]|0)+20|0)|0;m=q;c[m>>2]=g;c[m+4>>2]=C;if((c[n>>2]|0)>28)c[r>>2]=d[(c[o>>2]|0)+28>>0];else c[r>>2]=0;o=c[k>>2]|0;n=c[l>>2]|0;m=p;p=c[m>>2]|0;g=c[m+4>>2]|0;m=q;q=Ue(1e3,0,c[m>>2]|0,c[m+4>>2]|0)|0;oc(o,n,p,g,q,C)|0;mc(c[k>>2]|0,c[l>>2]|0,c[r>>2]|0)|0;Zc(c[k>>2]|0,c[l>>2]|0,3)|0;c[j>>2]=1;s=c[j>>2]|0;i=h;return s|0}function id(a){a=a|0;var b=0,e=0,f=0,g=0;b=i;i=i+16|0;e=b+8|0;f=b+4|0;g=b;c[e>>2]=a;c[f>>2]=d[c[e>>2]>>0]|0|(d[(c[e>>2]|0)+1>>0]|0)<<8|(d[(c[e>>2]|0)+2>>0]|0)<<16|(d[(c[e>>2]|0)+3>>0]|0)<<24;c[g>>2]=d[(c[e>>2]|0)+4>>0]|0|(d[(c[e>>2]|0)+5>>0]|0)<<8|(d[(c[e>>2]|0)+6>>0]|0)<<16|(d[(c[e>>2]|0)+7>>0]|0)<<24;C=c[g>>2]|0;i=b;return c[f>>2]|0}function jd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0;g=i;i=i+32|0;h=g+16|0;j=g+12|0;c[h>>2]=a;c[j>>2]=b;c[g+8>>2]=d;c[g+4>>2]=e;c[g>>2]=f;oc(c[h>>2]|0,c[j>>2]|0,0,0,1,0)|0;i=g;return 1}function kd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0;g=i;i=i+32|0;h=g+16|0;j=g+12|0;c[h>>2]=a;c[j>>2]=b;c[g+8>>2]=d;c[g+4>>2]=e;c[g>>2]=f;oc(c[h>>2]|0,c[j>>2]|0,0,0,1,0)|0;Zc(c[h>>2]|0,c[j>>2]|0,1)|0;i=g;return 1}function ld(a,b,e,f,g){a=a|0;b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0;h=i;i=i+32|0;j=h+24|0;k=h+16|0;l=h+20|0;m=h+8|0;n=h;c[j>>2]=a;c[k>>2]=b;c[l>>2]=e;c[h+28>>2]=f;c[h+12>>2]=g;c[m>>2]=c[l>>2];l=n;c[l>>2]=0;c[l+4>>2]=0;l=(d[(c[m>>2]|0)+14>>0]|0)<<12;g=(d[(c[m>>2]|0)+15>>0]|0)<<4;f=(d[(c[m>>2]|0)+16>>0]|0)>>4&15;m=n;c[m>>2]=l|g|f;c[m+4>>2]=((l|0)<0)<<31>>31|((g|0)<0)<<31>>31|((f|0)<0)<<31>>31;f=n;oc(c[j>>2]|0,c[k>>2]|0,c[f>>2]|0,c[f+4>>2]|0,1e3,0)|0;Zc(c[j>>2]|0,c[k>>2]|0,3)|0;i=h;return 1}function md(b,e,f,g){b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;h=i;i=i+48|0;j=h;k=h+8|0;l=h+20|0;m=h+28|0;n=h+16|0;o=h+32|0;p=h+24|0;q=k;c[q>>2]=b;c[q+4>>2]=e;c[l>>2]=f;c[m>>2]=g;do if(c[(c[l>>2]|0)+504>>2]|0){c[n>>2]=c[(c[l>>2]|0)+504>>2];if((d[c[c[m>>2]>>2]>>0]|0|0)==255)c[(c[n>>2]|0)+8>>2]=1;g=k;if((((c[g>>2]|0)==-1?(c[g+4>>2]|0)==-1:0)?(d[c[c[m>>2]>>2]>>0]|0|0)==255:0)?(c[(c[m>>2]|0)+4>>2]|0)>2:0){a[o>>0]=((d[(c[c[m>>2]>>2]|0)+2>>0]|0)&240)>>4;do switch(d[o>>0]|0|0){case 0:{c[p>>2]=-1;break}case 1:{c[p>>2]=192;break}case 2:{c[p>>2]=576;break}case 3:{c[p>>2]=1152;break}case 4:{c[p>>2]=2304;break}case 5:{c[p>>2]=4608;break}case 6:{c[p>>2]=-1;break}case 7:{c[p>>2]=-1;break}case 8:{c[p>>2]=256;break}case 9:{c[p>>2]=512;break}case 10:{c[p>>2]=1024;break}case 11:{c[p>>2]=2048;break}case 12:{c[p>>2]=4096;break}case 13:{c[p>>2]=8192;break}case 14:{c[p>>2]=16384;break}case 15:{c[p>>2]=32768;break}default:c[p>>2]=-1}while(0);if((c[p>>2]|0)==-1)break;g=c[n>>2]|0;f=c[p>>2]|0;e=Me(c[g>>2]|0,c[g+4>>2]|0,f|0,((f|0)<0)<<31>>31|0)|0;f=k;c[f>>2]=e;c[f+4>>2]=C;break}f=k;if(((c[f>>2]|0)==-1?(c[f+4>>2]|0)==-1:0)?(c[(c[n>>2]|0)+8>>2]|0)==0:0){f=k;c[f>>2]=0;c[f+4>>2]=0}}else{f=ye(16)|0;c[(c[l>>2]|0)+504>>2]=f;if(c[(c[l>>2]|0)+504>>2]|0){c[n>>2]=c[(c[l>>2]|0)+504>>2];f=c[n>>2]|0;c[f>>2]=0;c[f+4>>2]=0;c[(c[n>>2]|0)+8>>2]=0;break}f=j;c[f>>2]=-1;c[f+4>>2]=-1;r=j;s=r;t=c[s>>2]|0;u=r+4|0;v=u;w=c[v>>2]|0;C=w;i=h;return t|0}while(0);l=k;p=c[l+4>>2]|0;o=c[n>>2]|0;c[o>>2]=c[l>>2];c[o+4>>2]=p;p=k;k=c[p+4>>2]|0;o=j;c[o>>2]=c[p>>2];c[o+4>>2]=k;r=j;s=r;t=c[s>>2]|0;u=r+4|0;v=u;w=c[v>>2]|0;C=w;i=h;return t|0}function nd(a,b,e,f,g){a=a|0;b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;h=i;i=i+48|0;j=h+32|0;k=h+12|0;l=h+28|0;m=h+24|0;n=h+36|0;o=h+16|0;p=h;q=h+20|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=e;c[n>>2]=f;c[h+8>>2]=g;c[o>>2]=c[m>>2];m=p;c[m>>2]=0;c[m+4>>2]=0;if((c[n>>2]|0)<51){c[j>>2]=0;r=c[j>>2]|0;i=h;return r|0}else{n=(d[(c[o>>2]|0)+27>>0]|0)<<12;m=(d[(c[o>>2]|0)+28>>0]|0)<<4;g=(d[(c[o>>2]|0)+29>>0]|0)>>4&15;f=p;c[f>>2]=n|m|g;c[f+4>>2]=((n|0)<0)<<31>>31|((m|0)<0)<<31>>31|((g|0)<0)<<31>>31;g=p;oc(c[k>>2]|0,c[l>>2]|0,c[g>>2]|0,c[g+4>>2]|0,1e3,0)|0;c[q>>2]=(od((c[o>>2]|0)+7|0)|0)&65535;Zc(c[k>>2]|0,c[l>>2]|0,c[q>>2]|0)|0;c[j>>2]=1;r=c[j>>2]|0;i=h;return r|0}return 0}function od(a){a=a|0;var b=0,e=0;b=i;i=i+16|0;e=b;c[e>>2]=a;i=b;return ((d[c[e>>2]>>0]|0)<<8|(d[(c[e>>2]|0)+1>>0]|0))&65535|0}function pd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;g=i;i=i+48|0;h=g+32|0;j=g+28|0;k=g+36|0;l=g+16|0;m=g+40|0;n=g+20|0;o=g;p=g+8|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[g+24>>2]=f;c[n>>2]=c[l>>2];l=o;c[l>>2]=0;c[l+4>>2]=0;l=p;c[l>>2]=0;c[l+4>>2]=0;if((c[m>>2]|0)<28){c[h>>2]=0;q=c[h>>2]|0;i=g;return q|0}else{m=id((c[n>>2]|0)+8|0)|0;l=o;c[l>>2]=m;c[l+4>>2]=C;l=id((c[n>>2]|0)+16|0)|0;n=p;c[n>>2]=l;c[n+4>>2]=C;n=c[j>>2]|0;j=c[k>>2]|0;k=o;o=c[k>>2]|0;l=c[k+4>>2]|0;k=p;p=Ue(1e3,0,c[k>>2]|0,c[k+4>>2]|0)|0;oc(n,j,o,l,p,C)|0;c[h>>2]=1;q=c[h>>2]|0;i=g;return q|0}return 0}function qd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;g=i;i=i+48|0;h=g+32|0;j=g+12|0;k=g+28|0;l=g+24|0;m=g+36|0;n=g+16|0;o=g;p=g+20|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[g+8>>2]=f;c[n>>2]=c[l>>2];l=o;c[l>>2]=0;c[l+4>>2]=0;if((c[m>>2]|0)<56){c[h>>2]=0;q=c[h>>2]|0;i=g;return q|0}else{m=bd((c[n>>2]|0)+40|0)|0;l=o;c[l>>2]=m;c[l+4>>2]=((m|0)<0)<<31>>31;m=o;oc(c[j>>2]|0,c[k>>2]|0,c[m>>2]|0,c[m+4>>2]|0,1e3,0)|0;m=bd((c[n>>2]|0)+52|0)|0;n=Me(m|0,((m|0)<0)<<31>>31|0,2,0)|0;c[p>>2]=n;Zc(c[j>>2]|0,c[k>>2]|0,c[p>>2]|0)|0;c[h>>2]=1;q=c[h>>2]|0;i=g;return q|0}return 0}function rd(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0;f=i;i=i+32|0;g=f+8|0;h=f;j=f+24|0;k=f+16|0;l=h;c[l>>2]=a;c[l+4>>2]=b;c[j>>2]=d;c[f+20>>2]=e;c[k>>2]=c[(c[j>>2]|0)+504>>2];do if(!(c[(c[j>>2]|0)+504>>2]|0)){e=ye(12)|0;c[(c[j>>2]|0)+504>>2]=e;if(!(c[(c[j>>2]|0)+504>>2]|0)){e=g;c[e>>2]=-1;c[e+4>>2]=-1;break}else{c[k>>2]=c[(c[j>>2]|0)+504>>2];c[(c[k>>2]|0)+8>>2]=0;c[(c[k>>2]|0)+4>>2]=256;c[c[k>>2]>>2]=1;e=g;c[e>>2]=0;c[e+4>>2]=0;break}}else{e=c[k>>2]|0;if((c[c[k>>2]>>2]|0)<2)c[e>>2]=(c[e>>2]|0)+1;else c[e+8>>2]=1;e=h;d=c[e+4>>2]|0;if((d|0)>-1|(d|0)==-1&(c[e>>2]|0)>>>0>4294967295){e=h;d=c[e+4>>2]|0;b=g;c[b>>2]=c[e>>2];c[b+4>>2]=d;break}if(!(c[(c[k>>2]|0)+8>>2]|0)){d=g;c[d>>2]=0;c[d+4>>2]=0;break}d=(c[j>>2]|0)+488|0;b=c[d+4>>2]|0;if((b|0)>0|(b|0)==0&(c[d>>2]|0)>>>0>0){d=(c[j>>2]|0)+488|0;b=c[(c[k>>2]|0)+4>>2]|0;e=Me(c[d>>2]|0,c[d+4>>2]|0,b|0,((b|0)<0)<<31>>31|0)|0;b=g;c[b>>2]=e;c[b+4>>2]=C;break}else{b=g;c[b>>2]=-1;c[b+4>>2]=-1;break}}while(0);k=g;C=c[k+4>>2]|0;i=f;return c[k>>2]|0}function sd(b,e,f,g,h){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;j=i;i=i+48|0;k=j;l=j+16|0;m=j+4|0;n=j+8|0;o=j+32|0;p=j+12|0;q=j+24|0;r=j+20|0;s=j+40|0;t=j+28|0;c[l>>2]=b;c[m>>2]=e;c[n>>2]=f;c[o>>2]=g;c[j+36>>2]=h;c[p>>2]=c[n>>2];a[s>>0]=0;if((c[o>>2]|0)<64){c[k>>2]=0;u=c[k>>2]|0;i=j;return u|0}else{c[q>>2]=bd((c[p>>2]|0)+24|0)|0;c[r>>2]=bd((c[p>>2]|0)+28|0)|0;a[s>>0]=a[(c[p>>2]|0)+15>>0]|0;c[t>>2]=d[(c[p>>2]|0)+11>>0];p=c[l>>2]|0;o=c[m>>2]|0;n=c[q>>2]|0;q=c[r>>2]|0;r=Ue(1e3,0,q|0,((q|0)<0)<<31>>31|0)|0;oc(p,o,n,((n|0)<0)<<31>>31,r,C)|0;mc(c[l>>2]|0,c[m>>2]|0,d[s>>0]|0)|0;Zc(c[l>>2]|0,c[m>>2]|0,c[t>>2]|0)|0;c[k>>2]=1;u=c[k>>2]|0;i=j;return u|0}return 0}function td(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0;g=i;i=i+32|0;h=g+4|0;j=g+16|0;k=g+8|0;l=g+20|0;m=g+28|0;n=g+12|0;o=g+24|0;c[j>>2]=a;c[k>>2]=b;c[l>>2]=d;c[m>>2]=e;c[g>>2]=f;c[n>>2]=22;c[o>>2]=ye(48)|0;if(!(c[o>>2]|0)){c[h>>2]=-1;p=c[h>>2]|0;i=g;return p|0}if((rc(c[o>>2]|0,c[l>>2]|0,c[m>>2]|0)|0)==-1){ze(c[o>>2]|0);c[h>>2]=-1;p=c[h>>2]|0;i=g;return p|0}else{m=c[j>>2]|0;l=c[k>>2]|0;f=Ue(2,0,c[(c[o>>2]|0)+32>>2]|0,0)|0;e=C;d=Ue(1e3,0,c[(c[o>>2]|0)+36>>2]|0,0)|0;oc(m,l,f,e,d,C)|0;mc(c[j>>2]|0,c[k>>2]|0,c[n>>2]|0)|0;Zc(c[j>>2]|0,c[k>>2]|0,0)|0;ze(c[o>>2]|0);c[h>>2]=1;p=c[h>>2]|0;i=g;return p|0}return 0}function ud(b,e,f,g,h){b=b|0;e=e|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0;j=i;i=i+32|0;k=j+24|0;l=j+16|0;m=j+20|0;n=j+12|0;o=j+4|0;p=j+28|0;c[l>>2]=b;c[m>>2]=e;c[n>>2]=f;c[o>>2]=g;c[j>>2]=h;c[j+8>>2]=c[n>>2];if((c[o>>2]|0)<19){c[k>>2]=0;q=c[k>>2]|0;i=j;return q|0}a[p>>0]=a[(c[n>>2]|0)+9>>0]|0;if((d[p>>0]|0|0)<1){c[k>>2]=0;q=c[k>>2]|0;i=j;return q|0}else{oc(c[l>>2]|0,c[m>>2]|0,48e3,0,1e3,0)|0;mc(c[l>>2]|0,c[m>>2]|0,0)|0;p=c[l>>2]|0;o=c[m>>2]|0;qc(p,o,(vd((c[n>>2]|0)+10|0)|0)&65535,0)|0;Zc(c[l>>2]|0,c[m>>2]|0,2)|0;c[k>>2]=1;q=c[k>>2]|0;i=j;return q|0}return 0}function vd(a){a=a|0;var b=0,e=0;b=i;i=i+16|0;e=b;c[e>>2]=a;i=b;return (d[c[e>>2]>>0]|0|(d[(c[e>>2]|0)+1>>0]|0)<<8)&65535|0}function wd(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;f=i;i=i+48|0;g=f+16|0;h=f+24|0;j=f+36|0;k=f+40|0;l=f+32|0;m=f;n=f+8|0;o=h;c[o>>2]=a;c[o+4>>2]=b;c[j>>2]=d;c[k>>2]=e;c[l>>2]=c[(c[j>>2]|0)+504>>2];if(!(c[(c[j>>2]|0)+504>>2]|0)){e=ye(16)|0;c[(c[j>>2]|0)+504>>2]=e;if(!(c[(c[j>>2]|0)+504>>2]|0)){e=g;c[e>>2]=-1;c[e+4>>2]=-1;p=g;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=f;return r|0}else{c[l>>2]=c[(c[j>>2]|0)+504>>2];c[(c[l>>2]|0)+4>>2]=0;c[c[l>>2]>>2]=1;e=(c[l>>2]|0)+8|0;c[e>>2]=0;c[e+4>>2]=0;e=g;c[e>>2]=0;c[e+4>>2]=0;p=g;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=f;return r|0}}e=c[l>>2]|0;if((c[c[l>>2]>>2]|0)<2)c[e>>2]=(c[e>>2]|0)+1;else c[e+4>>2]=1;e=h;d=c[e+4>>2]|0;if((d|0)>-1|(d|0)==-1&(c[e>>2]|0)>>>0>4294967295){e=h;h=c[e+4>>2]|0;d=g;c[d>>2]=c[e>>2];c[d+4>>2]=h;p=g;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=f;return r|0}if(!(c[(c[l>>2]|0)+4>>2]|0)){h=g;c[h>>2]=0;c[h+4>>2]=0;p=g;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=f;return r|0}h=xd(c[k>>2]|0)|0;k=m;c[k>>2]=h;c[k+4>>2]=C;k=(c[j>>2]|0)+488|0;h=c[k+4>>2]|0;if(!((h|0)>0|(h|0)==0&(c[k>>2]|0)>>>0>0)){k=m;h=(c[l>>2]|0)+8|0;l=h;d=Me(c[l>>2]|0,c[l+4>>2]|0,c[k>>2]|0,c[k+4>>2]|0)|0;k=h;c[k>>2]=d;c[k+4>>2]=C;k=g;c[k>>2]=-1;c[k+4>>2]=-1;p=g;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=f;return r|0}k=(c[j>>2]|0)+488|0;d=m;m=Me(c[k>>2]|0,c[k+4>>2]|0,c[d>>2]|0,c[d+4>>2]|0)|0;d=n;c[d>>2]=m;c[d+4>>2]=C;d=n;m=c[d+4>>2]|0;k=(c[j>>2]|0)+496|0;h=c[k+4>>2]|0;if((m|0)>(h|0)|((m|0)==(h|0)?(c[d>>2]|0)>>>0>(c[k>>2]|0)>>>0:0)?(k=(c[j>>2]|0)+496|0,d=c[k+4>>2]|0,h=(c[j>>2]|0)+488|0,m=c[h+4>>2]|0,(d|0)>(m|0)|((d|0)==(m|0)?(c[k>>2]|0)>>>0>=(c[h>>2]|0)>>>0:0)):0){h=(c[j>>2]|0)+496|0;v=c[h>>2]|0;w=c[h+4>>2]|0}else{h=n;v=c[h>>2]|0;w=c[h+4>>2]|0}h=g;c[h>>2]=v;c[h+4>>2]=w;p=g;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=f;return r|0}function xd(b){b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;e=i;i=i+32|0;f=e;g=e+16|0;h=e+21|0;j=e+22|0;k=e+20|0;l=e+8|0;m=e+12|0;c[g>>2]=b;do if((c[(c[g>>2]|0)+4>>2]|0)>=1){a[h>>0]=a[c[c[g>>2]>>2]>>0]|0;a[j>>0]=(d[h>>0]|0)&3;c[l>>2]=c[1968+((d[h>>0]|0)>>3<<2)>>2];if((d[j>>0]|0|0)==3?(c[(c[g>>2]|0)+4>>2]|0)<2:0){b=f;c[b>>2]=0;c[b+4>>2]=0;break}b=d[j>>0]|0;if((b|0)==3)a[k>>0]=(d[(c[c[g>>2]>>2]|0)+1>>0]|0)&63;else if(!b)a[k>>0]=1;else if((b|0)==2|(b|0)==1)a[k>>0]=2;c[m>>2]=_(c[l>>2]|0,d[k>>0]|0)|0;if((c[m>>2]|0)>5760){b=f;c[b>>2]=0;c[b+4>>2]=0;break}else{b=c[m>>2]|0;n=f;c[n>>2]=b;c[n+4>>2]=((b|0)<0)<<31>>31;break}}else{b=f;c[b>>2]=0;c[b+4>>2]=0}while(0);m=f;C=c[m+4>>2]|0;i=e;return c[m>>2]|0}function yd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;g=i;i=i+32|0;h=g+8|0;j=g+28|0;k=g+24|0;l=g+20|0;m=g+16|0;n=g;o=h;c[o>>2]=a;c[o+4>>2]=b;c[j>>2]=d;c[k>>2]=e;c[l>>2]=f;c[m>>2]=c[(c[j>>2]|0)+504>>2];j=h;f=c[j+4>>2]|0;e=(c[m>>2]|0)+8|0;d=c[e+4>>2]|0;b=h;h=c[b>>2]|0;o=c[b+4>>2]|0;if(!((f|0)>(d|0)|((f|0)==(d|0)?(c[j>>2]|0)>>>0>=(c[e>>2]|0)>>>0:0))){e=n;c[e>>2]=h;c[e+4>>2]=o;e=xd(c[k>>2]|0)|0;k=(c[m>>2]|0)+8|0;j=k;d=Ge(c[j>>2]|0,c[j+4>>2]|0,e|0,C|0)|0;e=k;c[e>>2]=d;c[e+4>>2]=C;p=n;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=g;return r|0}e=xd(c[l>>2]|0)|0;l=Ge(h|0,o|0,e|0,C|0)|0;e=n;c[e>>2]=l;c[e+4>>2]=C;e=n;l=c[e+4>>2]|0;o=(c[m>>2]|0)+8|0;h=c[o+4>>2]|0;if((l|0)<(h|0)|((l|0)==(h|0)?(c[e>>2]|0)>>>0<(c[o>>2]|0)>>>0:0)){o=(c[m>>2]|0)+8|0;e=c[o+4>>2]|0;h=n;c[h>>2]=c[o>>2];c[h+4>>2]=e}e=(c[m>>2]|0)+8|0;c[e>>2]=0;c[e+4>>2]=0;p=n;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=g;return r|0}function zd(a,b,e,f,g){a=a|0;b=b|0;e=e|0;f=f|0;g=g|0;var h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0;h=i;i=i+48|0;j=h+28|0;k=h+16|0;l=h+4|0;m=h+8|0;n=h+32|0;o=h+12|0;p=h+24|0;q=h+20|0;c[k>>2]=a;c[l>>2]=b;c[m>>2]=e;c[n>>2]=f;c[h>>2]=g;c[o>>2]=c[m>>2];if((c[n>>2]|0)<26){c[j>>2]=0;r=c[j>>2]|0;i=h;return r|0}if((d[c[m>>2]>>0]|0|0)!=79){c[j>>2]=0;r=c[j>>2]|0;i=h;return r|0}if(ve((c[m>>2]|0)+1|0,2512,4)|0){c[j>>2]=0;r=c[j>>2]|0;i=h;return r|0}if((d[(c[m>>2]|0)+5>>0]|0|0)!=1){c[j>>2]=0;r=c[j>>2]|0;i=h;return r|0}if((d[(c[m>>2]|0)+6>>0]|0|0)!=1){c[j>>2]=0;r=c[j>>2]|0;i=h;return r|0}else{c[p>>2]=Yc((c[o>>2]|0)+18|0)|0;c[q>>2]=Yc((c[o>>2]|0)+22|0)|0;o=c[k>>2]|0;m=c[l>>2]|0;n=c[p>>2]|0;p=c[q>>2]|0;q=Ue(1e3,0,p|0,((p|0)<0)<<31>>31|0)|0;oc(o,m,n,((n|0)<0)<<31>>31,q,C)|0;mc(c[k>>2]|0,c[l>>2]|0,32)|0;Zc(c[k>>2]|0,c[l>>2]|0,1)|0;c[j>>2]=1;r=c[j>>2]|0;i=h;return r|0}return 0}function Ad(a,b,e,f){a=a|0;b=b|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0;g=i;i=i+80|0;h=g+40|0;j=g+24|0;k=g+48|0;l=g+52|0;m=g+56|0;n=g+60|0;o=g+68|0;p=g+64|0;q=g+32|0;r=g;s=g+8|0;t=g+16|0;u=j;c[u>>2]=a;c[u+4>>2]=b;c[k>>2]=e;c[l>>2]=f;c[p>>2]=c[(c[k>>2]|0)+504>>2];if(!(c[(c[k>>2]|0)+504>>2]|0)){f=ye(8)|0;c[(c[k>>2]|0)+504>>2]=f;if(!(c[(c[k>>2]|0)+504>>2]|0)){f=h;c[f>>2]=-1;c[f+4>>2]=-1;v=h;w=v;x=c[w>>2]|0;y=v+4|0;z=y;A=c[z>>2]|0;C=A;i=g;return x|0}else{c[p>>2]=c[(c[k>>2]|0)+504>>2];c[(c[p>>2]|0)+4>>2]=0;c[c[p>>2]>>2]=1;f=h;c[f>>2]=0;c[f+4>>2]=0;v=h;w=v;x=c[w>>2]|0;y=v+4|0;z=y;A=c[z>>2]|0;C=A;i=g;return x|0}}if(!(c[(c[l>>2]|0)+4>>2]|0))B=1;else B=(d[c[c[l>>2]>>2]>>0]|0|0)==79;c[m>>2]=B&1;if((c[m>>2]|0)==0?(c[(c[l>>2]|0)+4>>2]|0)>0:0)D=((d[c[c[l>>2]>>2]>>0]|0)&1|0)==0;else D=0;c[n>>2]=D&1;if((c[m>>2]|0)==0?(c[(c[l>>2]|0)+4>>2]|0)>0:0)E=((d[c[c[l>>2]>>2]>>0]|0)>>4&1|0)!=0;else E=0;c[o>>2]=E&1;E=c[p>>2]|0;if(c[m>>2]|0)c[E>>2]=(c[E>>2]|0)+1;else c[E+4>>2]=1;E=j;l=c[E+4>>2]|0;if((l|0)>-1|(l|0)==-1&(c[E>>2]|0)>>>0>4294967295){E=j;j=c[E+4>>2]|0;l=h;c[l>>2]=c[E>>2];c[l+4>>2]=j;v=h;w=v;x=c[w>>2]|0;y=v+4|0;z=y;A=c[z>>2]|0;C=A;i=g;return x|0}if(!(c[(c[p>>2]|0)+4>>2]|0)){p=h;c[p>>2]=0;c[p+4>>2]=0;v=h;w=v;x=c[w>>2]|0;y=v+4|0;z=y;A=c[z>>2]|0;C=A;i=g;return x|0}p=(c[k>>2]|0)+488|0;j=c[p+4>>2]|0;if(!((j|0)>0|(j|0)==0&(c[p>>2]|0)>>>0>0)){p=h;c[p>>2]=-1;c[p+4>>2]=-1;v=h;w=v;x=c[w>>2]|0;y=v+4|0;z=y;A=c[z>>2]|0;C=A;i=g;return x|0}p=(c[k>>2]|0)+488|0;j=c[p>>2]|0;l=c[p+4>>2]|0;if(c[m>>2]|0){m=h;c[m>>2]=j;c[m+4>>2]=l;v=h;w=v;x=c[w>>2]|0;y=v+4|0;z=y;A=c[z>>2]|0;C=A;i=g;return x|0}m=Fe(j|0,l|0,32)|0;l=q;c[l>>2]=m;c[l+4>>2]=C;l=(c[k>>2]|0)+488|0;m=Fe(c[l>>2]|0,c[l+4>>2]|0,30)|0;l=r;c[l>>2]=m&3;c[l+4>>2]=0;l=(c[k>>2]|0)+488|0;k=Fe(c[l>>2]|0,c[l+4>>2]|0,3)|0;l=s;c[l>>2]=k&134217727;c[l+4>>2]=0;if(c[n>>2]|0){n=s;c[n>>2]=0;c[n+4>>2]=0}else{n=s;l=Me(c[n>>2]|0,c[n+4>>2]|0,1,0)|0;n=s;c[n>>2]=l;c[n+4>>2]=C}do if(!(c[o>>2]|0)){n=r;if((c[n>>2]|0)==3&(c[n+4>>2]|0)==0){n=r;c[n>>2]=0;c[n+4>>2]=0;break}else{n=r;l=Me(c[n>>2]|0,c[n+4>>2]|0,1,0)|0;n=r;c[n>>2]=l;c[n+4>>2]=C;break}}else{n=q;l=Me(c[n>>2]|0,c[n+4>>2]|0,1,0)|0;n=q;c[n>>2]=l;c[n+4>>2]=C;n=r;c[n>>2]=3;c[n+4>>2]=0}while(0);o=c[q>>2]|0;q=r;r=Ie(c[q>>2]|0,c[q+4>>2]|0,30)|0;q=o|C;o=s;s=Ie(c[o>>2]|0,c[o+4>>2]|0,3)|0;o=t;c[o>>2]=r|s;c[o+4>>2]=q|C;q=t;t=c[q+4>>2]|0;o=h;c[o>>2]=c[q>>2];c[o+4>>2]=t;v=h;w=v;x=c[w>>2]|0;y=v+4|0;z=y;A=c[z>>2]|0;C=A;i=g;return x|0}function Bd(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0;e=i;i=i+16|0;f=e+12|0;g=e+8|0;h=e+4|0;j=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=d;c[j>>2]=c[(c[f>>2]|0)+(c[g>>2]<<2)>>2];c[(c[f>>2]|0)+(c[g>>2]<<2)>>2]=c[(c[f>>2]|0)+(c[h>>2]<<2)>>2];c[(c[f>>2]|0)+(c[h>>2]<<2)>>2]=c[j>>2];i=e;return}function Cd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;g=i;i=i+32|0;h=g+8|0;j=g+28|0;k=g+24|0;l=g;m=g+16|0;c[j>>2]=a;c[k>>2]=b;b=l;c[b>>2]=d;c[b+4>>2]=e;c[g+20>>2]=f;c[m>>2]=sb(c[j>>2]|0,c[k>>2]|0)|0;if(!(c[m>>2]|0)){k=h;c[k>>2]=-1;c[k+4>>2]=-1;n=h;o=n;p=c[o>>2]|0;q=n+4|0;r=q;s=c[r>>2]|0;C=s;i=g;return p|0}k=l;j=c[k+4>>2]|0;f=(c[m>>2]|0)+392|0;e=c[f+4>>2]|0;if((j|0)<(e|0)|((j|0)==(e|0)?(c[k>>2]|0)>>>0<=(c[f>>2]|0)>>>0:0)){t=0;u=0}else{f=l;k=(c[m>>2]|0)+392|0;e=Ge(c[f>>2]|0,c[f+4>>2]|0,c[k>>2]|0,c[k+4>>2]|0)|0;t=e;u=C}e=l;c[e>>2]=t;c[e+4>>2]=u;u=(c[m>>2]|0)+384|0;e=l;l=Ue(c[u>>2]|0,c[u+4>>2]|0,c[e>>2]|0,c[e+4>>2]|0)|0;e=(c[m>>2]|0)+376|0;m=Se(l|0,C|0,c[e>>2]|0,c[e+4>>2]|0)|0;e=h;c[e>>2]=m;c[e+4>>2]=C;n=h;o=n;p=c[o>>2]|0;q=n+4|0;r=q;s=c[r>>2]|0;C=s;i=g;return p|0}function Dd(a,d,f,g,h){a=a|0;d=d|0;f=f|0;g=g|0;h=h|0;var j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;j=i;i=i+80|0;k=j+32|0;l=j+48|0;m=j+52|0;n=j+8|0;o=j+64|0;p=j+40|0;q=j;r=j+56|0;s=j+68|0;t=j+16|0;u=j+24|0;c[l>>2]=a;c[m>>2]=d;d=n;c[d>>2]=f;c[d+4>>2]=g;c[j+60>>2]=h;c[o>>2]=sb(c[l>>2]|0,c[m>>2]|0)|0;if(!(c[o>>2]|0)){m=k;c[m>>2]=-1;c[m+4>>2]=-1;v=k;w=v;x=c[w>>2]|0;y=v+4|0;z=y;A=c[z>>2]|0;C=A;i=j;return x|0}else{m=n;l=Fe(c[m>>2]|0,c[m+4>>2]|0,c[(c[o>>2]|0)+408>>2]|0)|0;m=p;c[m>>2]=l;c[m+4>>2]=C;m=n;n=c[m>>2]|0;l=c[m+4>>2]|0;m=p;h=Ie(c[m>>2]|0,c[m+4>>2]|0,c[(c[o>>2]|0)+408>>2]|0)|0;m=Ge(n|0,l|0,h|0,C|0)|0;h=q;c[h>>2]=m;c[h+4>>2]=C;h=p;p=q;m=Me(c[h>>2]|0,c[h+4>>2]|0,c[p>>2]|0,c[p+4>>2]|0)|0;p=Fe(m|0,C|0,9)|0;c[r>>2]=p;p=q;q=Fe(c[p>>2]|0,c[p+4>>2]|0,9)|0;b[s>>1]=q;q=Ge(c[r>>2]|0,0,e[s>>1]|0|0,0)|0;s=t;c[s>>2]=q;c[s+4>>2]=C;s=t;t=(c[o>>2]|0)+384|0;q=Ue(c[s>>2]|0,c[s+4>>2]|0,c[t>>2]|0,c[t+4>>2]|0)|0;t=(c[o>>2]|0)+376|0;o=Se(q|0,C|0,c[t>>2]|0,c[t+4>>2]|0)|0;t=u;c[t>>2]=o;c[t+4>>2]=C;t=u;u=c[t+4>>2]|0;o=k;c[o>>2]=c[t>>2];c[o+4>>2]=u;v=k;w=v;x=c[w>>2]|0;y=v+4|0;z=y;A=c[z>>2]|0;C=A;i=j;return x|0}return 0}function Ed(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0;g=i;i=i+48|0;h=g+24|0;j=g+32|0;k=g+36|0;l=g+16|0;m=g+40|0;n=g;o=g+8|0;c[j>>2]=a;c[k>>2]=b;b=l;c[b>>2]=d;c[b+4>>2]=e;c[g+44>>2]=f;c[m>>2]=sb(c[j>>2]|0,c[k>>2]|0)|0;if(!(c[m>>2]|0)){k=h;c[k>>2]=-1;c[k+4>>2]=-1;p=h;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=g;return r|0}else{k=l;l=Fe(c[k>>2]|0,c[k+4>>2]|0,c[(c[m>>2]|0)+408>>2]|0)|0;k=n;c[k>>2]=l;c[k+4>>2]=C;k=n;n=(c[m>>2]|0)+384|0;l=Ue(c[k>>2]|0,c[k+4>>2]|0,c[n>>2]|0,c[n+4>>2]|0)|0;n=(c[m>>2]|0)+376|0;m=Se(l|0,C|0,c[n>>2]|0,c[n+4>>2]|0)|0;n=o;c[n>>2]=m;c[n+4>>2]=C;n=o;o=c[n+4>>2]|0;m=h;c[m>>2]=c[n>>2];c[m+4>>2]=o;p=h;q=p;r=c[q>>2]|0;s=p+4|0;t=s;u=c[t>>2]|0;C=u;i=g;return r|0}return 0}function Fd(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0;g=i;i=i+64|0;h=g+32|0;j=g+40|0;k=g+44|0;l=g;m=g+52|0;n=g+24|0;o=g+8|0;p=g+16|0;c[j>>2]=a;c[k>>2]=b;b=l;c[b>>2]=d;c[b+4>>2]=e;c[g+48>>2]=f;c[m>>2]=sb(c[j>>2]|0,c[k>>2]|0)|0;if(!(c[m>>2]|0)){k=h;c[k>>2]=-1;c[k+4>>2]=-1;q=h;r=q;s=c[r>>2]|0;t=q+4|0;u=t;v=c[u>>2]|0;C=v;i=g;return s|0}k=l;j=Fe(c[k>>2]|0,c[k+4>>2]|0,c[(c[m>>2]|0)+408>>2]|0)|0;k=n;c[k>>2]=j;c[k+4>>2]=C;k=l;j=c[k>>2]|0;f=c[k+4>>2]|0;k=n;e=Ie(c[k>>2]|0,c[k+4>>2]|0,c[(c[m>>2]|0)+408>>2]|0)|0;k=Ge(j|0,f|0,e|0,C|0)|0;e=o;c[e>>2]=k;c[e+4>>2]=C;e=n;n=o;o=Me(c[e>>2]|0,c[e+4>>2]|0,c[n>>2]|0,c[n+4>>2]|0)|0;n=l;c[n>>2]=o;c[n+4>>2]=C;n=l;o=c[n+4>>2]|0;if((o|0)>0|(o|0)==0&(c[n>>2]|0)>>>0>0){n=(c[m>>2]|0)+392|0;o=l;e=Ge(c[o>>2]|0,c[o+4>>2]|0,c[n>>2]|0,c[n+4>>2]|0)|0;n=l;c[n>>2]=e;c[n+4>>2]=C}n=l;l=(c[m>>2]|0)+384|0;e=Ue(c[n>>2]|0,c[n+4>>2]|0,c[l>>2]|0,c[l+4>>2]|0)|0;l=(c[m>>2]|0)+376|0;m=Se(e|0,C|0,c[l>>2]|0,c[l+4>>2]|0)|0;l=p;c[l>>2]=m;c[l+4>>2]=C;l=p;p=c[l+4>>2]|0;m=h;c[m>>2]=c[l>>2];c[m+4>>2]=p;q=h;r=q;s=c[r>>2]|0;t=q+4|0;u=t;v=c[u>>2]|0;C=v;i=g;return s|0}function Gd(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[k>>2]=0;while(1){if((c[h>>2]|0)<=0){l=9;break}if((c[(c[g>>2]|0)+4>>2]|0)>>>0>=(c[(c[g>>2]|0)+8>>2]|0)>>>0){l=9;break}b=(c[(c[g>>2]|0)+12>>2]|0)-(c[h>>2]|0)|0;c[j>>2]=b;m=d[c[(c[g>>2]|0)+4>>2]>>0]|0;if((b|0)>=0)break;c[k>>2]=c[k>>2]|(m&c[2096+(c[(c[g>>2]|0)+12>>2]<<2)>>2])<<0-(c[j>>2]|0);c[h>>2]=(c[h>>2]|0)-(c[(c[g>>2]|0)+12>>2]|0);b=(c[g>>2]|0)+4|0;c[b>>2]=(c[b>>2]|0)+1;c[(c[g>>2]|0)+12>>2]=8}if((l|0)==9){c[f>>2]=c[k>>2];n=c[f>>2]|0;i=e;return n|0}c[k>>2]=c[k>>2]|m>>c[j>>2]&c[2096+(c[h>>2]<<2)>>2];j=(c[g>>2]|0)+12|0;c[j>>2]=(c[j>>2]|0)-(c[h>>2]|0);if(!(c[(c[g>>2]|0)+12>>2]|0)){h=(c[g>>2]|0)+4|0;c[h>>2]=(c[h>>2]|0)+1;c[(c[g>>2]|0)+12>>2]=8}c[f>>2]=c[k>>2];n=c[f>>2]|0;i=e;return n|0}function Hd(){var a=0,d=0,e=0,f=0,g=0;a=i;i=i+16|0;d=a+4|0;e=a;c[e>>2]=0;c[e>>2]=Ae(1,136)|0;if(!(c[e>>2]|0)){c[d>>2]=0;f=c[d>>2]|0;i=a;return f|0}g=Sd()|0;c[(c[e>>2]|0)+112>>2]=g;g=c[e>>2]|0;if(!(c[(c[e>>2]|0)+112>>2]|0)){ze(g);c[d>>2]=0;f=c[d>>2]|0;i=a;return f|0}else{b[g+116>>1]=0;b[(c[e>>2]|0)+118>>1]=0;c[(c[e>>2]|0)+120>>2]=0;g=(c[e>>2]|0)+128|0;c[g>>2]=0;c[g+4>>2]=0;c[d>>2]=c[e>>2];f=c[d>>2]|0;i=a;return f|0}return 0}function Id(a){a=a|0;var b=0,d=0,e=0,f=0;b=i;i=i+16|0;d=b+4|0;e=b;c[e>>2]=a;if(!(c[e>>2]|0)){c[d>>2]=-2;f=c[d>>2]|0;i=b;return f|0}else{Td(c[(c[e>>2]|0)+112>>2]|0);ze(c[e>>2]|0);c[d>>2]=0;f=c[d>>2]|0;i=b;return f|0}return 0}function Jd(a,d){a=a|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+16|0;f=e+12|0;g=e+8|0;h=e+4|0;j=e;c[g>>2]=a;c[h>>2]=d;c[j>>2]=-1;if(!(c[g>>2]|0)){c[f>>2]=-2;k=c[f>>2]|0;i=e;return k|0}if(!(c[h>>2]|0)){c[f>>2]=-13;k=c[f>>2]|0;i=e;return k|0}if(c[(c[h>>2]|0)+12>>2]|0){if((c[(c[g>>2]|0)+120>>2]|0)!=1){c[f>>2]=-1;k=c[f>>2]|0;i=e;return k|0}b[(c[g>>2]|0)+118>>1]=1;c[(c[g>>2]|0)+120>>2]=2;if(c[(c[h>>2]|0)+4>>2]|0){c[f>>2]=-6;k=c[f>>2]|0;i=e;return k|0}else{c[f>>2]=0;k=c[f>>2]|0;i=e;return k|0}}do if(!(ve(c[c[h>>2]>>2]|0,2520,8)|0)){c[j>>2]=Xd(c[g>>2]|0,c[h>>2]|0)|0;if(c[j>>2]|0){if(c[(c[h>>2]|0)+8>>2]|0){if(c[(c[g>>2]|0)+120>>2]|0)c[j>>2]=-14}else c[j>>2]=-12;c[(c[g>>2]|0)+120>>2]=1}}else{if(!(ve(c[c[h>>2]>>2]|0,2536,8)|0)){c[j>>2]=Yd(c[g>>2]|0,c[h>>2]|0)|0;if(!(c[j>>2]|0))break;if((c[(c[g>>2]|0)+120>>2]|0)==1)break;c[j>>2]=-14;break}if(ve(c[c[h>>2]>>2]|0,2552,6)|0){c[j>>2]=-1;break}b[(c[g>>2]|0)+116>>1]=1;c[j>>2]=Zd(c[g>>2]|0,c[h>>2]|0)|0;if((c[j>>2]|0)!=0?(c[(c[g>>2]|0)+120>>2]|0)!=1:0)c[j>>2]=-14}while(0);c[f>>2]=c[j>>2];k=c[f>>2]|0;i=e;return k|0}function Kd(a,d){a=a|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+16|0;f=e+12|0;g=e+8|0;h=e+4|0;j=e;c[g>>2]=a;c[h>>2]=d;c[j>>2]=-1;d=_d(c[g>>2]|0,c[h>>2]|0)|0;c[j>>2]=d;if((d|0)<0){c[f>>2]=c[j>>2];k=c[f>>2]|0;i=e;return k|0}else{b[c[h>>2]>>1]=b[c[g>>2]>>1]|0;c[f>>2]=0;k=c[f>>2]|0;i=e;return k|0}return 0}function Ld(a,d){a=a|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+16|0;f=e+12|0;g=e+8|0;h=e+4|0;j=e;c[g>>2]=a;c[h>>2]=d;c[j>>2]=-1;d=_d(c[g>>2]|0,c[h>>2]|0)|0;c[j>>2]=d;if((d|0)<0){c[f>>2]=c[j>>2];k=c[f>>2]|0;i=e;return k|0}else{b[c[h>>2]>>1]=b[(c[g>>2]|0)+2>>1]|0;c[f>>2]=0;k=c[f>>2]|0;i=e;return k|0}return 0}function Md(a,b){a=a|0;b=b|0;var d=0,f=0,g=0,h=0,j=0,k=0,l=0;d=i;i=i+32|0;f=d+16|0;g=d+12|0;h=d+8|0;j=d+4|0;k=d;c[g>>2]=a;c[h>>2]=b;c[j>>2]=-1;c[k>>2]=0;b=_d(c[g>>2]|0,c[h>>2]|0)|0;c[j>>2]=b;if((b|0)<0){c[f>>2]=c[j>>2];l=c[f>>2]|0;i=d;return l|0}c[k>>2]=(e[c[g>>2]>>1]|0)<<16|(e[(c[g>>2]|0)+2>>1]|0);if((c[k>>2]|0)>>>0<196610){c[f>>2]=-1;l=c[f>>2]|0;i=d;return l|0}else{k=(c[g>>2]|0)+96|0;g=c[k+4>>2]|0;j=c[h>>2]|0;c[j>>2]=c[k>>2];c[j+4>>2]=g;c[f>>2]=0;l=c[f>>2]|0;i=d;return l|0}return 0}function Nd(a,d,f,g,h,j){a=a|0;d=d|0;f=f|0;g=g|0;h=h|0;j=j|0;var k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0;k=i;i=i+64|0;l=k+44|0;m=k+28|0;n=k+16|0;o=k+20|0;p=k+8|0;q=k+48|0;r=k+24|0;s=k+36|0;t=k+40|0;u=k;v=k+32|0;c[m>>2]=a;c[n>>2]=d;c[o>>2]=f;f=p;c[f>>2]=g;c[f+4>>2]=h;c[q>>2]=j;c[r>>2]=0;c[s>>2]=-1;c[t>>2]=0;j=u;c[j>>2]=-1;c[j+4>>2]=2147483647;j=_d(c[m>>2]|0,c[q>>2]|0)|0;c[s>>2]=j;if((j|0)<0){c[l>>2]=c[s>>2];w=c[l>>2]|0;i=k;return w|0}if(!(b[(c[m>>2]|0)+116>>1]|0)){c[l>>2]=-19;w=c[l>>2]|0;i=k;return w|0}if((c[n>>2]|0)==0|(c[o>>2]|0)==0){c[l>>2]=-1;w=c[l>>2]|0;i=k;return w|0}do if((e[c[m>>2]>>1]|0)==3){s=(c[m>>2]|0)+80|0;j=c[s+4>>2]|0;h=p;f=c[h+4>>2]|0;if(!((j|0)<(f|0)|((j|0)==(f|0)?(c[s>>2]|0)>>>0<(c[h>>2]|0)>>>0:0))?(h=p,s=c[h+4>>2]|0,f=(c[m>>2]|0)+64|0,j=c[f+4>>2]|0,!((s|0)<(j|0)|((s|0)==(j|0)?(c[h>>2]|0)>>>0<(c[f>>2]|0)>>>0:0))):0)break;c[l>>2]=-17;w=c[l>>2]|0;i=k;return w|0}while(0);c[t>>2]=0;while(1){if((c[t>>2]|0)>>>0>=(c[o>>2]|0)>>>0){x=23;break}c[v>>2]=0;f=Wd(c[(c[m>>2]|0)+112>>2]|0,c[(c[n>>2]|0)+(c[t>>2]<<2)>>2]|0)|0;c[r>>2]=f;if(!f){x=14;break}if((e[c[m>>2]>>1]|0)==4){f=(c[r>>2]|0)+32|0;h=c[f+4>>2]|0;j=p;s=c[j+4>>2]|0;if((h|0)<(s|0)|((h|0)==(s|0)?(c[f>>2]|0)>>>0<(c[j>>2]|0)>>>0:0)){x=18;break}j=p;f=c[j+4>>2]|0;s=(c[r>>2]|0)+24|0;h=c[s+4>>2]|0;if((f|0)<(h|0)|((f|0)==(h|0)?(c[j>>2]|0)>>>0<(c[s>>2]|0)>>>0:0)){x=18;break}}s=p;c[v>>2]=$d(c[r>>2]|0,c[s>>2]|0,c[s+4>>2]|0)|0;if((c[v>>2]|0)!=0?(s=c[v>>2]|0,j=c[s+4>>2]|0,h=u,f=c[h+4>>2]|0,!((j|0)>(f|0)|((j|0)==(f|0)?(c[s>>2]|0)>>>0>(c[h>>2]|0)>>>0:0))):0){h=c[v>>2]|0;s=c[h+4>>2]|0;f=u;c[f>>2]=c[h>>2];c[f+4>>2]=s}c[t>>2]=(c[t>>2]|0)+1}if((x|0)==14){c[l>>2]=-8;w=c[l>>2]|0;i=k;return w|0}else if((x|0)==18){c[l>>2]=-17;w=c[l>>2]|0;i=k;return w|0}else if((x|0)==23){x=u;if((c[x>>2]|0)==-1?(c[x+4>>2]|0)==2147483647:0){c[l>>2]=-1;w=c[l>>2]|0;i=k;return w|0}else{x=u;u=c[x+4>>2]|0;t=c[q>>2]|0;c[t>>2]=c[x>>2];c[t+4>>2]=u;c[l>>2]=0;w=c[l>>2]|0;i=k;return w|0}}return 0}function Od(a,b,d){a=a|0;b=b|0;d=d|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;i=i+32|0;g=f+20|0;h=f+16|0;j=f+12|0;k=f+8|0;l=f+4|0;m=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=-1;d=_d(c[h>>2]|0,c[k>>2]|0)|0;c[l>>2]=d;if((d|0)<0){c[g>>2]=c[l>>2];n=c[g>>2]|0;i=f;return n|0}do if((e[c[h>>2]>>1]|0|0)<4){l=(c[h>>2]|0)+64|0;d=c[l+4>>2]|0;b=c[k>>2]|0;c[b>>2]=c[l>>2];c[b+4>>2]=d}else{c[m>>2]=0;d=Wd(c[(c[h>>2]|0)+112>>2]|0,c[j>>2]|0)|0;c[m>>2]=d;if(d){d=(c[m>>2]|0)+24|0;b=c[d+4>>2]|0;l=c[k>>2]|0;c[l>>2]=c[d>>2];c[l+4>>2]=b;break}c[g>>2]=-8;n=c[g>>2]|0;i=f;return n|0}while(0);c[g>>2]=0;n=c[g>>2]|0;i=f;return n|0}function Pd(a,b,d){a=a|0;b=b|0;d=d|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;i=i+32|0;g=f+20|0;h=f+16|0;j=f+12|0;k=f+8|0;l=f+4|0;m=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=-1;d=_d(c[h>>2]|0,c[k>>2]|0)|0;c[l>>2]=d;if((d|0)<0){c[g>>2]=c[l>>2];n=c[g>>2]|0;i=f;return n|0}do if((e[c[h>>2]>>1]|0|0)<4){l=(c[h>>2]|0)+72|0;d=c[l+4>>2]|0;b=c[k>>2]|0;c[b>>2]=c[l>>2];c[b+4>>2]=d}else{c[m>>2]=0;d=Wd(c[(c[h>>2]|0)+112>>2]|0,c[j>>2]|0)|0;c[m>>2]=d;if(d){d=(c[m>>2]|0)+16|0;b=c[d+4>>2]|0;l=c[k>>2]|0;c[l>>2]=c[d>>2];c[l+4>>2]=b;break}c[g>>2]=-8;n=c[g>>2]|0;i=f;return n|0}while(0);c[g>>2]=0;n=c[g>>2]|0;i=f;return n|0}function Qd(a,b,d){a=a|0;b=b|0;d=d|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;i=i+32|0;g=f+20|0;h=f+16|0;j=f+12|0;k=f+8|0;l=f+4|0;m=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=-1;d=_d(c[h>>2]|0,c[k>>2]|0)|0;c[l>>2]=d;if((d|0)<0){c[g>>2]=c[l>>2];n=c[g>>2]|0;i=f;return n|0}do if((e[c[h>>2]>>1]|0|0)<4){l=(c[h>>2]|0)+80|0;d=c[l+4>>2]|0;b=c[k>>2]|0;c[b>>2]=c[l>>2];c[b+4>>2]=d}else{c[m>>2]=0;d=Wd(c[(c[h>>2]|0)+112>>2]|0,c[j>>2]|0)|0;c[m>>2]=d;if(d){d=(c[m>>2]|0)+32|0;b=c[d+4>>2]|0;l=c[k>>2]|0;c[l>>2]=c[d>>2];c[l+4>>2]=b;break}c[g>>2]=-8;n=c[g>>2]|0;i=f;return n|0}while(0);c[g>>2]=0;n=c[g>>2]|0;i=f;return n|0}function Rd(a,b,d){a=a|0;b=b|0;d=d|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0;f=i;i=i+32|0;g=f+20|0;h=f+16|0;j=f+12|0;k=f+8|0;l=f+4|0;m=f;c[h>>2]=a;c[j>>2]=b;c[k>>2]=d;c[l>>2]=-1;d=_d(c[h>>2]|0,c[k>>2]|0)|0;c[l>>2]=d;if((d|0)<0){c[g>>2]=c[l>>2];n=c[g>>2]|0;i=f;return n|0}do if((e[c[h>>2]>>1]|0|0)<4){l=(c[h>>2]|0)+88|0;d=c[l+4>>2]|0;b=c[k>>2]|0;c[b>>2]=c[l>>2];c[b+4>>2]=d}else{c[m>>2]=0;d=Wd(c[(c[h>>2]|0)+112>>2]|0,c[j>>2]|0)|0;c[m>>2]=d;if(d){d=(c[m>>2]|0)+16|0;b=c[d+4>>2]|0;l=c[k>>2]|0;c[l>>2]=c[d>>2];c[l+4>>2]=b;break}c[g>>2]=-8;n=c[g>>2]|0;i=f;return n|0}while(0);c[g>>2]=0;n=c[g>>2]|0;i=f;return n|0}function Sd(){var a=0,b=0,d=0;a=i;i=i+16|0;b=a+4|0;d=a;c[d>>2]=Ae(1,8)|0;if(!(c[d>>2]|0))c[b>>2]=0;else c[b>>2]=c[d>>2];i=a;return c[b>>2]|0}function Td(a){a=a|0;var b=0,d=0,e=0;b=i;i=i+16|0;d=b+4|0;e=b;c[d>>2]=a;c[e>>2]=0;if(!(c[d>>2]|0)){i=b;return}if(c[(c[d>>2]|0)+4>>2]|0){c[e>>2]=0;while(1){if((c[e>>2]|0)>>>0>=(c[c[d>>2]>>2]|0)>>>0)break;if(c[(c[(c[d>>2]|0)+4>>2]|0)+((c[e>>2]|0)*12|0)+4>>2]|0){if(c[(c[(c[(c[d>>2]|0)+4>>2]|0)+((c[e>>2]|0)*12|0)+4>>2]|0)+48>>2]|0)ze(c[(c[(c[(c[d>>2]|0)+4>>2]|0)+((c[e>>2]|0)*12|0)+4>>2]|0)+48>>2]|0);ze(c[(c[(c[d>>2]|0)+4>>2]|0)+((c[e>>2]|0)*12|0)+4>>2]|0)}if(c[(c[(c[d>>2]|0)+4>>2]|0)+((c[e>>2]|0)*12|0)+8>>2]|0){if(c[(c[(c[(c[d>>2]|0)+4>>2]|0)+((c[e>>2]|0)*12|0)+8>>2]|0)+40>>2]|0)ze(c[(c[(c[(c[d>>2]|0)+4>>2]|0)+((c[e>>2]|0)*12|0)+8>>2]|0)+40>>2]|0);ze(c[(c[(c[d>>2]|0)+4>>2]|0)+((c[e>>2]|0)*12|0)+8>>2]|0)}c[e>>2]=(c[e>>2]|0)+1}ze(c[(c[d>>2]|0)+4>>2]|0)}ze(c[d>>2]|0);i=b;return}function Ud(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=0;do if(c[g>>2]|0){if(!(c[h>>2]|0)){c[f>>2]=-1;break}c[k>>2]=be(c[g>>2]|0,c[j>>2]|0)|0;if(!(c[k>>2]|0)){c[f>>2]=-4;break}if(c[(c[k>>2]|0)+4>>2]|0){c[f>>2]=-1;break}else{c[(c[k>>2]|0)+4>>2]=c[h>>2];c[f>>2]=1;break}}else c[f>>2]=-1;while(0);i=e;return c[f>>2]|0}function Vd(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e+4|0;k=e;c[g>>2]=a;c[h>>2]=b;c[j>>2]=d;c[k>>2]=0;do if(c[g>>2]|0){if(!(c[h>>2]|0)){c[f>>2]=-1;break}c[k>>2]=be(c[g>>2]|0,c[j>>2]|0)|0;if(!(c[k>>2]|0)){c[f>>2]=-4;break}if(c[(c[k>>2]|0)+8>>2]|0){c[f>>2]=-1;break}else{c[(c[k>>2]|0)+8>>2]=c[h>>2];c[f>>2]=1;break}}else c[f>>2]=-1;while(0);i=e;return c[f>>2]|0}function Wd(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;c[h>>2]=0;if(!(c[f>>2]|0)){c[e>>2]=0;j=c[e>>2]|0;i=d;return j|0}c[h>>2]=ae(c[f>>2]|0,c[g>>2]|0)|0;if(!(c[h>>2]|0))k=0;else k=c[(c[h>>2]|0)+8>>2]|0;c[e>>2]=k;j=c[e>>2]|0;i=d;return j|0}function Xd(b,d){b=b|0;d=d|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+32|0;g=f+16|0;h=f+12|0;j=f+8|0;k=f+4|0;l=f;c[h>>2]=b;c[j>>2]=d;c[l>>2]=0;if(!(c[h>>2]|0)){c[g>>2]=-2;m=c[g>>2]|0;i=f;return m|0}if((c[j>>2]|0)!=0?(c[c[j>>2]>>2]|0)!=0:0){c[l>>2]=(c[c[j>>2]>>2]|0)+8;c[l>>2]=ce(c[l>>2]|0,c[h>>2]|0)|0;c[l>>2]=ce(c[l>>2]|0,(c[h>>2]|0)+2|0)|0;c[k>>2]=(e[c[h>>2]>>1]|0)<<16|(e[(c[h>>2]|0)+2>>1]|0);if((c[k>>2]|0)>>>0>262144){c[g>>2]=-11;m=c[g>>2]|0;i=f;return m|0}if((c[k>>2]|0)==262144?(c[(c[j>>2]|0)+4>>2]|0)!=80:0){c[g>>2]=-18;m=c[g>>2]|0;i=f;return m|0}if((e[c[h>>2]>>1]|0|0)==3){if((e[(c[h>>2]|0)+2>>1]|0|0)>=2?(c[(c[j>>2]|0)+4>>2]|0)!=112:0){c[g>>2]=-18;m=c[g>>2]|0;i=f;return m|0}if((e[(c[h>>2]|0)+2>>1]|0|0)==0?(c[(c[j>>2]|0)+4>>2]|0)!=64:0){c[g>>2]=-18;m=c[g>>2]|0;i=f;return m|0}}c[l>>2]=de(c[l>>2]|0,(c[h>>2]|0)+8|0)|0;c[l>>2]=de(c[l>>2]|0,(c[h>>2]|0)+16|0)|0;c[l>>2]=de(c[l>>2]|0,(c[h>>2]|0)+24|0)|0;c[l>>2]=de(c[l>>2]|0,(c[h>>2]|0)+32|0)|0;j=(c[h>>2]|0)+40|0;d=c[l>>2]|0;b=j+20|0;do{a[j>>0]=a[d>>0]|0;j=j+1|0;d=d+1|0}while((j|0)<(b|0));if((c[k>>2]|0)>>>0>=196610){c[l>>2]=(c[l>>2]|0)+20;if((e[c[h>>2]>>1]|0|0)==3){c[l>>2]=de(c[l>>2]|0,(c[h>>2]|0)+64|0)|0;c[l>>2]=de(c[l>>2]|0,(c[h>>2]|0)+72|0)|0;c[l>>2]=de(c[l>>2]|0,(c[h>>2]|0)+80|0)|0;c[l>>2]=de(c[l>>2]|0,(c[h>>2]|0)+88|0)|0}c[l>>2]=de(c[l>>2]|0,(c[h>>2]|0)+96|0)|0;de(c[l>>2]|0,(c[h>>2]|0)+104|0)|0}c[g>>2]=1;m=c[g>>2]|0;i=f;return m|0}c[g>>2]=-13;m=c[g>>2]|0;i=f;return m|0}function Yd(b,d){b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0;e=i;i=i+32|0;f=e+20|0;g=e+16|0;h=e+12|0;j=e+8|0;k=e+4|0;l=e;c[g>>2]=b;c[h>>2]=d;c[j>>2]=0;c[k>>2]=-1;c[l>>2]=0;if(!(c[g>>2]|0)){c[f>>2]=-2;m=c[f>>2]|0;i=e;return m|0}if((c[h>>2]|0)!=0?(c[c[h>>2]>>2]|0)!=0:0){if((c[(c[h>>2]|0)+4>>2]|0)<52){c[f>>2]=-7;m=c[f>>2]|0;i=e;return m|0}c[j>>2]=Ae(1,56)|0;if(!(c[j>>2]|0)){c[f>>2]=-4;m=c[f>>2]|0;i=e;return m|0}c[l>>2]=(c[c[h>>2]>>2]|0)+8;c[l>>2]=ee(c[l>>2]|0,c[j>>2]|0)|0;c[l>>2]=fe(c[l>>2]|0,(c[j>>2]|0)+4|0)|0;c[l>>2]=ee(c[l>>2]|0,(c[j>>2]|0)+8|0)|0;c[l>>2]=de(c[l>>2]|0,(c[j>>2]|0)+16|0)|0;c[l>>2]=de(c[l>>2]|0,(c[j>>2]|0)+24|0)|0;c[l>>2]=de(c[l>>2]|0,(c[j>>2]|0)+32|0)|0;c[l>>2]=ee(c[l>>2]|0,(c[j>>2]|0)+40|0)|0;a[(c[j>>2]|0)+44>>0]=a[c[l>>2]>>0]|0;l=Ae((c[(c[h>>2]|0)+4>>2]|0)-52|0,1)|0;c[(c[j>>2]|0)+48>>2]=l;l=c[j>>2]|0;if(!(c[(c[j>>2]|0)+48>>2]|0)){ze(l);c[f>>2]=-4;m=c[f>>2]|0;i=e;return m|0}Ke(c[l+48>>2]|0,(c[c[h>>2]>>2]|0)+52|0,(c[(c[h>>2]|0)+4>>2]|0)-52|0)|0;c[k>>2]=Ud(c[(c[g>>2]|0)+112>>2]|0,c[j>>2]|0,c[(c[j>>2]|0)+4>>2]|0)|0;if((c[k>>2]|0)<0)ze(c[j>>2]|0);c[f>>2]=c[k>>2];m=c[f>>2]|0;i=e;return m|0}c[f>>2]=-13;m=c[f>>2]|0;i=e;return m|0}function Zd(a,b){a=a|0;b=b|0;var d=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0;d=i;i=i+80|0;f=d+72|0;g=d+56|0;h=d+60|0;j=d+16|0;k=d+8|0;l=d;m=d+48|0;n=d+76|0;o=d+40|0;p=d+68|0;q=d+64|0;r=d+24|0;s=d+32|0;c[g>>2]=a;c[h>>2]=b;b=j;c[b>>2]=0;c[b+4>>2]=0;b=k;c[b>>2]=0;c[b+4>>2]=0;b=l;c[b>>2]=0;c[b+4>>2]=0;b=m;c[b>>2]=1e3;c[b+4>>2]=0;c[n>>2]=0;b=o;c[b>>2]=-1;c[b+4>>2]=-1;c[p>>2]=0;c[q>>2]=-1;if(!(c[g>>2]|0)){c[f>>2]=-2;t=c[f>>2]|0;i=d;return t|0}if((c[h>>2]|0)!=0?(c[c[h>>2]>>2]|0)!=0:0){c[n>>2]=Ae(1,48)|0;if(!(c[n>>2]|0)){c[f>>2]=-4;t=c[f>>2]|0;i=d;return t|0}c[p>>2]=(c[c[h>>2]>>2]|0)+6;c[p>>2]=fe(c[p>>2]|0,c[n>>2]|0)|0;c[p>>2]=de(c[p>>2]|0,(c[n>>2]|0)+8|0)|0;c[p>>2]=de(c[p>>2]|0,(c[n>>2]|0)+16|0)|0;if(((e[c[g>>2]>>1]|0)<<16|(e[(c[g>>2]|0)+2>>1]|0)|0)==262144){c[p>>2]=de(c[p>>2]|0,(c[n>>2]|0)+24|0)|0;c[p>>2]=de(c[p>>2]|0,(c[n>>2]|0)+32|0)|0}b=(c[n>>2]|0)+16|0;do if((c[b>>2]|0)==0&(c[b+4>>2]|0)==0)c[q>>2]=-9;else{a=(c[n>>2]|0)+8|0;u=Ue(c[a>>2]|0,c[a+4>>2]|0,2,0)|0;a=Me(26,0,u|0,C|0)|0;u=o;c[u>>2]=a;c[u+4>>2]=C;u=o;a=c[u+4>>2]|0;v=c[(c[h>>2]|0)+4>>2]|0;w=((v|0)<0)<<31>>31;if((a|0)>(w|0)|((a|0)==(w|0)?(c[u>>2]|0)>>>0>v>>>0:0)){c[q>>2]=-10;break}v=Ae(c[(c[n>>2]|0)+8>>2]|0,16)|0;c[(c[n>>2]|0)+40>>2]=v;if(!(c[(c[n>>2]|0)+40>>2]|0)){c[q>>2]=-4;break}v=j;c[v>>2]=0;c[v+4>>2]=0;while(1){v=j;u=c[v+4>>2]|0;w=(c[n>>2]|0)+8|0;a=c[w+4>>2]|0;if(!((u|0)<(a|0)|((u|0)==(a|0)?(c[v>>2]|0)>>>0<(c[w>>2]|0)>>>0:0)))break;w=r;c[w>>2]=0;c[w+4>>2]=0;w=s;c[w>>2]=0;c[w+4>>2]=0;c[p>>2]=ge(c[p>>2]|0,r)|0;w=r;v=k;a=Me(c[v>>2]|0,c[v+4>>2]|0,c[w>>2]|0,c[w+4>>2]|0)|0;w=k;c[w>>2]=a;c[w+4>>2]=C;c[p>>2]=ge(c[p>>2]|0,s)|0;w=s;a=l;v=Me(c[a>>2]|0,c[a+4>>2]|0,c[w>>2]|0,c[w+4>>2]|0)|0;w=l;c[w>>2]=v;c[w+4>>2]=C;w=k;v=c[w+4>>2]|0;a=(c[(c[n>>2]|0)+40>>2]|0)+(c[j>>2]<<4)|0;c[a>>2]=c[w>>2];c[a+4>>2]=v;v=l;a=m;w=Ue(c[v>>2]|0,c[v+4>>2]|0,c[a>>2]|0,c[a+4>>2]|0)|0;a=(c[n>>2]|0)+16|0;v=Se(w|0,C|0,c[a>>2]|0,c[a+4>>2]|0)|0;a=(c[(c[n>>2]|0)+40>>2]|0)+(c[j>>2]<<4)+8|0;c[a>>2]=v;c[a+4>>2]=C;a=j;v=Me(c[a>>2]|0,c[a+4>>2]|0,1,0)|0;a=j;c[a>>2]=v;c[a+4>>2]=C}c[q>>2]=Vd(c[(c[g>>2]|0)+112>>2]|0,c[n>>2]|0,c[c[n>>2]>>2]|0)|0}while(0);if((c[q>>2]|0)<0)ze(c[n>>2]|0);c[f>>2]=c[q>>2];t=c[f>>2]|0;i=d;return t|0}c[f>>2]=-13;t=c[f>>2]|0;i=d;return t|0}function _d(a,d){a=a|0;d=d|0;var e=0,f=0,g=0,h=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[g>>2]=a;c[h>>2]=d;do if(c[g>>2]|0){if(!(b[(c[g>>2]|0)+118>>1]|0)){c[f>>2]=-5;break}if(!(c[h>>2]|0)){c[f>>2]=-16;break}else{c[f>>2]=0;break}}else c[f>>2]=-2;while(0);i=e;return c[f>>2]|0}function $d(a,b,d){a=a|0;b=b|0;d=d|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0;e=i;i=i+48|0;f=e+36|0;g=e+32|0;h=e+24|0;j=e+16|0;k=e+8|0;l=e;c[g>>2]=a;a=h;c[a>>2]=b;c[a+4>>2]=d;d=j;c[d>>2]=0;c[d+4>>2]=0;d=k;c[d>>2]=0;c[d+4>>2]=0;if(!(c[g>>2]|0)){c[f>>2]=0;m=c[f>>2]|0;i=e;return m|0}d=(c[g>>2]|0)+8|0;a=Ge(c[d>>2]|0,c[d+4>>2]|0,1,0)|0;d=k;c[d>>2]=a;c[d+4>>2]=C;while(1){d=k;a=c[d+4>>2]|0;b=j;n=c[b+4>>2]|0;if(!((a|0)>(n|0)|((a|0)==(n|0)?(c[d>>2]|0)>>>0>(c[b>>2]|0)>>>0:0)))break;b=j;d=k;n=Me(c[b>>2]|0,c[b+4>>2]|0,c[d>>2]|0,c[d+4>>2]|0)|0;d=Me(n|0,C|0,1,0)|0;n=Fe(d|0,C|0,1)|0;d=l;c[d>>2]=n;c[d+4>>2]=C;d=(c[(c[g>>2]|0)+40>>2]|0)+(c[l>>2]<<4)+8|0;n=h;b=l;o=c[b>>2]|0;p=c[b+4>>2]|0;if((c[d>>2]|0)==(c[n>>2]|0)?(c[d+4>>2]|0)==(c[n+4>>2]|0):0){q=6;break}n=(c[(c[g>>2]|0)+40>>2]|0)+(o<<4)+8|0;d=c[n+4>>2]|0;b=h;a=c[b+4>>2]|0;r=l;s=c[r>>2]|0;t=c[r+4>>2]|0;if((d|0)<(a|0)|((d|0)==(a|0)?(c[n>>2]|0)>>>0<(c[b>>2]|0)>>>0:0)){b=j;c[b>>2]=s;c[b+4>>2]=t;continue}else{b=Ge(s|0,t|0,1,0)|0;t=k;c[t>>2]=b;c[t+4>>2]=C;continue}}if((q|0)==6){q=j;c[q>>2]=o;c[q+4>>2]=p}c[f>>2]=(c[(c[g>>2]|0)+40>>2]|0)+(c[j>>2]<<4);m=c[f>>2]|0;i=e;return m|0}function ae(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;c[h>>2]=0;c[h>>2]=0;while(1){if((c[h>>2]|0)>>>0>=(c[c[f>>2]>>2]|0)>>>0){j=6;break}k=c[h>>2]|0;if((c[(c[(c[f>>2]|0)+4>>2]|0)+((c[h>>2]|0)*12|0)>>2]|0)==(c[g>>2]|0)){j=4;break}c[h>>2]=k+1}if((j|0)==4){c[e>>2]=(c[(c[f>>2]|0)+4>>2]|0)+(k*12|0);l=c[e>>2]|0;i=d;return l|0}else if((j|0)==6){c[e>>2]=0;l=c[e>>2]|0;i=d;return l|0}return 0}function be(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0;d=i;i=i+16|0;e=d+12|0;f=d+8|0;g=d+4|0;h=d;c[f>>2]=a;c[g>>2]=b;c[h>>2]=0;b=ae(c[f>>2]|0,c[g>>2]|0)|0;c[h>>2]=b;do if(!b){c[h>>2]=Be(c[(c[f>>2]|0)+4>>2]|0,((c[c[f>>2]>>2]|0)+1|0)*12|0)|0;if(c[h>>2]|0){c[(c[f>>2]|0)+4>>2]=c[h>>2];a=c[f>>2]|0;c[a>>2]=(c[a>>2]|0)+1;c[h>>2]=(c[(c[f>>2]|0)+4>>2]|0)+(((c[c[f>>2]>>2]|0)-1|0)*12|0);c[c[h>>2]>>2]=c[g>>2];c[(c[h>>2]|0)+4>>2]=0;c[(c[h>>2]|0)+8>>2]=0;break}c[e>>2]=0;j=c[e>>2]|0;i=d;return j|0}while(0);c[e>>2]=c[h>>2];j=c[e>>2]|0;i=d;return j|0}function ce(a,e){a=a|0;e=e|0;var f=0,g=0,h=0,j=0,k=0;f=i;i=i+16|0;g=f+8|0;h=f+4|0;j=f;c[h>>2]=a;c[j>>2]=e;if((c[h>>2]|0)==0|(c[j>>2]|0)==0){c[g>>2]=0;k=c[g>>2]|0;i=f;return k|0}else{b[c[j>>2]>>1]=d[c[h>>2]>>0]|0|(d[(c[h>>2]|0)+1>>0]|0)<<8;c[g>>2]=(c[h>>2]|0)+2;k=c[g>>2]|0;i=f;return k|0}return 0}function de(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0,k=0;d=i;i=i+32|0;e=d+16|0;f=d+12|0;g=d+8|0;h=d+4|0;j=d;c[f>>2]=a;c[g>>2]=b;c[h>>2]=-1;c[j>>2]=-1;if((c[f>>2]|0)==0|(c[g>>2]|0)==0){c[e>>2]=0;k=c[e>>2]|0;i=d;return k|0}else{c[f>>2]=ee(c[f>>2]|0,h)|0;c[f>>2]=fe(c[f>>2]|0,j)|0;b=c[j>>2]|0;j=Me(c[h>>2]|0,0,0,b|0)|0;b=c[g>>2]|0;c[b>>2]=j;c[b+4>>2]=C;c[e>>2]=c[f>>2];k=c[e>>2]|0;i=d;return k|0}return 0}function ee(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,j=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[g>>2]=a;c[h>>2]=b;if((c[g>>2]|0)==0|(c[h>>2]|0)==0){c[f>>2]=0;j=c[f>>2]|0;i=e;return j|0}else{c[c[h>>2]>>2]=d[c[g>>2]>>0]|0|(d[(c[g>>2]|0)+1>>0]|0)<<8|(d[(c[g>>2]|0)+2>>0]|0)<<16|(d[(c[g>>2]|0)+3>>0]|0)<<24;c[f>>2]=(c[g>>2]|0)+4;j=c[f>>2]|0;i=e;return j|0}return 0}function fe(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,j=0;e=i;i=i+16|0;f=e+8|0;g=e+4|0;h=e;c[g>>2]=a;c[h>>2]=b;if((c[g>>2]|0)==0|(c[h>>2]|0)==0){c[f>>2]=0;j=c[f>>2]|0;i=e;return j|0}else{c[c[h>>2]>>2]=d[c[g>>2]>>0]|0|(d[(c[g>>2]|0)+1>>0]|0)<<8|(d[(c[g>>2]|0)+2>>0]|0)<<16|(d[(c[g>>2]|0)+3>>0]|0)<<24;c[f>>2]=(c[g>>2]|0)+4;j=c[f>>2]|0;i=e;return j|0}return 0}function ge(a,b){a=a|0;b=b|0;var e=0,f=0,g=0,h=0,j=0,k=0,l=0,m=0;e=i;i=i+32|0;f=e+16|0;g=e+12|0;h=e+8|0;j=e;c[f>>2]=a;c[g>>2]=b;c[h>>2]=0;b=j;c[b>>2]=0;c[b+4>>2]=0;b=c[g>>2]|0;c[b>>2]=0;c[b+4>>2]=0;do{b=j;c[b>>2]=d[c[f>>2]>>0];c[b+4>>2]=0;b=Ie(c[j>>2]&127|0,0,c[h>>2]|0)|0;a=c[g>>2]|0;k=a;l=c[k+4>>2]|C;m=a;c[m>>2]=c[k>>2]|b;c[m+4>>2]=l;c[h>>2]=(c[h>>2]|0)+7;c[f>>2]=(c[f>>2]|0)+1}while(0!=0?1:(c[j>>2]&128|0)!=128);i=e;return c[f>>2]|0}function he(){var a=0;c[644]=0;a=ob(32)|0;c[646]=a;Gb(a,-1,8,0)|0;c[648]=Hd()|0;return}function ie(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;d=i;i=i+16|0;e=d+8|0;f=d;c[662]=1;do if((c[644]|0)==2){if((c[650]|0)!=0?(ua()|0)==0:0)break;if((c[652]|0)!=0?(Ja()|0)==0:0)break;c[662]=0}while(0);do if((b|0)>0){g=Mb(c[646]|0,a,b)|0;if((g|0)<0){c[f>>2]=g;za(2656,f|0)|0;break}if((g|0)<(b|0)){c[e>>2]=g;c[e+4>>2]=b;za(2688,e|0)|0}}while(0);i=d;return c[662]^1|0}function je(){Id(c[648]|0)|0;pb(c[646]|0)|0;return}function ke(){var a=0,b=0,d=0,e=0;a=i;i=i+16|0;b=a;d=b;c[d>>2]=-1;c[d+4>>2]=-1;if(!(c[654]|0)){e=-1;i=a;return e|0}Md(c[648]|0,b)|0;e=c[b>>2]|0;i=a;return e|0}function le(){var a=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0,l=0.0,m=0,n=0.0,o=0.0,p=0,q=0,r=0.0,s=0.0,t=0.0,u=0.0,v=0.0;a=i;i=i+48|0;d=a+42|0;e=a+40|0;f=a+32|0;g=a+24|0;h=a+16|0;j=a;k=a+8|0;if(!(c[654]|0)){l=-1.0;i=a;return +l}b[d>>1]=-1;b[e>>1]=-1;Kd(c[648]|0,d)|0;Ld(c[648]|0,e)|0;e=c[656]|0;if(!e)m=0;else{c[f>>2]=e;m=1}e=c[658]|0;if(!e)if(!m){n=-1.0;o=-1.0}else{p=1;q=7}else{c[f+(m<<2)>>2]=e;p=m+1|0;q=7}if((q|0)==7){r=-1.0;q=0;s=-1.0;while(1){m=g;c[m>>2]=-1;c[m+4>>2]=-1;m=h;c[m>>2]=-1;c[m+4>>2]=-1;m=j;c[m>>2]=-1;c[m+4>>2]=-1;m=k;c[m>>2]=-1;c[m+4>>2]=-1;m=c[f+(q<<2)>>2]|0;Od(c[648]|0,m,g)|0;Pd(c[648]|0,m,h)|0;Qd(c[648]|0,m,j)|0;Rd(c[648]|0,m,k)|0;m=g;e=h;t=(+((c[m>>2]|0)>>>0)+4294967296.0*+(c[m+4>>2]|0))/(+((c[e>>2]|0)>>>0)+4294967296.0*+(c[e+4>>2]|0));u=r==-1.0|t<r?t:r;e=j;m=k;t=(+((c[e>>2]|0)>>>0)+4294967296.0*+(c[e+4>>2]|0))/(+((c[m>>2]|0)>>>0)+4294967296.0*+(c[m+4>>2]|0));v=s==-1.0|t>s?t:s;q=q+1|0;if((q|0)==(p|0)){n=u;o=v;break}else{r=u;s=v}}}l=o-n;i=a;return +l}function me(){return c[654]|0}function ne(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,j=0,k=0;b=i;i=i+16|0;d=b;e=b+8|0;f=d;c[f>>2]=-1;c[f+4>>2]=-1;if(!(c[654]|0)){g=-1;i=b;return g|0}f=c[656]|0;if(!f){h=c[658]|0;if(!h){j=e;k=0}else{c[e>>2]=h;j=e;k=1}}else{c[e>>2]=f;j=e;k=1}Nd(c[648]|0,j,k,a,((a|0)<0)<<31>>31,d)|0;g=c[d>>2]|0;i=b;return g|0}function oe(){Ob(c[646]|0)|0;Pb(c[646]|0,0,1)|0;return}function pe(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0;e=i;i=i+16|0;a=e+8|0;f=e;c[662]=0;g=c[644]|0;if(!g){if(!(c[b+8>>2]|0))if(!(c[660]|0)){c[644]=2;na(c[640]|0,c[642]|0);re(b,d);h=0;i=e;return h|0}else{c[644]=1;h=qe(b,d)|0;i=e;return h|0}j=Xb(c[646]|0,d)|0;if(!(c[656]|j)){c[650]=j;c[640]=2744;c[656]=d;xa(c[b>>2]|0,c[b+4>>2]|0,-1.0,-1.0);h=0;i=e;return h|0}k=(c[658]|0)==0;if((j|0)==1&k){c[652]=1;c[642]=2752;c[658]=d;ma(c[b>>2]|0,c[b+4>>2]|0,-1.0);h=0;i=e;return h|0}if((j|0)==13&k){c[652]=13;c[642]=2760;c[658]=d;ma(c[b>>2]|0,c[b+4>>2]|0,-1.0);h=0;i=e;return h|0}if(!((j|0)==6&(c[660]|0)==0)){h=0;i=e;return h|0}c[660]=d;j=Jd(c[648]|0,b)|0;if(!j){c[654]=1;h=0;i=e;return h|0}if((j|0)>0){h=0;i=e;return h|0}c[f>>2]=j;za(2768,f|0)|0;h=-1;i=e;return h|0}else if((g|0)==2){re(b,d);h=0;i=e;return h|0}else if((g|0)==1){h=qe(b,d)|0;i=e;return h|0}else{za(2808,a|0)|0;h=-1;i=e;return h|0}return 0}function qe(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,j=0.0,k=0,l=0,m=0,n=0.0,o=0;d=i;i=i+32|0;e=d+16|0;f=d+8|0;g=d;h=qb(c[646]|0)|0;j=(+(h>>>0)+4294967296.0*+(C|0))/1.0e3;h=rb(c[646]|0)|0;k=C;l=nc(c[646]|0,b)|0;m=f;c[m>>2]=0;c[m+4>>2]=0;m=g;c[m>>2]=0;c[m+4>>2]=0;pc(c[646]|0,b,f,g)|0;m=Fe(h|0,k|0,l|0)|0;l=g;g=f;n=(+(m>>>0)+4294967296.0*+(C|0))*(+((c[l>>2]|0)>>>0)+4294967296.0*+(c[l+4>>2]|0))/(+((c[g>>2]|0)>>>0)+4294967296.0*+(c[g+4>>2]|0));do if((c[660]|0)==(b|0)){g=Jd(c[648]|0,a)|0;if((g|0)<0){c[e>>2]=g;za(2848,e|0)|0;o=-1;i=d;return o|0}else{if(!(c[a+12>>2]|0))break;c[654]=1;c[644]=2;na(c[640]|0,c[642]|0);break}}while(0);if((c[656]|0)==(b|0))xa(c[a>>2]|0,c[a+4>>2]|0,+j,+n);if((c[658]|0)!=(b|0)){o=0;i=d;return o|0}ma(c[a>>2]|0,c[a+4>>2]|0,+j);o=0;i=d;return o|0}function re(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0.0,j=0,k=0,l=0,m=0,n=0;d=i;i=i+16|0;e=d+8|0;f=d;g=qb(c[646]|0)|0;h=(+(g>>>0)+4294967296.0*+(C|0))/1.0e3;g=rb(c[646]|0)|0;j=C;k=nc(c[646]|0,b)|0;l=e;c[l>>2]=0;c[l+4>>2]=0;l=f;c[l>>2]=0;c[l+4>>2]=0;pc(c[646]|0,b,e,f)|0;l=f;f=c[l>>2]|0;m=c[l+4>>2]|0;l=e;e=c[l>>2]|0;n=c[l+4>>2]|0;if((c[656]|0)==(b|0)){l=Fe(g|0,j|0,k|0)|0;xa(c[a>>2]|0,c[a+4>>2]|0,+h,+((+(l>>>0)+4294967296.0*+(C|0))*(+(f>>>0)+4294967296.0*+(m|0))/(+(e>>>0)+4294967296.0*+(n|0))))}if((c[658]|0)!=(b|0)){i=d;return}ma(c[a>>2]|0,c[a+4>>2]|0,+h);i=d;return}function se(a){a=a|0;return (a+-65|0)>>>0<26|0}function te(a){a=a|0;var b=0;b=(se(a)|0)==0;return (b?a:a|32)|0}function ue(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0;f=d&255;g=(e|0)!=0;a:do if(g&(b&3|0)!=0){h=d&255;i=e;j=b;while(1){if((a[j>>0]|0)==h<<24>>24){k=i;l=j;m=6;break a}n=j+1|0;o=i+-1|0;p=(o|0)!=0;if(p&(n&3|0)!=0){i=o;j=n}else{q=o;r=p;s=n;m=5;break}}}else{q=e;r=g;s=b;m=5}while(0);if((m|0)==5)if(r){k=q;l=s;m=6}else{t=0;u=s}b:do if((m|0)==6){s=d&255;if((a[l>>0]|0)==s<<24>>24){t=k;u=l}else{q=_(f,16843009)|0;c:do if(k>>>0>3){r=k;b=l;while(1){g=c[b>>2]^q;if((g&-2139062144^-2139062144)&g+-16843009){v=r;w=b;break}g=b+4|0;e=r+-4|0;if(e>>>0>3){r=e;b=g}else{x=e;y=g;m=11;break c}}z=v;A=w}else{x=k;y=l;m=11}while(0);if((m|0)==11)if(!x){t=0;u=y;break}else{z=x;A=y}while(1){if((a[A>>0]|0)==s<<24>>24){t=z;u=A;break b}q=A+1|0;z=z+-1|0;if(!z){t=0;u=q;break}else A=q}}}while(0);return ((t|0)!=0?u:0)|0}function ve(b,c,d){b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0;if(!d){e=0;return e|0}else{f=d;g=b;h=c}while(1){c=a[g>>0]|0;b=a[h>>0]|0;if(c<<24>>24!=b<<24>>24){i=c;j=b;break}f=f+-1|0;if(!f){e=0;k=5;break}else{g=g+1|0;h=h+1|0}}if((k|0)==5)return e|0;e=(i&255)-(j&255)|0;return e|0}function we(b,c){b=b|0;c=c|0;var e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0;e=a[b>>0]|0;a:do if(!(e<<24>>24)){f=0;g=c}else{h=e;i=e&255;j=b;k=c;while(1){l=a[k>>0]|0;if(!(l<<24>>24)){f=h;g=k;break a}if(h<<24>>24!=l<<24>>24?(l=te(i)|0,(l|0)!=(te(d[k>>0]|0)|0)):0){m=j;n=k;break}j=j+1|0;l=k+1|0;o=a[j>>0]|0;if(!(o<<24>>24)){f=0;g=l;break a}else{h=o;i=o&255;k=l}}f=a[m>>0]|0;g=n}while(0);n=te(f&255)|0;return n-(te(d[g>>0]|0)|0)|0}function xe(b,c){b=b|0;c=c|0;var d=0,e=0,f=0,g=0;d=a[b>>0]|0;e=a[c>>0]|0;if(d<<24>>24==0?1:d<<24>>24!=e<<24>>24){f=d;g=e}else{e=b;b=c;do{e=e+1|0;b=b+1|0;c=a[e>>0]|0;d=a[b>>0]|0}while(!(c<<24>>24==0?1:c<<24>>24!=d<<24>>24));f=c;g=d}return (f&255)-(g&255)|0}
+function ye(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0,N=0,O=0,P=0,Q=0,R=0,S=0,T=0,U=0,V=0,W=0,X=0,Y=0,Z=0,_=0,$=0,aa=0,ba=0,ca=0,da=0,ea=0,fa=0,ga=0,ha=0,ia=0,ja=0,ka=0,la=0,ma=0,na=0,oa=0,pa=0,qa=0,sa=0,ta=0,ua=0,wa=0,xa=0,ya=0,za=0,Aa=0,Ba=0,Ca=0,Fa=0,Ha=0,Ia=0,Ja=0,Ka=0,La=0,Ma=0,Na=0,Oa=0,Pa=0,Qa=0,Ra=0,Sa=0,Ta=0,Ua=0,Va=0,Wa=0,Xa=0;do if(a>>>0<245){b=a>>>0<11?16:a+11&-8;d=b>>>3;e=c[722]|0;f=e>>>d;if(f&3){g=(f&1^1)+d|0;h=g<<1;i=2928+(h<<2)|0;j=2928+(h+2<<2)|0;h=c[j>>2]|0;k=h+8|0;l=c[k>>2]|0;do if((i|0)!=(l|0)){if(l>>>0<(c[726]|0)>>>0)Ea();m=l+12|0;if((c[m>>2]|0)==(h|0)){c[m>>2]=i;c[j>>2]=l;break}else Ea()}else c[722]=e&~(1<<g);while(0);l=g<<3;c[h+4>>2]=l|3;j=h+(l|4)|0;c[j>>2]=c[j>>2]|1;n=k;return n|0}j=c[724]|0;if(b>>>0>j>>>0){if(f){l=2<<d;i=f<<d&(l|0-l);l=(i&0-i)+-1|0;i=l>>>12&16;m=l>>>i;l=m>>>5&8;o=m>>>l;m=o>>>2&4;p=o>>>m;o=p>>>1&2;q=p>>>o;p=q>>>1&1;r=(l|i|m|o|p)+(q>>>p)|0;p=r<<1;q=2928+(p<<2)|0;o=2928+(p+2<<2)|0;p=c[o>>2]|0;m=p+8|0;i=c[m>>2]|0;do if((q|0)!=(i|0)){if(i>>>0<(c[726]|0)>>>0)Ea();l=i+12|0;if((c[l>>2]|0)==(p|0)){c[l>>2]=q;c[o>>2]=i;s=c[724]|0;break}else Ea()}else{c[722]=e&~(1<<r);s=j}while(0);j=r<<3;e=j-b|0;c[p+4>>2]=b|3;i=p+b|0;c[p+(b|4)>>2]=e|1;c[p+j>>2]=e;if(s){j=c[727]|0;o=s>>>3;q=o<<1;d=2928+(q<<2)|0;f=c[722]|0;k=1<<o;if(f&k){o=2928+(q+2<<2)|0;h=c[o>>2]|0;if(h>>>0<(c[726]|0)>>>0)Ea();else{t=o;u=h}}else{c[722]=f|k;t=2928+(q+2<<2)|0;u=d}c[t>>2]=j;c[u+12>>2]=j;c[j+8>>2]=u;c[j+12>>2]=d}c[724]=e;c[727]=i;n=m;return n|0}i=c[723]|0;if(i){e=(i&0-i)+-1|0;i=e>>>12&16;d=e>>>i;e=d>>>5&8;j=d>>>e;d=j>>>2&4;q=j>>>d;j=q>>>1&2;k=q>>>j;q=k>>>1&1;f=c[3192+((e|i|d|j|q)+(k>>>q)<<2)>>2]|0;q=(c[f+4>>2]&-8)-b|0;k=f;j=f;while(1){f=c[k+16>>2]|0;if(!f){d=c[k+20>>2]|0;if(!d){v=q;w=j;break}else x=d}else x=f;f=(c[x+4>>2]&-8)-b|0;d=f>>>0<q>>>0;q=d?f:q;k=x;j=d?x:j}j=c[726]|0;if(w>>>0<j>>>0)Ea();k=w+b|0;if(w>>>0>=k>>>0)Ea();q=c[w+24>>2]|0;m=c[w+12>>2]|0;do if((m|0)==(w|0)){p=w+20|0;r=c[p>>2]|0;if(!r){d=w+16|0;f=c[d>>2]|0;if(!f){y=0;break}else{z=f;A=d}}else{z=r;A=p}while(1){p=z+20|0;r=c[p>>2]|0;if(r){z=r;A=p;continue}p=z+16|0;r=c[p>>2]|0;if(!r){B=z;C=A;break}else{z=r;A=p}}if(C>>>0<j>>>0)Ea();else{c[C>>2]=0;y=B;break}}else{p=c[w+8>>2]|0;if(p>>>0<j>>>0)Ea();r=p+12|0;if((c[r>>2]|0)!=(w|0))Ea();d=m+8|0;if((c[d>>2]|0)==(w|0)){c[r>>2]=m;c[d>>2]=p;y=m;break}else Ea()}while(0);do if(q){m=c[w+28>>2]|0;j=3192+(m<<2)|0;if((w|0)==(c[j>>2]|0)){c[j>>2]=y;if(!y){c[723]=c[723]&~(1<<m);break}}else{if(q>>>0<(c[726]|0)>>>0)Ea();m=q+16|0;if((c[m>>2]|0)==(w|0))c[m>>2]=y;else c[q+20>>2]=y;if(!y)break}m=c[726]|0;if(y>>>0<m>>>0)Ea();c[y+24>>2]=q;j=c[w+16>>2]|0;do if(j)if(j>>>0<m>>>0)Ea();else{c[y+16>>2]=j;c[j+24>>2]=y;break}while(0);j=c[w+20>>2]|0;if(j)if(j>>>0<(c[726]|0)>>>0)Ea();else{c[y+20>>2]=j;c[j+24>>2]=y;break}}while(0);if(v>>>0<16){q=v+b|0;c[w+4>>2]=q|3;j=w+(q+4)|0;c[j>>2]=c[j>>2]|1}else{c[w+4>>2]=b|3;c[w+(b|4)>>2]=v|1;c[w+(v+b)>>2]=v;j=c[724]|0;if(j){q=c[727]|0;m=j>>>3;j=m<<1;p=2928+(j<<2)|0;d=c[722]|0;r=1<<m;if(d&r){m=2928+(j+2<<2)|0;f=c[m>>2]|0;if(f>>>0<(c[726]|0)>>>0)Ea();else{D=m;E=f}}else{c[722]=d|r;D=2928+(j+2<<2)|0;E=p}c[D>>2]=q;c[E+12>>2]=q;c[q+8>>2]=E;c[q+12>>2]=p}c[724]=v;c[727]=k}n=w+8|0;return n|0}else F=b}else F=b}else if(a>>>0<=4294967231){p=a+11|0;q=p&-8;j=c[723]|0;if(j){r=0-q|0;d=p>>>8;if(d)if(q>>>0>16777215)G=31;else{p=(d+1048320|0)>>>16&8;f=d<<p;d=(f+520192|0)>>>16&4;m=f<<d;f=(m+245760|0)>>>16&2;i=14-(d|p|f)+(m<<f>>>15)|0;G=q>>>(i+7|0)&1|i<<1}else G=0;i=c[3192+(G<<2)>>2]|0;a:do if(!i){H=r;I=0;J=0;K=86}else{f=r;m=0;p=q<<((G|0)==31?0:25-(G>>>1)|0);d=i;e=0;while(1){h=c[d+4>>2]&-8;o=h-q|0;if(o>>>0<f>>>0)if((h|0)==(q|0)){L=o;M=d;N=d;K=90;break a}else{O=o;P=d}else{O=f;P=e}o=c[d+20>>2]|0;d=c[d+16+(p>>>31<<2)>>2]|0;h=(o|0)==0|(o|0)==(d|0)?m:o;if(!d){H=O;I=h;J=P;K=86;break}else{f=O;m=h;p=p<<1;e=P}}}while(0);if((K|0)==86){if((I|0)==0&(J|0)==0){i=2<<G;r=j&(i|0-i);if(!r){F=q;break}i=(r&0-r)+-1|0;r=i>>>12&16;b=i>>>r;i=b>>>5&8;k=b>>>i;b=k>>>2&4;e=k>>>b;k=e>>>1&2;p=e>>>k;e=p>>>1&1;Q=c[3192+((i|r|b|k|e)+(p>>>e)<<2)>>2]|0;R=0}else{Q=I;R=J}if(!Q){S=H;T=R}else{L=H;M=Q;N=R;K=90}}if((K|0)==90)while(1){K=0;e=(c[M+4>>2]&-8)-q|0;p=e>>>0<L>>>0;k=p?e:L;e=p?M:N;p=c[M+16>>2]|0;if(p){L=k;M=p;N=e;K=90;continue}M=c[M+20>>2]|0;if(!M){S=k;T=e;break}else{L=k;N=e;K=90}}if((T|0)!=0?S>>>0<((c[724]|0)-q|0)>>>0:0){j=c[726]|0;if(T>>>0<j>>>0)Ea();e=T+q|0;if(T>>>0>=e>>>0)Ea();k=c[T+24>>2]|0;p=c[T+12>>2]|0;do if((p|0)==(T|0)){b=T+20|0;r=c[b>>2]|0;if(!r){i=T+16|0;m=c[i>>2]|0;if(!m){U=0;break}else{V=m;W=i}}else{V=r;W=b}while(1){b=V+20|0;r=c[b>>2]|0;if(r){V=r;W=b;continue}b=V+16|0;r=c[b>>2]|0;if(!r){X=V;Y=W;break}else{V=r;W=b}}if(Y>>>0<j>>>0)Ea();else{c[Y>>2]=0;U=X;break}}else{b=c[T+8>>2]|0;if(b>>>0<j>>>0)Ea();r=b+12|0;if((c[r>>2]|0)!=(T|0))Ea();i=p+8|0;if((c[i>>2]|0)==(T|0)){c[r>>2]=p;c[i>>2]=b;U=p;break}else Ea()}while(0);do if(k){p=c[T+28>>2]|0;j=3192+(p<<2)|0;if((T|0)==(c[j>>2]|0)){c[j>>2]=U;if(!U){c[723]=c[723]&~(1<<p);break}}else{if(k>>>0<(c[726]|0)>>>0)Ea();p=k+16|0;if((c[p>>2]|0)==(T|0))c[p>>2]=U;else c[k+20>>2]=U;if(!U)break}p=c[726]|0;if(U>>>0<p>>>0)Ea();c[U+24>>2]=k;j=c[T+16>>2]|0;do if(j)if(j>>>0<p>>>0)Ea();else{c[U+16>>2]=j;c[j+24>>2]=U;break}while(0);j=c[T+20>>2]|0;if(j)if(j>>>0<(c[726]|0)>>>0)Ea();else{c[U+20>>2]=j;c[j+24>>2]=U;break}}while(0);b:do if(S>>>0>=16){c[T+4>>2]=q|3;c[T+(q|4)>>2]=S|1;c[T+(S+q)>>2]=S;k=S>>>3;if(S>>>0<256){j=k<<1;p=2928+(j<<2)|0;b=c[722]|0;i=1<<k;if(b&i){k=2928+(j+2<<2)|0;r=c[k>>2]|0;if(r>>>0<(c[726]|0)>>>0)Ea();else{Z=k;_=r}}else{c[722]=b|i;Z=2928+(j+2<<2)|0;_=p}c[Z>>2]=e;c[_+12>>2]=e;c[T+(q+8)>>2]=_;c[T+(q+12)>>2]=p;break}p=S>>>8;if(p)if(S>>>0>16777215)$=31;else{j=(p+1048320|0)>>>16&8;i=p<<j;p=(i+520192|0)>>>16&4;b=i<<p;i=(b+245760|0)>>>16&2;r=14-(p|j|i)+(b<<i>>>15)|0;$=S>>>(r+7|0)&1|r<<1}else $=0;r=3192+($<<2)|0;c[T+(q+28)>>2]=$;c[T+(q+20)>>2]=0;c[T+(q+16)>>2]=0;i=c[723]|0;b=1<<$;if(!(i&b)){c[723]=i|b;c[r>>2]=e;c[T+(q+24)>>2]=r;c[T+(q+12)>>2]=e;c[T+(q+8)>>2]=e;break}b=c[r>>2]|0;c:do if((c[b+4>>2]&-8|0)!=(S|0)){r=S<<(($|0)==31?0:25-($>>>1)|0);i=b;while(1){j=i+16+(r>>>31<<2)|0;p=c[j>>2]|0;if(!p){aa=j;ba=i;break}if((c[p+4>>2]&-8|0)==(S|0)){ca=p;break c}else{r=r<<1;i=p}}if(aa>>>0<(c[726]|0)>>>0)Ea();else{c[aa>>2]=e;c[T+(q+24)>>2]=ba;c[T+(q+12)>>2]=e;c[T+(q+8)>>2]=e;break b}}else ca=b;while(0);b=ca+8|0;i=c[b>>2]|0;r=c[726]|0;if(i>>>0>=r>>>0&ca>>>0>=r>>>0){c[i+12>>2]=e;c[b>>2]=e;c[T+(q+8)>>2]=i;c[T+(q+12)>>2]=ca;c[T+(q+24)>>2]=0;break}else Ea()}else{i=S+q|0;c[T+4>>2]=i|3;b=T+(i+4)|0;c[b>>2]=c[b>>2]|1}while(0);n=T+8|0;return n|0}else F=q}else F=q}else F=-1;while(0);T=c[724]|0;if(T>>>0>=F>>>0){S=T-F|0;ca=c[727]|0;if(S>>>0>15){c[727]=ca+F;c[724]=S;c[ca+(F+4)>>2]=S|1;c[ca+T>>2]=S;c[ca+4>>2]=F|3}else{c[724]=0;c[727]=0;c[ca+4>>2]=T|3;S=ca+(T+4)|0;c[S>>2]=c[S>>2]|1}n=ca+8|0;return n|0}ca=c[725]|0;if(ca>>>0>F>>>0){S=ca-F|0;c[725]=S;ca=c[728]|0;c[728]=ca+F;c[ca+(F+4)>>2]=S|1;c[ca+4>>2]=F|3;n=ca+8|0;return n|0}do if(!(c[840]|0)){ca=va(30)|0;if(!(ca+-1&ca)){c[842]=ca;c[841]=ca;c[843]=-1;c[844]=-1;c[845]=0;c[833]=0;c[840]=(Ga(0)|0)&-16^1431655768;break}else Ea()}while(0);ca=F+48|0;S=c[842]|0;T=F+47|0;ba=S+T|0;aa=0-S|0;S=ba&aa;if(S>>>0<=F>>>0){n=0;return n|0}$=c[832]|0;if(($|0)!=0?(_=c[830]|0,Z=_+S|0,Z>>>0<=_>>>0|Z>>>0>$>>>0):0){n=0;return n|0}d:do if(!(c[833]&4)){$=c[728]|0;e:do if($){Z=3336;while(1){_=c[Z>>2]|0;if(_>>>0<=$>>>0?(U=Z+4|0,(_+(c[U>>2]|0)|0)>>>0>$>>>0):0){da=Z;ea=U;break}Z=c[Z+8>>2]|0;if(!Z){K=174;break e}}Z=ba-(c[725]|0)&aa;if(Z>>>0<2147483647){U=ra(Z|0)|0;_=(U|0)==((c[da>>2]|0)+(c[ea>>2]|0)|0);X=_?Z:0;if(_)if((U|0)==(-1|0))fa=X;else{ga=U;ha=X;K=194;break d}else{ia=U;ja=Z;ka=X;K=184}}else fa=0}else K=174;while(0);do if((K|0)==174){$=ra(0)|0;if(($|0)!=(-1|0)){q=$;X=c[841]|0;Z=X+-1|0;if(!(Z&q))la=S;else la=S-q+(Z+q&0-X)|0;X=c[830]|0;q=X+la|0;if(la>>>0>F>>>0&la>>>0<2147483647){Z=c[832]|0;if((Z|0)!=0?q>>>0<=X>>>0|q>>>0>Z>>>0:0){fa=0;break}Z=ra(la|0)|0;q=(Z|0)==($|0);X=q?la:0;if(q){ga=$;ha=X;K=194;break d}else{ia=Z;ja=la;ka=X;K=184}}else fa=0}else fa=0}while(0);f:do if((K|0)==184){X=0-ja|0;do if(ca>>>0>ja>>>0&(ja>>>0<2147483647&(ia|0)!=(-1|0))?(Z=c[842]|0,$=T-ja+Z&0-Z,$>>>0<2147483647):0)if((ra($|0)|0)==(-1|0)){ra(X|0)|0;fa=ka;break f}else{ma=$+ja|0;break}else ma=ja;while(0);if((ia|0)==(-1|0))fa=ka;else{ga=ia;ha=ma;K=194;break d}}while(0);c[833]=c[833]|4;na=fa;K=191}else{na=0;K=191}while(0);if((((K|0)==191?S>>>0<2147483647:0)?(fa=ra(S|0)|0,S=ra(0)|0,fa>>>0<S>>>0&((fa|0)!=(-1|0)&(S|0)!=(-1|0))):0)?(ma=S-fa|0,S=ma>>>0>(F+40|0)>>>0,S):0){ga=fa;ha=S?ma:na;K=194}if((K|0)==194){na=(c[830]|0)+ha|0;c[830]=na;if(na>>>0>(c[831]|0)>>>0)c[831]=na;na=c[728]|0;g:do if(na){ma=3336;do{S=c[ma>>2]|0;fa=ma+4|0;ia=c[fa>>2]|0;if((ga|0)==(S+ia|0)){oa=S;pa=fa;qa=ia;sa=ma;K=204;break}ma=c[ma+8>>2]|0}while((ma|0)!=0);if(((K|0)==204?(c[sa+12>>2]&8|0)==0:0)?na>>>0<ga>>>0&na>>>0>=oa>>>0:0){c[pa>>2]=qa+ha;ma=(c[725]|0)+ha|0;ia=na+8|0;fa=(ia&7|0)==0?0:0-ia&7;ia=ma-fa|0;c[728]=na+fa;c[725]=ia;c[na+(fa+4)>>2]=ia|1;c[na+(ma+4)>>2]=40;c[729]=c[844];break}ma=c[726]|0;if(ga>>>0<ma>>>0){c[726]=ga;ta=ga}else ta=ma;ma=ga+ha|0;ia=3336;while(1){if((c[ia>>2]|0)==(ma|0)){ua=ia;wa=ia;K=212;break}ia=c[ia+8>>2]|0;if(!ia){xa=3336;break}}if((K|0)==212)if(!(c[wa+12>>2]&8)){c[ua>>2]=ga;ia=wa+4|0;c[ia>>2]=(c[ia>>2]|0)+ha;ia=ga+8|0;ma=(ia&7|0)==0?0:0-ia&7;ia=ga+(ha+8)|0;fa=(ia&7|0)==0?0:0-ia&7;ia=ga+(fa+ha)|0;S=ma+F|0;ka=ga+S|0;ja=ia-(ga+ma)-F|0;c[ga+(ma+4)>>2]=F|3;h:do if((ia|0)!=(na|0)){if((ia|0)==(c[727]|0)){T=(c[724]|0)+ja|0;c[724]=T;c[727]=ka;c[ga+(S+4)>>2]=T|1;c[ga+(T+S)>>2]=T;break}T=ha+4|0;ca=c[ga+(T+fa)>>2]|0;if((ca&3|0)==1){la=ca&-8;ea=ca>>>3;i:do if(ca>>>0>=256){da=c[ga+((fa|24)+ha)>>2]|0;aa=c[ga+(ha+12+fa)>>2]|0;do if((aa|0)==(ia|0)){ba=fa|16;X=ga+(T+ba)|0;$=c[X>>2]|0;if(!$){Z=ga+(ba+ha)|0;ba=c[Z>>2]|0;if(!ba){ya=0;break}else{za=ba;Aa=Z}}else{za=$;Aa=X}while(1){X=za+20|0;$=c[X>>2]|0;if($){za=$;Aa=X;continue}X=za+16|0;$=c[X>>2]|0;if(!$){Ba=za;Ca=Aa;break}else{za=$;Aa=X}}if(Ca>>>0<ta>>>0)Ea();else{c[Ca>>2]=0;ya=Ba;break}}else{X=c[ga+((fa|8)+ha)>>2]|0;if(X>>>0<ta>>>0)Ea();$=X+12|0;if((c[$>>2]|0)!=(ia|0))Ea();Z=aa+8|0;if((c[Z>>2]|0)==(ia|0)){c[$>>2]=aa;c[Z>>2]=X;ya=aa;break}else Ea()}while(0);if(!da)break;aa=c[ga+(ha+28+fa)>>2]|0;X=3192+(aa<<2)|0;do if((ia|0)!=(c[X>>2]|0)){if(da>>>0<(c[726]|0)>>>0)Ea();Z=da+16|0;if((c[Z>>2]|0)==(ia|0))c[Z>>2]=ya;else c[da+20>>2]=ya;if(!ya)break i}else{c[X>>2]=ya;if(ya)break;c[723]=c[723]&~(1<<aa);break i}while(0);aa=c[726]|0;if(ya>>>0<aa>>>0)Ea();c[ya+24>>2]=da;X=fa|16;Z=c[ga+(X+ha)>>2]|0;do if(Z)if(Z>>>0<aa>>>0)Ea();else{c[ya+16>>2]=Z;c[Z+24>>2]=ya;break}while(0);Z=c[ga+(T+X)>>2]|0;if(!Z)break;if(Z>>>0<(c[726]|0)>>>0)Ea();else{c[ya+20>>2]=Z;c[Z+24>>2]=ya;break}}else{Z=c[ga+((fa|8)+ha)>>2]|0;aa=c[ga+(ha+12+fa)>>2]|0;da=2928+(ea<<1<<2)|0;do if((Z|0)!=(da|0)){if(Z>>>0<ta>>>0)Ea();if((c[Z+12>>2]|0)==(ia|0))break;Ea()}while(0);if((aa|0)==(Z|0)){c[722]=c[722]&~(1<<ea);break}do if((aa|0)==(da|0))Fa=aa+8|0;else{if(aa>>>0<ta>>>0)Ea();X=aa+8|0;if((c[X>>2]|0)==(ia|0)){Fa=X;break}Ea()}while(0);c[Z+12>>2]=aa;c[Fa>>2]=Z}while(0);Ha=ga+((la|fa)+ha)|0;Ia=la+ja|0}else{Ha=ia;Ia=ja}ea=Ha+4|0;c[ea>>2]=c[ea>>2]&-2;c[ga+(S+4)>>2]=Ia|1;c[ga+(Ia+S)>>2]=Ia;ea=Ia>>>3;if(Ia>>>0<256){T=ea<<1;ca=2928+(T<<2)|0;da=c[722]|0;X=1<<ea;do if(!(da&X)){c[722]=da|X;Ja=2928+(T+2<<2)|0;Ka=ca}else{ea=2928+(T+2<<2)|0;$=c[ea>>2]|0;if($>>>0>=(c[726]|0)>>>0){Ja=ea;Ka=$;break}Ea()}while(0);c[Ja>>2]=ka;c[Ka+12>>2]=ka;c[ga+(S+8)>>2]=Ka;c[ga+(S+12)>>2]=ca;break}T=Ia>>>8;do if(!T)La=0;else{if(Ia>>>0>16777215){La=31;break}X=(T+1048320|0)>>>16&8;da=T<<X;la=(da+520192|0)>>>16&4;$=da<<la;da=($+245760|0)>>>16&2;ea=14-(la|X|da)+($<<da>>>15)|0;La=Ia>>>(ea+7|0)&1|ea<<1}while(0);T=3192+(La<<2)|0;c[ga+(S+28)>>2]=La;c[ga+(S+20)>>2]=0;c[ga+(S+16)>>2]=0;ca=c[723]|0;ea=1<<La;if(!(ca&ea)){c[723]=ca|ea;c[T>>2]=ka;c[ga+(S+24)>>2]=T;c[ga+(S+12)>>2]=ka;c[ga+(S+8)>>2]=ka;break}ea=c[T>>2]|0;j:do if((c[ea+4>>2]&-8|0)!=(Ia|0)){T=Ia<<((La|0)==31?0:25-(La>>>1)|0);ca=ea;while(1){da=ca+16+(T>>>31<<2)|0;$=c[da>>2]|0;if(!$){Ma=da;Na=ca;break}if((c[$+4>>2]&-8|0)==(Ia|0)){Oa=$;break j}else{T=T<<1;ca=$}}if(Ma>>>0<(c[726]|0)>>>0)Ea();else{c[Ma>>2]=ka;c[ga+(S+24)>>2]=Na;c[ga+(S+12)>>2]=ka;c[ga+(S+8)>>2]=ka;break h}}else Oa=ea;while(0);ea=Oa+8|0;ca=c[ea>>2]|0;T=c[726]|0;if(ca>>>0>=T>>>0&Oa>>>0>=T>>>0){c[ca+12>>2]=ka;c[ea>>2]=ka;c[ga+(S+8)>>2]=ca;c[ga+(S+12)>>2]=Oa;c[ga+(S+24)>>2]=0;break}else Ea()}else{ca=(c[725]|0)+ja|0;c[725]=ca;c[728]=ka;c[ga+(S+4)>>2]=ca|1}while(0);n=ga+(ma|8)|0;return n|0}else xa=3336;while(1){S=c[xa>>2]|0;if(S>>>0<=na>>>0?(ka=c[xa+4>>2]|0,ja=S+ka|0,ja>>>0>na>>>0):0){Pa=S;Qa=ka;Ra=ja;break}xa=c[xa+8>>2]|0}ma=Pa+(Qa+-39)|0;ja=Pa+(Qa+-47+((ma&7|0)==0?0:0-ma&7))|0;ma=na+16|0;ka=ja>>>0<ma>>>0?na:ja;ja=ka+8|0;S=ga+8|0;ia=(S&7|0)==0?0:0-S&7;S=ha+-40-ia|0;c[728]=ga+ia;c[725]=S;c[ga+(ia+4)>>2]=S|1;c[ga+(ha+-36)>>2]=40;c[729]=c[844];S=ka+4|0;c[S>>2]=27;c[ja>>2]=c[834];c[ja+4>>2]=c[835];c[ja+8>>2]=c[836];c[ja+12>>2]=c[837];c[834]=ga;c[835]=ha;c[837]=0;c[836]=ja;ja=ka+28|0;c[ja>>2]=7;if((ka+32|0)>>>0<Ra>>>0){ia=ja;do{ja=ia;ia=ia+4|0;c[ia>>2]=7}while((ja+8|0)>>>0<Ra>>>0)}if((ka|0)!=(na|0)){ia=ka-na|0;c[S>>2]=c[S>>2]&-2;c[na+4>>2]=ia|1;c[ka>>2]=ia;ja=ia>>>3;if(ia>>>0<256){fa=ja<<1;ca=2928+(fa<<2)|0;ea=c[722]|0;T=1<<ja;if(ea&T){ja=2928+(fa+2<<2)|0;Z=c[ja>>2]|0;if(Z>>>0<(c[726]|0)>>>0)Ea();else{Sa=ja;Ta=Z}}else{c[722]=ea|T;Sa=2928+(fa+2<<2)|0;Ta=ca}c[Sa>>2]=na;c[Ta+12>>2]=na;c[na+8>>2]=Ta;c[na+12>>2]=ca;break}ca=ia>>>8;if(ca)if(ia>>>0>16777215)Ua=31;else{fa=(ca+1048320|0)>>>16&8;T=ca<<fa;ca=(T+520192|0)>>>16&4;ea=T<<ca;T=(ea+245760|0)>>>16&2;Z=14-(ca|fa|T)+(ea<<T>>>15)|0;Ua=ia>>>(Z+7|0)&1|Z<<1}else Ua=0;Z=3192+(Ua<<2)|0;c[na+28>>2]=Ua;c[na+20>>2]=0;c[ma>>2]=0;T=c[723]|0;ea=1<<Ua;if(!(T&ea)){c[723]=T|ea;c[Z>>2]=na;c[na+24>>2]=Z;c[na+12>>2]=na;c[na+8>>2]=na;break}ea=c[Z>>2]|0;k:do if((c[ea+4>>2]&-8|0)!=(ia|0)){Z=ia<<((Ua|0)==31?0:25-(Ua>>>1)|0);T=ea;while(1){fa=T+16+(Z>>>31<<2)|0;ca=c[fa>>2]|0;if(!ca){Va=fa;Wa=T;break}if((c[ca+4>>2]&-8|0)==(ia|0)){Xa=ca;break k}else{Z=Z<<1;T=ca}}if(Va>>>0<(c[726]|0)>>>0)Ea();else{c[Va>>2]=na;c[na+24>>2]=Wa;c[na+12>>2]=na;c[na+8>>2]=na;break g}}else Xa=ea;while(0);ea=Xa+8|0;ia=c[ea>>2]|0;ma=c[726]|0;if(ia>>>0>=ma>>>0&Xa>>>0>=ma>>>0){c[ia+12>>2]=na;c[ea>>2]=na;c[na+8>>2]=ia;c[na+12>>2]=Xa;c[na+24>>2]=0;break}else Ea()}}else{ia=c[726]|0;if((ia|0)==0|ga>>>0<ia>>>0)c[726]=ga;c[834]=ga;c[835]=ha;c[837]=0;c[731]=c[840];c[730]=-1;ia=0;do{ea=ia<<1;ma=2928+(ea<<2)|0;c[2928+(ea+3<<2)>>2]=ma;c[2928+(ea+2<<2)>>2]=ma;ia=ia+1|0}while((ia|0)!=32);ia=ga+8|0;ma=(ia&7|0)==0?0:0-ia&7;ia=ha+-40-ma|0;c[728]=ga+ma;c[725]=ia;c[ga+(ma+4)>>2]=ia|1;c[ga+(ha+-36)>>2]=40;c[729]=c[844]}while(0);ha=c[725]|0;if(ha>>>0>F>>>0){ga=ha-F|0;c[725]=ga;ha=c[728]|0;c[728]=ha+F;c[ha+(F+4)>>2]=ga|1;c[ha+4>>2]=F|3;n=ha+8|0;return n|0}}c[(Da()|0)>>2]=12;n=0;return n|0}function ze(a){a=a|0;var b=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0,K=0,L=0,M=0;if(!a)return;b=a+-8|0;d=c[726]|0;if(b>>>0<d>>>0)Ea();e=c[a+-4>>2]|0;f=e&3;if((f|0)==1)Ea();g=e&-8;h=a+(g+-8)|0;do if(!(e&1)){i=c[b>>2]|0;if(!f)return;j=-8-i|0;k=a+j|0;l=i+g|0;if(k>>>0<d>>>0)Ea();if((k|0)==(c[727]|0)){m=a+(g+-4)|0;n=c[m>>2]|0;if((n&3|0)!=3){o=k;p=l;break}c[724]=l;c[m>>2]=n&-2;c[a+(j+4)>>2]=l|1;c[h>>2]=l;return}n=i>>>3;if(i>>>0<256){i=c[a+(j+8)>>2]|0;m=c[a+(j+12)>>2]|0;q=2928+(n<<1<<2)|0;if((i|0)!=(q|0)){if(i>>>0<d>>>0)Ea();if((c[i+12>>2]|0)!=(k|0))Ea()}if((m|0)==(i|0)){c[722]=c[722]&~(1<<n);o=k;p=l;break}if((m|0)!=(q|0)){if(m>>>0<d>>>0)Ea();q=m+8|0;if((c[q>>2]|0)==(k|0))r=q;else Ea()}else r=m+8|0;c[i+12>>2]=m;c[r>>2]=i;o=k;p=l;break}i=c[a+(j+24)>>2]|0;m=c[a+(j+12)>>2]|0;do if((m|0)==(k|0)){q=a+(j+20)|0;n=c[q>>2]|0;if(!n){s=a+(j+16)|0;t=c[s>>2]|0;if(!t){u=0;break}else{v=t;w=s}}else{v=n;w=q}while(1){q=v+20|0;n=c[q>>2]|0;if(n){v=n;w=q;continue}q=v+16|0;n=c[q>>2]|0;if(!n){x=v;y=w;break}else{v=n;w=q}}if(y>>>0<d>>>0)Ea();else{c[y>>2]=0;u=x;break}}else{q=c[a+(j+8)>>2]|0;if(q>>>0<d>>>0)Ea();n=q+12|0;if((c[n>>2]|0)!=(k|0))Ea();s=m+8|0;if((c[s>>2]|0)==(k|0)){c[n>>2]=m;c[s>>2]=q;u=m;break}else Ea()}while(0);if(i){m=c[a+(j+28)>>2]|0;q=3192+(m<<2)|0;if((k|0)==(c[q>>2]|0)){c[q>>2]=u;if(!u){c[723]=c[723]&~(1<<m);o=k;p=l;break}}else{if(i>>>0<(c[726]|0)>>>0)Ea();m=i+16|0;if((c[m>>2]|0)==(k|0))c[m>>2]=u;else c[i+20>>2]=u;if(!u){o=k;p=l;break}}m=c[726]|0;if(u>>>0<m>>>0)Ea();c[u+24>>2]=i;q=c[a+(j+16)>>2]|0;do if(q)if(q>>>0<m>>>0)Ea();else{c[u+16>>2]=q;c[q+24>>2]=u;break}while(0);q=c[a+(j+20)>>2]|0;if(q)if(q>>>0<(c[726]|0)>>>0)Ea();else{c[u+20>>2]=q;c[q+24>>2]=u;o=k;p=l;break}else{o=k;p=l}}else{o=k;p=l}}else{o=b;p=g}while(0);if(o>>>0>=h>>>0)Ea();b=a+(g+-4)|0;u=c[b>>2]|0;if(!(u&1))Ea();if(!(u&2)){if((h|0)==(c[728]|0)){d=(c[725]|0)+p|0;c[725]=d;c[728]=o;c[o+4>>2]=d|1;if((o|0)!=(c[727]|0))return;c[727]=0;c[724]=0;return}if((h|0)==(c[727]|0)){d=(c[724]|0)+p|0;c[724]=d;c[727]=o;c[o+4>>2]=d|1;c[o+d>>2]=d;return}d=(u&-8)+p|0;x=u>>>3;do if(u>>>0>=256){y=c[a+(g+16)>>2]|0;w=c[a+(g|4)>>2]|0;do if((w|0)==(h|0)){v=a+(g+12)|0;r=c[v>>2]|0;if(!r){f=a+(g+8)|0;e=c[f>>2]|0;if(!e){z=0;break}else{A=e;B=f}}else{A=r;B=v}while(1){v=A+20|0;r=c[v>>2]|0;if(r){A=r;B=v;continue}v=A+16|0;r=c[v>>2]|0;if(!r){C=A;D=B;break}else{A=r;B=v}}if(D>>>0<(c[726]|0)>>>0)Ea();else{c[D>>2]=0;z=C;break}}else{v=c[a+g>>2]|0;if(v>>>0<(c[726]|0)>>>0)Ea();r=v+12|0;if((c[r>>2]|0)!=(h|0))Ea();f=w+8|0;if((c[f>>2]|0)==(h|0)){c[r>>2]=w;c[f>>2]=v;z=w;break}else Ea()}while(0);if(y){w=c[a+(g+20)>>2]|0;l=3192+(w<<2)|0;if((h|0)==(c[l>>2]|0)){c[l>>2]=z;if(!z){c[723]=c[723]&~(1<<w);break}}else{if(y>>>0<(c[726]|0)>>>0)Ea();w=y+16|0;if((c[w>>2]|0)==(h|0))c[w>>2]=z;else c[y+20>>2]=z;if(!z)break}w=c[726]|0;if(z>>>0<w>>>0)Ea();c[z+24>>2]=y;l=c[a+(g+8)>>2]|0;do if(l)if(l>>>0<w>>>0)Ea();else{c[z+16>>2]=l;c[l+24>>2]=z;break}while(0);l=c[a+(g+12)>>2]|0;if(l)if(l>>>0<(c[726]|0)>>>0)Ea();else{c[z+20>>2]=l;c[l+24>>2]=z;break}}}else{l=c[a+g>>2]|0;w=c[a+(g|4)>>2]|0;y=2928+(x<<1<<2)|0;if((l|0)!=(y|0)){if(l>>>0<(c[726]|0)>>>0)Ea();if((c[l+12>>2]|0)!=(h|0))Ea()}if((w|0)==(l|0)){c[722]=c[722]&~(1<<x);break}if((w|0)!=(y|0)){if(w>>>0<(c[726]|0)>>>0)Ea();y=w+8|0;if((c[y>>2]|0)==(h|0))E=y;else Ea()}else E=w+8|0;c[l+12>>2]=w;c[E>>2]=l}while(0);c[o+4>>2]=d|1;c[o+d>>2]=d;if((o|0)==(c[727]|0)){c[724]=d;return}else F=d}else{c[b>>2]=u&-2;c[o+4>>2]=p|1;c[o+p>>2]=p;F=p}p=F>>>3;if(F>>>0<256){u=p<<1;b=2928+(u<<2)|0;d=c[722]|0;E=1<<p;if(d&E){p=2928+(u+2<<2)|0;h=c[p>>2]|0;if(h>>>0<(c[726]|0)>>>0)Ea();else{G=p;H=h}}else{c[722]=d|E;G=2928+(u+2<<2)|0;H=b}c[G>>2]=o;c[H+12>>2]=o;c[o+8>>2]=H;c[o+12>>2]=b;return}b=F>>>8;if(b)if(F>>>0>16777215)I=31;else{H=(b+1048320|0)>>>16&8;G=b<<H;b=(G+520192|0)>>>16&4;u=G<<b;G=(u+245760|0)>>>16&2;E=14-(b|H|G)+(u<<G>>>15)|0;I=F>>>(E+7|0)&1|E<<1}else I=0;E=3192+(I<<2)|0;c[o+28>>2]=I;c[o+20>>2]=0;c[o+16>>2]=0;G=c[723]|0;u=1<<I;a:do if(G&u){H=c[E>>2]|0;b:do if((c[H+4>>2]&-8|0)!=(F|0)){b=F<<((I|0)==31?0:25-(I>>>1)|0);d=H;while(1){h=d+16+(b>>>31<<2)|0;p=c[h>>2]|0;if(!p){J=h;K=d;break}if((c[p+4>>2]&-8|0)==(F|0)){L=p;break b}else{b=b<<1;d=p}}if(J>>>0<(c[726]|0)>>>0)Ea();else{c[J>>2]=o;c[o+24>>2]=K;c[o+12>>2]=o;c[o+8>>2]=o;break a}}else L=H;while(0);H=L+8|0;d=c[H>>2]|0;b=c[726]|0;if(d>>>0>=b>>>0&L>>>0>=b>>>0){c[d+12>>2]=o;c[H>>2]=o;c[o+8>>2]=d;c[o+12>>2]=L;c[o+24>>2]=0;break}else Ea()}else{c[723]=G|u;c[E>>2]=o;c[o+24>>2]=E;c[o+12>>2]=o;c[o+8>>2]=o}while(0);o=(c[730]|0)+-1|0;c[730]=o;if(!o)M=3344;else return;while(1){o=c[M>>2]|0;if(!o)break;else M=o+8|0}c[730]=-1;return}function Ae(a,b){a=a|0;b=b|0;var d=0,e=0;if(a){d=_(b,a)|0;if((b|a)>>>0>65535)e=((d>>>0)/(a>>>0)|0|0)==(b|0)?d:-1;else e=d}else e=0;d=ye(e)|0;if(!d)return d|0;if(!(c[d+-4>>2]&3))return d|0;He(d|0,0,e|0)|0;return d|0}function Be(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0;if(!a){d=ye(b)|0;return d|0}if(b>>>0>4294967231){c[(Da()|0)>>2]=12;d=0;return d|0}e=Ce(a+-8|0,b>>>0<11?16:b+11&-8)|0;if(e){d=e+8|0;return d|0}e=ye(b)|0;if(!e){d=0;return d|0}f=c[a+-4>>2]|0;g=(f&-8)-((f&3|0)==0?8:4)|0;Ke(e|0,a|0,(g>>>0<b>>>0?g:b)|0)|0;ze(a);d=e;return d|0}function Ce(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0;d=a+4|0;e=c[d>>2]|0;f=e&-8;g=a+f|0;h=c[726]|0;i=e&3;if(!((i|0)!=1&a>>>0>=h>>>0&a>>>0<g>>>0))Ea();j=a+(f|4)|0;k=c[j>>2]|0;if(!(k&1))Ea();if(!i){if(b>>>0<256){l=0;return l|0}if(f>>>0>=(b+4|0)>>>0?(f-b|0)>>>0<=c[842]<<1>>>0:0){l=a;return l|0}l=0;return l|0}if(f>>>0>=b>>>0){i=f-b|0;if(i>>>0<=15){l=a;return l|0}c[d>>2]=e&1|b|2;c[a+(b+4)>>2]=i|3;c[j>>2]=c[j>>2]|1;De(a+b|0,i);l=a;return l|0}if((g|0)==(c[728]|0)){i=(c[725]|0)+f|0;if(i>>>0<=b>>>0){l=0;return l|0}j=i-b|0;c[d>>2]=e&1|b|2;c[a+(b+4)>>2]=j|1;c[728]=a+b;c[725]=j;l=a;return l|0}if((g|0)==(c[727]|0)){j=(c[724]|0)+f|0;if(j>>>0<b>>>0){l=0;return l|0}i=j-b|0;if(i>>>0>15){c[d>>2]=e&1|b|2;c[a+(b+4)>>2]=i|1;c[a+j>>2]=i;m=a+(j+4)|0;c[m>>2]=c[m>>2]&-2;n=a+b|0;o=i}else{c[d>>2]=e&1|j|2;i=a+(j+4)|0;c[i>>2]=c[i>>2]|1;n=0;o=0}c[724]=o;c[727]=n;l=a;return l|0}if(k&2){l=0;return l|0}n=(k&-8)+f|0;if(n>>>0<b>>>0){l=0;return l|0}o=n-b|0;i=k>>>3;do if(k>>>0>=256){j=c[a+(f+24)>>2]|0;m=c[a+(f+12)>>2]|0;do if((m|0)==(g|0)){p=a+(f+20)|0;q=c[p>>2]|0;if(!q){r=a+(f+16)|0;s=c[r>>2]|0;if(!s){t=0;break}else{u=s;v=r}}else{u=q;v=p}while(1){p=u+20|0;q=c[p>>2]|0;if(q){u=q;v=p;continue}p=u+16|0;q=c[p>>2]|0;if(!q){w=u;x=v;break}else{u=q;v=p}}if(x>>>0<h>>>0)Ea();else{c[x>>2]=0;t=w;break}}else{p=c[a+(f+8)>>2]|0;if(p>>>0<h>>>0)Ea();q=p+12|0;if((c[q>>2]|0)!=(g|0))Ea();r=m+8|0;if((c[r>>2]|0)==(g|0)){c[q>>2]=m;c[r>>2]=p;t=m;break}else Ea()}while(0);if(j){m=c[a+(f+28)>>2]|0;p=3192+(m<<2)|0;if((g|0)==(c[p>>2]|0)){c[p>>2]=t;if(!t){c[723]=c[723]&~(1<<m);break}}else{if(j>>>0<(c[726]|0)>>>0)Ea();m=j+16|0;if((c[m>>2]|0)==(g|0))c[m>>2]=t;else c[j+20>>2]=t;if(!t)break}m=c[726]|0;if(t>>>0<m>>>0)Ea();c[t+24>>2]=j;p=c[a+(f+16)>>2]|0;do if(p)if(p>>>0<m>>>0)Ea();else{c[t+16>>2]=p;c[p+24>>2]=t;break}while(0);p=c[a+(f+20)>>2]|0;if(p)if(p>>>0<(c[726]|0)>>>0)Ea();else{c[t+20>>2]=p;c[p+24>>2]=t;break}}}else{p=c[a+(f+8)>>2]|0;m=c[a+(f+12)>>2]|0;j=2928+(i<<1<<2)|0;if((p|0)!=(j|0)){if(p>>>0<h>>>0)Ea();if((c[p+12>>2]|0)!=(g|0))Ea()}if((m|0)==(p|0)){c[722]=c[722]&~(1<<i);break}if((m|0)!=(j|0)){if(m>>>0<h>>>0)Ea();j=m+8|0;if((c[j>>2]|0)==(g|0))y=j;else Ea()}else y=m+8|0;c[p+12>>2]=m;c[y>>2]=p}while(0);if(o>>>0<16){c[d>>2]=n|e&1|2;y=a+(n|4)|0;c[y>>2]=c[y>>2]|1;l=a;return l|0}else{c[d>>2]=e&1|b|2;c[a+(b+4)>>2]=o|3;e=a+(n|4)|0;c[e>>2]=c[e>>2]|1;De(a+b|0,o);l=a;return l|0}return 0}function De(a,b){a=a|0;b=b|0;var d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,C=0,D=0,E=0,F=0,G=0,H=0,I=0,J=0;d=a+b|0;e=c[a+4>>2]|0;do if(!(e&1)){f=c[a>>2]|0;if(!(e&3))return;g=a+(0-f)|0;h=f+b|0;i=c[726]|0;if(g>>>0<i>>>0)Ea();if((g|0)==(c[727]|0)){j=a+(b+4)|0;k=c[j>>2]|0;if((k&3|0)!=3){l=g;m=h;break}c[724]=h;c[j>>2]=k&-2;c[a+(4-f)>>2]=h|1;c[d>>2]=h;return}k=f>>>3;if(f>>>0<256){j=c[a+(8-f)>>2]|0;n=c[a+(12-f)>>2]|0;o=2928+(k<<1<<2)|0;if((j|0)!=(o|0)){if(j>>>0<i>>>0)Ea();if((c[j+12>>2]|0)!=(g|0))Ea()}if((n|0)==(j|0)){c[722]=c[722]&~(1<<k);l=g;m=h;break}if((n|0)!=(o|0)){if(n>>>0<i>>>0)Ea();o=n+8|0;if((c[o>>2]|0)==(g|0))p=o;else Ea()}else p=n+8|0;c[j+12>>2]=n;c[p>>2]=j;l=g;m=h;break}j=c[a+(24-f)>>2]|0;n=c[a+(12-f)>>2]|0;do if((n|0)==(g|0)){o=16-f|0;k=a+(o+4)|0;q=c[k>>2]|0;if(!q){r=a+o|0;o=c[r>>2]|0;if(!o){s=0;break}else{t=o;u=r}}else{t=q;u=k}while(1){k=t+20|0;q=c[k>>2]|0;if(q){t=q;u=k;continue}k=t+16|0;q=c[k>>2]|0;if(!q){v=t;w=u;break}else{t=q;u=k}}if(w>>>0<i>>>0)Ea();else{c[w>>2]=0;s=v;break}}else{k=c[a+(8-f)>>2]|0;if(k>>>0<i>>>0)Ea();q=k+12|0;if((c[q>>2]|0)!=(g|0))Ea();r=n+8|0;if((c[r>>2]|0)==(g|0)){c[q>>2]=n;c[r>>2]=k;s=n;break}else Ea()}while(0);if(j){n=c[a+(28-f)>>2]|0;i=3192+(n<<2)|0;if((g|0)==(c[i>>2]|0)){c[i>>2]=s;if(!s){c[723]=c[723]&~(1<<n);l=g;m=h;break}}else{if(j>>>0<(c[726]|0)>>>0)Ea();n=j+16|0;if((c[n>>2]|0)==(g|0))c[n>>2]=s;else c[j+20>>2]=s;if(!s){l=g;m=h;break}}n=c[726]|0;if(s>>>0<n>>>0)Ea();c[s+24>>2]=j;i=16-f|0;k=c[a+i>>2]|0;do if(k)if(k>>>0<n>>>0)Ea();else{c[s+16>>2]=k;c[k+24>>2]=s;break}while(0);k=c[a+(i+4)>>2]|0;if(k)if(k>>>0<(c[726]|0)>>>0)Ea();else{c[s+20>>2]=k;c[k+24>>2]=s;l=g;m=h;break}else{l=g;m=h}}else{l=g;m=h}}else{l=a;m=b}while(0);s=c[726]|0;if(d>>>0<s>>>0)Ea();v=a+(b+4)|0;w=c[v>>2]|0;if(!(w&2)){if((d|0)==(c[728]|0)){u=(c[725]|0)+m|0;c[725]=u;c[728]=l;c[l+4>>2]=u|1;if((l|0)!=(c[727]|0))return;c[727]=0;c[724]=0;return}if((d|0)==(c[727]|0)){u=(c[724]|0)+m|0;c[724]=u;c[727]=l;c[l+4>>2]=u|1;c[l+u>>2]=u;return}u=(w&-8)+m|0;t=w>>>3;do if(w>>>0>=256){p=c[a+(b+24)>>2]|0;e=c[a+(b+12)>>2]|0;do if((e|0)==(d|0)){k=a+(b+20)|0;n=c[k>>2]|0;if(!n){f=a+(b+16)|0;j=c[f>>2]|0;if(!j){x=0;break}else{y=j;z=f}}else{y=n;z=k}while(1){k=y+20|0;n=c[k>>2]|0;if(n){y=n;z=k;continue}k=y+16|0;n=c[k>>2]|0;if(!n){A=y;B=z;break}else{y=n;z=k}}if(B>>>0<s>>>0)Ea();else{c[B>>2]=0;x=A;break}}else{k=c[a+(b+8)>>2]|0;if(k>>>0<s>>>0)Ea();n=k+12|0;if((c[n>>2]|0)!=(d|0))Ea();f=e+8|0;if((c[f>>2]|0)==(d|0)){c[n>>2]=e;c[f>>2]=k;x=e;break}else Ea()}while(0);if(p){e=c[a+(b+28)>>2]|0;h=3192+(e<<2)|0;if((d|0)==(c[h>>2]|0)){c[h>>2]=x;if(!x){c[723]=c[723]&~(1<<e);break}}else{if(p>>>0<(c[726]|0)>>>0)Ea();e=p+16|0;if((c[e>>2]|0)==(d|0))c[e>>2]=x;else c[p+20>>2]=x;if(!x)break}e=c[726]|0;if(x>>>0<e>>>0)Ea();c[x+24>>2]=p;h=c[a+(b+16)>>2]|0;do if(h)if(h>>>0<e>>>0)Ea();else{c[x+16>>2]=h;c[h+24>>2]=x;break}while(0);h=c[a+(b+20)>>2]|0;if(h)if(h>>>0<(c[726]|0)>>>0)Ea();else{c[x+20>>2]=h;c[h+24>>2]=x;break}}}else{h=c[a+(b+8)>>2]|0;e=c[a+(b+12)>>2]|0;p=2928+(t<<1<<2)|0;if((h|0)!=(p|0)){if(h>>>0<s>>>0)Ea();if((c[h+12>>2]|0)!=(d|0))Ea()}if((e|0)==(h|0)){c[722]=c[722]&~(1<<t);break}if((e|0)!=(p|0)){if(e>>>0<s>>>0)Ea();p=e+8|0;if((c[p>>2]|0)==(d|0))C=p;else Ea()}else C=e+8|0;c[h+12>>2]=e;c[C>>2]=h}while(0);c[l+4>>2]=u|1;c[l+u>>2]=u;if((l|0)==(c[727]|0)){c[724]=u;return}else D=u}else{c[v>>2]=w&-2;c[l+4>>2]=m|1;c[l+m>>2]=m;D=m}m=D>>>3;if(D>>>0<256){w=m<<1;v=2928+(w<<2)|0;u=c[722]|0;C=1<<m;if(u&C){m=2928+(w+2<<2)|0;d=c[m>>2]|0;if(d>>>0<(c[726]|0)>>>0)Ea();else{E=m;F=d}}else{c[722]=u|C;E=2928+(w+2<<2)|0;F=v}c[E>>2]=l;c[F+12>>2]=l;c[l+8>>2]=F;c[l+12>>2]=v;return}v=D>>>8;if(v)if(D>>>0>16777215)G=31;else{F=(v+1048320|0)>>>16&8;E=v<<F;v=(E+520192|0)>>>16&4;w=E<<v;E=(w+245760|0)>>>16&2;C=14-(v|F|E)+(w<<E>>>15)|0;G=D>>>(C+7|0)&1|C<<1}else G=0;C=3192+(G<<2)|0;c[l+28>>2]=G;c[l+20>>2]=0;c[l+16>>2]=0;E=c[723]|0;w=1<<G;if(!(E&w)){c[723]=E|w;c[C>>2]=l;c[l+24>>2]=C;c[l+12>>2]=l;c[l+8>>2]=l;return}w=c[C>>2]|0;a:do if((c[w+4>>2]&-8|0)==(D|0))H=w;else{C=D<<((G|0)==31?0:25-(G>>>1)|0);E=w;while(1){F=E+16+(C>>>31<<2)|0;v=c[F>>2]|0;if(!v){I=F;J=E;break}if((c[v+4>>2]&-8|0)==(D|0)){H=v;break a}else{C=C<<1;E=v}}if(I>>>0<(c[726]|0)>>>0)Ea();c[I>>2]=l;c[l+24>>2]=J;c[l+12>>2]=l;c[l+8>>2]=l;return}while(0);J=H+8|0;I=c[J>>2]|0;D=c[726]|0;if(!(I>>>0>=D>>>0&H>>>0>=D>>>0))Ea();c[I+12>>2]=l;c[J>>2]=l;c[l+8>>2]=I;c[l+12>>2]=H;c[l+24>>2]=0;return}function Ee(){}function Fe(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>c;return a>>>c|(b&(1<<c)-1)<<32-c}C=(b|0)<0?-1:0;return b>>c-32|0}function Ge(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=b-d>>>0;e=b-d-(c>>>0>a>>>0|0)>>>0;return (C=e,a-c>>>0|0)|0}function He(b,d,e){b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,i=0;f=b+e|0;if((e|0)>=20){d=d&255;g=b&3;h=d|d<<8|d<<16|d<<24;i=f&~3;if(g){g=b+4-g|0;while((b|0)<(g|0)){a[b>>0]=d;b=b+1|0}}while((b|0)<(i|0)){c[b>>2]=h;b=b+4|0}}while((b|0)<(f|0)){a[b>>0]=d;b=b+1|0}return b-e|0}function Ie(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b<<c|(a&(1<<c)-1<<32-c)>>>32-c;return a<<c}C=a<<c-32;return 0}function Je(b){b=b|0;var c=0;c=b;while(a[c>>0]|0)c=c+1|0;return c-b|0}function Ke(b,d,e){b=b|0;d=d|0;e=e|0;var f=0;if((e|0)>=4096)return sa(b|0,d|0,e|0)|0;f=b|0;if((b&3)==(d&3)){while(b&3){if(!e)return f|0;a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}while((e|0)>=4){c[b>>2]=c[d>>2];b=b+4|0;d=d+4|0;e=e-4|0}}while((e|0)>0){a[b>>0]=a[d>>0]|0;b=b+1|0;d=d+1|0;e=e-1|0}return f|0}function Le(b,c,d){b=b|0;c=c|0;d=d|0;var e=0,f=0;while((e|0)<(d|0)){a[b+e>>0]=f?0:a[c+e>>0]|0;f=f?1:(a[c+e>>0]|0)==0;e=e+1|0}return b|0}function Me(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0;e=a+c>>>0;return (C=b+d+(e>>>0<a>>>0|0)>>>0,e|0)|0}function Ne(b,c,d){b=b|0;c=c|0;d=d|0;var e=0;if((c|0)<(b|0)&(b|0)<(c+d|0)){e=b;c=c+d|0;b=b+d|0;while((d|0)>0){b=b-1|0;c=c-1|0;d=d-1|0;a[b>>0]=a[c>>0]|0}b=e}else Ke(b,c,d)|0;return b|0}function Oe(b,c){b=b|0;c=c|0;var d=0;do{a[b+d>>0]=a[c+d>>0];d=d+1|0}while(a[c+(d-1)>>0]|0);return b|0}function Pe(a,b,c){a=a|0;b=b|0;c=c|0;if((c|0)<32){C=b>>>c;return a>>>c|(b&(1<<c)-1)<<32-c}C=0;return b>>>c-32|0}function Qe(b){b=b|0;var c=0;c=a[m+(b&255)>>0]|0;if((c|0)<8)return c|0;c=a[m+(b>>8&255)>>0]|0;if((c|0)<8)return c+8|0;c=a[m+(b>>16&255)>>0]|0;if((c|0)<8)return c+16|0;return (a[m+(b>>>24)>>0]|0)+24|0}function Re(a,b){a=a|0;b=b|0;var c=0,d=0,e=0,f=0;c=a&65535;d=b&65535;e=_(d,c)|0;f=a>>>16;a=(e>>>16)+(_(d,f)|0)|0;d=b>>>16;b=_(d,c)|0;return (C=(a>>>16)+(_(d,f)|0)+(((a&65535)+b|0)>>>16)|0,a+b<<16|e&65535|0)|0}function Se(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0,g=0,h=0,i=0;e=b>>31|((b|0)<0?-1:0)<<1;f=((b|0)<0?-1:0)>>31|((b|0)<0?-1:0)<<1;g=d>>31|((d|0)<0?-1:0)<<1;h=((d|0)<0?-1:0)>>31|((d|0)<0?-1:0)<<1;i=Ge(e^a,f^b,e,f)|0;b=C;a=g^e;e=h^f;return Ge((Xe(i,b,Ge(g^c,h^d,g,h)|0,C,0)|0)^a,C^e,a,e)|0}function Te(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0,h=0,j=0,k=0,l=0,m=0;f=i;i=i+8|0;g=f|0;h=b>>31|((b|0)<0?-1:0)<<1;j=((b|0)<0?-1:0)>>31|((b|0)<0?-1:0)<<1;k=e>>31|((e|0)<0?-1:0)<<1;l=((e|0)<0?-1:0)>>31|((e|0)<0?-1:0)<<1;m=Ge(h^a,j^b,h,j)|0;b=C;Xe(m,b,Ge(k^d,l^e,k,l)|0,C,g)|0;l=Ge(c[g>>2]^h,c[g+4>>2]^j,h,j)|0;j=C;i=f;return (C=j,l)|0}function Ue(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;var e=0,f=0;e=a;a=c;c=Re(e,a)|0;f=C;return (C=(_(b,a)|0)+(_(d,e)|0)+f|f&0,c|0|0)|0}function Ve(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return Xe(a,b,c,d,0)|0}function We(a,b,d,e){a=a|0;b=b|0;d=d|0;e=e|0;var f=0,g=0;f=i;i=i+8|0;g=f|0;Xe(a,b,d,e,g)|0;i=f;return (C=c[g+4>>2]|0,c[g>>2]|0)|0}function Xe(a,b,d,e,f){a=a|0;b=b|0;d=d|0;e=e|0;f=f|0;var g=0,h=0,i=0,j=0,k=0,l=0,m=0,n=0,o=0,p=0,q=0,r=0,s=0,t=0,u=0,v=0,w=0,x=0,y=0,z=0,A=0,B=0,D=0,E=0,F=0,G=0,H=0;g=a;h=b;i=h;j=d;k=e;l=k;if(!i){m=(f|0)!=0;if(!l){if(m){c[f>>2]=(g>>>0)%(j>>>0);c[f+4>>2]=0}n=0;o=(g>>>0)/(j>>>0)>>>0;return (C=n,o)|0}else{if(!m){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=b&0;n=0;o=0;return (C=n,o)|0}}m=(l|0)==0;do if(j){if(!m){p=(aa(l|0)|0)-(aa(i|0)|0)|0;if(p>>>0<=31){q=p+1|0;r=31-p|0;s=p-31>>31;t=q;u=g>>>(q>>>0)&s|i<<r;v=i>>>(q>>>0)&s;w=0;x=g<<r;break}if(!f){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=h|b&0;n=0;o=0;return (C=n,o)|0}r=j-1|0;if(r&j){s=(aa(j|0)|0)+33-(aa(i|0)|0)|0;q=64-s|0;p=32-s|0;y=p>>31;z=s-32|0;A=z>>31;t=s;u=p-1>>31&i>>>(z>>>0)|(i<<p|g>>>(s>>>0))&A;v=A&i>>>(s>>>0);w=g<<q&y;x=(i<<q|g>>>(z>>>0))&y|g<<p&s-33>>31;break}if(f){c[f>>2]=r&g;c[f+4>>2]=0}if((j|0)==1){n=h|b&0;o=a|0|0;return (C=n,o)|0}else{r=Qe(j|0)|0;n=i>>>(r>>>0)|0;o=i<<32-r|g>>>(r>>>0)|0;return (C=n,o)|0}}else{if(m){if(f){c[f>>2]=(i>>>0)%(j>>>0);c[f+4>>2]=0}n=0;o=(i>>>0)/(j>>>0)>>>0;return (C=n,o)|0}if(!g){if(f){c[f>>2]=0;c[f+4>>2]=(i>>>0)%(l>>>0)}n=0;o=(i>>>0)/(l>>>0)>>>0;return (C=n,o)|0}r=l-1|0;if(!(r&l)){if(f){c[f>>2]=a|0;c[f+4>>2]=r&i|b&0}n=0;o=i>>>((Qe(l|0)|0)>>>0);return (C=n,o)|0}r=(aa(l|0)|0)-(aa(i|0)|0)|0;if(r>>>0<=30){s=r+1|0;p=31-r|0;t=s;u=i<<p|g>>>(s>>>0);v=i>>>(s>>>0);w=0;x=g<<p;break}if(!f){n=0;o=0;return (C=n,o)|0}c[f>>2]=a|0;c[f+4>>2]=h|b&0;n=0;o=0;return (C=n,o)|0}while(0);if(!t){B=x;D=w;E=v;F=u;G=0;H=0}else{b=d|0|0;d=k|e&0;e=Me(b|0,d|0,-1,-1)|0;k=C;h=x;x=w;w=v;v=u;u=t;t=0;do{a=h;h=x>>>31|h<<1;x=t|x<<1;g=v<<1|a>>>31|0;a=v>>>31|w<<1|0;Ge(e,k,g,a)|0;i=C;l=i>>31|((i|0)<0?-1:0)<<1;t=l&1;v=Ge(g,a,l&b,(((i|0)<0?-1:0)>>31|((i|0)<0?-1:0)<<1)&d)|0;w=C;u=u-1|0}while((u|0)!=0);B=h;D=x;E=w;F=v;G=0;H=t}t=D;D=0;if(f){c[f>>2]=F;c[f+4>>2]=E}n=(t|0)>>>31|(B|D)<<1|(D<<1|t>>>31)&0|G;o=(t<<1|0>>>31)&-2|H;return (C=n,o)|0}function Ye(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;return La[a&1](b|0,c|0,d|0)|0}function Ze(a,b){a=a|0;b=b|0;Ma[a&1](b|0)}function _e(a,b){a=a|0;b=b|0;return Na[a&7](b|0)|0}function $e(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;return Oa[a&15](b|0,c|0,d|0,e|0)|0}function af(a,b,c){a=a|0;b=b|0;c=c|0;return Pa[a&1](b|0,c|0)|0}function bf(a,b,c,d,e,f){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;f=f|0;return Qa[a&31](b|0,c|0,d|0,e|0,f|0)|0}function cf(a,b,c){a=a|0;b=b|0;c=c|0;ba(0);return 0}function df(a){a=a|0;ba(1)}function ef(a){a=a|0;ba(2);return 0}function ff(a,b,c,d){a=a|0;b=b|0;c=c|0;d=d|0;ba(3);return 0}function gf(a,b){a=a|0;b=b|0;ba(4);return 0}function hf(a,b,c,d,e){a=a|0;b=b|0;c=c|0;d=d|0;e=e|0;ba(5);return 0}
+
+// EMSCRIPTEN_END_FUNCS
+var La=[cf,wc];var Ma=[df,xc];var Na=[ef,tc,Jb,Kb,Lb,Vc,Nb,ef];var Oa=[ff,_c,cd,fd,md,rd,wd,Ad,pe,ff,ff,ff,ff,ff,ff,ff];var Pa=[gf,uc];var Qa=[hf,Xc,$c,ad,dd,ed,gd,hd,jd,kd,ld,nd,pd,qd,sd,td,ud,yd,zd,Cd,Dd,Ed,Fd,hf,hf,hf,hf,hf,hf,hf,hf,hf];return{_i64Subtract:Ge,_ogv_demuxer_keypoint_offset:ne,_memset:He,_ogv_demuxer_process:ie,_strncpy:Le,_ogv_demuxer_flush:oe,_bitshift64Ashr:Fe,_ogv_demuxer_init:he,_strlen:Je,_ogv_demuxer_destroy:je,_malloc:ye,_i64Add:Me,_ogv_demuxer_seekable:me,_ogv_demuxer_media_duration:le,_ogv_demuxer_media_length:ke,_memmove:Ne,_free:ze,_memcpy:Ke,_strcpy:Oe,_bitshift64Shl:Ie,runPostSets:Ee,stackAlloc:Ra,stackSave:Sa,stackRestore:Ta,establishStackSpace:Ua,setThrew:Va,setTempRet0:Ya,getTempRet0:Za,dynCall_iiii:Ye,dynCall_vi:Ze,dynCall_ii:_e,dynCall_iiiii:$e,dynCall_iii:af,dynCall_iiiiii:bf}})
+
+
+// EMSCRIPTEN_END_ASM
+(Module.asmGlobalArg,Module.asmLibraryArg,buffer);var runPostSets=Module["runPostSets"]=asm["runPostSets"];var _i64Subtract=Module["_i64Subtract"]=asm["_i64Subtract"];var _ogv_demuxer_keypoint_offset=Module["_ogv_demuxer_keypoint_offset"]=asm["_ogv_demuxer_keypoint_offset"];var _memcpy=Module["_memcpy"]=asm["_memcpy"];var _ogv_demuxer_process=Module["_ogv_demuxer_process"]=asm["_ogv_demuxer_process"];var _strncpy=Module["_strncpy"]=asm["_strncpy"];var _ogv_demuxer_flush=Module["_ogv_demuxer_flush"]=asm["_ogv_demuxer_flush"];var _bitshift64Ashr=Module["_bitshift64Ashr"]=asm["_bitshift64Ashr"];var _ogv_demuxer_init=Module["_ogv_demuxer_init"]=asm["_ogv_demuxer_init"];var _memset=Module["_memset"]=asm["_memset"];var _ogv_demuxer_destroy=Module["_ogv_demuxer_destroy"]=asm["_ogv_demuxer_destroy"];var _malloc=Module["_malloc"]=asm["_malloc"];var _i64Add=Module["_i64Add"]=asm["_i64Add"];var _ogv_demuxer_seekable=Module["_ogv_demuxer_seekable"]=asm["_ogv_demuxer_seekable"];var _ogv_demuxer_media_duration=Module["_ogv_demuxer_media_duration"]=asm["_ogv_demuxer_media_duration"];var _strlen=Module["_strlen"]=asm["_strlen"];var _ogv_demuxer_media_length=Module["_ogv_demuxer_media_length"]=asm["_ogv_demuxer_media_length"];var _memmove=Module["_memmove"]=asm["_memmove"];var _free=Module["_free"]=asm["_free"];var _strcpy=Module["_strcpy"]=asm["_strcpy"];var _bitshift64Shl=Module["_bitshift64Shl"]=asm["_bitshift64Shl"];var dynCall_iiii=Module["dynCall_iiii"]=asm["dynCall_iiii"];var dynCall_vi=Module["dynCall_vi"]=asm["dynCall_vi"];var dynCall_ii=Module["dynCall_ii"]=asm["dynCall_ii"];var dynCall_iiiii=Module["dynCall_iiiii"]=asm["dynCall_iiiii"];var dynCall_iii=Module["dynCall_iii"]=asm["dynCall_iii"];var dynCall_iiiiii=Module["dynCall_iiiiii"]=asm["dynCall_iiiiii"];Runtime.stackAlloc=asm["stackAlloc"];Runtime.stackSave=asm["stackSave"];Runtime.stackRestore=asm["stackRestore"];Runtime.establishStackSpace=asm["establishStackSpace"];Runtime.setTempRet0=asm["setTempRet0"];Runtime.getTempRet0=asm["getTempRet0"];var i64Math=(function(){var goog={math:{}};goog.math.Long=(function(low,high){this.low_=low|0;this.high_=high|0});goog.math.Long.IntCache_={};goog.math.Long.fromInt=(function(value){if(-128<=value&&value<128){var cachedObj=goog.math.Long.IntCache_[value];if(cachedObj){return cachedObj}}var obj=new goog.math.Long(value|0,value<0?-1:0);if(-128<=value&&value<128){goog.math.Long.IntCache_[value]=obj}return obj});goog.math.Long.fromNumber=(function(value){if(isNaN(value)||!isFinite(value)){return goog.math.Long.ZERO}else if(value<=-goog.math.Long.TWO_PWR_63_DBL_){return goog.math.Long.MIN_VALUE}else if(value+1>=goog.math.Long.TWO_PWR_63_DBL_){return goog.math.Long.MAX_VALUE}else if(value<0){return goog.math.Long.fromNumber(-value).negate()}else{return new goog.math.Long(value%goog.math.Long.TWO_PWR_32_DBL_|0,value/goog.math.Long.TWO_PWR_32_DBL_|0)}});goog.math.Long.fromBits=(function(lowBits,highBits){return new goog.math.Long(lowBits,highBits)});goog.math.Long.fromString=(function(str,opt_radix){if(str.length==0){throw Error("number format error: empty string")}var radix=opt_radix||10;if(radix<2||36<radix){throw Error("radix out of range: "+radix)}if(str.charAt(0)=="-"){return goog.math.Long.fromString(str.substring(1),radix).negate()}else if(str.indexOf("-")>=0){throw Error('number format error: interior "-" character: '+str)}var radixToPower=goog.math.Long.fromNumber(Math.pow(radix,8));var result=goog.math.Long.ZERO;for(var i=0;i<str.length;i+=8){var size=Math.min(8,str.length-i);var value=parseInt(str.substring(i,i+size),radix);if(size<8){var power=goog.math.Long.fromNumber(Math.pow(radix,size));result=result.multiply(power).add(goog.math.Long.fromNumber(value))}else{result=result.multiply(radixToPower);result=result.add(goog.math.Long.fromNumber(value))}}return result});goog.math.Long.TWO_PWR_16_DBL_=1<<16;goog.math.Long.TWO_PWR_24_DBL_=1<<24;goog.math.Long.TWO_PWR_32_DBL_=goog.math.Long.TWO_PWR_16_DBL_*goog.math.Long.TWO_PWR_16_DBL_;goog.math.Long.TWO_PWR_31_DBL_=goog.math.Long.TWO_PWR_32_DBL_/2;goog.math.Long.TWO_PWR_48_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_16_DBL_;goog.math.Long.TWO_PWR_64_DBL_=goog.math.Long.TWO_PWR_32_DBL_*goog.math.Long.TWO_PWR_32_DBL_;goog.math.Long.TWO_PWR_63_DBL_=goog.math.Long.TWO_PWR_64_DBL_/2;goog.math.Long.ZERO=goog.math.Long.fromInt(0);goog.math.Long.ONE=goog.math.Long.fromInt(1);goog.math.Long.NEG_ONE=goog.math.Long.fromInt(-1);goog.math.Long.MAX_VALUE=goog.math.Long.fromBits(4294967295|0,2147483647|0);goog.math.Long.MIN_VALUE=goog.math.Long.fromBits(0,2147483648|0);goog.math.Long.TWO_PWR_24_=goog.math.Long.fromInt(1<<24);goog.math.Long.prototype.toInt=(function(){return this.low_});goog.math.Long.prototype.toNumber=(function(){return this.high_*goog.math.Long.TWO_PWR_32_DBL_+this.getLowBitsUnsigned()});goog.math.Long.prototype.toString=(function(opt_radix){var radix=opt_radix||10;if(radix<2||36<radix){throw Error("radix out of range: "+radix)}if(this.isZero()){return"0"}if(this.isNegative()){if(this.equals(goog.math.Long.MIN_VALUE)){var radixLong=goog.math.Long.fromNumber(radix);var div=this.div(radixLong);var rem=div.multiply(radixLong).subtract(this);return div.toString(radix)+rem.toInt().toString(radix)}else{return"-"+this.negate().toString(radix)}}var radixToPower=goog.math.Long.fromNumber(Math.pow(radix,6));var rem=this;var result="";while(true){var remDiv=rem.div(radixToPower);var intval=rem.subtract(remDiv.multiply(radixToPower)).toInt();var digits=intval.toString(radix);rem=remDiv;if(rem.isZero()){return digits+result}else{while(digits.length<6){digits="0"+digits}result=""+digits+result}}});goog.math.Long.prototype.getHighBits=(function(){return this.high_});goog.math.Long.prototype.getLowBits=(function(){return this.low_});goog.math.Long.prototype.getLowBitsUnsigned=(function(){return this.low_>=0?this.low_:goog.math.Long.TWO_PWR_32_DBL_+this.low_});goog.math.Long.prototype.getNumBitsAbs=(function(){if(this.isNegative()){if(this.equals(goog.math.Long.MIN_VALUE)){return 64}else{return this.negate().getNumBitsAbs()}}else{var val=this.high_!=0?this.high_:this.low_;for(var bit=31;bit>0;bit--){if((val&1<<bit)!=0){break}}return this.high_!=0?bit+33:bit+1}});goog.math.Long.prototype.isZero=(function(){return this.high_==0&&this.low_==0});goog.math.Long.prototype.isNegative=(function(){return this.high_<0});goog.math.Long.prototype.isOdd=(function(){return(this.low_&1)==1});goog.math.Long.prototype.equals=(function(other){return this.high_==other.high_&&this.low_==other.low_});goog.math.Long.prototype.notEquals=(function(other){return this.high_!=other.high_||this.low_!=other.low_});goog.math.Long.prototype.lessThan=(function(other){return this.compare(other)<0});goog.math.Long.prototype.lessThanOrEqual=(function(other){return this.compare(other)<=0});goog.math.Long.prototype.greaterThan=(function(other){return this.compare(other)>0});goog.math.Long.prototype.greaterThanOrEqual=(function(other){return this.compare(other)>=0});goog.math.Long.prototype.compare=(function(other){if(this.equals(other)){return 0}var thisNeg=this.isNegative();var otherNeg=other.isNegative();if(thisNeg&&!otherNeg){return-1}if(!thisNeg&&otherNeg){return 1}if(this.subtract(other).isNegative()){return-1}else{return 1}});goog.math.Long.prototype.negate=(function(){if(this.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.MIN_VALUE}else{return this.not().add(goog.math.Long.ONE)}});goog.math.Long.prototype.add=(function(other){var a48=this.high_>>>16;var a32=this.high_&65535;var a16=this.low_>>>16;var a00=this.low_&65535;var b48=other.high_>>>16;var b32=other.high_&65535;var b16=other.low_>>>16;var b00=other.low_&65535;var c48=0,c32=0,c16=0,c00=0;c00+=a00+b00;c16+=c00>>>16;c00&=65535;c16+=a16+b16;c32+=c16>>>16;c16&=65535;c32+=a32+b32;c48+=c32>>>16;c32&=65535;c48+=a48+b48;c48&=65535;return goog.math.Long.fromBits(c16<<16|c00,c48<<16|c32)});goog.math.Long.prototype.subtract=(function(other){return this.add(other.negate())});goog.math.Long.prototype.multiply=(function(other){if(this.isZero()){return goog.math.Long.ZERO}else if(other.isZero()){return goog.math.Long.ZERO}if(this.equals(goog.math.Long.MIN_VALUE)){return other.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO}else if(other.equals(goog.math.Long.MIN_VALUE)){return this.isOdd()?goog.math.Long.MIN_VALUE:goog.math.Long.ZERO}if(this.isNegative()){if(other.isNegative()){return this.negate().multiply(other.negate())}else{return this.negate().multiply(other).negate()}}else if(other.isNegative()){return this.multiply(other.negate()).negate()}if(this.lessThan(goog.math.Long.TWO_PWR_24_)&&other.lessThan(goog.math.Long.TWO_PWR_24_)){return goog.math.Long.fromNumber(this.toNumber()*other.toNumber())}var a48=this.high_>>>16;var a32=this.high_&65535;var a16=this.low_>>>16;var a00=this.low_&65535;var b48=other.high_>>>16;var b32=other.high_&65535;var b16=other.low_>>>16;var b00=other.low_&65535;var c48=0,c32=0,c16=0,c00=0;c00+=a00*b00;c16+=c00>>>16;c00&=65535;c16+=a16*b00;c32+=c16>>>16;c16&=65535;c16+=a00*b16;c32+=c16>>>16;c16&=65535;c32+=a32*b00;c48+=c32>>>16;c32&=65535;c32+=a16*b16;c48+=c32>>>16;c32&=65535;c32+=a00*b32;c48+=c32>>>16;c32&=65535;c48+=a48*b00+a32*b16+a16*b32+a00*b48;c48&=65535;return goog.math.Long.fromBits(c16<<16|c00,c48<<16|c32)});goog.math.Long.prototype.div=(function(other){if(other.isZero()){throw Error("division by zero")}else if(this.isZero()){return goog.math.Long.ZERO}if(this.equals(goog.math.Long.MIN_VALUE)){if(other.equals(goog.math.Long.ONE)||other.equals(goog.math.Long.NEG_ONE)){return goog.math.Long.MIN_VALUE}else if(other.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.ONE}else{var halfThis=this.shiftRight(1);var approx=halfThis.div(other).shiftLeft(1);if(approx.equals(goog.math.Long.ZERO)){return other.isNegative()?goog.math.Long.ONE:goog.math.Long.NEG_ONE}else{var rem=this.subtract(other.multiply(approx));var result=approx.add(rem.div(other));return result}}}else if(other.equals(goog.math.Long.MIN_VALUE)){return goog.math.Long.ZERO}if(this.isNegative()){if(other.isNegative()){return this.negate().div(other.negate())}else{return this.negate().div(other).negate()}}else if(other.isNegative()){return this.div(other.negate()).negate()}var res=goog.math.Long.ZERO;var rem=this;while(rem.greaterThanOrEqual(other)){var approx=Math.max(1,Math.floor(rem.toNumber()/other.toNumber()));var log2=Math.ceil(Math.log(approx)/Math.LN2);var delta=log2<=48?1:Math.pow(2,log2-48);var approxRes=goog.math.Long.fromNumber(approx);var approxRem=approxRes.multiply(other);while(approxRem.isNegative()||approxRem.greaterThan(rem)){approx-=delta;approxRes=goog.math.Long.fromNumber(approx);approxRem=approxRes.multiply(other)}if(approxRes.isZero()){approxRes=goog.math.Long.ONE}res=res.add(approxRes);rem=rem.subtract(approxRem)}return res});goog.math.Long.prototype.modulo=(function(other){return this.subtract(this.div(other).multiply(other))});goog.math.Long.prototype.not=(function(){return goog.math.Long.fromBits(~this.low_,~this.high_)});goog.math.Long.prototype.and=(function(other){return goog.math.Long.fromBits(this.low_&other.low_,this.high_&other.high_)});goog.math.Long.prototype.or=(function(other){return goog.math.Long.fromBits(this.low_|other.low_,this.high_|other.high_)});goog.math.Long.prototype.xor=(function(other){return goog.math.Long.fromBits(this.low_^other.low_,this.high_^other.high_)});goog.math.Long.prototype.shiftLeft=(function(numBits){numBits&=63;if(numBits==0){return this}else{var low=this.low_;if(numBits<32){var high=this.high_;return goog.math.Long.fromBits(low<<numBits,high<<numBits|low>>>32-numBits)}else{return goog.math.Long.fromBits(0,low<<numBits-32)}}});goog.math.Long.prototype.shiftRight=(function(numBits){numBits&=63;if(numBits==0){return this}else{var high=this.high_;if(numBits<32){var low=this.low_;return goog.math.Long.fromBits(low>>>numBits|high<<32-numBits,high>>numBits)}else{return goog.math.Long.fromBits(high>>numBits-32,high>=0?0:-1)}}});goog.math.Long.prototype.shiftRightUnsigned=(function(numBits){numBits&=63;if(numBits==0){return this}else{var high=this.high_;if(numBits<32){var low=this.low_;return goog.math.Long.fromBits(low>>>numBits|high<<32-numBits,high>>>numBits)}else if(numBits==32){return goog.math.Long.fromBits(high,0)}else{return goog.math.Long.fromBits(high>>>numBits-32,0)}}});var navigator={appName:"Modern Browser"};var dbits;var canary=0xdeadbeefcafe;var j_lm=(canary&16777215)==15715070;function BigInteger(a,b,c){if(a!=null)if("number"==typeof a)this.fromNumber(a,b,c);else if(b==null&&"string"!=typeof a)this.fromString(a,256);else this.fromString(a,b)}function nbi(){return new BigInteger(null)}function am1(i,x,w,j,c,n){while(--n>=0){var v=x*this[i++]+w[j]+c;c=Math.floor(v/67108864);w[j++]=v&67108863}return c}function am2(i,x,w,j,c,n){var xl=x&32767,xh=x>>15;while(--n>=0){var l=this[i]&32767;var h=this[i++]>>15;var m=xh*l+h*xl;l=xl*l+((m&32767)<<15)+w[j]+(c&1073741823);c=(l>>>30)+(m>>>15)+xh*h+(c>>>30);w[j++]=l&1073741823}return c}function am3(i,x,w,j,c,n){var xl=x&16383,xh=x>>14;while(--n>=0){var l=this[i]&16383;var h=this[i++]>>14;var m=xh*l+h*xl;l=xl*l+((m&16383)<<14)+w[j]+c;c=(l>>28)+(m>>14)+xh*h;w[j++]=l&268435455}return c}if(j_lm&&navigator.appName=="Microsoft Internet Explorer"){BigInteger.prototype.am=am2;dbits=30}else if(j_lm&&navigator.appName!="Netscape"){BigInteger.prototype.am=am1;dbits=26}else{BigInteger.prototype.am=am3;dbits=28}BigInteger.prototype.DB=dbits;BigInteger.prototype.DM=(1<<dbits)-1;BigInteger.prototype.DV=1<<dbits;var BI_FP=52;BigInteger.prototype.FV=Math.pow(2,BI_FP);BigInteger.prototype.F1=BI_FP-dbits;BigInteger.prototype.F2=2*dbits-BI_FP;var BI_RM="0123456789abcdefghijklmnopqrstuvwxyz";var BI_RC=new Array;var rr,vv;rr="0".charCodeAt(0);for(vv=0;vv<=9;++vv)BI_RC[rr++]=vv;rr="a".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;rr="A".charCodeAt(0);for(vv=10;vv<36;++vv)BI_RC[rr++]=vv;function int2char(n){return BI_RM.charAt(n)}function intAt(s,i){var c=BI_RC[s.charCodeAt(i)];return c==null?-1:c}function bnpCopyTo(r){for(var i=this.t-1;i>=0;--i)r[i]=this[i];r.t=this.t;r.s=this.s}function bnpFromInt(x){this.t=1;this.s=x<0?-1:0;if(x>0)this[0]=x;else if(x<-1)this[0]=x+DV;else this.t=0}function nbv(i){var r=nbi();r.fromInt(i);return r}function bnpFromString(s,b){var k;if(b==16)k=4;else if(b==8)k=3;else if(b==256)k=8;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else{this.fromRadix(s,b);return}this.t=0;this.s=0;var i=s.length,mi=false,sh=0;while(--i>=0){var x=k==8?s[i]&255:intAt(s,i);if(x<0){if(s.charAt(i)=="-")mi=true;continue}mi=false;if(sh==0)this[this.t++]=x;else if(sh+k>this.DB){this[this.t-1]|=(x&(1<<this.DB-sh)-1)<<sh;this[this.t++]=x>>this.DB-sh}else this[this.t-1]|=x<<sh;sh+=k;if(sh>=this.DB)sh-=this.DB}if(k==8&&(s[0]&128)!=0){this.s=-1;if(sh>0)this[this.t-1]|=(1<<this.DB-sh)-1<<sh}this.clamp();if(mi)BigInteger.ZERO.subTo(this,this)}function bnpClamp(){var c=this.s&this.DM;while(this.t>0&&this[this.t-1]==c)--this.t}function bnToString(b){if(this.s<0)return"-"+this.negate().toString(b);var k;if(b==16)k=4;else if(b==8)k=3;else if(b==2)k=1;else if(b==32)k=5;else if(b==4)k=2;else return this.toRadix(b);var km=(1<<k)-1,d,m=false,r="",i=this.t;var p=this.DB-i*this.DB%k;if(i-->0){if(p<this.DB&&(d=this[i]>>p)>0){m=true;r=int2char(d)}while(i>=0){if(p<k){d=(this[i]&(1<<p)-1)<<k-p;d|=this[--i]>>(p+=this.DB-k)}else{d=this[i]>>(p-=k)&km;if(p<=0){p+=this.DB;--i}}if(d>0)m=true;if(m)r+=int2char(d)}}return m?r:"0"}function bnNegate(){var r=nbi();BigInteger.ZERO.subTo(this,r);return r}function bnAbs(){return this.s<0?this.negate():this}function bnCompareTo(a){var r=this.s-a.s;if(r!=0)return r;var i=this.t;r=i-a.t;if(r!=0)return this.s<0?-r:r;while(--i>=0)if((r=this[i]-a[i])!=0)return r;return 0}function nbits(x){var r=1,t;if((t=x>>>16)!=0){x=t;r+=16}if((t=x>>8)!=0){x=t;r+=8}if((t=x>>4)!=0){x=t;r+=4}if((t=x>>2)!=0){x=t;r+=2}if((t=x>>1)!=0){x=t;r+=1}return r}function bnBitLength(){if(this.t<=0)return 0;return this.DB*(this.t-1)+nbits(this[this.t-1]^this.s&this.DM)}function bnpDLShiftTo(n,r){var i;for(i=this.t-1;i>=0;--i)r[i+n]=this[i];for(i=n-1;i>=0;--i)r[i]=0;r.t=this.t+n;r.s=this.s}function bnpDRShiftTo(n,r){for(var i=n;i<this.t;++i)r[i-n]=this[i];r.t=Math.max(this.t-n,0);r.s=this.s}function bnpLShiftTo(n,r){var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<cbs)-1;var ds=Math.floor(n/this.DB),c=this.s<<bs&this.DM,i;for(i=this.t-1;i>=0;--i){r[i+ds+1]=this[i]>>cbs|c;c=(this[i]&bm)<<bs}for(i=ds-1;i>=0;--i)r[i]=0;r[ds]=c;r.t=this.t+ds+1;r.s=this.s;r.clamp()}function bnpRShiftTo(n,r){r.s=this.s;var ds=Math.floor(n/this.DB);if(ds>=this.t){r.t=0;return}var bs=n%this.DB;var cbs=this.DB-bs;var bm=(1<<bs)-1;r[0]=this[ds]>>bs;for(var i=ds+1;i<this.t;++i){r[i-ds-1]|=(this[i]&bm)<<cbs;r[i-ds]=this[i]>>bs}if(bs>0)r[this.t-ds-1]|=(this.s&bm)<<cbs;r.t=this.t-ds;r.clamp()}function bnpSubTo(a,r){var i=0,c=0,m=Math.min(a.t,this.t);while(i<m){c+=this[i]-a[i];r[i++]=c&this.DM;c>>=this.DB}if(a.t<this.t){c-=a.s;while(i<this.t){c+=this[i];r[i++]=c&this.DM;c>>=this.DB}c+=this.s}else{c+=this.s;while(i<a.t){c-=a[i];r[i++]=c&this.DM;c>>=this.DB}c-=a.s}r.s=c<0?-1:0;if(c<-1)r[i++]=this.DV+c;else if(c>0)r[i++]=c;r.t=i;r.clamp()}function bnpMultiplyTo(a,r){var x=this.abs(),y=a.abs();var i=x.t;r.t=i+y.t;while(--i>=0)r[i]=0;for(i=0;i<y.t;++i)r[i+x.t]=x.am(0,y[i],r,i,0,x.t);r.s=0;r.clamp();if(this.s!=a.s)BigInteger.ZERO.subTo(r,r)}function bnpSquareTo(r){var x=this.abs();var i=r.t=2*x.t;while(--i>=0)r[i]=0;for(i=0;i<x.t-1;++i){var c=x.am(i,x[i],r,2*i,0,1);if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1))>=x.DV){r[i+x.t]-=x.DV;r[i+x.t+1]=1}}if(r.t>0)r[r.t-1]+=x.am(i,x[i],r,2*i,0,1);r.s=0;r.clamp()}function bnpDivRemTo(m,q,r){var pm=m.abs();if(pm.t<=0)return;var pt=this.abs();if(pt.t<pm.t){if(q!=null)q.fromInt(0);if(r!=null)this.copyTo(r);return}if(r==null)r=nbi();var y=nbi(),ts=this.s,ms=m.s;var nsh=this.DB-nbits(pm[pm.t-1]);if(nsh>0){pm.lShiftTo(nsh,y);pt.lShiftTo(nsh,r)}else{pm.copyTo(y);pt.copyTo(r)}var ys=y.t;var y0=y[ys-1];if(y0==0)return;var yt=y0*(1<<this.F1)+(ys>1?y[ys-2]>>this.F2:0);var d1=this.FV/yt,d2=(1<<this.F1)/yt,e=1<<this.F2;var i=r.t,j=i-ys,t=q==null?nbi():q;y.dlShiftTo(j,t);if(r.compareTo(t)>=0){r[r.t++]=1;r.subTo(t,r)}BigInteger.ONE.dlShiftTo(ys,t);t.subTo(y,y);while(y.t<ys)y[y.t++]=0;while(--j>=0){var qd=r[--i]==y0?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);if((r[i]+=y.am(0,qd,r,j,0,ys))<qd){y.dlShiftTo(j,t);r.subTo(t,r);while(r[i]<--qd)r.subTo(t,r)}}if(q!=null){r.drShiftTo(ys,q);if(ts!=ms)BigInteger.ZERO.subTo(q,q)}r.t=ys;r.clamp();if(nsh>0)r.rShiftTo(nsh,r);if(ts<0)BigInteger.ZERO.subTo(r,r)}function bnMod(a){var r=nbi();this.abs().divRemTo(a,null,r);if(this.s<0&&r.compareTo(BigInteger.ZERO)>0)a.subTo(r,r);return r}function Classic(m){this.m=m}function cConvert(x){if(x.s<0||x.compareTo(this.m)>=0)return x.mod(this.m);else return x}function cRevert(x){return x}function cReduce(x){x.divRemTo(this.m,null,x)}function cMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r)}function cSqrTo(x,r){x.squareTo(r);this.reduce(r)}Classic.prototype.convert=cConvert;Classic.prototype.revert=cRevert;Classic.prototype.reduce=cReduce;Classic.prototype.mulTo=cMulTo;Classic.prototype.sqrTo=cSqrTo;function bnpInvDigit(){if(this.t<1)return 0;var x=this[0];if((x&1)==0)return 0;var y=x&3;y=y*(2-(x&15)*y)&15;y=y*(2-(x&255)*y)&255;y=y*(2-((x&65535)*y&65535))&65535;y=y*(2-x*y%this.DV)%this.DV;return y>0?this.DV-y:-y}function Montgomery(m){this.m=m;this.mp=m.invDigit();this.mpl=this.mp&32767;this.mph=this.mp>>15;this.um=(1<<m.DB-15)-1;this.mt2=2*m.t}function montConvert(x){var r=nbi();x.abs().dlShiftTo(this.m.t,r);r.divRemTo(this.m,null,r);if(x.s<0&&r.compareTo(BigInteger.ZERO)>0)this.m.subTo(r,r);return r}function montRevert(x){var r=nbi();x.copyTo(r);this.reduce(r);return r}function montReduce(x){while(x.t<=this.mt2)x[x.t++]=0;for(var i=0;i<this.m.t;++i){var j=x[i]&32767;var u0=j*this.mpl+((j*this.mph+(x[i]>>15)*this.mpl&this.um)<<15)&x.DM;j=i+this.m.t;x[j]+=this.m.am(0,u0,x,i,0,this.m.t);while(x[j]>=x.DV){x[j]-=x.DV;x[++j]++}}x.clamp();x.drShiftTo(this.m.t,x);if(x.compareTo(this.m)>=0)x.subTo(this.m,x)}function montSqrTo(x,r){x.squareTo(r);this.reduce(r)}function montMulTo(x,y,r){x.multiplyTo(y,r);this.reduce(r)}Montgomery.prototype.convert=montConvert;Montgomery.prototype.revert=montRevert;Montgomery.prototype.reduce=montReduce;Montgomery.prototype.mulTo=montMulTo;Montgomery.prototype.sqrTo=montSqrTo;function bnpIsEven(){return(this.t>0?this[0]&1:this.s)==0}function bnpExp(e,z){if(e>4294967295||e<1)return BigInteger.ONE;var r=nbi(),r2=nbi(),g=z.convert(this),i=nbits(e)-1;g.copyTo(r);while(--i>=0){z.sqrTo(r,r2);if((e&1<<i)>0)z.mulTo(r2,g,r);else{var t=r;r=r2;r2=t}}return z.revert(r)}function bnModPowInt(e,m){var z;if(e<256||m.isEven())z=new Classic(m);else z=new Montgomery(m);return this.exp(e,z)}BigInteger.prototype.copyTo=bnpCopyTo;BigInteger.prototype.fromInt=bnpFromInt;BigInteger.prototype.fromString=bnpFromString;BigInteger.prototype.clamp=bnpClamp;BigInteger.prototype.dlShiftTo=bnpDLShiftTo;BigInteger.prototype.drShiftTo=bnpDRShiftTo;BigInteger.prototype.lShiftTo=bnpLShiftTo;BigInteger.prototype.rShiftTo=bnpRShiftTo;BigInteger.prototype.subTo=bnpSubTo;BigInteger.prototype.multiplyTo=bnpMultiplyTo;BigInteger.prototype.squareTo=bnpSquareTo;BigInteger.prototype.divRemTo=bnpDivRemTo;BigInteger.prototype.invDigit=bnpInvDigit;BigInteger.prototype.isEven=bnpIsEven;BigInteger.prototype.exp=bnpExp;BigInteger.prototype.toString=bnToString;BigInteger.prototype.negate=bnNegate;BigInteger.prototype.abs=bnAbs;BigInteger.prototype.compareTo=bnCompareTo;BigInteger.prototype.bitLength=bnBitLength;BigInteger.prototype.mod=bnMod;BigInteger.prototype.modPowInt=bnModPowInt;BigInteger.ZERO=nbv(0);BigInteger.ONE=nbv(1);function bnpFromRadix(s,b){this.fromInt(0);if(b==null)b=10;var cs=this.chunkSize(b);var d=Math.pow(b,cs),mi=false,j=0,w=0;for(var i=0;i<s.length;++i){var x=intAt(s,i);if(x<0){if(s.charAt(i)=="-"&&this.signum()==0)mi=true;continue}w=b*w+x;if(++j>=cs){this.dMultiply(d);this.dAddOffset(w,0);j=0;w=0}}if(j>0){this.dMultiply(Math.pow(b,j));this.dAddOffset(w,0)}if(mi)BigInteger.ZERO.subTo(this,this)}function bnpChunkSize(r){return Math.floor(Math.LN2*this.DB/Math.log(r))}function bnSigNum(){if(this.s<0)return-1;else if(this.t<=0||this.t==1&&this[0]<=0)return 0;else return 1}function bnpDMultiply(n){this[this.t]=this.am(0,n-1,this,0,0,this.t);++this.t;this.clamp()}function bnpDAddOffset(n,w){if(n==0)return;while(this.t<=w)this[this.t++]=0;this[w]+=n;while(this[w]>=this.DV){this[w]-=this.DV;if(++w>=this.t)this[this.t++]=0;++this[w]}}function bnpToRadix(b){if(b==null)b=10;if(this.signum()==0||b<2||b>36)return"0";var cs=this.chunkSize(b);var a=Math.pow(b,cs);var d=nbv(a),y=nbi(),z=nbi(),r="";this.divRemTo(d,y,z);while(y.signum()>0){r=(a+z.intValue()).toString(b).substr(1)+r;y.divRemTo(d,y,z)}return z.intValue().toString(b)+r}function bnIntValue(){if(this.s<0){if(this.t==1)return this[0]-this.DV;else if(this.t==0)return-1}else if(this.t==1)return this[0];else if(this.t==0)return 0;return(this[1]&(1<<32-this.DB)-1)<<this.DB|this[0]}function bnpAddTo(a,r){var i=0,c=0,m=Math.min(a.t,this.t);while(i<m){c+=this[i]+a[i];r[i++]=c&this.DM;c>>=this.DB}if(a.t<this.t){c+=a.s;while(i<this.t){c+=this[i];r[i++]=c&this.DM;c>>=this.DB}c+=this.s}else{c+=this.s;while(i<a.t){c+=a[i];r[i++]=c&this.DM;c>>=this.DB}c+=a.s}r.s=c<0?-1:0;if(c>0)r[i++]=c;else if(c<-1)r[i++]=this.DV+c;r.t=i;r.clamp()}BigInteger.prototype.fromRadix=bnpFromRadix;BigInteger.prototype.chunkSize=bnpChunkSize;BigInteger.prototype.signum=bnSigNum;BigInteger.prototype.dMultiply=bnpDMultiply;BigInteger.prototype.dAddOffset=bnpDAddOffset;BigInteger.prototype.toRadix=bnpToRadix;BigInteger.prototype.intValue=bnIntValue;BigInteger.prototype.addTo=bnpAddTo;var Wrapper={abs:(function(l,h){var x=new goog.math.Long(l,h);var ret;if(x.isNegative()){ret=x.negate()}else{ret=x}HEAP32[tempDoublePtr>>2]=ret.low_;HEAP32[tempDoublePtr+4>>2]=ret.high_}),ensureTemps:(function(){if(Wrapper.ensuredTemps)return;Wrapper.ensuredTemps=true;Wrapper.two32=new BigInteger;Wrapper.two32.fromString("4294967296",10);Wrapper.two64=new BigInteger;Wrapper.two64.fromString("18446744073709551616",10);Wrapper.temp1=new BigInteger;Wrapper.temp2=new BigInteger}),lh2bignum:(function(l,h){var a=new BigInteger;a.fromString(h.toString(),10);var b=new BigInteger;a.multiplyTo(Wrapper.two32,b);var c=new BigInteger;c.fromString(l.toString(),10);var d=new BigInteger;c.addTo(b,d);return d}),stringify:(function(l,h,unsigned){var ret=(new goog.math.Long(l,h)).toString();if(unsigned&&ret[0]=="-"){Wrapper.ensureTemps();var bignum=new BigInteger;bignum.fromString(ret,10);ret=new BigInteger;Wrapper.two64.addTo(bignum,ret);ret=ret.toString(10)}return ret}),fromString:(function(str,base,min,max,unsigned){Wrapper.ensureTemps();var bignum=new BigInteger;bignum.fromString(str,base);var bigmin=new BigInteger;bigmin.fromString(min,10);var bigmax=new BigInteger;bigmax.fromString(max,10);if(unsigned&&bignum.compareTo(BigInteger.ZERO)<0){var temp=new BigInteger;bignum.addTo(Wrapper.two64,temp);bignum=temp}var error=false;if(bignum.compareTo(bigmin)<0){bignum=bigmin;error=true}else if(bignum.compareTo(bigmax)>0){bignum=bigmax;error=true}var ret=goog.math.Long.fromString(bignum.toString());HEAP32[tempDoublePtr>>2]=ret.low_;HEAP32[tempDoublePtr+4>>2]=ret.high_;if(error)throw"range error"})};return Wrapper})();function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}ExitStatus.prototype=new Error;ExitStatus.prototype.constructor=ExitStatus;var initialStackTop;var preloadStartTime=null;var calledMain=false;dependenciesFulfilled=function runCaller(){if(!Module["calledRun"])run();if(!Module["calledRun"])dependenciesFulfilled=runCaller};Module["callMain"]=Module.callMain=function callMain(args){assert(runDependencies==0,"cannot call main when async dependencies remain! (listen on __ATMAIN__)");assert(__ATPRERUN__.length==0,"cannot call main when preRun functions remain to be called");args=args||[];ensureInitRuntime();var argc=args.length+1;function pad(){for(var i=0;i<4-1;i++){argv.push(0)}}var argv=[allocate(intArrayFromString(Module["thisProgram"]),"i8",ALLOC_NORMAL)];pad();for(var i=0;i<argc-1;i=i+1){argv.push(allocate(intArrayFromString(args[i]),"i8",ALLOC_NORMAL));pad()}argv.push(0);argv=allocate(argv,"i32",ALLOC_NORMAL);initialStackTop=STACKTOP;try{var ret=Module["_main"](argc,argv,0);exit(ret,true)}catch(e){if(e instanceof ExitStatus){return}else if(e=="SimulateInfiniteLoop"){Module["noExitRuntime"]=true;return}else{if(e&&typeof e==="object"&&e.stack)Module.printErr("exception thrown: "+[e,e.stack]);throw e}}finally{calledMain=true}};function run(args){args=args||Module["arguments"];if(preloadStartTime===null)preloadStartTime=Date.now();if(runDependencies>0){return}preRun();if(runDependencies>0)return;if(Module["calledRun"])return;function doRun(){if(Module["calledRun"])return;Module["calledRun"]=true;if(ABORT)return;ensureInitRuntime();preMain();if(ENVIRONMENT_IS_WEB&&preloadStartTime!==null){Module.printErr("pre-main prep time: "+(Date.now()-preloadStartTime)+" ms")}if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(Module["_main"]&&shouldRunNow)Module["callMain"](args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout((function(){setTimeout((function(){Module["setStatus"]("")}),1);doRun()}),1)}else{doRun()}}Module["run"]=Module.run=run;function exit(status,implicit){if(implicit&&Module["noExitRuntime"]){return}if(Module["noExitRuntime"]){}else{ABORT=true;EXITSTATUS=status;STACKTOP=initialStackTop;exitRuntime();if(Module["onExit"])Module["onExit"](status)}if(ENVIRONMENT_IS_NODE){process["stdout"]["once"]("drain",(function(){process["exit"](status)}));console.log(" ");setTimeout((function(){process["exit"](status)}),500)}else if(ENVIRONMENT_IS_SHELL&&typeof quit==="function"){quit(status)}throw new ExitStatus(status)}Module["exit"]=Module.exit=exit;var abortDecorators=[];function abort(what){if(what!==undefined){Module.print(what);Module.printErr(what);what=JSON.stringify(what)}else{what=""}ABORT=true;EXITSTATUS=1;var extra="\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.";var output="abort("+what+") at "+stackTrace()+extra;if(abortDecorators){abortDecorators.forEach((function(decorator){output=decorator(output,what)}))}throw output}Module["abort"]=Module.abort=abort;if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=false;if(Module["noInitialRun"]){shouldRunNow=false}Module["noExitRuntime"]=true;run();var inputBuffer,inputBufferSize;function reallocInputBuffer(size){if(inputBuffer&&inputBufferSize>=size){return inputBuffer}if(inputBuffer){Module._free(inputBuffer)}inputBufferSize=size;inputBuffer=Module._malloc(inputBufferSize);return inputBuffer}Module.loadedmetadata=false;Module.videoCodec=null;Module.audioCodec=null;Module.duration=NaN;Module.audioPackets=[];Object.defineProperty(Module,"hasAudio",{get:(function(){return Module.loadedMetadata&&Module.audioCodec})});Object.defineProperty(Module,"audioReady",{get:(function(){return Module.audioPackets.length>0})});Object.defineProperty(Module,"audioTimestamp",{get:(function(){if(Module.audioPackets.length>0){return Module.audioPackets[0].timestamp}else{return-1}})});Module.videoPackets=[];Object.defineProperty(Module,"hasVideo",{get:(function(){return Module.loadedMetadata&&Module.videoCodec})});Object.defineProperty(Module,"frameReady",{get:(function(){return Module.videoPackets.length>0})});Object.defineProperty(Module,"frameTimestamp",{get:(function(){if(Module.videoPackets.length>0){return Module.videoPackets[0].timestamp}else{return-1}})});Object.defineProperty(Module,"keyframeTimestamp",{get:(function(){if(Module.videoPackets.length>0){return Module.videoPackets[0].keyframeTimestamp}else{return-1}})});Object.defineProperty(Module,"processing",{get:function getProcessing(){return false}});Object.defineProperty(Module,"seekable",{get:(function(){return!!Module._ogv_demuxer_seekable()})});Module.init=(function(callback){Module._ogv_demuxer_init();callback()});Module.process=(function(data,callback){var len=data.byteLength;var buffer=reallocInputBuffer(len);Module.HEAPU8.set(new Uint8Array(data),buffer);var ret=Module._ogv_demuxer_process(buffer,len);callback(ret)});Module.dequeueVideoPacket=(function(callback){if(Module.videoPackets.length){var packet=Module.videoPackets.shift().data;callback(packet)}else{callback(null)}});Module.dequeueAudioPacket=(function(callback){if(Module.audioPackets.length){var packet=Module.audioPackets.shift().data;callback(packet)}else{callback(null)}});Module.getKeypointOffset=(function(timeSeconds,callback){var offset=Module._ogv_demuxer_keypoint_offset(timeSeconds*1e3);callback(offset)});Module.flush=(function(callback){Module.audioPackets.splice(0,Module.audioPackets.length);Module.videoPackets.splice(0,Module.videoPackets.length);Module._ogv_demuxer_flush();callback()})
+
+
+
+
+
+ return Module;
+};
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-support.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-support.js
new file mode 100644
index 00000000..5c2933ed
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-support.js
@@ -0,0 +1,201 @@
+//
+// -- ogv-support.js
+// https://github.com/brion/ogv.js
+// Copyright (c) 2013-2015 Brion Vibber
+//
+
+(function() {
+
+
+/**
+ * A quick CPU/JS engine benchmark to guesstimate whether we're
+ * fast enough to handle 360p video in JavaScript.
+ */
+function BogoSlow() {
+ var self = this;
+
+ var timer;
+ if (window.performance && window.performance.now) {
+ timer = function() {
+ return window.performance.now();
+ };
+ } else {
+ timer = function() {
+ return Date.now();
+ };
+ }
+
+ var savedSpeed = null;
+ function run() {
+ var ops = 0;
+ var fibonacci = function(n) {
+ ops++;
+ if (n < 2) {
+ return n;
+ } else {
+ return fibonacci(n - 2) + fibonacci(n - 1);
+ }
+ };
+
+ var start = timer();
+
+ fibonacci(30);
+
+ var delta = timer() - start;
+ savedSpeed = (ops / delta);
+ }
+
+ /**
+ * Return a scale value of operations/sec from the benchmark.
+ * If the benchmark has already been run, uses a memoized result.
+ *
+ * @property {number}
+ */
+ Object.defineProperty(self, 'speed', {
+ get: function() {
+ if (savedSpeed === null) {
+ run();
+ }
+ return savedSpeed;
+ }
+ });
+
+ /**
+ * Return the defined cutoff speed value for 'slow' devices,
+ * based on results measured from some test devices.
+ *
+ * @property {number}
+ */
+ Object.defineProperty(self, 'slowCutoff', {
+ get: function() {
+ // 2012 Retina MacBook Pro (Safari 7) ~150,000
+ // 2009 Dell T5500 (IE 11) ~100,000
+ // iPad Air (iOS 7) ~65,000
+ // 2010 MBP / OS X 10.9 (Safari 7) ~62,500
+ // 2010 MBP / Win7 VM (IE 11) ~50,000+-
+ // ^ these play 360p ok
+ // ----------- line of moderate doom ----------
+ return 50000;
+ // v these play 160p ok
+ // iPad Mini non-Retina (iOS 8 beta) ~25,000
+ // Dell Inspiron Duo (IE 11) ~25,000
+ // Surface RT (IE 11) ~18,000
+ // iPod Touch 5th-gen (iOS 8 beta) ~16,000
+ }
+ });
+
+ /**
+ * Return the defined cutoff speed value for 'too slow' devices,
+ * based on results measured from some test devices.
+ *
+ * @property {number}
+ */
+ Object.defineProperty(self, 'tooSlowCutoff', {
+ get: function() {
+ // ------------ line of total doom ------------
+ return 12000;
+ // v these are toooooo slow and explode
+ // Chrome on iPhone 5s (iOS 8) ~8,000
+ // iPod 4th-gen (iOS 6.1) ~6,750
+ // iPhone 3Gs (iOS 6.1) ~4,500
+ }
+ });
+
+ /**
+ * 'Slow' devices can play audio and should sorta play our
+ * extra-tiny Wikimedia 160p15 transcodes
+ *
+ * @property {boolean}
+ */
+ Object.defineProperty(self, 'slow', {
+ get: function() {
+ return (self.speed < self.slowCutoff);
+ }
+ });
+
+ /**
+ * 'Too slow' devices aren't reliable at all
+ *
+ * @property {boolean}
+ */
+ Object.defineProperty(self, 'tooSlow', {
+ get: function() {
+ return (self.speed < self.tooSlowCutoff);
+ }
+ });
+}
+
+
+
+OGVCompat = {
+ benchmark: new BogoSlow(),
+
+ hasTypedArrays: function() {
+ // emscripten-compiled code requires typed arrays
+ return !!window.Uint32Array;
+ },
+
+ hasWebAudio: function() {
+ return !!(window.AudioContext || window.webkitAudioContext);
+ },
+
+ hasFlash: function() {
+ if (navigator.userAgent.indexOf('Trident') !== -1) {
+ // We only do the ActiveX test because we only need Flash in
+ // Internet Explorer 10/11. Other browsers use Web Audio directly
+ // (Edge, Safari) or native playback, so there's no need to test
+ // other ways of loading Flash.
+ try {
+ var obj = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
+ return true;
+ } catch(e) {
+ return false;
+ }
+ }
+ return false;
+ },
+
+ hasAudio: function() {
+ return this.hasWebAudio() || this.hasFlash();
+ },
+
+ isBlacklisted: function(userAgent) {
+ // JIT bugs in old Safari versions
+ var blacklist = [
+ /\(i.* OS [67]_.* like Mac OS X\).* Mobile\/.* Safari\//,
+ /\(Macintosh.* Version\/6\..* Safari\/\d/
+ ];
+ var blacklisted = false;
+ blacklist.forEach(function(regex) {
+ if (userAgent.match(regex)) {
+ blacklisted = true;
+ }
+ });
+ return blacklisted;
+ },
+
+ isSlow: function() {
+ return this.benchmark.slow;
+ },
+
+ isTooSlow: function() {
+ return this.benchmark.tooSlow;
+ },
+
+ supported: function(component) {
+ if (component === 'OGVDecoder') {
+ return (this.hasTypedArrays() && !this.isBlacklisted(navigator.userAgent));
+ }
+ if (component === 'OGVPlayer') {
+ return (this.supported('OGVDecoder') && this.hasAudio() && !this.isTooSlow());
+ }
+ return false;
+ }
+};
+
+
+ this.OGVCompat = OGVCompat;
+
+})();
+
+this.OGVVersion = "1.0-20150904182230-dd3c8e8";
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-version.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-version.js
new file mode 100644
index 00000000..e6a7a670
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-version.js
@@ -0,0 +1 @@
+this.OGVVersion = "1.0-20150904182230-dd3c8e8";
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-worker-audio.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-worker-audio.js
new file mode 100644
index 00000000..c7c0ff25
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-worker-audio.js
@@ -0,0 +1,317 @@
+(function() {
+ var global = this;
+
+ var scriptMap = {
+ OGVDemuxerOgg: 'ogv-demuxer-ogg.js',
+ OGVDemuxerWebM: 'ogv-demuxer-webm.js',
+ OGVDecoderAudioOpus: 'ogv-decoder-audio-opus.js',
+ OGVDecoderAudioVorbis: 'ogv-decoder-audio-vorbis.js',
+ OGVDecoderVideoTheora: 'ogv-decoder-video-theora.js',
+ OGVDecoderVideoVP8: 'ogv-decoder-video-vp8.js'
+ };
+
+ var proxyMap = {
+ OGVDecoderAudioOpus: 'OGVDecoderAudioProxy',
+ OGVDecoderAudioVorbis: 'OGVDecoderAudioProxy',
+ OGVDecoderVideoTheora: 'OGVDecoderVideoProxy',
+ OGVDecoderVideoVP8: 'OGVDecoderVideoProxy'
+ };
+ var workerMap = {
+ OGVDecoderAudioProxy: 'ogv-worker-audio.js',
+ OGVDecoderVideoProxy: 'ogv-worker-video.js'
+ };
+
+ function urlForClass(className) {
+ var scriptName = scriptMap[className];
+ if (scriptName) {
+ return urlForScript(scriptName);
+ } else {
+ throw new Error('asked for URL for unknown class ' + className);
+ }
+ };
+
+ function urlForScript(scriptName) {
+ if (scriptName) {
+ var base = OGVLoader.base;
+ if (base) {
+ base += '/';
+ }
+ return base + scriptName + '?version=' + encodeURIComponent(OGVVersion);
+ } else {
+ throw new Error('asked for URL for unknown script ' + scriptName);
+ }
+ };
+
+ var scriptStatus = {},
+ scriptCallbacks = {};
+ function loadWebScript(src, callback) {
+ if (scriptStatus[src] == 'done') {
+ callback();
+ } else if (scriptStatus[src] == 'loading') {
+ scriptCallbacks[src].push(callback);
+ } else {
+ scriptStatus[src] = 'loading';
+ scriptCallbacks[src] = [callback];
+
+ var scriptNode = document.createElement('script');
+ function done(event) {
+ var callbacks = scriptCallbacks[src];
+ delete scriptCallbacks[src];
+ scriptStatus[src] = 'done';
+
+ callbacks.forEach(function(cb) {
+ cb();
+ });
+ }
+ scriptNode.addEventListener('load', done);
+ scriptNode.addEventListener('error', done);
+ scriptNode.src = src;
+ document.querySelector('head').appendChild(scriptNode);
+ }
+ }
+
+ function defaultBase() {
+ if (typeof global.window === 'object') {
+
+ // for browser, try to autodetect
+ var scriptNodes = document.querySelectorAll('script'),
+ regex = /^(?:(.*)\/)ogv(?:-support)?\.js(?:\?|#|$)/,
+ path;
+ for (var i = 0; i < scriptNodes.length; i++) {
+ path = scriptNodes[i].getAttribute('src');
+ if (path) {
+ matches = path.match(regex);
+ if (matches) {
+ return matches[1];
+ }
+ }
+ }
+
+ } else {
+
+ // for workers, assume current directory
+ // if not a worker, too bad.
+ return '';
+
+ }
+ }
+
+ OGVLoader = {
+ base: defaultBase(),
+
+ loadClass: function(className, callback, options) {
+ options = options || {};
+ if (options.worker) {
+ this.workerProxy(className, callback);
+ } else if (typeof global[className] === 'function') {
+ // already loaded!
+ callback(global[className]);
+ } else if (typeof global.window === 'object') {
+ loadWebScript(urlForClass(className), function() {
+ callback(global[className]);
+ });
+ } else if (typeof global.importScripts === 'function') {
+ // worker has convenient sync importScripts
+ global.importScripts(urlForClass(className));
+ callback(global[className]);
+ }
+ },
+
+ workerProxy: function(className, callback) {
+ var proxyClass = proxyMap[className],
+ workerScript = workerMap[proxyClass];
+
+ if (!proxyClass) {
+ throw new Error('Requested worker for class with no proxy: ' + className);
+ }
+ if (!workerScript) {
+ throw new Error('Requested worker for class with no worker: ' + className);
+ }
+
+ this.loadClass(proxyClass, function(classObj) {
+ var construct = function(options) {
+ var worker = new Worker(urlForScript(workerScript));
+ return new classObj(worker, className, options);
+ };
+ callback(construct);
+ });
+ }
+ };
+})();
+/**
+ * Web Worker wrapper for codec fun
+ */
+function OGVWorkerSupport(propList, handlers) {
+
+ var transferables = (function() {
+ var buffer = new ArrayBuffer(1024),
+ bytes = new Uint8Array(buffer);
+ try {
+ postMessage({
+ action: 'transferTest',
+ bytes: bytes
+ }, [buffer]);
+ if (buffer.byteLength) {
+ // No transferable support
+ return false;
+ } else {
+ return true;
+ }
+ } catch (e) {
+ return false;
+ }
+ })();
+
+ var self = this;
+ self.target = null;
+
+ var sentProps = {};
+
+ function copyObject(obj) {
+ var copy = {};
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ copy[prop] = obj[prop];
+ }
+ }
+ return copy;
+ }
+
+ function copyAudioBuffer(data) {
+ if (data == null) {
+ return null;
+ } else {
+ // Array of Float32Arrays
+ var copy = [];
+ for (var i = 0; i < data.length; i++) {
+ copy[i] = new Float32Array(data[i]);
+ }
+ return copy;
+ }
+ }
+
+ function copyByteArray(bytes) {
+ var heap = bytes.buffer;
+ if (typeof heap.slice === 'function') {
+ var extract = heap.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
+ return new Uint8Array(extract);
+ } else {
+ // Hella slow in IE 10/11!
+ // But only game in town on IE 10.
+ return new Uint8Array(bytes);
+ }
+ }
+
+ function copyFrameBuffer(buffer) {
+ if (buffer == null) {
+ return null;
+ } else {
+ var copy = copyObject(buffer);
+ copy.bytesY = copyByteArray(buffer.bytesY);
+ copy.bytesCb = copyByteArray(buffer.bytesCb);
+ copy.bytesCr = copyByteArray(buffer.bytesCr);
+ return copy;
+ }
+ }
+
+ handlers.construct = function(args, callback) {
+ var className = args[0],
+ options = args[1];
+
+ OGVLoader.loadClass(className, function(classObj) {
+ self.target = new classObj(options);
+ callback();
+ });
+ };
+
+ addEventListener('message', function workerOnMessage(event) {
+ var data = event.data;
+
+ if (data && data.action == 'transferTest') {
+ // ignore
+ return;
+ }
+
+ if (typeof data !== 'object' || typeof data.action !== 'string' || typeof data.callbackId !== 'string' || typeof data.args !== 'object') {
+ console.log('invalid message data', data);
+ } else if (!(data.action in handlers)) {
+ console.log('invalid message action', data.action);
+ } else {
+ handlers[data.action].call(self, data.args, function(args) {
+ args = args || [];
+
+ // Collect and send any changed properties...
+ var props = {},
+ transfers = [];
+ propList.forEach(function(propName) {
+ var propVal = self.target[propName];
+
+ if (sentProps[propName] !== propVal) {
+ // Save this value for later reference...
+ sentProps[propName] = propVal;
+
+ if (propName == 'duration' && isNaN(propVal) && isNaN(sentProps[propName])) {
+ // NaN is not === itself. Nice!
+ // no need to update it here.
+ } else if (propName == 'audioBuffer') {
+ // Don't send the entire emscripten heap!
+ propVal = copyAudioBuffer(propVal);
+ props[propName] = propVal;
+ if (propVal) {
+ for (i = 0; i < propVal.length; i++) {
+ transfers.push(propVal[i].buffer);
+ }
+ }
+ } else if (propName == 'frameBuffer') {
+ // Don't send the entire emscripten heap!
+ propVal = copyFrameBuffer(propVal);
+ props[propName] = propVal;
+ if (propVal) {
+ transfers.push(propVal.bytesY.buffer);
+ transfers.push(propVal.bytesCb.buffer);
+ transfers.push(propVal.bytesCr.buffer);
+ }
+ } else {
+ props[propName] = propVal;
+ }
+ }
+ });
+
+ var out = {
+ action: 'callback',
+ callbackId: data.callbackId,
+ args: args,
+ props: props
+ };
+ if (transferables) {
+ postMessage(out, transfers);
+ } else {
+ postMessage(out);
+ }
+ });
+ }
+ });
+
+}
+proxy = new OGVWorkerSupport([
+ 'loadedMetadata',
+ 'audioFormat',
+ 'audioBuffer'
+], {
+ init: function(args, callback) {
+ this.target.init(callback);
+ },
+
+ processHeader: function(args, callback) {
+ this.target.processHeader(args[0], function(ok) {
+ callback([ok]);
+ });
+ },
+
+ processAudio: function(args, callback) {
+ this.target.processAudio(args[0], function(ok) {
+ callback([ok]);
+ });
+ }
+});
+this.OGVVersion = "1.0-20150904182230-dd3c8e8";
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-worker-video.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-worker-video.js
new file mode 100644
index 00000000..3afd769b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-worker-video.js
@@ -0,0 +1,317 @@
+(function() {
+ var global = this;
+
+ var scriptMap = {
+ OGVDemuxerOgg: 'ogv-demuxer-ogg.js',
+ OGVDemuxerWebM: 'ogv-demuxer-webm.js',
+ OGVDecoderAudioOpus: 'ogv-decoder-audio-opus.js',
+ OGVDecoderAudioVorbis: 'ogv-decoder-audio-vorbis.js',
+ OGVDecoderVideoTheora: 'ogv-decoder-video-theora.js',
+ OGVDecoderVideoVP8: 'ogv-decoder-video-vp8.js'
+ };
+
+ var proxyMap = {
+ OGVDecoderAudioOpus: 'OGVDecoderAudioProxy',
+ OGVDecoderAudioVorbis: 'OGVDecoderAudioProxy',
+ OGVDecoderVideoTheora: 'OGVDecoderVideoProxy',
+ OGVDecoderVideoVP8: 'OGVDecoderVideoProxy'
+ };
+ var workerMap = {
+ OGVDecoderAudioProxy: 'ogv-worker-audio.js',
+ OGVDecoderVideoProxy: 'ogv-worker-video.js'
+ };
+
+ function urlForClass(className) {
+ var scriptName = scriptMap[className];
+ if (scriptName) {
+ return urlForScript(scriptName);
+ } else {
+ throw new Error('asked for URL for unknown class ' + className);
+ }
+ };
+
+ function urlForScript(scriptName) {
+ if (scriptName) {
+ var base = OGVLoader.base;
+ if (base) {
+ base += '/';
+ }
+ return base + scriptName + '?version=' + encodeURIComponent(OGVVersion);
+ } else {
+ throw new Error('asked for URL for unknown script ' + scriptName);
+ }
+ };
+
+ var scriptStatus = {},
+ scriptCallbacks = {};
+ function loadWebScript(src, callback) {
+ if (scriptStatus[src] == 'done') {
+ callback();
+ } else if (scriptStatus[src] == 'loading') {
+ scriptCallbacks[src].push(callback);
+ } else {
+ scriptStatus[src] = 'loading';
+ scriptCallbacks[src] = [callback];
+
+ var scriptNode = document.createElement('script');
+ function done(event) {
+ var callbacks = scriptCallbacks[src];
+ delete scriptCallbacks[src];
+ scriptStatus[src] = 'done';
+
+ callbacks.forEach(function(cb) {
+ cb();
+ });
+ }
+ scriptNode.addEventListener('load', done);
+ scriptNode.addEventListener('error', done);
+ scriptNode.src = src;
+ document.querySelector('head').appendChild(scriptNode);
+ }
+ }
+
+ function defaultBase() {
+ if (typeof global.window === 'object') {
+
+ // for browser, try to autodetect
+ var scriptNodes = document.querySelectorAll('script'),
+ regex = /^(?:(.*)\/)ogv(?:-support)?\.js(?:\?|#|$)/,
+ path;
+ for (var i = 0; i < scriptNodes.length; i++) {
+ path = scriptNodes[i].getAttribute('src');
+ if (path) {
+ matches = path.match(regex);
+ if (matches) {
+ return matches[1];
+ }
+ }
+ }
+
+ } else {
+
+ // for workers, assume current directory
+ // if not a worker, too bad.
+ return '';
+
+ }
+ }
+
+ OGVLoader = {
+ base: defaultBase(),
+
+ loadClass: function(className, callback, options) {
+ options = options || {};
+ if (options.worker) {
+ this.workerProxy(className, callback);
+ } else if (typeof global[className] === 'function') {
+ // already loaded!
+ callback(global[className]);
+ } else if (typeof global.window === 'object') {
+ loadWebScript(urlForClass(className), function() {
+ callback(global[className]);
+ });
+ } else if (typeof global.importScripts === 'function') {
+ // worker has convenient sync importScripts
+ global.importScripts(urlForClass(className));
+ callback(global[className]);
+ }
+ },
+
+ workerProxy: function(className, callback) {
+ var proxyClass = proxyMap[className],
+ workerScript = workerMap[proxyClass];
+
+ if (!proxyClass) {
+ throw new Error('Requested worker for class with no proxy: ' + className);
+ }
+ if (!workerScript) {
+ throw new Error('Requested worker for class with no worker: ' + className);
+ }
+
+ this.loadClass(proxyClass, function(classObj) {
+ var construct = function(options) {
+ var worker = new Worker(urlForScript(workerScript));
+ return new classObj(worker, className, options);
+ };
+ callback(construct);
+ });
+ }
+ };
+})();
+/**
+ * Web Worker wrapper for codec fun
+ */
+function OGVWorkerSupport(propList, handlers) {
+
+ var transferables = (function() {
+ var buffer = new ArrayBuffer(1024),
+ bytes = new Uint8Array(buffer);
+ try {
+ postMessage({
+ action: 'transferTest',
+ bytes: bytes
+ }, [buffer]);
+ if (buffer.byteLength) {
+ // No transferable support
+ return false;
+ } else {
+ return true;
+ }
+ } catch (e) {
+ return false;
+ }
+ })();
+
+ var self = this;
+ self.target = null;
+
+ var sentProps = {};
+
+ function copyObject(obj) {
+ var copy = {};
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ copy[prop] = obj[prop];
+ }
+ }
+ return copy;
+ }
+
+ function copyAudioBuffer(data) {
+ if (data == null) {
+ return null;
+ } else {
+ // Array of Float32Arrays
+ var copy = [];
+ for (var i = 0; i < data.length; i++) {
+ copy[i] = new Float32Array(data[i]);
+ }
+ return copy;
+ }
+ }
+
+ function copyByteArray(bytes) {
+ var heap = bytes.buffer;
+ if (typeof heap.slice === 'function') {
+ var extract = heap.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
+ return new Uint8Array(extract);
+ } else {
+ // Hella slow in IE 10/11!
+ // But only game in town on IE 10.
+ return new Uint8Array(bytes);
+ }
+ }
+
+ function copyFrameBuffer(buffer) {
+ if (buffer == null) {
+ return null;
+ } else {
+ var copy = copyObject(buffer);
+ copy.bytesY = copyByteArray(buffer.bytesY);
+ copy.bytesCb = copyByteArray(buffer.bytesCb);
+ copy.bytesCr = copyByteArray(buffer.bytesCr);
+ return copy;
+ }
+ }
+
+ handlers.construct = function(args, callback) {
+ var className = args[0],
+ options = args[1];
+
+ OGVLoader.loadClass(className, function(classObj) {
+ self.target = new classObj(options);
+ callback();
+ });
+ };
+
+ addEventListener('message', function workerOnMessage(event) {
+ var data = event.data;
+
+ if (data && data.action == 'transferTest') {
+ // ignore
+ return;
+ }
+
+ if (typeof data !== 'object' || typeof data.action !== 'string' || typeof data.callbackId !== 'string' || typeof data.args !== 'object') {
+ console.log('invalid message data', data);
+ } else if (!(data.action in handlers)) {
+ console.log('invalid message action', data.action);
+ } else {
+ handlers[data.action].call(self, data.args, function(args) {
+ args = args || [];
+
+ // Collect and send any changed properties...
+ var props = {},
+ transfers = [];
+ propList.forEach(function(propName) {
+ var propVal = self.target[propName];
+
+ if (sentProps[propName] !== propVal) {
+ // Save this value for later reference...
+ sentProps[propName] = propVal;
+
+ if (propName == 'duration' && isNaN(propVal) && isNaN(sentProps[propName])) {
+ // NaN is not === itself. Nice!
+ // no need to update it here.
+ } else if (propName == 'audioBuffer') {
+ // Don't send the entire emscripten heap!
+ propVal = copyAudioBuffer(propVal);
+ props[propName] = propVal;
+ if (propVal) {
+ for (i = 0; i < propVal.length; i++) {
+ transfers.push(propVal[i].buffer);
+ }
+ }
+ } else if (propName == 'frameBuffer') {
+ // Don't send the entire emscripten heap!
+ propVal = copyFrameBuffer(propVal);
+ props[propName] = propVal;
+ if (propVal) {
+ transfers.push(propVal.bytesY.buffer);
+ transfers.push(propVal.bytesCb.buffer);
+ transfers.push(propVal.bytesCr.buffer);
+ }
+ } else {
+ props[propName] = propVal;
+ }
+ }
+ });
+
+ var out = {
+ action: 'callback',
+ callbackId: data.callbackId,
+ args: args,
+ props: props
+ };
+ if (transferables) {
+ postMessage(out, transfers);
+ } else {
+ postMessage(out);
+ }
+ });
+ }
+ });
+
+}
+proxy = new OGVWorkerSupport([
+ 'loadedMetadata',
+ 'videoFormat',
+ 'frameBuffer'
+], {
+ init: function(args, callback) {
+ this.target.init(callback);
+ },
+
+ processHeader: function(args, callback) {
+ this.target.processHeader(args[0], function(ok) {
+ callback([ok]);
+ });
+ },
+
+ processFrame: function(args, callback) {
+ this.target.processFrame(args[0], function(ok) {
+ callback([ok]);
+ });
+ }
+});
+this.OGVVersion = "1.0-20150904182230-dd3c8e8";
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv.js
new file mode 100644
index 00000000..a29b4b3b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv.js
@@ -0,0 +1,3966 @@
+//
+// -- ogv.js
+// https://github.com/brion/ogv.js
+// Copyright (c) 2013-2015 Brion Vibber
+//
+
+(function() {
+
+// -- OGVLoader.js
+
+(function() {
+ var global = this;
+
+ var scriptMap = {
+ OGVDemuxerOgg: 'ogv-demuxer-ogg.js',
+ OGVDemuxerWebM: 'ogv-demuxer-webm.js',
+ OGVDecoderAudioOpus: 'ogv-decoder-audio-opus.js',
+ OGVDecoderAudioVorbis: 'ogv-decoder-audio-vorbis.js',
+ OGVDecoderVideoTheora: 'ogv-decoder-video-theora.js',
+ OGVDecoderVideoVP8: 'ogv-decoder-video-vp8.js'
+ };
+
+ var proxyMap = {
+ OGVDecoderAudioOpus: 'OGVDecoderAudioProxy',
+ OGVDecoderAudioVorbis: 'OGVDecoderAudioProxy',
+ OGVDecoderVideoTheora: 'OGVDecoderVideoProxy',
+ OGVDecoderVideoVP8: 'OGVDecoderVideoProxy'
+ };
+ var workerMap = {
+ OGVDecoderAudioProxy: 'ogv-worker-audio.js',
+ OGVDecoderVideoProxy: 'ogv-worker-video.js'
+ };
+
+ function urlForClass(className) {
+ var scriptName = scriptMap[className];
+ if (scriptName) {
+ return urlForScript(scriptName);
+ } else {
+ throw new Error('asked for URL for unknown class ' + className);
+ }
+ };
+
+ function urlForScript(scriptName) {
+ if (scriptName) {
+ var base = OGVLoader.base;
+ if (base) {
+ base += '/';
+ }
+ return base + scriptName + '?version=' + encodeURIComponent(OGVVersion);
+ } else {
+ throw new Error('asked for URL for unknown script ' + scriptName);
+ }
+ };
+
+ var scriptStatus = {},
+ scriptCallbacks = {};
+ function loadWebScript(src, callback) {
+ if (scriptStatus[src] == 'done') {
+ callback();
+ } else if (scriptStatus[src] == 'loading') {
+ scriptCallbacks[src].push(callback);
+ } else {
+ scriptStatus[src] = 'loading';
+ scriptCallbacks[src] = [callback];
+
+ var scriptNode = document.createElement('script');
+ function done(event) {
+ var callbacks = scriptCallbacks[src];
+ delete scriptCallbacks[src];
+ scriptStatus[src] = 'done';
+
+ callbacks.forEach(function(cb) {
+ cb();
+ });
+ }
+ scriptNode.addEventListener('load', done);
+ scriptNode.addEventListener('error', done);
+ scriptNode.src = src;
+ document.querySelector('head').appendChild(scriptNode);
+ }
+ }
+
+ function defaultBase() {
+ if (typeof global.window === 'object') {
+
+ // for browser, try to autodetect
+ var scriptNodes = document.querySelectorAll('script'),
+ regex = /^(?:(.*)\/)ogv(?:-support)?\.js(?:\?|#|$)/,
+ path;
+ for (var i = 0; i < scriptNodes.length; i++) {
+ path = scriptNodes[i].getAttribute('src');
+ if (path) {
+ matches = path.match(regex);
+ if (matches) {
+ return matches[1];
+ }
+ }
+ }
+
+ } else {
+
+ // for workers, assume current directory
+ // if not a worker, too bad.
+ return '';
+
+ }
+ }
+
+ OGVLoader = {
+ base: defaultBase(),
+
+ loadClass: function(className, callback, options) {
+ options = options || {};
+ if (options.worker) {
+ this.workerProxy(className, callback);
+ } else if (typeof global[className] === 'function') {
+ // already loaded!
+ callback(global[className]);
+ } else if (typeof global.window === 'object') {
+ loadWebScript(urlForClass(className), function() {
+ callback(global[className]);
+ });
+ } else if (typeof global.importScripts === 'function') {
+ // worker has convenient sync importScripts
+ global.importScripts(urlForClass(className));
+ callback(global[className]);
+ }
+ },
+
+ workerProxy: function(className, callback) {
+ var proxyClass = proxyMap[className],
+ workerScript = workerMap[proxyClass];
+
+ if (!proxyClass) {
+ throw new Error('Requested worker for class with no proxy: ' + className);
+ }
+ if (!workerScript) {
+ throw new Error('Requested worker for class with no worker: ' + className);
+ }
+
+ this.loadClass(proxyClass, function(classObj) {
+ var construct = function(options) {
+ var worker = new Worker(urlForScript(workerScript));
+ return new classObj(worker, className, options);
+ };
+ callback(construct);
+ });
+ }
+ };
+})();
+
+
+// -- StreamFile.js
+
+/**
+ * Quickie wrapper around XHR to fetch a file as array buffer chunks.
+ *
+ * Call streamFile.readBytes() after an onread event's data has been
+ * processed to trigger the next read.
+ *
+ * IE 10: uses MSStream / MSStreamReader for true streaming
+ * Firefox: uses moz-chunked-arraybuffer to buffer & deliver during download
+ * Safari, Chrome: uses binary string to buffer & deliver during download
+ *
+ * @author Brion Vibber <brion@pobox.com>
+ * @copyright 2014
+ * @license MIT-style
+ */
+function StreamFile(options) {
+ var self = this,
+ url = options.url,
+ started = false,
+ onstart = options.onstart || function(){},
+ onbuffer = options.onbuffer || function(){},
+ onread = options.onread || function(){},
+ ondone = options.ondone || function(){},
+ onerror = options.onerror || function(){},
+ bufferSize = options.bufferSize || 8192,
+ minBufferSize = options.minBufferSize || 65536,
+ seekPosition = options.seekPosition || 0,
+ bufferPosition = seekPosition,
+ chunkSize = options.chunkSize || 1024 * 1024, // read/buffer up to a megabyte at a time
+ waitingForInput = false,
+ doneBuffering = false,
+ bytesTotal = 0,
+ bytesRead = 0,
+ buffers = [],
+ cachever = 0,
+ responseHeaders = {};
+
+
+
+ // -- internal private methods
+ var internal = {
+ /**
+ * @var {XMLHttpRequest}
+ */
+ xhr: null,
+
+ /**
+ * Test if a given responseType value is valid on an XHR
+ *
+ * @return boolean
+ */
+ tryMethod: function(rt) {
+ var xhr = new XMLHttpRequest();
+ xhr.open("GET", url);
+ try {
+ // Set the response type and see if it explodes!
+ xhr.responseType = rt;
+ } catch (e) {
+ // Safari 6 throws a DOM Exception on invalid setting
+ return false;
+ }
+ // Other browsers just don't accept the setting, so check
+ // whether it made it through.
+ return (xhr.responseType == rt);
+ },
+
+ setBytesTotal: function(xhr) {
+ if (xhr.status == 206) {
+ bytesTotal = internal.getXHRRangeTotal(xhr);
+ } else {
+ var contentLength = xhr.getResponseHeader('Content-Length');
+ if (contentLength === null || contentLength === '') {
+ // Unknown file length... maybe streaming live?
+ bytesTotal = 0;
+ } else {
+ bytesTotal = parseInt(contentLength, 10);
+ }
+ }
+ },
+
+ // Save HTTP response headers from the HEAD request for later
+ processResponseHeaders: function(xhr) {
+ responseHeaders = {};
+ var allResponseHeaders = xhr.getAllResponseHeaders(),
+ headerLines = allResponseHeaders.split(/\n/);
+ headerLines.forEach(function(line) {
+ var bits = line.split(/:\s*/, 2);
+ if (bits.length > 1) {
+ var name = bits[0].toLowerCase(),
+ value = bits[1];
+ responseHeaders[name] = value;
+ }
+ });
+ },
+
+ openXHR: function() {
+ var getUrl = url;
+ if (cachever) {
+ //
+ // Safari sometimes messes up and gives us the wrong chunk.
+ // Seems to be a general problem with Safari and cached XHR ranges.
+ //
+ // Interestingly, it allows you to request _later_ ranges successfully,
+ // but when requesting _earlier_ ranges it returns the latest one retrieved.
+ // So we only need to update the cache-buster when we rewind.
+ //
+ // https://bugs.webkit.org/show_bug.cgi?id=82672
+ //
+ getUrl += '?ogvjs_cachever=' + cachever;
+ }
+
+ var xhr = internal.xhr = new XMLHttpRequest();
+ xhr.open("GET", getUrl);
+
+ internal.setXHROptions(xhr);
+
+ var range = null;
+ if (seekPosition || chunkSize) {
+ range = 'bytes=' + seekPosition + '-';
+ }
+ if (chunkSize) {
+ if (bytesTotal) {
+ range += Math.min(seekPosition + chunkSize, bytesTotal) - 1;
+ } else {
+ range += (seekPosition + chunkSize) - 1;
+ }
+ }
+ if (range !== null) {
+ xhr.setRequestHeader('Range', range);
+ }
+
+ bytesRead = 0;
+
+ xhr.onreadystatechange = function(event) {
+ if (xhr.readyState == 2) {
+ if (xhr.status == 206) {
+ var foundPosition = internal.getXHRRangeStart(xhr);
+ if (seekPosition != foundPosition) {
+ //
+ // Safari sometimes messes up and gives us the wrong chunk.
+ // Seems to be a general problem with Safari and cached XHR ranges.
+ //
+ // Interestingly, it allows you to request _later_ ranges successfully,
+ // but when requesting _earlier_ ranges it returns the latest one retrieved.
+ // So we only need to update the cache-buster when we rewind and actually
+ // get an incorrect range.
+ //
+ // https://bugs.webkit.org/show_bug.cgi?id=82672
+ //
+ console.log('Expected start at ' + seekPosition + ' but got ' + foundPosition +
+ '; working around Safari range caching bug: https://bugs.webkit.org/show_bug.cgi?id=82672');
+ cachever++;
+ internal.abortXHR(xhr);
+ internal.openXHR();
+ return;
+ }
+ }
+ if (!started) {
+ internal.setBytesTotal(xhr);
+ internal.processResponseHeaders(xhr);
+ started = true;
+ onstart();
+ }
+ //internal.onXHRHeadersReceived(xhr);
+ // @todo check that partial content was supported if relevant
+ } else if (xhr.readyState == 3) {
+ internal.onXHRLoading(xhr);
+ } else if (xhr.readyState == 4) {
+ // Complete.
+ internal.onXHRDone(xhr);
+ }
+ };
+
+ xhr.send();
+ },
+
+ getXHRRangeMatches: function(xhr) {
+ // Note Content-Range must be whitelisted for CORS requests
+ var contentRange = xhr.getResponseHeader('Content-Range');
+ return contentRange && contentRange.match(/^bytes (\d+)-(\d+)\/(\d+)/);
+ },
+
+ getXHRRangeStart: function(xhr) {
+ var matches = internal.getXHRRangeMatches(xhr);
+ if (matches) {
+ return parseInt(matches[1], 10);
+ } else {
+ return 0;
+ }
+ },
+
+ getXHRRangeTotal: function(xhr) {
+ var matches = internal.getXHRRangeMatches(xhr);
+ if (matches) {
+ return parseInt(matches[3], 10);
+ } else {
+ return 0;
+ }
+ },
+
+ setXHROptions: function(xhr) {
+ throw new Error('abstract function');
+ },
+
+ /*
+ onXHRHeadersReceived: function(xhr) {
+ if (xhr.status >= 400) {
+ // errrorrrrrrr
+ console.log("HTTP " + xhr.status + ": " +xhr.statusText);
+ onerror();
+ xhr.abort();
+ } else {
+ internal.setBytesTotal(xhr);
+ internal.processResponseHeaders(xhr);
+ started = true;
+ onstart();
+ }
+ },
+ */
+
+ onXHRLoading: function(xhr) {
+ throw new Error('abstract function');
+ },
+
+ onXHRDone: function(xhr) {
+ doneBuffering = true;
+ },
+
+ abortXHR: function(xhr) {
+ xhr.onreadystatechange = null;
+ xhr.abort();
+ },
+
+ bufferData: function(buffer) {
+ if (buffer) {
+ buffers.push(buffer);
+ onbuffer();
+
+ internal.readNextChunk();
+ }
+ },
+
+ bytesBuffered: function() {
+ var bytes = 0;
+ buffers.forEach(function(buffer) {
+ bytes += buffer.byteLength;
+ });
+ return bytes;
+ },
+
+ dataToRead: function() {
+ return internal.bytesBuffered() > 0;
+ },
+
+ popBuffer: function() {
+ var bufferOut = new ArrayBuffer(bufferSize),
+ bytesOut = new Uint8Array(bufferOut),
+ byteLength = 0;
+
+ function stuff(bufferIn) {
+ var bytesIn = new Uint8Array(bufferIn);
+ bytesOut.set(bytesIn, byteLength);
+ byteLength += bufferIn.byteLength;
+ }
+
+ while (byteLength < minBufferSize) {
+ var needBytes = minBufferSize - byteLength,
+ nextBuffer = buffers.shift();
+ if (!nextBuffer) {
+ break;
+ }
+
+ if (needBytes >= nextBuffer.byteLength) {
+ // if it fits, it sits
+ stuff(nextBuffer);
+ } else {
+ // Split the buffer and requeue the rest
+ var croppedBuffer = nextBuffer.slice(0, needBytes),
+ remainderBuffer = nextBuffer.slice(needBytes);
+ buffers.unshift(remainderBuffer);
+ stuff(croppedBuffer);
+ break;
+ }
+ }
+
+ bytesRead += byteLength;
+ bufferPosition += byteLength;
+ return bufferOut.slice(0, byteLength);
+ },
+
+ clearReadState: function() {
+ bytesRead = 0;
+ doneBuffering = false;
+ waitingForInput = true;
+ },
+
+ clearBuffers: function() {
+ internal.clearReadState();
+ buffers.splice(0, buffers.length);
+ bufferPosition = seekPosition;
+ },
+
+ // Read the next binary buffer out of the buffered data
+ readNextChunk: function() {
+ if (waitingForInput) {
+ waitingForInput = false;
+ onread(internal.popBuffer());
+ if (doneBuffering && !internal.dataToRead()) {
+ internal.onReadDone();
+ }
+ }
+ },
+
+ onReadDone: function() {
+ ondone();
+ },
+
+ // See if we can seek within already-buffered data
+ quickSeek: function(pos) {
+ return false;
+ }
+
+ };
+
+ // -- Public methods
+ self.readBytes = function() {
+ if (internal.dataToRead()) {
+ var buffer = internal.popBuffer();
+ onread(buffer);
+ if (doneBuffering && self.bytesBuffered < Math.min(bufferPosition + chunkSize, self.bytesTotal)) {
+ seekPosition += chunkSize;
+ internal.clearReadState();
+ internal.openXHR();
+ }
+ } else if (doneBuffering) {
+ // We're out of data!
+ internal.onReadDone();
+ } else {
+ // Nothing queued...
+ waitingForInput = true;
+ }
+ };
+
+ self.abort = function() {
+ if (internal.xhr) {
+ internal.abortXHR(internal.xhr);
+ internal.xhr = null;
+ internal.clearBuffers();
+ }
+ };
+
+ self.seek = function(bytePosition) {
+ if (internal.quickSeek(bytePosition)) {
+ //console.log('quick seek successful');
+ } else {
+ self.abort();
+ seekPosition = bytePosition;
+ internal.clearBuffers();
+ internal.openXHR();
+ }
+ };
+
+ self.getResponseHeader = function(headerName) {
+ var lowerName = headerName.toLowerCase(),
+ value = responseHeaders[lowerName];
+ if (value === undefined) {
+ return null;
+ } else {
+ return value;
+ }
+ };
+
+ // -- public properties
+ Object.defineProperty(self, 'bytesTotal', {
+ get: function() {
+ return bytesTotal;
+ }
+ });
+
+ Object.defineProperty(self, 'bytesBuffered', {
+ get: function() {
+ return bufferPosition + internal.bytesBuffered();
+ }
+ });
+
+ Object.defineProperty(self, 'bytesRead', {
+ get: function() {
+ return seekPosition + bytesRead;
+ }
+ });
+
+ Object.defineProperty(self, 'seekable', {
+ get: function() {
+ return (self.bytesTotal > 0);
+ }
+ });
+
+ // Handy way to call super functions
+ var orig = {};
+ for (var prop in internal) {
+ orig[prop] = internal[prop];
+ }
+
+ // -- Backend selection and method overrides
+ if (internal.tryMethod('moz-chunked-arraybuffer')) {
+ internal.setXHROptions = function(xhr) {
+ xhr.responseType = 'moz-chunked-arraybuffer';
+
+ xhr.onprogress = function() {
+ // xhr.response is a per-chunk ArrayBuffer
+ internal.bufferData(xhr.response);
+ };
+ };
+
+ internal.abortXHR = function(xhr) {
+ xhr.onprogress = null;
+ orig.abortXHR(xhr);
+ };
+
+ internal.onXHRLoading = function(xhr) {
+ // we have to get from the 'progress' event
+ };
+
+ } else if (internal.tryMethod('ms-stream')) {
+ // IE 10 supports returning a Stream from XHR.
+
+ // Don't bother reading in chunks, MSStream handles it for us
+ chunkSize = 0;
+
+ var stream, streamReader;
+ var restarted = false;
+
+ internal.setXHROptions = function(xhr) {
+ xhr.responseType = 'ms-stream';
+ };
+
+ internal.abortXHR = function(xhr) {
+ restarted = true;
+ if (streamReader) {
+ streamReader.abort();
+ streamReader = null;
+ }
+ if (stream) {
+ stream.msClose();
+ stream = null;
+ }
+ orig.abortXHR(xhr);
+ };
+
+ internal.onXHRLoading = function(xhr) {
+ // Transfer us over to the StreamReader...
+ stream = xhr.response;
+ xhr.onreadystatechange = null;
+ if (waitingForInput) {
+ waitingForInput = false;
+ self.readBytes();
+ }
+ };
+
+ internal.bytesBuffered = function() {
+ // We don't know how much ahead is buffered, it's opaque.
+ // Just return what we've read.
+ return 0;
+ };
+
+ self.readBytes = function() {
+ if (stream) {
+ streamReader = new MSStreamReader();
+ streamReader.onload = function(event) {
+ var buffer = event.target.result,
+ len = buffer.byteLength;
+ if (len > 0) {
+ bytesRead += len;
+ bufferPosition += len;
+ onread(buffer);
+ } else {
+ // Zero length means end of stream.
+ ondone();
+ }
+ };
+ streamReader.onerror = function(event) {
+ onerror('mystery error streaming');
+ };
+ streamReader.readAsArrayBuffer(stream, bufferSize);
+ } else {
+ waitingForInput = true;
+ }
+ };
+
+ } else if ((new XMLHttpRequest()).overrideMimeType !== undefined) {
+
+ // Use old binary string method since we can read reponseText
+ // progressively and extract ArrayBuffers from that.
+
+ internal.setXHROptions = function(xhr) {
+ xhr.responseType = "text";
+ xhr.overrideMimeType('text/plain; charset=x-user-defined');
+ };
+
+ var lastPosition = 0;
+
+ // Is there a better way to do this conversion? :(
+ var stringToArrayBuffer = function(chunk) {
+ var len = chunk.length,
+ buffer = new ArrayBuffer(len),
+ bytes = new Uint8Array(buffer);
+ for (var i = 0; i < len; i++) {
+ bytes[i] = chunk.charCodeAt(i);
+ }
+ return buffer;
+ };
+
+ internal.clearReadState = function() {
+ orig.clearReadState();
+ lastPosition = 0;
+ };
+
+ internal.onXHRLoading = function(xhr) {
+ // xhr.responseText is a binary string of entire file so far
+ var str = xhr.responseText;
+ if (lastPosition < str.length) {
+ var chunk = str.slice(lastPosition),
+ buffer = stringToArrayBuffer(chunk);
+ lastPosition = str.length;
+ internal.bufferData(buffer);
+ }
+ };
+
+ /*
+ internal.quickSeek = function(pos) {
+ var bufferedPos = pos - seekPosition;
+ if (bufferedPos < 0) {
+ return false;
+ } else if (bufferedPos >= internal.xhr.responseText.length) {
+ return false;
+ } else {
+ lastPosition = bufferedPos;
+ bytesRead = lastPosition;
+ setTimeout(function() {
+ onbuffer()
+ }, 0);
+ return true;
+ }
+ };
+ */
+ } else {
+ throw new Error("No streaming HTTP input method found.");
+ }
+
+ internal.openXHR();
+}
+
+
+// -- AudioFeeder.js
+
+var AudioFeeder;
+
+(function() {
+ var global = this,
+ AudioContext = global.AudioContext || global.webkitAudioContext;
+
+ /**
+ * Object that we can throw audio data into and have it drain out.
+ *
+ * Because changing the number of channels on the fly is hard, hardcoding
+ * to 2 output channels. That's also all we can do on IE with Flash output.
+ *
+ * @param options: dictionary of config settings:
+ * 'base' - Base URL to find additional resources in,
+ * such as the Flash audio output shim
+ */
+ AudioFeeder = function(options) {
+ var self = this;
+ options = options || {};
+
+ // Look for W3C Audio API
+ if (!AudioContext) {
+ // use Flash fallback
+ var flashOptions = {};
+ if (typeof options.base === 'string') {
+ flashOptions.swf = options.base + '/dynamicaudio.swf?version=' + OGVVersion;
+ }
+ this.flashaudio = new DynamicAudio( flashOptions );
+ }
+
+ var bufferSize = this.bufferSize = 4096,
+ channels = 0, // call init()!
+ rate = 0; // call init()!
+
+ // Always create stereo output. For iOS we have to set this stuff up
+ // before we've actually gotten the info from the codec because we
+ // must initialize from a UI event. Bah!
+ var outputChannels = 2;
+
+ function freshBuffer() {
+ var buffer = [];
+ for (var channel = 0; channel < outputChannels; channel++) {
+ buffer[channel] = new Float32Array(bufferSize);
+ }
+ return buffer;
+ }
+
+ var buffers = [],
+ context,
+ node,
+ pendingBuffer = freshBuffer(),
+ pendingPos = 0,
+ muted = false,
+ queuedTime = 0,
+ playbackTimeAtBufferTail = -1,
+ targetRate,
+ dropped = 0,
+ delayedTime = 0;
+
+ if(AudioContext) {
+ if (typeof options.audioContext !== 'undefined') {
+ // We were passed a pre-existing AudioContext object,
+ // in the hopes this gets around iOS's weird activation rules.
+ context = options.audioContext;
+ } else {
+ AudioFeeder.initSharedAudioContext();
+ context = AudioFeeder.sharedAudioContext;
+ }
+ playbackTimeAtBufferTail = context.currentTime;
+
+ if (context.createScriptProcessor) {
+ node = context.createScriptProcessor(bufferSize, 0, outputChannels);
+ } else if (context.createJavaScriptNode) {
+ node = context.createJavaScriptNode(bufferSize, 0, outputChannels);
+ } else {
+ throw new Error("Bad version of web audio API?");
+ }
+ targetRate = this.targetRate = context.sampleRate;
+ } else {
+ targetRate = this.targetRate = 44100; // flash fallback
+ }
+
+ function popNextBuffer() {
+ // hack hack
+ // fixme: grab the right number of samples
+ // and... rescale
+ if (buffers.length > 0) {
+ return buffers.shift();
+ }
+ }
+
+ function audioProcess(event) {
+ var channel, input, output, i, playbackTime;
+ if (typeof event.playbackTime === 'number') {
+ playbackTime = event.playbackTime;
+ } else {
+ // Safari 6.1 hack
+ playbackTime = context.currentTime + (bufferSize / targetRate);
+ }
+
+ var expectedTime = playbackTimeAtBufferTail;
+ if (expectedTime < playbackTime) {
+ // we may have lost some time while something ran too slow
+ delayedTime += (playbackTime - expectedTime);
+ }
+
+ var inputBuffer = popNextBuffer(bufferSize);
+ if (!inputBuffer) {
+ // We might be in a throttled background tab; go ping the decoder
+ // and let it know we need more data now!
+ if (self.onstarved) {
+ self.onstarved();
+ inputBuffer = popNextBuffer(bufferSize);
+ }
+ }
+
+ // If we haven't got enough data, write a buffer of of silence to
+ // both channels
+ if (!inputBuffer) {
+ for (channel = 0; channel < outputChannels; channel++) {
+ output = event.outputBuffer.getChannelData(channel);
+ for (i = 0; i < bufferSize; i++) {
+ output[i] = 0;
+ }
+ }
+ dropped++;
+ return;
+ }
+
+ var volume = (muted ? 0 : 1);
+ for (channel = 0; channel < outputChannels; channel++) {
+ input = inputBuffer[channel];
+ output = event.outputBuffer.getChannelData(channel);
+ for (i = 0; i < Math.min(bufferSize, input.length); i++) {
+ output[i] = input[i] * volume;
+ }
+ }
+ queuedTime += (bufferSize / context.sampleRate);
+ playbackTimeAtBufferTail = playbackTime + (bufferSize / context.sampleRate);
+ }
+
+ /**
+ * This is horribly naive and wrong.
+ * Replace me with a better algo!
+ */
+ function resample(samples) {
+ if (rate == targetRate && channels == outputChannels) {
+ return samples;
+ } else {
+ var newSamples = [];
+ for (var channel = 0; channel < outputChannels; channel++) {
+ var inputChannel = channel;
+ if (channel >= channels) {
+ inputChannel = 0;
+ }
+ var input = samples[inputChannel],
+ output = new Float32Array(Math.round(input.length * targetRate / rate));
+ for (var i = 0; i < output.length; i++) {
+ output[i] = input[(i * rate / targetRate) | 0];
+ }
+ newSamples.push(output);
+ }
+ return newSamples;
+ }
+ }
+
+ /**
+ * Resampling, scaling and reordering for the Flash fallback.
+ * The Flash fallback expects 44.1 kHz, stereo
+ * Resampling: This is horribly naive and wrong.
+ * TODO: Replace me with a better algo!
+ */
+ function resampleFlash(samples) {
+ var sampleincr = rate / 44100;
+ var samplecount = (samples[0].length * (44100 / rate)) | 0;
+ var newSamples = new Int16Array(samplecount * 2);
+ var chanLeft = samples[0];
+ var chanRight = channels > 1 ? samples[1] : chanLeft;
+ var multiplier = 16384; // smaller than 32768 to allow some headroom from those floats
+ for(var s = 0; s < samplecount; s++) {
+ var idx = (s * sampleincr) | 0;
+ var idx_out = s * 2;
+ // Use a smaller
+ newSamples[idx_out] = chanLeft[idx] * multiplier;
+ newSamples[idx_out + 1] = chanRight[idx] * multiplier;
+ }
+ return newSamples;
+ }
+
+ function resampleFlashMuted(samples) {
+ // if muted: generate fitting number of samples for audio clock
+ var samplecount = (samples[0].length * (44100 / rate)) | 0;
+ return new Int16Array(samplecount * 2);
+ }
+
+
+ function pushSamples(samples) {
+ var firstChannel = samples[0],
+ sampleCount = firstChannel.length;
+ for (var i = 0; i < sampleCount; i++) {
+ for (var channel = 0; channel < outputChannels; channel++) {
+ pendingBuffer[channel][pendingPos] = samples[channel][i];
+ }
+ if (++pendingPos == bufferSize) {
+ buffers.push(pendingBuffer);
+ pendingPos = 0;
+ pendingBuffer = freshBuffer();
+ }
+ }
+ }
+
+ this.init = function(numChannels, sampleRate) {
+ // warning: can't change channels here reliably
+ rate = sampleRate;
+ channels = numChannels;
+ pendingBuffer = freshBuffer();
+ };
+
+ var hexDigits = ['0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
+ var hexBytes = [];
+ for (var i = 0; i < 256; i++) {
+ hexBytes[i] = hexDigits[(i & 0x0f)] +
+ hexDigits[(i & 0xf0) >> 4];
+ }
+ function hexString(buffer) {
+ var samples = new Uint8Array(buffer);
+ var digits = "",
+ len = samples.length;
+ for (var i = 0; i < len; i++) {
+ // Note that in IE 11 strong concatenation is twice as fast as
+ // the traditional make-an-array-and-join here.
+ digits += hexBytes[samples[i]];
+ }
+ return digits;
+ }
+
+ var flashBuffer = '',
+ flushTimeout = null;
+ function flushFlashBuffer() {
+ var chunk = flashBuffer;
+ if (self.flashaudio.flashElement.write) {
+ self.flashaudio.flashElement.write(chunk);
+ } else {
+ self.waitUntilReady(function() {
+ self.flashaudio.flashElement.write(chunk);
+ });
+ }
+ flashBuffer = '';
+ flushTimeout = null;
+ }
+ this.bufferData = function(samplesPerChannel) {
+ if(this.flashaudio) {
+ var resamples = !muted ? resampleFlash(samplesPerChannel) : resampleFlashMuted(samplesPerChannel);
+ var flashElement = this.flashaudio.flashElement;
+ if(resamples.length > 0) {
+ var str = hexString(resamples.buffer);
+ flashBuffer += str;
+ if (!flushTimeout) {
+ // consolidate multiple consecutive tiny buffers in one pass;
+ // pushing data to Flash is relatively expensive on slow machines
+ flushTimeout = setTimeout(flushFlashBuffer, 0);
+ }
+ }
+ } else if (buffers) {
+ var samples = resample(samplesPerChannel);
+ pushSamples(samples);
+ } else {
+ console.log('no valid whatsit');
+ self.close();
+ }
+ };
+
+ function samplesQueued() {
+ if (buffers) {
+ var numSamplesQueued = 0;
+ buffers.forEach(function(buffer) {
+ numSamplesQueued += buffer[0].length;
+ });
+
+ var bufferedSamples = numSamplesQueued;
+ var remainingSamples = Math.floor(Math.max(0, (playbackTimeAtBufferTail - context.currentTime)) * context.sampleRate);
+
+ return bufferedSamples + remainingSamples;
+ } else {
+ return 0;
+ }
+ }
+
+ var cachedFlashState = null,
+ cachedFlashTime = 0,
+ cachedFlashInterval = 40; // resync state no more often than every X ms
+
+ /**
+ * @return {
+ * playbackPosition: {number} seconds, with a system-provided base time
+ * samplesQueued: {int}
+ * dropped: {int}
+ * }
+ */
+ this.getPlaybackState = function() {
+ if (this.flashaudio) {
+ var flashElement = this.flashaudio.flashElement;
+ if (flashElement.write) {
+ var now = Date.now(),
+ delta = now - cachedFlashTime,
+ state;
+ if (cachedFlashState && delta < cachedFlashInterval) {
+ state = {
+ playbackPosition: cachedFlashState.playbackPosition + delta / 1000,
+ samplesQueued: cachedFlashState.samplesQueued - delta * targetRate / 1000,
+ dropped: cachedFlashState.dropped,
+ delayed: cachedFlashState.delayed
+ };
+ } else {
+ state = flashElement.getPlaybackState();
+ cachedFlashState = state;
+ cachedFlashTime = now;
+ }
+ state.samplesQueued += flashBuffer.length / 2;
+ return state;
+ } else {
+ //console.log('getPlaybackState USED TOO EARLY');
+ return {
+ playbackPosition: 0,
+ samplesQueued: 0,
+ dropped: 0,
+ delayed: 0
+ };
+ }
+ } else {
+ return {
+ playbackPosition: queuedTime - Math.max(0, playbackTimeAtBufferTail - context.currentTime),
+ samplesQueued: samplesQueued(),
+ dropped: dropped,
+ delayed: delayedTime
+ };
+ }
+ };
+
+ this.mute = function() {
+ this.muted = muted = true;
+ };
+
+ this.unmute = function() {
+ this.muted = muted = false;
+ };
+
+ this.close = function() {
+ this.stop();
+
+ if(this.flashaudio) {
+ var wrapper = this.flashaudio.flashWrapper;
+ wrapper.parentNode.removeChild(wrapper);
+ this.flashaudio = null;
+ }
+
+ context = null;
+ buffers = null;
+ };
+
+ this.waitUntilReady = function(callback) {
+ var times = 0,
+ maxTimes = 100;
+ function pingFlashPlugin() {
+ setTimeout(function doPingFlashPlugin() {
+ times++;
+ if (self.flashaudio && self.flashaudio.flashElement.write) {
+ callback(this);
+ } else if (times > maxTimes) {
+ console.log("Failed to initialize Flash audio shim");
+ self.close();
+ callback(null);
+ } else {
+ pingFlashPlugin();
+ }
+ }, 20);
+ }
+ if (self.flashaudio) {
+ pingFlashPlugin();
+ } else {
+ setTimeout(callback, 0);
+ }
+ };
+
+ this.start = function() {
+ if (this.flashaudio) {
+ this.flashaudio.flashElement.start();
+ } else {
+ node.onaudioprocess = audioProcess;
+ node.connect(context.destination);
+ playbackTimeAtBufferTail = context.currentTime;
+ }
+ };
+
+ this.stop = function() {
+ if (this.flashaudio) {
+ this.flashaudio.flashElement.stop();
+ } else {
+ if (node) {
+ node.onaudioprocess = null;
+ node.disconnect();
+ }
+ }
+ };
+
+ /**
+ * A callback when we find we're out of buffered data.
+ */
+ this.onstarved = null;
+ };
+
+ AudioFeeder.sharedAudioContext = null;
+ AudioFeeder.initSharedAudioContext = function() {
+ if (AudioFeeder.sharedAudioContext === null) {
+ if ( AudioContext ) {
+ // We're only allowed 4 contexts on many browsers
+ // and there's no way to discard them (!)...
+ var context = AudioFeeder.sharedAudioContext = new AudioContext(),
+ node;
+ if ( context.createScriptProcessor ) {
+ node = context.createScriptProcessor( 1024, 0, 2 );
+ } else if ( context.createJavaScriptNode ) {
+ node = context.createJavaScriptNode( 1024, 0, 2 );
+ } else {
+ throw new Error( "Bad version of web audio API?" );
+ }
+
+ // Don't actually run any audio, just start & stop the node
+ node.connect( context.destination );
+ node.disconnect();
+ }
+ }
+ };
+
+
+ /** Flash fallback **/
+
+ /*
+ The Flash fallback is based on https://github.com/an146/dynamicaudio.js
+
+ This is the contents of the LICENSE file:
+
+ Copyright (c) 2010, Ben Firshman
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * The names of its contributors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+ function DynamicAudio(args) {
+ if (this instanceof arguments.callee) {
+ if (typeof this.init === "function") {
+ this.init.apply(this, (args && args.callee) ? args : arguments);
+ }
+ } else {
+ return new arguments.callee(arguments);
+ }
+ }
+
+
+ DynamicAudio.nextId = 1;
+
+ DynamicAudio.prototype = {
+ nextId: null,
+ swf: 'dynamicaudio.swf?' + Math.random(),
+
+ flashWrapper: null,
+ flashElement: null,
+
+ init: function(opts) {
+ var self = this;
+ self.id = DynamicAudio.nextId++;
+
+ if (opts && typeof opts.swf !== 'undefined') {
+ self.swf = opts.swf;
+ }
+
+
+ self.flashWrapper = document.createElement('div');
+ self.flashWrapper.id = 'dynamicaudio-flashwrapper-'+self.id;
+ // Credit to SoundManager2 for this:
+ var s = self.flashWrapper.style;
+ s.position = 'fixed';
+ s.width = '11px'; // must be at least 6px for flash to run fast
+ s.height = '11px';
+ s.bottom = s.left = '0px';
+ s.overflow = 'hidden';
+ self.flashElement = document.createElement('div');
+ self.flashElement.id = 'dynamicaudio-flashelement-'+self.id;
+ self.flashWrapper.appendChild(self.flashElement);
+
+ document.body.appendChild(self.flashWrapper);
+
+ var id = self.flashElement.id;
+
+ self.flashWrapper.innerHTML = "<object id='"+id+"' width='10' height='10' type='application/x-shockwave-flash' data='"+self.swf+"' style='visibility: visible;'><param name='allowscriptaccess' value='always'></object>";
+ self.flashElement = document.getElementById(id);
+ },
+ };
+
+})();
+
+
+// -- FrameSink.js
+
+/**
+ * @param HTMLCanvasElement canvas
+ * @constructor
+ */
+function FrameSink(canvas, videoInfo) {
+ var self = this,
+ ctx = canvas.getContext('2d'),
+ imageData = null,
+ resampleCanvas = null,
+ resampleContext = null;
+
+
+/**
+ * Basic YCbCr->RGB conversion
+ *
+ * @author Brion Vibber <brion@pobox.com>
+ * @copyright 2014
+ * @license MIT-style
+ *
+ * @param ybcbr {bytesY, bytesCb, bytesCr, strideY, strideCb, strideCr, width, height, hdec, vdec}
+ * @param TypedArray output: CanvasPixelArray or Uint8ClampedArray to draw RGBA into
+ * Assumes that the output array already has alpha channel set to opaque.
+ */
+function convertYCbCr(ybcbr, output) {
+ var width = ybcbr.width,
+ height = ybcbr.height,
+ hdec = ybcbr.hdec,
+ vdec = ybcbr.vdec,
+ bytesY = ybcbr.bytesY,
+ bytesCb = ybcbr.bytesCb,
+ bytesCr = ybcbr.bytesCr,
+ strideY = ybcbr.strideY,
+ strideCb = ybcbr.strideCb,
+ strideCr = ybcbr.strideCr,
+ outStride = 4 * width,
+ YPtr = 0, Y0Ptr = 0, Y1Ptr = 0,
+ CbPtr = 0, CrPtr = 0,
+ outPtr = 0, outPtr0 = 0, outPtr1 = 0,
+ colorCb = 0, colorCr = 0,
+ multY = 0, multCrR = 0, multCbCrG = 0, multCbB = 0,
+ x = 0, y = 0, xdec = 0, ydec = 0;
+
+ if (hdec == 1 && vdec == 1) {
+ // Optimize for 4:2:0, which is most common
+ outPtr0 = 0;
+ outPtr1 = outStride;
+ ydec = 0;
+ for (y = 0; y < height; y += 2) {
+ Y0Ptr = y * strideY;
+ Y1Ptr = Y0Ptr + strideY;
+ CbPtr = ydec * strideCb;
+ CrPtr = ydec * strideCr;
+ for (x = 0; x < width; x += 2) {
+ colorCb = bytesCb[CbPtr++];
+ colorCr = bytesCr[CrPtr++];
+
+ // Quickie YUV conversion
+ // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.2020_conversion
+ // multiplied by 256 for integer-friendliness
+ multCrR = (409 * colorCr) - 57088;
+ multCbCrG = (100 * colorCb) + (208 * colorCr) - 34816;
+ multCbB = (516 * colorCb) - 70912;
+
+ multY = (298 * bytesY[Y0Ptr++]);
+ output[outPtr0++] = (multY + multCrR) >> 8;
+ output[outPtr0++] = (multY - multCbCrG) >> 8;
+ output[outPtr0++] = (multY + multCbB) >> 8;
+ outPtr0++;
+
+ multY = (298 * bytesY[Y0Ptr++]);
+ output[outPtr0++] = (multY + multCrR) >> 8;
+ output[outPtr0++] = (multY - multCbCrG) >> 8;
+ output[outPtr0++] = (multY + multCbB) >> 8;
+ outPtr0++;
+
+ multY = (298 * bytesY[Y1Ptr++]);
+ output[outPtr1++] = (multY + multCrR) >> 8;
+ output[outPtr1++] = (multY - multCbCrG) >> 8;
+ output[outPtr1++] = (multY + multCbB) >> 8;
+ outPtr1++;
+
+ multY = (298 * bytesY[Y1Ptr++]);
+ output[outPtr1++] = (multY + multCrR) >> 8;
+ output[outPtr1++] = (multY - multCbCrG) >> 8;
+ output[outPtr1++] = (multY + multCbB) >> 8;
+ outPtr1++;
+ }
+ outPtr0 += outStride;
+ outPtr1 += outStride;
+ ydec++;
+ }
+ } else {
+ outPtr = 0;
+ for (y = 0; y < height; y++) {
+ xdec = 0;
+ ydec = y >> vdec;
+ YPtr = y * strideY;
+ CbPtr = ydec * strideCb;
+ CrPtr = ydec * strideCr;
+
+ for (x = 0; x < width; x++) {
+ xdec = x >> hdec;
+ colorCb = bytesCb[CbPtr + xdec];
+ colorCr = bytesCr[CrPtr + xdec];
+
+ // Quickie YUV conversion
+ // https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.2020_conversion
+ // multiplied by 256 for integer-friendliness
+ multCrR = (409 * colorCr) - 57088;
+ multCbCrG = (100 * colorCb) + (208 * colorCr) - 34816;
+ multCbB = (516 * colorCb) - 70912;
+
+ multY = 298 * bytesY[YPtr++];
+ output[outPtr++] = (multY + multCrR) >> 8;
+ output[outPtr++] = (multY - multCbCrG) >> 8;
+ output[outPtr++] = (multY + multCbB) >> 8;
+ outPtr++;
+ }
+ }
+ }
+}
+
+
+ function initImageData(width, height) {
+ imageData = ctx.createImageData(width, height);
+
+ // Prefill the alpha to opaque
+ var data = imageData.data,
+ pixelCount = width * height * 4;
+ for (var i = 0; i < pixelCount; i += 4) {
+ data[i + 3] = 255;
+ }
+ }
+
+ function initResampleCanvas() {
+ resampleCanvas = document.createElement('canvas');
+ resampleCanvas.width = videoInfo.picWidth;
+ resampleCanvas.height = videoInfo.picHeight;
+ resampleContext = resampleCanvas.getContext('2d');
+ }
+
+ /**
+ * Actually draw a frame into the canvas.
+ */
+ self.drawFrame = function drawFrame(yCbCrBuffer) {
+ if (imageData === null ||
+ imageData.width != yCbCrBuffer.width ||
+ imageData.height != yCbCrBuffer.height) {
+ initImageData(yCbCrBuffer.width, yCbCrBuffer.height);
+ }
+ convertYCbCr(yCbCrBuffer, imageData.data);
+
+ var resample = (videoInfo.picWidth != videoInfo.displayWidth || videoInfo.picHeight != videoInfo.displayHeight);
+ if (resample) {
+ // hack for non-square aspect-ratio
+ // putImageData doesn't resample, so we have to draw in two steps.
+ if (!resampleCanvas) {
+ initResampleCanvas();
+ }
+ drawContext = resampleContext;
+ } else {
+ drawContext = ctx;
+ }
+
+ drawContext.putImageData(imageData,
+ 0, 0,
+ videoInfo.picX, videoInfo.picY,
+ videoInfo.picWidth, videoInfo.picHeight);
+
+ if (resample) {
+ ctx.drawImage(resampleCanvas, 0, 0, videoInfo.displayWidth, videoInfo.displayHeight);
+ }
+ };
+
+ return self;
+}
+
+
+
+// -- WebGLFrameSink.js
+
+
+/**
+ * Warning: canvas must not have been used for 2d drawing prior!
+ *
+ * @param HTMLCanvasElement canvas
+ * @constructor
+ */
+function WebGLFrameSink(canvas, videoInfo) {
+ var self = this,
+ gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'),
+ debug = false; // swap this to enable more error checks, which can slow down rendering
+
+ if (gl === null) {
+ throw new Error('WebGL unavailable');
+ }
+
+ // GL!
+ function checkError() {
+ if (debug) {
+ err = gl.getError();
+ if (err !== 0) {
+ throw new Error("GL error " + err);
+ }
+ }
+ }
+
+ function compileShader(type, source) {
+ var shader = gl.createShader(type);
+ gl.shaderSource(shader, source);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ var err = gl.getShaderInfoLog(shader);
+ gl.deleteShader(shader);
+ throw new Error('GL shader compilation for ' + type + ' failed: ' + err);
+ }
+
+ return shader;
+ }
+
+
+ var vertexShader,
+ fragmentShader,
+ program,
+ buffer,
+ err;
+
+ // In the world of GL there are no rectangles.
+ // There are only triangles.
+ // THERE IS NO SPOON.
+ var rectangle = new Float32Array([
+ // First triangle (top left, clockwise)
+ -1.0, -1.0,
+ +1.0, -1.0,
+ -1.0, +1.0,
+
+ // Second triangle (bottom right, clockwise)
+ -1.0, +1.0,
+ +1.0, -1.0,
+ +1.0, +1.0
+ ]);
+
+ var textures = {};
+ function attachTexture(name, register, index, width, height, data) {
+ var texture,
+ texWidth = WebGLFrameSink.stripe ? (width / 4) : width,
+ format = WebGLFrameSink.stripe ? gl.RGBA : gl.LUMINANCE,
+ filter = WebGLFrameSink.stripe ? gl.NEAREST : gl.LINEAR;
+
+ if (textures[name]) {
+ // Reuse & update the existing texture
+ texture = textures[name];
+ } else {
+ textures[name] = texture = gl.createTexture();
+ checkError();
+
+ gl.uniform1i(gl.getUniformLocation(program, name), index);
+ checkError();
+ }
+ gl.activeTexture(register);
+ checkError();
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ checkError();
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ checkError();
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ checkError();
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
+ checkError();
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
+ checkError();
+
+ gl.texImage2D(
+ gl.TEXTURE_2D,
+ 0, // mip level
+ format, // internal format
+ texWidth,
+ height,
+ 0, // border
+ format, // format
+ gl.UNSIGNED_BYTE, //type
+ data // data!
+ );
+ checkError();
+
+ return texture;
+ }
+
+ function buildStripe(width, height) {
+ var len = width * height,
+ out = new Uint32Array(len);
+ for (var i = 0; i < len; i += 4) {
+ out[i ] = 0x000000ff;
+ out[i + 1] = 0x0000ff00;
+ out[i + 2] = 0x00ff0000;
+ out[i + 3] = 0xff000000;
+ }
+ return new Uint8Array(out.buffer);
+ }
+
+ function init(yCbCrBuffer) {
+ vertexShader = compileShader(gl.VERTEX_SHADER, "attribute vec2 aPosition;\nattribute vec2 aLumaPosition;\nattribute vec2 aChromaPosition;\nvarying vec2 vLumaPosition;\nvarying vec2 vChromaPosition;\nvoid main() {\n gl_Position = vec4(aPosition, 0, 1);\n vLumaPosition = aLumaPosition;\n vChromaPosition = aChromaPosition;\n}\n");
+ if (WebGLFrameSink.stripe) {
+ fragmentShader = compileShader(gl.FRAGMENT_SHADER, "// inspired by https://github.com/mbebenita/Broadway/blob/master/Player/canvas.js\n// extra 'stripe' texture fiddling to work around IE 11's poor performance on gl.LUMINANCE and gl.ALPHA textures\n\nprecision mediump float;\nuniform sampler2D uStripeLuma;\nuniform sampler2D uStripeChroma;\nuniform sampler2D uTextureY;\nuniform sampler2D uTextureCb;\nuniform sampler2D uTextureCr;\nvarying vec2 vLumaPosition;\nvarying vec2 vChromaPosition;\nvoid main() {\n // Y, Cb, and Cr planes are mapped into a pseudo-RGBA texture\n // so we can upload them without expanding the bytes on IE 11\n // which doesn\\'t allow LUMINANCE or ALPHA textures.\n // The stripe textures mark which channel to keep for each pixel.\n vec4 vStripeLuma = texture2D(uStripeLuma, vLumaPosition);\n vec4 vStripeChroma = texture2D(uStripeChroma, vChromaPosition);\n\n // Each texture extraction will contain the relevant value in one\n // channel only.\n vec4 vY = texture2D(uTextureY, vLumaPosition) * vStripeLuma;\n vec4 vCb = texture2D(uTextureCb, vChromaPosition) * vStripeChroma;\n vec4 vCr = texture2D(uTextureCr, vChromaPosition) * vStripeChroma;\n\n // Now assemble that into a YUV vector, and premultipy the Y...\n vec3 YUV = vec3(\n (vY.x + vY.y + vY.z + vY.w) * 1.1643828125,\n (vCb.x + vCb.y + vCb.z + vCb.w),\n (vCr.x + vCr.y + vCr.z + vCr.w)\n );\n // And convert that to RGB!\n gl_FragColor = vec4(\n YUV.x + 1.59602734375 * YUV.z - 0.87078515625,\n YUV.x - 0.39176171875 * YUV.y - 0.81296875 * YUV.z + 0.52959375,\n YUV.x + 2.017234375 * YUV.y - 1.081390625,\n 1\n );\n}\n");
+ } else {
+ fragmentShader = compileShader(gl.FRAGMENT_SHADER, "// inspired by https://github.com/mbebenita/Broadway/blob/master/Player/canvas.js\n\nprecision mediump float;\nuniform sampler2D uTextureY;\nuniform sampler2D uTextureCb;\nuniform sampler2D uTextureCr;\nvarying vec2 vLumaPosition;\nvarying vec2 vChromaPosition;\nvoid main() {\n // Y, Cb, and Cr planes are uploaded as LUMINANCE textures.\n float fY = texture2D(uTextureY, vLumaPosition).x;\n float fCb = texture2D(uTextureCb, vChromaPosition).x;\n float fCr = texture2D(uTextureCr, vChromaPosition).x;\n\n // Premultipy the Y...\n float fYmul = fY * 1.1643828125;\n\n // And convert that to RGB!\n gl_FragColor = vec4(\n fYmul + 1.59602734375 * fCr - 0.87078515625,\n fYmul - 0.39176171875 * fCb - 0.81296875 * fCr + 0.52959375,\n fYmul + 2.017234375 * fCb - 1.081390625,\n 1\n );\n}\n");
+ }
+
+ program = gl.createProgram();
+ gl.attachShader(program, vertexShader);
+ checkError();
+
+ gl.attachShader(program, fragmentShader);
+ checkError();
+
+ gl.linkProgram(program);
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ var err = gl.getProgramInfoLog(program);
+ gl.deleteProgram(program);
+ throw new Error('GL program linking failed: ' + err);
+ }
+
+ gl.useProgram(program);
+ checkError();
+
+ if (WebGLFrameSink.stripe) {
+ attachTexture(
+ 'uStripeLuma',
+ gl.TEXTURE3,
+ 3,
+ yCbCrBuffer.strideY * 4,
+ yCbCrBuffer.height,
+ buildStripe(yCbCrBuffer.strideY, yCbCrBuffer.height)
+ );
+ checkError();
+
+ attachTexture(
+ 'uStripeChroma',
+ gl.TEXTURE4,
+ 4,
+ yCbCrBuffer.strideCb * 4,
+ yCbCrBuffer.height >> yCbCrBuffer.vdec,
+ buildStripe(yCbCrBuffer.strideCb, yCbCrBuffer.height >> yCbCrBuffer.vdec)
+ );
+ checkError();
+ }
+ }
+
+ self.drawFrame = function(yCbCrBuffer) {
+ if (!program) {
+ init(yCbCrBuffer);
+ }
+
+ // Set up the rectangle and draw it
+
+ //
+ // Set up geometry
+ //
+
+ buffer = gl.createBuffer();
+ checkError();
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ checkError();
+
+ gl.bufferData(gl.ARRAY_BUFFER, rectangle, gl.STATIC_DRAW);
+ checkError();
+
+ var positionLocation = gl.getAttribLocation(program, 'aPosition');
+ checkError();
+
+ gl.enableVertexAttribArray(positionLocation);
+ checkError();
+
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
+ checkError();
+
+
+ // Set up the texture geometry...
+ function setupTexturePosition(varname, texWidth, texHeight) {
+ // Warning: assumes that the stride for Cb and Cr is the same size in output pixels
+ var textureX0 = videoInfo.picX / texWidth;
+ var textureX1 = (videoInfo.picX + videoInfo.picWidth) / texWidth;
+ var textureY0 = (videoInfo.picY + videoInfo.picHeight) / texHeight;
+ var textureY1 = videoInfo.picY / texHeight;
+ var textureRectangle = new Float32Array([
+ textureX0, textureY0,
+ textureX1, textureY0,
+ textureX0, textureY1,
+ textureX0, textureY1,
+ textureX1, textureY0,
+ textureX1, textureY1
+ ]);
+
+ var texturePositionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, texturePositionBuffer);
+ checkError();
+
+ gl.bufferData(gl.ARRAY_BUFFER, textureRectangle, gl.STATIC_DRAW);
+ checkError();
+
+ var texturePositionLocation = gl.getAttribLocation(program, varname);
+ checkError();
+
+ gl.enableVertexAttribArray(texturePositionLocation);
+ checkError();
+
+ gl.vertexAttribPointer(texturePositionLocation, 2, gl.FLOAT, false, 0, 0);
+ checkError();
+ }
+ setupTexturePosition('aLumaPosition', yCbCrBuffer.strideY, yCbCrBuffer.height);
+ setupTexturePosition('aChromaPosition', yCbCrBuffer.strideCb << yCbCrBuffer.hdec, yCbCrBuffer.height);
+
+ // Create the textures...
+ var textureY = attachTexture(
+ 'uTextureY',
+ gl.TEXTURE0,
+ 0,
+ yCbCrBuffer.strideY,
+ yCbCrBuffer.height,
+ yCbCrBuffer.bytesY
+ );
+ var textureCb = attachTexture(
+ 'uTextureCb',
+ gl.TEXTURE1,
+ 1,
+ yCbCrBuffer.strideCb,
+ yCbCrBuffer.height >> yCbCrBuffer.vdec,
+ yCbCrBuffer.bytesCb
+ );
+ var textureCr = attachTexture(
+ 'uTextureCr',
+ gl.TEXTURE2,
+ 2,
+ yCbCrBuffer.strideCr,
+ yCbCrBuffer.height >> yCbCrBuffer.vdec,
+ yCbCrBuffer.bytesCr
+ );
+
+ // Aaaaand draw stuff.
+ gl.drawArrays(gl.TRIANGLES, 0, rectangle.length / 2);
+ checkError();
+ };
+
+ return self;
+}
+
+// For Windows; luminance and alpha textures are ssllooww to upload,
+// so we pack into RGBA and unpack in the shaders.
+//
+// This seems to affect all browsers on Windows, probably due to fun
+// mismatches between GL and D3D.
+WebGLFrameSink.stripe = (function() {
+ if (navigator.userAgent.indexOf('Windows') !== -1) {
+ return true;
+ }
+ return false;
+})();
+
+/**
+ * Static function to check if WebGL will be available with appropriate features.
+ *
+ * @return boolean
+ */
+WebGLFrameSink.isAvailable = function() {
+ var canvas = document.createElement('canvas'),
+ gl;
+ canvas.width = 1;
+ canvas.height = 1;
+ var options = {
+ failIfMajorPerformanceCaveat: true
+ };
+ try {
+ gl = canvas.getContext('webgl', options) || canvas.getContext('experimental-webgl', options);
+ } catch (e) {
+ return false;
+ }
+ if (gl) {
+ var register = gl.TEXTURE0,
+ width = 4,
+ height = 4,
+ texture = gl.createTexture(),
+ data = new Uint8Array(width * height),
+ texWidth = WebGLFrameSink.stripe ? (width / 4) : width,
+ format = WebGLFrameSink.stripe ? gl.RGBA : gl.LUMINANCE,
+ filter = WebGLFrameSink.stripe ? gl.NEAREST : gl.LINEAR;
+
+ gl.activeTexture(register);
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
+ gl.texImage2D(
+ gl.TEXTURE_2D,
+ 0, // mip level
+ format, // internal format
+ texWidth,
+ height,
+ 0, // border
+ format, // format
+ gl.UNSIGNED_BYTE, //type
+ data // data!
+ );
+
+ var err = gl.getError();
+ if (err) {
+ // Doesn't support luminance textures?
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ return false;
+ }
+};
+
+
+
+// -- Bisector.js
+
+/**
+ * Give as your 'process' function something that will trigger an async
+ * operation, then call the left() or right() methods to run another
+ * iteration, bisecting to the given direction.
+ *
+ * Caller is responsible for determining when done.
+ *
+ * @params options object {
+ * start: number,
+ * end: number,
+ * process: function(start, position, end)
+ * }
+ */
+function Bisector(options) {
+ var start = options.start,
+ end = options.end,
+ position = 0,
+ self = this,
+ n = 0;
+
+ function iterate() {
+ n++;
+ position = Math.floor((start + end) / 2);
+ return options.process(start, end, position);
+ }
+
+ self.start = function() {
+ iterate();
+ return self;
+ };
+
+ self.left = function() {
+ end = position;
+ return iterate();
+ };
+
+ self.right = function() {
+ start = position;
+ return iterate();
+ };
+}
+
+
+// -- OGVMediaType.js
+
+function OGVMediaType(contentType) {
+ contentType = '' + contentType;
+
+ var self = this;
+ self.major = null;
+ self.minor = null;
+ self.codecs = null;
+
+ function trim(str) {
+ return str.replace(/^\s+/, '').replace(/\s+$/, '');
+ }
+
+ function split(str, sep, limit) {
+ var bits = str.split(sep, limit).map(function(substr) {
+ return trim(substr);
+ });
+ if (typeof limit === 'number') {
+ while (bits.length < limit) {
+ bits.push(null);
+ }
+ }
+ return bits;
+ }
+
+ var parts = split(contentType, ';');
+ if (parts.length) {
+ var base = parts.shift();
+ if (base) {
+ var bits = split(base, '/', 2);
+ self.major = bits[0];
+ self.minor = bits[1];
+ }
+
+ parts.forEach(function(str) {
+ var matches = str.match(/^codecs\s*=\s*"(.*?)"$/);
+ if (matches) {
+ self.codecs = split(matches[1], ',');
+ }
+ });
+ }
+}
+
+
+// -- OGVWrapperCodec.js
+
+/**
+ * Proxy object for web worker interface for codec classes.
+ *
+ * Used by the high-level player interface.
+ *
+ * @author Brion Vibber <brion@pobox.com>
+ * @copyright 2015
+ * @license MIT-style
+ */
+OGVWrapperCodec = (function(options) {
+ options = options || {};
+ var self = this,
+ suffix = '?version=' + encodeURIComponent(OGVVersion),
+ base = (typeof options.base === 'string') ? (options.base + '/') : '',
+ type = (typeof options.type === 'string') ? options.type : 'video/ogg',
+ processing = false,
+ demuxer = null,
+ videoDecoder = null,
+ audioDecoder = null;
+
+ var loadedMetadata = false;
+ Object.defineProperty(self, 'loadedMetadata', {
+ get: function() {
+ return loadedMetadata;
+ }
+ });
+
+ Object.defineProperty(self, 'processing', {
+ get: function() {
+ return processing
+ || (videoDecoder && videoDecoder.processing)
+ || (audioDecoder && audioDecoder.processing);
+ }
+ });
+
+ Object.defineProperty(self, 'duration', {
+ get: function() {
+ if (self.loadedMetadata) {
+ return demuxer.duration;
+ } else {
+ return NaN;
+ }
+ }
+ });
+
+ Object.defineProperty(self, 'hasAudio', {
+ get: function() {
+ return self.loadedMetadata && !!audioDecoder;
+ }
+ });
+
+ Object.defineProperty(self, 'audioReady', {
+ get: function() {
+ return self.hasAudio && demuxer.audioReady;
+ }
+ });
+
+ Object.defineProperty(self, 'audioTimestamp', {
+ get: function() {
+ return demuxer.audioTimestamp;
+ }
+ });
+
+ Object.defineProperty(self, 'audioFormat', {
+ get: function() {
+ if (self.hasAudio) {
+ return audioDecoder.audioFormat;
+ } else {
+ return null;
+ }
+ }
+ });
+
+ Object.defineProperty(self, 'audioBuffer', {
+ get: function() {
+ if (self.hasAudio) {
+ return audioDecoder.audioBuffer;
+ } else {
+ return null;
+ }
+ }
+ });
+
+ Object.defineProperty(self, 'hasVideo', {
+ get: function() {
+ return self.loadedMetadata && !!videoDecoder;
+ }
+ });
+
+ Object.defineProperty(self, 'frameReady', {
+ get: function() {
+ return self.hasVideo && demuxer.frameReady;
+ }
+ });
+
+ Object.defineProperty(self, 'frameTimestamp', {
+ get: function() {
+ return demuxer.frameTimestamp;
+ }
+ });
+
+ Object.defineProperty(self, 'keyframeTimestamp', {
+ get: function() {
+ return demuxer.keyframeTimestamp;
+ }
+ });
+
+ Object.defineProperty(self, 'videoFormat', {
+ get: function() {
+ if (self.hasVideo) {
+ return videoDecoder.videoFormat;
+ } else {
+ return null;
+ }
+ }
+ });
+
+ Object.defineProperty(self, 'frameBuffer', {
+ get: function() {
+ if (self.hasVideo) {
+ return videoDecoder.frameBuffer;
+ } else {
+ return null;
+ }
+ }
+ });
+
+ Object.defineProperty(self, 'seekable', {
+ get: function() {
+ return demuxer.seekable;
+ }
+ });
+
+ // - public methods
+ self.init = function(callback) {
+ var demuxerClassName;
+ if (options.type === 'video/webm') {
+ demuxerClassName = 'OGVDemuxerWebM';
+ } else {
+ demuxerClassName = 'OGVDemuxerOgg';
+ }
+ OGVLoader.loadClass(demuxerClassName, function(demuxerClass) {
+ demuxer = new demuxerClass();
+ demuxer.init(callback);
+ });
+ };
+
+ self.destroy = function() {
+ demuxer = null;
+ videoDecoder = null;
+ audioDecoder = null;
+ };
+
+ var inputQueue = [];
+ self.receiveInput = function(data, callback) {
+ inputQueue.push(data);
+ callback();
+ };
+
+ var audioClassMap = {
+ vorbis: 'OGVDecoderAudioVorbis',
+ opus: 'OGVDecoderAudioOpus'
+ };
+ function loadAudioCodec(callback) {
+ if (demuxer.audioCodec) {
+ var className = audioClassMap[demuxer.audioCodec];
+ processing = true;
+ OGVLoader.loadClass(className, function(audioCodecClass) {
+ var audioOptions = {};
+ if (demuxer.audioFormat) {
+ audioOptions.audioFormat = demuxer.audioFormat;
+ }
+ audioDecoder = new audioCodecClass(audioOptions);
+ audioDecoder.init(function() {
+ loadedAudioMetadata = audioDecoder.loadedMetadata;
+ processing = false;
+ callback();
+ });
+ }, {
+ worker: options.worker
+ });
+ } else {
+ callback();
+ }
+ }
+
+ var videoClassMap = {
+ theora: 'OGVDecoderVideoTheora',
+ vp8: 'OGVDecoderVideoVP8',
+ vp9: 'OGVDecoderVideoVP9'
+ };
+ function loadVideoCodec(callback) {
+ if (demuxer.videoCodec) {
+ var className = videoClassMap[demuxer.videoCodec];
+ processing = true;
+ OGVLoader.loadClass(className, function(videoCodecClass) {
+ var videoOptions = {};
+ if (demuxer.videoFormat) {
+ videoOptions.videoFormat = demuxer.videoFormat;
+ }
+ videoDecoder = new videoCodecClass(videoOptions);
+ videoDecoder.init(function() {
+ loadedVideoMetadata = videoDecoder.loadedMetadata;
+ processing = false;
+ callback();
+ });
+ }, {
+ worker: options.worker
+ });
+ } else {
+ callback();
+ }
+ }
+
+ var loadedDemuxerMetadata = false,
+ loadedAudioMetadata = false,
+ loadedVideoMetadata = false;
+
+ self.process = function(callback) {
+ if (processing) {
+ throw new Error('reentrancy fail on OGVWrapperCodec.process');
+ }
+ processing = true;
+ function finish(result) {
+ processing = false;
+ callback(result);
+ }
+
+ function doProcessData() {
+ if (inputQueue.length) {
+ var data = inputQueue.shift();
+ demuxer.process(data, function(more) {
+ if (!more && inputQueue.length) {
+ // we've got more to process already
+ more = true;
+ }
+ finish(more);
+ });
+ } else {
+ // out of data! ask for more
+ finish(false);
+ }
+ }
+
+ if (demuxer.loadedMetadata && !loadedDemuxerMetadata) {
+
+ // Demuxer just reached its metadata. Load the relevant codecs!
+ loadAudioCodec(function() {
+ loadVideoCodec(function() {
+ loadedDemuxerMetadata = true;
+ loadedAudioMetadata = !audioDecoder;
+ loadedVideoMetadata = !videoDecoder;
+ loadedAllMetadata = loadedAudioMetadata && loadedVideoMetadata;
+ finish(true);
+ });
+ });
+
+ } else if (loadedDemuxerMetadata && !loadedAudioMetadata) {
+
+ if (audioDecoder.loadedMetadata) {
+
+ loadedAudioMetadata = true;
+ loadedAllMetadata = loadedAudioMetadata && loadedVideoMetadata;
+ finish(true);
+
+ } else if (demuxer.audioReady) {
+
+ demuxer.dequeueAudioPacket(function(packet) {
+ audioDecoder.processHeader(packet, function(ret) {
+ finish(true);
+ });
+ });
+
+ } else {
+
+ doProcessData();
+
+ }
+
+ } else if (loadedAudioMetadata && !loadedVideoMetadata) {
+
+ if (videoDecoder.loadedMetadata) {
+
+ loadedVideoMetadata = true;
+ loadedAllMetadata = loadedAudioMetadata && loadedVideoMetadata;
+ finish(true);
+
+ } else if (demuxer.frameReady) {
+
+ processing = true;
+ demuxer.dequeueVideoPacket(function(packet) {
+ videoDecoder.processHeader(packet, function() {
+ finish(true);
+ });
+ });
+
+ } else {
+
+ doProcessData();
+
+ }
+
+ } else if (loadedVideoMetadata && !self.loadedMetadata && loadedAllMetadata) {
+
+ // Ok we've found all the metadata there is. Enjoy.
+ loadedMetadata = true;
+ finish(true);
+
+ } else if (self.loadedMetadata && (!self.hasAudio || demuxer.audioReady) && (!self.hasVideo || demuxer.frameReady)) {
+
+ // Already queued up some packets. Go read them!
+ finish(true);
+
+ } else {
+
+ // We need to process more of the data we've already received,
+ // or ask for more if we ran out!
+ doProcessData();
+
+ }
+
+ };
+
+ self.decodeFrame = function(callback) {
+ var timestamp = self.frameTimestamp,
+ keyframeTimestamp = self.keyframeTimestamp;
+ demuxer.dequeueVideoPacket(function(packet) {
+ videoDecoder.processFrame(packet, function(ok) {
+ // hack
+ if (self.frameBuffer) {
+ self.frameBuffer.timestamp = timestamp;
+ self.frameBuffer.keyframeTimestamp = keyframeTimestamp;
+ }
+ callback(ok);
+ });
+ });
+ };
+
+ self.decodeAudio = function(callback) {
+ demuxer.dequeueAudioPacket(function(packet) {
+ audioDecoder.processAudio(packet, function(ok) {
+ callback(ok);
+ });
+ });
+ }
+
+ self.discardFrame = function(callback) {
+ demuxer.dequeueVideoPacket(function(packet) {
+ callback();
+ });
+ };
+
+ self.discardAudio = function(callback) {
+ demuxer.dequeueAudioPacket(function(packet) {
+ callback(ok);
+ });
+ };
+
+ self.flush = function(callback) {
+ inputQueue.splice(0, inputQueue.length);
+ demuxer.flush(callback);
+ };
+
+ self.getKeypointOffset = function(timeSeconds, callback) {
+ demuxer.getKeypointOffset(timeSeconds, callback);
+ };
+
+ return self;
+});
+
+
+// -- OGVProxyClass.js
+
+/**
+ * Proxy object for web worker interface for codec classes.
+ *
+ * Used by the high-level player interface.
+ *
+ * @author Brion Vibber <brion@pobox.com>
+ * @copyright 2015
+ * @license MIT-style
+ */
+function OGVProxyClass(initialProps, methods) {
+ return function(worker, className, options) {
+ options = options || {};
+ var self = this;
+
+ var transferables = (function() {
+ var buffer = new ArrayBuffer(1024),
+ bytes = new Uint8Array(buffer);
+ try {
+ worker.postMessage({
+ action: 'transferTest',
+ bytes: bytes
+ }, [buffer]);
+ if (buffer.byteLength) {
+ // No transferable support
+ return false;
+ } else {
+ return true;
+ }
+ } catch (e) {
+ return false;
+ }
+ })();
+
+ // Set up proxied property getters
+ var props = {};
+ for (var iPropName in initialProps) {
+ if (initialProps.hasOwnProperty(iPropName)) {
+ (function(propName) {
+ props[propName] = initialProps[propName];
+ Object.defineProperty(self, propName, {
+ get: function getProperty() {
+ return props[propName];
+ }
+ });
+ })(iPropName);
+ }
+ }
+
+ // Current player wants to avoid async confusion.
+ var processingQueue = 0;
+ Object.defineProperty(self, 'processing', {
+ get: function() {
+ return (processingQueue > 0);
+ }
+ });
+
+ // Set up proxied methods
+ for (var method in methods) {
+ if (methods.hasOwnProperty(method)) {
+ self[method] = methods[method];
+ }
+ }
+
+ // And some infrastructure!
+ var messageCount = 0,
+ pendingCallbacks = {};
+ this.proxy = function(action, args, callback, transfers) {
+ var callbackId = 'callback-' + (++messageCount) + '-' + action;
+ if (callback) {
+ pendingCallbacks[callbackId] = callback;
+ }
+ var out = {
+ 'action': action,
+ 'callbackId': callbackId,
+ 'args': args || []
+ };
+ processingQueue++;
+ if (transferables) {
+ worker.postMessage(out, transfers || []);
+ } else {
+ worker.postMessage(out);
+ }
+ };
+
+ worker.addEventListener('message', function proxyOnMessage(event) {
+ processingQueue--;
+ if (event.data.action !== 'callback') {
+ // ignore
+ return;
+ }
+
+ var data = event.data,
+ callbackId = data.callbackId,
+ args = data.args,
+ callback = pendingCallbacks[callbackId];
+
+ // Save any updated properties returned to us...
+ if (data.props) {
+ for (var propName in data.props) {
+ if (data.props.hasOwnProperty(propName)) {
+ props[propName] = data.props[propName];
+ }
+ }
+ }
+
+ if (callback) {
+ delete pendingCallbacks[callbackId];
+ callback.apply(this, args);
+ }
+ });
+
+ // Tell the proxy to load and initialize the appropriate class
+ self.proxy('construct', [className, options], function() {});
+
+ return self;
+ };
+}
+
+
+// -- OGVDecoderAudioProxy.js
+
+OGVDecoderAudioProxy = OGVProxyClass({
+ loadedMetadata: false,
+ audioFormat: null,
+ audioBuffer: null
+}, {
+ init: function(callback) {
+ this.proxy('init', [], callback);
+ },
+
+ processHeader: function(data, callback) {
+ this.proxy('processHeader', [data], callback, [data]);
+ },
+
+ processAudio: function(data, callback) {
+ this.proxy('processAudio', [data], callback, [data]);
+ }
+});
+
+
+// -- OGVDecoderVideoProxy.js
+
+OGVDecoderVideoProxy = OGVProxyClass({
+ loadedMetadata: false,
+ videoFormat: null,
+ frameBuffer: null
+}, {
+ init: function(callback) {
+ this.proxy('init', [], callback);
+ },
+
+ processHeader: function(data, callback) {
+ this.proxy('processHeader', [data], callback, [data]);
+ },
+
+ processFrame: function(data, callback) {
+ this.proxy('processFrame', [data], callback, [data]);
+ }
+});
+
+
+// -- OGVPlayer.js
+
+/**
+ * Constructor for an analogue of the TimeRanges class
+ * returned by various HTMLMediaElement properties
+ *
+ * Pass an array of two-element arrays, each containing a start and end time.
+ */
+OGVTimeRanges = window.OGVTimeRanges = function(ranges) {
+ Object.defineProperty(this, 'length', {
+ get: function getLength() {
+ return ranges.length;
+ }
+ });
+ this.start = function(i) {
+ return ranges[i][0];
+ };
+ this.end = function(i) {
+ return ranges[i][1];
+ };
+ return this;
+};
+
+/**
+ * Player class -- instantiate one of these to get an 'ogvjs' HTML element
+ * which has a similar interface to the HTML audio/video elements.
+ *
+ * @param options: optional dictionary of options:
+ * 'base': string; base URL for additional resources, such as Flash audio shim
+ * 'webGL': bool; pass true to use WebGL acceleration if available
+ * 'forceWebGL': bool; pass true to require WebGL even if not detected
+ */
+OGVPlayer = window.OGVPlayer = function(options) {
+ options = options || {};
+
+ var instanceId = 'ogvjs' + (++OGVPlayer.instanceCount);
+
+ var codecClassName = null,
+ codecClass = null,
+ codecType = null;
+
+ var webGLdetected = WebGLFrameSink.isAvailable();
+ var useWebGL = (options.webGL !== false) && webGLdetected;
+ if(!!options.forceWebGL) {
+ useWebGL = true;
+ if(!webGLdetected) {
+ console.log("No support for WebGL detected, but WebGL forced on!");
+ }
+ }
+
+ // Experimental options
+ var enableWebM = !!options.enableWebM;
+
+ // Running the codec in a worker thread equals happy times!
+ var enableWorker = !!window.Worker;
+ if (typeof options.worker !== 'undefined') {
+ enableWorker = !!options.worker;
+ }
+
+ var State = {
+ INITIAL: 'INITIAL',
+ SEEKING_END: 'SEEKING_END',
+ LOADED: 'LOADED',
+ READY: 'READY',
+ PLAYING: 'PLAYING',
+ SEEKING: 'SEEKING',
+ ENDED: 'ENDED'
+ }, state = State.INITIAL;
+
+ var SeekState = {
+ NOT_SEEKING: 'NOT_SEEKING',
+ BISECT_TO_TARGET: 'BISECT_TO_TARGET',
+ BISECT_TO_KEYPOINT: 'BISECT_TO_KEYPOINT',
+ LINEAR_TO_TARGET: 'LINEAR_TO_TARGET'
+ }, seekState = SeekState.NOT_SEEKING;
+
+ var audioOptions = {},
+ codecOptions = {};
+ options.base = options.base || OGVLoader.base;
+ if (typeof options.base === 'string') {
+ // Pass the resource dir down to AudioFeeder, so it can load the dynamicaudio.swf
+ audioOptions.base = options.base;
+
+ // And to the worker thread, so it can load the codec JS
+ codecOptions.base = options.base;
+ }
+ if (typeof options.audioContext !== 'undefined') {
+ // Try passing a pre-created audioContext in?
+ audioOptions.audioContext = options.audioContext;
+ }
+ codecOptions.worker = enableWorker;
+
+ var canvas = document.createElement('canvas');
+ var frameSink;
+
+ // Return a magical custom element!
+ var self = document.createElement('ogvjs');
+ self.className = instanceId;
+
+ canvas.style.position = 'absolute';
+ canvas.style.top = '0';
+ canvas.style.left = '0';
+ canvas.style.width = '100%';
+ canvas.style.height = '100%';
+ canvas.style.objectFit = 'contain';
+ self.appendChild(canvas);
+
+ var getTimestamp;
+ if (window.performance === undefined || window.performance.now === undefined) {
+ getTimestamp = Date.now;
+ } else {
+ getTimestamp = window.performance.now.bind(window.performance);
+ }
+ function time(cb) {
+ var start = getTimestamp();
+ cb();
+ var delta = getTimestamp() - start;
+ lastFrameDecodeTime += delta;
+ return delta;
+ }
+
+ var then = getTimestamp();
+ function log(msg) {
+ if (options.debug) {
+ /*
+ var now = getTimestamp(),
+ delta = now - then;
+
+ console.log('+' + delta + 'ms proc: ' + msg);
+ then = now;
+ */
+ console.log('OGVPlayer: ' + msg);
+ }
+ }
+
+ function fireEvent(eventName, props) {
+ var event;
+ props = props || {};
+
+ if (typeof window.Event == 'function') {
+ // standard event creation
+ event = new CustomEvent(eventName);
+ } else {
+ // IE back-compat mode
+ // https://msdn.microsoft.com/en-us/library/dn905219%28v=vs.85%29.aspx
+ event = document.createEvent('Event');
+ event.initEvent(eventName, false, false);
+ }
+
+ for (var prop in props) {
+ if (props.hasOwnProperty(prop)) {
+ event[prop] = props[prop];
+ }
+ }
+
+ self.dispatchEvent(event);
+ }
+
+ var codec,
+ actionQueue = [],
+ audioFeeder;
+ var muted = false,
+ initialPlaybackPosition = 0.0,
+ initialPlaybackOffset = 0.0;
+ function initAudioFeeder() {
+ audioFeeder = new AudioFeeder( audioOptions );
+ if (muted) {
+ audioFeeder.mute();
+ }
+ audioFeeder.onstarved = function() {
+ // If we're in a background tab, timers may be throttled.
+ // When audio buffers run out, go decode some more stuff.
+ if (nextProcessingTimer) {
+ clearTimeout(nextProcessingTimer);
+ nextProcessingTimer = null;
+ pingProcessing();
+ }
+ };
+ audioFeeder.init(audioInfo.channels, audioInfo.rate);
+ }
+
+ function startPlayback(offset) {
+ if (audioFeeder) {
+ audioFeeder.start();
+ var state = audioFeeder.getPlaybackState();
+ initialPlaybackPosition = state.playbackPosition;
+ } else {
+ initialPlaybackPosition = getTimestamp() / 1000;
+ }
+ if (offset !== undefined) {
+ initialPlaybackOffset = offset;
+ }
+ log('continuing at ' + initialPlaybackPosition + ', ' + initialPlaybackOffset);
+ }
+
+ function stopPlayback() {
+ if (audioFeeder) {
+ audioFeeder.stop();
+ }
+ initialPlaybackOffset = getPlaybackTime();
+ log('pausing at ' + initialPlaybackOffset);
+ }
+
+ /**
+ * Get audio playback time position in file's units
+ *
+ * @return {number} seconds since file start
+ */
+ function getPlaybackTime(state) {
+ var position;
+ if (audioFeeder) {
+ state = state || audioFeeder.getPlaybackState();
+ position = state.playbackPosition;
+ } else {
+ position = getTimestamp() / 1000;
+ }
+ return (position - initialPlaybackPosition) + initialPlaybackOffset;
+ }
+
+ var stream,
+ byteLength = 0,
+ duration = null,
+ lastSeenTimestamp = null,
+ nextProcessingTimer,
+ started = false,
+ paused = true,
+ ended = false,
+ startedPlaybackInDocument = false,
+ waitingOnInput = false;
+
+ var framesPlayed = 0;
+ // Benchmark data, exposed via getPlaybackStats()
+ var framesProcessed = 0, // frames
+ targetPerFrameTime = 1000 / 60, // ms
+ totalFrameTime = 0, // ms
+ totalFrameCount = 0, // frames
+ playTime = 0, // ms
+ demuxingTime = 0, // ms
+ videoDecodingTime = 0, // ms
+ audioDecodingTime = 0, // ms
+ bufferTime = 0, // ms
+ drawingTime = 0, // ms
+ totalJitter = 0; // sum of ms we're off from expected frame delivery time
+ // Benchmark data that doesn't clear
+ var droppedAudio = 0, // number of times we were starved for audio
+ delayedAudio = 0; // seconds audio processing was delayed by blocked CPU
+ var poster = '', thumbnail;
+
+ function stopVideo() {
+ log("STOPPING");
+ // kill the previous video if any
+ state = State.INITIAL;
+ started = false;
+ paused = true;
+ ended = true;
+ frameEndTimestamp = 0.0;
+ audioEndTimestamp = 0.0;
+ lastFrameDecodeTime = 0.0;
+
+ if (stream) {
+ stream.abort();
+ stream = null;
+ }
+ if (codec) {
+ codec.destroy();
+ codec = null;
+ }
+ if (audioFeeder) {
+ audioFeeder.close();
+ audioFeeder = undefined;
+ }
+ if (nextProcessingTimer) {
+ clearTimeout(nextProcessingTimer);
+ nextProcessingTimer = null;
+ }
+ }
+
+ var lastFrameTime = getTimestamp(),
+ frameEndTimestamp = 0.0,
+ audioEndTimestamp = 0.0,
+ yCbCrBuffer = null;
+ var lastFrameDecodeTime = 0.0;
+ var lastFrameTimestamp = 0.0;
+
+ function doFrameComplete() {
+ if (startedPlaybackInDocument && !document.body.contains(self)) {
+ // We've been de-parented since we last ran
+ // Stop playback at next opportunity!
+ setTimeout(function() {
+ self.stop();
+ }, 0);
+ }
+
+ var newFrameTimestamp = getTimestamp(),
+ wallClockTime = newFrameTimestamp - lastFrameTimestamp,
+ jitter = Math.abs(wallClockTime - targetPerFrameTime);
+ totalJitter += jitter;
+ playTime += wallClockTime;
+
+ fireEvent('framecallback', {
+ cpuTime: lastFrameDecodeTime,
+ clockTime: wallClockTime
+ });
+ lastFrameDecodeTime = 0;
+ lastFrameTimestamp = newFrameTimestamp;
+ }
+
+
+ // -- seek functions
+ var seekTargetTime = 0.0,
+ seekTargetKeypoint = 0.0,
+ bisectTargetTime = 0.0,
+ lastSeekPosition,
+ lastFrameSkipped,
+ seekBisector;
+
+ function startBisection(targetTime) {
+ bisectTargetTime = targetTime;
+ seekBisector = new Bisector({
+ start: 0,
+ end: stream.bytesTotal - 1,
+ process: function(start, end, position) {
+ if (position == lastSeekPosition) {
+ return false;
+ } else {
+ lastSeekPosition = position;
+ lastFrameSkipped = false;
+ codec.flush(function() {
+ stream.seek(position);
+ readBytesAndWait();
+ });
+ return true;
+ }
+ }
+ });
+ seekBisector.start();
+ }
+
+ function seek(toTime) {
+ if (stream.bytesTotal === 0) {
+ throw new Error('Cannot bisect a non-seekable stream');
+ }
+ state = State.SEEKING;
+ seekTargetTime = toTime;
+ seekTargetKeypoint = -1;
+ lastFrameSkipped = false;
+ lastSeekPosition = -1;
+
+ actionQueue.push(function() {
+ stopPlayback();
+
+ codec.flush(function() {
+ codec.getKeypointOffset(toTime, function(offset) {
+ if (offset > 0) {
+ // This file has an index!
+ //
+ // Start at the keypoint, then decode forward to the desired time.
+ //
+ seekState = SeekState.LINEAR_TO_TARGET;
+ stream.seek(offset);
+ readBytesAndWait();
+ } else {
+ // No index.
+ //
+ // Bisect through the file finding our target time, then we'll
+ // have to do it again to reach the keypoint, and *then* we'll
+ // have to decode forward back to the desired time.
+ //
+ seekState = SeekState.BISECT_TO_TARGET;
+ startBisection(seekTargetTime);
+ }
+ });
+ });
+ });
+ }
+
+ function continueSeekedPlayback() {
+ seekState = SeekState.NOT_SEEKING;
+ state = State.PLAYING;
+ frameEndTimestamp = codec.frameTimestamp;
+ audioEndTimestamp = codec.audioTimestamp;
+ if (codec.hasAudio) {
+ seekTargetTime = codec.audioTimestamp;
+ } else {
+ seekTargetTime = codec.frameTimestamp;
+ }
+ startPlayback(seekTargetTime);
+ if (paused) {
+ stopPlayback(); // :P
+ } else {
+ if (isProcessing()) {
+ // wait for whatever's going on to complete
+ } else {
+ pingProcessing(0);
+ }
+ }
+ }
+
+ /**
+ * @return {boolean} true to continue processing, false to wait for input data
+ */
+ function doProcessLinearSeeking() {
+ var frameDuration;
+ if (codec.hasVideo) {
+ frameDuration = targetPerFrameTime;
+ } else {
+ frameDuration = 1 / 256; // approximate packet audio size, fake!
+ }
+
+ if (codec.hasVideo) {
+ if (!codec.frameReady) {
+ // Haven't found a frame yet, process more data
+ pingProcessing();
+ return;
+ } else if (codec.frameTimestamp < 0 || codec.frameTimestamp + frameDuration < seekTargetTime) {
+ // Haven't found a time yet, or haven't reached the target time.
+ // Decode it in case we're at our keyframe or a following intraframe...
+ codec.decodeFrame(function() {
+ pingProcessing();
+ });
+ return;
+ } else {
+ // Reached or surpassed the target time.
+ if (codec.hasAudio) {
+ // Keep processing the audio track
+ // fall through...
+ } else {
+ continueSeekedPlayback();
+ return;
+ }
+ }
+ }
+ if (codec.hasAudio) {
+ if (!codec.audioReady) {
+ // Haven't found an audio packet yet, process more data
+ pingProcessing();
+ return;
+ }
+ if (codec.audioTimestamp < 0 || codec.audioTimestamp + frameDuration < seekTargetTime) {
+ // Haven't found a time yet, or haven't reached the target time.
+ // Decode it so when we reach the target we've got consistent data.
+ codec.decodeAudio(function() {
+ pingProcessing();
+ });
+ return;
+ } else {
+ continueSeekedPlayback();
+ return;
+ }
+ }
+ }
+
+ function doProcessBisectionSeek() {
+ var frameDuration,
+ timestamp;
+ if (codec.hasVideo) {
+ if (!codec.frameReady) {
+ // Haven't found a frame yet, process more data
+ pingProcessing();
+ return;
+ }
+ timestamp = codec.frameTimestamp;
+ frameDuration = targetPerFrameTime;
+ } else if (codec.hasAudio) {
+ if (!codec.audioReady) {
+ // Haven't found an audio packet yet, process more data
+ pingProcessing();
+ return;
+ }
+ timestamp = codec.audioTimestamp;
+ frameDuration = 1 / 256; // approximate packet audio size, fake!
+ } else {
+ throw new Error('Invalid seek state; no audio or video track available');
+ }
+
+ if (timestamp < 0) {
+ // Haven't found a time yet.
+ // Decode in case we're at our keyframe or a following intraframe...
+ if (codec.frameReady) {
+ codec.decodeFrame(function() {
+ pingProcessing();
+ });
+ } else if (codec.audioReady) {
+ codec.decodeAudio(function() {
+ pingProcessing();
+ });
+ } else {
+ pingProcessing();
+ }
+ } else if (timestamp - frameDuration > bisectTargetTime) {
+ if (seekBisector.left()) {
+ // wait for new data to come in
+ } else {
+ seekTargetTime = codec.frameTimestamp;
+ continueSeekedPlayback();
+ }
+ } else if (timestamp + frameDuration < bisectTargetTime) {
+ if (seekBisector.right()) {
+ // wait for new data to come in
+ } else {
+ seekTargetTime = codec.frameTimestamp;
+ continueSeekedPlayback();
+ }
+ } else {
+ // Reached the bisection target!
+ if (seekState == SeekState.BISECT_TO_TARGET && (codec.hasVideo && codec.keyframeTimestamp < codec.frameTimestamp)) {
+ // We have to go back and find a keyframe. Sigh.
+ seekState = SeekState.BISECT_TO_KEYPOINT;
+ startBisection(codec.keyframeTimestamp);
+ } else {
+ // Switch to linear mode to find the final target.
+ seekState = SeekState.LINEAR_TO_TARGET;
+ pingProcessing();
+ }
+ }
+ }
+
+ function setupVideo() {
+ if (videoInfo.fps > 0) {
+ targetPerFrameTime = 1000 / videoInfo.fps;
+ } else {
+ targetPerFrameTime = 16.667; // recalc this later
+ }
+
+ canvas.width = videoInfo.displayWidth;
+ canvas.height = videoInfo.displayHeight;
+ OGVPlayer.styleManager.appendRule('.' + instanceId, {
+ width: videoInfo.displayWidth + 'px',
+ height: videoInfo.displayHeight + 'px'
+ });
+ OGVPlayer.updatePositionOnResize();
+
+ if (useWebGL) {
+ frameSink = new WebGLFrameSink(canvas, videoInfo);
+ } else {
+ frameSink = new FrameSink(canvas, videoInfo);
+ }
+ }
+
+ var depth = 0,
+ useImmediate = options.useImmediate && !!window.setImmediate,
+ useTailCalls = !useImmediate,
+ pendingFrame = 0,
+ pendingAudio = 0;
+
+ function tailCall(func) {
+ if (useImmediate) {
+ setImmediate(func);
+ } else if (!useTailCalls) {
+ setTimeout(func, 0);
+ } else {
+ func();
+ }
+ }
+
+ function doProcessing() {
+ nextProcessingTimer = null;
+
+ if (isProcessing()) {
+ // Called async while waiting for something else to complete...
+ // let it finish, then we'll get called again to continue.
+ return;
+ }
+
+ if (depth > 0 && !useTailCalls) {
+ throw new Error('REENTRANCY FAIL: doProcessing recursing unexpectedly');
+ }
+ depth++;
+
+ if (actionQueue.length) {
+ // data or user i/o to process in our serialized event stream
+ // The function should eventually bring us back here via pingProcessing(),
+ // directly or via further i/o.
+
+ var action = actionQueue.shift();
+ action();
+
+ } else if (state == State.INITIAL) {
+
+ codec.process(function processInitial(more) {
+ if (codec.loadedMetadata) {
+ // we just fell over from headers into content; call onloadedmetadata etc
+ if (!codec.hasVideo && !codec.hasAudio) {
+ throw new Error('No audio or video found, something is wrong');
+ }
+ if (codec.hasAudio) {
+ audioInfo = codec.audioFormat;
+ }
+ if (codec.hasVideo) {
+ videoInfo = codec.videoFormat;
+ setupVideo();
+ }
+ if (!isNaN(codec.duration)) {
+ duration = codec.duration;
+ }
+ if (duration === null) {
+ if (stream.seekable) {
+ state = State.SEEKING_END;
+ lastSeenTimestamp = -1;
+ codec.flush(function() {
+ stream.seek(Math.max(0, stream.bytesTotal - 65536 * 2));
+ readBytesAndWait();
+ });
+ } else {
+ // Stream not seekable and no x-content-duration; assuming infinite stream.
+ state = State.LOADED;
+ pingProcessing();
+ }
+ } else {
+ // We already know the duration.
+ state = State.LOADED;
+ pingProcessing();
+ }
+ } else if (!more) {
+ // Read more data!
+ log('reading more cause we are out of data');
+ readBytesAndWait();
+ } else {
+ // Keep processing headers
+ pingProcessing();
+ }
+ });
+
+ } else if (state == State.SEEKING_END) {
+
+ // Look for the last item.
+ codec.process(function processSeekingEnd(more) {
+ if (codec.hasVideo && codec.frameReady) {
+ lastSeenTimestamp = Math.max(lastSeenTimestamp, codec.frameTimestamp);
+ codec.discardFrame(function() {
+ pingProcessing();
+ });
+ } else if (codec.hasAudio && codec.audioReady) {
+ lastSeenTimestamp = Math.max(lastSeenTimestamp, codec.audioTimestamp);
+ codec.decodeAudio(function() {
+ pingProcessing();
+ });
+ } else if (!more) {
+ // Read more data!
+ if (stream.bytesRead < stream.bytesTotal) {
+ readBytesAndWait();
+ } else {
+ // We are at the end!
+ if (lastSeenTimestamp > 0) {
+ duration = lastSeenTimestamp;
+ }
+
+ // Ok, seek back to the beginning and resync the streams.
+ state = State.LOADED;
+ codec.flush(function() {
+ stream.seek(0);
+ readBytesAndWait();
+ });
+ }
+ } else {
+ // Keep processing headers
+ pingProcessing();
+ }
+ });
+
+ } else if (state == State.LOADED) {
+
+ state = State.READY;
+ if (paused) {
+ // Paused? stop here.
+ log('pausing stopping at loaded');
+ } else {
+ // Not paused? Continue on to play processing.
+ log('not paused so continuing');
+ pingProcessing(0);
+ }
+ fireEvent('loadedmetadata');
+
+ } else if (state == State.READY) {
+
+ if (paused) {
+
+ // Paused? stop here.
+ log('paused while in ready');
+
+ } else {
+
+ function finishStartPlaying() {
+ log('finishStartPlaying');
+
+ state = State.PLAYING;
+ lastFrameTimestamp = getTimestamp();
+
+ startPlayback(0.0);
+ pingProcessing(0);
+ fireEvent('play');
+ }
+
+ if (codec.hasAudio) {
+ initAudioFeeder();
+ audioFeeder.waitUntilReady(finishStartPlaying);
+ } else {
+ finishStartPlaying();
+ }
+ }
+
+ } else if (state == State.SEEKING) {
+
+ codec.process(function processSeeking(more) {
+ if (!more) {
+ readBytesAndWait();
+ } else if (seekState == SeekState.NOT_SEEKING) {
+ throw new Error('seeking in invalid state (not seeking?)');
+ } else if (seekState == SeekState.BISECT_TO_TARGET) {
+ doProcessBisectionSeek();
+ } else if (seekState == SeekState.BISECT_TO_KEYPOINT) {
+ doProcessBisectionSeek();
+ } else if (seekState == SeekState.LINEAR_TO_TARGET) {
+ doProcessLinearSeeking();
+ }
+ });
+
+ } else if (state == State.PLAYING) {
+
+ var demuxStartTime = getTimestamp();
+ codec.process(function doProcessPlay(more) {
+ var delta = getTimestamp() - demuxStartTime;
+ demuxingTime += delta;
+ lastFrameDecodeTime += delta;
+
+ //console.log(more, codec.audioReady, codec.frameReady, codec.audioTimestamp, codec.frameTimestamp);
+
+ if (!more) {
+ if (stream) {
+ // Ran out of buffered input
+ readBytesAndWait();
+ } else {
+ // Ran out of stream!
+ var finalDelay = 0;
+ if (codec.hasAudio) {
+ audioState = audioFeeder.getPlaybackState();
+ audioBufferedDuration = (audioState.samplesQueued / audioFeeder.targetRate);
+ finalDelay = audioBufferedDuration * 1000;
+ }
+ if (pendingAudio || pendingFrame || finalDelay > 0) {
+ pingProcessing(Math.max(0, finalDelay));
+ } else {
+ log("ENDING NOW");
+ stopVideo();
+ ended = true;
+ fireEvent('ended');
+ }
+ }
+ } else if (paused) {
+
+ // ok we're done for now!
+
+ } else {
+
+ if (!((codec.audioReady || !codec.hasAudio) && (codec.frameReady || !codec.frameReady))) {
+
+ log('need more data');
+
+ // Have to process some more pages to find data.
+ pingProcessing();
+
+ } else {
+
+ var audioBufferedDuration = 0,
+ audioDecodingDuration = 0,
+ audioState = null,
+ playbackPosition = 0,
+ nextDelays = [],
+ readyForAudioDecode,
+ readyForFrameDraw,
+ readyForFrameDecode;
+
+ if (codec.hasAudio && audioFeeder) {
+ // Drive on the audio clock!
+ audioState = audioFeeder.getPlaybackState();
+ playbackPosition = getPlaybackTime(audioState);
+
+ audioBufferedDuration = (audioState.samplesQueued / audioFeeder.targetRate);
+ //audioBufferedDuration = audioEndTimestamp - playbackPosition; // @fixme?
+
+ //console.log('audio buffered', audioBufferedDuration, audioDecodingDuration);
+
+ droppedAudio = audioState.dropped;
+ delayedAudio = audioState.delayed;
+ //readyForAudioDecode = audioState.samplesQueued <= (audioFeeder.bufferSize * 2);
+ var bufferDuration = (audioFeeder.bufferSize / audioFeeder.targetRate) * 2;
+ readyForAudioDecode = codec.audioReady && (audioBufferedDuration <= bufferDuration);
+
+ // Check in when all audio runs out
+ if (pendingAudio) {
+ // We'll check in when done decoding
+ } else if (!codec.audioReady) {
+ // NEED MOAR BUFFERS
+ nextDelays.push(-1);
+ } else if (codec.hasVideo && (playbackPosition - frameEndTimestamp) > bufferDuration) {
+ // don't get too far ahead of the video if it's slow!
+ readyForAudioDecode = false;
+ nextDelays.push((playbackPosition - frameEndTimestamp) * 1000);
+ } else {
+ // Check in when the audio buffer runs low again...
+ nextDelays.push((audioBufferedDuration - bufferDuration) * 1000);
+
+ // @todo figure out why the above doesn't do the job reliably
+ // with Flash audio shim on IE!
+ nextDelays.push(bufferDuration * 1000 / 4);
+ }
+ } else {
+ // No audio; drive on the general clock.
+ // @fixme account for dropped frame times...
+ playbackPosition = getPlaybackTime();
+ }
+
+ if (codec.hasVideo) {
+ var fudgeDelta = 0.1,
+ frameDelay = (frameEndTimestamp - playbackPosition) * 1000;
+
+ frameDelay = Math.max(0, frameDelay);
+ frameDelay = Math.min(frameDelay, targetPerFrameTime);
+
+ readyForFrameDraw = !!yCbCrBuffer && !pendingFrame && (frameDelay <= fudgeDelta);
+ readyForFrameDecode = !yCbCrBuffer && !pendingFrame && codec.frameReady;
+
+ if (yCbCrBuffer) {
+ // Check in when the decoded frame is due
+ nextDelays.push(frameDelay);
+ } else if (pendingFrame) {
+ // We'll check in when done decoding
+ } else if (!codec.frameReady) {
+ // need more data!
+ nextDelays.push(-1);
+ } else {
+ // Check in when the decoded frame is due
+ nextDelays.push(frameDelay);
+ }
+ }
+
+ log([playbackPosition, frameEndTimestamp, audioEndTimestamp, readyForFrameDraw, readyForFrameDecode, readyForAudioDecode].join(', '));
+
+ if (readyForFrameDraw) {
+
+ log('ready to draw frame');
+
+ // Ready to draw the decoded frame...
+ if (thumbnail) {
+ self.removeChild(thumbnail);
+ thumbnail = null;
+ }
+
+ drawingTime += time(function() {
+ frameSink.drawFrame(yCbCrBuffer);
+ });
+ yCbCrBuffer = null;
+
+ framesProcessed++;
+ framesPlayed++;
+
+ doFrameComplete();
+
+ pingProcessing(0);
+
+ } else if (readyForFrameDecode) {
+
+ log('ready to decode frame');
+
+ var videoStartTime = getTimestamp();
+ pendingFrame++;
+ if (videoInfo.fps == 0 && (codec.frameTimestamp - frameEndTimestamp) > 0) {
+ // WebM doesn't encode a frame rate
+ targetPerFrameTime = (codec.frameTimestamp - frameEndTimestamp) * 1000;
+ }
+ totalFrameTime += targetPerFrameTime;
+ totalFrameCount++;
+ frameEndTimestamp = codec.frameTimestamp;
+ var pendingFramePing = false;
+ codec.decodeFrame(function processingDecodeFrame(ok) {
+ log('decoded frame');
+ var delta = getTimestamp() - videoStartTime;
+ videoDecodingTime += delta;
+ lastFrameDecodeTime += delta;
+ if (ok) {
+ // Save the buffer until it's time to draw
+ yCbCrBuffer = codec.frameBuffer;
+ } else {
+ // Bad packet or something.
+ log('Bad video packet or something');
+ }
+ pendingFrame--;
+ if (!isProcessing()) {
+ pingProcessing();
+ }
+ });
+ if (!isProcessing()) {
+ pingProcessing();
+ }
+
+ } else if (readyForAudioDecode) {
+
+ log('ready for audio');
+
+ var audioStartTime = getTimestamp();
+ pendingAudio++;
+ audioEndTimestamp = codec.audioTimestamp;
+ codec.decodeAudio(function processingDecodeAudio(ok) {
+ log('decoded audio');
+ var delta = getTimestamp() - audioStartTime;
+ audioDecodingTime += delta;
+ lastFrameDecodeTime += delta;
+
+ if (ok) {
+ var buffer = codec.audioBuffer;
+ if (buffer) {
+ // Keep track of how much time we spend queueing audio as well
+ // This is slow when using the Flash shim on IE 10/11
+ bufferTime += time(function() {
+ audioFeeder.bufferData(buffer);
+ });
+ audioBufferedDuration += (buffer[0].length / audioInfo.rate) * 1000;
+ }
+ }
+ pendingAudio--;
+ if (!isProcessing()) {
+ pingProcessing();
+ }
+ });
+ if (!isProcessing()) {
+ pingProcessing();
+ }
+
+ } else {
+
+ var nextDelay = Math.min.apply(Math, nextDelays);
+ if (nextDelays.length > 0) {
+ log('idle: ' + nextDelay + ' - ' + nextDelays.join(','));
+ if (!codec.hasVideo) {
+ framesProcessed++; // pretend!
+ doFrameComplete();
+ }
+ pingProcessing(Math.max(0, nextDelay));
+ } else if (pendingFrame || pendingAudio) {
+ log('waiting on pending events');
+ } else {
+ log('we may be lost');
+ }
+ }
+ }
+ }
+ });
+
+ } else {
+
+ throw new Error('Unexpected OGVPlayer state ' + state);
+
+ }
+
+ depth--;
+ }
+
+ /**
+ * Are we waiting on an async operation we can't interrupt?
+ */
+ function isProcessing() {
+ return waitingOnInput || (codec && codec.processing);
+ }
+
+ function readBytesAndWait() {
+ waitingOnInput = true;
+ stream.readBytes();
+ }
+
+ function pingProcessing(delay) {
+ if (delay === undefined) {
+ delay = -1;
+ }
+ if (isProcessing()) {
+ throw new Error('REENTRANCY FAIL: asked to pingProcessing() while already waiting');
+ }
+ if (nextProcessingTimer) {
+ //log('canceling old processing timer');
+ clearTimeout(nextProcessingTimer);
+ nextProcessingTimer = null;
+ }
+ var fudge = -1 / 256;
+ if (delay > fudge) {
+ //log('pingProcessing delay: ' + delay);
+ nextProcessingTimer = setTimeout(doProcessing, delay);
+ } else {
+ //log('pingProcessing tail call (' + delay + ')');
+ tailCall(doProcessing);
+ }
+ }
+
+ var videoInfo,
+ audioInfo;
+
+ function startProcessingVideo() {
+ if (started || codec) {
+ return;
+ }
+
+ framesProcessed = 0;
+ demuxingTime = 0;
+ videoDecodingTime = 0;
+ audioDecodingTime = 0;
+ bufferTime = 0;
+ drawingTime = 0;
+ started = true;
+ ended = false;
+
+ codec = new codecClass(codecOptions);
+ codec.init(function() {
+ readBytesAndWait();
+ });
+ }
+
+ function loadCodec(callback) {
+ // @todo use the demuxer and codec interfaces directly
+ codecClassName = 'OGVWrapperCodec';
+
+ // @todo fix detection proper
+ if (enableWebM && self.src.match(/\.webm$/i)) {
+ codecOptions.type = 'video/webm';
+ } else {
+ codecOptions.type = 'video/ogg';
+ }
+
+ OGVLoader.loadClass(codecClassName, function(classObj) {
+ codecClass = classObj;
+ callback();
+ });
+ }
+
+ /**
+ * HTMLMediaElement load method
+ */
+ self.load = function() {
+ if (stream) {
+ // already loaded.
+ return;
+ }
+
+ started = false;
+ stream = new StreamFile({
+ url: self.src,
+ bufferSize: 65536 * 4,
+ onstart: function() {
+ // Fire off the read/decode/draw loop...
+ byteLength = stream.bytesTotal;
+
+ // If we get X-Content-Duration, that's as good as an explicit hint
+ var durationHeader = stream.getResponseHeader('X-Content-Duration');
+ if (typeof durationHeader === 'string') {
+ duration = parseFloat(durationHeader);
+ }
+ loadCodec(startProcessingVideo);
+ },
+ onread: function(data) {
+ log('got input');
+ waitingOnInput = false;
+
+ // Save chunk to pass into the codec's buffer
+ actionQueue.push(function doReceiveInput() {
+ codec.receiveInput(data, function() {
+ pingProcessing();
+ });
+ });
+
+ if (isProcessing()) {
+ // We're waiting on the codec already...
+ } else {
+ pingProcessing();
+ }
+ },
+ ondone: function() {
+ waitingOnInput = false;
+
+ if (state == State.SEEKING) {
+ pingProcessing();
+ } else if (state == State.SEEKING_END) {
+ pingProcessing();
+ } else {
+ log('closing stream (done)');
+ stream = null;
+
+ if (isProcessing()) {
+ // We're waiting on the codec already...
+ } else {
+ // Let the read/decode/draw loop know we're out!
+ pingProcessing();
+ }
+ }
+ },
+ onerror: function(err) {
+ console.log("reading error: " + err);
+ }
+ });
+ };
+
+ /**
+ * HTMLMediaElement canPlayType method
+ */
+ self.canPlayType = function(contentType) {
+ var type = new OGVMediaType(contentType);
+ if (type.minor === 'ogg' &&
+ (type.major === 'audio' || type.major === 'video' || type.major === 'application')) {
+ if (type.codecs) {
+ var supported = ['vorbis', 'opus', 'theora'],
+ knownCodecs = 0,
+ unknownCodecs = 0;
+ type.codecs.forEach(function(codec) {
+ if (supported.indexOf(codec) >= 0) {
+ knownCodecs++;
+ } else {
+ unknownCodecs++;
+ }
+ });
+ if (knownCodecs === 0) {
+ return '';
+ } else if (unknownCodecs > 0) {
+ return '';
+ }
+ // All listed codecs are ones we know. Neat!
+ return 'probably';
+ } else {
+ return 'maybe';
+ }
+ } else {
+ // @todo when webm support is more complete, handle it
+ return '';
+ }
+ };
+
+ /**
+ * HTMLMediaElement play method
+ */
+ self.play = function() {
+ if (!audioOptions.audioContext) {
+ OGVPlayer.initSharedAudioContext();
+ }
+
+ if (paused) {
+ startedPlaybackInDocument = document.body.contains(self);
+
+ paused = false;
+
+ if (started) {
+
+ log('.play() while already started');
+
+ actionQueue.push(function() {
+ startPlayback();
+ fireEvent('play');
+ pingProcessing(0);
+ });
+ if (isProcessing()) {
+ // waiting on the codec already
+ } else {
+ pingProcessing();
+ }
+
+ } else {
+
+ log('.play() before started');
+
+ // Let playback begin when metadata loading is complete
+ if (!stream) {
+ self.load();
+ }
+
+ }
+ }
+ };
+
+ /**
+ * custom getPlaybackStats method
+ */
+ self.getPlaybackStats = function() {
+ return {
+ targetPerFrameTime: targetPerFrameTime,
+ framesProcessed: framesProcessed,
+ playTime: playTime,
+ demuxingTime: demuxingTime,
+ videoDecodingTime: videoDecodingTime,
+ audioDecodingTime: audioDecodingTime,
+ bufferTime: bufferTime,
+ drawingTime: drawingTime,
+ droppedAudio: droppedAudio,
+ delayedAudio: delayedAudio,
+ jitter: totalJitter / framesProcessed
+ };
+ };
+ self.resetPlaybackStats = function() {
+ framesProcessed = 0;
+ playTime = 0;
+ demuxingTime = 0;
+ videoDecodingTime = 0;
+ audioDecodingTime = 0;
+ bufferTime = 0;
+ drawingTime = 0;
+ totalJitter = 0;
+ totalFrameTime = 0;
+ totalFrameCount = 0;
+ };
+
+ /**
+ * HTMLMediaElement pause method
+ */
+ self.pause = function() {
+ if (!stream) {
+ paused = true;
+ self.load();
+ } else if (!paused) {
+ clearTimeout(nextProcessingTimer);
+ nextProcessingTimer = null;
+ stopPlayback();
+ paused = true;
+ fireEvent('pause');
+ }
+ };
+
+ /**
+ * custom 'stop' method
+ */
+ self.stop = function() {
+ stopVideo();
+ };
+
+ /**
+ * HTMLMediaElement src property
+ */
+ self.src = "";
+
+ /**
+ * HTMLMediaElement buffered property
+ */
+ Object.defineProperty(self, "buffered", {
+ get: function getBuffered() {
+ var estimatedBufferTime;
+ if (stream && byteLength && duration) {
+ estimatedBufferTime = (stream.bytesBuffered / byteLength) * duration;
+ } else {
+ estimatedBufferTime = 0;
+ }
+ return new OGVTimeRanges([[0, estimatedBufferTime]]);
+ }
+ });
+
+ /**
+ * HTMLMediaElement seekable property
+ */
+ Object.defineProperty(self, "seekable", {
+ get: function getSeekable() {
+ if (self.duration < Infinity && stream && stream.seekable && codec && codec.seekable) {
+ return new OGVTimeRanges([[0, duration]]);
+ } else {
+ return new OGVTimeRanges([]);
+ }
+ }
+ });
+
+ /**
+ * HTMLMediaElement currentTime property
+ */
+ Object.defineProperty(self, "currentTime", {
+ get: function getCurrentTime() {
+ if (state == State.SEEKING) {
+ return seekTargetTime;
+ } else {
+ if (codec) {
+ if (state == State.PLAYING && !paused) {
+ return getPlaybackTime();
+ } else {
+ return initialPlaybackOffset;
+ }
+ } else {
+ return 0;
+ }
+ }
+ },
+ set: function setCurrentTime(val) {
+ if (stream && byteLength && duration) {
+ seek(val);
+ }
+ }
+ });
+
+ /**
+ * HTMLMediaElement duration property
+ */
+ Object.defineProperty(self, "duration", {
+ get: function getDuration() {
+ if (codec && codec.loadedMetadata) {
+ if (duration !== null) {
+ return duration;
+ } else {
+ return Infinity;
+ }
+ } else {
+ return NaN;
+ }
+ }
+ });
+
+ /**
+ * HTMLMediaElement paused property
+ */
+ Object.defineProperty(self, "paused", {
+ get: function getPaused() {
+ return paused;
+ }
+ });
+
+ /**
+ * HTMLMediaElement ended property
+ */
+ Object.defineProperty(self, "ended", {
+ get: function getEnded() {
+ return ended;
+ }
+ });
+
+ /**
+ * HTMLMediaElement ended property
+ */
+ Object.defineProperty(self, "seeking", {
+ get: function getEnded() {
+ return (state == State.SEEKING);
+ }
+ });
+
+ /**
+ * HTMLMediaElement muted property
+ */
+ Object.defineProperty(self, "muted", {
+ get: function getMuted() {
+ return muted;
+ },
+ set: function setMuted(val) {
+ muted = val;
+ if (audioFeeder) {
+ if (muted) {
+ audioFeeder.mute();
+ } else {
+ audioFeeder.unmute();
+ }
+ }
+ }
+ });
+
+ Object.defineProperty(self, "poster", {
+ get: function getPoster() {
+ return poster;
+ },
+ set: function setPoster(val) {
+ poster = val;
+ if (!started) {
+ if (thumbnail) {
+ self.removeChild(thumbnail);
+ }
+ thumbnail = new Image();
+ thumbnail.src = poster;
+ thumbnail.className = 'ogvjs-poster';
+ thumbnail.style.position = 'absolute';
+ thumbnail.style.top = '0';
+ thumbnail.style.left = '0';
+ thumbnail.style.width = '100%';
+ thumbnail.style.height = '100%';
+ thumbnail.style.objectFit = 'contain';
+ thumbnail.addEventListener('load', function() {
+ OGVPlayer.styleManager.appendRule('.' + instanceId, {
+ width: thumbnail.naturalWidth + 'px',
+ height: thumbnail.naturalHeight + 'px'
+ });
+ self.appendChild(thumbnail);
+ OGVPlayer.updatePositionOnResize();
+ });
+ }
+ }
+ });
+
+ // Video metadata properties...
+ Object.defineProperty(self, "videoWidth", {
+ get: function getVideoWidth() {
+ if (videoInfo) {
+ return videoInfo.displayWidth;
+ } else {
+ return 0;
+ }
+ }
+ });
+ Object.defineProperty(self, "videoHeight", {
+ get: function getVideoHeight() {
+ if (videoInfo) {
+ return videoInfo.displayHeight;
+ } else {
+ return 0;
+ }
+ }
+ });
+ Object.defineProperty(self, "ogvjsVideoFrameRate", {
+ get: function getOgvJsVideoFrameRate() {
+ if (videoInfo) {
+ if (videoInfo.fps == 0) {
+ return totalFrameCount / (totalFrameTime / 1000);
+ } else {
+ return videoInfo.fps;
+ }
+ } else {
+ return 0;
+ }
+ }
+ });
+
+ // Audio metadata properties...
+ Object.defineProperty(self, "ogvjsAudioChannels", {
+ get: function getOgvJsAudioChannels() {
+ if (audioInfo) {
+ return audioInfo.channels;
+ } else {
+ return 0;
+ }
+ }
+ });
+ Object.defineProperty(self, "ogvjsAudioSampleRate", {
+ get: function getOgvJsAudioChannels() {
+ if (audioInfo) {
+ return audioInfo.rate;
+ } else {
+ return 0;
+ }
+ }
+ });
+
+ // Display size...
+ var width = 0, height = 0;
+ Object.defineProperty(self, "width", {
+ get: function getWidth() {
+ return width;
+ },
+ set: function setWidth(val) {
+ width = parseInt(val, 10);
+ self.style.width = width + 'px';
+ }
+ });
+
+ Object.defineProperty(self, "height", {
+ get: function getHeight() {
+ return height;
+ },
+ set: function setHeight(val) {
+ height = parseInt(val, 10);
+ self.style.height = height + 'px';
+ }
+ });
+
+ // Events!
+
+ /**
+ * custom onframecallback, takes frame decode time in ms
+ */
+ self.onframecallback = null;
+
+ /**
+ * Called when all metadata is available.
+ * Note in theory we must know 'duration' at this point.
+ */
+ self.onloadedmetadata = null;
+
+ /**
+ * Called when we start playback
+ */
+ self.onplay = null;
+
+ /**
+ * Called when we get paused
+ */
+ self.onpause = null;
+
+ /**
+ * Called when playback ends
+ */
+ self.onended = null;
+
+ return self;
+};
+
+OGVPlayer.initSharedAudioContext = function() {
+ AudioFeeder.initSharedAudioContext();
+};
+
+OGVPlayer.instanceCount = 0;
+
+function StyleManager() {
+ var self = this;
+ var el = document.createElement('style');
+ el.type = 'text/css';
+ el.textContent = 'ogvjs { display: inline-block; position: relative; }';
+ document.head.appendChild(el);
+
+ var sheet = el.sheet;
+
+ self.appendRule = function(selector, defs) {
+ var bits = [];
+ for (var prop in defs) {
+ if (defs.hasOwnProperty(prop)) {
+ bits.push(prop + ':' + defs[prop]);
+ }
+ }
+ var rule = selector + '{' + bits.join(';') + '}';
+ sheet.insertRule(rule, sheet.length - 1);
+ };
+}
+OGVPlayer.styleManager = new StyleManager();
+
+// IE 10/11 and Edge 12 don't support object-fit.
+// Chrome 43 supports it but it doesn't work on <canvas>!
+// Safari for iOS 8/9 supports it but positions our <canvas> incorrectly >:(
+// Also just for fun, IE 10 doesn't support 'auto' sizing on canvas. o_O
+//OGVPlayer.supportsObjectFit = (typeof document.createElement('div').style.objectFit === 'string');
+OGVPlayer.supportsObjectFit = false;
+if (OGVPlayer.supportsObjectFit) {
+ OGVPlayer.updatePositionOnResize = function() {
+ // no-op
+ };
+} else {
+ OGVPlayer.updatePositionOnResize = function() {
+ function fixup(el, width, height) {
+ var container = el.offsetParent || el.parentNode,
+ containerAspect = container.offsetWidth / container.offsetHeight,
+ intrinsicAspect = width / height;
+ if (intrinsicAspect > containerAspect) {
+ var vsize = container.offsetWidth / intrinsicAspect,
+ vpad = (container.offsetHeight - vsize) / 2;
+ el.style.width = '100%';
+ el.style.height = vsize + 'px';
+ el.style.marginLeft = 0;
+ el.style.marginRight = 0;
+ el.style.marginTop = vpad + 'px';
+ el.style.marginBottom = vpad + 'px';
+ } else {
+ var hsize = container.offsetHeight * intrinsicAspect,
+ hpad = (container.offsetWidth - hsize) / 2;
+ el.style.width = hsize + 'px';
+ el.style.height = '100%';
+ el.style.marginLeft = hpad + 'px';
+ el.style.marginRight = hpad + 'px';
+ el.style.marginTop = 0;
+ el.style.marginBottom = 0;
+ }
+ }
+ function queryOver(selector, callback) {
+ var nodeList = document.querySelectorAll(selector),
+ nodeArray = Array.prototype.slice.call(nodeList);
+ nodeArray.forEach(callback);
+ }
+
+ queryOver('ogvjs > canvas', function(canvas) {
+ fixup(canvas, canvas.width, canvas.height);
+ });
+ queryOver('ogvjs > img', function(poster) {
+ fixup(poster, poster.naturalWidth, poster.naturalHeight);
+ });
+ };
+ var fullResizeVideo = function() {
+ // fullscreens may ping us before the resize happens
+ setTimeout(OGVPlayer.updatePositionOnResize, 0);
+ };
+
+ window.addEventListener('resize', OGVPlayer.updatePositionOnResize);
+ window.addEventListener('orientationchange', OGVPlayer.updatePositionOnResize);
+
+ document.addEventListener('fullscreenchange', fullResizeVideo);
+ document.addEventListener('mozfullscreenchange', fullResizeVideo);
+ document.addEventListener('webkitfullscreenchange', fullResizeVideo);
+ document.addEventListener('MSFullscreenChange', fullResizeVideo);
+}
+
+
+// exports
+this.OGVLoader = OGVLoader;
+this.OGVMediaType = OGVMediaType;
+this.OGVTimeRanges = OGVTimeRanges;
+this.OGVPlayer = OGVPlayer;
+
+})();
+
+this.OGVVersion = "1.0-20150904182230-dd3c8e8";
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/readme.md b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/readme.md
new file mode 100644
index 00000000..6d58ac6f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/readme.md
@@ -0,0 +1,237 @@
+ogv.js
+======
+
+Media decoder and player for Ogg Vorbis/Opus/Theora and (experimentally) WebM video.
+
+Based around libogg, libvorbis, libtheora, libopus, libvpx, and libnestegg compiled to JavaScript with Emscripten.
+
+## Updates
+
+* 1.0 - 2015-09-04
+ * initial stable release, as used on Wikipedia
+
+## Current status
+
+As of August 2015, ogv.js can be seen in action [on Wikipedia and Wikimedia Commons](https://commons.wikimedia.org/wiki/Commons:Video) in Safari and IE/Edge where native Ogg and WebM playback is not available. (See [technical details on MediaWiki integration](https://www.mediawiki.org/wiki/Extension:TimedMediaHandler/ogv.js).)
+
+See also a standalone demo with performance metrics at https://brionv.com/misc/ogv.js/demo/
+
+* streaming: yes (with Range header)
+* seeking: yes for Ogg (with Range header), no for WebM
+* color: yes
+* audio: yes, with a/v sync (requires Web Audio or Flash)
+* background threading: yes (video, audio decoders in Workers)
+* [GPU accelerated drawing: yes (WebGL)](https://github.com/brion/ogv.js/wiki/GPU-acceleration)
+* GPU accelerated decoding: no
+* SIMD acceleration: no
+* controls: no (currently provided by demo or other UI harness)
+
+Ogg files are fairly well supported, but WebM is still very experimental.
+
+
+## Goals
+
+Long-form goal is to create a drop-in replacement for the HTML5 video and audio tags which can be used for basic playback of Ogg Theora and Vorbis or WebM media on browsers that don't support Ogg or WebM natively.
+
+The API isn't quite complete, but works pretty well.
+
+
+## Compatibility
+
+ogv.js requires a fast JS engine with typed arrays, and either Web Audio or Flash for audio playback.
+
+The primary target browsers are (testing 360p/30fps):
+* Safari 6.1/7/8 on Mac OS X 10.7-10.10
+* Safari on iOS 8 64-bit
+* Edge on Windows 10 desktop/tablet
+* Internet Explorer 10/11 on Windows 7/8/8.1 (desktop/tablet)
+
+And for lower-resolution files (testing 160p/15fps):
+* Safari on iOS 8 32-bit
+* Edge on Windows 10 Mobile
+* Internet Explorer 10/11 on Windows RT
+
+Older versions of Safari have flaky JIT compilers. IE 9 and below lack typed arrays.
+
+(Note that Windows and Mac OS X can support Ogg and WebM by installing codecs or alternate browsers with built-in support, but this is not possible on iOS, Windows RT, or Windows 10 Mobile.)
+
+Testing browsers (these support .ogv natively):
+* Firefox 40
+* Chrome 44
+
+
+## Usage
+
+The `OGVPlayer` class implements a player, and supports a subset of the events, properties and methods from [HTMLMediaElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement) and [HTMLVideoElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement).
+
+```
+ // Create a new player with the constructor
+ var player = new OGVPlayer();
+
+ // Or with options
+ var player = new OGVPlayer({
+ enableWebM: true
+ });
+
+ // Now treat it just like a video or audio element
+ containerElement.appendChild(player);
+ player.src = 'path/to/media.ogv';
+ player.play();
+ player.addEventListener('ended', function() {
+ // ta-da!
+ });
+```
+
+To check for compatibility before creating a player, include `ogv-support.js` and use the `OGVCompat` API:
+
+```
+ if (OGVCompat.supported('OGVPlayer')) {
+ // go load the full player from ogv.js and instantiate stuff
+ }
+```
+
+This will check for typed arrays, audio/Flash, blacklisted iOS versions, and super-slow/broken JIT compilers.
+
+If you need a URL versioning/cache-buster parameter for dynamic loading of `ogv.js`, you can use the `OGVVersion` symbol provided by `ogv-support.js` or the even tinier `ogv-version.js`:
+
+```
+ var script = document.createElement('script');
+ script.src = 'ogv.js?version=' + encodeURIComponent(OGVVersion);
+ document.querySelector('head').appendChild(script);
+```
+
+Usually, ogv.js will auto-detect the path to its resources based on the script element that loads ogv.js or ogv-support.js. If you load ogv.js through a non-customary bundler (such as MediaWiki's ResourceLoader) you may need to override this manually before instantiating players:
+
+```
+ // Path to ogv-demuxer-ogg.js, ogv-worker-audio.js, dynamicaudio.swf etc
+ OGVLoader.base = '/path/to/resources';
+```
+
+
+## Performance
+
+As of 2015, for SD-or-less resolution basic Ogg Theora decoding speed is reliable on desktop and newer high-end mobile devices; current high-end desktops and laptops can even reach HD resolutions. Older and low-end mobile devices may have difficulty on any but audio and the lowest-resolution video files.
+
+WebM is much slower, and remains experimental.
+
+*Low-res targets*
+
+I've gotten acceptable performance for Vorbis audio and 160p/15fps Theora files on 32-bit iOS devices: iPhone 4s, iPod Touch 5th-gen and iPad 3. These have difficulty at 240p and above, and just won't keep up with higher resolutions.
+
+Meanwhile, newer 64-bit iPhones and iPads are comparable to low-end laptops, and videos at 360p and often 480p play acceptably. Since 32-bit and 64-bit iOS devices have the same user-agent, a benchmark must be used to approximately test minimum CPU speed.
+
+(On iOS 8, Safari performs significantly better than Chrome or other alternative browsers that are unable to enable the JIT due to iOS limitations on third-party developers. Again, a benchmark must be used to detect slow performance, as the browser remains otherwise compatible.)
+
+
+Windows on 32-bit ARM platforms is similar... IE 11 on Windows RT 8.1 on a Surface tablet (NVidia Tegra 3), and Edge on Windows 10 Mobile build 10166 on a Lumia 635, perform acceptably with audio and with 160p/15fps videos but have trouble starting around 240p.
+
+
+In both cases, a native application looms as a possibly better alternative. See [OGVKit ](https://github.com/brion/OGVKit) and [OgvRt](https://github.com/brion/OgvRT) projects for experiments in those directions.
+
+
+Note that at these lower resolutions, Vorbis audio and Theora video decoding are about equally expensive operations -- dual-core phones and tablets should be able to eek out a little parallelism here thanks to audio and video being in separate Worker threads.
+
+
+*WebGL drawing acceleration*
+
+Accelerated YCbCr->RGB conversion and drawing is done using WebGL on supporting browsers (Firefox, Chrome, IE 11, Edge, and Safari for iOS 8 & OS X 10.9), and is enabled by default if available.
+
+WebGL noticeably improves playback performance at HD and SD resolutions.
+
+Early versions of IE 11 do not support luminance or alpha textures, and in IE 11 update 1 and Edge they are still unexpectedly slow on Windows (in all browsers so far). As a workaround, on Windows the data is packed into RGBA textures for faster texture upload and unpacked in the shader. See [GPU acceleration page](https://github.com/brion/ogv.js/wiki/GPU-acceleration) for more info.
+
+
+It may be possible to do further acceleration of actual decoding operations using WebGL shaders, but this could be ... tricky. WebGL is also only available on the main thread, and there are no compute shaders yet so would have to use fragment shaders.
+
+
+## Difficulties
+
+*Threading*
+
+Currently the video and audio codecs run in worker threads by default, while the demuxer
+and player logic run on the UI thread. This seems to work pretty well.
+
+There is some overhead in extracting data out of each emscripten module's heap and in the thread-to-thread communications, but the parallelism and smoother main thread makes up for it.
+
+
+*Streaming download*
+
+In IE and Edge, the (MS-prefixed) Stream/StreamReader interface is used to read data on demand into ArrayBuffer objects.
+
+In Firefox, the 'moz-chunked-array' responseType on XHR is used to read data as ArrayBuffer chunks during download. Safari and Chrome use a 'binary string' read which requires manually converting input to ArrayBuffer chunks.
+
+The Firefox and Safari/Chrome cases have been hacked up to do streaming buffering by chunking the requests at up to a megabyte each, using the HTTP Range header. For cross-site playback, this requires CORS setup to whitelist the Range header!
+
+[Safari has a bug with Range headers](https://bugs.webkit.org/show_bug.cgi?id=82672) which is worked around as necessary with a 'cache-busting' URL string parameter. Hopefully this will be fixed in future versions of Mac OS X and iOS.
+
+
+*Seeking*
+
+Seeking is implemented via the HTTP Range: header.
+
+For Ogg files with keyframe indices in a skeleton index, seeking is very fast. Otherwise, a bisection search is used to locate the target frame or audio position, which is very slow over the internet as it creates a lot of short-lived HTTP requests.
+
+For WebM files, seeking is not yet supported; this will require refactoring the demuxer modules to present a synchronous i/o abstraction to the demuxer library.
+
+As with chunked streaming, cross-site playback requires CORS support for the Range header.
+
+
+*Audio output*
+
+Firefox, Safari, Chrome, and Edge support the W3C Web Audio API.
+
+IE doesn't support Web Audio, but does bundle the Flash player in Windows 8/8.1/RT. A small Flash shim is included here and used as a fallback -- thanks to Maik Merten for hacking some pieces together and getting this working!
+
+A/V synchronization is performed on files with both audio and video, and seems to
+actually work. Yay!
+
+Note that autoplay doesn't work on iOS Safari due to limitations with starting audio playback from event handlers.
+
+
+*WebM*
+
+WebM support was added in June 2015, and is currently very experimental. Not everything works yet, and performance is pretty bad. See [issue tracker for WebM milestone](https://github.com/brion/ogv.js/milestones/WebM%20playback) on the GitHub page.
+
+The i/o model of the nestegg WebM container demuxing library is a bit different from what ogv.js was designed around so seeking is not yet supported and it may sometimes cut off partway through a file. Needs more work.
+
+To enable, set `enableWebM: true` in your `options` array.
+
+
+## Upstream library notes
+
+We've experimented with tremor (libivorbis), an integer-only variant of libvorbis. This actually does *not* decode faster, but does save about 200kb off our generated JavaScript, presumably thanks to not including an encoder in the library. However on slow devices like iPod Touch 5th-generation, it makes a significant negative impact on the decode time so we've gone back to libvorbis.
+
+The Ogg Skeleton library (libskeleton) is a bit ... unfinished and is slightly modified here.
+
+
+## Building JS components
+
+Building ogv.js is known to work on Mac OS X and Linux (tested Ubuntu 15.04).
+
+1. You will need autoconf, automake, libtool, and pkg-config. These can be installed through Homebrew on Mac OS X, or through distribution-specific methods on Linux.
+2. Install [Emscripten](http://kripken.github.io/emscripten-site/docs/getting_started/Tutorial.html); currently using the 1.34.1 SDK release for distribution builds.
+3. `git submodule update --init`
+4. Run `make js` to configure and build the libraries and the C wrapper
+
+
+## Building Flash components
+
+Rebuilding dynamicaudio.swf shim for IE 10/11:
+
+1. Install [Apache Flex SDK](http://flex.apache.org/), and put it into PATH
+2. `make swf` to rebuild src/dynamicaudio.swf
+3. `make` to rebuild the demo and update its .swf
+
+
+## Building the demo
+
+If you did all the setup above, just run `make demo` or `make`. Look in build/demo/ and enjoy!
+
+
+## License
+
+libogg, libvorbis, libtheora, libopus, nestegg, and libvpx are available under their respective licenses, and the JavaScript and C wrapper code in this repo is licensed under MIT.
+
+Based on build scripts from https://github.com/devongovett/ogg.js
+
+dynamicaudio.as and other Flash-related bits are based on code under BSD license, (c) 2010 Ben Firshman (see src/AudioFeeder.js flash fallback section).
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/af.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/af.json
new file mode 100644
index 00000000..14191ff4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/af.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Naudefj"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Naam: $1",
+ "mwe-embedplayer-loading_plugin": "laai uitbreiding ...",
+ "mwe-embedplayer-add_to_end_of_sequence": "Voeg by aan die einde van die reeks",
+ "mwe-embedplayer-volume_control": "Volumebeheer",
+ "mwe-embedplayer-download": "Aflaai",
+ "mwe-embedplayer-share": "Deel",
+ "mwe-embedplayer-credits": "Krediete",
+ "mwe-embedplayer-menu_btn": "Keuses",
+ "mwe-embedplayer-close_btn": "Sluit",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-uitbreiding",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-selected": "(gekies)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-embed_site_or_blog": "Voeg by jou webblad of webjoernaal"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/aln.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/aln.json
new file mode 100644
index 00000000..519ac9d6
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/aln.json
@@ -0,0 +1,34 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mdupont"
+ ]
+ },
+ "mwe-embedplayer-share_this_video": "Share this video",
+ "mwe-embedplayer-video_credits": "kreditë Video",
+ "mwe-embedplayer-kaltura-platform-title": "video Kaltura me burim të hapur platformën",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Afër",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC player",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 lojtar ZQM",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 lojtar H.264",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Generic Ogg plugin",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime plugin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "lojtar Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(Zgjedhur)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "Flash Vorbis OMTK",
+ "mwe-embedplayer-for_best_experience": "Për një përvojë më të mirë video rishikim të këshillojmë <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">Firefox fundit</a> .",
+ "mwe-embedplayer-do_not_warn_again": "Shkarkojë tani për tani.",
+ "mwe-embedplayer-playerSelect": "Lojtaret",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Lexoni kete</a> para se embedding.",
+ "mwe-embedplayer-embed_site_or_blog": "Embed në një faqe",
+ "mwe-embedplayer-related_videos": "Related videos",
+ "mwe-embedplayer-seeking": "kërkojnë",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-flv": "Flash video",
+ "mwe-embedplayer-video-ogg": "video Ogg",
+ "mwe-embedplayer-video-audio": "Ogg audio",
+ "mwe-embedplayer-missing-source": "Nuk ka video burim u gjet."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ar.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ar.json
new file mode 100644
index 00000000..8f53df42
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ar.json
@@ -0,0 +1,59 @@
+{
+ "@metadata": {
+ "authors": [
+ "Alzahrani",
+ "Meno25",
+ "OsamaK",
+ "روخو"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "عنوان: $1",
+ "mwe-embedplayer-credit-date": "تاريخ: $1",
+ "mwe-embedplayer-credit-author": "المؤلف: $1",
+ "mwe-embedplayer-loading_plugin": "تحميل ملحق...",
+ "mwe-embedplayer-select_playback": "تعيين تفضيلات التشغيل",
+ "mwe-embedplayer-add_to_end_of_sequence": "أضف إلى نهاية السلسلة",
+ "mwe-embedplayer-missing_video_stream": "ملف الفيديو لهذا النسق مفقود",
+ "mwe-embedplayer-play_clip": "شغّل المقطع",
+ "mwe-embedplayer-pause_clip": "ألبث المقطع",
+ "mwe-embedplayer-volume_control": "التحكم بحجم الصوت",
+ "mwe-embedplayer-player_options": "خيارات المُشغّل",
+ "mwe-embedplayer-player_fullscreen": "املأ الشاشة",
+ "mwe-embedplayer-next_clip_msg": "شغّل المقطع التالي",
+ "mwe-embedplayer-prev_clip_msg": "شغل المقطع السابق",
+ "mwe-embedplayer-current_clip_msg": "متابعة تشغيل هذا المقطع",
+ "mwe-embedplayer-seek_to": "ابحث في $1",
+ "mwe-embedplayer-paused": "ايقاف مؤقت",
+ "mwe-embedplayer-download_segment": "نزّل المحدد:",
+ "mwe-embedplayer-download_full": "تحميل كامل ملف الفيديو:",
+ "mwe-embedplayer-download_right_click": "لتحميل, اضغط بزر الفارة الايمن واختر <i>حفظ الرابط كـ...</i>",
+ "mwe-embedplayer-download_clip": "نزّل الفيديو",
+ "mwe-embedplayer-download_text": "تحميل النص",
+ "mwe-embedplayer-download": "نزّل",
+ "mwe-embedplayer-share": "مشاركة",
+ "mwe-embedplayer-about-library": "عن مشغل كالشورا",
+ "mwe-embedplayer-clip_linkback": "صفحة مصدر المقطع",
+ "mwe-embedplayer-choose_player": "اختر مشغل الفيديو",
+ "mwe-embedplayer-no-player": "لا يوجد مشغل لـ $1",
+ "mwe-embedplayer-share_this_video": "شارك هذا الفيديو",
+ "mwe-embedplayer-kaltura-platform-title": "كالشورا منصة فيديو مفتوحة المصدر",
+ "mwe-embedplayer-menu_btn": "قائمة",
+ "mwe-embedplayer-close_btn": "أغلق",
+ "mwe-embedplayer-ogg-player-vlc-player": "المشغل VLC",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "اضافة لبرنامج كويك تايم",
+ "mwe-embedplayer-ogg-player-cortado": "جافا كورتادو",
+ "mwe-embedplayer-ogg-player-kplayer": "مشغل كالشورا",
+ "mwe-embedplayer-ogg-player-selected": "(مختار)",
+ "mwe-embedplayer-for_best_experience": "للحصول على أفضل تجربة لعرض الفيديو نحن ننصح بـ <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">مستعرض HTML5 للفيديو</a>",
+ "mwe-embedplayer-fullscreen-tip": "اضغط <b>F11</b> لتبديل <i>متصفح الوب</i> لوضع الشاشة الكاملة",
+ "mwe-embedplayer-fullscreen-tip-osx": "اضغط <b>shift ⌘ F</b> لوضع شاشة كاملة",
+ "mwe-embedplayer-do_not_warn_again": "لا تظهر هذه الرسالة في المرة القادمة",
+ "mwe-embedplayer-playerSelect": "لاعبون",
+ "mwe-embedplayer-related_videos": "فيديوهات ذات صلة",
+ "mwe-embedplayer-video-h264": "فيديو بترمز H.264",
+ "mwe-embedplayer-video-webm": "فيديو بترمز WebM",
+ "mwe-embedplayer-video-flv": "فلاش فيديو",
+ "mwe-embedplayer-video-ogg": "فيديو بترمز Ogg",
+ "mwe-embedplayer-video-audio": "صوت بترمز Ogg",
+ "mwe-embedplayer-missing-source": "لم يعثر على مصدر الفيديو"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/arc.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/arc.json
new file mode 100644
index 00000000..ef336c30
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/arc.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Basharh"
+ ]
+ },
+ "mwe-embedplayer-credit-author": "ܣܝܘܡܐ: $1"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ast.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ast.json
new file mode 100644
index 00000000..1745c4fb
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ast.json
@@ -0,0 +1,89 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xuacu"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Títulu: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "Nun hai créditos disponibles",
+ "mwe-embedplayer-loading_plugin": "Cargando complementu...",
+ "mwe-embedplayer-select_playback": "Configurar preferencies de reproducción",
+ "mwe-embedplayer-link_back": "Enllazar de vuelta",
+ "mwe-embedplayer-error_swap_vid": "Error: mwEmbed nun pudo intercambiar la etiqueta de videu pa la interfaz de mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Amestar al final de la secuencia",
+ "mwe-embedplayer-missing_video_stream": "Falta'l ficheru de videu d'esta canal",
+ "mwe-embedplayer-play_clip": "Reproducir clip",
+ "mwe-embedplayer-pause_clip": "Posar clip",
+ "mwe-embedplayer-volume_control": "Control de volume",
+ "mwe-embedplayer-player_options": "Opciones del reproductor",
+ "mwe-embedplayer-timed_text": "Testu sincronizáu",
+ "mwe-embedplayer-player_fullscreen": "Pantalla completa",
+ "mwe-embedplayer-next_clip_msg": "Reproducir el siguiente clip",
+ "mwe-embedplayer-prev_clip_msg": "Reproducir el clip anterior",
+ "mwe-embedplayer-current_clip_msg": "Siguir reproduciendo esti clip",
+ "mwe-embedplayer-seek_to": "Buscar $1",
+ "mwe-embedplayer-paused": "en pausa",
+ "mwe-embedplayer-download_segment": "Descargar seleición:",
+ "mwe-embedplayer-download_full": "Descargar el ficheru de videu completu:",
+ "mwe-embedplayer-download_right_click": "Pa descargar, faiga click col botón drechu y seleicione <i>Guardar enllaz como...</i>",
+ "mwe-embedplayer-download_clip": "Descargar el videu",
+ "mwe-embedplayer-download_text": "Descargar testu",
+ "mwe-embedplayer-download": "Descargar",
+ "mwe-embedplayer-share": "Compartir",
+ "mwe-embedplayer-credits": "Créditos",
+ "mwe-embedplayer-about-library": "Tocante al reproductor Kaltura",
+ "mwe-embedplayer-about-library-desc": "La biblioteca HTML5 de Kaltura permite-y aprovechar güei les etiquetes de HTML5 &lt;video&gt; y &lt;audio&gt; con una interfaz de reproductor constante ente los navegadores más importantes.\n\t\n[$1 Más información sobro la biblioteca del reproductor Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Páxina d'orixe del clip",
+ "mwe-embedplayer-choose_player": "Escoyer el reproductor de videu",
+ "mwe-embedplayer-no-player": "Nun hai nengún reproductor disponible pa $1",
+ "mwe-embedplayer-share_this_video": "Compartir esti videu",
+ "mwe-embedplayer-video_credits": "Créditos del videu",
+ "mwe-embedplayer-no-video_credits": "Nun hai créditos disponibles",
+ "mwe-embedplayer-kaltura-platform-title": "Plataforma de videu de códigu abiertu Kaltura",
+ "mwe-embedplayer-menu_btn": "Menú",
+ "mwe-embedplayer-close_btn": "Zarrar",
+ "mwe-embedplayer-ogg-player-vlc-player": "Reproductor VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Reproductor Ogg HTML5",
+ "mwe-embedplayer-ogg-player-mp3Native": "Reproductor MP3 HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Reproductor AAC HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Reproductor H.264 HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Reproductor WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Complementu Ogg xenéricu",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "app VLC pa iOS",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Complementu QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX QuickTime",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Reproductor Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(seleicionáu)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Pa una meyor esperiencia de reproducción de videu recomendamos un <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">navegador de videu HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Nun se detectó nengún reproductor compatible integráu col navegador: pa una reproducción integrada nel navegador, descargue la [$1 última versión de Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Calque <b>F11</b> pa conmutar la pantalla completa del <i>navegador web</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Calque <b>mayús ⌘ F</b> pa conmutar la pantalla completa",
+ "mwe-embedplayer-do_not_warn_again": "Nun amosar esti mensaxe nel futuru",
+ "mwe-embedplayer-playerSelect": "Reproductores",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Llea esto</a> enantes d'inxertar.",
+ "mwe-embedplayer-embed_site_or_blog": "Inxertar nuna páxina",
+ "mwe-embedplayer-embed_wiki": "Inxertar nuna wiki",
+ "mwe-embedplayer-related_videos": "Videos rellacionaos",
+ "mwe-embedplayer-seeking": "buscando",
+ "mwe-embedplayer-buffering": "cargando nel búfer",
+ "mwe-embedplayer-video-h264": "Videu H.264",
+ "mwe-embedplayer-video-webm": "Videu WebM",
+ "mwe-embedplayer-video-flv": "Videu Flash",
+ "mwe-embedplayer-video-ogg": "Videu Ogg",
+ "mwe-embedplayer-video-audio": "Soníu Ogg",
+ "mwe-embedplayer-audio-mpeg": "Soníu MPEG",
+ "mwe-embedplayer-video-3gp": "Videu 3GP",
+ "mwe-embedplayer-video-mpeg": "Videu MPEG",
+ "mwe-embedplayer-video-msvideo": "Videu AVI",
+ "mwe-embedplayer-missing-source": "Nun s'alcontró'l videu orixinal.",
+ "mwe-embedplayer-vlcapp-intro": "Pa ver videos d'esti sitiu nun iPhone o iPad, necesites la $1 de baldre.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "app VLC",
+ "mwe-embedplayer-vlcapp-downloadapp": "Descarga la app VLC dende la App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Abri esti videu na app VLC",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Descarga esti videu",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Pa reproducir videos d'esti sitiu, necesites la app de baldre VLC. ¿Instalala agora?"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/az.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/az.json
new file mode 100644
index 00000000..7ad7f7de
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/az.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cekli829"
+ ]
+ },
+ "mwe-embedplayer-credit-date": "Tarix: $1",
+ "mwe-embedplayer-credit-author": "Müəllif: $1",
+ "mwe-embedplayer-download": "Yüklə"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ba.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ba.json
new file mode 100644
index 00000000..9a304406
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ba.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Haqmar"
+ ]
+ },
+ "mwe-embedplayer-video-h264": "H.264 видео",
+ "mwe-embedplayer-video-webm": "WebM видео",
+ "mwe-embedplayer-video-flv": "Flash видео",
+ "mwe-embedplayer-video-ogg": "Ogg видео",
+ "mwe-embedplayer-video-audio": "Ogg аудио",
+ "mwe-embedplayer-audio-mpeg": "MPEG аудио",
+ "mwe-embedplayer-video-3gp": "3GP видео",
+ "mwe-embedplayer-video-mpeg": "MPEG видео",
+ "mwe-embedplayer-video-msvideo": "AVI видео"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/be-tarask.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/be-tarask.json
new file mode 100644
index 00000000..6b26cd9f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/be-tarask.json
@@ -0,0 +1,86 @@
+{
+ "@metadata": {
+ "authors": [
+ "EugeneZelenko",
+ "Jim-by",
+ "Wizardist",
+ "Zedlik"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Назва: $1",
+ "mwe-embedplayer-credit-date": "Дата: $1",
+ "mwe-embedplayer-credit-author": "Аўтар: $1",
+ "mwe-embedplayer-nocredits": "Зьвестак пра аўтараў няма",
+ "mwe-embedplayer-loading_plugin": "Загружаецца дапаўненьне …",
+ "mwe-embedplayer-select_playback": "Устанавіць настройкі прайграваньня",
+ "mwe-embedplayer-link_back": "Адваротная спасылка",
+ "mwe-embedplayer-error_swap_vid": "Памылка: mwEmbed ня змог памяняць відэа тэг для інтэрфэйсу mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Дадаць у канец пасьлядоўнасьці",
+ "mwe-embedplayer-missing_video_stream": "Відэа-файл для гэтага струменя адсутнічае",
+ "mwe-embedplayer-play_clip": "Прайграць кліп",
+ "mwe-embedplayer-pause_clip": "Прыпыніць прайграваньне",
+ "mwe-embedplayer-volume_control": "Рэгуляваньне гучнасьці",
+ "mwe-embedplayer-player_options": "Налады прайгравальніка",
+ "mwe-embedplayer-timed_text": "Сынхранізаваны тэкст",
+ "mwe-embedplayer-player_fullscreen": "На ўвесь экран",
+ "mwe-embedplayer-next_clip_msg": "Прайграць наступны кліп",
+ "mwe-embedplayer-prev_clip_msg": "Прайграць папярэдні кліп",
+ "mwe-embedplayer-current_clip_msg": "Працягваць прайграваньне гэтай часткі файла",
+ "mwe-embedplayer-seek_to": "Перайсьці да $1",
+ "mwe-embedplayer-paused": "паўза",
+ "mwe-embedplayer-download_segment": "Выбар загрузкі:",
+ "mwe-embedplayer-download_full": "Загрузіць поўны відэа-файл:",
+ "mwe-embedplayer-download_right_click": "Для загрузкі націсьніце правую кнопку мышкі і выберыце <i>Захаваць спасылку як…</i>",
+ "mwe-embedplayer-download_clip": "Загрузіць відэа",
+ "mwe-embedplayer-download_text": "Загрузіць тэкст",
+ "mwe-embedplayer-download": "Загрузіць",
+ "mwe-embedplayer-share": "Зрабіць агульным",
+ "mwe-embedplayer-credits": "Стваральнікі",
+ "mwe-embedplayer-about-library": "Пра прайгравальнік Kaltura",
+ "mwe-embedplayer-about-library-desc": "HTML5 мэдыя-бібліятэка Kaltura дазваляе Вам выкарыстоўваць перавагамі HTML5 <code><nowiki><video></nowiki></code> і <code><nowiki><audio></nowiki></code> тэгаў ужо зараз, з аднолькавым інтэрфэйсам прайграваньня ва ўсіх асноўных браўзэрах.\n\t\n[$1 даведацца болей пра бібліятэку прайгравальніка Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Крынічная старонка часткі файла",
+ "mwe-embedplayer-choose_player": "Выберыце відэа-прайгравальнік",
+ "mwe-embedplayer-no-player": "Няма прайгравальніка для $1",
+ "mwe-embedplayer-share_this_video": "Зрабіць гэтае відэа агульным",
+ "mwe-embedplayer-video_credits": "Стваральнікі відэа",
+ "mwe-embedplayer-no-video_credits": "Зьвестак пра аўтараў няма",
+ "mwe-embedplayer-kaltura-platform-title": "Відэа-плятформа з вольным крынічным кодам Kaltura",
+ "mwe-embedplayer-menu_btn": "Мэню",
+ "mwe-embedplayer-close_btn": "Закрыць",
+ "mwe-embedplayer-ogg-player-vlc-player": "Прайгравальнік VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Прайгравальнік HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-mp3Native": "Прайгравальнік HTML5 MP3",
+ "mwe-embedplayer-ogg-player-aacNative": "Прайгравальнік HTML5 AAC",
+ "mwe-embedplayer-ogg-player-h264Native": "Прайгравальнік HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Прайгравальнік HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Агульнае дапаўненьне Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Дапаўненьне QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Прайгравальнік Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(выбраны)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Для лепшага прайграваньня відэа мы рэкамэндуем <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">браўзэр з падтрымкай HTML5-відэа</a>.",
+ "mwe-embedplayer-download-warn": "Ня знойдзены ўбудаваны прайгравальнік: для прагляду ў браўзэры загрузіце [$1 апошнюю вэрсію Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Клявіша <b>F11</b> пераключае <i>вэб-браўзэр</i> у поўнаэкранны рэжым",
+ "mwe-embedplayer-fullscreen-tip-osx": "Націсьніце <b>shift ⌘ F</b> для пераходу ў поўнаэкранны рэжым",
+ "mwe-embedplayer-do_not_warn_again": "Не паказваць гэтае паведамленьне ў будучыні",
+ "mwe-embedplayer-playerSelect": "Прайгравальнікі",
+ "mwe-embedplayer-read_before_embed": "Калі ласка, <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">прачытайце гэта</a> перад устаўкай!",
+ "mwe-embedplayer-embed_site_or_blog": "Уставіць на старонку",
+ "mwe-embedplayer-embed_wiki": "Уставіць у вікі",
+ "mwe-embedplayer-related_videos": "Зьвязаныя відэа",
+ "mwe-embedplayer-seeking": "пошук",
+ "mwe-embedplayer-buffering": "буфэрызацыя",
+ "mwe-embedplayer-video-h264": "H.264 відэа",
+ "mwe-embedplayer-video-webm": "WebM відэа",
+ "mwe-embedplayer-video-flv": "Flash-відэа",
+ "mwe-embedplayer-video-ogg": "Ogg-відэа",
+ "mwe-embedplayer-video-audio": "Ogg-аўдыё",
+ "mwe-embedplayer-audio-mpeg": "MPEG-аўдыё",
+ "mwe-embedplayer-video-3gp": "3GP-відэа",
+ "mwe-embedplayer-video-mpeg": "MPEG-відэа",
+ "mwe-embedplayer-video-msvideo": "AVI-відэа",
+ "mwe-embedplayer-missing-source": "Ня знойдзена крынічнае відэа."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bg.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bg.json
new file mode 100644
index 00000000..3402ed3f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bg.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද",
+ "DCLXVI"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Заглавие: $1",
+ "mwe-embedplayer-credit-date": "Дата: $1",
+ "mwe-embedplayer-credit-author": "Автор: $1",
+ "mwe-embedplayer-close_btn": "Затваряне"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bho.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bho.json
new file mode 100644
index 00000000..e19056b0
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bho.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nepaboy"
+ ]
+ },
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "आईओएस एप्लीकेशन खातिर विएलसी",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "विएलसी एप्लीकेशन",
+ "mwe-embedplayer-vlcapp-downloadapp": "एप० स्टोर से विएलसी एप० डाउनलोड करीं",
+ "mwe-embedplayer-vlcapp-openvideo": "विएलसी एप० में इ वीडियो खोलीं",
+ "mwe-embedplayer-vlcapp-downloadvideo": "इ विडियो डाउनलोड करीं",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "इ साईट पर वीडियो चलावे खातिर, आप के विएलसी एप० के जरुरत पड़ी। अभी इनस्टॉल करब?"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bn.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bn.json
new file mode 100644
index 00000000..063989dc
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bn.json
@@ -0,0 +1,74 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aftab1995",
+ "Aftabuzzaman"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "শিরোনাম: $1",
+ "mwe-embedplayer-credit-date": "তারিখ: $1",
+ "mwe-embedplayer-credit-author": "প্রণেতা: $1",
+ "mwe-embedplayer-nocredits": "কোন ক্রেডিট উপলব্ধ নয়",
+ "mwe-embedplayer-loading_plugin": "প্লাগইন লোড হচ্ছে ...",
+ "mwe-embedplayer-select_playback": "প্লেব্যাক পছন্দ নির্ধারণ করুন",
+ "mwe-embedplayer-play_clip": "ক্লিপ চালান",
+ "mwe-embedplayer-pause_clip": "ক্লিপ থামান",
+ "mwe-embedplayer-volume_control": "ভলিউম নিয়ন্ত্রণ",
+ "mwe-embedplayer-player_options": "প্লেয়ার অপশন",
+ "mwe-embedplayer-timed_text": "টাইমড টেক্সট",
+ "mwe-embedplayer-player_fullscreen": "পূর্ণ স্ক্রিন",
+ "mwe-embedplayer-next_clip_msg": "পরবর্তী ক্লিপ চালান",
+ "mwe-embedplayer-prev_clip_msg": "পূর্ববর্তী ক্লিপ চালান",
+ "mwe-embedplayer-current_clip_msg": "এই ক্লিপ অবিরত চালান",
+ "mwe-embedplayer-paused": "থামানো হয়েছে",
+ "mwe-embedplayer-download_segment": "ডাউনলোড নির্বাচন:",
+ "mwe-embedplayer-download_full_video": "সম্পূর্ণ ভিডিও ফাইল ডাউনলোড করুন:",
+ "mwe-embedplayer-download_full_audio": "সম্পূর্ণ অডিও ফাইল ডাউনলোড করুন:",
+ "mwe-embedplayer-download_right_click": "ডাউনলোড করতে, ডান ক্লিক করে <i>Save link as...</i> নির্বাচন করুন",
+ "mwe-embedplayer-download_clip": "ভিডিও ডাউনলোড করুন",
+ "mwe-embedplayer-download_text": "লেখা ডাউনলোড করুন",
+ "mwe-embedplayer-download": "ডাউনলোড",
+ "mwe-embedplayer-share": "শেয়ার",
+ "mwe-embedplayer-credits": "কৃতিত্ব",
+ "mwe-embedplayer-about-library": "Kaltura প্লেয়ার সম্পর্কে",
+ "mwe-embedplayer-choose_player": "ভিডিও প্লেয়ার চয়ন করুন",
+ "mwe-embedplayer-no-player": "$1-এর জন্য কোন প্লেয়ার উপলব্ধ নেই",
+ "mwe-embedplayer-video_credits": "ভিডিও কৃতিত্ব",
+ "mwe-embedplayer-no-video_credits": "কোন কৃতিত্ব উপলব্ধ নয়",
+ "mwe-embedplayer-menu_btn": "মেনু",
+ "mwe-embedplayer-close_btn": "বন্ধ",
+ "mwe-embedplayer-ogg-player-vlc-player": "ভিএলসি প্লেয়ার",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg প্লেয়ার",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3 প্লেয়ার",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC প্লেয়ার",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 প্লেয়ার",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM প্লেয়ার",
+ "mwe-embedplayer-ogg-player-oggPlugin": "জেনেরিক অগ প্লাগইন",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "iOS অ্যাপের জন্য VLC",
+ "mwe-embedplayer-ogg-player-flowplayer": "ফ্লোপ্লেয়ার",
+ "mwe-embedplayer-ogg-player-kplayer": "কালটুরা প্লেয়ার",
+ "mwe-embedplayer-ogg-player-selected": "(নির্বাচিত)",
+ "mwe-embedplayer-do_not_warn_again": "ভবিষ্যতে, এই বার্তা প্রদর্শন করবেন না",
+ "mwe-embedplayer-playerSelect": "প্লেয়ারগুলি",
+ "mwe-embedplayer-read_before_embed": "এম্বেড করার আগে <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">এটি পড়ুন</a>।",
+ "mwe-embedplayer-embed_site_or_blog": "একটি পাতায় এম্বেড করুন",
+ "mwe-embedplayer-embed_wiki": "একটি উইকিতে এম্বেড করুন",
+ "mwe-embedplayer-related_videos": "সম্পর্কিত ভিডিও",
+ "mwe-embedplayer-buffering": "বাফারিং",
+ "mwe-embedplayer-video-h264": "H.264 ভিডিও",
+ "mwe-embedplayer-video-webm": "WebM ভিডিও",
+ "mwe-embedplayer-video-flv": "ফ্ল্যাশ ভিডিও",
+ "mwe-embedplayer-video-ogg": "অগ ভিডিও",
+ "mwe-embedplayer-video-audio": "অগ অডিও",
+ "mwe-embedplayer-audio-mpeg": "এমপিইজি অডিও",
+ "mwe-embedplayer-video-3gp": "৩জিপি ভিডিও",
+ "mwe-embedplayer-video-mpeg": "এমপিইজি ভিডিও",
+ "mwe-embedplayer-video-msvideo": "এভিআই ভিডিও",
+ "mwe-embedplayer-missing-source": "কোন উৎস ভিডিও পাওয়া যায়নি",
+ "mwe-embedplayer-vlcapp-intro": "একটি আইফোন বা আইপ্যাড থেকে এই সাইটে ভিডিও দেখার জন্য, আপনার বিনামূল্যের $1 প্রয়োজন।",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "VLC অ্যাপ",
+ "mwe-embedplayer-vlcapp-downloadapp": "অ্যাপ স্টোর থেকে VLC অ্যাপ ডাউনলোড করুন",
+ "mwe-embedplayer-vlcapp-openvideo": "ভিএলসি অ্যাপে এই ভিডিও খুলুন",
+ "mwe-embedplayer-vlcapp-downloadvideo": "এই ভিডিও ডাউনলোড করুন",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "এই সাইটে ভিডিও চালানোর জন্য, আপনার বিনামূল্যের ভিএলসি অ্যাপটি প্রয়োজন। এখন ইনস্টল করবেন?"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/br.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/br.json
new file mode 100644
index 00000000..42ca1e35
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/br.json
@@ -0,0 +1,76 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fulup",
+ "Y-M D"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titl : $1",
+ "mwe-embedplayer-credit-date": "Deiziad : $1",
+ "mwe-embedplayer-credit-author": "Aozer : $1",
+ "mwe-embedplayer-loading_plugin": "O kargañ ar plugin...",
+ "mwe-embedplayer-select_playback": "Termeniñ ar penndibaboù lenn",
+ "mwe-embedplayer-link_back": "Liamm distreiñ",
+ "mwe-embedplayer-error_swap_vid": "Fazi : n'eo ket deuet a-benn mwEmbed da eskemm doareenn ar video evit an etrefas mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Ouzhpennañ e dibenn ar sekañs",
+ "mwe-embedplayer-missing_video_stream": "Mankout a ra ar restr video evit ar gwazh-mañ",
+ "mwe-embedplayer-play_clip": "Lenn ar c'hlip",
+ "mwe-embedplayer-pause_clip": "Ehanañ ar c'hlip",
+ "mwe-embedplayer-volume_control": "Kontrol an tregern",
+ "mwe-embedplayer-player_options": "Dibarzhioù al lenner",
+ "mwe-embedplayer-timed_text": "Testenn o tibunañ",
+ "mwe-embedplayer-player_fullscreen": "Skramm leun",
+ "mwe-embedplayer-next_clip_msg": "Lenn ar c'hlip da-heul",
+ "mwe-embedplayer-prev_clip_msg": "Lenn ar c'hlip kent",
+ "mwe-embedplayer-current_clip_msg": "Kenderc'hel da lenn ar c'hlip-mañ",
+ "mwe-embedplayer-seek_to": "Mont da $1",
+ "mwe-embedplayer-paused": "ehanet",
+ "mwe-embedplayer-download_segment": "Pellgargañ an diuzadenn",
+ "mwe-embedplayer-download_full": "Pellgargañ ar restr video a-bezh :",
+ "mwe-embedplayer-download_right_click": "Evit pellgargañ, grit ur c'hlik-dehou ha diuzit <i>Enrollañ an ere evel...</i>",
+ "mwe-embedplayer-download_clip": "Pellgargañ ar video",
+ "mwe-embedplayer-download_text": "Enrollañ an destenn",
+ "mwe-embedplayer-download": "Pellgargañ",
+ "mwe-embedplayer-share": "Rannañ",
+ "mwe-embedplayer-credits": "Kredoù",
+ "mwe-embedplayer-about-library": "Diwar-benn al lenner Kaltura",
+ "mwe-embedplayer-about-library-desc": "Talvezout a ra al levraoueg Kaltura deoc'h d'ober ho mad eus ar balizennoù HTML5 <code><nowiki><video></nowiki></code> ha <code><nowiki><klevet></nowiki></code> diouzhtu gant ul lenner hag un etrefas kenglotus gant ar merdeerioù pennañ.\n\t\n[$1 Evit gouzout hiroc'h diwar-benn al levraoueg lenn Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Pajenn mammenn ar c'hlip",
+ "mwe-embedplayer-choose_player": "Dibab al lenner video",
+ "mwe-embedplayer-no-player": "N'eus lenner ebet hag a zo dieub evit $1",
+ "mwe-embedplayer-share_this_video": "Rannañ ar video-mañ",
+ "mwe-embedplayer-video_credits": "Kredadoù ar video",
+ "mwe-embedplayer-no-video_credits": "N'eus tamm kred ebet",
+ "mwe-embedplayer-kaltura-platform-title": "Savenn video e mammenn digor Kaltura",
+ "mwe-embedplayer-menu_btn": "Lañser",
+ "mwe-embedplayer-close_btn": "Serriñ",
+ "mwe-embedplayer-ogg-player-vlc-player": "Lenner VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Lenner Ogg HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Lenner H.264 HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Lenner WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Plugin hollek Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Plugin QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Lenner Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(diuzet)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Evit gwelet gwelloc'h e erbedadomp deoc'h : <br /><a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">Firefox 3.5</a>.",
+ "mwe-embedplayer-download-warn": "N'eo ket kenglotus ar Merdeer web detektet; evit lenn er merdeer, pellgargit [$1 stumm nevez Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Pouezit war <b>F11</b> da wintañ e mod Skramm leun ar <i>merdeer web</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Pouezit war <b>pennlizh. ⌘ F</b> evit gwintañ d'ar mod Skramm leun",
+ "mwe-embedplayer-do_not_warn_again": "Arabat diskouez ar gemennadenn-mañ ken",
+ "mwe-embedplayer-playerSelect": "Lennerien",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Lennit an dra-mañ</a> a-raok ober.",
+ "mwe-embedplayer-embed_site_or_blog": "Enframmañ en ur bajenn",
+ "mwe-embedplayer-related_videos": "Videoioù liammet",
+ "mwe-embedplayer-seeking": "o klask",
+ "mwe-embedplayer-buffering": "o krubuilhañ",
+ "mwe-embedplayer-video-h264": "video H.264",
+ "mwe-embedplayer-video-webm": "Video WebM",
+ "mwe-embedplayer-video-flv": "video Flash",
+ "mwe-embedplayer-video-ogg": "video Ogg",
+ "mwe-embedplayer-video-audio": "Son Ogg",
+ "mwe-embedplayer-missing-source": "N'eus bet kavet mammenn video ebet."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bs.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bs.json
new file mode 100644
index 00000000..2a96f223
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/bs.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": [],
+ "mwe-embedplayer-player_fullscreen": "Puni ekran",
+ "mwe-embedplayer-paused": "zaustavljeno",
+ "mwe-embedplayer-download": "Učitavanje",
+ "mwe-embedplayer-share": "Dijeli",
+ "mwe-embedplayer-credits": "Zasluge",
+ "mwe-embedplayer-share_this_video": "Dijeli ovaj video",
+ "mwe-embedplayer-menu_btn": "Meni",
+ "mwe-embedplayer-close_btn": "Zatvori",
+ "mwe-embedplayer-related_videos": "Povezani snimci"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ca.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ca.json
new file mode 100644
index 00000000..e64d37b3
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ca.json
@@ -0,0 +1,46 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pitort",
+ "Vriullop",
+ "Xavier Dengra"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Títol: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "Sense crèdits disponibles",
+ "mwe-embedplayer-loading_plugin": "Carregant el connector...",
+ "mwe-embedplayer-play_clip": "Reprodueix el tall",
+ "mwe-embedplayer-pause_clip": "Posa en pausa",
+ "mwe-embedplayer-volume_control": "Control de volum",
+ "mwe-embedplayer-player_options": "Opcions del reproductor",
+ "mwe-embedplayer-timed_text": "Text sincronitzat",
+ "mwe-embedplayer-player_fullscreen": "Pantalla completa",
+ "mwe-embedplayer-current_clip_msg": "Continua reproduint",
+ "mwe-embedplayer-paused": "en pausa",
+ "mwe-embedplayer-download_full_video": "Descàrrega del fitxer audiovisual:",
+ "mwe-embedplayer-download_right_click": "Per descarregar, cliqueu el botó dret i seleccioneu <i>Desa l'enllaç com a...</i>",
+ "mwe-embedplayer-download": "Descàrrega",
+ "mwe-embedplayer-share": "Compartir",
+ "mwe-embedplayer-credits": "Crèdits",
+ "mwe-embedplayer-share_this_video": "Compartiu aquest multimèdia",
+ "mwe-embedplayer-menu_btn": "Menú",
+ "mwe-embedplayer-close_btn": "Tanca",
+ "mwe-embedplayer-for_best_experience": "Per a una millor experiència de visualització es recomana un <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download/ca\" target=\"_blank\">reproductor de vídeo HTML5</a>.",
+ "mwe-embedplayer-download-warn": "No s'ha detectat cap reproductor compatible: per tenir un reproductor integrat al navegador, descarregueu la [$1 darrera versió de Firefox]",
+ "mwe-embedplayer-do_not_warn_again": "No mostris més aquest missatge en el futur",
+ "mwe-embedplayer-playerSelect": "Reproductors",
+ "mwe-embedplayer-embed_site_or_blog": "Incrustat en una pàgina",
+ "mwe-embedplayer-embed_wiki": "Incrustat en un wiki",
+ "mwe-embedplayer-video-h264": "Vídeo H.264",
+ "mwe-embedplayer-video-webm": "Vídeo WebM",
+ "mwe-embedplayer-video-flv": "Vídeo flaix",
+ "mwe-embedplayer-video-ogg": "Vídeo Ogg",
+ "mwe-embedplayer-video-audio": "Àudio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Àudio MPEG",
+ "mwe-embedplayer-video-3gp": "Vídeo 3GP",
+ "mwe-embedplayer-video-mpeg": "Vídeo MPEG",
+ "mwe-embedplayer-video-msvideo": "Vídeo AVI",
+ "mwe-embedplayer-missing-source": "No s'ha trobat cap font de vídeo"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ce.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ce.json
new file mode 100644
index 00000000..ea6a1c4f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ce.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sasan700",
+ "Умар"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "ЦӀе: $1",
+ "mwe-embedplayer-seek_to": "Дехьа гӀо $1",
+ "mwe-embedplayer-download_clip": "Чуяккха видео",
+ "mwe-embedplayer-download_text": "Чудаккха йоза",
+ "mwe-embedplayer-download": "Чуяккха",
+ "mwe-embedplayer-close_btn": "ДӀачӀагӀа",
+ "mwe-embedplayer-seeking": "лахар"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/cs.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/cs.json
new file mode 100644
index 00000000..3170abee
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/cs.json
@@ -0,0 +1,68 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mormegil",
+ "Vks"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Název: $1",
+ "mwe-embedplayer-credit-date": "Datum: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-select_playback": "Nastavení voleb přehrávání",
+ "mwe-embedplayer-link_back": "Odkaz zpět",
+ "mwe-embedplayer-play_clip": "Přehrát klip",
+ "mwe-embedplayer-pause_clip": "Pozastavit klip",
+ "mwe-embedplayer-volume_control": "Ovládání hlasitosti",
+ "mwe-embedplayer-player_options": "Možnosti přehrávače",
+ "mwe-embedplayer-timed_text": "Titulky",
+ "mwe-embedplayer-player_fullscreen": "Celá obrazovka",
+ "mwe-embedplayer-next_clip_msg": "Přehrát další klip",
+ "mwe-embedplayer-prev_clip_msg": "Přehrát předchozí klip",
+ "mwe-embedplayer-seek_to": "Přesun na $1",
+ "mwe-embedplayer-paused": "pozastaveno",
+ "mwe-embedplayer-download_full": "Stažení celého videosouboru:",
+ "mwe-embedplayer-download_clip": "Stáhnout video",
+ "mwe-embedplayer-download": "Stáhnout",
+ "mwe-embedplayer-share": "Sdílet",
+ "mwe-embedplayer-credits": "O souboru",
+ "mwe-embedplayer-about-library": "O přehrávači Kaltura",
+ "mwe-embedplayer-about-library-desc": "Knihovna médií pro HTML5 Kaltura vám umožňuje už dnes využívat značky HTML5 &lt;video&gt; a &lt;audio&gt; a mít konzistentní rozhraní prohlížeče na všech hlavních prohlížečích.\n\n[$1 Více informací o přehrávací knihovně Kaltura]",
+ "mwe-embedplayer-choose_player": "Vybrat přehrávač videa",
+ "mwe-embedplayer-no-player": "Pro $1 není dostupný žádný přehrávač",
+ "mwe-embedplayer-share_this_video": "Sdílet toto video",
+ "mwe-embedplayer-kaltura-platform-title": "Otevřená platforma pro video Kaltura",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Zavřít",
+ "mwe-embedplayer-ogg-player-vlc-player": "Přehrávač VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 přehrávač Ogg",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 přehrávač H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 přehrávač WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Generický zásuvný modul Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Zásuvný modul QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX prvek QuickTime",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Přehrávač Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(vybraný)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Pro příjemnější přehrávání videa doporučujeme <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5 prohlížeč videa</a>.",
+ "mwe-embedplayer-fullscreen-tip": "Stisknutím <b>F11</b> přepínáte celoobrazovkový režim <i>webového prohlížeče</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Stisknutím <b>shift ⌘ F</b> přepínáte celoobrazovkový režim",
+ "mwe-embedplayer-do_not_warn_again": "Příště tuto zprávu nezobrazovat.",
+ "mwe-embedplayer-playerSelect": "Přehrávače",
+ "mwe-embedplayer-read_before_embed": "Před vkládáním <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">čtěte upozornění</a>.",
+ "mwe-embedplayer-embed_site_or_blog": "Vložení na stránku",
+ "mwe-embedplayer-related_videos": "Související videa",
+ "mwe-embedplayer-seeking": "přesun",
+ "mwe-embedplayer-buffering": "načítání do paměti",
+ "mwe-embedplayer-video-h264": "Video v H.264",
+ "mwe-embedplayer-video-webm": "Video WebM",
+ "mwe-embedplayer-video-flv": "Video ve Flashi",
+ "mwe-embedplayer-video-ogg": "Video v Ogg",
+ "mwe-embedplayer-video-audio": "Zvuk v Ogg",
+ "mwe-embedplayer-audio-mpeg": "Audio MPEG",
+ "mwe-embedplayer-video-3gp": "Video 3GP",
+ "mwe-embedplayer-video-mpeg": "Video MPEG",
+ "mwe-embedplayer-video-msvideo": "Video AVI",
+ "mwe-embedplayer-missing-source": "Nebylo nalezeno zdrojové video"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/cu.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/cu.json
new file mode 100644
index 00000000..8475311f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/cu.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "ОйЛ"
+ ]
+ },
+ "mwe-embedplayer-credit-author": "творьць : $1",
+ "mwe-embedplayer-close_btn": "ꙁакрꙑи"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/de.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/de.json
new file mode 100644
index 00000000..9acb4658
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/de.json
@@ -0,0 +1,98 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln",
+ "Metalhead64",
+ "Purodha"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titel: $1",
+ "mwe-embedplayer-credit-date": "Datum: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "Keine Danksagungen verfügbar",
+ "mwe-embedplayer-loading_plugin": "lade Plugin …",
+ "mwe-embedplayer-select_playback": "Wiedergabeeinstellungen ändern",
+ "mwe-embedplayer-link_back": "Link zurück",
+ "mwe-embedplayer-error_swap_vid": "Fehler: mv_embed konnte nicht das Videotag für die mv_embed-Oberfläche auslagern",
+ "mwe-embedplayer-add_to_end_of_sequence": "Zum Ende der Sequenz hinzufügen",
+ "mwe-embedplayer-missing_video_stream": "Die Videodatei für diesen Stream fehlt",
+ "mwe-embedplayer-play_clip": "Clip abspielen",
+ "mwe-embedplayer-pause_clip": "Clip pausieren",
+ "mwe-embedplayer-volume_control": "Lautstärkeregelung",
+ "mwe-embedplayer-player_options": "Playeroptionen",
+ "mwe-embedplayer-timed_text": "Zeitbezogene Untertitel",
+ "mwe-embedplayer-player_fullscreen": "Vollbild",
+ "mwe-embedplayer-next_clip_msg": "Nächsten Clip wiedergeben",
+ "mwe-embedplayer-prev_clip_msg": "Vorherigen Clip wiedergeben",
+ "mwe-embedplayer-current_clip_msg": "Mit der Wiedergabe dieses Clips fortfahren",
+ "mwe-embedplayer-seek_to": "Suche $1",
+ "mwe-embedplayer-paused": "pausiert",
+ "mwe-embedplayer-download_segment": "Auswahl herunterladen:",
+ "mwe-embedplayer-download_full_video": "Ganze Videodatei herunterladen:",
+ "mwe-embedplayer-download_full_audio": "Ganze Audiodatei herunterladen:",
+ "mwe-embedplayer-download_right_click": "Zum Herunterladen die rechte Maustaste nutzen und <i>Link speichern unter …</i> auswählen",
+ "mwe-embedplayer-download_clip": "Video herunterladen",
+ "mwe-embedplayer-download_text": "Text herunterladen",
+ "mwe-embedplayer-download": "Herunterladen",
+ "mwe-embedplayer-share": "Teilen",
+ "mwe-embedplayer-credits": "Urheberschaft",
+ "mwe-embedplayer-about-library": "Über den Kaltura-Player",
+ "mwe-embedplayer-about-library-desc": "Kalturas HTML5-Medienbibliothek ermöglicht es die Vorteile der beiden HTML5-Tags <code><nowiki><video></nowiki></code> und <code><nowiki><audio></nowiki></code> mit einem einheitlichen Player-Interface bei allen führenden Webbrowsern nutzen zu können.\n\n[$1 Weitere Informationen zu Kalturas HTML5-Medienbibliothek].",
+ "mwe-embedplayer-clip_linkback": "Clip-Quellseite",
+ "mwe-embedplayer-choose_player": "Videoplayer auswählen",
+ "mwe-embedplayer-no-player": "Es ist für $1 kein Player verfügbar",
+ "mwe-embedplayer-share_this_video": "Dieses Video teilen",
+ "mwe-embedplayer-share_this_audio": "Diese Audiodatei teilen",
+ "mwe-embedplayer-video_credits": "Videocredits",
+ "mwe-embedplayer-no-video_credits": "Keine Urheberangaben verfügbar",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura Open-Source-Video-Plattform",
+ "mwe-embedplayer-menu_btn": "Menü",
+ "mwe-embedplayer-close_btn": "Schließen",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC-Player",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg-Player",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5-MP3-Player",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5-AAC-Player",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264-Player",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM-Player",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Allgemeines Ogg-Plugin",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "VLC für die iOS-App",
+ "mwe-embedplayer-ogg-player-IEWebMPrompt": "IE-WebM-Plugin-Downloader",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-Plugin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura-Player",
+ "mwe-embedplayer-ogg-player-selected": "(ausgewählt)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Für eine bessere Videowiedergabe wird ein <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download/de\" target=\"_blank\">HTML5-Videobrowser</a> empfohlen.",
+ "mwe-embedplayer-download-warn": "Beim Browser wurde ein inkompatibles Wiedergabeprogramm erkannt. Für eine im Browser eingebettete Wiedergabe wird die Nutzung der [$1 neuesten Version von Mozilla Firefox] empfohlen.",
+ "mwe-embedplayer-fullscreen-tip": "Die Taste <b>F11</b> drücken, um zum Vollbildmodus des <i>Webbrowsers</i> umzuschalten.",
+ "mwe-embedplayer-fullscreen-tip-osx": "Die Tasten <b>UMSCHALT ⌘ F</b> drücken, um zum Vollbildmodus des <i>Webbrowsers</i> umzuschalten.",
+ "mwe-embedplayer-do_not_warn_again": "Diese Meldung in Zukunft nicht mehr anzeigen.",
+ "mwe-embedplayer-playerSelect": "Player",
+ "mwe-embedplayer-read_before_embed": "Vor dem Einbinden die <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Sicherheitsanmerkungen</a> durchlesen!",
+ "mwe-embedplayer-embed_site_or_blog": "Auf einer Seite einbinden",
+ "mwe-embedplayer-embed_wiki": "Auf einem Wiki einbetten",
+ "mwe-embedplayer-related_videos": "Ähnliche Videos",
+ "mwe-embedplayer-seeking": "suchen",
+ "mwe-embedplayer-buffering": "puffert",
+ "mwe-embedplayer-video-h264": "H.264-Video",
+ "mwe-embedplayer-video-webm": "WebM-Video",
+ "mwe-embedplayer-video-flv": "Flash-Video",
+ "mwe-embedplayer-video-ogg": "Ogg-Video",
+ "mwe-embedplayer-video-audio": "Ogg-Audiodatei",
+ "mwe-embedplayer-audio-mpeg": "MPEG-Audio",
+ "mwe-embedplayer-video-3gp": "3gp-Video",
+ "mwe-embedplayer-video-mpeg": "MPEG-Video",
+ "mwe-embedplayer-video-msvideo": "AVI-Video",
+ "mwe-embedplayer-missing-source": "Es konnte kein Videoclip gefunden werden.",
+ "mwe-embedplayer-vlcapp-intro": "Um Videos von dieser Website auf einem iPhone oder iPad anzusehen, musst du die kostenlose $1 herunterladen.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "VLC-App",
+ "mwe-embedplayer-vlcapp-downloadapp": "Die VLC-App aus dem App Store herunterladen",
+ "mwe-embedplayer-vlcapp-openvideo": "Dieses Video in der VLC-App öffnen",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Dieses Video herunterladen",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Um Videos auf dieser Website abzuspielen, benötigst du die kostenlose VLC-App. Jetzt installieren?",
+ "mwe-embedplayer-iewebmprompt-intro": "Huch! Eine weitere Sache, bevor du dieses Video abspielen kannst …",
+ "mwe-embedplayer-iewebmprompt-linktext": "Installiere WebM-Medienkomponenten für den Microsoft Internet Explorer",
+ "mwe-embedplayer-iewebmprompt-outro": "Lade nach der Installation diese Seite neu."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/diq.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/diq.json
new file mode 100644
index 00000000..ac3c19da
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/diq.json
@@ -0,0 +1,70 @@
+{
+ "@metadata": {
+ "authors": [
+ "Erdemaslancan",
+ "Mirzali"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Sername: $1",
+ "mwe-embedplayer-credit-date": "Tarix: $1",
+ "mwe-embedplayer-credit-author": "Nuştoğ: $1",
+ "mwe-embedplayer-loading_plugin": "loading plugin ...",
+ "mwe-embedplayer-select_playback": "tercihê kaydayişi eyar ker",
+ "mwe-embedplayer-link_back": "tepiya agêrayiş re gıre bıd'",
+ "mwe-embedplayer-error_swap_vid": "xeta: qey mv_embed, mv_embed'i etiketê videoyi nêşkeno teqas bıkero",
+ "mwe-embedplayer-add_to_end_of_sequence": "bıerz peyni rêz",
+ "mwe-embedplayer-missing_video_stream": "qey no herikyayişi dosyaya videoyi nêaseno",
+ "mwe-embedplayer-play_clip": "klib bıde kaykerdış",
+ "mwe-embedplayer-pause_clip": "klib bıde vındertış",
+ "mwe-embedplayer-volume_control": "kontrolê vengi",
+ "mwe-embedplayer-player_options": "Opsiyonê kaykerdoği",
+ "mwe-embedplayer-player_fullscreen": "Tam asenge",
+ "mwe-embedplayer-next_clip_msg": "klibo bin bıde kaykerdış",
+ "mwe-embedplayer-prev_clip_msg": "klibo verin bıde kaykerdış",
+ "mwe-embedplayer-current_clip_msg": "kaykerdışê no klibi re dewam bıker",
+ "mwe-embedplayer-seek_to": "Şo muddet ser $1",
+ "mwe-embedplayer-paused": "vındarnaye",
+ "mwe-embedplayer-download_segment": "tercihi biyar war",
+ "mwe-embedplayer-download_full_video": "dosyaya videoyi tam biya war:",
+ "mwe-embedplayer-download_right_click": "qey wari ardışi, raşt bıtıknê u <i>Hedef bıferq qeyd ker...</i> bıtıknê",
+ "mwe-embedplayer-download_clip": "video biyar war",
+ "mwe-embedplayer-download_text": "Metn biyar war",
+ "mwe-embedplayer-download": "biyar war",
+ "mwe-embedplayer-share": "Vıla ke",
+ "mwe-embedplayer-credits": "êyê ke destek dayê",
+ "mwe-embedplayer-clip_linkback": "pelê çımeyi yo klibi",
+ "mwe-embedplayer-choose_player": "video player bıweçin",
+ "mwe-embedplayer-share_this_video": "na video bare/par bıker",
+ "mwe-embedplayer-video_credits": "êyê ke destek dayê video",
+ "mwe-embedplayer-menu_btn": "menu",
+ "mwe-embedplayer-close_btn": "Racnê",
+ "mwe-embedplayer-ogg-player-vlc-player": "Kay kerdogê VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg kayker",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 kayker",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM kayker",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Cenerik olekenê Ogg'i",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime plugin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaykerdoğê kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(tercih biyaye)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Seba daêna rınd kaykerdışê videoy ma <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">html5 video arden</a> tewsiya kenime.",
+ "mwe-embedplayer-do_not_warn_again": "Vındero bahdo, na mesac newkê memocne",
+ "mwe-embedplayer-playerSelect": "Kaykeri",
+ "mwe-embedplayer-read_before_embed": "kerem kerê verê nımıtışi <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">derheqê dûr ra nımıtışi de malumatê pawıtışan</a> bıwenê!",
+ "mwe-embedplayer-embed_site_or_blog": "Zerreyê keyepel u blogê xo de bınımnê",
+ "mwe-embedplayer-related_videos": "videoyê ke elaqedari",
+ "mwe-embedplayer-seeking": "cıgêrayox",
+ "mwe-embedplayer-buffering": "tamponkerdış",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-webm": "WebM video",
+ "mwe-embedplayer-video-flv": "Flash video",
+ "mwe-embedplayer-video-ogg": "Ogg video",
+ "mwe-embedplayer-video-audio": "Ogg audio",
+ "mwe-embedplayer-audio-mpeg": "MPEG audio",
+ "mwe-embedplayer-video-3gp": "3GP video",
+ "mwe-embedplayer-video-mpeg": "MPEG video",
+ "mwe-embedplayer-video-msvideo": "AVI video"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/dsb.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/dsb.json
new file mode 100644
index 00000000..61685dad
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/dsb.json
@@ -0,0 +1,83 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titel: $1",
+ "mwe-embedplayer-credit-date": "Datum: $1",
+ "mwe-embedplayer-credit-author": "Awtor: $1",
+ "mwe-embedplayer-nocredits": "Žadne źěkowanja k dispoziciji",
+ "mwe-embedplayer-loading_plugin": "Tykac se zacytujo ...",
+ "mwe-embedplayer-select_playback": "Nastajenje za playback stajiś",
+ "mwe-embedplayer-link_back": "Wótkaz slědk",
+ "mwe-embedplayer-error_swap_vid": "Zmólka: mv_embed njejo mógał wideotoflicku za pówjerch mv_embed wuměstniś",
+ "mwe-embedplayer-add_to_end_of_sequence": "Kóńcoju sekwence pśidaś",
+ "mwe-embedplayer-missing_video_stream": "Wideowa dataja za toś tu tšugu felujo",
+ "mwe-embedplayer-play_clip": "Klip wótegraś",
+ "mwe-embedplayer-pause_clip": "Klip zastajiś",
+ "mwe-embedplayer-volume_control": "Regulěrowanje głosnosći",
+ "mwe-embedplayer-player_options": "Opcije wótegrawaka",
+ "mwe-embedplayer-timed_text": "Synchronizěrowany tekst",
+ "mwe-embedplayer-player_fullscreen": "Połna wobrazowka",
+ "mwe-embedplayer-next_clip_msg": "Pśiducy klip wótegraś",
+ "mwe-embedplayer-prev_clip_msg": "Pjerwjejšny klip wótegraś",
+ "mwe-embedplayer-current_clip_msg": "Klip dalej wótegraś",
+ "mwe-embedplayer-seek_to": "$1 pytaś",
+ "mwe-embedplayer-paused": "zastajony",
+ "mwe-embedplayer-download_segment": "Wuběrk ześěgnuś:",
+ "mwe-embedplayer-download_full": "Dopołnu wideowu dataju ześěgnuś:",
+ "mwe-embedplayer-download_right_click": "Aby ześěgnuł, klikni z pšaweju tastu a wubjeŕ <i>Wótkaz składowaś ako...</i>",
+ "mwe-embedplayer-download_clip": "Wideo ześěgnuś",
+ "mwe-embedplayer-download_text": "Tekst",
+ "mwe-embedplayer-download": "Ześěgnuś",
+ "mwe-embedplayer-share": "Źěliś",
+ "mwe-embedplayer-credits": "Źěkowanje",
+ "mwe-embedplayer-about-library": "Wó wótegrawaku Kaltura",
+ "mwe-embedplayer-about-library-desc": "Medijowa biblioteka HTML 5 wótgrawaka Kaltury zmóžnja lěpšyny HTML 5-elementowu code><nowiki><video></nowiki></code> a <code><nowiki><audio></nowiki></code> z jadnotnym powjerchom wótgrawaka pśi wjeducych wótglědowakach.\n\n[$1 Dalšne informacije wó bibliotece wótgrawaka Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Žrědłowy bok klipow",
+ "mwe-embedplayer-choose_player": "Wideowótegrawak wubraś",
+ "mwe-embedplayer-no-player": "Za $1 žeden wótgrawak k dispoziciji",
+ "mwe-embedplayer-share_this_video": "Toś to wideo źěliś",
+ "mwe-embedplayer-video_credits": "Źěkowanja za napóranje wideo",
+ "mwe-embedplayer-no-video_credits": "Žedne pódaśa wó awtorje k dispoziciji",
+ "mwe-embedplayer-kaltura-platform-title": "Wideowa platforma zjawnego žrědła Kaltura",
+ "mwe-embedplayer-menu_btn": "Meni",
+ "mwe-embedplayer-close_btn": "Zacyniś",
+ "mwe-embedplayer-ogg-player-vlc-player": "Grajadło VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Wótgrawak HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-mp3Native": "Wótgrawak HTML5 MP3",
+ "mwe-embedplayer-ogg-player-aacNative": "Wótgrawak HTML5 AAC",
+ "mwe-embedplayer-ogg-player-h264Native": "Wótgrawak HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Wótegrawak HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Tykac Generic Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Tykac QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX QuickTime",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Grajadło Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(wubrany)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vobis",
+ "mwe-embedplayer-for_best_experience": "Za lěpše wideodožywjenje pórucujomy <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">wideowobglědowak HTML 5</a>.",
+ "mwe-embedplayer-download-warn": "Njekompatibelne wótegrawak we wobglědowaku namakany: za wótegrawanje we wobglědowaku ześěgni pšosym [$1 nejnowšu wersiju Mozilla Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Tłoc <b>F11</b>, aby <i>webwobglědowak</i> do połneje wobrazowki pśešaltował",
+ "mwe-embedplayer-fullscreen-tip-osx": "Tłoc <b>UMSCH ⌘ F</b>, aby pśešaltował do modusa połneje wobrazowki",
+ "mwe-embedplayer-do_not_warn_again": "W pśichoźe toś tu powěźeńku wěcej njepokazaś",
+ "mwe-embedplayer-playerSelect": "Wótgrawaki",
+ "mwe-embedplayer-read_before_embed": "Pšosym cytaj <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">wěstotne pśipiski wó zdalonem zasajźenju</a>, nježli až napšawdu zasajźujoš!",
+ "mwe-embedplayer-embed_site_or_blog": "Na boku zasajźiś",
+ "mwe-embedplayer-embed_wiki": "We wikiju zasajźiś",
+ "mwe-embedplayer-related_videos": "Pśiwuzne wideo",
+ "mwe-embedplayer-seeking": "pyta se",
+ "mwe-embedplayer-buffering": "pufrujo",
+ "mwe-embedplayer-video-h264": "Wideo H.264",
+ "mwe-embedplayer-video-webm": "WebM-wideo",
+ "mwe-embedplayer-video-flv": "Wideo Flash",
+ "mwe-embedplayer-video-ogg": "Ogg-wideo",
+ "mwe-embedplayer-video-audio": "Ogg-awdio",
+ "mwe-embedplayer-audio-mpeg": "MPEG awdio",
+ "mwe-embedplayer-video-3gp": "3GP wideo",
+ "mwe-embedplayer-video-mpeg": "MPEG wideo",
+ "mwe-embedplayer-video-msvideo": "AVI wideo",
+ "mwe-embedplayer-missing-source": "Žedno žrědłowe wideo namakane."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/el.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/el.json
new file mode 100644
index 00000000..3dcbb269
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/el.json
@@ -0,0 +1,77 @@
+{
+ "@metadata": {
+ "authors": [
+ "Geraki"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Τίτλος: $1",
+ "mwe-embedplayer-credit-date": "Ημερομηνία: $1",
+ "mwe-embedplayer-credit-author": "Συγγραφέας: $1",
+ "mwe-embedplayer-nocredits": "Δεν διατίθενται αναφορές",
+ "mwe-embedplayer-loading_plugin": "Φόρτωση plugin ...",
+ "mwe-embedplayer-select_playback": "Ορισμός προτίμησης αναπαραγωγής",
+ "mwe-embedplayer-link_back": "Σύνδεση πίσω",
+ "mwe-embedplayer-error_swap_vid": "Σφάλμα: το mwEmbed δεν ήταν σε θέση να ανταλλάξει την ετικέτα βίντεο για την διεπαφή mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Προσθήκη στο τέλος της ακολουθίας",
+ "mwe-embedplayer-missing_video_stream": "Το αρχείο βίντεο για αυτή τη ροή λείπει",
+ "mwe-embedplayer-play_clip": "Αναπαραγωγή κλιπ",
+ "mwe-embedplayer-pause_clip": "Παύση κλιπ",
+ "mwe-embedplayer-volume_control": "Έλεγχος έντασης ήχου",
+ "mwe-embedplayer-player_options": "Ρυθμίσεις αναπαραγωγής",
+ "mwe-embedplayer-timed_text": "Χρονισμένο κείμενο",
+ "mwe-embedplayer-player_fullscreen": "Πλήρης οθόνη",
+ "mwe-embedplayer-next_clip_msg": "Αναπαραγωγή επόμενου κλιπ",
+ "mwe-embedplayer-prev_clip_msg": "Αναπαραγωγή προηγούμενου κλιπ",
+ "mwe-embedplayer-current_clip_msg": "Συνέχεια αναπαραγωγής αυτού του κλιπ",
+ "mwe-embedplayer-seek_to": "Αναζήτηση για $1",
+ "mwe-embedplayer-paused": "σε παύση",
+ "mwe-embedplayer-download_segment": "Λήψη επιλογής:",
+ "mwe-embedplayer-download_full": "Κατεβάστε το πλήρες αρχείο βίντεο:",
+ "mwe-embedplayer-download_right_click": "Για να κατεβάσετε, κάντε δεξί κλικ και επιλέξτε <i>Αποθήκευση συνδέσμου ως ...</i>",
+ "mwe-embedplayer-download_clip": "Λήψη βίντεο",
+ "mwe-embedplayer-download_text": "Κατεβάστε το κείμενο",
+ "mwe-embedplayer-download": "Λήψη",
+ "mwe-embedplayer-share": "Διαμοιρασμός",
+ "mwe-embedplayer-credits": "Συντελεστές",
+ "mwe-embedplayer-about-library": "Σχετικά με την εφαρμογή Kaltura",
+ "mwe-embedplayer-clip_linkback": "Σελίδα προέλευσης βίντεο",
+ "mwe-embedplayer-choose_player": "Επιλέξτε πρόγραμμα αναπαραγωγής βίντεο",
+ "mwe-embedplayer-no-player": "Κανένα πρόγραμμα αναπαραγωγής δεν διατίθεται για το $1",
+ "mwe-embedplayer-share_this_video": "Μοιραστείτε αυτό το βίντεο",
+ "mwe-embedplayer-video_credits": "Συντελεστές βίντεο",
+ "mwe-embedplayer-no-video_credits": "Δεν διατίθενται αναφορές",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura open source video platform",
+ "mwe-embedplayer-menu_btn": "Μενου",
+ "mwe-embedplayer-close_btn": "Κλείσιμο",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC player",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg player",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 player",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Γενικό plugin Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime plugin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura player",
+ "mwe-embedplayer-ogg-player-selected": "(επιλεγμένο)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Για μια καλύτερη εμπειρία αναπαραγωγής βίντεο σας προτείνουμε ένα <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">περιηγητή HTML5 video</a>.",
+ "mwe-embedplayer-fullscreen-tip": "Πατήστε <b>F11</b> για εναλλαγή <i>του προγράμματος περιήγησης</i> σε πλήρη οθόνη",
+ "mwe-embedplayer-fullscreen-tip-osx": "Πατήστε <b>shift ⌘ F</b> για την εναλλαγή πλήρους οθόνης",
+ "mwe-embedplayer-do_not_warn_again": "Στο μέλλον, να μην εμφανιστεί αυτό το μήνυμα",
+ "mwe-embedplayer-playerSelect": "Λογισμικό αναπαραγωγής",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Διαβάστε αυτό</a> πριν από την ενσωμάτωση.",
+ "mwe-embedplayer-embed_site_or_blog": "Ενσωμάτωση στο σάιτ ή μπλογκ σας",
+ "mwe-embedplayer-embed_wiki": "Ενσωματώστε σε ένα wiki",
+ "mwe-embedplayer-related_videos": "Σχετικά βίντεο",
+ "mwe-embedplayer-seeking": "αναζήτηση",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-webm": "WebM βίντεο",
+ "mwe-embedplayer-video-flv": "Flash video",
+ "mwe-embedplayer-video-ogg": "Ogg video",
+ "mwe-embedplayer-video-audio": "Ogg audio",
+ "mwe-embedplayer-audio-mpeg": "MPEG ήχος",
+ "mwe-embedplayer-video-3gp": "3GP βίντεο",
+ "mwe-embedplayer-video-mpeg": "MPEG βίντεο",
+ "mwe-embedplayer-video-msvideo": "AVI βίντεο",
+ "mwe-embedplayer-missing-source": "Δεν βρέθηκε πηγή βίντεο"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/en-gb.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/en-gb.json
new file mode 100644
index 00000000..ca785d7b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/en-gb.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shirayuki"
+ ]
+ },
+ "mwe-embedplayer-do_not_warn_again": "In future, do not show this message"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/en.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/en.json
new file mode 100644
index 00000000..91041ffc
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/en.json
@@ -0,0 +1,95 @@
+{
+ "@metadata": {
+ "authors": []
+ },
+ "mwe-embedplayer-credit-title": "Title: $1",
+ "mwe-embedplayer-credit-date": "Date: $1",
+ "mwe-embedplayer-credit-author": "Author: $1",
+ "mwe-embedplayer-nocredits": "No credits available",
+ "mwe-embedplayer-loading_plugin": "Loading plugin ...",
+ "mwe-embedplayer-select_playback": "Set playback preference",
+ "mwe-embedplayer-link_back": "Link back",
+ "mwe-embedplayer-error_swap_vid": "Error: mwEmbed was unable to swap the video tag for the mwEmbed interface",
+ "mwe-embedplayer-add_to_end_of_sequence": "Add to end of sequence",
+ "mwe-embedplayer-missing_video_stream": "The video file for this stream is missing",
+ "mwe-embedplayer-play_clip": "Play clip",
+ "mwe-embedplayer-pause_clip": "Pause clip",
+ "mwe-embedplayer-volume_control": "Volume control",
+ "mwe-embedplayer-player_options": "Player options",
+ "mwe-embedplayer-timed_text": "Timed text",
+ "mwe-embedplayer-player_fullscreen": "Fullscreen",
+ "mwe-embedplayer-next_clip_msg": "Play next clip",
+ "mwe-embedplayer-prev_clip_msg": "Play previous clip",
+ "mwe-embedplayer-current_clip_msg": "Continue playing this clip",
+ "mwe-embedplayer-seek_to": "Seek $1",
+ "mwe-embedplayer-paused": "paused",
+ "mwe-embedplayer-download_segment": "Download selection:",
+ "mwe-embedplayer-download_full_video": "Download full video file:",
+ "mwe-embedplayer-download_full_audio": "Download full audio file:",
+ "mwe-embedplayer-download_right_click": "To download, right click and select <i>Save link as...</i>",
+ "mwe-embedplayer-download_clip": "Download video",
+ "mwe-embedplayer-download_text": "Download text",
+ "mwe-embedplayer-download": "Download",
+ "mwe-embedplayer-share": "Share",
+ "mwe-embedplayer-credits": "Credits",
+ "mwe-embedplayer-about-library": "About Kaltura player",
+ "mwe-embedplayer-about-library-desc": "Kaltura's HTML5 media library enables you to take advantage of the HTML5 &lt;video&gt; and &lt;audio&gt; tags today with a consistent player interface across all major browsers.\n\n[$1 More about the Kaltura player library].",
+ "mwe-embedplayer-clip_linkback": "Clip source page",
+ "mwe-embedplayer-choose_player": "Choose video player",
+ "mwe-embedplayer-no-player": "No player available for $1",
+ "mwe-embedplayer-share_this_video": "Share this video",
+ "mwe-embedplayer-share_this_audio": "Share this audio file",
+ "mwe-embedplayer-video_credits": "Video credits",
+ "mwe-embedplayer-no-video_credits": "No credits available",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura open source video platform",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Close",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC player",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg player",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3 player",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC player",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 player",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM player",
+ "mwe-embedplayer-ogg-player-vp9Native": "HTML5 VP9 player",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Generic Ogg plugin",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "VLC for iOS app",
+ "mwe-embedplayer-ogg-player-IEWebMPrompt": "IE WebM plugin downloader",
+ "mwe-embedplayer-ogg-player-ogvJsPlayer": "JavaScript Ogg player",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime plugin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura player",
+ "mwe-embedplayer-ogg-player-selected": "(selected)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "For a better video playback experience we recommend an <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5 video browser</a>.",
+ "mwe-embedplayer-download-warn": "No compatible in-browser player was detected: for in-browser playback, please download the [$1 latest Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Press <b>F11</b> toggle <i>web browser</i> fullscreen",
+ "mwe-embedplayer-fullscreen-tip-osx": "Press <b>shift ⌘ F</b> to toggle fullscreen",
+ "mwe-embedplayer-do_not_warn_again": "In the future, do not show this message",
+ "mwe-embedplayer-playerSelect": "Players",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Read this</a> before embedding.",
+ "mwe-embedplayer-embed_site_or_blog": "Embed on a page",
+ "mwe-embedplayer-embed_wiki": "Embed on a wiki",
+ "mwe-embedplayer-related_videos": "Related videos",
+ "mwe-embedplayer-seeking": "seeking",
+ "mwe-embedplayer-buffering": "buffering",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-webm": "WebM video",
+ "mwe-embedplayer-video-flv": "Flash video",
+ "mwe-embedplayer-video-ogg": "Ogg video",
+ "mwe-embedplayer-video-audio": "Ogg audio",
+ "mwe-embedplayer-audio-mpeg": "MPEG audio",
+ "mwe-embedplayer-video-3gp": "3GP video",
+ "mwe-embedplayer-video-mpeg": "MPEG video",
+ "mwe-embedplayer-video-msvideo": "AVI video",
+ "mwe-embedplayer-missing-source": "No source video was found",
+ "mwe-embedplayer-vlcapp-intro": "In order to view videos from this site on an iPhone or iPad, you need the free $1.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "VLC app",
+ "mwe-embedplayer-vlcapp-downloadapp": "Download the VLC app from the App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Open this video in the VLC app",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Download this video",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "To play videos on this site, you need the free VLC app. Install now?",
+ "mwe-embedplayer-iewebmprompt-intro": "Oops! One more thing before you can play this video...",
+ "mwe-embedplayer-iewebmprompt-linktext": "Install WebM media components for Microsoft Internet Explorer",
+ "mwe-embedplayer-iewebmprompt-outro": "Reload this page after installing."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/eo.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/eo.json
new file mode 100644
index 00000000..bb972255
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/eo.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Yekrats"
+ ]
+ },
+ "mwe-embedplayer-player_fullscreen": "Plenekrana",
+ "mwe-embedplayer-download_full": "Elŝuti kompletan filmetan dosieron:",
+ "mwe-embedplayer-download_clip": "Elŝuti filmeton",
+ "mwe-embedplayer-download": "Elŝuti",
+ "mwe-embedplayer-share": "Konigi",
+ "mwe-embedplayer-share_this_video": "Konigi ĉi tiun filmeton",
+ "mwe-embedplayer-menu_btn": "Menuo",
+ "mwe-embedplayer-close_btn": "Fermi",
+ "mwe-embedplayer-ogg-player-selected": "(elektita)",
+ "mwe-embedplayer-playerSelect": "Ludantoj",
+ "mwe-embedplayer-read_before_embed": "Bonvolu legi la <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">sekurecajn notojn pri ekstera enkorpigado</a> antaŭ fakte enkorpigado!",
+ "mwe-embedplayer-embed_site_or_blog": "Enmeti en paĝo",
+ "mwe-embedplayer-related_videos": "Rilataj videoj",
+ "mwe-embedplayer-seeking": "serĉante",
+ "mwe-embedplayer-buffering": "bufrante",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-flv": "Flash video",
+ "mwe-embedplayer-video-ogg": "Ogg video",
+ "mwe-embedplayer-video-audio": "Ogg aŭdiaĵo",
+ "mwe-embedplayer-missing-source": "Neniu fonta video estis trovita"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/es.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/es.json
new file mode 100644
index 00000000..8dd70f29
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/es.json
@@ -0,0 +1,99 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armando-Martin",
+ "Crazymadlover",
+ "Translationista",
+ "Fitoschido",
+ "Koavf",
+ "Macofe",
+ "Laurenslimb"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Título: $1",
+ "mwe-embedplayer-credit-date": "Fecha: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "No hay créditos disponibles",
+ "mwe-embedplayer-loading_plugin": "Cargando plugin ...",
+ "mwe-embedplayer-select_playback": "Configurar preferencia de reproducción",
+ "mwe-embedplayer-link_back": "Referir a enlace",
+ "mwe-embedplayer-error_swap_vid": "Error: mwEmbed no pudo sustituír la etiqueta de vídeo por la interfaz mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Agregar al final de la secuencia",
+ "mwe-embedplayer-missing_video_stream": "Falta el archivo de vídeo de esta transmisión",
+ "mwe-embedplayer-play_clip": "Reproducir clip",
+ "mwe-embedplayer-pause_clip": "Pausar clip",
+ "mwe-embedplayer-volume_control": "Control de volumen",
+ "mwe-embedplayer-player_options": "Opciones de reproductor",
+ "mwe-embedplayer-timed_text": "Texto sincronizado",
+ "mwe-embedplayer-player_fullscreen": "Pantalla completa",
+ "mwe-embedplayer-next_clip_msg": "Reproducir siguiente clip",
+ "mwe-embedplayer-prev_clip_msg": "Reproducir clip anterior",
+ "mwe-embedplayer-current_clip_msg": "Continuar reproduciendo este clip",
+ "mwe-embedplayer-seek_to": "Buscar $1",
+ "mwe-embedplayer-paused": "en pausa",
+ "mwe-embedplayer-download_segment": "Descargar selección:",
+ "mwe-embedplayer-download_full_video": "Descargar archivo de video completo:",
+ "mwe-embedplayer-download_right_click": "Para descargar, haga click con el botón derecho del ratón y seleccione <i>Guardar enlace como...</i>",
+ "mwe-embedplayer-download_clip": "Descargar archivo",
+ "mwe-embedplayer-download_text": "Descargar texto",
+ "mwe-embedplayer-download": "Descargar",
+ "mwe-embedplayer-share": "Compartir",
+ "mwe-embedplayer-credits": "Créditos",
+ "mwe-embedplayer-about-library": "Acerca del reproductor Kaltura",
+ "mwe-embedplayer-about-library-desc": "La biblioteca HTMl5 de Kaltura permite utilizar etiquetas de <code><nowiki><video></nowiki></code> y <code><nowiki><audio></nowiki></code> ahora con una interfaz de reproductor consistente en los navegadores más usados.\n\t\n[$1 Más acerca de la biblioteca del reproductor Kalltura].",
+ "mwe-embedplayer-clip_linkback": "Página fuente de clip",
+ "mwe-embedplayer-choose_player": "Elegir reproductor de video",
+ "mwe-embedplayer-no-player": "No hay ningún reproductor disponible para $1",
+ "mwe-embedplayer-share_this_video": "Compartir este video",
+ "mwe-embedplayer-video_credits": "Créditos de video",
+ "mwe-embedplayer-no-video_credits": "No hay créditos disponibles",
+ "mwe-embedplayer-kaltura-platform-title": "Plataforma de vídeo de código abierto Kaltura",
+ "mwe-embedplayer-menu_btn": "Menú",
+ "mwe-embedplayer-close_btn": "Cerrar",
+ "mwe-embedplayer-ogg-player-vlc-player": "Reproductor de VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Reproductor HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-mp3Native": "Reproductor de MP3 HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Reproductor de AAC HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Reproductor HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Reproductor WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Plugin Ogg genérico",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "aplicación VLC para iOS",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Plugin QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Reproductor Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(seleccionado)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Para una mejor experiencia de reproducción de vídeo recomendamos un <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">navegador de vídeo html5</a>.",
+ "mwe-embedplayer-download-warn": "Se detectó un reproductor no compatible con el explorador: para reproducción integrada en el navegador descargue la [$1 última versión de Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Presione <b>F11</b> para activar o desactivar la pantalla completa del <i>navegador web</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Presione <b>shift ⌘ F</b> para activar o desactivarl a pantalla completa",
+ "mwe-embedplayer-do_not_warn_again": "No mostrar este mensaje en el futuro.",
+ "mwe-embedplayer-playerSelect": "Reproductores",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Leer esto</a> antes de insertar.",
+ "mwe-embedplayer-embed_site_or_blog": "Insertar en una página",
+ "mwe-embedplayer-embed_wiki": "Incrustar en un wiki",
+ "mwe-embedplayer-related_videos": "Videos relacionados",
+ "mwe-embedplayer-seeking": "buscando",
+ "mwe-embedplayer-buffering": "cargando en el búfer",
+ "mwe-embedplayer-video-h264": "Video H.264",
+ "mwe-embedplayer-video-webm": "Vídeo WebM",
+ "mwe-embedplayer-video-flv": "Video Flash",
+ "mwe-embedplayer-video-ogg": "Video Ogg",
+ "mwe-embedplayer-video-audio": "Audio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Audio MPEG",
+ "mwe-embedplayer-video-3gp": "Vídeo 3GP",
+ "mwe-embedplayer-video-mpeg": "Vídeo MPEG",
+ "mwe-embedplayer-video-msvideo": "Vídeo AVI",
+ "mwe-embedplayer-missing-source": "No se encontró ningún vídeo de origen.",
+ "mwe-embedplayer-vlcapp-intro": "Para ver videos de este sitio en un iPhone o iPad, necesitas la $1 gratuita.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "aplicación VLC",
+ "mwe-embedplayer-vlcapp-downloadapp": "Descargar la aplicación VLC desde la App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Abre este video en la aplicación VLC",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Descarga este video",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Para reproducir videos en este sitio, necesitas la aplicación gratuita VLC. ¿Instalar ahora?",
+ "mwe-embedplayer-iewebmprompt-intro": "¡Espere! Una cosa más antes de que pueda ver este vídeo...",
+ "mwe-embedplayer-iewebmprompt-linktext": "Instalar componentes multimedia de WebM para Microsoft Internet Explorer",
+ "mwe-embedplayer-iewebmprompt-outro": "Recargar esta página después de la instalación."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/et.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/et.json
new file mode 100644
index 00000000..587c9515
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/et.json
@@ -0,0 +1,48 @@
+{
+ "@metadata": {
+ "authors": [
+ "Avjoska",
+ "Pikne"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Pealkiri: $1",
+ "mwe-embedplayer-credit-date": "Kuupäev: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-loading_plugin": "Lisa laadimine...",
+ "mwe-embedplayer-missing_video_stream": "Selle voogedastuse jaoks puudub videofail.",
+ "mwe-embedplayer-play_clip": "Esita lõik",
+ "mwe-embedplayer-pause_clip": "Peata lõik",
+ "mwe-embedplayer-volume_control": "Helitugevuse seadmine",
+ "mwe-embedplayer-player_options": "Esitaja seaded",
+ "mwe-embedplayer-timed_text": "Ajastatud tekst",
+ "mwe-embedplayer-player_fullscreen": "Täisekraan",
+ "mwe-embedplayer-paused": "peatatud",
+ "mwe-embedplayer-download_full": "Laadi alla terve videofail:",
+ "mwe-embedplayer-download_clip": "Laadi video alla",
+ "mwe-embedplayer-download_text": "Laadi tekst alla",
+ "mwe-embedplayer-download": "Laadi alla",
+ "mwe-embedplayer-share": "Jaga",
+ "mwe-embedplayer-credits": "Autorsus",
+ "mwe-embedplayer-clip_linkback": "Lõigu alliklehekülg",
+ "mwe-embedplayer-choose_player": "Videoesitaja valimine",
+ "mwe-embedplayer-share_this_video": "Selle video jagamine",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura avatud lähtekoodiga videoplatvorm",
+ "mwe-embedplayer-menu_btn": "Menüü",
+ "mwe-embedplayer-close_btn": "Sule",
+ "mwe-embedplayer-do_not_warn_again": "Edaspidi ära seda sõnumit näita",
+ "mwe-embedplayer-playerSelect": "Esitajad",
+ "mwe-embedplayer-embed_site_or_blog": "Kasuta leheküljel",
+ "mwe-embedplayer-embed_wiki": "Kasuta vikis",
+ "mwe-embedplayer-seeking": "otsimine",
+ "mwe-embedplayer-buffering": "puhverdamine",
+ "mwe-embedplayer-video-h264": "H.264-video",
+ "mwe-embedplayer-video-webm": "WebM-video",
+ "mwe-embedplayer-video-flv": "Flash-video",
+ "mwe-embedplayer-video-ogg": "Ogg-video",
+ "mwe-embedplayer-video-audio": "Ogg-helifail",
+ "mwe-embedplayer-audio-mpeg": "MPEG-helifail",
+ "mwe-embedplayer-video-3gp": "3GP-video",
+ "mwe-embedplayer-video-mpeg": "MPEG-video",
+ "mwe-embedplayer-video-msvideo": "AVI-video",
+ "mwe-embedplayer-missing-source": "Allikvideot ei leitud."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/eu.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/eu.json
new file mode 100644
index 00000000..ccfe919d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/eu.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "Subi"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Izenburua: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Egilea: $1",
+ "mwe-embedplayer-player_fullscreen": "Pantaila osoan",
+ "mwe-embedplayer-paused": "pausatua",
+ "mwe-embedplayer-download": "Jaitsi",
+ "mwe-embedplayer-share": "Partekatu",
+ "mwe-embedplayer-credits": "Kredituak",
+ "mwe-embedplayer-menu_btn": "Menua",
+ "mwe-embedplayer-close_btn": "Itxi"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fa.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fa.json
new file mode 100644
index 00000000..1f4f2fe9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fa.json
@@ -0,0 +1,87 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armin1392",
+ "Ebraminio",
+ "Mjbmr",
+ "Pouyana",
+ "Reza1615",
+ "پاناروما"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "عنوان: $1",
+ "mwe-embedplayer-credit-date": "تاریخ: $1",
+ "mwe-embedplayer-credit-author": "نویسنده = $1",
+ "mwe-embedplayer-nocredits": "هیچ اعتباری در دسترس نیست",
+ "mwe-embedplayer-loading_plugin": "در حال بارگیری افزایه...",
+ "mwe-embedplayer-select_playback": "تنظیم اولویت پخش",
+ "mwe-embedplayer-link_back": "پیوند بازگشت",
+ "mwe-embedplayer-error_swap_vid": "خطا: ام‌دبلیو‌اِمبد قادر به تعویض برچسب فیلم برای رابط ام‌دبلیو‌اِمبد نبود",
+ "mwe-embedplayer-add_to_end_of_sequence": "اضافه کردن به انتهای دنباله",
+ "mwe-embedplayer-missing_video_stream": "پوشه تصویری برای این جریان از دست می‌رود",
+ "mwe-embedplayer-play_clip": "نشان دادن کلیپ",
+ "mwe-embedplayer-pause_clip": "توقف کلیپ",
+ "mwe-embedplayer-volume_control": "تنظیم صدا",
+ "mwe-embedplayer-player_options": "گزینه‌های دستگاه پخش",
+ "mwe-embedplayer-timed_text": "متن زمان‌بندی‌ شده",
+ "mwe-embedplayer-player_fullscreen": "تمام صفحه",
+ "mwe-embedplayer-next_clip_msg": "نمایش کلیپ بعدی",
+ "mwe-embedplayer-prev_clip_msg": "نمایش کلیپ قبلی",
+ "mwe-embedplayer-current_clip_msg": "ادامه دادن نمایش کلیپ",
+ "mwe-embedplayer-seek_to": "در جستجوی $1",
+ "mwe-embedplayer-paused": "مکث",
+ "mwe-embedplayer-download_segment": "انتخاب دانلودː",
+ "mwe-embedplayer-download_full": "دریافت پروندهٔ ویدیویی کامل:",
+ "mwe-embedplayer-download_right_click": "برای بارگیری، کلیک راست کنید و این گزینه را انتخاب کنید<i>Save link as...</i>",
+ "mwe-embedplayer-download_clip": "دریافت ویدیو",
+ "mwe-embedplayer-download_text": "دریافت متن",
+ "mwe-embedplayer-download": "دریافت",
+ "mwe-embedplayer-share": "به اشتراک گذاشتن",
+ "mwe-embedplayer-credits": "اعتبار",
+ "mwe-embedplayer-about-library": "دربارهٔ‌کالترا پلیر",
+ "mwe-embedplayer-about-library-desc": "کتابخانه رسانه اچ‌تی‌ام‌ال۵ کالتُرا به شمارا قادر به مزیت اچ‌تی‌ام‌ال۵و ال‌تی؛ویدیوو جی‌تی؛ و ال‌تی؛صوتی‌وجی‌تی؛برچسبهای امروز با رابط دستگاه پخش سازگار در سراسر همه مرورگرهای اصلی می‌کند.\n[ $1 بیشتر درباره کتابخانه پخش کالتُرا].",
+ "mwe-embedplayer-clip_linkback": "صفحهٔ منبع کلیپ",
+ "mwe-embedplayer-choose_player": "انتخاب دستگاه پخش ویدیو",
+ "mwe-embedplayer-no-player": "دسترسی به پخش‌کننده وجود ندارد $1",
+ "mwe-embedplayer-share_this_video": "این تصویر را به اشتراک گذارید",
+ "mwe-embedplayer-video_credits": "اعتبارات ویدیو",
+ "mwe-embedplayer-no-video_credits": "هیچ اعتباری در دسترس نیست",
+ "mwe-embedplayer-kaltura-platform-title": "منبع باز صحنه ویدیو کالتُرا",
+ "mwe-embedplayer-menu_btn": "فهرست",
+ "mwe-embedplayer-close_btn": "بستن",
+ "mwe-embedplayer-ogg-player-vlc-player": "وی‌ال‌سی پلیر",
+ "mwe-embedplayer-ogg-player-oggNative": "پخش صوتی اچ‌تی‌ام‌ال۵",
+ "mwe-embedplayer-ogg-player-mp3Native": "پخش ام‌پی‌تری اچ‌تی‌ام‌ال۵",
+ "mwe-embedplayer-ogg-player-aacNative": "پخش ای‌سی‌سی اچ‌تی‌ام‌ال۵",
+ "mwe-embedplayer-ogg-player-h264Native": "پخش اچ.۲۶۴ اچ‌تی‌ام‌ال۵",
+ "mwe-embedplayer-ogg-player-webmNative": "پخش وب‌ام اچ‌تی‌ام‌ال۵",
+ "mwe-embedplayer-ogg-player-oggPlugin": "پلاگین صوتی عمومی",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "پلاگین زمان زود",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "اکتیو‌ایکس زمان زود",
+ "mwe-embedplayer-ogg-player-flowplayer": "پخش جریان",
+ "mwe-embedplayer-ogg-player-kplayer": "پخش کالترا",
+ "mwe-embedplayer-ogg-player-selected": "(انتخاب شده)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "اُ‌ام‌تی‌کا فلش وُربیس",
+ "mwe-embedplayer-for_best_experience": "برای یک تجربه پخش ویدیو بهتر، ما یک <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5 video browser</a> را توصیه می‌کنیم.",
+ "mwe-embedplayer-download-warn": "هیچ پخش در مرورگر سازگاری شناسایی نشد: برای پخش در مرورگر، لطفاً [ $1 آخرین فایرفاکس] را دانلود کنید",
+ "mwe-embedplayer-fullscreen-tip": "فشار دادن <b>F11</b> دکمه <i> مرورگر وب </i> تمام صفحه",
+ "mwe-embedplayer-fullscreen-tip-osx": "فشار دادن <b> کلید مبدل ⌘ F</b> به دکمه تمام صفحه",
+ "mwe-embedplayer-do_not_warn_again": "در آینده، این پیام را نشان ندهید",
+ "mwe-embedplayer-playerSelect": "بازیکنان",
+ "mwe-embedplayer-read_before_embed": "<ahref=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\"> این را </a> قبل از جاسازی بخوانید.",
+ "mwe-embedplayer-embed_site_or_blog": "قرار دادن در یک صفحه",
+ "mwe-embedplayer-embed_wiki": "قرار دادن در یک ویکی",
+ "mwe-embedplayer-related_videos": "مرتبط شدن ویدیو‌ها",
+ "mwe-embedplayer-seeking": "در حال پیگرد",
+ "mwe-embedplayer-buffering": "در حال بافر",
+ "mwe-embedplayer-video-h264": "ویدیو اچ.۲۶۴",
+ "mwe-embedplayer-video-webm": "ویدیو وب‌ام",
+ "mwe-embedplayer-video-flv": "فلش ویدیو",
+ "mwe-embedplayer-video-ogg": "صوتی تصویری",
+ "mwe-embedplayer-video-audio": "آهنگ صوتی",
+ "mwe-embedplayer-audio-mpeg": "ام‌پی‌ای‌جی صوتی",
+ "mwe-embedplayer-video-3gp": "ویدیو ۳‌جی‌پی",
+ "mwe-embedplayer-video-mpeg": "ویدیو ام‌پی‌ای‌جی",
+ "mwe-embedplayer-video-msvideo": "ویدیو ای‌وی‌آی",
+ "mwe-embedplayer-missing-source": "هیچ منبع ویدئویی پیدا نشد"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fi.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fi.json
new file mode 100644
index 00000000..21ac8482
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fi.json
@@ -0,0 +1,41 @@
+{
+ "@metadata": {
+ "authors": [
+ "Crt",
+ "Nedergard",
+ "Nike",
+ "Silvonen",
+ "Tofu II",
+ "MrTapsa"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Otsikko: $1",
+ "mwe-embedplayer-credit-date": "Päivämäärä: $1",
+ "mwe-embedplayer-credit-author": "Tekijä: $1",
+ "mwe-embedplayer-loading_plugin": "Ladataan liitännäistä...",
+ "mwe-embedplayer-player_options": "Soittimen asetukset",
+ "mwe-embedplayer-timed_text": "Ajastettu teksti",
+ "mwe-embedplayer-player_fullscreen": "Koko näyttö",
+ "mwe-embedplayer-download_full_video": "Lataa koko videotiedosto:",
+ "mwe-embedplayer-download_full_audio": "Lataa koko äänitiedosto:",
+ "mwe-embedplayer-download_clip": "Lataa video",
+ "mwe-embedplayer-download_text": "Lataa teksti",
+ "mwe-embedplayer-download": "Lataa",
+ "mwe-embedplayer-share": "Jaa",
+ "mwe-embedplayer-about-library": "Tietoja Kaltura-soittimesta",
+ "mwe-embedplayer-share_this_video": "Jaa tämä video",
+ "mwe-embedplayer-share_this_audio": "Jaa tämä äänitiedosto",
+ "mwe-embedplayer-menu_btn": "Valikko",
+ "mwe-embedplayer-close_btn": "Sulje",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura-soitin",
+ "mwe-embedplayer-ogg-player-selected": "(valittu)",
+ "mwe-embedplayer-for_best_experience": "Parempaa videotoistokokemusta varten suosituksena on selain, joka <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">tukee HTML5-videota</a>.",
+ "mwe-embedplayer-video-h264": "H.264-video",
+ "mwe-embedplayer-video-webm": "WebM-video",
+ "mwe-embedplayer-video-flv": "Flash-video",
+ "mwe-embedplayer-video-ogg": "Ogg-video",
+ "mwe-embedplayer-video-3gp": "3GP-video",
+ "mwe-embedplayer-video-mpeg": "MPEG-video",
+ "mwe-embedplayer-video-msvideo": "AVI-video"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fr.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fr.json
new file mode 100644
index 00000000..c7877923
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fr.json
@@ -0,0 +1,97 @@
+{
+ "@metadata": {
+ "authors": [
+ "Brunoperel",
+ "Crochet.david",
+ "Gomoko",
+ "IAlex",
+ "Nnemo",
+ "Peter17",
+ "Windes"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titre : $1",
+ "mwe-embedplayer-credit-date": "Date : $1",
+ "mwe-embedplayer-credit-author": "Auteur : $1",
+ "mwe-embedplayer-nocredits": "Aucun crédit disponible",
+ "mwe-embedplayer-loading_plugin": "chargement du greffon ...",
+ "mwe-embedplayer-select_playback": "Définir les préférences de lecture",
+ "mwe-embedplayer-link_back": "Lien retour",
+ "mwe-embedplayer-error_swap_vid": "Erreur : mv_embed n'a pas réussi à échanger l'attribut de la vidéo pour l'interface mv_embed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Ajouter à la fin de la séquence",
+ "mwe-embedplayer-missing_video_stream": "Le fichier vidéo pour ce flux est manquant",
+ "mwe-embedplayer-play_clip": "Lire le clip",
+ "mwe-embedplayer-pause_clip": "Mettre le clip en pause",
+ "mwe-embedplayer-volume_control": "Contrôle du volume",
+ "mwe-embedplayer-player_options": "Options du lecteur",
+ "mwe-embedplayer-timed_text": "Texte synchronisé",
+ "mwe-embedplayer-player_fullscreen": "Plein écran",
+ "mwe-embedplayer-next_clip_msg": "Lire le clip suivant",
+ "mwe-embedplayer-prev_clip_msg": "Lire le clip précédent",
+ "mwe-embedplayer-current_clip_msg": "Poursuivre la lecture de ce clip",
+ "mwe-embedplayer-seek_to": "Atteindre $1",
+ "mwe-embedplayer-paused": "en pause",
+ "mwe-embedplayer-download_segment": "Télécharger la sélection :",
+ "mwe-embedplayer-download_full_video": "Télécharger le fichier de la vidéo complète :",
+ "mwe-embedplayer-download_right_click": "Pour télécharger, cliquez-droit et sélectionnez <i>Enregistrer la cible du lien sous...</i>",
+ "mwe-embedplayer-download_clip": "Télécharger la vidéo",
+ "mwe-embedplayer-download_text": "Télécharger le texte",
+ "mwe-embedplayer-download": "Télécharger",
+ "mwe-embedplayer-share": "Partager",
+ "mwe-embedplayer-credits": "Crédits",
+ "mwe-embedplayer-about-library": "À propos du lecteur Kaltura",
+ "mwe-embedplayer-about-library-desc": "La bibliothèque HTML5 de Kaltura vous permet de profiter des balises HTML5 <code><nowiki><video></nowiki></code> et <code><nowiki><audio></nowiki></code> dès à présent avec un lecteur et une interface compatibles avec tous les principaux navigateurs.\n\t\n[$1 Pour en savoir plus sur la bibliothèque de lecture Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Page source du clip",
+ "mwe-embedplayer-choose_player": "Choisir le lecteur vidéo",
+ "mwe-embedplayer-no-player": "Aucun lecteur disponible pour $1",
+ "mwe-embedplayer-share_this_video": "Partager cette vidéo",
+ "mwe-embedplayer-share_this_audio": "Partager ce fichier audio",
+ "mwe-embedplayer-video_credits": "Crédits de la vidéo",
+ "mwe-embedplayer-no-video_credits": "Aucun crédit disponible",
+ "mwe-embedplayer-kaltura-platform-title": "Plateforme vidéo en source ouverte Kaltura",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Fermer",
+ "mwe-embedplayer-ogg-player-vlc-player": "Lecteur VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Lecteur Ogg HTML5",
+ "mwe-embedplayer-ogg-player-mp3Native": "Lecteur MP3 HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Lecteur AAC HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Lecteur H.264 HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Lecteur WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Module générique Ogg",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "VLC pour application iOS",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Module QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX QuickTime",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Lecteur Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(sélectionné)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Pour un meilleur visionnage de la vidéo, nous recommandons un <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">navigateur vidéo HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Aucun navigateur web compatible détecté: pour une lecteur intégré au navigateur, veuillez télécharger la [$1 dernière version de Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Appuyez sur <b>F11</b> pour basculer le <i>navigateur web</i> en mode plein écran",
+ "mwe-embedplayer-fullscreen-tip-osx": "Appuyez sur <b>maj ⌘ F</b> pour basculer en plein écran",
+ "mwe-embedplayer-do_not_warn_again": "Ne plus afficher ce message à l'avenir",
+ "mwe-embedplayer-playerSelect": "Lecteurs",
+ "mwe-embedplayer-read_before_embed": "Veuillez <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">lire ceci</a> avant de procéder !",
+ "mwe-embedplayer-embed_site_or_blog": "Intégrer dans une page",
+ "mwe-embedplayer-embed_wiki": "Intégré dans un wiki",
+ "mwe-embedplayer-related_videos": "Vidéos associées",
+ "mwe-embedplayer-seeking": "recherche",
+ "mwe-embedplayer-buffering": "mise en mémoire tampon",
+ "mwe-embedplayer-video-h264": "vidéo H.264",
+ "mwe-embedplayer-video-webm": "Vidéo WebM",
+ "mwe-embedplayer-video-flv": "vidéo Flash",
+ "mwe-embedplayer-video-ogg": "vidéo Ogg",
+ "mwe-embedplayer-video-audio": "Audio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Audio MPEG",
+ "mwe-embedplayer-video-3gp": "Vidéo 3GP",
+ "mwe-embedplayer-video-mpeg": "Vidéo MPEG",
+ "mwe-embedplayer-video-msvideo": "Vidéo AVI",
+ "mwe-embedplayer-missing-source": "Aucune source vidéo n'a été trouvée.",
+ "mwe-embedplayer-vlcapp-intro": "Afin de visualiser les vidéos de ce site sur un iPhone ou un iPad, vous avez besoin de $1, gratuite.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "Application VLC",
+ "mwe-embedplayer-vlcapp-downloadapp": "Télécharger l’application VLC depuis l’App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Ouvrir cette vidéo dans l’application VLC",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Télécharger cette vidéo",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Pour jouer des vidéos sur ce site, vous avez besoin de l’application gratuite VLC. L’installer maintenant ?"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/frp.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/frp.json
new file mode 100644
index 00000000..d70988ea
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/frp.json
@@ -0,0 +1,76 @@
+{
+ "@metadata": {
+ "authors": [
+ "ChrisPtDe"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titro : $1",
+ "mwe-embedplayer-credit-date": "Dâta : $1",
+ "mwe-embedplayer-credit-author": "Ôtor : $1",
+ "mwe-embedplayer-nocredits": "Gins de crèdit disponiblo",
+ "mwe-embedplayer-loading_plugin": "Chargement du modulo d’èxtension ...",
+ "mwe-embedplayer-select_playback": "Dèfenir les prèferences de lèctura",
+ "mwe-embedplayer-link_back": "Lim retôrn",
+ "mwe-embedplayer-error_swap_vid": "Èrror : mv_embed at pas reussi a èchangiér la balisa de la vidèô por l’entèrface mv_embed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Apondre a la fin de la sèquence",
+ "mwe-embedplayer-missing_video_stream": "Lo fichiér vidèô por cél flux est manquent",
+ "mwe-embedplayer-play_clip": "Liére lo clipe",
+ "mwe-embedplayer-pause_clip": "Betar lo clipe en pousa",
+ "mwe-embedplayer-volume_control": "Contrôlo du volumo",
+ "mwe-embedplayer-player_options": "Chouèx du liésor",
+ "mwe-embedplayer-timed_text": "Tèxto sincronisâ",
+ "mwe-embedplayer-player_fullscreen": "Plen ècran",
+ "mwe-embedplayer-next_clip_msg": "Liére lo clipe aprés",
+ "mwe-embedplayer-prev_clip_msg": "Liére lo clipe devant",
+ "mwe-embedplayer-current_clip_msg": "Porsiuvre la lèctura de ceti clipe",
+ "mwe-embedplayer-seek_to": "Avengiér $1",
+ "mwe-embedplayer-paused": "en pousa",
+ "mwe-embedplayer-download_segment": "Tèlèchargiér lo chouèx :",
+ "mwe-embedplayer-download_full": "Tèlèchargiér lo fichiér vidèô complèt :",
+ "mwe-embedplayer-download_right_click": "Por tèlèchargiér, clicâd-drêt et pués chouèsésséd <i>Encartar la ciba du lim desot...</i>",
+ "mwe-embedplayer-download_clip": "Tèlèchargiér la vidèô",
+ "mwe-embedplayer-download_text": "Tèlèchargiér lo tèxto",
+ "mwe-embedplayer-download": "Tèlèchargiér",
+ "mwe-embedplayer-share": "Partagiér",
+ "mwe-embedplayer-credits": "Crèdits",
+ "mwe-embedplayer-about-library": "Sur lo liésor Kaltura",
+ "mwe-embedplayer-clip_linkback": "Pâge sôrsa du clipe",
+ "mwe-embedplayer-choose_player": "Chouèsir lo liésor vidèô",
+ "mwe-embedplayer-no-player": "Gins de liésor disponiblo por $1",
+ "mwe-embedplayer-share_this_video": "Partagiér ceta vidèô",
+ "mwe-embedplayer-video_credits": "Crèdits de la vidèô",
+ "mwe-embedplayer-no-video_credits": "Gins de crèdit disponiblo",
+ "mwe-embedplayer-kaltura-platform-title": "Platafôrma vidèô a sôrsa uvèrta Kaltura",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Cllôre",
+ "mwe-embedplayer-ogg-player-vlc-player": "Liésor VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Liésor Ogg HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Liésor H.264 HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Liésor WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Modulo d’èxtension g·ènèrico Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Modulo d’èxtension QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX QuickTime",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Liésor Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(chouèsi)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-fullscreen-tip": "Apoyéd dessus <b>F11</b> por bascular lo <i>navigator vouèbe</i> en plen ècran",
+ "mwe-embedplayer-fullscreen-tip-osx": "Apoyéd dessus <b>granta lètra (''shift'') ⌘ F</b> por bascular en plen ècran",
+ "mwe-embedplayer-do_not_warn_again": "Pas més fâre vêre cél mèssâjo a l’avegnir.",
+ "mwe-embedplayer-playerSelect": "Liésors",
+ "mwe-embedplayer-read_before_embed": "Volyéd <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">liére cen</a> devant qu’apondre !",
+ "mwe-embedplayer-embed_site_or_blog": "Apondre a una pâge",
+ "mwe-embedplayer-related_videos": "Vidèôs associyês",
+ "mwe-embedplayer-seeking": "rechèrche",
+ "mwe-embedplayer-buffering": "misa en mèmouère tampon",
+ "mwe-embedplayer-video-h264": "Vidèô H.264",
+ "mwe-embedplayer-video-webm": "Vidèô WebM",
+ "mwe-embedplayer-video-flv": "Vidèô Flash",
+ "mwe-embedplayer-video-ogg": "Vidèô Ogg",
+ "mwe-embedplayer-video-audio": "Ôdiô Ogg",
+ "mwe-embedplayer-audio-mpeg": "Ôdiô MPEG",
+ "mwe-embedplayer-video-3gp": "Vidèô 3GP",
+ "mwe-embedplayer-video-mpeg": "Vidèô MPEG",
+ "mwe-embedplayer-video-msvideo": "Vidèô AVI",
+ "mwe-embedplayer-missing-source": "Niona sôrsa vidèô at étâ trovâ."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fy.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fy.json
new file mode 100644
index 00000000..7c57dd3e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/fy.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robin0van0der0vliet"
+ ]
+ },
+ "mwe-embedplayer-player_fullscreen": "Folsleinskerm",
+ "mwe-embedplayer-close_btn": "Slute"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ga.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ga.json
new file mode 100644
index 00000000..1333c22d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ga.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-embedplayer-close_btn": "Dún"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/gl.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/gl.json
new file mode 100644
index 00000000..252f08a2
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/gl.json
@@ -0,0 +1,96 @@
+{
+ "@metadata": {
+ "authors": [
+ "Toliño",
+ "Elisardojm"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Título: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "Non hai créditos dispoñibles",
+ "mwe-embedplayer-loading_plugin": "Cargando o complemento...",
+ "mwe-embedplayer-select_playback": "Configurar as preferencias de reprodución",
+ "mwe-embedplayer-link_back": "Ligazón de volta",
+ "mwe-embedplayer-error_swap_vid": "Erro: mwEmbed foi incapaz de cambiar a etiqueta do vídeo para a interface mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Engadir ao final da secuencia",
+ "mwe-embedplayer-missing_video_stream": "Falta o ficheiro de vídeo para ese fluxo",
+ "mwe-embedplayer-play_clip": "Reproducir o vídeo",
+ "mwe-embedplayer-pause_clip": "Pór o vídeo en pausa",
+ "mwe-embedplayer-volume_control": "Control do volume",
+ "mwe-embedplayer-player_options": "Opcións do reprodutor",
+ "mwe-embedplayer-timed_text": "Texto sincronizado",
+ "mwe-embedplayer-player_fullscreen": "Pantalla completa",
+ "mwe-embedplayer-next_clip_msg": "Reproducir o seguinte vídeo",
+ "mwe-embedplayer-prev_clip_msg": "Reproducir o vídeo anterior",
+ "mwe-embedplayer-current_clip_msg": "Continuar a reprodución deste vídeo",
+ "mwe-embedplayer-seek_to": "Buscar $1",
+ "mwe-embedplayer-paused": "en pausa",
+ "mwe-embedplayer-download_segment": "Descargar a selección:",
+ "mwe-embedplayer-download_full_video": "Descargar o ficheiro de vídeo completo:",
+ "mwe-embedplayer-download_full_audio": "Descargar o ficheiro de son completo:",
+ "mwe-embedplayer-download_right_click": "Para descargar, faga clic dereito e seleccione <i>Gardar a ligazón como...</i>",
+ "mwe-embedplayer-download_clip": "Descargar o vídeo",
+ "mwe-embedplayer-download_text": "Descargar o texto",
+ "mwe-embedplayer-download": "Descargar",
+ "mwe-embedplayer-share": "Compartir",
+ "mwe-embedplayer-credits": "Créditos",
+ "mwe-embedplayer-about-library": "Acerca do reprodutor Kaltura",
+ "mwe-embedplayer-about-library-desc": "A biblioteca HTML5 do Kaltura permite sacar proveito das etiquetas <code><nowiki><video></nowiki></code> e <code><nowiki><audio></nowiki></code> do HTML5 cun reprodutor e unha interface compatibles cos principais navegadores.\n\t\n[$1 Máis información sobre a biblioteca do reprodutor Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Páxina de orixe do vídeo",
+ "mwe-embedplayer-choose_player": "Escolla o reprodutor de vídeo",
+ "mwe-embedplayer-no-player": "Non hai ningún reprodutor dispoñible para $1",
+ "mwe-embedplayer-share_this_video": "Compartir este vídeo",
+ "mwe-embedplayer-share_this_audio": "Compartir este ficheiro de son",
+ "mwe-embedplayer-video_credits": "Créditos do vídeo",
+ "mwe-embedplayer-no-video_credits": "Non hai créditos dispoñibles",
+ "mwe-embedplayer-kaltura-platform-title": "Plataforma de vídeo de código aberto Kaltura",
+ "mwe-embedplayer-menu_btn": "Menú",
+ "mwe-embedplayer-close_btn": "Pechar",
+ "mwe-embedplayer-ogg-player-vlc-player": "Reprodutor VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Reprodutor Ogg HTML5",
+ "mwe-embedplayer-ogg-player-mp3Native": "Reprodutor MP3 HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Reprodutor AAC HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Reprodutor H.264 HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Reprodutor WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Complemento xenérico Ogg",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "VLC para aplicación iOS",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Complemento QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX QuickTime",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Reprodutor Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(seleccionado)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Para unha mellor experiencia de reprodución de vídeo recomendamos un <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">navegador de vídeo HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Non se detectou ningún reprodutor integrado compatible co navegador: Para ter unha mellor experiencia de reprodución de vídeo recomendamos a [$1 última versión do Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Prema <b>F11</b> para activar ou desactivar a pantalla completa do <i>navegador web</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Prema <b>maiús ⌘ F</b> para activar ou desactivar a pantalla completa",
+ "mwe-embedplayer-do_not_warn_again": "Non mostrar esta mensaxe no futuro.",
+ "mwe-embedplayer-playerSelect": "Reprodutores",
+ "mwe-embedplayer-read_before_embed": "Por favor, <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">olle isto</a> antes da inserción.",
+ "mwe-embedplayer-embed_site_or_blog": "Integrar nunha páxina",
+ "mwe-embedplayer-embed_wiki": "Integrar nun wiki",
+ "mwe-embedplayer-related_videos": "Vídeos relacionados",
+ "mwe-embedplayer-seeking": "procurando",
+ "mwe-embedplayer-buffering": "cargando no búfer",
+ "mwe-embedplayer-video-h264": "Vídeo H.264",
+ "mwe-embedplayer-video-webm": "Vídeo WebM",
+ "mwe-embedplayer-video-flv": "Vídeo Flash",
+ "mwe-embedplayer-video-ogg": "Vídeo Ogg",
+ "mwe-embedplayer-video-audio": "Son Ogg",
+ "mwe-embedplayer-audio-mpeg": "Son MPEG",
+ "mwe-embedplayer-video-3gp": "Vídeo 3gp",
+ "mwe-embedplayer-video-mpeg": "Vídeo MPEG",
+ "mwe-embedplayer-video-msvideo": "Vídeo AVI",
+ "mwe-embedplayer-missing-source": "Non se atopou o vídeo de orixe.",
+ "mwe-embedplayer-vlcapp-intro": "Para ver vídeos deste sitio nun iPhone ou iPad, necesita a $1 gratuíta.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "Aplicación VLC",
+ "mwe-embedplayer-vlcapp-downloadapp": "Descargar a aplicación VLC desde a App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Abrir este vídeo na aplicación VLC",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Descargar este vídeo",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Para reproducir vídeos neste sitio, necesita a aplicación gratuíta VLC. Instalar agora?",
+ "mwe-embedplayer-iewebmprompt-intro": "Oops! Unha cousa máis antes de que poida ver este vídeo...",
+ "mwe-embedplayer-iewebmprompt-linktext": "Instalar compoñentes multimedia de WebM para Microsoft Internet Explorer",
+ "mwe-embedplayer-iewebmprompt-outro": "Recargar esta páxina despois da instalación."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/grc.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/grc.json
new file mode 100644
index 00000000..c85efb15
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/grc.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Crazymadlover"
+ ]
+ },
+ "mwe-embedplayer-credit-date": "Ἡμερομηνία: $1"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/gsw.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/gsw.json
new file mode 100644
index 00000000..129b03cc
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/gsw.json
@@ -0,0 +1,80 @@
+{
+ "@metadata": {
+ "authors": [
+ "Als-Chlämens",
+ "Als-Holder"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titel: $1",
+ "mwe-embedplayer-credit-date": "Datum: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-loading_plugin": "Am Lade vum Plugin ...",
+ "mwe-embedplayer-select_playback": "Yystellige fir s Abspile setze",
+ "mwe-embedplayer-link_back": "Link retur",
+ "mwe-embedplayer-error_swap_vid": "Fähler: mv_embed het s Video-Tag fir d mv_embed-Oberflechi nit chenne uustusche",
+ "mwe-embedplayer-add_to_end_of_sequence": "Am Änd vum Abschnitt yyfiege",
+ "mwe-embedplayer-missing_video_stream": "D Videodatei fir dää Strang fählt",
+ "mwe-embedplayer-play_clip": "Clip abspile",
+ "mwe-embedplayer-pause_clip": "Clip aahalte",
+ "mwe-embedplayer-volume_control": "Yystellig fir d Lutsterki",
+ "mwe-embedplayer-player_options": "Yystellige fir s Abspilprogramm",
+ "mwe-embedplayer-timed_text": "Ächtzyt-Text",
+ "mwe-embedplayer-player_fullscreen": "Vollbildschrim",
+ "mwe-embedplayer-next_clip_msg": "Dr negscht Clip abspile",
+ "mwe-embedplayer-prev_clip_msg": "Dr vorig Clip abspile",
+ "mwe-embedplayer-current_clip_msg": "Dää Clip wyter abspile",
+ "mwe-embedplayer-seek_to": "$1 sueche",
+ "mwe-embedplayer-paused": "pausiert",
+ "mwe-embedplayer-download_segment": "Uuswahl zum Abelade:",
+ "mwe-embedplayer-download_full": "Di ganz Videodatei abelade:",
+ "mwe-embedplayer-download_right_click": "Zum Abelade druck uf di rächt Muustaschte un wehl <i>Link spychere unter...</i> uus",
+ "mwe-embedplayer-download_clip": "Video abelade",
+ "mwe-embedplayer-download_text": "Tekscht abelade",
+ "mwe-embedplayer-download": "Abelade",
+ "mwe-embedplayer-share": "Ufteile",
+ "mwe-embedplayer-credits": "Anerkännige",
+ "mwe-embedplayer-about-library": "Iber dr Kaltura-Player",
+ "mwe-embedplayer-about-library-desc": "D HTML5-Mediebibliothek vu Kaltura macht s megli d Vorteil vu dr beide HTML5-Tags <code><nowiki><video></nowiki></code> un <code><nowiki><audio></nowiki></code> mit eim eiheitlige Player-Interface bi allne fierende Webbrowser z bruche.\n\n[$1 Meh Informatione zue dr HTML5-Mediebibliothek vu Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Clip-Quällsyte",
+ "mwe-embedplayer-choose_player": "Videospiler uuswehle",
+ "mwe-embedplayer-no-player": "Fir $1 isch kei Player verfiegbar",
+ "mwe-embedplayer-share_this_video": "Des Video teile",
+ "mwe-embedplayer-video_credits": "Videokredit",
+ "mwe-embedplayer-no-video_credits": "Kei Urheberrächtsaagabe verfiegbar",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura Open-Source-Video-Plattform",
+ "mwe-embedplayer-menu_btn": "Uuswahl",
+ "mwe-embedplayer-close_btn": "Zuemache",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC-Player",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg-Player",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264-Player",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM-Player",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Generisch Ogg-Plugin",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-Plugin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura-Player",
+ "mwe-embedplayer-ogg-player-selected": "(uusgwehlt)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Fir e besseri Abspilqualitet vu däm Video empfähle mir:<br /><a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">Firefox 3.5</a>.",
+ "mwe-embedplayer-download-warn": "S Wiidergabeprogramm im Browser isch nit kompatibel. Zume im Browser aaluege, due bitte d [$1 nöisti Version vo Firefox] abelade.",
+ "mwe-embedplayer-fullscreen-tip": "D Taschte <b>F11</b> drugge, zume uff de Vollbildmodus vum <i>Webbrowsers</i> umzschalte.",
+ "mwe-embedplayer-fullscreen-tip-osx": "D Taschte <b>UMSCHALT ⌘ F</b> drugge, zume uff de Vollbildmodus vum <i>Webbrowsers</i> umzschalte.",
+ "mwe-embedplayer-do_not_warn_again": "Die Mäldig ab jetz nümm aazeige.",
+ "mwe-embedplayer-playerSelect": "Player",
+ "mwe-embedplayer-read_before_embed": "Bitte lis d <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Sicherheitsnotize iber s Yyfiege</a> voreb Du s wirkli yyfiege tuesch!",
+ "mwe-embedplayer-embed_site_or_blog": "Yybunde in e Syte",
+ "mwe-embedplayer-related_videos": "Verwandti Video",
+ "mwe-embedplayer-seeking": "Am Sueche",
+ "mwe-embedplayer-buffering": "pufferet",
+ "mwe-embedplayer-video-h264": "H.264-Video",
+ "mwe-embedplayer-video-webm": "WebM-Video",
+ "mwe-embedplayer-video-flv": "Flash-Video",
+ "mwe-embedplayer-video-ogg": "Ogg-Video",
+ "mwe-embedplayer-video-audio": "Ogg-Audiodatei",
+ "mwe-embedplayer-audio-mpeg": "MPEG-Audio",
+ "mwe-embedplayer-video-3gp": "3gp-Video",
+ "mwe-embedplayer-video-mpeg": "MPEG-Video",
+ "mwe-embedplayer-video-msvideo": "AVI-Video",
+ "mwe-embedplayer-missing-source": "S isch kei Videoclip gfunde wore."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/he.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/he.json
new file mode 100644
index 00000000..f12abe37
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/he.json
@@ -0,0 +1,83 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Guycn2",
+ "Inkbug",
+ "YaronSh"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "כותרת: $1",
+ "mwe-embedplayer-credit-date": "תאריך: $1",
+ "mwe-embedplayer-credit-author": "יוצר: $1",
+ "mwe-embedplayer-nocredits": "אין קרדיטים",
+ "mwe-embedplayer-loading_plugin": "טעינת תוסף...",
+ "mwe-embedplayer-select_playback": "הגדרת העדפות נגינה",
+ "mwe-embedplayer-link_back": "קישור חזרה",
+ "mwe-embedplayer-error_swap_vid": "שגיאה: mwEmbed לא היה מסוגל להחליף את תג הווידאו של ממשק mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "בסוף הרצף",
+ "mwe-embedplayer-missing_video_stream": "קובץ הווידאו עבור זרם זה חסר",
+ "mwe-embedplayer-play_clip": "נגינת הסרטון",
+ "mwe-embedplayer-pause_clip": "השהיית הסרטון",
+ "mwe-embedplayer-volume_control": "בקרת עוצמת השמע",
+ "mwe-embedplayer-player_options": "אפשרויות הנגן",
+ "mwe-embedplayer-timed_text": "טקסט מתוזמן",
+ "mwe-embedplayer-player_fullscreen": "מסך מלא",
+ "mwe-embedplayer-next_clip_msg": "נגינת הסרטון הבא",
+ "mwe-embedplayer-prev_clip_msg": "נגינת הסרטון הקודם",
+ "mwe-embedplayer-current_clip_msg": "המשך נגינת הסרטון",
+ "mwe-embedplayer-seek_to": "חיפוש $1",
+ "mwe-embedplayer-paused": "מושהה",
+ "mwe-embedplayer-download_segment": "הורדת הבחירה:",
+ "mwe-embedplayer-download_full": "להוריד למחשב את קובץ הווידאו המלא:",
+ "mwe-embedplayer-download_right_click": "כדי להוריד, לחצו בכפתור ימני של העכבר ובחרו באפשרות \"שמירה בשם...\" (<i>Save Link As ...</i>)",
+ "mwe-embedplayer-download_clip": "הורדת הווידאו",
+ "mwe-embedplayer-download_text": "להוריד למחשב את הטקסט",
+ "mwe-embedplayer-download": "הורדה",
+ "mwe-embedplayer-share": "שיתוף",
+ "mwe-embedplayer-credits": "תודות",
+ "mwe-embedplayer-about-library": "על אודות הנגן קלטורה",
+ "mwe-embedplayer-about-library-desc": "ספריית לנגינת מדיה בתקן HTML5 של קלטורה מאפשרת לכם להשתמש בפקודות <code><nowiki><video></nowiki></code> ו־<code><nowiki><audio></nowiki></code> של HTML5 היום עם ממשק קבוע בכל הדפדפנים הנפוצים.\n\n[$1 מידע נוסף על ספריית נגן המדיה של קלטורה]",
+ "mwe-embedplayer-clip_linkback": "דף המקור של הסרטון",
+ "mwe-embedplayer-choose_player": "בחירת נגן וידאו",
+ "mwe-embedplayer-no-player": "הנגן עבור $1 אינו זמין",
+ "mwe-embedplayer-share_this_video": "שיתוף סרט זה",
+ "mwe-embedplayer-video_credits": "יוצרי הסרט",
+ "mwe-embedplayer-no-video_credits": "הקרדיטים לא זמינים",
+ "mwe-embedplayer-kaltura-platform-title": "פלטפורמת וידאו בקוד פתוח של קלטורה",
+ "mwe-embedplayer-menu_btn": "תפריט",
+ "mwe-embedplayer-close_btn": "לסגור",
+ "mwe-embedplayer-ogg-player-vlc-player": "נגן VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "נגן Ogg שך HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "נגן H.264 של HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "נגן WebM של HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "תוסף Ogg כללי",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "תוסף QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "נגן קלטורה",
+ "mwe-embedplayer-ogg-player-selected": "(נבחר)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "להצגת וידאו משופרת אנחנו ממליצים על <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">דפדפן שתומך בווידאו ב־html5</a>.",
+ "mwe-embedplayer-download-warn": "לא נמצא נגן תואם בדפדפן: כדי לנגן בתוך הדפדפן יש להוריד את [$1 הגרסה החדשה ביותר של פיירפוקס].",
+ "mwe-embedplayer-fullscreen-tip": "לחצו <b>F11</b> כדי להעביר את הדפדפן למצב מסך מלא וחזרה",
+ "mwe-embedplayer-fullscreen-tip-osx": "לחיצה על <b>shift ⌘ F</b> מפעילה מסך מלא",
+ "mwe-embedplayer-do_not_warn_again": "לא להציג את ההודעה הזאת שוב",
+ "mwe-embedplayer-playerSelect": "נגנים",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">אנא קִראו</a> לפני הטמעה.",
+ "mwe-embedplayer-embed_site_or_blog": "הטמעה באתר או בבלוג שלכם",
+ "mwe-embedplayer-embed_wiki": "להטמיע בוויקי",
+ "mwe-embedplayer-related_videos": "סרטונים קשורים",
+ "mwe-embedplayer-seeking": "חיפוש",
+ "mwe-embedplayer-buffering": "אגירה",
+ "mwe-embedplayer-video-h264": "סרט H.264",
+ "mwe-embedplayer-video-webm": "סרט WebM",
+ "mwe-embedplayer-video-flv": "סרט Flash",
+ "mwe-embedplayer-video-ogg": "סרט Ogg",
+ "mwe-embedplayer-video-audio": "שמע Ogg",
+ "mwe-embedplayer-audio-mpeg": "שמע MPEG",
+ "mwe-embedplayer-video-3gp": "סרט 3GP",
+ "mwe-embedplayer-video-mpeg": "סרט MPEG",
+ "mwe-embedplayer-video-msvideo": "סרט AVI",
+ "mwe-embedplayer-missing-source": "הסרט המקורי לא נמצא"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/hsb.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/hsb.json
new file mode 100644
index 00000000..d52ebb0b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/hsb.json
@@ -0,0 +1,83 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titul: $1",
+ "mwe-embedplayer-credit-date": "Datum: $1",
+ "mwe-embedplayer-credit-author": "Awtor: $1",
+ "mwe-embedplayer-nocredits": "Žane dźakprajenja k dispoziciji",
+ "mwe-embedplayer-loading_plugin": "tykač so začituje ...",
+ "mwe-embedplayer-select_playback": "Nastajenje za playback stajić",
+ "mwe-embedplayer-link_back": "Wotkaz wróćo",
+ "mwe-embedplayer-error_swap_vid": "Zmylk: mv_embed njemóžeše widejotafličku za powjerch mv_embed wuměnić",
+ "mwe-embedplayer-add_to_end_of_sequence": "Na kóncu sekwency přidać",
+ "mwe-embedplayer-missing_video_stream": "Widejowa dataja za tutón prud faluje",
+ "mwe-embedplayer-play_clip": "Klip wothrać",
+ "mwe-embedplayer-pause_clip": "Klip zastajić",
+ "mwe-embedplayer-volume_control": "Regulowanje sylnosće zwuka",
+ "mwe-embedplayer-player_options": "Opcije wothrawaka",
+ "mwe-embedplayer-timed_text": "Synchronizowany tekst",
+ "mwe-embedplayer-player_fullscreen": "Połna wobrazowka",
+ "mwe-embedplayer-next_clip_msg": "Přichodny klip wothrać",
+ "mwe-embedplayer-prev_clip_msg": "Předchadny klip wothrać",
+ "mwe-embedplayer-current_clip_msg": "Tutón klip dale wothrać",
+ "mwe-embedplayer-seek_to": "$1 pytać",
+ "mwe-embedplayer-paused": "zastajeny",
+ "mwe-embedplayer-download_segment": "Wuběr sćahnyć:",
+ "mwe-embedplayer-download_full": "Dospołnu widejowu dataju sćahnyć:",
+ "mwe-embedplayer-download_right_click": "Zo by sćahnył, klikń z prawej tastu a wubjer <i>Wotkaz składować jako...</i>",
+ "mwe-embedplayer-download_clip": "Widejo sćahnyć",
+ "mwe-embedplayer-download_text": "Tekst",
+ "mwe-embedplayer-download": "Sćahnyć",
+ "mwe-embedplayer-share": "Dźělić",
+ "mwe-embedplayer-credits": "Dźakprajenje",
+ "mwe-embedplayer-about-library": "Wo wothrawaku Kaltura",
+ "mwe-embedplayer-about-library-desc": "Medijowa HTML5-biblioteka Kaltury zmóžnja lěpšiny tafličkow <code><nowiki><video></code> a <code><nowiki><audio></code> dźensa z jednotnym powjerchom wothrawaka ze wšěmi načolnymi wobhladowakami wužiwać.\n\n[$1 Wjace wo bibliotece wothrawaka Kaltura]",
+ "mwe-embedplayer-clip_linkback": "Žórłow strona klipa",
+ "mwe-embedplayer-choose_player": "Widejowy wothrawak wubrać",
+ "mwe-embedplayer-no-player": "Žadyn wothrawak za $1 k dispoziciji",
+ "mwe-embedplayer-share_this_video": "Tute widejo zhromadnje wužiwać",
+ "mwe-embedplayer-video_credits": "Dźakprajenja za wutworjenje wideja",
+ "mwe-embedplayer-no-video_credits": "Žane podaća wo awtorach",
+ "mwe-embedplayer-kaltura-platform-title": "Widejoplatforma Kaltura ze zjawneho žórła",
+ "mwe-embedplayer-menu_btn": "Meni",
+ "mwe-embedplayer-close_btn": "Začinić",
+ "mwe-embedplayer-ogg-player-vlc-player": "Wothrawak VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Wothrawak HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-mp3Native": "Wothrawak HTML5 MP3",
+ "mwe-embedplayer-ogg-player-aacNative": "Wothrawak HTML5 AAC",
+ "mwe-embedplayer-ogg-player-h264Native": "Wothrawak HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Wothrawak za HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Tykač Generic Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Tykač QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX QuickTime",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Wothrawak Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(wubrany)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Za lěpše wothrawanje widejow poručamy <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">widejowobhladowak za HTML 5</a>.",
+ "mwe-embedplayer-download-warn": "Njekompatibelne wothrawak we wobhladowaku namakany: za wothrawanje znutřka wobhladowaka, sćehń prošu [$1 najnowšu wersiju Mozilla Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Tłóč na <b>F11</b>, zo by <i>webwobhladowak</i> do modusa połneje wobrazowki přepinał",
+ "mwe-embedplayer-fullscreen-tip-osx": "Stłóč <b>UMSCH ⌘ F</b>, zo by do modusa połneje wobrazowki přepinył",
+ "mwe-embedplayer-do_not_warn_again": "W přichodźe tutu zdźělenku wjace njepokazać",
+ "mwe-embedplayer-playerSelect": "Wothrawaki",
+ "mwe-embedplayer-read_before_embed": "Prošu <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">čitaj to</a> do zasadźenja!",
+ "mwe-embedplayer-embed_site_or_blog": "Na stronje zasadźić",
+ "mwe-embedplayer-embed_wiki": "We wikiju zasadźić",
+ "mwe-embedplayer-related_videos": "Přiwuzne wideja",
+ "mwe-embedplayer-seeking": "pyta so",
+ "mwe-embedplayer-buffering": "pufruje so",
+ "mwe-embedplayer-video-h264": "Wideo H.264",
+ "mwe-embedplayer-video-webm": "WebM-widejo",
+ "mwe-embedplayer-video-flv": "Widejo Flash",
+ "mwe-embedplayer-video-ogg": "Ogg-widejo",
+ "mwe-embedplayer-video-audio": "Ogg-awdio",
+ "mwe-embedplayer-audio-mpeg": "MPEG awdio",
+ "mwe-embedplayer-video-3gp": "3GP widejo",
+ "mwe-embedplayer-video-mpeg": "MPEG widejo",
+ "mwe-embedplayer-video-msvideo": "AVI widejo",
+ "mwe-embedplayer-missing-source": "Žane widejo namakane."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/hu.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/hu.json
new file mode 100644
index 00000000..c9c13278
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/hu.json
@@ -0,0 +1,75 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dani",
+ "Misibacsi",
+ "Tacsipacsi",
+ "Csega"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Cím: $1",
+ "mwe-embedplayer-credit-date": "Dátum: $1",
+ "mwe-embedplayer-credit-author": "Szerző: $1",
+ "mwe-embedplayer-loading_plugin": "bővítmény betöltése…",
+ "mwe-embedplayer-select_playback": "Használt lejátszó kiválasztása",
+ "mwe-embedplayer-link_back": "Visszahivatkozás",
+ "mwe-embedplayer-error_swap_vid": "Hiba: az mv_embed nem tudta kicserélni a videó taget az mv_embed felületére",
+ "mwe-embedplayer-add_to_end_of_sequence": "Hozzáadás a szekvencia végéhez",
+ "mwe-embedplayer-missing_video_stream": "Az adatfolyamhoz tartozó videofájl nincs meg",
+ "mwe-embedplayer-play_clip": "Klip lejátszása",
+ "mwe-embedplayer-pause_clip": "Klip pillanatállj",
+ "mwe-embedplayer-volume_control": "Hangerőszabályzó",
+ "mwe-embedplayer-player_options": "Lejátszó beállításai",
+ "mwe-embedplayer-timed_text": "Időzített szöveg",
+ "mwe-embedplayer-player_fullscreen": "Teljes képernyő",
+ "mwe-embedplayer-next_clip_msg": "Következő klip lejátszása",
+ "mwe-embedplayer-prev_clip_msg": "Előző klip lejátszása",
+ "mwe-embedplayer-current_clip_msg": "Klip lejátszásának folytatása",
+ "mwe-embedplayer-seek_to": "$1 keresése",
+ "mwe-embedplayer-paused": "szüneteltetve",
+ "mwe-embedplayer-download_segment": "Kijelölés letöltése:",
+ "mwe-embedplayer-download_full_video": "Teljes videofájl letöltése:",
+ "mwe-embedplayer-download_full_audio": "Teljes audiofájl letöltése:",
+ "mwe-embedplayer-download_right_click": "A letöltéshez kattints jobb gombbal, és <i>Cél mentése másként…</i>",
+ "mwe-embedplayer-download_clip": "Videó letöltése",
+ "mwe-embedplayer-download_text": "Szöveg letöltése",
+ "mwe-embedplayer-download": "Letöltés",
+ "mwe-embedplayer-share": "Megosztás",
+ "mwe-embedplayer-credits": "Készítők",
+ "mwe-embedplayer-about-library": "A Kaltura lejátszó névjegye",
+ "mwe-embedplayer-about-library-desc": "A Kaltura HTML5-ös médialejátszó lehetővé teszi, hogy kihasználd a HTML5 <code><nowiki><video></nowiki></code> és <code><nowiki><audio></nowiki></code> elemeit azonos felületet biztonsítva az összes lényeges böngésző esetén.\n\t\n[$1 További információ a Kaltura lejátszóról].",
+ "mwe-embedplayer-clip_linkback": "Klip forráslapja",
+ "mwe-embedplayer-choose_player": "Videolejátszó választása",
+ "mwe-embedplayer-no-player": "Nincs megfelelő lejátszó a következőhöz: $1",
+ "mwe-embedplayer-share_this_video": "Videó megosztása",
+ "mwe-embedplayer-share_this_audio": "Audiofájl megosztása",
+ "mwe-embedplayer-video_credits": "A videó készítői",
+ "mwe-embedplayer-menu_btn": "Menü",
+ "mwe-embedplayer-close_btn": "Bezárás",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC player",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg lejátszó",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 lejátszó",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM-lejátszó",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Általános Ogg bővítmény",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-bővítmény",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura lejátszó",
+ "mwe-embedplayer-ogg-player-selected": "(kiválasztva)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "A jobb videolejátszási élményhez <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5-öt támogató böngészőt</a> ajánlunk.",
+ "mwe-embedplayer-do_not_warn_again": "A jövőben ne jelenjen meg ez az üzenet",
+ "mwe-embedplayer-playerSelect": "Lejátszók",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Olvasd el ezt</a>, mielőtt beillesztenéd.",
+ "mwe-embedplayer-embed_site_or_blog": "Beágyazás egy lapra",
+ "mwe-embedplayer-related_videos": "Kapcsolódó videók",
+ "mwe-embedplayer-seeking": "keresés",
+ "mwe-embedplayer-buffering": "pufferelés",
+ "mwe-embedplayer-video-h264": "H.264 videó",
+ "mwe-embedplayer-video-webm": "WebM-videó",
+ "mwe-embedplayer-video-flv": "Flash videó",
+ "mwe-embedplayer-video-ogg": "Ogg videó",
+ "mwe-embedplayer-video-audio": "Ogg hangfájl",
+ "mwe-embedplayer-missing-source": "Nem található forrásvideó"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ia.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ia.json
new file mode 100644
index 00000000..94586400
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ia.json
@@ -0,0 +1,79 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titulo: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-loading_plugin": "cargamento del plug-in ...",
+ "mwe-embedplayer-select_playback": "Definir preferentia de reproduction",
+ "mwe-embedplayer-link_back": "Retroligamine",
+ "mwe-embedplayer-error_swap_vid": "Error: mv_embed non poteva excambiar le etiquetta de video pro le interfacie mv_embed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Adder al fin del sequentia",
+ "mwe-embedplayer-missing_video_stream": "Le file de video pro iste fluxo es mancante",
+ "mwe-embedplayer-play_clip": "Reproducer clip",
+ "mwe-embedplayer-pause_clip": "Pausar clip",
+ "mwe-embedplayer-volume_control": "Controlo de volumine",
+ "mwe-embedplayer-player_options": "Optiones de reproductor",
+ "mwe-embedplayer-timed_text": "Subtitulos",
+ "mwe-embedplayer-player_fullscreen": "Schermo complete",
+ "mwe-embedplayer-next_clip_msg": "Reproducer sequente clip",
+ "mwe-embedplayer-prev_clip_msg": "Reproducer precedente clip",
+ "mwe-embedplayer-current_clip_msg": "Continuar a reproducer iste clip",
+ "mwe-embedplayer-seek_to": "Ir a $1",
+ "mwe-embedplayer-paused": "in pausa",
+ "mwe-embedplayer-download_segment": "Discargar selection:",
+ "mwe-embedplayer-download_full": "Discargar file de video complete:",
+ "mwe-embedplayer-download_right_click": "Pro discargar, face clic a dextra e selige <i>Immagazinar ligamine como...</i> (Save link as...)",
+ "mwe-embedplayer-download_clip": "Discargar video",
+ "mwe-embedplayer-download_text": "Discargar texto",
+ "mwe-embedplayer-download": "Discargar",
+ "mwe-embedplayer-share": "Divider",
+ "mwe-embedplayer-credits": "Creditos",
+ "mwe-embedplayer-about-library": "A proposito del reproductor Kaltura",
+ "mwe-embedplayer-about-library-desc": "Le bibliotheca multimedia HTML5 de Kaltura te permitte traher avantage del etiquettas HTML5 <code><nowiki><video></nowiki></code> e <code><nowiki><audio></nowiki></code> jam hodie con un interfacie de reproductor consistente trans tote le major navigatores.\n\t\n[$1 Plus a proposito del bibliotheca reproductor Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Pagina de fonte del clip",
+ "mwe-embedplayer-choose_player": "Seliger reproductor de video",
+ "mwe-embedplayer-no-player": "Nulle reproductor disponibile pro $1",
+ "mwe-embedplayer-share_this_video": "Divider iste video",
+ "mwe-embedplayer-video_credits": "Creditos de video",
+ "mwe-embedplayer-no-video_credits": "Nulle credito disponibile",
+ "mwe-embedplayer-kaltura-platform-title": "Platteforma video a codice aperte Kaltura",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Clauder",
+ "mwe-embedplayer-ogg-player-vlc-player": "Reproductor VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Reproductor Ogg HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Reproductor H.264 HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Lector WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Plug-in generic pro Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Plug-in de QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Le reproductor Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(seligite)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Pro un melior experientia de reproduction de video, nos recommenda:<br /><a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">Firefox 3.5</a>.",
+ "mwe-embedplayer-download-warn": "Nulle lector compatibile esseva detegite in le navigator del web. Pro reproduction in le navigator, per favor discarga le [$1 ultime version de Firefox].",
+ "mwe-embedplayer-fullscreen-tip": "Preme <b>F11</b> pro alternar le <i>navigator del web</i> in plen schermo",
+ "mwe-embedplayer-fullscreen-tip-osx": "Preme <b>shift ⌘ F</b> pro alternar plen schermo",
+ "mwe-embedplayer-do_not_warn_again": "In le futuro, non monstrar iste message",
+ "mwe-embedplayer-playerSelect": "Reproductores",
+ "mwe-embedplayer-read_before_embed": "Per favor lege le <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">notas de securitate super incastramento remote</a> ante de incastrar un cosa!",
+ "mwe-embedplayer-embed_site_or_blog": "Incastrar in un pagina",
+ "mwe-embedplayer-related_videos": "Videos connexe",
+ "mwe-embedplayer-seeking": "cercante",
+ "mwe-embedplayer-buffering": "precargamento",
+ "mwe-embedplayer-video-h264": "Video H.264",
+ "mwe-embedplayer-video-webm": "Video WebM",
+ "mwe-embedplayer-video-flv": "Video Flash",
+ "mwe-embedplayer-video-ogg": "Video Ogg",
+ "mwe-embedplayer-video-audio": "Audio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Audio MPEG",
+ "mwe-embedplayer-video-3gp": "Video 3gp",
+ "mwe-embedplayer-video-mpeg": "Video MPEG",
+ "mwe-embedplayer-video-msvideo": "Video AVI",
+ "mwe-embedplayer-missing-source": "Nulle video de origine ha essite trovate."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/id.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/id.json
new file mode 100644
index 00000000..58c68df9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/id.json
@@ -0,0 +1,76 @@
+{
+ "@metadata": {
+ "authors": [
+ "Farras",
+ "IvanLanin"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Judul: $1",
+ "mwe-embedplayer-credit-date": "Tanggal: $1",
+ "mwe-embedplayer-credit-author": "Pembuat: $1",
+ "mwe-embedplayer-loading_plugin": "memuat pengaya ...",
+ "mwe-embedplayer-select_playback": "Atur preferensi pemutar",
+ "mwe-embedplayer-link_back": "Pranala balik",
+ "mwe-embedplayer-error_swap_vid": "Kesalahan: mv_embed tak dapat menukar tag video untuk antarmuka mv_embed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Tambahkan ke akhir rangkaian",
+ "mwe-embedplayer-missing_video_stream": "Berkas video untuk aliran tidak ditemukan",
+ "mwe-embedplayer-play_clip": "Mainkan klip",
+ "mwe-embedplayer-pause_clip": "Jeda klip",
+ "mwe-embedplayer-volume_control": "Kontrol volume",
+ "mwe-embedplayer-player_options": "Pilihan pemutar",
+ "mwe-embedplayer-timed_text": "Teks berjangka waktu",
+ "mwe-embedplayer-player_fullscreen": "Layar penuh",
+ "mwe-embedplayer-next_clip_msg": "Putar klip berikut",
+ "mwe-embedplayer-prev_clip_msg": "Putar klip sebelumnya",
+ "mwe-embedplayer-current_clip_msg": "Lanjutkan pemutaran klip ini",
+ "mwe-embedplayer-seek_to": "Cari $1",
+ "mwe-embedplayer-paused": "jeda",
+ "mwe-embedplayer-download_segment": "Unduh pilihan:",
+ "mwe-embedplayer-download_full": "Unduh berkas video lengkap:",
+ "mwe-embedplayer-download_right_click": "Untuk mengunduh, klik kanan dan pilih <i>Simpan tautan sebagai...</i>",
+ "mwe-embedplayer-download_clip": "Unduh video",
+ "mwe-embedplayer-download_text": "Unduh teks",
+ "mwe-embedplayer-download": "Unduh",
+ "mwe-embedplayer-share": "Bagikan",
+ "mwe-embedplayer-credits": "Kredit",
+ "mwe-embedplayer-about-library": "About pemutar Kaltura",
+ "mwe-embedplayer-about-library-desc": "Pustaka media HTML5 Kaltura memungkinkan Anda untuk mengambil keuntungan dari tag HTML5 <nowiki><video></nowiki> dan <nowiki><audio></nowiki> dengan antarmuka pemutar yang konsisten di semua peramban utama.\n\n [$1 Selengkapnya tentang pustaka pemutar Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Halaman sumber klip",
+ "mwe-embedplayer-choose_player": "Pilih pemutar video",
+ "mwe-embedplayer-no-player": "Tidak ada pemutar yang tersedia untuk $1",
+ "mwe-embedplayer-share_this_video": "Bagikan video ini",
+ "mwe-embedplayer-video_credits": "Kredit video",
+ "mwe-embedplayer-no-video_credits": "Kredit tidak tersedia",
+ "mwe-embedplayer-kaltura-platform-title": "Platform video terbuka Kaltura",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Tutup",
+ "mwe-embedplayer-ogg-player-vlc-player": "Pemutar VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Pemutar Ogg HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Pemutar H.264 HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Pemutar WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Pengaya generik Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Pengaya QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX QuickTime",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Pemutar Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(dipilih)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Untuk pengalaman pemutaran video yang lebih baik kami menyarankan: <br /><a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">Firefox 3.5</a>.",
+ "mwe-embedplayer-download-warn": "Pemutar dalam peramban yang kompatibel tidak ditemukan. Untuk pemutaran dalam peramban silakan unduh [$1 Firefox terbaru]",
+ "mwe-embedplayer-fullscreen-tip": "Tekan <b>F11</b> untuk beralih ke layar penuh <i>peramban web</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Tekan <b>shift ⌘ F</b> untuk beralih ke layar penuh",
+ "mwe-embedplayer-do_not_warn_again": "Jangan tampilkan lagi pesan ini",
+ "mwe-embedplayer-playerSelect": "Pemutar",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Baca ini</a> sebelum mengikutkan.",
+ "mwe-embedplayer-embed_site_or_blog": "Sertakan pada suatu halaman",
+ "mwe-embedplayer-related_videos": "Video yang berhubungan",
+ "mwe-embedplayer-seeking": "mencari",
+ "mwe-embedplayer-buffering": "menyinggahkan",
+ "mwe-embedplayer-video-h264": "Video H.264",
+ "mwe-embedplayer-video-webm": "Video WebM",
+ "mwe-embedplayer-video-flv": "Video flash",
+ "mwe-embedplayer-video-ogg": "Video ogg",
+ "mwe-embedplayer-video-audio": "Audio ogg",
+ "mwe-embedplayer-missing-source": "Tidak ada video sumber yang ditemukan."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ilo.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ilo.json
new file mode 100644
index 00000000..b379d2a9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ilo.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lam-ang"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titulo: $1",
+ "mwe-embedplayer-credit-date": "Petsa: $1",
+ "mwe-embedplayer-credit-author": "Mannurat: $1",
+ "mwe-embedplayer-nocredits": "Awan dagiti pammadayaw a magun-od",
+ "mwe-embedplayer-loading_plugin": "Agikarkarga ti plugin ...",
+ "mwe-embedplayer-select_playback": "Agikabil ti preperensia ti panagy-ayam",
+ "mwe-embedplayer-link_back": "Agisilpo",
+ "mwe-embedplayer-error_swap_vid": "Biddut: Ti mwEmbed ket saan a nakaisukat ti etiketa ti video para iti interface ti mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Inayon idiay gibus ti pangsasarunuan"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/is.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/is.json
new file mode 100644
index 00000000..3a61ae5e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/is.json
@@ -0,0 +1,64 @@
+{
+ "@metadata": {
+ "authors": [
+ "Snævar"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titill: $1",
+ "mwe-embedplayer-credit-date": "Dagsetning: $1",
+ "mwe-embedplayer-credit-author": "Höfundur: $1",
+ "mwe-embedplayer-loading_plugin": "Hleð viðbót...",
+ "mwe-embedplayer-select_playback": "Setja afspilunar stillingar",
+ "mwe-embedplayer-link_back": "Tengja tilbaka",
+ "mwe-embedplayer-error_swap_vid": "Villa: mwEmbad gat ekki skipt myndbands tagi út fyrir mwEmbed valmyndina",
+ "mwe-embedplayer-missing_video_stream": "Myndbandið fyrir streymið vantar",
+ "mwe-embedplayer-play_clip": "Spila myndband",
+ "mwe-embedplayer-pause_clip": "Gera hlé á spilun",
+ "mwe-embedplayer-volume_control": "Hljóðstyrkur",
+ "mwe-embedplayer-player_options": "Stillingar spilarans",
+ "mwe-embedplayer-player_fullscreen": "Fylla skjá",
+ "mwe-embedplayer-next_clip_msg": "Spila næsta myndband",
+ "mwe-embedplayer-prev_clip_msg": "Spila fyrra myndband",
+ "mwe-embedplayer-current_clip_msg": "Halda áfram spilun",
+ "mwe-embedplayer-seek_to": "Sæki $1",
+ "mwe-embedplayer-paused": "í bið",
+ "mwe-embedplayer-download_segment": "Hlaða niður hluta:",
+ "mwe-embedplayer-download_full": "Hlaða niður allri skránni:",
+ "mwe-embedplayer-download_right_click": "Til að hlaða niður, hægri smelltu og veldu <i>Vista tengil sem...</i>",
+ "mwe-embedplayer-download_clip": "Sækja myndband",
+ "mwe-embedplayer-download_text": "Hlaða niður texta",
+ "mwe-embedplayer-download": "Hlaða niður",
+ "mwe-embedplayer-share": "Deila",
+ "mwe-embedplayer-about-library": "Um Kaltura-spilarann",
+ "mwe-embedplayer-choose_player": "Velja myndbands spilara",
+ "mwe-embedplayer-no-player": "Enginn spilari til fyrir $1",
+ "mwe-embedplayer-share_this_video": "Deila þessu myndbandi",
+ "mwe-embedplayer-close_btn": "Loka",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC-spilari",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg-spilari",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264-spilari",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML WebM-spilari",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Almenn Ogg viðbót",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-viðbót",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura-spilari",
+ "mwe-embedplayer-ogg-player-selected": "(valið)",
+ "mwe-embedplayer-download-warn": "Enginn samhæfður spilari fannst. Til þess að spila myndbandið í \tvafranum vinsamlegst sóttu [$1 nýjasta Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Til þess að fylla út í skjáinn, smelltu á <b>F11</b>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Til þess að fylla út í skjáinn, smelltu á <b>shift ⌘ F</b>",
+ "mwe-embedplayer-do_not_warn_again": "Ekki sýna þessi skilaboð framvegis",
+ "mwe-embedplayer-playerSelect": "Spilarar",
+ "mwe-embedplayer-related_videos": "Svipuð myndbönd",
+ "mwe-embedplayer-seeking": "sæki",
+ "mwe-embedplayer-buffering": "hleð niður í biðminni",
+ "mwe-embedplayer-video-h264": "H.264-myndband",
+ "mwe-embedplayer-video-webm": "WebM-myndband",
+ "mwe-embedplayer-video-flv": "Flash-myndband",
+ "mwe-embedplayer-video-ogg": "Ogg-myndband",
+ "mwe-embedplayer-video-audio": "Ogg-hljóðskrá",
+ "mwe-embedplayer-audio-mpeg": "MPEG-hljóðskrá",
+ "mwe-embedplayer-video-3gp": "3GP-myndband",
+ "mwe-embedplayer-video-mpeg": "MPEG-myndband",
+ "mwe-embedplayer-video-msvideo": "AVI-myndband"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/it.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/it.json
new file mode 100644
index 00000000..e991b7d8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/it.json
@@ -0,0 +1,92 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beta16",
+ "Darth Kule",
+ "F. Cosoleto",
+ "Gianfranco"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titolo: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autore: $1",
+ "mwe-embedplayer-nocredits": "Crediti non disponibili",
+ "mwe-embedplayer-loading_plugin": "Caricamento plugin...",
+ "mwe-embedplayer-select_playback": "Imposta le preferenze per la riproduzione",
+ "mwe-embedplayer-link_back": "Link di ritorno",
+ "mwe-embedplayer-error_swap_vid": "Errore: mwEmbed non è riuscito a scambiare il tag video per l'interfaccia mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Aggiungi alla fine della sequenza",
+ "mwe-embedplayer-missing_video_stream": "Manca il file video per questo flusso",
+ "mwe-embedplayer-play_clip": "Riproduci clip",
+ "mwe-embedplayer-pause_clip": "Pausa clip",
+ "mwe-embedplayer-volume_control": "Controllo volume",
+ "mwe-embedplayer-player_options": "Opzioni lettore",
+ "mwe-embedplayer-timed_text": "Sottotitoli",
+ "mwe-embedplayer-player_fullscreen": "Schermo intero",
+ "mwe-embedplayer-next_clip_msg": "Riproduci clip successivo",
+ "mwe-embedplayer-prev_clip_msg": "Riproduci clip precedente",
+ "mwe-embedplayer-current_clip_msg": "Continuare a riprodurre questa clip",
+ "mwe-embedplayer-seek_to": "Salta a $1",
+ "mwe-embedplayer-paused": "in pausa",
+ "mwe-embedplayer-download_segment": "Scarica selezione:",
+ "mwe-embedplayer-download_full": "Scarica file video completo:",
+ "mwe-embedplayer-download_right_click": "Per scaricare, fare clic col destro e selezionare <i>Salva link con nome...</i>",
+ "mwe-embedplayer-download_clip": "Scarica video",
+ "mwe-embedplayer-download_text": "Scarica testo",
+ "mwe-embedplayer-download": "Scarica",
+ "mwe-embedplayer-share": "Condividi",
+ "mwe-embedplayer-credits": "Crediti",
+ "mwe-embedplayer-about-library": "Informazioni su Kaltura player",
+ "mwe-embedplayer-about-library-desc": "La libreria multimediale HTML5 di Kaltura consente adesso di utilizzare l'etichette HTML5 &lt;video&gt; and &lt;audio&gt; con una interfaccia del media player coerente in tutti i principali browser.\n\n[$1 Maggiori informazioni sulla libreria Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Pagina di origine clip",
+ "mwe-embedplayer-choose_player": "Scegli riproduttore video",
+ "mwe-embedplayer-no-player": "Nessun lettore disponibile per $1",
+ "mwe-embedplayer-share_this_video": "Condividi questo video",
+ "mwe-embedplayer-video_credits": "Crediti video",
+ "mwe-embedplayer-no-video_credits": "Crediti non disponibili",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura - piattaforma video open source",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Chiudi",
+ "mwe-embedplayer-ogg-player-vlc-player": "Lettore VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Lettore HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-mp3Native": "Lettore HTML5 MP3",
+ "mwe-embedplayer-ogg-player-aacNative": "Lettore HTML5 AAC",
+ "mwe-embedplayer-ogg-player-h264Native": "Lettore HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Lettore HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Plugin generico Ogg",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "VLC per iOS app",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime plugin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Player Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(selezionato)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Per una migliore esperienza di riproduzione dei video si consiglia un <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">browser che supporti i video HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Rilevato lettore integrato non compatibile: per la riproduzione tramite browser scaricare [$1 l'ultima versione di Firefox].",
+ "mwe-embedplayer-fullscreen-tip": "Premere <b>F11</b> attiva/disattiva la modalità a schermo intero del <i>browser web</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Premere <b>Maiusc ⌘ F</b> attiva/disattiva la modalità a schermo intero",
+ "mwe-embedplayer-do_not_warn_again": "In futuro, non mostrare questo messaggio",
+ "mwe-embedplayer-playerSelect": "Lettori",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Leggi questo</a> prima di incorporare.",
+ "mwe-embedplayer-embed_site_or_blog": "Incorpora in una pagina",
+ "mwe-embedplayer-embed_wiki": "Incorpora su un wiki",
+ "mwe-embedplayer-related_videos": "Video correlati",
+ "mwe-embedplayer-seeking": "cerca",
+ "mwe-embedplayer-buffering": "Riempimento buffer",
+ "mwe-embedplayer-video-h264": "Video H.264",
+ "mwe-embedplayer-video-webm": "Video WebM",
+ "mwe-embedplayer-video-flv": "Video Flash",
+ "mwe-embedplayer-video-ogg": "Video Ogg",
+ "mwe-embedplayer-video-audio": "Audio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Audio MPEG",
+ "mwe-embedplayer-video-3gp": "Video 3GP",
+ "mwe-embedplayer-video-mpeg": "Video MPEG",
+ "mwe-embedplayer-video-msvideo": "Video AVI",
+ "mwe-embedplayer-missing-source": "Non è stata trovata alcuna sorgente video",
+ "mwe-embedplayer-vlcapp-intro": "Per poter visualizzare i video da questo sito su un iPhone o iPad, è necessaria $1 gratuita.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "VLC app",
+ "mwe-embedplayer-vlcapp-downloadapp": "Scarica l'app VLC da App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Apri questo video nell'app VLC",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Scarica questo video",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Per riprodurre i video su questo sito, è necessaria l'app VLC. Installarla ora?"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ja.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ja.json
new file mode 100644
index 00000000..d65876b9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ja.json
@@ -0,0 +1,84 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shirayuki",
+ "青子守歌"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "タイトル: $1",
+ "mwe-embedplayer-credit-date": "日付: $1",
+ "mwe-embedplayer-credit-author": "作者: $1",
+ "mwe-embedplayer-nocredits": "著作者情報はありません",
+ "mwe-embedplayer-loading_plugin": "プラグインを読み込み中 ...",
+ "mwe-embedplayer-select_playback": "再生環境を設定",
+ "mwe-embedplayer-link_back": "トラックバック",
+ "mwe-embedplayer-error_swap_vid": "エラー: mv_embed 形式にあった動画タグに置換できませんでした。",
+ "mwe-embedplayer-add_to_end_of_sequence": "シーケンスの終わりに追加",
+ "mwe-embedplayer-missing_video_stream": "このストリームに必要な動画ファイルが見つかりません",
+ "mwe-embedplayer-play_clip": "クリップを再生",
+ "mwe-embedplayer-pause_clip": "クリップを一時停止",
+ "mwe-embedplayer-volume_control": "音量調節",
+ "mwe-embedplayer-player_options": "プレーヤーの設定",
+ "mwe-embedplayer-timed_text": "字幕",
+ "mwe-embedplayer-player_fullscreen": "全画面表示",
+ "mwe-embedplayer-next_clip_msg": "次のクリップを再生",
+ "mwe-embedplayer-prev_clip_msg": "前のクリップを再生",
+ "mwe-embedplayer-current_clip_msg": "このクリップの再生を続ける",
+ "mwe-embedplayer-seek_to": "$1 へシーク",
+ "mwe-embedplayer-paused": "一時停止中",
+ "mwe-embedplayer-download_segment": "ダウンロード方法を選択:",
+ "mwe-embedplayer-download_full": "動画ファイル全体をダウンロード:",
+ "mwe-embedplayer-download_right_click": "ダウンロードするには、右クリックして<i>名前を付けてリンク先を保存</i>を選んでください",
+ "mwe-embedplayer-download_clip": "動画をダウンロード",
+ "mwe-embedplayer-download_text": "テキストをダウンロード",
+ "mwe-embedplayer-download": "ダウンロード",
+ "mwe-embedplayer-share": "共有",
+ "mwe-embedplayer-credits": "クレジット",
+ "mwe-embedplayer-about-library": "Kaltura プレーヤーについて",
+ "mwe-embedplayer-about-library-desc": "Kaltura の HTML5 メディア ライブラリは、すべての主要ブラウザー間で一貫性のある再生インターフェイスを HTML5 の <code><nowiki><video></nowiki></code> タグと <code><nowiki><audio></nowiki></code> タグで活用できます。\n\n[$1 Kaltura プレーヤー ライブラリについての詳細情報]。",
+ "mwe-embedplayer-clip_linkback": "クリップの情報ページ",
+ "mwe-embedplayer-choose_player": "動画のプレーヤーを選択",
+ "mwe-embedplayer-no-player": "$1 を再生できるプレーヤーはありません",
+ "mwe-embedplayer-share_this_video": "この動画を共有する",
+ "mwe-embedplayer-video_credits": "動画のクレジット",
+ "mwe-embedplayer-no-video_credits": "著作者情報はありません",
+ "mwe-embedplayer-kaltura-platform-title": "Kalturaオープンソース動画プラットフォーム",
+ "mwe-embedplayer-menu_btn": "メニュー",
+ "mwe-embedplayer-close_btn": "閉じる",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC プレーヤー",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg プレーヤー",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3 プレーヤー",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC プレーヤー",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 プレーヤー",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM プレーヤー",
+ "mwe-embedplayer-ogg-player-oggPlugin": "汎用の Ogg プラグイン",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTimeプラグイン",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura プレーヤー",
+ "mwe-embedplayer-ogg-player-selected": "(選択済み)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "動画再生品質の向上のために、<a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5 動画対応のブラウザー</a>をお勧めします。",
+ "mwe-embedplayer-download-warn": "互換性がないブラウザー内プレーヤーを検出しました: ブラウザー内で再生するには、[$1 最新版の Firefox] をダウンロードしてください",
+ "mwe-embedplayer-fullscreen-tip": "<i>ウェブ ブラウザー</i>の全画面表示を切り替えるには <b>F11</b> キーを押してください",
+ "mwe-embedplayer-fullscreen-tip-osx": "全画面表示を切り替えるには <b>shift &#x2318; F</b> を押してください",
+ "mwe-embedplayer-do_not_warn_again": "今後、このメッセージを表示しない",
+ "mwe-embedplayer-playerSelect": "プレーヤー",
+ "mwe-embedplayer-read_before_embed": "埋め込む前に<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">注意事項</a>をお読みください。",
+ "mwe-embedplayer-embed_site_or_blog": "ページに埋め込む",
+ "mwe-embedplayer-embed_wiki": "ウィキに埋め込む",
+ "mwe-embedplayer-related_videos": "関連する動画",
+ "mwe-embedplayer-seeking": "シーク中",
+ "mwe-embedplayer-buffering": "バッファリング",
+ "mwe-embedplayer-video-h264": "H.264 動画",
+ "mwe-embedplayer-video-webm": "WebM 動画",
+ "mwe-embedplayer-video-flv": "Flash 動画",
+ "mwe-embedplayer-video-ogg": "Ogg 動画",
+ "mwe-embedplayer-video-audio": "Ogg 音声",
+ "mwe-embedplayer-audio-mpeg": "MPEG 音声",
+ "mwe-embedplayer-video-3gp": "3GP 動画",
+ "mwe-embedplayer-video-mpeg": "MPEG 動画",
+ "mwe-embedplayer-video-msvideo": "AVI 動画",
+ "mwe-embedplayer-missing-source": "ソースとなる動画が見つかりませんでした"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ka.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ka.json
new file mode 100644
index 00000000..95c48673
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ka.json
@@ -0,0 +1,73 @@
+{
+ "@metadata": {
+ "authors": [
+ "David1010",
+ "MIKHEIL"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "სათაური: $1",
+ "mwe-embedplayer-credit-date": "თარიღი: $1",
+ "mwe-embedplayer-credit-author": "ავტორი: $1",
+ "mwe-embedplayer-loading_plugin": "იტვირთება პლაგინი ...",
+ "mwe-embedplayer-link_back": "უკუბმული",
+ "mwe-embedplayer-add_to_end_of_sequence": "თანმიმდევრობის ბოლოში დამატება",
+ "mwe-embedplayer-play_clip": "კლიპის დაკვრა",
+ "mwe-embedplayer-pause_clip": "კლიპის შეჩერება",
+ "mwe-embedplayer-volume_control": "ხმის კონტროლი",
+ "mwe-embedplayer-player_options": "დამკვრელის პარამეტრები",
+ "mwe-embedplayer-timed_text": "სინქრონიზირებული ტექსტი",
+ "mwe-embedplayer-player_fullscreen": "მთელ ეკრანზე",
+ "mwe-embedplayer-next_clip_msg": "შემდეგი კლიპის დაკვრა",
+ "mwe-embedplayer-prev_clip_msg": "წინა კლიპის დაკვრა",
+ "mwe-embedplayer-current_clip_msg": "ამ კლიპის დაკვრის გაგრძელება",
+ "mwe-embedplayer-seek_to": "გადასვლა $1",
+ "mwe-embedplayer-paused": "შეჩერებულია",
+ "mwe-embedplayer-download_segment": "არჩეულის ჩამოტვირთვა:",
+ "mwe-embedplayer-download_full_video": "მთლიანი ვიდეო-ფაილის ჩამოტვირთვა:",
+ "mwe-embedplayer-download_full_audio": "მთლიანი აუდიო-ფაილის ჩამოტვირთვა:",
+ "mwe-embedplayer-download_clip": "ვიდეოს ჩამოტვირთვა",
+ "mwe-embedplayer-download_text": "ტექსტის ჩამოტვირთვა",
+ "mwe-embedplayer-download": "ჩამოტვირთვა",
+ "mwe-embedplayer-share": "გაზიარება",
+ "mwe-embedplayer-credits": "შემქმნელები",
+ "mwe-embedplayer-about-library": "Kaltura player-ის შესახებ",
+ "mwe-embedplayer-clip_linkback": "კლიპის წყაროს გვერდი",
+ "mwe-embedplayer-choose_player": "აირჩიეთ ვიდეოდამკვრელი",
+ "mwe-embedplayer-share_this_video": "ამ ვიდეოს გაზიარება",
+ "mwe-embedplayer-share_this_audio": "ამ აუდიო-ფაილის გაზიარება",
+ "mwe-embedplayer-video_credits": "ვიდეოს შემქმნელები",
+ "mwe-embedplayer-menu_btn": "მენიუ",
+ "mwe-embedplayer-close_btn": "დახურვა",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC player",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg player",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3 დამკვრელი",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC დამკვრელი",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 player",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM player",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Ogg-ის საერთო პლაგინი",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-ის პლაგინი",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura player",
+ "mwe-embedplayer-ogg-player-selected": "(არჩეულია)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-fullscreen-tip": "ღილაკს <b>F11</b> გადაჰყავს <i>ვებ-ბრაუზერი</i> სრულეკრანიან რეჟიმში",
+ "mwe-embedplayer-fullscreen-tip-osx": "დააჭირეთ <b>shift ⌘ F</b> სრულეკრანიან რეჟიმზე გადასასვლელად",
+ "mwe-embedplayer-do_not_warn_again": "მომავალში აღარ აჩვენო ეს შეტყობინება",
+ "mwe-embedplayer-playerSelect": "დამკვრელები",
+ "mwe-embedplayer-read_before_embed": "გთხოვთ, <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">წაიკითხეთ ეს</a> ჩაშენებამდე!",
+ "mwe-embedplayer-embed_site_or_blog": "გვერდში ჩადგმა",
+ "mwe-embedplayer-related_videos": "დაკავშირებული ვიდეოები",
+ "mwe-embedplayer-seeking": "ძიება",
+ "mwe-embedplayer-buffering": "ბუფერიზაცია",
+ "mwe-embedplayer-video-h264": "H.264 ვიდეო",
+ "mwe-embedplayer-video-webm": "WebM ვიდეო",
+ "mwe-embedplayer-video-flv": "Flash ვიდეო",
+ "mwe-embedplayer-video-ogg": "Ogg ვიდეო",
+ "mwe-embedplayer-video-audio": "Ogg აუდიო",
+ "mwe-embedplayer-audio-mpeg": "MPEG აუდიო",
+ "mwe-embedplayer-video-3gp": "3GP ვიდეო",
+ "mwe-embedplayer-video-mpeg": "MPEG ვიდეო",
+ "mwe-embedplayer-video-msvideo": "AVI ვიდეო",
+ "mwe-embedplayer-missing-source": "ვიდეოს წყარო ვერ მოიძებნა"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ko.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ko.json
new file mode 100644
index 00000000..75e9374d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ko.json
@@ -0,0 +1,83 @@
+{
+ "@metadata": {
+ "authors": [
+ "Priviet",
+ "아라"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "제목: $1",
+ "mwe-embedplayer-credit-date": "날짜: $1",
+ "mwe-embedplayer-credit-author": "저자: $1",
+ "mwe-embedplayer-nocredits": "사용 가능한 제작진이 없습니다",
+ "mwe-embedplayer-loading_plugin": "플러그인을 불러오는 중...",
+ "mwe-embedplayer-select_playback": "재생 환경 설정",
+ "mwe-embedplayer-link_back": "링크 백",
+ "mwe-embedplayer-error_swap_vid": "오류: mwEmbed는 mwEmbed 인터페이스에 대한 동영상 태그를 전환할 수 없습니다",
+ "mwe-embedplayer-add_to_end_of_sequence": "시퀀스의 끝에 추가",
+ "mwe-embedplayer-missing_video_stream": "이 스트림에 대한 동영상 파일이 없습니다",
+ "mwe-embedplayer-play_clip": "클립 재생",
+ "mwe-embedplayer-pause_clip": "클립 일시 정지",
+ "mwe-embedplayer-volume_control": "음량 컨트롤",
+ "mwe-embedplayer-player_options": "플레이어 설정",
+ "mwe-embedplayer-timed_text": "자막",
+ "mwe-embedplayer-player_fullscreen": "전체 화면",
+ "mwe-embedplayer-next_clip_msg": "다음 클립 재생",
+ "mwe-embedplayer-prev_clip_msg": "이전 클립 재생",
+ "mwe-embedplayer-current_clip_msg": "이 클립 재생 계속하기",
+ "mwe-embedplayer-seek_to": "$1 탐색",
+ "mwe-embedplayer-paused": "일시 정지함",
+ "mwe-embedplayer-download_segment": "선택 다운로드:",
+ "mwe-embedplayer-download_full_video": "전체 동영상 파일 다운로드:",
+ "mwe-embedplayer-download_right_click": "다운로드하려면 오른쪽을 클릭하고 <i>다른 이름으로 링크 저장...</i>을 선택하세요",
+ "mwe-embedplayer-download_clip": "동영상 다운로드",
+ "mwe-embedplayer-download_text": "텍스트 다운로드",
+ "mwe-embedplayer-download": "다운로드",
+ "mwe-embedplayer-share": "공유",
+ "mwe-embedplayer-credits": "제작진",
+ "mwe-embedplayer-about-library": "Kaltura 플레이어 정보",
+ "mwe-embedplayer-about-library-desc": "Kaltura의 HTML5 미디어 라이브러리는 모든 주요 브라우저에서 일관된 플레이어 인터페이스로 오늘날 HTML5의 &lt;video&gt; 및 &lt;audio&gt; 태그를 이용할 수 있습니다.\n\n[$1 Kaltura 플레이어 라이브러리에 대해 자세히 알아봅니다].",
+ "mwe-embedplayer-clip_linkback": "클립 원본 페이지",
+ "mwe-embedplayer-choose_player": "동영상 플레이어 선택",
+ "mwe-embedplayer-no-player": "$1에 대해 사용 가능한 플레이어가 없습니다",
+ "mwe-embedplayer-share_this_video": "이 동영상 공유하기",
+ "mwe-embedplayer-video_credits": "동영상 제작진",
+ "mwe-embedplayer-no-video_credits": "사용 가능한 제작진이 없습니다",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura 오픈 소스 동영상 플랫폼",
+ "mwe-embedplayer-menu_btn": "메뉴",
+ "mwe-embedplayer-close_btn": "닫기",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC 플레이어",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg 플레이어",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3 플레이어",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC 플레이어",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 플레이어",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM 플레이어",
+ "mwe-embedplayer-ogg-player-oggPlugin": "일반 Ogg 플러그인",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime 플러그인",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura 플레이어",
+ "mwe-embedplayer-ogg-player-selected": "(선택됨)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK 플레시 보비스",
+ "mwe-embedplayer-for_best_experience": "더 나은 동영상 재생을 위해서는<a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">html5 동영상 브라우저</a>를 권장합니다.",
+ "mwe-embedplayer-download-warn": "호환되지 않는 브라우저 안의 플레이어를 감지했습니다: 브라우저 안에 재생을 하려면 [$1 최신 Firefox]를 다운로드하세요",
+ "mwe-embedplayer-fullscreen-tip": "<i>웹 브라우저</i>를 전체 화면으로 전환하려면 <b>F11</b>을 누르세요",
+ "mwe-embedplayer-fullscreen-tip-osx": "전체 화면으로 전환하려면 <b>shift ⌘ F</b>를 누르세요",
+ "mwe-embedplayer-do_not_warn_again": "나중에 이 메시지를 보여주지 않음",
+ "mwe-embedplayer-playerSelect": "플레이어",
+ "mwe-embedplayer-read_before_embed": "포함하기 전에 <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">이 글을 읽으세요</a>.",
+ "mwe-embedplayer-embed_site_or_blog": "문서에 포함",
+ "mwe-embedplayer-embed_wiki": "위키에 포함",
+ "mwe-embedplayer-related_videos": "관련 동영상",
+ "mwe-embedplayer-seeking": "탐색 중",
+ "mwe-embedplayer-buffering": "버퍼링",
+ "mwe-embedplayer-video-h264": "H.264 동영상",
+ "mwe-embedplayer-video-webm": "WebM 동영상",
+ "mwe-embedplayer-video-flv": "플래시 동영상",
+ "mwe-embedplayer-video-ogg": "Ogg 동영상",
+ "mwe-embedplayer-video-audio": "Ogg 소리",
+ "mwe-embedplayer-audio-mpeg": "MPEG 소리",
+ "mwe-embedplayer-video-3gp": "3GP 동영상",
+ "mwe-embedplayer-video-mpeg": "MPEG 동영상",
+ "mwe-embedplayer-video-msvideo": "AVI 동영상",
+ "mwe-embedplayer-missing-source": "원본 동영상을 찾을 수 없습니다"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ksh.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ksh.json
new file mode 100644
index 00000000..91f9beb5
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ksh.json
@@ -0,0 +1,84 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Tittel: $1",
+ "mwe-embedplayer-credit-date": "Dattum: $1",
+ "mwe-embedplayer-credit-author": "Schriever: $1",
+ "mwe-embedplayer-nocredits": "Mer han kein Dangksaaronge ze jriefe",
+ "mwe-embedplayer-loading_plugin": "Ben dat Ongerprojramm aam laade&nbsp;…",
+ "mwe-embedplayer-select_playback": "Enstellunge för et Affshpelle maache",
+ "mwe-embedplayer-link_back": "Lengk retuur",
+ "mwe-embedplayer-error_swap_vid": "Fähler: <code lang=\"en\">mv_embed</code> kunnt de Etikätte för dä Viddejo för <code lang=\"en\">mv_embed</code> sing Schnetshtäl nit ußtuusche.",
+ "mwe-embedplayer-add_to_end_of_sequence": "Aam Engk vun dä Afschpellleß aanfööje",
+ "mwe-embedplayer-missing_video_stream": "De Viddejodattei för heh dä Daateshrom fählt",
+ "mwe-embedplayer-play_clip": "Donn dä Ußschnedd afshpelle",
+ "mwe-embedplayer-pause_clip": "Donn dä Ußschnedd aanhallde",
+ "mwe-embedplayer-volume_control": "Enshtellung för de Loutshtärk",
+ "mwe-embedplayer-player_options": "Enschtellunge för Affshpellprojramme",
+ "mwe-embedplayer-timed_text": "Ongertitele met Zigge",
+ "mwe-embedplayer-player_fullscreen": "Op der janze Beldscherm jonn",
+ "mwe-embedplayer-next_clip_msg": "Donn dä Ußschnedd donoh shpelle",
+ "mwe-embedplayer-prev_clip_msg": "Donn dä Ußschnedd dovöör shpelle",
+ "mwe-embedplayer-current_clip_msg": "Donn dä Ußschnedd wigger shpelle",
+ "mwe-embedplayer-seek_to": "Söhk bes: $1",
+ "mwe-embedplayer-paused": "aanjehallde",
+ "mwe-embedplayer-download_segment": "Ußwahl för erunger ze laade:",
+ "mwe-embedplayer-download_full_video": "Donn dä janze Viddejo erunge laade:",
+ "mwe-embedplayer-download_right_click": "Zom Eronger laade, kleck met dä rääschte Taßd_aan Dinge Muuß, un söhk „Afshpeishere onger&nbsp;…“ uß",
+ "mwe-embedplayer-download_clip": "Viddejo erunger lade",
+ "mwe-embedplayer-download_text": "Tex erungerlaade",
+ "mwe-embedplayer-download": "Eronger laade",
+ "mwe-embedplayer-share": "Wigger jävve",
+ "mwe-embedplayer-credits": "Aanerkennunge för Beidrääsch",
+ "mwe-embedplayer-about-library": "Övver der Kaltuura Schpeller",
+ "mwe-embedplayer-clip_linkback": "Däm Ußschnett singe Quällsigg",
+ "mwe-embedplayer-choose_player": "Donn en Affshpellprojramm för Viddejos ußsöhke",
+ "mwe-embedplayer-no-player": "Mer han keine Afschpeller för $1",
+ "mwe-embedplayer-share_this_video": "Donn dä Viddejo wigger jävve",
+ "mwe-embedplayer-video_credits": "Aanerkennunge för Beidrääsch aan dämm Viddejo",
+ "mwe-embedplayer-no-video_credits": "Mer han kein Dangksaaronge ze jriefe",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltuura - Viddejo Projramme med offe Quälle",
+ "mwe-embedplayer-menu_btn": "Ußwahl",
+ "mwe-embedplayer-close_btn": "Zohmaache",
+ "mwe-embedplayer-ogg-player-vlc-player": "Dä <i lang=\"en\">VLC</i>-Affschpeller",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5-<i lang=\"en\">Ogg</i>-Affschpeller",
+ "mwe-embedplayer-ogg-player-mp3Native": "<i lang=\"en\">MP3</i> Speller för <i lang=\"en\">HTML5</i>",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5-<i lang=\"en\">MP3</i>-Affschpeller",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5-<i lang=\"en\">H.264</i>-Affschpeller",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5-<i lang=\"en\">WebM</i>-Affschpeller",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Däm <i lang=\"en\">Ogg</i>-Shpeller sing Stanndatt-<i lang=\"en\">plugin</i>",
+ "mwe-embedplayer-ogg-player-IEWebMPrompt": "Et Zohsaprojramm <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"WebM\">WebM</i> för der <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Microsoft Internet Explorer\">IE</i> eronger lahde",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Dä <i lang=\"en\">QuickTime</i>-Shpeller als <i lang=\"en\">plugin</i>",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "Dä <i lang=\"en\">QuickTime</i>-Shpeller övver <i lang=\"en\">ActiveX</i>",
+ "mwe-embedplayer-ogg-player-cortado": "Dä <i lang=\"en\">Java Cortado</i> Shpeller",
+ "mwe-embedplayer-ogg-player-flowplayer": "Dä <i lang=\"en\">Flow</i>shpeller",
+ "mwe-embedplayer-ogg-player-kplayer": "Dä <i lang=\"en\">Kaltura</i> Afshpeller",
+ "mwe-embedplayer-ogg-player-selected": "(ußjesöhk)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "<i lang=\"en\">OMTK Flash Vorbis</i> Shpeller",
+ "mwe-embedplayer-for_best_experience": "öm en bäßere Qualliteit för dä Viddejo ze krijje, dom_mer der <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5-Viddejo-Browser</a> ämfähle.",
+ "mwe-embedplayer-fullscreen-tip": "Met däm <b>F11</b>-Knopp schalldt mer dä <i>Brauser</i> op der kumplätte Beldscherrem öm, un widder retuur.",
+ "mwe-embedplayer-fullscreen-tip-osx": "Met <b>Ömschallde-⌘-F</b> schalldt mer op der kumplätte Beldscherrem öm",
+ "mwe-embedplayer-do_not_warn_again": "Donn heh di Nohreesch en Zohkonf nit norr_ens aanzeije.",
+ "mwe-embedplayer-playerSelect": "Schpeller",
+ "mwe-embedplayer-read_before_embed": "Beß esu joot un liß <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">övver de Sesherheit bemm Ennfööje övver et Netz</a> iih dat De jet ennfööschß!",
+ "mwe-embedplayer-embed_site_or_blog": "En en Websigg udder <i lang=\"en\">Blog</i>_erinndonn",
+ "mwe-embedplayer-embed_wiki": "En e Wiki enboue",
+ "mwe-embedplayer-related_videos": "Verwandte Viddejos",
+ "mwe-embedplayer-seeking": "aam Söhke",
+ "mwe-embedplayer-video-h264": "En <i lang=\"en\">H.264</i>-Viddejo-Dattei",
+ "mwe-embedplayer-video-webm": "En <i lang=\"en\">WebM</i>-Viddejo-Dattei",
+ "mwe-embedplayer-video-flv": "En <i lang=\"en\">Flash</i>-Viddejo-Dattei",
+ "mwe-embedplayer-video-ogg": "En <i lang=\"en\">Ogg</i>-Viddejo-Dattei",
+ "mwe-embedplayer-video-audio": "En <i lang=\"en\">Ogg</i>-Tohn-Dattei",
+ "mwe-embedplayer-audio-mpeg": "En <i lang=\"en\">MPEG </i>-Tohn-Dattei",
+ "mwe-embedplayer-video-3gp": "En <i lang=\"en\">3GP</i>-Viddejo-Dattei",
+ "mwe-embedplayer-video-mpeg": "En <i lang=\"en\">MPEG</i>-Viddejo-Dattei",
+ "mwe-embedplayer-video-msvideo": "En <i lang=\"en\">AVI</i>-Viddejo-Dattei",
+ "mwe-embedplayer-missing-source": "Mer han kein Viddejo-Quälle-Dattei jefonge",
+ "mwe-embedplayer-iewebmprompt-intro": "Eine Schrett mih, ih dat De dä Viddejo afschpelle kanns&nbsp;…",
+ "mwe-embedplayer-iewebmprompt-linktext": "Donn de Ongerstözong för <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"WebM\">WebM</i> em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\">Microsoft Internet Explorer</i> eronger lahde un enschtallehre",
+ "mwe-embedplayer-iewebmprompt-outro": "Donn heh di Sigg nohm Enschtallehre norr_ens neu lahde."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ku-latn.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ku-latn.json
new file mode 100644
index 00000000..c51aa6ca
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ku-latn.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gomada"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Sernav: $1",
+ "mwe-embedplayer-credit-date": "Dîrok: $1",
+ "mwe-embedplayer-credit-author": "Xwedî: $1"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ky.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ky.json
new file mode 100644
index 00000000..9098a14a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ky.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Growingup"
+ ]
+ },
+ "mwe-embedplayer-menu_btn": "Меню",
+ "mwe-embedplayer-close_btn": "Жабуу"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lb.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lb.json
new file mode 100644
index 00000000..b3811f5d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lb.json
@@ -0,0 +1,55 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robby",
+ "Soued031"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titel: $1",
+ "mwe-embedplayer-credit-date": "Datum: $1",
+ "mwe-embedplayer-credit-author": "Auteur: $1",
+ "mwe-embedplayer-loading_plugin": "Plugin lueden ...",
+ "mwe-embedplayer-select_playback": "Astellunge vum Ofspillen festleeën",
+ "mwe-embedplayer-link_back": "Link zréck",
+ "mwe-embedplayer-add_to_end_of_sequence": "Um Schluss vun der Sequenz derbäisetzen",
+ "mwe-embedplayer-missing_video_stream": "De Video-Fichier fir dëse Stream feelt",
+ "mwe-embedplayer-play_clip": "Clip spillen",
+ "mwe-embedplayer-pause_clip": "Clip ënnerbriechen",
+ "mwe-embedplayer-player_options": "Optioune vum Player",
+ "mwe-embedplayer-player_fullscreen": "Ganzen Ecran",
+ "mwe-embedplayer-next_clip_msg": "Nächste Clip spillen",
+ "mwe-embedplayer-prev_clip_msg": "Virege Clip spillen",
+ "mwe-embedplayer-current_clip_msg": "Dëse Clip weiderspillen",
+ "mwe-embedplayer-seek_to": "No $1 sichen",
+ "mwe-embedplayer-paused": "ënnerbrach",
+ "mwe-embedplayer-download_segment": "Dat wat erausgesicht ass eroflueden:",
+ "mwe-embedplayer-download_full_video": "Ganze Videofichier eroflueden:",
+ "mwe-embedplayer-download_full_audio": "Ganzen Audiofichier eroflueden:",
+ "mwe-embedplayer-download_right_click": "Fir erofzelueden, klickt op déi riets Maustast a wielt <i>Link späicheren als...</i>",
+ "mwe-embedplayer-download_clip": "Video eroflueden",
+ "mwe-embedplayer-download_text": "Text eroflueden",
+ "mwe-embedplayer-download": "Eroflueden",
+ "mwe-embedplayer-share": "Deelen",
+ "mwe-embedplayer-clip_linkback": "Quellsäit vum Clip",
+ "mwe-embedplayer-share_this_video": "Dëse Video deelen",
+ "mwe-embedplayer-share_this_audio": "Dësen Audio-Fichier deelen",
+ "mwe-embedplayer-menu_btn": "Menü",
+ "mwe-embedplayer-close_btn": "Zoumaachen",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC-Player",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "VLC fir iOS-App",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-Plugin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura-Player",
+ "mwe-embedplayer-ogg-player-selected": "(erausgesicht)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-do_not_warn_again": "Dëse Message an Zukunft net méi weisen.",
+ "mwe-embedplayer-playerSelect": "Player",
+ "mwe-embedplayer-read_before_embed": "Liest w.e.g. virum Abannen d'<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Sécherheetsinformatiounen iwwer d'Abannen iwwer Remote</a> ier Dir mam Abanne weidermaacht!",
+ "mwe-embedplayer-embed_site_or_blog": "An Är Säit abauen",
+ "mwe-embedplayer-related_videos": "Ähnlech Videoen",
+ "mwe-embedplayer-seeking": "sichen",
+ "mwe-embedplayer-missing-source": "Et gouf kee Video fonnt",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Dëse Video eroflueden",
+ "mwe-embedplayer-iewebmprompt-outro": "No der Installatioun dës säit nei lueden."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lt.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lt.json
new file mode 100644
index 00000000..3a3b6f50
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lt.json
@@ -0,0 +1,90 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hugo.arg",
+ "Gediminas",
+ "Pofka"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Pavadinimas: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autorius: $1",
+ "mwe-embedplayer-nocredits": "Nėra duomenų apie kūrėjus",
+ "mwe-embedplayer-loading_plugin": "Kraunamas įskiepis...",
+ "mwe-embedplayer-select_playback": "Nustatyti grojimo nustatymus",
+ "mwe-embedplayer-link_back": "Atgalinė nuoroda",
+ "mwe-embedplayer-error_swap_vid": "Klaida: mwEmbed negali pakeisti video žymės mwEmbed aplinkai",
+ "mwe-embedplayer-add_to_end_of_sequence": "Pridėti į sekos galą",
+ "mwe-embedplayer-missing_video_stream": "Nėra vaizdo įrašo rinkmenos šiam srautui",
+ "mwe-embedplayer-play_clip": "Leisti įrašą",
+ "mwe-embedplayer-pause_clip": "Pristabdyti įrašą",
+ "mwe-embedplayer-volume_control": "Garso valdymas",
+ "mwe-embedplayer-player_options": "Grotuvo parinktys",
+ "mwe-embedplayer-timed_text": "Priskirtas tekstas",
+ "mwe-embedplayer-player_fullscreen": "Per visą ekraną",
+ "mwe-embedplayer-next_clip_msg": "Leisti kitą įrašą",
+ "mwe-embedplayer-prev_clip_msg": "Leisti praeitą įrašą",
+ "mwe-embedplayer-current_clip_msg": "Tęsti šio įrašo atlikimą",
+ "mwe-embedplayer-seek_to": "Siekti $1",
+ "mwe-embedplayer-paused": "pristabdyta",
+ "mwe-embedplayer-download_segment": "Atsisiuntimo būdas:",
+ "mwe-embedplayer-download_full_video": "Atsisiųsti visą vaizdo įrašo rinkmeną:",
+ "mwe-embedplayer-download_right_click": "Atsisiuntimui spauskite dešiniuoju pelės mygtuku ir pasirinkite <i>Išsaugoti nuorodą kaip...</i>",
+ "mwe-embedplayer-download_clip": "Atsisiųsti vaizdo įrašą",
+ "mwe-embedplayer-download_text": "Atsisiųsti tekstą",
+ "mwe-embedplayer-download": "Atsisiųsti",
+ "mwe-embedplayer-share": "Dalintis",
+ "mwe-embedplayer-credits": "Rinkmenos duomenys",
+ "mwe-embedplayer-about-library": "Apie Kaltura grotuvą",
+ "mwe-embedplayer-clip_linkback": "Įrašo išeities puslapis",
+ "mwe-embedplayer-choose_player": "Pasirinkite vaizdo grotuvą",
+ "mwe-embedplayer-no-player": "Nėra $1 tinkamo grotuvo",
+ "mwe-embedplayer-share_this_video": "Dalintis šiuo įrašu",
+ "mwe-embedplayer-video_credits": "Apie įrašo kūrėjus",
+ "mwe-embedplayer-no-video_credits": "Nėra duomenų apie kūrėjus",
+ "mwe-embedplayer-kaltura-platform-title": "„Kaltura“ atvirojo kodo įrašų grotuvo platforma",
+ "mwe-embedplayer-menu_btn": "Parinktys",
+ "mwe-embedplayer-close_btn": "Uždaryti",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC grotuvas",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg grotuvas",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3 grotuvas",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC grotuvas",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 grotuvas",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM grotuvas",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Bendrasis Ogg įskiepis",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "VLC, skirtas iOS taikomajai programai",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime įskiepis",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura grotuvas",
+ "mwe-embedplayer-ogg-player-selected": "(pasirinkta)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Geresnei vaizdo įrašo peržiūros kokybei siūlome <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5 palaikančią naršyklę</a>.",
+ "mwe-embedplayer-fullscreen-tip": "Spauskite <b>F11</b> mygtuką, kuris nustatys <i>naršyklę</i> pilno ekrano režimui",
+ "mwe-embedplayer-fullscreen-tip-osx": "Spauskite <b>shift ⌘ F</b>, kad pereitumėte į pilno ekrano režimą",
+ "mwe-embedplayer-do_not_warn_again": "Ateityje nerodyti šio pranešimo",
+ "mwe-embedplayer-playerSelect": "Grotuvai",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Perskaitykite tai</a> prieš talpinant.",
+ "mwe-embedplayer-embed_site_or_blog": "Įterpti puslapyje",
+ "mwe-embedplayer-embed_wiki": "Talpinti wiki svetainėje",
+ "mwe-embedplayer-related_videos": "Susiję vaizdo įrašai",
+ "mwe-embedplayer-seeking": "ieškoma",
+ "mwe-embedplayer-buffering": "duomenų kaupimas",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-webm": "WebM video",
+ "mwe-embedplayer-video-flv": "Flash video",
+ "mwe-embedplayer-video-ogg": "Ogg video",
+ "mwe-embedplayer-video-audio": "Ogg audio",
+ "mwe-embedplayer-audio-mpeg": "MPEG audio",
+ "mwe-embedplayer-video-3gp": "3GP video",
+ "mwe-embedplayer-video-mpeg": "MPEG video",
+ "mwe-embedplayer-video-msvideo": "AVI video",
+ "mwe-embedplayer-missing-source": "Nerastas vaizdo įrašo šaltinis",
+ "mwe-embedplayer-vlcapp-intro": "Kad galėtumėte peržiūrėti vaizdo įrašus iPhone ar iPad įrenginiuose, jums reikia nemokamo $1.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "VLC programėlė",
+ "mwe-embedplayer-vlcapp-downloadapp": "Atsisiųsti VLC taikomąją programą iš App Store internetinės krautuvės",
+ "mwe-embedplayer-vlcapp-openvideo": "Atverti šį vaizdo įrašą VLC taikomąja programa",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Atsisiųsti šį vaizdo įrašą",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Kad galėtumėte peržiūrėti vaizdo įrašus šioje svetainėje jums reikia nemokamos VLC taikomosios programos. Ar ją įrašyti dabar?",
+ "mwe-embedplayer-iewebmprompt-intro": "Oi! Dar vienas dalykas prieš paleidžiant šį vaizdo įrašą..."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lv.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lv.json
new file mode 100644
index 00000000..6a9d9d01
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/lv.json
@@ -0,0 +1,60 @@
+{
+ "@metadata": {
+ "authors": [
+ "Papuass"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Nosaukums: $1",
+ "mwe-embedplayer-credit-date": "Datums: $1",
+ "mwe-embedplayer-credit-author": "Autors: $1",
+ "mwe-embedplayer-loading_plugin": "Ielādē spraudni...",
+ "mwe-embedplayer-play_clip": "Atskaņot ierakstu",
+ "mwe-embedplayer-pause_clip": "Pauzēt ierakstu",
+ "mwe-embedplayer-volume_control": "Skaļuma regulēšana",
+ "mwe-embedplayer-player_options": "Atskaņotāja iespējas",
+ "mwe-embedplayer-player_fullscreen": "Pilnekrāna režīms",
+ "mwe-embedplayer-next_clip_msg": "Atskaņot nākamo ierakstu",
+ "mwe-embedplayer-prev_clip_msg": "Atskaņot iepriekšējo ierakstu",
+ "mwe-embedplayer-current_clip_msg": "Turpināt atskaņot šo klipu",
+ "mwe-embedplayer-paused": "nopauzēts",
+ "mwe-embedplayer-download_segment": "Lejupielādes izvēle:",
+ "mwe-embedplayer-download_full": "Lejupielādēt pilnu video failu:",
+ "mwe-embedplayer-download_clip": "Lejupielādēt video",
+ "mwe-embedplayer-download_text": "Lejupielādēt tekstu",
+ "mwe-embedplayer-download": "Lejupielādēt",
+ "mwe-embedplayer-share": "Dalīties",
+ "mwe-embedplayer-about-library": "Par Kaltura atskaņotāju",
+ "mwe-embedplayer-choose_player": "Izvēlieties video atskaņotāju",
+ "mwe-embedplayer-share_this_video": "Dalīties ar šo video",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura atvērtā koda video platforma",
+ "mwe-embedplayer-menu_btn": "Izvēlne",
+ "mwe-embedplayer-close_btn": "Aizvērt",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC atskaņotājs",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg atskaņotājs",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 atskaņotājs",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM atskaņotājs",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Vienkāršs Ogg spraudnis",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime spraudnis",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura atskaņotājs",
+ "mwe-embedplayer-ogg-player-selected": "(izvēlēts)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-fullscreen-tip": "Nospiediet <b>F11</b>, lai pārslēgtu <i>tīmekļa pārlūku</i> pilnekrāna režīmā",
+ "mwe-embedplayer-fullscreen-tip-osx": "Nospiediet <b>shift ⌘ F</b>, lai pārslēgtos pilnekrāna režīmā",
+ "mwe-embedplayer-do_not_warn_again": "Turpmāk nerādīt šo ziņojumu",
+ "mwe-embedplayer-playerSelect": "Atskaņotāji",
+ "mwe-embedplayer-embed_site_or_blog": "Iekļaut lapā",
+ "mwe-embedplayer-related_videos": "Saistītie video",
+ "mwe-embedplayer-seeking": "meklē",
+ "mwe-embedplayer-buffering": "buferizācija",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-webm": "WebM video",
+ "mwe-embedplayer-video-flv": "Flash video",
+ "mwe-embedplayer-video-ogg": "Ogg video",
+ "mwe-embedplayer-video-audio": "Ogg audio",
+ "mwe-embedplayer-audio-mpeg": "MPEG audio",
+ "mwe-embedplayer-video-3gp": "3GP video",
+ "mwe-embedplayer-video-mpeg": "MPEG video",
+ "mwe-embedplayer-video-msvideo": "AVI video"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/mk.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/mk.json
new file mode 100644
index 00000000..a31ed300
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/mk.json
@@ -0,0 +1,95 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Наслов: $1",
+ "mwe-embedplayer-credit-date": "Датум: $1",
+ "mwe-embedplayer-credit-author": "Автор: $1",
+ "mwe-embedplayer-nocredits": "Нема авторски податоци",
+ "mwe-embedplayer-loading_plugin": "Го вчитувам приклучокот...",
+ "mwe-embedplayer-select_playback": "Постави изведбени нагодувања",
+ "mwe-embedplayer-link_back": "Обратна врска",
+ "mwe-embedplayer-error_swap_vid": "Грешка: mwEmbed не можеше да ја смени видео-ознаката за mwEmbed-посредникот",
+ "mwe-embedplayer-add_to_end_of_sequence": "Додај на крајот од низата",
+ "mwe-embedplayer-missing_video_stream": "Видео-податотеката за овој канал недостасува",
+ "mwe-embedplayer-play_clip": "Пушти ја снимката",
+ "mwe-embedplayer-pause_clip": "Паузирај снимка",
+ "mwe-embedplayer-volume_control": "Регулирање гласност",
+ "mwe-embedplayer-player_options": "Нагодувања на изведувачот",
+ "mwe-embedplayer-timed_text": "Синхронизиран текст",
+ "mwe-embedplayer-player_fullscreen": "На цел екран",
+ "mwe-embedplayer-next_clip_msg": "Пушти следна снимка",
+ "mwe-embedplayer-prev_clip_msg": "Пушти претходна снимка",
+ "mwe-embedplayer-current_clip_msg": "Продолжи со изведба на снимкава",
+ "mwe-embedplayer-seek_to": "Прејди на $1",
+ "mwe-embedplayer-paused": "паузирано",
+ "mwe-embedplayer-download_segment": "Преземи избрано:",
+ "mwe-embedplayer-download_full_video": "Преземете ја полната видео-податотека:",
+ "mwe-embedplayer-download_full_audio": "Преземете ја полната аудио-податотека:",
+ "mwe-embedplayer-download_right_click": "За да преземете, стиснете го десното копче и одберете „Сними ја врската како...“",
+ "mwe-embedplayer-download_clip": "Преземи видео",
+ "mwe-embedplayer-download_text": "Преземи текст",
+ "mwe-embedplayer-download": "Преземи",
+ "mwe-embedplayer-share": "Сподели",
+ "mwe-embedplayer-credits": "Автори",
+ "mwe-embedplayer-about-library": "За изведувачот Kaltura",
+ "mwe-embedplayer-about-library-desc": "HTML5-мултимедијалната библиотека на Kaltura ви овозможува уште веднаш да користите HTML5-ознаки <code><nowiki><video></nowiki></code> и <code><nowiki><audio></nowiki></code> со еднообразен и стандарден посредник за изведувачот кај сите најзастапени прелистувачи.\n\n[$1 Повеќе за библиотеката на изведувачот Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Изворна страница на снимката",
+ "mwe-embedplayer-choose_player": "Одберете видео-изведувач",
+ "mwe-embedplayer-no-player": "Нема допстапен изведувач за $1",
+ "mwe-embedplayer-share_this_video": "Сподели ја снимкава",
+ "mwe-embedplayer-share_this_audio": "Сподели ја аудо-податотекава",
+ "mwe-embedplayer-video_credits": "За авторите на снимката",
+ "mwe-embedplayer-no-video_credits": "Нема авторски податоци",
+ "mwe-embedplayer-kaltura-platform-title": "Отворена видео-платформа Kaltura",
+ "mwe-embedplayer-menu_btn": "Мени",
+ "mwe-embedplayer-close_btn": "Скриј",
+ "mwe-embedplayer-ogg-player-vlc-player": "Изведувач VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg-изведувач",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3-изведувач",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC-изведувач",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264-изведувач",
+ "mwe-embedplayer-ogg-player-webmNative": "Изведувач WebM (HTML5)",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Општ Ogg-приклучок",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "Извршник VLC за iOS",
+ "mwe-embedplayer-ogg-player-IEWebMPrompt": "Преземач на WebM-додаток за Internet Explorer",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Приклучок QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Изведувач Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(избрано)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "За поквалитетно прегледување на снимките ви го препорачуваме <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">видеопрелистувачот со HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Не најдов прикладен изведувач за пуштање од прелистувач Ако сакате да пуштате од прелистувач, преземете го [$1 најновиот Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Притиснете <b>F11</b> за да го префрлите <i>прелистувачот</i> на полн екран",
+ "mwe-embedplayer-fullscreen-tip-osx": "Притиснете <b>shift ⌘ F</b> за преглед на цел екран",
+ "mwe-embedplayer-do_not_warn_again": "Отсега не ја прикажувај оваа порака",
+ "mwe-embedplayer-playerSelect": "Изведувач",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Прочитајте го ова</a> пред да вметнувате.",
+ "mwe-embedplayer-embed_site_or_blog": "Вметни во страница",
+ "mwe-embedplayer-embed_wiki": "Вметни во вики",
+ "mwe-embedplayer-related_videos": "Поврзани видеа",
+ "mwe-embedplayer-seeking": "барам",
+ "mwe-embedplayer-buffering": "меѓускладирање",
+ "mwe-embedplayer-video-h264": "H.264 видео",
+ "mwe-embedplayer-video-webm": "WebM-видео",
+ "mwe-embedplayer-video-flv": "Flash видео",
+ "mwe-embedplayer-video-ogg": "Ogg видео",
+ "mwe-embedplayer-video-audio": "Ogg аудио",
+ "mwe-embedplayer-audio-mpeg": "MPEG аудио",
+ "mwe-embedplayer-video-3gp": "3gp видео",
+ "mwe-embedplayer-video-mpeg": "MPEG видео",
+ "mwe-embedplayer-video-msvideo": "AVI видео",
+ "mwe-embedplayer-missing-source": "Не е пронајден извор на снимката.",
+ "mwe-embedplayer-vlcapp-intro": "За да ги гледате видеата на оваа страница на iPhone или iPad, ќе ви треба бесплатниот извршник $1.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "Извршник VLC",
+ "mwe-embedplayer-vlcapp-downloadapp": "Преземете го извршникот VLC од Продавницата за прилози (App Store)",
+ "mwe-embedplayer-vlcapp-openvideo": "Отвори го видеово во извршникот VLC",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Преземи го видеово",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "За да гледате видеа на странцава, ќе ви треба бесплатниот извршник VLC. Да го преземам сега?",
+ "mwe-embedplayer-iewebmprompt-intro": "Упс! Уште нешто пред да го пуштите видеото...",
+ "mwe-embedplayer-iewebmprompt-linktext": "Воспоставете ги медиумските делови на WebM за Internet Explorer",
+ "mwe-embedplayer-iewebmprompt-outro": "Превчитај ја страницата по воспоставката."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ml.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ml.json
new file mode 100644
index 00000000..03c562be
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ml.json
@@ -0,0 +1,96 @@
+{
+ "@metadata": {
+ "authors": [
+ "Praveenp"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "തലക്കെട്ട്: $1",
+ "mwe-embedplayer-credit-date": "തീയതി: $1",
+ "mwe-embedplayer-credit-author": "സ്രഷ്ടാവ്: $1",
+ "mwe-embedplayer-nocredits": "കടപ്പാടുകൾ ലഭ്യമല്ല",
+ "mwe-embedplayer-loading_plugin": "പ്ലഗ്ഗിൻ ശേഖരിക്കുന്നു...",
+ "mwe-embedplayer-select_playback": "പ്രവർത്തനോപാധികൾ സജ്ജീകരിക്കുക",
+ "mwe-embedplayer-link_back": "പിന്നിലേയ്ക്ക് കണ്ണി സൃഷ്ടിക്കുക",
+ "mwe-embedplayer-error_swap_vid": "പിഴവ്: mwEmbed സമ്പർക്കമുഖത്തിനായുള്ള ചലച്ചിത്ര ടാഗ് മാറ്റാൻ mwEmbed-ന് സാധിച്ചില്ല",
+ "mwe-embedplayer-add_to_end_of_sequence": "പരമ്പരയുടെ ഒടുവിൽ ചേർക്കുക",
+ "mwe-embedplayer-missing_video_stream": "ഈ സ്ട്രീമിനായുള്ള ചലച്ചിത്ര പ്രമാണം കാണുന്നില്ല",
+ "mwe-embedplayer-play_clip": "മീഡിയാശകലം പ്രവർത്തിപ്പിക്കുക",
+ "mwe-embedplayer-pause_clip": "മീഡിയാശകലം തത്കാലം നിർത്തുക",
+ "mwe-embedplayer-volume_control": "ശബ്ദ നിയന്ത്രണം",
+ "mwe-embedplayer-player_options": "പ്ലേയർ ഐച്ഛികങ്ങൾ",
+ "mwe-embedplayer-timed_text": "സമയമനുസരിച്ചുള്ള എഴുത്ത്",
+ "mwe-embedplayer-player_fullscreen": "പൂർണ്ണസ്ക്രീൻ",
+ "mwe-embedplayer-next_clip_msg": "അടുത്ത മീഡിയാശകലം പ്രവർത്തിപ്പിക്കുക",
+ "mwe-embedplayer-prev_clip_msg": "മുൻ മീഡിയാശകലം പ്രവർത്തിപ്പിക്കുക",
+ "mwe-embedplayer-current_clip_msg": "ഈ മീഡിയാശകലം പ്രവർത്തിപ്പിക്കുന്നതു തുടരുക",
+ "mwe-embedplayer-seek_to": "$1 നോക്കുക",
+ "mwe-embedplayer-paused": "തത്കാലം നിർത്തിവെച്ചിരിക്കുന്നു",
+ "mwe-embedplayer-download_segment": "തിരഞ്ഞെടുത്തത് ഡൗൺലോഡ് ചെയ്യുക:",
+ "mwe-embedplayer-download_full_video": "പൂർണ്ണ ചലച്ചിത്ര പ്രമാണം ഡൗൺലോഡ് ചെയ്യുക:",
+ "mwe-embedplayer-download_full_audio": "പൂർണ്ണ ശബ്ദ പ്രമാണം ഡൗൺലോഡ് ചെയ്യുക:",
+ "mwe-embedplayer-download_right_click": "ഡൗൺലോഡ് ചെയ്യുവാനായി, റൈറ്റ് ക്ലിക്ക് ചെയ്തശേഷം <i>Save link as...</i> എന്നതുപയോഗിക്കുക",
+ "mwe-embedplayer-download_clip": "ചലച്ചിത്രം ഡൗൺലോഡ് ചെയ്യുക",
+ "mwe-embedplayer-download_text": "എഴുത്ത് ഡൗൺലോഡ് ചെയ്യുക",
+ "mwe-embedplayer-download": "ഡൗൺലോഡ് ചെയ്യുക",
+ "mwe-embedplayer-share": "പങ്ക് വെയ്ക്കുക",
+ "mwe-embedplayer-credits": "കടപ്പാടുകൾ",
+ "mwe-embedplayer-about-library": "കൽടൂറ പ്ലേയർ വിവരണം",
+ "mwe-embedplayer-about-library-desc": "കൽടൂറയുടെ എച്ച്.റ്റി.എം.എൽ.5 മീഡിയ ലൈബ്രറി, ഇന്നത്തെ എല്ലാ പ്രധാന ബ്രൗസറുകളിലും സുസ്ഥിരമായ പ്രവർത്തനോപാധിയ്ക്കുള്ള സമ്പർക്കമുഖത്തോടെ എച്ച്.റ്റി.എം.എൽ.5-ലെ &lt;video&gt;, &lt;audio&gt; എന്നീ ടാഗുകൾ ഉപയോഗിക്കാൻ താങ്കളെ അനുവദിക്കുന്നു.\n\n[$1 കൽടൂറ പ്ലേയർ ലൈബ്രറിയെക്കുറിച്ച് കൂടുതൽ].",
+ "mwe-embedplayer-clip_linkback": "മീഡിയാശകലത്തിന്റെ സ്രോതസ് താൾ",
+ "mwe-embedplayer-choose_player": "ചലച്ചിത്ര പ്ലേയർ തിരഞ്ഞെടുക്കുക",
+ "mwe-embedplayer-no-player": "$1 എന്നതിനുള്ള പ്ലേയറുകൾ ലഭ്യമല്ല",
+ "mwe-embedplayer-share_this_video": "ഈ ചലച്ചിത്രം പങ്ക് വെയ്ക്കുക",
+ "mwe-embedplayer-share_this_audio": "ഈ ശബ്ദ പ്രമാണം പങ്ക് വെയ്ക്കുക",
+ "mwe-embedplayer-video_credits": "ചലച്ചിത്രത്തിനുള്ള കടപ്പാടുകൾ",
+ "mwe-embedplayer-no-video_credits": "കടപ്പാടുകൾ ലഭ്യമല്ല",
+ "mwe-embedplayer-kaltura-platform-title": "കൽടൂറ ഓപ്പൺ സോഴ്സ് ചലച്ചിത്ര പ്ലാറ്റ്‌ഫോം",
+ "mwe-embedplayer-menu_btn": "ഉള്ളടക്കം",
+ "mwe-embedplayer-close_btn": "അടയ്ക്കുക",
+ "mwe-embedplayer-ogg-player-vlc-player": "വി.എൽ.സി. പ്ലേയർ",
+ "mwe-embedplayer-ogg-player-oggNative": "എച്ച്.റ്റി.എം.എൽ.5 ഓഗ് പ്രവർത്തനോപകരണം",
+ "mwe-embedplayer-ogg-player-mp3Native": "എച്ച്.റ്റി.എം.എൽ.5 എം.പി.3 പ്രവർത്തനോപകരണം",
+ "mwe-embedplayer-ogg-player-aacNative": "എച്ച്.റ്റി.എം.എൽ.5 എ.എ.സി. പ്രവർത്തനോപകരണം",
+ "mwe-embedplayer-ogg-player-h264Native": "എച്ച്.റ്റി.എം.എൽ.5 എച്ച്.264 പ്രവർത്തനോപകരണം",
+ "mwe-embedplayer-ogg-player-webmNative": "എച്ച്.റ്റി.എം.എൽ.5 വെബ്‌എം പ്രവർത്തനോപകരണം",
+ "mwe-embedplayer-ogg-player-oggPlugin": "ജെനറിക് ഓഗ് പ്ലഗിൻ",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "ഐഒഎസ് ആപിനുള്ള വി.എൽ.സി.",
+ "mwe-embedplayer-ogg-player-IEWebMPrompt": "ഐ.ഇ. വെബ്എം പ്ലഗിൻ ഡൗൺലോഡർ",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "ക്വിക്ക്റ്റൈം പ്ലഗിൻ",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ക്വിക്ക്റ്റൈം ആക്റ്റീവ്‌‌എക്സ്",
+ "mwe-embedplayer-ogg-player-cortado": "ജാവ കോർറ്റാഡോ",
+ "mwe-embedplayer-ogg-player-flowplayer": "ഫ്ലോപ്ലേയർ",
+ "mwe-embedplayer-ogg-player-kplayer": "കൽടൂറ പ്ലേയർ",
+ "mwe-embedplayer-ogg-player-selected": "(തിരഞ്ഞെടുത്തവ)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "ഓ‌‌എംറ്റികെ ഫ്ലാഷ് വോർബിസ്",
+ "mwe-embedplayer-for_best_experience": "മെച്ചപ്പെട്ട ചലച്ചിത്രാസ്വാദനത്തിനു ഞങ്ങൾ നിർദ്ദേശിക്കുന്നത് <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">എച്ച്.റ്റി.എം.എൽ.5 വീഡിയോ ബ്രൗസർ</a> ആണ്.",
+ "mwe-embedplayer-download-warn": "ബ്രൗസറിനുള്ളിൽ അനുരൂപമായ പ്രവർത്തനോപകരണം കണ്ടെത്താനായില്ല: ബ്രൗസറിനുള്ളിൽ തന്നെ പ്രവർത്തിപ്പിക്കാൻ, ദയവായി [$1 ഏറ്റവും പുതിയ ഫയർഫോക്സ്] ഡൗൺലോഡ് ചെയ്യുക",
+ "mwe-embedplayer-fullscreen-tip": " <i>വെബ് ബ്രൗസർ</i> സ്ക്രീൻ നിറഞ്ഞ് കാണാനും മാറ്റാനും <b>F11</b> അമർത്തുക",
+ "mwe-embedplayer-fullscreen-tip-osx": "സ്ക്രീൻ നിറഞ്ഞ് കാണാനും മാറ്റാനും <b>ഷിഫ്റ്റ് ⌘ F</b> അമർത്തുക",
+ "mwe-embedplayer-do_not_warn_again": "ഭാവിയിൽ ഈ സന്ദേശം കാണിക്കേണ്ടതില്ല",
+ "mwe-embedplayer-playerSelect": "പ്രവർത്തനോപാധികൾ",
+ "mwe-embedplayer-read_before_embed": "ഉൾപ്പെടുത്തുന്നതിനു മുമ്പ് <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">ഇത് വായിക്കുക</a>.",
+ "mwe-embedplayer-embed_site_or_blog": "ഒരു താളിൽ ഉൾപ്പെടുത്തുക",
+ "mwe-embedplayer-embed_wiki": "ഒരു വിക്കിയിൽ ഉൾപ്പെടുത്തുക",
+ "mwe-embedplayer-related_videos": "ബന്ധപ്പെട്ട ചലച്ചിത്രങ്ങൾ",
+ "mwe-embedplayer-seeking": "നോക്കുന്നു",
+ "mwe-embedplayer-buffering": "ബഫറിങ്",
+ "mwe-embedplayer-video-h264": "എച്ച്.264 ചലച്ചിത്രം",
+ "mwe-embedplayer-video-webm": "വെബ്‌എം ചലച്ചിത്രം",
+ "mwe-embedplayer-video-flv": "ഫ്ലാഷ് ചലച്ചിത്രം",
+ "mwe-embedplayer-video-ogg": "ഓഗ് ചലച്ചിത്രം",
+ "mwe-embedplayer-video-audio": "ഓഗ് ശബ്ദപ്രമാണം",
+ "mwe-embedplayer-audio-mpeg": "എംപെഗ് ശബ്ദം",
+ "mwe-embedplayer-video-3gp": "3ജി.പി. ചലച്ചിത്രം",
+ "mwe-embedplayer-video-mpeg": "എംപെഗ് ചലച്ചിത്രം",
+ "mwe-embedplayer-video-msvideo": "എ.വി.ഐ. ചലച്ചിത്രം",
+ "mwe-embedplayer-missing-source": "സ്രോതസ്സ് ചലച്ചിത്രം കണ്ടെത്താനായില്ല",
+ "mwe-embedplayer-vlcapp-intro": "ഈ സൈറ്റിൽ നിന്നുമുള്ള ചലച്ചിത്രങ്ങൾ ഐഫോണിലോ ഐപാഡിലോ കാണുന്നതിനായി സൗജന്യ $1 ആവശ്യമാണ്.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "വി.എൽ.സി. ആപ്",
+ "mwe-embedplayer-vlcapp-downloadapp": "ആപ് സ്റ്റോറിൽ നിന്നും വി.എൽ.സി. ആപ് ഡൗൺലോഡ് ചെയ്യുക",
+ "mwe-embedplayer-vlcapp-openvideo": "ഈ ചലച്ചിത്രം വി.എൽ.സി. ആപിൽ തുറക്കുക",
+ "mwe-embedplayer-vlcapp-downloadvideo": "ചലച്ചിത്രം ഡൗൺലോഡ് ചെയ്യുക",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "ഈ സൈറ്റിൽ ചലച്ചിത്രങ്ങൾ പ്രദർശിപ്പിക്കാൻ, സൗജന്യ വി.എൽ.സി. ആപ് ആവശ്യമാണ്. ഇൻസ്റ്റോൾ ചെയ്യണോ?",
+ "mwe-embedplayer-iewebmprompt-intro": "അയ്യോ! ഈ ചലച്ചിത്രം പ്രവർത്തിക്കുന്നതിനു മുമ്പ് ചെയ്യേണ്ട ഒരു കാര്യം കൂടി...",
+ "mwe-embedplayer-iewebmprompt-linktext": "ഇന്റർനെറ്റ് എക്സ്പ്ലോററിനുള്ള വെബ്എം മീഡിയ ഭാഗങ്ങൾ ഇൻസ്റ്റോൾ ചെയ്യുക",
+ "mwe-embedplayer-iewebmprompt-outro": "ഇൻസ്റ്റോൾ ചെയ്ത ശേഷം ഈ താൾ വീണ്ടുമെടുക്കുക."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ms.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ms.json
new file mode 100644
index 00000000..f19d2f22
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ms.json
@@ -0,0 +1,82 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Tajuk: $1",
+ "mwe-embedplayer-credit-date": "Tarikh: $1",
+ "mwe-embedplayer-credit-author": "Pengarang: $1",
+ "mwe-embedplayer-nocredits": "Tidak terdapat kredit",
+ "mwe-embedplayer-loading_plugin": "Plugin sedang dimuatkan...",
+ "mwe-embedplayer-select_playback": "Tetapan tayangan video",
+ "mwe-embedplayer-link_back": "Paut balik",
+ "mwe-embedplayer-error_swap_vid": "Ralat: mwEmbed tidak dapat menukar teg video untuk antaramuka mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Tambah pada hujung urutan",
+ "mwe-embedplayer-missing_video_stream": "Fail video untuk strim ini tidak dijumpai",
+ "mwe-embedplayer-play_clip": "Putarkan klip",
+ "mwe-embedplayer-pause_clip": "Hentikan klip sejenak",
+ "mwe-embedplayer-volume_control": "Kawalan kelantangan bunyi",
+ "mwe-embedplayer-player_options": "Pilihan pemain",
+ "mwe-embedplayer-timed_text": "Teks bermasa",
+ "mwe-embedplayer-player_fullscreen": "Skrin penuh",
+ "mwe-embedplayer-next_clip_msg": "Putarkan klip seterusnya",
+ "mwe-embedplayer-prev_clip_msg": "Putarkan klip sebelumnya",
+ "mwe-embedplayer-current_clip_msg": "Sambung putarkan klip ini",
+ "mwe-embedplayer-seek_to": "Cari $1",
+ "mwe-embedplayer-paused": "dihentikan sejenak",
+ "mwe-embedplayer-download_segment": "Muat turun pilihan:",
+ "mwe-embedplayer-download_full": "Muat turun fail video selengkapnya:",
+ "mwe-embedplayer-download_right_click": "Untuk memuat turun, klik kanan dan pilih <i>Save link as...</i>",
+ "mwe-embedplayer-download_clip": "Muat turun video",
+ "mwe-embedplayer-download_text": "Muat turun teks",
+ "mwe-embedplayer-download": "Muat turun",
+ "mwe-embedplayer-share": "Kongsi",
+ "mwe-embedplayer-credits": "Kredit",
+ "mwe-embedplayer-about-library": "Tentang pemain Kaltura",
+ "mwe-embedplayer-about-library-desc": "Pustaka media HTML5 Kaltura kini membolehkan anda untuk memanfaatkan teg-teg HTML5 &lt;video&gt; dan &lt;audio&gt; dengan antaramuka pemain yang konsisten di semua pelayar utama.\n\n[$1 Maklumat lanjut tentang pustaka Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Halaman sumber klip",
+ "mwe-embedplayer-choose_player": "Pilih pemain video",
+ "mwe-embedplayer-no-player": "Tidak terdapat pemain untuk $1",
+ "mwe-embedplayer-share_this_video": "Kongsi video ini",
+ "mwe-embedplayer-video_credits": "Kredit video",
+ "mwe-embedplayer-no-video_credits": "Tidak terdapat kredit",
+ "mwe-embedplayer-kaltura-platform-title": "Platform video sumber terbuka Kaltura",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Tutup",
+ "mwe-embedplayer-ogg-player-vlc-player": "Pemain VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Pemain Ogg HTML5",
+ "mwe-embedplayer-ogg-player-mp3Native": "Pemain MP3 HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Pemain AAC HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Pemain H.264 HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Pemain WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Plugin Ogg am",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Plugin QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(dipilih)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Untuk tontonan video yang lebih baik, kami mencadangkan <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">pelayar video HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Tiada pemain dalam pelayar serasi yang dikesan: untuk menayangkan video dalam pelayar, sila muat turun [$1 Firefox terbaru]",
+ "mwe-embedplayer-fullscreen-tip": "Tekan <b>F11</b> untuk menogol <i>pelayar web</i> ke skrin penuh",
+ "mwe-embedplayer-fullscreen-tip-osx": "Tekan <b>shift ⌘ F</b> untuk ke skrin penuh",
+ "mwe-embedplayer-do_not_warn_again": "Jangan paparkan mesej ini lagi",
+ "mwe-embedplayer-playerSelect": "Pemain",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Baca ini</a> sebelum menyiratkan video.",
+ "mwe-embedplayer-embed_site_or_blog": "Siratkan pada halaman",
+ "mwe-embedplayer-embed_wiki": "Siratkan pada wiki",
+ "mwe-embedplayer-related_videos": "Video-video berkaitan",
+ "mwe-embedplayer-seeking": "mencari",
+ "mwe-embedplayer-buffering": "menimbal",
+ "mwe-embedplayer-video-h264": "video H.264",
+ "mwe-embedplayer-video-webm": "video WebM",
+ "mwe-embedplayer-video-flv": "video Flash",
+ "mwe-embedplayer-video-ogg": "video Ogg",
+ "mwe-embedplayer-video-audio": "audio Ogg",
+ "mwe-embedplayer-audio-mpeg": "audio MPEG",
+ "mwe-embedplayer-video-3gp": "video 3GP",
+ "mwe-embedplayer-video-mpeg": "video MPEG",
+ "mwe-embedplayer-video-msvideo": "video AVI",
+ "mwe-embedplayer-missing-source": "Video sumber tidak dijumpai"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/mt.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/mt.json
new file mode 100644
index 00000000..9414549e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/mt.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chrisportelli"
+ ]
+ },
+ "mwe-embedplayer-close_btn": "Agħlaq",
+ "mwe-embedplayer-ogg-player-selected": "(magħżul)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-do_not_warn_again": "Fil-futur, turix dan il-messaġġ",
+ "mwe-embedplayer-playerSelect": "Plejers",
+ "mwe-embedplayer-related_videos": "Vidjows relatati",
+ "mwe-embedplayer-video-h264": "Vidjow H.264",
+ "mwe-embedplayer-video-webm": "Vidjow WebM",
+ "mwe-embedplayer-video-flv": "Vidjow Flash",
+ "mwe-embedplayer-video-ogg": "Vidjow Ogg",
+ "mwe-embedplayer-video-audio": "Awdjo Ogg",
+ "mwe-embedplayer-audio-mpeg": "Awdjo MPEG",
+ "mwe-embedplayer-video-3gp": "Vidjow 3GP",
+ "mwe-embedplayer-video-mpeg": "Vidjow MPEG",
+ "mwe-embedplayer-video-msvideo": "Vidjow AVI",
+ "mwe-embedplayer-missing-source": "L-ebda sors ta' vidjow ma nstab"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nb.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nb.json
new file mode 100644
index 00000000..00a6c126
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nb.json
@@ -0,0 +1,92 @@
+{
+ "@metadata": {
+ "authors": [
+ "Danmichaelo",
+ "Nghtwlkr"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Tittel: $1",
+ "mwe-embedplayer-credit-date": "Dato: $1",
+ "mwe-embedplayer-credit-author": "Opphavsperson: $1",
+ "mwe-embedplayer-nocredits": "Ingen kreditering tilgjengelig",
+ "mwe-embedplayer-loading_plugin": "Laster utvidelse ...",
+ "mwe-embedplayer-select_playback": "Angi avspillingsinnstillinger",
+ "mwe-embedplayer-link_back": "Lenk tilbake",
+ "mwe-embedplayer-error_swap_vid": "Feil: mwEmbed kunne ikke bytte ut videoelementet for mwEmbed-grensesnittet",
+ "mwe-embedplayer-add_to_end_of_sequence": "Legg til på slutten av sekvensen",
+ "mwe-embedplayer-missing_video_stream": "Videofilen for denne strømmen mangler",
+ "mwe-embedplayer-play_clip": "Spill av klipp",
+ "mwe-embedplayer-pause_clip": "Pause klipp",
+ "mwe-embedplayer-volume_control": "Volumkontroll",
+ "mwe-embedplayer-player_options": "Avspillerinnstillinger",
+ "mwe-embedplayer-timed_text": "Tidsbestemt tekst",
+ "mwe-embedplayer-player_fullscreen": "Fullskjerm",
+ "mwe-embedplayer-next_clip_msg": "Spill av neste klipp",
+ "mwe-embedplayer-prev_clip_msg": "Spill av forrige klipp",
+ "mwe-embedplayer-current_clip_msg": "Fortsett å spille av dette klippet",
+ "mwe-embedplayer-seek_to": "Søk $1",
+ "mwe-embedplayer-paused": "pauset",
+ "mwe-embedplayer-download_segment": "Last ned utvalg:",
+ "mwe-embedplayer-download_full_video": "Last ned hele videofilen:",
+ "mwe-embedplayer-download_full_audio": "Last ned hele lydfilen:",
+ "mwe-embedplayer-download_right_click": "For å laste ned, høyreklikk og velg <i>Lagre lenke som...</i>",
+ "mwe-embedplayer-download_clip": "Last ned video",
+ "mwe-embedplayer-download_text": "Last ned tekst",
+ "mwe-embedplayer-download": "Last ned",
+ "mwe-embedplayer-share": "Del",
+ "mwe-embedplayer-credits": "Info",
+ "mwe-embedplayer-about-library": "Om Kaltura-avspilleren",
+ "mwe-embedplayer-about-library-desc": "Kaltura HTML5-biblioteket gir muligheten til å ta i bruk HTML5-taggene &lt;video&gt; og &lt;audio&gt; i dag med et konsistent avspillingsgrensesnitt på tvers av alle de viktigste nettleserne.\n\n[$1 Mer om Kaltura avspillingsbiblioteket].",
+ "mwe-embedplayer-clip_linkback": "Kildesiden for klippet",
+ "mwe-embedplayer-choose_player": "Velg videospiller",
+ "mwe-embedplayer-no-player": "Ingen spiller tilgjengelig for $1",
+ "mwe-embedplayer-share_this_video": "Del denne videoen",
+ "mwe-embedplayer-share_this_audio": "Del denne lydfilen",
+ "mwe-embedplayer-video_credits": "Kreditering",
+ "mwe-embedplayer-no-video_credits": "Ingen kreditering tilgjengelig",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura åpen kildekode-videoplattform",
+ "mwe-embedplayer-menu_btn": "Meny",
+ "mwe-embedplayer-close_btn": "Lukk",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC-spiller",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg-spiller",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3-spiller",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC-spiller",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264-spiller",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM-avspiller",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Generisk Ogg-utvidelse",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "appen VLC for iOS",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-utvidelse",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura-spiller",
+ "mwe-embedplayer-ogg-player-selected": "(valgt)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "For en bedre avspillingsopplevelse anbefaler vi en <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5-videofremviser</a>.",
+ "mwe-embedplayer-download-warn": "Ingen kompatibel mediespiller for nettleseren ble funnet: for avspilling i nettleseren kan du laste ned [$1 nyeste utgave av Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Trykk <b>F11</b> for å sette <i>nettleseren</i> i fullskjermmodus",
+ "mwe-embedplayer-fullscreen-tip-osx": "Trykk <b>shift ⌘ F</b> for å vise i fullskjerm",
+ "mwe-embedplayer-do_not_warn_again": "Ikke vis denne meldingen i fremtiden",
+ "mwe-embedplayer-playerSelect": "Spillere",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Les dette</a> før du bygger inn.",
+ "mwe-embedplayer-embed_site_or_blog": "Bygg inn på en side",
+ "mwe-embedplayer-embed_wiki": "Bygg inn på en wiki",
+ "mwe-embedplayer-related_videos": "Relaterte videoer",
+ "mwe-embedplayer-seeking": "søker",
+ "mwe-embedplayer-buffering": "mellomlagrer",
+ "mwe-embedplayer-video-h264": "H.264-video",
+ "mwe-embedplayer-video-webm": "WebM-video",
+ "mwe-embedplayer-video-flv": "Flash-video",
+ "mwe-embedplayer-video-ogg": "Ogg-video",
+ "mwe-embedplayer-video-audio": "Ogg-audio",
+ "mwe-embedplayer-audio-mpeg": "MPEG-lyd",
+ "mwe-embedplayer-video-3gp": "3GP-video",
+ "mwe-embedplayer-video-mpeg": "MPEG-video",
+ "mwe-embedplayer-video-msvideo": "AVI-video",
+ "mwe-embedplayer-missing-source": "Ingen kildevideo ble funnet",
+ "mwe-embedplayer-vlcapp-intro": "For å spille av videoer fra dette nettstedet på en iPhone eller iPad, trenger du $1 (gratis).",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "appen VLC",
+ "mwe-embedplayer-vlcapp-downloadapp": "Last ned appen VLC fra App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Åpne denne videoen i VLC-appen",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Last ned denne videoen",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "For å spille av videoer på dette nettstedet, trenger du appen VLC (gratis). Vil du installere nå?"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nds-nl.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nds-nl.json
new file mode 100644
index 00000000..36e62cdb
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nds-nl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Servien"
+ ]
+ },
+ "mwe-embedplayer-play_clip": "Klip aofspeulen"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nl.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nl.json
new file mode 100644
index 00000000..66fef83a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nl.json
@@ -0,0 +1,85 @@
+{
+ "@metadata": {
+ "authors": [
+ "Arent",
+ "Siebrand",
+ "Southparkfan"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Naam: $1",
+ "mwe-embedplayer-credit-date": "Datum: $1",
+ "mwe-embedplayer-credit-author": "Auteur: $1",
+ "mwe-embedplayer-nocredits": "Geen auteursgegevens beschikbaar",
+ "mwe-embedplayer-loading_plugin": "Bezig met het laden van de uitbreiding...",
+ "mwe-embedplayer-select_playback": "Afspeelinstellingen instellen",
+ "mwe-embedplayer-link_back": "Terugverwijzen",
+ "mwe-embedplayer-error_swap_vid": "Fout: mvEmbed kon de videotag voor de mwEmbed-interface niet wisselen",
+ "mwe-embedplayer-add_to_end_of_sequence": "Aan het einde van de reeks toevoegen",
+ "mwe-embedplayer-missing_video_stream": "Het videobestand voor deze stream is niet aanwezig",
+ "mwe-embedplayer-play_clip": "Clip afspelen",
+ "mwe-embedplayer-pause_clip": "Clip pauzeren",
+ "mwe-embedplayer-volume_control": "Volumebeheer",
+ "mwe-embedplayer-player_options": "Mediaspelerinstellingen",
+ "mwe-embedplayer-timed_text": "Ondertitels",
+ "mwe-embedplayer-player_fullscreen": "Volledig scherm",
+ "mwe-embedplayer-next_clip_msg": "Volgende clip afspelen",
+ "mwe-embedplayer-prev_clip_msg": "Vorige clip afspelen",
+ "mwe-embedplayer-current_clip_msg": "Doorgaan met het afspelen van deze clip",
+ "mwe-embedplayer-seek_to": "Zoeken naar $1",
+ "mwe-embedplayer-paused": "gepauzeerd",
+ "mwe-embedplayer-download_segment": "Selectie downloaden:",
+ "mwe-embedplayer-download_full": "Volledig videobestand downloaden:",
+ "mwe-embedplayer-download_right_click": "Klik rechts en selecteer <i>Koppeling opslaan als...</i> om het bestand te downloaden",
+ "mwe-embedplayer-download_clip": "Video downloaden",
+ "mwe-embedplayer-download_text": "Tekst downloaden",
+ "mwe-embedplayer-download": "Downloaden",
+ "mwe-embedplayer-share": "Delen",
+ "mwe-embedplayer-credits": "Vermeldingen",
+ "mwe-embedplayer-about-library": "Over de Kalturaspeler",
+ "mwe-embedplayer-about-library-desc": "De HTML5-bibliotheek van Kaltura zorgt dat u nu kunt profiteren van de HTML5-labels <nowiki><video></nowiki> en <nowiki><audio></nowiki> met een consistent uiterlijk van de speler in alle veelgebruikte browsers.\n\n[$1 Meer over de bibliotheek van de Kaltura-speler].",
+ "mwe-embedplayer-clip_linkback": "Bronpagina van de clip",
+ "mwe-embedplayer-choose_player": "Mediaspeler kiezen",
+ "mwe-embedplayer-no-player": "Geen speler beschikbaar voor $1",
+ "mwe-embedplayer-share_this_video": "Deze video delen",
+ "mwe-embedplayer-video_credits": "Naamsvermeldingen video",
+ "mwe-embedplayer-no-video_credits": "Geen auteursinformatie beschikbaar",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura open source videoplatform",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Sluiten",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC-mediaspeler",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg-speler",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3-speler",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC-speler",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264-speler",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM-speler",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Algemene Ogg-plugin",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-plugin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura mediaspeler",
+ "mwe-embedplayer-ogg-player-selected": "(geselecteerd)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Voor een betere kwaliteitsbeleving adviseren we een <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5 videobrowser</a>.",
+ "mwe-embedplayer-download-warn": "Er is geen compatibele speler in de browser aangetroffen. Download de [$1 meest recente versie van Firefox] om dit bestand in de browser af te kunnen spelen.",
+ "mwe-embedplayer-fullscreen-tip": "Druk op <b>F11</b> om de <i>web browser</i> in het volledige scherm weer te geven",
+ "mwe-embedplayer-fullscreen-tip-osx": "Typ <b>SHIRT+⌘+F</b> voor volledig scherm of terug",
+ "mwe-embedplayer-do_not_warn_again": "Dit bericht niet meer weergeven.",
+ "mwe-embedplayer-playerSelect": "Spelers",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Lees dit</a> voordat u gaat embedden (Engels)!",
+ "mwe-embedplayer-embed_site_or_blog": "Toevoegen aan een pagina",
+ "mwe-embedplayer-embed_wiki": "Toevoegen aan een pagina",
+ "mwe-embedplayer-related_videos": "Gerelateerde video's",
+ "mwe-embedplayer-seeking": "bezig met zoeken",
+ "mwe-embedplayer-buffering": "bufferen",
+ "mwe-embedplayer-video-h264": "H.264-video",
+ "mwe-embedplayer-video-webm": "WebM video",
+ "mwe-embedplayer-video-flv": "Flash-video",
+ "mwe-embedplayer-video-ogg": "Ogg-video",
+ "mwe-embedplayer-video-audio": "Ogg-audio",
+ "mwe-embedplayer-audio-mpeg": "MPEG-audio",
+ "mwe-embedplayer-video-3gp": "3GP-video",
+ "mwe-embedplayer-video-mpeg": "MPEG-video",
+ "mwe-embedplayer-video-msvideo": "AVI-video",
+ "mwe-embedplayer-missing-source": "Er is geen bronvideo gevonden."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nn.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nn.json
new file mode 100644
index 00000000..c96be9d4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/nn.json
@@ -0,0 +1,84 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nghtwlkr",
+ "Njardarlogar",
+ "Gaute",
+ "Ranveig"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Tittel: $1",
+ "mwe-embedplayer-credit-date": "Dato: $1",
+ "mwe-embedplayer-credit-author": "Forfattar: $1",
+ "mwe-embedplayer-nocredits": "Inga godskriving tilgjengeleg",
+ "mwe-embedplayer-loading_plugin": "Lastar inn utviding …",
+ "mwe-embedplayer-select_playback": "Set avspelingsinnstillingar",
+ "mwe-embedplayer-link_back": "Lenkja attende",
+ "mwe-embedplayer-error_swap_vid": "Feil: mwEmbed kunne ikkje byta videomerket for mwEmbed-grensesnittet",
+ "mwe-embedplayer-add_to_end_of_sequence": "Legg til ved enden av sekvensen",
+ "mwe-embedplayer-missing_video_stream": "Videofila for strøyminga manglar",
+ "mwe-embedplayer-play_clip": "Spel av klipp",
+ "mwe-embedplayer-pause_clip": "Stogg klipp",
+ "mwe-embedplayer-volume_control": "Volumstyring",
+ "mwe-embedplayer-player_options": "Spelarval",
+ "mwe-embedplayer-timed_text": "Tidbunden tekst",
+ "mwe-embedplayer-player_fullscreen": "Fullskjerm",
+ "mwe-embedplayer-next_clip_msg": "Spel av neste klippet",
+ "mwe-embedplayer-prev_clip_msg": "Spel av førre klippet",
+ "mwe-embedplayer-current_clip_msg": "Haldt fram med å spela av klippet",
+ "mwe-embedplayer-seek_to": "Søk $1",
+ "mwe-embedplayer-paused": "stogga",
+ "mwe-embedplayer-download_segment": "Last ned utval:",
+ "mwe-embedplayer-download_full_video": "Last ned heile videofila:",
+ "mwe-embedplayer-download_full_audio": "Last ned heile lydfila:",
+ "mwe-embedplayer-download_right_click": "For å lasta ned, høgreklikk og vel <i>Lagra lenkje som...</i>",
+ "mwe-embedplayer-download_clip": "Last ned video",
+ "mwe-embedplayer-download_text": "Last ned tekst",
+ "mwe-embedplayer-download": "Last ned",
+ "mwe-embedplayer-share": "Del",
+ "mwe-embedplayer-credits": "Godskriving",
+ "mwe-embedplayer-about-library": "Om Kaltura-spelaren",
+ "mwe-embedplayer-about-library-desc": "HTML5-mediebiblioteket i Kaltura tillèt deg å utnytta føremonene til HTML5-merka &lt;video&gt; og &lt;audio&gt; i dag med eit konsistent spelargrensesnitt gjennom alle dei størrre nettlesarane.\n\n[$1 Meir om spelarbiblioteket Kaltura]",
+ "mwe-embedplayer-clip_linkback": "Kjeldesida til klippet",
+ "mwe-embedplayer-choose_player": "Vel videospelar",
+ "mwe-embedplayer-no-player": "Ingen spelar tilgjengeleg for $1",
+ "mwe-embedplayer-share_this_video": "Del videoen",
+ "mwe-embedplayer-share_this_audio": "Del denne lydfila",
+ "mwe-embedplayer-video_credits": "Videogodskriving",
+ "mwe-embedplayer-no-video_credits": "Inga godskriving tilgjengeleg",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura, videoplattform med open kjeldekode",
+ "mwe-embedplayer-menu_btn": "Meny",
+ "mwe-embedplayer-close_btn": "Lat att",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC-spelar",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg-spelar",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264-spelar",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM-spelar",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Generisk Ogg-utviding",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-utviding",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura-spelar",
+ "mwe-embedplayer-ogg-player-selected": "(vald)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "For ei betre videoavspelingsoppleving tilrår me ein <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">html5-videolesar</a>.",
+ "mwe-embedplayer-download-warn": "Det vart ikkje funne nokon kompatibel spelar i nettlesaren; for å spela av i nettlesaren bør du lasta ned [$1 siste utgåva av Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Trykk <b>F11</b> for å slå på fullskjermen til <i>nettlesaren</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Trykk på <b>shift ⌘ F</b> for å slå på fullskjerm",
+ "mwe-embedplayer-do_not_warn_again": "Ikkje vis meldinga i framtida.",
+ "mwe-embedplayer-playerSelect": "Avspelarar",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Les dette</a> før du byggjer inn.",
+ "mwe-embedplayer-embed_site_or_blog": "Bygg inn i ei side",
+ "mwe-embedplayer-related_videos": "Skylde videoar",
+ "mwe-embedplayer-seeking": "søkjer",
+ "mwe-embedplayer-buffering": "buffrar",
+ "mwe-embedplayer-video-h264": "H.264-video",
+ "mwe-embedplayer-video-webm": "WebM-video",
+ "mwe-embedplayer-video-flv": "Flash-video",
+ "mwe-embedplayer-video-ogg": "Ogg-video",
+ "mwe-embedplayer-video-audio": "Ogg-ljod",
+ "mwe-embedplayer-audio-mpeg": "MPEG-ljod",
+ "mwe-embedplayer-video-3gp": "3GP-video",
+ "mwe-embedplayer-video-mpeg": "MPEG-video",
+ "mwe-embedplayer-video-msvideo": "AVI-video",
+ "mwe-embedplayer-missing-source": "Ingen kjeldevideo vart funnen"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/oc.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/oc.json
new file mode 100644
index 00000000..c481affa
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/oc.json
@@ -0,0 +1,50 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cedric31"
+ ]
+ },
+ "mwe-embedplayer-loading_plugin": "cargament del plugin ...",
+ "mwe-embedplayer-select_playback": "Definir las preferéncias de lectura",
+ "mwe-embedplayer-link_back": "Ligam retorn",
+ "mwe-embedplayer-error_swap_vid": "Erreur : mv_embed a pas capitat d'escambiar l'atribut de la vidèo per l'interfàcia mv_embed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Apondre a la fin de la sequéncia",
+ "mwe-embedplayer-missing_video_stream": "Lo fichièr vidèo per aqueste flus es mancant",
+ "mwe-embedplayer-play_clip": "Legir lo clip",
+ "mwe-embedplayer-pause_clip": "Metre lo clip en pausa",
+ "mwe-embedplayer-volume_control": "Contraròtle del volum",
+ "mwe-embedplayer-player_options": "Opcions del lector",
+ "mwe-embedplayer-player_fullscreen": "Ecran plen",
+ "mwe-embedplayer-next_clip_msg": "Legir lo clip seguent",
+ "mwe-embedplayer-prev_clip_msg": "Legir lo clip precedent",
+ "mwe-embedplayer-current_clip_msg": "Perseguir la lectura d'aqueste clip",
+ "mwe-embedplayer-seek_to": "Aténher $1",
+ "mwe-embedplayer-paused": "en pausa",
+ "mwe-embedplayer-download_segment": "Telecargar la seleccion :",
+ "mwe-embedplayer-download_full": "Telecargar lo fichièr de la vidèo completa :",
+ "mwe-embedplayer-download_right_click": "Per telecargar, clicatz-drech e seleccionatz <i>Enregistrar la cibla del ligam jos...</i>",
+ "mwe-embedplayer-download_clip": "Telecargar la vidèo",
+ "mwe-embedplayer-download_text": "Telecargar lo tèxte",
+ "mwe-embedplayer-download": "Telecargar",
+ "mwe-embedplayer-share": "Partejar",
+ "mwe-embedplayer-credits": "Credits",
+ "mwe-embedplayer-clip_linkback": "Pagina font del clip",
+ "mwe-embedplayer-choose_player": "Causir lo lector vidèo",
+ "mwe-embedplayer-share_this_video": "Partejar aquesta vidèo",
+ "mwe-embedplayer-video_credits": "Credits de la vidèo",
+ "mwe-embedplayer-menu_btn": "Menú",
+ "mwe-embedplayer-close_btn": "Tampar",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Modul generic Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Modul QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX QuickTime",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-selected": "(seleccionat)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Per un melhor visionatge recomandam un <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">navigador vidèo HTML5</a>.",
+ "mwe-embedplayer-do_not_warn_again": "Afichar pas mai aqueste messatge a l'avenir",
+ "mwe-embedplayer-read_before_embed": "Legissètz <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">aquò</a> abans de procedir !",
+ "mwe-embedplayer-embed_site_or_blog": "Integrar dins una pagina",
+ "mwe-embedplayer-related_videos": "Vidèos associadas",
+ "mwe-embedplayer-seeking": "recèrca"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pam.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pam.json
new file mode 100644
index 00000000..bb3f6794
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pam.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Leeheonjin"
+ ]
+ },
+ "mwe-embedplayer-iewebmprompt-intro": "Ui! Atin pang metung a bage bayu me pa i-play ing video a ini..."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pdc.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pdc.json
new file mode 100644
index 00000000..b78c9b0a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pdc.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xqt"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titel: $1",
+ "mwe-embedplayer-seek_to": "Guck uff $1"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pl.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pl.json
new file mode 100644
index 00000000..97e49986
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pl.json
@@ -0,0 +1,81 @@
+{
+ "@metadata": {
+ "authors": [
+ "BeginaFelicysym",
+ "Sp5uhe"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Tytuł – $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "Informacja o twórcach nie jest dostępna",
+ "mwe-embedplayer-loading_plugin": "trwa ładowanie wtyczki...",
+ "mwe-embedplayer-select_playback": "Ustaw preferencje odtwarzania",
+ "mwe-embedplayer-link_back": "Link powrotny",
+ "mwe-embedplayer-error_swap_vid": "Błąd – mv_embed nie był w stanie zamieniać znacznika filmu dla interfejsu mv_embed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Dodaj na koniec sekwencji",
+ "mwe-embedplayer-missing_video_stream": "Brak pliku z filmem dla tego strumienia",
+ "mwe-embedplayer-play_clip": "Odtwórz klip",
+ "mwe-embedplayer-pause_clip": "Wstrzymaj odtwarzanie klipu",
+ "mwe-embedplayer-volume_control": "Regulacja głośności",
+ "mwe-embedplayer-player_options": "Opcje odtwarzacza",
+ "mwe-embedplayer-timed_text": "Lista dialogowa",
+ "mwe-embedplayer-player_fullscreen": "Pełny ekran",
+ "mwe-embedplayer-next_clip_msg": "Odtwórz następny klip",
+ "mwe-embedplayer-prev_clip_msg": "Odtwórz poprzedni klip",
+ "mwe-embedplayer-current_clip_msg": "Kontynuuj odtwarzanie tego klipu",
+ "mwe-embedplayer-seek_to": "Przewiń $1",
+ "mwe-embedplayer-paused": "wstrzymane",
+ "mwe-embedplayer-download_segment": "Wybór pobierania",
+ "mwe-embedplayer-download_full": "Pobierz pełny plik z filmem",
+ "mwe-embedplayer-download_right_click": "Aby pobrać, kliknij prawym przyciskiem myszy i wybierz <i>Zapisz link jako...</i>",
+ "mwe-embedplayer-download_clip": "Pobierz film",
+ "mwe-embedplayer-download_text": "Pobierz tekst",
+ "mwe-embedplayer-download": "Pobierz",
+ "mwe-embedplayer-share": "Udostępnij",
+ "mwe-embedplayer-credits": "Twórcy",
+ "mwe-embedplayer-about-library": "O odtwarzaczu Kaltura",
+ "mwe-embedplayer-about-library-desc": "Biblioteka Kaltura obsługi mediów dla HTML5 pozwala na użycie znaczników HTML5 <code><nowiki><video></nowiki></code> i <code><nowiki><audio></nowiki></code> ze spójnym interfejsem odtwarzacza we wszystkich najpopularniejszych przeglądarkach.\n\n[$1 Więcej na temat biblioteki odtwarzacza Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Strona źródłowa klipu",
+ "mwe-embedplayer-choose_player": "Wybierz odtwarzacz wideo",
+ "mwe-embedplayer-no-player": "Brak dostępnych odtwarzaczy dla $1",
+ "mwe-embedplayer-share_this_video": "Udostępnij ten film",
+ "mwe-embedplayer-video_credits": "Twórcy filmu",
+ "mwe-embedplayer-no-video_credits": "Informacja o twórcach nie jest dostępna",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura – platforma filmów z otwartym kodem",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Zamknij",
+ "mwe-embedplayer-ogg-player-vlc-player": "Odtwarzacz VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Odtwarzacz HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-h264Native": "Odtwarzacz HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Odtwarzacz HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Pierwotna wtyczka Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Wtyczka QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Cortado w Java",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Odtwarzacz Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(zaznaczone)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Dla lepszego odtwarzania filmów polecamy [przeglądarkę video html5 $1</a>.",
+ "mwe-embedplayer-download-warn": "Nie odnaleziono zgodnego odtwarzacza dla przeglądarki, aby odtworzyć tą zawartość w przeglądarce należy pobrać [$1 najnowszą wersjęFirefox]",
+ "mwe-embedplayer-fullscreen-tip": "Naciśnij klawisz <b>F11</b> by przełączyć <i>przeglądarkę</i> w tryb pełnoekranowy",
+ "mwe-embedplayer-fullscreen-tip-osx": "Naciśnij klawisze <b>shift ⌘ f</b> aby przełączyć w tryb pełnoekranowy",
+ "mwe-embedplayer-do_not_warn_again": "W przyszłości nie pokazuj tego komunikatu",
+ "mwe-embedplayer-playerSelect": "Odtwarzacze",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Przeczytaj to</a> przed wstawieniem.",
+ "mwe-embedplayer-embed_site_or_blog": "Umieść na swojej stronie lub blogu",
+ "mwe-embedplayer-related_videos": "Podobne filmy",
+ "mwe-embedplayer-seeking": "przewijanie",
+ "mwe-embedplayer-buffering": "buforowanie",
+ "mwe-embedplayer-video-h264": "Wideo w H.264",
+ "mwe-embedplayer-video-webm": "Wideo WebM",
+ "mwe-embedplayer-video-flv": "Wideo we Flash",
+ "mwe-embedplayer-video-ogg": "Wideo w Ogg",
+ "mwe-embedplayer-video-audio": "Dźwięk w Ogg",
+ "mwe-embedplayer-audio-mpeg": "Wideo MPEG",
+ "mwe-embedplayer-video-3gp": "Wideo 3GP",
+ "mwe-embedplayer-video-mpeg": "Wideo MPEG",
+ "mwe-embedplayer-video-msvideo": "Wideo AVI",
+ "mwe-embedplayer-missing-source": "Nie ustalono źródła obrazu."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pms.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pms.json
new file mode 100644
index 00000000..b667b89e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pms.json
@@ -0,0 +1,80 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borichèt",
+ "Dragonòt"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Tìtol: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "Gnun arconossiment ëd paternità disponìbil",
+ "mwe-embedplayer-loading_plugin": "Carié plugin...",
+ "mwe-embedplayer-select_playback": "Amposté gust ëd letura",
+ "mwe-embedplayer-link_back": "Anliura andré",
+ "mwe-embedplayer-error_swap_vid": "Eror: mwEmbed a l'é pa stàit bon a cangé la tichëtta dël filmà për l'antërfacia mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Gionté a la fin ëd la sequensa",
+ "mwe-embedplayer-missing_video_stream": "L'archivi dël filmà pr'ës fluss a manca",
+ "mwe-embedplayer-play_clip": "Fà parte ël curtmetragi",
+ "mwe-embedplayer-pause_clip": "Ferma ël curtmetragi",
+ "mwe-embedplayer-volume_control": "Contròl dël volum",
+ "mwe-embedplayer-player_options": "Opsion dël letor",
+ "mwe-embedplayer-timed_text": "Test sincronisà",
+ "mwe-embedplayer-player_fullscreen": "A scren pien",
+ "mwe-embedplayer-next_clip_msg": "Fà parte ël curtmetragi ch'a ven",
+ "mwe-embedplayer-prev_clip_msg": "Fà parte ël curtmetragi prima",
+ "mwe-embedplayer-current_clip_msg": "Continua a fé giré sto curtmetragi",
+ "mwe-embedplayer-seek_to": "Serca $1",
+ "mwe-embedplayer-paused": "an pàusa",
+ "mwe-embedplayer-download_segment": "Dëscarié la selession:",
+ "mwe-embedplayer-download_full": "Dëscarié l'archivi antregh dël filmà:",
+ "mwe-embedplayer-download_right_click": "Për dëscarié, sgnaca con ël tast drit dël rat e selession-a <i>Salva ël colegament com...</i>",
+ "mwe-embedplayer-download_clip": "Dëscarié ël filmà",
+ "mwe-embedplayer-download_text": "Dëscarié ël test",
+ "mwe-embedplayer-download": "Dëscaria",
+ "mwe-embedplayer-share": "Condivid",
+ "mwe-embedplayer-credits": "Arconossiment",
+ "mwe-embedplayer-about-library": "A propòsit dël riprodutor Kaltura",
+ "mwe-embedplayer-about-library-desc": "La librarìa dël mojen HTML5 ëd Kaltura a lo abìlita a sfruté ancheuj le tichëtte HTML5 <code><nowiki><video></nowiki></code> e <code><nowiki><audio></nowiki></code> con n'antërfacia ëd riprodussion coerenta con tùit ij navigador prinsipaj.\n\n[$1 Për savèjne ëd pi a propòsit ëd la librarìa dël riprodutor Kaltura]",
+ "mwe-embedplayer-clip_linkback": "Pàgina sorgiss dël curt-metragi",
+ "mwe-embedplayer-choose_player": "Serne ël letor dij filmà",
+ "mwe-embedplayer-no-player": "Pa gnun letor disponìbij për $1",
+ "mwe-embedplayer-share_this_video": "Partagé ës filmà",
+ "mwe-embedplayer-video_credits": "Arconossiment dël filmà",
+ "mwe-embedplayer-no-video_credits": "Pa gnun crédit disponìbij",
+ "mwe-embedplayer-kaltura-platform-title": "Piataforma për filmà a sorgiss duverta Kaltura",
+ "mwe-embedplayer-menu_btn": "Lista",
+ "mwe-embedplayer-close_btn": "Sara",
+ "mwe-embedplayer-ogg-player-vlc-player": "Letor VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Letor HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-h264Native": "Letor HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Letor HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Plugin Generic Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Plugin QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Letor Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(selessionà)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Per n'esperiensa ëd vision pi bon-a i arcomandoma un <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">navigador adat ai filmà html5</a>.",
+ "mwe-embedplayer-download-warn": "A l'é trovasse che ël navigador a l'é nen compatìbil, për na letura ant ël navigador, për piasì ch'a dëscaria l'[$1 ùltim Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Sgnaché <b>F11</b> për passé al <i>navigador dl'aragnà</i> a scren antregh",
+ "mwe-embedplayer-fullscreen-tip-osx": "Ch'a sgnaca <b>majùscole ⌘ F</b> për passé a scren antregh",
+ "mwe-embedplayer-do_not_warn_again": "Ant l'avnì, mostré pa pi ës mëssagi",
+ "mwe-embedplayer-playerSelect": "Letor",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Les sossì</a> prima d'ancorporé.",
+ "mwe-embedplayer-embed_site_or_blog": "Ancorporé an sna pàgina",
+ "mwe-embedplayer-related_videos": "Filmà assossià",
+ "mwe-embedplayer-seeking": "arserca",
+ "mwe-embedplayer-buffering": "an camin a buté ant la memòria tampon",
+ "mwe-embedplayer-video-h264": "filmà H.264",
+ "mwe-embedplayer-video-webm": "Filmà WebM",
+ "mwe-embedplayer-video-flv": "filmà Flash",
+ "mwe-embedplayer-video-ogg": "filmà Ogg",
+ "mwe-embedplayer-video-audio": "Àudio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Sonor MPEG",
+ "mwe-embedplayer-video-3gp": "Filmà 3GP",
+ "mwe-embedplayer-video-mpeg": "Filmà MPEG",
+ "mwe-embedplayer-video-msvideo": "Filmà AVI",
+ "mwe-embedplayer-missing-source": "Gnun filmà sorgiss a l'é stàit trovà."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ps.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ps.json
new file mode 100644
index 00000000..7bb42723
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ps.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ahmed-Najib-Biabani-Ibrahimkhel"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "سرليک: $1",
+ "mwe-embedplayer-credit-date": "نېټه: $1",
+ "mwe-embedplayer-credit-author": "ليکوال: $1",
+ "mwe-embedplayer-download_clip": "ويډيو ښکته کول",
+ "mwe-embedplayer-download_text": "متن ښکته کول",
+ "mwe-embedplayer-download": "ښکته کول",
+ "mwe-embedplayer-share": "شريکول",
+ "mwe-embedplayer-close_btn": "تړل",
+ "mwe-embedplayer-ogg-player-selected": "(ټاکل شوی)",
+ "mwe-embedplayer-playerSelect": "غږونکي",
+ "mwe-embedplayer-audio-mpeg": "MPEG غږ",
+ "mwe-embedplayer-video-3gp": "3GP ويډيو",
+ "mwe-embedplayer-video-mpeg": "MPEG ويډيو",
+ "mwe-embedplayer-video-msvideo": "AVI ويډيو"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pt-br.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pt-br.json
new file mode 100644
index 00000000..830e4dce
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pt-br.json
@@ -0,0 +1,86 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cainamarques",
+ "Dianakc",
+ "Giro720",
+ "Luckas",
+ "Luckas Blade"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Título: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "Créditos não disponíveis",
+ "mwe-embedplayer-loading_plugin": "Carregando plugin ...",
+ "mwe-embedplayer-select_playback": "Definir preferências de reprodução",
+ "mwe-embedplayer-link_back": "Criar link de volta",
+ "mwe-embedplayer-error_swap_vid": "Erro: o mv_embed não conseguiu trocar o elemento de vídeo pela interface mv_embed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Adicionar ao fim da sequência",
+ "mwe-embedplayer-missing_video_stream": "O arquivo de vídeo para esta transmissão está em falta",
+ "mwe-embedplayer-play_clip": "Tocar videoclipe",
+ "mwe-embedplayer-pause_clip": "Pausar clipe",
+ "mwe-embedplayer-volume_control": "Controle de volume",
+ "mwe-embedplayer-player_options": "Opções do tocador",
+ "mwe-embedplayer-timed_text": "Legendas",
+ "mwe-embedplayer-player_fullscreen": "Tela inteira",
+ "mwe-embedplayer-next_clip_msg": "Tocar o clipe seguinte",
+ "mwe-embedplayer-prev_clip_msg": "Tocar o clipe anteiror",
+ "mwe-embedplayer-current_clip_msg": "Continue a tocar este clipe",
+ "mwe-embedplayer-seek_to": "Procurar $1",
+ "mwe-embedplayer-paused": "pausado",
+ "mwe-embedplayer-download_segment": "Download da seleção:",
+ "mwe-embedplayer-download_full": "Donwload do arquivo completo:",
+ "mwe-embedplayer-download_right_click": "Para fazer donwload, clique com o botão direito e selecione <i>Salvar link como...</i>",
+ "mwe-embedplayer-download_clip": "Download de vídeo",
+ "mwe-embedplayer-download_text": "Download do texto",
+ "mwe-embedplayer-download": "Download",
+ "mwe-embedplayer-share": "Compartilhar",
+ "mwe-embedplayer-credits": "Créditos",
+ "mwe-embedplayer-about-library": "Sobre o reprodutor Kaltura",
+ "mwe-embedplayer-about-library-desc": "A biblioteca de mídia HTML5 da Kaltura permite que você tira vantagem hoje das marcações HTML5 <code><nowiki><video></nowiki></code> e <code><nowiki><audio></nowiki></code> com uma interface de reprodutor consistente em todos os principais navegadores.\n\n[$1 Mais sobre a biblioteca de reprodução Kaltura].\n\nenables you to take advantage of the HTML5 <code><nowiki><video></nowiki></code> and <code><nowiki><audio></nowiki></code> tags today with a consistent player interface across all major browsers.\n\t\n[$1 More about the Kaltura player library].",
+ "mwe-embedplayer-clip_linkback": "Página da fonte do clipe",
+ "mwe-embedplayer-choose_player": "Escolher leitor de vídeo",
+ "mwe-embedplayer-no-player": "Não há nenhum leitor disponível para $1",
+ "mwe-embedplayer-share_this_video": "Compartilhar este vídeo",
+ "mwe-embedplayer-video_credits": "Créditos do vídeo",
+ "mwe-embedplayer-no-video_credits": "Créditos não disponíveis",
+ "mwe-embedplayer-kaltura-platform-title": "Plataforma de vídeo em código aberto Kaltura",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Fechar",
+ "mwe-embedplayer-ogg-player-vlc-player": "Leitor VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Leitor Ogg HTML5",
+ "mwe-embedplayer-ogg-player-mp3Native": "Tocador de MP3 em HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Tocador de ACC em HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Tocador de H.264 em HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Tocador WebM em HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Plugin Ogg genérico",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Plugin QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Tocador Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(selecionado)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Para uma melhor experiência de reprodução de vídeo recomendamos um <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">navegador que suporta HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Não foi detetado nenhum leitor compatível integrado ao browser: para reproduzir pelo browser, faça o download da [$1 última versão do Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Aperte <b>F11</b> para ativar ou desativar o modo de tela inteira no <i>browser</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Aperte <b>shift ⌘ F</b> para ativar ou desativar o modo de tela inteira",
+ "mwe-embedplayer-do_not_warn_again": "No futuro, não mostrar esta mensagem",
+ "mwe-embedplayer-playerSelect": "Tocadores",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Leia isto</a> antes de incorporar.",
+ "mwe-embedplayer-embed_site_or_blog": "Incorporar em uma página",
+ "mwe-embedplayer-embed_wiki": "Incorporar em uma wiki",
+ "mwe-embedplayer-related_videos": "Vídeos relacionados",
+ "mwe-embedplayer-seeking": "procurando",
+ "mwe-embedplayer-buffering": "criando buffer",
+ "mwe-embedplayer-video-h264": "Vídeo H.264",
+ "mwe-embedplayer-video-webm": "Vídeo WebM",
+ "mwe-embedplayer-video-flv": "Vídeo Flash",
+ "mwe-embedplayer-video-ogg": "Vídeo Ogg",
+ "mwe-embedplayer-video-audio": "Áudio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Áudio MPEG",
+ "mwe-embedplayer-video-3gp": "Vídeo 3GP",
+ "mwe-embedplayer-video-mpeg": "Vídeo MPEG",
+ "mwe-embedplayer-video-msvideo": "Vídeo AVI",
+ "mwe-embedplayer-missing-source": "Nenhum vídeo foi encontrado"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pt.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pt.json
new file mode 100644
index 00000000..b5b83814
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/pt.json
@@ -0,0 +1,101 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cainamarques",
+ "Hamilton Abreu",
+ "Imperadeiro98",
+ "Luckas",
+ "Malafaya",
+ "SandroHc",
+ "Vitorvicentevalente",
+ "Waldir"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Título: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "Sem créditos disponíveis",
+ "mwe-embedplayer-loading_plugin": "A carregar o ''plugin'' ...",
+ "mwe-embedplayer-select_playback": "Definir a preferência de reprodução",
+ "mwe-embedplayer-link_back": "Ligar atrás",
+ "mwe-embedplayer-error_swap_vid": "Erro: o mv_embed não conseguiu trocar o elemento de vídeo pela interface mv_embed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Adicionar ao fim da sequência",
+ "mwe-embedplayer-missing_video_stream": "O ficheiro vídeo para esta transmissão está em falta",
+ "mwe-embedplayer-play_clip": "Reproduzir clipe",
+ "mwe-embedplayer-pause_clip": "Pausar clipe",
+ "mwe-embedplayer-volume_control": "Controlo de volume",
+ "mwe-embedplayer-player_options": "Opções do leitor",
+ "mwe-embedplayer-timed_text": "Legendas",
+ "mwe-embedplayer-player_fullscreen": "Ecrã inteiro",
+ "mwe-embedplayer-next_clip_msg": "Reproduzir clipe seguinte",
+ "mwe-embedplayer-prev_clip_msg": "Reproduzir clipe anterior",
+ "mwe-embedplayer-current_clip_msg": "Continuar a reproduzir este clipe",
+ "mwe-embedplayer-seek_to": "Procurar $1",
+ "mwe-embedplayer-paused": "em pausa",
+ "mwe-embedplayer-download_segment": "Descarga da selecção:",
+ "mwe-embedplayer-download_full_video": "Descarga do ficheiro vídeo completo:",
+ "mwe-embedplayer-download_full_audio": "Descarregar ficheiro de áudio completo:",
+ "mwe-embedplayer-download_right_click": "Para descarregar, clique no botão direito do rato e seleccione <i>Guardar ligação como...</i>",
+ "mwe-embedplayer-download_clip": "Descarga do vídeo",
+ "mwe-embedplayer-download_text": "Descarga do texto",
+ "mwe-embedplayer-download": "Descarga",
+ "mwe-embedplayer-share": "Partilhar",
+ "mwe-embedplayer-credits": "Créditos",
+ "mwe-embedplayer-about-library": "Sobre o leitor Kaltura",
+ "mwe-embedplayer-about-library-desc": "A biblioteca multimédia HTML5 do Kaltura permite-lhe utilizar já hoje os elementos <code><nowiki><video></nowiki></code> e <code><nowiki><audio></nowiki></code> do HTML5 com uma interface consistente do leitor em todos os navegadores principais.\n\t\n[$1 Mais sobre a biblioteca do leitor Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Página fonte do clipe",
+ "mwe-embedplayer-choose_player": "Escolher leitor de vídeo",
+ "mwe-embedplayer-no-player": "Não há nenhum leitor disponível para $1",
+ "mwe-embedplayer-share_this_video": "Partilhar este vídeo",
+ "mwe-embedplayer-share_this_audio": "Partilhar ficheiro de áudio",
+ "mwe-embedplayer-video_credits": "Créditos do vídeo",
+ "mwe-embedplayer-no-video_credits": "Sem créditos disponíveis",
+ "mwe-embedplayer-kaltura-platform-title": "Plataforma de vídeo em código aberto Kaltura",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Fechar",
+ "mwe-embedplayer-ogg-player-vlc-player": "Leitor VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Leitor Ogg HTML5",
+ "mwe-embedplayer-ogg-player-mp3Native": "Leitor MP3 HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Leitor AAC HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Leitor H.264 HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Leitor WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "''Plugin'' Ogg genérico",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "VLC para aplicação iOS",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "''Plugin'' QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Leitor Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(seleccionado)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Para uma melhor experiência de reprodução de vídeo recomendamos um <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">navegador de vídeo HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Não foi detectado nenhum leitor compatível integrado no navegador: para reproduzir no navegador, faça a descarga da [$1 última versão do Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Carregue em <b>F11</b> para activar ou desactivar o modo de ecrã inteiro no navegador",
+ "mwe-embedplayer-fullscreen-tip-osx": "Carregue em <b>shift ⌘ F</b> para activar ou dcesativar o modo de ecrã inteiro",
+ "mwe-embedplayer-do_not_warn_again": "No futuro, não mostrar esta mensagem",
+ "mwe-embedplayer-playerSelect": "Leitores",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Leia isto</a> antes de incorporar.",
+ "mwe-embedplayer-embed_site_or_blog": "Incorporar numa página",
+ "mwe-embedplayer-embed_wiki": "Incorporar numa wiki",
+ "mwe-embedplayer-related_videos": "Vídeos relacionados",
+ "mwe-embedplayer-seeking": "a procurar",
+ "mwe-embedplayer-buffering": "a carregar",
+ "mwe-embedplayer-video-h264": "Vídeo H.264",
+ "mwe-embedplayer-video-webm": "Vídeo WebM",
+ "mwe-embedplayer-video-flv": "Vídeo Flash",
+ "mwe-embedplayer-video-ogg": "Vídeo Ogg",
+ "mwe-embedplayer-video-audio": "Áudio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Áudio MPEG",
+ "mwe-embedplayer-video-3gp": "Vídeo 3GP",
+ "mwe-embedplayer-video-mpeg": "Vídeo MPEG",
+ "mwe-embedplayer-video-msvideo": "Vídeo AVI",
+ "mwe-embedplayer-missing-source": "Não foi encontrado nenhum vídeo.",
+ "mwe-embedplayer-vlcapp-intro": "Para conseguir ver vídeos a partir deste sítio num iPhone ou iPad, precisa da gratuita $1.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "Aplicação VLC",
+ "mwe-embedplayer-vlcapp-downloadapp": "Descarregar a aplicação VLC a partir da App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Abrir este vídeo na aplicação VLC",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Descarregar este vídeo",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Para reproduzir vídeos neste sítio, precisa da aplicação gratuita VLC. Instalar agora?",
+ "mwe-embedplayer-iewebmprompt-intro": "Ops! Só mais uma coisa antes de poder ver o vídeo...",
+ "mwe-embedplayer-iewebmprompt-outro": "Recarregar esta página após a instalação."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/qqq.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/qqq.json
new file mode 100644
index 00000000..7d0939c3
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/qqq.json
@@ -0,0 +1,50 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "EugeneZelenko",
+ "Shirayuki",
+ "Umherirrender"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Used as a part of the credit. Parameters:\n* $1 - title\nThis message is followed by the following messages:\n* {{msg-mw|mwe-embedplayer-credit-author}}\n* {{msg-mw|mwe-embedplayer-credit-date}}",
+ "mwe-embedplayer-credit-date": "Parameters:\n* $1 - date\n{{Identical|Date}}",
+ "mwe-embedplayer-credit-author": "Parameters:\n* $1 - author\n{{Identical|Author}}",
+ "mwe-embedplayer-player_fullscreen": "{{Identical|Full screen}}",
+ "mwe-embedplayer-seek_to": "Used as the Player status string. Parameters:\n* $1 - a time in the NPT format. NPT (Normal play time) is defined in [//www.ietf.org/rfc/rfc2326.txt RFC 2326].",
+ "mwe-embedplayer-paused": "{{Identical|Paused}}",
+ "mwe-embedplayer-download_full_video": "Header for the Download tab in the menu, when it's a video file.",
+ "mwe-embedplayer-download_full_audio": "Header for the Download tab in the menu, when it's an audio file.",
+ "mwe-embedplayer-download": "{{Identical|Download}}",
+ "mwe-embedplayer-share": "{{Identical|Share}}",
+ "mwe-embedplayer-credits": "{{Identical|Credit}}",
+ "mwe-embedplayer-about-library-desc": "Parameters:\n* $1 - URL",
+ "mwe-embedplayer-no-player": "This message means that there are no available players to play $1.\n* $1 - source media title",
+ "mwe-embedplayer-share_this_video": "Header for the Share tab in the menu, when it's a video file.",
+ "mwe-embedplayer-share_this_audio": "Header for the Share tab in the menu, when it's an audio file.",
+ "mwe-embedplayer-menu_btn": "{{Identical|Menu}}",
+ "mwe-embedplayer-close_btn": "{{Identical|Close}}",
+ "mwe-embedplayer-ogg-player-mp3Native": "name of mp3 player in configuration screen",
+ "mwe-embedplayer-ogg-player-aacNative": "name of AAC player in configuration screen",
+ "mwe-embedplayer-ogg-player-webmNative": "name of WebM player in configuration screen",
+ "mwe-embedplayer-ogg-player-vp9Native": "name of VP9 player in configuration screen",
+ "mwe-embedplayer-ogg-player-IEWebMPrompt": "name of IE WebM plugin installer helper in configuration screen",
+ "mwe-embedplayer-ogg-player-selected": "{{Identical|Selected}}",
+ "mwe-embedplayer-ogg-player-IEWebMPrompt": "name of IE WebM plugin installer helper in configuration screen",
+ "mwe-embedplayer-ogg-player-ogvJsPlayer": "name of ogv.js Ogg JavaScript player in configuration screen",
+ "mwe-embedplayer-for_best_experience": "Shown when user's browser doesn't support playing videos. Parameters:\n* $1 - An empty &lt;a&gt; tag. Don't use this parameter.",
+ "mwe-embedplayer-download-warn": "Parameters:\n* $1 - URL",
+ "mwe-embedplayer-do_not_warn_again": "Standard message for disabling\nfuture identical warnings messages",
+ "mwe-embedplayer-playerSelect": "{{Identical|Player}}",
+ "mwe-embedplayer-embed_site_or_blog": "title for iframe embed code in share dialog",
+ "mwe-embedplayer-embed_wiki": "title for wiki embed code in share dialog",
+ "mwe-embedplayer-vlcapp-intro": "Shown where a video would be on the page, on iPhones/iPads. Parameter $1 is a link to the App store page for the vlc app, with the text contianed in the mwe-embedplayer-vlcapp-vlcapplinktext message. This message is followed by a bulleted list of links consisting of the messages: mwe-embedplayer-vlcapp-downloadapp, mwe-embedplayer-vlcapp-openvideo, mwe-embedplayer-vlcapp-openvideo. See also the related mwe-embedplayer-vlcapp-vlcapppopup message.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "Text of the $1 parameter of mwe-embedplayer-vlcapp-intro. Will be linked to https://itunes.apple.com/us/app/vlc-for-ios/id650377962?mt=8 (the download page for the vlc app).",
+ "mwe-embedplayer-vlcapp-downloadapp": "First bullet point after the mwe-embedplayer-vlcapp-intro. Links to the download page for installing the vlc app ( https://itunes.apple.com/us/app/vlc-for-ios/id650377962?mt=8 ).",
+ "mwe-embedplayer-vlcapp-openvideo": "Second bullet point after the mwe-embedplayer-vlcapp-intro. Link will open the video in the VLC app, if the app is installed",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Third bullet point after the mwe-embedplayer-vlcapp-intro. Linked directly to the video file",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Popup dialog box shown to user if they do not have the VLC app installed when trying to play a video on iPhone/iPad. Box will be presented with this message and two buttons (OK and cancel. Actual text of buttons may vary.) If user presses ok, they are redirected to https://itunes.apple.com/us/app/vlc-for-ios/id650377962?mt=8.",
+ "mwe-embedplayer-iewebmprompt-intro": "Shown where a video would be on the page, on IE with no WebM or Ogg support. Followed by mwe-embedplayer-iewebmprompt-linktext",
+ "mwe-embedplayer-iewebmprompt-linktext": "Shown where a video would be on the page, on IE with no WebM or Ogg support. When clicked links to https://tools.google.com/dlpage/webmmf/",
+ "mwe-embedplayer-iewebmprompt-outro": "Shown where a video would be on the page, on IE with no WebM or Ogg support. Follows mwe-embedplayer-iewebmprompt-linktext"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/qu.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/qu.json
new file mode 100644
index 00000000..6f0d1346
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/qu.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "AlimanRuna"
+ ]
+ },
+ "mwe-embedplayer-credit-date": "P'unchaw: $1"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ro.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ro.json
new file mode 100644
index 00000000..1742edd2
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ro.json
@@ -0,0 +1,83 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minisarm",
+ "Stelistcristi"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titlu: $1",
+ "mwe-embedplayer-credit-date": "Data: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-nocredits": "Niciun credit disponibil",
+ "mwe-embedplayer-loading_plugin": "Se încarcă modulul...",
+ "mwe-embedplayer-select_playback": "Setează preferințele de redare",
+ "mwe-embedplayer-link_back": "Legătură către înapoi",
+ "mwe-embedplayer-error_swap_vid": "Eroare: mwEmbed nu a putut schimba eticheta videoului pentru interfața mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Adaugă la sfârșitul secvenței",
+ "mwe-embedplayer-missing_video_stream": "Fișierul video pentru acest flux lipsește",
+ "mwe-embedplayer-play_clip": "Redă clipul",
+ "mwe-embedplayer-pause_clip": "Pauză",
+ "mwe-embedplayer-volume_control": "Control de volum",
+ "mwe-embedplayer-player_options": "Opțiunile playerului",
+ "mwe-embedplayer-timed_text": "Subtitrare sincronizată",
+ "mwe-embedplayer-player_fullscreen": "Ecran complet",
+ "mwe-embedplayer-next_clip_msg": "Redă clipul următor",
+ "mwe-embedplayer-prev_clip_msg": "Redă clip precedent",
+ "mwe-embedplayer-current_clip_msg": "Continuă redarea acestui clip",
+ "mwe-embedplayer-seek_to": "Derulează la $1",
+ "mwe-embedplayer-paused": "în pauză",
+ "mwe-embedplayer-download_segment": "Descarcă selecția:",
+ "mwe-embedplayer-download_full": "Descărcare videoclip întreg:",
+ "mwe-embedplayer-download_right_click": "Pentru a descărca, faceți clic dreapta și selectați <i>Salvează legătura ca...</i>",
+ "mwe-embedplayer-download_clip": "Descarcă videoclipul",
+ "mwe-embedplayer-download_text": "Descărcare subtitrare",
+ "mwe-embedplayer-download": "Descărcare",
+ "mwe-embedplayer-share": "Distribuire",
+ "mwe-embedplayer-credits": "Credite",
+ "mwe-embedplayer-about-library": "Despre playerul Kaltura",
+ "mwe-embedplayer-about-library-desc": "Biblioteca HTML5 de la Kaltura vă ajută să profitați de avantajele atributelor &lt;video&gt; și &lt;audio&gt; prezente astăzi în HTML5 cu o interfață de player consistentă și compatibilă cu cele mai populare navigatoare.\n\n[$1 Mai multe despre biblioteca playerului Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Pagina sursă a clipului",
+ "mwe-embedplayer-choose_player": "Alegere player video",
+ "mwe-embedplayer-no-player": "Niciun player disponibil pentru $1",
+ "mwe-embedplayer-share_this_video": "Distribuire videoclip",
+ "mwe-embedplayer-video_credits": "Creditele videoclipului",
+ "mwe-embedplayer-no-video_credits": "Niciun credit disponibil",
+ "mwe-embedplayer-kaltura-platform-title": "Platforma video cu sursă deschisă de la Kaltura",
+ "mwe-embedplayer-menu_btn": "Meniu",
+ "mwe-embedplayer-close_btn": "Închide",
+ "mwe-embedplayer-ogg-player-vlc-player": "Player VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Player HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-mp3Native": "Player MP3 HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Player AAC HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Player HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Player HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Modul generic Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Modul QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX QuickTime",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Player Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(selectat)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Pentru o vizionare mai bună a videoclipului vă recomandăm un <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">navigator compatibil cu modulul video din HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Nu s-a detectat niciun player integrat în navigator compatibil: pentru a reda în navigator, vă rugăm să descărcați [$1 ultima versiune de Firefox].",
+ "mwe-embedplayer-fullscreen-tip": "Apăsați <b>F11</b> pentru a comuta <i>navigatorul</i> în modul ecran complet",
+ "mwe-embedplayer-fullscreen-tip-osx": "Apăsați <b>shift ⌘ F</b> pentru a comuta în modul ecran complet",
+ "mwe-embedplayer-do_not_warn_again": "Nu mai afișa acest mesaj în viitor",
+ "mwe-embedplayer-playerSelect": "Playere",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Citiți aici</a> înainte de a încorpora.",
+ "mwe-embedplayer-embed_site_or_blog": "Încorporare pe o pagină",
+ "mwe-embedplayer-embed_wiki": "Încorporare pe un wiki",
+ "mwe-embedplayer-related_videos": "Videoclipuri similare",
+ "mwe-embedplayer-seeking": "derulare",
+ "mwe-embedplayer-buffering": "încărcare în memoria tampon",
+ "mwe-embedplayer-video-h264": "Video H.264",
+ "mwe-embedplayer-video-webm": "Video WebM",
+ "mwe-embedplayer-video-flv": "Video Flash",
+ "mwe-embedplayer-video-ogg": "Video Ogg",
+ "mwe-embedplayer-video-audio": "Audio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Audio MPEG",
+ "mwe-embedplayer-video-3gp": "Video 3GP",
+ "mwe-embedplayer-video-mpeg": "Video MPEG",
+ "mwe-embedplayer-video-msvideo": "Video AVI",
+ "mwe-embedplayer-missing-source": "Nu s-a găsit niciun videoclip sursă."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/roa-tara.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/roa-tara.json
new file mode 100644
index 00000000..698f8860
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/roa-tara.json
@@ -0,0 +1,33 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titole: $1",
+ "mwe-embedplayer-credit-date": "Date: $1",
+ "mwe-embedplayer-credit-author": "Autore: $1",
+ "mwe-embedplayer-download_clip": "Scareche 'u video",
+ "mwe-embedplayer-download_text": "Scareche 'u teste",
+ "mwe-embedplayer-download": "Scareche",
+ "mwe-embedplayer-share": "Condivide",
+ "mwe-embedplayer-credits": "Credite",
+ "mwe-embedplayer-menu_btn": "Menù",
+ "mwe-embedplayer-close_btn": "Chiude",
+ "mwe-embedplayer-ogg-player-vlc-player": "Visualizzatore VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Visualizzatore Ogg de HTML5",
+ "mwe-embedplayer-ogg-player-mp3Native": "Visualizzatore MP3 de HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Visualizzatore AAC de HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Visualizzatore H.264 de HTML5",
+ "mwe-embedplayer-ogg-player-webmNative": "Visualizzatore WebM de HTML5",
+ "mwe-embedplayer-ogg-player-selected": "(scacchiate)",
+ "mwe-embedplayer-video-h264": "Video H.264",
+ "mwe-embedplayer-video-webm": "Video WebM",
+ "mwe-embedplayer-video-flv": "Video Flash",
+ "mwe-embedplayer-video-ogg": "Video Ogg",
+ "mwe-embedplayer-video-audio": "Audio Ogg",
+ "mwe-embedplayer-audio-mpeg": "Audio MPEG",
+ "mwe-embedplayer-video-3gp": "Video 3GP",
+ "mwe-embedplayer-video-mpeg": "Video MPEG",
+ "mwe-embedplayer-video-msvideo": "Video AVI"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ru.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ru.json
new file mode 100644
index 00000000..899217a0
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ru.json
@@ -0,0 +1,100 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eleferen",
+ "MaxSem",
+ "Okras",
+ "Александр Сигачёв",
+ "Kaganer"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Название: $1",
+ "mwe-embedplayer-credit-date": "Дата: $1",
+ "mwe-embedplayer-credit-author": "Автор: $1",
+ "mwe-embedplayer-nocredits": "Нет сведений о создателях",
+ "mwe-embedplayer-loading_plugin": "загрузка плагина ...",
+ "mwe-embedplayer-select_playback": "Установить настройки воспроизведения",
+ "mwe-embedplayer-link_back": "Обратная ссылка",
+ "mwe-embedplayer-error_swap_vid": "Ошибка: mv_embed не может поменять тег видео для интерфейса mv_embed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Добавить в конец последовательности",
+ "mwe-embedplayer-missing_video_stream": "Видеофайл для этого потока отсутствует",
+ "mwe-embedplayer-play_clip": "Воспроизвести клип",
+ "mwe-embedplayer-pause_clip": "Приостановить клип",
+ "mwe-embedplayer-volume_control": "Регулировка громкости",
+ "mwe-embedplayer-player_options": "Настройки проигрывателя",
+ "mwe-embedplayer-timed_text": "Синхронизированный текст",
+ "mwe-embedplayer-player_fullscreen": "На весь экран",
+ "mwe-embedplayer-next_clip_msg": "Воспроизвести следующий клип",
+ "mwe-embedplayer-prev_clip_msg": "Воспроизвести предыдущий клип",
+ "mwe-embedplayer-current_clip_msg": "Продолжить воспроизведение этого клипа",
+ "mwe-embedplayer-seek_to": "Перейти к $1",
+ "mwe-embedplayer-paused": "пауза",
+ "mwe-embedplayer-download_segment": "Выбор загрузки:",
+ "mwe-embedplayer-download_full_video": "Загрузить полный видео-файл:",
+ "mwe-embedplayer-download_full_audio": "Загрузить полный аудио-файл:",
+ "mwe-embedplayer-download_right_click": "Чтобы загрузить, нажмите правую кнопку и выберите «Сохранить объект как…»",
+ "mwe-embedplayer-download_clip": "Загрузить видео",
+ "mwe-embedplayer-download_text": "Загрузить текст",
+ "mwe-embedplayer-download": "Скачать",
+ "mwe-embedplayer-share": "Поделиться",
+ "mwe-embedplayer-credits": "Создатели",
+ "mwe-embedplayer-about-library": "О проигрывателе Kaltura",
+ "mwe-embedplayer-about-library-desc": "HTML5 медиа-библиотека Kaltura позволяет вам уже сейчас пользоваться тегами HTML5 <code><nowiki><video></nowiki></code> и <code><nowiki><audio></nowiki></code> со стандартным интерфейсом воспроизведения во всех основных браузерах.\n\n[$1 Подробнее о библиотеке проигрывателя Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Исходная страница клипа",
+ "mwe-embedplayer-choose_player": "Выбор проигрывателя",
+ "mwe-embedplayer-no-player": "Нет проигрывателя для $1",
+ "mwe-embedplayer-share_this_video": "Поделиться этим видео",
+ "mwe-embedplayer-share_this_audio": "Поделиться этим аудио-файлом",
+ "mwe-embedplayer-video_credits": "О создателях видео",
+ "mwe-embedplayer-no-video_credits": "Нет сведений о создателях",
+ "mwe-embedplayer-kaltura-platform-title": "Видео-платформа с открытым исходным кодом Kaltura",
+ "mwe-embedplayer-menu_btn": "Меню",
+ "mwe-embedplayer-close_btn": "Закрыть",
+ "mwe-embedplayer-ogg-player-vlc-player": "Проигрыватель VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Проигрыватель HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3-проигрыватель",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC-проигрыватель",
+ "mwe-embedplayer-ogg-player-h264Native": "Проигрыватель HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Проигрыватель HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Общий плагин Ogg",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "Приложение VLC для iOS",
+ "mwe-embedplayer-ogg-player-IEWebMPrompt": "Загрузчик плагина IE WebM",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Плагин QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Проигрыватель Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(выбрано)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Для лучшего воспроизведения видео мы рекомендуем <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">браузер, поддерживающий HTML5</a>.",
+ "mwe-embedplayer-download-warn": "Не найдено встроенного в браузер проигрывателя, для воспроизведении в браузере загрузите [$1 последний Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Клавиша <b>F11</b> переводит <i>веб-браузер</i> в полноэкранный режим",
+ "mwe-embedplayer-fullscreen-tip-osx": "Нажмите <b>shift ⌘ F</b> для перехода в полноэкранный режим",
+ "mwe-embedplayer-do_not_warn_again": "Не показывать это сообщение в будущем",
+ "mwe-embedplayer-playerSelect": "Проигрыватели",
+ "mwe-embedplayer-read_before_embed": "Пожалуйста, <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">прочтите это</a> перед встраиванием!",
+ "mwe-embedplayer-embed_site_or_blog": "Вставить на страницу",
+ "mwe-embedplayer-embed_wiki": "Внедрён в вики",
+ "mwe-embedplayer-related_videos": "Связанные видео",
+ "mwe-embedplayer-seeking": "поиск",
+ "mwe-embedplayer-buffering": "буферизация",
+ "mwe-embedplayer-video-h264": "Видео H.264",
+ "mwe-embedplayer-video-webm": "Видео WebM",
+ "mwe-embedplayer-video-flv": "Flash-видео",
+ "mwe-embedplayer-video-ogg": "Ogg-видео",
+ "mwe-embedplayer-video-audio": "Ogg-аудио",
+ "mwe-embedplayer-audio-mpeg": "MPEG-аудио",
+ "mwe-embedplayer-video-3gp": "3GP-видео",
+ "mwe-embedplayer-video-mpeg": "MPEG-видео",
+ "mwe-embedplayer-video-msvideo": "AVI-видео",
+ "mwe-embedplayer-missing-source": "Не найден источник видео",
+ "mwe-embedplayer-vlcapp-intro": "Для просмотра видео с этого сайта на iPhone или iPad вам нужно бесплатное приложение $1.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "Приложение VLC",
+ "mwe-embedplayer-vlcapp-downloadapp": "Загрузить приложение VLC из App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Открыть это видео в приложении VLC",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Скачать это видео",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Для воспроизведения видео на этом сайте вам необходимо бесплатное приложение VLC. Установить сейчас?",
+ "mwe-embedplayer-iewebmprompt-intro": "Упс! Ещё кое-что, прежде чем вы сможете просмотреть это видео…",
+ "mwe-embedplayer-iewebmprompt-linktext": "Установите медиа-компоненты WebM для Microsoft Internet Explorer",
+ "mwe-embedplayer-iewebmprompt-outro": "После установки перезагрузите эту страницу."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/rue.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/rue.json
new file mode 100644
index 00000000..86c2c343
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/rue.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gazeb"
+ ]
+ },
+ "mwe-embedplayer-close_btn": "Заперти",
+ "mwe-embedplayer-ogg-player-vlc-player": "Перегравач VLC"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/si.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/si.json
new file mode 100644
index 00000000..76991f4a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/si.json
@@ -0,0 +1,78 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද",
+ "Susith Chandira Gts"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "මාතෘකාව: $1",
+ "mwe-embedplayer-credit-date": "දිනය: $1",
+ "mwe-embedplayer-credit-author": "කතෘ: $1",
+ "mwe-embedplayer-nocredits": "ස්තූති කිසිවක් ලබා ගත නොහැක",
+ "mwe-embedplayer-loading_plugin": "ප්ලගීනය පූරණය වෙමින් ...",
+ "mwe-embedplayer-select_playback": "පිළිවැයිම් අභිරුචිය සකසන්න",
+ "mwe-embedplayer-link_back": "නැවත සම්බන්ධ කරන්න",
+ "mwe-embedplayer-add_to_end_of_sequence": "අනුක්‍රමයේ අවසානයට එක් කරන්න",
+ "mwe-embedplayer-missing_video_stream": "මෙම ප්‍රවාහය සඳහා වීඩියෝ ගොනුව දක්නට නොමැත",
+ "mwe-embedplayer-play_clip": "ක්ලිපය වයන්න",
+ "mwe-embedplayer-pause_clip": "ක්ලිපය විරාමගත කරන්න",
+ "mwe-embedplayer-volume_control": "ශබ්ද ප්‍රමාණ පාලකය",
+ "mwe-embedplayer-player_options": "වාදක විකල්පයන්",
+ "mwe-embedplayer-timed_text": "කාලිත පෙළ",
+ "mwe-embedplayer-player_fullscreen": "පූර්ණ තිරය",
+ "mwe-embedplayer-next_clip_msg": "මීළඟ ක්ලිපය වයන්න",
+ "mwe-embedplayer-prev_clip_msg": "පෙර ක්ලිපය වයන්න",
+ "mwe-embedplayer-current_clip_msg": "මෙම ක්ලිපය දිගටම වයන්න",
+ "mwe-embedplayer-seek_to": "$1 ඉලියන්න",
+ "mwe-embedplayer-paused": "විරාමගතයි",
+ "mwe-embedplayer-download_segment": "තේරීම බාගන්න:",
+ "mwe-embedplayer-download_full_video": "සම්පූර්ණ වීඩියෝ ගොනුව බාගන්න:",
+ "mwe-embedplayer-download_full_audio": "පූර්ණ සංගීත ගොනුව බාගන්න:",
+ "mwe-embedplayer-download_right_click": "බාගත කිරීම සඳහා, දකුණ ක්ලික් කර <i>Save link as...</i> තෝරන්න",
+ "mwe-embedplayer-download_clip": "වීඩියෝව බාගන්න",
+ "mwe-embedplayer-download_text": "පාඨය බාගන්න",
+ "mwe-embedplayer-download": "බාගන්න",
+ "mwe-embedplayer-share": "හුවමාරු කරන්න",
+ "mwe-embedplayer-credits": "ස්තුතිය",
+ "mwe-embedplayer-about-library": "Kaltura වාදකය පිළිබඳ",
+ "mwe-embedplayer-clip_linkback": "ක්ලිපයේ මූලාශ්‍ර පිටුව",
+ "mwe-embedplayer-choose_player": "වීඩියෝ වාදකය තෝරන්න",
+ "mwe-embedplayer-no-player": "$1 සඳහා වාදකයක් ලබා ගත නොහැක",
+ "mwe-embedplayer-share_this_video": "මෙම වීඩියෝව හුවමාරු කරන්න",
+ "mwe-embedplayer-share_this_audio": "මෙම සංගීත ගොනුව හුවමාරු කරන්න",
+ "mwe-embedplayer-video_credits": "වීඩියෝ ස්තූතිය",
+ "mwe-embedplayer-no-video_credits": "ස්තූතිය ලබා ගත නොහැක",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura විවෘත මූලාශ්‍ර විදෘශ්‍ය කරළිය",
+ "mwe-embedplayer-menu_btn": "මෙනුව",
+ "mwe-embedplayer-close_btn": "වසන්න",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC වාදකය",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg වාදකය",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 වාදකය",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM වාදකය",
+ "mwe-embedplayer-ogg-player-oggPlugin": "ප්‍රජාතීය Ogg ප්ලගීනය",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime ප්ලගීනය",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "ෆ්ලොව්වාදකය",
+ "mwe-embedplayer-ogg-player-kplayer": "කල්තුරා වාදකය",
+ "mwe-embedplayer-ogg-player-selected": "(තෝරාගත්)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK ෆ්ලෑෂ් Vorbis",
+ "mwe-embedplayer-fullscreen-tip": "ටොගල <i>වෙබ් ගවේෂක</i> පූර්ණ තිරය සඳහා <b>F11</b> ඔබන්න",
+ "mwe-embedplayer-fullscreen-tip-osx": "ටොගල පූර්ණ තිරය සඳහා <b>shift ⌘ F</b> ඔබන්න",
+ "mwe-embedplayer-do_not_warn_again": "ඉදිරියේදී, මෙම පණිවුඩය පෙන්වන්න එපා",
+ "mwe-embedplayer-playerSelect": "වාදක",
+ "mwe-embedplayer-read_before_embed": "එබ්බීම පෙර <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">මෙය කියවන්න</a>.",
+ "mwe-embedplayer-embed_site_or_blog": "පිටුවක ඔබ්බවන්න",
+ "mwe-embedplayer-related_videos": "ආශ්‍රිත වීඩියෝ",
+ "mwe-embedplayer-seeking": "ඉලියමින්",
+ "mwe-embedplayer-buffering": "අවරෝධීකරණය කරමින්",
+ "mwe-embedplayer-video-h264": "H.264 වීඩියෝ",
+ "mwe-embedplayer-video-webm": "වෙබ්එම් වීඩියෝ",
+ "mwe-embedplayer-video-flv": "ෆ්ලෑෂ් වීඩියෝ",
+ "mwe-embedplayer-video-ogg": "Ogg වීඩියෝ",
+ "mwe-embedplayer-video-audio": "Ogg ශ්‍රව්‍ය",
+ "mwe-embedplayer-audio-mpeg": "MPEG වීඩියෝ",
+ "mwe-embedplayer-video-3gp": "3GP වීඩියෝ",
+ "mwe-embedplayer-video-mpeg": "MPEG වීඩියෝ",
+ "mwe-embedplayer-video-msvideo": "AVI වීඩියෝ",
+ "mwe-embedplayer-missing-source": "මූලාශ්‍ර වීඩියෝවක් හමු නොවුණි"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sk.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sk.json
new file mode 100644
index 00000000..fee61f56
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sk.json
@@ -0,0 +1,6 @@
+{
+ "@metadata": [],
+ "mwe-embedplayer-download": "Stiahnuť",
+ "mwe-embedplayer-close_btn": "Zavrieť",
+ "mwe-embedplayer-do_not_warn_again": "Nateraz nezobrazovať"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sr-ec.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sr-ec.json
new file mode 100644
index 00000000..fa893c4a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sr-ec.json
@@ -0,0 +1,78 @@
+{
+ "@metadata": {
+ "authors": [
+ "Milicevic01",
+ "Rancher",
+ "Михајло Анђелковић"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Наслов: $1",
+ "mwe-embedplayer-credit-date": "Датум: $1",
+ "mwe-embedplayer-credit-author": "Аутор: $1",
+ "mwe-embedplayer-loading_plugin": "Учитавам додатак…",
+ "mwe-embedplayer-select_playback": "Постави подешавања за извођење",
+ "mwe-embedplayer-link_back": "Обрнута веза",
+ "mwe-embedplayer-error_swap_vid": "Грешка: mwEmbed не може да замени видео-ознаку за окружење mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Додај на крај низа",
+ "mwe-embedplayer-missing_video_stream": "Недостаје видео-снимак за овај ток",
+ "mwe-embedplayer-play_clip": "Пусти клип",
+ "mwe-embedplayer-pause_clip": "Паузирај клип",
+ "mwe-embedplayer-volume_control": "Контрола јачине звука",
+ "mwe-embedplayer-player_options": "Поставке извођача",
+ "mwe-embedplayer-timed_text": "Усклађен текст",
+ "mwe-embedplayer-player_fullscreen": "Цео екран",
+ "mwe-embedplayer-next_clip_msg": "Пусти следећи клип",
+ "mwe-embedplayer-prev_clip_msg": "Пусти претходни клип",
+ "mwe-embedplayer-current_clip_msg": "Настави с извођењем овог снимка",
+ "mwe-embedplayer-seek_to": "Скочи на $1",
+ "mwe-embedplayer-paused": "паузирано",
+ "mwe-embedplayer-download_segment": "Избор за преузимање:",
+ "mwe-embedplayer-download_full": "Преузмите цео видео-снимак:",
+ "mwe-embedplayer-download_right_click": "За преузимање, притисните десни клик и изаберите <i>Сачувај везу као…</i>",
+ "mwe-embedplayer-download_clip": "Преузми видео-снимак",
+ "mwe-embedplayer-download_text": "Преузми текст",
+ "mwe-embedplayer-download": "Преузми",
+ "mwe-embedplayer-share": "Дели",
+ "mwe-embedplayer-credits": "Заслуге",
+ "mwe-embedplayer-about-library": "О извођачу Калтура",
+ "mwe-embedplayer-about-library-desc": "Калтурина мултимедијална библиотека HTML5 вам омогућава да користите HTML5 ознаке &lt;video&gt; и &lt;audio&gt; са стандардним сучељем за извођење преко најзаступљенијих прегледача.\n\n[$1 Више о Калтуриној библиотеци за извођење].",
+ "mwe-embedplayer-clip_linkback": "Изворна страница снимка",
+ "mwe-embedplayer-choose_player": "Изаберите видео-плејер",
+ "mwe-embedplayer-no-player": "Нема доступних извођача за $1",
+ "mwe-embedplayer-share_this_video": "Дели овај снимак",
+ "mwe-embedplayer-video_credits": "Аутори снимка",
+ "mwe-embedplayer-no-video_credits": "Нема ауторских података",
+ "mwe-embedplayer-kaltura-platform-title": "Калтурина отворена видео-платформа",
+ "mwe-embedplayer-menu_btn": "Мени",
+ "mwe-embedplayer-close_btn": "Затвори",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC плејер",
+ "mwe-embedplayer-ogg-player-oggNative": "Извођач .ogg (HTML5)",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 плејер",
+ "mwe-embedplayer-ogg-player-webmNative": "Извођач WebM (HTML5)",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Генерички Ogg плагин",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime плагин",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "Квиктајм (Активикс)",
+ "mwe-embedplayer-ogg-player-cortado": "Кортадо (Јава)",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Извођач Калтура",
+ "mwe-embedplayer-ogg-player-selected": "(изабрано)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "За квалитетније прегледање снимака, препоручујемо вам <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5 видео прегледач</a>.",
+ "mwe-embedplayer-download-warn": "Није пронађен прикладан извођач за пуштање преко прегледача. Преузмите [$1 најновији Фајерфокс]",
+ "mwe-embedplayer-fullscreen-tip": "Притисните <b>F11</b> да пребаците <i>прегледач</i> на цео екран",
+ "mwe-embedplayer-fullscreen-tip-osx": "Притисните <b>Shift ⌘ F</b> за пребацивање на цео екран",
+ "mwe-embedplayer-do_not_warn_again": "Не приказуј ову поруку поново",
+ "mwe-embedplayer-playerSelect": "Извођачи",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Прочитајте ово</a> пре уграђивања.",
+ "mwe-embedplayer-embed_site_or_blog": "Угради у страницу",
+ "mwe-embedplayer-related_videos": "Сродни видео-снимци",
+ "mwe-embedplayer-seeking": "тражим",
+ "mwe-embedplayer-buffering": "учитавам",
+ "mwe-embedplayer-video-h264": "H.264 видео",
+ "mwe-embedplayer-video-webm": "WebM видео",
+ "mwe-embedplayer-video-flv": "Флеш видео",
+ "mwe-embedplayer-video-ogg": "Ogg видео",
+ "mwe-embedplayer-video-audio": "Ogg аудио",
+ "mwe-embedplayer-missing-source": "Није пронађен извор снимка.",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Преузми овај видео"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sr-el.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sr-el.json
new file mode 100644
index 00000000..84f4cb21
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sr-el.json
@@ -0,0 +1,77 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rancher",
+ "Milicevic01"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Naslov: $1",
+ "mwe-embedplayer-credit-date": "Datum: $1",
+ "mwe-embedplayer-credit-author": "Autor: $1",
+ "mwe-embedplayer-loading_plugin": "Učitavam dodatak…",
+ "mwe-embedplayer-select_playback": "Postavi podešavanja za izvođenje",
+ "mwe-embedplayer-link_back": "Obrnuta veza",
+ "mwe-embedplayer-error_swap_vid": "Greška: mwEmbed ne može da zameni video-oznaku za sučelje mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Dodaj na kraj niza",
+ "mwe-embedplayer-missing_video_stream": "Nedostaje video-snimak za ovaj tok",
+ "mwe-embedplayer-play_clip": "Pusti klip",
+ "mwe-embedplayer-pause_clip": "Pauziraj klip",
+ "mwe-embedplayer-volume_control": "Kontrola jačine zvuka",
+ "mwe-embedplayer-player_options": "Postavke izvođača",
+ "mwe-embedplayer-timed_text": "Usklađen tekst",
+ "mwe-embedplayer-player_fullscreen": "Ceo ekran",
+ "mwe-embedplayer-next_clip_msg": "Pusti sledeći klip",
+ "mwe-embedplayer-prev_clip_msg": "Pusti prethodni klip",
+ "mwe-embedplayer-current_clip_msg": "Nastavi s izvođenjem ovog snimka",
+ "mwe-embedplayer-seek_to": "Skoči na $1",
+ "mwe-embedplayer-paused": "pauzirano",
+ "mwe-embedplayer-download_segment": "Izbor za preuzimanje:",
+ "mwe-embedplayer-download_full": "Preuzmite ceo video-snimak:",
+ "mwe-embedplayer-download_right_click": "Za preuzimanje, pritisnite desni klik i izaberite <i>Sačuvaj vezu kao…</i>",
+ "mwe-embedplayer-download_clip": "Preuzmi video-snimak",
+ "mwe-embedplayer-download_text": "Preuzmi tekst",
+ "mwe-embedplayer-download": "Preuzmi",
+ "mwe-embedplayer-share": "Deli",
+ "mwe-embedplayer-credits": "Zasluge",
+ "mwe-embedplayer-about-library": "O izvođaču Kaltura",
+ "mwe-embedplayer-about-library-desc": "Kalturina multimedijalna biblioteka HTML5 vam omogućava da koristite HTML5 oznake &lt;video&gt; i &lt;audio&gt; sa standardnim sučeljem za izvođenje preko najzastupljenijih pregledača.\n\n[$1 Više o Kalturinoj biblioteci za izvođenje].",
+ "mwe-embedplayer-clip_linkback": "Izvorna stranica snimka",
+ "mwe-embedplayer-choose_player": "Izaberite video-plejer",
+ "mwe-embedplayer-no-player": "Nema dostupnih izvođača za $1",
+ "mwe-embedplayer-share_this_video": "Deli ovaj snimak",
+ "mwe-embedplayer-video_credits": "Autori snimka",
+ "mwe-embedplayer-no-video_credits": "Nema autorskih podataka",
+ "mwe-embedplayer-kaltura-platform-title": "Kalturina otvorena video-platforma",
+ "mwe-embedplayer-menu_btn": "Meni",
+ "mwe-embedplayer-close_btn": "Zatvori",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC plejer",
+ "mwe-embedplayer-ogg-player-oggNative": "Izvođač .ogg (HTML5)",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 plejer",
+ "mwe-embedplayer-ogg-player-webmNative": "Izvođač WebM (HTML5)",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Generički Ogg plagin",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime plagin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "Kviktajm (Aktiviks)",
+ "mwe-embedplayer-ogg-player-cortado": "Kortado (Java)",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Izvođač Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(izabrano)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Za kvalitetnije pregledanje snimaka, preporučujemo vam <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">najnoviji Fajerfoks</a>.",
+ "mwe-embedplayer-download-warn": "Nije pronađen prikladan izvođač za puštanje preko pregledača. Preuzmite [$1 najnoviji Fajerfoks]",
+ "mwe-embedplayer-fullscreen-tip": "Pritisnite <b>F11</b> da prebacite <i>pregledač</i> na ceo ekran",
+ "mwe-embedplayer-fullscreen-tip-osx": "Pritisnite <b>Shift ⌘ F</b> za prebacivanje na ceo ekran",
+ "mwe-embedplayer-do_not_warn_again": "Ne prikazuj ovu poruku ponovo",
+ "mwe-embedplayer-playerSelect": "Izvođači",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Pročitajte ovo</a> pre ugrađivanja.",
+ "mwe-embedplayer-embed_site_or_blog": "Ugradi u stranicu",
+ "mwe-embedplayer-related_videos": "Srodni video-snimci",
+ "mwe-embedplayer-seeking": "tražim",
+ "mwe-embedplayer-buffering": "učitavam",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-webm": "WebM video",
+ "mwe-embedplayer-video-flv": "Fleš video",
+ "mwe-embedplayer-video-ogg": "Ogg video",
+ "mwe-embedplayer-video-audio": "Ogg audio",
+ "mwe-embedplayer-missing-source": "Nije pronađen izvor snimka.",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Preuzmi ovaj video"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sv.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sv.json
new file mode 100644
index 00000000..d34d25d2
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/sv.json
@@ -0,0 +1,96 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ainali",
+ "Dafer45",
+ "Lokal Profil",
+ "WikiPhoenix",
+ "Jenniesarina"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Titel: $1",
+ "mwe-embedplayer-credit-date": "Datum: $1",
+ "mwe-embedplayer-credit-author": "Författare: $1",
+ "mwe-embedplayer-nocredits": "Inga erkännanden tillgängliga",
+ "mwe-embedplayer-loading_plugin": "laddar insticksmodul...",
+ "mwe-embedplayer-select_playback": "Ange uppspelningsinställningar",
+ "mwe-embedplayer-link_back": "Länka tillbaka",
+ "mwe-embedplayer-error_swap_vid": "Fel: mwEmbed kunde inte att byta videoetiketten för mwEmbed-gränssnittet",
+ "mwe-embedplayer-add_to_end_of_sequence": "Lägg till i slutet av sekvens",
+ "mwe-embedplayer-missing_video_stream": "Videofil för den här dataströmmen saknas",
+ "mwe-embedplayer-play_clip": "Spela klipp",
+ "mwe-embedplayer-pause_clip": "Pausa klipp",
+ "mwe-embedplayer-volume_control": "Volymkontroll",
+ "mwe-embedplayer-player_options": "Spelaralternativ",
+ "mwe-embedplayer-timed_text": "Tidsbestämd text",
+ "mwe-embedplayer-player_fullscreen": "Fullskärm",
+ "mwe-embedplayer-next_clip_msg": "Spela nästa klipp",
+ "mwe-embedplayer-prev_clip_msg": "Spela föregående klipp",
+ "mwe-embedplayer-current_clip_msg": "Fortsätt spela detta klipp",
+ "mwe-embedplayer-seek_to": "Sök $1",
+ "mwe-embedplayer-paused": "pausad",
+ "mwe-embedplayer-download_segment": "Hämta urval:",
+ "mwe-embedplayer-download_full_video": "Ladda ner den fullständiga videofilen:",
+ "mwe-embedplayer-download_full_audio": "Ladda ned fullständig ljudfil:",
+ "mwe-embedplayer-download_right_click": "För att ladda ner, högerklicka och välj <i>Spara länk som ...</i>",
+ "mwe-embedplayer-download_clip": "Ladda ner video",
+ "mwe-embedplayer-download_text": "Ladda ner text",
+ "mwe-embedplayer-download": "Ladda ner",
+ "mwe-embedplayer-share": "Dela",
+ "mwe-embedplayer-credits": "Erkännanden",
+ "mwe-embedplayer-about-library": "Om Kaltura player",
+ "mwe-embedplayer-about-library-desc": "Kaltura's HTML5 mediabibliotek ger dig möjlighet att utnyttja HTML5 &lt;video&gt; och &lt;audio&gt; taggar idag med ett konsekvent spelargränssnitt över alla större webbläsare.\n\n[$1 Mer om Kaltura spelarbiblioteket].",
+ "mwe-embedplayer-clip_linkback": "Klippkällsidan",
+ "mwe-embedplayer-choose_player": "Välj videouppspelare",
+ "mwe-embedplayer-no-player": "Ingen spelare tillgänglig för $1",
+ "mwe-embedplayer-share_this_video": "Dela denna video",
+ "mwe-embedplayer-share_this_audio": "Dela denna ljudfil",
+ "mwe-embedplayer-video_credits": "Videoerkännanden",
+ "mwe-embedplayer-no-video_credits": "Inga erkännanden tillgängliga",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura öppen källkod videoplattform",
+ "mwe-embedplayer-menu_btn": "Meny",
+ "mwe-embedplayer-close_btn": "Stäng",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC spelare",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg spelare",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3-spelare",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC-spelare",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 spelare",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM spelare",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Generiella Ogg-tillägg",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "VLC för iOS-app",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-insticksmodul",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura spelare",
+ "mwe-embedplayer-ogg-player-selected": "(vald)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "För en bättre videouppspelningsupplevelse rekommenderar vi en <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5 videowebbläsare</a>.",
+ "mwe-embedplayer-download-warn": "Ingen kompatibel mediaspelare i webbläsaren upptäcktes: för webbläsaruppspelning, hämta [$1 senaste Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Tryck på <b>F11</b> för att växla <i>webbläsaren</i> till helskärm",
+ "mwe-embedplayer-fullscreen-tip-osx": "Tryck på <b>SKIFT ⌘ f</b> för att växla till helskärm",
+ "mwe-embedplayer-do_not_warn_again": "Visa inte detta meddelande fortsättningsvis",
+ "mwe-embedplayer-playerSelect": "Spelare",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Läs detta</a> innan inbäddning.",
+ "mwe-embedplayer-embed_site_or_blog": "Bädda in på en sida",
+ "mwe-embedplayer-embed_wiki": "Bädda in på en wiki",
+ "mwe-embedplayer-related_videos": "Relaterade videos",
+ "mwe-embedplayer-seeking": "söker",
+ "mwe-embedplayer-buffering": "buffring",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-webm": "WebM video",
+ "mwe-embedplayer-video-flv": "Flash-video",
+ "mwe-embedplayer-video-ogg": "Ogg video",
+ "mwe-embedplayer-video-audio": "Ogg ljud",
+ "mwe-embedplayer-audio-mpeg": "MPEG audio",
+ "mwe-embedplayer-video-3gp": "3GP video",
+ "mwe-embedplayer-video-mpeg": "MPEG video",
+ "mwe-embedplayer-video-msvideo": "AVI video",
+ "mwe-embedplayer-missing-source": "Ingen källvideo hittades",
+ "mwe-embedplayer-vlcapp-intro": "I för att visa video från denna webbplats på en iPhone eller iPad, behöver du den kostnadsfria $1.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "VLC-app",
+ "mwe-embedplayer-vlcapp-downloadapp": "Ladda ner VLC-appen från App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Öppna denna video i VLC-appen",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Ladda ner denna video",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "För att spela upp video på denna webbplats, behöver du den kostnadsfria VLC-appen. Installera nu?",
+ "mwe-embedplayer-iewebmprompt-intro": "Oops! En sak till innan du kan spela denna video..."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ta.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ta.json
new file mode 100644
index 00000000..5e8d84a9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ta.json
@@ -0,0 +1,40 @@
+{
+ "@metadata": {
+ "authors": [
+ "Karthi.dr",
+ "Shanmugamp7",
+ "மதனாஹரன்"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "தலைப்பு: $1",
+ "mwe-embedplayer-credit-date": "தேதி: $1",
+ "mwe-embedplayer-credit-author": "ஆக்குனர்: $1",
+ "mwe-embedplayer-play_clip": "துண்டை இயக்கு",
+ "mwe-embedplayer-player_fullscreen": "முழுத்திரை",
+ "mwe-embedplayer-next_clip_msg": "அடுத்த துண்டை இயக்கு",
+ "mwe-embedplayer-prev_clip_msg": "முந்தைய துண்டை இயக்கு",
+ "mwe-embedplayer-current_clip_msg": "இத்துண்டை இயக்குவதைத் தொடர்",
+ "mwe-embedplayer-paused": "இடைநிறுத்தப்பட்டது",
+ "mwe-embedplayer-download_segment": "தெரிவைத் தரவிறக்கு:",
+ "mwe-embedplayer-download_full": "முழுக் காணொளிக் கோப்பைத் தரவிறக்கு:",
+ "mwe-embedplayer-download_clip": "காணொளியைத் தரவிறக்கு",
+ "mwe-embedplayer-download_text": "உரையைத் தரவிறக்கு",
+ "mwe-embedplayer-download": "பதிவிறக்கம் செய்",
+ "mwe-embedplayer-share": "பகிர்",
+ "mwe-embedplayer-choose_player": "காணொளி இயக்கியைத் தெரி",
+ "mwe-embedplayer-share_this_video": "இக் காணொளியைப் பகிர்க",
+ "mwe-embedplayer-menu_btn": "பட்டி",
+ "mwe-embedplayer-close_btn": "மூடு",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC ஊடக இயக்கி",
+ "mwe-embedplayer-do_not_warn_again": "வருங்காலத்தில் இச்செய்தியைக் காட்ட வேண்டாம்",
+ "mwe-embedplayer-playerSelect": "இயக்கிகள்",
+ "mwe-embedplayer-related_videos": "தொடர்புள்ள காணொளிகள்",
+ "mwe-embedplayer-video-h264": "H.264 காணொளி",
+ "mwe-embedplayer-video-webm": "WebM காணொளி",
+ "mwe-embedplayer-video-flv": "பிளாஷ் காணொளி",
+ "mwe-embedplayer-video-ogg": "Ogg காணொளி",
+ "mwe-embedplayer-video-3gp": "3GP காணொளி",
+ "mwe-embedplayer-video-mpeg": "MPEG காணொளி",
+ "mwe-embedplayer-video-msvideo": "AVI காணொளி",
+ "mwe-embedplayer-missing-source": "மூலக் காணொளியேதும் கண்டுபிடிக்கப்படவில்லை"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/te.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/te.json
new file mode 100644
index 00000000..3c69d4f7
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/te.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "Veeven"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "శీర్షిక: $1",
+ "mwe-embedplayer-credit-date": "తేదీ: $1",
+ "mwe-embedplayer-player_fullscreen": "నిండుతెర",
+ "mwe-embedplayer-download": "దింపుకోలు",
+ "mwe-embedplayer-share": "పంచుకోండి",
+ "mwe-embedplayer-share_this_video": "ఈ వీడియోని పంచుకోండి",
+ "mwe-embedplayer-menu_btn": "మెనూ",
+ "mwe-embedplayer-close_btn": "మూసివేయి",
+ "mwe-embedplayer-ogg-player-selected": "(ఎంచుకున్నారు)",
+ "mwe-embedplayer-related_videos": "సంబంధిత దృశ్యకాలు"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tet.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tet.json
new file mode 100644
index 00000000..3e73c4ed
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tet.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "MF-Warburg"
+ ]
+ },
+ "mwe-embedplayer-credit-author": "Autór: $1"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tl.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tl.json
new file mode 100644
index 00000000..78eb2b06
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tl.json
@@ -0,0 +1,83 @@
+{
+ "@metadata": {
+ "authors": [
+ "AnakngAraw",
+ "Sky Harbor",
+ "Leeheonjin"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Pamagat: $1",
+ "mwe-embedplayer-credit-date": "Petsa: $1",
+ "mwe-embedplayer-credit-author": "May-akda: $1",
+ "mwe-embedplayer-nocredits": "Walang makuhang mga pagbanggit",
+ "mwe-embedplayer-loading_plugin": "Ikinakarga ang pampasak ...",
+ "mwe-embedplayer-select_playback": "Itakda ang nais sa pagpapaandar",
+ "mwe-embedplayer-link_back": "Ikawing pabalik",
+ "mwe-embedplayer-error_swap_vid": "Kamalian: hindi nagawang pagpalitin ng mwEmbed ang tatak ng bidyo para sa hangganang-mukha ng mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Idagdag sa huli ng sunuran",
+ "mwe-embedplayer-missing_video_stream": "Nawawala ang talaksan ng biyo para sa daloy na ito",
+ "mwe-embedplayer-play_clip": "Palaruin ang klip",
+ "mwe-embedplayer-pause_clip": "Pahintuin ang klip",
+ "mwe-embedplayer-volume_control": "Pangtaban ng lakas ng tunog",
+ "mwe-embedplayer-player_options": "Pagpipiliang pangpampaandar",
+ "mwe-embedplayer-timed_text": "Tekstong inoorasan",
+ "mwe-embedplayer-player_fullscreen": "Buong panooran",
+ "mwe-embedplayer-next_clip_msg": "Paandarin ang susunod na putol",
+ "mwe-embedplayer-prev_clip_msg": "Paandarin ang nakaraang putol",
+ "mwe-embedplayer-current_clip_msg": "Ipagpatuloy ang pagpapaandar ng putol na ito",
+ "mwe-embedplayer-seek_to": "Hanapin ang $1",
+ "mwe-embedplayer-paused": "hininto",
+ "mwe-embedplayer-download_segment": "Ikargang pababa ang napili:",
+ "mwe-embedplayer-download_full_video": "Ikargang pababa ang buong talaksan ng bidyo:",
+ "mwe-embedplayer-download_right_click": "Upang maikargang paibaba, pindutin ang kanan at piliin ang <i>Sagipin ang kawing bilang...</i>",
+ "mwe-embedplayer-download_clip": "Ikargang pababa ang bidyo",
+ "mwe-embedplayer-download_text": "Ikargang paibaba ang teksto",
+ "mwe-embedplayer-download": "Ikargang pababa",
+ "mwe-embedplayer-share": "Ipamahagi",
+ "mwe-embedplayer-credits": "Mga banggit-pagkilala",
+ "mwe-embedplayer-about-library": "Tungkol sa pampaandar na Kaltura",
+ "mwe-embedplayer-about-library-desc": "Ang aklatan ng midyang HTML5 ng Kaltura ay nagpapahintulot sa iyong samantalahin ang mga tatak na <code><nowiki><bidyo></nowiki></code> na HTML5 at <code><nowiki><audio></nowiki></code> ngayon ng isang ugnayang-mukha ng palagiang pampaandar sa kahabaan ng lahat ng pangunahing mga pantingin-tingin.\n\n[$1 Marami pang hinggil sa aklatan ng pampaandar ng Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Pahinang batayan ng klip",
+ "mwe-embedplayer-choose_player": "Piliin ang pampaandar ng bidyo",
+ "mwe-embedplayer-no-player": "Walang makuhang pampaandar para sa $1",
+ "mwe-embedplayer-share_this_video": "Ipamahagi ang bidyong ito",
+ "mwe-embedplayer-video_credits": "Mga banggit-pagkilala ng bidyo",
+ "mwe-embedplayer-no-video_credits": "Walang makuhang mga pagbanggit",
+ "mwe-embedplayer-kaltura-platform-title": "Plataporma ng bukas na pinagmulan ng bidyo ng Kaltura",
+ "mwe-embedplayer-menu_btn": "Menu",
+ "mwe-embedplayer-close_btn": "Isara",
+ "mwe-embedplayer-ogg-player-vlc-player": "Pampaandar ng VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Pampaandar ng HTML5 Ogg",
+ "mwe-embedplayer-ogg-player-h264Native": "Pampaandar ng HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Pampaandar ng HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Panlahatang pamasak ng Ogg",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Pampasak ng QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "ActiveX ng QuickTime",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Pampaandar na Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Pampaandar ng Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(napili na)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Para sa mas mainam na karanasan ng pagpapaandar ng bidyo iminumungkahi namin ang <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">pantingin-tingin ng bidyo na html5</a>.",
+ "mwe-embedplayer-download-warn": "Walang napansin na kaugmang pampaandar ng pantingin-tingin, para sa pag-uulit ng pagpapaandar ng pantingin-tingin ikargang paibaba ang [$1 pinakahuling Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Pindutin ang <b>F11</b> pampalit-lipat ng <i>pantingin-tingin sa web</i> na buo ang panooran",
+ "mwe-embedplayer-fullscreen-tip-osx": "Pindutin ang <b>shift ⌘ F</b> upang mapalitan at malipatan ang buong panooran",
+ "mwe-embedplayer-do_not_warn_again": "Sa hinaharap, huwag ipakita ang mensaheng ito",
+ "mwe-embedplayer-playerSelect": "Mga pampaandar",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Basahin ito</a> bago ibaon.",
+ "mwe-embedplayer-embed_site_or_blog": "Ibaon sa isang pahina",
+ "mwe-embedplayer-related_videos": "Kaugnay na mga bidyo",
+ "mwe-embedplayer-seeking": "hinahanap",
+ "mwe-embedplayer-buffering": "pinapakinis",
+ "mwe-embedplayer-video-h264": "Bidyong H.264",
+ "mwe-embedplayer-video-webm": "Bidyong WebM",
+ "mwe-embedplayer-video-flv": "Bidyong Flash",
+ "mwe-embedplayer-video-ogg": "Bidyong Ogg",
+ "mwe-embedplayer-video-audio": "Tunog na Ogg",
+ "mwe-embedplayer-audio-mpeg": "Tunog na MPEG",
+ "mwe-embedplayer-video-3gp": "Bidyong 3GP",
+ "mwe-embedplayer-video-mpeg": "Bidyong MPEG",
+ "mwe-embedplayer-video-msvideo": "Bidyong AVI",
+ "mwe-embedplayer-missing-source": "Walang natagpuang batayang bidyo",
+ "mwe-embedplayer-iewebmprompt-intro": "Ui! Isa pang bagay bago mo i-play itong video..."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tr.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tr.json
new file mode 100644
index 00000000..e76ebff4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tr.json
@@ -0,0 +1,85 @@
+{
+ "@metadata": {
+ "authors": [
+ "Emperyan",
+ "Sayginer"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Başlık: $1",
+ "mwe-embedplayer-credit-date": "Tarih: $1",
+ "mwe-embedplayer-credit-author": "Yazar: $1",
+ "mwe-embedplayer-loading_plugin": "Eklenti yükleniyor ...",
+ "mwe-embedplayer-select_playback": "Tekrar oynatma tercihini ayarla",
+ "mwe-embedplayer-link_back": "Geri bağlantı ver",
+ "mwe-embedplayer-error_swap_vid": "Hata: mwEmbed, mwEmbed arayüzü için video etiketini değiş tokuş yapamıyor",
+ "mwe-embedplayer-add_to_end_of_sequence": "Sıranın sonuna ekle",
+ "mwe-embedplayer-missing_video_stream": "Bu akış için video dosyası kayıp",
+ "mwe-embedplayer-play_clip": "Klibi oynat",
+ "mwe-embedplayer-pause_clip": "Klibi durdur",
+ "mwe-embedplayer-volume_control": "Ses denetimi",
+ "mwe-embedplayer-player_options": "Oynatıcı seçenekleri",
+ "mwe-embedplayer-timed_text": "Zamanlanmış metin",
+ "mwe-embedplayer-player_fullscreen": "Tam ekran",
+ "mwe-embedplayer-next_clip_msg": "Sonraki klibi oynat",
+ "mwe-embedplayer-prev_clip_msg": "Önceki klibi oynat",
+ "mwe-embedplayer-current_clip_msg": "Bu klibi oynatmaya devam et",
+ "mwe-embedplayer-seek_to": "$1 süresine git",
+ "mwe-embedplayer-paused": "durduruldu",
+ "mwe-embedplayer-download_segment": "Seçimi indir:",
+ "mwe-embedplayer-download_full_video": "Tam video dosyasını indir:",
+ "mwe-embedplayer-download_full_audio": "Ses dosyasının tamamını indir:",
+ "mwe-embedplayer-download_right_click": "İndirmek için, sağ tıklayın ve <i>Bağlantıyı farklı kaydet...</i>'i seçin",
+ "mwe-embedplayer-download_clip": "Videoyu indir",
+ "mwe-embedplayer-download_text": "Metni indir",
+ "mwe-embedplayer-download": "İndir",
+ "mwe-embedplayer-share": "Paylaş",
+ "mwe-embedplayer-credits": "Katkıda bulunanlar",
+ "mwe-embedplayer-about-library": "Kaltura oynatıcısı hakkında",
+ "mwe-embedplayer-clip_linkback": "Klip kaynak sayfası",
+ "mwe-embedplayer-choose_player": "Video oynatıcı seç",
+ "mwe-embedplayer-no-player": "$1 için oynatıcı mevcut değil",
+ "mwe-embedplayer-share_this_video": "Bu videoyu paylaş",
+ "mwe-embedplayer-share_this_audio": "Bu ses dosyasını paylaş",
+ "mwe-embedplayer-video_credits": "Videoya katkıda bulunanlar",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura açık kaynak kodlu video platformu",
+ "mwe-embedplayer-menu_btn": "Menü",
+ "mwe-embedplayer-close_btn": "Kapat",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC player",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg oynatıcı",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3 oynatıcı",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC oynatıcı",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 oynatıcı",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM oynatıcı",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Jenerik Ogg eklentisi",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime eklentisi",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura oynatıcısı",
+ "mwe-embedplayer-ogg-player-selected": "(seçili)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Daha iyi bir video oynatma deneyimi için önerimiz:<br /><a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">Firefox 3.5</a>.",
+ "mwe-embedplayer-do_not_warn_again": "Gelecekte bu iletiyi gösterme",
+ "mwe-embedplayer-playerSelect": "Oynatıcılar",
+ "mwe-embedplayer-read_before_embed": "Lütfen gerçekten gömmeden <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">uzaktan gömme hakkındaki güvenlik notlarını</a> okuyun!",
+ "mwe-embedplayer-embed_site_or_blog": "Bir sayfaya gömün",
+ "mwe-embedplayer-embed_wiki": "Bir viki üzerinde göm",
+ "mwe-embedplayer-related_videos": "İlgili videolar",
+ "mwe-embedplayer-seeking": "aranıyor",
+ "mwe-embedplayer-buffering": "ara belleğe alınıyor",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-webm": "WebM video",
+ "mwe-embedplayer-video-flv": "Flash, video",
+ "mwe-embedplayer-video-ogg": "Ogg video",
+ "mwe-embedplayer-video-audio": "Ogg ses",
+ "mwe-embedplayer-audio-mpeg": "MPEG ses",
+ "mwe-embedplayer-video-3gp": "3GP video",
+ "mwe-embedplayer-video-mpeg": "MPEG video",
+ "mwe-embedplayer-video-msvideo": "AVI video",
+ "mwe-embedplayer-missing-source": "Video kaynağı bulunamadı",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "VLC uygulaması",
+ "mwe-embedplayer-vlcapp-downloadapp": "VLC uygulamasını App Store'dan indir",
+ "mwe-embedplayer-vlcapp-openvideo": "Bu videoyu VLC uygulamasıyla aç",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Bu videoyu indir",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Bu sitedeki videoları oynatmak için, ücretsiz olan VLC uygulaması gerekiyor. Şimdi yüklensin mi?"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tzm.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tzm.json
new file mode 100644
index 00000000..8a49fbb4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/tzm.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tifinaghes"
+ ]
+ },
+ "mwe-embedplayer-share": "ⴼⵙⴻⵔ",
+ "mwe-embedplayer-video-h264": "H.264 video",
+ "mwe-embedplayer-video-flv": "ⴼⵍⴰⵛ video",
+ "mwe-embedplayer-video-ogg": "Ogg video"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/uk.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/uk.json
new file mode 100644
index 00000000..5089e774
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/uk.json
@@ -0,0 +1,92 @@
+{
+ "@metadata": {
+ "authors": [
+ "Andriykopanytsia",
+ "Base",
+ "Ата",
+ "Тест"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Назва: $1",
+ "mwe-embedplayer-credit-date": "Дата: $1",
+ "mwe-embedplayer-credit-author": "Автор: $1",
+ "mwe-embedplayer-nocredits": "Нема відомостей про автора",
+ "mwe-embedplayer-loading_plugin": "Завантаження додатка ...",
+ "mwe-embedplayer-select_playback": "Встановити налаштування відтворення",
+ "mwe-embedplayer-link_back": "Зворотнє посилання",
+ "mwe-embedplayer-error_swap_vid": "Помилка: mwEmbed не вдалося замінити тег відео для інтерфейсу mwEmbed",
+ "mwe-embedplayer-add_to_end_of_sequence": "Додати у кінець послідовності",
+ "mwe-embedplayer-missing_video_stream": "Відеофайл для цього потоку відсутній",
+ "mwe-embedplayer-play_clip": "Відтворити кліп",
+ "mwe-embedplayer-pause_clip": "Призупинити кліп",
+ "mwe-embedplayer-volume_control": "Регулювання гучності",
+ "mwe-embedplayer-player_options": "Налаштування програвача",
+ "mwe-embedplayer-timed_text": "Субтитри",
+ "mwe-embedplayer-player_fullscreen": "На весь екран",
+ "mwe-embedplayer-next_clip_msg": "Відтворити наступний кліп",
+ "mwe-embedplayer-prev_clip_msg": "Відтворити попередній кліп",
+ "mwe-embedplayer-current_clip_msg": "Продовжити відтворення цього кліпу",
+ "mwe-embedplayer-seek_to": "Перейти до $1",
+ "mwe-embedplayer-paused": "пауза",
+ "mwe-embedplayer-download_segment": "Вибір завантаження:",
+ "mwe-embedplayer-download_full": "Завантажити весь відео-файл:",
+ "mwe-embedplayer-download_right_click": "Для завантаження, натисніть праву кнопку миші і оберіть «Зберегти об'єкт як…»",
+ "mwe-embedplayer-download_clip": "Завантажити відео",
+ "mwe-embedplayer-download_text": "Завантажити текст",
+ "mwe-embedplayer-download": "Завантажити",
+ "mwe-embedplayer-share": "Поділитись",
+ "mwe-embedplayer-credits": "Створювачі",
+ "mwe-embedplayer-about-library": "Про програвач Kaltura",
+ "mwe-embedplayer-about-library-desc": "HTML5 медіа-бібліотека Kaltura дозволяє Вам користуватись HTML5 тегами &lt;відео&gt; та &lt;аудіо&gt; вже сьогодні зі стандартним інтерфейсом відтворення у різних браузерах.\n\n[$1 Більше про бібліотеку програвача Kaltura].",
+ "mwe-embedplayer-clip_linkback": "Вихідна сторінка кліпу",
+ "mwe-embedplayer-choose_player": "Виберіть відео плеєр",
+ "mwe-embedplayer-no-player": "Нема програвача для $1",
+ "mwe-embedplayer-share_this_video": "Поділитись цим відео",
+ "mwe-embedplayer-video_credits": "Про створювачів відео",
+ "mwe-embedplayer-no-video_credits": "Нема відомостей про автора",
+ "mwe-embedplayer-kaltura-platform-title": "Відео-платформа з відкритим кодом Kaltura",
+ "mwe-embedplayer-menu_btn": "Меню",
+ "mwe-embedplayer-close_btn": "Закрити",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC програвач",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg програвач",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3-програвач",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC-програвач",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264 програвач",
+ "mwe-embedplayer-ogg-player-webmNative": "Програвач HTML5 WebM",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Загальний плаґін Ogg",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "Програма VLC для iOS",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Додаток QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Програвач Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(обрано)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "Для кращого відтворення відео рекомендуємо <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">html5 відео браузер</a>.",
+ "mwe-embedplayer-download-warn": "Не знайдено вбудованого програвача для браузера, для відтворення в браузері завантажте, будь ласка, [$1 останній Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "Натисніть кнопку <b>F11</b> для перемикання <i>веб-браузеру</i> у повноекранний режим",
+ "mwe-embedplayer-fullscreen-tip-osx": "Натисніть кнопку <b>shift ⌘ F</b> для переходу у повноекранний режим",
+ "mwe-embedplayer-do_not_warn_again": "Не показувати це повідомлення у майбутньому",
+ "mwe-embedplayer-playerSelect": "Програвачі",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Прочитайте це</a> перед включенням.",
+ "mwe-embedplayer-embed_site_or_blog": "Включити на сторінку",
+ "mwe-embedplayer-embed_wiki": "Вбудований у вікі",
+ "mwe-embedplayer-related_videos": "Пов'язані відео",
+ "mwe-embedplayer-seeking": "пошук",
+ "mwe-embedplayer-buffering": "буферизація",
+ "mwe-embedplayer-video-h264": "H.264 відео",
+ "mwe-embedplayer-video-webm": "Відео WebM",
+ "mwe-embedplayer-video-flv": "Флеш відео",
+ "mwe-embedplayer-video-ogg": "Ogg відео",
+ "mwe-embedplayer-video-audio": "Ogg аудіо",
+ "mwe-embedplayer-audio-mpeg": "MPEG-аудіо",
+ "mwe-embedplayer-video-3gp": "3GP-відео",
+ "mwe-embedplayer-video-mpeg": "MPEG-відео",
+ "mwe-embedplayer-video-msvideo": "AVI-відео",
+ "mwe-embedplayer-missing-source": "Не знайдено джерело відео",
+ "mwe-embedplayer-vlcapp-intro": "Для перегляду відео з цього сайту на iPhone або iPad вам потрібна безкоштовна програма $1.",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "Програма VLC",
+ "mwe-embedplayer-vlcapp-downloadapp": "Завантажити програму VLC із App Store",
+ "mwe-embedplayer-vlcapp-openvideo": "Відкрити це відео у програмі VLC",
+ "mwe-embedplayer-vlcapp-downloadvideo": "Завантажити це відео",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "Для відтворення відео на цьому сайті потрібна безкоштовна програма VLC. Встановити зараз?"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ur.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ur.json
new file mode 100644
index 00000000..2136b2ba
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/ur.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-embedplayer-download": "ڈاؤن لوڈ ، اتارنا",
+ "mwe-embedplayer-share": "حصہ",
+ "mwe-embedplayer-credits": "کریڈٹ",
+ "mwe-embedplayer-menu_btn": "مینو",
+ "mwe-embedplayer-close_btn": "بند"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vec.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vec.json
new file mode 100644
index 00000000..6c166455
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vec.json
@@ -0,0 +1,38 @@
+{
+ "@metadata": [],
+ "mwe-embedplayer-credit-title": "Titolo: $1",
+ "mwe-embedplayer-loading_plugin": "so' drio cargar el plugin...",
+ "mwe-embedplayer-link_back": "Colèga indrìo",
+ "mwe-embedplayer-add_to_end_of_sequence": "Taca in fondo a la sequensa",
+ "mwe-embedplayer-play_clip": "Riprodusi",
+ "mwe-embedplayer-pause_clip": "Meti in pausa",
+ "mwe-embedplayer-volume_control": "Controlo volume",
+ "mwe-embedplayer-player_fullscreen": "Schermo intiero",
+ "mwe-embedplayer-seek_to": "Serca $1",
+ "mwe-embedplayer-paused": "en pausa",
+ "mwe-embedplayer-download_segment": "Descarga la selession:",
+ "mwe-embedplayer-download_full": "Descarga tuto el file video:",
+ "mwe-embedplayer-download_right_click": "Par descargar, struca el boton destro e selessiona <i>Salva colegamento come...</i>",
+ "mwe-embedplayer-download_clip": "Descarga el video",
+ "mwe-embedplayer-download": "Descarga",
+ "mwe-embedplayer-share": "Spartissi",
+ "mwe-embedplayer-credits": "Riconossimenti",
+ "mwe-embedplayer-choose_player": "Siegli el letor multimedial",
+ "mwe-embedplayer-share_this_video": "Condividi sto video",
+ "mwe-embedplayer-video_credits": "Riconossimenti del video",
+ "mwe-embedplayer-menu_btn": "Menù",
+ "mwe-embedplayer-close_btn": "Sara",
+ "mwe-embedplayer-ogg-player-vlc-player": "Letor VLC",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Plugin Ogg generico",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Plugin QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Letor Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(selessionà)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-read_before_embed": "<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">Lèzi qua</a> prima de 'ndar vanti.",
+ "mwe-embedplayer-embed_site_or_blog": "Inserissi drento na pagina",
+ "mwe-embedplayer-related_videos": "Video ligà a sto qua",
+ "mwe-embedplayer-seeking": "so' drio sercar"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vep.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vep.json
new file mode 100644
index 00000000..c90787dd
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vep.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": [],
+ "mwe-embedplayer-link_back": "Kosketuz tagaze",
+ "mwe-embedplayer-play_clip": "Väta klip",
+ "mwe-embedplayer-credits": "Tegijad",
+ "mwe-embedplayer-menu_btn": "Menü",
+ "mwe-embedplayer-close_btn": "Saubata",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime-plagin",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-selected": "(valitud)"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vi.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vi.json
new file mode 100644
index 00000000..a88dd46d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/vi.json
@@ -0,0 +1,77 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minh Nguyen"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "Tựa: $1",
+ "mwe-embedplayer-credit-date": "Ngày: $1",
+ "mwe-embedplayer-credit-author": "Tác giả: $1",
+ "mwe-embedplayer-nocredits": "Không có sẵn lời ghi công",
+ "mwe-embedplayer-loading_plugin": "đang tải phần bổ trợ …",
+ "mwe-embedplayer-select_playback": "Cấu hình phát lại",
+ "mwe-embedplayer-missing_video_stream": "Tập tin video của luồng này bị mất",
+ "mwe-embedplayer-play_clip": "Chơi clip",
+ "mwe-embedplayer-pause_clip": "Tạm ngừng clip",
+ "mwe-embedplayer-volume_control": "Điều khiển âm lượng",
+ "mwe-embedplayer-player_options": "Tùy chọn trình chơi",
+ "mwe-embedplayer-timed_text": "Văn bản đồng bộ",
+ "mwe-embedplayer-player_fullscreen": "Toàn màn hình",
+ "mwe-embedplayer-next_clip_msg": "Chơi clip sau",
+ "mwe-embedplayer-prev_clip_msg": "Chơi clip trước",
+ "mwe-embedplayer-current_clip_msg": "Chơi clip này tiếp",
+ "mwe-embedplayer-seek_to": "Nhảy tới $1",
+ "mwe-embedplayer-paused": "đang tạm ngừng",
+ "mwe-embedplayer-download_segment": "Tải về lựa chọn:",
+ "mwe-embedplayer-download_full": "Tải về cả tập tin video:",
+ "mwe-embedplayer-download_right_click": "Để tải về, hãy nhấn chuột phải và chọn <i>Lưu Liên Kết dưới dạng…</i> (<i>Save Link As…</i>)",
+ "mwe-embedplayer-download_clip": "Tải về video",
+ "mwe-embedplayer-download_text": "Tải về văn bản",
+ "mwe-embedplayer-download": "Tải về",
+ "mwe-embedplayer-share": "Chia sẻ",
+ "mwe-embedplayer-credits": "Ghi công",
+ "mwe-embedplayer-about-library": "Giới thiệu trình chơi Kaltura",
+ "mwe-embedplayer-clip_linkback": "Trang nguồn clip",
+ "mwe-embedplayer-choose_player": "Chọn trình chơi video",
+ "mwe-embedplayer-no-player": "Không có sẵn trình chơi cho $1",
+ "mwe-embedplayer-share_this_video": "Chia sẻ video này",
+ "mwe-embedplayer-video_credits": "Ghi công về video",
+ "mwe-embedplayer-no-video_credits": "Không có sẵn lời ghi công",
+ "mwe-embedplayer-kaltura-platform-title": "Nền tảng video nguồn mở Kaltura",
+ "mwe-embedplayer-menu_btn": "Trình đơn",
+ "mwe-embedplayer-close_btn": "Đóng",
+ "mwe-embedplayer-ogg-player-vlc-player": "Trình chơi VLC",
+ "mwe-embedplayer-ogg-player-oggNative": "Trình chơi Ogg HTML5",
+ "mwe-embedplayer-ogg-player-mp3Native": "Trình chơi MP3 HTML5",
+ "mwe-embedplayer-ogg-player-aacNative": "Trình chơi AAC HTML5",
+ "mwe-embedplayer-ogg-player-h264Native": "Trình chơi HTML5 H.264",
+ "mwe-embedplayer-ogg-player-webmNative": "Trình chơi WebM HTML5",
+ "mwe-embedplayer-ogg-player-oggPlugin": "Phần bổ trợ Ogg thường",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "Phần bổ trợ QuickTime",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-cortado": "Java Cortado",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Trình chơi Kaltura",
+ "mwe-embedplayer-ogg-player-selected": "(được chọn)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-fullscreen-tip": "Bấm <b>F11</b> để bật/tắt chế độ toàn màn hình <i>của trình duyệt</i>",
+ "mwe-embedplayer-fullscreen-tip-osx": "Bấm tổ hợp <b>⇧⌘F</b> để bật/tắt chế độ toàn màn hình",
+ "mwe-embedplayer-do_not_warn_again": "Từ nay không hiển thị thông báo này",
+ "mwe-embedplayer-playerSelect": "Trình chơi",
+ "mwe-embedplayer-read_before_embed": "Hãy <a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding?uselang=vi\" target=\"new\">đọc cảnh báo</a> trước khi nhúng.",
+ "mwe-embedplayer-embed_site_or_blog": "Nhúng vào trang",
+ "mwe-embedplayer-embed_wiki": "Nhúng vào trang wiki",
+ "mwe-embedplayer-related_videos": "Video liên quan",
+ "mwe-embedplayer-seeking": "đang nhảy",
+ "mwe-embedplayer-buffering": "đang đệm",
+ "mwe-embedplayer-video-h264": "Video H.264",
+ "mwe-embedplayer-video-webm": "Video WebM",
+ "mwe-embedplayer-video-flv": "Video Flash",
+ "mwe-embedplayer-video-ogg": "Video Ogg",
+ "mwe-embedplayer-video-audio": "Âm thanh Ogg",
+ "mwe-embedplayer-audio-mpeg": "Âm thanh MPEG",
+ "mwe-embedplayer-video-3gp": "Video 3GP",
+ "mwe-embedplayer-video-mpeg": "Video MPEG",
+ "mwe-embedplayer-video-msvideo": "Video AVI",
+ "mwe-embedplayer-missing-source": "Không tìm thấy video gốc"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/yi.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/yi.json
new file mode 100644
index 00000000..ce1af5d6
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/yi.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "פוילישער",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-embedplayer-credit-date": "דאַטע: $1",
+ "mwe-embedplayer-close_btn": "שליסן"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/zh-hans.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/zh-hans.json
new file mode 100644
index 00000000..debfbc6e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/zh-hans.json
@@ -0,0 +1,102 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hydra",
+ "Shizhao",
+ "Xiaomingyan",
+ "Yfdyh000",
+ "乌拉跨氪",
+ "NigelSoft",
+ "Liuxinyu970226",
+ "Duolaimi"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "标题:$1",
+ "mwe-embedplayer-credit-date": "日期:$1",
+ "mwe-embedplayer-credit-author": "作者:$1",
+ "mwe-embedplayer-nocredits": "没有制作人员名单",
+ "mwe-embedplayer-loading_plugin": "正在载入插件...",
+ "mwe-embedplayer-select_playback": "设置播放偏好",
+ "mwe-embedplayer-link_back": "链接回",
+ "mwe-embedplayer-error_swap_vid": "出错:mwEmbed无法将视频标签转换为mwEmbed界面",
+ "mwe-embedplayer-add_to_end_of_sequence": "添加至队列末尾",
+ "mwe-embedplayer-missing_video_stream": "该视频流的视频文件丢失",
+ "mwe-embedplayer-play_clip": "播放片段",
+ "mwe-embedplayer-pause_clip": "暂停片段",
+ "mwe-embedplayer-volume_control": "调整音量",
+ "mwe-embedplayer-player_options": "播放器选项",
+ "mwe-embedplayer-timed_text": "字幕",
+ "mwe-embedplayer-player_fullscreen": "全屏",
+ "mwe-embedplayer-next_clip_msg": "播放下一片段",
+ "mwe-embedplayer-prev_clip_msg": "播放上一片段",
+ "mwe-embedplayer-current_clip_msg": "继续播放本片段",
+ "mwe-embedplayer-seek_to": "寻找$1",
+ "mwe-embedplayer-paused": "已暂停",
+ "mwe-embedplayer-download_segment": "下载节选片段:",
+ "mwe-embedplayer-download_full_video": "下载完整视频文件:",
+ "mwe-embedplayer-download_full_audio": "下载完整音频文件:",
+ "mwe-embedplayer-download_right_click": "下载请单击鼠标右键并选择“链接另存为...”",
+ "mwe-embedplayer-download_clip": "下载视频",
+ "mwe-embedplayer-download_text": "下载字幕",
+ "mwe-embedplayer-download": "下载",
+ "mwe-embedplayer-share": "分享",
+ "mwe-embedplayer-credits": "制作人员",
+ "mwe-embedplayer-about-library": "关于Kaltura播放器",
+ "mwe-embedplayer-about-library-desc": "Kaltura的HTML5媒体库可以让你在所有的主流浏览器使用一致的播放器界面享受HTML5&lt;video&gt;和&lt;audio&gt;标签的便利。\n\n[$1 更多关于Kaltura播放器库的信息]。",
+ "mwe-embedplayer-clip_linkback": "片段源页面",
+ "mwe-embedplayer-choose_player": "选择视频播放器",
+ "mwe-embedplayer-no-player": "没有适用于$1的播放器",
+ "mwe-embedplayer-share_this_video": "分享该视频",
+ "mwe-embedplayer-share_this_audio": "分享这个音频文件",
+ "mwe-embedplayer-video_credits": "视频制作人员",
+ "mwe-embedplayer-no-video_credits": "没有制作人员名单",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura开源视频平台",
+ "mwe-embedplayer-menu_btn": "菜单",
+ "mwe-embedplayer-close_btn": "关闭",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC播放器",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg播放器",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3播放器",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC播放器",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264播放器",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM播放器",
+ "mwe-embedplayer-ogg-player-oggPlugin": "通用Ogg插件",
+ "mwe-embedplayer-ogg-player-vlcAppPlayer": "用于iOS的VLC应用程序",
+ "mwe-embedplayer-ogg-player-IEWebMPrompt": "IE WebM插件下载器",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime插件",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura播放器",
+ "mwe-embedplayer-ogg-player-selected": "(已选)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "为了得到更好的视频播放体验,我们推荐<a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5视频浏览器</a>。",
+ "mwe-embedplayer-download-warn": "检测到播放器和浏览器不兼容:为了能在浏览器中播放,请下载[$1 最新Firefox]",
+ "mwe-embedplayer-fullscreen-tip": "按<b>F11</b>切换浏览器至全屏",
+ "mwe-embedplayer-fullscreen-tip-osx": "按<b>Shift ⌘ F</b>切换至全屏",
+ "mwe-embedplayer-do_not_warn_again": "以后不再显示该信息",
+ "mwe-embedplayer-playerSelect": "播放器",
+ "mwe-embedplayer-read_before_embed": "嵌入前请<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">阅读本文</a>。",
+ "mwe-embedplayer-embed_site_or_blog": "嵌入页面",
+ "mwe-embedplayer-embed_wiki": "嵌入wiki",
+ "mwe-embedplayer-related_videos": "相关视频",
+ "mwe-embedplayer-seeking": "正在寻找",
+ "mwe-embedplayer-buffering": "正在缓冲",
+ "mwe-embedplayer-video-h264": "H.264视频",
+ "mwe-embedplayer-video-webm": "WebM视频",
+ "mwe-embedplayer-video-flv": "Flash视频",
+ "mwe-embedplayer-video-ogg": "Ogg视频",
+ "mwe-embedplayer-video-audio": "Ogg音频",
+ "mwe-embedplayer-audio-mpeg": "MPEG音频",
+ "mwe-embedplayer-video-3gp": "3GP视频",
+ "mwe-embedplayer-video-mpeg": "MPEG视频",
+ "mwe-embedplayer-video-msvideo": "AVI视频",
+ "mwe-embedplayer-missing-source": "未找到源视频",
+ "mwe-embedplayer-vlcapp-intro": "为了在iPhone或iPad上观看此站的视频,您需要免费的$1。",
+ "mwe-embedplayer-vlcapp-vlcapplinktext": "VLC应用程序",
+ "mwe-embedplayer-vlcapp-downloadapp": "从App Store下载VLC应用程序",
+ "mwe-embedplayer-vlcapp-openvideo": "使用VLC应用程序打开此视频",
+ "mwe-embedplayer-vlcapp-downloadvideo": "下载这个视频",
+ "mwe-embedplayer-vlcapp-vlcapppopup": "要在该网站播放视频,您需要免费的VLC应用程序。现在安装?",
+ "mwe-embedplayer-iewebmprompt-intro": "哎呀!在您可以播放该视频前您还需要做一件事……",
+ "mwe-embedplayer-iewebmprompt-linktext": "为Microsoft Internet Explorer安装WebM媒体组件",
+ "mwe-embedplayer-iewebmprompt-outro": "在安装后重新加载此页面。"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/zh-hant.json b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/zh-hant.json
new file mode 100644
index 00000000..5dceb76e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/i18n/zh-hant.json
@@ -0,0 +1,86 @@
+{
+ "@metadata": {
+ "authors": [
+ "Justincheng12345",
+ "Mark85296341",
+ "Simon Shek",
+ "StephDC",
+ "LNDDYL"
+ ]
+ },
+ "mwe-embedplayer-credit-title": "標題:$1",
+ "mwe-embedplayer-credit-date": "日期:$1",
+ "mwe-embedplayer-credit-author": "作者:$1",
+ "mwe-embedplayer-nocredits": "未署名",
+ "mwe-embedplayer-loading_plugin": "正在載入外掛程式...",
+ "mwe-embedplayer-select_playback": "設定回放偏好",
+ "mwe-embedplayer-link_back": "反連",
+ "mwe-embedplayer-error_swap_vid": "錯誤:mwEmbed無法轉換用於mwEmbed介面的影片標籤",
+ "mwe-embedplayer-add_to_end_of_sequence": "添加至序列末尾",
+ "mwe-embedplayer-missing_video_stream": "此串流的影片檔案已遺失",
+ "mwe-embedplayer-play_clip": "播放剪輯",
+ "mwe-embedplayer-pause_clip": "暫停剪輯",
+ "mwe-embedplayer-volume_control": "音量控制",
+ "mwe-embedplayer-player_options": "播放器選項",
+ "mwe-embedplayer-timed_text": "字幕",
+ "mwe-embedplayer-player_fullscreen": "全螢幕",
+ "mwe-embedplayer-next_clip_msg": "播放下一剪輯",
+ "mwe-embedplayer-prev_clip_msg": "播放前一剪輯",
+ "mwe-embedplayer-current_clip_msg": "繼續播放此剪輯",
+ "mwe-embedplayer-seek_to": "尋找$1",
+ "mwe-embedplayer-paused": "暫停",
+ "mwe-embedplayer-download_segment": "下載選段:",
+ "mwe-embedplayer-download_full": "下載完整的影片檔:",
+ "mwe-embedplayer-download_right_click": "下載請按右鍵並選擇<i>連結另存為...</i>",
+ "mwe-embedplayer-download_clip": "下載影片",
+ "mwe-embedplayer-download_text": "下載字幕",
+ "mwe-embedplayer-download": "下載",
+ "mwe-embedplayer-share": "分享",
+ "mwe-embedplayer-credits": "署名",
+ "mwe-embedplayer-about-library": "關於Kaltura播放器",
+ "mwe-embedplayer-about-library-desc": "Kaltura的HTML5媒體櫃讓您在當今能跨越所有主流瀏覽器充分地利用HTML5影片和音訊標籤。\n\n[$1 更多關於Kaltura播放器櫃的資訊]。",
+ "mwe-embedplayer-clip_linkback": "剪輯源頁面",
+ "mwe-embedplayer-choose_player": "選擇影片播放器",
+ "mwe-embedplayer-no-player": "$1沒有可用播放器",
+ "mwe-embedplayer-share_this_video": "分享該影片",
+ "mwe-embedplayer-video_credits": "影片署名",
+ "mwe-embedplayer-no-video_credits": "無署名",
+ "mwe-embedplayer-kaltura-platform-title": "Kaltura開放原始碼影片平台",
+ "mwe-embedplayer-menu_btn": "選單",
+ "mwe-embedplayer-close_btn": "關閉",
+ "mwe-embedplayer-ogg-player-vlc-player": "VLC播放器",
+ "mwe-embedplayer-ogg-player-oggNative": "HTML5 Ogg播放器",
+ "mwe-embedplayer-ogg-player-mp3Native": "HTML5 MP3 播放機",
+ "mwe-embedplayer-ogg-player-aacNative": "HTML5 AAC 播放機",
+ "mwe-embedplayer-ogg-player-h264Native": "HTML5 H.264播放器",
+ "mwe-embedplayer-ogg-player-webmNative": "HTML5 WebM播放器",
+ "mwe-embedplayer-ogg-player-oggPlugin": "未注冊Ogg插件",
+ "mwe-embedplayer-ogg-player-quicktime-mozilla": "QuickTime外掛程式",
+ "mwe-embedplayer-ogg-player-quicktime-activex": "QuickTime ActiveX",
+ "mwe-embedplayer-ogg-player-flowplayer": "Flowplayer",
+ "mwe-embedplayer-ogg-player-kplayer": "Kaltura播放器",
+ "mwe-embedplayer-ogg-player-selected": "(已選取)",
+ "mwe-embedplayer-ogg-player-omtkplayer": "OMTK Flash Vorbis",
+ "mwe-embedplayer-for_best_experience": "為取得更好影片播放體驗,我們推薦<a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\" target=\"_blank\">HTML5影片瀏覽器</a>。",
+ "mwe-embedplayer-download-warn": "檢測到播放器與瀏覽器不相容,如希望於瀏覽器中播放請下載[$1 最新版本Firefox瀏覽器]",
+ "mwe-embedplayer-fullscreen-tip": "按<b>F11</b>把瀏覽器設為全螢幕",
+ "mwe-embedplayer-fullscreen-tip-osx": "按<b>Shift ⌘ F</b>設為全螢幕",
+ "mwe-embedplayer-do_not_warn_again": "以後不再顯示此訊息",
+ "mwe-embedplayer-playerSelect": "播放器",
+ "mwe-embedplayer-read_before_embed": "嵌入前請先<a href=\"https://www.mediawiki.org/wiki/Security_Notes_on_Remote_Embedding\" target=\"new\">閱讀本文</a>。",
+ "mwe-embedplayer-embed_site_or_blog": "嵌入頁面",
+ "mwe-embedplayer-embed_wiki": "在 wiki 上嵌入",
+ "mwe-embedplayer-related_videos": "相關影片",
+ "mwe-embedplayer-seeking": "正在搜尋",
+ "mwe-embedplayer-buffering": "緩衝中",
+ "mwe-embedplayer-video-h264": "H.264影片",
+ "mwe-embedplayer-video-webm": "WebM影片",
+ "mwe-embedplayer-video-flv": "Flash影片",
+ "mwe-embedplayer-video-ogg": "Ogg影片",
+ "mwe-embedplayer-video-audio": "Ogg音訊",
+ "mwe-embedplayer-audio-mpeg": "MPEG音訊",
+ "mwe-embedplayer-video-3gp": "3GP影片",
+ "mwe-embedplayer-video-mpeg": "MPEG影片",
+ "mwe-embedplayer-video-msvideo": "AVI影片",
+ "mwe-embedplayer-missing-source": "未找到原始影片"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/blackvideo.mp4 b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/blackvideo.mp4
new file mode 100644
index 00000000..cf86d1a8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/blackvideo.mp4
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayer.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayer.js
new file mode 100644
index 00000000..131302a2
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayer.js
@@ -0,0 +1,2760 @@
+/**
+* embedPlayer is the base class for html5 video tag javascript abstraction library
+* embedPlayer include a few subclasses:
+*
+* mediaPlayer Media player embed system ie: java, vlc or native.
+* mediaElement Represents source media elements
+* mw.PlayerControlBuilder Handles skinning of the player controls
+*/
+( function( mw, $ ) {"use strict";
+ /**
+ * Merge in the default video attributes supported by embedPlayer:
+ */
+ mw.mergeConfig('EmbedPlayer.Attributes', {
+ /*
+ * Base html element attributes:
+ */
+
+ // id: Auto-populated if unset
+ "id" : null,
+
+ // Width: alternate to "style" to set player width
+ "width" : null,
+
+ // Height: alternative to "style" to set player height
+ "height" : null,
+
+ /*
+ * Base html5 video element attributes / states also see:
+ * http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
+ */
+
+ // Media src URI, can be relative or absolute URI
+ "src" : null,
+
+ // Poster attribute for displaying a place holder image before loading
+ // or playing the video
+ "poster" : null,
+
+ // Autoplay if the media should start playing
+ "autoplay" : false,
+
+ // Loop attribute if the media should repeat on complete
+ "loop" : false,
+
+ // If the player controls should be displayed
+ "controls" : true,
+
+ // Video starts "paused"
+ "paused" : true,
+
+ // ReadyState an attribute informs clients of video loading state:
+ // see: http://www.whatwg.org/specs/web-apps/current-work/#readystate
+ "readyState" : 0,
+
+ // Loading state of the video element
+ "networkState" : 0,
+
+ // Current playback position
+ "currentTime" : 0,
+
+ // Previous player set time
+ // Lets javascript use $('#videoId')[0].currentTime = newTime;
+ "previousTime" : 0,
+
+ // Previous player set volume
+ // Lets javascript use $('#videoId')[0].volume = newVolume;
+ "previousVolume" : 1,
+
+ // Initial player volume:
+ "volume" : 0.75,
+
+ // Caches the volume before a mute toggle
+ "preMuteVolume" : 0.75,
+
+ // Media duration: Value is populated via
+ // custom data-durationhint attribute or via the media file once its played
+ "duration" : null,
+
+ // A hint to the duration of the media file so that duration
+ // can be displayed in the player without loading the media file
+ 'data-durationhint': null,
+
+ // to disable menu or timedText for a given embed
+ 'data-disablecontrols': null,
+
+ // Also support direct durationHint attribute ( backwards compatibly )
+ // @deprecated please use data-durationhint instead.
+ 'durationHint' : null,
+
+ // Mute state
+ "muted" : false,
+
+ /**
+ * Custom attributes for embedPlayer player: (not part of the html5
+ * video spec)
+ */
+
+ // Default video aspect ratio
+ 'videoAspect' : '4:3',
+
+ // Start time of the clip
+ "start" : 0,
+
+ // End time of the clip
+ "end" : null,
+
+ // If the player controls should be overlaid
+ // ( Global default via config EmbedPlayer.OverlayControls in module
+ // loader.js)
+ "overlaycontrols" : true,
+
+ // Attribute to use 'native' controls
+ "usenativecontrols" : false,
+
+ // If the player should include an attribution button:
+ 'attributionbutton' : true,
+
+ // A player error object (Includes title and message)
+ // * Used to display an error instead of a play button
+ // * The full player api available
+ 'playerError' : {},
+
+ // A flag to hide the player gui and disable autoplay
+ // * Used for empty players or a player where you want to dynamically set sources, then play.
+ // * The player API remains active.
+ 'data-blockPlayerDisplay': null,
+
+ // If serving an ogg_chop segment use this to offset the presentation time
+ // ( for some plugins that use ogg page time rather than presentation time )
+ "startOffset" : 0,
+
+ // If the download link should be shown
+ "downloadLink" : true,
+
+ // Content type of the media
+ "type" : null
+
+ } );
+
+
+ /**
+ * The base source attribute checks also see:
+ * http://dev.w3.org/html5/spec/Overview.html#the-source-element
+ */
+ mw.mergeConfig( 'EmbedPlayer.SourceAttributes', [
+ // source id
+ 'id',
+
+ // media url
+ 'src',
+
+ // Title string for the source asset
+ 'title',
+
+ // The html5 spec uses label instead of 'title' for naming sources
+ 'label',
+
+ // boolean if we support temporal url requests on the source media
+ 'URLTimeEncoding',
+
+ // Media has a startOffset ( used for plugins that
+ // display ogg page time rather than presentation time
+ 'startOffset',
+
+ // Media start time
+ 'start',
+
+ // Media end time
+ 'end',
+
+ // If the source is the default source
+ 'default',
+
+ // Title of the source
+ 'title',
+
+ // titleKey ( used for api lookups TODO move into mediaWiki specific support
+ 'titleKey'
+ ] );
+
+
+ /**
+ * Base embedPlayer object
+ *
+ * @param {Element}
+ * element, the element used for initialization.
+ * @constructor
+ */
+ mw.EmbedPlayer = function( element ) {
+ return this.init( element );
+ };
+
+ mw.EmbedPlayer.prototype = {
+
+ // The mediaElement object containing all mediaSource objects
+ 'mediaElement' : null,
+
+ // Object that describes the supported feature set of the underling plugin /
+ // Support list is described in PlayerControlBuilder components
+ 'supports': { },
+
+ // If the player is done loading ( does not guarantee playability )
+ // for example if there is an error playerReadyFlag is still set to true once
+ // no more loading is to be done
+ 'playerReadyFlag' : false,
+
+ // Stores the loading errors
+ 'loadError' : false,
+
+ // Thumbnail updating flag ( to avoid rewriting an thumbnail thats already
+ // being updated)
+ 'thumbnailUpdatingFlag' : false,
+
+ // Stopped state flag
+ 'stopped' : true,
+
+ // Local variable to hold CMML meeta data about the current clip
+ // for more on CMML see: http://wiki.xiph.org/CMML
+ 'cmmlData': null,
+
+ // Stores the seek time request, Updated by the seek function
+ 'serverSeekTime' : 0,
+
+ // If the embedPlayer is current 'seeking'
+ 'seeking' : false,
+
+ // Percent of the clip buffered:
+ 'bufferedPercent' : 0,
+
+ // Holds the timer interval function
+ 'monitorTimerId' : null,
+
+ // Buffer flags
+ 'bufferStartFlag' : false,
+ 'bufferEndFlag' : false,
+
+ // For supporting media fragments stores the play end time
+ 'pauseTime' : null,
+
+ // On done playing
+ 'donePlayingCount' : 0
+ ,
+ // if player events should be Propagated
+ '_propagateEvents': true,
+
+ // If the onDone interface should be displayed
+ 'onDoneInterfaceFlag': true,
+
+ // if we should check for a loading spinner in the monitor function:
+ '_checkHideSpinner' : false,
+
+ // If pause play controls click controls should be active:
+ '_playContorls' : true,
+
+ // If player should be displayed (in some caused like audio, we don't need the player to be visible
+ 'displayPlayer': true,
+
+ // Widget loaded should only fire once
+ 'widgetLoaded': false,
+
+ /**
+ * embedPlayer
+ *
+ * @constructor
+ *
+ * @param {Element}
+ * element DOM element that we are building the player interface for.
+ */
+ init: function( element ) {
+ var _this = this;
+ mw.log('EmbedPlayer: initEmbedPlayer: ' + $(element).width() );
+
+ var playerAttributes = mw.config.get( 'EmbedPlayer.Attributes' );
+
+ // Store the rewrite element tag type
+ this.rewriteElementTagName = element.tagName.toLowerCase();
+
+ this.noPlayerFallbackHTML = $( element ).html();
+
+ // Setup the player Interface from supported attributes:
+ for ( var attr in playerAttributes ) {
+ // We can't use $(element).attr( attr ) because we have to check for boolean attributes:
+ if ( element.getAttribute( attr ) != null ) {
+ // boolean attributes
+ if( element.getAttribute( attr ) == '' ){
+ this[ attr ] = true;
+ } else {
+ this[ attr ] = element.getAttribute( attr );
+ }
+ } else {
+ this[attr] = playerAttributes[attr];
+ }
+ // string -> boolean
+ if( this[ attr ] == "false" ) this[attr] = false;
+ if( this[ attr ] == "true" ) this[attr] = true;
+ }
+
+ // Hide "controls" if using native player controls:
+ if( this.useNativePlayerControls() ){
+ _this.controls = true;
+ }
+ // Set the skin name from the class
+ var sn = $(element).attr( 'class' );
+
+ if ( sn && sn != '' ) {
+ var skinList = mw.config.get('EmbedPlayer.SkinList');
+ for ( var n = 0; n < skinList.length; n++ ) {
+ if ( sn.indexOf( skinList[n].toLowerCase() ) !== -1 ) {
+ this.skinName = skinList[ n ];
+ }
+ }
+ }
+ // Set the default skin if unset:
+ if ( !this.skinName ) {
+ this.skinName = mw.config.get( 'EmbedPlayer.DefaultSkin' );
+ }
+
+ // Support custom monitorRate Attribute ( if not use default )
+ if( !this.monitorRate ){
+ this.monitorRate = mw.config.get( 'EmbedPlayer.MonitorRate' );
+ }
+
+ // Make sure startOffset is cast as an float:
+ if ( this.startOffset && this.startOffset.split( ':' ).length >= 2 ) {
+ this.startOffset = parseFloat( mw.npt2seconds( this.startOffset ) );
+ }
+
+ // Make sure offset is in float:
+ this.startOffset = parseFloat( this.startOffset );
+
+ // Set the source duration
+ if ( $( element ).attr( 'duration' ) ) {
+ _this.duration = $( element ).attr( 'duration' );
+ }
+ // Add durationHint property form data-durationhint:
+ if( _this['data-durationhint']){
+ _this.durationHint = _this['data-durationhint'];
+ }
+ // Update duration from provided durationHint
+ if ( _this.durationHint && ! _this.duration){
+ _this.duration = mw.npt2seconds( _this.durationHint );
+ }
+
+ // Make sure duration is a float:
+ this.duration = parseFloat( this.duration );
+ mw.log( 'EmbedPlayer::init:' + this.id + " duration is: " + this.duration );
+
+ // Add disablecontrols property form data-disablecontrols:
+ if( _this['data-disablecontrols'] ){
+ _this.disablecontrols = _this['data-disablecontrols'];
+ }
+
+ // Set the playerElementId id
+ this.pid = 'pid_' + this.id;
+
+ // Add the mediaElement object with the elements sources:
+ this.mediaElement = new mw.MediaElement( element );
+
+ this.bindHelper( 'updateLayout', function() {
+ _this.updateLayout();
+ });
+ },
+ /**
+ * Bind helpers to help iOS retain bind context
+ *
+ * Yes, iOS will fail when you run $( embedPlayer ).bind()
+ * but "work" when you run embedPlayer.bind() if the script urls are from diffrent "resources"
+ */
+ bindHelper: function( name, callback ){
+ $( this ).bind( name, callback );
+ return this;
+ },
+ unbindHelper: function( bindName ){
+ if( bindName ) {
+ $( this ).unbind( bindName );
+ }
+ return this;
+ },
+ triggerQueueCallback: function( name, callback ){
+ $( this ).triggerQueueCallback( name, callback );
+ },
+ triggerHelper: function( name, obj ){
+ try{
+ $( this ).trigger( name, obj );
+ } catch( e ){
+ // ignore try catch calls
+ // mw.log( "EmbedPlayer:: possible error in trgger: " + name + " " + e.toString() );
+ }
+ },
+ /**
+ * Stop events from Propagation and blocks interface updates and trigger events.
+ * @return
+ */
+ stopEventPropagation: function(){
+ mw.log("EmbedPlayer:: stopEventPropagation");
+ this.stopMonitor();
+ this._propagateEvents = false;
+ },
+
+ /**
+ * Restores event propagation
+ * @return
+ */
+ restoreEventPropagation: function(){
+ mw.log("EmbedPlayer:: restoreEventPropagation");
+ this._propagateEvents = true;
+ this.startMonitor();
+ },
+
+ /**
+ * Enables the play controls ( for example when an ad is done )
+ */
+ enablePlayControls: function(){
+ mw.log("EmbedPlayer:: enablePlayControls" );
+ if( this.useNativePlayerControls() ){
+ return ;
+ }
+ this._playContorls = true;
+ // re-enable hover:
+ this.getInterface().find( '.play-btn' )
+ .buttonHover()
+ .css('cursor', 'pointer' );
+
+ this.controlBuilder.enableSeekBar();
+ /*
+ * We should pass an array with enabled components, and the controlBuilder will listen
+ * to this event and handle the layout changes. we should not call to this.controlBuilder inside embedPlayer.
+ * [ 'playButton', 'seekBar' ]
+ */
+ $( this ).trigger( 'onEnableInterfaceComponents');
+ },
+
+ /**
+ * Disables play controls, for example when an ad is playing back
+ */
+ disablePlayControls: function(){
+ if( this.useNativePlayerControls() ){
+ return ;
+ }
+ this._playContorls = false;
+ // turn off hover:
+ this.getInterface().find( '.play-btn' )
+ .unbind('mouseenter mouseleave')
+ .css('cursor', 'default' );
+
+ this.controlBuilder.disableSeekBar();
+ /**
+ * We should pass an array with disabled components, and the controlBuilder will listen
+ * to this event and handle the layout changes. we should not call to this.controlBuilder inside embedPlayer.
+ * [ 'playButton', 'seekBar' ]
+ */
+ $( this ).trigger( 'onDisableInterfaceComponents');
+ },
+
+ /**
+ * For plugin-players to update supported features
+ */
+ updateFeatureSupport: function(){
+ $( this ).trigger('updateFeatureSupportEvent', this.supports );
+ return ;
+ },
+ /**
+ * Apply Intrinsic Aspect ratio of a given image to a poster image layout
+ */
+ applyIntrinsicAspect: function(){
+ var $this = $( this );
+ // Check if a image thumbnail is present:
+ if( this.getInterface().find('.playerPoster').length ){
+ var img = this.getInterface().find('.playerPoster')[0];
+ var pHeight = $this.height();
+ // Check for intrinsic width and maintain aspect ratio
+ if( img.naturalWidth && img.naturalHeight ){
+ var pWidth = parseInt( img.naturalWidth / img.naturalHeight * pHeight);
+ if( pWidth > $this.width() ){
+ pWidth = $this.width();
+ pHeight = parseInt( img.naturalHeight / img.naturalWidth * pWidth );
+ }
+ $( img ).css({
+ 'height' : pHeight + 'px',
+ 'width': pWidth + 'px',
+ 'left': ( ( $this.width() - pWidth ) * .5 ) + 'px',
+ 'top': ( ( $this.height() - pHeight ) * .5 ) + 'px',
+ 'position' : 'absolute'
+ });
+ }
+ }
+ },
+ /**
+ * Set the width & height from css style attribute, element attribute, or by
+ * default value if no css or attribute is provided set a callback to
+ * resize.
+ *
+ * Updates this.width & this.height
+ *
+ * @param {Element}
+ * element Source element to grab size from
+ */
+ loadPlayerSize: function( element ) {
+ // check for direct element attribute:
+ this.height = element.height > 0 ? element.height + '' : $(element).css( 'height' );
+ this.width = element.width > 0 ? element.width + '' : $(element).css( 'width' );
+
+ // Special check for chrome 100% with re-mapping to 32px
+ // Video embed at 32x32 will have to wait for intrinsic video size later on
+ if( this.height == '32px' || this.height =='32px' ){
+ this.width = '100%';
+ this.height = '100%';
+ }
+ mw.log('EmbedPlayer::loadPlayerSize: css size:' + this.width + ' h: ' + this.height);
+
+ // Set to parent size ( resize events will cause player size updates)
+ if( this.height.indexOf('100%') != -1 || this.width.indexOf('100%') != -1 ){
+ var $relativeParent = $(element).parents().filter(function() {
+ // reduce to only relative position or "body" elements
+ return $( this ).is('body') || $( this ).css('position') == 'relative';
+ }).slice(0,1); // grab only the "first"
+ this.width = $relativeParent.width();
+ this.height = $relativeParent.height();
+ }
+ // Make sure height and width are a number
+ this.height = parseInt( this.height );
+ this.width = parseInt( this.width );
+
+ // Set via attribute if CSS is zero or NaN and we have an attribute value:
+ this.height = ( this.height==0 || isNaN( this.height )
+ && $(element).attr( 'height' ) ) ?
+ parseInt( $(element).attr( 'height' ) ): this.height;
+ this.width = ( this.width == 0 || isNaN( this.width )
+ && $(element).attr( 'width' ) )?
+ parseInt( $(element).attr( 'width' ) ): this.width;
+
+
+ // Special case for audio
+
+ // Firefox sets audio height to "0px" while webkit uses 32px .. force zero:
+ if( this.isAudio() && this.height == '32' ) {
+ this.height = 20;
+ }
+
+ // Use default aspect ration to get height or width ( if rewriting a non-audio player )
+ if( this.isAudio() && this.videoAspect ) {
+ var aspect = this.videoAspect.split( ':' );
+ if( this.height && !this.width ) {
+ this.width = parseInt( this.height * ( aspect[0] / aspect[1] ) );
+ }
+ if( this.width && !this.height ) {
+ var apectRatio = ( aspect[1] / aspect[0] );
+ this.height = parseInt( this.width * ( aspect[1] / aspect[0] ) );
+ }
+ }
+
+ // On load sometimes attr is temporally -1 as we don't have video metadata yet.
+ // or in IE we get NaN for width height
+ //
+ // NOTE: browsers that do support height width should set "waitForMeta" flag in addElement
+ if( ( isNaN( this.height )|| isNaN( this.width ) ) ||
+ ( this.height == -1 || this.width == -1 ) ||
+ // Check for firefox defaults
+ // Note: ideally firefox would not do random guesses at css
+ // values
+ ( (this.height == 150 || this.height == 64 ) && this.width == 300 )
+ ) {
+ var defaultSize = mw.config.get( 'EmbedPlayer.DefaultSize' ).split( 'x' );
+ if( isNaN( this.width ) ){
+ this.width = defaultSize[0];
+ }
+
+ // Special height default for audio tag ( if not set )
+ if( this.isAudio() ) {
+ this.height = 20;
+ }else{
+ this.height = defaultSize[1];
+ }
+ }
+ },
+
+ /**
+ * Get the player pixel width not including controls
+ *
+ * @return {Number} pixel height of the video
+ */
+ getPlayerWidth: function() {
+ var profile = $.client.profile();
+
+ if ( profile.name === 'firefox' && profile.versionNumber < 2 ) {
+ return ( $( this ).parent().parent().width() );
+ }
+ return $( this ).width();
+ },
+
+ /**
+ * Get the player pixel height not including controls
+ *
+ * @return {Number} pixel height of the video
+ */
+ getPlayerHeight: function() {
+ return $( this ).height();
+ },
+
+ /**
+ * Check player for sources. If we need to get media sources form an
+ * external file that request is issued here
+ */
+ checkPlayerSources: function() {
+ mw.log( 'EmbedPlayer::checkPlayerSources: ' + this.id );
+ var _this = this;
+ // Allow plugins to listen to a preCheckPlayerSources ( for registering the source loading point )
+ $( _this ).trigger( 'preCheckPlayerSources' );
+
+ // Allow plugins to block on sources lookup ( cases where we just have an api key for example )
+ $( _this ).triggerQueueCallback( 'checkPlayerSourcesEvent', function(){
+ _this.setupSourcePlayer();
+ });
+ },
+
+ /**
+ * Get text tracks from the mediaElement
+ */
+ getTextTracks: function(){
+ if( !this.mediaElement ){
+ return [];
+ }
+ return this.mediaElement.getTextTracks();
+ },
+ /**
+ * Empty the player sources
+ */
+ emptySources: function(){
+ if( this.mediaElement ){
+ this.mediaElement.sources = [];
+ this.mediaElement.selectedSource = null;
+ }
+ // setup pointer to old source:
+ this.prevPlayer = this.selectedPlayer;
+ // don't null out the selected player on empty sources
+ //this.selectedPlayer =null;
+ },
+
+ /**
+ * Switch and play a video source
+ *
+ * Checks if the target source is the same playback mode and does player switch if needed.
+ * and calls playerSwitchSource
+ */
+ switchPlaySource: function( source, switchCallback, doneCallback ){
+ var _this = this;
+ var targetPlayer = mw.EmbedTypes.getMediaPlayers().defaultPlayer( source.mimeType ) ;
+ if( targetPlayer.library != this.selectedPlayer.library ){
+ this.selectedPlayer = targetPlayer;
+ this.updatePlaybackInterface( function(){
+ _this.playerSwitchSource( source, switchCallback, doneCallback );
+ });
+ } else {
+ // Call the player switch directly:
+ _this.playerSwitchSource( source, switchCallback, doneCallback );
+ }
+ },
+ /**
+ * abstract function player interface must support actual source switch
+ */
+ playerSwitchSource: function( source, switchCallback, doneCallback ){
+ mw.log( "Error player interface must support actual source switch");
+ },
+
+ /**
+ * Set up the select source player
+ *
+ * issues autoSelectSource call
+ *
+ * Sets load error if no source is playable
+ */
+ setupSourcePlayer: function() {
+ var _this = this;
+ mw.log("EmbedPlayer::setupSourcePlayer: " + this.id + ' sources: ' + this.mediaElement.sources.length );
+
+ // Check for source replace configuration:
+ if( mw.config.get('EmbedPlayer.ReplaceSources' ) ){
+ this.emptySources();
+ $.each( mw.config.get('EmbedPlayer.ReplaceSources' ), function( inx, source ){
+ _this.mediaElement.tryAddSource( source );
+ });
+ }
+
+ // Autoseletct the media source
+ this.mediaElement.autoSelectSource();
+
+ // Auto select player based on default order
+ if( this.mediaElement.selectedSource ){
+ this.selectedPlayer = mw.EmbedTypes.getMediaPlayers().defaultPlayer( this.mediaElement.selectedSource.mimeType );
+ // Check if we need to switch player rendering libraries:
+ if ( this.selectedPlayer && ( !this.prevPlayer || this.prevPlayer.library != this.selectedPlayer.library ) ) {
+ // Inherit the playback system of the selected player:
+ this.updatePlaybackInterface();
+ return ;
+ }
+ }
+
+ // Check if no player is selected
+ if( !this.selectedPlayer || !this.mediaElement.selectedSource ){
+ this.showPlayerError();
+ mw.log( "EmbedPlayer:: setupSourcePlayer > player ready ( but with errors ) ");
+ } else {
+ // Trigger layout ready event
+ $( this ).trigger( 'layoutReady' );
+ // Show the interface:
+ this.getInterface().find( '.control-bar').show();
+ this.addLargePlayBtn();
+ }
+ // We still do the playerReady sequence on errors to provide an api
+ // and player error events
+ this.playerReadyFlag = true;
+ // trigger the player ready event;
+ $( this ).trigger( 'playerReady' );
+ this.triggerWidgetLoaded();
+ },
+
+ /**
+ * Updates the player interface
+ *
+ * Loads and inherit methods from the selected player interface.
+ *
+ * @param {Function}
+ * callback Function to be called once playback-system has been
+ * inherited
+ */
+ updatePlaybackInterface: function( callback ) {
+ var _this = this;
+ mw.log( "EmbedPlayer::updatePlaybackInterface: duration is: " + this.getDuration() + ' playerId: ' + this.id );
+ // Clear out any non-base embedObj methods:
+ if ( this.instanceOf ) {
+ // Update the prev instance var used for swiching interfaces to know the previous instance.
+ $( this ).data( 'previousInstanceOf', this.instanceOf );
+ var tmpObj = window['mw.EmbedPlayer' + this.instanceOf ];
+ for ( var i in tmpObj ) {
+ // Restore parent into local location
+ if ( typeof this[ 'parent_' + i ] != 'undefined' ) {
+ this[i] = this[ 'parent_' + i];
+ } else {
+ this[i] = null;
+ }
+ }
+ }
+ // Set up the new embedObj
+ mw.log( 'EmbedPlayer::updatePlaybackInterface: embedding with ' + this.selectedPlayer.library );
+ this.selectedPlayer.load( function() {
+ _this.updateLoadedPlayerInterface( callback );
+ });
+ },
+ /**
+ * Update a loaded player interface by setting local methods to the
+ * updated player prototype methods
+ *
+ * @parma {function}
+ * callback function called once player has been loaded
+ */
+ updateLoadedPlayerInterface: function( callback ){
+ var _this = this;
+ mw.log( 'EmbedPlayer::updateLoadedPlayerInterface ' + _this.selectedPlayer.library + " player loaded for " + _this.id );
+
+ // Get embed library player Interface
+ var playerInterface = mw[ 'EmbedPlayer' + _this.selectedPlayer.library ];
+
+ // Build the player interface ( if the interface includes an init )
+ if( playerInterface.init ){
+ playerInterface.init();
+ }
+
+ for ( var method in playerInterface ) {
+ if ( typeof _this[method] != 'undefined' && !_this['parent_' + method] ) {
+ _this['parent_' + method] = _this[method];
+ }
+ _this[ method ] = playerInterface[ method ];
+ }
+ // Update feature support
+ _this.updateFeatureSupport();
+ // Update duration
+ _this.getDuration();
+ // show player inline
+ _this.showPlayer();
+ // Run the callback if provided
+ if ( callback && $.isFunction( callback ) ){
+ callback();
+ }
+ },
+
+ /**
+ * Select a player playback system
+ *
+ * @param {Object}
+ * player Player playback system to be selected player playback
+ * system include vlc, native, java etc.
+ */
+ selectPlayer: function( player ) {
+ mw.log("EmbedPlayer:: selectPlayer " + player.id );
+ var _this = this;
+ if ( this.selectedPlayer.id != player.id ) {
+ this.selectedPlayer = player;
+ this.updatePlaybackInterface( function(){
+ // Hide / remove track container
+ _this.getInterface().find( '.track' ).remove();
+ // We have to re-bind hoverIntent ( has to happen in this scope )
+ if( !_this.useNativePlayerControls() && _this.controls && _this.controlBuilder.isOverlayControls() ){
+ _this.controlBuilder.showControlBar();
+ _this.getInterface().hoverIntent({
+ 'sensitivity': 4,
+ 'timeout' : 2000,
+ 'over' : function(){
+ _this.controlBuilder.showControlBar();
+ },
+ 'out' : function(){
+ _this.controlBuilder.hideControlBar();
+ }
+ });
+ }
+ });
+ }
+ },
+
+ /**
+ * Get a time range from the media start and end time
+ *
+ * @return startNpt and endNpt time if present
+ */
+ getTimeRange: function() {
+ var end_time = ( this.controlBuilder.longTimeDisp )? '/' + mw.seconds2npt( this.getDuration() ) : '';
+ var defaultTimeRange = '0:00' + end_time;
+ if ( !this.mediaElement ){
+ return defaultTimeRange;
+ }
+ if ( !this.mediaElement.selectedSource ){
+ return defaultTimeRange;
+ }
+ if ( !this.mediaElement.selectedSource.endNpt ){
+ return defaultTimeRange;
+ }
+ return this.mediaElement.selectedSource.startNpt + this.mediaElement.selectedSource.endNpt;
+ },
+
+ /**
+ * Get the duration of the embed player
+ */
+ getDuration: function() {
+ if ( isNaN(this.duration) && this.mediaElement && this.mediaElement.selectedSource &&
+ typeof this.mediaElement.selectedSource.durationHint != 'undefined' ){
+ this.duration = this.mediaElement.selectedSource.durationHint;
+ }
+ return this.duration;
+ },
+
+ /**
+ * Get the player height
+ */
+ getHeight: function() {
+ return this.getInterface().height();
+ },
+
+ /**
+ * Get the player width
+ */
+ getWidth: function(){
+ return this.getInterface().width();
+ },
+
+ /**
+ * Check if the selected source is an audio element:
+ */
+ isAudio: function(){
+ return ( this.rewriteElementTagName == 'audio'
+ ||
+ ( this.mediaElement && this.mediaElement.selectedSource && this.mediaElement.selectedSource.mimeType.indexOf('audio/') !== -1 )
+ );
+ },
+
+ /**
+ * Get the plugin embed html ( should be implemented by embed player interface )
+ */
+ embedPlayerHTML: function() {
+ return 'Error: function embedPlayerHTML should be implemented by embed player interface ';
+ },
+
+ /**
+ * Seek function ( should be implemented by embedPlayer interface
+ * playerNative, playerKplayer etc. ) embedPlayer seek only handles URL
+ * time seeks
+ * @param {Float}
+ * percent of the video total length to seek to
+ */
+ seek: function( percent ) {
+ var _this = this;
+ this.seeking = true;
+ // Trigger preSeek event for plugins that want to store pre seek conditions.
+ $( this ).trigger( 'preSeek', percent );
+
+ // Do argument checking:
+ if( percent < 0 ){
+ percent = 0;
+ }
+
+ if( percent > 1 ){
+ percent = 1;
+ }
+ // set the playhead to the target position
+ this.updatePlayHead( percent );
+
+ // See if we should do a server side seek ( player independent )
+ if ( this.supportsURLTimeEncoding() ) {
+ mw.log( 'EmbedPlayer::seek:: updated serverSeekTime: ' + mw.seconds2npt ( this.serverSeekTime ) +
+ ' currentTime: ' + _this.currentTime );
+ // make sure we need to seek:
+ if( _this.currentTime == _this.serverSeekTime ){
+ return ;
+ }
+
+ this.stop();
+ this.didSeekJump = true;
+ // Make sure this.serverSeekTime is up-to-date:
+ this.serverSeekTime = mw.npt2seconds( this.startNpt ) + parseFloat( percent * this.getDuration() );
+ }
+ // Run the onSeeking interface update
+ // NOTE controlBuilder should really bind to html5 events rather
+ // than explicitly calling it or inheriting stuff.
+ this.controlBuilder.onSeek();
+ },
+
+ /**
+ * Seeks to the requested time and issues a callback when ready (should be
+ * overwritten by client that supports frame serving)
+ */
+ setCurrentTime: function( time, callback ) {
+ mw.log( 'Error: EmbedPlayer, setCurrentTime not overriden' );
+ if( $.isFunction( callback ) ){
+ callback();
+ }
+ },
+
+ /**
+ * On clip done action. Called once a clip is done playing
+ * TODO clean up end sequence flow
+ */
+ triggeredEndDone: false,
+ postSequence: false,
+ onClipDone: function() {
+ var _this = this;
+ // Don't run onclipdone if _propagateEvents is off
+ if( !_this._propagateEvents ){
+ return ;
+ }
+ mw.log( 'EmbedPlayer::onClipDone: propagate:' + _this._propagateEvents + ' id:' + this.id + ' doneCount:' + this.donePlayingCount + ' stop state:' +this.isStopped() );
+ // Only run stopped once:
+ if( !this.isStopped() ){
+ // set the "stopped" flag:
+ this.stopped = true;
+
+ // Show the control bar:
+ this.controlBuilder.showControlBar();
+
+ // TOOD we should improve the end event flow
+ // First end event for ads or current clip ended bindings
+ if( ! this.onDoneInterfaceFlag ){
+ this.stopEventPropagation();
+ }
+
+ mw.log("EmbedPlayer:: trigger: ended ( inteface continue pre-check: " + this.onDoneInterfaceFlag + ' )' );
+ $( this ).trigger( 'ended' );
+ mw.log("EmbedPlayer::onClipDone:Trigged ended, continue? " + this.onDoneInterfaceFlag);
+
+
+ if( ! this.onDoneInterfaceFlag ){
+ // Restore events if we are not running the interface done actions
+ this.restoreEventPropagation();
+ return ;
+ }
+
+ // A secondary end event for playlist and clip sequence endings
+ if( this.onDoneInterfaceFlag ){
+ // We trigger two end events to match KDP and ensure playbackComplete always comes before playerPlayEnd
+ // in content ends.
+ mw.log("EmbedPlayer:: trigger: playbackComplete");
+ $( this ).trigger( 'playbackComplete' );
+ // now trigger postEnd for( playerPlayEnd )
+ mw.log("EmbedPlayer:: trigger: postEnded");
+ $( this ).trigger( 'postEnded' );
+ }
+ // if the ended event did not trigger more timeline actions run the actual stop:
+ if( this.onDoneInterfaceFlag ){
+ mw.log("EmbedPlayer::onDoneInterfaceFlag=true do interface done");
+ // Prevent the native "onPlay" event from propagating that happens when we rewind:
+ this.stopEventPropagation();
+
+ // Update the clip done playing count ( for keeping track of replays )
+ _this.donePlayingCount ++;
+
+ // Rewind the player to the start:
+ // NOTE: Setting to 0 causes lags on iPad when replaying, thus setting to 0.01
+ this.setCurrentTime(0.01, function(){
+
+ // Set to stopped state:
+ _this.stop();
+
+ // Restore events after we rewind the player
+ _this.restoreEventPropagation();
+
+ // Check if we have the "loop" property set
+ if( _this.loop ) {
+ _this.stopped = false;
+ _this.play();
+ return;
+ } else {
+ // make sure we are in a paused state.
+ _this.pause();
+ }
+ // Check if have a force display of the large play button
+ if( mw.config.get('EmbedPlayer.ForceLargeReplayButton') === true ){
+ _this.addLargePlayBtn();
+ } else{
+ // Check if we should hide the large play button on end:
+ if( $( _this ).data( 'hideEndPlayButton' ) || !_this.useLargePlayBtn() ){
+ _this.hideLargePlayBtn();
+ } else {
+ _this.addLargePlayBtn();
+ }
+ }
+ // An event for once the all ended events are done.
+ mw.log("EmbedPlayer:: trigger: onEndedDone");
+ if ( !_this.triggeredEndDone ){
+ _this.triggeredEndDone = true;
+ $( _this ).trigger( 'onEndedDone', [_this.id] );
+ }
+ })
+ }
+ }
+ },
+
+
+ /**
+ * Shows the video Thumbnail, updates pause state
+ */
+ showThumbnail: function() {
+ var _this = this;
+ mw.log( 'EmbedPlayer::showThumbnail::' + this.stopped );
+
+ // Close Menu Overlay:
+ this.controlBuilder.closeMenuOverlay();
+
+ // update the thumbnail html:
+ this.updatePosterHTML();
+
+ this.paused = true;
+ this.stopped = true;
+
+ // Once the thumbnail is shown run the mediaReady trigger (if not using native controls)
+ if( !this.useNativePlayerControls() ){
+ mw.log("mediaLoaded");
+ $( this ).trigger( 'mediaLoaded' );
+ }
+ },
+
+ /**
+ * Show the player
+ */
+ showPlayer: function () {
+ mw.log( 'EmbedPlayer:: showPlayer: ' + this.id + ' interface: w:' + this.width + ' h:' + this.height );
+ var _this = this;
+
+ // Remove the player loader spinner if it exists
+ this.hideSpinnerAndPlayBtn();
+ // If a isPersistentNativePlayer ( overlay the controls )
+ if( !this.useNativePlayerControls() && this.isPersistentNativePlayer() ){
+ $( this ).show();
+ }
+ // Add controls if enabled:
+ if ( this.controls ) {
+ if( this.useNativePlayerControls() ){
+ if( this.getPlayerElement() ){
+ $( this.getPlayerElement() ).attr('controls', "true");
+ }
+ } else {
+ this.controlBuilder.addControls();
+ }
+ }
+
+ // Update Thumbnail for the "player"
+ this.updatePosterHTML();
+
+ // Update temporal url if present
+ this.updateTemporalUrl();
+
+ // Do we need to show the player?
+ if( this.displayPlayer === false ) {
+ _this.getVideoHolder().hide();
+ _this.getInterface().height( _this.getComponentsHeight() );
+ _this.triggerHelper('updateLayout');
+ }
+
+ // Update layout
+ this.updateLayout();
+
+ // Make sure we have a play btn:
+ this.addLargePlayBtn();
+
+ // Update the playerReady flag
+ this.playerReadyFlag = true;
+ mw.log("EmbedPlayer:: Trigger: playerReady");
+ // trigger the player ready event;
+ $( this ).trigger( 'playerReady' );
+ this.triggerWidgetLoaded();
+
+ // Check if we want to block the player display
+ if( this['data-blockPlayerDisplay'] ){
+ this.blockPlayerDisplay();
+ return ;
+ }
+
+ // Check if there are any errors to be displayed:
+ if( this.getError() ){
+ this.showErrorMsg( this.getError() );
+ return ;
+ }
+ // Auto play stopped ( no playerReady has already started playback ) and if not on an iPad with iOS > 3
+ if ( this.isStopped() && this.autoplay && (!mw.isIOS() || mw.isIpad3() ) ) {
+ mw.log( 'EmbedPlayer::showPlayer::Do autoPlay' );
+ _this.play();
+ }
+ },
+
+ getComponentsHeight: function() {
+ var height = 0;
+
+ // Go over all playerContainer direct children with .block class
+ this.getInterface().find('.block').each(function() {
+ height += $( this ).outerHeight( true );
+ });
+
+ // FIXME embedPlayer should know nothing about playlist layout
+ /* If we're in vertical playlist mode, and not in fullscreen add playlist height
+ if( $('#container').hasClass('vertical') && ! this.controlBuilder.isInFullScreen() && this.displayPlayer ) {
+ height += $('#playlistContainer').outerHeight( true );
+ }
+ */
+
+ //
+ var offset = (mw.isIOS()) ? 5 : 0;
+
+ return height + offset;
+ },
+ updateLayout: function() {
+ // update image layout:
+ this.applyIntrinsicAspect();
+ if( !mw.config.get('EmbedPlayer.IsIframeServer' ) ){
+ // Use intrensic container size
+ return ;
+ }
+ // Set window height if in iframe:
+ var windowHeight;
+ if( mw.isIOS() && ! this.controlBuilder.isInFullScreen() ) {
+ windowHeight = $( window.parent.document.getElementById( this.id ) ).height();
+ } else {
+ windowHeight = window.innerHeight;
+ }
+
+ var newHeight = windowHeight - this.getComponentsHeight();
+ var currentHeight = this.getVideoHolder().height();
+ // Always update videoHolder height
+ if( currentHeight !== newHeight ) {
+ mw.log('EmbedPlayer: updateLayout:: window: ' + windowHeight + ', components: ' + this.getComponentsHeight() + ', videoHolder old height: ' + currentHeight + ', new height: ' + newHeight );
+ this.getVideoHolder().height( newHeight );
+ }
+ },
+ /**
+ * Gets a refrence to the main player interface, builds if not avaliable
+ */
+ getInterface: function(){
+ if( !this.$interface ){
+ // init the control builder
+ this.controlBuilder = new mw.PlayerControlBuilder( this );
+
+ // build the interface wrapper
+ this.$interface = $( this ).wrap(
+ $('<div />')
+ .addClass( 'mwPlayerContainer ' + this.controlBuilder.playerClass )
+ .append(
+ $('<div />').addClass( 'videoHolder' )
+ )
+ ).parent().parent();
+
+ // pass along any inhereted style:
+ if( this.style.cssText ){
+ this.$interface[0].style.cssText = this.style.cssText;
+ }
+ // clear out base style
+ this.style.cssText = '';
+
+ // if not displayiung a play button, ( pass through to native player )
+ if( ! this.useLargePlayBtn() ){
+ this.$interface.css('pointer-events', 'none');
+ }
+ }
+ return this.$interface;
+ },
+
+ /**
+ * Media fragments handler based on:
+ * http://www.w3.org/2008/WebVideo/Fragments/WD-media-fragments-spec/#fragment-dimensions
+ *
+ * We support seconds and npt ( normal play time )
+ *
+ * Updates the player per fragment url info if present
+ *
+ */
+ updateTemporalUrl: function(){
+ var sourceHash = /[^\#]+$/.exec( this.getSrc() ).toString();
+ if( sourceHash.indexOf('t=') === 0 ){
+ // parse the times
+ var times = sourceHash.substr(2).split(',');
+ if( times[0] ){
+ // update the current time
+ this.currentTime = mw.npt2seconds( times[0].toString() );
+ }
+ if( times[1] ){
+ this.pauseTime = mw.npt2seconds( times[1].toString() );
+ // ignore invalid ranges:
+ if( this.pauseTime < this.currentTime ){
+ this.pauseTime = null;
+ }
+ }
+ // Update the play head
+ this.updatePlayHead( this.currentTime / this.duration );
+ // Update status:
+ this.controlBuilder.setStatus( mw.seconds2npt( this.currentTime ) );
+ }
+ },
+ /**
+ * Sets an error message on the player
+ *
+ * @param {string}
+ * errorMsg
+ */
+ setError: function( errorObj ){
+ var _this = this;
+ if ( typeof errorObj == 'string' ) {
+ this.playerError = {
+ 'title' : _this.getKalturaMsg( 'ks-GENERIC_ERROR_TITLE' ),
+ 'message' : errorObj
+ }
+ return ;
+
+ }
+ this.playerError = errorObj;
+ },
+ /**
+ * Gets the current player error
+ */
+ getError: function() {
+ if ( !$.isEmptyObject( this.playerError ) ) {
+ return this.playerError;
+ }
+ return null;
+ },
+
+ /**
+ * Show an error message on the player
+ *
+ * @param {object}
+ * errorObj
+ */
+ showErrorMsg: function( errorObj ){
+ // Remove a loading spinner
+ this.hideSpinnerAndPlayBtn();
+ if( this.controlBuilder ) {
+ if( mw.config.get("EmbedPlayer.ShowPlayerAlerts") ) {
+ var alertObj = $.extend( errorObj, {
+ 'isModal': true,
+ 'keepOverlay': true,
+ 'noButtons': true,
+ 'isError': true
+ } );
+ this.controlBuilder.displayAlert( alertObj );
+ }
+ }
+ return ;
+ },
+
+ /**
+ * Blocks the player display by invoking an empty error msg
+ */
+ blockPlayerDisplay: function(){
+ this.showErrorMsg();
+ this.getInterface().find( '.error' ).hide();
+ },
+
+ /**
+ * Get missing plugin html (check for user included code)
+ *
+ * @param {String}
+ * [misssingType] missing type mime
+ */
+ showPlayerError: function( ) {
+ var _this = this;
+ var $this = $( this );
+ mw.log("EmbedPlayer::showPlayerError");
+ // Hide loader
+ this.hideSpinnerAndPlayBtn();
+
+ // Error in loading media ( trigger the mediaLoadError )
+ $this.trigger( 'mediaLoadError' );
+
+ // We don't distiguish between mediaError and mediaLoadError right now
+ // TODO fire mediaError only on failed to recive audio/video data.
+ $this.trigger( 'mediaError' );
+
+ // Check if we want to block the player display ( no error displayed )
+ if( this['data-blockPlayerDisplay'] ){
+ this.blockPlayerDisplay();
+ return ;
+ }
+
+ // Check if there is a more specific error:
+ if( this.getError() ){
+ this.showErrorMsg( this.getError() );
+ return ;
+ }
+
+ // If no error is given assume missing sources:
+ this.showNoInlinePlabackSupport();
+ },
+
+ /**
+ * Show player missing sources method
+ */
+ showNoInlinePlabackSupport: function(){
+ var _this = this;
+ var $this = $( this);
+
+ // Check if any sources are avaliable:
+ if( this.mediaElement.sources.length == 0
+ ||
+ !mw.config.get('EmbedPlayer.NotPlayableDownloadLink') )
+ {
+ return ;
+ }
+ // Set the isLink player flag:
+ this.isLinkPlayer= true;
+ // Update the poster and html:
+ this.updatePosterHTML();
+
+ // Make sure we have a play btn:
+ this.addLargePlayBtn();
+
+ // By default set the direct download url to the first source.
+ var downloadUrl = this.mediaElement.sources[0].getSrc();
+ // Allow plugins to update the download url ( to point to server side tools to select
+ // stream based on user agent ( i.e IE8 h.264 file, blackberry 3gp file etc )
+ this.triggerHelper( 'directDownloadLink', function( dlUrl ){
+ if( dlUrl ){
+ downloadUrl = dlUrl;
+ }
+ });
+ // Set the play button to the first available source:
+ var $pBtn = this.getInterface().find('.play-btn-large')
+ .attr( 'title', mw.msg('mwe-embedplayer-play_clip') )
+ .show()
+ .unbind( 'click' )
+ .click( function() {
+ _this.triggerHelper( 'firstPlay', [ _this.id ] ); // To send stats event for play
+ _this.triggerHelper( 'playing' );
+ return true;
+ });
+ if( !$pBtn.parent('a').length ){
+ $pBtn.wrap( $( '<a />' ).attr("target", "_blank" ) );
+ }
+ $pBtn.parent('a').attr( "href", downloadUrl );
+
+ $( this ).trigger( 'showInlineDownloadLink' );
+ },
+ /**
+ * Update the video time request via a time request string
+ *
+ * @param {String}
+ * timeRequest video time to be updated
+ */
+ updateVideoTimeReq: function( timeRequest ) {
+ mw.log( 'EmbedPlayer::updateVideoTimeReq:' + timeRequest );
+ var timeParts = timeRequest.split( '/' );
+ this.updateVideoTime( timeParts[0], timeParts[1] );
+ },
+
+ /**
+ * Update Video time from provided startNpt and endNpt values
+ *
+ * @param {String}
+ * startNpt the new start time in npt format ( hh:mm:ss.ms )
+ * @param {String}
+ * endNpt the new end time in npt format ( hh:mm:ss.ms )
+ */
+ updateVideoTime: function( startNpt, endNpt ) {
+ // update media
+ this.mediaElement.updateSourceTimes( startNpt, endNpt );
+
+ // update time
+ this.controlBuilder.setStatus( startNpt + '/' + endNpt );
+
+ // reset slider
+ this.updatePlayHead( 0 );
+
+ // Reset the serverSeekTime if urlTimeEncoding is enabled
+ if ( this.supportsURLTimeEncoding() ) {
+ this.serverSeekTime = 0;
+ } else {
+ this.serverSeekTime = mw.npt2seconds( startNpt );
+ }
+ },
+
+
+ /**
+ * Update Thumb time with npt formated time
+ *
+ * @param {String}
+ * time NPT formated time to update thumbnail
+ */
+ updateThumbTimeNPT: function( time ) {
+ this.updateThumbTime( mw.npt2seconds( time ) - parseInt( this.startOffset ) );
+ },
+
+ /**
+ * Update the thumb with a new time
+ *
+ * @param {Float}
+ * floatSeconds Time to update the thumb to
+ */
+ updateThumbTime:function( floatSeconds ) {
+ // mw.log('updateThumbTime:'+floatSeconds);
+ var _this = this;
+ if ( typeof this.orgThumSrc == 'undefined' ) {
+ this.orgThumSrc = this.poster;
+ }
+ if ( this.orgThumSrc.indexOf( 't=' ) !== -1 ) {
+ this.lastThumbUrl = mw.replaceUrlParams( this.orgThumSrc,
+ {
+ 't' : mw.seconds2npt( floatSeconds + parseInt( this.startOffset ) )
+ }
+ );
+ if ( !this.thumbnailUpdatingFlag ) {
+ this.updatePoster( this.lastThumbUrl , false );
+ this.lastThumbUrl = null;
+ }
+ }
+ },
+
+ /**
+ * Updates the displayed thumbnail via percent of the stream
+ *
+ * @param {Float}
+ * percent Percent of duration to update thumb
+ */
+ updateThumbPerc:function( percent ) {
+ return this.updateThumbTime( ( this.getDuration() * percent ) );
+ },
+
+ /**
+ * Update the poster source
+ * @param {String}
+ * posterSrc Poster src url
+ */
+ updatePosterSrc: function( posterSrc ){
+ if( ! posterSrc ) {
+ posterSrc = mw.config.get( 'EmbedPlayer.BlackPixel' );
+ }
+ this.poster = posterSrc;
+ this.updatePosterHTML();
+ this.applyIntrinsicAspect();
+ },
+
+ /**
+ * Called after sources are updated, and your ready for the player to change media
+ * @return
+ */
+ changeMedia: function( callback ){
+ var _this = this;
+ var $this = $( this );
+ mw.log( 'EmbedPlayer:: changeMedia ');
+ // Empty out embedPlayer object sources
+ this.emptySources();
+
+ // onChangeMedia triggered at the start of the change media commands
+ $this.trigger( 'onChangeMedia' );
+
+ // Reset first play to true, to count that play event
+ this.firstPlay = true;
+ // reset donePlaying count on change media.
+ this.donePlayingCount = 0;
+ this.triggeredEndDone = false;
+ this.preSequence = false;
+ this.postSequence = false;
+
+ this.setCurrentTime( 0.01 );
+ // Reset the playhead
+ this.updatePlayHead( 0 );
+ // update the status:
+ this.controlBuilder.setStatus( this.getTimeRange() );
+
+ // Add a loader to the embed player:
+ this.pauseLoading();
+
+ // Clear out any player error ( both via attr and object property ):
+ this.setError( null );
+
+ // Clear out any player display blocks
+ this['data-blockPlayerDisplay'] = null
+ $this.attr( 'data-blockPlayerDisplay', '');
+
+ // Clear out the player error div:
+ this.getInterface().find('.error').remove();
+ this.controlBuilder.closeAlert();
+ this.controlBuilder.closeMenuOverlay();
+
+ // Restore the control bar:
+ this.getInterface().find('.control-bar').show();
+ // Hide the play btn
+ this.hideLargePlayBtn();
+
+ //If we are change playing media add a ready binding:
+ var bindName = 'playerReady.changeMedia';
+ $this.unbind( bindName ).bind( bindName, function(){
+ mw.log('EmbedPlayer::changeMedia playerReady callback');
+ // hide the loading spinner:
+ _this.hideSpinnerAndPlayBtn();
+ // check for an erro on change media:
+ if( _this.getError() ){
+ _this.showErrorMsg( _this.getError() );
+ return ;
+ }
+ // Always show the control bar on switch:
+ if( _this.controlBuilder ){
+ _this.controlBuilder.showControlBar();
+ }
+ // Make sure the play button reflects the original play state
+ if( _this.autoplay ){
+ _this.hideLargePlayBtn();
+ } else {
+ _this.addLargePlayBtn();
+ }
+ var source = _this.getSource();
+ if( (_this.isPersistentNativePlayer() || _this.useNativePlayerControls()) && source ){
+ // If switching a Persistent native player update the source:
+ // ( stop and play won't refresh the source )
+ _this.switchPlaySource( source, function(){
+ _this.changeMediaStarted = false;
+ $this.trigger( 'onChangeMediaDone' );
+ if( _this.autoplay ){
+ _this.play();
+ } else {
+ // pause is need to keep pause sate, while
+ // switch source calls .play() that some browsers require.
+ // to reflect source swiches.
+ _this.pause();
+ _this.addLargePlayBtn();
+ }
+ if( callback ){
+ callback()
+ }
+ });
+ // we are handling trigger and callback asynchronously return here.
+ return ;
+ }
+
+ // Reset changeMediaStarted flag
+ _this.changeMediaStarted = false;
+
+ // Stop should unload the native player
+ _this.stop();
+
+ // reload the player
+ if( _this.autoplay ){
+ _this.play();
+ } else {
+ _this.addLargePlayBtn();
+ }
+
+ $this.trigger( 'onChangeMediaDone' );
+ if( callback ) {
+ callback();
+ }
+ });
+
+ // Load new sources per the entry id via the checkPlayerSourcesEvent hook:
+ $this.triggerQueueCallback( 'checkPlayerSourcesEvent', function(){
+ // Start player events leading to playerReady
+ _this.setupSourcePlayer();
+ });
+ },
+ /**
+ * Checks if the current player / configuration is an image play screen:
+ */
+ isImagePlayScreen:function(){
+ return ( this.useNativePlayerControls() &&
+ !this.isLinkPlayer &&
+ mw.isIphone() &&
+ mw.config.get( 'EmbedPlayer.iPhoneShowHTMLPlayScreen')
+ );
+ },
+ /**
+ * Triggers widgetLoaded event - Needs to be triggered only once, at the first time playerReady is trigerred
+ */
+ triggerWidgetLoaded: function() {
+ if ( !this.widgetLoaded ) {
+ this.widgetLoaded = true;
+ mw.log( "EmbedPlayer:: Trigger: widgetLoaded");
+ this.triggerHelper( 'widgetLoaded' );
+ }
+ },
+
+ /**
+ * Updates the poster HTML
+ */
+ updatePosterHTML: function () {
+ mw.log( 'EmbedPlayer:updatePosterHTML::' + this.id );
+
+ var _this = this,
+ thumb_html = '',
+ class_atr = '',
+ style_atr = '',
+ profile = $.client.profile();
+
+ if( this.isImagePlayScreen() ){
+ this.addPlayScreenWithNativeOffScreen();
+ return ;
+ }
+
+ // Set by default thumb value if not found
+ var posterSrc = ( this.poster ) ? this.poster :
+ mw.config.get( 'EmbedPlayer.BlackPixel' );
+
+ // Update PersistentNativePlayer poster:
+ if( this.isPersistentNativePlayer() ){
+ var $vid = $( '#' + this.pid ).show();
+ $vid.attr( 'poster', posterSrc );
+ // Add a quick timeout hide / show ( firefox 4x bug with native poster updates )
+ if ( profile.name === 'firefox' ){
+ $vid.hide();
+ setTimeout( function () {
+ $vid.show();
+ }, 0);
+ }
+ } else {
+ // hide the pid if present:
+ $( '#' + this.pid ).hide();
+ // Poster support is not very consistent in browsers use a jpg poster image:
+ $( this )
+ .html(
+ $( '<img />' )
+ .css({
+ 'position': 'absolute',
+ 'top': 0,
+ 'left': 0,
+ 'right': 0,
+ 'bottom': 0
+ })
+ .attr({
+ 'src' : posterSrc
+ })
+ .addClass( 'playerPoster' )
+ .load(function(){
+ _this.applyIntrinsicAspect();
+ })
+ ).show();
+ }
+ if ( this.useLargePlayBtn() && this.controlBuilder
+ &&
+ this.height > this.controlBuilder.getComponentHeight( 'playButtonLarge' )
+ ) {
+ this.addLargePlayBtn();
+ }
+ },
+ /**
+ * Abstract method, must be set by player inteface
+ */
+ addPlayScreenWithNativeOffScreen: function(){
+ mw.log( "Error: EmbedPlayer, Must override 'addPlayScreenWithNativeOffScreen' with player inteface" );
+ return ;
+ },
+ /**
+ * Checks if a large play button should be displayed on the
+ * otherwise native player
+ */
+ useLargePlayBtn: function(){
+ if( this.isPersistantPlayBtn() ){
+ return true;
+ }
+ // If we are using native controls return false:
+ return !this.useNativePlayerControls();
+ },
+ /**
+ * Checks if the play button should stay on screen during playback,
+ * cases where a native player is dipalyed such as iPhone.
+ */
+ isPersistantPlayBtn: function(){
+ return mw.isAndroid2() ||
+ ( mw.isIphone() && mw.config.get( 'EmbedPlayer.iPhoneShowHTMLPlayScreen' ) );
+ },
+ /**
+ * Checks if native controls should be used
+ *
+ * @returns boolean true if the mwEmbed player interface should be used
+ * false if the mwEmbed player interface should not be used
+ */
+ useNativePlayerControls: function() {
+ if( this.usenativecontrols === true ){
+ return true;
+ }
+
+ if( mw.config.get('EmbedPlayer.NativeControls') === true ) {
+ return true;
+ }
+
+ // Check for special webkit property that allows inline iPhone playback:
+ if( mw.config.get('EmbedPlayer.WebKitPlaysInline') === true && mw.isIphone() ) {
+ return false;
+ }
+
+ // Do some device detection devices that don't support overlays
+ // and go into full screen once play is clicked:
+ if( mw.isAndroid2() || mw.isIpod() || mw.isIphone() ){
+ return true;
+ }
+
+ // iPad can use html controls if its a persistantPlayer in the dom before loading )
+ // else it needs to use native controls:
+ if( mw.isIpad() ){
+ if( mw.config.get('EmbedPlayer.EnableIpadHTMLControls') === true){
+ return false;
+ } else {
+ // Set warning that your trying to do iPad controls without
+ // persistent native player:
+ return true;
+ }
+ }
+ return false;
+ },
+ /**
+ * Checks if the native player is persistent in the dom since the intial page build out.
+ */
+ isPersistentNativePlayer: function(){
+ if( this.isLinkPlayer ){
+ return false;
+ }
+ // Since we check this early on sometimes the player
+ // has not yet been updated to the pid location
+ if( $('#' + this.pid ).length == 0 ){
+ return $('#' + this.id ).hasClass('persistentNativePlayer');
+ }
+ return $('#' + this.pid ).hasClass('persistentNativePlayer');
+ },
+ //
+ isTouchDevice: function(){
+ return mw.isIpad()
+ ||
+ mw.isAndroid40()
+ ||
+ mw.isMobileChrome();
+ },
+ /**
+ * Hides the large play button
+ * TODO move to player controls
+ */
+ hideLargePlayBtn: function(){
+ if( this.getInterface() ){
+ this.getInterface().find( '.play-btn-large' ).hide();
+ }
+ },
+ /**
+ * Add a play button (if not already there )
+ */
+ addLargePlayBtn: function(){
+ // check if we are pauseLoading ( i.e switching media, seeking, etc. and don't display play btn:
+ if( this.isPauseLoading ){
+ mw.log("EmbedPlayer:: addLargePlayBtn ( skip play button, during load )");
+ return;
+ }
+ // if using native controls make sure we can click the big play button by restoring
+ // interface click events:
+ if( this.useNativePlayerControls() ){
+ this.getInterface().css('pointer-events', 'auto');
+ }
+
+ // iPhone in WebKitPlaysInline mode does not support clickable overlays as of iOS 5.0
+ if( mw.config.get( 'EmbedPlayer.WebKitPlaysInline') && mw.isIphone() ) {
+ return ;
+ }
+ if( this.getInterface().find( '.play-btn-large' ).length ){
+ this.getInterface().find( '.play-btn-large' ).show();
+ } else {
+ this.getVideoHolder().append(
+ this.controlBuilder.getComponent( 'playButtonLarge' )
+ );
+ }
+ },
+
+ getVideoHolder: function() {
+ return this.getInterface().find('.videoHolder');
+ },
+
+ /**
+ * Abstract method,
+ * Get native player html ( should be set by mw.EmbedPlayerNative )
+ */
+ getNativePlayerHtml: function(){
+ return $('<div />' )
+ .css( 'width', this.getWidth() )
+ .html( 'Error: Trying to get native html5 player without native support for codec' );
+ },
+
+ /**
+ * Should be set via native embed support
+ */
+ applyMediaElementBindings: function(){
+ mw.log("Warning applyMediaElementBindings should be implemented by player interface" );
+ return ;
+ },
+
+ /**
+ * Gets code to embed the player remotely for "share" this player links
+ */
+ getSharingEmbedCode: function() {
+ switch( mw.config.get( 'EmbedPlayer.ShareEmbedMode' ) ){
+ case 'iframe':
+ return this.getShareIframeObject();
+ break;
+ case 'videojs':
+ return this.getShareEmbedVideoJs();
+ break;
+ }
+ },
+
+ /**
+ * Gets code to embed the player in a wiki
+ */
+ getWikiEmbedCode: function() {
+ if( this.apiTitleKey) {
+ return '[[File:' + this.apiTitleKey + ']]';
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Get the iframe share code:
+ */
+ getShareIframeObject: function(){
+ // TODO move to getShareIframeSrc
+ var iframeUrl = this.getIframeSourceUrl();
+
+ // Set up embedFrame src path
+ var embedCode = '&lt;iframe src=&quot;' + mw.html.escape( iframeUrl ) + '&quot; ';
+
+ // Set width / height of embed object
+ embedCode += 'width=&quot;' + this.getPlayerWidth() +'&quot; ';
+ embedCode += 'height=&quot;' + this.getPlayerHeight() + '&quot; ';
+ embedCode += 'frameborder=&quot;0&quot; ';
+ embedCode += 'webkitAllowFullScreen mozallowfullscreen allowFullScreen';
+
+ // Close up the embedCode tag:
+ embedCode+='&gt;&lt/iframe&gt;';
+
+ // Return the embed code
+ return embedCode;
+ },
+ /**
+ * Gets the iframe source url
+ */
+ getIframeSourceUrl: function(){
+ var iframeUrl = false;
+ this.triggerHelper( 'getShareIframeSrc', [ function( localIframeSrc ){
+ if( iframeUrl){
+ mw.log("Error multiple modules binding getShareIframeSrc" );
+ }
+ iframeUrl = localIframeSrc;
+ }, this.id ]);
+ if( iframeUrl ){
+ return iframeUrl;
+ }
+ // old style embed:
+ var iframeUrl = mw.getMwEmbedPath() + 'mwEmbedFrame.php?';
+ var params = {'src[]' : []};
+
+ // Output all the video sources:
+ for( var i=0; i < this.mediaElement.sources.length; i++ ){
+ var source = this.mediaElement.sources[i];
+ if( source.src ) {
+ params['src[]'].push(mw.absoluteUrl( source.src ));
+ }
+ }
+ // Output the poster attr
+ if( this.poster ){
+ params.poster = this.poster;
+ }
+
+ // Set the skin if set to something other than default
+ if( this.skinName ){
+ params.skin = this.skinName;
+ }
+
+ if( this.duration ) {
+ params.durationHint = parseFloat( this.duration );
+ }
+ iframeUrl += $.param( params );
+ return iframeUrl;
+ },
+ /**
+ * Get the share embed Video tag html to share the embed code.
+ */
+ getShareEmbedVideoJs: function(){
+
+ // Set the embed tag type:
+ var embedtag = ( this.isAudio() )? 'audio': 'video';
+
+ // Set up the mwEmbed js include:
+ var embedCode = '&lt;script type=&quot;text/javascript&quot; ' +
+ 'src=&quot;' +
+ mw.html.escape(
+ mw.absoluteUrl(
+ mw.getMwEmbedSrc()
+ )
+ ) + '&quot;&gt;&lt;/script&gt' +
+ '&lt;' + embedtag + ' ';
+
+ if( this.poster ) {
+ embedCode += 'poster=&quot;' +
+ mw.html.escape( mw.absoluteUrl( this.poster ) ) +
+ '&quot; ';
+ }
+
+ // Set the skin if set to something other than default
+ if( this.skinName ){
+ embedCode += 'class=&quot;' +
+ mw.html.escape( this.skinName ) +
+ '&quot; ';
+ }
+
+ if( this.duration ) {
+ embedCode +='durationHint=&quot;' + parseFloat( this.duration ) + '&quot; ';
+ }
+
+ if( this.width || this.height ){
+ embedCode += 'style=&quot;';
+ embedCode += ( this.width )? 'width:' + this.width +'px;': '';
+ embedCode += ( this.height )? 'height:' + this.height +'px;': '';
+ embedCode += '&quot; ';
+ }
+
+ // Close the video attr
+ embedCode += '&gt;';
+
+ // Output all the video sources:
+ for( var i=0; i < this.mediaElement.sources.length; i++ ){
+ var source = this.mediaElement.sources[i];
+ if( source.src ) {
+ embedCode +='&lt;source src=&quot;' +
+ mw.absoluteUrl( source.src ) +
+ '&quot; &gt;&lt;/source&gt;';
+ }
+ }
+ // Close the video tag
+ embedCode += '&lt;/video&gt;';
+
+ return embedCode;
+ },
+
+
+
+ /**
+ * Base Embed Controls
+ */
+
+ /**
+ * The Play Action
+ *
+ * Handles play requests, updates relevant states:
+ * seeking =false
+ * paused =false
+ *
+ * Triggers the play event
+ *
+ * Updates pause button Starts the "monitor"
+ */
+ firstPlay : true,
+ preSequence: false,
+ inPreSequence: false,
+ replayEventCount : 0,
+ play: function() {
+ var _this = this;
+ var $this = $( this );
+ // Store the absolute play time ( to track native events that should not invoke interface updates )
+ mw.log( "EmbedPlayer:: play: " + this._propagateEvents + ' poster: ' + this.stopped );
+
+ this.absoluteStartPlayTime = new Date().getTime();
+
+ // Check if thumbnail is being displayed and embed html
+ if ( _this.isStopped() && (_this.preSequence == false || (_this.sequenceProxy && _this.sequenceProxy.isInSequence == false) )) {
+ if ( !_this.selectedPlayer ) {
+ _this.showPlayerError();
+ return false;
+ } else {
+ _this.embedPlayerHTML();
+ }
+ }
+ // playing, exit stopped state:
+ _this.stopped = false;
+
+ if( !this.preSequence ) {
+ this.preSequence = true;
+ mw.log( "EmbedPlayer:: trigger preSequence " );
+ this.triggerHelper( 'preSequence' );
+ this.playInterfaceUpdate();
+ // if we entered into ad loading return
+ if( _this.sequenceProxy && _this.sequenceProxy.isInSequence ){
+ mw.log("EmbedPlayer:: isInSequence, do NOT play content");
+ return false;
+ }
+ }
+
+ // We need first play event for analytics purpose
+ if( this.firstPlay && this._propagateEvents) {
+ this.firstPlay = false;
+ this.triggerHelper( 'firstPlay', [ _this.id ] );
+ }
+
+ if( this.paused === true ){
+ this.paused = false;
+ // Check if we should Trigger the play event
+ mw.log("EmbedPlayer:: trigger play event::" + !this.paused + ' events:' + this._propagateEvents );
+ // trigger the actual play event:
+ if( this._propagateEvents ) {
+ this.triggerHelper( 'onplay' );
+ }
+ }
+
+ // If we previously finished playing this clip run the "replay hook"
+ if( this.donePlayingCount > 0 && !this.paused && this._propagateEvents ) {
+ this.replayEventCount++;
+ // Trigger end done on replay
+ this.triggeredEndDone = false;
+ if( this.replayEventCount <= this.donePlayingCount){
+ mw.log("EmbedPlayer::play> trigger replayEvent");
+ this.triggerHelper( 'replayEvent' );
+ }
+ }
+
+ // If we have start time defined, start playing from that point
+ if( this.currentTime < this.startTime ) {
+ $this.bind('playing.startTime', function(){
+ $this.unbind('playing.startTime');
+ if( !mw.isIOS() ){
+ _this.setCurrentTime( _this.startTime );
+ _this.startTime = 0;
+ } else {
+ // iPad seeking on syncronus play event sucks
+ setTimeout( function(){
+ _this.setCurrentTime( _this.startTime, function(){
+ _this.play();
+ });
+ _this.startTime = 0;
+ }, 500 )
+ }
+ _this.startTime = 0;
+ });
+ }
+
+ this.playInterfaceUpdate();
+ // If play controls are enabled continue to video content element playback:
+ if( _this._playContorls ){
+ return true;
+ } else {
+ // return false ( Mock play event, or handled elsewhere )
+ return false;
+ }
+ },
+ /**
+ * Update the player inteface for playback
+ * TODO move to controlBuilder
+ */
+ playInterfaceUpdate: function(){
+ var _this = this;
+ mw.log( 'EmbedPlayer:: playInterfaceUpdate' );
+ // Hide any overlay:
+ if( this.controlBuilder ){
+ this.controlBuilder.closeMenuOverlay();
+ }
+ // Hide any buttons or errors if present:
+ this.getInterface().find( '.error' ).remove();
+ this.hideLargePlayBtn();
+
+ this.getInterface().find('.play-btn span')
+ .removeClass( 'ui-icon-play' )
+ .addClass( 'ui-icon-pause' );
+
+ this.hideSpinnerOncePlaying();
+
+ this.getInterface().find( '.play-btn' )
+ .unbind('click')
+ .click( function( ) {
+ if( _this._playContorls ){
+ _this.pause();
+ }
+ } )
+ .attr( 'title', mw.msg( 'mwe-embedplayer-pause_clip' ) );
+ },
+ /**
+ * Pause player, and display a loading animation
+ * @return
+ */
+ pauseLoading: function(){
+ this.pause();
+ this.addPlayerSpinner();
+ this.isPauseLoading = true;
+ },
+ /**
+ * Adds a loading spinner to the player.
+ */
+ addPlayerSpinner: function(){
+ var sId = 'loadingSpinner_' + this.id;
+ // remove any old spinner
+ $( '#' + sId ).remove();
+ // hide the play btn if present
+ this.hideLargePlayBtn();
+ // re add an absolute positioned spinner:
+ $( this ).show().getAbsoluteOverlaySpinner()
+ .attr( 'id', sId );
+ },
+ hideSpinner: function(){
+ // remove the spinner
+ $( '#loadingSpinner_' + this.id + ',.loadingSpinner' ).remove();
+ },
+ /**
+ * Hides the loading spinner
+ */
+ hideSpinnerAndPlayBtn: function(){
+ this.isPauseLoading = false;
+ this.hideSpinner();
+ // hide the play btn
+ this.hideLargePlayBtn();
+ },
+ /**
+ * Hides the loading spinner once playing.
+ */
+ hideSpinnerOncePlaying: function(){
+ this._checkHideSpinner = true;
+ },
+ /**
+ * Base embed pause Updates the play/pause button state.
+ *
+ * There is no general way to pause the video must be overwritten by embed
+ * object to support this functionality.
+ *
+ * @param {Boolean} if the event was triggered by user action or propagated by js.
+ */
+ pause: function() {
+ var _this = this;
+ // Trigger the pause event if not already paused and using native controls:
+ if( this.paused === false ){
+ this.paused = true;
+ if( this._propagateEvents ){
+ mw.log( 'EmbedPlayer:trigger pause:' + this.paused );
+ // we only trigger "onpause" to avoid event propagation to the native object method
+ // i.e in jQuery ( this ).trigger('pause') also calls: this.pause();
+ $( this ).trigger( 'onpause' );
+ }
+ }
+ _this.pauseInterfaceUpdate();
+ },
+ /**
+ * Sets the player interface to paused mode.
+ */
+ pauseInterfaceUpdate: function(){
+ var _this =this;
+ mw.log("EmbedPlayer::pauseInterfaceUpdate");
+ // Update the ctrl "paused state"
+ this.getInterface().find('.play-btn span' )
+ .removeClass( 'ui-icon-pause' )
+ .addClass( 'ui-icon-play' );
+
+ this.getInterface().find( '.play-btn' )
+ .unbind('click')
+ .click( function() {
+ if( _this._playContorls ){
+ _this.play();
+ }
+ } )
+ .attr( 'title', mw.msg( 'mwe-embedplayer-play_clip' ) );
+ },
+ /**
+ * Maps the html5 load request. There is no general way to "load" clips so
+ * underling plugin-player libs should override.
+ */
+ load: function() {
+ // should be done by child (no base way to pre-buffer video)
+ mw.log( 'Waring:: the load method should be overided by player interface' );
+ },
+
+
+ /**
+ * Base embed stop
+ *
+ * Updates the player to the stop state.
+ *
+ * Shows Thumbnail
+ * Resets Buffer
+ * Resets Playhead slider
+ * Resets Status
+ *
+ * Trigger the "doStop" event
+ */
+ stop: function() {
+ var _this = this;
+ mw.log( 'EmbedPlayer::stop:' + this.id );
+ // update the player to stopped state:
+ this.stopped = true;
+
+ // Rest the prequecne flag:
+ this.preSequence = false;
+
+ // Trigger the stop event:
+ $( this ).trigger( 'doStop' );
+
+ // no longer seeking:
+ this.didSeekJump = false;
+
+ // Reset current time and prev time and seek offset
+ this.currentTime = this.previousTime = this.serverSeekTime = 0;
+
+ this.stopMonitor();
+
+ // pause playback ( if playing )
+ if( !this.paused ){
+ this.pause();
+ }
+ // Restore the play button ( if not native controls or is android )
+ if( this.useLargePlayBtn() ){
+ this.addLargePlayBtn();
+ this.pauseInterfaceUpdate();
+ }
+
+ // Native player controls:
+ if( !this.isPersistentNativePlayer() ){
+ // Rewrite the html to thumbnail disp
+ this.showThumbnail();
+ this.bufferedPercent = 0; // reset buffer state
+ this.controlBuilder.setStatus( this.getTimeRange() );
+ }
+ // Reset the playhead
+ this.updatePlayHead( 0 );
+ // update the status:
+ this.controlBuilder.setStatus( this.getTimeRange() );
+ // reset buffer indicator:
+ this.bufferedPercent = 0;
+ this.updateBufferStatus();
+ },
+
+ /**
+ * Base Embed mute
+ *
+ * Handles interface updates for toggling mute. Plug-in / player interface
+ * must handle the actual media player action
+ */
+ toggleMute: function( userAction ) {
+ mw.log( 'EmbedPlayer::toggleMute> (old state:) ' + this.muted );
+ if ( this.muted ) {
+ this.muted = false;
+ var percent = this.preMuteVolume;
+ } else {
+ this.muted = true;
+ this.preMuteVolume = this.volume;
+ var percent = 0;
+ }
+ // Change the volume and trigger the volume change so that other plugins can listen.
+ this.setVolume( percent, true );
+ // Update the interface
+ this.setInterfaceVolume( percent );
+ // trigger the onToggleMute event
+ $( this ).trigger('onToggleMute');
+ },
+
+ /**
+ * Update volume function ( called from interface updates )
+ *
+ * @param {float}
+ * percent Percent of full volume
+ * @param {triggerChange}
+ * boolean change if the event should be triggered
+ */
+ setVolume: function( percent, triggerChange ) {
+ var _this = this;
+ // ignore NaN percent:
+ if( isNaN( percent ) ){
+ return ;
+ }
+ // Set the local volume attribute
+ this.previousVolume = this.volume;
+
+ this.volume = percent;
+
+ // Un-mute if setting positive volume
+ if( percent != 0 ){
+ this.muted = false;
+ }
+
+ // Update the playerElement volume
+ this.setPlayerElementVolume( percent );
+ //mw.log("EmbedPlayer:: setVolume:: " + percent + ' trigger volumeChanged: ' + triggerChange );
+ if( triggerChange ){
+ $( _this ).trigger('volumeChanged', percent );
+ }
+ },
+
+ /**
+ * Updates the interface volume
+ *
+ * TODO should move to controlBuilder
+ *
+ * @param {float}
+ * percent Percentage volume to update interface
+ */
+ setInterfaceVolume: function( percent ) {
+ if( this.supports[ 'volumeControl' ] &&
+ this.getInterface().find( '.volume-slider' ).length
+ ) {
+ this.getInterface().find( '.volume-slider' ).slider( 'value', percent * 100 );
+ }
+ },
+
+ /**
+ * Abstract method Update volume Method must be override by plug-in / player interface
+ *
+ * @param {float}
+ * percent Percentage volume to update
+ */
+ setPlayerElementVolume: function( percent ) {
+ mw.log('Error player does not support volume adjustment' );
+ },
+
+ /**
+ * Abstract method get volume Method must be override by plug-in / player interface
+ * (if player does not override we return the abstract player value )
+ */
+ getPlayerElementVolume: function(){
+ // mw.log(' error player does not support getting volume property' );
+ return this.volume;
+ },
+
+ /**
+ * Abstract method get volume muted property must be overwritten by plug-in /
+ * player interface (if player does not override we return the abstract
+ * player value )
+ */
+ getPlayerElementMuted: function(){
+ // mw.log(' error player does not support getting mute property' );
+ return this.muted;
+ },
+
+ /**
+ * Passes a fullscreen request to the controlBuilder interface
+ */
+ fullscreen: function() {
+ this.controlBuilder.toggleFullscreen();
+ },
+
+ /**
+ * Abstract method to be run post embedding the player Generally should be
+ * overwritten by the plug-in / player
+ */
+ postEmbedActions:function() {
+ return ;
+ },
+
+ /**
+ * Checks the player state based on thumbnail display & paused state
+ *
+ * @return {Boolean} true if playing false if not playing
+ */
+ isPlaying : function() {
+ if ( this.stopped ) {
+ // in stopped state
+ return false;
+ } else if ( this.paused ) {
+ // paused state
+ return false;
+ } else {
+ return true;
+ }
+ },
+
+ /**
+ * Get Stopped state
+ *
+ * @return {Boolean} true if stopped false if playing
+ */
+ isStopped: function() {
+ return this.stopped;
+ },
+ /**
+ * Stop the play state monitor
+ */
+ stopMonitor: function(){
+ clearInterval( this.monitorInterval );
+ this.monitorInterval = 0;
+ },
+ /**
+ * Start the play state monitor
+ */
+ startMonitor: function(){
+ this.monitor();
+ },
+
+ /**
+ * Monitor playback and update interface components. underling player classes
+ * are responsible for updating currentTime
+ */
+ monitor: function() {
+ var _this = this;
+
+ // Check for current time update outside of embed player
+ _this.syncCurrentTime();
+
+ // mw.log( "monitor:: " + this.currentTime + ' propagateEvents: ' + _this._propagateEvents );
+
+ // update player status
+ _this.updatePlayheadStatus();
+
+ // Keep volume proprties set outside of the embed player in sync
+ _this.syncVolume();
+
+ // Make sure the monitor continues to run as long as the video is not stoped
+ _this.syncMonitor()
+
+ if( _this._propagateEvents ){
+
+ // mw.log('trigger:monitor:: ' + this.currentTime );
+ $( _this ).trigger( 'monitorEvent', [ _this.id ] );
+
+ // Trigger the "progress" event per HTML5 api support
+ if( _this.progressEventData ) {
+ $( _this ).trigger( 'progress', _this.progressEventData );
+ }
+ }
+ },
+ /**
+ * Sync the monitor function
+ */
+ syncMonitor: function(){
+ var _this = this;
+ // Call monitor at this.monitorRate interval.
+ // ( use setInterval to avoid stacking monitor requests )
+ if( ! this.isStopped() ) {
+ if( !this.monitorInterval ){
+ this.monitorInterval = setInterval( function(){
+ if( _this.monitor )
+ _this.monitor();
+ }, this.monitorRate );
+ }
+ } else {
+ // If stopped "stop" monitor:
+ this.stopMonitor();
+ }
+ },
+
+ /**
+ * Sync the video volume
+ */
+ syncVolume: function(){
+ var _this = this;
+ // Check if volume was set outside of embed player function
+ // mw.log( ' this.volume: ' + _this.volume + ' prev Volume:: ' + _this.previousVolume );
+ if( Math.round( _this.volume * 100 ) != Math.round( _this.previousVolume * 100 ) ) {
+ _this.setInterfaceVolume( _this.volume );
+ }
+ // Update the previous volume
+ _this.previousVolume = _this.volume;
+
+ // Update the volume from the player element
+ _this.volume = this.getPlayerElementVolume();
+
+ // update the mute state from the player element
+ if( _this.muted != _this.getPlayerElementMuted() && ! _this.isStopped() ){
+ mw.log( "EmbedPlayer::syncVolume: muted does not mach embed player" );
+ _this.toggleMute();
+ // Make sure they match:
+ _this.muted = _this.getPlayerElementMuted();
+ }
+ },
+
+ /**
+ * Checks if the currentTime was updated outside of the getPlayerElementTime function
+ */
+ syncCurrentTime: function(){
+ var _this = this;
+
+ // Hide the spinner once we have time update:
+ if( _this._checkHideSpinner && _this.currentTime != _this.getPlayerElementTime() ){
+ _this._checkHideSpinner = false;
+ _this.hideSpinnerAndPlayBtn();
+
+ if( _this.isPersistantPlayBtn() ){
+ // add the play button likely iphone or native player that needs the play button on
+ // non-event "exit native html5 player"
+ _this.addLargePlayBtn();
+ } else{
+ // also hide the play button ( in case it was there somehow )
+ _this.hideLargePlayBtn();
+ }
+ }
+
+ // Check if a javascript currentTime change based seek has occurred
+ if( parseInt( _this.previousTime ) != parseInt( _this.currentTime ) &&
+ !this.userSlide &&
+ !this.seeking &&
+ !this.isStopped()
+ ){
+ // If the time has been updated and is in range issue a seek
+ if( _this.getDuration() && _this.currentTime <= _this.getDuration() ){
+ var seekPercent = _this.currentTime / _this.getDuration();
+ mw.log("EmbedPlayer::syncCurrentTime::" + _this.previousTime + ' != ' +
+ _this.currentTime + " javascript based currentTime update to " +
+ seekPercent + ' == ' + _this.currentTime );
+ _this.previousTime = _this.currentTime;
+ this.seek( seekPercent );
+ }
+ }
+
+ // Update currentTime via embedPlayer
+ _this.currentTime = _this.getPlayerElementTime();
+
+ // Update any offsets from server seek
+ if( _this.serverSeekTime && _this.supportsURLTimeEncoding() ){
+ _this.currentTime = parseInt( _this.serverSeekTime ) + parseInt( _this.getPlayerElementTime() );
+ }
+
+ // Update the previousTime ( so we can know if the user-javascript changed currentTime )
+ _this.previousTime = _this.currentTime;
+
+ // Check for a pauseTime to stop playback in temporal media fragments
+ if( _this.pauseTime && _this.currentTime > _this.pauseTime ){
+ _this.pause();
+ _this.pauseTime = null;
+ }
+ },
+ /**
+ * Updates the player time and playhead position based on currentTime
+ */
+ updatePlayheadStatus: function(){
+ var _this = this;
+ if ( this.currentTime >= 0 && this.duration ) {
+ if ( !this.userSlide && !this.seeking ) {
+ if ( parseInt( this.startOffset ) != 0 ) {
+ this.updatePlayHead( ( this.currentTime - this.startOffset ) / this.duration );
+ var et = ( this.controlBuilder.longTimeDisp ) ? '/' + mw.seconds2npt( parseFloat( this.startOffset ) + parseFloat( this.duration ) ) : '';
+ this.controlBuilder.setStatus( mw.seconds2npt( this.currentTime ) + et );
+ } else {
+ // use raw currentTIme for playhead updates
+ var ct = ( this.getPlayerElement() ) ? this.getPlayerElement().currentTime || this.currentTime: this.currentTime;
+ this.updatePlayHead( ct / this.duration );
+ // Only include the end time if longTimeDisp is enabled:
+ var et = ( this.controlBuilder.longTimeDisp ) ? '/' + mw.seconds2npt( this.duration ) : '';
+ this.controlBuilder.setStatus( mw.seconds2npt( this.currentTime ) + et );
+ }
+ }
+ // Check if we are "done"
+ var endPresentationTime = ( this.startOffset ) ? ( this.startOffset + this.duration ) : this.duration;
+ if ( this.currentTime >= endPresentationTime && !this.isStopped() ) {
+ mw.log( "EmbedPlayer::updatePlayheadStatus > should run clip done :: " + this.currentTime + ' > ' + endPresentationTime );
+ this.onClipDone();
+ }
+ } else {
+ // Media lacks duration just show end time
+ if ( this.isStopped() ) {
+ this.controlBuilder.setStatus( this.getTimeRange() );
+ } else if ( this.paused ) {
+ this.controlBuilder.setStatus( mw.msg( 'mwe-embedplayer-paused' ) );
+ } else if ( this.isPlaying() ) {
+ if ( this.currentTime && ! this.duration )
+ this.controlBuilder.setStatus( mw.seconds2npt( this.currentTime ) + ' /' );
+ else
+ this.controlBuilder.setStatus( " - - - " );
+ } else {
+ this.controlBuilder.setStatus( this.getTimeRange() );
+ }
+ }
+ },
+
+ /**
+ * Abstract getPlayerElementTime function
+ */
+ getPlayerElementTime: function(){
+ mw.log("Error: getPlayerElementTime should be implemented by embed library");
+ },
+
+ /**
+ * Abstract getPlayerElementTime function
+ */
+ getPlayerElement: function(){
+ mw.log("Error: getPlayerElement should be implemented by embed library, or you may be calling this event too soon");
+ },
+
+ /**
+ * Update the Buffer status based on the local bufferedPercent var
+ */
+ updateBufferStatus: function() {
+ // Get the buffer target based for playlist vs clip
+ var $buffer = this.getInterface().find( '.mw_buffer' );
+ // Update the buffer progress bar (if available )
+ if ( this.bufferedPercent != 0 ) {
+ // mw.log('Update buffer css: ' + ( this.bufferedPercent * 100 ) +
+ // '% ' + $buffer.length );
+ if ( this.bufferedPercent > 1 ){
+ this.bufferedPercent = 1;
+ }
+ $buffer.css({
+ "width" : ( this.bufferedPercent * 100 ) + '%'
+ });
+ $( this ).trigger( 'updateBufferPercent', this.bufferedPercent );
+ } else {
+ $buffer.css( "width", '0px' );
+ }
+
+ // if we have not already run the buffer start hook
+ if( this.bufferedPercent > 0 && !this.bufferStartFlag ) {
+ this.bufferStartFlag = true;
+ mw.log("EmbedPlayer::bufferStart");
+ $( this ).trigger( 'bufferStartEvent' );
+ }
+
+ // if we have not already run the buffer end hook
+ if( this.bufferedPercent == 1 && !this.bufferEndFlag){
+ this.bufferEndFlag = true;
+ $( this ).trigger( 'bufferEndEvent' );
+ }
+ },
+
+ /**
+ * Update the player playhead
+ *
+ * @param {Float}
+ * perc Value between 0 and 1 for position of playhead
+ */
+ updatePlayHead: function( perc ) {
+ //mw.log( 'EmbedPlayer: updatePlayHead: '+ perc);
+ if( this.getInterface() ){
+ var $playHead = this.getInterface().find( '.play_head' );
+ if ( !this.useNativePlayerControls() && $playHead.length != 0 ) {
+ var val = parseInt( perc * 1000 );
+ $playHead.slider( 'value', val );
+ }
+ }
+ $( this ).trigger('updatePlayHeadPercent', perc);
+ },
+
+
+ /**
+ * Helper Functions for selected source
+ */
+
+ /**
+ * Get the current selected media source or first source
+ *
+ * @param {Number}
+ * Requested time in seconds to be passed to the server if the
+ * server supports supportsURLTimeEncoding
+ * @return src url
+ */
+ getSrc: function( serverSeekTime ) {
+ if( serverSeekTime ){
+ this.serverSeekTime = serverSeekTime;
+ }
+ if( this.currentTime && !this.serverSeekTime){
+ this.serverSeekTime = this.currentTime;
+ }
+
+ // No media element we can't return src
+ if( !this.mediaElement ){
+ return false;
+ }
+
+ // If no source selected auto select the source:
+ if( !this.mediaElement.selectedSource ){
+ this.mediaElement.autoSelectSource();
+ };
+
+ // Return selected source:
+ if( this.mediaElement.selectedSource ){
+ // See if we should pass the requested time to the source generator:
+ if( this.supportsURLTimeEncoding() ){
+ // get the first source:
+ return this.mediaElement.selectedSource.getSrc( this.serverSeekTime );
+ } else {
+ return this.mediaElement.selectedSource.getSrc();
+ }
+ }
+ // No selected source return false:
+ return false;
+ },
+ /**
+ * Return the currently selected source
+ */
+ getSource: function(){
+ // update the current selected source:
+ this.mediaElement.autoSelectSource();
+ return this.mediaElement.selectedSource;
+ },
+ /**
+ * Static helper to get media sources from a set of videoFiles
+ *
+ * Uses mediaElement select logic to chose a
+ * video file among a set of sources
+ *
+ * @param videoFiles
+ * @return
+ */
+ getCompatibleSource: function( videoFiles ){
+ // Convert videoFiles json into HTML element:
+ // TODO mediaElement should probably accept JSON
+ var $media = $('<video />');
+ $.each(videoFiles, function( inx, source){
+ $media.append( $('<source />').attr({
+ 'src' : source.src,
+ 'type' : source.type
+ }));
+ mw.log("EmbedPlayer::getCompatibleSource: add " + source.src + ' of type:' + source.type );
+ });
+ var myMediaElement = new mw.MediaElement( $media[0] );
+ var source = myMediaElement.autoSelectSource();
+ if( source ){
+ mw.log("EmbedPlayer::getCompatibleSource: " + source.getSrc());
+ return source;
+ }
+ mw.log("Error:: could not find compatible source");
+ return false;
+ },
+ /**
+ * If the selected src supports URL time encoding
+ *
+ * @return {Boolean} true if the src supports url time requests false if the
+ * src does not support url time requests
+ */
+ supportsURLTimeEncoding: function() {
+ var timeUrls = mw.config.get('EmbedPlayer.EnableURLTimeEncoding') ;
+ if( timeUrls == 'none' ){
+ return false;
+ } else if( timeUrls == 'always' ){
+ return this.mediaElement.selectedSource.URLTimeEncoding;
+ } else if( timeUrls == 'flash' ){
+ if( this.mediaElement.selectedSource && this.mediaElement.selectedSource.URLTimeEncoding){
+ // see if the current selected player is flash:
+ return ( this.instanceOf == 'Kplayer' );
+ }
+ } else {
+ mw.log("Error:: invalid config value for EmbedPlayer.EnableURLTimeEncoding:: " + mw.config.get('EmbedPlayer.EnableURLTimeEncoding') );
+ }
+ return false;
+ }
+ };
+
+})( mw, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerGeneric.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerGeneric.js
new file mode 100644
index 00000000..fc8dec55
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerGeneric.js
@@ -0,0 +1,36 @@
+/*
+* Simple embed object for unknown application/ogg plugin
+*/
+
+( function( mw, $ ) { "use strict";
+
+mw.EmbedPlayerGeneric = {
+ // List of supported features of the generic plugin
+ supports: {
+ 'playHead':false,
+ 'pause':false,
+ 'stop':true,
+ 'fullscreen':false,
+ 'timeDisplay':false,
+ 'volumeControl':false
+ },
+
+ // Instance name:
+ instanceOf:'Generic',
+
+ /*
+ * Generic embed html
+ *
+ * @return {String}
+ * embed code for generic ogg plugin
+ */
+ embedPlayerHTML: function() {
+ $( this ).html(
+ '<object type="application/ogg" ' +
+ 'width="' + this.getWidth() + '" height="' + this.getHeight() + '" ' +
+ 'data="' + this.getSrc( this.seekTimeSec ) + '"></object>'
+ );
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerIEWebMPrompt.css b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerIEWebMPrompt.css
new file mode 100644
index 00000000..9cf7b490
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerIEWebMPrompt.css
@@ -0,0 +1,18 @@
+.mwEmbedPlayer .iewebm-prompt {
+ position: absolute;
+ top: 100px;
+ bottom: 60px;
+ left: 20px;
+ right: 20px;
+ border-radius: 20px;
+ background-color: rgba(255, 255, 255, 0.75);
+
+ width: auto !important;
+ height: auto !important;
+
+ padding: 20px;
+}
+
+.mwEmbedPlayer .iewebm-prompt div {
+ color: black;
+} \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerIEWebMPrompt.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerIEWebMPrompt.js
new file mode 100644
index 00000000..00694f81
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerIEWebMPrompt.js
@@ -0,0 +1,46 @@
+/**
+ * Show a prompt to install WebM plugin for IE 9+
+ */
+
+( function( mw, $ ) { "use strict";
+
+mw.EmbedPlayerIEWebMPrompt = {
+ // List of supported features (or lack thereof)
+ supports: {
+ 'playHead':false, /* The seek slider */
+ 'pause':true, /* Play pause button in control bar */
+ 'stop':true, /* Does this actually do anything?? */
+ 'fullscreen':false,
+ 'timeDisplay':false,
+ 'volumeControl':false
+ },
+
+ // Instance name:
+ instanceOf:'IEWebMPrompt',
+
+ /*
+ * Embed this "fake" player
+ *
+ * @return {String}
+ * embed code to link to WebM plugin download
+ */
+ embedPlayerHTML: function() {
+ var pluginUrl = 'https://tools.google.com/dlpage/webmmf/',
+ $link;
+
+ // Overlay the video placeholder with download plugin link.
+ $link = $( '<a></a>' )
+ .attr( 'href', pluginUrl )
+ .attr( 'target', '_blank' )
+ .text( mw.msg( 'mwe-embedplayer-iewebmprompt-linktext' ) );
+ $( this ).append( $( '<div class="iewebm-prompt"></div>' )
+ .width( this.getWidth() )
+ .height( this.getHeight() )
+ .append( $( '<div></div>' ).text( mw.msg( 'mwe-embedplayer-iewebmprompt-intro' ) ) )
+ .append( $link )
+ .append( $( '<div></div>' ).text( mw.msg( 'mwe-embedplayer-iewebmprompt-outro' ) ) )
+ );
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerImageOverlay.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerImageOverlay.js
new file mode 100644
index 00000000..f6271621
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerImageOverlay.js
@@ -0,0 +1,307 @@
+/**
+ * Used to Overlay images and take over player controls
+ *
+ * extends EmbedPlayerNative object image overlay support
+ */
+
+mw.EmbedPlayerImageOverlay = {
+
+ instanceOf: 'ImageOverlay',
+
+ // If the player is "ready to play"
+ playerReady : true,
+
+ // Pause time used to track player time between pauses
+ lastPauseTime: 0,
+
+ // currentTime updated via internal clockStartTime var
+ currentTime:0,
+
+ // StartOffset support seeking into the virtual player
+ startOffset:0,
+
+ // The local clock used to emulate playback time
+ clockStartTime: 0,
+
+ /**
+ * Build the player interface:
+ */
+ init: function(){
+ // Check if features are already updated:
+ if( this['native_instaceOf'] == 'Native' ){
+ return ;
+ }
+ // inherit mw.EmbedPlayerNative (
+ for( var i in mw.EmbedPlayerNative ){
+ if( typeof mw.EmbedPlayerImageOverlay[ i ] != 'undefined' ){
+ this['native_' + i ] = mw.EmbedPlayerNative[i];
+ } else {
+ this[ i ] = mw.EmbedPlayerNative[i];
+ }
+ }
+ },
+
+ /**
+ * When on playback method switch remove imageOverlay
+ * @param {function} callback
+ */
+ updatePlaybackInterface: function( callback ){
+ mw.log( 'EmbedPlayerImageOverlay:: updatePlaybackInterface remove imageOverlay: ' + $(this).siblings( '.imageOverlay' ).length );
+ // Reset lastPauseTime
+ this.lastPauseTime = 0;
+ // Clear imageOverlay sibling:
+ $( this ).find( '.imageOverlay' ).remove();
+ // Restore the video element on screen position:
+ $( this.getPlayerElement() ).css('left', 0 );
+ // Call normal parent updatePlaybackInterface
+ this.parent_updatePlaybackInterface( callback );
+ },
+
+ /**
+ * The method called to "show the player"
+ * For image overlay we want to:
+ * Set black video urls for player source
+ * Add an image overlay
+ */
+ updatePosterHTML: function(){
+ var vid = this.getPlayerElement();
+ $( vid ).empty()
+
+ // Provide modules the opportunity to supply black sources ( for registering event click )
+ // this is need for iPad to capture the play click to auto continue after "playing an image"
+ // ( iOS requires a user gesture to initiate video playback )
+
+ // We don't just include the sources as part of core config, since it would result in
+ // a possible privacy leakage i.e hitting the kaltura servers when playing images.
+ this.triggerHelper( 'AddEmptyBlackSources', [ vid ] );
+
+ // embed the image:
+ this.embedPlayerHTML();
+
+ // add the play btn:
+ this.addLargePlayBtn();
+ },
+
+ /**
+ * Play function starts the video playback
+ */
+ play: function() {
+ mw.log( 'EmbedPlayerImageOverlay::play> lastPauseTime:' + this.lastPauseTime + ' ct: ' + this.currentTime );
+ this.applyIntrinsicAspect();
+ // Check for image duration
+
+ // Reset playback if currentTime > duration:
+ if( this.currentTime > this.getDuration() ) {
+ this.currentTime = this.pauseTime = 0;
+ }
+
+ // No longer in a stopped state:
+ this.stopped = false;
+
+ // Capture the play event on the native player: ( should just be black silent sources )
+ // This is needed so that if a playlist starts with image, it can continue to play the
+ // subsequent video without on iOS without requiring another click.
+ if( ! $( this ).data('previousInstanceOf') ){
+ // Update the previousInstanceOf flag:
+ $( this ).data('previousInstanceOf', this.instanceOf );
+ var vid = this.getPlayerElement();
+ // populate the video with black video sources:
+ this.triggerHelper( 'AddEmptyBlackSources', [ vid ] );
+ // run play:
+ vid.play();
+ // inline pause
+ setTimeout(function(){
+ vid.pause();
+ },0);
+ // add another pause request after 500 ms ( iOS sometimes does not listen the first time )
+ setTimeout(function(){
+ vid.pause();
+ }, mw.config.get( 'EmbedPlayer.MonitorRate' ) * 2 );
+ }
+ // call the parent play ( to update interface and call respective triggers )
+ this.parent_play();
+ // make sure we are in play interface:
+ this.playInterfaceUpdate();
+
+ this.clockStartTime = new Date().getTime();
+ // Start up monitor:
+ this.monitor();
+ },
+ getDuration: function(){
+ if( this.duration ){
+ return this.duration;
+ }
+ if( this.imageDuration ){
+ this.duration = this.imageDuration ;
+ } else {
+ this.duration = mw.config.get( "EmbedPlayer.DefaultImageDuration" );
+ }
+ // make sure duration has type float:
+ this.duration = parseFloat( this.duration );
+ return this.duration;
+ },
+ /**
+ * Stops the playback
+ */
+ stop: function() {
+ this.currentTime = 0;
+ this.parent_stop();
+ },
+ _onpause: function(){
+ // catch the native event ( and do nothing )
+ },
+ /**
+ * Preserves the pause time across for timed playback
+ */
+ pause: function( ) {
+ this.lastPauseTime = this.currentTime;
+ mw.log( 'EmbedPlayerImageOverlay::pause, lastPauseTime: ' + this.lastPauseTime );
+ // run parent pause;
+ this.parent_pause();
+ this.stopMonitor();
+ },
+
+ monitor: function(){
+ if( this.duration == 0 ){
+ this.disablePlayControls();
+ return ;
+ }
+ $( this ).trigger( 'timeupdate' );
+
+ if ( this.currentTime >= this.duration ) {
+ $( this ).trigger( 'ended' );
+ } else {
+ // Run the parent monitor:
+ this.parent_monitor();
+ }
+ },
+ /**
+ * Seeks to a given percent and updates the lastPauseTime
+ *
+ * @param {Float} seekPercent Percentage to seek into the virtual player
+ */
+ seek: function( seekPercent ) {
+ this.lastPauseTime = seekPercent * this.getDuration();
+ this.seeking = false;
+ // start seeking:
+ $( this ).trigger( 'seeking' );
+ // Done seeking
+ $( this ).trigger( 'seeked' );
+ this.play();
+ },
+
+ /**
+ * Sets the current Time
+ *
+ * @param {Float} perc Percentage to seek into the virtual player
+ * @param {Function} callback Function called once time has been updated
+ */
+ setCurrentTime: function( time, callback ) {
+ this.lastPauseTime = time;
+ // start seeking:
+ $( this ).trigger( 'seeking' );
+ // Done seeking
+ $( this ).trigger( 'seeked' );
+ if( callback ){
+ callback();
+ }
+ },
+ /**
+ * Switch the image playback
+ */
+ playerSwitchSource: function( source, switchCallback, doneCallback ){
+ var _this = this;
+ this.selectedSource = source;
+ this.embedPlayerHTML();
+ this.applyIntrinsicAspect();
+ this.play();
+ if( switchCallback ){
+ switchCallback( this );
+ }
+ // Wait for ended event to tr
+ $( this ).bind('ended.playerSwitchSource', function(){
+ $( _this ).unbind('ended.playerSwitchSource');
+ if( doneCallback ) {
+ doneCallback( this );
+ }
+ })
+ },
+ /**
+ * Get the embed player time
+ */
+ getPlayerElementTime: function() {
+ this.currentTime = ( ( new Date().getTime() - this.clockStartTime ) / 1000 ) + this.lastPauseTime;
+ return this.currentTime;
+ },
+ /**
+ * Get the "embed" html for the html player
+ */
+ embedPlayerHTML: function() {
+ var _this = this;
+ // remove any old imageOverlay:
+ this.$interface.find('.imageOverlay').remove();
+ mw.log( 'EmbedPlayerImageOverlay :doEmbedHTML: ' + this.id );
+
+ var currentSoruceObj = this.selectedSource;
+
+ if( !currentSoruceObj ){
+ mw.log("Error:: EmbedPlayerImageOverlay:embedPlayerHTML> missing source" );
+ return ;
+ }
+ var $image =
+ $( '<img />' )
+ .css({
+ 'position': 'relative',
+ 'width': '100%',
+ 'height': '100%'
+ })
+ .attr({
+ 'src' : currentSoruceObj.getSrc()
+ })
+ .addClass( 'imageOverlay' )
+ .load( function(){
+ // reset clock time:
+ _this.clockStartTime = new Date().getTime();
+ _this.monitor();
+ })
+
+ // move the video element off screen:
+ $( this.getPlayerElement() ).css({
+ 'left': this.getWidth()+50,
+ 'position' : 'absolute'
+ });
+
+ // Add the image before the video element or before the playerInterface
+ $( this ).html( $image );
+
+ this.applyIntrinsicAspect();
+ },
+ // wrap the parent rewize player to apply intensic apsect
+ resizePlayer: function( size , animate, callback){
+ this.parent_resizePlayer( size , animate, callback );
+ this.applyIntrinsicAspect();
+ },
+ applyIntrinsicAspect: function(){
+ var $this = this.$interface;
+ // Check if a image thumbnail is present:
+ /*if( this.$interface && this.$interface.find('.imageOverlay').length ){
+ var img = this.$interface.find('.imageOverlay')[0];
+ var pHeight = $this.height();
+ // Check for intrinsic width and maintain aspect ratio
+ if( img.naturalWidth && img.naturalHeight ){
+ var pWidth = parseInt( img.naturalWidth / img.naturalHeight * pHeight);
+ if( pWidth > $this.width() ){
+ pWidth = $this.width();
+ pHeight = parseInt( img.naturalHeight / img.naturalWidth * pWidth );
+ }
+ $( img ).css({
+ 'height' : pHeight + 'px',
+ 'width': pWidth + 'px',
+ 'left': ( ( $this.width() - pWidth ) * .5 ) + 'px',
+ 'top': ( ( $this.height() - pHeight ) * .5 ) + 'px',
+ 'position' : 'absolute'
+ });
+ }
+ }*/
+ }
+}; \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerKplayer.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerKplayer.js
new file mode 100644
index 00000000..739a7769
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerKplayer.js
@@ -0,0 +1,485 @@
+/*
+ * The "kaltura player" embedPlayer interface for fallback h.264 and flv video format support
+ */
+( function( mw, $ ) { "use strict";
+
+// Called from the kdp.swf
+window.jsInterfaceReadyFunc = function() {
+ return true;
+}
+
+mw.EmbedPlayerKplayer = {
+
+ // Instance name:
+ instanceOf : 'Kplayer',
+
+ bindPostfix: '.kPlayer',
+
+ // List of supported features:
+ supports : {
+ 'playHead' : true,
+ 'pause' : true,
+ 'stop' : true,
+ 'timeDisplay' : true,
+ 'volumeControl' : true,
+ 'overlays' : true,
+ 'fullscreen' : true
+ },
+
+ // Stores the current time as set from flash player
+ flashCurrentTime : 0,
+
+ /*
+ * Write the Embed html to the target
+ */
+ embedPlayerHTML : function() {
+ var _this = this;
+
+ mw.log("EmbedPlayerKplayer:: embed src::" + _this.getSrc());
+ var flashvars = {};
+ flashvars.autoPlay = "true";
+ flashvars.loop = "false";
+
+ var playerPath = mw.absoluteUrl( mw.getEmbedPlayerPath() + '/binPlayers/kaltura-player' );
+ flashvars.entryId = mw.absoluteUrl( _this.getSrc() );
+
+ // Use a relative url if the protocol is file://
+ if ( new mw.Uri( document.URL ).protocol == 'file' ) {
+ playerPath = mw.getRelativeMwEmbedPath() + 'modules/EmbedPlayer/binPlayers/kaltura-player';
+ flashvars.entryId = _this.getSrc();
+ }
+
+ flashvars.debugMode = "false";
+ flashvars.fileSystemMode = "true";
+ flashvars.widgetId = "_7463";
+ flashvars.partnerId = "7463";
+ flashvars.pluginDomain = "kdp3/plugins/";
+ flashvars.kml = "local";
+ flashvars.kmlPath = playerPath + '/config.xml';
+ flashvars.sourceType = "url";
+ flashvars.jsInterfaceReadyFunc = "jsInterfaceReadyFunc";
+
+ // flashvars.host = "www.kaltura.com";
+ flashvars.externalInterfaceDisabled = "false";
+ flashvars.skinPath = playerPath + '/skin.swf';
+
+ flashvars["full.skinPath"] = playerPath + '/LightDoodleskin.swf';
+ var flashVarParam = '';
+ $.each( flashvars, function( fKey, fVal ){
+ flashVarParam += '&' + fKey + '=' + encodeURIComponent( fVal );
+ } );
+
+ var kdpPath = playerPath + "/kdp3.3.5.27.swf";
+
+ mw.log( "KPlayer:: embedPlayerHTML" );
+ // remove any existing pid ( if present )
+ $( '#' + this.pid ).remove();
+
+ var orgJsReadyCallback = window.jsCallbackReady;
+ window.jsCallbackReady = function( playerId ){
+ _this.postEmbedActions();
+ window.jsCallbackReady = orgJsReadyCallback;
+ };
+ // attributes and params:
+ flashembed( $( this ).attr('id'),
+ {
+ id : this.pid,
+ src : kdpPath,
+ height : '100%',
+ width : '100%',
+ bgcolor : "#000000",
+ allowNetworking : "all",
+ version : [10,0],
+ wmode : "opaque"
+ },
+ flashvars
+ )
+ // Remove any old bindings:
+ $(_this).unbind( this.bindPostfix );
+
+ // Flash player loses its bindings once it changes sizes::
+ $(_this).bind('onOpenFullScreen' + this.bindPostfix , function() {
+ _this.postEmbedActions();
+ });
+ $(_this).bind('onCloseFullScreen' + this.bindPostfix, function() {
+ _this.postEmbedActions();
+ });
+ },
+
+ // The number of times we have tried to bind the player
+ bindTryCount : 0,
+
+ /**
+ * javascript run post player embedding
+ */
+ postEmbedActions : function() {
+ var _this = this;
+ this.getPlayerElement();
+ if ( this.playerElement && this.playerElement.addJsListener ) {
+ var bindEventMap = {
+ 'playerPaused' : 'onPause',
+ 'playerPlayed' : 'onPlay',
+ 'durationChange' : 'onDurationChange',
+ 'playerPlayEnd' : 'onClipDone',
+ 'playerUpdatePlayhead' : 'onUpdatePlayhead',
+ 'bytesTotalChange' : 'onBytesTotalChange',
+ 'bytesDownloadedChange' : 'onBytesDownloadedChange'
+ };
+
+ $.each( bindEventMap, function( bindName, localMethod ) {
+ _this.bindPlayerFunction(bindName, localMethod);
+ });
+ this.bindTryCount = 0;
+ // Start the monitor
+ this.monitor();
+ } else {
+ this.bindTryCount++;
+ // Keep trying to get the player element
+ if( this.bindTryCount > 500 ){ // 5 seconds
+ mw.log('Error:: KDP player never ready for bindings!');
+ return ;
+ }
+ setTimeout(function() {
+ _this.postEmbedActions();
+ }, 100);
+ }
+ },
+
+ /**
+ * Bind a Player Function,
+ *
+ * Build a global callback to bind to "this" player instance:
+ *
+ * @param {String}
+ * flash binding name
+ * @param {String}
+ * function callback name
+ */
+ bindPlayerFunction : function(bindName, methodName) {
+ mw.log( 'EmbedPlayerKplayer:: bindPlayerFunction:' + bindName );
+ // The kaltura kdp can only call a global function by given name
+ var gKdpCallbackName = 'kdp_' + methodName + '_cb_' + this.id.replace(/[^a-zA-Z 0-9]+/g,'');
+
+ // Create an anonymous function with local player scope
+ var createGlobalCB = function(cName, embedPlayer) {
+ window[ cName ] = function(data) {
+ // Track all events ( except for playerUpdatePlayhead )
+ if( bindName != 'playerUpdatePlayhead' ){
+ mw.log("EmbedPlayerKplayer:: event: " + bindName);
+ }
+ if ( embedPlayer._propagateEvents ) {
+ embedPlayer[methodName](data);
+ }
+ };
+ }(gKdpCallbackName, this);
+ // Remove the listener ( if it exists already )
+ this.playerElement.removeJsListener( bindName, gKdpCallbackName );
+ // Add the listener to the KDP flash player:
+ this.playerElement.addJsListener( bindName, gKdpCallbackName);
+ },
+
+ /**
+ * on Pause callback from the kaltura flash player calls parent_pause to
+ * update the interface
+ */
+ onPause : function() {
+ this.parent_pause();
+ },
+
+ /**
+ * onPlay function callback from the kaltura flash player directly call the
+ * parent_play
+ */
+ onPlay : function() {
+ this.parent_play();
+ },
+
+ onDurationChange : function(data, id) {
+ // Update the duration ( only if not in url time encoding mode:
+ if( !this.supportsURLTimeEncoding() ){
+ this.duration = data.newValue;
+ this.triggerHelper('durationchange');
+ }
+ },
+
+ /**
+ * play method calls parent_play to update the interface
+ */
+ play: function() {
+ if ( this.playerElement && this.playerElement.sendNotification ) {
+ this.playerElement.sendNotification('doPlay');
+ }
+ this.parent_play();
+ },
+
+ /**
+ * pause method calls parent_pause to update the interface
+ */
+ pause: function() {
+ if (this.playerElement && this.playerElement.sendNotification) {
+ this.playerElement.sendNotification('doPause');
+ }
+ this.parent_pause();
+ },
+ /**
+ * playerSwitchSource switches the player source working around a few bugs in browsers
+ *
+ * @param {object}
+ * source Video Source object to switch to.
+ * @param {function}
+ * switchCallback Function to call once the source has been switched
+ * @param {function}
+ * doneCallback Function to call once the clip has completed playback
+ */
+ playerSwitchSource: function( source, switchCallback, doneCallback ){
+ var _this = this;
+ var waitCount = 0;
+ var src = source.getSrc();
+ // Check if the source is already set to the target:
+ if( !src || src == this.getSrc() ){
+ if( switchCallback ){
+ switchCallback();
+ }
+ setTimeout(function(){
+ if( doneCallback )
+ doneCallback();
+ }, 100);
+ return ;
+ }
+
+ var waitForJsListen = function( callback ){
+ if( _this.getPlayerElement() && _this.getPlayerElement().addJsListener ){
+ callback();
+ } else {
+ // waited for 2 seconds fail
+ if( waitCount > 20 ){
+ mw.log( "Error: Failed to swtich player source!");
+ if( switchCallback )
+ switchCallback();
+ if( doneCallback )
+ doneCallback();
+ return;
+ }
+
+ setTimeout(function(){
+ waitCount++;
+ waitForJsListen( callback );
+ },100)
+ }
+ };
+ // wait for jslistener to be ready:
+ waitForJsListen( function(){
+ var gPlayerReady = 'kdp_switch_' + _this.id + '_switchSrcReady';
+ var gDoneName = 'kdp_switch_' + _this.id + '_switchSrcEnd';
+ var gChangeMedia = 'kdp_switch_' + _this.id + '_changeMedia';
+ window[ gPlayerReady ] = function(){
+ mw.log("EmbedPlayerKplayer:: playerSwitchSource: " + src);
+ // remove the binding as soon as possible ( we only want this event once )
+ _this.getPlayerElement().removeJsListener( 'playerReady', gPlayerReady );
+
+ _this.getPlayerElement().sendNotification("changeMedia", { 'entryId': src } );
+
+ window[ gChangeMedia ] = function (){
+ mw.log("EmbedPlayerKplayer:: Media changed: " + src);
+ if( $.isFunction( switchCallback) ){
+ switchCallback( _this );
+ switchCallback = null
+ }
+ // restore monitor:
+ _this.monitor();
+ }
+ // Add change media binding
+ _this.getPlayerElement().removeJsListener('changeMedia', gChangeMedia);
+ _this.getPlayerElement().addJsListener( 'changeMedia', gChangeMedia);
+
+ window[ gDoneName ] = function(){
+ if( $.isFunction( doneCallback ) ){
+ doneCallback();
+ doneCallback = null;
+ }
+ };
+ _this.getPlayerElement().removeJsListener('playerPlayEnd', gDoneName);
+ _this.getPlayerElement().addJsListener( 'playerPlayEnd', gDoneName);
+ };
+ // Remove then add the event:
+ _this.getPlayerElement().removeJsListener( 'playerReady', gPlayerReady );
+ _this.getPlayerElement().addJsListener( 'playerReady', gPlayerReady );
+ });
+ },
+
+ /**
+ * Issues a seek to the playerElement
+ *
+ * @param {Float}
+ * percentage Percentage of total stream length to seek to
+ */
+ seek : function(percentage) {
+ var _this = this;
+ var seekTime = percentage * this.getDuration();
+ mw.log( 'EmbedPlayerKalturaKplayer:: seek: ' + percentage + ' time:' + seekTime );
+ if (this.supportsURLTimeEncoding()) {
+
+ // Make sure we could not do a local seek instead:
+ if (!(percentage < this.bufferedPercent
+ && this.playerElement.duration && !this.didSeekJump)) {
+ // We support URLTimeEncoding call parent seek:
+ this.parent_seek( percentage );
+ return;
+ }
+ }
+ // Add a seeked callback event:
+ var seekedCallback = 'kdp_seek_' + this.id + '_' + new Date().getTime();
+ window[ seekedCallback ] = function(){
+ _this.seeking = false;
+ _this.triggerHelper( 'seeked' );
+ if( seekInterval ) {
+ clearInterval( seekInterval );
+ }
+ };
+ this.playerElement.addJsListener('playerSeekEnd', seekedCallback );
+
+ if ( this.getPlayerElement() ) {
+ // trigger the html5 event:
+ _this.triggerHelper( 'seeking' );
+
+ // Issue the seek to the flash player:
+ this.playerElement.sendNotification('doSeek', seekTime);
+
+ // Include a fallback seek timer: in case the kdp does not fire 'playerSeekEnd'
+ var orgTime = this.flashCurrentTime;
+ var seekInterval = setInterval( function(){
+ if( _this.flashCurrentTime != orgTime ){
+ _this.seeking = false;
+ clearInterval( seekInterval );
+ this.triggerHelper( 'seeked' );
+ }
+ }, mw.config.get( 'EmbedPlayer.MonitorRate' ) );
+
+ } else {
+ // try to do a play then seek:
+ this.doPlayThenSeek(percentage);
+ }
+
+ // Run the onSeeking interface update
+ this.controlBuilder.onSeek();
+ },
+
+ /**
+ * Seek in a existing stream
+ *
+ * @param {Float}
+ * percentage Percentage of the stream to seek to between 0 and 1
+ */
+ doPlayThenSeek : function(percentage) {
+ mw.log('EmbedPlayerKplayer::doPlayThenSeek::');
+ var _this = this;
+ // issue the play request
+ this.play();
+
+ // let the player know we are seeking
+ _this.seeking = true;
+ this.triggerHelper( 'seeking' );
+
+ var getPlayerCount = 0;
+ var readyForSeek = function() {
+ _this.getPlayerElement();
+ // if we have duration then we are ready to do the seek ( flash can't
+ // seek untill there is some buffer )
+ if (_this.playerElement && _this.playerElement.sendNotification
+ && _this.getDuration() && _this.bufferedPercent) {
+ var seekTime = percentage * _this.getDuration();
+ // Issue the seek to the flash player:
+ _this.playerElement.sendNotification('doSeek', seekTime);
+ } else {
+ // Try to get player for 20 seconds:
+ if (getPlayerCount < 400) {
+ setTimeout(readyForSeek, 50);
+ getPlayerCount++;
+ } else {
+ mw.log('Error: doPlayThenSeek failed');
+ }
+ }
+ };
+ readyForSeek();
+ },
+
+ /**
+ * Issues a volume update to the playerElement
+ *
+ * @param {Float}
+ * percentage Percentage to update volume to
+ */
+ setPlayerElementVolume : function(percentage) {
+ if ( this.getPlayerElement() && this.playerElement.sendNotification ) {
+ this.playerElement.sendNotification('changeVolume', percentage);
+ }
+ },
+
+ /**
+ * function called by flash at set interval to update the playhead.
+ */
+ onUpdatePlayhead : function( playheadValue ) {
+ //mw.log('Update play head::' + playheadValue);
+ this.flashCurrentTime = playheadValue;
+ },
+
+ /**
+ * function called by flash when the total media size changes
+ */
+ onBytesTotalChange : function(data, id) {
+ this.bytesTotal = data.newValue;
+ },
+
+ /**
+ * function called by flash applet when download bytes changes
+ */
+ onBytesDownloadedChange : function(data, id) {
+ //mw.log('onBytesDownloadedChange');
+ this.bytesLoaded = data.newValue;
+ this.bufferedPercent = this.bytesLoaded / this.bytesTotal;
+
+ // Fire the parent html5 action
+ this.triggerHelper('progress', {
+ 'loaded' : this.bytesLoaded,
+ 'total' : this.bytesTotal
+ });
+ },
+
+ /**
+ * Get the embed player time
+ */
+ getPlayerElementTime : function() {
+ // update currentTime
+ return this.flashCurrentTime;
+ },
+
+ /**
+ * Get the embed fla object player Element
+ */
+ getPlayerElement : function() {
+ this.playerElement = document.getElementById( this.pid );
+ return this.playerElement;
+ }
+};
+
+} )( mediaWiki, jQuery );
+
+/*
+ * jQuery Tools 1.2.5 - The missing UI library for the Web
+ *
+ * [toolbox.flashembed]
+ *
+ * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
+ *
+ * http://flowplayer.org/tools/
+ *
+ * File generated: Fri Oct 22 13:51:38 GMT 2010
+ */
+(function(){function f(a,b){if(b)for(var c in b)if(b.hasOwnProperty(c))a[c]=b[c];return a}function l(a,b){var c=[];for(var d in a)if(a.hasOwnProperty(d))c[d]=b(a[d]);return c}function m(a,b,c){if(e.isSupported(b.version))a.innerHTML=e.getHTML(b,c);else if(b.expressInstall&&e.isSupported([6,65]))a.innerHTML=e.getHTML(f(b,{src:b.expressInstall}),{MMredirectURL:location.href,MMplayerType:"PlugIn",MMdoctitle:document.title});else{if(!a.innerHTML.replace(/\s/g,"")){a.innerHTML="<h2>Flash version "+b.version+
+" or greater is required</h2><h3>"+(g[0]>0?"Your version is "+g:"You have no flash plugin installed")+"</h3>"+(a.tagName=="A"?"<p>Click here to download latest version</p>":"<p>Download latest version from <a href='"+k+"'>here</a></p>");if(a.tagName=="A")a.onclick=function(){location.href=k}}if(b.onFail){var d=b.onFail.call(this);if(typeof d=="string")a.innerHTML=d}}if(i)window[b.id]=document.getElementById(b.id);f(this,{getRoot:function(){return a},getOptions:function(){return b},getConf:function(){return c},
+getApi:function(){return a.firstChild}})}var i=document.all,k="http://www.adobe.com/go/getflashplayer",n=typeof jQuery=="function",o=/(\d+)[^\d]+(\d+)[^\d]*(\d*)/,j={width:"100%",height:"100%",id:"_"+(""+Math.random()).slice(9),allowfullscreen:true,allowscriptaccess:"always",quality:"high",version:[3,0],onFail:null,expressInstall:null,w3c:false,cachebusting:false};window.attachEvent&&window.attachEvent("onbeforeunload",function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){}});
+window.flashembed=function(a,b,c){if(typeof a=="string")a=document.getElementById(a.replace("#",""));if(a){if(typeof b=="string")b={src:b};return new m(a,f(f({},j),b),c)}};var e=f(window.flashembed,{conf:j,getVersion:function(){var a,b;try{b=navigator.plugins["Shockwave Flash"].description.slice(16)}catch(c){try{b=(a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7"))&&a.GetVariable("$version")}catch(d){try{b=(a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"))&&a.GetVariable("$version")}catch(h){}}}return(b=
+o.exec(b))?[b[1],b[3]]:[0,0]},asString:function(a){if(a===null||a===undefined)return null;var b=typeof a;if(b=="object"&&a.push)b="array";switch(b){case "string":a=a.replace(new RegExp('(["\\\\])',"g"),"\\$1");a=a.replace(/^\s?(\d+\.?\d+)%/,"$1pct");return'"'+a+'"';case "array":return"["+l(a,function(d){return e.asString(d)}).join(",")+"]";case "function":return'"function()"';case "object":b=[];for(var c in a)a.hasOwnProperty(c)&&b.push('"'+c+'":'+e.asString(a[c]));return"{"+b.join(",")+"}"}return String(a).replace(/\s/g,
+" ").replace(/\'/g,'"')},getHTML:function(a,b){a=f({},a);var c='<object width="'+a.width+'" height="'+a.height+'" id="'+a.id+'" name="'+a.id+'"';if(a.cachebusting)a.src+=(a.src.indexOf("?")!=-1?"&":"?")+Math.random();c+=a.w3c||!i?' data="'+a.src+'" type="application/x-shockwave-flash"':' classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"';c+=">";if(a.w3c||i)c+='<param name="movie" value="'+a.src+'" />';a.width=a.height=a.id=a.w3c=a.src=null;a.onFail=a.version=a.expressInstall=null;for(var d in a)if(a[d])c+=
+'<param name="'+d+'" value="'+a[d]+'" />';a="";if(b){for(var h in b)if(b[h]){d=b[h];a+=h+"="+(/function|object/.test(typeof d)?e.asString(d):d)+"&"}a=a.slice(0,-1);c+='<param name="flashvars" value=\''+a+"' />"}c+="</object>";return c},isSupported:function(a){return g[0]>a[0]||g[0]==a[0]&&g[1]>=a[1]}}),g=e.getVersion();if(n){jQuery.tools=jQuery.tools||{version:"1.2.5"};jQuery.tools.flashembed={conf:j};jQuery.fn.flashembed=function(a,b){return this.each(function(){$(this).data("flashembed",flashembed(this,
+a,b))})}}})();
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerNative.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerNative.js
new file mode 100644
index 00000000..8c514f70
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerNative.js
@@ -0,0 +1,1088 @@
+/**
+* Native embed library:
+*
+* Enables embedPlayer support for native html5 browser playback system
+*/
+( function( mw, $ ) { "use strict";
+
+mw.EmbedPlayerNative = {
+
+ //Instance Name
+ instanceOf: 'Native',
+
+ // Flag to only load the video ( not play it )
+ onlyLoadFlag:false,
+
+ //Callback fired once video is "loaded"
+ onLoadedCallback: null,
+
+ // The previous "currentTime" to sniff seek actions
+ // NOTE the bug where onSeeked does not seem fire consistently may no longer be applicable
+ prevCurrentTime: -1,
+
+ // Store the progress event ( updated during monitor )
+ progressEventData: null,
+
+ // If the media loaded event has been fired
+ mediaLoadedFlag: null,
+
+ // A flag to keep the video tag offscreen.
+ keepPlayerOffScreenFlag: null,
+
+ // A flag to designate the first play event, as to not propagate the native event in this case
+ isFirstEmbedPlay: null,
+
+ // A local var to store the current seek target time:
+ currentSeekTargetTime: null,
+
+ // All the native events per:
+ // http://www.w3.org/TR/html5/video.html#mediaevents
+ nativeEvents : [
+ 'loadstart',
+ 'progress',
+ 'suspend',
+ 'abort',
+ 'error',
+ 'emptied',
+ 'stalled',
+ 'play',
+ 'pause',
+ 'loadedmetadata',
+ 'loadeddata',
+ 'waiting',
+ 'playing',
+ 'canplay',
+ 'canplaythrough',
+ 'seeking',
+ 'seeked',
+ 'timeupdate',
+ 'ended',
+ 'ratechange',
+ 'durationchange',
+ 'volumechange'
+ ],
+
+ // Native player supported feature set
+ supports: {
+ 'playHead' : true,
+ 'pause' : true,
+ 'fullscreen' : true,
+ 'sourceSwitch': true,
+ 'timeDisplay' : true,
+ 'volumeControl' : true,
+ 'overlays' : true
+ },
+ /**
+ * Updates the supported features given the "type of player"
+ */
+ updateFeatureSupport: function(){
+ // The native controls function checks for overly support
+ // especially the special case of iPad in-dom or not support
+ if( this.useNativePlayerControls() ) {
+ this.supports.overlays = false;
+ this.supports.volumeControl = false;
+ }
+ // iOS does not support volume control
+ if( mw.isIpad() ){
+ this.supports.volumeControl = false;
+ }
+ // Check if we already have a selected source and a player in the page,
+ if( this.getPlayerElement() && this.getSrc() ){
+ $( this.getPlayerElement() ).attr( 'src', this.getSrc() );
+ }
+ // Check if we already have a video element an apply bindings ( for native interfaces )
+ if( this.getPlayerElement() ){
+ this.applyMediaElementBindings();
+ }
+
+ this.parent_updateFeatureSupport();
+ },
+ /**
+ * Adds an HTML screen and moves the video tag off screen, works around some iPhone bugs
+ */
+ addPlayScreenWithNativeOffScreen: function(){
+ var _this = this;
+ // Hide the player offscreen:
+ this.hidePlayerOffScreen();
+ this.keepPlayerOffScreenFlag = true;
+
+ // Add a play button on the native player:
+ this.addLargePlayBtn();
+
+ // Add a binding to show loader once clicked to show the loader
+ // bad ui to leave the play button displayed
+ this.$interface.find( '.play-btn-large' ).click( function(){
+ _this.$interface.find( '.play-btn-large' ).hide();
+ _this.addPlayerSpinner();
+ _this.hideSpinnerOncePlaying();
+ });
+
+ // Add an image poster:
+ var posterSrc = ( this.poster ) ? this.poster :
+ mw.config.get( 'EmbedPlayer.BlackPixel' );
+
+ // Check if the poster is already present:
+ if( $( this ).find( '.playerPoster' ).length ){
+ $( this ).find( '.playerPoster' ).attr('src', posterSrc );
+ } else {
+ $( this ).append(
+ $('<img />').css({
+ 'margin' : '0',
+ 'width': '100%',
+ 'height': '100%'
+ })
+ .attr( 'src', posterSrc)
+ .addClass('playerPoster')
+ )
+ }
+ $( this ).show();
+ },
+ /**
+ * Return the embed code
+ */
+ embedPlayerHTML : function () {
+ var _this = this;
+ var vid = _this.getPlayerElement();
+ this.isFirstEmbedPlay = true;
+
+ // Check if we should have a play button on the native player:
+ if( this.useLargePlayBtn() ){
+ this.addLargePlayBtn();
+ }
+
+ if( vid && $( vid ).attr('src') == this.getSrc( this.currentTime ) ){
+ _this.postEmbedActions();
+ return ;
+ }
+ mw.log( "EmbedPlayerNative::embedPlayerHTML > play url:" + this.getSrc( this.currentTime ) + ' startOffset: ' + this.start_ntp + ' end: ' + this.end_ntp );
+
+ // Check if using native controls and already the "pid" is already in the DOM
+ if( this.isPersistentNativePlayer() && vid ) {
+ _this.postEmbedActions();
+ return ;
+ }
+ // Reset some play state flags:
+ _this.bufferStartFlag = false;
+ _this.bufferEndFlag = false;
+
+ $( this ).html(
+ _this.getNativePlayerHtml()
+ );
+
+ // Directly run postEmbedActions ( if playerElement is not available it will retry )
+ _this.postEmbedActions();
+ },
+
+ /**
+ * Get the native player embed code.
+ *
+ * @param {object} playerAttributes Attributes to be override in function call
+ * @return {object} cssSet css to apply to the player
+ */
+ getNativePlayerHtml: function( playerAttributes, cssSet ){
+ if( !playerAttributes) {
+ playerAttributes = {};
+ }
+ // Update required attributes
+ if( !playerAttributes['id'] ){
+ playerAttributes['id'] = this.pid;
+ }
+ if( !playerAttributes['src'] ){
+ playerAttributes['src'] = this.getSrc( this.currentTime);
+ }
+
+ // If autoplay pass along to attribute ( needed for iPad / iPod no js autoplay support
+ if( this.autoplay ) {
+ playerAttributes['autoplay'] = 'true';
+ }
+
+ if( !cssSet ){
+ cssSet = {};
+ }
+
+ // Set default width height to 100% of parent container
+ if( !cssSet['width'] ) cssSet['width'] = '100%';
+ if( !cssSet['height'] ) cssSet['height'] = '100%';
+
+ // Also need to set the loop param directly for iPad / iPod
+ if( this.loop ) {
+ playerAttributes['loop'] = 'true';
+ }
+
+ var tagName = this.isAudio() ? 'audio' : 'video';
+
+ return $( '<' + tagName + ' />' )
+ // Add the special nativeEmbedPlayer to avoid any rewrites of of this video tag.
+ .addClass( 'nativeEmbedPlayerPid' )
+ .attr( playerAttributes )
+ .css( cssSet )
+ },
+
+ /**
+ * Post element javascript, binds event listeners and starts monitor
+ */
+ postEmbedActions: function() {
+ var _this = this;
+ // Setup local pointer:
+ var vid = this.getPlayerElement();
+ if( !vid ){
+ return ;
+ }
+ // Update the player source ( if needed )
+ if( $( vid).attr( 'src' ) != this.getSrc( this.currentTime ) ){
+ $( vid ).attr( 'src', this.getSrc( this.currentTime ) );
+ }
+ // Update the WebKitPlaysInline value
+ if( mw.config.get( 'EmbedPlayer.WebKitPlaysInline') ){
+ $( vid ).attr( 'webkit-playsinline', 1 );
+ }
+ // Update the EmbedPlayer.WebKitAllowAirplay option:
+ if( mw.config.get( 'EmbedPlayer.WebKitAllowAirplay' ) ){
+ $( vid ).attr( 'x-webkit-airplay', "allow" );
+ }
+ // make sure to display native controls if enabled:
+ if( this.useNativePlayerControls() ){
+ $( vid ).attr( 'controls', "true" );
+ }
+
+ // Apply media element bindings:
+ _this.applyMediaElementBindings();
+
+ // Make sure we start playing in the correct place:
+ if( this.currentTime != vid.currentTime ){
+ var waitReadyStateCount = 0;
+ var checkReadyState = function(){
+ if( vid.readyState > 0 ){
+ vid.currentTime = this.currentTime;
+ return ;
+ }
+ if( waitReadyStateCount > 1000 ){
+ mw.log("Error: EmbedPlayerNative: could not run native seek");
+ return ;
+ }
+ waitReadyStateCount++;
+ setTimeout( function() {
+ checkReadyState();
+ }, 10 );
+ };
+ }
+ // Some mobile devices ( iOS need a load call before play will work )
+ if ( !_this.loop ) {
+ vid.load();
+ }
+ },
+ /**
+ * Apply media element bindings
+ */
+ applyMediaElementBindings: function(){
+ var _this = this;
+ mw.log("EmbedPlayerNative::MediaElementBindings");
+ var vid = this.getPlayerElement();
+ if( ! vid ){
+ mw.log( " Error: applyMediaElementBindings without player elemnet");
+ return ;
+ }
+ $.each( _this.nativeEvents, function( inx, eventName ){
+ $( vid ).unbind( eventName + '.embedPlayerNative').bind( eventName + '.embedPlayerNative', function(){
+ if( _this._propagateEvents ){
+ var argArray = $.makeArray( arguments );
+ // always pass the current ref id as the last argument
+ // helps check against some event trigger ref issues in jQuery
+ argArray.push( _this.id );
+ // Check if there is local handler:
+ if( _this[ '_on' + eventName ] ){
+ _this[ '_on' + eventName ].apply( _this, argArray);
+ } else {
+ // No local handler directly propagate the event to the abstract object:
+ $( _this ).trigger( eventName, argArray );
+ }
+ }
+ });
+ });
+ },
+
+ // basic monitor function to update buffer
+ monitor: function(){
+ var _this = this;
+ var vid = _this.getPlayerElement();
+
+ // Update the bufferedPercent
+ if( vid && vid.buffered && vid.buffered.end && vid.duration ) {
+ try{
+ this.bufferedPercent = ( vid.buffered.end(0) / vid.duration );
+ } catch ( e ){
+ // opera does not have buffered.end zero index support ?
+ }
+ }
+ _this.parent_monitor();
+ },
+
+
+ /**
+ * Issue a seeking request.
+ *
+ * @param {Float} percent
+ * @param {bollean} stopAfterSeek if the player should stop after the seek
+ */
+ seek: function( percent, stopAfterSeek ) {
+ // bounds check
+ if( percent < 0 ){
+ percent = 0;
+ }
+
+ if( percent > 1 ){
+ percent = 1;
+ }
+ mw.log( 'EmbedPlayerNative::seek p: ' + percent + ' : ' + this.supportsURLTimeEncoding() + ' dur: ' + this.getDuration() + ' sts:' + this.seekTimeSec );
+
+ // Trigger preSeek event for plugins that want to store pre seek conditions.
+ this.triggerHelper( 'preSeek', percent );
+
+ this.seeking = true;
+ // Update the current time ( local property )
+ this.currentTime = ( percent * this.duration ).toFixed( 2 ) ;
+
+ // trigger the seeking event:
+ mw.log( 'EmbedPlayerNative::seek:trigger' );
+ this.triggerHelper( 'seeking' );
+
+ // Run the onSeeking interface update
+ this.controlBuilder.onSeek();
+
+ // @@todo check if the clip is loaded here (if so we can do a local seek)
+ if ( this.supportsURLTimeEncoding() ) {
+ // Make sure we could not do a local seek instead:
+ if ( percent < this.bufferedPercent && this.playerElement.duration && !this.didSeekJump ) {
+ mw.log( "EmbedPlayerNative::seek local seek " + percent + ' is already buffered < ' + this.bufferedPercent );
+ this.doNativeSeek( percent );
+ } else {
+ // We support URLTimeEncoding call parent seek:
+ this.parent_seek( percent );
+ }
+ } else {
+ // Try to do a play then seek:
+ this.doNativeSeek( percent );
+ }
+ },
+
+ /**
+ * Do a native seek by updating the currentTime
+ * @param {float} percent
+ * Percent to seek to of full time
+ */
+ doNativeSeek: function( percent, callback ) {
+ // If player already seeking, exit
+ var _this = this;
+ // chrome crashes with multiple seeks:
+ if( (navigator.userAgent.indexOf('Chrome') === -1) && _this.playerElement.seeking ) {
+ return ;
+ }
+
+ mw.log( 'EmbedPlayerNative::doNativeSeek::' + percent );
+ this.seeking = true;
+
+ this.seekTimeSec = 0;
+
+ // Hide iPad video off screen ( iOS shows quicktime logo during seek )
+ if( mw.isIOS() ){
+ this.hidePlayerOffScreen();
+ }
+
+ this.setCurrentTime( ( percent * this.duration ) , function(){
+ // Update the current time ( so that there is not a monitor delay in reflecting "seeked time" )
+ _this.currentTime = _this.getPlayerElement().currentTime;
+ // Done seeking ( should be a fallback trigger event ) :
+ if( _this.seeking ){
+ _this.seeking = false;
+ $( _this ).trigger( 'seeked' );
+ }
+ // restore iPad video position:
+ _this.restorePlayerOnScreen();
+
+ _this.monitor();
+ // issue the callback:
+ if( callback ){
+ callback();
+ }
+ });
+ },
+
+ /**
+ * Seek in a existing stream, we first play then seek to work around issues with iPad seeking.
+ *
+ * @param {Float} percent
+ * percent of the stream to seek to between 0 and 1
+ */
+ doPlayThenSeek: function( percent ) {
+ mw.log( 'EmbedPlayerNative::doPlayThenSeek::' + percent + ' isPaused ' + this.paused);
+ var _this = this;
+ var oldPauseState = this.paused;
+ this.play();
+ var retryCount = 0;
+ var readyForSeek = function() {
+ _this.getPlayerElement();
+ // If we have duration then we are ready to do the seek
+ if ( _this.playerElement && _this.playerElement.duration ) {
+ _this.doNativeSeek( percent, function(){
+ // restore pause if paused:
+ if( oldPauseState ){
+ _this.pause();
+ }
+ } );
+ } else {
+ // Try to get player for 30 seconds:
+ // (it would be nice if the onmetadata type callbacks where fired consistently)
+ if ( retryCount < 800 ) {
+ setTimeout( readyForSeek, 10 );
+ retryCount++;
+ } else {
+ mw.log( 'EmbedPlayerNative:: Error: doPlayThenSeek failed :' + _this.playerElement.duration);
+ }
+ }
+ };
+ readyForSeek();
+ },
+
+ /**
+ * Set the current time with a callback
+ *
+ * @param {Float} position
+ * Seconds to set the time to
+ * @param {Function} callback
+ * Function called once time has been set.
+ */
+ setCurrentTime: function( seekTime , callback, callbackCount ) {
+ var _this = this;
+ if( !callbackCount ){
+ callbackCount = 0;
+ }
+ mw.log( "EmbedPlayerNative:: setCurrentTime seekTime:" + seekTime + ' count:' + callbackCount );
+
+ // Make sure all the timeouts don't seek to an expired target:
+ $( this ).data('currentSeekTarget', seekTime );
+
+ var vid = this.getPlayerElement();
+ // add a callback handler to null out callback:
+ var callbackHandler = function(){
+ if( $.isFunction( callback ) ){
+ callback();
+ callback = null;
+ }
+ }
+ if( !vid ) {
+ callbackHandler();
+ _this.currentSeekTargetTime = seekTime.toFixed( 2 );
+ return;
+ }
+ // Check if player is ready for seek:
+ if( vid.readyState < 1 ){
+ // Try to seek for 4 seconds:
+ if( callbackCount >= 40 ){
+ mw.log("Error:: EmbedPlayerNative: with seek request, media never in ready state");
+ callbackHandler();
+ return ;
+ }
+ setTimeout( function(){
+ // Check that this seek did not expire:
+ if( $( _this ).data('currentSeekTarget') != seekTime ){
+ mw.log("EmbedPlayerNative:: expired seek target");
+ return ;
+ }
+ _this.setCurrentTime( seekTime, callback , callbackCount+1);
+ }, 100 );
+ return ;
+ }
+ // Check if currentTime is already set to the seek target:
+ if( vid.currentTime.toFixed(2) == seekTime.toFixed(2) ){
+ mw.log("EmbedPlayerNative:: setCurrentTime: current time matches seek target: " +
+ vid.currentTime.toFixed(2) + ' == ' + seekTime.toFixed(2) );
+ callbackHandler();
+ return;
+ }
+ // setup a namespaced seek bind:
+ var seekBind = 'seeked.nativeSeekBind';
+
+ // Remove any old listeners
+ $( vid ).unbind( seekBind );
+ // Bind a seeked listener for the callback
+ $( vid ).bind( seekBind, function( event ) {
+ // Remove the listener:
+ $( vid ).unbind( seekBind );
+
+ // Check if seeking to zero:
+ if( seekTime == 0 && vid.currentTime == 0 ){
+ callbackHandler();
+ return ;
+ }
+
+ // Check if we got a valid seek:
+ if( vid.currentTime > 0 ){
+ callbackHandler();
+ } else {
+ mw.log( "Error:: EmbedPlayerNative: seek callback without time updatet " + vid.currentTime );
+ }
+ });
+ setTimeout(function(){
+ // Check that this seek did not expire:
+ if( $( _this ).data('currentSeekTarget') != seekTime ){
+ mw.log("EmbedPlayerNative:: Expired seek target");
+ return ;
+ }
+
+ if( $.isFunction( callback ) ){
+ // if seek is within 5 seconds of the target assume success. ( key frame intervals can mess with seek accuracy )
+ // this only runs where the seek callback failed ( i.e broken html5 seek ? )
+ if( Math.abs( vid.currentTime - seekTime ) < 5 ){
+ mw.log( "EmbedPlayerNative:: Seek time is within 5 seconds of target, sucessfull seek");
+ callback();
+ } else {
+ mw.log( "Error:: EmbedPlayerNative: Seek still has not made a callback after 5 seconds, retry");
+ _this.setCurrentTime( seekTime, callback , callbackCount++ );
+ }
+ }
+ }, 5000);
+
+ // Try to update the playerElement time:
+ try {
+ _this.currentSeekTargetTime = seekTime.toFixed( 2 );
+ // use toFixed ( iOS issue with float seek times )
+ vid.currentTime = _this.currentSeekTargetTime;
+ } catch ( e ) {
+ mw.log("Error:: EmbedPlayerNative: Could not set video tag seekTime");
+ callbackHandler();
+ return ;
+ }
+
+ // Check for seeking state ( some player iOS / iPad can only seek while playing )
+ if(! vid.seeking ){
+ mw.log( "Error:: not entering seek state, play and wait for positive time" );
+ vid.play();
+ setTimeout(function(){
+ _this.waitForPositiveCurrentTime( function(){
+ mw.log("EmbedPlayerNative:: Got possitive time:" + vid.currentTime.toFixed(3) + ", trying to seek again");
+ _this.setCurrentTime( seekTime , callback, callbackCount+1 );
+ });
+ }, mw.config.get( 'EmbedPlayer.MonitorRate' ) );
+ }
+ },
+ waitForPositiveCurrentTime: function( callback ){
+ var _this = this;
+ var vid = this.getPlayerElement();
+ this.waitForPositiveCurrentTimeCount++;
+ // Wait for playback for 10 seconds
+ if( vid.currentTime > 0 ){
+ mw.log( 'EmbedPlayerNative:: waitForPositiveCurrentTime success' );
+ callback();
+ } else if( this.waitForPositiveCurrentTimeCount > 200 ){
+ mw.log( "Error:: waitForPositiveCurrentTime failed to reach possitve time");
+ callback();
+ } else {
+ setTimeout(function(){ _this.waitForPositiveCurrentTime( callback ) }, 50 )
+ }
+ },
+ /**
+ * Get the embed player time
+ */
+ getPlayerElementTime: function() {
+ var _this = this;
+ // Make sure we have .vid obj
+ this.getPlayerElement();
+ if ( !this.playerElement ) {
+ mw.log( 'EmbedPlayerNative::getPlayerElementTime: ' + this.id + ' not in dom ( stop monitor)' );
+ this.stop();
+ return false;
+ }
+ var ct = this.playerElement.currentTime;
+ // Return 0 or a positive number:
+ if( ! ct || isNaN( ct ) || ct < 0 || ! isFinite( ct ) ){
+ return 0;
+ }
+ // Return the playerElement currentTime
+ return this.playerElement.currentTime;
+ },
+
+ // Update the poster src ( updates the native object if in dom )
+ updatePosterSrc: function( src ){
+ if( this.getPlayerElement() ){
+ $( this.getPlayerElement() ).attr('poster', src );
+ }
+ // Also update the embedPlayer poster
+ this.parent_updatePosterSrc( src );
+ },
+ /**
+ * Empty player sources from the active video tag element
+ */
+ emptySources: function(){
+ // empty player source:
+ $( this.getPlayerElement() ).attr( 'src', null );
+ // empty out generic sources:
+ this.parent_emptySources();
+ },
+ /**
+ * playerSwitchSource switches the player source working around a few bugs in browsers
+ *
+ * @param {Object}
+ * Source object to switch to.
+ * @param {function}
+ * switchCallback Function to call once the source has been switched
+ * @param {function}
+ * doneCallback Function to call once the clip has completed playback
+ */
+ playerSwitchSource: function( source, switchCallback, doneCallback ){
+ var _this = this;
+ var src = source.getSrc();
+ var vid = this.getPlayerElement();
+ var switchBindPostfix = '.playerSwitchSource';
+ this.isPauseLoading = false;
+ // Make sure the switch source is different:
+ if( !src || src == vid.src ){
+ if( $.isFunction( switchCallback ) ){
+ switchCallback( vid );
+ }
+ // Delay done callback to allow any non-blocking switch callback code to fully execute
+ if( $.isFunction( doneCallback ) ){
+ doneCallback();
+ }
+ return ;
+ }
+
+ // only display switch msg if actually switching:
+ mw.log( 'EmbedPlayerNative:: playerSwitchSource: ' + src + ' native time: ' + vid.currentTime );
+
+ // Update some parent embedPlayer vars:
+ this.currentTime = 0;
+ this.previousTime = 0;
+ if ( vid ) {
+ try {
+ // Remove all switch player bindings
+ $( vid ).unbind( switchBindPostfix );
+
+ // pause before switching source
+ vid.pause();
+
+ var orginalControlsState = vid.controls;
+ // Hide controls ( to not display native play button while switching sources )
+ vid.removeAttribute('controls');
+
+ // dissable seeking ( if we were in a seeking state before the switch )
+ _this.seeking = false;
+
+ // add a loading indicator:
+ _this.addPlayerSpinner();
+
+ // Do the actual source switch:
+ vid.src = src;
+ // load the updated src
+ vid.load();
+
+ // hide the player offscreen while we switch
+ _this.hidePlayerOffScreen();
+ // restore position once we have metadata
+ $( vid ).bind( 'loadedmetadata' + switchBindPostfix, function(){
+ $( vid ).unbind( 'loadedmetadata' + switchBindPostfix);
+ mw.log("EmbedPlayerNative:: playerSwitchSource> loadedmetadata callback for:" + src + ' switchCallback: ' + switchCallback );
+ // Only update duration if we didn't get it server side
+ // Some browsers report bad duration (e.g. Android native browser)
+ // So avoid using the browser detected value if possible.
+ if ( !_this.duration && isFinite( vid.duration ) ) {
+ _this.duration = vid.duration;
+ }
+ // keep going towards playback! if switchCallback has not been called yet
+ // we need the "playing" event to trigger the switch callback
+ if ( $.isFunction( switchCallback ) ){
+ vid.play();
+ }
+ });
+
+ var handleSwitchCallback = function(){
+ // restore video position ( now that we are playing with metadata size )
+ _this.restorePlayerOnScreen();
+ // play hide loading spinner:
+ _this.hideSpinnerAndPlayBtn();
+ // Restore
+ vid.controls = orginalControlsState;
+ // check if we have a switch callback and issue it now:
+ if ( $.isFunction( switchCallback ) ){
+ switchCallback( vid );
+ switchCallback = null;
+ }
+ }
+
+ // once playing issue callbacks:
+ $( vid ).bind( 'playing' + switchBindPostfix, function(){
+ $( vid ).unbind( 'playing' + switchBindPostfix );
+ mw.log("EmbedPlayerNative:: playerSwitchSource> playing callback");
+ handleSwitchCallback();
+ });
+
+ // Add the end binding if we have a post event:
+ if( $.isFunction( doneCallback ) ){
+ $( vid ).bind( 'ended' + switchBindPostfix , function( event ) {
+ // remove end binding:
+ $( vid ).unbind( switchBindPostfix );
+ // issue the doneCallback
+ doneCallback();
+
+ // Support loop for older iOS
+ // Temporarly disabled pending more testing or refactor into a better place.
+ //if ( _this.loop ) {
+ // vid.play();
+ //}
+ return false;
+ });
+ }
+
+ // issue the play request:
+ vid.play();
+
+ // check if ready state is loading or doing anything ( iOS play restriction )
+ // give iOS 5 seconds to ~start~ loading media
+ setTimeout(function(){
+ // Check that the player got out of readyState 0
+ if( vid.readyState === 0 && $.isFunction( switchCallback ) ){
+ mw.log("EmbedPlayerNative:: possible iOS play without gesture failed, issue callback");
+ // hand off to the swtich callback method.
+ handleSwitchCallback();
+ // make sure we are in a pause state ( failed to change and play media );
+ _this.pause();
+ // show the big play button so the user can give us a user gesture:
+ if( ! _this.useLargePlayBtn() ){
+ _this.addLargePlayBtn();
+ }
+ }
+ }, 5000 );
+
+
+ } catch (e) {
+ mw.log("Error: EmbedPlayerNative Error in switching source playback");
+ }
+ }
+ },
+ hidePlayerOffScreen:function( vid ){
+ var vid = this.getPlayerElement();
+ // Move the video offscreen while it switches ( hides quicktime logo only applies to iPad )
+ $( vid ).css( {
+ 'position' : 'absolute',
+ 'left': '-4048px'
+ });
+ },
+ restorePlayerOnScreen: function( vid ){
+ var vid = this.getPlayerElement();
+ if( this.keepPlayerOffScreenFlag ){
+ return ;
+ }
+
+ // Remove any poster div ( that would overlay the player )
+ $( this ).find( '.playerPoster' ).remove();
+ // Restore video pos before calling sync syze
+ $( vid ).css( {
+ 'left': '0px'
+ });
+ },
+ /**
+ * Pause the video playback
+ * calls parent_pause to update the interface
+ */
+ pause: function( ) {
+ this.getPlayerElement();
+ this.parent_pause(); // update interface
+ if ( this.playerElement ) { // update player
+ this.playerElement.pause();
+ }
+ },
+
+ /**
+ * Play back the video stream
+ * calls parent_play to update the interface
+ */
+ play: function() {
+ var _this = this;
+ // if starting playback from stoped state and not in an ad or otherise blocked controls state:
+ // restore player:
+ if( this.isStopped() && this._playContorls ){
+ this.restorePlayerOnScreen();
+ }
+ // Run parent play:
+ if( _this.parent_play() ){
+ if ( this.getPlayerElement() && this.getPlayerElement().play ) {
+ mw.log( "EmbedPlayerNative:: issue native play call" );
+ // If in pauseloading state make sure the loading spinner is present:
+ if( this.isPauseLoading ){
+ this.hideSpinnerOncePlaying();
+ }
+ // issue a play request
+ this.getPlayerElement().play();
+ // re-start the monitor:
+ this.monitor();
+ }
+ } else {
+ mw.log( "EmbedPlayerNative:: parent play returned false, don't issue play on native element");
+ }
+ },
+
+ /**
+ * Stop the player ( end all listeners )
+ */
+ stop: function(){
+ var _this = this;
+ if( this.playerElement && this.playerElement.currentTime){
+ this.playerElement.currentTime = 0;
+ this.playerElement.pause();
+ }
+ this.parent_stop();
+ },
+
+ /**
+ * Toggle the Mute
+ * calls parent_toggleMute to update the interface
+ */
+ toggleMute: function() {
+ this.parent_toggleMute();
+ this.getPlayerElement();
+ if ( this.playerElement )
+ this.playerElement.muted = this.muted;
+ },
+
+ /**
+ * Update Volume
+ *
+ * @param {Float} percent Value between 0 and 1 to set audio volume
+ */
+ setPlayerElementVolume : function( percent ) {
+ if ( this.getPlayerElement() ) {
+ // Disable mute if positive volume
+ if( percent != 0 ) {
+ this.playerElement.muted = false;
+ }
+ this.playerElement.volume = percent;
+ }
+ },
+
+ /**
+ * get Volume
+ *
+ * @return {Float}
+ * Audio volume between 0 and 1.
+ */
+ getPlayerElementVolume: function() {
+ if ( this.getPlayerElement() ) {
+ return this.playerElement.volume;
+ }
+ },
+ /**
+ * get the native muted state
+ */
+ getPlayerElementMuted: function(){
+ if ( this.getPlayerElement() ) {
+ return this.playerElement.muted;
+ }
+ },
+
+ /**
+ * Get the native media duration
+ */
+ getNativeDuration: function() {
+ if ( this.playerElement ) {
+ return this.playerElement.duration;
+ }
+ },
+
+ /**
+ * Load the video stream with a callback fired once the video is "loaded"
+ *
+ * @parma {Function} callbcak Function called once video is loaded
+ */
+ load: function( callback ) {
+ this.getPlayerElement();
+ if ( !this.playerElement ) {
+ // No vid loaded
+ mw.log( 'EmbedPlayerNative::load() ... doEmbed' );
+ this.onlyLoadFlag = true;
+ this.embedPlayerHTML();
+ this.onLoadedCallback = callback;
+ } else {
+ // Should not happen offten
+ this.playerElement.load();
+ if( callback ){
+ callback();
+ }
+ }
+ },
+
+ /**
+ * Get /update the playerElement value
+ */
+ getPlayerElement: function () {
+ this.playerElement = $( '#' + this.pid ).get( 0 );
+ return this.playerElement;
+ },
+
+ /**
+ * Bindings for the Video Element Events
+ */
+
+ /**
+ * Local method for seeking event
+ * fired when "seeking"
+ */
+ _onseeking: function() {
+ mw.log( "EmbedPlayerNative::onSeeking " + this.seeking + ' new time: ' + this.getPlayerElement().currentTime );
+ if( this.seeking && Math.round( this.getPlayerElement().currentTime - this.currentSeekTargetTime ) > 2 ){
+ mw.log( "Error:: EmbedPlayerNative Seek time missmatch: target:" + this.getPlayerElement().currentTime +
+ ' actual ' + this.currentSeekTargetTime + ', note apple HLS can only seek to 10 second targets');
+ }
+ // Trigger the html5 seeking event
+ //( if not already set from interface )
+ if( !this.seeking ) {
+ this.currentSeekTargetTime = this.getPlayerElement().currentTime;
+ this.seeking = true;
+ // Run the onSeeking interface update
+ this.controlBuilder.onSeek();
+
+ // Trigger the html5 "seeking" trigger
+ mw.log("EmbedPlayerNative::seeking:trigger:: " + this.seeking);
+ if( this._propagateEvents ){
+ this.triggerHelper( 'seeking' );
+ }
+ }
+ },
+
+ /**
+ * Local method for seeked event
+ * fired when done seeking
+ */
+ _onseeked: function() {
+ mw.log("EmbedPlayerNative::onSeeked " + this.seeking + ' ct:' + this.playerElement.currentTime );
+ // sync the seek checks so that we don't re-issue the seek request
+ this.previousTime = this.currentTime = this.playerElement.currentTime;
+
+ // Trigger the html5 action on the parent
+ if( this.seeking ){
+
+ // HLS safari triggers onseek when its not even close to the target time,
+ // we don't want to trigger the seek event for these "fake" onseeked triggers
+ if( Math.abs( this.currentSeekTargetTime - this.getPlayerElement().currentTime ) > 2 ){
+ mw.log( "Error:: EmbedPlayerNative:seeked triggred with time mismatch: target:" +
+ this.currentSeekTargetTime +
+ ' actual:' + this.getPlayerElement().currentTime );
+ return ;
+ }
+ this.seeking = false;
+ if( this._propagateEvents ){
+ mw.log( "EmbedPlayerNative:: trigger: seeked" );
+ this.triggerHelper( 'seeked' );
+ }
+ }
+ this.hideSpinner();
+ // update the playhead status
+ if( this.isStopped() ){
+ this.addLargePlayBtn();
+ }
+ this.monitor();
+ },
+
+ /**
+ * Handle the native paused event
+ */
+ _onpause: function(){
+ var _this = this;
+ var timeSincePlay = Math.abs( this.absoluteStartPlayTime - new Date().getTime() );
+ mw.log( "EmbedPlayerNative:: OnPaused:: propagate:" + this._propagateEvents + ' time since play: ' + timeSincePlay + ' isNative=true' );
+ // Only trigger parent pause if more than MonitorRate time has gone by.
+ // Some browsers trigger native pause events when they "play" or after a src switch
+ if( timeSincePlay > mw.config.get( 'EmbedPlayer.MonitorRate' ) ){
+ _this.parent_pause();
+ } else {
+ // continue playback:
+ this.getPlayerElement().play();
+ }
+ },
+
+ /**
+ * Handle the native play event
+ */
+ _onplay: function(){
+ mw.log("EmbedPlayerNative:: OnPlay:: propogate:" + this._propagateEvents + ' paused: ' + this.paused);
+ // if using native controls make sure the inteface does not block the native controls interface:
+ if( this.useNativePlayerControls() ){
+ this.$interface.css('pointer-events', 'none');
+ }
+
+ // Update the interface ( if paused )
+ if( ! this.isFirstEmbedPlay && this._propagateEvents && this.paused ){
+ this.parent_play();
+ } else {
+ // make sure the interface reflects the current play state if not calling parent_play()
+ this.playInterfaceUpdate();
+ }
+ // Set firstEmbedPlay state to false to avoid initial play invocation :
+ this.isFirstEmbedPlay = false;
+ },
+
+ /**
+ * Local method for metadata ready
+ * fired when metadata becomes available
+ *
+ * Used to update the media duration to
+ * accurately reflect the src duration
+ */
+ _onloadedmetadata: function() {
+ this.getPlayerElement();
+
+ if ( this.playerElement && !isNaN( this.playerElement.duration ) && isFinite( this.playerElement.duration) ) {
+ mw.log( 'EmbedPlayerNative :onloadedmetadata metadata ready Update duration:' + this.playerElement.duration + ' old dur: ' + this.getDuration() );
+ // Only update duration if we didn't get it server side
+ // Some browsers report bad duration (e.g. Android native browser)
+ // So avoid using the browser detected value if possible.
+ if( !this.duration && this.playerElement && isFinite( this.playerElement.duration ) ) {
+ this.duration = this.playerElement.duration;
+ }
+ }
+
+ // Check if in "playing" state and we are _propagateEvents events and continue to playback:
+ if( !this.paused && this._propagateEvents ){
+ this.getPlayerElement().play();
+ }
+
+ //Fire "onLoaded" flags if set
+ if( typeof this.onLoadedCallback == 'function' ) {
+ this.onLoadedCallback();
+ }
+
+ // Trigger "media loaded"
+ if( ! this.mediaLoadedFlag ){
+ $( this ).trigger( 'mediaLoaded' );
+ this.mediaLoadedFlag = true;
+ }
+ },
+
+ /**
+ * Local method for end of media event
+ */
+ _onended: function( event ) {
+ var _this = this;
+ if( this.getPlayerElement() ){
+ mw.log( 'EmbedPlayer:native: onended:' + this.playerElement.currentTime + ' real dur:' + this.getDuration() + ' ended ' + this._propagateEvents );
+ if( this._propagateEvents ){
+ this.onClipDone();
+ }
+ }
+ },
+ /**
+ * Local onClip done function for native player.
+ */
+ onClipDone: function(){
+ var _this = this;
+ // add clip done binding ( will only run on sequence complete )
+ $(this).unbind('onEndedDone.onClipDone').bind( 'onEndedDone.onClipDone', function(){
+ _this.addPlayScreenWithNativeOffScreen();
+ // if not a legitmate play screen don't keep the player offscreen when playback starts:
+ if( !_this.isImagePlayScreen() ){
+ _this.keepPlayerOffScreenFlag =false;
+ }
+ });
+ this.parent_onClipDone();
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerOgvJs.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerOgvJs.js
new file mode 100644
index 00000000..791459f3
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerOgvJs.js
@@ -0,0 +1,222 @@
+( function( mw, $ ) { "use strict";
+
+var support = mw.OgvJsSupport;
+
+mw.EmbedPlayerOgvJs = {
+
+ // Instance name:
+ instanceOf: 'OgvJs',
+
+ // Supported feature set of the OGVPlayer widget:
+ supports: {
+ 'playHead' : true,
+ 'pause' : true,
+ 'stop' : true,
+ 'fullscreen' : true,
+ 'sourceSwitch': true,
+ 'timeDisplay' : true,
+ 'volumeControl' : false,
+ 'overlays': true,
+ 'timedText': true
+ },
+
+ /**
+ * Perform setup in response to a play start command.
+ * This means loading the code asynchronously if needed,
+ * and enabling web audio for iOS Safari inside the event
+ * handler.
+ *
+ * @return jQuery.Deferred
+ */
+ _ogvJsPreInit: function() {
+ if( mw.isIOS() ) {
+ this._initializeAudioForiOS();
+ }
+ return support.loadOgvJs();
+ },
+
+ /**
+ * Actually initialize the player.
+ *
+ * @return OGVPlayer
+ */
+ _ogvJsInit: function() {
+ var options = {};
+ if ( this._iOSAudioContext ) {
+ // Reuse the audio context we opened earlier
+ options.audioContext = this._iOSAudioContext;
+ }
+ return new OGVPlayer( options );
+ },
+
+ _iOSAudioContext: undefined,
+
+ _initializeAudioForiOS: function() {
+ // iOS Safari Web Audio API must be initialized from an input event handler
+ if ( this._iOSAudioContext ) {
+ return;
+ }
+ this._iOSAudioContext = support.initAudioContext();
+ },
+
+ /**
+ * Output the the embed html
+ */
+ embedPlayerHTML: function (optionalCallback) {
+
+ $( this )
+ .empty()
+ .append( $.createSpinner( {
+ size: 'large',
+ type: 'block'
+ } ) );
+
+ var _this = this;
+ if( mw.isIOS() ) {
+ _this._initializeAudioForiOS();
+ }
+ support.loadOgvJs().done( function() {
+
+ var player = _this._ogvJsInit();
+ player.id = _this.pid;
+ player.style.width = '100%';
+ player.style.height = '100%';
+ player.src = _this.getSrc();
+ if ( _this.getDuration() ) {
+ player.durationHint = parseFloat( _this.getDuration() );
+ }
+ player.addEventListener('ended', function() {
+ _this.onClipDone();
+ });
+
+ // simulate timeupdate events, needed for subtitles
+ // @todo switch this to native timeupdate event when available upstream
+ var lastTime = 0,
+ timeupdateInterval = 0.25;
+ player.addEventListener( 'framecallback', function( event ) {
+ var player = _this.getPlayerElement(),
+ now = player ? player.currentTime : lastTime;
+ // Don't spam time updates on every frame
+ if ( Math.abs( now - lastTime ) >= timeupdateInterval ) {
+ lastTime = now;
+ $( _this ).trigger( 'timeupdate', [event, _this.id] );
+ }
+ });
+
+ $( _this ).empty().append( player );
+ player.play();
+
+ // Start the monitor:
+ _this.monitor();
+
+ if ( optionalCallback ) {
+ optionalCallback();
+ }
+ });
+ },
+
+ /**
+ * Get the embed player time
+ */
+ getPlayerElementTime: function() {
+ this.getPlayerElement();
+ var currentTime = 0;
+ if ( this.playerElement ) {
+ currentTime = this.playerElement.currentTime;
+ } else {
+ mw.log( "EmbedPlayerOgvJs:: Could not find playerElement" );
+ }
+ return currentTime;
+ },
+
+ /**
+ * Update the playerElement instance with a pointer to the embed object
+ */
+ getPlayerElement: function() {
+ // this.pid is in the form 'pid_mwe_player_<number>'; inherited from mw.EmbedPlayer.js
+ var $el = $( '#' + this.pid );
+ if( !$el.length ) {
+ return false;
+ }
+ this.playerElement = $el.get( 0 );
+ return this.playerElement;
+ },
+
+ /**
+ * Issue the doPlay request to the playerElement
+ * calls parent_play to update interface
+ */
+ play: function() {
+ this.getPlayerElement();
+ this.parent_play();
+ if ( this.playerElement ) {
+ this.playerElement.play();
+ // Restart the monitor if on second playthrough
+ this.monitor();
+ }
+ },
+
+ /**
+ * Pause playback
+ * calls parent_pause to update interface
+ */
+ pause: function() {
+ this.getPlayerElement();
+ // Update the interface
+ this.parent_pause();
+ // Call the pause function if it exists:
+ if ( this.playerElement ) {
+ this.playerElement.pause();
+ }
+ },
+
+ /**
+ * Switch the source!
+ * For simplicity we just replace the player here.
+ */
+ playerSwitchSource: function( source, switchCallback, doneCallback ){
+ var _this = this;
+ var src = source.getSrc();
+ var vid = this.getPlayerElement();
+ if ( typeof vid.stop !== 'undefined' ) {
+ vid.stop();
+ }
+
+ switchCallback();
+
+ // Currently have to tear down the player and make a new one
+ this.embedPlayerHTML( doneCallback );
+ },
+
+ /**
+ * Seek in the ogg stream
+ * @param {Float} percentage Percentage to seek into the stream
+ */
+ seek: function( percentage ) {
+ this.setCurrentTime( percentage * parseFloat( this.getDuration() ) );
+ },
+
+ setCurrentTime: function( time, callback ) {
+ this.getPlayerElement();
+
+ if ( this.playerElement ) {
+ this.playerElement.currentTime = time;
+ }
+
+ this.currentTime = time;
+ this.previousTime = time; // prevent weird double-seek. MwEmbedPlyer is weird!
+
+ // Run the onSeeking interface update
+ this.controlBuilder.onSeek();
+ // @todo add proper events upstream
+ if( this.seeking ){
+ this.seeking = false;
+ $( this ).trigger( 'seeked' );
+ }
+ if ( $.isFunction( callback ) ) {
+ callback();
+ }
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerVLCApp.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerVLCApp.js
new file mode 100644
index 00000000..5fa6c6f8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerVLCApp.js
@@ -0,0 +1,101 @@
+/**
+ * Play the video using the vlc app on iOS
+ */
+
+( function( mw, $ ) { "use strict";
+
+mw.EmbedPlayerVLCApp = {
+ // List of supported features (or lack thereof)
+ supports: {
+ 'playHead':false, /* The seek slider */
+ 'pause':true, /* Play pause button in control bar */
+ 'stop':true, /* Does this actually do anything?? */
+ 'fullscreen':false,
+ 'timeDisplay':false,
+ 'volumeControl':false
+ },
+
+ // Instance name:
+ instanceOf:'VLCApp',
+
+ /*
+ * Embed this "fake" player
+ *
+ * @return {String}
+ * embed code to link to VLC app
+ */
+ embedPlayerHTML: function() {
+ var fileUrl = this.getSrc( this.seekTimeSec ),
+ vlcUrl = 'vlc://' + (new mw.Uri( fileUrl )).toString(),
+ appStoreUrl = '//itunes.apple.com/us/app/vlc-for-ios/id650377962',
+ appInstalled = false,
+ promptInstallTimeout,
+ $link,
+ startTime;
+
+ // Replace video with download in vlc link.
+ // the <span> ends up being not used as we get the html via .html()
+ $link = $( '<span></span>' ).append( $( '<a></a>' ).attr( 'href', appStoreUrl ).append(
+ mw.html.escape( mw.msg( 'mwe-embedplayer-vlcapp-vlcapplinktext' ) )
+ ) );
+ $( this ).html( $( '<div class="vlcapp-player"></div>' )
+ .width( this.getWidth() )
+ .height( this.getHeight() )
+ .append(
+ // mw.msg doesn't have rawParams() equivalent. Lame.
+ mw.html.escape(
+ mw.msg( 'mwe-embedplayer-vlcapp-intro' )
+ ).replace( /\$1/g, $link.html() )
+ ).append( $( '<ul></ul>' )
+ .append( $( '<li></li>' ).append( $( '<a></a>' ).attr( 'href', appStoreUrl )
+ .text( mw.msg( 'mwe-embedplayer-vlcapp-downloadapp' ) ) )
+ ).append( $( '<li></li>' ).append( $( '<a></a>' ).attr( 'href', vlcUrl )
+ .text( mw.msg( 'mwe-embedplayer-vlcapp-openvideo' ) ) )
+ ).append( $( '<li></li>' ).append( $( '<a></a>' ).attr( 'href', fileUrl )
+ .text( mw.msg( 'mwe-embedplayer-vlcapp-downloadvideo' ) ) )
+ )
+ )
+ );
+
+ // Try to auto-open in vlc.
+ // Based on http://stackoverflow.com/questions/627916/check-if-url-scheme-is-supported-in-javascript
+
+ $( window ).one( 'pagehide', function() {
+ appInstalled = true;
+ if ( promptInstallTimeout ) {
+ window.clearTimeout( promptInstallTimeout );
+ }
+ } );
+ startTime = (new Date).getTime();
+ try {
+ window.location = vlcUrl;
+ } catch( e ) {
+ // Just to be safe, ignore any exceptions
+ // However, it appears iOS doesn't throw any. Other browsers do.
+ }
+ promptInstallTimeout = window.setTimeout( function() {
+ var install;
+ if ( appInstalled ) {
+ return;
+ }
+ if ( document.hidden || document.webkitHidden ) {
+ // browser still running, but in background.
+ // probably means an App was opened up.
+ return;
+ }
+ if ( (new Date).getTime() - 15000 > startTime ) {
+ // We switched to VLC more than fifteen seconds ago.
+ // Probably we succesfully switched and the other detection
+ // methods failed.
+ return;
+ }
+ install = confirm( mw.msg( 'mwe-embedplayer-vlcapp-vlcapppopup' ) );
+ if ( install ) {
+ window.location = appStoreUrl;
+ }
+ // Note about timeout: iPad air needs longer than an iPhone
+ }, 1000 );
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerVlc.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerVlc.js
new file mode 100644
index 00000000..c668cf40
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedPlayerVlc.js
@@ -0,0 +1,358 @@
+/*
+* VLC embed based on: http://people.videolan.org/~damienf/plugin-0.8.6.html
+* javascript api: http://www.videolan.org/doc/play-howto/en/ch04.html
+* assume version > 0.8.5.1
+*/
+( function( mw, $ ) { "use strict";
+
+mw.EmbedPlayerVlc = {
+
+ //Instance Name:
+ instanceOf : 'Vlc',
+
+ //What the vlc player / plug-in supports:
+ supports : {
+ 'playHead':true,
+ 'pause':true,
+ 'stop':true,
+ 'fullscreen':true,
+ 'timeDisplay':true,
+ 'volumeControl':true,
+
+ 'playlist_driver':true, // if the object supports playlist functions
+ 'overlay':false
+ },
+
+ // The previous state of the player instance
+ prevState : 0,
+
+ // Counter for waiting for vlc embed to be ready
+ waitForVlcCount:0,
+
+ // Store the current play time for vlc
+ vlcCurrentTime: 0,
+
+ /**
+ * Get embed HTML
+ */
+ embedPlayerHTML: function() {
+ var _this = this;
+ $( this ).html(
+ '<object classid="clsid:9BE31822-FDAD-461B-AD51-BE1D1C159921" ' +
+ 'codebase="http://downloads.videolan.org/pub/videolan/vlc/latest/win32/axvlc.cab#Version=0,8,6,0" ' +
+ 'id="' + this.pid + '" events="True" height="' + this.getPlayerHeight() + '" width="' + this.getPlayerWidth() + '"' +
+ '>' +
+ '<param name="MRL" value="">' +
+ '<param name="ShowDisplay" value="True">' +
+ '<param name="AutoLoop" value="False">' +
+ '<param name="AutoPlay" value="False">' +
+ '<param name="Volume" value="50">' +
+ '<param name="StartTime" value="0">' +
+ '<embed pluginspage="http://www.videolan.org" type="application/x-vlc-plugin" ' +
+ 'progid="VideoLAN.VLCPlugin.2" name="' + this.pid + '" ' +
+ 'height="' + this.getHeight() + '" width="' + this.getWidth() + '" ' +
+ // Set the style for IE layout issues )
+ 'style="width:' + this.getWidth() + 'px;height:' + this.getHeight() + 'px;" ' +
+ '>' +
+ '</object>'
+ )
+ // Call postEmbedActions directly ( postEmbedJs will wait for player ready )
+ _this.postEmbedActions();
+ },
+
+ /**
+ * Javascript to run post vlc embedding
+ * Inserts the requested src to the embed instance
+ */
+ postEmbedActions: function() {
+ var _this = this;
+ // Load a pointer to the vlc into the object (this.playerElement)
+ this.getPlayerElement();
+ if ( this.playerElement && this.playerElement.playlist) {
+ // manipulate the dom object to make sure vlc has the correct size:
+ this.playerElement.style.width = this.getWidth();
+ this.playerElement.style.height = this.getHeight();
+ this.playerElement.playlist.items.clear();
+
+ // VLC likes absolute urls:
+ var src = mw.absoluteUrl( this.getSrc() ) ;
+
+ mw.log( "EmbedPlayerVlc:: postEmbedActions play src:" + src );
+ var itemId = this.playerElement.playlist.add( src );
+ if ( itemId != -1 ) {
+ // Play
+ this.playerElement.playlist.playItem( itemId );
+ } else {
+ mw.log( "Error:: EmbedPlayerVlc can not play" );
+ }
+ setTimeout( function() {
+ _this.monitor();
+ }, 100 );
+ } else {
+ mw.log( 'EmbedPlayerVlc:: postEmbedActions: vlc not ready' );
+ this.waitForVlcCount++;
+ if ( this.waitForVlcCount < 10 ) {
+ setTimeout( function() {
+ _this.postEmbedActions();
+ }, 100 );
+ } else {
+ mw.log( 'EmbedPlayerVlc:: vlc never ready' );
+ }
+ }
+ },
+
+ /**
+ * Handles seek requests based on temporal media source type support
+ *
+ * @param {Float} percent Seek to this percent of the stream
+ */
+ seek : function( percent ) {
+ this.getPlayerElement();
+ // Use the parent (re) embed with new seek url method if urlTimeEncoding is supported.
+ if ( this.supportsURLTimeEncoding() ) {
+ this.parent_seek( percent );
+ } else if ( this.playerElement ) {
+ this.seeking = true;
+ mw.log( "EmbedPlayerVlc:: seek to: " + percent )
+ if ( ( this.playerElement.input.state == 3 ) && ( this.playerElement.input.position != percent ) )
+ {
+ this.playerElement.input.position = percent;
+ this.controlBuilder.setStatus( mw.msg('mwe-embedplayer-seeking') );
+ }
+ } else {
+ this.doPlayThenSeek( percent );
+ }
+ this.parent_monitor();
+ },
+
+ /**
+ * Issues a play request then seeks to a given time
+ *
+ * @param {Float} percent Seek to this percent of the stream after playing
+ */
+ doPlayThenSeek:function( percent ) {
+ mw.log( 'EmbedPlayerVlc:: doPlayThenSeek' );
+ var _this = this;
+ this.play();
+ var seekCount = 0;
+ var readyForSeek = function() {
+ _this.getPlayerElement();
+ var newState = _this.playerElement.input.state;
+ // If playing we are ready to do the seek
+ if ( newState == 3 ) {
+ _this.seek( percent );
+ } else {
+ // Try to get player for 10 seconds:
+ if ( seekCount < 200 ) {
+ setTimeout( readyForSeek, 50 );
+ rfsCount++;
+ } else {
+ mw.log( 'Error: EmbedPlayerVlc doPlayThenSeek failed' );
+ }
+ }
+ }
+ readyForSeek();
+ },
+
+ /**
+ * Updates the status time and player state
+ */
+ monitor: function() {
+ this.getPlayerElement();
+ if ( ! this.playerElement ){
+ return ;
+ }
+ // Try to get relay vlc log messages to the console.
+ try{
+ if ( this.playerElement.log.messages.count > 0 ) {
+ // there is one or more messages in the log
+ var iter = this.playerElement.log.messages.iterator();
+ while ( iter.hasNext ) {
+ var msg = iter.next();
+ var msgtype = msg.type.toString();
+ if ( ( msg.severity == 1 ) && ( msgtype == "input" ) )
+ {
+ mw.log( msg.message );
+ }
+ }
+ // clear the log once finished to avoid clogging
+ this.playerElement.log.messages.clear();
+ }
+
+ var newState = this.playerElement.input.state;
+ if ( this.prevState != newState ) {
+ if ( newState == 0 )
+ {
+ // current media has stopped
+ this.onStop();
+ }
+ else if ( newState == 1 )
+ {
+ // current media is opening/connecting
+ this.onOpen();
+ }
+ else if ( newState == 2 )
+ {
+ // current media is buffering data
+ this.onBuffer();
+ }
+ else if ( newState == 3 )
+ {
+ // current media is now playing
+ this.onPlay();
+ }
+ else if ( this.playerElement.input.state == 4 ) {
+ // current media is now paused
+ this.onPause();
+ }
+ this.prevState = newState;
+ } else if ( newState == 3 ) {
+ // current media is playing
+ this.onPlaying();
+ }
+ } catch( e ){
+ mw.log("EmbedPlayerVlc:: Monitor error");
+ }
+ // Update the status and check timer via universal parent monitor
+ this.parent_monitor();
+ },
+
+ /**
+ * Events:
+ */
+ onOpen: function() {
+ // Open is considered equivalent to other players buffer status:
+ this.controlBuilder.setStatus( mw.msg('mwe-embedplayer-buffering') );
+ },
+ onBuffer: function() {
+ this.controlBuilder.setStatus( mw.msg('mwe-embedplayer-buffering') );
+ },
+ onPlay: function() {
+ this.onPlaying();
+ },
+ onPlaying: function() {
+ this.seeking = false;
+ // For now trust the duration from url over vlc input.length
+ if ( !this.getDuration() && this.playerElement.input.length > 0 )
+ {
+ // mw.log('setting duration to ' + this.playerElement.input.length /1000);
+ this.duration = this.playerElement.input.length / 1000;
+ }
+ this.vlcCurrentTime = this.playerElement.input.time / 1000;
+ },
+
+ /**
+ * Get the embed player time
+ */
+ getPlayerElementTime: function(){
+ return this.vlcCurrentTime;
+ },
+
+ onPause: function() {
+ // Update the interface if paused via native plugin
+ this.parent_pause();
+ },
+ onStop: function() {
+ mw.log( 'EmbedPlayerVlc:: onStop' );
+ if ( !this.seeking ){
+ this.onClipDone();
+ }
+ },
+
+ /**
+ * Handles play requests
+ */
+ play: function() {
+ mw.log( 'EmbedPlayerVlc:: play' );
+ // Update the interface
+ this.parent_play();
+ if ( this.getPlayerElement() ) {
+ // plugin is already being present send play call:
+ // clear the message log and enable error logging
+ if ( this.playerElement.log ) {
+ this.playerElement.log.messages.clear();
+ }
+ if ( this.playerElement.playlist && typeof this.playerElement.playlist.play == 'function')
+ this.playerElement.playlist.play();
+
+ if( typeof this.playerElement.play == 'function' )
+ this.playerElement.play();
+
+ this.paused = false;
+
+ // re-start the monitor:
+ this.monitor();
+ }
+ },
+
+ /**
+ * Passes the Pause request to the plugin.
+ * calls parent "pause" to update interface
+ */
+ pause: function() {
+ this.parent_pause(); // update the interface if paused via native control
+ if ( this.getPlayerElement() ) {
+ try{
+ this.playerElement.playlist.togglePause();
+ } catch( e ){
+ mw.log("EmbedPlayerVlc:: Could not pause video " + e);
+ }
+ }
+ },
+
+ /**
+ * Mutes the video
+ * calls parent "toggleMute" to update interface
+ */
+ toggleMute:function() {
+ this.parent_toggleMute();
+ if ( this.getPlayerElement() ){
+ this.playerElement.audio.toggleMute();
+ }
+ },
+
+ /**
+ * Update the player volume
+ * @parm {Float} percent Percent of total volume
+ */
+ setPlayerElementVolume: function ( percent ) {
+ if ( this.getPlayerElement() && this.playerElement.audio ) {
+ this.playerElement.audio.volume = percent * 100;
+ }
+ },
+
+ /**
+ * Gets the current volume
+ * @return {Float} percent percent of total volume
+ */
+ getVolumen:function() {
+ if ( this.getPlayerElement() ){
+ return this.playerElement.audio.volume / 100;
+ }
+ },
+
+ /**
+ * Passes fullscreen request to plugin
+ */
+ fullscreen : function() {
+ if ( this.playerElement ) {
+ if ( this.playerElement.video ){
+ try{
+ this.playerElement.video.toggleFullscreen();
+ } catch ( e ){
+ mw.log("EmbedPlayerVlc:: toggle fullscreen : possible error: " + e);
+ }
+ }
+ }
+ },
+
+ /**
+ * Get the embed vlc object
+ */
+ getPlayerElement : function() {
+ this.playerElement = $( '#' + this.pid )[0];
+ return this.playerElement;
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedTypes.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedTypes.js
new file mode 100644
index 00000000..21b2f452
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.EmbedTypes.js
@@ -0,0 +1,360 @@
+/**
+ * mw.EmbedTypes object handles setting and getting of supported embed types:
+ * closely mirrors OggHandler so that its easier to share efforts in this area:
+ * http://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/OggHandler/OggPlayer.js
+ */
+( function( mw, $ ) { "use strict";
+
+/**
+ * Setup local players and supported mime types In an ideal world we would query the plugin
+ * to get what mime types it supports in practice not always reliable/available
+ *
+ * We can't cleanly store these values per library since player library is sometimes
+ * loaded post player detection
+ */
+// Flash based players:
+var kplayer = new mw.MediaPlayer('kplayer', [
+ 'video/x-flv',
+ 'video/h264',
+ 'video/mp4; codecs="avc1.42E01E"',
+ 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
+ 'audio/mpeg'
+], 'Kplayer');
+
+// Native html5 players
+var oggNativePlayer = new mw.MediaPlayer( 'oggNative', [
+ 'video/ogg',
+ 'video/ogg; codecs="theora"',
+ 'video/ogg; codecs="theora, vorbis"',
+ 'audio/ogg',
+ 'audio/ogg; codecs="vorbis"',
+ 'application/ogg'
+], 'Native' );
+// Native html5 players
+var opusNativePlayer = new mw.MediaPlayer( 'opusNative', [
+ 'audio/ogg; codecs="opus"',
+], 'Native' );
+var h264NativePlayer = new mw.MediaPlayer( 'h264Native', [
+ 'video/h264',
+ 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
+], 'Native' );
+var appleVdnPlayer = new mw.MediaPlayer( 'appleVdn', [
+ 'application/vnd.apple.mpegurl',
+ 'application/vnd.apple.mpegurl; codecs="avc1.42E01E"'
+], 'Native');
+var mp3NativePlayer = new mw.MediaPlayer( 'mp3Native', [
+ 'audio/mpeg',
+ 'audio/mp3'
+], 'Native' );
+var aacNativePlayer = new mw.MediaPlayer( 'aacNative', [
+ 'audio/mp4',
+ 'audio/mp4; codecs="mp4a.40.5"'
+], 'Native' );
+var webmNativePlayer = new mw.MediaPlayer( 'webmNative', [
+ 'video/webm',
+ 'video/webm; codecs="vp8"',
+ 'video/webm; codecs="vp8, vorbis"',
+ 'audio/webm',
+ 'audio/webm; codecs="vorbis"'
+], 'Native' );
+var vp9NativePlayer = new mw.MediaPlayer( 'vp9Native', [
+ 'video/webm; codecs="vp9"',
+ 'video/webm; codecs="vp9, opus"',
+ 'video/webm; codecs="vp9, vorbis"',
+ 'audio/webm; codecs="opus"'
+], 'Native' );
+
+// Image Overlay player ( extends native )
+var imageOverlayPlayer = new mw.MediaPlayer( 'imageOverlay', [
+ 'image/jpeg',
+ 'image/png'
+], 'ImageOverlay' );
+
+// VLC player
+//var vlcMimeList = ['video/ogg', 'audio/ogg', 'audio/mpeg', 'application/ogg', 'video/x-flv', 'video/mp4', 'video/h264', 'video/x-msvideo', 'video/mpeg', 'video/3gp'];
+//var vlcPlayer = new mw.MediaPlayer( 'vlc-player', vlcMimeList, 'Vlc' );
+
+var vlcAppPlayer = new mw.MediaPlayer( 'vlcAppPlayer', [
+ 'video/ogg',
+ 'video/ogg; codecs="theora"',
+ 'video/ogg; codecs="theora, vorbis"',
+ 'audio/ogg',
+ 'audio/ogg; codecs="vorbis"',
+ 'audio/ogg; codecs="opus"',
+ 'application/ogg',
+ 'video/webm',
+ 'video/webm; codecs="vp8"',
+ 'video/webm; codecs="vp8, vorbis"',
+], 'VLCApp' );
+
+var IEWebMPrompt = new mw.MediaPlayer( 'IEWebMPrompt', [
+ 'video/webm',
+ 'video/webm; codecs="vp8"',
+ 'video/webm; codecs="vp8, vorbis"'
+], 'IEWebMPrompt' );
+
+var ogvJsPlayer = new mw.MediaPlayer( 'ogvJsPlayer', [
+ 'video/ogg',
+ 'video/ogg; codecs="theora"',
+ 'video/ogg; codecs="theora, vorbis"',
+ 'video/ogg; codecs="theora, opus"',
+ 'audio/ogg',
+ 'audio/ogg; codecs="vorbis"',
+ 'audio/ogg; codecs="opus"',
+ 'application/ogg'
+], 'OgvJs' );
+
+// Generic plugin
+//var oggPluginPlayer = new mw.MediaPlayer( 'oggPlugin', ['video/ogg', 'application/ogg'], 'Generic' );
+
+
+mw.EmbedTypes = {
+
+ // MediaPlayers object ( supports methods for quering set of browser players )
+ mediaPlayers: null,
+
+ // Detect flag for completion
+ detect_done:false,
+
+ /**
+ * Runs the detect method and update the detect_done flag
+ *
+ * @constructor
+ */
+ init: function() {
+ // detect supported types
+ this.detect();
+ this.detect_done = true;
+ },
+
+ getMediaPlayers: function(){
+ if( this.mediaPlayers ){
+ return this.mediaPlayers;
+ }
+ this.mediaPlayers = new mw.MediaPlayers();
+ // detect available players
+ this.detectPlayers();
+ return this.mediaPlayers;
+ },
+
+ /**
+ * If the browsers supports a given mimetype
+ *
+ * @param {String}
+ * mimeType Mime type for browser plug-in check
+ */
+ supportedMimeType: function( mimeType ) {
+ for ( var i =0; i < navigator.plugins.length; i++ ) {
+ var plugin = navigator.plugins[i];
+ if ( typeof plugin[ mimeType ] != "undefined" ){
+ return true;
+ }
+ }
+ return false;
+ },
+ addFlashPlayer: function(){
+ if( !mw.config.get( 'EmbedPlayer.DisableHTML5FlashFallback' ) ){
+ this.mediaPlayers.addPlayer( kplayer );
+ }
+ },
+ /**
+ * Detects what plug-ins the client supports
+ */
+ detectPlayers: function() {
+ mw.log( "EmbedTypes::detectPlayers running detect" );
+
+ // All players support for playing "images"
+ this.mediaPlayers.addPlayer( imageOverlayPlayer );
+
+ // Some browsers filter out duplicate mime types, hiding some plugins
+ var uniqueMimesOnly = $.client.test( { opera: null, safari: null } );
+
+ // Use core mw.supportsFlash check:
+ if( mw.supportsFlash() ){
+ this.addFlashPlayer();
+ }
+
+ // ActiveX plugins
+ if ( $.client.profile().name === 'msie' ) {
+ // VLC
+ //if ( this.testActiveX( 'VideoLAN.VLCPlugin.2' ) ) {
+ // this.mediaPlayers.addPlayer( vlcPlayer );
+ //}
+
+ // quicktime (currently off)
+ // if ( this.testActiveX(
+ // 'QuickTimeCheckObject.QuickTimeCheck.1' ) )
+ // this.mediaPlayers.addPlayer(quicktimeActiveXPlayer);
+ }
+ // <video> element
+ if ( ! mw.config.get('EmbedPlayer.DisableVideoTagSupport' ) // to support testing limited / old browsers
+ &&
+ (
+ typeof HTMLVideoElement == 'object' // Firefox, Safari
+ ||
+ typeof HTMLVideoElement == 'function' // Opera
+ )
+ ){
+ // Test what codecs the native player supports:
+ try {
+ var dummyvid = document.createElement( "video" );
+ if( dummyvid.canPlayType ) {
+ // Add the webm player
+ if( dummyvid.canPlayType('video/webm; codecs="vp8, vorbis"') ){
+ this.mediaPlayers.addPlayer( webmNativePlayer );
+ }
+ if( dummyvid.canPlayType('video/webm; codecs="vp9, opus"') ){
+ this.mediaPlayers.addPlayer( vp9NativePlayer );
+ }
+
+ // Test for MP3:
+ if ( this.supportedMimeType('audio/mpeg') ) {
+ this.mediaPlayers.addPlayer( mp3NativePlayer );
+ }
+
+ // Test for AAC:
+ if ( dummyvid.canPlayType( 'audio/mp4; codecs="mp4a.40.5"' ) ) {
+ this.mediaPlayers.addPlayer( aacNativePlayer );
+ }
+
+ // Test for h264:
+ if ( dummyvid.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"' ) ) {
+ this.mediaPlayers.addPlayer( h264NativePlayer );
+ // Check for iOS for vdn player support ( apple adaptive ) or vdn canPlayType != '' ( ie maybe/probably )
+ if( mw.isIOS() || dummyvid.canPlayType('application/vnd.apple.mpegurl; codecs="avc1.42E01E"' ) ){
+ // Android 3x lies about HLS support ( only add if not Android 3.x )
+ if( navigator.userAgent.indexOf( 'Android 3.') == -1 ){
+ this.mediaPlayers.addPlayer( appleVdnPlayer );
+ }
+ }
+
+ }
+ // For now if Android assume we support h264Native (FIXME
+ // test on real devices )
+ if ( mw.isAndroid2() ){
+ this.mediaPlayers.addPlayer( h264NativePlayer );
+ }
+
+ // Test for ogg
+ if ( dummyvid.canPlayType( 'video/ogg; codecs="theora, vorbis"' ) ||
+ dummyvid.canPlayType( 'audio/ogg; codecs="vorbis"' )
+ ) {
+ this.mediaPlayers.addPlayer( oggNativePlayer );
+ }
+
+ // Test for opus
+ if ( dummyvid.canPlayType( 'audio/ogg; codecs="opus"' ).replace(/maybe/, '') ) {
+ this.mediaPlayers.addPlayer( opusNativePlayer );
+ }
+ }
+ } catch ( e ) {
+ mw.log( 'could not run canPlayType ' + e );
+ }
+ }
+
+ // "navigator" plugins
+ if ( navigator.mimeTypes && navigator.mimeTypes.length > 0 ) {
+ for ( var i = 0; i < navigator.mimeTypes.length; i++ ) {
+ var type = navigator.mimeTypes[i].type;
+ var semicolonPos = type.indexOf( ';' );
+ if ( semicolonPos > -1 ) {
+ type = type.substr( 0, semicolonPos );
+ }
+ // mw.log( 'on type: ' + type );
+ var pluginName = navigator.mimeTypes[i].enabledPlugin ? navigator.mimeTypes[i].enabledPlugin.name : '';
+ if ( !pluginName ) {
+ // In case it is null or undefined
+ pluginName = '';
+ }
+ //if ( pluginName.toLowerCase() == 'vlc multimedia plugin' || pluginName.toLowerCase() == 'vlc multimedia plug-in' ) {
+ // this.mediaPlayers.addPlayer( vlcPlayer );
+ // continue;
+ //}
+
+ if ( (type == 'video/mpeg' || type == 'video/x-msvideo') ){
+ //pluginName.toLowerCase() == 'vlc multimedia plugin' ) {
+ //this.mediaPlayers.addPlayer( vlcMozillaPlayer );
+ }
+
+ if ( type == 'application/ogg' ) {
+ //if ( pluginName.toLowerCase() == 'vlc multimedia plugin' ) {
+ //this.mediaPlayers.addPlayer( vlcMozillaPlayer );
+ //else if ( pluginName.indexOf( 'QuickTime' ) > -1 )
+ //this.mediaPlayers.addPlayer(quicktimeMozillaPlayer);
+ //} else {
+ //this.mediaPlayers.addPlayer( oggPluginPlayer );
+ //}
+ continue;
+ } else if ( uniqueMimesOnly ) {
+ if ( type == 'application/x-vlc-player' ) {
+ // this.mediaPlayers.addPlayer( vlcMozillaPlayer );
+ continue;
+ } else if ( type == 'video/quicktime' ) {
+ // this.mediaPlayers.addPlayer(quicktimeMozillaPlayer);
+ continue;
+ }
+ }
+ }
+ }
+
+ if ( mw.isIOS() ) {
+ this.mediaPlayers.addPlayer( vlcAppPlayer );
+ }
+
+ // Note IE 11 doesn't identify itself as 'MSIE'.
+ // For simplicity just check for the rendering engine codename 'Trident'.
+ if ( navigator.userAgent.indexOf( 'Trident' ) != -1 ) {
+ if ( this.mediaPlayers.isSupportedPlayer( 'webmNative' ) ) {
+ // IE has the WebM components already, leave it be!
+ } else if ( navigator.userAgent.indexOf( 'ARM' ) != -1 ) {
+ // Windows RT doesn't allow installation of the WebM components.
+ // Don't tease the poor user.
+ } else {
+ // Prompt user to install the WebM media components for IE 9+
+ this.mediaPlayers.addPlayer( IEWebMPrompt );
+ }
+ }
+
+ // ogv.js compatibility detection...
+ if ( OGVCompat.supported( 'OGVPlayer' ) ) {
+ // ogv.js emscripten version
+ //
+ // Works in:
+ // * Safari 6.1+ on Mac OS X
+ // * Safari on iOS 8+ (best on 64-bit devices)
+ // * IE 10/11 on Windows 7/8/8.1 (requires Flash for audio)
+ // * Edge on Windows 10 (no plugins needed)
+ //
+ // Current Firefox, Chrome, Opera all work great too, but use
+ // native playback by default of course!
+ //
+ this.mediaPlayers.addPlayer( ogvJsPlayer );
+ }
+
+ // Allow extensions to detect and add their own "players"
+ mw.log("EmbedPlayer::trigger:embedPlayerUpdateMediaPlayersEvent");
+ $( mw ).trigger( 'embedPlayerUpdateMediaPlayersEvent' , this.mediaPlayers );
+
+ },
+
+ /**
+ * Test IE for activeX by name
+ *
+ * @param {String}
+ * name Name of ActiveXObject to look for
+ */
+ testActiveX : function ( name ) {
+ mw.log("EmbedPlayer::detect: test testActiveX: " + name);
+ var hasObj = true;
+ try {
+ // No IE, not a class called "name", it's a variable
+ var obj = new ActiveXObject( '' + name );
+ } catch ( e ) {
+ hasObj = false;
+ }
+ return hasObj;
+ }
+};
+
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaElement.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaElement.js
new file mode 100644
index 00000000..9af48998
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaElement.js
@@ -0,0 +1,491 @@
+/**
+ * A media element corresponding to a <video> element.
+ *
+ * It is implemented as a collection of mediaSource objects. The media sources
+ * will be initialized from the <video> element, its child <source> elements,
+ * and/or the ROE file referenced by the <video> element.
+ *
+ * @param {element}
+ * videoElement <video> element used for initialization.
+ * @constructor
+ */
+( function( mw, $ ) { "use strict";
+
+mw.MediaElement = function( element ) {
+ this.init( element );
+};
+
+mw.MediaElement.prototype = {
+
+ // The array of mediaSource elements.
+ sources: null,
+
+ // flag for ROE data being added.
+ addedROEData: false,
+
+ // Selected mediaSource element.
+ selectedSource: null,
+
+ /**
+ * Media Element constructor
+ *
+ * Sets up a mediaElement from a provided top level "video" element adds any
+ * child sources that are found
+ *
+ * @param {Element}
+ * videoElement Element that has src attribute or has children
+ * source elements
+ */
+ init: function( videoElement ) {
+ var _this = this;
+ mw.log( "EmbedPlayer::mediaElement:init:" + videoElement.id );
+ this.parentEmbedId = videoElement.id;
+ this.sources = new Array();
+
+ // Process the videoElement as a source element:
+ if( videoElement ){
+ if ( $( videoElement ).attr( "src" ) ) {
+ _this.tryAddSource( videoElement );
+ }
+ // Process elements source children
+ $( videoElement ).find( 'source,track' ).each( function( ) {
+ _this.tryAddSource( this );
+ } );
+ }
+ },
+
+ /**
+ * Updates the time request for all sources that have a standard time
+ * request argument (ie &t=start_time/end_time)
+ *
+ * @param {String}
+ * startNpt Start time in npt format
+ * @param {String}
+ * endNpt End time in npt format
+ */
+ updateSourceTimes: function( startNpt, endNpt ) {
+ var _this = this;
+ $.each( this.sources, function( inx, mediaSource ) {
+ mediaSource.updateSrcTime( startNpt, endNpt );
+ } );
+ },
+
+ /**
+ * Get Text tracks
+ */
+ getTextTracks: function(){
+ var textTracks = [];
+ $.each( this.sources, function(inx, source ){
+ if ( source.nodeName == 'track' || ( source.mimeType && source.mimeType.indexOf('text/') !== -1 )){
+ textTracks.push( source );
+ }
+ });
+ return textTracks;
+ },
+ /**
+ * Returns the array of mediaSources of this element.
+ *
+ * @param {String}
+ * [mimeFilter] Filter criteria for set of mediaSources to return
+ * @return {Array} mediaSource elements.
+ */
+ getSources: function( mimeFilter ) {
+ if ( !mimeFilter ) {
+ return this.sources;
+ }
+ // Apply mime filter:
+ var source_set = new Array();
+ for ( var i = 0; i < this.sources.length ; i++ ) {
+ if ( this.sources[i].mimeType &&
+ this.sources[i].mimeType.indexOf( mimeFilter ) != -1 )
+ {
+ source_set.push( this.sources[i] );
+ }
+ }
+ return source_set;
+ },
+
+ /**
+ * Selects a source by id
+ *
+ * @param {String}
+ * sourceId Id of the source to select.
+ * @return {MediaSource} The selected mediaSource or null if not found
+ */
+ getSourceById:function( sourceId ) {
+ for ( var i = 0; i < this.sources.length ; i++ ) {
+ if ( this.sources[i].id == sourceId ) {
+ return this.sources[i];
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Selects a particular source for playback updating the "selectedSource"
+ *
+ * @param {Number}
+ * index Index of source element to set as selectedSource
+ */
+ setSourceByIndex: function( index ) {
+ mw.log( 'EmbedPlayer::mediaElement:selectSource: ' + index );
+ var oldSrc = this.selectedSource.getSrc();
+ var playableSources = this.getPlayableSources();
+ for ( var i = 0; i < playableSources.length; i++ ) {
+ if ( i == index ) {
+ this.selectedSource = playableSources[i];
+ break;
+ }
+ }
+ if( oldSrc != this.selectedSource.getSrc() ){
+ $( '#' + this.parentEmbedId ).trigger( 'SourceChange');
+ }
+ },
+ /**
+ * Sets a the selected source to passed in source object
+ * @param {Object} Source
+ */
+ setSource: function( source ){
+ var oldSrc = this.selectedSource.getSrc();
+ this.selectedSource = source;
+ if( oldSrc != this.selectedSource.getSrc() ){
+ $( '#' + this.parentEmbedId ).trigger( 'SourceChange');
+ }
+ },
+
+
+ /**
+ * Selects the default source via cookie preference, default marked, or by
+ * id order
+ */
+ autoSelectSource: function() {
+ mw.log( 'EmbedPlayer::mediaElement::autoSelectSource' );
+ var _this = this;
+ // Select the default source
+ var playableSources = this.getPlayableSources();
+ var flash_flag = false, ogg_flag = false;
+ // Check if there are any playableSources
+ if( playableSources.length == 0 ){
+ return false;
+ }
+ var setSelectedSource = function( source ){
+ _this.selectedSource = source;
+ return _this.selectedSource;
+ };
+
+ // Set via module driven preference:
+ $( this ).trigger( 'onSelectSource', playableSources );
+
+ if( _this.selectedSource ){
+ mw.log('MediaElement::autoSelectSource: Set via trigger::' + _this.selectedSource.getTitle() );
+ return _this.selectedSource;
+ }
+
+ // Set via marked default:
+ $.each( playableSources, function( inx, source ){
+ if ( source.markedDefault ) {
+ mw.log( 'MediaElement::autoSelectSource: Set via marked default: ' + source.markedDefault );
+ return setSelectedSource( source );;
+ }
+ });
+
+ // Set apple adaptive ( if available )
+ var vndSources = this.getPlayableSources('application/vnd.apple.mpegurl')
+ if( vndSources.length && mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'application/vnd.apple.mpegurl' ).length ){
+ // Check for device flags:
+ var desktopVdn, mobileVdn;
+ $.each( vndSources, function( inx, source) {
+ // Kaltura tags vdn sources with iphonenew
+ if( source.getFlavorId() && source.getFlavorId().toLowerCase() == 'iphonenew' ){
+ mobileVdn = source;
+ } else {
+ desktopVdn = source;
+ }
+ })
+ // NOTE: We really should not have two VDN sources the point of vdn is to be a set of adaptive streams.
+ // This work around is a result of Kaltura HLS stream tagging
+ if( mw.isIphone() && mobileVdn ){
+ setSelectedSource( mobileVdn );
+ } else if( desktopVdn ){
+ setSelectedSource( desktopVdn );
+ }
+ }
+ if ( this.selectedSource ) {
+ mw.log('MediaElement::autoSelectSource: Set via Adaptive HLS: source flavor id:' + _this.selectedSource.getFlavorId() + ' src: ' + _this.selectedSource.getSrc() );
+ return this.selectedSource;
+ }
+
+ // Set via user bandwidth pref will always set source to closest bandwidth allocation while not going over EmbedPlayer.UserBandwidth
+ if( $.cookie('EmbedPlayer.UserBandwidth') ){
+ var bandwidthDelta = 999999999;
+ var bandwidthTarget = $.cookie('EmbedPlayer.UserBandwidth');
+ $.each( playableSources, function(inx, source ){
+ if( source.bandwidth ){
+ // Check if a native source ( takes president over bandwidth selection )
+ var player = mw.EmbedTypes.getMediaPlayers().defaultPlayer( source.mimeType );
+ if ( !player || player.library != 'Native' ) {
+ // continue
+ return true;
+ }
+
+ if( Math.abs( source.bandwidth - bandwidthTarget ) < bandwidthDelta ){
+ bandwidthDelta = Math.abs( source.bandwidth - bandwidthTarget );
+ setSelectedSource( source );
+ }
+ }
+ });
+ }
+
+ if ( this.selectedSource ) {
+ mw.log('MediaElement::autoSelectSource: Set via bandwidth prefrence: source ' + this.selectedSource.bandwidth + ' user: ' + $.cookie('EmbedPlayer.UserBandwidth') );
+ return this.selectedSource;
+ }
+
+
+ // If we have at least one native source, throw out non-native sources
+ // for size based source selection:
+ var nativePlayableSources = [];
+ $.each( playableSources, function(inx, source ){
+ var mimeType = source.mimeType;
+ var player = mw.EmbedTypes.getMediaPlayers().defaultPlayer( mimeType );
+ if ( player && player.library == 'Native' ) {
+ nativePlayableSources.push( source );
+ }
+ });
+
+ // Prefer native playback ( and prefer WebM over ogg and h.264 )
+ var namedSourceSet = {};
+ var useBogoSlow = false; // use benchmark only for ogv.js
+ $.each( playableSources, function(inx, source ){
+ var mimeType = source.mimeType;
+ var player = mw.EmbedTypes.getMediaPlayers().defaultPlayer( mimeType );
+ if ( player && ( player.library == 'Native' || player.library == 'OgvJs' ) ) {
+ switch( player.id ){
+ case 'mp3Native':
+ var shortName = 'mp3';
+ break;
+ case 'aacNative':
+ var shortName = 'aac';
+ break;
+ case 'oggNative':
+ var shortName = 'ogg';
+ break;
+ case 'ogvJsPlayer':
+ useBogoSlow = true;
+ var shortName = 'ogg';
+ break;
+ case 'webmNative':
+ var shortName = 'webm';
+ break;
+ case 'vp9Native':
+ var shortName = 'vp9';
+ break;
+ case 'h264Native':
+ var shortName = 'h264';
+ break;
+ case 'appleVdn':
+ var shortName = 'appleVdn';
+ break;
+ }
+ if( !namedSourceSet[ shortName ] ){
+ namedSourceSet[ shortName ] = [];
+ }
+ namedSourceSet[ shortName ].push( source );
+ }
+ });
+
+ var codecPref = mw.config.get( 'EmbedPlayer.CodecPreference');
+
+ // if on android 4 use mp4 over webm
+ if( mw.isAndroid40() ){
+ if( codecPref && codecPref[0] == 'webm' ){
+ codecPref[0] = 'h264';
+ codecPref[1] = 'webm';
+ }
+ }
+
+ if( codecPref ){
+ for(var i =0; i < codecPref.length; i++){
+ var codec = codecPref[ i ];
+ if( ! namedSourceSet[ codec ] ){
+ continue;
+ }
+ if( namedSourceSet[ codec ].length == 1 ){
+ mw.log('MediaElement::autoSelectSource: Set 1 source via EmbedPlayer.CodecPreference: ' + namedSourceSet[ codec ][0].getTitle() );
+ return setSelectedSource( namedSourceSet[ codec ][0] );
+ } else if( namedSourceSet[ codec ].length > 1 ) {
+ // select based on size:
+ // Set via embed resolution closest to relative to display size
+ var minSizeDelta = null;
+
+ // unless we're really slow...
+ var isBogoSlow = useBogoSlow && OGVCompat.isSlow();
+
+ if( this.parentEmbedId ){
+ var displayWidth = $('#' + this.parentEmbedId).width();
+ $.each( namedSourceSet[ codec ], function(inx, source ){
+ if ( ( isBogoSlow && source.height > 240 )
+ || (useBogoSlow && source.height > 360 ) ) {
+ // On iOS or slow Windows devices, large videos decoded in JavaScript are a bad idea!
+ // continue
+ return true;
+ }
+ if( source.width && displayWidth ){
+ var sizeDelta = Math.abs( source.width - displayWidth );
+ mw.log('MediaElement::autoSelectSource: size delta : ' + sizeDelta + ' for s:' + source.width );
+ if( minSizeDelta == null || sizeDelta < minSizeDelta){
+ minSizeDelta = sizeDelta;
+ setSelectedSource( source );
+ }
+ }
+ });
+ }
+ // If we found a source via display size return:
+ if ( this.selectedSource ) {
+ mw.log('MediaElement::autoSelectSource: from ' + this.selectedSource.mimeType + ' because of resolution:' + this.selectedSource.width + ' close to: ' + displayWidth );
+ return this.selectedSource;
+ }
+ // if no size info is set just select the first source:
+ if( namedSourceSet[ codec ][0] ){
+ return setSelectedSource( namedSourceSet[ codec ][0] );
+ }
+ }
+ };
+ }
+
+ // Set h264 via native or flash fallback
+ $.each( playableSources, function(inx, source ){
+ var mimeType = source.mimeType;
+ var player = mw.EmbedTypes.getMediaPlayers().defaultPlayer( mimeType );
+ if ( mimeType == 'video/h264'
+ && player
+ && (
+ player.library == 'Native'
+ ||
+ player.library == 'Kplayer'
+ )
+ ) {
+ if( source ){
+ mw.log('MediaElement::autoSelectSource: Set h264 via native or flash fallback:' + source.getTitle() );
+ return setSelectedSource( source );
+ }
+ }
+ });
+
+ // Else just select the first playable source
+ if ( !this.selectedSource && playableSources[0] ) {
+ mw.log( 'MediaElement::autoSelectSource: Set via first source: ' + playableSources[0].getTitle() + ' mime: ' + playableSources[0].getMIMEType() );
+ return setSelectedSource( playableSources[0] );
+ }
+ // No Source found so no source selected
+ return false;
+ },
+
+ /**
+ * check if the mime is ogg
+ */
+ isOgg: function( mimeType ){
+ if ( mimeType == 'video/ogg'
+ || mimeType == 'ogg/video'
+ || mimeType == 'video/annodex'
+ || mimeType == 'application/ogg'
+ ) {
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Returns the thumbnail URL for the media element.
+ *
+ * @returns {String} thumbnail URL
+ */
+ getPosterSrc: function( ) {
+ return this.poster;
+ },
+
+ /**
+ * Checks whether there is a stream of a specified MIME type.
+ *
+ * @param {String}
+ * mimeType MIME type to check.
+ * @return {Boolean} true if sources include MIME false if not.
+ */
+ hasStreamOfMIMEType: function( mimeType )
+ {
+ for ( var i = 0; i < this.sources.length; i++ )
+ {
+ if ( this.sources[i].getMIMEType() == mimeType ){
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Checks if media is a playable type
+ */
+ isPlayableType: function( mimeType ) {
+ // mw.log("isPlayableType:: " + mimeType);
+ if ( mw.EmbedTypes.getMediaPlayers().defaultPlayer( mimeType ) ) {
+ mw.log("isPlayableType:: " + mimeType);
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Adds a single mediaSource using the provided element if the element has a
+ * 'src' attribute.
+ *
+ * @param {Element}
+ * element <video>, <source> or <mediaSource> <text> element.
+ */
+ tryAddSource: function( element ) {
+ //mw.log( 'mw.MediaElement::tryAddSource:' + $( element ).attr( "src" ) );
+ var newSrc = $( element ).attr( 'src' );
+ if ( newSrc ) {
+ // Make sure an existing element with the same src does not already exist:
+ for ( var i = 0; i < this.sources.length; i++ ) {
+ if ( this.sources[i].src == newSrc ) {
+ // Source already exists update any new attr:
+ this.sources[i].updateSource( element );
+ return this.sources[i];
+ }
+ }
+ }
+ // Create a new source
+ var source = new mw.MediaSource( element );
+
+ this.sources.push( source );
+ //mw.log( 'tryAddSource: added source ::' + source + 'sl:' + this.sources.length );
+ return source;
+ },
+
+ /**
+ * Get playable sources
+ *
+ *@pram mimeFilter {=string} (optional) Filter the playable sources set by mime filter
+ *
+ * @returns {Array} of playable media sources
+ */
+ getPlayableSources: function( mimeFilter ) {
+ var playableSources = [];
+ for ( var i = 0; i < this.sources.length; i++ ) {
+ if ( this.isPlayableType( this.sources[i].mimeType )
+ &&
+ ( !mimeFilter || this.sources[i].mimeType.indexOf( mimeFilter) != -1 )
+ ){
+ playableSources.push( this.sources[i] );
+ }
+ };
+ mw.log( "MediaElement::GetPlayableSources mimeFilter:" + mimeFilter + " " +
+ playableSources.length + ' sources playable out of ' + this.sources.length );
+
+ return playableSources;
+ }
+};
+
+} )( mediaWiki, jQuery );
+
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaPlayer.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaPlayer.js
new file mode 100644
index 00000000..94ef9708
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaPlayer.js
@@ -0,0 +1,85 @@
+/**
+ * mediaPlayer represents a media player plugin.
+ *
+ * @param {String}
+ * id id used for the plugin.
+ * @param {Array}
+ * supportedTypes an array of supported MIME types.
+ * @param {String}
+ * library external script containing the plugin interface code.
+ * @constructor
+ */
+( function( mw, $ ) { "use strict";
+
+mw.MediaPlayer = function( id, supportedTypes, library )
+{
+ this.id = id;
+ this.supportedTypes = supportedTypes;
+ this.library = library;
+ this.loaded = false;
+ this.loading_callbacks = new Array();
+ return this;
+};
+mw.MediaPlayer.prototype = {
+ // Id of the mediaPlayer
+ id:null,
+
+ // Mime types supported by this player
+ supportedTypes:null,
+
+ // Player library ie: native, vlc etc.
+ library:null,
+
+ // Flag stores the mediaPlayer load state
+ loaded:false,
+
+ /**
+ * Checks support for a given MIME type
+ *
+ * @param {String}
+ * type Mime type to check against supportedTypes
+ * @return {Boolean} true if mime type is supported false if mime type is
+ * unsupported
+ */
+ supportsMIMEType: function( type ) {
+ for ( var i = 0; i < this.supportedTypes.length; i++ ) {
+ if ( this.supportedTypes[i] == type )
+ return true;
+ }
+ return false;
+ },
+
+ /**
+ * Get the "name" of the player from a predictable msg key
+ */
+ getName: function() {
+ // Give grep a chance to find the usages:
+ // mwe-embedplayer-ogg-player-vlc-player, mwe-embedplayer-ogg-player-oggNative, mwe-embedplayer-ogg-player-mp3Native,
+ // mwe-embedplayer-ogg-player-aacNative, mwe-embedplayer-ogg-player-h264Native, mwe-embedplayer-ogg-player-webmNative,
+ // mwe-embedplayer-ogg-player-oggPlugin, mwe-embedplayer-ogg-player-quicktime-mozilla,
+ // mwe-embedplayer-ogg-player-quicktime-activex, mwe-embedplayer-ogg-player-cortado,
+ // mwe-embedplayer-ogg-player-flowplayer, mwe-embedplayer-ogg-player-kplayer, mwe-embedplayer-ogg-player-selected,
+ // mwe-embedplayer-ogg-player-omtkplayer
+ return mw.msg( 'mwe-embedplayer-ogg-player-' + this.id );
+ },
+
+ /**
+ * Loads the player library & player skin config ( if needed ) and then
+ * calls the callback.
+ *
+ * @param {Function}
+ * callback Function to be called once player library is loaded.
+ */
+ load: function( callback ) {
+ // Load player library ( upper case the first letter of the library )
+ mw.load( [
+ 'mw.EmbedPlayer' + this.library.substr(0,1).toUpperCase() + this.library.substr(1)
+ ], function() {
+ if( callback ){
+ callback();
+ }
+ } );
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaPlayers.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaPlayers.js
new file mode 100644
index 00000000..9d1e34f4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaPlayers.js
@@ -0,0 +1,195 @@
+/**
+ * mediaPlayers is a collection of mediaPlayer objects supported by the client.
+ *
+ * @constructor
+ */
+( function( mw, $ ) { "use strict";
+
+mw.MediaPlayers = function(){
+ this.init();
+};
+
+mw.MediaPlayers.prototype = {
+ // The list of players supported
+ players : null,
+
+ // Store per mime-type preferences for players
+ preference : { },
+
+ // Stores the default set of players for a given mime type
+ defaultPlayers : { },
+
+ /**
+ * Initializartion function sets the default order for players for a given
+ * mime type
+ */
+ init: function() {
+ this.players = new Array();
+ this.loadPreferences();
+
+ // Set up default players order for each library type
+ this.defaultPlayers['video/x-flv'] = ['Kplayer', 'Vlc'];
+ this.defaultPlayers['video/h264'] = ['Native', 'Kplayer', 'Vlc'];
+
+ this.defaultPlayers['application/vnd.apple.mpegurl'] = ['Native'];
+
+ this.defaultPlayers['video/ogg'] = ['Native', 'Vlc', 'OgvJs', 'Generic', 'VLCApp'];
+ this.defaultPlayers['audio/webm'] = ['Native', 'Vlc', 'VLCApp', 'IEWebMPrompt'];
+ this.defaultPlayers['video/webm'] = ['Native', 'Vlc', 'VLCApp', 'IEWebMPrompt'];
+ this.defaultPlayers['application/ogg'] = ['Native', 'Vlc', 'OgvJs', 'Generic', 'VLCApp'];
+ this.defaultPlayers['audio/ogg'] = ['Native', 'Vlc', 'OgvJs', 'VLCApp'];
+ this.defaultPlayers['audio/mpeg']= ['Native', 'Kplayer'];
+ this.defaultPlayers['audio/mp3']= ['Native', 'Kplayer'];
+ this.defaultPlayers['audio/mp4']= ['Native'];
+ this.defaultPlayers['video/mp4'] = ['Native', 'Vlc'];
+ this.defaultPlayers['video/mpeg'] = ['Vlc'];
+ this.defaultPlayers['video/x-msvideo'] = ['Vlc'];
+
+ // this.defaultPlayers['text/html'] = ['Html'];
+ //this.defaultPlayers['image/svg'] = ['ImageOverlay'];
+
+ this.defaultPlayers['image/jpeg'] = ['ImageOverlay'];
+ this.defaultPlayers['image/png'] = ['ImageOverlay'];
+
+ },
+
+ /**
+ * Adds a Player to the player list
+ *
+ * @param {Object}
+ * player Player object to be added
+ */
+ addPlayer: function( player ) {
+ for ( var i = 0; i < this.players.length; i++ ) {
+ if ( this.players[i].id == player.id ) {
+ // Player already found
+ return ;
+ }
+ }
+ // Add the player:
+ this.players.push( player );
+ },
+
+ /**
+ * Checks if a player is supported by id
+ */
+ isSupportedPlayer: function( playerId ){
+ for( var i=0; i < this.players.length; i++ ){
+ if( this.players[i].id == playerId ){
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * get players that support a given mimeType
+ *
+ * @param {String}
+ * mimeType Mime type of player set
+ * @return {Array} Array of players that support a the requested mime type
+ */
+ getMIMETypePlayers: function( mimeType ) {
+ var mimePlayers = new Array();
+ var _this = this;
+ var baseMimeType = mimeType.split( ';' )[0];
+ if ( this.defaultPlayers[ baseMimeType ] ) {
+ $.each( this.defaultPlayers[ baseMimeType ], function( d, lib ) {
+ var library = _this.defaultPlayers[ baseMimeType ][ d ];
+ for ( var i = 0; i < _this.players.length; i++ ) {
+ if ( _this.players[i].library == library && _this.players[i].supportsMIMEType( mimeType ) ) {
+ mimePlayers.push( _this.players[i] );
+ }
+ }
+ } );
+ }
+ return mimePlayers;
+ },
+
+ /**
+ * Default player for a given mime type
+ *
+ * @param {String}
+ * mimeType Mime type of the requested player
+ * @return Player for mime type null if no player found
+ */
+ defaultPlayer : function( mimeType ) {
+ // mw.log( "get defaultPlayer for " + mimeType );
+ var mimePlayers = this.getMIMETypePlayers( mimeType );
+ if ( mimePlayers.length > 0 )
+ {
+ // Select the default player:
+ for ( var i = 0; i < mimePlayers.length; i++ ) {
+ // Check for native:
+ if( mimePlayers[i].librayr == 'Native' ){
+ return mimePlayers[i];
+ }
+ // else check for preference
+ if ( mimePlayers[i].id == this.preference[mimeType] ){
+ return mimePlayers[i];
+ }
+ }
+ // Otherwise just return the first compatible player
+ // (it will be chosen according to the defaultPlayers list
+ return mimePlayers[0];
+ }
+ // mw.log( 'No default player found for ' + mimeType );
+ return null;
+ },
+
+ /**
+ * Sets the format preference.
+ *
+ * @param {String}
+ * mimeFormat Prefered format
+ */
+ setFormatPreference : function ( mimeFormat ) {
+ this.preference['formatPreference'] = mimeFormat;
+ $.cookie( 'EmbedPlayer.Preference', JSON.stringify( this.preference) );
+ },
+
+ /**
+ * Loads the user preference settings from a cookie
+ */
+ loadPreferences : function ( ) {
+ this.preference = { };
+ // See if we have a cookie set to a clientSupported type:
+ if( $.cookie( 'EmbedPlayer.Preference' ) ) {
+ this.preference = JSON.parse( $.cookie( 'EmbedPlayer.Preference' ) );
+ }
+ },
+
+ /**
+ * Sets the player preference
+ *
+ * @param {String}
+ * playerId Preferred player id
+ * @param {String}
+ * mimeType Mime type for the associated player stream
+ */
+ setPlayerPreference : function( playerId, mimeType ) {
+ var selectedPlayer = null;
+ for ( var i = 0; i < this.players.length; i++ ) {
+ if ( this.players[i].id == playerId ) {
+ selectedPlayer = this.players[i];
+ mw.log( 'EmbedPlayer::setPlayerPreference: choosing ' + playerId + ' for ' + mimeType );
+ this.preference[ mimeType ] = playerId;
+ $.cookie( 'EmbedPlayer.Preference', JSON.stringify( this.preference ) );
+ break;
+ }
+ }
+ // Update All the player instances on the page
+ if ( selectedPlayer ) {
+ $('.mwEmbedPlayer').each(function(inx, playerTarget ){
+ var embedPlayer = $( playerTarget ).get( 0 );
+ if ( embedPlayer.mediaElement.selectedSource
+ && ( embedPlayer.mediaElement.selectedSource.mimeType == mimeType ) )
+ {
+ embedPlayer.selectPlayer( selectedPlayer );
+ }
+ });
+ }
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaSource.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaSource.js
new file mode 100644
index 00000000..9449a5d4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.MediaSource.js
@@ -0,0 +1,490 @@
+/**
+ * mediaSource class represents a source for a media element.
+ *
+ * @param {Element}
+ * element: MIME type of the source.
+ * @constructor
+ */
+
+/**
+ * The base source attribute checks also see:
+ * http://dev.w3.org/html5/spec/Overview.html#the-source-element
+ */
+
+( function( mw, $ ) { "use strict";
+
+mw.mergeConfig( 'EmbedPlayer.SourceAttributes', [
+ // source id
+ 'id',
+
+ // media url
+ 'src',
+
+ // Title string for the source asset
+ 'title',
+
+ // boolean if we support temporal url requests on the source media
+ 'URLTimeEncoding',
+
+ // Store the node name for type identification
+ 'nodeName',
+
+ /**
+ * data- attributes ( not yet standards )
+ */
+
+ // Media has a startOffset ( used for plugins that
+ // display ogg page time rather than presentation time
+ 'data-startoffset',
+
+ // A hint to the duration of the media file so that duration
+ // can be displayed in the player without loading the media file
+ 'data-durationhint',
+
+ // Source stream qualities
+ // NOTE data- is striped from the attribute as we build out the "mediaSource" object
+ 'data-shorttitle', // short title for stream ( useful for stream switching control bar widget)
+ 'data-width', // the width of the stream
+ 'data-height', // the height of the stream
+ 'data-bandwidth', // the overall bitrate of the stream in bytes
+ 'data-sizebytes', // the size of the stream in bytes
+ 'data-framerate', // the framereate of the stream
+ 'data-flavorid', // a source flavor id ( useful for targeting devices )
+ 'data-aspect', // the aspect ratio, useful for adaptive protocal urls that don't have a strict height / width
+
+ // Used as title in download panel
+ 'data-title',
+
+ // Used for download attribute on mediawiki
+ 'data-mwtitle',
+ // used for setting the api provider for mediawiki
+ 'data-mwprovider',
+
+ // to disable menu or timedText for a given embed
+ 'data-disablecontrols',
+
+ // used for language direction of subtitles
+ 'data-dir',
+
+ // Media start time
+ 'start',
+
+ // Media end time
+ 'end',
+
+ // If the source is the default source
+ 'default'
+] );
+
+mw.MediaSource = function( element ) {
+ this.init( element );
+};
+
+mw.MediaSource.prototype = {
+ // MIME type of the source.
+ mimeType:null,
+
+ // URI of the source.
+ uri:null,
+
+ // Title of the source.
+ title: null,
+
+ // True if the source has been marked as the default.
+ markedDefault: false,
+
+ // True if the source supports url specification of offset and duration
+ URLTimeEncoding:false,
+
+ // Start offset of the requested segment
+ startOffset: 0,
+
+ // Duration of the requested segment (0 if not known)
+ duration:0,
+
+ // source id
+ id: null,
+
+ // Start time in npt format
+ startNpt: null,
+
+ // End time in npt format
+ endNpt: null,
+
+ // Language of the file
+ srclang: null,
+ /**
+ * MediaSource constructor:
+ */
+ init : function( element ) {
+ var _this = this;
+ // mw.log('EmbedPlayer::adding mediaSource: ' + element);
+ this.src = $( element ).attr( 'src' );
+
+ // Set default URLTimeEncoding if we have a time url:
+ // not ideal way to discover if content is on an oggz_chop server.
+ // should check some other way.
+ var pUrl = new mw.Uri ( this.src );
+ if ( typeof pUrl.query[ 't' ] != 'undefined' ) {
+ this.URLTimeEncoding = true;
+ }
+
+ var sourceAttr = mw.config.get( 'EmbedPlayer.SourceAttributes' );
+ $.each( sourceAttr, function( inx, attr ){
+ if ( $( element ).attr( attr ) ) {
+ // strip data- from the attribute name
+ var attrName = ( attr.indexOf('data-') === 0) ? attr.substr(5) : attr
+ _this[ attrName ] = $( element ).attr( attr );
+ }
+ });
+
+ // Normalize "label" to "title" ( label is the actual spec so use that over title )
+ if( this.label ){
+ this.title = this.label;
+ }
+
+ // Set the content type:
+ if ( $( element ).attr( 'type' ) ) {
+ this.mimeType = $( element ).attr( 'type' );
+ }else if ( $( element ).attr( 'content-type' ) ) {
+ this.mimeType = $( element ).attr( 'content-type' );
+ }else if( $( element )[0].tagName.toLowerCase() == 'audio' ){
+ // If the element is an "audio" tag set audio format
+ this.mimeType = 'audio/ogg';
+ } else {
+ this.mimeType = this.detectType( this.src );
+ }
+
+ // Conform the mime type to ogg
+ if( this.mimeType == 'video/theora') {
+ this.mimeType = 'video/ogg';
+ }
+
+ if( this.mimeType == 'audio/vorbis') {
+ this.mimeType = 'audio/ogg';
+ }
+
+ // Check for parent elements ( supplies categories in "track" )
+ if( $( element ).parent().attr('category') ) {
+ this.category = $( element ).parent().attr('category');
+ }
+
+ if( $( element ).attr( 'default' ) ){
+ this.markedDefault = true;
+ }
+
+ // Get the url duration ( if applicable )
+ this.getURLDuration();
+ },
+
+ /**
+ * Update Source title via Element
+ *
+ * @param {Element}
+ * element Source element to update attributes from
+ */
+ updateSource: function( element ) {
+ // for now just update the title:
+ if ( $( element ).attr( "title" ) ) {
+ this.title = $( element ).attr( "title" );
+ }
+ },
+
+ /**
+ * Updates the src time and start & end
+ *
+ * @param {String}
+ * start_time: in NPT format
+ * @param {String}
+ * end_time: in NPT format
+ */
+ updateSrcTime: function ( startNpt, endNpt ) {
+ // mw.log("f:updateSrcTime: "+ startNpt+'/'+ endNpt + ' from org: ' +
+ // this.startNpt+ '/'+this.endNpt);
+ // mw.log("pre uri:" + this.src);
+ // if we have time we can use:
+ if ( this.URLTimeEncoding ) {
+ // make sure its a valid start time / end time (else set default)
+ if ( !mw.npt2seconds( startNpt ) ) {
+ startNpt = this.startNpt;
+ }
+
+ if ( !mw.npt2seconds( endNpt ) ) {
+ endNpt = this.endNpt;
+ }
+
+ this.src = mw.replaceUrlParams( this.src, {
+ 't': startNpt + '/' + endNpt
+ });
+
+ // update the duration
+ this.getURLDuration();
+ }
+ },
+
+ /**
+ * Sets the duration and sets the end time if unset
+ *
+ * @param {Float}
+ * duration: in seconds
+ */
+ setDuration: function ( duration ) {
+ this.duration = duration;
+ if ( !this.endNpt ) {
+ this.endNpt = mw.seconds2npt( this.startOffset + duration );
+ }
+ },
+
+ /**
+ * MIME type accessor function.
+ *
+ * @return {String} the MIME type of the source.
+ */
+ getMIMEType: function() {
+ if( this.mimeType ) {
+ return this.mimeType;
+ }
+ this.mimeType = this.detectType( this.src );
+ return this.mimeType;
+ },
+ /**
+ * Update the local src
+ * @param {String}
+ * src The URL to the media asset
+ */
+ setSrc: function( src ){
+ this.src = src;
+ },
+
+ /**
+ * URI function.
+ *
+ * @param {Number}
+ * serverSeekTime Int: Used to adjust the URI for url based
+ * seeks)
+ * @return {String} the URI of the source.
+ */
+ getSrc: function( serverSeekTime ) {
+ if ( !serverSeekTime || !this.URLTimeEncoding ) {
+ return this.src;
+ }
+ var endvar = '';
+ if ( this.endNpt ) {
+ endvar = '/' + this.endNpt;
+ }
+ return mw.replaceUrlParams( this.src,
+ {
+ 't': mw.seconds2npt( serverSeekTime ) + endvar
+ }
+ );
+ },
+ /**
+ * Title accessor function.
+ *
+ * @return {String} Title of the source.
+ */
+ getTitle : function() {
+ if( this.title ){
+ return this.title;
+ }
+ // Text tracks use "label" instead of "title"
+ if( this.label ){
+ return this.label;
+ }
+
+ // Return a Title based on mime type:
+ var mimeType = this.getMIMEType().split( ';' )[0];
+ switch( mimeType ) {
+ case 'video/h264' :
+ case 'video/mp4' :
+ return mw.msg( 'mwe-embedplayer-video-h264' );
+ break;
+ case 'video/x-flv' :
+ return mw.msg( 'mwe-embedplayer-video-flv' );
+ break;
+ case 'video/webm' :
+ return mw.msg( 'mwe-embedplayer-video-webm');
+ break;
+ case 'video/ogg' :
+ return mw.msg( 'mwe-embedplayer-video-ogg' );
+ break;
+ case 'audio/ogg' :
+ return mw.msg( 'mwe-embedplayer-video-audio' );
+ break;
+ case 'audio/mpeg' :
+ return mw.msg('mwe-embedplayer-audio-mpeg');
+ break;
+ case 'video/3gp' :
+ return mw.msg('mwe-embedplayer-video-3gp');
+ break;
+ case 'video/mpeg' :
+ return mw.msg('mwe-embedplayer-video-mpeg');
+ break;
+ case 'video/x-msvideo' :
+ return mw.msg('mwe-embedplayer-video-msvideo' );
+ break;
+ }
+
+ // Return title based on file name:
+ try{
+ var fileName = new mw.Uri( mw.absoluteUrl( this.getSrc() ) ).path.split('/').pop();
+ if( fileName ){
+ return fileName;
+ }
+ } catch(e){}
+
+ // Return the mime type string if not known type.
+ return this.mimeType;
+ },
+ /**
+ * Get a short title for the stream
+ */
+ getShortTitle: function(){
+ var _this =this;
+ if( this.shorttitle ){
+ return this.shorttitle;
+ }
+ // Just use a short "long title"
+ var longTitle = this.getTitle();
+ if(longTitle.length > 20) {
+ longTitle = longTitle.substring(0,17)+"...";
+ }
+ return longTitle
+ },
+ /**
+ *
+ * Get Duration of the media in milliseconds from the source url.
+ *
+ * Supports media_url?t=ntp_start/ntp_end url request format
+ */
+ getURLDuration : function() {
+ // check if we have a URLTimeEncoding:
+ if ( this.URLTimeEncoding ) {
+ var annoURL = new mw.Uri( this.src );
+ if ( annoURL.query.t ) {
+ var times = annoURL.query.t.split( '/' );
+ this.startNpt = times[0];
+ this.endNpt = times[1];
+ this.startOffset = mw.npt2seconds( this.startNpt );
+ this.duration = mw.npt2seconds( this.endNpt ) - this.startOffset;
+ } else {
+ // look for this info as attributes
+ if ( this.startOffset ) {
+ this.startNpt = mw.seconds2npt( this.startOffset );
+ }
+ if ( this.duration ) {
+ this.endNpt = mw.seconds2npt( parseInt( this.duration ) + parseInt( this.startOffset ) );
+ }
+ }
+ }
+ },
+ /**
+ * Get the extension of a url
+ * @param String uri
+ */
+ getExt : function( uri ){
+ var urlParts = new mw.Uri( uri );
+ // Get the extension from the url or from the relative name:
+ var ext = ( urlParts.file ) ? /[^.]+$/.exec( urlParts.file ) : /[^.]+$/.exec( uri );
+ // remove the hash string if present
+ ext = /[^#]*/g.exec( ext.toString() );
+ ext = ext || '';
+ return ext.toString().toLowerCase();
+ },
+ /**
+ * Get the flavorId if available.
+ */
+ getFlavorId: function(){
+ if( this.flavorid ){
+ return this.flavorid;
+ }
+ return ;
+ },
+
+ /**
+ * Attempts to detect the type of a media file based on the URI.
+ *
+ * @param {String}
+ * uri URI of the media file.
+ * @return {String} The guessed MIME type of the file.
+ */
+ detectType: function( uri ) {
+ // NOTE: if media is on the same server as the javascript
+ // we can issue a HEAD request and read the mime type of the media...
+ // ( this will detect media mime type independently of the url name )
+ // http://www.jibbering.com/2002/4/httprequest.html
+ switch( this.getExt( uri ) ) {
+ case 'smil':
+ case 'sml':
+ return 'application/smil';
+ break;
+ case 'm4v':
+ case 'mp4':
+ return 'video/h264';
+ break;
+ case 'm3u8':
+ return 'application/vnd.apple.mpegurl';
+ break;
+ case 'webm':
+ return 'video/webm';
+ break;
+ case '3gp':
+ return 'video/3gp';
+ break;
+ case 'srt':
+ return 'text/x-srt';
+ break;
+ case 'flv':
+ return 'video/x-flv';
+ break;
+ case 'ogg':
+ case 'ogv':
+ return 'video/ogg';
+ break;
+ case 'oga':
+ return 'audio/ogg';
+ break;
+ case 'mp3':
+ return 'audio/mpeg';
+ case 'm4a':
+ return 'audio/mp4';
+ break;
+ case 'anx':
+ return 'video/ogg';
+ break;
+ case 'xml':
+ return 'text/xml';
+ break;
+ case 'avi':
+ return 'video/x-msvideo';
+ break;
+ case 'mpg':
+ return 'video/mpeg';
+ break;
+ case 'mpeg':
+ return 'video/mpeg';
+ break;
+ }
+ mw.log( "Error: could not detect type of media src: " + uri );
+ },
+ /**
+ * bitrate is mesured in kbs rather than bandwith bytes per second
+ */
+ getBitrate: function() {
+ if( this.bandwidth ){
+ return this.bandwidth / 1024;
+ }
+ return 0;
+ },
+ /**
+ * Get the size of the stream in bytes
+ */
+ getSize: function(){
+ if( this.sizebytes ){
+ return this.sizebytes;
+ }
+ return 0;
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.processEmbedPlayers.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.processEmbedPlayers.js
new file mode 100644
index 00000000..0748ccd0
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.processEmbedPlayers.js
@@ -0,0 +1,353 @@
+/**
+ * Selector based embedPlayer processing
+ *
+ * @param {Function=}
+ * callback Optional Function to be called once video interfaces
+ * are ready
+ *
+ */
+
+( function( mw, $ ) { "use strict";
+
+mw.processEmbedPlayers = function( playerSet, callback ) {
+ mw.log( 'processEmbedPlayers:: playerSet: ', playerSet);
+ // The player id list container
+ var playerIdList = [];
+
+ // Check if the selected player set is ready if ready issue the parent callback
+ var areSelectedPlayersReady = function(){
+ var playersLoaded = true;
+ $.each( playerIdList, function(inx, playerId){
+ if( ! $( '#' + playerId )[0].playerReadyFlag ){
+ playersLoaded = false;
+ return false;
+ }
+ })
+ if( playersLoaded ){
+ if( callback ){
+ callback();
+ }
+ }
+ }
+
+ /**
+ * Adds a player element for the embedPlayer to rewrite
+ *
+ * uses embedPlayer interface on audio / video elements uses mvPlayList
+ * interface on playlist elements
+ *
+ * Once a player interface is established the following chain of functions
+ * are called;
+ *
+ * _this.checkPlayerSources()
+ * _this.setupSourcePlayer()
+ * _this.updatePlaybackInterface()
+ * _this.selectedPlayer.load()
+ * _this.showPlayer()
+ *
+ * @param {Element}
+ * playerElement DOM element to be swapped
+ */
+ var addPlayerElement = function( playerElement ) {
+ var _this = this;
+ mw.log('EmbedPlayer:: addElement:: ' + playerElement.id );
+
+ // Be sure to "stop" the target ( Firefox 3x keeps playing
+ // the video even though its been removed from the DOM )
+ if( playerElement.pause ){
+ playerElement.pause();
+ }
+
+ // Allow modules to override the wait for metadata flag:
+ $( mw ).trigger( 'EmbedPlayerWaitForMetaCheck', playerElement );
+
+ // DOM *could* load height, width and duration eventually, in some browsers
+ // By default, don't bother waiting for this.
+ var waitForMeta = false;
+
+ // if a plugin has told us not to waitForMeta, don't
+ if ( playerElement.waitForMeta !== false ) {
+ // Check if we should wait for metadata, after all
+ waitForMeta = waitForMetaCheck( playerElement );
+ }
+
+ var ranPlayerSwapFlag = false;
+
+ // Local callback to runPlayer swap once playerElement has metadata
+ var runPlayerSwap = function () {
+ // Don't run player swap twice
+ if( ranPlayerSwapFlag ){
+ return ;
+ }
+ ranPlayerSwapFlag = true;
+ mw.log( "processEmbedPlayers::runPlayerSwap::" + $( playerElement ).attr('id') );
+
+ var playerInterface = new mw.EmbedPlayer( playerElement );
+ var inDomPlayer = swapEmbedPlayerElement( playerElement, playerInterface );
+
+ // IE/Edge with WebM components re-triggers autoplay after removal as well.
+ if( playerElement.pause ){
+ playerElement.pause();
+ }
+
+ // Trigger the EmbedPlayerNewPlayer for embedPlayer interface
+ mw.log("processEmbedPlayers::trigger:: EmbedPlayerNewPlayer " + inDomPlayer.id );
+
+ // Allow plugins to add bindings to the inDomPlayer
+ $( mw ).trigger ( 'EmbedPlayerNewPlayer', inDomPlayer );
+
+ // Add a player ready binding:
+ $( inDomPlayer ).bind( 'playerReady.swap', function(event, id){
+ $( inDomPlayer ).unbind( 'playerReady.swap' );
+ areSelectedPlayersReady();
+ });
+
+ //
+ // Allow modules to block player build out
+ //
+ // this is needed in cases where you need to do an asynchronous
+ // player interface setup. like iframes asynchronous announcing its ready for
+ // bindings that can affect player setup.
+ mw.log("EmbedPlayer::addPlayerElement :trigger startPlayerBuildOut:" + inDomPlayer.id );
+ $( '#' + inDomPlayer.id ).triggerQueueCallback( 'startPlayerBuildOut', function(){
+ // Issue the checkPlayerSources call to the new player
+ // interface: make sure to use the element that is in the DOM:
+ inDomPlayer.checkPlayerSources();
+ });
+ };
+
+ if( waitForMeta && mw.config.get('EmbedPlayer.WaitForMeta' ) ) {
+ mw.log('processEmbedPlayers::WaitForMeta ( video missing height (' +
+ $( playerElement ).attr('height') + '), width (' +
+ $( playerElement ).attr('width') + ') or duration: ' +
+ $( playerElement ).attr('duration')
+ );
+ $( playerElement ).bind( "loadedmetadata", runPlayerSwap );
+
+ // Time-out of 5 seconds ( maybe still playable but no timely metadata )
+ setTimeout( runPlayerSwap, 5000 );
+ return ;
+ } else {
+ runPlayerSwap();
+ return ;
+ }
+ };
+
+ /**
+ * Check if we should wait for metadata.
+ *
+ * @return true if the size is "likely" to be updated by waiting for metadata
+ * false if the size has been set via an attribute or is already loaded
+ */
+ var waitForMetaCheck = function( playerElement ){
+ var waitForMeta = false;
+
+ // Don't wait for metadata for non html5 media elements
+ if( !playerElement ){
+ return false;
+ }
+ if( !playerElement.tagName || ( playerElement.tagName.toLowerCase() != 'audio' && playerElement.tagName.toLowerCase() != 'video' ) ){
+ return false;
+ }
+ // If we don't have a native player don't wait for metadata
+ if( !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'oggNative') &&
+ !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'webmNative') &&
+ !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'h264Native' ) &&
+ !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'appleVdnPlayer' ) )
+ {
+ return false;
+ }
+
+
+ var width = $( playerElement ).css( 'width' );
+ var height = $( playerElement ).css( 'height' );
+ // Css video defaults ( firefox )
+ if( $( playerElement ).css( 'width' ) == '300px' &&
+ $( playerElement ).css( 'height' ) == '150px'
+ ){
+ waitForMeta = true;
+ } else {
+ // Check if we should wait for duration:
+ if( $( playerElement ).attr( 'duration') ||
+ $( playerElement ).attr( 'durationHint') ||
+ $( playerElement ).attr('data-durationhint')
+ ){
+ // height, width and duration set; do not wait for meta data:
+ return false;
+ } else {
+ waitForMeta = true;
+ }
+ }
+
+ // Firefox ~ sometimes~ gives -1 for unloaded media
+ if ( $(playerElement).attr( 'width' ) == -1 || $(playerElement).attr( 'height' ) == -1 ) {
+ waitForMeta = true;
+ }
+
+ // Google Chrome / safari gives 0 width height for unloaded media
+ if( $(playerElement).attr( 'width' ) === 0 ||
+ $(playerElement).attr( 'height' ) === 0
+ ) {
+ waitForMeta = true;
+ }
+
+ // Firefox default width height is ~sometimes~ 150 / 300
+ if( playerElement.height == 150 && playerElement.width == 300 ){
+ waitForMeta = true;
+ }
+
+ // Make sure we have a src attribute or source child
+ // ( i.e not a video tag to be dynamically populated or looked up from
+ // xml resource description )
+ if( waitForMeta &&
+ (
+ $( playerElement ).attr('src') ||
+ $( playerElement ).find("source[src]").length !== 0
+ )
+ ) {
+ // Detect src type ( if no type set )
+ return true;
+ } else {
+ // playerElement is not likely to update its meta data ( no src )
+ return false;
+ }
+ };
+
+ /**
+ * swapEmbedPlayerElement
+ *
+ * Takes a video element as input and swaps it out with an embed player interface
+ *
+ * @param {Element}
+ * targetElement Element to be swapped
+ * @param {Object}
+ * playerInterface Interface to swap into the target element
+ */
+ var swapEmbedPlayerElement = function( targetElement, playerInterface ) {
+ mw.log( 'processEmbedPlayers::swapEmbedPlayerElement: ' + targetElement.id );
+ // Create a new element to swap the player interface into
+ var swapPlayerElement = document.createElement('div');
+
+ // Add a class that identifies all embedPlayers:
+ $( swapPlayerElement ).addClass( 'mwEmbedPlayer' );
+
+ // Get properties / methods from playerInterface:
+ for ( var method in playerInterface ) {
+ if ( method != 'readyState' ) { // readyState crashes IE ( don't include )
+ swapPlayerElement[ method ] = playerInterface[ method ];
+ }
+ }
+ // copy over css text:
+ swapPlayerElement.style.cssText = targetElement.style.cssText;
+ // player element must always be relative to host video and image layout
+ swapPlayerElement.style.position = 'relative';
+
+ // Copy any data attributes from the target player element over to the swapPlayerElement
+ var dataAttributes = mw.config.get("EmbedPlayer.DataAttributes");
+ if( dataAttributes ){
+ $.each( dataAttributes, function( attrName, na ){
+ if( $( targetElement ).data( attrName ) ){
+ $( swapPlayerElement ).data( attrName, $( targetElement ).data( attrName ) );
+ }
+ });
+ }
+ // Check for Persistent native player ( should keep the video embed around )
+ if( playerInterface.isPersistentNativePlayer()
+ ||
+ // Also check for native controls on a video or audio tag
+ ( playerInterface.useNativePlayerControls()
+ &&
+ ( targetElement.nodeName == 'video' || targetElement.nodeName == 'audio' )
+ )
+ ) {
+
+ $( targetElement )
+ .attr( 'id', playerInterface.pid )
+ .addClass( 'nativeEmbedPlayerPid' )
+ .show()
+ .after(
+ $( swapPlayerElement ).css( 'display', 'none' )
+ );
+
+ } else {
+ $( targetElement ).replaceWith( swapPlayerElement );
+ }
+
+ // If we don't already have a loadSpiner add one:
+ if( $('#loadingSpinner_' + playerInterface.id ).length == 0 && $.client.profile().name !== 'firefox' ){
+ if( playerInterface.useNativePlayerControls() || playerInterface.isPersistentNativePlayer() ) {
+ var $spinner = $( targetElement )
+ .getAbsoluteOverlaySpinner();
+ }else{
+ var $spinner = $( swapPlayerElement ).getAbsoluteOverlaySpinner();
+ }
+ $spinner.attr('id', 'loadingSpinner_' + playerInterface.id );
+ }
+ return swapPlayerElement;
+ };
+
+ // Add a loader for <div /> embed player rewrites:
+ $( playerSet ).each( function( index, playerElement) {
+
+ // Make sure the playerElement has an id:
+ if( !$( playerElement ).attr('id') ){
+ $( playerElement ).attr( "id", 'mwe_vid' + ( index ) );
+ }
+ // Add the player Id to the playerIdList
+ playerIdList.push( $( playerElement ).attr( "id") );
+
+ // If we are dynamically embedding on a "div" check if we can
+ // add a poster image behind the loader:
+ if( playerElement.nodeName.toLowerCase() == 'div'
+ &&
+ $(playerElement).attr( 'poster' ) )
+ {
+ var posterSrc = $(playerElement).attr( 'poster' );
+
+ // Set image size:
+ var width = $( playerElement ).width();
+ var height = $( playerElement ).height();
+ if( !width ){
+ var width = '100%';
+ }
+ if( !height ){
+ var height = '100%';
+ }
+
+ mw.log('EmbedPlayer:: set loading background: ' + posterSrc);
+ $( playerElement ).append(
+ $( '<img />' )
+ .attr( 'src', posterSrc)
+ .css({
+ 'position' : 'absolute',
+ 'width' : width,
+ 'height' : height
+ })
+ );
+ }
+ });
+
+ // Make sure we have user preference setup for setting preferences on video selection
+ var addedPlayersFlag = false;
+ mw.log("processEmbedPlayers:: Do: " + $( playerSet ).length + ' players ');
+ // Add each selected element to the player manager:
+ $( playerSet ).each( function( index, playerElement) {
+ // Make sure the video tag was not generated by our library:
+ if( $( playerElement ).hasClass( 'nativeEmbedPlayerPid' ) ){
+ $( '#loadingSpinner_' + $( playerElement ).attr('id') ).remove();
+ mw.log( 'processEmbedPlayers::$.embedPlayer skip embedPlayer gennerated video: ' + playerElement );
+ } else {
+ addedPlayersFlag = true;
+ // Add the player
+ addPlayerElement( playerElement );
+ }
+ });
+ if( !addedPlayersFlag ){
+ // Run the callback directly if no players were added
+ if( callback ){
+ callback();
+ }
+ }
+};
+
+})( mw, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/EmbedPlayer.css b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/EmbedPlayer.css
new file mode 100644
index 00000000..9699c2e9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/EmbedPlayer.css
@@ -0,0 +1,166 @@
+.ui-dialog-content .mediaContainer { margin: 0 auto; }
+.mwPlayerContainer, video { width: 100%; height: 100%; }
+.mwPlayerContainer { position: relative; height: 100%; background: #000; }
+.videoHolder {
+ position: absolute;
+ top: 0px;
+ left:0px;
+ right:0px;
+ bottom:0px;
+ overflow: hidden;
+}
+.mwPlayerContainer.fullscreen {
+ position: absolute !important;
+ width: 100% !important;
+ height: 100%! important;
+ z-index: 9999;
+ min-height: 100%;
+ top: 0;
+ left: 0;
+ margin: 0;
+}
+
+.mwEmbedPlayer { width: 100%; height: 100%; overflow: hidden; position: absolute; top: 0; left: 0; }
+
+
+.player_select_list {
+ color:white;
+ font-size:10pt;
+/* display:none;*/
+}
+.player_select_list a:visited {
+ color:white;
+}
+.mv_playhead {
+ position:absolute;
+ top:0;
+ left:0;
+ width:17px;
+ height:21px;
+ /*http://art.gnome.org/themes/gtk2*/
+}
+
+.mv_status {
+ font-family:"Times New Roman", Times, serif;
+ font-size:14px;
+ float:left;
+}
+.set_ogg_player_pref{
+ text-align:left;
+}
+
+.large_play_button {
+ display:block;
+ width: 130px;
+ height: 96px;
+ margin: auto;
+/* margin: -202px 0 0 154px;*/
+ position: absolute;
+ z-index: 3;
+ cursor: pointer;
+}
+
+/* jquery.ui overrides */
+
+.ui-icon_link {
+ padding: .4em 1em .4em 20px;
+ text-decoration: none;
+ position: relative;
+}
+.ui-icon_link span.ui-icon {
+ margin: 0 5px 0 0;
+ position: absolute;
+ left: 0.2em;
+ right: auto;
+ top: 50%;
+ margin-top: -8px;
+ zoom: 1;
+}
+.ui-icon_link span.ui-text {
+ position: absolute;
+ left: 0.2em;
+ right: auto;
+ margin-top: -3px;
+ zoom: 1;
+}
+
+.ui-progressbar-value{
+ background-image: none;
+}
+
+.kplayer .ui-widget-overlay {
+ background: black; opacity: .40; filter: Alpha(Opacity=40);
+}
+
+.kplayer .ui-widget-content input {
+ padding: 5px;
+}
+.kplayer .ui-widget-content a {
+ color: #222;
+}
+
+ul.ui-provider-selection {
+ list-style-type: none;
+ margin: 0 0 0.6em 0;
+ overflow: hidden;
+ padding: 0;
+ text-align: center;
+}
+
+ul.ui-provider-selection li {
+ border-left: 1px solid black;
+ float: left;
+ line-height: 1.1em;
+ margin: 0 0.5em 0 -0.5em;
+ padding: 0 0.5em;
+ color: blue;
+ list-style-image:none;
+ cursor:pointer;
+}
+
+ul.ui-provider-selection li .ui-selected {
+ color: black;
+ font-weight: bold;
+}
+
+ul.ui-provider-selection li a.ui-active {
+ color: black;
+ font-weight: bold;
+}
+
+ul.ui-provider-selection li a {
+ color: blue;
+ text-decoration: none;
+}
+.fg-menu .ui-icon{
+ position:relative;
+ top:-1px;
+}
+
+.ui-dialog-buttonpane a{
+ float: right;
+ margin-right: 10px;
+}
+
+
+/* Custom */
+.mv-player .overlay-win { background: transparent; border: 0; } /* Custom */
+.mv-player .overlay-content { padding: 10px; }
+.mv-player .overlay-content h3 { display: block; font-size: 16px; font-weight: bold; color: #fff; font-family: arial; }
+.mv-player .overlay-win h2 { font-size: 18px; margin-top: 0; }
+.mv-player .overlay-content div { font-size: 12px; color: #fff; font-weight: bold; }
+.mv-player .overlay-content div a { color: #00a8ff }
+.mv-player .overlay-content div a:hover { color: #3abcff }
+.mv-player .overlay-content ul { list-style: none; margin: 0 0 10px 0; padding: 0; }
+.mv-player .vol_container {
+ background: #272727;
+ opacity: .80;
+ filter:Alpha(Opacity=80);
+ position:absolute;
+ left:0px;
+}
+.mv-player .ui-icon ui-icon-closethick { border: 1px solid #606060; background: #222;font-weight: normal; color: #EEE; }
+.mv-player .overlay-win textarea { background: #e4e4e4; height: 35px; padding: 6px; color: #666; border: 0; }
+.mv-player .overlay-content .copycode { padding: 8px 12px; font-weight: bold; float: right; cursor: pointer; }
+.control-bar .ui-icon_link { border: 0; }
+.control-bar .ui-state-hover { border: 0; }
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/PlayerSkinKskin.css b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/PlayerSkinKskin.css
new file mode 100644
index 00000000..f6c675d7
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/PlayerSkinKskin.css
@@ -0,0 +1,484 @@
+/*
+* K-skin player
+*/
+.k-player {
+ color: #FFF;
+ background-color: #000;
+}
+.k-player .videoHolder a {
+ color: #0645AD;
+}
+.k-player .videoHolder a:visited {
+ color: #0B0080;
+}
+.k-player .ui-widget-content {
+ color: #555;
+ z-index: 1503;
+}
+.k-player .ui-widget-content a{
+ color: #555;
+}
+/* large play button */
+.k-player .play-btn-large {
+ width: 70px;
+ height: 55px;
+ background: url(images/ksprite.png) no-repeat 0px -433px;
+ position: absolute;
+ cursor: pointer;
+ border: none;
+}
+@print {
+ .k-player .play-btn-large {
+ display: none;
+ }
+}
+/*.ui-state-default */
+.k-player .play-btn-large:hover {
+ background: url(images/ksprite.png) no-repeat 0px -377px;
+}
+
+/* control icons: */
+.k-player .control-bar .ui-icon,.k-player .control-bar .ui-icon{
+ background: transparent url(images/ksprite.png) no-repeat scroll 0 -48px;
+}
+
+.k-player .ui-state-default .ui-icon-arrow-4-diag {
+ background-position: 0 -32px;
+}
+/* fullscreen */
+.k-player .ui-state-hover .ui-icon-arrow-4-diag {
+ background-position: -16px -32px;
+}
+
+.k-player .ui-state-hover .ui-icon-volume-on{
+ background-position: -16px -48px;
+}
+
+/* cc icon */
+.k-player .ui-state-default .ui-icon-comment {
+ background-position: 0px -65px;
+}
+
+.k-player .ui-state-default .ui-icon-play {
+ background: url(images/ksprite.png) no-repeat 0 0;
+}
+
+.k-player .ui-state-hover .ui-icon-play {
+ background-position: -16px 0;
+}
+
+.k-player .ui-state-default .ui-icon-pause {
+ background: url(images/ksprite.png) no-repeat 0 -17px;
+}
+
+.k-player .ui-state-hover .ui-icon-pause {
+ background-position: -16px -17px;
+}
+
+.k-player .control-bar {
+ border:1px solid #c8c8c8;
+ border-top: 0px;
+ border-right: 0px;
+ height: 21px;
+ padding: 2px 0 0 6px;
+ margin-top: 0px;
+ background: url(images/ksprite.png) repeat-x 0 -81px;
+ font: normal 11px arial, sans-serif;
+ color: #555;
+
+ position:absolute;
+ bottom:0px;
+ left:0px;
+ right:0px;
+
+ z-index: 2;
+}
+
+.k-player .play_head {
+ background: url("images/ksprite.png") repeat-x scroll 0 -350px
+ transparent;
+ display: inline;
+ /* @noflip */
+ float: left;
+ margin-left: 10px;
+ border: 1px solid #EEEEEE;
+ height: 8px;
+ margin: 5px 2px 0 0px;
+ position: relative;
+ /* @noflip */
+ direction: ltr;
+}
+
+.k-player .play_head .ui-slider-handle {
+ background: url("images/ksprite.png") no-repeat scroll -67px -341px
+ transparent !important;
+ border: 1px solid #888888;
+ display: block;
+ height: 8px;
+ margin: -1px 0 0 -5px;
+ position: absolute;
+ top: 0;
+ width: 8px;
+ cursor: pointer;
+ -moz-border-radius:5px 5px 5px 5px;
+ border-radius:5px 5px 5px 5px;
+ -webkit-border-radius:5px 5px 5px 5px;
+}
+
+.k-player .ui-corner-all {
+ border-radius:5px 5px 5px 5px !important;
+ -webkit-border-radius:5px 5px 5px 5px !important;
+ -moz-border-radius:5px 5px 5px 5px !important;
+}
+.k-player ul.fg-menu{
+ margin: 0.3em 0 0 .3em;
+ font-size: 1.2em;
+ padding: 0px;
+}
+.k-player .fg-menu-container{
+ padding: 0px;
+ /* @noflip */
+ right: 16px;
+ /* Add scroll bar to list */
+ overflow: auto;
+}
+
+.ui-dialog-content .k-player ul.fg-menu{
+ font-size: 1.2em;
+}
+
+.k-player .time-disp {
+ border: medium none;
+ display: inline;
+ color: #555555;
+ font: 11px arial, sans-serif;
+ line-height: 20px;
+ overflow: hidden;
+ width: 39px;
+ /* @noflip */
+ float: right;
+}
+
+.k-player .source-switch {
+ border: medium none;
+ display: inline;
+ color: #555;
+ font: 11px arial, sans-serif;
+ line-height: 20px;
+ overflow: hidden;
+ width: 70px;
+ cursor: pointer;
+ /* @noflip */
+ float: right;
+ text-align: center;
+}
+
+.k-player .lButton {
+ cursor: pointer;
+ /* @noflip */
+ float: left;
+ list-style: none outside none;
+ margin: 2px;
+ padding: 0px 0;
+ width: 19px;
+ height: 16px;
+ position: relative;
+ background: none repeat scroll 0 0 transparent !important;
+ border: medium none;
+}
+
+.k-player .rButton {
+ cursor: pointer;
+ /* @noflip */
+ float: right;
+ list-style: none outside none;
+ margin-top: 2px;
+ padding: 0px 0;
+ width: 22px;
+ height: 16px;
+ position: relative;
+ background: none repeat scroll 0 0 transparent !important;
+ border: medium none;
+}
+
+.k-player .k-options {
+ border: 1px solid #AAAAAA !important;
+ color: #555555 !important;
+ /* @noflip */
+ float: right;
+ height: 21px;
+ margin-top: -2px;
+ margin-right: 0px;
+ width: 50px;
+ background: none repeat scroll 0 0 transparent !important;
+ font-family: Lucida Grande, Lucida Sans, Arial, sans-serif;
+ font-size: 11px;
+ text-transform: uppercase;
+ text-align: center;
+}
+
+.k-player .k-options span {
+ position: relative;
+ top: 4px;
+}
+
+.k-player .k-menu-screens {
+ /* @noflip */
+ float: left;
+ font-size: 14px;
+ text-align: left;
+ padding: 5px 5px 10px 5px;
+}
+
+.k-player ul.k-menu-bar {
+ background: url("images/ksprite.png") no-repeat scroll -99px -104px
+ transparent;
+ bottom: 5px;
+ height: 128px;
+ list-style: none outside none;
+ padding: 0 0 5px;
+ position: absolute;
+ /* @noflip */
+ right: 0;
+ margin-left: 0;
+}
+
+.k-player .k-menu {
+ background: none repeat scroll 0 0 #181818;
+ border: medium none;
+ display: none;
+ left: 0;
+ position: absolute;
+ top: 0;
+}
+
+.k-player .k-menu-bar li a {
+ background: url("images/ksprite.png") no-repeat scroll -51px -110px
+ transparent;
+ display: block;
+ height: 32px;
+ margin-left: 1px;
+ overflow: hidden;
+ text-indent: 99999px;
+ width: 49px;
+}
+
+.k-menu-bar li a:hover {
+ background-position: -1px -110px;
+}
+
+.k-menu-bar li.k-download-btn a {
+ background-position: -51px -203px;
+}
+
+.k-menu-bar li.k-download-btn a:hover {
+ background-position: -1px -203px;
+}
+
+.k-menu-bar li.k-share-btn a {
+ background-position: -51px -172px;
+}
+
+.k-menu-bar li.k-share-btn a:hover {
+ background-position: -1px -172px;
+}
+
+.k-menu-bar li.k-credits-btn a {
+ background-position: -51px -141px;
+}
+
+.k-menu-bar li.k-credits-btn a:hover {
+ background-position: -1px -141px;
+}
+
+
+
+.k-menu-screens p {
+ margin: 6px 0;
+}
+
+.k-menu-screens a img {
+ border: none;
+}
+
+.k-menu-screens ul {
+ padding: 0;
+ margin: 6px 0 0;
+ list-style: none outside none;
+}
+
+.k-edit-screen {
+ width: 370px;
+ height: 223px;
+ padding-top: 77px;
+ text-align: center;
+ background: #181818;
+ color: #fff;
+}
+
+.k-edit-screen div {
+
+}
+
+.k-edit-screen a {
+ color: #7BB8FC;
+}
+
+.k-edit-screen a img {
+ border: none;
+}
+
+
+.k-menu-screens h2, .k-menu-screens h3 {
+ padding: 0 0 5px 15px;
+ clear: both;
+ font-size: 12px;
+ color: #999;
+ border-bottom: 0;
+}
+
+.k-menu-screens p {
+ margin: 6px 0;
+}
+
+.k-menu-screens a img {
+ border: none;
+}
+
+.k-menu-screens ul {
+ padding: 0;
+ margin: 6px 0 0;
+ list-style: none outside none;
+}
+
+.k-menu-screens li {
+ margin-bottom: 6px;
+}
+
+.k-menu-screens li a {
+ padding-left: 22px;
+ padding-right: 22px;
+ background: url(images/ksprite.png) no-repeat -85px -274px;
+ text-decoration: none;
+ color: #BBB;
+}
+
+.k-menu-screens li a.active,.k-menu-screens li a:hover .active {
+ background-position: -85px -245px;
+}
+
+.k-menu-screens li a:hover {
+ background-position: -85px -259px;
+}
+
+.k-menu textarea {
+ background: none repeat scroll 0 0 transparent;
+ border-color: #000000 -moz-use-text-color -moz-use-text-color #000000;
+ border-style: solid none none solid;
+ border-width: 2px medium medium 2px;
+ color: #CCCCCC;
+ font: 11px arial, sans-serif;
+ overflow: hidden;
+ padding-left: 2px;
+ width: 95%;
+}
+
+.menu-screen.menu-share button {
+ background: url("images/ksprite.png") no-repeat scroll 0 -81px #D4D4D4;
+ border: 1px solid #000000;
+ color: #000000;
+ float: right;
+ height: 34px;
+ padding: 0 5px 3px;
+ font-size: 1em;
+}
+
+.k-player .menu-screen {
+ height: 100%;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+
+.k-player .menu-screen.menu-share div.ui-state-highlight {
+ background: none repeat scroll 0 0 transparent;
+ border-color: #554926;
+ color: #FFE96E;
+ float: left;
+ padding: 2px 5px;
+}
+
+.k-player .menu-screen.menu-share div.ui-state-highlight a {
+ color: #FFE96E;
+ font-weight: bold;
+}
+
+.k-player .volume_control {
+ /* @noflip */
+ margin-right: 2px;
+ width: 16px;
+}
+
+.k-player .volume_control span {
+ margin-right: 0px;
+}
+
+.k-player .volume-slider {
+ width: 20px;
+ /* @noflip */
+ direction: ltr;
+}
+
+.k-player .volume-slider .ui-slider-range {
+ -moz-border-radius: 0 0 0 0;
+ background: url("images/ksprite.png") repeat-x scroll -66px -306px transparent !important;
+ height: 17px;
+ position: absolute;
+}
+
+.k-player .volume-slider a.ui-slider-handle {
+ background: none repeat scroll 0 0 transparent;
+ border: medium none;
+ display: block;
+ height: 18px;
+ margin: -3px 5px 0 -1px;
+ position: absolute;
+ width: 8px;
+}
+
+.k-player .ui-slider-horizontal .ui-slider-range-min {
+ /* @noflip */
+ left: 0;
+}
+
+.k-player .credits_box {
+ background-attachment:scroll;
+ background-color:white;
+ background-image:none;
+ background-position:0 0;
+ bottom: 20px;
+ left: 20px;
+ position:absolute;
+ right: 20px;
+ top: 30px;
+ overflow:hidden;
+}
+.k-player .credits_box a{
+ color:#666;
+ text-decoration: underline;
+}
+.k-player .creditline img {
+ float: left;
+ width: 90px;
+ margin: 4px;
+}
+
+.k-player .k-attribution{
+ position:absolute;
+ bottom: 5px;
+ right : 20px;
+ background: url("images/kaltura_open_source_video_platform.png");
+ width : 51px;
+ height : 12px;
+ cursor: pointer;
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/kaltura_open_source_video_platform.gif b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/kaltura_open_source_video_platform.gif
new file mode 100644
index 00000000..cf05af25
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/kaltura_open_source_video_platform.gif
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/kaltura_open_source_video_platform.png b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/kaltura_open_source_video_platform.png
new file mode 100644
index 00000000..77f2a32a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/kaltura_open_source_video_platform.png
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/ksprite.png b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/ksprite.png
new file mode 100644
index 00000000..53c772eb
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/images/ksprite.png
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/mw.PlayerSkinKskin.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/mw.PlayerSkinKskin.js
new file mode 100644
index 00000000..39b43834
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/kskin/mw.PlayerSkinKskin.js
@@ -0,0 +1,394 @@
+/**
+* Skin js allows you to override contrlBuilder html/class output
+*/
+
+( function( mw, $ ) {"use strict";
+
+mw.PlayerSkinKskin = {
+
+ // The parent class for all kskin css:
+ playerClass: 'k-player',
+
+ // Display time string length
+ longTimeDisp: false,
+
+ // Default control bar height
+ height: 20,
+
+ // Volume control layout is horizontal
+ volumeLayout: 'horizontal',
+
+ // Skin "kskin" is specific for wikimedia we have an
+ // api Title key so the "credits" menu item can be showed.
+ supportedMenuItems: {
+ 'credits': true
+ },
+ // Stores the current menu item id
+ currentMenuItem: null,
+
+ // Extends base components with kskin specific options:
+ components: {
+ 'pause': {
+ 'w': 28
+ },
+ 'volumeControl': {
+ 'w': 40
+ },
+ 'playButtonLarge' : {
+ 'h' : 55
+ },
+ 'options': {
+ 'w': 52,
+ 'o': function( ctrlObj ) {
+ return $( '<div />' )
+ .attr( 'title', mw.msg( 'mwe-embedplayer-player_options' ) )
+ .addClass( "ui-state-default ui-corner-bl rButton k-options" )
+ .append(
+ $( '<span />' )
+ .text( mw.msg( 'mwe-embedplayer-menu_btn' ) )
+ );
+ }
+ },
+ // No attributionButton component for kSkin ( its integrated into the credits screen )
+ 'attributionButton' : false,
+
+ // Time display:
+ 'timeDisplay': {
+ 'w': 52
+ },
+ 'optionsMenu': {
+ 'w' : 0,
+ 'o' : function( ctrlObj ) {
+ var embedPlayer = ctrlObj.embedPlayer;
+ var $menuOverlay = $( '<div />')
+ .addClass( 'overlay-win k-menu ui-widget-content' )
+ .css( {
+ 'width' : '100%',
+ 'position': 'absolute',
+ 'top' : '0px',
+ 'bottom' : ( ctrlObj.getHeight() + 2 ) + 'px'
+ } );
+
+ // Note safari can't display video overlays with text:
+ // see bug https://bugs.webkit.org/show_bug.cgi?id=48379
+
+ var userAgent = navigator.userAgent.toLowerCase();
+ if( userAgent.indexOf('safari') != -1 ){
+ $menuOverlay.css('opacity', '0.9');
+ }
+ // Setup menu offset ( if player height < getOverlayHeight )
+ // This displays the menu outside of the player on small embeds
+ if ( embedPlayer.getPlayerHeight() < ctrlObj.getOverlayHeight() ) {
+ var topPos = ( ctrlObj.isOverlayControls() )
+ ? embedPlayer.getPlayerHeight()
+ : embedPlayer.getPlayerHeight() + ctrlObj.getHeight();
+
+ if( embedPlayer.isAudio() ){
+ topPos = ctrlObj.embedPlayer.getInterface().height();
+ }
+
+ $menuOverlay.css( {
+ 'top' : topPos + 'px',
+ 'bottom' : null,
+ 'width' : ctrlObj.getOverlayWidth(),
+ 'height' : ctrlObj.getOverlayHeight() + 'px'
+ } );
+ // Special common overflow hack for thumbnail display of player
+ $( embedPlayer ).parents( '.thumbinner' ).css( 'overflow', 'visible' );
+ }
+
+ var $menuBar = $( '<ul />' )
+ .addClass( 'k-menu-bar' );
+
+ // Don't include about player menu item ( FIXME should be moved to a init function )
+ delete ctrlObj.supportedMenuItems['aboutPlayerLibrary'];
+
+ // Output menu item containers:
+ for ( var menuItem in ctrlObj.supportedMenuItems ) {
+ // Give grep a chance to find the usages:
+ // mwe-embedplayer-playerSelect, mwe-embedplayer-download,
+ // mwe-embedplayer-share, mwe-embedplayer-credits
+ $menuBar.append(
+ $( '<li />')
+ // Add the menu item class:
+ .addClass( 'k-' + menuItem + '-btn' )
+ .attr( 'rel', menuItem )
+ .append(
+ $( '<a />' )
+ .attr( {
+ 'title' : mw.msg( 'mwe-embedplayer-' + menuItem ),
+ 'href' : '#'
+ })
+ )
+ );
+ }
+
+ // Add the menuBar to the menuOverlay
+ $menuOverlay.append( $menuBar );
+
+ var $menuScreens = $( '<div />' )
+ .addClass( 'k-menu-screens' )
+ .css( {
+ 'position' : 'absolute',
+ 'top' : '0px',
+ 'left' : '0px',
+ 'bottom' : '0px',
+ 'right' : '45px',
+ 'overflow' : 'hidden'
+ } );
+ for ( var menuItem in ctrlObj.supportedMenuItems ) {
+ $menuScreens.append(
+ $( '<div />' )
+ .addClass( 'menu-screen menu-' + menuItem )
+ );
+ }
+
+ // Add the menuScreens to the menuOverlay
+ $menuOverlay.append( $menuScreens );
+
+ return $menuOverlay;
+
+ }
+ }
+ },
+
+ /**
+ * Get minimal width for interface overlay
+ */
+ getOverlayWidth: function(){
+ return ( this.embedPlayer.getPlayerWidth() < 220 )? 220 : this.embedPlayer.getPlayerWidth();
+ },
+
+ /**
+ * Get minimal height for interface overlay
+ */
+ getOverlayHeight: function(){
+ return ( this.embedPlayer.getPlayerHeight() < 160 )? 160 : this.embedPlayer.getPlayerHeight();
+ },
+
+ /**
+ * Adds the skin Control Bindings
+ */
+ addSkinControlBindings: function() {
+ var embedPlayer = this.embedPlayer;
+ var _this = this;
+
+ // Set up control bar pointer
+ this.$playerTarget = embedPlayer.$interface;
+ // Set the menu target:
+
+
+ // Options menu display:
+ this.$playerTarget.find( '.k-options' )
+ .unbind()
+ .click( function() {
+ _this.checkMenuOverlay();
+ var $kmenu = _this.$playerTarget.find( '.k-menu' );
+ if ( $kmenu.is( ':visible' ) ) {
+ _this.closeMenuOverlay( );
+ } else {
+ _this.showMenuOverlay();
+ // no other item is selected by default show the media credits:
+ if ( !_this.currentMenuItem ){
+ _this.showMenuItem('credits');
+ // Hide the others
+ _this.$playerTarget.find( '.menu-screen' ).hide();
+ // Show credits
+ _this.$playerTarget.find( '.menu-credits' ).fadeIn( "fast" );
+ }
+ }
+ } );
+
+ },
+
+ /**
+ * checks for menu overlay and runs menu bindings if unset
+ */
+ checkMenuOverlay: function(){
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+ if ( _this.$playerTarget.find( '.k-menu' ).length == 0 ) {
+ // Stop the player if it does not support overlays:
+ if ( !embedPlayer.supports['overlays'] ) {
+ embedPlayer.stop();
+ }
+
+ // Add the menu binding
+ _this.addMenuBinding();
+ }
+ },
+
+ /**
+ * Close the menu overlay
+ */
+ closeMenuOverlay: function() {
+ mw.log("PlayerSkinKskin:: close menu overlay" );
+ var embedPlayer = this.embedPlayer;
+ var $optionsMenu = embedPlayer.getInterface().find( '.k-options' );
+ var $kmenu = embedPlayer.getInterface().find( '.k-menu' );
+ $kmenu.fadeOut( "fast", function() {
+ $optionsMenu.find( 'span' )
+ .text ( mw.msg( 'mwe-embedplayer-menu_btn' ) );
+ } );
+ // show the play button if not playing
+ if( !embedPlayer.isPlaying() ){
+ embedPlayer.getInterface().find( '.play-btn-large' ).fadeIn( 'fast' );
+ }
+
+ // re-display the control bar if hidden:
+ this.showControlBar();
+
+ // Set close overlay menu flag:
+ this.displayOptionsMenuFlag = false;
+ },
+
+ /**
+ * Show the menu overlay
+ */
+ showMenuOverlay: function( $ktxt ) {
+ var $optionsMenu = this.$playerTarget.find( '.k-options' );
+ var $kmenu = this.$playerTarget.find( '.k-menu' );
+
+ $kmenu.fadeIn( "fast", function() {
+ $optionsMenu.find( 'span' )
+ .text ( mw.msg( 'mwe-embedplayer-close_btn' ) );
+ } );
+ this.$playerTarget.find( '.play-btn-large' ).fadeOut( 'fast' );
+
+ $(this.embedPlayer).trigger( 'displayMenuOverlay' );
+
+ // Set the Options Menu display flag to true:
+ this.displayOptionsMenuFlag = true;
+ },
+
+ /**
+ * Adds binding for the options menu
+ *
+ * @param {Object} $tp Target video container for
+ */
+ addMenuBinding: function() {
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+ // Set local player target pointer:
+ var $playerTarget = embedPlayer.$interface;
+
+ // Check if k-menu already exists:
+ if ( $playerTarget.find( '.k-menu' ).length != 0 )
+ return false;
+
+ // Add options menu to top of player target children:
+ $playerTarget.append(
+ _this.getComponent( 'optionsMenu' )
+ );
+
+ // By default its hidden:
+ $playerTarget.find( '.k-menu' ).hide();
+
+ // Add menu-items bindings:
+ for ( var menuItem in _this.supportedMenuItems ) {
+ $playerTarget.find( '.k-' + menuItem + '-btn' ).click( function( ) {
+
+ // Grab the context from the "clicked" menu item
+ var mk = $( this ).attr( 'rel' );
+
+ // hide all menu items
+ var $targetItem = $playerTarget.find( '.menu-' + mk );
+
+ // call the function showMenuItem
+ _this.showMenuItem( mk );
+
+ // Hide the others
+ $playerTarget.find( '.menu-screen' ).hide();
+
+ // Show the target menu item:
+ $targetItem.fadeIn( "fast" );
+
+ // Don't follow the # link
+ return false;
+ } );
+ }
+ },
+
+ /**
+ * Shows a selected menu_item
+ *
+ * NOTE: this should be merged with parent mw.PlayerControlBuilder optionMenuItems
+ * binding mode
+ *
+ * @param {String} menu_itme Menu item key to display
+ */
+ showMenuItem:function( menuItem ) {
+ var embedPlayer = this.embedPlayer;
+ this.currentMenuItem = menuItem;
+ //handle special k-skin specific display;
+ switch( menuItem ){
+ case 'credits':
+ this.showCredits();
+ break;
+ case 'playerSelect':
+ embedPlayer.$interface.find( '.menu-playerSelect').html(
+ this.getPlayerSelect()
+ );
+ break;
+ case 'download' :
+ embedPlayer.$interface.find( '.menu-download').text(
+ mw.msg('mwe-loading_txt' )
+ );
+ // Call show download with the target to be populated
+ this.showDownload(
+ embedPlayer.$interface.find( '.menu-download')
+ );
+ break;
+ case 'share':
+ embedPlayer.$interface.find( '.menu-share' ).html(
+ this.getShare()
+ );
+ break;
+ }
+ },
+
+ /**
+ * Show the credit screen ( presently specific to kaltura skin )
+ */
+ showCredits: function() {
+ // Set up the shortcuts:
+ var embedPlayer = this.embedPlayer;
+ var _this = this;
+ var $target = embedPlayer.$interface.find( '.menu-credits' );
+
+ $target.empty().append(
+ $('<h2 />')
+ .text( mw.msg( 'mwe-embedplayer-credits' ) ),
+ $('<div />')
+ .addClass( "credits_box ui-corner-all" )
+ .append(
+ $('<div/>')
+ .loadingSpinner()
+ .css({'position':'absolute','top':'50%','left':'50%'})
+ )
+ );
+
+ if( mw.config.get( 'EmbedPlayer.KalturaAttribution' ) == true ){
+ $target.append(
+ $( '<div />' )
+ .addClass( 'k-attribution' )
+ .attr({
+ 'title': mw.msg('mwe-embedplayer-kaltura-platform-title')
+ })
+ .click( function( ) {
+ window.location = 'http://html5video.org';
+ })
+ );
+ }
+ var $creditBox = $target.find('.credits_box');
+ $creditBox.data( 'playerId', embedPlayer.id );
+ $( embedPlayer ).triggerQueueCallback('showCredits', $creditBox, function( addedCredits ){
+ if( !addedCredits ){
+ $creditBox.find('.credits_box').text( mw.msg( 'mwe-embedplayer-nocredits') )
+ }
+ });
+ }
+
+};
+
+} )( mw, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/PlayerSkinMvpcf.css b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/PlayerSkinMvpcf.css
new file mode 100644
index 00000000..a9664ec5
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/PlayerSkinMvpcf.css
@@ -0,0 +1,194 @@
+/**
+ * reference player skin
+ */
+
+
+/*.ui-state-default */
+.mv-player a:link {color: #2060c1; text-decoration: underline;}
+.mv-player a:visited {color: #2060c1; text-decoration: underline;}
+/*a:visited {color: #75a5e4; text-decoration: underline;}*/ /*Not sure if you want this*/
+.mv-player a:hover {color: #75a5e4; text-decoration: underline;}
+.mv-player img, .mv-player img a, .mv-player img a:hover {border: 0;}
+
+
+.mv-player .video {
+ display: block;
+ position: relative;
+ font-size: 1px;
+ height: 305px;
+}
+.mv-player .control-bar {
+ overflow: hidden;
+ height: 29px;
+ margin: 0;
+ padding: 0;
+ border: 0;
+ z-index: 2;
+}
+.mv-player .controlInnerSmall {
+/* width: 430px;*/
+ height: 29px;
+ float: left;
+ display: inline;
+}
+
+.mv-player .lButton {
+ cursor:pointer;
+ float:left;
+ list-style:none outside none;
+ margin:2px;
+ padding:4px 0;
+ width: 24px;
+ height:16px;
+ position:relative;
+}
+.mv-player .rButton {
+ cursor:pointer;
+ float:right;
+ list-style:none outside none;
+ margin:2px;
+ padding:4px 0;
+ width: 23px;
+ height:16px;
+ position:relative;
+}
+
+.mv-player .volume_icon {
+ float: right;
+ display: inline;
+ width: 22px;
+ height: 29px;
+ padding: 0 0 0 0;
+
+}
+
+.mv-player .vol_container{
+ z-index:99;
+ width:23px;
+ height:75px;
+ width:23px;
+ position:absolute;
+ left:0px;
+ background: #CCC;
+}
+.mv-player .vol_container_below{
+ top:30px;
+}
+.mv-player .vol_container_top{
+ top:-77px;
+}
+.mv-player .vol_container .volume-slider{
+ margin-top:5px;
+ height:65px;
+ width:10px;
+ margin-left: auto ;
+ margin-right: auto ;
+}
+.mv-player .vol_container .ui-slider-handle{
+ cursor : pointer;
+ width:10px;
+ height:10px;
+ position:absolute;
+ left:-1px;
+}
+
+.mv-player .time-disp {
+ line-height: 32px;
+ height: 29px;
+ overflow: visible;
+ font-size: 10.2px;
+ float: right;
+ display: inline;
+ border:none;
+ padding-right:4px;
+}
+
+.mv-player .source-switch {
+ border: medium none;
+ display: inline;
+ color: #eee;
+ font: 11px arial, sans-serif;
+ line-height: 20px;
+ overflow: hidden;
+ width: 70px;
+ cursor: pointer;
+ float: right;
+ text-align: center;
+ padding-top:6px;
+}
+
+
+.mv-player .play_head{
+ float: left;
+ display: inline;
+ height: 10px;
+ margin-left:8px;
+ margin-top:10px;
+ margin-right: 8px;
+ position:relative;
+}
+
+.mv-player .play_head .ui-slider-handle{
+ width:10px;
+ height:15px;
+ margin-left:-5px;
+ margin-top: -0px;
+ z-index: 2;
+}
+
+.mv-player .inOutSlider .ui-slider-handle{
+ width:8px;
+ cusror: move;
+}
+
+.mv-player .overlay-win textarea {
+ background:none repeat scroll 0 0 transparent;
+ border: 2px solid #333;
+ color: #fff;
+ font: 11px arial,sans-serif;
+ height:15px;
+ overflow:hidden;
+ padding-left:2px;
+ width:97%;
+}
+
+.mv-player .overlay-win div.ui-state-highlight {
+ background:none repeat scroll 0 0 transparent;
+ border-color:#554926;
+ color:#FFE96E;
+ float:left;
+ padding:2px 5px;
+}
+
+.mv-player .videoOptionsComplete div.ui-state-highlight a {
+ color:#eee;
+ font-weight:bold;
+}
+
+.mv-player .overlay-win h2{
+ font-size: 115%;
+}
+
+.mv-player .overlay-win{
+ font-family : arial,sans-serif;
+ font-size : 85%;
+}
+.mv-player .overlay-win a{
+ text-decoration: none;
+}
+
+.mv-player .overlay-win ul{
+ padding-left: 15px;
+}
+
+.mv-player a:hover {}
+
+.mv-player .overlay-win ul li span { font-weight:bold; color:#fff;}
+
+.mv-player .overlay-win h2 { font-size:16px;}
+.mv-player .overlay-win h3 { font-size:14px;}
+
+.active { font-size: 12px; }
+
+.ui-slider-horizontal.volume-slider { width: 44px; height: 2px; top: 7px; }
+.ui-slider-horizontal.volume-slider .ui-slider-handle { border-width: 1px; }
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/images/player_big_play_button.png b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/images/player_big_play_button.png
new file mode 100644
index 00000000..155f15e1
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/images/player_big_play_button.png
Binary files differ
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/mw.PlayerSkinMvpcf.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/mw.PlayerSkinMvpcf.js
new file mode 100644
index 00000000..4b270418
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mvpcf/mw.PlayerSkinMvpcf.js
@@ -0,0 +1,7 @@
+/*
+mvpcf skin config
+*/
+
+mw.PlayerSkinMvpcf = {
+ playerClass : 'mv-player'
+}; \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mw.PlayerControlBuilder.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mw.PlayerControlBuilder.js
new file mode 100644
index 00000000..5ef54d4f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/skins/mw.PlayerControlBuilder.js
@@ -0,0 +1,2721 @@
+/**
+* Msg text is inherited from embedPlayer
+*/
+
+( function( mw, $ ) { "use strict";
+/**
+* mw.PlayerControlBuilder object
+* @param the embedPlayer element we are targeting
+*/
+mw.PlayerControlBuilder = function( embedPlayer, options ) {
+ return this.init( embedPlayer, options );
+};
+
+/**
+ * ControlsBuilder prototype:
+ */
+mw.PlayerControlBuilder.prototype = {
+ //Default Local values:
+
+ // Parent css Class name
+ playerClass : 'mv-player',
+
+ // Long string display of time value
+ longTimeDisp: true,
+
+ // Default volume layout is "vertical"
+ volumeLayout : 'vertical',
+
+ // Default control bar height
+ height: mw.config.get( 'EmbedPlayer.ControlsHeight' ),
+
+ // Default supported components is merged with embedPlayer set of supported types
+ supportedComponents: {
+ // All playback types support options
+ 'options': true
+ },
+
+ // Default supported menu items is merged with skin menu items
+ supportedMenuItems: {
+ // Player Select
+ 'playerSelect' : true,
+
+ // Download the file menu
+ 'download' : true,
+
+ // Share the video menu
+ 'share' : true,
+
+ // Player library link
+ 'aboutPlayerLibrary': true
+ },
+
+ // Flag to store the current fullscreen mode
+ inFullScreen: false,
+
+ // Flag to store if a warning binding has been added
+ addWarningFlag: false,
+
+ // Flag to store state of overlay on player
+ displayOptionsMenuFlag: false,
+
+ // Local storage of ControlBar Callback
+ hideControlBarCallback: false,
+
+ // Flag to store controls status (disabled/enabled)
+ controlsDisabled: false,
+
+ // binding postfix
+ bindPostfix: '.controlBuilder',
+
+ /**
+ * Initialization Object for the control builder
+ *
+ * @param {Object} embedPlayer EmbedPlayer interface
+ */
+ init: function( embedPlayer ) {
+ var _this = this;
+ this.embedPlayer = embedPlayer;
+ // Check for skin overrides for controlBuilder
+ var skinClass = embedPlayer.skinName.substr(0,1).toUpperCase() + embedPlayer.skinName.substr( 1 );
+ if ( mw['PlayerSkin' + skinClass ] ) {
+ // Clone as to not override prototype with the skin config
+ _this = $.extend( true, { }, this, mw['PlayerSkin' + skinClass ] );
+ }
+ if ( _this.embedPlayer.mediaElement.getPlayableSources().length <= 1
+ && _this.supportedMenuItems.playerSelect ) {
+ delete _this.supportedMenuItems.playerSelect;
+ }
+ // Return the controlBuilder Object:
+ return _this;
+ },
+
+ /**
+ * Get the control bar height
+ * @return {Number} control bar height
+ */
+ getHeight: function(){
+ return this.height;
+ },
+
+
+ /**
+ * Add the controls html to player interface
+ */
+ addControls: function() {
+ // Set up local pointer to the embedPlayer
+ var embedPlayer = this.embedPlayer,
+ profile = $.client.profile();
+
+ // Set up local controlBuilder
+ var _this = this;
+
+ // Remove any old controls & old overlays:
+ embedPlayer.getInterface().find( '.control-bar,.overlay-win' ).remove();
+
+ // Reset flags:
+ _this.displayOptionsMenuFlag = false;
+
+ // Setup the controlBar container ( starts hidden )
+ var $controlBar = $('<div />')
+ .addClass( 'ui-state-default ui-widget-header ui-helper-clearfix control-bar' )
+ .css( 'height', this.height );
+
+ // Controls are hidden by default if overlaying controls:
+ if( _this.isOverlayControls() ){
+ $controlBar.hide();
+ } else {
+ // Include the control bar height when calculating the layout
+ $controlBar.addClass('block');
+ }
+
+ // Make room for audio controls in the interface:
+ if( embedPlayer.isAudio() && embedPlayer.getInterface().height() == 0 ){
+ embedPlayer.getInterface().css( {
+ 'height' : this.height
+ } );
+ }
+
+ // Add the controls to the interface
+ embedPlayer.getInterface().append( $controlBar );
+
+ if ( profile.name === 'firefox' && profile.versionNumber < 2 ) {
+ embedPlayer.triggerHelper( 'resizeIframeContainer', [ {'height' : embedPlayer.height + $controlBar.height() - 1} ] );
+ }
+
+ // Add the Controls Component
+ this.addControlComponents();
+
+ // Add top level Controls bindings
+ this.addControlBindings();
+ },
+
+ /**
+ * Add control components as defined per this.components
+ */
+ addControlComponents: function( ) {
+ var _this = this;
+
+ // Set up local pointer to the embedPlayer
+ var embedPlayer = this.embedPlayer;
+
+ //Set up local var to control container:
+ var $controlBar = embedPlayer.getInterface().find( '.control-bar' );
+
+ this.availableWidth = embedPlayer.getPlayerWidth();
+
+ mw.log( 'PlayerControlsBuilder:: addControlComponents into:' + this.availableWidth );
+ // Build the supportedComponents list
+ this.supportedComponents = $.extend( this.supportedComponents, embedPlayer.supports );
+
+ // Check for Attribution button
+ if( mw.config.get( 'EmbedPlayer.AttributionButton' ) && embedPlayer.attributionbutton ){
+ this.supportedComponents[ 'attributionButton' ] = true;
+ }
+ // Check global fullscreen enabled flag
+ if( mw.config.get( 'EmbedPlayer.EnableFullscreen' ) === false ){
+ this.supportedComponents[ 'fullscreen'] = false;
+ }
+ // Check if the options item is available
+ if( mw.config.get( 'EmbedPlayer.EnableOptionsMenu' ) === false ){
+ this.supportedComponents[ 'options'] = false;
+ }
+ // Check for volume control
+ if( mw.config.get( 'EmbedPlayer.EnableVolumeControl') === false ){
+ this.supportedComponents[ 'volumeControl'] = false;
+ }
+
+ // Check if we have multiple playable sources ( if only one source don't display source switch )
+
+ if( embedPlayer.mediaElement.getPlayableSources().length == 1 ){
+ this.supportedComponents[ 'sourceSwitch' ] = false;
+
+ }
+
+ // Give embeds option to explicitly disable components via flag
+ var source = embedPlayer.mediaElement.getPlayableSources()[0];
+ if ( !embedPlayer.disablecontrols && source ) {
+ embedPlayer.disablecontrols = source.disablecontrols;
+ }
+ if ( embedPlayer.disablecontrols ) {
+ embedPlayer.disablecontrols.split(',').forEach(function( key ) {
+ mw.log( 'PlayerControlBuilder:: disabled component via flag:' + key );
+ _this.supportedComponents[ key ] = false;
+ });
+ }
+
+ $( embedPlayer ).trigger( 'addControlBarComponent', this );
+
+ var components = [];
+ var largestPos = 0;
+ var addComponent = function( componentId ){
+ if ( _this.supportedComponents[ componentId ] ) {
+ if ( _this.availableWidth >= _this.components[ componentId ].w ) {
+ _this.availableWidth -= _this.components[ componentId ].w;
+ // Check if position is defined, if not, place at end of known positions
+ var position = _this.components[ componentId ].position ?
+ _this.components[ componentId ].position:
+ largestPos+1
+ if( position > largestPos ){
+ largestPos = position;
+ }
+ components.push({
+ 'id': componentId,
+ 'position': position
+ });
+ //mw.log(" availableWidth:" + _this.availableWidth + ' ' + componentId + ' took: ' + _this.components[ componentId ].w )
+ } else {
+ mw.log( 'PlayerControlBuilder:: Not enough space for control component:' + componentId );
+ }
+ }
+ };
+
+ var addComponents = function() {
+ components.sort(function(a, b) {
+ return b.position - a.position;
+ });
+ for(var i=0;i<components.length;i++) {
+ $controlBar.append(
+ _this.getComponent( components[ i ]['id'] )
+ );
+ }
+ }
+
+ // Output components
+ for ( var componentId in this.components ) {
+ // Check for (component === false ) and skip
+ if( this.components[ componentId ] === false ){
+ continue;
+ }
+
+ // Special case with playhead and time ( to make sure they are to the left of everything else )
+ if ( componentId == 'playHead' ){
+ continue;
+ }
+ if( componentId == 'timeDisplay' && !mw.config.get( 'EmbedPlayer.EnableTimeDisplay' ) ){
+ continue;
+ }
+
+ // Skip "fullscreen" button for assets or where height is 0px ( audio )
+ if( componentId == 'fullscreen' && this.embedPlayer.isAudio() ){
+ continue;
+ }
+ // Skip sourceSwitch if width < smalles derivative
+ if ( componentId == 'sourceSwitch' && this.availableWidth < 320) {
+ continue;
+ }
+ addComponent( componentId );
+ }
+ if( this.availableWidth > 30 ){
+ addComponent( 'playHead' );
+ }
+ addComponents();
+ $(embedPlayer).trigger( 'controlBarBuildDone' );
+ },
+
+ /**
+ * Get a window size for the player while preserving aspect ratio:
+ *
+ * @@TODO This has similar logic to mw.embedPlayerNative applyIntrinsicAspect we should look
+ * at merging their functionality.
+ *
+ * @param {object} windowSize
+ * object that set { 'width': {width}, 'height':{height} } of target window
+ * @return {object}
+ * css settings for fullscreen player
+ */
+ getAspectPlayerWindowCss: function( windowSize ) {
+ var embedPlayer = this.embedPlayer;
+ var _this = this;
+ // Setup target height width based on max window size
+ if( !windowSize ){
+ var windowSize = {
+ 'width' : $( window ).width(),
+ 'height' : $( window ).height()
+ };
+ }
+ windowSize.width = parseInt( windowSize.width );
+ windowSize.height = parseInt( windowSize.height );
+ // See if we need to leave space for control bar
+ if( !_this.isOverlayControls() ){
+ //targetHeight = targetHeight - this.height;
+ windowSize.height = windowSize.height - this.height;
+ }
+
+ // Set target width
+ var targetWidth = windowSize.width;
+ var targetHeight = targetWidth * ( 1 / _this.getIntrinsicAspect() );
+ // Check if it exceeds the height constraint:
+ if( targetHeight > windowSize.height ){
+ targetHeight = windowSize.height;
+ targetWidth = parseInt( targetHeight * _this.getIntrinsicAspect() );
+ }
+ var offsetTop = 0;
+ // Move the video down 1/2 of the difference of window height
+ offsetTop+= ( targetHeight < windowSize.height )? ( windowSize.height- targetHeight ) / 2 : 0;
+ // if the video is very tall in a short window adjust the size:
+ var offsetLeft = ( targetWidth < windowSize.width )? parseInt( windowSize.width- targetWidth ) / 2 : 0;
+
+ var position = (mw.isIOS4() && mw.isIphone()) ? 'static' : 'absolute';
+ mw.log( 'PlayerControlBuilder::getAspectPlayerWindowCss: ' + ' h:' + targetHeight + ' w:' + targetWidth + ' t:' + offsetTop + ' l:' + offsetLeft );
+ return {
+ 'position' : position,
+ 'height': parseInt( targetHeight ),
+ 'width' : parseInt( targetWidth ),
+ 'top' : parseInt( offsetTop ),
+ 'left': parseInt( offsetLeft)
+ };
+ },
+
+ /**
+ * Get the intrinsic aspect ratio of media ( width / height )
+ * @return {float}
+ * size object with width and height
+ */
+ getIntrinsicAspect: function(){
+ var vid = this.embedPlayer.getPlayerElement();
+ // Check for raw intrinsic media size:
+ if( vid && vid.videoWidth && vid.videoHeight ){
+ return vid.videoWidth / vid.videoHeight;
+ }
+
+ // See if we have source data attributes available:
+ if( this.embedPlayer.mediaElement &&
+ this.embedPlayer.mediaElement.selectedSource )
+ {
+ var ss = this.embedPlayer.mediaElement.selectedSource;
+ // See if we have a hardcoded aspect to the source ( Adaptive streams don't have width / height )
+ if( ss.aspect ){
+ return ss.aspect;
+ }
+
+ if( ss.width && ss.height ){
+ return ss.width / ss.height
+ }
+ }
+
+ // check for posterImage size: ( should have Intrinsic aspect size as well )
+ var img = this.embedPlayer.getInterface().find('.playerPoster')[0];
+ if( img && img.naturalWidth && img.naturalHeight){
+ return img.naturalWidth / img.naturalHeight
+ }
+
+ // if all else fails use embedPlayer.getWidth()
+ return this.embedPlayer.getWidth() / this.embedPlayer.getHeight()
+ },
+
+ /**
+ * Get the play button css
+ */
+ getPlayButtonPosition: function() {
+ var _this = this;
+ return {
+ 'position' : 'absolute',
+ 'left' : '50%',
+ 'top' : '50%',
+ 'margin-left' : - .5 * this.getComponentWidth( 'playButtonLarge' ),
+ 'margin-top' : - .5 * this.getComponentHeight( 'playButtonLarge' )
+ };
+ },
+
+ /**
+ * Check if we're in Fullscreen
+ * @return {boolean)
+ */
+ isInFullScreen: function() {
+ return this.inFullScreen;
+ },
+
+ /**
+ * Toggles full screen by calling
+ * doFullScreenPlayer to enable fullscreen mode
+ * restoreWindowPlayer to restore window mode
+ */
+ toggleFullscreen: function( forceClose ) {
+ var _this = this;
+ // Do normal in-page fullscreen handling:
+ if( this.isInFullScreen() ){
+ this.restoreWindowPlayer();
+ }else {
+ this.doFullScreenPlayer();
+ }
+ // Don't follow the # link:
+ return false;
+ },
+
+ /**
+ * Do full-screen mode
+ */
+ doFullScreenPlayer: function( callback ) {
+ mw.log("PlayerControlBuilder:: doFullScreenPlayer" );
+ // Setup pointer to control builder :
+ var _this = this,
+ profile = $.client.profile();
+
+ // Store the page vertical scroll
+ var doc = window.document;
+ var context = window;
+ this.verticalScrollPosition = doc.all ? doc.scrollTop : context.pageYOffset;
+
+ // Setup local reference to embed player:
+ var embedPlayer = this.embedPlayer;
+
+ // Setup a local reference to the player interface:
+ var $interface = embedPlayer.getInterface();
+ // Check fullscreen state ( if already true do nothing )
+ if( this.isInFullScreen() == true ){
+ return ;
+ }
+ this.inFullScreen = true;
+
+ // Add fullscreen class to interface:
+ $interface.addClass( 'fullscreen' );
+
+ // if overlaying controls add hide show player binding.
+ if( _this.isOverlayControls() && !embedPlayer.isTouchDevice() ){
+ _this.addFullscreenMouseMoveHideShowControls();
+ }
+
+ // Store the current scroll location on the iframe:
+ $( embedPlayer ).trigger( 'fullScreenStoreVerticalScroll' );
+
+ if( window.fullScreenApi.supportsFullScreen ) {
+ _this.preFullscreenPlayerSize = this.getPlayerSize();
+ var fullscreenHeight = null;
+ var fsTarget = this.getFsTarget();
+
+ var escapeFullscreen = function( event ) {
+ // grab the correct document target to check for fullscreen
+ if ( ! window.fullScreenApi.isFullScreen( window.document ) ) {
+ _this.restoreWindowPlayer();
+ }
+ }
+ // remove any old binding:
+ fsTarget.removeEventListener( fullScreenApi.fullScreenEventName, escapeFullscreen );
+ // Add a binding to catch "escape" fullscreen
+ fsTarget.addEventListener( fullScreenApi.fullScreenEventName, escapeFullscreen );
+ // Make the iframe fullscreen:
+ window.fullScreenApi.requestFullScreen( fsTarget );
+
+ // There is a bug with mozfullscreenchange event in all versions of firefox with supportsFullScreen
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=724816
+ // so we have to have an extra binding to check for size change and then restore.
+ if( profile.name === 'firefox' ){
+ _this.fullscreenRestoreCheck = setInterval( function(){
+ if( fullscreenHeight && $(window).height() < fullscreenHeight ){
+ // Mozilla triggered size change:
+ clearInterval ( _this.fullscreenRestoreCheck );
+ _this.restoreWindowPlayer();
+ }
+ // set fullscreen height:
+ if( ! fullscreenHeight && _this.preFullscreenPlayerSize.height != $(window).height() ){
+ fullscreenHeight = $(window).height();
+ }
+ }, 250 );
+ }
+ } else {
+ // Check for hybrid html controls / native fullscreen support:
+ var vid = this.embedPlayer.getPlayerElement();
+ if( mw.config.get('EmbedPlayer.EnableIpadNativeFullscreen')
+ &&
+ vid && vid.webkitSupportsFullscreen
+ ){
+ this.doHybridNativeFullscreen();
+ return ;
+ } else {
+ // make the player traget or iframe fullscreen
+ this.doContextTargetFullscreen();
+ }
+ }
+
+ // Bind escape to restore in page clip ( IE9 needs a secondary escape binding )
+ $( window ).keyup( function( event ) {
+ // Escape check
+ if( event.keyCode == 27 ){
+ _this.restoreWindowPlayer();
+ }
+ } );
+
+ // trigger the open fullscreen event:
+ $( embedPlayer ).trigger( 'onOpenFullScreen' );
+
+ // re draw the controls after a timeout ( to allow the screen dom to update )
+ setTimeout( function(){
+ _this.addControls();
+ },100)
+ },
+
+ /**
+ * Make the target player interface or iframe fullscreen
+ */
+ doContextTargetFullscreen: function() {
+ var
+ _this = this,
+ doc = window.document,
+ $doc = $( doc ),
+ $target = $( this.getFsTarget() ),
+ context = window;
+
+ // update / reset local restore properties
+ this.parentsAbsoluteList = [];
+ this.parentsRelativeList = [];
+
+ // Set the original parent page scale if possible:
+ this.orginalParnetViewPortContent = $doc.find( 'meta[name="viewport"]' ).attr( 'content' );
+ this.orginalTargetElementLayout = {
+ 'style' : $target[0].style.cssText,
+ 'width' : $target.width(),
+ 'height' : $target.height()
+ };
+
+ mw.log("PlayerControls:: doParentIframeFullscreen> verticalScrollPosition:" + this.verticalScrollPosition);
+ context.scroll(0, 0);
+
+ // Make sure the parent page page has a zoom of 1:
+ if( ! $doc.find('meta[name="viewport"]').length ){
+ $doc.find('head').append( $( '<meta />' ).attr('name', 'viewport') );
+ }
+ $doc.find('meta[name="viewport"]').attr('content', 'initial-scale=1; maximum-scale=1; minimum-scale=1;' );
+
+ // iPad 5 supports fixed position in a bad way, use absolute pos for iOS
+ var playerCssPosition = ( mw.isIOS() ) ? 'absolute': 'fixed';
+
+ // Remove absolute css of the $target's parents
+ $target.parents().each( function() {
+ var $parent = $( this );
+ if( $parent.css( 'position' ) == 'absolute' ) {
+ _this.parentsAbsoluteList.push( $parent );
+ $parent.css( 'position', 'static' );
+ }
+ if( $parent.css( 'position' ) == 'relative' ) {
+ _this.parentsRelativeList.push( $parent );
+ $parent.css( 'position', 'static' );
+ }
+ });
+
+ // Make the $target fullscreen
+ $target
+ .css({
+ 'z-index': mw.config.get( 'EmbedPlayer.FullScreenZIndex' ),
+ 'position': playerCssPosition,
+ 'top' : '0px',
+ 'left' : '0px',
+ 'margin': 0
+ })
+ .data(
+ 'isFullscreen', true
+ );
+
+ var updateTargetSize = function() {
+ context.scroll(0, 0);
+ $target.css({
+ 'width' : context.innerWidth,
+ 'height' : context.innerHeight
+ });
+ // update player size if needed:
+ _this.embedPlayer.applyIntrinsicAspect();
+ };
+
+ updateTargetSize();
+
+ // Bind orientation change to resize player ( if fullscreen )
+ $( context ).bind( 'orientationchange', function(e){
+ if( _this.isInFullScreen() ){
+ updateTargetSize();
+ }
+ });
+
+ // prevent scrolling when in fullscreen: ( both iframe and dom target use document )
+ document.ontouchmove = function( e ){
+ if( _this.isInFullScreen() ){
+ e.preventDefault();
+ }
+ };
+ },
+ /**
+ * Restore the player interface or iframe to a window player
+ */
+ restoreContextPlayer: function(){
+ var
+ _this = this,
+ doc = window.document,
+ $doc = $( doc ),
+ $target = $( this.getFsTarget() ),
+ context = window;
+
+ mw.log("PlayerControlsBuilder:: restoreContextPlayer> verticalScrollPosition:" + this.verticalScrollPosition );
+
+ // Restore document zoom:
+ if( this.orginalParnetViewPortContent ){
+ $doc.find('meta[name="viewport"]').attr('content', this.orginalParnetViewPortContent );
+ } else {
+ // Restore user zoom: ( NOTE, there does not appear to be a way to know the
+ // initial scale, so we just restore to 1 in the absence of explicit viewport tag )
+ // In order to restore zoom, we must set maximum-scale to a valid value
+ $doc.find('meta[name="viewport"]').attr('content', 'initial-scale=1; maximum-scale=8; minimum-scale=1;' );
+ }
+ if( this.orginalTargetElementLayout ) {
+ $target[0].style.cssText = this.orginalTargetElementLayout.style;
+ $target.attr({
+ 'width': this.orginalTargetElementLayout.width,
+ 'height': this.orginalTargetElementLayout.height
+ });
+ // update player size if needed:
+ _this.embedPlayer.applyIntrinsicAspect();
+ }
+ // Restore any parent absolute pos:
+ $doc.find( _this.parentsAbsoluteList ).each( function() {
+ $( this ).css( 'position', 'absolute' );
+ } );
+ $doc.find( _this.parentsRelativeList ).each( function() {
+ $( this ).css( 'position', 'relative' );
+ } );
+ },
+
+ /**
+ * Supports hybrid native fullscreen, player html controls, and fullscreen is native
+ */
+ doHybridNativeFullscreen: function(){
+ var vid = this.embedPlayer.getPlayerElement();
+ var _this = this;
+ vid.webkitEnterFullscreen();
+ // start to pull for exit fullscreen:
+ this.fsIntervalID = setInterval( function(){
+ var currentFS = vid.webkitDisplayingFullscreen;
+ // Check if we have entered fullscreen but the player
+ // has exited fullscreen with native controls click
+ if( _this.isInFullScreen() && !currentFS ){
+ // restore non-fullscreen player state
+ _this.inFullScreen = false;
+ // Trigger the onCloseFullscreen event:
+ $( _this.embedPlayer ).trigger( 'onCloseFullScreen' );
+ // stop polling for state change.
+ clearInterval( _this.fsIntervalID );
+ }
+ }, 250 );
+ },
+ getWindowSize: function(){
+ return {
+ 'width' : $(window).width(),
+ 'height' : $(window).height()
+ };
+ },
+ doDomFullscreen: function(){
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+ var $interface = embedPlayer.getInterface();
+ // Remove any old mw-fullscreen-overlay
+ $( '.mw-fullscreen-overlay' ).remove();
+
+ _this.preFullscreenPlayerSize = this.getPlayerSize();
+
+ // Add the css fixed fullscreen black overlay as a sibling to the video element
+ // iOS4 does not respect z-index
+ $interface.after(
+ $( '<div />' )
+ .addClass( 'mw-fullscreen-overlay' )
+ // Set some arbitrary high z-index
+ .css('z-index', mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) )
+ .hide()
+ .fadeIn("slow")
+ );
+
+ // get the original interface to absolute positioned:
+ if( ! this.windowPositionStyle ){
+ this.windowPositionStyle = $interface.css( 'position' );
+ }
+ if( !this.windowZindex ){
+ this.windowZindex = $interface.css( 'z-index' );
+ }
+ // Get the base offset:
+ this.windowOffset = this.getWindowOffset();
+
+ // Change the z-index of the interface
+ $interface.css( {
+ 'position' : 'fixed',
+ 'z-index' : mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) + 1,
+ 'top' : this.windowOffset.top,
+ 'left' : this.windowOffset.left
+ } );
+
+ // If native persistent native player update z-index:
+ if( embedPlayer.isPersistentNativePlayer() ){
+ $( embedPlayer.getPlayerElement() ).css( {
+ 'z-index': mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) + 1,
+ 'position': 'absolute'
+ });
+ }
+
+ // Empty out the parent absolute index
+ _this.parentsAbsolute = [];
+
+ // Hide the body scroll bar
+ $('body').css( 'overflow', 'hidden' );
+
+ var topOffset = '0px';
+ var leftOffset = '0px';
+
+ // Check if we have an offsetParent
+ if( $interface.offsetParent()[0].tagName
+ &&
+ $interface.offsetParent()[0].tagName.toLowerCase() != 'body' )
+ {
+ topOffset = -this.windowOffset.top + 'px';
+ leftOffset = -this.windowOffset.left + 'px';
+ }
+
+ // Overflow hidden in fullscreen:
+ $interface.css( 'overlow', 'hidden' );
+
+ // Remove absolute css of the interface parents
+ $interface.parents().each( function() {
+ //mw.log(' parent : ' + $( this ).attr('id' ) + ' class: ' + $( this ).attr('class') + ' pos: ' + $( this ).css( 'position' ) );
+ if( $( this ).css( 'position' ) == 'absolute' ) {
+ _this.parentsAbsolute.push( $( this ) );
+ $( this ).css( 'position', null );
+ mw.log( 'PlayerControlBuilder:: should update position: ' + $( this ).css( 'position' ) );
+ }
+ });
+
+ // Bind escape to restore in page clip
+ $( window ).keyup( function( event ) {
+ // Escape check
+ if( event.keyCode == 27 ){
+ _this.restoreWindowPlayer();
+ }
+ } );
+ },
+ addFullscreenMouseMoveHideShowControls:function(){
+ var _this = this;
+ // Bind mouse move in interface to hide control bar
+ _this.mouseMovedFlag = false;
+ _this.embedPlayer.getInterface().mousemove( function(e){
+ _this.mouseMovedFlag = true;
+ });
+
+ // Check every 2 seconds reset flag status if controls are overlay
+ var checkMovedMouse = function(){
+ if( _this.isInFullScreen() ){
+ if( _this.mouseMovedFlag ){
+ _this.mouseMovedFlag = false;
+ _this.showControlBar();
+ // Once we move the mouse keep displayed for 3 seconds
+ setTimeout(checkMovedMouse, 3000);
+ } else {
+ // Check for mouse movement every 250ms
+ _this.hideControlBar();
+ setTimeout(checkMovedMouse, 250 );
+ }
+ return;
+ }
+ };
+ // always initially show the control bar:
+ _this.showControlBar();
+ // start monitoring for moving mouse
+ checkMovedMouse();
+ },
+ getWindowOffset: function(){
+ var windowOffset = this.embedPlayer.getInterface().offset();
+ windowOffset.top = windowOffset.top - $(document).scrollTop();
+ windowOffset.left = windowOffset.left - $(document).scrollLeft();
+ this.windowOffset = windowOffset;
+ return this.windowOffset;
+ },
+ // Display a fullscreen tip if configured to do and the browser supports it.
+ displayFullscreenTip: function(){
+ var _this = this;
+ // Mobile devices don't have f11 key
+ if( mw.isMobileDevice() ){
+ return ;
+ }
+ // Safari does not have a DOM fullscreen ( no subtitles, no controls )
+ if ( $.client.profile().name === 'safari' ) {
+ return;
+ }
+
+ // OSX has a different short cut than windows and liux
+ var toolTipMsg = ( navigator.userAgent.indexOf('Mac OS X') != -1 )?
+ mw.msg( 'mwe-embedplayer-fullscreen-tip-osx') :
+ mw.msg( 'mwe-embedplayer-fullscreen-tip');
+
+ var $targetTip = this.addWarningBinding( 'EmbedPlayer.FullscreenTip',
+ $('<h3/>').html(
+ toolTipMsg
+ )
+ );
+
+ // Display the target warning:
+ $targetTip.show();
+
+ var hideTip = function(){
+ mw.setConfig('EmbedPlayer.FullscreenTip', false );
+ $targetTip.fadeOut('fast');
+ };
+
+ // Hide fullscreen tip if:
+ // We leave fullscreen,
+ $( this.embedPlayer ).bind( 'onCloseFullScreen', hideTip );
+ // After 5 seconds,
+ setTimeout( hideTip, 5000 );
+ // Or if we catch an f11 button press
+ $( document ).keyup( function( event ){
+ if( event.keyCode == 122 ){
+ hideTip();
+ }
+ return true;
+ });
+ },
+ // TOOD fullscreen iframe vs inpage object abstraction
+ //( avoid repatiave conditionals in getters )
+ getPlayerSize: function(){
+ var height = $(window).height() - this.getHeight();
+ if( mw.config.get('EmbedPlayer.IsIframeServer' ) ){
+ return {
+ 'height' : height,
+ 'width' : $(window).width()
+ }
+ } else {
+ return {
+ 'height' : this.embedPlayer.getInterface().height(),
+ 'width' : this.embedPlayer.getInterface().width()
+ }
+ }
+ },
+ getFsTarget: function(){
+ var $interface = this.embedPlayer.getInterface();
+ return $interface[0];
+ },
+ /**
+ * Restore the window player
+ */
+ restoreWindowPlayer: function() {
+ var _this = this;
+ mw.log("PlayerControlBuilder :: restoreWindowPlayer" );
+ var embedPlayer = this.embedPlayer;
+
+ // Check if fullscreen mode is already restored:
+ if( this.isInFullScreen() === false ){
+ return ;
+ }
+ // Set fullscreen mode to false
+ this.inFullScreen = false;
+
+ // remove the fullscreen interface
+ embedPlayer.getInterface().removeClass( 'fullscreen' );
+
+ // Check for native support for fullscreen and support native fullscreen restore
+ if ( window.fullScreenApi.supportsFullScreen ) {
+ var fsTarget = this.getFsTarget();
+ window.fullScreenApi.cancelFullScreen( fsTarget );
+ }
+
+ // Restore the iFrame context player
+ this.restoreContextPlayer();
+
+ // Restore scrolling on iPad
+ $( document ).unbind( 'touchend.fullscreen' );
+
+ // Trigger the onCloseFullscreen event:
+ $( embedPlayer ).trigger( 'onCloseFullScreen' );
+
+ // Scroll back to the previews position ( do in async call to allow dom fullscreen restore )
+ setTimeout( function(){
+ window.scroll( 0, _this.verticalScrollPosition );
+ }, 100 );
+
+ // re draw the controls after a timeout ( to allow the screen dom to update )
+ setTimeout( function(){
+ _this.addControls();
+ },100)
+ },
+ restoreDomPlayer: function(){
+ var _this = this;
+ // local ref to embedPlayer:
+ var embedPlayer = this.embedPlayer;
+
+ var $interface = embedPlayer.$interface;
+ var interfaceHeight = ( _this.isOverlayControls() )
+ ? embedPlayer.getHeight()
+ : embedPlayer.getHeight() + _this.getHeight();
+
+ mw.log( 'restoreWindowPlayer:: h:' + interfaceHeight + ' w:' + embedPlayer.getWidth());
+ $('.mw-fullscreen-overlay').remove( 'slow' );
+
+ mw.log( 'restore embedPlayer:: ' + embedPlayer.getWidth() + ' h: ' + embedPlayer.getHeight() );
+
+ // Restore the player:
+ embedPlayer.getInterface().css( {
+ 'width' : _this.preFullscreenPlayerSize.width,
+ 'height' : _this.preFullscreenPlayerSize.height
+ });
+ var topPos = {
+ 'position' : _this.windowPositionStyle,
+ 'z-index' : _this.windowZindex,
+ 'overlow' : 'visible',
+ 'top' : '0px',
+ 'left' : '0px'
+ };
+ // Restore non-absolute layout:
+ $( [ $interface, $interface.find('.playerPoster'), embedPlayer ] ).css( topPos );
+ if( embedPlayer.getPlayerElement() ){
+ $( embedPlayer.getPlayerElement() )
+ .css( topPos )
+ }
+ // Restore the body scroll bar
+ $('body').css( 'overflow', 'auto' );
+
+ // If native player restore z-index:
+ if( embedPlayer.isPersistentNativePlayer() ){
+ $( embedPlayer.getPlayerElement() ).css( {
+ 'z-index': 'auto'
+ });
+ }
+ },
+ /**
+ * Get minimal width for interface overlay
+ */
+ getOverlayWidth: function( ) {
+ return ( this.embedPlayer.getPlayerWidth() < 300 )? 300 : this.embedPlayer.getPlayerWidth();
+ },
+
+ /**
+ * Get minimal height for interface overlay
+ */
+ getOverlayHeight: function( ) {
+ return ( this.embedPlayer.getPlayerHeight() < 200 )? 200 : this.embedPlayer.getPlayerHeight();
+ },
+
+ /**
+ * addControlBindings
+ * Adds control hooks once controls are in the DOM
+ */
+ addControlBindings: function( ) {
+ // Set up local pointer to the embedPlayer
+ var embedPlayer = this.embedPlayer,
+ _this = this,
+ $interface = embedPlayer.getInterface(),
+ profile = $.client.profile();
+
+ _this.onControlBar = false;
+
+ // Remove any old interface bindings
+ $( embedPlayer ).unbind( this.bindPostfix );
+
+ var bindFirstPlay = false;
+ _this.addRightClickBinding();
+
+ // add the player click bindings
+ _this.addPlayerClickBindings();
+
+ // Bind into play.ctrl namespace ( so we can unbind without affecting other play bindings )
+ $( embedPlayer ).bind( 'onplay' + this.bindPostfix, function() { //Only bind once played
+ // add right click binding again ( in case the player got swaped )
+ embedPlayer.controlBuilder.addRightClickBinding();
+ });
+
+ $( embedPlayer ).bind( 'timeupdate' + this.bindPostfix, function(){
+ embedPlayer.updatePlayheadStatus()
+ });
+
+ // Update buffer information
+ $( embedPlayer ).bind( 'progress' + this.bindPostfix, function( event, jEvent, id){
+ // regain scope
+ var embedPlayer = $( '#' + id )[0];
+ embedPlayer.updateBufferStatus();
+ });
+
+ // Bind to EnableInterfaceComponents
+ $( embedPlayer ).bind( 'onEnableInterfaceComponents' + this.bindPostfix, function() {
+ embedPlayer.controlBuilder.controlsDisabled = false;
+ embedPlayer.controlBuilder.addPlayerClickBindings();
+ });
+
+ // Bind to DisableInterfaceComponents
+ $( embedPlayer ).bind( 'onDisableInterfaceComponents' + this.bindPostfix, function() {
+ embedPlayer.controlBuilder.controlsDisabled = true;
+ embedPlayer.controlBuilder.removePlayerClickBindings();
+ });
+
+
+ // TODO select a player on the page
+ var bindSpaceUp = function(){
+ $(window).bind('keyup' + _this.bindPostfix, function(e) {
+ if( e.keyCode == 32 ) {
+ if(embedPlayer.paused) {
+ embedPlayer.play();
+ } else {
+ embedPlayer.pause();
+ }
+ return false;
+ }
+ });
+ };
+
+ var bindSpaceDown = function() {
+ $(window).unbind( 'keyup' + _this.bindPostfix );
+ };
+
+ // Bind to resize event
+ /*
+ var triggerUpdate;
+ $( window ).resize(function() {
+ // We use setTimeout because of iOS 4.2 issues
+ clearTimeout(triggerUpdate);
+ triggerUpdate = setTimeout(function() {
+ //embedPlayer.triggerHelper('updateLayout');
+ }, 100);
+ });
+ */
+
+ $(window).on("debouncedresize", function() {
+ embedPlayer.triggerHelper('updateLayout');
+ });
+
+ // Add hide show bindings for control overlay (if overlay is enabled )
+ if( ! _this.isOverlayControls() ) {
+ $interface
+ .show()
+ .hover( bindSpaceUp, bindSpaceDown );
+
+ // include touch start pause binding
+ $( embedPlayer).bind( 'touchstart' + this.bindPostfix, function() {
+ embedPlayer._playContorls = true;
+ mw.log( "PlayerControlBuilder:: touchstart:" + ' isPause:' + embedPlayer.paused);
+ if( embedPlayer.paused ) {
+ embedPlayer.play();
+ } else {
+ embedPlayer.pause();
+ }
+ });
+ } else { // hide show controls:
+ // Bind a startTouch to show controls
+ $( embedPlayer).bind( 'touchstart' + this.bindPostfix, function() {
+ if ( embedPlayer.getInterface().find( '.control-bar' ).is( ':visible' ) ) {
+ if( embedPlayer.paused ) {
+ embedPlayer.play();
+ } else {
+ embedPlayer.pause();
+ }
+ } else {
+ _this.showControlBar();
+ }
+ clearTimeout( _this.hideControlBarCallback );
+ _this.hideControlBarCallback = setTimeout( function() {
+ _this.hideControlBar();
+ }, 60000 );
+ // ( Once the user touched the video "don't hide" )
+ return true;
+ } );
+
+ var hoverIntentConfig = {
+ 'sensitivity': 100,
+ 'timeout' : 1000,
+ 'over' : function(e){
+ // Clear timeout on IE9
+ if( mw.isIE9() ) {
+ clearTimeout(_this.hideControlBarCallback);
+ _this.hideControlBarCallback = false;
+ }
+ // Show controls with a set timeout ( avoid fade in fade out on short mouse over )
+ _this.showControlBar();
+ bindSpaceUp();
+ },
+ 'out' : function(e){
+ _this.hideControlBar();
+ bindSpaceDown();
+ }
+ };
+
+ // Check if we should display the interface:
+ // special check for IE9 ( does not count hover on non-visiable inerface div
+ if( mw.isIE9() ){
+ $( embedPlayer.getPlayerElement() ).hoverIntent( hoverIntentConfig );
+
+ // Add hover binding to control bar
+ embedPlayer.getInterface().find( '.control-bar' ).hover( function(e) {
+ _this.onControlBar = true;
+ embedPlayer.getInterface().find( '.control-bar' ).show();
+ }, function( e ) {
+ if (!_this.hideControlBarCallback) {
+ _this.hideControlBarCallback = setTimeout(function(){
+ _this.hideControlBar();
+ },1000);
+ }
+ _this.onControlBar = false;
+ });
+
+ } else {
+ if ( !mw.isIpad() ) {
+ $interface.hoverIntent( hoverIntentConfig );
+ }
+ }
+
+ }
+
+ // Add recommend firefox if we have non-native playback:
+ if ( _this.checkNativeWarning( ) ) {
+ _this.addWarningBinding(
+ 'EmbedPlayer.ShowNativeWarning',
+ mw.msg( 'mwe-embedplayer-for_best_experience',
+ $('<div>').append(
+ $('<a />')
+ .attr({
+ 'href': 'http://www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download',
+ 'target' : '_new'
+ })
+ )[0].innerHTML
+ )
+ );
+ }
+
+ // Do png fix for ie6
+ if ( profile.name === 'msie' && profile.versionNumber <= 6 ) {
+ $( '#' + embedPlayer.id + ' .play-btn-large' ).pngFix();
+ }
+
+ this.doVolumeBinding();
+
+ // Check if we have any custom skin Bindings to run
+ if ( this.addSkinControlBindings && typeof( this.addSkinControlBindings ) == 'function' ){
+ this.addSkinControlBindings();
+ }
+
+ mw.log( 'trigger::addControlBindingsEvent' );
+ $( embedPlayer ).trigger( 'addControlBindingsEvent' );
+ },
+ removePlayerClickBindings: function(){
+ $( this.embedPlayer )
+ .unbind( "click" + this.bindPostfix )
+ .unbind( "dblclick" + this.bindPostfix );
+ },
+ addPlayerClickBindings: function(){
+
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+
+ // prevent scrolling when in fullscreen:
+ document.ontouchmove = function( e ){
+ if( _this.isInFullScreen() ){
+ e.preventDefault();
+ }
+ };
+ // Remove old click bindings before adding:
+ this.removePlayerClickBindings();
+
+ // Setup "dobuleclick" fullscreen binding to embedPlayer ( if enabled )
+ if ( this.supportedComponents['fullscreen'] ){
+ $( embedPlayer ).bind( "dblclick" + _this.bindPostfix, function(){
+ embedPlayer.fullscreen();
+ });
+ }
+
+ var dblClickTime = 300;
+ var lastClickTime = 0;
+ var didDblClick = false;
+
+ var playerClickCb = function( event ) {
+ // make sure the event matches:
+ if( event.currentTarget.id != embedPlayer.id ){
+ embedPlayer = $( '#' + event.currentTarget.id )[0];
+ }
+ mw.log( "PlayerControlBuilder:: click:" + embedPlayer.id + ' isPause:' + embedPlayer.paused);
+ // Don't do anything if touch interface or native controls are shown
+ if( embedPlayer.useNativePlayerControls()
+ ||
+ _this.isControlsDisabled()
+ ||
+ embedPlayer.isTouchDevice()
+ ) {
+ return true;
+ }
+ var clickTime = new Date().getTime();
+ if( clickTime -lastClickTime < dblClickTime ) {
+ didDblClick = true;
+ setTimeout( function(){
+ didDblClick = false;
+ }, dblClickTime + 10 );
+ }
+ lastClickTime = clickTime;
+ setTimeout( function(){
+ // check if no click has since the time we called the setTimeout
+ if( !didDblClick ){
+ if( embedPlayer.paused ) {
+ embedPlayer.play();
+ } else {
+ embedPlayer.pause();
+ }
+ }
+ }, dblClickTime );
+ return true;
+ };
+ // Add click binding: ( $(embedPlayer).click ) has scope issues )
+ if ( embedPlayer.attachEvent ) {
+ embedPlayer.attachEvent("onclick", playerClickCb);
+ } else{
+ // Firefox 3.5 requires third argument to addEventListener
+ embedPlayer.addEventListener('click', playerClickCb, false );
+ }
+
+ },
+ addRightClickBinding: function(){
+ var embedPlayer = this.embedPlayer;
+ // check config:
+ if( mw.config.get( 'EmbedPlayer.EnableRightClick') === false ){
+ document.oncontextmenu= function(e){return false;};
+ $(embedPlayer).mousedown(function(e){
+ if( e.button == 2 ) {
+ return false;
+ }
+ });
+ }
+ },
+ /**
+ * Hide the control bar.
+ */
+ hideControlBar : function(){
+ var animateDuration = 'fast';
+ var _this = this;
+
+ // Do not hide control bar if overlay menu item is being displayed:
+ if( _this.displayOptionsMenuFlag || _this.keepControlBarOnScreen ) {
+ setTimeout( function(){
+ _this.hideControlBar();
+ }, 200 );
+ return ;
+ }
+
+ // IE9: If the user mouse is on the control bar, don't hide it
+ if( this.onControlBar === true ) {
+ return ;
+ }
+
+ // Hide the control bar
+ this.embedPlayer.getInterface().find( '.control-bar')
+ .fadeOut( animateDuration );
+ //mw.log('about to trigger hide control bar')
+ // Allow interface items to update:
+ $( this.embedPlayer ).trigger('onHideControlBar', [ {'bottom' : 15}, this.embedPlayer.id ] );
+
+ },
+ restoreControlsHover:function(){
+ if( this.isOverlayControls() ){
+ this.keepControlBarOnScreen = false;
+ }
+ },
+ /**
+ * Show the control bar
+ */
+ showControlBar: function( keepOnScreen ){
+ var animateDuration = 'fast';
+ if(! this.embedPlayer )
+ return ;
+
+ if( this.embedPlayer.getPlayerElement && ! this.embedPlayer.isPersistentNativePlayer() ){
+ $( this.embedPlayer.getPlayerElement() ).css( 'z-index', '1' );
+ }
+ mw.log( 'PlayerControlBuilder:: ShowControlBar, keep on screen: ' + keepOnScreen );
+
+ // Show interface controls
+ this.embedPlayer.getInterface().find( '.control-bar' )
+ .fadeIn( animateDuration );
+
+ if( keepOnScreen ){
+ this.keepControlBarOnScreen = true;
+ }
+
+ // Trigger the screen overlay with layout info:
+ $( this.embedPlayer ).trigger( 'onShowControlBar', [{
+ 'bottom' : this.getHeight() + 15
+ }, this.embedPlayer.id ] );
+ },
+
+ /**
+ * Checks if the browser supports overlays and the controlsOverlay is
+ * set to true for the player or via config
+ */
+ isOverlayControls: function(){
+ //if the player "supports" overlays:
+ if( ! this.embedPlayer.supports['overlays'] ){
+ return false;
+ }
+
+ // If disabled via the player
+ if( this.embedPlayer.overlaycontrols === false ){
+ return false;
+ }
+
+ // Don't overlay controls if in audio mode:
+ if( this.embedPlayer.isAudio() ){
+ return false;
+ }
+
+
+ // If the config is false
+ if( mw.config.get( 'EmbedPlayer.OverlayControls' ) === false){
+ return false;
+ }
+
+ if( this.embedPlayer.controls === false ){
+ return false;
+ }
+
+ // Past all tests OverlayControls is true:
+ return true;
+ },
+
+ /* Check if the controls are disabled */
+
+ isControlsDisabled: function() {
+ return this.controlsDisabled;
+ },
+
+ /**
+ * Check if a warning should be issued to non-native playback systems
+ *
+ * dependent on mediaElement being setup
+ */
+ checkNativeWarning: function( ) {
+ if( mw.config.get( 'EmbedPlayer.ShowNativeWarning' ) === false ){
+ return false;
+ }
+
+ // Don't show for imageOverlay player:
+ if( this.embedPlayer.instanceOf == 'ImageOverlay' ){
+ return false;
+ }
+
+ // If the resolution is too small don't display the warning
+ if( parseInt( this.embedPlayer.getPlayerHeight() ) < 199 ){
+ return false;
+ }
+
+ // See if we have we have native support
+ if( this.embedPlayer.instanceOf == 'Native' ){
+ return false;
+ }
+
+ // Not a lot of good options for an iPhone
+ if( this.embedPlayer.instanceOf == 'VLCApp' ){
+ return false;
+ }
+ if( this.embedPlayer.instanceOf == 'OgvJs' ){
+ return false;
+ }
+
+ // Chrome's webM support is oky though:
+ if( /chrome/.test(navigator.userAgent.toLowerCase() ) &&
+ mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'video/webm' ).length ){
+ return false;
+ }
+
+
+ // Check for h264 and or flash/flv source and playback support and don't show warning
+ if(
+ ( mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'video/h264' ).length
+ && this.embedPlayer.mediaElement.getSources( 'video/h264' ).length )
+ ||
+ ( mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'video/x-flv' ).length
+ && this.embedPlayer.mediaElement.getSources( 'video/x-flv' ).length )
+ ||
+ ( mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'application/vnd.apple.mpegurl' ).length
+ && this.embedPlayer.mediaElement.getSources( 'application/vnd.apple.mpegurl' ).length )
+ ||
+ ( mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'audio/mpeg' ).length
+ && this.embedPlayer.mediaElement.getSources( 'audio/mpeg' ).length )
+ ){
+ // No firefox link if a h.264 or flash/flv stream is present
+ return false;
+ }
+
+ // Should issue the native warning
+ return true;
+ },
+
+ /**
+ * Does a native warning check binding to the player on mouse over.
+ * @param {string} preferenceId The preference Id
+ * @param {object} warningMsg The jQuery object warning message to be displayed.
+ *
+ */
+ /**
+ * Display a warning message on the player
+ * checks a preference Id to enable or disable it.
+ * @param {string} preferenceId The preference Id
+ * @param {object} warningMsg The jQuery object warning message to be displayed.
+ * @param {boolean} if the hide ui should be exposed
+ *
+ */
+ addWarningBinding: function( preferenceId, warningMsg, hideDisableUi ) {
+ mw.log( 'mw.PlayerControlBuilder: addWarningBinding: ' + preferenceId + ' wm: ' + warningMsg);
+ // Set up local pointer to the embedPlayer
+ var embedPlayer = this.embedPlayer;
+ var _this = this;
+ // make sure the player is large enough
+ if( embedPlayer.getWidth() < 200 ){
+ return false;
+ }
+
+ // Can be uncommented to reset hide prefrence
+ //$.cookie( preferenceId, '' );
+
+ // Check if a cookie has been set to hide the warning:
+ if ( mw.config.get( preferenceId ) === true && $.cookie( preferenceId ) == 'hidewarning' ){
+ return ;
+ }
+
+ var warnId = "warningOverlay_" + embedPlayer.id;
+ $( '#' + warnId ).remove();
+
+ // Add the targetWarning:
+ var $targetWarning = $('<div />')
+ .attr( {
+ 'id': warnId
+ } )
+ .addClass( 'ui-corner-all' )
+ .css({
+ 'position' : 'absolute',
+ 'background' : '#FFF',
+ 'color' : '#111',
+ 'top' : '10px',
+ 'left' : '10px',
+ 'right' : '10px',
+ 'padding' : '4px',
+ // z-index should be > than play button, as well as greater
+ // than the dialog box (in pop up video), or link won't work.
+ 'z-index' : '1502',
+ })
+ .html( warningMsg );
+
+ embedPlayer.getInterface().append(
+ $targetWarning
+ );
+
+ $targetWarning.append(
+ $('<br />')
+ );
+ // check if we should show the checkbox
+ if( !hideDisableUi ){
+
+ $targetWarning.append(
+ $( '<input type="checkbox" />' )
+ .attr({
+ 'id' : 'ffwarn_' + embedPlayer.id,
+ 'name' : 'ffwarn_' + embedPlayer.id
+ })
+ .click( function() {
+ mw.log("WarningBindinng:: set " + preferenceId + ' to hidewarning ' );
+ // Set up a cookie for 30 days:
+ $.cookie( preferenceId, 'hidewarning', {expires: 30} );
+ // Set the current instance
+ mw.setConfig( preferenceId, false );
+ $( '#warningOverlay_' + embedPlayer.id ).fadeOut( 'slow' );
+ // set the local preference to false
+ _this.addWarningFlag = false;
+ } )
+ );
+ $targetWarning.append(
+ $('<label />')
+ .text( mw.msg( 'mwe-embedplayer-do_not_warn_again' ) )
+ .attr( 'for', 'ffwarn_' + embedPlayer.id )
+ );
+ }
+
+ return $targetWarning;
+ },
+
+ /**
+ * Binds the volume controls
+ */
+ doVolumeBinding: function( ) {
+ var embedPlayer = this.embedPlayer;
+ var _this = this;
+ embedPlayer.getInterface().find( '.volume_control' ).unbind().buttonHover().click( function() {
+ mw.log( 'Volume control toggle' );
+ embedPlayer.toggleMute();
+ } );
+
+ // Add vertical volume display hover
+ if ( this.volumeLayout == 'vertical' ) {
+ // Default volume binding:
+ var hoverOverDelay = false;
+ var $targetvol = embedPlayer.getInterface().find( '.vol_container' ).hide();
+ embedPlayer.getInterface().find( '.volume_control' ).hover(
+ function() {
+ $targetvol.addClass( 'vol_container_top' );
+ // Set to "below" if playing and embedType != native
+ if ( embedPlayer && embedPlayer.isPlaying && embedPlayer.isPlaying() && !embedPlayer.supports['overlays'] ) {
+ $targetvol.removeClass( 'vol_container_top' ).addClass( 'vol_container_below' );
+ }
+ $targetvol.fadeIn( 'fast' );
+ hoverOverDelay = true;
+ },
+ function() {
+ hoverOverDelay = false;
+ setTimeout( function() {
+ if ( !hoverOverDelay ) {
+ $targetvol.fadeOut( 'fast' );
+ }
+ }, 500 );
+ }
+ );
+ }
+ var userSlide=false;
+ // Setup volume slider:
+ var sliderConf = {
+ range: "min",
+ value: 80,
+ min: 0,
+ max: 100,
+ slide: function( event, ui ) {
+ var percent = ui.value / 100;
+ mw.log('PlayerControlBuilder::slide:update volume:' + percent);
+ embedPlayer.setVolume( percent );
+ userSlide = true;
+ },
+ change: function( event, ui ) {
+ var percent = ui.value / 100;
+ if ( percent == 0 ) {
+ embedPlayer.getInterface().find( '.volume_control span' ).removeClass( 'ui-icon-volume-on' ).addClass( 'ui-icon-volume-off' );
+ } else {
+ embedPlayer.getInterface().find( '.volume_control span' ).removeClass( 'ui-icon-volume-off' ).addClass( 'ui-icon-volume-on' );
+ }
+ mw.log('PlayerControlBuilder::change:update volume:' + percent);
+ embedPlayer.setVolume( percent, userSlide );
+ userSlide = false;
+ }
+ };
+
+ if ( this.volumeLayout == 'vertical' ) {
+ sliderConf[ 'orientation' ] = "vertical";
+ }
+
+ embedPlayer.getInterface().find( '.volume-slider' ).slider( sliderConf );
+ },
+
+ /**
+ * Get the options menu ul with li menu items
+ */
+ getOptionsMenu: function( ) {
+ var $optionsMenu = $( '<ul />' );
+ for( var menuItemKey in this.optionMenuItems ){
+
+ // Make sure its supported in the current controlBuilder config:
+ if( $.inArray( menuItemKey, mw.config.get( 'EmbedPlayer.EnabledOptionsMenuItems' ) ) === -1 ) {
+ continue;
+ }
+
+ $optionsMenu.append(
+ this.optionMenuItems[ menuItemKey ]( this )
+ );
+ }
+ return $optionsMenu;
+ },
+
+ /**
+ * Allow the controlBuilder to do interface actions onDone
+ */
+ onClipDone: function(){
+ // Related videos could be shown here
+ },
+
+ /**
+ * The ctrl builder updates the interface on seeking
+ */
+ onSeek: function(){
+ //mw.log( "controlBuilder:: onSeek" );
+ // Update the interface:
+ this.setStatus( mw.msg( 'mwe-embedplayer-seeking' ) );
+ // add a loading spinner:
+ this.embedPlayer.addPlayerSpinner();
+ // hide once playing again:
+ this.embedPlayer.hideSpinnerOncePlaying();
+ },
+
+ /**
+ * Updates the player status that displays short text msgs and the play clock
+ * @param {String} value Status string value to update
+ */
+ setStatus: function( value ) {
+ // update status:
+ if( this.embedPlayer.getInterface() ){
+ this.embedPlayer.getInterface().find( '.time-disp' ).text( value );
+ }
+ },
+
+ /**
+ * Option menu items
+ *
+ * @return
+ * 'li' a li line item with click action for that menu item
+ */
+ optionMenuItems: {
+ // Share the video menu
+ 'share': function( ctrlObj ) {
+ return $.getLineItem(
+ mw.msg( 'mwe-embedplayer-share' ),
+ 'mail-closed',
+ function( ) {
+ ctrlObj.displayMenuOverlay(
+ ctrlObj.getShare()
+ );
+ $( ctrlObj.embedPlayer ).trigger( 'showShareEvent' );
+ }
+ );
+ },
+
+ 'aboutPlayerLibrary' : function( ctrlObj ){
+ return $.getLineItem(
+ mw.msg( 'mwe-embedplayer-about-library' ),
+ 'info',
+ function( ) {
+ ctrlObj.displayMenuOverlay(
+ ctrlObj.aboutPlayerLibrary()
+ );
+ $( ctrlObj.embedPlayer ).trigger( 'aboutPlayerLibrary' );
+ }
+ );
+ }
+ },
+
+ /**
+ * Close a menu overlay
+ */
+ closeMenuOverlay: function(){
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+ var $overlay = embedPlayer.getInterface().find( '.overlay-win,.ui-widget-overlay,.ui-widget-shadow' );
+
+ this.displayOptionsMenuFlag = false;
+ //mw.log(' closeMenuOverlay: ' + this.displayOptionsMenuFlag);
+
+ $overlay.fadeOut( "slow", function() {
+ $overlay.remove();
+ } );
+
+ // Show the big play button: ( if not in an ad .. TODO clean up )
+ if( embedPlayer.isStopped() &&
+ (
+ embedPlayer.sequenceProxy &&
+ embedPlayer.sequenceProxy.isInSequence == false
+ )
+ ){
+ embedPlayer.getInterface().find( '.play-btn-large' ).fadeIn( 'slow' );
+ }
+
+ $(embedPlayer).trigger( 'closeMenuOverlay' );
+
+ return false; // onclick action return false
+ },
+
+ /**
+ * Generic function to display custom HTML overlay on video.
+ *
+ * @param {String} overlayContent content to be displayed
+ */
+ displayMenuOverlay: function( overlayContent, closeCallback, hideCloseButton ) {
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+ mw.log( 'PlayerControlBuilder:: displayMenuOverlay' );
+ // set the overlay display flag to true:
+ this.displayOptionsMenuFlag = true;
+
+ if ( !this.supportedComponents[ 'overlays' ] ) {
+ embedPlayer.stop();
+ }
+
+
+ // Hide the big play button:
+ embedPlayer.hideLargePlayBtn();
+
+ // Check if overlay window is already present:
+ if ( embedPlayer.getInterface().find( '.overlay-win' ).length != 0 ) {
+ //Update the content
+ embedPlayer.getInterface().find( '.overlay-content' ).html(
+ overlayContent
+ );
+ return ;
+ }
+
+ // Add an overlay
+ embedPlayer.getInterface().append(
+ $('<div />')
+ .addClass( 'ui-widget-overlay' )
+ .css( {
+ 'height' : '100%',
+ 'width' : '100%',
+ 'z-index' : 2
+ } )
+ );
+
+ var $closeButton = [];
+
+ if ( !hideCloseButton ) {
+ // Setup the close button
+ $closeButton = $('<div />')
+ .addClass( 'ui-state-default ui-corner-all ui-icon_link rButton')
+ .css({
+ 'position': 'absolute',
+ 'cursor' : 'pointer',
+ 'top' : '2px',
+ 'right' : '2px'
+ })
+ .click( function() {
+ _this.closeMenuOverlay();
+ if( closeCallback ){
+ closeCallback();
+ }
+ } )
+ .append(
+ $('<span />')
+ .addClass( 'ui-icon ui-icon-closethick' )
+ );
+ }
+
+ var controlBarHeight = embedPlayer.getInterface().find( '.control-bar' ).height();
+ var overlayWidth = (embedPlayer.getWidth() - 30);
+ var overlayHeight = (embedPlayer.getHeight() - (controlBarHeight + 30));
+ var overlayTop = (( (embedPlayer.getInterface().height() - controlBarHeight) - overlayHeight) / 2);
+ var overlayLeft = ((embedPlayer.getInterface().width() - overlayWidth) / 2);
+
+ var overlayMenuCss = {
+ 'height' : overlayHeight + 'px',
+ 'width' : overlayWidth + 'px',
+ 'position' : 'absolute',
+ 'top' : overlayTop + 'px',
+ 'left': overlayLeft + 'px',
+ 'margin': '0 10px 10px 0',
+ 'overflow' : 'auto',
+ 'padding' : '4px',
+ 'z-index' : 3
+ };
+ var $overlayMenu = $('<div />')
+ .addClass( 'overlay-win ui-state-default ui-widget-header ui-corner-all' )
+ .css( overlayMenuCss )
+ .append(
+ $closeButton,
+ $('<div />')
+ .addClass( 'overlay-content' )
+ .append( overlayContent )
+ );
+
+
+ // Append the overlay menu to the player interface
+ embedPlayer.getInterface().prepend(
+ $overlayMenu
+ )
+ .find( '.overlay-win' )
+ .fadeIn( "slow" );
+
+ // Trigger menu overlay display
+ $( embedPlayer ).trigger( 'displayMenuOverlay' );
+
+ return false; // onclick action return false
+ },
+
+ /**
+ * Close an alert
+ */
+ closeAlert: function( keepOverlay ) {
+ var embedPlayer = this.embedPlayer;
+ var $alert = $( '#alertContainer' );
+
+ mw.log( 'mw.PlayerControlBuilder::closeAlert' );
+ if ( !keepOverlay || ( mw.isIpad() && this.inFullScreen ) ) {
+ embedPlayer.controlBuilder.closeMenuOverlay();
+ if ( mw.isIpad() ) {
+ embedPlayer.disablePlayControls();
+ }
+ }
+
+ $alert.remove();
+
+ return false; // onclick action return false;
+ },
+
+ /**
+ * Generic function to display custom alert overlay on video.
+ *
+ * @param (Object) Object which includes:
+ * title Alert Title
+ * body Alert body
+ * buttonSet[label,callback] Array of buttons
+ * style CSS object
+ */
+ displayAlert: function( alertObj ) {
+ var embedPlayer = this.embedPlayer;
+ var callback;
+ mw.log( 'PlayerControlBuilder::displayAlert:: ' + alertObj.title );
+ // Check if callback is external or internal (Internal by default)
+
+ // Check if overlay window is already present:
+ if ( embedPlayer.getInterface().find( '.overlay-win' ).length != 0 ) {
+ return;
+ }
+ if( typeof alertObj.callbackFunction == 'string' ) {
+ if ( alertObj.isExternal ) {
+ // TODO better support of running external JS functions, instead of window.parent
+ try{
+ callback = window.parent[ alertObj.callbackFunction ];
+ } catch ( e ){
+ // could not call parent method
+ }
+ } else {
+ callback = window[ alertObj.callbackFunction ];
+ }
+ } else if( typeof alertObj.callbackFunction == 'function' ) {
+ // Make life easier for internal usage of the listener mapping by supporting
+ // passing a callback by function ref
+ callback = alertObj.callbackFunction;
+ } else {
+ mw.log( "PlayerControlBuilder :: displayAlert :: Error: bad callback type" );
+ callback = function() {};
+ }
+
+ var $container = $( '<div />' ).attr( 'id', 'alertContainer' ).addClass( 'alert-container' );
+ var $title = $( '<div />' ).text( alertObj.title ).addClass( 'alert-title alert-text' );
+ if ( alertObj.props && alertObj.props.titleTextColor ) {
+ $title.removeClass( 'alert-text' );
+ $title.css( 'color', mw.getHexColor( alertObj.props.titleTextColor ) );
+ }
+ var $message = $( '<div />' ).text( alertObj.message ).addClass( 'alert-message alert-text' );
+ if ( alertObj.isError ) {
+ $message.addClass( 'error' );
+ }
+ if ( alertObj.props && alertObj.props.textColor ) {
+ $message.removeClass( 'alert-text' );
+ $message.css( 'color', mw.getHexColor( alertObj.props.textColor ) );
+ }
+ var $buttonsContainer = $( '<div />' ).addClass( 'alert-buttons-container' );
+ if ( alertObj.props && alertObj.props.buttonRowSpacing ) {
+ $buttonsContainer.css( 'margin-top', alertObj.props.buttonRowSpacing );
+ }
+ var $buttonSet = alertObj.buttons || [];
+
+ // If no button was passed display just OK button
+ var buttonsNum = $buttonSet.length;
+ if ( buttonsNum == 0 && !alertObj.noButtons ) {
+ $buttonSet = ["OK"];
+ buttonsNum++;
+ }
+
+ $.each( $buttonSet, function(i) {
+ var label = this.toString();
+ var $currentButton = $( '<button />' )
+ .addClass( 'alert-button' )
+ .text( label )
+ .click( function( eventObject ) {
+ callback( eventObject );
+ embedPlayer.controlBuilder.closeAlert( alertObj.keepOverlay );
+ } );
+ if ( alertObj.props && alertObj.props.buttonHeight ) {
+ $currentButton.css( 'height', alertObj.props.buttonHeight );
+ }
+ // Apply buttons spacing only when more than one is present
+ if (buttonsNum > 1) {
+ if (i < buttonsNum-1) {
+ if ( alertObj.props && alertObj.props.buttonSpacing ) {
+ $currentButton.css( 'margin-right', alertObj.props.buttonSpacing );
+ }
+ }
+ }
+ $buttonsContainer.append( $currentButton );
+ } )
+ $container.append( $title, $message, $buttonsContainer );
+ return embedPlayer.controlBuilder.displayMenuOverlay( $container, false, true );
+ },
+
+ aboutPlayerLibrary: function(){
+ return $( '<div />' )
+ .append(
+ $( '<h2 />' )
+ .text(
+ mw.msg('mwe-embedplayer-about-library')
+ )
+ ,
+ $( '<span />')
+ .append(
+ mw.msg('mwe-embedplayer-about-library-desc',
+ $('<div>').append(
+ $('<a />').attr({
+ 'href' : mw.config.get( 'EmbedPlayer.LibraryPage' ),
+ 'target' : '_new'
+ })
+ )[0].innerHTML
+ )
+ )
+ );
+ },
+ /**
+ * Get the "share" interface
+ *
+ * TODO share should be enabled via <embed> tag usage to be compatible
+ * with sites social networking sites that allow <embed> tags but not js
+ *
+ * @param {Object} $target Target jQuery object to set share html
+ */
+ getShare: function( ) {
+ var embedPlayer = this.embedPlayer;
+ var embed_code = embedPlayer.getSharingEmbedCode();
+ var embed_wiki_code = embedPlayer.getWikiEmbedCode();
+ var _this = this;
+
+ var $shareInterface = $('<div />');
+
+ var $shareList = $( '<ul />' );
+
+ $shareList
+ .append(
+ $('<li />').text(
+ mw.msg( 'mwe-embedplayer-embed_site_or_blog' )
+ )
+ /*
+ .append(
+ $('<a />')
+ .attr('href', '#')
+ .addClass( 'active' )
+ .text(
+ mw.msg( 'mwe-embedplayer-embed_site_or_blog' )
+ )
+ )
+ */
+ );
+
+ $shareInterface.append(
+ $( '<h2 />' )
+ .text( embedPlayer.isAudio() ?
+ mw.msg( 'mwe-embedplayer-share_this_audio' ) :
+ mw.msg( 'mwe-embedplayer-share_this_video' ) )
+ );
+
+ if ( embed_wiki_code ) {
+ $shareInterface.append(
+ $('<ul />').append(
+ $('<li />').text(
+ mw.msg( 'mwe-embedplayer-embed_wiki' )
+ )
+ ),
+ $( '<textarea />' )
+ .attr( 'rows', 1 )
+ .html( embed_wiki_code )
+ .click( function() {
+ $( this ).select();
+ }),
+ $('<br />')
+ );
+ }
+
+ $shareInterface.append(
+ $shareList
+ );
+
+ $shareInterface.append(
+
+ $( '<textarea />' )
+ .attr( 'rows', 4 )
+ .html( embed_code )
+ .click( function() {
+ $( this ).select();
+ }),
+
+ $('<br />'),
+ $('<br />')
+ );
+ return $shareInterface;
+ },
+
+ /**
+ * Shows the Player Select interface
+ *
+ * @param {Object} $target jQuery target for output
+ */
+ getPlayerSelect: function( ) {
+ mw.log('PlayerControlBuilder::getPlayerSelect: source:' +
+ this.embedPlayer.mediaElement.selectedSource.getSrc() +
+ ' player: ' + this.embedPlayer.selectedPlayer.id );
+
+ var embedPlayer = this.embedPlayer;
+
+ var _this = this;
+
+ var $playerSelect = $('<div />')
+ .append(
+ $( '<h2 />' )
+ .text( mw.msg( 'mwe-embedplayer-choose_player' ) )
+ );
+
+ $.each( embedPlayer.mediaElement.getPlayableSources(), function( sourceId, source ) {
+
+ var isPlayable = (typeof mw.EmbedTypes.getMediaPlayers().defaultPlayer( source.getMIMEType() ) == 'object' );
+ var isSelected = ( source.getSrc() == embedPlayer.mediaElement.selectedSource.getSrc() );
+
+ $playerSelect.append(
+ $( '<h3 />' )
+ .text( source.getTitle() )
+ );
+
+ if ( isPlayable ) {
+ var $playerList = $('<ul />');
+ // output the player select code:
+
+ var supportingPlayers = mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( source.getMIMEType() );
+
+ for ( var i = 0; i < supportingPlayers.length ; i++ ) {
+ // Add link to select the player if not already selected )
+ if( embedPlayer.selectedPlayer.id == supportingPlayers[i].id && isSelected ) {
+ // Active player ( no link )
+ var $playerLine = $( '<span />' )
+ .append(
+ $('<a />')
+ .attr({
+ 'href' : '#'
+ })
+ .addClass( 'active')
+ .text(
+ supportingPlayers[i].getName()
+ ).click( function(){
+ embedPlayer.controlBuilder.closeMenuOverlay();
+ // Don't follow the # link:
+ return false;
+ })
+ );
+ //.addClass( 'ui-state-highlight ui-corner-all' ); removed by ran
+ } else {
+ // Non active player add link to select:
+ $playerLine = $( '<a />')
+ .attr({
+ 'href' : '#',
+ 'id' : 'sc_' + sourceId + '_' + supportingPlayers[i].id
+ })
+ .addClass( 'ui-corner-all')
+ .text( supportingPlayers[i].getName() )
+ .click( function() {
+ var iparts = $( this ).attr( 'id' ).replace(/sc_/ , '' ).split( '_' );
+ var sourceId = iparts[0];
+ var player_id = iparts[1];
+ mw.log( 'PlayerControlBuilder:: source id: ' + sourceId + ' player id: ' + player_id );
+
+ embedPlayer.controlBuilder.closeMenuOverlay();
+
+ // Close fullscreen if we are in fullscreen mode
+ if( _this.isInFullScreen() ){
+ _this.restoreWindowPlayer();
+ }
+
+ embedPlayer.mediaElement.setSourceByIndex( sourceId );
+ var playableSources = embedPlayer.mediaElement.getPlayableSources();
+
+ mw.EmbedTypes.getMediaPlayers().setPlayerPreference(
+ player_id,
+ playableSources[ sourceId ].getMIMEType()
+ );
+
+ // Issue a stop
+ embedPlayer.stop();
+
+ // Don't follow the # link:
+ return false;
+ } )
+ .hover(
+ function(){
+ $( this ).addClass('active');
+ },
+ function(){
+ $( this ).removeClass('active');
+ }
+ );
+ }
+
+ // Add the player line to the player list:
+ $playerList.append(
+ $( '<li />' ).append(
+ $playerLine
+ )
+ );
+ }
+
+ // Append the player list:
+ $playerSelect.append( $playerList );
+
+ } else {
+ // No player available:
+ $playerSelect.append( mw.msg( 'mwe-embedplayer-no-player', source.getTitle() ) );
+ }
+ } );
+
+ // Return the player select elements
+ return $playerSelect;
+ },
+
+ /**
+ * Loads sources and calls showDownloadWithSources
+ * @param {Object} $target jQuery target to output to
+ */
+ showDownload: function( $target ) {
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+ _this.showDownloadWithSources( $target );
+ },
+
+ /**
+ * Shows the download interface with sources loaded
+ * @param {Object} $target jQuery target to output to
+ */
+ showDownloadWithSources : function( $target ) {
+ var _this = this;
+ mw.log( 'PlayerControlBuilder:: showDownloadWithSources::' + $target.length );
+ var embedPlayer = this.embedPlayer;
+ // Empty the target:
+ $target.empty();
+ $target.append( $('<div />') );
+ $target = $target.find('div');
+
+ var $mediaList = $( '<ul />' );
+ var $textList = $( '<ul />' );
+ $.each( embedPlayer.mediaElement.getSources(), function( index, source ) {
+ if( source.getSrc() ) {
+ mw.log("showDownloadWithSources:: Add src: " + source.getTitle() );
+ var fileName = source.mwtitle;
+ if ( !fileName ) {
+ var path = new mw.Uri( source.getSrc() ).path;
+ var pathParts = path.split( '/' );
+ fileName = pathParts[ pathParts.length -1 ];
+ }
+ var $dlLine = $( '<li />').append(
+ $('<a />')
+ .attr( {
+ 'href': source.getSrc(),
+ 'download': fileName
+ })
+ .text( source.getTitle() )
+ );
+ // Add link to correct "bucket"
+
+ //Add link to time segment:
+ if ( source.getSrc().indexOf( '?t=' ) !== -1 ) {
+ $target.append( $dlLine );
+ } else if ( this.getMIMEType().indexOf('text') === 0 ) {
+ // Add link to text list
+ $textList.append( $dlLine );
+ } else {
+ // Add link to media list
+ $mediaList.append( $dlLine );
+ }
+
+ }
+ } );
+ if( $mediaList.find('li').length != 0 ) {
+ $target.append(
+ $('<h2 />')
+ .text( embedPlayer.isAudio() ?
+ mw.msg( 'mwe-embedplayer-download_full_audio' ) :
+ mw.msg( 'mwe-embedplayer-download_full_video' ) ),
+ $mediaList
+ );
+ }
+
+ if( $textList.find('li').length != 0 ) {
+ $target.append(
+ $('<h2 />')
+ .html( mw.msg( 'mwe-embedplayer-download_text' ) ),
+ $textList
+ );
+ }
+ },
+ getSwitchSourceMenu: function(){
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+ // for each source with "native playback"
+ var $sourceMenu = $('<ul />');
+
+ // Local function to closure the "source" variable scope:
+ function addToSourceMenu( source ){
+ // Check if source is selected:
+ var icon = ( source.getSrc() == embedPlayer.mediaElement.selectedSource.getSrc() ) ? 'bullet' : 'radio-on';
+ $sourceMenu.append(
+ $.getLineItem( source.getShortTitle() , icon, function(){
+ mw.log( 'PlayerControlBuilder::SwitchSourceMenu: ' + source.getSrc() );
+ // update menu selecting parent li siblings
+ $( this ).parent().siblings().find('span.ui-icon').removeClass( 'ui-icon-bullet').addClass( 'ui-icon-radio-on' );
+ $( this ).find('span.ui-icon').removeClass( 'ui-icon-radio-on').addClass( 'ui-icon-bullet' );
+ // update control bar text
+ embedPlayer.getInterface().find( '.source-switch' ).text( source.getShortTitle() );
+
+
+ // TODO this logic should be in mw.EmbedPlayer
+ embedPlayer.mediaElement.setSource( source );
+ if( ! _this.embedPlayer.isStopped() ){
+ // Get the exact play time from the video element ( instead of parent embed Player )
+ var oldMediaTime = _this.embedPlayer.getPlayerElement().currentTime;
+ var oldPaused = _this.embedPlayer.paused;
+ // Do a live switch
+ embedPlayer.playerSwitchSource( source, function( vid ){
+ // issue a seek
+ embedPlayer.setCurrentTime( oldMediaTime, function(){
+ // reflect pause state
+ if( oldPaused ){
+ embedPlayer.pause();
+ }
+ } );
+ });
+ }
+ })
+ );
+ }
+ var addedSources = {};
+ $.each( this.embedPlayer.mediaElement.getPlayableSources(), function( sourceIndex, source ) {
+ // Output the player select code:
+ var supportingPlayers = mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( source.getMIMEType() );
+ for ( var i = 0; i < supportingPlayers.length ; i++ ) {
+ var lib = supportingPlayers[i].library;
+ if( lib === 'Native' || lib === 'OgvJs' ){ // @fixme use supports.sourceSwitch ... if preloaded?
+ if ( !( source.getSrc() in addedSources ) ) {
+ addedSources[source.getSrc()] = true;
+ addToSourceMenu( source );
+ }
+ }
+ }
+ });
+ return $sourceMenu;
+ },
+
+ /**
+ * Get component
+ *
+ * @param {String} componentId Component key to grab html output
+ */
+ getComponent: function( componentId ) {
+ if ( this.components[ componentId ] ) {
+ return this.components[ componentId ].o( this );
+ } else {
+ return false;
+ }
+ },
+
+ /**
+ * Get a component height
+ *
+ * @param {String} componentId Component key to grab height
+ * @return height or false if not set
+ */
+ getComponentHeight: function( componentId ) {
+ if ( this.components[ componentId ]
+ && this.components[ componentId ].h )
+ {
+ return this.components[ componentId ].h;
+ }
+ return 0;
+ },
+
+ /**
+ * Get a component width
+ * @param {String} componentId Component key to grab width
+ * @return width or false if not set
+ */
+ getComponentWidth: function( componentId ){
+ if ( this.components[ componentId ]
+ && this.components[ componentId ].w )
+ {
+ return this.components[ componentId ].w;
+ }
+ return 0;
+ },
+
+ // Set up the disable playhead function:
+ // TODO this will move into the disableSeekBar binding in the new theme framework
+ disableSeekBar : function(){
+ var $playHead = this.embedPlayer.getInterface().find( ".play_head" );
+ if( $playHead.length ){
+ $playHead.slider( "option", "disabled", true );
+ }
+ },
+ enableSeekBar : function(){
+ var $playHead = this.embedPlayer.getInterface().find( ".play_head" );
+ if( $playHead.length ){
+ $playHead.slider( "option", "disabled", false);
+ }
+ },
+
+ /**
+ * Components Object
+ * Take in the embedPlayer and return some html for the given component.
+ *
+ * components can be overwritten by skin javascript
+ *
+ * Component JSON structure is as follows:
+ * 'o' Function to return a binded jQuery object ( accepts the ctrlObject as a parameter )
+ * 'w' The width of the component
+ * 'h' The height of the component ( if height is undefined the height of the control bar is used )
+ * 'position' elements are inserted into the dom based on component order and available space.
+ * if the element is inserted, position is then used to set relative dom insert order.
+ */
+ components: {
+ /**
+ * The pause / play button
+ */
+ 'pause': {
+ 'w': 28,
+ 'position': 1,
+ 'o': function( ctrlObj ) {
+ return $( '<div />' )
+ .attr( 'title', mw.msg( 'mwe-embedplayer-play_clip' ) )
+ .addClass ( "ui-state-default ui-corner-all ui-icon_link lButton play-btn" )
+ .append(
+ $( '<span />' )
+ .addClass( "ui-icon ui-icon-play" )
+ )
+ // Play / pause binding
+ .buttonHover()
+ .click( function() {
+ ctrlObj.embedPlayer.play();
+ // Don't follow the # link:
+ return false;
+ });
+ }
+ },
+
+ /**
+ * The volume control interface html
+ */
+ 'volumeControl': {
+ 'w' : 28,
+ 'position': 7,
+ 'o' : function( ctrlObj ) {
+ mw.log( 'PlayerControlBuilder::Set up volume control for: ' + ctrlObj.embedPlayer.id );
+ var $volumeOut = $( '<span />' );
+ if ( ctrlObj.volumeLayout == 'horizontal' ) {
+ $volumeOut.append(
+ $( '<div />' )
+ .addClass( "ui-slider ui-slider-horizontal rButton volume-slider" )
+ );
+ }
+
+ // Add the volume control icon
+ $volumeOut.append(
+ $('<div />')
+ .attr( 'title', mw.msg( 'mwe-embedplayer-volume_control' ) )
+ .addClass( "ui-state-default ui-corner-all ui-icon_link rButton volume_control" )
+ .append(
+ $( '<span />' )
+ .addClass( "ui-icon ui-icon-volume-on" )
+ )
+ );
+ if ( ctrlObj.volumeLayout == 'vertical' ) {
+ $volumeOut.find('.volume_control').append(
+ $( '<div />' )
+ .hide()
+ .addClass( "vol_container ui-corner-all" )
+ .append(
+ $( '<div />' )
+ .addClass ( "volume-slider" )
+ )
+ );
+ }
+ //Return the inner html
+ return $volumeOut.html();
+ }
+ },
+
+ /**
+ * The large play button in center of the player
+ */
+ 'playButtonLarge': {
+ 'w' : 70,
+ 'h' : 53,
+ 'position': 2,
+ 'o' : function( ctrlObj ) {
+ return $( '<div />' )
+ .attr( {
+ 'title' : mw.msg( 'mwe-embedplayer-play_clip' ),
+ 'class' : "play-btn-large"
+ } )
+ // Get dynamic position for big play button
+ .css( ctrlObj.getPlayButtonPosition() )
+ // Add play hook:
+ .click( function() {
+ ctrlObj.embedPlayer.play();
+ return false; // Event Stop Propagation
+ } );
+ }
+ },
+
+ /**
+ * The Attribution button ( by default this is kaltura-icon
+ */
+ 'attributionButton' : {
+ 'w' : 28,
+ 'position': 3,
+ 'o' : function( ctrlObj ){
+ var buttonConfig = mw.config.get( 'EmbedPlayer.AttributionButton');
+ // Check for source ( by configuration convention this is a 16x16 image
+ if( buttonConfig.iconurl ){
+ var $icon = $('<img />')
+ .attr('src', buttonConfig.iconurl );
+ } else {
+ var $icon = $('<span />')
+ .addClass( 'ui-icon' );
+ if( buttonConfig['class'] ){
+ $icon.addClass( buttonConfig['class'] );
+ }
+ }
+ if( typeof buttonConfig.style != 'object'){
+ buttonConfig.style = {};
+ }
+ // update the configured size of the attribution button if we have a specific width configured
+ if( buttonConfig.style.width ){
+ this.w = parseInt( buttonConfig.style.width );
+ } else {
+ buttonConfig.style.width = parseInt( this.w ) + 'px';
+ }
+
+ return $( '<div />' )
+ .addClass( 'rButton' )
+ .css({
+ 'top' : '1px',
+ 'left' : '2px'
+ })
+ // Allow button config style to override
+ .css( buttonConfig.style )
+ .append(
+ $('<a />')
+ .attr({
+ 'href': buttonConfig.href,
+ 'title' : buttonConfig.title,
+ 'target' : '_new'
+ })
+ .append( $icon )
+ );
+ }
+ },
+
+ /*
+ * The time display area
+ */
+ 'timeDisplay': {
+ 'w' : mw.config.get( 'EmbedPlayer.TimeDisplayWidth' ),
+ 'position': 6,
+ 'o' : function( ctrlObj ) {
+ return $( '<div />' )
+ .addClass( "ui-widget time-disp" )
+ .append(
+ ctrlObj.embedPlayer.getTimeRange()
+ );
+ }
+ },
+
+ /**
+ * The options button, invokes display of the options menu
+ */
+ 'options': {
+ 'w': 28,
+ 'position': 10,
+ 'o': function( ctrlObj ) {
+ return $( '<div />' )
+ .attr( 'title', mw.msg( 'mwe-embedplayer-player_options' ) )
+ .addClass( 'ui-state-default ui-corner-all ui-icon_link rButton options-btn' )
+ .append(
+ $('<span />')
+ .addClass( 'ui-icon ui-icon-wrench' )
+ )
+ .buttonHover()
+ // Options binding:
+ .embedMenu( {
+ 'content' : ctrlObj.getOptionsMenu(),
+ 'zindex' : mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) + 2,
+ 'positionOpts': {
+ 'directionV' : 'up',
+ 'offsetY' : 30,
+ 'directionH' : 'left',
+ 'offsetX' : -28
+ }
+ } );
+ }
+ },
+
+ /**
+ * The fullscreen button for displaying the video fullscreen
+ */
+ 'fullscreen': {
+ 'w': 24,
+ 'position': 8,
+ 'o': function( ctrlObj ) {
+ var $btn = $( '<div />' )
+ .attr( 'title', mw.msg( 'mwe-embedplayer-player_fullscreen' ) )
+ .addClass( "ui-state-default ui-corner-all ui-icon_link rButton fullscreen-btn" )
+ .append(
+ $( '<span />' )
+ .addClass( "ui-icon ui-icon-arrow-4-diag" )
+ )
+ // Fullscreen binding:
+ .buttonHover();
+ // Link out to another window if iPad 3x ( broken iframe resize )
+ if( (
+ mw.config.get('EmbedPlayer.IsIframeServer')
+ &&
+ mw.isIpad3()
+ )
+ ||
+ mw.config.get( "EmbedPlayer.NewWindowFullscreen" )
+ ||
+ ( mw.config.get('EmbedPlayer.IsIframeServer') && mw.config.get('EmbedPlayer.EnableIframeApi') === false )
+ ){
+ // Get the iframe url:
+ var url = ctrlObj.embedPlayer.getIframeSourceUrl();
+ // Change button into new window ( of the same url as the iframe ) :
+ return $('<a />').attr({
+ 'href': url,
+ 'target' : '_new'
+ })
+ .click(function(){
+ // Update the url:
+ var url = $(this).attr('href');
+ var iframeMwConfig = {};
+
+ iframeMwConfig['EmbedPlayer.IsFullscreenIframe'] = true;
+ // add a seek offset:
+ iframeMwConfig['EmbedPlayer.IframeCurrentTime'] = ctrlObj.embedPlayer.currentTime;
+ // add play state:
+ iframeMwConfig['EmbedPlayer.IframeIsPlaying'] = ctrlObj.embedPlayer.isPlaying();
+
+ // Append the configuration and request domain to the iframe hash:
+
+ // Add the parentUrl to the iframe config:
+ iframeMwConfig['EmbedPlayer.IframeParentUrl'] = document.URL;
+
+ url += '#' + encodeURIComponent(
+ JSON.stringify({
+ 'mwConfig' :iframeMwConfig,
+ 'playerId' : playerId
+ })
+ );
+ ctrlObj.embedPlayer.pause();
+ // try and do a browser popup:
+ var newwin = window.open(
+ url,
+ ctrlObj.embedPlayer.id,
+ // Fullscreen window params:
+ 'width=' + screen.width +
+ ', height=' + ( screen.height - 90 ) +
+ ', top=0, left=0' +
+ ', fullscreen=yes'
+ );
+ // if for some reason we could not open the window run the href link:
+ if( newwin === null){
+ return true;
+ }
+ if ( window.focus ) {
+ newwin.focus();
+ }
+ // Else do not follow the href link
+ return false;
+ })
+ .append($btn);
+ } else {
+ return $btn.click( function() {
+ ctrlObj.embedPlayer.fullscreen();
+ } );
+ }
+ }
+ },
+
+ 'sourceSwitch' : {
+ 'w' : 70,
+ 'position': 9,
+ 'o' : function( ctrlObj ){
+ var $menuContainer = $('<div />').addClass( 'swMenuContainer' ).hide();
+ ctrlObj.embedPlayer.getInterface().append(
+ $menuContainer
+ )
+ // Stream switching widget ( display the current selected stream text )
+ return $( '<div />' )
+ .addClass('ui-widget source-switch')
+ .append(
+ ctrlObj.embedPlayer.mediaElement.selectedSource.getShortTitle()
+ ).embedMenu( {
+ 'content' : ctrlObj.getSwitchSourceMenu(),
+ 'zindex' : mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) + 2,
+ 'keepPosition' : true,
+ 'targetMenuContainer' : $menuContainer,
+ 'width' : 130,
+ 'showSpeed': 0,
+ 'createMenuCallback' : function(){
+ var $interface = ctrlObj.embedPlayer.getInterface();
+ var $sw = $interface.find( '.source-switch' );
+ var $swMenuContainer = $interface.find('.swMenuContainer');
+ var height = $swMenuContainer.find( 'li' ).length * 30;
+ // position from top ( unkown why we can't use bottom here )
+ var top = $interface.height() - height - ctrlObj.getHeight() - 6;
+ $menuContainer.css({
+ 'position' : 'absolute',
+ 'left': $sw[0].offsetLeft,
+ 'top' : top,
+ 'bottom': ctrlObj.getHeight(),
+ 'height' : height
+ })
+ ctrlObj.showControlBar( true );
+ },
+ 'closeMenuCallback' : function(){
+ ctrlObj.restoreControlsHover()
+ }
+ } );
+ }
+ },
+
+ /**
+ * The playhead component
+ */
+ 'playHead': {
+ 'w':0, // special case (takes up remaining space)
+ 'position': 5,
+ 'o':function( ctrlObj ) {
+
+ var sliderConfig = {
+ range: "min",
+ value: 0,
+ min: 0,
+ max: 1000,
+ start: function( event, ui ) {
+ var id = ( embedPlayer.pc != null ) ? embedPlayer.pc.pp.id:embedPlayer.id;
+ embedPlayer.userSlide = true;
+ $( id + ' .play-btn-large' ).fadeOut( 'fast' );
+ // If playlist always start at 0
+ embedPlayer.startTimeSec = ( embedPlayer.instanceOf == 'mvPlayList' ) ? 0:
+ mw.npt2seconds( embedPlayer.getTimeRange().split( '/' )[0] );
+ },
+ slide: function( event, ui ) {
+ var perc = ui.value / 1000;
+ embedPlayer.jumpTime = mw.seconds2npt( parseFloat( parseFloat( embedPlayer.getDuration() ) * perc ) + embedPlayer.startTimeSec );
+ // mw.log('perc:' + perc + ' * ' + embedPlayer.getDuration() + ' jt:'+ this.jumpTime);
+ if ( _this.longTimeDisp ) {
+ ctrlObj.setStatus( mw.msg( 'mwe-embedplayer-seek_to', embedPlayer.jumpTime ) );
+ } else {
+ ctrlObj.setStatus( embedPlayer.jumpTime );
+ }
+ // Update the thumbnail / frame
+ if ( embedPlayer.isPlaying == false ) {
+ embedPlayer.updateThumbPerc( perc );
+ }
+ },
+ change: function( event, ui ) {
+ // Only run the onChange event if done by a user slide
+ // (otherwise it runs times it should not)
+ if ( embedPlayer.userSlide ) {
+ embedPlayer.userSlide = false;
+ embedPlayer.seeking = true;
+
+ var perc = ui.value / 1000;
+ // set seek time (in case we have to do a url seek)
+ embedPlayer.seekTimeSec = mw.npt2seconds( embedPlayer.jumpTime, true );
+ mw.log( 'PlayerControlBuilder:: seek to: ' + embedPlayer.jumpTime + ' perc:' + perc + ' sts:' + embedPlayer.seekTimeSec );
+ ctrlObj.setStatus( mw.msg( 'mwe-embedplayer-seeking' ) );
+ if( embedPlayer.isStopped() ){
+ embedPlayer.play();
+ }
+ embedPlayer.seek( perc );
+ }
+ }
+ };
+
+ var embedPlayer = ctrlObj.embedPlayer;
+ var _this = this;
+ var $playHead = $( '<div />' )
+ .addClass ( "play_head" )
+ .css({
+ "position" : 'absolute',
+ "left" : '33px',
+ "right" : ( ( embedPlayer.getPlayerWidth() - ctrlObj.availableWidth - 33 ) ) + 'px'
+ })
+ // Playhead binding
+ .slider( sliderConfig );
+
+ // Up the z-index of the default status indicator:
+ $playHead.find( '.ui-slider-handle' ).css( 'z-index', 4 );
+ $playHead.find( '.ui-slider-range' ).addClass( 'ui-corner-all' ).css( 'z-index', 2 );
+
+ // Add buffer html:
+ $playHead.append(
+ $('<div />')
+ .addClass( "ui-slider-range ui-slider-range-min ui-widget-header")
+ .addClass( "ui-state-highlight ui-corner-all mw_buffer")
+ );
+
+ // Show video timeline position on hover and when dragging playhead
+ function showPosition(event) {
+ var pos = ( event.clientX - $playHead.offset().left ) / $playHead.width();
+ var time = mw.seconds2npt( parseFloat( embedPlayer.getDuration() ) * pos + (embedPlayer.startTimeSec || 0) );
+ $playHead.attr('title', time);
+ }
+ $playHead.on({
+ mouseenter: showPosition,
+ mouseleave: function(event) {
+ $playHead.attr({title: ''});
+ },
+ mousemove: showPosition
+ });
+
+ return $playHead;
+ }
+ }
+ }
+};
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Audio.html b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Audio.html
new file mode 100644
index 00000000..e0d0c19e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Audio.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <!-- <script type="text/javascript" src="../../../ResourceLoader.php?class=window.jQuery,mwEmbed&&debug=true"></script> -->
+ <script type="text/javascript" src="../../../mwEmbedStartup.php"></script>
+<title>Audio Player sample</title>
+</head>
+<body>
+<h3> Audio Player </h3>
+<audio class="kskin" src="http://upload.wikimedia.org/wikipedia/commons/4/4c/Faurepiece.ogg" durationHint="164"></audio>
+<h3> Audio Player mp3 </h3>
+<audio src="http://ia600300.us.archive.org/35/items/tube122/tube122-02-entia_non_-_perfunctory_jousting.mp3" durationHint="133"></audio>
+
+</body>
+</html> \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_DynamicEmbed.html b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_DynamicEmbed.html
new file mode 100644
index 00000000..135e1713
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_DynamicEmbed.html
@@ -0,0 +1,24 @@
+<html>
+ <head>
+ <script type="text/javascript" src="../../../mwEmbedStartup.php"></script>
+ </head>
+<body>
+
+ <div style="width:640px; height:480px;" id="mwplayer"></div>
+
+ <script>
+ mw.ready(function(){
+
+ mw.load('EmbedPlayer', function(){
+ // seems to trip a bug in IE8/win7
+ $('#mwplayer').embedPlayer({
+ 'poster' : "http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/bbb480.jpg",
+ 'sources':[{
+ 'src':'http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/bbb_trailer_iphone.m4v',
+ 'type':'video/h264'}]
+ });
+ });
+ });
+ </script>
+
+</body>
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_IncludeJQuery.html b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_IncludeJQuery.html
new file mode 100644
index 00000000..ebe3bac9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_IncludeJQuery.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Player sources</title>
+
+<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js" type="text/javascript"></script>
+<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7/jquery-ui.min.js" type="text/javascript"></script>
+<script type="text/javascript" src="../../../mwEmbedStartup.php"></script>
+<script type="text/javascript">
+ $(document).ready(function(){
+ $('#test').text('jQuery $ supported' );
+ });
+</script>
+</head>
+<body>
+<div id="test"></div>
+
+<video poster="http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/elephants-dream.jpg"
+ duration="10:53" preload="auto">
+ <source type="video/webm" src="http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/elephants-dream_400p.webm" />
+ <source type="video/h264" src="http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/elephants-dream_iphone.m4v" />
+ <source type="video/ogg" src="http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/elephants-dream_400p.ogv" />
+</video>
+
+
+</body>
+</html> \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Native_Bindings.html b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Native_Bindings.html
new file mode 100644
index 00000000..433ffa21
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Native_Bindings.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Native Player html5 bindings </title>
+
+
+</head>
+<body>
+<div style="position:absolute;display:block; left: 500px; width:300px; background: #eee; border:solid thin black">
+ <table style="font-size:.8em">
+ <tr>
+ <td colspan="2">
+ <b>Media Events:</b>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2"><textarea style="width:288px" rows="10" id="mediaeventlog"></textarea></td>
+ </tr>
+
+
+ <tr>
+ <td colspan="2">
+ <b>Events logging: (not quite there yet)</b>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2"><div id="eventSelectors"> </div></td>
+ </tr>
+
+ </table>
+</div>
+
+<div style="width:500px;height:300px;display:block;position:relative">
+ <video id="myVid" poster="http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/elephants-dream.jpg"
+ duration="10:53" preload="auto" controls>
+ <source type="video/h264" src="http://www.archive.org/download/ElephantsDream/ed_1024_512kb.mp4" >
+ <source type="video/ogg" src="http://www.archive.org/download/ElephantsDream/ed_hd.ogv" >
+ </video>
+</div>
+
+
+<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.3.min.js"></script>
+<script type="text/javascript" src="../../../mwEmbedStartup.php"></script>
+<script type="text/javascript">
+ /*
+ Media Event Bindings
+ from http://www.w3.org/TR/html5/video.html
+ 4.8.9.12 Event summary
+ The following events fire on media elements as part of the processing model described above:
+ */
+ var vid,
+ mediaEvents = [
+ { event: 'loadstart', logMessage: 'The user agent has begun looking for media data, as part of the resource selection algorithm.' },
+ { event: 'progress', logMessage: 'The user agent is fetching media data.' },
+ { event: 'suspend', logMessage: 'The user agent is intentionally not currently fetching media data, but does not have the entire media resource downloaded.' },
+ { event: 'abort', logMessage: 'The user agent stops fetching the media data before it is completely downloaded, but not due to an error.' },
+ { event: 'error', logMessage: 'An error occurs while fetching the media data.' },
+ { event: 'emptied', logMessage: "A media element whose networkState was previously not in the NETWORK_EMPTY state has just switched to that state (either because of a fatal error during load that's about to be reported, or because the load() method was invoked while the resource selection algorithm was already running)." },
+ { event: 'stalled', logMessage: 'The user agent is trying to fetch media data, but data is unexpectedly not forthcoming.' },
+ { event: 'play', logMessage: 'Playback has begun. Fired after the play() method has returned, or when the autoplay attribute has caused playback to begin.' },
+ { event: 'pause', logMessage: 'Playback has been paused. Fired after the pause() method has returned.' },
+ { event: 'loadedmetadata', logMessage: 'The user agent has just determined the duration and dimensions of the media resource' },
+ { event: 'loadeddata', logMessage: 'The user agent can render the media data at the current playback position for the first time.' },
+ { event: 'waiting', logMessage: 'Playback has stopped because the next frame is not available, but the user agent expects that frame to become available in due course.' },
+ { event: 'playing', logMessage: 'Playback has started.' },
+ { event: 'canplay', logMessage: 'The user agent can resume playback of the media data, but estimates that if playback were to be started now, the media resource could not be rendered at the current playback rate up to its end without having to stop for further buffering of content.' },
+ { event: 'canplaythrough', logMessage: 'The user agent estimates that if playback were to be started now, the media resource could be rendered at the current playback rate all the way to its end without having to stop for further buffering.' },
+ { event: 'seeking', logMessage: 'The seeking IDL attribute changed to true and the seek operation is taking long enough that the user agent has time to fire the event.' },
+ { event: 'seeked', logMessage: 'The seeking IDL attribute changed to false.' },
+ { event: 'timeupdate', logMessage: 'The current playback position changed as part of normal playback or in an especially interesting way, for example discontinuously.' },
+ { event: 'ended', logMessage: 'Playback has stopped because the end of the media resource was reached.' },
+ { event: 'ratechange', logMessage: 'Either the defaultPlaybackRate or the playbackRate attribute has just been updated.' },
+ { event: 'durationchange', logMessage: 'The duration attribute has just been updated.' },
+ { event: 'volumechange', logMessage: 'Either the volume attribute or the muted attribute has changed.' }
+ ];
+
+// log to textarea
+function logME(event) {
+ $('#mediaeventlog').append(event+'\n');
+}
+
+
+// setup logging for an event or tear it down
+function setLogging(event, isActive, message) {
+ if ( isActive === true ) {
+ $(mediaEvents).each(function (i, e) {
+ if ( e.event === event ) {
+ message = e.logMessage;
+ }
+ });
+ $j('#myVid').bind( event, function() { logME('* ' + event + ' fired: ' + message); });
+ } else {
+ $j('#myVid').unbind( event );
+ }
+
+}
+
+mw.ready(function() {
+
+ var vid = $j('#myVid');
+
+ // setup checkboxes to control logging
+ $(mediaEvents).each(function (i, e) {
+ var event = e.event;
+ var message = e.logMessage;
+ $('#eventSelectors').append('<input class="eventSelector" type=checkbox checked name="' + event +'">' + event + '</input><br />');
+ setLogging(event, true, message);
+ });
+
+ //$('.eventSelector').each(function(i, s) { //change(console.log('changed'));
+
+//
+//console.log(s);
+// $(s).change('click');
+//});
+
+ //disable logging for timeupdate
+ setLogging('timeupdate', false);
+ $('input[name=timeupdate]').prop( 'checked', false );
+
+ logME('* the media player is ready');
+
+});
+
+
+</script>
+
+</body>
+</html>
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Seek.html b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Seek.html
new file mode 100644
index 00000000..8c0f8e9d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Seek.html
@@ -0,0 +1,35 @@
+<html>
+ <head>
+ <script type="text/javascript" src="../../../mwEmbedStartup.php"></script>
+ </head>
+ <body>
+ <h2>mwEmbed / archive.org server side seek</h2>
+ Start Playing at <input id="startTime" size="5" value ="50"></input> seconds. <input value="go" type="button" id="doPageSeek"></input></br>
+ <video id="vid1" poster="http://www.archive.org/download/night_of_the_living_dead/format=Thumbnail&x.jpg"
+ style="width:400px;height:300px" durationHint="5717.21">
+ <source src="http://www.archive.org/download/night_of_the_living_dead/night_of_the_living_dead_512kb.mp4"/>
+ <source src="http://www.archive.org/download/night_of_the_living_dead/night_of_the_living_dead.ogv"/>
+ </video>
+ <script type="text/javascript">
+ mw.ready( function(){
+ // check for hash:
+ var urlParts = new mw.Uri ( document.URL);
+ if( urlParts.anchor ){
+ // run the start offset:
+ var startTime = urlParts.anchor.split('=')[1];
+
+ //update the input box:
+ $j('#startTime').val( startTime );
+
+ // update current time then play:
+ $j('#vid1')[0].currentTime = startTime;
+ $j('#vid1')[0].play();
+ }
+ // bind button:
+ $j('#doPageSeek').click(function(){
+ document.location = 'Player_Seek.html?' + Math.random(1) + '#start=' + $j("#startTime").val();
+ });
+ });
+ </script>
+ </body>
+</html>
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_ServerSeek.html b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_ServerSeek.html
new file mode 100644
index 00000000..6a9d7d04
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_ServerSeek.html
@@ -0,0 +1,35 @@
+<html>
+ <head>
+ <script type="text/javascript" src="../../../mwEmbedStartup.php"></script>
+ </head>
+ <body>
+ <h2>mwEmbed / archive.org server side seek</h2>
+ Start Playing at <input id="startTime" size="5" value="50"></input> seconds. <input value="go" type="button" id="doPageSeek"></input></br>
+ <video id="vid1" poster="http://www.archive.org/download/night_of_the_living_dead/format=Thumbnail&x.jpg"
+ style="width:400px;height:300px" durationHint="5717.21">
+ <source URLTimeEncoding='true' src="http://www.archive.org/download/night_of_the_living_dead/night_of_the_living_dead_512kb.mp4"/>
+ <source URLTimeEncoding='true' src="http://www.archive.org/download/night_of_the_living_dead/night_of_the_living_dead.ogv"/>
+ </video>
+ <script type="text/javascript">
+ mw.ready( function(){
+ // check for hash:
+ var urlParts = new mw.Uri( document.URL);
+ if( urlParts.anchor ){
+ // run the start offset:
+ var startTime = urlParts.anchor.split('=')[1];
+
+ //update the input box:
+ $j('#startTime').val( startTime );
+
+ // update current time then play:
+ $j('#vid1')[0].currentTime = startTime;
+ $j('#vid1')[0].play();
+ }
+ // bind button:
+ $j('#doPageSeek').click(function(){
+ document.location = 'Player_ServerSeek.html?' + Math.random(1) + '#start=' + $j("#startTime").val();
+ });
+ });
+ </script>
+ </body>
+</html>
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_ServerSideSeek.html b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_ServerSideSeek.html
new file mode 100644
index 00000000..26c87a6a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_ServerSideSeek.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <script type="text/javascript" src="../../../mwEmbedStartup.php"></script>
+ </head>
+ <body>
+ <h2>mwEmbed / archive.org server side seek</h2>
+
+ <video poster="http://www.archive.org/download/night_of_the_living_dead/format=Thumbnail&x.jpg"
+ style="width:400px;height:300px" durationHint="5717.21">
+ <source URLTimeEncoding="true" src="http://www.archive.org/download/night_of_the_living_dead/night_of_the_living_dead_512kb.mp4"/>
+ <source URLTimeEncoding="true" src="http://www.archive.org/download/night_of_the_living_dead/night_of_the_living_dead.ogv"/>
+ </video>
+ </body>
+</html>
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Sources.html b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Sources.html
new file mode 100644
index 00000000..244ae1fa
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Sources.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Player sources</title>
+
+ <script type="text/javascript" src="../../../mwEmbedStartup.php"></script>
+<!-- <script type="text/javascript" src="http://html5.kaltura.org/js"></script>-->
+
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+
+</head>
+<body>
+
+<video id="vid1" width="480" height="267"
+ poster="http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/bbb480.jpg"
+ durationHint="33"
+ controls >
+ <source type="video/h264" src="http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/bbb_trailer_iphone.m4v"></source>
+ <source type="video/ogg" src="http://cdn.kaltura.org/apis/html5lib/kplayer-examples/media/bbb_trailer_400p.ogv"></source>
+</video>
+
+</body>
+</html>
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Themable.html b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Themable.html
new file mode 100644
index 00000000..d70b4084
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/tests/Player_Themable.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+ <title> Sample Themed Player </title>
+ Pre-loading demo ( stuff ) likely needed for video display
+ <!-- <script type="text/javascript" src="../../../ResourceLoader.php?debug=true&class=mwEmbed"></script> -->
+ <script type="text/javascript" src="../../../mwEmbedStartup.php"></script>
+
+</head>
+<script type="text/javascript">
+ // Show the controls ( this is a theme demo )
+ mw.setConfig( 'EmbedPlayer.OverlayControls', false );
+</script>
+<body>
+
+<h3> Sample Themable Player:</h3>
+To play with dynamic Themes install <a href="http://jqueryui.com/themeroller/developertool/">Themeroller</a><p><p>
+
+<div style="width:450px;float:left">
+<video
+ style="width:400px;height:300px"
+ src="http://upload.wikimedia.org/wikipedia/commons/2/29/Charles_Lindbergh_flight_to_Brussels.ogg"
+ poster="http://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Charles_Lindbergh_flight_to_Brussels.ogg/mid-Charles_Lindbergh_flight_to_Brussels.ogg.jpg"
+ apiTitleKey="Charles_Lindbergh_flight_to_Brussels.ogg"
+ apiProvider="commons"
+ durationHint="60" >
+</video>
+
+<video
+ style="width:208px;height:160px;float:left"
+ src="http://upload.wikimedia.org/wikipedia/commons/2/29/Charles_Lindbergh_flight_to_Brussels.ogg"
+ apiTitleKey="Charles_Lindbergh_flight_to_Brussels.ogg"
+ apiProvider="commons"
+ poster="http://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Charles_Lindbergh_flight_to_Brussels.ogg/mid-Charles_Lindbergh_flight_to_Brussels.ogg.jpg"
+ durationHint="60">
+ </video>
+
+<b>Source Code used:</b><br>
+<textarea cols="50" rows="7"><video style="width:400px;height:288px" poster="http://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Charles_Lindbergh_flight_to_Brussels.ogg/mid-Charles_Lindbergh_flight_to_Brussels.ogg.jpg"
+src="http://upload.wikimedia.org/wikipedia/commons/2/29/Charles_Lindbergh_flight_to_Brussels.ogg"></video></textarea>
+</div>
+
+<div style="width:450px;float:left">
+<video
+ class="kskin"
+ style="width:400px;height:300px"
+ src="http://upload.wikimedia.org/wikipedia/commons/2/29/Charles_Lindbergh_flight_to_Brussels.ogg"
+ apiTitleKey="Charles_Lindbergh_flight_to_Brussels.ogg"
+ apiProvider="commons"
+ poster="http://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Charles_Lindbergh_flight_to_Brussels.ogg/mid-Charles_Lindbergh_flight_to_Brussels.ogg.jpg"
+ durationHint="60">
+</video>
+<video
+ class="kskin"
+ apiTitleKey="Charles_Lindbergh_flight_to_Brussels.ogg"
+ apiProvider="commons"
+ style="width:208px;height:160px;float:left;" src="http://upload.wikimedia.org/wikipedia/commons/2/29/Charles_Lindbergh_flight_to_Brussels.ogg"
+ poster="http://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Charles_Lindbergh_flight_to_Brussels.ogg/mid-Charles_Lindbergh_flight_to_Brussels.ogg.jpg"
+ durationHint="60">
+</video>
+
+<b>(kskin) Source Code used:</b><br>
+<textarea cols="50" rows="7"><video class="kskin" style="width:400px;height:288px" poster="http://upload.wikimedia.org/wikipedia/commons/thumb/2/29/Charles_Lindbergh_flight_to_Brussels.ogg/mid-Charles_Lindbergh_flight_to_Brussels.ogg.jpg"
+src="http://upload.wikimedia.org/wikipedia/commons/2/29/Charles_Lindbergh_flight_to_Brussels.ogg"></video></textarea>
+</div>
+
+
+</body>
+</html>
+
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.config.php b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.config.php
new file mode 100644
index 00000000..46547697
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.config.php
@@ -0,0 +1,31 @@
+<?php
+ /**
+ * Do not edit this file instead use LocalSettings.php and
+ * $wgMwEmbedModuleConfig[ {configuration name} ] = value; format
+ */
+
+ return array(
+ // If the Timed Text interface should be displayed:
+ // 'always' Displays link and call to contribute always
+ // 'auto' Looks for child timed text elements or "apiTitleKey" & load interface
+ // 'off' Does not display the timed text interface
+ "TimedText.ShowInterface" => "auto",
+
+ /**
+ * If the "add timed text" link / interface should be exposed
+ * allows usere to upload text files to the wiki
+ */
+ 'TimedText.ShowAddTextLink' => false,
+
+ // If the link to request a transcript should be shown on video files
+ 'TimedText.ShowRequestTranscript' => false,
+
+ // The category for listing videos that need transcription:
+ 'TimedText.NeedsTranscriptCategory' => 'Videos needing subtitles',
+
+ // The default bottom text padding
+ 'TimedText.BottomPadding' => 10,
+
+ // Height of black box below video.
+ 'TimedText.BelowVideoBlackBoxHeight' => 40
+ );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.loader.js b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.loader.js
new file mode 100644
index 00000000..bbd62d0e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.loader.js
@@ -0,0 +1,52 @@
+/**
+* TimedText loader.
+*/
+// Scope everything in "mw" ( keeps the global namespace clean )
+( function( mw, $ ) {
+
+ /**
+ * Check if the video tags in the page support timed text
+ * this way we can add our timed text libraries to the player
+ * library request.
+ */
+ // Update the player loader request with timedText library if the embedPlayer
+ // includes timedText tracks.
+ $( mw ).bind( 'EmbedPlayerUpdateDependencies', function( event, playerElement, classRequest ) {
+ if( mw.isTimedTextSupported( playerElement ) ) {
+ classRequest = $.merge( classRequest, ['mw.TimedText'] );
+ }
+ } );
+ // On new embed player check if we need to add timedText
+ $( mw ).bind( 'EmbedPlayerNewPlayer', function( event, embedPlayer ){
+ if( mw.isTimedTextSupported( embedPlayer ) ){
+ embedPlayer.timedText = new mw.TimedText( embedPlayer );
+ }
+ });
+
+ /**
+ * Check timedText is active for a given embedPlayer
+ * @param {object} embedPlayer The player to be checked for timedText properties
+ */
+ mw.isTimedTextSupported = function( embedPlayer ) {
+ //EmbedPlayerNewPlayer passes a div with data-mwprovider set,
+ //EmbedPlayerUpdateDependencies passes video element with data attribute
+ //catch both
+ var mwprovider = embedPlayer['data-mwprovider'] || $( embedPlayer ).data('mwprovider');
+ var showInterface = mw.config.get( 'TimedText.ShowInterface.' + mwprovider ) ||
+ mw.config.get( 'TimedText.ShowInterface' );
+
+ if ( showInterface == 'always' ) {
+ return true;
+ } else if ( showInterface == 'off' ) {
+ return false;
+ }
+
+ // Check for standard 'track' attribute:
+ if ( $( embedPlayer ).find( 'track' ).length != 0 ) {
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.php b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.php
new file mode 100644
index 00000000..57f50043
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/TimedText.php
@@ -0,0 +1,21 @@
+<?php
+
+ // Register all the timedText modules
+ return array(
+ "mw.TimedText" => array(
+ 'scripts' => "resources/mw.TimedText.js",
+ 'styles' => "resources/mw.style.TimedText.css",
+ 'dependencies' => array(
+ 'mw.EmbedPlayer',
+ 'mw.TextSource'
+ ),
+ 'messageDir' => 'i18n',
+ ),
+ "mw.TextSource" => array(
+ 'scripts' => "resources/mw.TextSource.js",
+ 'dependencies' => array(
+ 'mediawiki.UtilitiesTime',
+ "mw.ajaxProxy",
+ )
+ )
+ );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/af.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/af.json
new file mode 100644
index 00000000..0024412a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/af.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Naudefj"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Terug",
+ "mwe-timedtext-textcat-cc": "Onderskrifte",
+ "mwe-timedtext-textcat-lrc": "Lirieke"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ar.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ar.json
new file mode 100644
index 00000000..48597e00
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ar.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Meno25",
+ "روخو"
+ ]
+ },
+ "mwe-timedtext-back-btn": "رجوع",
+ "mwe-timedtext-layout-off": "إخفاء الترجمات",
+ "mwe-timedtext-loading-text": "جاري تحميل النص...",
+ "mwe-timedtext-textcat-cc": "نصوص توضيحية",
+ "mwe-timedtext-textcat-cue": "نقاط تلميح",
+ "mwe-timedtext-upload-timed-text": "إضافة الترجمات"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ast.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ast.json
new file mode 100644
index 00000000..9df51f24
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ast.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xuacu"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Anterior",
+ "mwe-timedtext-layout-off": "Tapecer subtítulos",
+ "mwe-timedtext-loading-text": "Cargando'l testu...",
+ "mwe-timedtext-textcat-cc": "Lleendes",
+ "mwe-timedtext-textcat-sub": "Subtítulos",
+ "mwe-timedtext-textcat-tad": "Descripción del soníu",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Testu en movimientu",
+ "mwe-timedtext-textcat-ar": "Rexones actives",
+ "mwe-timedtext-textcat-nb": "Anotación",
+ "mwe-timedtext-textcat-meta": "Metadatos cronometraos",
+ "mwe-timedtext-textcat-trx": "Trescripción",
+ "mwe-timedtext-textcat-lrc": "Lletra",
+ "mwe-timedtext-textcat-lin": "Formatu llingüísticu",
+ "mwe-timedtext-textcat-cue": "Puntos de referencia",
+ "mwe-timedtext-no-subs": "Nun hai pistes de testu disponibles",
+ "mwe-timedtext-language-subtitles-for-clip": "Subtítulos en $1 pal videu: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nun s'alcontraron los subtítulos en $1 pal videu: $2",
+ "mwe-timedtext-upload-timed-text": "Añadir subtítulos"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/be-tarask.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/be-tarask.json
new file mode 100644
index 00000000..5c25527d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/be-tarask.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "EugeneZelenko",
+ "Jim-by",
+ "Wizardist"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Вярнуцца",
+ "mwe-timedtext-layout-off": "Схаваць субтытры",
+ "mwe-timedtext-loading-text": "Загрузка тэксту…",
+ "mwe-timedtext-textcat-cc": "Субтытры",
+ "mwe-timedtext-textcat-sub": "Субтытры:",
+ "mwe-timedtext-textcat-tad": "Аўдыя-апісаньне",
+ "mwe-timedtext-textcat-ktv": "Караоке",
+ "mwe-timedtext-textcat-tik": "Тэкставыя карткі",
+ "mwe-timedtext-textcat-ar": "Актыўныя рэгіёны",
+ "mwe-timedtext-textcat-nb": "Анатацыя",
+ "mwe-timedtext-textcat-meta": "Сынхранізаваныя мета-зьвесткі",
+ "mwe-timedtext-textcat-trx": "Стэнаграма",
+ "mwe-timedtext-textcat-lrc": "Словы",
+ "mwe-timedtext-textcat-lin": "Лінгвістычная разьметка",
+ "mwe-timedtext-textcat-cue": "Сыгнальныя кропкі",
+ "mwe-timedtext-no-subs": "Субтытраў няма",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 субтытры для кліпу: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Субтытры $1 для кліпу ня знойдзеныя: $2",
+ "mwe-timedtext-upload-timed-text": "Дадаць субтытры"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bg.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bg.json
new file mode 100644
index 00000000..b88de95d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bg.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bn.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bn.json
new file mode 100644
index 00000000..395fbe7b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bn.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aftab1995",
+ "Bellayet"
+ ]
+ },
+ "mwe-timedtext-back-btn": "পিছনে",
+ "mwe-timedtext-layout-off": "উপশিরোনাম লুকাও",
+ "mwe-timedtext-loading-text": "টেক্সট লোড হচ্ছে ...",
+ "mwe-timedtext-textcat-cc": "পরিচয়লিপি",
+ "mwe-timedtext-textcat-sub": "উপশিরোনাম",
+ "mwe-timedtext-textcat-tad": "অডিও বিবরণ",
+ "mwe-timedtext-upload-timed-text": "উপশিরোনাম যুক্ত করুন"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/br.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/br.json
new file mode 100644
index 00000000..eacd0f20
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/br.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fulup",
+ "Y-M D"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Distreiñ",
+ "mwe-timedtext-layout-off": "Kuzhat an istitloù",
+ "mwe-timedtext-loading-text": "O kargañ an destenn...",
+ "mwe-timedtext-textcat-cc": "Alc'hwezioù",
+ "mwe-timedtext-textcat-sub": "Istitloù",
+ "mwe-timedtext-textcat-tad": "Deskrivadur son",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Barenn titouroù",
+ "mwe-timedtext-textcat-ar": "Rannvroioù oberiant",
+ "mwe-timedtext-textcat-nb": "Notennadur",
+ "mwe-timedtext-textcat-meta": "Metaroadennoù sinkronelaet",
+ "mwe-timedtext-textcat-trx": "Treuzskrivañ",
+ "mwe-timedtext-textcat-lrc": "Komzoù",
+ "mwe-timedtext-textcat-lin": "Balizennoù yezhel",
+ "mwe-timedtext-textcat-cue": "Poent lec'hiañ",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 istitl evit ar c'hlip : $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "N'eo ket bet kavet $1 istitl evit ar c'hlip : $2",
+ "mwe-timedtext-upload-timed-text": "Enporzhiañ istitloù"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bs.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bs.json
new file mode 100644
index 00000000..f8d0cd23
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/bs.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "CERminator"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Nazad",
+ "mwe-timedtext-textcat-sub": "Podnaslovi",
+ "mwe-timedtext-textcat-tad": "Opis zvuka"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ca.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ca.json
new file mode 100644
index 00000000..ce45bfb5
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ca.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pitort"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Enrere",
+ "mwe-timedtext-textcat-sub": "Subtítols"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ce.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ce.json
new file mode 100644
index 00000000..f1580f0d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ce.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Умар"
+ ]
+ },
+ "mwe-timedtext-textcat-tad": "Аудио-хаам"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cs.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cs.json
new file mode 100644
index 00000000..94a5e7eb
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cs.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mormegil",
+ "Vks"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zpět",
+ "mwe-timedtext-layout-off": "Skrýt titulky",
+ "mwe-timedtext-loading-text": "Načítá se text…",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-nb": "Anotace",
+ "mwe-timedtext-textcat-trx": "Přepis",
+ "mwe-timedtext-language-subtitles-for-clip": "Titulky ke klipu $2 v jazyce $1",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Ke klipu $2 nebyly nalezeny titulky v jazyce $1"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cy.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cy.json
new file mode 100644
index 00000000..fd0eea45
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/cy.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lloffiwr",
+ "Robin Owain"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Yn ôl",
+ "mwe-timedtext-layout-off": "Cuddio'r isdeitlau",
+ "mwe-timedtext-loading-text": "Yn llwytho'r testun...",
+ "mwe-timedtext-textcat-cc": "Geiriad",
+ "mwe-timedtext-textcat-sub": "Isdeitlau",
+ "mwe-timedtext-textcat-tad": "Disgrifiad o'r sain",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Testun",
+ "mwe-timedtext-textcat-ar": "Ardaloedd gweithredolo",
+ "mwe-timedtext-textcat-nb": "Anodiad",
+ "mwe-timedtext-textcat-meta": "Metadata a amserwyd",
+ "mwe-timedtext-textcat-trx": "Trawsysgrif",
+ "mwe-timedtext-textcat-lrc": "Geiriau",
+ "mwe-timedtext-textcat-cue": "Cerrig milltir",
+ "mwe-timedtext-no-subs": "Dim traciau testun ar gael",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 isdeitl ar gael ar gyfer clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Dim $1 isdeitl ar gael ar gyfer: $2",
+ "mwe-timedtext-upload-timed-text": "Ychwanegu isdeitlau"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de-formal.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de-formal.json
new file mode 100644
index 00000000..10c9c650
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de-formal.json
@@ -0,0 +1,7 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln"
+ ]
+ }
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de.json
new file mode 100644
index 00000000..35d1cef9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/de.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln",
+ "Metalhead64",
+ "Purodha"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zurück",
+ "mwe-timedtext-layout-off": "Untertitel ausblenden",
+ "mwe-timedtext-loading-text": "Text wird geladen …",
+ "mwe-timedtext-textcat-cc": "Legenden",
+ "mwe-timedtext-textcat-sub": "Untertitel",
+ "mwe-timedtext-textcat-tad": "Beschreibung (Audio)",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Text-Ticker",
+ "mwe-timedtext-textcat-ar": "Aktive Regionen",
+ "mwe-timedtext-textcat-nb": "Annotation",
+ "mwe-timedtext-textcat-meta": "„Timed Text“-Metadaten",
+ "mwe-timedtext-textcat-trx": "Abschrift",
+ "mwe-timedtext-textcat-lrc": "Liedtext",
+ "mwe-timedtext-textcat-lin": "Sprachliche Beschreibung",
+ "mwe-timedtext-textcat-cue": "Cue-Punkte",
+ "mwe-timedtext-no-subs": "Es sind keine Untertitel verfügbar",
+ "mwe-timedtext-language-subtitles-for-clip": "Untertitel auf $1 für den Videoclip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Keine Untertitel auf $1 für den Videoclip gefunden: $2",
+ "mwe-timedtext-upload-timed-text": "Untertitel hinzufügen"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/diq.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/diq.json
new file mode 100644
index 00000000..ee86ed2c
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/diq.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Erdemaslancan",
+ "Mirzali"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Peyser",
+ "mwe-timedtext-textcat-cc": "Bınnuşte",
+ "mwe-timedtext-textcat-sub": "Sernuştey bıni",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-nb": "Ole şınasiye"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/dsb.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/dsb.json
new file mode 100644
index 00000000..362d95c8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/dsb.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Derbeth",
+ "Michawiki"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Slědk",
+ "mwe-timedtext-layout-off": "Pódtitele schowaś",
+ "mwe-timedtext-loading-text": "Tekst se zacytujo...",
+ "mwe-timedtext-textcat-cc": "Wopisanja",
+ "mwe-timedtext-textcat-sub": "Pódtitele",
+ "mwe-timedtext-textcat-tad": "Awdiowopisanje",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Běžecy tekst",
+ "mwe-timedtext-textcat-ar": "Aktiwne regiony",
+ "mwe-timedtext-textcat-nb": "Anotacija",
+ "mwe-timedtext-textcat-meta": "Synchronizěrowane metadaty",
+ "mwe-timedtext-textcat-trx": "Pśepisaś",
+ "mwe-timedtext-textcat-lrc": "Spiwny tekst",
+ "mwe-timedtext-textcat-lin": "Rěcywědne wopisanje",
+ "mwe-timedtext-textcat-cue": "Zastupne dypki",
+ "mwe-timedtext-no-subs": "Žedne pódtitele k dispoziciji",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 {{PLURAL:$1|pódtitel|pódtitela|pódtitele|oódtitelow}} za klip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Žedne pódtitele $1 su se za klip namakali: $2",
+ "mwe-timedtext-upload-timed-text": "Pódtitele pśidaś"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/el.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/el.json
new file mode 100644
index 00000000..9de04eff
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/el.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Geraki"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Επιστροφή",
+ "mwe-timedtext-layout-off": "Απόκρυψη υπότιτλων",
+ "mwe-timedtext-loading-text": "Φόρτωση κείμενου...",
+ "mwe-timedtext-textcat-cc": "Λεζάντες",
+ "mwe-timedtext-textcat-sub": "Υπότιτλοι",
+ "mwe-timedtext-textcat-tad": "Ακουστική περιγραφή",
+ "mwe-timedtext-textcat-ktv": "Καραόκε",
+ "mwe-timedtext-textcat-tik": "Κυλιόμενο κείμενο",
+ "mwe-timedtext-textcat-ar": "Ενεργές περιοχές",
+ "mwe-timedtext-textcat-nb": "Σχόλιο",
+ "mwe-timedtext-textcat-meta": "Χρονισμένα μεταδεδομένα",
+ "mwe-timedtext-textcat-trx": "Μεταγραφή",
+ "mwe-timedtext-textcat-lrc": "Στίχοι",
+ "mwe-timedtext-textcat-lin": "Γλωσσολογική σύνταξη",
+ "mwe-timedtext-textcat-cue": "Cue points",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 υπότιτλοι για το βίντεο: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Δεν βρέθηκαν υπότιτλοι $1 για το βίντεο: $2"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/en.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/en.json
new file mode 100644
index 00000000..0505d5b7
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/en.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": []
+ },
+ "mwe-timedtext-back-btn": "Back",
+ "mwe-timedtext-layout-off": "Hide subtitles",
+ "mwe-timedtext-loading-text": "Loading text ...",
+ "mwe-timedtext-key-language": "$1, $2",
+ "mwe-timedtext-textcat-cc": "Captions",
+ "mwe-timedtext-textcat-sub": "Subtitles",
+ "mwe-timedtext-textcat-tad": "Audio description",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Ticker text",
+ "mwe-timedtext-textcat-ar": "Active regions",
+ "mwe-timedtext-textcat-nb": "Annotation",
+ "mwe-timedtext-textcat-meta": "Timed metadata",
+ "mwe-timedtext-textcat-trx": "Transcript",
+ "mwe-timedtext-textcat-lrc": "Lyrics",
+ "mwe-timedtext-textcat-lin": "Linguistic markup",
+ "mwe-timedtext-textcat-cue": "Cue points",
+ "mwe-timedtext-no-subs": "No text tracks available",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 subtitles for clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "No $1 subtitles were found for clip: $2",
+ "mwe-timedtext-upload-timed-text": "Add subtitles"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eo.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eo.json
new file mode 100644
index 00000000..f787b8a6
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eo.json
@@ -0,0 +1,7 @@
+{
+ "@metadata": {
+ "authors": [
+ "Yekrats"
+ ]
+ }
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/es.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/es.json
new file mode 100644
index 00000000..e753ece1
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/es.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armando-Martin",
+ "Crazymadlover",
+ "Locos epraix",
+ "Pertile",
+ "Translationista"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Atrás",
+ "mwe-timedtext-layout-off": "Ocultar subtítulos",
+ "mwe-timedtext-loading-text": "Cargando texto ...",
+ "mwe-timedtext-textcat-cc": "Leyendas",
+ "mwe-timedtext-textcat-sub": "Subtítulos",
+ "mwe-timedtext-textcat-tad": "Descripción de audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Texto desplazable",
+ "mwe-timedtext-textcat-ar": "Regiones activas",
+ "mwe-timedtext-textcat-nb": "Anotación",
+ "mwe-timedtext-textcat-meta": "Metadatos sincronizados",
+ "mwe-timedtext-textcat-trx": "Transcribir",
+ "mwe-timedtext-textcat-lrc": "Letra",
+ "mwe-timedtext-textcat-lin": "Marcador lingüístico",
+ "mwe-timedtext-textcat-cue": "Puntos de referencia",
+ "mwe-timedtext-no-subs": "No hay pistas de texto disponibles",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 subtítulos para el clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "No se ha encontrado subtítulos $1 para el clip: $2",
+ "mwe-timedtext-upload-timed-text": "Añadir subtítulos"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/et.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/et.json
new file mode 100644
index 00000000..a57273aa
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/et.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "Avjoska",
+ "Pikne"
+ ]
+ },
+ "mwe-timedtext-layout-off": "Peida alltiitrid",
+ "mwe-timedtext-loading-text": "Teksti laadimine...",
+ "mwe-timedtext-textcat-sub": "Alltiitrid",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-meta": "Ajastatud metaandmed",
+ "mwe-timedtext-textcat-lrc": "Laulusõnad",
+ "mwe-timedtext-no-subs": "Alltiitreid pole saadaval",
+ "mwe-timedtext-language-subtitles-for-clip": "Lõigu $2 $1 alltiitrid",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Lõigu $2 jaoks ei leitud $1 alltiitreid",
+ "mwe-timedtext-upload-timed-text": "Lisa alltiitrid"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eu.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eu.json
new file mode 100644
index 00000000..5c30fe9d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/eu.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද",
+ "Subi"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Atzera",
+ "mwe-timedtext-textcat-ktv": "Karaokea"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fa.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fa.json
new file mode 100644
index 00000000..c6fa166e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fa.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Armin1392",
+ "Ebraminio",
+ "Pouyana",
+ "Reza1615",
+ "پاناروما"
+ ]
+ },
+ "mwe-timedtext-back-btn": "بازگشت",
+ "mwe-timedtext-layout-off": "پنهان کردن زیرنویس",
+ "mwe-timedtext-loading-text": "در حال بارگیری متن ...",
+ "mwe-timedtext-textcat-cc": "عناوین:",
+ "mwe-timedtext-textcat-sub": "زیرنویس",
+ "mwe-timedtext-textcat-tad": "توضیح صوتی",
+ "mwe-timedtext-textcat-ktv": "کارائوکه",
+ "mwe-timedtext-textcat-tik": "متن تیکر",
+ "mwe-timedtext-textcat-ar": "مناطق فعال",
+ "mwe-timedtext-textcat-nb": "یادداشت",
+ "mwe-timedtext-textcat-meta": "فرادادهٔ به هنگام",
+ "mwe-timedtext-textcat-trx": "رونوشت",
+ "mwe-timedtext-textcat-lrc": "متن ترانه‌ها",
+ "mwe-timedtext-textcat-lin": "زبان نشانه‌گذاری",
+ "mwe-timedtext-textcat-cue": "نقاط نشانه",
+ "mwe-timedtext-no-subs": "هیچ آهنگ متنی دردسترس نیست",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 زیرنویس برای کلیپ: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "هیچ $1 زیرنویسی برای کلیپ پیدا نشد: $2",
+ "mwe-timedtext-upload-timed-text": "اضافه کردن زیرنویس"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fi.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fi.json
new file mode 100644
index 00000000..e0fa5944
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fi.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Nedergard",
+ "Nike",
+ "Silvonen"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Takaisin",
+ "mwe-timedtext-layout-off": "Piilota tekstitys",
+ "mwe-timedtext-loading-text": "Ladataan tekstiä...",
+ "mwe-timedtext-textcat-cc": "Kuvatekstit",
+ "mwe-timedtext-textcat-sub": "Tekstitykset",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-upload-timed-text": "Lisää tekstitys"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fr.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fr.json
new file mode 100644
index 00000000..4e74e546
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fr.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "IAlex",
+ "Peter17",
+ "Tititou36",
+ "Verdy p"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Arrière",
+ "mwe-timedtext-layout-off": "Masquer les sous-titres",
+ "mwe-timedtext-loading-text": "Chargement du texte ...",
+ "mwe-timedtext-textcat-cc": "Légendes",
+ "mwe-timedtext-textcat-sub": "Sous-titres",
+ "mwe-timedtext-textcat-tad": "Description audio",
+ "mwe-timedtext-textcat-ktv": "Karaoké",
+ "mwe-timedtext-textcat-tik": "Barre d'informations",
+ "mwe-timedtext-textcat-ar": "Régions actives",
+ "mwe-timedtext-textcat-nb": "Annotation",
+ "mwe-timedtext-textcat-meta": "métadonnées synchronisées",
+ "mwe-timedtext-textcat-trx": "Transcription",
+ "mwe-timedtext-textcat-lrc": "Paroles",
+ "mwe-timedtext-textcat-lin": "Balisage linguistique",
+ "mwe-timedtext-textcat-cue": "Points de repère",
+ "mwe-timedtext-no-subs": "Aucun texte de piste disponible",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 sous-titres pour clip : $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Aucun sous-titre $1 n'a été trouvé pour le clip : $2",
+ "mwe-timedtext-upload-timed-text": "Ajouter des sous-titres"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/frp.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/frp.json
new file mode 100644
index 00000000..eeb629b9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/frp.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "ChrisPtDe"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Tornar",
+ "mwe-timedtext-layout-off": "Cachiér los sot-titros",
+ "mwe-timedtext-loading-text": "Chargement du tèxto ...",
+ "mwe-timedtext-textcat-cc": "Lègendes",
+ "mwe-timedtext-textcat-sub": "Sot-titros",
+ "mwe-timedtext-textcat-tad": "Dèscripcion ôdiô",
+ "mwe-timedtext-textcat-ktv": "Caraoquè",
+ "mwe-timedtext-textcat-tik": "Bârra d’enformacions",
+ "mwe-timedtext-textcat-ar": "Règ·ions actives",
+ "mwe-timedtext-textcat-nb": "Nota",
+ "mwe-timedtext-textcat-meta": "Mètabalyês sincronisâs",
+ "mwe-timedtext-textcat-trx": "Transcripcion",
+ "mwe-timedtext-textcat-lrc": "Paroles",
+ "mwe-timedtext-textcat-lin": "Balisâjo lengouistico",
+ "mwe-timedtext-textcat-cue": "Pouents de repèro",
+ "mwe-timedtext-no-subs": "Gins de pista de tèxto disponibla",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 sot-titros por clipe : $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nion sot-titro $1 at étâ trovâ por lo clipe : $2",
+ "mwe-timedtext-upload-timed-text": "Apondre des sot-titros"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fy.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fy.json
new file mode 100644
index 00000000..69f89218
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/fy.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robin0van0der0vliet"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Foarige"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gl.json
new file mode 100644
index 00000000..df9d0409
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gl.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Toliño"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Volver",
+ "mwe-timedtext-layout-off": "Agochar os subtítulos",
+ "mwe-timedtext-loading-text": "Cargando o texto...",
+ "mwe-timedtext-textcat-cc": "Pés de foto",
+ "mwe-timedtext-textcat-sub": "Subtítulos",
+ "mwe-timedtext-textcat-tad": "Descrición do son",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Barra de información",
+ "mwe-timedtext-textcat-ar": "Rexións activas",
+ "mwe-timedtext-textcat-nb": "Anotación",
+ "mwe-timedtext-textcat-meta": "Metadatos sincronizados",
+ "mwe-timedtext-textcat-trx": "Transcrición",
+ "mwe-timedtext-textcat-lrc": "Letra",
+ "mwe-timedtext-textcat-lin": "Formato lingüístico",
+ "mwe-timedtext-textcat-cue": "Puntos de sinal",
+ "mwe-timedtext-no-subs": "Non hai pistas de texto dispoñibles",
+ "mwe-timedtext-language-subtitles-for-clip": "Subtítulos en $1 para o vídeo: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Non se atoparon os subtítulos en $1 para o vídeo: $2",
+ "mwe-timedtext-upload-timed-text": "Engadir subtítulos"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gsw.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gsw.json
new file mode 100644
index 00000000..c48c3c0c
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/gsw.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Als-Chlämens",
+ "Als-Holder"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zruck",
+ "mwe-timedtext-layout-off": "Untertitel uusblände",
+ "mwe-timedtext-loading-text": "Am Lade vum Text ...",
+ "mwe-timedtext-textcat-cc": "Bschryybige",
+ "mwe-timedtext-textcat-sub": "Untertitel",
+ "mwe-timedtext-textcat-tad": "Audio-Bschryybig",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Text-Ticker",
+ "mwe-timedtext-textcat-ar": "Aktivi Regione",
+ "mwe-timedtext-textcat-nb": "Aamerkig",
+ "mwe-timedtext-textcat-meta": "Ächtzyt-Metadate",
+ "mwe-timedtext-textcat-trx": "Abschrift",
+ "mwe-timedtext-textcat-lrc": "Liedtext",
+ "mwe-timedtext-textcat-lin": "Sprochwisseschaftligi Bschryybig",
+ "mwe-timedtext-textcat-cue": "Cue-Pinkt",
+ "mwe-timedtext-no-subs": "Untertitel sin nit verfiegbar",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 Untertitel gfunde fir dr Videoclip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Kei $1 Untertitel gfunde fir dr Videoclip: $2",
+ "mwe-timedtext-upload-timed-text": "Untertitel uffelade"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/he.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/he.json
new file mode 100644
index 00000000..5137aa27
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/he.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Guycn2",
+ "YaronSh"
+ ]
+ },
+ "mwe-timedtext-back-btn": "חזרה",
+ "mwe-timedtext-layout-off": "הסתרת כתוביות",
+ "mwe-timedtext-loading-text": "טעינת טקסט...",
+ "mwe-timedtext-textcat-cc": "כותרות",
+ "mwe-timedtext-textcat-sub": "כתוביות",
+ "mwe-timedtext-textcat-tad": "תיאור השמע",
+ "mwe-timedtext-textcat-ktv": "קראוקה",
+ "mwe-timedtext-textcat-tik": "שפת השורה הרצה",
+ "mwe-timedtext-textcat-ar": "אזורים פעילים",
+ "mwe-timedtext-textcat-nb": "פרשנות",
+ "mwe-timedtext-textcat-meta": "מטא־מתונים מתוזמנים",
+ "mwe-timedtext-textcat-trx": "תמליל",
+ "mwe-timedtext-textcat-lrc": "מילות השיר",
+ "mwe-timedtext-textcat-lin": "סימון בלשני",
+ "mwe-timedtext-textcat-cue": "נקודות סימנית",
+ "mwe-timedtext-no-subs": "אין רצועת תמליל זמינה",
+ "mwe-timedtext-language-subtitles-for-clip": "כתוביות ב{{grammar:תחילית|$1}} עבור הסרטון $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "לא נמצאו כתוביות ב{{grammar:תחילית|$1}} עבור $2",
+ "mwe-timedtext-upload-timed-text": "הוספת כתוביות"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hsb.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hsb.json
new file mode 100644
index 00000000..325044d8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hsb.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Wróćo",
+ "mwe-timedtext-layout-off": "Podtitule schować",
+ "mwe-timedtext-loading-text": "Tekst so začituje...",
+ "mwe-timedtext-textcat-cc": "Nadpisma",
+ "mwe-timedtext-textcat-sub": "Podtitule",
+ "mwe-timedtext-textcat-tad": "Awdiowopisanje",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Tekstowy běžacy pask",
+ "mwe-timedtext-textcat-ar": "Aktiwne regiony",
+ "mwe-timedtext-textcat-nb": "Anotacija",
+ "mwe-timedtext-textcat-meta": "Synchronizowane metadaty",
+ "mwe-timedtext-textcat-trx": "Přepis",
+ "mwe-timedtext-textcat-lrc": "Spěwowy tekst",
+ "mwe-timedtext-textcat-lin": "Rěčespytne wopisanje",
+ "mwe-timedtext-textcat-cue": "Zastupne dypki",
+ "mwe-timedtext-no-subs": "Žane podtitule k dispoziciji",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 {{PLURAL:$1|podtitul|podtitulej|podtitule|podtitulow}} za klip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Žane podtitule $1 za klip namakane: $2",
+ "mwe-timedtext-upload-timed-text": "Podtitule přidać"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hu.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hu.json
new file mode 100644
index 00000000..a5eb9692
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/hu.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dani",
+ "Glanthor Reviol",
+ "Misibacsi"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Vissza",
+ "mwe-timedtext-layout-off": "Feliratok elrejtése",
+ "mwe-timedtext-loading-text": "Szöveg betöltése…",
+ "mwe-timedtext-textcat-cc": "Feliratok",
+ "mwe-timedtext-textcat-sub": "Felirat",
+ "mwe-timedtext-textcat-tad": "Hang leírása",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-ar": "Aktív régiók",
+ "mwe-timedtext-textcat-nb": "Annotáció",
+ "mwe-timedtext-textcat-meta": "Időzített metaadatok",
+ "mwe-timedtext-textcat-trx": "Átirat",
+ "mwe-timedtext-textcat-lrc": "Dalszöveg",
+ "mwe-timedtext-textcat-lin": "Nyelvi jelölés",
+ "mwe-timedtext-upload-timed-text": "Felirat hozzáadása"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ia.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ia.json
new file mode 100644
index 00000000..624dc45d
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ia.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Retornar",
+ "mwe-timedtext-layout-off": "Celar subtitulos",
+ "mwe-timedtext-loading-text": "Carga texto…",
+ "mwe-timedtext-textcat-cc": "Subtitulos",
+ "mwe-timedtext-textcat-sub": "Subtitulos",
+ "mwe-timedtext-textcat-tad": "Description audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Barra de information",
+ "mwe-timedtext-textcat-ar": "Regiones active",
+ "mwe-timedtext-textcat-nb": "Annotation",
+ "mwe-timedtext-textcat-meta": "Metadatos de synchronisation",
+ "mwe-timedtext-textcat-trx": "Transcription",
+ "mwe-timedtext-textcat-lrc": "Lyricos",
+ "mwe-timedtext-textcat-lin": "Marcation lingusitic",
+ "mwe-timedtext-textcat-cue": "Punctos de entrata",
+ "mwe-timedtext-no-subs": "Subtitulos non disponibile",
+ "mwe-timedtext-language-subtitles-for-clip": "Subtitulos in $1 pro le clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nulle subtitulos in $1 ha essite trovate pro le clip: $2",
+ "mwe-timedtext-upload-timed-text": "Adder subtitulos"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/id.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/id.json
new file mode 100644
index 00000000..12a35bd7
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/id.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Farras",
+ "IvanLanin"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Kembali",
+ "mwe-timedtext-layout-off": "Sembunyikan subjudul",
+ "mwe-timedtext-loading-text": "Memuat teks ...",
+ "mwe-timedtext-textcat-cc": "Keterangan",
+ "mwe-timedtext-textcat-sub": "Subjudul",
+ "mwe-timedtext-textcat-tad": "Deskripsi audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Teks tik",
+ "mwe-timedtext-textcat-ar": "Wilayah aktif",
+ "mwe-timedtext-textcat-nb": "Anotasi",
+ "mwe-timedtext-textcat-meta": "Data meta berjangka waktu",
+ "mwe-timedtext-textcat-trx": "Transkrip",
+ "mwe-timedtext-textcat-lrc": "Lirik",
+ "mwe-timedtext-textcat-lin": "Ubahan linguistik",
+ "mwe-timedtext-textcat-cue": "Titik acuan",
+ "mwe-timedtext-no-subs": "Jalur teks tidak tersedia",
+ "mwe-timedtext-language-subtitles-for-clip": "Subjudul $1 untuk klip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Tidak ada subjudul $1 yang ditemukan untuk klip: $2",
+ "mwe-timedtext-upload-timed-text": "Unggah teks film"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/it.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/it.json
new file mode 100644
index 00000000..4e2fad3a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/it.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Beta16",
+ "Darth Kule",
+ "F. Cosoleto",
+ "Gianfranco"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Indietro",
+ "mwe-timedtext-layout-off": "Nascondi sottotitoli",
+ "mwe-timedtext-loading-text": "Caricamento testo...",
+ "mwe-timedtext-textcat-cc": "Didascalie",
+ "mwe-timedtext-textcat-sub": "Sottotitoli",
+ "mwe-timedtext-textcat-tad": "Descrizione audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Testo in movimento",
+ "mwe-timedtext-textcat-ar": "Regioni attive",
+ "mwe-timedtext-textcat-nb": "Annotazione",
+ "mwe-timedtext-textcat-meta": "Metadati temporizzati",
+ "mwe-timedtext-textcat-trx": "Trascrizione",
+ "mwe-timedtext-textcat-lrc": "Testi",
+ "mwe-timedtext-textcat-lin": "Markup linguistico",
+ "mwe-timedtext-textcat-cue": "Punti d'entrata",
+ "mwe-timedtext-no-subs": "Nessuna traccia di testo disponibile",
+ "mwe-timedtext-language-subtitles-for-clip": "sottotitoli in $1 per il filmato: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Sottotitoli in $1 non trovati per il filmato: $2",
+ "mwe-timedtext-upload-timed-text": "Aggiungi sottotitoli"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ja.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ja.json
new file mode 100644
index 00000000..7e048693
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ja.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aotake",
+ "Hosiryuhosi",
+ "Shirayuki",
+ "Yanajin66",
+ "青子守歌"
+ ]
+ },
+ "mwe-timedtext-back-btn": "戻る",
+ "mwe-timedtext-layout-off": "字幕を隠す",
+ "mwe-timedtext-loading-text": "テキストの読み込み中...",
+ "mwe-timedtext-textcat-cc": "見出し",
+ "mwe-timedtext-textcat-sub": "字幕",
+ "mwe-timedtext-textcat-tad": "音声の説明",
+ "mwe-timedtext-textcat-ktv": "カラオケ",
+ "mwe-timedtext-textcat-tik": "ティッカー文章",
+ "mwe-timedtext-textcat-ar": "アクティブな領域",
+ "mwe-timedtext-textcat-nb": "注釈",
+ "mwe-timedtext-textcat-meta": "時間メタデータ",
+ "mwe-timedtext-textcat-trx": "複写",
+ "mwe-timedtext-textcat-lrc": "歌詞",
+ "mwe-timedtext-textcat-lin": "言語マーク",
+ "mwe-timedtext-textcat-cue": "キューポイント",
+ "mwe-timedtext-language-subtitles-for-clip": "クリップ $2 の$1字幕",
+ "mwe-timedtext-language-no-subtitles-for-clip": "クリップ $2 には$1字幕がありません",
+ "mwe-timedtext-upload-timed-text": "字幕を追加"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ka.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ka.json
new file mode 100644
index 00000000..05eb95f5
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ka.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "David1010"
+ ]
+ },
+ "mwe-timedtext-back-btn": "უკან",
+ "mwe-timedtext-layout-off": "სუბტიტრების დამალვა",
+ "mwe-timedtext-loading-text": "იტვირთება ტექსტი ...",
+ "mwe-timedtext-textcat-cc": "წარწერები",
+ "mwe-timedtext-textcat-sub": "სუბტიტრები",
+ "mwe-timedtext-textcat-tad": "აუდიო აღწერა",
+ "mwe-timedtext-textcat-ktv": "კარაოკე",
+ "mwe-timedtext-textcat-tik": "ტექსტური ბარათები",
+ "mwe-timedtext-textcat-ar": "აქტიური რეგიონები",
+ "mwe-timedtext-textcat-nb": "ანოტაცია",
+ "mwe-timedtext-textcat-meta": "სინქრონიზირებული მეტამონაცემები",
+ "mwe-timedtext-textcat-trx": "სტენოგრამა",
+ "mwe-timedtext-textcat-lrc": "სიმღერის ტექსტები",
+ "mwe-timedtext-textcat-lin": "ლინგვისტური დანამატი",
+ "mwe-timedtext-textcat-cue": "ნიშნული წერტილები",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 სუბტიტრები კლიპისათვის: $2",
+ "mwe-timedtext-upload-timed-text": "სუბტიტრების დამატება"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ko.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ko.json
new file mode 100644
index 00000000..9b4faaf5
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ko.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "아라"
+ ]
+ },
+ "mwe-timedtext-back-btn": "뒤로",
+ "mwe-timedtext-layout-off": "자막 숨기기",
+ "mwe-timedtext-loading-text": "텍스트 불러오는 중 ...",
+ "mwe-timedtext-textcat-cc": "설명",
+ "mwe-timedtext-textcat-sub": "자막",
+ "mwe-timedtext-textcat-tad": "소리 설명",
+ "mwe-timedtext-textcat-ktv": "가라오케",
+ "mwe-timedtext-textcat-tik": "표시기 문자",
+ "mwe-timedtext-textcat-ar": "활성 영역",
+ "mwe-timedtext-textcat-nb": "주석",
+ "mwe-timedtext-textcat-meta": "시간 메타데이터",
+ "mwe-timedtext-textcat-trx": "복사",
+ "mwe-timedtext-textcat-lrc": "가사",
+ "mwe-timedtext-textcat-lin": "언어 마크업",
+ "mwe-timedtext-textcat-cue": "큐 포인트",
+ "mwe-timedtext-no-subs": "사용할 수 있는 텍스트 트랙이 없습니다",
+ "mwe-timedtext-language-subtitles-for-clip": "클립에 대한 $1 자막: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "클립에 대한 $1 자막을 찾을 수 없습니다: $2",
+ "mwe-timedtext-upload-timed-text": "자막 추가"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ksh.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ksh.json
new file mode 100644
index 00000000..13036810
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ksh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "mwe-timedtext-language-no-subtitles-for-clip": "Mer han kei $1 Ongertittelle jefonge för dat Shtöck: $2"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lb.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lb.json
new file mode 100644
index 00000000..ad8d40e7
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lb.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robby",
+ "Soued031"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zréck",
+ "mwe-timedtext-layout-off": "Ënnertitele verstoppen",
+ "mwe-timedtext-loading-text": "Text gëtt gelueden ...",
+ "mwe-timedtext-textcat-sub": "Ënnertitelen",
+ "mwe-timedtext-textcat-tad": "Audio-Beschreiwung",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Text-Ticker",
+ "mwe-timedtext-textcat-ar": "Aktiv Regiounen",
+ "mwe-timedtext-textcat-nb": "Notiz",
+ "mwe-timedtext-textcat-lrc": "Liddertext",
+ "mwe-timedtext-textcat-lin": "Linguistesch Markéierung",
+ "mwe-timedtext-textcat-cue": "Referenz-Punkten",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 Ënnertitele fir de Clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Keng $1 Ënnertitele goufe fonnt fir de Clip: $2",
+ "mwe-timedtext-upload-timed-text": "Ënnertitelen derbäisetzen"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lt.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lt.json
new file mode 100644
index 00000000..af653701
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lt.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hugo.arg"
+ ]
+ },
+ "mwe-timedtext-no-subs": "Nėra tekstinių takelių",
+ "mwe-timedtext-upload-timed-text": "Pridėti subtitrus"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lv.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lv.json
new file mode 100644
index 00000000..55f99f5a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/lv.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Papuass"
+ ]
+ },
+ "mwe-timedtext-textcat-nb": "Anotācija",
+ "mwe-timedtext-textcat-trx": "Transkripts"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/mk.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/mk.json
new file mode 100644
index 00000000..1dd29c01
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/mk.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад",
+ "mwe-timedtext-layout-off": "Скриј титлови",
+ "mwe-timedtext-loading-text": "Го вчитувам текстот...",
+ "mwe-timedtext-textcat-cc": "Опис",
+ "mwe-timedtext-textcat-sub": "Титлови",
+ "mwe-timedtext-textcat-tad": "Аудио-опис",
+ "mwe-timedtext-textcat-ktv": "Караоке",
+ "mwe-timedtext-textcat-tik": "Текст-картички",
+ "mwe-timedtext-textcat-ar": "Активни региони",
+ "mwe-timedtext-textcat-nb": "Прибелешка",
+ "mwe-timedtext-textcat-meta": "Синхронизирани метаподатоци",
+ "mwe-timedtext-textcat-trx": "Стенограм",
+ "mwe-timedtext-textcat-lrc": "Текст на песната",
+ "mwe-timedtext-textcat-lin": "Лингвистичко означување",
+ "mwe-timedtext-textcat-cue": "Моментни точки",
+ "mwe-timedtext-no-subs": "Нема титлови на располагање",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 — титлови за снимката: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Нема пронајдено титлови на $1 за снимката: $2",
+ "mwe-timedtext-upload-timed-text": "Стави титлови"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ml.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ml.json
new file mode 100644
index 00000000..a8d34824
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ml.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Praveenp"
+ ]
+ },
+ "mwe-timedtext-back-btn": "പുറകോട്ട്",
+ "mwe-timedtext-layout-off": "സംഭാഷണരേഖ മറയ്ക്കുക",
+ "mwe-timedtext-loading-text": "എഴുത്ത് ശേഖരിക്കുന്നു...",
+ "mwe-timedtext-textcat-cc": "തലവാക്യം",
+ "mwe-timedtext-textcat-sub": "സംഭാഷണരേഖകൾ",
+ "mwe-timedtext-textcat-tad": "ശബ്ദത്തിന്റെ വിവരണം",
+ "mwe-timedtext-textcat-ktv": "കരോക്കേ",
+ "mwe-timedtext-textcat-tik": "മിന്നിവരുന്ന എഴുത്ത്",
+ "mwe-timedtext-textcat-ar": "സജീവമായ പ്രദേശങ്ങൾ",
+ "mwe-timedtext-textcat-nb": "ടിപ്പണി",
+ "mwe-timedtext-textcat-meta": "സമയമനുസരിച്ചുള്ള മെറ്റാഡേറ്റ",
+ "mwe-timedtext-textcat-trx": "പകർത്തിയെഴുത്ത്",
+ "mwe-timedtext-textcat-lrc": "വരികൾ",
+ "mwe-timedtext-textcat-lin": "ഭാഷാസംബന്ധിയായ അടയാളഭാഷ",
+ "mwe-timedtext-textcat-cue": "സൂചക ബിന്ദുക്കൾ",
+ "mwe-timedtext-no-subs": "എഴുത്തുകളുടെ വരി ലഭ്യമല്ല",
+ "mwe-timedtext-language-subtitles-for-clip": "ഈ മീഡിയശകലത്തിന് $1 ഭാഷയിലുള്ള സംഭാഷണരേഖ: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "ഈ മീഡിയശകലത്തിന് $1 ഭാഷയിലുള്ള സംഭാഷണരേഖയൊന്നും കണ്ടെത്താനായില്ല: $2",
+ "mwe-timedtext-upload-timed-text": "സംഭാഷണരേഖ കൂട്ടിച്ചേർക്കുക"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ms.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ms.json
new file mode 100644
index 00000000..712fff27
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ms.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Kembali",
+ "mwe-timedtext-layout-off": "Sorokkan sari kata",
+ "mwe-timedtext-loading-text": "Teks sedang dimuatkan...",
+ "mwe-timedtext-textcat-cc": "Kapsyen",
+ "mwe-timedtext-textcat-sub": "Sari kata",
+ "mwe-timedtext-textcat-tad": "Keterangan audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Teks ticker",
+ "mwe-timedtext-textcat-ar": "Kawasan aktif",
+ "mwe-timedtext-textcat-nb": "Anotasi",
+ "mwe-timedtext-textcat-meta": "Metadata bermasa",
+ "mwe-timedtext-textcat-trx": "Transkrip",
+ "mwe-timedtext-textcat-lrc": "Lirik",
+ "mwe-timedtext-textcat-lin": "Penanda linguistik",
+ "mwe-timedtext-textcat-cue": "Titik kiu",
+ "mwe-timedtext-no-subs": "Tidak terdapat runut teks",
+ "mwe-timedtext-language-subtitles-for-clip": "Sari kata $1 untuk klip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Tidak terdapat sari kata $1 untuk klip: $2",
+ "mwe-timedtext-upload-timed-text": "Letak sari kata"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nb.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nb.json
new file mode 100644
index 00000000..a273d46b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nb.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Danmichaelo",
+ "Nghtwlkr"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Tilbake",
+ "mwe-timedtext-layout-off": "Gjem undertekster",
+ "mwe-timedtext-loading-text": "Laster tekst ...",
+ "mwe-timedtext-textcat-cc": "Undertektster",
+ "mwe-timedtext-textcat-sub": "Undertekster",
+ "mwe-timedtext-textcat-tad": "Lydbeskrivelse",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Tekst-ticker",
+ "mwe-timedtext-textcat-ar": "Aktive regioner",
+ "mwe-timedtext-textcat-nb": "Merknad",
+ "mwe-timedtext-textcat-meta": "Tidsbestemt metadata",
+ "mwe-timedtext-textcat-trx": "Transkripsjon",
+ "mwe-timedtext-textcat-lrc": "Tekster",
+ "mwe-timedtext-no-subs": "Ingen tekstspor finnes",
+ "mwe-timedtext-language-subtitles-for-clip": "Undertekster på $1 for klippet: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Ingen undertekster på $1 ble funnet for klippet: $2",
+ "mwe-timedtext-upload-timed-text": "Legg til undertekster"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nl.json
new file mode 100644
index 00000000..7b225402
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nl.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Siebrand"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Terug",
+ "mwe-timedtext-layout-off": "Ondertitels verbergen",
+ "mwe-timedtext-loading-text": "Bezig met het laden van de tekst...",
+ "mwe-timedtext-textcat-cc": "Ondertitels",
+ "mwe-timedtext-textcat-sub": "Ondertitels",
+ "mwe-timedtext-textcat-tad": "Audiobeschrijving",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Informatiebalk",
+ "mwe-timedtext-textcat-ar": "Actieve gebieden",
+ "mwe-timedtext-textcat-nb": "Annotatie",
+ "mwe-timedtext-textcat-meta": "Tijdgebaseerde metadata",
+ "mwe-timedtext-textcat-trx": "Transcriptie",
+ "mwe-timedtext-textcat-lrc": "Songteksten",
+ "mwe-timedtext-textcat-lin": "Taalkundige markup",
+ "mwe-timedtext-textcat-cue": "Richtpunten",
+ "mwe-timedtext-no-subs": "Er zijn geen teksttracks beschikbaar",
+ "mwe-timedtext-language-subtitles-for-clip": "Ondertitels in het $1 voor clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Er zijn geen ondertitels in de taal $1 gevonden voor clip: $2",
+ "mwe-timedtext-upload-timed-text": "Ondertitels toevoegen"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nn.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nn.json
new file mode 100644
index 00000000..696c63d4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/nn.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Njardarlogar"
+ ]
+ },
+ "mwe-timedtext-layout-off": "Gøym undertekstar",
+ "mwe-timedtext-textcat-sub": "Undertekstar",
+ "mwe-timedtext-textcat-lrc": "Tekstar",
+ "mwe-timedtext-no-subs": "Ingen tekstspor er tilgjengelege",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 undertekstar for klippet: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Ingen undertekster på $1 vart funne for klippet: $2",
+ "mwe-timedtext-upload-timed-text": "Legg til undertekstar"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pdc.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pdc.json
new file mode 100644
index 00000000..56c9fe84
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pdc.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xqt"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Zerrick"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pfl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pfl.json
new file mode 100644
index 00000000..2e41e363
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pfl.json
@@ -0,0 +1,7 @@
+{
+ "@metadata": {
+ "authors": [
+ "Manuae"
+ ]
+ }
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pl.json
new file mode 100644
index 00000000..544812d0
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pl.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "BeginaFelicysym",
+ "Leinad",
+ "Shadown",
+ "Sp5uhe"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Wstecz",
+ "mwe-timedtext-layout-off": "Ukryj napisy",
+ "mwe-timedtext-loading-text": "Ładowanie tekstu...",
+ "mwe-timedtext-textcat-cc": "Podpisy",
+ "mwe-timedtext-textcat-sub": "Napisy do filmu",
+ "mwe-timedtext-textcat-tad": "Opis ścieżki dźwiękowej",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Notatka",
+ "mwe-timedtext-textcat-ar": "Aktywne regiony",
+ "mwe-timedtext-textcat-nb": "Adnotacja",
+ "mwe-timedtext-textcat-meta": "Metadane ze znacznikami czasu",
+ "mwe-timedtext-textcat-trx": "Rozpisz",
+ "mwe-timedtext-textcat-lrc": "Teksty piosenek",
+ "mwe-timedtext-textcat-lin": "Znaczniki językowe",
+ "mwe-timedtext-textcat-cue": "Punkty kontrolne",
+ "mwe-timedtext-no-subs": "Nie ma dostępnych ścieżek tekstowych",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 napisy do filmu: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nie odnaleziono $1 napisów do filmu: $2",
+ "mwe-timedtext-upload-timed-text": "Dodaj napisy"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pms.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pms.json
new file mode 100644
index 00000000..7ffca36c
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pms.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borichèt",
+ "Dragonòt"
+ ]
+ },
+ "mwe-timedtext-back-btn": "André",
+ "mwe-timedtext-layout-off": "Stërmé ij sot-tìtoj",
+ "mwe-timedtext-loading-text": "Cariament dël test...",
+ "mwe-timedtext-textcat-cc": "Descrission",
+ "mwe-timedtext-textcat-sub": "Sot-tìtoj",
+ "mwe-timedtext-textcat-tad": "Descrission àudio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Test ëd la telescrivent",
+ "mwe-timedtext-textcat-ar": "Region ative",
+ "mwe-timedtext-textcat-nb": "Nòta",
+ "mwe-timedtext-textcat-meta": "Metadat sincronisà",
+ "mwe-timedtext-textcat-trx": "Trascrission",
+ "mwe-timedtext-textcat-lrc": "Lìriche",
+ "mwe-timedtext-textcat-lin": "Marcador lenghìstich",
+ "mwe-timedtext-textcat-cue": "Pont d'arferiment",
+ "mwe-timedtext-no-subs": "Gnun-e marche ëd test disponìbij",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 sot-tìtoj për ël tòch: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "A l'é trovasse gnun sot-tìtoj $1 per ël tòch: $2",
+ "mwe-timedtext-upload-timed-text": "Gionté dij sot-tìtoj"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ps.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ps.json
new file mode 100644
index 00000000..fd556365
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ps.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ahmed-Najib-Biabani-Ibrahimkhel"
+ ]
+ },
+ "mwe-timedtext-textcat-ktv": "کارااوکه"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt-br.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt-br.json
new file mode 100644
index 00000000..008c55ba
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt-br.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dianakc",
+ "Giro720",
+ "Luckas",
+ "Luckas Blade",
+ "555"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Voltar",
+ "mwe-timedtext-layout-off": "Ocultar legendas",
+ "mwe-timedtext-loading-text": "Carregando o texto ...",
+ "mwe-timedtext-textcat-cc": "Títulos",
+ "mwe-timedtext-textcat-sub": "Legendas",
+ "mwe-timedtext-textcat-tad": "Descrição do áudio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Texto deslizante",
+ "mwe-timedtext-textcat-ar": "Regiões ativas",
+ "mwe-timedtext-textcat-nb": "Anotação",
+ "mwe-timedtext-textcat-meta": "Metadados sincronizados",
+ "mwe-timedtext-textcat-trx": "Transcrição",
+ "mwe-timedtext-textcat-lrc": "Letra",
+ "mwe-timedtext-textcat-lin": "Marcação linguística",
+ "mwe-timedtext-textcat-cue": "Pontos de entrada",
+ "mwe-timedtext-no-subs": "Não há nenhum texto disponível",
+ "mwe-timedtext-language-subtitles-for-clip": "Legendas em $1 para o clipe: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Não foram encontradas legendas em $1 para o clipe: $2",
+ "mwe-timedtext-upload-timed-text": "Adicionar legendas"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt.json
new file mode 100644
index 00000000..4917da79
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/pt.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Giro720",
+ "Hamilton Abreu",
+ "Luckas",
+ "SandroHc",
+ "Vitorvicentevalente"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Voltar",
+ "mwe-timedtext-layout-off": "Ocultar legendas",
+ "mwe-timedtext-loading-text": "A carregar o texto ...",
+ "mwe-timedtext-textcat-cc": "Títulos",
+ "mwe-timedtext-textcat-sub": "Legendas",
+ "mwe-timedtext-textcat-tad": "Descrição de áudio",
+ "mwe-timedtext-textcat-ktv": "Caraoque",
+ "mwe-timedtext-textcat-tik": "Cotações",
+ "mwe-timedtext-textcat-ar": "Regiões activas",
+ "mwe-timedtext-textcat-nb": "Anotação",
+ "mwe-timedtext-textcat-meta": "Metadados de sincronização",
+ "mwe-timedtext-textcat-trx": "Transcrição",
+ "mwe-timedtext-textcat-lrc": "Letra",
+ "mwe-timedtext-textcat-lin": "Marcação linguística",
+ "mwe-timedtext-textcat-cue": "Pontos de entrada",
+ "mwe-timedtext-no-subs": "Não há nenhuma faixa de texto disponível",
+ "mwe-timedtext-language-subtitles-for-clip": "Legendas em $1 para o clipe: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Não foram encontradas legendas em $1 para o clipe: $2",
+ "mwe-timedtext-upload-timed-text": "Adicionar legendas"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/qqq.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/qqq.json
new file mode 100644
index 00000000..4714d5b1
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/qqq.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "EugeneZelenko",
+ "Shirayuki",
+ "Siebrand",
+ "Umherirrender"
+ ]
+ },
+ "mwe-timedtext-back-btn": "{{Identical|Back}}",
+ "mwe-timedtext-key-language": "{{optional}}\nParameters:\n* $1 - language key. e.g. \"en\"\n* $2 - language name",
+ "mwe-timedtext-textcat-cc": "{{Identical|Caption}}",
+ "mwe-timedtext-textcat-sub": "{{Identical|Subtitle}}",
+ "mwe-timedtext-textcat-ktv": "See [[w:Karaoke]].",
+ "mwe-timedtext-textcat-nb": "{{Identical|Annotation}}",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 is language name for subtitles (e.g. \"English\"), $2 is title of file that timed text is for.\nShown as the page title on a TimedText namespace page when the page exists. See also mwe-timedtext-language-no-subtitles-for-clip.",
+ "mwe-timedtext-language-no-subtitles-for-clip": "$1 is language name, $2 is title of file that timed text is for.\nShown as the page title on a TimedText namespace page when the page does not exist. See also mwe-timedtext-language-subtitles-for-clip",
+ "mwe-timedtext-upload-timed-text": "After clicking the 'CC' button on the video player, the button on the resulting menu to add subtitles to a video file."
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ro.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ro.json
new file mode 100644
index 00000000..77892ab4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ro.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minisarm",
+ "Stelistcristi"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Înapoi",
+ "mwe-timedtext-layout-off": "Ascunde subtitrările",
+ "mwe-timedtext-loading-text": "Se încarcă textul...",
+ "mwe-timedtext-textcat-cc": "Legende",
+ "mwe-timedtext-textcat-sub": "Subtitrări",
+ "mwe-timedtext-textcat-tad": "Descriere audio",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Text mai gros",
+ "mwe-timedtext-textcat-ar": "Regiuni active",
+ "mwe-timedtext-textcat-nb": "Adnotare",
+ "mwe-timedtext-textcat-meta": "Metadate sincronizate",
+ "mwe-timedtext-textcat-trx": "Transcripție",
+ "mwe-timedtext-textcat-lrc": "Versuri",
+ "mwe-timedtext-textcat-lin": "Etichete lingvistice",
+ "mwe-timedtext-textcat-cue": "Puncte de tac",
+ "mwe-timedtext-no-subs": "Niciun text de piesă disponibil",
+ "mwe-timedtext-language-subtitles-for-clip": "Subtitrare în limba $1 pentru clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nu s-a găsit nicio subtitrare în limba $1 pentru clip: $2",
+ "mwe-timedtext-upload-timed-text": "Adaugă subtitrări"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/roa-tara.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/roa-tara.json
new file mode 100644
index 00000000..a26678a4
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/roa-tara.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Rrete",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-nb": "Annotazione",
+ "mwe-timedtext-textcat-meta": "Metadate temborizzate",
+ "mwe-timedtext-textcat-trx": "Trascrive",
+ "mwe-timedtext-textcat-lrc": "Teste",
+ "mwe-timedtext-upload-timed-text": "Aggiunge le sottotitole"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ru.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ru.json
new file mode 100644
index 00000000..8b3ff81c
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ru.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "MaxSem",
+ "Okras",
+ "Александр Сигачёв",
+ "Kaganer"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад",
+ "mwe-timedtext-layout-off": "Скрыть субтитры",
+ "mwe-timedtext-loading-text": "Загрузка текста…",
+ "mwe-timedtext-textcat-cc": "Субтитры-описания",
+ "mwe-timedtext-textcat-sub": "Субтитры",
+ "mwe-timedtext-textcat-tad": "Описание аудиофайла",
+ "mwe-timedtext-textcat-ktv": "Караоке",
+ "mwe-timedtext-textcat-tik": "Текстовые карточки",
+ "mwe-timedtext-textcat-ar": "Активные области",
+ "mwe-timedtext-textcat-nb": "Аннотация",
+ "mwe-timedtext-textcat-meta": "Синхронизированные метаданные",
+ "mwe-timedtext-textcat-trx": "Стенограмма",
+ "mwe-timedtext-textcat-lrc": "Слова песни",
+ "mwe-timedtext-textcat-lin": "Лингвистическая разметка",
+ "mwe-timedtext-textcat-cue": "Знаковые точки",
+ "mwe-timedtext-no-subs": "Нет текстовых дорожек",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 — субтитры для клипа: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Не найдено субтитров на $1 для клипа: $2",
+ "mwe-timedtext-upload-timed-text": "Добавить субтитры"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/rue.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/rue.json
new file mode 100644
index 00000000..1cc92d6f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/rue.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gazeb"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/si.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/si.json
new file mode 100644
index 00000000..8af0327f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/si.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-timedtext-back-btn": "ආපසු",
+ "mwe-timedtext-layout-off": "උපශීර්ෂ සඟවන්න",
+ "mwe-timedtext-loading-text": "පෙළ පූරණය වෙමින් ...",
+ "mwe-timedtext-textcat-cc": "උපන්‍යාස",
+ "mwe-timedtext-textcat-sub": "උපශීර්ෂ",
+ "mwe-timedtext-textcat-tad": "ශ්‍රව්‍ය විස්තරය",
+ "mwe-timedtext-textcat-ktv": "කැරෝකේ",
+ "mwe-timedtext-textcat-tik": "ඔරලෝසු පෙළ",
+ "mwe-timedtext-textcat-ar": "සක්‍රිය ප්‍රදේශ",
+ "mwe-timedtext-textcat-nb": "ටීකාව",
+ "mwe-timedtext-textcat-meta": "කාලිත පාරදත්ත",
+ "mwe-timedtext-textcat-trx": "ප්‍රතිලේඛනය",
+ "mwe-timedtext-textcat-lrc": "ගීපදවැල්",
+ "mwe-timedtext-textcat-lin": "භාෂාමය අධිකය",
+ "mwe-timedtext-textcat-cue": "ඉංගිත ගතිගුණ",
+ "mwe-timedtext-no-subs": "මීළඟ පථ ලබාගත නොහැක",
+ "mwe-timedtext-language-subtitles-for-clip": "ක්ලිපය සඳහා $1 උපසිරුස: $2",
+ "mwe-timedtext-upload-timed-text": "උපශීර්ෂ එක් කරන්න"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sl.json
new file mode 100644
index 00000000..8df43558
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dbc334"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Nazaj"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/so.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/so.json
new file mode 100644
index 00000000..6a979a8b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/so.json
@@ -0,0 +1,7 @@
+{
+ "@metadata": {
+ "authors": [
+ "Abshirdheere"
+ ]
+ }
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-ec.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-ec.json
new file mode 100644
index 00000000..f3dfbbc6
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-ec.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rancher",
+ "Михајло Анђелковић"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад",
+ "mwe-timedtext-layout-off": "Сакриј сабтајтлове",
+ "mwe-timedtext-loading-text": "Учитава се текст ...",
+ "mwe-timedtext-key-language": "$1, $2",
+ "mwe-timedtext-textcat-cc": "Ознаке",
+ "mwe-timedtext-textcat-sub": "Поднаслови",
+ "mwe-timedtext-textcat-trx": "Транскрипт"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-el.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-el.json
new file mode 100644
index 00000000..100a6fc3
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sr-el.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rancher"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Nazad",
+ "mwe-timedtext-layout-off": "Sakrij sabtajtlove",
+ "mwe-timedtext-loading-text": "Učitava se tekst ...",
+ "mwe-timedtext-key-language": "$1, $2",
+ "mwe-timedtext-textcat-cc": "Oznake",
+ "mwe-timedtext-textcat-sub": "Podnaslovi",
+ "mwe-timedtext-textcat-trx": "Transkript"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sv.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sv.json
new file mode 100644
index 00000000..a0b693cd
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/sv.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ainali",
+ "Dafer45"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Tillbaka",
+ "mwe-timedtext-layout-off": "Dölj undertexter",
+ "mwe-timedtext-loading-text": "Laddar text ...",
+ "mwe-timedtext-textcat-cc": "Undertexter",
+ "mwe-timedtext-textcat-sub": "Undertexter",
+ "mwe-timedtext-textcat-tad": "Ljudbeskrivning",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Rullande text",
+ "mwe-timedtext-textcat-ar": "Aktiva regioner",
+ "mwe-timedtext-textcat-nb": "Anmärkning",
+ "mwe-timedtext-textcat-meta": "Tidsbestämd metadata",
+ "mwe-timedtext-textcat-trx": "Transkription",
+ "mwe-timedtext-textcat-lrc": "Texter",
+ "mwe-timedtext-textcat-lin": "Språkliga markeringar",
+ "mwe-timedtext-textcat-cue": "Referenspunkter",
+ "mwe-timedtext-no-subs": "Inga textspår finns",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 undertexter för klipp: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Inga $1 undertexter hittades för klipp: $2",
+ "mwe-timedtext-upload-timed-text": "Lägga till undertexter"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ta.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ta.json
new file mode 100644
index 00000000..6e9ef3e8
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ta.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Karthi.dr",
+ "Shanmugamp7",
+ "மதனாஹரன்"
+ ]
+ },
+ "mwe-timedtext-back-btn": "பின்செல்",
+ "mwe-timedtext-layout-off": "துணைத்தலைப்புக்களை மறை",
+ "mwe-timedtext-loading-text": "உரையை ஏற்றுகிறது ...",
+ "mwe-timedtext-textcat-sub": "துணைத்தலைப்புக்கள்",
+ "mwe-timedtext-textcat-tad": "ஒலித விவரணம்",
+ "mwe-timedtext-textcat-lrc": "பாடல் வரிகள்",
+ "mwe-timedtext-upload-timed-text": "துணைத்தலைப்புக்களைச் சேர்"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/te.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/te.json
new file mode 100644
index 00000000..50688138
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/te.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Veeven"
+ ]
+ },
+ "mwe-timedtext-back-btn": "వెనక్కి",
+ "mwe-timedtext-textcat-sub": "ఉపశీర్షికలు"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tl.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tl.json
new file mode 100644
index 00000000..971a8f30
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tl.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "AnakngAraw"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Bumalik",
+ "mwe-timedtext-layout-off": "Itago ang kabahaging mga pamagat",
+ "mwe-timedtext-loading-text": "Ikinakarga ang teksto ...",
+ "mwe-timedtext-key-language": "$1, $2",
+ "mwe-timedtext-textcat-cc": "Mga paliwanag",
+ "mwe-timedtext-textcat-sub": "Kabahaging mga pamagat",
+ "mwe-timedtext-textcat-tad": "Paglalarawan ng naririnig",
+ "mwe-timedtext-textcat-ktv": "Karaoke",
+ "mwe-timedtext-textcat-tik": "Teksto ng pampulso",
+ "mwe-timedtext-textcat-ar": "Masisiglang mga rehiyon",
+ "mwe-timedtext-textcat-nb": "Paliwanag",
+ "mwe-timedtext-textcat-meta": "Inorasang metadato",
+ "mwe-timedtext-textcat-trx": "Sipi ng salin",
+ "mwe-timedtext-textcat-lrc": "Titik ng awit",
+ "mwe-timedtext-textcat-lin": "Markang-pantaas ng lingguwistika",
+ "mwe-timedtext-textcat-cue": "Mga tuldok ng pahiwatig",
+ "mwe-timedtext-no-subs": "Walang makukuhang mga bakas ng teksto",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 kabahaging mga pamagat para sa putol na: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Walang natagpuang $1 kabahaging mga pamagat para sa putol na: $2",
+ "mwe-timedtext-upload-timed-text": "Magdagdag ng kabahaging mga pamagat"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tr.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tr.json
new file mode 100644
index 00000000..8b26730a
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/tr.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Emperyan"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Geri",
+ "mwe-timedtext-textcat-sub": "Alt yazılar",
+ "mwe-timedtext-no-subs": "Parça metni yok",
+ "mwe-timedtext-upload-timed-text": "Alt yazı ekle"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/uk.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/uk.json
new file mode 100644
index 00000000..916f0395
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/uk.json
@@ -0,0 +1,27 @@
+{
+ "@metadata": {
+ "authors": [
+ "Base",
+ "Тест"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Назад",
+ "mwe-timedtext-layout-off": "Приховати субтитри",
+ "mwe-timedtext-loading-text": "Завантаження тексту…",
+ "mwe-timedtext-textcat-cc": "Субтитри-підписи",
+ "mwe-timedtext-textcat-sub": "Субтитри",
+ "mwe-timedtext-textcat-tad": "Аудіо-опис",
+ "mwe-timedtext-textcat-ktv": "Караоке",
+ "mwe-timedtext-textcat-tik": "Текстові картки",
+ "mwe-timedtext-textcat-ar": "Активні області",
+ "mwe-timedtext-textcat-nb": "Анотація",
+ "mwe-timedtext-textcat-meta": "Синхронізовані метадані",
+ "mwe-timedtext-textcat-trx": "Стенограма",
+ "mwe-timedtext-textcat-lrc": "Слова пісні",
+ "mwe-timedtext-textcat-lin": "Лінгвістична розмітка",
+ "mwe-timedtext-textcat-cue": "Знакові точки",
+ "mwe-timedtext-no-subs": "Немає текстових доріжок",
+ "mwe-timedtext-language-subtitles-for-clip": "$1 — субтитри для кліпу: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Не знайдено субтитрів $1 для кліпу: $2",
+ "mwe-timedtext-upload-timed-text": "Додати субтитри"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ur.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ur.json
new file mode 100644
index 00000000..baafae32
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/ur.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-timedtext-back-btn": "واپس",
+ "mwe-timedtext-textcat-sub": "رومانیہ"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/vi.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/vi.json
new file mode 100644
index 00000000..5ee9bb9b
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/vi.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minh Nguyen",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "mwe-timedtext-back-btn": "Quay lại",
+ "mwe-timedtext-layout-off": "Ẩn phụ đề",
+ "mwe-timedtext-loading-text": "Đang tải văn bản…",
+ "mwe-timedtext-textcat-sub": "Phụ đề",
+ "mwe-timedtext-textcat-tad": "Lời miêu tả âm thanh",
+ "mwe-timedtext-textcat-ktv": "Karaôkê",
+ "mwe-timedtext-textcat-meta": "Siêu dữ liệu đồng bộ",
+ "mwe-timedtext-textcat-lrc": "Lời hát",
+ "mwe-timedtext-textcat-lin": "Đánh dấu ngôn ngữ học",
+ "mwe-timedtext-upload-timed-text": "Thêm phụ đề"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/wa.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/wa.json
new file mode 100644
index 00000000..c8d2fdf6
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/wa.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Srtxg"
+ ]
+ },
+ "mwe-timedtext-layout-off": "Catchî les dzo-tites",
+ "mwe-timedtext-loading-text": "Dji tchedje li tecse...",
+ "mwe-timedtext-textcat-cc": "Ledjindes",
+ "mwe-timedtext-textcat-sub": "Dizo-tites",
+ "mwe-timedtext-textcat-lrc": "Paroles",
+ "mwe-timedtext-textcat-lin": "Etiketes di lingaedje",
+ "mwe-timedtext-language-subtitles-for-clip": "Dizo-tites e $1 pol clip: $2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "Nou dzo-tite $1 di trové pol clip: $2"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/yi.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/yi.json
new file mode 100644
index 00000000..c05e1576
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/yi.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "פוילישער"
+ ]
+ },
+ "mwe-timedtext-back-btn": "צוריק",
+ "mwe-timedtext-textcat-cc": "באשרייבונגען"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hans.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hans.json
new file mode 100644
index 00000000..d13683e9
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hans.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shizhao",
+ "Simon Shek",
+ "Wilsonmess",
+ "Xiaomingyan",
+ "Yfdyh000"
+ ]
+ },
+ "mwe-timedtext-back-btn": "返回",
+ "mwe-timedtext-layout-off": "隐藏字幕",
+ "mwe-timedtext-loading-text": "正在载入文本...",
+ "mwe-timedtext-textcat-cc": "说明",
+ "mwe-timedtext-textcat-sub": "副标题",
+ "mwe-timedtext-textcat-tad": "声音说明",
+ "mwe-timedtext-textcat-ktv": "卡拉OK",
+ "mwe-timedtext-textcat-tik": "滚动文本",
+ "mwe-timedtext-textcat-ar": "作用区域",
+ "mwe-timedtext-textcat-nb": "注释",
+ "mwe-timedtext-textcat-meta": "字幕元数据",
+ "mwe-timedtext-textcat-trx": "字幕",
+ "mwe-timedtext-textcat-lrc": "歌词",
+ "mwe-timedtext-textcat-lin": "语言标记",
+ "mwe-timedtext-textcat-cue": "提示点",
+ "mwe-timedtext-no-subs": "没有可用的字幕",
+ "mwe-timedtext-language-subtitles-for-clip": "片段$2的$1字幕",
+ "mwe-timedtext-language-no-subtitles-for-clip": "没有找到片段$2的$1字幕",
+ "mwe-timedtext-upload-timed-text": "添加字幕"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hant.json b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hant.json
new file mode 100644
index 00000000..b653aeb1
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/i18n/zh-hant.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Justincheng12345",
+ "Mark85296341",
+ "Simon Shek",
+ "LNDDYL"
+ ]
+ },
+ "mwe-timedtext-back-btn": "返回",
+ "mwe-timedtext-layout-off": "隱藏字幕",
+ "mwe-timedtext-loading-text": "正在讀取文字……",
+ "mwe-timedtext-textcat-cc": "標題",
+ "mwe-timedtext-textcat-sub": "副標題",
+ "mwe-timedtext-textcat-tad": "音訊說明",
+ "mwe-timedtext-textcat-ktv": "卡拉OK",
+ "mwe-timedtext-textcat-tik": "滾動文本",
+ "mwe-timedtext-textcat-ar": "有效區城",
+ "mwe-timedtext-textcat-nb": "註解",
+ "mwe-timedtext-textcat-meta": "字幕元資料",
+ "mwe-timedtext-textcat-trx": "字幕",
+ "mwe-timedtext-textcat-lrc": "歌詞",
+ "mwe-timedtext-textcat-lin": "語言標記",
+ "mwe-timedtext-textcat-cue": "暗點",
+ "mwe-timedtext-no-subs": "無可用字幕",
+ "mwe-timedtext-language-subtitles-for-clip": "片段的$1字幕文件:$2",
+ "mwe-timedtext-language-no-subtitles-for-clip": "沒有找到片段的$1字幕文件:$2",
+ "mwe-timedtext-upload-timed-text": "添加字幕"
+}
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TextSource.js b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TextSource.js
new file mode 100644
index 00000000..cce8310f
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TextSource.js
@@ -0,0 +1,504 @@
+/**
+ * Base mw.TextSource object
+ *
+ * @param {Object} source Source object to extend
+ * @param {Object} textProvider [Optional] The text provider interface ( to load source from api )
+ */
+( function( mw, $ ) { "use strict";
+
+ mw.TextSource = function( source ) {
+ return this.init( source );
+ };
+ mw.TextSource.prototype = {
+
+ //The load state:
+ loaded: false,
+
+ // Container for the captions
+ // captions include "start", "end" and "content" fields
+ captions: [],
+
+ // The css style for captions ( some file formats specify display types )
+ styleCss: {},
+
+ // The previous index of the timed text served
+ // Avoids searching the entire array on time updates.
+ prevIndex: 0,
+
+ /**
+ * @constructor Inherits mediaSource from embedPlayer
+ * @param {source} Base source element
+ * @param {Object} Pointer to the textProvider
+ */
+ init: function( source , textProvider) {
+ // Inherits mediaSource
+ for( var i in source){
+ this[ i ] = source[ i ];
+ }
+
+ // Set default category to subtitle if unset:
+ if( ! this.kind ) {
+ this.kind = 'subtitle';
+ }
+ //Set the textProvider if provided
+ if( textProvider ) {
+ this.textProvider = textProvider;
+ }
+ return this;
+ },
+
+ /**
+ * Function to load and parse the source text
+ * @param {Function} callback Function called once text source is loaded
+ */
+ load: function( callback ) {
+ var _this = this;
+ mw.log("TextSource:: load src "+ _this.getSrc() );
+
+ // Setup up a callback ( in case it was not defined )
+ if( !callback ){
+ callback = function(){ return ; };
+ }
+
+ // Check if the captions have already been loaded:
+ if( this.loaded ){
+ return callback();
+ }
+
+ // Try to load src via XHR source
+ if( !this.getSrc() ) {
+ mw.log( "Error: TextSource no source url for text track");
+ return callback();
+ }
+
+ // Check type for special loaders:
+ $( mw ).triggerQueueCallback( 'TimedText_LoadTextSource', _this, function(){
+ if( _this.loaded ){
+ callback();
+ } else {
+ // if no module loaded the text source use the normal ajax proxy:
+ new mw.ajaxProxy({
+ url: _this.getSrc(),
+ success: function( resultXML ) {
+ _this.captions = _this.getCaptions( resultXML );
+ _this.loaded = true;
+ mw.log("mw.TextSource :: loaded from " + _this.getSrc() + " Found: " + _this.captions.length + ' captions' );
+ callback();
+ },
+ error: function() {
+ mw.log("Error: TextSource Error with http response");
+ _this.loaded = true;
+ callback();
+ }
+ });
+ }
+ })
+ },
+ /**
+ * Returns the text content for requested time
+ *
+ * @param {Number} time Time in seconds
+ */
+ getCaptionForTime: function ( time ) {
+ var prevCaption = this.captions[ this.prevIndex ];
+ var captionSet = {};
+
+ // Setup the startIndex:
+ if( prevCaption && time >= prevCaption.start ) {
+ var startIndex = this.prevIndex;
+ }else{
+ // If a backwards seek start searching at the start:
+ var startIndex = 0;
+ }
+ var firstCapIndex = 0;
+ // Start looking for the text via time, add all matches that are in range
+ for( var i = startIndex ; i < this.captions.length; i++ ) {
+ var caption = this.captions[ i ];
+ // Don't handle captions with 0 or -1 end time:
+ if( caption.end == 0 || caption.end == -1)
+ continue;
+
+ if( time >= caption.start &&
+ time <= caption.end ) {
+ // set the earliest valid time to the current start index:
+ if( !firstCapIndex ){
+ firstCapIndex = caption.start;
+ }
+
+ //mw.log("Start cap time: " + caption.start + ' End time: ' + caption.end );
+ captionSet[i] = caption ;
+ }
+ // captions are stored in start order stop search if we get larger than time
+ if( caption.start > time ){
+ break;
+ }
+ }
+ // Update the prevIndex:
+ this.prevIndex = firstCapIndex;
+ //Return the set of captions in range:
+ return captionSet;
+ },
+
+ /**
+ * Check if the caption is an overlay format ( and must be ontop of the player )
+ */
+ isOverlay: function(){
+ return this.mimeType == 'text/xml';
+ },
+
+ getCaptions: function( data ){
+ // Detect caption data type:
+ switch( this.mimeType ){
+ case 'text/mw-srt':
+ return this.getCaptiosnFromMediaWikiSrt( data );
+ break;
+ case 'text/x-srt':
+ return this.getCaptionsFromSrt( data);
+ break;
+ case 'text/xml':
+ return this.getCaptionsFromTMML( data );
+ break;
+ }
+ // caption mime not found return empty set:
+ return [];
+ },
+
+ getStyleCssById: function( styleId ){
+ if( this.styleCss[ styleId ] ){
+ return this.styleCss[ styleId ];
+ }
+ return {};
+ },
+ /**
+ * Grab timed text from TMML format
+ *
+ * @param data
+ * @return
+ */
+ getCaptionsFromTMML: function( data ){
+ var _this = this;
+ mw.log("TextSource::getCaptionsFromTMML", data);
+ // set up display information:
+ var captions = [];
+ var xml = ( $( data ).find("tt").length ) ? data : $.parseXML( data );
+
+ // Check for parse error:
+ try {
+ if( !xml || $( xml ).find('parsererror').length ){
+ mw.log("Error: close caption parse error: " + $( xml ).find('parsererror').text() );
+ return captions;
+ }
+ } catch ( e ) {
+ mw.log( "Error: close caption parse error: " + e.toString() );
+ return captions;
+ }
+
+ // Set the body Style
+ var bodyStyleId = $( xml ).find('body').attr('style');
+
+ // Set style translate ttml to css
+ $( xml ).find( 'style').each( function( inx, style){
+ var cssObject = {};
+ // Map CamelCase css properties:
+ $( style.attributes ).each(function(inx, attr){
+ var attrName = attr.name;
+ if( attrName.substr(0, 4) !== 'tts:' ){
+ // skip
+ return true;
+ }
+ var cssName = '';
+ for( var c = 4; c < attrName.length; c++){
+ if( attrName[c].toLowerCase() != attrName[c] ){
+ cssName += '-' + attrName[c].toLowerCase();
+ } else {
+ cssName+= attrName[c]
+ }
+ }
+ cssObject[ cssName ] = attr.nodeValue;
+ });
+ // for(var i =0; i< style.length )
+ _this.styleCss[ $( style).attr('id') ] = cssObject;
+ });
+
+ $( xml ).find( 'p' ).each( function( inx, p ){
+ // Get text content by converting ttml node to html
+ var content = '';
+ $.each( p.childNodes, function(inx, node){
+ content+= _this.convertTTML2HTML( node );
+ });
+ // Get the end time:
+ var end = null;
+ if( $( p ).attr( 'end' ) ){
+ end = mw.npt2seconds( $( p ).attr( 'end' ) );
+ }
+ // Look for dur
+ if( !end && $( p ).attr( 'dur' )){
+ end = mw.npt2seconds( $( p ).attr( 'begin' ) ) +
+ mw.npt2seconds( $( p ).attr( 'dur' ) );
+ }
+
+ // Create the caption object :
+ var captionObj ={
+ 'start': mw.npt2seconds( $( p ).attr( 'begin' ) ),
+ 'end': end,
+ 'content': content
+ };
+
+ // See if we have custom metadata for position of this caption object
+ // there are 35 columns across and 15 rows high
+ var $meta = $(p).find( 'metadata' );
+ if( $meta.length ){
+ captionObj['css'] = {
+ 'position': 'absolute'
+ };
+ if( $meta.attr('cccol') ){
+ captionObj['css']['left'] = ( $meta.attr('cccol') / 35 ) * 100 +'%';
+ // also means the width has to be reduced:
+ //captionObj['css']['width'] = 100 - parseInt( captionObj['css']['left'] ) + '%';
+ }
+ if( $meta.attr('ccrow') ){
+ captionObj['css']['top'] = ( $meta.attr('ccrow') / 15 ) * 100 +'%';
+ }
+ }
+ if( $(p).attr('tts:textAlign') ){
+ if( !captionObj['css'] ){
+ captionObj['css'] = {};
+ }
+ captionObj['css']['text-align'] = $(p).attr('tts:textAlign');
+
+ // Remove text align is "right" flip the css left:
+ if( captionObj['css']['text-align'] == 'right' && captionObj['css']['left'] ){
+ //captionObj['css']['width'] = captionObj['css']['left'];
+ captionObj['css']['left'] = null;
+ }
+ }
+
+ // check if this p has any style else use the body parent
+ if( $(p).attr('style') ){
+ captionObj['styleId'] = $(p).attr('style') ;
+ } else {
+ captionObj['styleId'] = bodyStyleId;
+ }
+ captions.push( captionObj);
+ });
+ return captions;
+ },
+ convertTTML2HTML: function( node ){
+ var _this = this;
+
+ // look for text node:
+ if( node.nodeType == 3 ){
+ return node.textContent;
+ }
+ // skip metadata nodes:
+ if( node.nodeName == 'metadata' ){
+ return '';
+ }
+ // if a br just append
+ if( node.nodeName == 'br' ){
+ return '<br />';
+ }
+ // Setup tts mappings TODO should be static property of a ttmlSource object.
+ var ttsStyleMap = {
+ 'tts:color' : 'color',
+ 'tts:fontWeight' : 'font-weight',
+ 'tts:fontStyle' : 'font-style'
+ };
+ if( node.childNodes.length ){
+ var nodeString = '';
+ var styleVal = '';
+ for( var attr in ttsStyleMap ){
+ if( node.getAttribute( attr ) ){
+ styleVal+= ttsStyleMap[ attr ] + ':' + node.getAttribute( attr ) + ';';
+ }
+ }
+ nodeString += '<' + node.nodeName + ' style="' + styleVal + '" >';
+ $.each( node.childNodes, function( inx, childNode ){
+ nodeString += _this.convertTTML2HTML( childNode );
+ });
+ nodeString += '</' + node.nodeName + '>';
+ return nodeString;
+ }
+ },
+ /**
+ * srt timed text parse handle:
+ * @param {String} data Srt string to be parsed
+ */
+ getCaptionsFromSrt: function ( data ){
+ mw.log("TextSource::getCaptionsFromSrt");
+ var _this = this;
+ // Check if the "srt" parses as an XML
+ try{
+ var xml = $.parseXML( data );
+ if( xml && $( xml ).find('parsererror').length == 0 ){
+ return this.getCaptionsFromTMML( data );
+ }
+ } catch ( e ){
+ // srt should not be xml
+ }
+ // Remove dos newlines
+ var srt = data.replace(/\r+/g, '');
+
+ // Trim white space start and end
+ srt = srt.replace(/^\s+|\s+$/g, '');
+
+ // Remove all html tags for security reasons
+ srt = srt.replace(/<[a-zA-Z\/][^>]*>/g, '');
+
+ // Get captions
+ var captions = [];
+ var caplist = srt.split('\n\n');
+ for (var i = 0; i < caplist.length; i++) {
+ var captionText = "";
+ var caption = false;
+ captionText = caplist[i];
+ var s = captionText.split(/\n/);
+ if (s.length < 2) {
+ // file format error or comment lines
+ continue;
+ }
+ if (s[0].match(/^\d+$/) && s[1].match(/\d+:\d+:\d+/)) {
+ // ignore caption number in s[0]
+ // parse time string
+ var m = s[1].match(/(\d+):(\d+):(\d+)(?:,(\d+))?\s*--?>\s*(\d+):(\d+):(\d+)(?:,(\d+))?/);
+ if (m) {
+ caption = _this.match2caption( m );
+ } else {
+ // Unrecognized timestring
+ continue;
+ }
+ if( caption ){
+ // concatenate text lines to html text
+ caption['content'] = s.slice(2).join("<br>");
+ }
+ } else {
+ // file format error or comment lines
+ continue;
+ }
+ // Add the current caption to the captions set:
+ captions.push( caption );
+ }
+
+ return captions;
+ },
+
+ /**
+ * Get srts from a mediawiki html / srt string
+ *
+ * Right now wiki -> html is not always friendly to our srt parsing.
+ * The long term plan is to move the srt parsing to server side and have the api
+ * server up the srt's times in JSON form
+ *
+ * Also see https://bugzilla.wikimedia.org/show_bug.cgi?id=29126
+ *
+ * TODO move to mediaWiki specific module.
+ */
+ getCaptiosnFromMediaWikiSrt: function( data ){
+ mw.log("TimedText::getCaptiosnFromMediaWikiSrt:");
+ var _this = this;
+ var captions = [ ];
+ var curentCap = {
+ 'content': ''
+ };
+ var parseNextAsTime = false;
+ // Note this string concatenation and html error wrapping sometimes causes
+ // parse issues where the wikitext includes many native <p /> tags without child
+ // subtitles. In prating this is not a deal breakers because the wikitext for
+ // TimedText namespace and associated srts already has a specific format.
+ // Long term we will move to server side parsing.
+ $( '<div>' + data + '</div>' ).find('p').each( function() {
+ var currentPtext = $(this).html();
+ //mw.log( 'pText: ' + currentPtext );
+
+ // We translate raw wikitext gennerated html into a matched srt time sample.
+ // The raw html looks like:
+ // #
+ // hh:mm:ss,ms --&gt hh:mm:ss,ms
+ // text
+ //
+ // You can read more about the srt format here:
+ // http://en.wikipedia.org/wiki/SubRip
+ //
+ // We attempt to be fairly robust in our regular expression to catch a few
+ // srt variations such as omition of commas and empty text lines.
+ var m = currentPtext
+ .replace('--&gt;', '-->') // restore --&gt with --> for easier srt parsing:
+ .match(/\d+\s([\d\-]+):([\d\-]+):([\d\-]+)(?:,([\d\-]+))?\s*--?>\s*([\d\-]+):([\d\-]+):([\d\-]+)(?:,([\d\-]+))?\n?(.*)/);
+
+ if (m) {
+ captions.push(
+ _this.match2caption( m )
+ );
+ return true;
+ }
+
+ /***
+ * Handle multi line sytle output
+ *
+ * Handles cases parse cases where an entire line can't be parsed in the single
+ * regular expression above, Since the diffrent captions pars are outputed in
+ * diffrent <p /> tags by the wikitext parser output.
+ */
+
+ // Check if we have reached the end of a multi line match
+ if( parseInt( currentPtext ) == currentPtext ) {
+ if( curentCap.content != '' ) {
+ captions.push( curentCap );
+ }
+ // Clear out the current caption content
+ curentCap = {
+ 'content': ''
+ };
+ return true;
+ }
+ // Check only for time match:
+ var m = currentPtext
+ .replace('--&gt;', '-->')
+ .match(/(\d+):(\d+):(\d+)(?:,(\d+))?\s*--?>\s*(\d+):(\d+):(\d+)(?:,(\d+))?/);
+ if (m) {
+ // Update the currentCap:
+ curentCap = _this.match2caption( m );
+ return true;
+ }
+ // Else append contnet for the curentCap
+ if( currentPtext != '<br>' ) {
+ curentCap['content'] += currentPtext;
+ }
+ });
+ //Push last subtitle:
+ if( curentCap.length != 0) {
+ captions.push( curentCap );
+ }
+ mw.log( "TimedText::getCaptiosnFromMediaWikiSrt found " + captions.length + ' captions');
+ return captions;
+ },
+ /**
+ * Takes a regular expresion match and converts it to a caption object
+ */
+ match2caption: function( m ){
+ var caption = {};
+ // Look for ms:
+ var startMs = (m[4]) ? parseInt(m[4], 10) : 0;
+ var endMs = (m[8]) ? parseInt(m[8], 10) : 0;
+ caption['start'] = this.timeParts2seconds( m[1], m[2], m[3], startMs );
+ caption['end'] = this.timeParts2seconds( m[5], m[6], m[7], endMs );
+ if( m[9] ){
+ caption['content'] = $.trim( m[9] );
+ }
+ return caption;
+ },
+ /**
+ * Takes time parts in hours, min, seconds and milliseconds and coverts to float seconds.
+ */
+ timeParts2seconds: function( hours, min, sec, ms ){
+ return mw.measurements2seconds({
+ 'hours': hours,
+ 'minutes': min,
+ 'seconds' : sec,
+ 'milliseconds': ms
+ });
+ }
+ };
+
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TimedText.js b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TimedText.js
new file mode 100644
index 00000000..2a69343e
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.TimedText.js
@@ -0,0 +1,1313 @@
+/**
+ * The Core timed Text interface object
+ *
+ * handles class mappings for:
+ * menu display ( jquery.ui themeable )
+ * timed text loading request
+ * timed text edit requests
+ * timed text search & seek interface ( version 2 )
+ *
+ * @author: Michael Dale
+ *
+ */
+
+( function( mw, $ ) {"use strict";
+
+ // Merge in timed text related attributes:
+ mw.mergeConfig( 'EmbedPlayer.SourceAttributes', [
+ 'srclang',
+ 'kind',
+ 'label'
+ ]);
+
+ /**
+ * Timed Text Object
+ * @param embedPlayer Host player for timedText interfaces
+ */
+ mw.TimedText = function( embedPlayer ) {
+ return this.init( embedPlayer );
+ };
+
+ mw.TimedText.prototype = {
+
+ /**
+ * Preferences config order is presently:
+ * 1) user cookie
+ * 2) defaults provided in this config var:
+ */
+ config: {
+ // Layout for basic "timedText" type can be 'ontop', 'off', 'below'
+ 'layout' : 'ontop',
+
+ //Set the default local ( should be grabbed from the browser )
+ 'userLanguage' : mw.config.get( 'wgUserLanguage' ) || 'en',
+
+ //Set the default kind of timedText to display ( un-categorized timed-text is by default "subtitles" )
+ 'userKind' : 'subtitles'
+ },
+
+ // The default display mode is 'ontop'
+ defaultDisplayMode : 'ontop',
+
+ // Save last layout mode
+ lastLayout : 'ontop',
+
+ // The bind prefix:
+ bindPostFix: '.timedText',
+
+ // Default options are empty
+ options: {},
+
+ /**
+ * The list of enabled sources
+ */
+ enabledSources: [],
+
+ // First loading flag - To set the layout at first load
+ firstLoad: true,
+
+ /**
+ * The current language key
+ */
+ currentLangKey : null,
+
+ /**
+ * The direction of the current language
+ */
+ currentLangDir : null,
+
+ /**
+ * Stores the last text string per kind to avoid dom checks for updated text
+ */
+ prevText: [],
+
+ /**
+ * Text sources ( a set of textSource objects )
+ */
+ textSources: [],
+
+ /**
+ * Valid "Track" categories
+ */
+ validCategoriesKeys: [
+ "CC",
+ "SUB",
+ "TAD",
+ "KTV",
+ "TIK",
+ "AR",
+ "NB",
+ "META",
+ "TRX",
+ "LRC",
+ "LIN",
+ "CUE"
+ ],
+
+ /**
+ * @constructor
+ * @param {Object} embedPlayer Host player for timedText interfaces
+ */
+ init: function( embedPlayer ) {
+ var _this = this;
+ mw.log("TimedText: init() ");
+ this.embedPlayer = embedPlayer;
+ // don't display captions on native player:
+ if( embedPlayer.useNativePlayerControls() ){
+ return this;
+ }
+
+ // Load user preferences config:
+ var preferenceConfig = $.cookie( 'TimedText.Preferences' );
+ if( preferenceConfig !== "false" && preferenceConfig != null ) {
+ this.config = JSON.parse( preferenceConfig );
+ }
+ // remove any old bindings on change media:
+ $( this.embedPlayer ).bind( 'onChangeMedia' + this.bindPostFix , function(){
+ _this.destroy();
+ });
+
+ // Remove any old bindings before we add the current bindings:
+ _this.destroy();
+
+ // Add player bindings
+ _this.addPlayerBindings();
+ return this;
+ },
+ destroy: function(){
+ // remove any old player bindings;
+ $( this.embedPlayer ).unbind( this.bindPostFix );
+ // Clear out enabled sources:
+ this.enabledSources = [];
+ // Clear out text sources:
+ this.textSources = [];
+ },
+ /**
+ * Add timed text related player bindings
+ * @return
+ */
+ addPlayerBindings: function(){
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+
+ // Check for timed text support:
+ _this.addInterface();
+
+ $( embedPlayer ).bind( 'timeupdate' + this.bindPostFix, function( event, jEvent, id ) {
+ // regain scope
+ _this = $('#' + id)[0].timedText;
+ // monitor text updates
+ _this.monitor();
+ } );
+
+ $( embedPlayer ).bind( 'firstPlay' + this.bindPostFix, function(event, id ) {
+ // regain scope
+ _this = $('#' + id)[0].timedText;
+ // Will load and setup timedText sources (if not loaded already loaded )
+ _this.setupTextSources();
+ // Hide the caption menu if presently displayed
+ $( '#textMenuContainer_' + _this.embedPlayer.id ).hide();
+ } );
+
+ // Re-Initialize when changing media
+ $( embedPlayer ).bind( 'onChangeMedia' + this.bindPostFix, function() {
+ _this.destroy();
+ _this.updateLayout();
+ _this.setupTextSources();
+ $( '#textMenuContainer_' + embedPlayer.id ).hide();
+ } );
+
+ // Resize the timed text font size per window width
+ $( embedPlayer ).bind( 'onCloseFullScreen' + this.bindPostFix + ' onOpenFullScreen' + this.bindPostFix, function() {
+ // Check if we are in fullscreen or not, if so add an additional bottom offset of
+ // double the default bottom padding.
+ var textOffset = _this.embedPlayer.controlBuilder.inFullScreen ?
+ mw.config.get("TimedText.BottomPadding") * 2 :
+ mw.config.get("TimedText.BottomPadding");
+
+ var textCss = _this.getInterfaceSizeTextCss({
+ 'width' : embedPlayer.getInterface().width(),
+ 'height' : embedPlayer.getInterface().height()
+ });
+
+ mw.log( 'TimedText::set text size for: : ' + embedPlayer.getInterface().width() + ' = ' + textCss['font-size'] );
+ if ( embedPlayer.controlBuilder.isOverlayControls() && !embedPlayer.getInterface().find( '.control-bar' ).is( ':hidden' ) ) {
+ textOffset += _this.embedPlayer.controlBuilder.getHeight();
+ }
+ embedPlayer.getInterface().find( '.track' )
+ .css( textCss )
+ .css({
+ // Get the text size scale then set it to control bar height + TimedText.BottomPadding;
+ 'bottom': textOffset + 'px'
+ });
+ });
+
+ // Update the timed text size
+ $( embedPlayer ).bind( 'updateLayout'+ this.bindPostFix, function() {
+ // If the the player resize action is an animation, animate text resize,
+ // else instantly adjust the css.
+ var textCss = _this.getInterfaceSizeTextCss( {
+ 'width': embedPlayer.getPlayerWidth(),
+ 'height': embedPlayer.getPlayerHeight()
+ });
+ mw.log( 'TimedText::updateLayout: ' + textCss['font-size']);
+ embedPlayer.getInterface().find( '.track' ).css( textCss );
+ });
+
+ // Setup display binding
+ $( embedPlayer ).bind( 'onShowControlBar'+ this.bindPostFix, function(event, layout, id ){
+ // update embedPlayer ref:
+ var embedPlayer = $('#' + id )[0];
+ if ( embedPlayer.controlBuilder.isOverlayControls() ) {
+ // Move the text track if present
+ embedPlayer.getInterface().find( '.track' )
+ .stop()
+ .animate( layout, 'fast' );
+ }
+ });
+
+ $( embedPlayer ).bind( 'onHideControlBar' + this.bindPostFix, function(event, layout, id ){
+ var embedPlayer = $('#' + id )[0];
+ if ( embedPlayer.controlBuilder.isOverlayControls() ) {
+ // Move the text track down if present
+ embedPlayer.getInterface().find( '.track' )
+ .stop()
+ .animate( layout, 'fast' );
+ }
+ });
+
+ $( embedPlayer ).bind( 'AdSupport_StartAdPlayback' + this.bindPostFix, function() {
+ if ( $( '#textMenuContainer_' + embedPlayer.id ).length ) {
+ $( '#textMenuContainer_' + embedPlayer.id ).hide();
+ }
+ var $textButton = embedPlayer.getInterface().find( '.timed-text' );
+ if ( $textButton.length ) {
+ $textButton.unbind( 'click' );
+ }
+ _this.lastLayout = _this.getLayoutMode();
+ _this.setLayoutMode( 'off' );
+ } );
+
+ $( embedPlayer ).bind( 'AdSupport_EndAdPlayback' + this.bindPostFix, function() {
+ var $textButton = embedPlayer.getInterface().find( '.timed-text' );
+ if ( $textButton.length ) {
+ _this.bindTextButton( $textButton );
+ }
+ _this.setLayoutMode( _this.lastLayout );
+ } );
+
+ },
+ addInterface: function(){
+ var _this = this;
+ // By default we include a button in the control bar.
+ $( _this.embedPlayer ).bind( 'addControlBarComponent' + this.bindPostFix, function(event, controlBar ){
+ if( controlBar.supportedComponents['timedText'] !== false &&
+ _this.includeCaptionButton() ) {
+ controlBar.supportedComponents['timedText'] = true;
+ controlBar.components['timedText'] = _this.getTimedTextButton();
+ }
+ });
+ },
+ includeCaptionButton:function(){
+ return mw.config.get( 'TimedText.ShowInterface' ) == 'always' ||
+ this.embedPlayer.getTextTracks().length;
+ },
+ /**
+ * Get the current language key
+ * @return
+ * @type {string}
+ */
+ getCurrentLangKey: function(){
+ return this.currentLangKey;
+ },
+ /**
+ * Get the current language direction
+ * @return
+ * @type {string}
+ */
+ getCurrentLangDir: function(){
+ if ( !this.currentLangDir ) {
+ var source = this.getSourceByLanguage( this.getCurrentLangKey() );
+ this.currentLangDir = source.dir;
+ }
+ return this.currentLangDir;
+ },
+
+ /**
+ * The timed text button to be added to the interface
+ */
+ getTimedTextButton: function(){
+ var _this = this;
+ /**
+ * The closed captions button
+ */
+ return {
+ 'w': 30,
+ 'position': 6.9,
+ 'o': function( ctrlObj ) {
+ var $textButton = $( '<div />' )
+ .attr( 'title', mw.msg( 'mwe-embedplayer-timed_text' ) )
+ .addClass( "ui-state-default ui-corner-all ui-icon_link rButton timed-text" )
+ .append(
+ $( '<span />' )
+ .addClass( "ui-icon ui-icon-comment" )
+ )
+ // Captions binding:
+ .buttonHover();
+ _this.bindTextButton( $textButton );
+ return $textButton;
+
+ }
+ };
+ },
+ bindTextButton: function( $textButton ){
+ var _this = this;
+ $textButton.unbind('click.textMenu').bind('click.textMenu', function() {
+ _this.showTextMenu();
+ return true;
+ } );
+ },
+
+ /**
+ * Get the fullscreen text css
+ */
+ getInterfaceSizeTextCss: function( size ) {
+ //mw.log(' win size is: ' + $( window ).width() + ' ts: ' + textSize );
+ return {
+ 'font-size' : this.getInterfaceSizePercent( size ) + '%'
+ };
+ },
+
+ /**
+ * Show the text interface library and show the text interface near the player.
+ */
+ showTextMenu: function() {
+ var embedPlayer = this.embedPlayer;
+ var loc = embedPlayer.getInterface().find( '.rButton.timed-text' ).offset();
+ mw.log('TimedText::showTextMenu:: ' + embedPlayer.id + ' location: ', loc);
+ // TODO: Fix menu animation
+ var $menuButton = this.embedPlayer.getInterface().find( '.timed-text' );
+ // Check if a menu has already been built out for the menu button:
+ if ( $menuButton[0].m ) {
+ $menuButton.embedMenu( 'show' );
+ } else {
+ // Bind the text menu:
+ this.buildMenu( true );
+ }
+ },
+ getTextMenuContainer: function(){
+ var textMenuId = 'textMenuContainer_' + this.embedPlayer.id;
+ if( !$( '#' + textMenuId ).length ){
+ //Setup the menu:
+ this.embedPlayer.getInterface().append(
+ $('<div>')
+ .addClass('ui-widget ui-widget-content ui-corner-all')
+ .attr( 'id', textMenuId )
+ .css( {
+ 'position' : 'absolute',
+ 'height' : '180px',
+ 'width' : '180px',
+ 'font-size' : '12px',
+ 'display' : 'none',
+ 'overflow' : 'auto'
+ } )
+
+ );
+ }
+ return $( '#' + textMenuId );
+ },
+ /**
+ * Gets a text size percent relative to about 30 columns of text for 400
+ * pixel wide player, at 100% text size.
+ *
+ * @param size {object} The size of the target player area width and height
+ */
+ getInterfaceSizePercent: function( size ) {
+ // This is a ugly hack we should read "original player size" and set based
+ // on some standard ish normal 31 columns 15 rows
+ var sizeFactor = 4;
+ if( size.height / size.width < .7 ){
+ sizeFactor = 6;
+ }
+ var textSize = size.width / sizeFactor;
+ if( textSize < 95 ){
+ textSize = 95;
+ }
+ if( textSize > 150 ){
+ textSize = 150;
+ }
+ return textSize;
+ },
+
+ /**
+ * Setups available text sources
+ * loads text sources
+ * auto-selects a source based on the user language
+ * @param {Function} callback Function to be called once text sources are setup.
+ */
+ setupTextSources: function( callback ) {
+ mw.log( 'TimedText::setupTextSources');
+ var _this = this;
+ // Load textSources
+ _this.loadTextSources( function() {
+ // Enable a default source and issue a request to "load it"
+ _this.autoSelectSource();
+
+ // Load and parse the text value of enabled text sources:
+ _this.loadEnabledSources();
+
+ if( callback ) {
+ callback();
+ }
+ } );
+ },
+
+ /**
+ * Binds the timed text menu
+ * and updates its content from "getMainMenu"
+ *
+ * @param {Object} target to display the menu
+ * @param {Boolean} autoShow If the menu should be displayed
+ */
+ buildMenu: function( autoShow ) {
+ var _this = this;
+ var embedPlayer = this.embedPlayer;
+ // Setup text sources ( will callback inline if already loaded )
+ _this.setupTextSources( function() {
+ var $menuButton = _this.embedPlayer.getInterface().find( '.timed-text' );
+
+ var positionOpts = { };
+ if( _this.embedPlayer.supports[ 'overlays' ] ){
+ var positionOpts = {
+ 'directionV' : 'up',
+ 'offsetY' : _this.embedPlayer.controlBuilder.getHeight(),
+ 'directionH' : 'left',
+ 'offsetX' : -28
+ };
+ }
+
+ if( !_this.embedPlayer.getInterface() ){
+ mw.log("TimedText:: interface called before interface ready, just wait for interface");
+ return ;
+ }
+ var $menuButton = _this.embedPlayer.getInterface().find( '.timed-text' );
+ var ctrlObj = _this.embedPlayer.controlBuilder;
+ // NOTE: Button target should be an option or config
+ $menuButton.embedMenu( {
+ 'content' : _this.getMainMenu(),
+ 'zindex' : mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) + 2,
+ 'crumbDefaultText' : ' ',
+ 'autoShow': autoShow,
+ 'keepPosition' : true,
+ 'showSpeed': 0,
+ 'height' : 100,
+ 'width' : 300,
+ 'targetMenuContainer' : _this.getTextMenuContainer(),
+ 'positionOpts' : positionOpts,
+ 'backLinkText' : mw.msg( 'mwe-timedtext-back-btn' ),
+ 'createMenuCallback' : function(){
+ var $interface = _this.embedPlayer.getInterface();
+ var $textContainer = _this.getTextMenuContainer();
+ var textHeight = 130;
+ var top = $interface.height() - textHeight - ctrlObj.getHeight() - 6;
+ if( top < 0 ){
+ top = 0;
+ }
+ // check for audio
+ if( _this.embedPlayer.isAudio() ){
+ top = _this.embedPlayer.controlBuilder.getHeight() + 4;
+ }
+ $textContainer.css({
+ 'top' : top,
+ 'height': textHeight,
+ 'position' : 'absolute',
+ 'left': $menuButton[0].offsetLeft - 165,
+ 'bottom': ctrlObj.getHeight()
+ })
+ ctrlObj.showControlBar( true );
+ },
+ 'closeMenuCallback' : function(){
+ ctrlObj.restoreControlsHover();
+ }
+ });
+ });
+ },
+
+ /**
+ * Monitor video time and update timed text filed[s]
+ */
+ monitor: function() {
+ //mw.log(" timed Text monitor: " + this.enabledSources.length );
+ var embedPlayer = this.embedPlayer;
+ // Setup local reference to currentTime:
+ var currentTime = embedPlayer.currentTime;
+
+ // Get the text per kind
+ var textCategories = [ ];
+
+ var source = this.enabledSources[ 0 ];
+ if( source ) {
+ this.updateSourceDisplay( source, currentTime );
+ }
+ },
+
+ /**
+ * Load all the available text sources from the inline embed
+ * @param {Function} callback Function to call once text sources are loaded
+ */
+ loadTextSources: function( callback ) {
+ var _this = this;
+ // check if text sources are already loaded ( not em )
+ if( this.textSources.length ){
+ callback( this.textSources );
+ return ;
+ }
+ this.textSources = [];
+ // load inline text sources:
+ $.each( this.embedPlayer.getTextTracks(), function( inx, textSource ){
+ _this.textSources.push( new mw.TextSource( textSource ) );
+ });
+ // return the callback with sources
+ callback( _this.textSources );
+ },
+
+ /**
+ * Get the layout mode
+ *
+ * Takes into consideration:
+ * Playback method overlays support ( have to put subtitles below video )
+ *
+ */
+ getLayoutMode: function() {
+ // Re-map "ontop" to "below" if player does not support
+ if( this.config.layout == 'ontop' && !this.embedPlayer.supports['overlays'] ) {
+ this.config.layout = 'below';
+ }
+ return this.config.layout;
+ },
+
+ /**
+ * Auto selects a source given the local configuration
+ *
+ * NOTE: presently this selects a "single" source.
+ * In the future we could support multiple "enabled sources"
+ */
+ autoSelectSource: function() {
+ var _this = this;
+ // If a source is enabled then don't auto select
+ if ( this.enabledSources.length ) {
+ return false;
+ }
+ this.enabledSources = [];
+
+ var setDefault = false;
+ // Check if any source is marked default:
+ $.each( this.textSources, function(inx, source){
+ if( source['default'] ){
+ _this.enableSource( source );
+ setDefault = true;
+ return false;
+ }
+ });
+ if ( setDefault ) {
+ return true;
+ }
+
+ var setLocalPref = false;
+ // Check if any source matches our "local" pref
+ $.each( this.textSources, function(inx, source){
+ if( _this.config.userLanguage == source.srclang.toLowerCase()
+ &&
+ _this.config.userKind == source.kind
+ ) {
+ _this.enableSource( source );
+ setLocalPref = true;
+ return false;
+ }
+ });
+ if ( setLocalPref ) {
+ return true;
+ }
+
+ var setEnglish = false;
+ // If no userLang, source try enabling English:
+ if( this.enabledSources.length == 0 ) {
+ for( var i=0; i < this.textSources.length; i++ ) {
+ var source = this.textSources[ i ];
+ if( source.srclang.toLowerCase() == 'en' ) {
+ _this.enableSource( source );
+ setEnglish = true;
+ return false;
+ }
+ }
+ }
+ if ( setEnglish ) {
+ return true;
+ }
+
+ var setFirst = false;
+ // If still no source try the first source we get;
+ if( this.enabledSources.length == 0 ) {
+ for( var i=0; i < this.textSources.length; i++ ) {
+ var source = this.textSources[ i ];
+ _this.enableSource( source );
+ setFirst = true;
+ return false;
+ }
+ }
+ if ( setFirst ) {
+ return true;
+ }
+
+ return false;
+ },
+ /**
+ * Enable a source and update the currentLangKey
+ * @param {object} source
+ * @return
+ */
+ enableSource: function( source ){
+ var _this = this;
+ // check if we have any source set yet:
+ if( !_this.enabledSources.length ){
+ _this.enabledSources.push( source );
+ _this.currentLangKey = source.srclang;
+ _this.currentLangDir = null;
+ return ;
+ }
+ var sourceEnabled = false;
+ // Make sure the source is not already enabled
+ $.each( this.enabledSources, function( inx, enabledSource ){
+ if( source.id == enabledSource.id ){
+ sourceEnabled = true;
+ }
+ });
+ if ( !sourceEnabled ) {
+ _this.enabledSources.push( source );
+ _this.currentLangKey = source.srclang;
+ _this.currentLangDir = null;
+ }
+ },
+
+ /**
+ * Get the current source sub captions
+ * @param {function} callback function called once source is loaded
+ */
+ loadCurrentSubSource: function( callback ){
+ mw.log("loadCurrentSubSource:: enabled source:" + this.enabledSources.length);
+ for( var i =0; i < this.enabledSources.length; i++ ){
+ var source = this.enabledSources[i];
+ if( source.kind == 'SUB' ){
+ source.load( function(){
+ callback( source);
+ return ;
+ });
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Get sub captions by language key:
+ *
+ * @param {string} langKey Key of captions to load
+ * @pram {function} callback function called once language key is loaded
+ */
+ getSubCaptions: function( langKey, callback ){
+ for( var i=0; i < this.textSources.length; i++ ) {
+ var source = this.textSources[ i ];
+ if( source.srclang.toLowerCase() === langKey ) {
+ var source = this.textSources[ i ];
+ source.load( function(){
+ callback( source.captions );
+ });
+ }
+ }
+ },
+
+ /**
+ * Issue a request to load all enabled Sources
+ * Should be called anytime enabled Source list is updated
+ */
+ loadEnabledSources: function() {
+ var _this = this;
+ mw.log( "TimedText:: loadEnabledSources " + this.enabledSources.length );
+ $.each( this.enabledSources, function( inx, enabledSource ) {
+ // check if the source requires ovelray ( ontop ) layout mode:
+ if( enabledSource.isOverlay() && _this.config.layout== 'ontop' ){
+ _this.setLayoutMode( 'ontop' );
+ }
+ enabledSource.load(function(){
+ // Trigger the text loading event:
+ $( _this.embedPlayer ).trigger('loadedTextSource', enabledSource);
+ });
+ });
+ },
+ /**
+ * Checks if a source is "on"
+ * @return {Boolean}
+ * true if source is on
+ * false if source is off
+ */
+ isSourceEnabled: function( source ) {
+ // no source is "enabled" if subtitles are "off"
+ if( this.getLayoutMode() == 'off' ){
+ return false;
+ }
+ var isEnabled = false;
+ $.each( this.enabledSources, function( inx, enabledSource ) {
+ if( source.id ) {
+ if( source.id === enabledSource.id ){
+ isEnabled = true;
+ }
+ }
+ if( source.src ){
+ if( source.src == enabledSource.src ){
+ isEnabled = true;
+ }
+ }
+ });
+ return isEnabled;
+ },
+
+ /**
+ * Marks the active captions in the menu
+ */
+ markActive: function( source ) {
+ var $menu = $( '#textMenuContainer_' + this.embedPlayer.id );
+ if ( $menu.length ) {
+ var $captionRows = $menu.find( '.captionRow' );
+ if ( $captionRows.length ) {
+ $captionRows.each( function() {
+ $( this ).removeClass( 'ui-icon-bullet ui-icon-radio-on' );
+ var iconClass = ( $( this ).data( 'caption-id' ) === source.id ) ? 'ui-icon-bullet' : 'ui-icon-radio-on';
+ $( this ).addClass( iconClass );
+ } );
+ }
+ }
+ },
+
+ /**
+ * Marks the active layout mode in the menu
+ */
+ markLayoutActive: function ( layoutMode ) {
+ var $menu = $( '#textMenuContainer_' + this.embedPlayer.id );
+ if ( $menu.length ) {
+ var $layoutRows = $menu.find( '.layoutRow' );
+ if ( $layoutRows.length ) {
+ $layoutRows.each( function() {
+ $( this ).removeClass( 'ui-icon-bullet ui-icon-radio-on' );
+ var iconClass = ( $( this ).data( 'layoutMode' ) === layoutMode ) ? 'ui-icon-bullet' : 'ui-icon-radio-on';
+ $( this ).addClass( iconClass );
+ } );
+ }
+ }
+ },
+
+ /**
+ * Get a source object by language, returns "false" if not found
+ * @param {string} langKey The language key filter for selected source
+ */
+ getSourceByLanguage: function ( langKey ) {
+ for(var i=0; i < this.textSources.length; i++) {
+ var source = this.textSources[ i ];
+ if( source.srclang == langKey ){
+ return source;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Builds the core timed Text menu and
+ * returns the binded jquery object / dom set
+ *
+ * Assumes text sources have been setup: ( _this.setupTextSources() )
+ *
+ * calls a few sub-functions:
+ * Basic menu layout:
+ * Chose Language
+ * All Subtiles here ( if we have categories list them )
+ * Layout
+ * Below video
+ * Ontop video ( only available to supported plugins )
+ * TODO features:
+ * [ Search Text ]
+ * [ This video ]
+ * [ All videos ]
+ * [ Chapters ] seek to chapter
+ */
+ getMainMenu: function() {
+ var _this = this;
+
+ // Set the menut to avaliable languages:
+ var $menu = _this.getLanguageMenu();
+
+ if( _this.textSources.length == 0 ){
+ $menu.append(
+ $.getLineItem( mw.msg( 'mwe-timedtext-no-subs'), 'close' )
+ );
+ } else {
+ // Layout Menu option if not in an iframe and we can expand video size:
+ $menu.append(
+ $.getLineItem(
+ mw.msg( 'mwe-timedtext-layout-off'),
+ ( _this.getLayoutMode() == 'off' ) ? 'bullet' : 'radio-on',
+ function() {
+ _this.setLayoutMode( 'off' );
+ },
+ 'layoutRow',
+ { 'layoutMode' : 'off' }
+ )
+ )
+ }
+ // Allow other modules to add to the timed text menu:
+ $( _this.embedPlayer ).trigger( 'TimedText_BuildCCMenu', [ $menu, _this.embedPlayer.id ] ) ;
+
+ // Test if only one menu item move its children to the top level
+ if( $menu.children('li').length == 1 ){
+ $menu.find('li > ul > li').detach().appendTo( $menu );
+ $menu.find('li').eq(0).remove();
+ }
+
+ return $menu;
+ },
+
+ /**
+ * Utility function to assist in menu build out:
+ * Get menu line item (li) html: <li><a> msgKey </a></li>
+ *
+ * @param {String} msgKey Msg key for menu item
+ */
+
+ /**
+ * Get line item (li) from source object
+ * @param {Object} source Source to get menu line item from
+ */
+ getLiSource: function( source ) {
+ var _this = this;
+ //See if the source is currently "on"
+ var sourceIcon = ( this.isSourceEnabled( source ) )? 'bullet' : 'radio-on';
+ if( source.title ) {
+ return $.getLineItem( source.title, sourceIcon, function() {
+ _this.selectTextSource( source );
+ }, 'captionRow', { 'caption-id' : source.id } );
+ }
+ if( source.srclang ) {
+ var langKey = source.srclang.toLowerCase();
+ return $.getLineItem(
+ mw.msg('mwe-timedtext-key-language', langKey, _this.getLanguageName ( langKey ) ),
+ sourceIcon,
+ function() {
+ // select the current text source:
+ _this.selectTextSource( source );
+ },
+ 'captionRow',
+ { 'caption-id' : source.id }
+ );
+ }
+ },
+
+ /**
+ * Get language name from language key
+ * @param {String} lang_key Language key
+ */
+ getLanguageName: function( lang_key ) {
+ if( mw.Language.names[ lang_key ]) {
+ return mw.Language.names[ lang_key ];
+ }
+ return false;
+ },
+
+
+ /**
+ * set the layout mode
+ * @param {Object} layoutMode The selected layout mode
+ */
+ setLayoutMode: function( layoutMode ) {
+ var _this = this;
+ mw.log("TimedText:: setLayoutMode: " + layoutMode + ' ( old mode: ' + _this.config.layout + ' )' );
+ if( ( layoutMode != _this.config.layout ) || _this.firstLoad ) {
+ // Update the config and redraw layout
+ _this.config.layout = layoutMode;
+ // Update the display:
+ _this.updateLayout();
+ _this.firstLoad = false;
+ }
+ _this.markLayoutActive( layoutMode );
+ },
+
+ toggleCaptions: function(){
+ mw.log( "TimedText:: toggleCaptions was:" + this.config.layout );
+ if( this.config.layout == 'off' ){
+ this.setLayoutMode( this.defaultDisplayMode );
+ } else {
+ this.setLayoutMode( 'off' );
+ }
+ },
+ /**
+ * Updates the timed text layout ( should be called when config.layout changes )
+ */
+ updateLayout: function() {
+ mw.log( "TimedText:: updateLayout " );
+ var $playerTarget = this.embedPlayer.getInterface();
+ if( $playerTarget ) {
+ // remove any existing caption containers:
+ $playerTarget.find('.captionContainer,.captionsOverlay').remove();
+ }
+ this.refreshDisplay();
+ },
+
+ /**
+ * Select a new source
+ *
+ * @param {Object} source Source object selected
+ */
+ selectTextSource: function( source ) {
+ var _this = this;
+ mw.log("TimedText:: selectTextSource: select lang: " + source.srclang );
+
+ // enable last non-off layout:
+ _this.setLayoutMode( _this.lastLayout );
+
+ // For some reason we lose binding for the menu ~sometimes~ re-bind
+ this.bindTextButton( this.embedPlayer.getInterface().find('timed-text') );
+
+ this.currentLangKey = source.srclang;
+ this.currentLangDir = null;
+
+ // Update the config language if the source includes language
+ if( source.srclang ){
+ this.config.userLanguage = source.srclang;
+ }
+
+ if( source.kind ){
+ this.config.userKind = source.kind;
+ }
+
+ // (@@todo update kind & setup kind language buckets? )
+
+ // Remove any other sources selected in sources kind
+ this.enabledSources = [];
+
+ this.enabledSources.push( source );
+
+ // Set any existing text target to "loading"
+ if( !source.loaded ) {
+ var $playerTarget = this.embedPlayer.getInterface();
+ $playerTarget.find('.track').text( mw.msg('mwe-timedtext-loading-text') );
+ // Load the text:
+ source.load( function(){
+ // Refresh the interface:
+ _this.refreshDisplay();
+ });
+ } else {
+ _this.refreshDisplay();
+ }
+
+ _this.markActive( source );
+
+ // Trigger the event
+ $( this.embedPlayer ).trigger( 'TimedText_ChangeSource' );
+ },
+
+ /**
+ * Refresh the display, updates the timedText layout, menu, and text display
+ * also updates the cookie preference.
+ *
+ * Called after a user option change
+ */
+ refreshDisplay: function() {
+ // Update the configuration object
+ $.cookie( 'TimedText.Preferences', JSON.stringify( this.config ) );
+
+ // Empty out previous text to force an interface update:
+ this.prevText = [];
+
+ // Refresh the Menu (if it has a target to refresh)
+ mw.log( 'TimedText:: bind menu refresh display' );
+ this.buildMenu();
+ this.resizeInterface();
+
+ // add an empty catption:
+ this.displayTextTarget( $( '<span /> ').text( '') );
+
+ // Issues a "monitor" command to update the timed text for the new layout
+ this.monitor();
+ },
+
+ /**
+ * Builds the language source list menu
+ * Cehck if the "track" tags had the "kind" attribute.
+ *
+ * The kind attribute forms "categories" of text tracks like "subtitles",
+ * "audio description", "chapter names". We check for these categories
+ * when building out the language menu.
+ */
+ getLanguageMenu: function() {
+ var _this = this;
+
+ // See if we have categories to worry about
+ // associative array of SUB etc categories. Each kind contains an array of textSources.
+ var categorySourceList = {};
+ var sourcesWithCategoryCount = 0;
+
+ // ( All sources should have a kind (depreciate )
+ var sourcesWithoutCategory = [ ];
+ for( var i=0; i < this.textSources.length; i++ ) {
+ var source = this.textSources[ i ];
+ if( source.kind ) {
+ var categoryKey = source.kind ;
+ // Init Category menu item if it does not already exist:
+ if( !categorySourceList[ categoryKey ] ) {
+ // Set up catList pointer:
+ categorySourceList[ categoryKey ] = [];
+ sourcesWithCategoryCount++;
+ }
+ // Append to the source kind key menu item:
+ categorySourceList[ categoryKey ].push(
+ _this.getLiSource( source )
+ );
+ }else{
+ sourcesWithoutCategory.push( _this.getLiSource( source ) );
+ }
+ }
+ var $langMenu = $('<ul>');
+ // Check if we have multiple categories ( if not just list them under the parent menu item)
+ if( sourcesWithCategoryCount > 1 ) {
+ for(var categoryKey in categorySourceList) {
+ var $catChildren = $('<ul>');
+ for(var i=0; i < categorySourceList[ categoryKey ].length; i++) {
+ $catChildren.append(
+ categorySourceList[ categoryKey ][i]
+ );
+ }
+ // Append a cat menu item for each kind list
+ // Give grep a chance to find the usages:
+ // mwe-timedtext-textcat-cc, mwe-timedtext-textcat-sub, mwe-timedtext-textcat-tad,
+ // mwe-timedtext-textcat-ktv, mwe-timedtext-textcat-tik, mwe-timedtext-textcat-ar,
+ // mwe-timedtext-textcat-nb, mwe-timedtext-textcat-meta, mwe-timedtext-textcat-trx,
+ // mwe-timedtext-textcat-lrc, mwe-timedtext-textcat-lin, mwe-timedtext-textcat-cue
+ $langMenu.append(
+ $.getLineItem( mw.msg( 'mwe-timedtext-textcat-' + categoryKey.toLowerCase() ) ).append(
+ $catChildren
+ )
+ );
+ }
+ } else {
+ for(var categoryKey in categorySourceList) {
+ for(var i=0; i < categorySourceList[ categoryKey ].length; i++) {
+ $langMenu.append(
+ categorySourceList[ categoryKey ][i]
+ );
+ }
+ }
+ }
+ // Add any remaning sources that did nto have a category
+ for(var i=0; i < sourcesWithoutCategory.length; i++) {
+ $langMenu.append( sourcesWithoutCategory[i] );
+ }
+
+ return $langMenu;
+ },
+
+ /**
+ * Updates a source display in the interface for a given time
+ * @param {object} source Source to update
+ * @param {number} time Caption time used to add and remove active captions.
+ */
+ updateSourceDisplay: function ( source, time ) {
+ var _this = this;
+ if( this.timeOffset ){
+ time = time + parseInt( this.timeOffset );
+ }
+
+ // Get the source text for the requested time:
+ var activeCaptions = source.getCaptionForTime( time );
+ var addedCaption = false;
+ // Show captions that are on:
+ $.each( activeCaptions, function( capId, caption ){
+ var $cap = _this.embedPlayer.getInterface().find( '.track[data-capId="' + capId +'"]');
+ if( caption.content != $cap.html() ){
+ // remove old
+ $cap.remove();
+ // add the updated value:
+ _this.addCaption( source, capId, caption );
+ addedCaption = true;
+ }
+ });
+
+ // hide captions that are off:
+ _this.embedPlayer.getInterface().find( '.track' ).each(function( inx, caption){
+ if( !activeCaptions[ $( caption ).attr('data-capId') ] ){
+ if( addedCaption ){
+ $( caption ).remove();
+ } else {
+ $( caption ).fadeOut( mw.config.get('EmbedPlayer.MonitorRate'), function(){$(this).remove();} );
+ }
+ }
+ });
+ },
+ addCaption: function( source, capId, caption ){
+ if( this.getLayoutMode() == 'off' ){
+ return ;
+ }
+
+ // use capId as a class instead of id for easy selections and no conflicts with
+ // multiple players on page.
+ var $textTarget = $('<div />')
+ .addClass( 'track' )
+ .attr( 'data-capId', capId )
+ .hide();
+
+ // Update text ( use "html" instead of "text" so that subtitle format can
+ // include html formating
+ // TOOD we should scrub this for non-formating html
+ $textTarget.append(
+ $('<span>')
+ .addClass( 'ttmlStyled' )
+ .css( 'pointer-events', 'auto')
+ .css( this.getCaptionCss() )
+ .append(
+ $('<span>')
+ // Prevent background (color) overflowing TimedText
+ // http://stackoverflow.com/questions/9077887/avoid-overlapping-rows-in-inline-element-with-a-background-color-applied
+ .css( 'position', 'relative' )
+ .html( caption.content )
+ )
+ );
+
+
+ // Add/update the lang option
+ $textTarget.attr( 'lang', source.srclang.toLowerCase() );
+
+ // Update any links to point to a new window
+ $textTarget.find( 'a' ).attr( 'target', '_blank' );
+
+ // Add TTML or other complex text styles / layouts if we have ontop captions:
+ if( this.getLayoutMode() == 'ontop' ){
+ if( caption.css ){
+ $textTarget.css( caption.css );
+ } else {
+ $textTarget.css( this.getDefaultStyle() );
+ }
+ }
+ // Apply any custom style ( if we are ontop of the video )
+ this.displayTextTarget( $textTarget );
+
+ // apply any interface size adjustments:
+ $textTarget.css( this.getInterfaceSizeTextCss({
+ 'width' : this.embedPlayer.getInterface().width(),
+ 'height' : this.embedPlayer.getInterface().height()
+ })
+ );
+
+ // Update the style of the text object if set
+ if( caption.styleId ){
+ var capCss = source.getStyleCssById( caption.styleId );
+ $textTarget.find('span.ttmlStyled').css(
+ capCss
+ );
+ }
+ $textTarget.fadeIn('fast');
+ },
+ displayTextTarget: function( $textTarget ){
+ var embedPlayer = this.embedPlayer;
+ var $interface = embedPlayer.getInterface();
+ var controlBarHeight = embedPlayer.controlBuilder.getHeight();
+
+ if( this.getLayoutMode() == 'off' ){
+ // sync player size per audio player:
+ if( embedPlayer.isAudio() ){
+ $interface.find( '.overlay-win' ).css( 'top', controlBarHeight );
+ $interface.css( 'height', controlBarHeight );
+ }
+ return;
+ }
+
+ if( this.getLayoutMode() == 'ontop' ){
+ this.addTextOverlay(
+ $textTarget
+ );
+ } else if( this.getLayoutMode() == 'below' ){
+ this.addTextBelowVideo( $textTarget );
+ } else {
+ mw.log("Possible Error, layout mode not recognized: " + this.getLayoutMode() );
+ }
+
+ // sync player size per audio player:
+ if( embedPlayer.isAudio() && embedPlayer.getInterface().height() < 80 ){
+ $interface.find( '.overlay-win' ).css( 'top', 80);
+ $interface.css( 'height', 80 );
+
+ $interface.find('.captionsOverlay' )
+ .css('bottom', embedPlayer.controlBuilder.getHeight() )
+ }
+
+ },
+ getDefaultStyle: function(){
+ var defaultBottom = 15;
+ if( this.embedPlayer.controlBuilder.isOverlayControls() && !this.embedPlayer.getInterface().find( '.control-bar' ).is( ':hidden' ) ) {
+ defaultBottom += this.embedPlayer.controlBuilder.getHeight();
+ }
+ var baseCss = {
+ 'position':'absolute',
+ 'bottom': defaultBottom,
+ 'width': '100%',
+ 'display': 'block',
+ 'opacity': .8,
+ 'text-align': 'center'
+ };
+ baseCss =$.extend( baseCss, this.getInterfaceSizeTextCss({
+ 'width' : this.embedPlayer.getInterface().width(),
+ 'height' : this.embedPlayer.getInterface().height()
+ }));
+ return baseCss;
+ },
+ addTextOverlay: function( $textTarget ){
+ var _this = this;
+ var $captionsOverlayTarget = this.embedPlayer.getInterface().find('.captionsOverlay');
+ var layoutCss = {
+ 'left': 0,
+ 'top': 0,
+ 'bottom': 0,
+ 'right': 0,
+ 'position': 'absolute',
+ 'direction': this.getCurrentLangDir(),
+ 'z-index': mw.config.get( 'EmbedPlayer.FullScreenZIndex' )
+ };
+
+ if( $captionsOverlayTarget.length == 0 ){
+ // TODO make this look more like addBelowVideoCaptionsTarget
+ $captionsOverlayTarget = $( '<div />' )
+ .addClass( 'captionsOverlay' )
+ .css( layoutCss )
+ .css('pointer-events', 'none');
+ this.embedPlayer.getVideoHolder().append( $captionsOverlayTarget );
+ }
+ // Append the text:
+ $captionsOverlayTarget.append( $textTarget );
+
+ },
+ /**
+ * Applies the default layout for a text target
+ */
+ addTextBelowVideo: function( $textTarget ) {
+ var $playerTarget = this.embedPlayer.getInterface();
+ // Get the relative positioned player class from the controlBuilder:
+ this.embedPlayer.controlBuilder.keepControlBarOnScreen = true;
+ if( !$playerTarget.find('.captionContainer').length || this.embedPlayer.useNativePlayerControls() ) {
+ this.addBelowVideoCaptionContainer();
+ }
+ $playerTarget.find('.captionContainer').html(
+ $textTarget.css( {
+ 'color':'white'
+ } )
+ );
+ },
+ addBelowVideoCaptionContainer: function(){
+ var _this = this;
+ mw.log( "TimedText:: addBelowVideoCaptionContainer" );
+ var $playerTarget = this.embedPlayer.getInterface();
+ if( $playerTarget.find('.captionContainer').length ) {
+ return ;
+ }
+ // Append after video container
+ this.embedPlayer.getVideoHolder().after(
+ $('<div>').addClass( 'captionContainer block' )
+ .css({
+ 'width' : '100%',
+ 'height' : mw.config.get( 'TimedText.BelowVideoBlackBoxHeight' ) + 'px',
+ 'background-color' : '#000',
+ 'text-align' : 'center',
+ 'padding-top' : '5px'
+ } )
+ );
+
+ _this.embedPlayer.triggerHelper('updateLayout');
+ },
+ /**
+ * Resize the interface for layoutMode == 'below' ( if not in full screen)
+ */
+ resizeInterface: function(){
+ var _this = this;
+ if( !_this.embedPlayer.controlBuilder ){
+ // too soon
+ return ;
+ }
+ if( !_this.embedPlayer.controlBuilder.inFullScreen && _this.originalPlayerHeight ){
+ _this.embedPlayer.triggerHelper( 'resizeIframeContainer', [{'height' : _this.originalPlayerHeight}] );
+ } else {
+ // removed resize on container content, since syncPlayerSize calls now handle keeping player aspect.
+ _this.embedPlayer.triggerHelper('updateLayout');
+ }
+ },
+ /**
+ * Build css for caption using this.options
+ */
+ getCaptionCss: function() {
+ return {};
+ }
+ };
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.style.TimedText.css b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.style.TimedText.css
new file mode 100644
index 00000000..e924ba34
--- /dev/null
+++ b/extensions/TimedMediaHandler/MwEmbedModules/TimedText/resources/mw.style.TimedText.css
@@ -0,0 +1,18 @@
+.ttmlStyled {
+ color: white;
+ letter-spacing: 0.04em;
+ text-align: center;
+ padding: 0.2em;
+ /*
+ // Text shadow is too slow with current browsers use background-color
+ text-shadow:0 2px 1px #000000, -1px 3px 1px #000000, -2px 2px 1px #000000, -2px 1px 1px #000000, -2px 0 1px #000000, 2px 2px 1px #000000, 1px 2px 1px #000000, 0 -2px 1px #000000, 2px -2px 1px #000000, -2px -1px 1px #000000, -1px -3px 1px #000000, -3px -2px 1px #000000, 0 0 25px #000000, 0 0 35px #000000, 0 0 35px #000000, 0 0 31px #FFFFFF, 0 0 31px #FFFFFF, 0 0 31px #FFFFFF;
+ */
+ background-color: #333;
+}
+.ttmlStyled a {
+ text-decoration: none;
+ color : #BBF;
+}
+.ttmlStyled a:visited{
+ color : #BBF;
+}
diff --git a/extensions/TimedMediaHandler/README b/extensions/TimedMediaHandler/README
new file mode 100644
index 00000000..c37c5ad8
--- /dev/null
+++ b/extensions/TimedMediaHandler/README
@@ -0,0 +1,127 @@
+== TimedMediaHandler ==
+
+This extension provides a media handler for the Ogg, WebM, mp4 container format.
+When enabled, a player will be automatically embedded in the file description
+page, or any wiki page while still using the same syntax as for images.
+
+* Broad support for input file formats
+* Transcoder to make video at web resolutions when embedding clips in a page
+* include support for timed Text per the w3c "track" recommendation
+* use embedPlayer mwEmbed javascript module for playback
+
+To install this extension, add the following to the end of your
+LocalSettings.php:
+
+ // You need mwEmbedSupport ( if not already added )
+ require( "$IP/extensions/MwEmbedSupport/MwEmbedSupport.php" );
+
+ // TimedMediaHandler
+ require( "$IP/extensions/TimedMediaHandler/TimedMediaHandler.php" );
+
+
+== Running Transcodes ==
+
+Transcoding a video to another resolution or format takes a good amount which
+prevents that processing to be handled as a web service. Instead, the extension
+implements an asynchronous job, named webVideoTranscode, which you must be
+running regularly as your web server user.
+
+The job can be run using the MediaWiki maintenance/runJobs.php utility (do not
+forget to su as a webserver user):
+
+ php runJobs.php --type webVideoTranscode --maxjobs 1
+
+
+== Kaltura HTML5 player library ==
+
+TimedMediaHandler uses the Kaltura HTML5 player library for video playback, it
+relies on the <video> element as well as JavaScript.
+
+For more information about the player library visit:
+ http://www.html5video.org/kaltura-player/docs
+
+
+== Libav ==
+
+We use Libav for two purposes:
+ - creating still images of videos (aka thumbnails)
+ - transcoding WebM, H.264 videos
+
+Wikimedia currently uses libav as shipped in Ubuntu 12.04 (libav 0.8.x).
+For best experience use that or any later release from http://libav.org.
+
+On Ubuntu/Debian:
+ apt-get install libav-tools
+
+For H.264 support:
+ apt-get install libav-tools libavcodec-extra-53
+
+If you operating system does not include the required libav software,
+you can download static builds for multiple platforms at:
+ http://firefogg.org/nightly/
+
+You can also build libav/ffmpeg from source.
+Guide for building ffmpeg with H.264 for Ubuntu:
+https://ffmpeg.org/trac/ffmpeg/wiki/UbuntuCompilationGuide
+
+Some old versions of FFmpeg had a bug which made it extremely slow to seek in
+large theora videos in order to generate a thumbnail. If you are using an old
+version of FFmpeg and find that performance is extremely poor (tens of seconds)
+to generate thumbnails of theora videos that are several minutes or more in
+length. Please update to a more recent version.
+
+In MediaWiki configuration, after the require line in LocalSettings.php, you
+will have to specify the FFmpeg binary location with:
+
+ $wgFFmpegLocation = '/path/to/ffmpeg';
+
+Default being `/usr/bin/avconv`.
+
+
+== ffmpeg2theora ==
+
+We use ffmpeg2theora for extract metadata from videos, you will need a copy on
+your server. For best experience, use the latest release of ffmpeg2theora. At a
+minimum you need to use ffmpeg2thoera 0.27.
+
+You can download static ffmpeg2theora builds for multiple platforms at:
+http://firefogg.org/nightly/
+
+Set the ffmpeg2theora binary location with:
+
+ $wgFFmpeg2theoraLocation = '/path/to/ffmpeg2theora';
+
+Default being `/usr/bin/ffmpeg2theora`.
+
+oggThumb
+-------
+
+We use oggvideotools for creating still images of videos, you will need a copy on your
+server.
+
+Set the oggThumb binary location with:
+
+ $wgOggThumbLocation = '/path/to/oggThumb';
+
+Download oggThumb from: http://dev.streamnik.de/oggvideotools.html
+
+== PEAR File_Ogg ==
+
+Tim Starling, a Wikimedia developer, forked the PEAR File_Ogg package and
+improved it significantly to support this extension.
+
+The PEAR bundle is licensed under the LGPL, you can get informations about
+this package on the pear webpage:
+
+ http://pear.php.net/package/File_Ogg
+
+== getID3 ==
+
+getID3 is used for metadata of WebM files.
+
+getID3() by James Heinrich <info@getid3.org>
+available at http://getid3.sourceforge.net
+or http://www.getid3.org/
+
+getID3 code is released under the GNU GPL:
+http://www.gnu.org/copyleft/gpl.html
diff --git a/extensions/TimedMediaHandler/SpecialOrphanedTimedText.php b/extensions/TimedMediaHandler/SpecialOrphanedTimedText.php
new file mode 100644
index 00000000..52e86bf4
--- /dev/null
+++ b/extensions/TimedMediaHandler/SpecialOrphanedTimedText.php
@@ -0,0 +1,258 @@
+<?php
+/**
+ * Implements Special:OrphanedTimedText
+ *
+ * @author Brian Wolff
+ * @file
+ * @ingroup SpecialPage
+ */
+
+/**
+ * Lists TimedText pages that don't have a corresponding video.
+ *
+ * @ingroup SpecialPage
+ */
+class SpecialOrphanedTimedText extends PageQueryPage {
+
+ /** @var Array with keys being names of valid files */
+ private $existingFiles;
+
+ public function __construct( $name = 'OrphanedTimedText' ) {
+ parent::__construct( $name );
+ }
+
+ /**
+ * This is alphabetical, so sort ascending.
+ */
+ public function sortDescending() {
+ return false;
+ }
+
+ /**
+ * Should this be cached?
+ *
+ * This query is actually almost cheap given the current
+ * number of things in TimedText namespace.
+ */
+ public function isExpensive() {
+ return true;
+ }
+
+ /**
+ * Main execution function
+ *
+ * @param $par String subpage
+ */
+ public function execute( $par ) {
+ global $wgEnableLocalTimedText;
+
+ if ( !$wgEnableLocalTimedText ) {
+ $this->setHeaders();
+ $this->getOutput()->addWikiMsg( 'orphanedtimedtext-notimedtext' );
+ return;
+ } elseif ( !$this->canExecuteQuery() ) {
+ $this->setHeaders();
+ $this->outputHeader();
+ $this->getOutput()->addWikiMsg( 'orphanedtimedtext-unsupported' );
+ return;
+ }
+ return parent::execute( $par );
+ }
+
+ /**
+ * Can we cache the results of this query?
+ *
+ * Only if we support the query.
+ * @return bool
+ */
+ public function isCacheable() {
+ return $this->canExecute();
+ }
+
+ /**
+ * List in Special:SpecialPages?
+ *
+ * @return bool
+ */
+ public function isListed() {
+ return $this->canExecute();
+ }
+
+ /**
+ * Can we execute this special page?
+ *
+ * The query uses a mysql specific feature (substring_index), so disable on non mysql dbs.
+ *
+ * @return bool
+ */
+ private function canExecuteQuery() {
+ $dbr = wfGetDB( DB_SLAVE );
+ return $dbr->getType() === 'mysql';
+ }
+
+ /**
+ * Can we execute this special page
+ *
+ * That is, db is mysql, and TimedText namespace enabled.
+ */
+ private function canExecute() {
+ global $wgEnableLocalTimedText;
+
+ return $this->canExecuteQuery() && $wgEnableLocalTimedText;
+ }
+
+ /**
+ * Get query info
+ *
+ * The query here is meant to retrieve all pages in the TimedText namespace,
+ * such that if you strip the last two extensions (e.g. Foo.bar.baz.en.srt -> Foo.bar.baz)
+ * there is no corresponding img_name in image table. So if there is a page in TimedText
+ * namespace named TimedText:My.Dog.webm.ceb.srt, it will include it in the list provided
+ * that File:My.Dog.webm is not uploaded.
+ *
+ * TimedText does not support file redirects or foreign files, so we don't have
+ * to worry about those.
+ *
+ * Potentially this should maybe also include pages not ending in
+ * .<valid lang code>.srt . However, determining what a valid lang code
+ * is, is pretty hard (although perhaps it could check if its [a-z]{2,3}
+ * however then we've got things like roa-tara, cbk-zam, etc)
+ * and TimedText throws away the final .srt extension and will work with
+ * any extension, so things not ending in .srt arguably aren't oprhaned.
+ *
+ * @note This uses "substring_index" which is a mysql extension.
+ * @return Array Standard query info values.
+ */
+ function getQueryInfo() {
+ $tables = array( 'page', 'image' );
+ $fields = array(
+ 'namespace' => 'page_namespace',
+ 'title' => 'page_title',
+ 'value' => 0,
+ );
+ $conds = array(
+ 'img_name' => null,
+ 'page_namespace' => NS_TIMEDTEXT,
+ );
+
+ // Now for the complicated bit
+ // Note: This bit is mysql specific. Probably could do something
+ // equivalent in postgress via split_part or regex substr,
+ // but my sql-fu is not good enough to figure out how to do
+ // this in standard sql, or in sqlite.
+ $baseCond = 'substr( page_title, 1, length( page_title ) - '
+ . "length( substring_index( page_title, '.' ,-2 ) ) - 1 )";
+ $joinConds = array(
+ 'image' => array(
+ 'LEFT OUTER JOIN',
+ $baseCond . ' = img_name'
+ )
+ );
+ return array(
+ 'tables' => $tables,
+ 'fields' => $fields,
+ 'conds' => $conds,
+ 'join_conds' => $joinConds
+ );
+ }
+
+ public function getOrderFields() {
+ return array( 'namespace', 'title' );
+ }
+
+ /**
+ * Is the TimedText page really orphaned?
+ *
+ * Given a title like "TimedText:Some bit here.webm.en.srt"
+ * check to see if "File:Some bit here.webm" really exists (locally).
+ * @return bool True if we should cross out the line.
+ */
+ protected function existenceCheck( Title $title ) {
+ $fileTitle = $this->getCorrespondingFile( $title );
+ if ( !$fileTitle ) {
+ return $title && !$title->isKnown();
+ }
+ return !$title->isKnown() ||
+ ( isset( $this->existingFiles[ $fileTitle->getDBKey() ] )
+ && $this->existingFiles[$fileTitle->getDBKey()]->getHandler()
+ && $this->existingFiles[$fileTitle->getDBKey()]->getHandler() instanceof TimedMediaHandler );
+ }
+
+ /**
+ * Given a TimedText title, get the File title
+ *
+ * @return Title|null Title in File namespace. null on error.
+ */
+ private function getCorrespondingFile( Title $timedText ) {
+ if ( !$timedText ) {
+ return false;
+ }
+ $titleParts = explode( '.', $timedText->getDBkey() );
+ array_pop( $titleParts );
+ array_pop( $titleParts );
+ $fileTitle = Title::makeTitleSafe( NS_FILE, implode( '.', $titleParts ) );
+ return $fileTitle;
+ }
+
+ /**
+ * What group to include this page in on Special:SpecialPages
+ * @return String
+ */
+ protected function getGroupName() {
+ return 'media';
+ }
+
+ /**
+ * Preprocess result to do existence checks all at once.
+ *
+ * @param $db Database
+ * @param $res ResultWraper
+ */
+ public function preprocessResults( $db, $res ) {
+ parent::preprocessResults( $db, $res );
+
+ if ( !$res->numRows() ) {
+ return;
+ }
+
+ $filesToLookFor = array();
+ foreach( $res as $row ) {
+ $title = Title::makeTitle( $row->namespace, $row->title );
+ $fileTitle = $this->getCorrespondingFile( $title );
+ if ( !$fileTitle ) {
+ continue;
+ }
+ $filesToLookFor[] = array( 'title' => $fileTitle, 'ignoreRedirect' => true );
+ }
+ $this->existingFiles = RepoGroup::singleton()->getLocalRepo()->findFiles( $filesToLookFor );
+ $res->seek( 0 );
+ }
+
+ /**
+ * Format the result as a simple link to the page
+ *
+ * Based on parent class but with an existence check added.
+ *
+ * @param Skin $skin
+ * @param object $row Result row
+ * @return string
+ */
+ public function formatResult( $skin, $row ) {
+ global $wgContLang;
+
+ $title = Title::makeTitleSafe( $row->namespace, $row->title );
+
+ if ( $title instanceof Title ) {
+ $text = $wgContLang->convert( $title->getPrefixedText() );
+ $link = Linker::link( $title, htmlspecialchars( $text ) );
+ if ( $this->existenceCheck( $title ) ) {
+ // File got uploaded since this page was cached
+ $link = '<del>' . $link . '</del>';
+ }
+ return $link;
+ } else {
+ return Html::element( 'span', array( 'class' => 'mw-invalidtitle' ),
+ Linker::getInvalidTitleDescription( $this->getContext(), $row->namespace, $row->title ) );
+ }
+ }
+}
diff --git a/extensions/TimedMediaHandler/SpecialTimedMediaHandler.php b/extensions/TimedMediaHandler/SpecialTimedMediaHandler.php
new file mode 100644
index 00000000..46f2fef8
--- /dev/null
+++ b/extensions/TimedMediaHandler/SpecialTimedMediaHandler.php
@@ -0,0 +1,235 @@
+<?php
+/**
+ * Special:TimedMediaHandler
+ *
+ * Show some information about unprocessed jobs
+ *
+ * @file
+ * @ingroup SpecialPage
+ */
+
+class SpecialTimedMediaHandler extends SpecialPage {
+ private $transcodeStates = array(
+ 'active' => 'transcode_time_startwork IS NOT NULL AND transcode_time_success IS NULL AND transcode_time_error IS NULL',
+ 'failed' => 'transcode_error != "" AND transcode_time_success IS NULL',
+ 'queued' => 'transcode_time_startwork IS NULL AND transcode_time_success IS NULL AND transcode_time_error IS NULL',
+
+ );
+ private $formats = array(
+ 'ogg' => 'img_major_mime="application" AND img_minor_mime = "ogg"',
+ 'webm' => 'img_major_mime="video" AND img_minor_mime = "webm"',
+ );
+ private $audioFormats = array(
+ 'ogg' => 'img_major_mime="application" AND img_minor_mime = "ogg"',
+ 'webm' => 'img_major_mime="audio" AND img_minor_mime = "webm"',
+ 'flac' => 'img_major_mime="audio" AND img_minor_mime="x-flac"',
+ 'wav' => 'img_major_mime="audio" AND img_minor_mime="wav"',
+ );
+
+ public function __construct( $request = null, $par = null ) {
+ parent::__construct( 'TimedMediaHandler', 'transcode-status' );
+ }
+
+ public function execute( $par ) {
+ $this->setHeaders();
+ $out = $this->getOutput();
+
+ $out->addModuleStyles( 'mediawiki.special' );
+
+ $stats = $this->getStats();
+
+ foreach( array( 'audios', 'videos' ) as $type ) {
+ // for grep timedmedia-audios, timedmedia-videos
+ $out->addHTML(
+ "<h2>"
+ . $this->msg( 'timedmedia-' . $type )->numParams( $stats[$type]['total'] )->escaped()
+ . "</h2>"
+ );
+ // Give grep a chance to find the usages: timedmedia-ogg-videos, timedmedia-webm-videos,
+ // timedmedia-ogg-audios, timedmedia-flac-audios, timedmedia-wav-audios
+ $formats = $type == 'audios' ? $this->audioFormats : $this->formats;
+ foreach ( $formats as $format => $condition ) {
+ if ( $stats[ $type ][ $format ] ) {
+ $out->addHTML(
+ $this->msg( "timedmedia-$format-$type" )->numParams( $stats[ $type ][ $format ] )->escaped()
+ . Html::element( 'br' )
+ );
+ }
+ }
+ }
+
+ $states = $this->getStates();
+ $this->renderState( $out, 'transcodes', $states, false );
+ foreach ( $this->transcodeStates as $state => $condition ) {
+ $this->renderState( $out, $state, $states );
+ }
+ }
+
+ /**
+ * @param OutputPage $out
+ * @param $state
+ * @param $states
+ * @param bool $showTable
+ */
+ private function renderState ( $out, $state, $states, $showTable = true ) {
+ global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet;
+ $allTranscodes = array_merge( $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet );
+ if ( $states[ $state ][ 'total' ] ) {
+ // Give grep a chance to find the usages:
+ // timedmedia-derivative-state-transcodes, timedmedia-derivative-state-active,
+ // timedmedia-derivative-state-queued, timedmedia-derivative-state-failed
+ $out->addHTML(
+ "<h2>"
+ . $this->msg( 'timedmedia-derivative-state-' . $state )->numParams( $states[ $state ]['total'] )->escaped()
+ . "</h2>"
+ );
+ foreach( $allTranscodes as $key ) {
+ if ( isset( $states[ $state ] )
+ && isset( $states[ $state ][ $key ] )
+ && $states[ $state ][ $key ] ) {
+ $out->addHTML(
+ htmlspecialchars( $this->getLanguage()->formatNum( $states[ $state ][ $key ] ) )
+ . ' '
+ . $this->msg( 'timedmedia-derivative-desc-' . $key )->escaped()
+ . "<br>" );
+ }
+ }
+ if ( $showTable ) {
+ $out->addHTML( $this->getTranscodesTable( $state ) );
+ }
+ }
+ }
+
+ private function getTranscodes ( $state, $limit = 50 ) {
+ global $wgMemc;
+ $memcKey = wfMemcKey( 'TimedMediaHandler', 'files', $state );
+ $files = $wgMemc->get( $memcKey );
+ if ( !$files ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $files = array();
+ $res = $dbr->select(
+ 'transcode',
+ '*',
+ $this->transcodeStates[ $state ],
+ __METHOD__,
+ array( 'LIMIT' => $limit, 'ORDER BY' => 'transcode_time_error DESC' )
+ );
+ foreach( $res as $row ) {
+ $transcode = array();
+ foreach( $row as $k => $v ){
+ $transcode[ str_replace( 'transcode_', '', $k ) ] = $v;
+ }
+ $files[] = $transcode;
+ }
+ $wgMemc->add( $memcKey, $files, 60 );
+ }
+ return $files;
+ }
+
+ private function getTranscodesTable ( $state, $limit = 50 ) {
+ $table = '<table class="wikitable">' . "\n"
+ . '<tr>'
+ . '<th>' . $this->msg( 'timedmedia-transcodeinfo' )->escaped() . '</th>'
+ . '<th>' . $this->msg( 'timedmedia-file' )->escaped() . '</th>'
+ . '</tr>'
+ . "\n";
+
+ foreach( $this->getTranscodes( $state, $limit ) as $transcode ) {
+ $title = Title::newFromText( $transcode[ 'image_name' ], NS_FILE );
+ $table .= '<tr>'
+ . '<td>' . $this->msg('timedmedia-derivative-desc-' . $transcode[ 'key' ] )->escaped() . '</td>'
+ . '<td>' . Linker::link( $title, $transcode[ 'image_name' ] ) . '</td>'
+ . '</tr>'
+ . "\n";
+ }
+ $table .= '</table>';
+ return $table;
+ }
+
+ private function getStats() {
+ global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet, $wgMemc;
+ $allTranscodes = array_merge( $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet );
+
+ $memcKey= wfMemcKey( 'TimedMediaHandler', 'stats', '1' /* version */ );
+ $stats = $wgMemc->get( $memcKey );
+ if ( !$stats ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $stats = array();
+ $stats[ 'videos' ] = array( 'total' => 0 );
+ foreach( $this->formats as $format => $condition ) {
+ $stats[ 'videos' ][ $format ] = (int)$dbr->selectField(
+ 'image',
+ 'COUNT(*)',
+ 'img_media_type = "VIDEO" AND (' . $condition . ')',
+ __METHOD__
+ );
+ $stats[ 'videos' ][ 'total' ] += $stats[ 'videos' ][ $format ];
+ }
+ $stats[ 'audios' ] = array( 'total' => 0 );
+ foreach( $this->audioFormats as $format => $condition ) {
+ $stats[ 'audios' ][ $format ] = (int)$dbr->selectField(
+ 'image',
+ 'COUNT(*)',
+ 'img_media_type = "AUDIO" AND (' . $condition . ')',
+ __METHOD__
+ );
+ $stats[ 'audios' ][ 'total' ] += $stats[ 'audios' ][ $format ];
+ }
+ }
+ return $stats;
+ }
+
+ private function getStates() {
+ global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet, $wgMemc;
+ $allTranscodes = array_merge( $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet );
+
+ $memcKey = wfMemcKey( 'TimedMediaHandler', 'states' );
+ $states = $wgMemc->get( $memcKey );
+ if ( !$states ) {
+ $dbr = wfGetDB( DB_SLAVE );
+ $states = array();
+ $states[ 'transcodes' ] = array( 'total' => 0 );
+ foreach ( $this->transcodeStates as $state => $condition ) {
+ $states[ $state ] = array( 'total' => 0 );
+ foreach( $allTranscodes as $type ) {
+ // Important to pre-initialize, as can give
+ // warnings if you don't have a lot of things in transcode table.
+ $states[ $state ][ $type ] = 0;
+ }
+ }
+ foreach ( $this->transcodeStates as $state => $condition ) {
+ $cond = array( 'transcode_key' => $allTranscodes );
+ $cond[] = $condition;
+ $res = $dbr->select( 'transcode',
+ array('COUNT(*) as count', 'transcode_key'),
+ $cond,
+ __METHOD__,
+ array( 'GROUP BY' => 'transcode_key' )
+ );
+ foreach( $res as $row ) {
+ $key = $row->transcode_key;
+ $states[ $state ][ $key ] = $row->count;
+ $states[ $state ][ 'total' ] += $states[ $state ][ $key ];
+ }
+ }
+ $res = $dbr->select( 'transcode',
+ array( 'COUNT(*) as count', 'transcode_key' ),
+ array( 'transcode_key' => $allTranscodes ),
+ __METHOD__,
+ array( 'GROUP BY' => 'transcode_key' )
+ );
+ foreach( $res as $row ) {
+ $key = $row->transcode_key;
+ $states[ 'transcodes' ][ $key ] = $row->count;
+ $states[ 'transcodes' ][ $key ] -= $states[ 'queued' ][ $key ];
+ $states[ 'transcodes' ][ 'total' ] += $states[ 'transcodes' ][ $key ];
+ }
+ $wgMemc->add( $memcKey, $states, 60 );
+ }
+ return $states;
+ }
+
+ protected function getGroupName() {
+ return 'media';
+ }
+}
diff --git a/extensions/TimedMediaHandler/TimedMediaHandler.hooks.php b/extensions/TimedMediaHandler/TimedMediaHandler.hooks.php
new file mode 100644
index 00000000..70768479
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedMediaHandler.hooks.php
@@ -0,0 +1,485 @@
+<?php
+
+/**
+ * Hooks for TimedMediaHandler extension
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+class TimedMediaHandlerHooks {
+
+ // Register TimedMediaHandler namespace IDs
+ // These are configurable due to Commons history: T123823
+ // These need to be before registerhooks due to: T123695
+ public static function onSetupAfterCache() {
+ global $wgEnableLocalTimedText, $wgExtraNamespaces, $wgTimedTextNS;
+ if ( $wgEnableLocalTimedText ) {
+ define( "NS_TIMEDTEXT", $wgTimedTextNS );
+ define( "NS_TIMEDTEXT_TALK", $wgTimedTextNS +1 );
+
+ $wgExtraNamespaces[NS_TIMEDTEXT] = "TimedText";
+ $wgExtraNamespaces[NS_TIMEDTEXT_TALK] = "TimedText_talk";
+ } else {
+ $wgTimedTextNS = false;
+ }
+ return true;
+ }
+
+ // Register TimedMediaHandler Hooks
+ public static function register() {
+ global $wgHooks, $wgJobClasses, $wgJobTypesExcludedFromDefaultQueue, $wgMediaHandlers,
+ $wgResourceModules, $wgExcludeFromThumbnailPurge, $wgParserOutputHooks,
+ $wgFileExtensions, $wgTmhEnableMp4Uploads, $wgExtensionAssetsPath,
+ $wgMwEmbedModuleConfig, $timedMediaDir, $wgEnableLocalTimedText,
+ $wgTmhFileExtensions, $wgTmhTheoraTwoPassEncoding, $wgTmhWebPlayer;
+
+ // Remove mp4 if not enabled:
+ if( $wgTmhEnableMp4Uploads === false ){
+ $index = array_search( 'mp4', $wgFileExtensions );
+ if ( $index !== false ) {
+ array_splice( $wgFileExtensions, $index, 1 );
+ }
+ }
+
+ if( !class_exists( 'MwEmbedResourceManager' ) ) {
+ echo "TimedMediaHandler requires the MwEmbedSupport extension.\n";
+ exit( 1 );
+ }
+
+ // Register the Timed Media Handler javascript resources ( MwEmbed modules )
+ MwEmbedResourceManager::register( 'extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer' );
+ MwEmbedResourceManager::register( 'extensions/TimedMediaHandler/MwEmbedModules/TimedText' );
+
+ // Set the default webPath for this embed player extension
+ $wgMwEmbedModuleConfig['EmbedPlayer.WebPath'] = $wgExtensionAssetsPath .
+ '/' . basename ( $timedMediaDir ) . '/MwEmbedModules/EmbedPlayer';
+
+ // Setup media Handlers:
+ $wgMediaHandlers['application/ogg'] = 'OggHandlerTMH';
+ $wgMediaHandlers['audio/webm'] = 'WebMHandler';
+ $wgMediaHandlers['video/webm'] = 'WebMHandler';
+ $wgMediaHandlers['video/mp4'] = 'Mp4Handler';
+ $wgMediaHandlers['audio/x-flac'] = 'FLACHandler';
+ $wgMediaHandlers['audio/flac'] = 'FLACHandler';
+ $wgMediaHandlers['audio/wav'] = 'WAVHandler';
+
+ // Add transcode job class:
+ $wgJobClasses['webVideoTranscode'] = 'WebVideoTranscodeJob';
+
+ // Transcode jobs must be explicitly requested from the job queue:
+ $wgJobTypesExcludedFromDefaultQueue[] = 'webVideoTranscode';
+
+ $baseExtensionResource = array(
+ 'localBasePath' => __DIR__,
+ 'remoteExtPath' => 'TimedMediaHandler',
+ );
+
+ // Add the PopUpMediaTransform module ( specific to timedMedia handler ( no support in mwEmbed modules )
+ $wgResourceModules+= array(
+ 'mw.PopUpMediaTransform' => $baseExtensionResource + array(
+ 'scripts' => 'resources/mw.PopUpThumbVideo.js',
+ 'dependencies' => array( 'mw.MwEmbedSupport', 'mediawiki.Title' ),
+ ),
+ 'mw.PopUpMediaTransform.styles' => $baseExtensionResource + array(
+ 'position' => 'top',
+ 'styles' => 'resources/PopUpThumbVideo.css',
+ ),
+ 'mw.TMHGalleryHook.js' => $baseExtensionResource + array(
+ 'scripts' => 'resources/mw.TMHGalleryHook.js',
+ // position top needed as it needs to load before mediawiki.page.gallery
+ 'position' => 'top',
+ ),
+ 'embedPlayerIframeStyle'=> $baseExtensionResource + array(
+ 'styles' => 'resources/embedPlayerIframe.css',
+ ),
+ 'ext.tmh.transcodetable' => $baseExtensionResource + array(
+ 'scripts' => 'resources/ext.tmh.transcodetable.js',
+ 'styles' => 'resources/transcodeTable.css',
+ 'dependencies' => array(
+ 'mediawiki.api.edit',
+ 'mw.MwEmbedSupport',
+ ),
+ 'messages'=> array(
+ 'mwe-ok',
+ 'mwe-cancel',
+ 'timedmedia-reset-error',
+ 'timedmedia-reset',
+ 'timedmedia-reset-confirm'
+ )
+ ),
+ 'ext.tmh.TimedTextSelector' => $baseExtensionResource + array(
+ 'scripts' => 'resources/ext.tmh.TimedTextSelector.js',
+ ),
+ "mw.MediaWikiPlayerSupport" => $baseExtensionResource + array(
+ 'scripts' => 'resources/mw.MediaWikiPlayerSupport.js',
+ 'dependencies'=> 'mw.Api',
+ ),
+ // adds support MediaWikiPlayerSupport player bindings
+ "mw.MediaWikiPlayer.loader" => $baseExtensionResource + array(
+ 'loaderScripts' => 'resources/mw.MediaWikiPlayer.loader.js',
+ ),
+ );
+
+ // Add OgvJs-related modules for Safari/IE/Edge Ogg playback
+ $wgResourceModules += array(
+ 'ext.tmh.OgvJsSupport' => $baseExtensionResource + array(
+ 'scripts' => array(
+ 'MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-support.js',
+ 'resources/ext.tmh.OgvJsSupport.js',
+ ),
+ 'targets' => array( 'mobile', 'desktop' ),
+ ),
+ 'ext.tmh.OgvJs' => $baseExtensionResource + array(
+ 'scripts' => array(
+ 'MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv.js',
+ ),
+ 'dependencies' => 'ext.tmh.OgvJsSupport',
+ 'targets' => array( 'mobile', 'desktop' ),
+ ),
+ );
+
+ // Setup a hook for iframe embed handling:
+ $wgHooks['ArticleFromTitle'][] = 'TimedMediaIframeOutput::iframeHook';
+
+ // When an upload completes ( check clear any existing transcodes )
+ $wgHooks['UploadComplete'][] = 'TimedMediaHandlerHooks::checkUploadComplete';
+
+ // When an image page is moved:
+ $wgHooks['TitleMove'][] = 'TimedMediaHandlerHooks::checkTitleMove';
+
+ // When image page is deleted so that we remove transcode settings / files.
+ $wgHooks['FileDeleteComplete'][] = 'TimedMediaHandlerHooks::onFileDeleteComplete';
+
+ // Add parser hook
+ $wgParserOutputHooks['TimedMediaHandler'] = array( 'TimedMediaHandler', 'outputHook' );
+
+ // Use a BeforePageDisplay hook to load the styles in pages that pull in media dynamically.
+ // (Special:Upload, for example, when there is an "existing file" warning.)
+ $wgHooks['BeforePageDisplay'][] = 'TimedMediaHandlerHooks::pageOutputHook';
+
+ // Make sure modules are loaded on image pages that don't have a media file in the wikitext.
+ $wgHooks['ImageOpenShowImageInlineBefore'][] = 'TimedMediaHandlerHooks::onImageOpenShowImageInlineBefore';
+
+ // Exclude transcoded assets from normal thumbnail purging
+ // ( a maintenance script could handle transcode asset purging)
+ if ( isset( $wgExcludeFromThumbnailPurge ) ) {
+ $wgExcludeFromThumbnailPurge = array_merge( $wgExcludeFromThumbnailPurge, $wgTmhFileExtensions );
+ // Also add the .log file ( used in two pass encoding )
+ // ( probably should move in-progress encodes out of web accessible directory )
+ $wgExcludeFromThumbnailPurge[] = 'log';
+ }
+
+ $wgHooks['LoadExtensionSchemaUpdates'][] = 'TimedMediaHandlerHooks::loadExtensionSchemaUpdates';
+
+ // Add unit tests
+ $wgHooks['UnitTestsList'][] = 'TimedMediaHandlerHooks::registerUnitTests';
+
+ /**
+ * Add support for the "TimedText" NameSpace
+ */
+ if ( $wgEnableLocalTimedText ) {
+ // Check for timed text page:
+ $wgHooks[ 'ArticleFromTitle' ][] = 'TimedMediaHandlerHooks::checkForTimedTextPage';
+ $wgHooks[ 'ArticleContentOnDiff' ][] = 'TimedMediaHandlerHooks::checkForTimedTextDiff';
+ } else {
+ // overwrite TimedText.ShowInterface for video with mw-provider=local
+ $wgMwEmbedModuleConfig['TimedText.ShowInterface.local'] = 'off';
+ }
+
+ // Add transcode status to video asset pages:
+ $wgHooks[ 'ImagePageAfterImageLinks' ][] = 'TimedMediaHandlerHooks::checkForTranscodeStatus';
+ $wgHooks[ 'NewRevisionFromEditComplete' ][] = 'TimedMediaHandlerHooks::onNewRevisionFromEditComplete';
+ $wgHooks[ 'ArticlePurge' ][] = 'TimedMediaHandlerHooks::onArticlePurge';
+
+ $wgHooks['LoadExtensionSchemaUpdates'][] = 'TimedMediaHandlerHooks::checkSchemaUpdates';
+ $wgHooks['wgQueryPages'][] = 'TimedMediaHandlerHooks::onwgQueryPages';
+ return true;
+ }
+
+ /**
+ * @param $imagePage ImagePage
+ * @param $wgOut OutputPage
+ * @return bool
+ */
+ public static function onImageOpenShowImageInlineBefore( $imagePage, $out ) {
+ $handler = $imagePage->getDisplayedFile()->getHandler();
+ if ( $handler !== false && $handler instanceof TimedMediaHandler ) {
+ TimedMediaHandler::outputHook( $out, null, null );
+ }
+ return true;
+ }
+
+ /**
+ * @param $title Title
+ * @param $article Article
+ * @return bool
+ */
+ public static function checkForTimedTextPage( &$title, &$article ){
+ global $wgTimedTextNS;
+ if ( $title->getNamespace() === $wgTimedTextNS ) {
+ $article = new TimedTextPage( $title );
+ }
+ return true;
+ }
+
+ /**
+ * @param $diffEngine DifferenceEngine
+ * @param $output OutputPage
+ * @return bool
+ */
+ public static function checkForTimedTextDiff( $diffEngine, $output ) {
+ global $wgTimedTextNS;
+ if ( $output->getTitle()->getNamespace() === $wgTimedTextNS ) {
+ $article = new TimedTextPage( $output->getTitle() );
+ $article->renderOutput( $output );
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Wraps the isTranscodableFile function
+ * @param $title Title
+ * @return bool
+ */
+ public static function isTranscodableTitle( $title ){
+ if( $title->getNamespace() != NS_FILE ){
+ return false;
+ }
+ $file = wfFindFile( $title );
+ return self::isTranscodableFile( $file );
+ }
+
+ /**
+ * Utility function to check if a given file can be "transcoded"
+ * @param $file File object
+ * @return bool
+ */
+ public static function isTranscodableFile( & $file ){
+ global $wgEnableTranscode, $wgEnabledAudioTranscodeSet;
+
+ // don't show the transcode table if transcode is disabled
+ if( !$wgEnableTranscode && !$wgEnabledAudioTranscodeSet ){
+ return false;
+ }
+ // Can't find file
+ if( !$file ){
+ return false;
+ }
+ // We can only transcode local files
+ if( !$file->isLocal() ){
+ return false;
+ }
+
+ $handler = $file->getHandler();
+ // Not able to transcode files without handler
+ if( !$handler ) {
+ return false;
+ }
+ $mediaType = $handler->getMetadataType( $file );
+ // If ogg or webm format and not audio we can "transcode" this file
+ $isAudio = $handler instanceof TimedMediaHandler && $handler->isAudio( $file );
+ if( ( $mediaType == 'webm' || $mediaType == 'ogg' || $mediaType =='mp4' )
+ && !$isAudio
+ ){
+ return true;
+ }
+ if( $isAudio && count( $wgEnabledAudioTranscodeSet ) ) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param $article Article
+ * @param $html string
+ * @return bool
+ */
+ public static function checkForTranscodeStatus( $article, &$html ){
+ // load the file:
+ $file = wfFindFile( $article->getTitle() );
+ if( self::isTranscodableFile( $file ) ){
+ $html .= TranscodeStatusTable::getHTML( $file );
+ }
+ return true;
+ }
+
+ /**
+ * @param $image UploadBase
+ * @return bool
+ */
+ public static function checkUploadComplete( $upload ){
+ $file = $upload->getLocalFile();
+ // Check that the file is a transcodable asset:
+ if( $file && self::isTranscodableFile( $file ) ){
+ // Remove all the transcode files and db states for this asset
+ WebVideoTranscode::removeTranscodes( $file );
+ WebVideoTranscode::startJobQueue( $file );
+ }
+ return true;
+ }
+ /**
+ * Handle moved titles
+ *
+ * For now we just remove all the derivatives for the oldTitle. In the future we could
+ * look at moving the files, but right now thumbs are not moved, so I don't want to be
+ * inconsistent.
+ * @param $title Title
+ * @param $newTitle Title
+ * @param $user User
+ * @return bool
+ */
+ public static function checkTitleMove( $title, $newTitle, $user ){
+ if( self::isTranscodableTitle( $title ) ){
+ // Remove all the transcode files and db states for this asset
+ // ( will be re-added the first time the asset is displayed with its new title )
+ $file = wfFindFile( $title );
+ WebVideoTranscode::removeTranscodes( $file );
+ }
+ return true;
+ }
+
+ /**
+ * Hook to FileDeleteComplete
+ * remove transcodes on delete
+ * @param $file File
+ * @param $oldimage
+ * @param $article Article
+ * @param $user User
+ * @param $reason string
+ * @return bool
+ */
+ public static function onFileDeleteComplete( $file, $oldimage, $article, $user, $reason ) {
+ if ( !$oldimage ) {
+ if( self::isTranscodableFile( $file ) ){
+ WebVideoTranscode::removeTranscodes( $file );
+ }
+ }
+ return true;
+ }
+
+ /*
+ * If file gets reverted to a previous version, reset transcodes.
+ */
+ public static function onNewRevisionFromEditComplete( $article, Revision $rev, $baseID, User $user ) {
+ if ( $baseID !== false ) {
+ // Check if the article is a file and remove transcode files:
+ if( $article->getTitle()->getNamespace() == NS_FILE ) {
+ $file = wfFindFile( $article->getTitle() );
+ if( self::isTranscodableFile( $file ) ){
+ WebVideoTranscode::removeTranscodes( $file );
+ WebVideoTranscode::startJobQueue( $file );
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * When a user asks for a purge, perhaps through our handy "update transcode status"
+ * link, make sure we've got the updated set of transcodes. This'll allow a user or
+ * automated process to see their status and reset them.
+ */
+ public static function onArticlePurge( $article ) {
+ if( $article->getTitle()->getNamespace() == NS_FILE ) {
+ $file = wfFindFile( $article->getTitle() );
+ if( self::isTranscodableFile( $file ) ){
+ WebVideoTranscode::cleanupTranscodes( $file );
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Adds the transcode sql
+ * @param $updater DatabaseUpdater
+ * @return bool
+ */
+ public static function loadExtensionSchemaUpdates( $updater ){
+ $updater->addExtensionTable( 'transcode', __DIR__ . '/TimedMediaHandler.sql' );
+ return true;
+ }
+
+ /**
+ * Hook to add list of PHPUnit test cases.
+ * @param $files Array of files
+ * @return bool
+ */
+ public static function registerUnitTests( array &$files ) {
+ $testDir = __DIR__ . '/tests/phpunit/';
+ $testFiles = array(
+ 'TestTimeParsing.php',
+ 'TestApiUploadVideo.php',
+ 'TestVideoThumbnail.php',
+ 'TestVideoTranscode.php',
+ 'TestOggHandler.php',
+ 'TestTimedMediaTransformOutput.php',
+ 'TestTimedMediaHandler.php'
+ );
+ foreach( $testFiles as $fileName ){
+ $files[] = $testDir . $fileName;
+ }
+ return true;
+ }
+
+ /**
+ * Add JavaScript and CSS for special pages that may include timed media
+ * but which will not fire the parser hook.
+ *
+ * FIXME: There ought to be a better interface for determining whether the
+ * page is liable to contain timed media.
+ *
+ * @param $out OutputPage
+ * @param $sk
+ * @return bool
+ */
+ static function pageOutputHook( &$out, &$sk ){
+ global $wgTimedTextNS;
+
+ $title = $out->getTitle();
+ $namespace = $title->getNamespace();
+ $addModules = false;
+
+ if ( $namespace === NS_CATEGORY || $namespace === $wgTimedTextNS ) {
+ $addModules = true;
+ }
+
+ if ( $title->isSpecialPage() ) {
+ list( $name, /* subpage */ ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
+ if ( stripos( $name, 'file' ) !== false || stripos( $name, 'image' ) !== false
+ || $name === 'Search' || $name === 'GlobalUsage' ) {
+ $addModules = true;
+ }
+ }
+
+ if ( $addModules ) {
+ $out->addModuleScripts( 'mw.PopUpMediaTransform' );
+ $out->addModuleStyles( 'mw.PopUpMediaTransform.styles' );
+ }
+
+ return true;
+ }
+
+ public static function checkSchemaUpdates( DatabaseUpdater $updater ) {
+ $base = __DIR__ ;
+
+ switch ( $updater->getDB()->getType() ) {
+ case 'mysql':
+ case 'sqlite':
+ $updater->addExtensionTable( 'transcode', "$base/TimedMediaHandler.sql" ); // Initial install tables
+ $updater->addExtensionUpdate( array( 'addIndex', 'transcode', 'transcode_name_key',
+ "$base/archives/transcode_name_key.sql", true ) );
+ break;
+ case 'postgres':
+ //TODO
+ break;
+ }
+ return true;
+ }
+
+ public static function onwgQueryPages( $qp ) {
+ $qp[] = array( 'SpecialOrphanedTimedText', 'OrphanedTimedText' );
+ return true;
+ }
+}
diff --git a/extensions/TimedMediaHandler/TimedMediaHandler.i18n.alias.php b/extensions/TimedMediaHandler/TimedMediaHandler.i18n.alias.php
new file mode 100644
index 00000000..35c28ad8
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedMediaHandler.i18n.alias.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Aliases for special pages for extension TimedMediaHandler
+ *
+ * @file
+ * @ingroup Extensions
+ */
+// @codingStandardsIgnoreFile
+
+$specialPageAliases = array();
+
+/** English (English) */
+$specialPageAliases['en'] = array(
+ 'TimedMediaHandler' => array( 'TimedMediaHandler' ),
+ 'OrphanedTimedText' => array( 'OrphanedTimedText' ),
+);
+
+/** Arabic (العربية) */
+$specialPageAliases['ar'] = array(
+ 'TimedMediaHandler' => array( 'معالج_الميديا_الزمنية' ),
+ 'OrphanedTimedText' => array( 'نص_زمني_يتيم' ),
+);
+
+/** Egyptian Arabic (مصرى) */
+$specialPageAliases['arz'] = array(
+ 'TimedMediaHandler' => array( 'معالج_الميديا-الزمنيه' ),
+);
+
+/** German (Deutsch) */
+$specialPageAliases['de'] = array(
+ 'TimedMediaHandler' => array( 'TimedMedia-Steuerungsprogramm' ),
+ 'OrphanedTimedText' => array( 'Verwaister_TimedText' ),
+);
+
+/** Zazaki (Zazaki) */
+$specialPageAliases['diq'] = array(
+ 'TimedMediaHandler' => array( 'MısnayoğéMedyayaZemanın' ),
+);
+
+/** Estonian (eesti) */
+$specialPageAliases['et'] = array(
+ 'TimedMediaHandler' => array( 'Ajastatud_meediafailide_töötleja' ),
+);
+
+/** Hebrew (עברית) */
+$specialPageAliases['he'] = array(
+ 'TimedMediaHandler' => array( 'מדיה_מתוזמנת' ),
+ 'OrphanedTimedText' => array( 'טקסט_מתוזמן_יתום' ),
+);
+
+/** Korean (한국어) */
+$specialPageAliases['ko'] = array(
+ 'TimedMediaHandler' => array( '자막미디어핸들러' ),
+);
+
+/** Macedonian (македонски) */
+$specialPageAliases['mk'] = array(
+ 'TimedMediaHandler' => array( 'СинхронизираниСнимки' ),
+ 'OrphanedTimedText' => array( 'ОсамениСинхронизации' ),
+);
+
+/** Malayalam (മലയാളം) */
+$specialPageAliases['ml'] = array(
+ 'TimedMediaHandler' => array( 'സമയാധിഷ്ഠിതമീഡിയകൈകാര്യോപകരണം' ),
+);
+
+/** Vietnamese (Tiếng Việt) */
+$specialPageAliases['vi'] = array(
+ 'TimedMediaHandler' => array( 'Bộ_xử_lý_phương_tiện_đồng_bộ', 'Bộ_xử_lí_phương_tiện_đồng_bộ' ),
+);
+
+/** Simplified Chinese (中文(简体)‎) */
+$specialPageAliases['zh-hans'] = array(
+ 'TimedMediaHandler' => array( '定时媒体处理器' ),
+ 'OrphanedTimedText' => array( '孤立定时文本' ),
+); \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/TimedMediaHandler.i18n.magic.php b/extensions/TimedMediaHandler/TimedMediaHandler.i18n.magic.php
new file mode 100644
index 00000000..878ceb17
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedMediaHandler.i18n.magic.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Internationalisation file for extension TimedMediaHandler.
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+$magicWords = array();
+
+$magicWords['en'] = array(
+ 'timedmedia_noplayer' => array( 0, 'noplayer' ),
+ 'timedmedia_noicon' => array( 0, 'noicon' ),
+ 'timedmedia_thumbtime' => array( 0, 'thumbtime=$1' ),
+ 'timedmedia_starttime' => array( 0, 'start=$1'),
+ 'timedmedia_endtime' => array( 0, 'end=$1'),
+ 'timedmedia_disablecontrols' => array( 0, 'disablecontrols=$1'),
+);
+
+$magicWords['af'] = array(
+ 'timedmedia_noplayer' => array( '0', 'geenspeler', 'noplayer' ),
+ 'timedmedia_noicon' => array( '0', 'geenikoon', 'noicon' ),
+ 'timedmedia_starttime' => array( '0', 'begin=$1', 'start=$1' ),
+ 'timedmedia_endtime' => array( '0', 'einde=$1', 'end=$1' ),
+);
+
+$magicWords['ar'] = array(
+ 'timedmedia_noplayer' => array( '0', 'لابرنامج', 'noplayer' ),
+ 'timedmedia_noicon' => array( '0', 'لاأيقونة', 'noicon' ),
+ 'timedmedia_thumbtime' => array( '0', 'وقت_التصغير=$1', 'thumbtime=$1' ),
+ 'timedmedia_starttime' => array( '0', 'بداية=$1', 'start=$1' ),
+ 'timedmedia_endtime' => array( '0', 'نهاية=$1', 'end=$1' ),
+);
+
+$magicWords['arc'] = array(
+ 'timedmedia_starttime' => array( '0', 'ܫܘܪܝܐ=', 'start=$1' ),
+ 'timedmedia_endtime' => array( '0', 'ܫܘܠܡܐ=$1', 'end=$1' ),
+);
+
+$magicWords['arz'] = array(
+ 'timedmedia_noplayer' => array( '0', 'لابرنامج', 'noplayer' ),
+ 'timedmedia_noicon' => array( '0', 'لاأيقونة', 'noicon' ),
+ 'timedmedia_thumbtime' => array( '0', 'وقت_التصغير=$1', 'thumbtime=$1' ),
+ 'timedmedia_starttime' => array( '0', 'بداية=$1', 'start=$1' ),
+ 'timedmedia_endtime' => array( '0', 'نهاية=$1', 'end=$1' ),
+);
+
+$magicWords['ko'] = array(
+ 'timedmedia_starttime' => array( '0', '시작=$1', 'start=$1' ),
+ 'timedmedia_endtime' => array( '0', '끝=$1', 'end=$1' ),
+);
+
+$magicWords['ml'] = array(
+ 'timedmedia_noplayer' => array( '0', 'പ്ലേയറില്ല', 'noplayer' ),
+ 'timedmedia_noicon' => array( '0', 'ഐകോണില്ല', 'noicon' ),
+ 'timedmedia_thumbtime' => array( '0', 'ലഘുരൂപസമയം=$1', 'thumbtime=$1' ),
+ 'timedmedia_starttime' => array( '0', 'തുടങ്ങുക=$1', 'start=$1' ),
+ 'timedmedia_endtime' => array( '0', 'നിർത്തുക=$1', 'end=$1' ),
+);
+
+$magicWords['mr'] = array(
+ 'timedmedia_thumbtime' => array( '0', 'थंबटाइम=$1', 'इवलावेळ=$1', 'thumbtime=$1' ),
+ 'timedmedia_starttime' => array( '0', 'सुरवात=$1', 'start=$1' ),
+ 'timedmedia_endtime' => array( '0', 'शेवट=$1', 'end=$1' ),
+);
+
+$magicWords['nds-nl'] = array(
+ 'timedmedia_noplayer' => array( '0', 'gienspeuler', 'geenspeler', 'noplayer' ),
+ 'timedmedia_noicon' => array( '0', 'gienicoon', 'geenicoon', 'noicon' ),
+ 'timedmedia_thumbtime' => array( '0', 'miniatuurtied=$1', 'miniatuurtijd=$1', 'thumbtime=$1' ),
+ 'timedmedia_endtime' => array( '0', 'einde=$1', 'eind=$1', 'end=$1' ),
+);
+
+$magicWords['nl'] = array(
+ 'timedmedia_noplayer' => array( '0', 'geenspeler', 'noplayer' ),
+ 'timedmedia_noicon' => array( '0', 'geenicoon', 'noicon' ),
+ 'timedmedia_thumbtime' => array( '0', 'miniatuurtijd=$1', 'thumbtime=$1' ),
+ 'timedmedia_endtime' => array( '0', 'eind=$1', 'end=$1' ),
+);
+
+$magicWords['ru'] = array(
+ 'timedmedia_noplayer' => array( '0', 'нетпроигрывателя', 'noplayer' ),
+ 'timedmedia_noicon' => array( '0', 'нетзначка', 'noicon' ),
+ 'timedmedia_starttime' => array( '0', 'начало=$1', 'start=$1' ),
+ 'timedmedia_endtime' => array( '0', 'окончание=$1', 'end=$1' ),
+);
diff --git a/extensions/TimedMediaHandler/TimedMediaHandler.php b/extensions/TimedMediaHandler/TimedMediaHandler.php
new file mode 100644
index 00000000..2c032e6a
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedMediaHandler.php
@@ -0,0 +1,306 @@
+<?php
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ echo "This is the TimedMediaHandler extension. Please see the README file for installation instructions.\n";
+ exit( 1 );
+}
+
+// Set up the timed media handler dir:
+$timedMediaDir = __DIR__;
+// Include WebVideoTranscode (prior to config so that its defined transcode keys can be used in configuration)
+$wgAutoloadClasses['WebVideoTranscode'] = "$timedMediaDir/WebVideoTranscode/WebVideoTranscode.php";
+
+// Add the rest transcode right:
+$wgAvailableRights[] = 'transcode-reset';
+$wgAvailableRights[] = 'transcode-status';
+
+
+
+/*** MwEmbed module configuration: *********************************/
+
+// Show a warning to the user if they are not using an html5 browser with high quality ogg support
+$wgMwEmbedModuleConfig['EmbedPlayer.DirectFileLinkWarning'] = true;
+
+// Show the options menu:
+$wgMwEmbedModuleConfig['EmbedPlayer.EnableOptionsMenu'] = true;
+
+$wgMwEmbedModuleConfig['EmbedPlayer.DisableHTML5FlashFallback' ] = true;
+
+// The text interface should always be shown
+// ( even if there are no text tracks for that asset at render time )
+$wgMwEmbedModuleConfig['TimedText.ShowInterface'] = 'always';
+
+// Show the add text link:
+$wgMwEmbedModuleConfig['TimedText.ShowAddTextLink'] = true;
+
+/*** Timed Media Handler configuration ****************************/
+
+// Which users can restart failed or expired transcode jobs:
+$wgGroupPermissions['sysop']['transcode-reset'] = true;
+$wgGroupPermissions['autoconfirmed']['transcode-reset'] = true;
+
+// Which users can see Special:TimedMediaHandler
+$wgGroupPermissions['sysop']['transcode-status'] = true;
+
+// How long you have to wait between transcode resets for non-error transcodes
+$wgWaitTimeForTranscodeReset = 3600;
+
+// The minimum size for an embed video player ( smaller than this size uses a pop-up player )
+$wgMinimumVideoPlayerSize = 200;
+
+// Set the supported ogg codecs:
+$wgMediaVideoTypes = array( 'Theora', 'VP8' );
+$wgMediaAudioTypes = array( 'Vorbis', 'Speex', 'FLAC', 'Opus' );
+
+// Default skin for mwEmbed player
+$wgVideoPlayerSkinModule = 'mw.PlayerSkinKskin';
+
+// Support iframe for remote embedding
+$wgEnableIframeEmbed = true;
+
+// If transcoding is enabled for this wiki (if disabled, no transcode jobs are added and no
+// transcode status is displayed). Note if remote embedding an asset we will still check if
+// the remote repo has transcoding enabled and associated flavors for that media embed.
+$wgEnableTranscode = true;
+
+// If the job runner should run transcode commands in a background thread and monitor the
+// transcoding progress. This enables more fine grain control of the transcoding process, wraps
+// encoding commands in a lower priority 'nice' call, and kills long running transcodes that are
+// not making any progress. If set to false, the job runner will use the more compatible
+// php blocking shell exec command.
+$wgEnableNiceBackgroundTranscodeJobs = false;
+
+// The priority to be used with the nice transcode commands.
+$wgTranscodeBackgroundPriority = 19;
+
+// The total amout of time a transcoding shell command can take:
+$wgTranscodeBackgroundTimeLimit = 3600 * 8;
+// Maximum amount of virtual memory available to transcoding processes in KB
+$wgTranscodeBackgroundMemoryLimit = 2 * 1024 * 1024; // 2GB avconv, ffmpeg2theora mmap resources so virtual memory needs to be high enough
+// Maximum file size transcoding processes can create, in KB
+$wgTranscodeBackgroundSizeLimit = 3 * 1024 * 1024; // 3GB
+
+// Number of threads to use in avconv for transcoding
+$wgFFmpegThreads = 1;
+
+// The location of ffmpeg2theora (transcoding)
+// Set to false to use avconv/ffmpeg to produce Ogg Theora transcodes instead;
+// beware this will disable Ogg skeleton metadata generation.
+$wgFFmpeg2theoraLocation = '/usr/bin/ffmpeg2theora';
+
+// Location of oggThumb binary ( used instead of ffmpeg )
+$wgOggThumbLocation = '/usr/bin/oggThumb';
+
+// Location of the avconv/ffmpeg binary (used to encode WebM and for thumbnails)
+$wgFFmpegLocation = '/usr/bin/avconv';
+
+// The NS for TimedText (registered on MediaWiki.org)
+// http://www.mediawiki.org/wiki/Extension_namespace_registration
+// Note commons pre-dates TimedMediaHandler and should set $wgTimedTextNS = 102 in LocalSettings.php
+$wgTimedTextNS = 710;
+
+// Set TimedText namespace for ForeignDBViaLBRepo on a per wikiID basis
+// $wgTimedTextForeignNamespaces = array( 'commonswiki' => 102 );
+$wgTimedTextForeignNamespaces = array();
+
+// Set to false to disable local TimedText,
+// you still get subtitles for videos from foreign repos
+// to disable all TimedText, set
+// $wgMwEmbedModuleConfig['TimedText.ShowInterface'] = 'off';
+$wgEnableLocalTimedText = true;
+
+/**
+ * Default enabled transcodes
+ *
+ * -If set to empty array, no derivatives will be created
+ * -Derivative keys encode settings are defined in WebVideoTranscode.php
+ *
+ * -These transcodes are *in addition to* the source file.
+ * -Only derivatives with smaller width than the source asset size will be created
+ * -Regardless of source size at least one WebM and Ogg source will be created from the $wgEnabledTranscodeSet
+ * -Derivative jobs are added to the MediaWiki JobQueue the first time the asset is displayed
+ * -Derivative should be listed min to max
+ */
+$wgEnabledTranscodeSet = array(
+
+ // WebM VP8/Vorbis
+ // primary free/open video format
+ // supported by Chrome/Firefox/Opera but not Safari/IE/Edge
+
+ // Medium-bitrate web streamable WebM video
+ WebVideoTranscode::ENC_WEBM_360P,
+
+ // Moderate-bitrate web streamable WebM video
+ WebVideoTranscode::ENC_WEBM_480P,
+
+ // A high quality WebM stream
+ WebVideoTranscode::ENC_WEBM_720P,
+
+ // A full-HD high quality WebM stream
+ WebVideoTranscode::ENC_WEBM_1080P,
+
+ // A 4K full high quality WebM stream
+ // WebVideoTranscode::ENC_WEBM_2160P,
+
+
+ // Ogg Theora/Vorbis
+ // Fallback for Safari/IE/Edge with ogv.js
+ //
+ // Requires twice the bitrate for same quality as VP8,
+ // and JS decoder can be slow, so shift to smaller sizes.
+
+ // Low-bitrate Ogg stream
+ WebVideoTranscode::ENC_OGV_160P,
+
+ // Medium-bitrate Ogg stream
+ WebVideoTranscode::ENC_OGV_240P,
+
+ // Moderate-bitrate Ogg stream
+ WebVideoTranscode::ENC_OGV_360P,
+
+ // High-bitrate Ogg stream
+ WebVideoTranscode::ENC_OGV_480P,
+
+/*
+ // MP4 H.264/AAC
+ // Primary format for the Apple/Microsoft world
+ //
+ // Check patent licensing issues in your country before use!
+ // Similar to WebM in quality/bitrate
+
+ // A least common denominator h.264 stream; first gen iPhone, iPods, early android etc.
+ WebVideoTranscode::ENC_H264_320P,
+
+ // A mid range h.264 stream; mid range phones and low end tables
+ WebVideoTranscode::ENC_H264_480P,
+
+ // An high quality HD stream; higher end phones, tablets, smart tvs
+ WebVideoTranscode::ENC_H264_720P,
+
+ // A full-HD high quality stream; higher end phones, tablets, smart tvs
+ WebVideoTranscode::ENC_H264_1080P,
+
+ // A 4K high quality stream; higher end phones, tablets, smart tvs
+ WebVideoTranscode::ENC_H264_2160P,
+*/
+);
+
+$wgEnabledAudioTranscodeSet = array(
+ WebVideoTranscode::ENC_OGG_VORBIS,
+
+ //opus support must be available in avconv
+ //WebVideoTranscode::ENC_OGG_OPUS,
+
+ //avconv needs libmp3lame support
+ //WebVideoTranscode::ENC_MP3,
+
+ //avconv needs libvo_aacenc support
+ //WebVideoTranscode::ENC_AAC,
+);
+
+// If mp4 source assets can be ingested:
+$wgTmhEnableMp4Uploads = false;
+
+/******************* CONFIGURATION ENDS HERE **********************/
+
+
+// List of extensions handled by Timed Media Handler since its referenced in a few places.
+// you should not modify this variable
+
+$wgTmhFileExtensions = array( 'ogg', 'ogv', 'oga', 'flac', 'wav', 'webm', 'mp4' );
+
+$wgFileExtensions = array_merge( $wgFileExtensions, $wgTmhFileExtensions );
+
+// Timed Media Handler AutoLoad Classes:
+$wgAutoloadClasses['TimedMediaHandler'] = "$timedMediaDir/TimedMediaHandler_body.php";
+$wgAutoloadClasses['TimedMediaHandlerHooks'] = "$timedMediaDir/TimedMediaHandler.hooks.php";
+$wgAutoloadClasses['TimedMediaTransformOutput'] = "$timedMediaDir/TimedMediaTransformOutput.php";
+$wgAutoloadClasses['TimedMediaIframeOutput'] = "$timedMediaDir/TimedMediaIframeOutput.php";
+$wgAutoloadClasses['TimedMediaThumbnail'] = "$timedMediaDir/TimedMediaThumbnail.php";
+// Transcode Page
+$wgAutoloadClasses['TranscodeStatusTable'] = "$timedMediaDir/TranscodeStatusTable.php";
+
+// Testing:
+$wgAutoloadClasses['ApiTestCaseVideoUpload'] = "$timedMediaDir/tests/phpunit/ApiTestCaseVideoUpload.php";
+
+// Ogg Handler
+$wgAutoloadClasses['OggHandlerTMH'] = "$timedMediaDir/handlers/OggHandler/OggHandler.php";
+$wgAutoloadClasses['OggException'] = "$timedMediaDir/handlers/OggHandler/OggException.php";
+$wgAutoloadClasses['File_Ogg'] = "$timedMediaDir/handlers/OggHandler/File_Ogg/File/Ogg.php";
+$wgAutoloadClasses['File_Ogg_Bitstream'] = "$timedMediaDir/handlers/OggHandler/File_Ogg/File/Ogg/Bitstream.php";
+$wgAutoloadClasses['File_Ogg_Flac'] = "$timedMediaDir/handlers/OggHandler/File_Ogg/File/Ogg/Flac.php";
+$wgAutoloadClasses['File_Ogg_Media'] = "$timedMediaDir/handlers/OggHandler/File_Ogg/File/Ogg/Media.php";
+$wgAutoloadClasses['File_Ogg_Opus'] = "$timedMediaDir/handlers/OggHandler/File_Ogg/File/Ogg/Opus.php";
+$wgAutoloadClasses['File_Ogg_Speex'] = "$timedMediaDir/handlers/OggHandler/File_Ogg/File/Ogg/Speex.php";
+$wgAutoloadClasses['File_Ogg_Theora'] = "$timedMediaDir/handlers/OggHandler/File_Ogg/File/Ogg/Theora.php";
+$wgAutoloadClasses['File_Ogg_Vorbis'] = "$timedMediaDir/handlers/OggHandler/File_Ogg/File/Ogg/Vorbis.php";
+
+// getID3 provides metadata for mp4 and webm files:
+$wgAutoloadClasses['getID3'] = "$timedMediaDir/libs/getid3/getid3.php";
+$wgAutoloadClasses['getid3_exception'] = "$timedMediaDir/libs/getid3/getid3.php";
+$wgAutoloadClasses['getid3_handler'] = "$timedMediaDir/libs/getid3/getid3.php";
+
+// ID3 Metadata Handler
+$wgAutoloadClasses['ID3Handler'] = "$timedMediaDir/handlers/ID3Handler/ID3Handler.php";
+// Mp4 / h264 Handler
+$wgAutoloadClasses['Mp4Handler'] = "$timedMediaDir/handlers/Mp4Handler/Mp4Handler.php";
+// WebM Handler
+$wgAutoloadClasses['WebMHandler'] = "$timedMediaDir/handlers/WebMHandler/WebMHandler.php";
+// FLAC Handler
+$wgAutoloadClasses['FLACHandler'] = "$timedMediaDir/handlers/FLACHandler/FLACHandler.php";
+// WAV Handler
+$wgAutoloadClasses['WAVHandler'] = "$timedMediaDir/handlers/WAVHandler/WAVHandler.php";
+
+// Text handler
+$wgAutoloadClasses['ForeignApiQueryAllPages'] = "$timedMediaDir/handlers/TextHandler/TextHandler.php";
+$wgAutoloadClasses['TextHandler'] = "$timedMediaDir/handlers/TextHandler/TextHandler.php";
+$wgAutoloadClasses['TimedTextPage'] = "$timedMediaDir/TimedTextPage.php";
+
+// Transcode support
+$wgAutoloadClasses['WebVideoTranscodeJob'] = "$timedMediaDir/WebVideoTranscode/WebVideoTranscodeJob.php";
+
+// API modules:
+$wgAutoloadClasses['ApiQueryVideoInfo'] = "$timedMediaDir/ApiQueryVideoInfo.php";
+$wgAPIPropModules['videoinfo'] = 'ApiQueryVideoInfo';
+
+$wgAutoloadClasses['ApiTranscodeStatus'] = "$timedMediaDir/ApiTranscodeStatus.php";
+$wgAPIPropModules['transcodestatus'] = 'ApiTranscodeStatus';
+
+$wgAutoloadClasses['ApiTranscodeReset'] = "$timedMediaDir/ApiTranscodeReset.php";
+$wgAPIModules['transcodereset'] = 'ApiTranscodeReset';
+
+// Localization
+$wgMessagesDirs['TimedMediaHandler'] = __DIR__ . '/i18n';
+$wgExtensionMessagesFiles['TimedMediaHandlerMagic'] = "$timedMediaDir/TimedMediaHandler.i18n.magic.php";
+$wgExtensionMessagesFiles['TimedMediaHandlerAliases'] = "$timedMediaDir/TimedMediaHandler.i18n.alias.php";
+// Inlcude module locationlizations
+$wgMessagesDirs['MwEmbed.EmbedPlayer'] = __DIR__ . '/MwEmbedModules/EmbedPlayer/i18n';
+$wgMessagesDirs['MwEmbed.TimedText'] = __DIR__ . '/MwEmbedModules/TimedText/i18n';
+
+// Special Pages
+$wgAutoloadClasses['SpecialTimedMediaHandler'] = "$timedMediaDir/SpecialTimedMediaHandler.php";
+$wgAutoloadClasses['SpecialOrphanedTimedText'] = "$timedMediaDir/SpecialOrphanedTimedText.php";
+
+// This way if you set a variable like $wgTimedTextNS in LocalSettings.php
+// after you include TimedMediaHandler we can still read the variable values
+// See also T123695 and T123823
+$wgHooks['SetupAfterCache'][] = 'TimedMediaHandlerHooks::onSetupAfterCache';
+
+// Register remaining Timed Media Handler hooks right after initial setup
+$wgExtensionFunctions[] = 'TimedMediaHandlerHooks::register';
+
+# add Special pages
+$wgSpecialPages['OrphanedTimedText'] = 'SpecialOrphanedTimedText';
+$wgSpecialPages['TimedMediaHandler'] = 'SpecialTimedMediaHandler';
+
+// Extension Credits
+$wgExtensionCredits['media'][] = array(
+ 'path' => __FILE__,
+ 'name' => 'TimedMediaHandler',
+ 'namemsg' => 'extensionname-timedmedia',
+ 'author' => array( 'Michael Dale', 'Tim Starling', 'James Heinrich', 'Jan Gerber', 'Brion Vibber' ),
+ 'url' => 'https://www.mediawiki.org/wiki/Extension:TimedMediaHandler',
+ 'descriptionmsg' => 'timedmedia-desc',
+ 'version' => '0.4.0',
+ 'license-name' => 'GPL-2.0+',
+);
diff --git a/extensions/TimedMediaHandler/TimedMediaHandler.sql b/extensions/TimedMediaHandler/TimedMediaHandler.sql
new file mode 100644
index 00000000..7bafe675
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedMediaHandler.sql
@@ -0,0 +1,19 @@
+-- TimedMediaHandler.sql
+-- 2011-04-05 <mdale@wikimedia.org>
+--
+CREATE TABLE /*_*/transcode (
+ transcode_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
+ transcode_image_name VARCHAR(255) NOT NULL,
+ transcode_key VARCHAR(48) NOT NULL,
+ transcode_error longtext NOT NULL,
+ transcode_time_addjob VARCHAR(14) NULL,
+ transcode_time_startwork VARCHAR(14) NULL,
+ transcode_time_success VARCHAR(14) NULL,
+ transcode_time_error VARCHAR(14) NULL,
+ transcode_final_bitrate INT NOT NULL
+) /*$wgDBTableOptions*/;
+
+CREATE INDEX /*i*/transcode_time_inx ON /*_*/transcode( transcode_time_addjob ,transcode_time_startwork , transcode_time_success, transcode_time_error );
+CREATE INDEX /*i*/transcode_key_idx ON /*_*/transcode( transcode_key );
+
+CREATE UNIQUE INDEX /*i*/transcode_name_key ON /*_*/transcode (transcode_image_name,transcode_key);
diff --git a/extensions/TimedMediaHandler/TimedMediaHandler_body.php b/extensions/TimedMediaHandler/TimedMediaHandler_body.php
new file mode 100644
index 00000000..cb689858
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedMediaHandler_body.php
@@ -0,0 +1,483 @@
+<?php
+
+class TimedMediaHandler extends MediaHandler {
+ static $magicDone = false;
+
+ /**
+ * @return bool
+ */
+ function isEnabled() {
+ return true;
+ }
+
+ /**
+ * Get an image size array like that returned by getimagesize(), or false if it
+ * can't be determined.
+ * @param $file File
+ * @param $path string
+ * @param $metadata bool
+ * @return array|bool
+ */
+ function getImageSize( $file, $path, $metadata = false ) {
+ /* override by handler */
+ return false;
+ }
+
+ /**
+ * Get the list of supported wikitext embed params
+ * @return array
+ */
+ function getParamMap() {
+ return array(
+ 'img_width' => 'width',
+ 'timedmedia_thumbtime' => 'thumbtime',
+ 'timedmedia_starttime' => 'start',
+ 'timedmedia_endtime' => 'end',
+ 'timedmedia_disablecontrols' => 'disablecontrols',
+ );
+ }
+
+ /**
+ * Validate a embed file parameters
+ *
+ * @param $name {String} Name of the param
+ * @param $value {Mixed} Value to validated
+ * @return bool
+ */
+ function validateParam( $name, $value ) {
+ if ( $name == 'thumbtime' || $name == 'start' || $name == 'end' ) {
+ if ( $this->parseTimeString( $value ) === false ) {
+ return false;
+ }
+ } elseif ( $name == 'disablecontrols' ) {
+ $values = explode( ',', $value);
+ foreach($values as $v) {
+ if ( !in_array( $v, array( 'options', 'timedText', 'fullscreen' ) ) ) {
+ return false;
+ }
+ }
+ } elseif( $name === 'width' || $name === 'height' ) {
+ return $value > 0;
+ }
+ return true;
+ }
+
+ /**
+ * TODO we should really have "$file" available here to validate the param string
+ * @param $params array
+ * @return string
+ */
+ function makeParamString( $params ) {
+ // Add the width param string ( same as images {width}px )
+ $paramString ='';
+ $paramString.= ( isset( $params['width'] ) )? $params['width'] . 'px' : '';
+ $paramString.= ( $paramString != '' )? '-' : '';
+
+ // Get the raw thumbTime from thumbtime or start param
+ if ( isset ( $params['thumbtime'] ) ) {
+ $thumbTime = $params['thumbtime'];
+ } elseif ( isset ( $params['start'] ) ) {
+ $thumbTime = $params['start'];
+ } else {
+ $thumbTime = false;
+ }
+
+ if ( $thumbTime !== false ) {
+ $time = $this->parseTimeString( $thumbTime );
+ if ( $time !== false ) {
+ return $paramString. 'seek=' . $time;
+ }
+ }
+
+ if ( !$paramString ) {
+ $paramString = 'mid';
+ }
+ return $paramString ;
+ }
+
+ /**
+ * Used by thumb.php to find url parameters
+ *
+ * @param $str string
+ * @return array|bool Array of thumbnail parameters, or false if string cannot be parsed
+ */
+ function parseParamString( $str ) {
+ $params = array();
+ if ( preg_match( '/^(mid|(\d*)px-)*(seek=([\d.]+))*$/', $str, $matches ) ) {
+ $size = $thumbtime = null;
+ if ( isset( $matches[2] ) ) {
+ $size = $matches[2];
+ }
+ if ( isset( $matches[4] ) ) {
+ $thumbtime = $matches[4];
+ }
+
+ if ( !is_null( $size ) && $size !== '' ) {
+ $params['width'] = (int) $size;
+ }
+ if ( !is_null( $thumbtime ) ) {
+ $params['thumbtime'] = (float) $thumbtime;
+ }
+ return $params; // valid thumbnail URL
+ } else {
+ // invalid parameter string
+ return false;
+ }
+ }
+
+ /**
+ * @param $image File
+ * @param $params array
+ * @return bool
+ */
+ function normaliseParams( $image, &$params ) {
+ $timeParam = array( 'thumbtime', 'start', 'end' );
+ // Parse time values if endtime or thumbtime can't be more than length -1
+ foreach($timeParam as $pn){
+ if ( isset( $params[$pn] ) && $params[$pn] !== false ) {
+ $length = $this->getLength( $image );
+ $time = $this->parseTimeString( $params[$pn] );
+ if ( $time === false ) {
+ return false;
+ } elseif ( $time > $length - 1 ) {
+ $params[$pn] = $length - 1;
+ } elseif ( $time <= 0 ) {
+ $params[$pn] = 0;
+ }
+ }
+ }
+
+ if ( $this->isAudio( $image ) ) {
+ // Assume a default for audio files
+ $size = array(
+ 'width' => 220,
+ 'height' => 23,
+ );
+ } else {
+ $size = array(
+ 'width' => $image->getWidth(),
+ 'height' => $image->getHeight(),
+ );
+ }
+ // Make sure we don't try and up-scale the asset:
+ if( isset( $params['width'] ) && (int)$params['width'] > $size['width'] ){
+ $params['width'] = $size['width'];
+ }
+
+ if ( isset( $params['height'] ) && $params['height'] != -1 ) {
+ if( $params['width'] * $size['height'] > $params['height'] * $size['width'] ) {
+ $params['width'] = self::fitBoxWidth( $size['width'], $size['height'], $params['height'] );
+ }
+ }
+ if ( isset( $params['width'] ) ) {
+ $params['height'] = File::scaleHeight( $size['width'], $size['height'], $params['width'] );
+ }
+
+ // Make sure start time is not > than end time
+ if( isset($params['start'])
+ && isset($params['end'] )
+ && $params['start'] !== false
+ && $params['end'] !== false
+ ) {
+ if ( $this->parseTimeString( $params['start'] ) > $this->parseTimeString( $params['end'] ) ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @param $parser Parser
+ * @param $file File
+ */
+ function parserTransformHook( $parser, $file ) {
+ $parserOutput = $parser->getOutput();
+ if ( isset( $parserOutput->hasTimedMediaTransform ) ) {
+ return ;
+ }
+ $parserOutput->hasTimedMediaTransform = true;
+ $parserOutput->addOutputHook( 'TimedMediaHandler' );
+ }
+
+ /**
+ * Parser output hook only adds the PopUpMediaTransform
+ *
+ * The core embedPlayer module is part of a "loaderScript" so it does not need to
+ * be registered here.
+ *
+ * TODO move core loader to on-page script as to not include it on all pages.
+ *
+ * @param $outputPage OutputPage
+ * @param $parserOutput
+ * @param $data
+ */
+ static function outputHook( $outputPage, $parserOutput, $data ) {
+ // Add the PopUpMediaTransform code
+ $outputPage->addModuleScripts( 'mw.PopUpMediaTransform' );
+ $outputPage->addModuleStyles( 'mw.PopUpMediaTransform.styles' );
+ $outputPage->addModules( 'mw.TMHGalleryHook.js' );
+ if ( $parserOutput ) {
+ // Not present when run from outputpage hooks, like File/Category etc...
+ $parserOutput->setExtensionData( 'mw_ext_TMH_hasTimedMediaTransform', true );
+ }
+ }
+
+ /**
+ * Utility functions
+ * @param $timeString
+ * @param $length
+ * @return bool|int
+ */
+ public static function parseTimeString( $timeString, $length = false ) {
+ $parts = explode( ':', $timeString );
+ $time = 0;
+ // Check for extra :s
+ if( count( $parts ) > 3 ){
+ return false;
+ }
+ for ( $i = 0; $i < count( $parts ); $i++ ) {
+ if ( !is_numeric( $parts[$i] ) ) {
+ return false;
+ }
+ $time += floatval( $parts[$i] ) * pow( 60, count( $parts ) - $i - 1 );
+ }
+
+ if ( $time < 0 ) {
+ wfDebug( __METHOD__.": specified negative time, using zero\n" );
+ $time = 0;
+ } elseif ( $length !== false && $time > $length - 1 ) {
+ wfDebug( __METHOD__.": specified near-end or past-the-end time {$time}s, using end minus 1s\n" );
+ $time = $length - 1;
+ }
+ return $time;
+ }
+
+ /**
+ * @static
+ * @param $timePassed
+ * @return string
+ */
+ public static function getTimePassedMsg( $timePassed ){
+ $t = array();
+ $t['days'] = floor($timePassed/60/60/24);
+ $t['hours'] = floor($timePassed/60/60)%24;
+ $t['minutes'] = floor($timePassed/60)%60;
+ $t['seconds'] = $timePassed%60;
+
+ foreach( $t as $k => $v ){
+ if($v == 0 ){
+ unset( $t[$k] );
+ } else {
+ // Give grep a chance to find the usages:
+ // timedmedia-days, timedmedia-hours, timedmedia-minutes,timedmedia-seconds
+ $t[$k] = wfMessage( 'timedmedia-' . $k, $v )->text();
+ }
+ }
+ if( count( $t ) == 0 ){
+ $t = array( wfMessage( 'timedmedia-seconds', 0 )->text() ) ;
+ }
+
+ global $wgLang;
+ return $wgLang->commaList( $t );
+ }
+
+ /**
+ * Converts seconds to Normal play time (NPT) time format:
+ * consist of hh:mm:ss.ms
+ * also see: http://www.ietf.org/rfc/rfc2326.txt section 3.6
+ *
+ * @param $time Number Seconds to be converted to npt time format
+ * @return bool|string
+ */
+ public static function seconds2npt( $time ){
+ if ( !is_numeric( $time ) ) {
+ wfDebug( __METHOD__.": trying to get npt time on NaN:" + $time);
+ return false;
+ }
+ if( $time < 0 ){
+ wfDebug( __METHOD__.": trying to time on negative value:" + $time);
+ return false;
+ }
+ $hours = floor( $time / 3600 );
+ $min = floor( ( $time / 60 ) % 60 );
+ $sec = ($time % 60 );
+ $ms = ( $time - round( $time, 3) != 0 ) ? '.' .( $time - round( $time, 3) ) : '';
+
+ return "{$hours}:{$min}:{$sec}{$ms}";
+ }
+
+ /**
+ * @param $metadata
+ * @return bool|mixed
+ */
+ function unpackMetadata( $metadata ) {
+ wfSuppressWarnings();
+ $unser = unserialize( $metadata );
+ wfRestoreWarnings();
+ if ( isset( $unser['version'] ) ) {
+ return $unser;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param $image
+ * @param $metadata
+ * @return bool
+ */
+ function isMetadataValid( $image, $metadata ) {
+ return $this->unpackMetadata( $metadata ) !== false;
+ }
+
+ /**
+ * @param $ext
+ * @param $mime
+ * @param null $params
+ * @return array
+ */
+ function getThumbType( $ext, $mime, $params = null ) {
+ return array( 'jpg', 'image/jpeg' );
+ }
+
+ /**
+ * checks if a given file is an audio file
+ * @param $file File
+ * @return bool
+ */
+ function isAudio( $file ){
+ return ( $file->getWidth() == 0 && $file->getHeight() == 0 );
+ }
+
+ /**
+ * @param $file File
+ * @param $dstPath String
+ * @param $dstUrl String
+ * @param $params array
+ * @param $flags int
+ * @return bool|MediaTransformError|MediaTransformOutput|TimedMediaTransformOutput
+ */
+ function doTransform( $file, $dstPath, $dstUrl, $params, $flags = 0 ) {
+ # Important or height handling is wrong.
+ if ( !$this->normaliseParams( $file, $params ) ) {
+ return new TransformParameterError( $params );
+ }
+
+ $srcWidth = $file->getWidth();
+ $srcHeight = $file->getHeight();
+
+ // Audio should not be transformed by size, give it a default width and height
+ if( $this->isAudio( $file ) ){
+ $srcWidth = 220;
+ $srcHeight = 23;
+ }
+
+ $params['width'] = isset( $params['width'] ) ? $params['width'] : $srcWidth;
+
+ // if height overtakes width use height as max:
+ $targetWidth = $params['width'];
+ $targetHeight = $srcWidth == 0 ? $srcHeight : round( $params['width'] * $srcHeight / $srcWidth );
+ if( isset( $params['height'] ) && $targetHeight > $params['height'] ){
+ $targetHeight = $params['height'];
+ $targetWidth = round( $params['height'] * $srcWidth / $srcHeight );
+ }
+ $options = array(
+ 'file' => $file,
+ 'length' => $this->getLength( $file ),
+ 'offset' => $this->getOffset( $file ),
+ 'width' => $targetWidth,
+ 'height' => $targetHeight,
+ 'isVideo' => !$this->isAudio( $file ),
+ 'thumbtime' => isset( $params['thumbtime'] ) ? $params['thumbtime'] : intval( $file->getLength() / 2 ),
+ 'start' => isset( $params['start'] ) ? $params['start'] : false,
+ 'end' => isset( $params['end'] ) ? $params['end'] : false,
+ 'fillwindow' => isset( $params['fillwindow'] ) ? $params['fillwindow'] : false,
+ 'disablecontrols' => isset ( $params['disablecontrols'] ) ? $params['disablecontrols'] : false
+ );
+
+ // No thumbs for audio
+ if( !$options['isVideo'] ){
+ return new TimedMediaTransformOutput( $options );
+ }
+
+ // Setup pointer to thumb arguments
+ $options[ 'thumbUrl' ] = $dstUrl;
+ $options[ 'dstPath' ] = $dstPath;
+ $options[ 'path' ] = $dstPath;
+
+ // Check if transform is deferred:
+ if ( $flags & self::TRANSFORM_LATER ) {
+ return new TimedMediaTransformOutput($options);
+ }
+
+ // Generate thumb:
+ $thumbStatus = TimedMediaThumbnail::get( $options );
+ if( $thumbStatus !== true ){
+ return $thumbStatus;
+ }
+
+ return new TimedMediaTransformOutput( $options );
+ }
+
+ /**
+ * @param $file
+ * @return bool
+ */
+ function canRender( $file ) { return true; }
+
+ /**
+ * @param $file
+ * @return bool
+ */
+ function mustRender( $file ) { return true; }
+
+ /**
+ * Get a stream offset time
+ * @param $file
+ * @return int
+ */
+ function getOffset( $file ){
+ return 0;
+ }
+
+ /**
+ * Get length of a file
+ * @param $file
+ * @return int
+ */
+ function getLength( $file ){
+ return $file->getLength();
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getDimensionsString( $file ) {
+ global $wgLang;
+
+ if ( $file->getWidth() ) {
+ return wfMessage( 'video-dims', $wgLang->formatTimePeriod( $this->getLength( $file ) ) )
+ ->numParams( $file->getWidth(), $file->getHeight() )->text();
+ } else {
+ return $wgLang->formatTimePeriod( $this->getLength( $file ) );
+ }
+ }
+
+ public function filterThumbnailPurgeList( &$files, $options ) {
+ global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet;
+
+ $transcodeSet = array_merge($wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet);
+
+ //dont remove derivatives on normal purge
+ foreach(array_slice($files, 1) as $key => $file) {
+ foreach( $transcodeSet as $transcodeKey ) {
+ if ( preg_match('/' . preg_quote($transcodeKey) . '$/', $file) ) {
+ unset($files[$key]);
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/extensions/TimedMediaHandler/TimedMediaIframeOutput.php b/extensions/TimedMediaHandler/TimedMediaIframeOutput.php
new file mode 100644
index 00000000..a0e2920b
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedMediaIframeOutput.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * Adds iframe output ( bug 25862 )
+ *
+ * This enables iframe based embeds of the wikimeia player with the following syntax:
+ *
+ * <iframe src="http://commons.wikimedia.org/wiki/File:Folgers.ogv?embedplayer=yes"
+ * width="240" height="180" frameborder="0" ></iframe>
+ *
+ */
+
+class TimedMediaIframeOutput {
+ /**
+ * The iframe hook check file pages embedplayer=yes
+ * @param $title Title
+ * @param $article Article
+ * @param bool $doOutput
+ * @return bool
+ */
+ static function iframeHook( &$title, &$article, $doOutput = true ) {
+ global $wgRequest, $wgOut, $wgEnableIframeEmbed;
+ if( !$wgEnableIframeEmbed )
+ return true; //continue normal output iframes are "off" (maybe throw a warning in the future)
+
+ // Make sure we are in the right namespace and iframe=true was called:
+ if( is_object( $title ) && $title->getNamespace() == NS_FILE &&
+ $wgRequest->getVal('embedplayer') == 'yes' &&
+ $wgEnableIframeEmbed &&
+ $doOutput ){
+
+ if ( self::outputIframe( $title ) ) {
+ // Turn off output of anything other than the iframe
+ $wgOut->disable();
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Output an iframe
+ * @param $title Title
+ * @throws Exception
+ */
+ static function outputIframe( $title ) {
+ global $wgEnableIframeEmbed, $wgOut, $wgUser, $wgBreakFrames;
+
+ if( !$wgEnableIframeEmbed ){
+ return false;
+ }
+
+ // Setup the render parm
+ $file = wfFindFile( $title );
+ if ( !$file ) {
+ // file was removed, show wiki page with warning
+ return false;
+ }
+ $params = array(
+ 'fillwindow' => true
+ );
+ $videoTransform = $file->transform( $params );
+
+ // Definitely do not want to break frames
+ $wgBreakFrames = false;
+ $wgOut->allowClickjacking();
+
+ $wgOut->addModules( array( 'embedPlayerIframeStyle', 'mw.EmbedPlayer' ) );
+ $wgOut->sendCacheControl();
+ ?>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta charset="UTF-8" />
+<title><?php echo $title->getText() ?></title>
+ <?php
+ echo Html::element( 'meta', array( 'name' => 'ResourceLoaderDynamicStyles', 'content' => '' ) );
+ ?>
+ <?php
+ echo implode( "\n", $wgOut->getHeadLinksArray() );
+ echo implode( "\n", $wgOut->getHeadLinksArray() );
+ ?>
+ <style type="text/css">
+ html, body {
+ height: 100%;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ overflow:hidden;
+ }
+ img#bgimage {
+ position:fixed;
+ top:0;
+ left:0;
+ width:100%;
+ height:100%;
+ }
+ .videoHolder {
+ position:relative;
+ }
+ </style>
+ <?php echo $wgOut->getHeadScripts(); ?>
+ <script>
+ window.RLQ = window.RLQ || [];
+ window.RLQ.push( function() {
+ mw.loader.using( 'mw.MwEmbedSupport', function() {
+ mw.setConfig('EmbedPlayer.RewriteSelector', '');
+ } );
+ // Turn off rewrite selector. This prevents automatic conversion of
+ // <video> tags, since we are going to do that ourselves later.
+ } );
+ </script>
+ </head>
+<body>
+ <img src="<?php echo $videoTransform->getUrl() ?>" id="bgimage" ></img>
+ <div id="videoContainer" style="visibility:hidden">
+ <?php echo $videoTransform->toHtml(); ?>
+ </div>
+ <?php echo $wgOut->getBottomScripts(); ?>
+ <script>
+ window.RLQ.push( function() {
+ mw.loader.using( 'mw.MwEmbedSupport', function() {
+ // only enable fullscreen if enabled in iframe
+ mw.setConfig('EmbedPlayer.EnableFullscreen', document.fullscreenEnabled || document.webkitFullscreenEnabled || document.mozFullScreenEnabled || false );
+ $('#bgimage').remove();
+
+ mw.setConfig( 'EmbedPlayer.IsIframeServer', true );
+
+ // rewrite player
+ $( '#<?php echo TimedMediaTransformOutput::PLAYER_ID_PREFIX . '0' ?>' ).embedPlayer(function(){
+
+ // Bind window resize to reize the player:
+ var fitPlayer = function(){
+ $( '#<?php echo TimedMediaTransformOutput::PLAYER_ID_PREFIX . '0' ?>' )
+ [0].updateLayout();
+ }
+
+ $( window ).resize( fitPlayer );
+ $('#videoContainer').css({
+ 'visibility':'visible'
+ } );
+ fitPlayer();
+ } );
+ } );
+ } );
+ </script>
+</body>
+</html>
+ <?php
+ return true;
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/TimedMediaThumbnail.php b/extensions/TimedMediaHandler/TimedMediaThumbnail.php
new file mode 100644
index 00000000..77757440
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedMediaThumbnail.php
@@ -0,0 +1,240 @@
+<?php
+class TimedMediaThumbnail {
+
+ /**
+ * @param $options array()
+ * @return bool|MediaTransformError
+ */
+ static function get( $options ){
+ if( !is_dir( dirname( $options['dstPath'] ) ) ){
+ wfMkdirParents( dirname( $options['dstPath'] ), null, __METHOD__ );
+ }
+
+ wfDebug( "Creating video thumbnail at " . $options['dstPath'] . "\n" );
+ if(
+ isset( $options['width'] ) && isset( $options['height'] ) &&
+ $options['width'] != $options['file']->getWidth() &&
+ $options['height'] != $options['file']->getHeight()
+ ){
+ return self::resizeThumb( $options );
+ }
+ // try OggThumb, and fallback to ffmpeg
+ $result = self::tryOggThumb( $options );
+ if ( $result === false ) {
+ return self::tryFfmpegThumb( $options );
+ }
+ return $result;
+ }
+
+ /**
+ * Run oggThumb to generate a still image from a video file, using a frame
+ * close to the given number of seconds from the start.
+ *
+ * @param $options array
+ * @return bool|MediaTransformError
+ *
+ */
+ static function tryOggThumb( $options ) {
+ global $wgOggThumbLocation;
+
+ // Check that the file is 'ogg' format
+ if( $options['file']->getHandler()->getMetadataType( $options['file'] ) != 'ogg' ){
+ return false;
+ }
+
+ // Check for $wgOggThumbLocation
+ if( !$wgOggThumbLocation || !is_file( $wgOggThumbLocation ) ){
+ return false;
+ }
+
+ $time = self::getThumbTime( $options );
+ $dstPath = $options['dstPath'];
+ $videoPath = $options['file']->getLocalRefPath();
+
+ $cmd = wfEscapeShellArg( $wgOggThumbLocation )
+ . ' -t ' . floatval( $time );
+ // Set the output size if set in options:
+ if( isset( $options['width'] ) && isset( $options['height'] ) ){
+ $cmd.= ' -s '. intval( $options['width'] ) . 'x' . intval( $options['height'] );
+ }
+ $cmd .= ' -n ' . wfEscapeShellArg( $dstPath ) .
+ ' ' . wfEscapeShellArg( $videoPath ) . ' 2>&1';
+ $retval = 0;
+ $returnText = wfShellExec( $cmd, $retval );
+
+ if ( $options['file']->getHandler()->removeBadFile( $dstPath, $retval ) || $retval ) {
+ // oggThumb spams both stderr and stdout with useless progress
+ // messages, and then often forgets to output anything when
+ // something actually does go wrong. So interpreting its output is
+ // a challenge.
+ $lines = explode( "\n", str_replace( "\r\n", "\n", $returnText ) );
+ if ( count( $lines ) > 0
+ && preg_match( '/invalid option -- \'n\'$/', $lines[0] ) )
+ {
+ $returnText = wfMessage( 'timedmedia-oggThumb-version', '0.9' )->inContentLanguage()->text();
+ } else {
+ $returnText = wfMessage( 'timedmedia-oggThumb-failed' )->inContentLanguage()->text();
+ }
+ return new MediaTransformError( 'thumbnail_error',
+ $options['width'], $options['height'], $returnText );
+ }
+ return true;
+ }
+
+ /**
+ * @param $options array
+ * @return bool|MediaTransformError
+ */
+ static function tryFfmpegThumb( $options ){
+ global $wgFFmpegLocation, $wgMaxShellMemory;
+
+ if( !$wgFFmpegLocation || !is_file( $wgFFmpegLocation ) ){
+ return false;
+ }
+
+ $cmd = wfEscapeShellArg( $wgFFmpegLocation ) . ' -threads 1 ';
+
+ $offset = intval( self::getThumbTime( $options ) );
+ /*
+ This is a workaround until ffmpegs ogg demuxer properly seeks to keyframes.
+ Seek N seconds before offset and seek in decoded stream after that.
+ -ss before input seeks without decode
+ -ss after input seeks in decoded stream
+
+ N depends on framerate of input, keyframe interval defaults
+ to 64 for most encoders, seeking a bit before that
+ */
+
+ $framerate = $options['file']->getHandler()->getFramerate( $options['file'] );
+ if ( $framerate > 0 ) {
+ $seekoffset = 1 + intval( 64 / $framerate );
+ } else {
+ $seekoffset = 3;
+ }
+
+ if($offset > $seekoffset) {
+ $cmd .= ' -ss ' . floatval($offset - $seekoffset);
+ $offset = $seekoffset;
+ }
+
+ //try to get temorary local url to file
+ $backend = $options['file']->getRepo()->getBackend();
+ // getFileHttpUrl was only added in mw 1.21, dont fail if it does not exist
+ if ( method_exists( $backend, 'getFileHttpUrl' ) ) {
+ $src = $backend->getFileHttpUrl( array(
+ 'src' => $options['file']->getPath()
+ ) );
+ } else {
+ $src = null;
+ }
+ if ( $src == null ) {
+ $src = $options['file']->getLocalRefPath();
+ }
+
+ $cmd .= ' -y -i ' . wfEscapeShellArg( $src );
+ $cmd .= ' -ss ' . $offset . ' ';
+
+ // Set the output size if set in options:
+ if( isset( $options['width'] ) && isset( $options['height'] ) ){
+ $cmd.= ' -s '. intval( $options['width'] ) . 'x' . intval( $options['height'] );
+ }
+
+ # MJPEG, that's the same as JPEG except it's supported by the windows build of ffmpeg
+ # No audio, one frame
+ $cmd .= ' -f mjpeg -an -vframes 1 ' .
+ wfEscapeShellArg( $options['dstPath'] ) . ' 2>&1';
+
+ $retval = 0;
+ $returnText = wfShellExec( $cmd, $retval );
+ // Check if it was successful
+ if ( !$options['file']->getHandler()->removeBadFile( $options['dstPath'], $retval ) ) {
+ return true;
+ }
+ $returnText = $cmd . "\nwgMaxShellMemory: $wgMaxShellMemory\n" . $returnText;
+ // Return error box
+ return new MediaTransformError( 'thumbnail_error', $options['width'], $options['height'], $returnText );
+ }
+
+ /**
+ * @param $options array
+ * @return bool|MediaTransformError
+ */
+ static function resizeThumb( $options ) {
+ $file = $options['file'];
+ $params = array();
+ foreach( array( 'start', 'thumbtime' ) as $key ) {
+ if( isset( $options[ $key ] ) ) {
+ $params[ $key ] = $options[ $key ];
+ }
+ }
+ $params["width"] = $file->getWidth();
+ $params["height"] = $file->getHeight();
+
+ $poolKey = $file->getRepo()->getSharedCacheKey( 'file', md5( $file->getName() ) );
+ $posOptions = array_flip( array( 'start', 'thumbtime' ) );
+ $poolKey = wfAppendQuery( $poolKey, array_intersect_key( $options, $posOptions ) );
+
+ if ( class_exists( 'PoolCounterWorkViaCallback' ) ) {
+ $work = new PoolCounterWorkViaCallback( 'TMHTransformFrame',
+ '_tmh:frame:' . $poolKey,
+ array( 'doWork' => function() use ($file, $params) {
+ return $file->transform( $params, File::RENDER_NOW );
+ } ) );
+ $thumb = $work->execute();
+ } else {
+ $thumb = $file->transform( $params, File::RENDER_NOW );
+ }
+
+ if ( !$thumb || $thumb->isError() ) {
+ return $thumb;
+ }
+ $src = $thumb->getStoragePath();
+ if ( !$src ) {
+ return false;
+ }
+ $thumbFile = new UnregisteredLocalFile( $file->getTitle(),
+ RepoGroup::singleton()->getLocalRepo(), $src, false );
+ $thumbParams = array(
+ "width" => $options['width'],
+ "height" => $options['height']
+ );
+ $handler = $thumbFile->getHandler();
+ if ( !$handler ) {
+ return false;
+ }
+ $scaledThumb = $handler->doTransform(
+ $thumbFile,
+ $options['dstPath'],
+ $options['dstPath'],
+ $thumbParams
+ );
+
+ if ( !$scaledThumb || $scaledThumb->isError() ) {
+ return $scaledThumb;
+ }
+ return true;
+ }
+
+ /**
+ * @param $options array
+ * @return bool|float|int
+ */
+ static function getThumbTime( $options ){
+ $length = $options['file']->getLength();
+
+ // If start time param isset use that for the thumb:
+ if( isset( $options['start'] ) ) {
+ $thumbtime = TimedMediaHandler::parseTimeString( $options['start'], $length );
+ if( $thumbtime !== false )
+ return $thumbtime;
+ }
+ // else use thumbtime
+ if ( isset( $options['thumbtime'] ) ) {
+ $thumbtime = TimedMediaHandler::parseTimeString( $options['thumbtime'], $length );
+ if( $thumbtime !== false )
+ return $thumbtime;
+ }
+ // Seek to midpoint by default, it tends to be more interesting than the start
+ return $length / 2;
+ }
+}
diff --git a/extensions/TimedMediaHandler/TimedMediaTransformOutput.php b/extensions/TimedMediaHandler/TimedMediaTransformOutput.php
new file mode 100644
index 00000000..36532093
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedMediaTransformOutput.php
@@ -0,0 +1,486 @@
+<?php
+
+class TimedMediaTransformOutput extends MediaTransformOutput {
+ static $serial = 0;
+
+ // Video file sources object lazy init in getSources()
+ var $sources = null;
+ var $textTracks = null;
+ var $hashTime = null;
+ var $textHandler = null; // lazy init in getTextHandler
+ var $disablecontrols = null;
+
+ var $start, $end, $fillwindow;
+
+ // The prefix for player ids
+ const PLAYER_ID_PREFIX = 'mwe_player_';
+
+ function __construct( $conf ){
+ $options = array( 'file', 'dstPath', 'sources', 'thumbUrl', 'start', 'end',
+ 'width', 'height', 'length', 'offset', 'isVideo', 'path', 'fillwindow',
+ 'sources', 'disablecontrols' );
+ foreach ( $options as $key ) {
+ if( isset( $conf[ $key ]) ){
+ $this->$key = $conf[$key];
+ } else {
+ $this->$key = false;
+ }
+ }
+ }
+
+ /**
+ * @return TextHandler
+ */
+ function getTextHandler(){
+ if( !$this->textHandler ){
+ // Init an associated textHandler
+ $this->textHandler = new TextHandler( $this->file );
+ }
+ return $this->textHandler;
+ }
+
+ /**
+ * Get the media transform thumbnail
+ * @return string
+ */
+ function getUrl( $sizeOverride = false ){
+ global $wgVersion, $wgResourceBasePath, $wgStylePath;
+ // Needs to be 1.24c because version_compare() works in confusing ways
+ if ( version_compare( $wgVersion, '1.24c', '>=' ) ) {
+ $url = "$wgResourceBasePath/resources/assets/file-type-icons/fileicon-ogg.png";
+ } else {
+ $url = "$wgStylePath/common/images/icons/fileicon-ogg.png";
+ }
+
+ if ( $this->isVideo ) {
+ if ( $this->thumbUrl ) {
+ $url = $this->thumbUrl;
+ }
+
+ // Update the $posterUrl to $sizeOverride ( if not an old file )
+ if( !$this->file->isOld() && $sizeOverride &&
+ $sizeOverride[0] && intval( $sizeOverride[0] ) != intval( $this->width ) ){
+ $apiUrl = $this->getPoster( $sizeOverride[0] );
+ if( $apiUrl ){
+ $url = $apiUrl;
+ }
+ }
+ }
+ return $url;
+ }
+
+ /**
+ * TODO get the local path
+ * @return mixed
+ */
+ function getPath(){
+ return $this->dstPath;
+ }
+
+ /**
+ * @return int
+ */
+ function getPlayerHeight(){
+ // Check if "video" tag output:
+ if ( $this->isVideo ) {
+ return intval( $this->height );
+ } else {
+ // Give sound files a height of 23px
+ return 23;
+ }
+ }
+
+ /**
+ * @return int
+ */
+ function getPlayerWidth(){
+ // Check if "video" tag output:
+ if ( $this->isVideo ) {
+ return intval( $this->width );
+ } else {
+ // Give sound files a width of 300px ( if unsized )
+ if( $this->width == 0 ){
+ return 300;
+ }
+ // else give the target size down to 35 px wide
+ return ( $this->width < 35 ) ? 35 : intval( $this->width ) ;
+ }
+ }
+
+ /**
+ * @return string
+ */
+ function getTagName(){
+ return ( $this->isVideo ) ? 'video' : 'audio';
+ }
+
+ /**
+ * @param $options array
+ * @return string
+ * @throws Exception
+ */
+ function toHtml( $options = array() ) {
+ if ( count( func_get_args() ) == 2 ) {
+ throw new Exception( __METHOD__ .' called in the old style' );
+ }
+
+ $oldHeight = $this->height;
+ $oldWidth = $this->width;
+ if ( isset( $options['override-height'] ) ) {
+ $this->height = $options['override-height'];
+ }
+ if ( isset( $options['override-width'] ) ) {
+ $this->width = $options['override-width'];
+ }
+
+ if ( $this->useImagePopUp() ) {
+ $res = $this->getImagePopUp();
+ } else {
+ $res = $this->getHtmlMediaTagOutput();
+ }
+ $this->width = $oldWidth;
+ $this->height = $oldHeight;
+ return $res;
+ }
+
+ /**
+ * Helper to determine if to use pop up dialog for videos
+ *
+ * @return boolean
+ */
+ private function useImagePopUp() {
+ global $wgMinimumVideoPlayerSize;
+ // Check if the video is too small to play inline ( instead do a pop-up dialog )
+ // If we're filling the window (e.g. during an iframe embed) one probably doesn't want the pop up.
+ // Also the pop up is broken in that case.
+ return $this->isVideo
+ && !$this->fillwindow
+ && $this->getPlayerWidth() < $wgMinimumVideoPlayerSize
+ // Do not do pop-up if its going to be the same size as inline player anyways
+ && $this->getPlayerWidth() < $this->getPopupPlayerWidth();
+ }
+
+ /**
+ * XXX migrate this to the mediawiki Html class as 'tagSet' helper function
+ * @param $tagName
+ * @param $tagSet
+ * @return string
+ */
+ static function htmlTagSet( $tagName, $tagSet ){
+ if( empty( $tagSet ) ){
+ return '';
+ }
+ $s = '';
+ foreach( $tagSet as $attr ){
+ $s .= Html::element( $tagName, $attr);
+ }
+ return $s;
+ }
+
+ /**
+ * @return string
+ */
+ function getImagePopUp(){
+ // pop up videos set the autoplay attribute to true:
+ $autoPlay = true;
+ return Xml::tags( 'div' , array(
+ 'id' => self::PLAYER_ID_PREFIX . TimedMediaTransformOutput::$serial++,
+ 'class' => 'PopUpMediaTransform',
+ 'style' => "width:" . $this->getPlayerWidth() . "px;",
+ 'videopayload' => $this->getHtmlMediaTagOutput( $this->getPopupPlayerSize(), $autoPlay ),
+ ),
+ Xml::tags( 'img', array(
+ 'alt' => $this->file->getTitle(),
+ 'style' => "width:" . $this->getPlayerWidth() . "px;height:" .
+ $this->getPlayerHeight() . "px",
+ 'src' => $this->getUrl(),
+ ),'')
+ .
+ // For javascript disabled browsers provide a link to the asset:
+ Xml::tags( 'a', array(
+ 'href'=> $this->file->getUrl(),
+ 'title' => wfMessage( 'timedmedia-play-media' )->escaped(),
+ 'target' => 'new'
+ ),
+ Xml::tags( 'span', array(
+ 'class' => 'play-btn-large'
+ ),
+ // Have some sort of text for lynx & screen readers.
+ Html::element(
+ 'span',
+ array( 'class' => 'mw-tmh-playtext' ),
+ wfMessage( 'timedmedia-play-media' )->text()
+ )
+ )
+ )
+ );
+ }
+
+ /**
+ * Get target popup player size
+ */
+ function getPopupPlayerSize(){
+ // Get the max width from the enabled transcode settings:
+ $maxImageSize = WebVideoTranscode::getMaxSizeWebStream();
+ return WebVideoTranscode::getMaxSizeTransform( $this->file, $maxImageSize);
+ }
+
+ /**
+ * Helper function to get pop up width
+ *
+ * Silly function because array index operations aren't allowed
+ * on function calls before php 5.4
+ */
+ private function getPopupPlayerWidth() {
+ list( $popUpWidth ) = $this->getPopupPlayerSize();
+ return $popUpWidth;
+ }
+
+ /**
+ * Sort media by bandwidth, but with things not wide enough at end
+ *
+ * The list should be in preferred source order, so we want the file
+ * with the lowest bitrate (to save bandwidth) first, but we also want
+ * appropriate resolution files before the 160p transcodes.
+ */
+ private function sortMediaByBandwidth( $a, $b ) {
+ $width = $this->getPlayerWidth();
+ $maxWidth = $this->getPopupPlayerWidth();
+ if ( $this->useImagePopUp() || $width > $maxWidth ) {
+ // If its a pop-up player than we should use the pop up player size
+ // if its a normal player, but has a bigger width than the pop-up
+ // player, then we use the pop-up players width as the target width
+ // as that is equivalent to the max transcode size. Otherwise this
+ // will suggest the original file as the best source, which seems like
+ // a potentially bad idea, as it could be anything size wise.
+ $width = $maxWidth;
+ }
+
+ if ( $a['width'] < $width && $b['width'] >= $width ) {
+ // $a is not wide enough but $b is
+ // so we consider $a > $b as we want $b before $a
+ return 1;
+ }
+ if ( $a['width'] >= $width && $b['width'] < $width ) {
+ // $b not wide enough, so $a must be preferred.
+ return -1;
+ }
+ if ( $a['width'] < $width && $b['width'] < $width && $a['width'] != $b['width'] ) {
+ // both are too small. Go with the one closer to the target width
+ return ( $a['width'] < $b['width'] ) ? -1 : 1;
+ }
+ // Both are big enough, or both equally too small. Go with the one
+ // that has a lower bit-rate (as it will be faster to download).
+ if ( isset( $a['bandwidth'] ) && isset( $b['bandwidth'] ) ) {
+ return ( $a['bandwidth'] < $b['bandwidth'] ) ? -1 : 1;
+ }
+
+ // We have no firm basis for a comparison, so consider them equal.
+ return 0;
+ }
+
+ /**
+ * Call mediaWiki xml helper class to build media tag output from
+ * supplied arrays
+ * @param $sizeOverride array
+ * @param $autoPlay boolean sets the autoplay attribute
+ * @return string
+ */
+ function getHtmlMediaTagOutput( $sizeOverride = array(), $autoPlay = false ){
+ // Try to get the first source src attribute ( usually this should be the source file )
+ $mediaSources = $this->getMediaSources();
+ reset( $mediaSources ); // do not rely on auto-resetting of arrays under HHVM
+ $firstSource = current( $mediaSources );
+
+ if( !$firstSource['src'] ){
+ // XXX media handlers don't seem to work with exceptions..
+ return 'Error missing media source';
+ };
+
+ // Sort sources by bandwidth least to greatest ( so default selection on resource constrained
+ // browsers ( without js? ) go with minimal source.
+ usort( $mediaSources, array( $this, 'sortMediaByBandwidth' ) );
+
+ // We prefix some source attributes with data- to pass along to the javascript player
+ $prefixedSourceAttr = Array( 'width', 'height', 'title', 'shorttitle', 'bandwidth', 'framerate', 'disablecontrols' );
+ foreach( $mediaSources as &$source ){
+ foreach( $source as $attr => $val ){
+ if( in_array( $attr, $prefixedSourceAttr ) ){
+ $source[ 'data-' . $attr ] = $val;
+ unset( $source[ $attr ] );
+ }
+ }
+ }
+
+ $width = $sizeOverride ? $sizeOverride[0] : $this->getPlayerWidth();
+ if( $this->fillwindow ){
+ $width = '100%';
+ } else {
+ $width .= 'px';
+ }
+ // Build the video tag output:
+ $s = Xml::tags( 'div' , array(
+ 'class' => 'mediaContainer',
+ 'style' => 'position:relative;display:block;width:'. $width
+ ),
+ Html::rawElement( $this->getTagName(), $this->getMediaAttr( $sizeOverride, $autoPlay ),
+ // The set of media sources:
+ self::htmlTagSet( 'source', $mediaSources ) .
+
+ // Timed text:
+ self::htmlTagSet( 'track',
+ $this->file ? $this->getTextHandler()->getTracks() : null ) .
+
+ // Fallback text displayed for browsers without js and without video tag support:
+ /// XXX note we may want to replace this with an image and download link play button
+ wfMessage( 'timedmedia-no-player-js', $firstSource['src'] )->text()
+ )
+ );
+ return $s;
+ }
+
+ /**
+ * Get poster.
+ * @param $width Integer width of poster. Should not equal $this->width.
+ * @throws Exception If $width is same as $this->width.
+ * @return String|bool url for poster or false
+ */
+ function getPoster ( $width ) {
+ if ( intval( $width ) === intval( $this->width ) ) {
+ // Prevent potential loop
+ throw new Exception( "Asked for poster in current size. Potential loop." );
+ }
+ $params = array( "width" => intval( $width ) );
+ $mto = $this->file->transform( $params );
+ if ( $mto ) {
+ return $mto->getUrl();
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get the media attributes
+ * @param $sizeOverride Array|bool of width and height
+ * @return array
+ */
+ function getMediaAttr( $sizeOverride = false, $autoPlay = false ){
+ global $wgVideoPlayerSkin ;
+ // Normalize values
+ $length = floatval( $this->length );
+ $offset = floatval( $this->offset );
+
+ $width = $sizeOverride ? $sizeOverride[0] : $this->getPlayerWidth();
+ $height = $sizeOverride ? $sizeOverride[1]: $this->getPlayerHeight();
+
+ // The poster url:
+ $posterUrl = $this->getUrl( $sizeOverride );
+
+ if( $this->fillwindow ){
+ $width = '100%';
+ $height = '100%';
+ } else{
+ $width .= 'px';
+ $height .= 'px';
+ }
+
+ $mediaAttr = array(
+ 'id' => self::PLAYER_ID_PREFIX . TimedMediaTransformOutput::$serial++,
+ 'style' => "width:{$width}",
+ // Get the correct size:
+ 'poster' => $posterUrl,
+
+ // Note we set controls to true ( for no-js players ) when mwEmbed rewrites the interface
+ // it updates the controls attribute of the embed video
+ 'controls'=> 'true',
+ // Since we will reload the item with javascript,
+ // tell browser to not load the video before
+ 'preload'=>'none',
+ );
+
+ if ( $this->isVideo ) {
+ $mediaAttr['style'] .= ";height:{$height}";
+ }
+
+ if( $autoPlay === true ){
+ $mediaAttr['autoplay'] = 'true';
+ }
+
+ // MediaWiki uses the kSkin class
+ $mediaAttr['class'] = 'kskin';
+
+ if ( $this->file ) {
+ // Custom data-attributes
+ $mediaAttr += array(
+ 'data-durationhint' => $length,
+ 'data-startoffset' => $offset,
+ 'data-mwtitle' => $this->file->getTitle()->getDBkey()
+ );
+
+ // Add api provider:
+ if( $this->file->isLocal() ){
+ $apiProviderName = 'local';
+ } else {
+ // Set the api provider name to "wikimediacommons" for shared ( instant commons convention )
+ // (provider names should have identified the provider instead of the provider type "shared")
+ $apiProviderName = $this->file->getRepoName();
+ if( $apiProviderName == 'shared' ) {
+ $apiProviderName = 'wikimediacommons';
+ }
+ }
+ // XXX Note: will probably migrate mwprovider to an escaped api url.
+ $mediaAttr[ 'data-mwprovider' ] = $apiProviderName;
+ } else {
+ if ( $length ) {
+ $mediaAttr[ 'data-durationhint' ] = $length;
+ }
+ if ( $offset ) {
+ $mediaAttr[ 'data-startoffset' ] = $offset;
+ }
+ }
+ if ( $this->disablecontrols ) {
+ $mediaAttr[ 'data-disablecontrols' ] = $this->disablecontrols;
+ }
+ return $mediaAttr;
+ }
+
+ /**
+ * @return null
+ */
+ function getMediaSources(){
+ if( !$this->sources ){
+ // Generate transcode jobs ( and get sources that are already transcoded)
+ // At a minimum this should return the source video file.
+ $this->sources = WebVideoTranscode::getSources( $this->file );
+ // Check if we have "start or end" times and append the temporal url fragment hash
+ foreach( $this->sources as &$source ){
+ $source['src'].= $this->getTemporalUrlHash();
+ }
+ }
+ return $this->sources;
+ }
+
+ function getTemporalUrlHash(){
+ if( $this->hashTime ){
+ return $this->hashTime;
+ }
+ $hash ='';
+ if( $this->start ){
+ $startSec = TimedMediaHandler::parseTimeString( $this->start );
+ if( $startSec !== false ){
+ $hash.= '#t=' . TimedMediaHandler::seconds2npt( $startSec );
+ }
+ }
+ if( $this->end ){
+ if( $hash == '' ){
+ $hash .= '#t=0';
+ }
+ $endSec = TimedMediaHandler::parseTimeString( $this->end );
+ if( $endSec !== false ){
+ $hash.= ',' . TimedMediaHandler::seconds2npt( $endSec );
+ }
+ }
+ $this->hashTime = $hash;
+ return $this->hashTime;
+ }
+}
diff --git a/extensions/TimedMediaHandler/TimedTextPage.php b/extensions/TimedMediaHandler/TimedTextPage.php
new file mode 100644
index 00000000..361c2eb9
--- /dev/null
+++ b/extensions/TimedMediaHandler/TimedTextPage.php
@@ -0,0 +1,187 @@
+<?php
+/**
+ * TimedText page display the current video with subtitles to the right.
+ *
+ * Future features for this page"
+ * @todo add srt download links
+ * @todo parse and validate srt files
+ * @todo link-in or include the universal subtitles editor
+ */
+class TimedTextPage extends Article {
+ // The width of the video plane:
+ static private $videoWidth = 400;
+ static private $knownTimedTextExtensions = array( 'srt', 'vtt' );
+
+ public function view() {
+ $request = $this->getContext()->getRequest();
+ $out = $this->getContext()->getOutput();
+ $user = $this->getContext()->getUser();
+
+ $diff = $request->getVal( 'diff' );
+
+ if ( $this->getTitle()->getNamespace() != NS_TIMEDTEXT || isset( $diff ) ) {
+ parent::view();
+ return;
+ }
+ $this->renderOutput( $out );
+ }
+
+ /**
+ * Render TimedText to given output
+ * @param $out OutputPage
+ */
+ public function renderOutput( $out ){
+ // parse page title:
+ $titleParts = explode( '.', $this->getTitle()->getDBkey() );
+ $timedTextExtension = array_pop( $titleParts );
+ $languageKey = array_pop( $titleParts );
+
+ $oldid = $this->getOldID();
+ # Are we looking at an old revision
+ if ( $oldid && $this->mRevision ) {
+ $this->fetchContentObject();
+ $out->setRevisionId( $this->getRevIdFetched() );
+ $this->setOldSubtitle( $oldid );
+
+ if ( !$this->showDeletedRevisionHeader() ) {
+ wfDebug( __METHOD__ . ": cannot view deleted revision\n" );
+ return;
+ }
+ }
+
+ // Check for File name without text extension:
+ // i.e TimedText:myfile.ogg
+ $fileTitle = Title::newFromText( $this->getTitle()->getDBkey(), NS_FILE );
+ $file = wfFindFile( $fileTitle );
+ // Check for a valid srt page, present redirect form for the full title match:
+ if( !in_array( $timedTextExtension, self::$knownTimedTextExtensions ) && $file && $file->exists() ){
+ if( $file->isLocal() ){
+ $this->doRedirectToPageForm( $fileTitle );
+ } else {
+ $this->doLinkToRemote( $file );
+ }
+ return;
+ }
+
+ // Check for File name with text extension ( from remaning parts of title )
+ // i.e TimedText:myfile.ogg.en.srt
+
+ $videoTitle = Title::newFromText( implode('.', $titleParts ), NS_FILE );
+
+ // Check for remote file
+ $basefile = wfFindFile( $videoTitle );
+ if ( !$basefile ) {
+ $out->addHTML( wfMessage( 'timedmedia-subtitle-no-video' )->escaped() );
+ return;
+ }
+
+ if( !$basefile->isLocal() ){
+ $this->doLinkToRemote( $basefile );
+ return;
+ }
+
+ // Look up the language name:
+ $language = $out->getLanguage()->getCode();
+ $languages = Language::fetchLanguageNames( $language, 'all' );
+ if( isset( $languages[ $languageKey ] ) ) {
+ $languageName = $languages[ $languageKey ];
+ } else {
+ $languageName = $languageKey;
+ }
+
+ // Set title
+ $message = $this->exists() ?
+ 'mwe-timedtext-language-subtitles-for-clip' :
+ 'mwe-timedtext-language-no-subtitles-for-clip';
+ $out->setPageTitle( wfMessage($message, $languageName, $videoTitle ) );
+
+ // Get the video with with a max of 600 pixel page
+ $out->addHTML(
+ xml::tags( 'table', array( 'style'=> 'border:none' ),
+ xml::tags( 'tr', null,
+ xml::tags( 'td', array( 'valign' => 'top', 'width' => self::$videoWidth ),
+ $this->getVideoHTML( $videoTitle )
+ ) .
+ xml::tags( 'td', array( 'valign' => 'top' ) , $this->getTimedTextHTML( $languageName ) )
+ )
+ )
+ );
+ }
+
+ /**
+ * Timed text or file is hosted on remote repo, Add a short description and link to foring repo
+ * @param $file File the base file
+ */
+ function doLinkToRemote( $file ){
+ $output = $this->getContext()->getOutput();
+ $output->setPageTitle( wfMessage( 'timedmedia-subtitle-remote',
+ $file->getRepo()->getDisplayName() ) );
+ $output->addHTML( wfMessage( 'timedmedia-subtitle-remote-link',
+ $file->getDescriptionUrl(), $file->getRepo()->getDisplayName() ) );
+ }
+
+ function doRedirectToPageForm(){
+ $lang = $this->getContext()->getLanguage();
+ $out = $this->getContext()->getOutput();
+
+ // Set the page title:
+ $out->setPageTitle( wfMessage( 'timedmedia-subtitle-new' ) );
+
+ // Look up the language name:
+ $language = $out->getLanguage()->getCode();
+ $attrs = array( 'id' => 'timedmedia-tt-input' );
+ $langSelect = Xml::languageSelector( $language, false, null, $attrs, null );
+
+ $out->addHTML(
+ Xml::tags('div', array( 'style' => 'text-align:center' ),
+ Xml::tags( 'div', null,
+ wfMessage( 'timedmedia-subtitle-new-desc', $lang->getCode() )->parse()
+ ) .
+ $langSelect[1] .
+ Xml::tags( 'button',
+ array( 'id' => 'timedmedia-tt-go' ),
+ wfMessage( 'timedmedia-subtitle-new-go' )->escaped()
+ )
+ )
+ );
+ $out->addModules( 'ext.tmh.TimedTextSelector' );
+ }
+
+ /**
+ * Gets the video HTML ( with the current language set as default )
+ * @param $videoTitle string
+ * @return String
+ */
+ private function getVideoHTML( $videoTitle ){
+ // Get the video embed:
+ $file = wfFindFile( $videoTitle );
+ if( !$file ){
+ return wfMessage( 'timedmedia-subtitle-no-video' )->escaped();
+ } else {
+ $videoTransform= $file->transform(
+ array(
+ 'width' => self::$videoWidth
+ )
+ );
+ return $videoTransform->toHTML();
+ }
+ }
+
+ /**
+ * Gets an HTML representation of the Timed Text
+ *
+ * @param $languageName string
+ * @return Message|string
+ */
+ private function getTimedTextHTML( $languageName ){
+ if( !$this->exists() ){
+ return wfMessage( 'timedmedia-subtitle-no-subtitles', $languageName );
+ }
+ return Xml::element(
+ 'pre',
+ array( 'style' => 'margin-top: 0px;' ),
+ $this->getContent(),
+ false
+ );
+ }
+}
diff --git a/extensions/TimedMediaHandler/TranscodeStatusTable.php b/extensions/TimedMediaHandler/TranscodeStatusTable.php
new file mode 100644
index 00000000..2220fc72
--- /dev/null
+++ b/extensions/TimedMediaHandler/TranscodeStatusTable.php
@@ -0,0 +1,236 @@
+<?php
+/**
+ * TranscodeStatusTable outputs a "transcode" status table to the ImagePage
+ *
+ * If logged in as autoconfirmed users can reset transcode states
+ * via the transcode api entry point
+ *
+ */
+class TranscodeStatusTable {
+ /**
+ * @param $file File
+ * @return string
+ */
+ public static function getHTML( $file ){
+ global $wgUser, $wgOut;
+
+ // Add transcode table css and javascript:
+ $wgOut->addModules( array( 'ext.tmh.transcodetable' ) );
+
+ $o = '<h2 id="transcodestatus">' . wfMessage( 'timedmedia-status-header' )->escaped() . '</h2>';
+ // Give the user a purge page link
+ $o.= Linker::link(
+ $file->getTitle(),
+ wfMessage('timedmedia-update-status')->escaped(),
+ array(),
+ array( 'action'=> 'purge' )
+ );
+
+ $o.= Xml::openElement( 'table', array( 'class' => 'wikitable mw-filepage-transcodestatus' ) ) . "\n"
+ . '<tr>'
+ . '<th>' . wfMessage( 'timedmedia-transcodeinfo' )->escaped() . '</th>'
+ . '<th>' . wfMessage( 'timedmedia-transcodebitrate' )->escaped() . '</th>'
+ . '<th>' . wfMessage( 'timedmedia-direct-link' )->escaped() . '</th>';
+
+ if( $wgUser->isAllowed( 'transcode-reset' ) ) {
+ $o.= '<th>' . wfMessage( 'timedmedia-actions' )->escaped() . '</th>';
+ }
+
+ $o.= '<th>' . wfMessage( 'timedmedia-status' )->escaped() . '</th>';
+ $o.= '<th>' . wfMessage( 'timedmedia-transcodeduration' )->escaped() . '</th>';
+ $o.= "</tr>\n";
+
+ $o.= self::getTranscodeRows( $file );
+
+ $o.= Xml::closeElement( 'table' );
+ return $o;
+ }
+
+ /**
+ * Get the video or audio codec for the defined transcode,
+ * for grouping/sorting purposes.
+ */
+ public static function codecFromTranscodeKey( $key ) {
+ if ( isset( WebVideoTranscode::$derivativeSettings[$key] ) ) {
+ $settings = WebVideoTranscode::$derivativeSettings[$key];
+ if ( isset( $settings['videoCodec'] ) ) {
+ return $settings['videoCodec'];
+ } else if ( isset( $settings['audioCodec'] ) ) {
+ return $settings['audioCodec'];
+ } else {
+ // this this shouldn't happen...
+ // fall through
+ }
+ } else {
+ // derivative type no longer defined or invalid def?
+ // fall through
+ }
+ return $key;
+ }
+
+ /**
+ * @param $file File
+ * @return string
+ */
+ public static function getTranscodeRows( $file ){
+ global $wgUser, $wgLang;
+ $o='';
+
+ $transcodeRows = WebVideoTranscode::getTranscodeState( $file );
+
+ uksort( $transcodeRows, function( $a, $b ) {
+ $formatOrder = array( 'vp9', 'vp8', 'h264', 'theora', 'opus', 'vorbis', 'aac' );
+
+ $aFormat = self::codecFromTranscodeKey( $a );
+ $bFormat = self::codecFromTranscodeKey( $b );
+ $aIndex = array_search( $aFormat, $formatOrder );
+ $bIndex = array_search( $bFormat, $formatOrder );
+
+ if ( $aIndex === false && $bIndex === false ) {
+ return -strnatcmp( $a, $b );
+ } else if ( $aIndex === false ) {
+ return 1;
+ } else if ( $bIndex === false ) {
+ return -1;
+ } else if ( $aIndex === $bIndex ) {
+ return -strnatcmp( $a, $b );
+ } else {
+ return ( $aIndex - $bIndex );
+ }
+ } );
+
+ foreach( $transcodeRows as $transcodeKey => $state ){
+ $o.='<tr>';
+ // Encode info:
+ $o.='<td>' . wfMessage('timedmedia-derivative-' . $transcodeKey )->escaped() . '</td>';
+ $o.='<td>' . self::getTranscodeBitrate( $file, $state ) . '</td>';
+
+ // Download file
+ $o.='<td>';
+ $o.= ( !is_null( $state['time_success'] ) ) ?
+ '<a href="'.self::getSourceUrl( $file, $transcodeKey ) .'" title="'.wfMessage
+ ('timedmedia-download' )->escaped() .'"><div class="download-btn"><span>' .
+ wfMessage('timedmedia-download' )->escaped(). '</span></div></a></td>' :
+ wfMessage('timedmedia-not-ready' )->escaped();
+ $o.='</td>';
+
+ // Check if we should include actions:
+ if( $wgUser->isAllowed( 'transcode-reset' ) ){
+ // include reset transcode action buttons
+ $o.='<td class="mw-filepage-transcodereset"><a href="#" data-transcodekey="' .
+ htmlspecialchars( $transcodeKey ). '">' . wfMessage('timedmedia-reset')->escaped() .
+ '</a></td>';
+ }
+
+ // Status:
+ $o.='<td>' . self::getStatusMsg( $file, $state ) . '</td>';
+ $o.='<td>' . self::getTranscodeDuration( $file, $state ) . '</td>';
+
+ $o.='</tr>';
+ }
+ return $o;
+ }
+
+ /**
+ * @param $file File
+ * @param $transcodeKey string
+ * @return string
+ */
+ public static function getSourceUrl( $file, $transcodeKey ){
+ return WebVideoTranscode::getTranscodedUrlForFile( $file, $transcodeKey );
+ }
+
+ /**
+ * @param $file File
+ * @param $state
+ * @return string
+ */
+ public static function getTranscodeDuration( $file, $state ) {
+ global $wgLang;
+ if( !is_null( $state['time_success'] ) ) {
+ $startTime = wfTimestamp( TS_UNIX, $state['time_startwork'] );
+ $endTime = wfTimestamp( TS_UNIX, $state['time_success'] );
+ $delta = $endTime - $startTime;
+ $duration = $wgLang->formatTimePeriod( $delta );
+ return $duration;
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * @param $file File
+ * @param $state
+ * @return string
+ */
+ public static function getTranscodeBitrate( $file, $state ) {
+ global $wgLang;
+ if( !is_null( $state['time_success'] ) ) {
+ return $wgLang->formatBitrate( $state['final_bitrate'] );
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * @param $file File
+ * @param $state
+ * @return string
+ */
+ public static function getStatusMsg( $file, $state ){
+ global $wgContLang;
+ // Check for success:
+ if( !is_null( $state['time_success'] ) ) {
+ return wfMessage( 'timedmedia-completed-on',
+ $wgContLang->timeAndDate( $state[ 'time_success' ] ) )->escaped();
+ }
+ // Check for error:
+ if( !is_null( $state['time_error'] ) ){
+ $attribs = array();
+ if( !is_null( $state['error'] ) ){
+ $attribs = array(
+ 'class' => 'mw-tmh-pseudo-error-link',
+ 'data-error' => $state['error'],
+ );
+ }
+
+ return Html::rawElement( 'span', $attribs,
+ wfMessage( 'timedmedia-error-on',
+ $wgContLang->timeAndDate( $state['time_error'] ) )->escaped()
+ );
+ }
+
+ //$db = wfGetDB( DB_SLAVE );
+ // Check for started encoding
+ if( !is_null( $state['time_startwork'] ) ){
+ $timePassed = time() - wfTimestamp ( TS_UNIX, $state['time_startwork'] );
+ // Get the rough estimate of time done: ( this is not very costly considering everything else
+ // that happens in an action=purge video page request )
+ /*$filePath = WebVideoTranscode::getTargetEncodePath( $file, $state['key'] );
+ if( is_file( $filePath ) ){
+ $targetSize = WebVideoTranscode::getProjectedFileSize( $file, $state['key'] );
+ if( $targetSize === false ){
+ $doneMsg = wfMessage( 'timedmedia-unknown-target-size', $wgLang->formatSize( filesize( $filePath ) ) )->escaped();
+ } else {
+ $doneMsg = wfMessage('timedmedia-percent-done', round( filesize( $filePath ) / $targetSize, 2 ) )->escaped();
+ }
+ } */
+ // Predicting percent done is not working well right now ( disabled for now )
+ $doneMsg = '';
+ return wfMessage(
+ 'timedmedia-started-transcode',
+ TimedMediaHandler::getTimePassedMsg( $timePassed ), $doneMsg
+ )->escaped();
+ }
+ // Check for job added ( but not started encoding )
+ if( !is_null( $state['time_addjob'] ) ){
+ $timePassed = time() - wfTimestamp ( TS_UNIX, $state['time_addjob'] );
+ return wfMessage(
+ 'timedmedia-in-job-queue',
+ TimedMediaHandler::getTimePassedMsg( $timePassed )
+ )->escaped();
+ }
+ // Return unknown status error:
+ return wfMessage('timedmedia-status-unknown')->escaped();
+ }
+}
diff --git a/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscode.php b/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscode.php
new file mode 100644
index 00000000..e4d02556
--- /dev/null
+++ b/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscode.php
@@ -0,0 +1,1192 @@
+<?php
+/**
+ * WebVideoTranscode provides:
+ * encode keys
+ * encode settings
+ *
+ * extends api to return all the streams
+ * extends video tag output to provide all the available sources
+ */
+
+/**
+ * Main WebVideoTranscode Class hold some constants and config values
+ */
+class WebVideoTranscode {
+ /**
+ * Key constants for the derivatives,
+ * this key is appended to the derivative file name
+ *
+ * If you update the wgDerivativeSettings for one of these keys
+ * and want to re-generate the video you should also update the
+ * key constant. ( Or just run a maintenance script to delete all
+ * the assets for a given profile )
+ *
+ * Msg keys for derivatives are set as follows:
+ * $messages['timedmedia-derivative-200_200kbs.ogv'] => 'Ogg 200';
+ */
+
+ // Ogg Profiles
+ const ENC_OGV_160P = '160p.ogv';
+ const ENC_OGV_240P = '240p.ogv';
+ const ENC_OGV_360P = '360p.ogv';
+ const ENC_OGV_480P = '480p.ogv';
+ const ENC_OGV_720P = '720p.ogv';
+ const ENC_OGV_1080P = '1080p.ogv';
+
+ // WebM VP8/Vorbis profiles:
+ const ENC_WEBM_160P = '160p.webm';
+ const ENC_WEBM_360P = '360p.webm';
+ const ENC_WEBM_480P = '480p.webm';
+ const ENC_WEBM_720P = '720p.webm';
+ const ENC_WEBM_1080P = '1080p.webm';
+ const ENC_WEBM_2160P = '2160p.webm';
+
+ // WebM VP9/Opus profiles:
+ const ENC_VP9_360P = '360p.vp9.webm';
+ const ENC_VP9_480P = '480p.vp9.webm';
+ const ENC_VP9_720P = '720p.vp9.webm';
+ const ENC_VP9_1080P = '1080p.vp9.webm';
+ const ENC_VP9_2160P = '2160p.vp9.webm';
+
+ // mp4 profiles:
+ const ENC_H264_320P = '320p.mp4';
+ const ENC_H264_480P = '480p.mp4';
+ const ENC_H264_720P = '720p.mp4';
+ const ENC_H264_1080P = '1080p.mp4';
+ const ENC_H264_2160P = '2160p.mp4';
+
+ const ENC_OGG_VORBIS = 'ogg';
+ const ENC_OGG_OPUS = 'opus';
+ const ENC_MP3 = 'mp3';
+ const ENC_AAC = 'm4a';
+
+ // Static cache of transcode state per instantiation
+ public static $transcodeState = array() ;
+
+ /**
+ * Encoding parameters are set via firefogg encode api
+ *
+ * For clarity and compatibility with passing down
+ * client side encode settings at point of upload
+ *
+ * http://firefogg.org/dev/index.html
+ */
+ public static $derivativeSettings = array(
+ WebVideoTranscode::ENC_OGV_160P =>
+ array(
+ 'maxSize' => '288x160',
+ 'videoBitrate' => '160',
+ 'framerate' => '15',
+ 'audioQuality' => '-1',
+ 'samplerate' => '44100',
+ 'channels' => '2',
+ 'noUpscaling' => 'true',
+ //'twopass' => 'true', // temporarily disabled for broken ffmpeg2theora
+ 'optimize' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'theora',
+ 'type' => 'video/ogg; codecs="theora, vorbis"',
+ ),
+ WebVideoTranscode::ENC_OGV_240P =>
+ array(
+ 'maxSize' => '426x240',
+ 'videoBitrate' => '512',
+ 'audioQuality' => '0',
+ 'samplerate' => '44100',
+ 'channels' => '2',
+ 'noUpscaling' => 'true',
+ //'twopass' => 'true', // temporarily disabled for broken ffmpeg2theora
+ 'optimize' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'theora',
+ 'type' => 'video/ogg; codecs="theora, vorbis"',
+ ),
+ WebVideoTranscode::ENC_OGV_360P =>
+ array(
+ 'maxSize' => '640x360',
+ 'videoBitrate' => '1024',
+ 'audioQuality' => '1',
+ 'samplerate' => '44100',
+ 'channels' => '2',
+ 'noUpscaling' => 'true',
+ //'twopass' => 'true', // temporarily disabled for broken ffmpeg2theora
+ 'optimize' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'theora',
+ 'type' => 'video/ogg; codecs="theora, vorbis"',
+ ),
+ WebVideoTranscode::ENC_OGV_480P =>
+ array(
+ 'maxSize' => '854x480',
+ 'videoBitrate' => '2048',
+ 'audioQuality' => '2',
+ 'samplerate' => '44100',
+ 'channels' => '2',
+ 'noUpscaling' => 'true',
+ //'twopass' => 'true', // temporarily disabled for broken ffmpeg2theora
+ 'optimize' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'theora',
+ 'type' => 'video/ogg; codecs="theora, vorbis"',
+ ),
+
+ WebVideoTranscode::ENC_OGV_720P =>
+ array(
+ 'maxSize' => '1280x720',
+ 'videoQuality' => 6,
+ 'audioQuality' => 3,
+ 'noUpscaling' => 'true',
+ //'twopass' => 'true', // temporarily disabled for broken ffmpeg2theora
+ 'optimize' => 'true',
+ 'keyframeInterval' => '128',
+ 'videoCodec' => 'theora',
+ 'type' => 'video/ogg; codecs="theora, vorbis"',
+ ),
+
+ WebVideoTranscode::ENC_OGV_1080P =>
+ array(
+ 'maxSize' => '1920x1080',
+ 'videoQuality' => 6,
+ 'audioQuality' => 3,
+ 'noUpscaling' => 'true',
+ //'twopass' => 'true', // temporarily disabled for broken ffmpeg2theora
+ 'optimize' => 'true',
+ 'keyframeInterval' => '128',
+ 'videoCodec' => 'theora',
+ 'type' => 'video/ogg; codecs="theora, vorbis"',
+ ),
+
+ // WebM transcode:
+ WebVideoTranscode::ENC_WEBM_160P =>
+ array(
+ 'maxSize' => '288x160',
+ 'videoBitrate' => '256',
+ 'audioQuality' => '-1',
+ 'samplerate' => '44100',
+ 'channels' => '2',
+ 'noUpscaling' => 'true',
+ 'twopass' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'vp8',
+ 'type' => 'video/webm; codecs="vp8, vorbis"',
+ ),
+ WebVideoTranscode::ENC_WEBM_360P =>
+ array(
+ 'maxSize' => '640x360',
+ 'videoBitrate' => '512',
+ 'audioQuality' => '1',
+ 'samplerate' => '44100',
+ 'noUpscaling' => 'true',
+ 'twopass' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'vp8',
+ 'type' => 'video/webm; codecs="vp8, vorbis"',
+ ),
+ WebVideoTranscode::ENC_WEBM_480P =>
+ array(
+ 'maxSize' => '854x480',
+ 'videoBitrate' => '1024',
+ 'audioQuality' => '2',
+ 'samplerate' => '44100',
+ 'noUpscaling' => 'true',
+ 'twopass' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'vp8',
+ 'type' => 'video/webm; codecs="vp8, vorbis"',
+ ),
+ WebVideoTranscode::ENC_WEBM_720P =>
+ array(
+ 'maxSize' => '1280x720',
+ 'videoQuality' => 7,
+ 'audioQuality' => 3,
+ 'noUpscaling' => 'true',
+ 'videoCodec' => 'vp8',
+ 'type' => 'video/webm; codecs="vp8, vorbis"',
+ ),
+ WebVideoTranscode::ENC_WEBM_1080P =>
+ array(
+ 'maxSize' => '1920x1080',
+ 'videoQuality' => 7,
+ 'audioQuality' => 3,
+ 'noUpscaling' => 'true',
+ 'videoCodec' => 'vp8',
+ 'type' => 'video/webm; codecs="vp8, vorbis"',
+ ),
+ WebVideoTranscode::ENC_WEBM_2160P =>
+ array(
+ 'maxSize' => '4096x2160',
+ 'videoQuality' => 7,
+ 'audioQuality' => 3,
+ 'noUpscaling' => 'true',
+ 'videoCodec' => 'vp8',
+ 'type' => 'video/webm; codecs="vp8, vorbis"',
+ ),
+
+ // WebM VP9 transcode:
+ WebVideoTranscode::ENC_VP9_360P =>
+ array(
+ 'maxSize' => '640x360',
+ 'videoBitrate' => '256',
+ 'samplerate' => '48000',
+ 'noUpscaling' => 'true',
+ 'twopass' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'vp9',
+ 'audioCodec' => 'opus',
+ 'type' => 'video/webm; codecs="vp9, opus"',
+ ),
+ WebVideoTranscode::ENC_VP9_480P =>
+ array(
+ 'maxSize' => '854x480',
+ 'videoBitrate' => '512',
+ 'samplerate' => '48000',
+ 'noUpscaling' => 'true',
+ 'twopass' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'vp9',
+ 'audioCodec' => 'opus',
+ 'type' => 'video/webm; codecs="vp9, opus"',
+ ),
+ WebVideoTranscode::ENC_VP9_720P =>
+ array(
+ 'maxSize' => '1280x720',
+ 'videoBitrate' => '1024',
+ 'samplerate' => '48000',
+ 'noUpscaling' => 'true',
+ 'twopass' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'vp9',
+ 'audioCodec' => 'opus',
+ 'tileColumns' => '2',
+ 'type' => 'video/webm; codecs="vp9, opus"',
+ ),
+ WebVideoTranscode::ENC_VP9_1080P =>
+ array(
+ 'maxSize' => '1920x1080',
+ 'videoBitrate' => '2048',
+ 'samplerate' => '48000',
+ 'noUpscaling' => 'true',
+ 'twopass' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'vp9',
+ 'audioCodec' => 'opus',
+ 'tileColumns' => '4',
+ 'type' => 'video/webm; codecs="vp9, opus"',
+ ),
+ WebVideoTranscode::ENC_VP9_2160P =>
+ array(
+ 'maxSize' => '4096x2160',
+ 'videoBitrate' => '8192',
+ 'samplerate' => '48000',
+ 'noUpscaling' => 'true',
+ 'twopass' => 'true',
+ 'keyframeInterval' => '128',
+ 'bufDelay' => '256',
+ 'videoCodec' => 'vp9',
+ 'audioCodec' => 'opus',
+ 'tileColumns' => '4',
+ 'type' => 'video/webm; codecs="vp9, opus"',
+ ),
+
+ // Losly defined per PCF guide to mp4 profiles:
+ // https://develop.participatoryculture.org/index.php/ConversionMatrix
+ // and apple HLS profile guide:
+ // https://developer.apple.com/library/ios/#documentation/networkinginternet/conceptual/streamingmediaguide/UsingHTTPLiveStreaming/UsingHTTPLiveStreaming.html#//apple_ref/doc/uid/TP40008332-CH102-DontLinkElementID_24
+
+ WebVideoTranscode::ENC_H264_320P =>
+ array(
+ 'maxSize' => '480x320',
+ 'videoCodec' => 'h264',
+ 'preset' => 'ipod320',
+ 'videoBitrate' => '400k',
+ 'audioCodec' => 'aac',
+ 'channels' => '2',
+ 'audioBitrate' => '40k',
+ 'type' => 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
+ ),
+
+ WebVideoTranscode::ENC_H264_480P =>
+ array(
+ 'maxSize' => '640x480',
+ 'videoCodec' => 'h264',
+ 'preset' => 'ipod640',
+ 'videoBitrate' => '1200k',
+ 'audioCodec' => 'aac',
+ 'channels' => '2',
+ 'audioBitrate' => '64k',
+ 'type' => 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
+ ),
+
+ WebVideoTranscode::ENC_H264_720P =>
+ array(
+ 'maxSize' => '1280x720',
+ 'videoCodec' => 'h264',
+ 'preset' => '720p',
+ 'videoBitrate' => '2500k',
+ 'audioCodec' => 'aac',
+ 'channels' => '2',
+ 'audioBitrate' => '128k',
+ 'type' => 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
+ ),
+
+ WebVideoTranscode::ENC_H264_1080P =>
+ array(
+ 'maxSize' => '1920x1080',
+ 'videoCodec' => 'h264',
+ 'videoBitrate' => '5000k',
+ 'audioCodec' => 'aac',
+ 'channels' => '2',
+ 'audioBitrate' => '128k',
+ 'type' => 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
+ ),
+ WebVideoTranscode::ENC_H264_2160P =>
+ array(
+ 'maxSize' => '4096x2160',
+ 'videoCodec' => 'h264',
+ 'videoBitrate' => '16384k',
+ 'audioCodec' => 'aac',
+ 'channels' => '2',
+ 'audioBitrate' => '128k',
+ 'type' => 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
+ ),
+
+ //Audio profiles
+ WebVideoTranscode::ENC_OGG_VORBIS =>
+ array(
+ 'audioCodec' => 'vorbis',
+ 'audioQuality' => '1',
+ 'samplerate' => '44100',
+ 'channels' => '2',
+ 'noUpscaling' => 'true',
+ 'novideo' => 'true',
+ 'type' => 'audio/ogg; codecs="vorbis"',
+ ),
+ WebVideoTranscode::ENC_OGG_OPUS =>
+ array(
+ 'audioCodec' => 'opus',
+ 'audioQuality' => '1',
+ 'samplerate' => '44100',
+ 'channels' => '2',
+ 'noUpscaling' => 'true',
+ 'novideo' => 'true',
+ 'type' => 'audio/ogg; codecs="opus"',
+ ),
+ WebVideoTranscode::ENC_MP3 =>
+ array(
+ 'audioCodec' => 'mp3',
+ 'audioQuality' => '1',
+ 'samplerate' => '44100',
+ 'channels' => '2',
+ 'noUpscaling' => 'true',
+ 'novideo' => 'true',
+ 'type' => 'audio/mpeg',
+ ),
+ WebVideoTranscode::ENC_AAC =>
+ array(
+ 'audioCodec' => 'aac',
+ 'audioQuality' => '1',
+ 'samplerate' => '44100',
+ 'channels' => '2',
+ 'noUpscaling' => 'true',
+ 'novideo' => 'true',
+ 'type' => 'audio/mp4; codecs="mp4a.40.5"',
+ ),
+ );
+
+ /**
+ * @param $file File
+ * @param $transcodeKey string
+ * @return string
+ */
+ static public function getDerivativeFilePath( $file, $transcodeKey ) {
+ return $file->getTranscodedPath( self::getTranscodeFileBaseName( $file, $transcodeKey ) );
+ }
+
+ /**
+ * Get the name to use as the base name for the transcode.
+ *
+ * Swift has problems where the url-encoded version of
+ * the path (ie 'filename.ogv/filename.ogv.720p.webm' )
+ * is greater that > 1024 bytes, so shorten in that case.
+ *
+ * Future versions might respect FileRepo::$abbrvThreshold.
+ *
+ * @param File $file
+ * @param String $suffix Optional suffix (e.g. transcode key).
+ * @return String File name, or the string transcode.
+ */
+ static public function getTranscodeFileBaseName( $file, $suffix = '' ) {
+ $name = $file->getName();
+ if ( strlen( urlencode( $name ) ) * 2 + 12 > 1024 ) {
+ return 'transcode' . '.' . $suffix;
+ } else {
+ return $name . '.' . $suffix;
+ }
+ }
+
+ /**
+ * Get url for a transcode.
+ *
+ * @param $file File
+ * @param $suffix string Transcode key
+ * @return string
+ */
+ static public function getTranscodedUrlForFile( $file, $suffix = '' ) {
+ return $file->getTranscodedUrl( self::getTranscodeFileBaseName( $file, $suffix ) );
+ }
+
+ /**
+ * Get temp file at target path for video encode
+ *
+ * @param $file File
+ * @param $transcodeKey String
+ *
+ * @return TempFSFile at target encode path
+ */
+ static public function getTargetEncodeFile( &$file, $transcodeKey ){
+ $filePath = self::getDerivativeFilePath( $file, $transcodeKey );
+ $ext = strtolower( pathinfo( "$filePath", PATHINFO_EXTENSION ) );
+
+ // Create a temp FS file with the same extension
+ $tmpFile = TempFSFile::factory( 'transcode_' . $transcodeKey, $ext);
+ if ( !$tmpFile ) {
+ return False;
+ }
+ return $tmpFile;
+ }
+
+ /**
+ * Get the max size of the web stream ( constant bitrate )
+ * @return int
+ */
+ static public function getMaxSizeWebStream(){
+ global $wgEnabledTranscodeSet;
+ $maxSize = 0;
+ foreach( $wgEnabledTranscodeSet as $transcodeKey ){
+ if( isset( self::$derivativeSettings[$transcodeKey]['videoBitrate'] ) ){
+ $currentSize = self::$derivativeSettings[$transcodeKey]['maxSize'];
+ if( $currentSize > $maxSize ){
+ $maxSize = $currentSize;
+ }
+ }
+ }
+ return $maxSize;
+ }
+
+ /**
+ * Give a rough estimate on file size
+ * Note this is not always accurate.. especially with variable bitrate codecs ;)
+ * @param $file File
+ * @param $transcodeKey string
+ * @return number
+ */
+ static public function getProjectedFileSize( $file, $transcodeKey ){
+ $settings = self::$derivativeSettings[$transcodeKey];
+ if( $settings[ 'videoBitrate' ] && $settings['audioBitrate'] ){
+ return $file->getLength() * 8 * (
+ self::$derivativeSettings[$transcodeKey]['videoBitrate']
+ +
+ self::$derivativeSettings[$transcodeKey]['audioBitrate']
+ );
+ }
+ // Else just return the size of the source video ( we have no idea how large the actual derivative size will be )
+ return $file->getLength() * $file->getHandler()->getBitrate( $file ) * 8;
+ }
+
+ /**
+ * Static function to get the set of video assets
+ * Checks if the file is local or remote and grabs respective sources
+ * @param $file File
+ * @param $options array
+ * @return array|mixed
+ */
+ static public function getSources( &$file , $options = array() ){
+ if( $file->isLocal() || $file->repo instanceof ForeignDBViaLBRepo ){
+ return self::getLocalSources( $file , $options );
+ } else {
+ return self::getRemoteSources( $file , $options );
+ }
+ }
+
+ /**
+ * Grabs sources from the remote repo via ApiQueryVideoInfo.php entry point.
+ *
+ * TODO: This method could use some rethinking. See comments on PS1 of
+ * <https://gerrit.wikimedia.org/r/#/c/117916/>
+ *
+ * Because this works with commons regardless of whether TimedMediaHandler is installed or not
+ * @param $file File
+ * @param $options array
+ * @return array|mixed
+ */
+ static public function getRemoteSources(&$file , $options = array() ){
+ global $wgMemc;
+ // Setup source attribute options
+ $dataPrefix = in_array( 'nodata', $options )? '': 'data-';
+
+ // Use descriptionCacheExpiry as our expire for timed text tracks info
+ if ( $file->repo->descriptionCacheExpiry > 0 ) {
+ wfDebug("Attempting to get sources from cache...");
+ $key = $file->repo->getLocalCacheKey( 'WebVideoSources', 'url', $file->getName() );
+ $sources = $wgMemc->get($key);
+ if ( $sources ) {
+ wfDebug("Success found sources in local cache\n");
+ return $sources;
+ }
+ wfDebug("source cache miss\n");
+ }
+
+ wfDebug("Get Video sources from remote api for " . $file->getName() . "\n");
+ $query = array(
+ 'action' => 'query',
+ 'prop' => 'videoinfo',
+ 'viprop' => 'derivatives',
+ 'titles' => MWNamespace::getCanonicalName( NS_FILE ) .':'. $file->getTitle()->mTextform
+ );
+
+ $data = $file->repo->fetchImageQuery( $query );
+
+ if( isset( $data['warnings'] ) && isset( $data['warnings']['query'] )
+ && $data['warnings']['query']['*'] == "Unrecognized value for parameter 'prop': videoinfo" )
+ {
+ // Commons does not yet have TimedMediaHandler.
+ // Use the normal file repo system single source:
+ return array( self::getPrimarySourceAttributes( $file, array( $dataPrefix ) ) );
+ }
+ $sources = array();
+ // Generate the source list from the data response:
+ if( isset( $data['query'] ) && $data['query']['pages'] ){
+ $vidResult = array_shift( $data['query']['pages'] );
+ if( isset( $vidResult['videoinfo'] ) ) {
+ $derResult = array_shift( $vidResult['videoinfo'] );
+ $derivatives = $derResult['derivatives'];
+ foreach( $derivatives as $derivativeSource ){
+ $sources[] = $derivativeSource;
+ }
+ }
+ }
+
+ // Update the cache:
+ if ( $sources && $file->repo->descriptionCacheExpiry > 0 ) {
+ $wgMemc->set( $key, $sources, $file->repo->descriptionCacheExpiry );
+ }
+
+ return $sources;
+
+ }
+
+ /**
+ * Based on the $wgEnabledTranscodeSet set of enabled derivatives we
+ * return sources that are ready.
+ *
+ * This will not automatically update or queue anything!
+ *
+ * @param $file File object
+ * @param $options array Options, a set of options:
+ * 'nodata' Strips the data- attribute, useful when your output is not html
+ * @return array an associative array of sources suitable for <source> tag output
+ */
+ static public function getLocalSources( &$file , $options=array() ){
+ global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet, $wgEnableTranscode;
+ $sources = array();
+
+ // Add the original file:
+ $sources[] = self::getPrimarySourceAttributes( $file, $options );
+
+ // If $wgEnableTranscode is false don't look for or add other local sources:
+ if( $wgEnableTranscode === false &&
+ !($file->repo instanceof ForeignDBViaLBRepo) ){
+ return $sources;
+ }
+
+ // If an "oldFile" don't look for other sources:
+ if( $file->isOld() ){
+ return $sources;
+ }
+
+ // Now Check for derivatives
+ if( $file->getHandler()->isAudio( $file ) ){
+ $transcodeSet = $wgEnabledAudioTranscodeSet;
+ } else {
+ $transcodeSet = $wgEnabledTranscodeSet;
+ }
+ foreach( $transcodeSet as $transcodeKey ){
+ if ( self::isTranscodeEnabled( $file, $transcodeKey ) ) {
+ // Try and add the source
+ self::addSourceIfReady( $file, $sources, $transcodeKey, $options );
+ }
+ }
+
+ return $sources;
+ }
+
+ /**
+ * Get the transcode state for a given filename and transcodeKey
+ *
+ * @param $fileName string
+ * @param $transcodeKey string
+ * @return bool
+ */
+ public static function isTranscodeReady( $file, $transcodeKey ){
+
+ // Check if we need to populate the transcodeState cache:
+ $transcodeState = self::getTranscodeState( $file );
+
+ // If no state is found the cache for this file is false:
+ if( !isset( $transcodeState[ $transcodeKey ] ) ) {
+ return false;
+ }
+ // Else return boolean ready state ( if not null, then ready ):
+ return !is_null( $transcodeState[ $transcodeKey ]['time_success'] );
+ }
+
+ /**
+ * Clear the transcode state cache:
+ * @param String $fileName Optional fileName to clear transcode cache for
+ */
+ public static function clearTranscodeCache( $fileName = null){
+ if( $fileName ){
+ unset( self::$transcodeState[ $fileName ] );
+ } else {
+ self::$transcodeState = array();
+ }
+ }
+
+ /**
+ * Populates the transcode table with the current DB state of transcodes
+ * if transcodes are not found in the database their state is set to "false"
+ *
+ * @param {Object} File object
+ */
+ public static function getTranscodeState( $file, $db = false ){
+ global $wgTranscodeBackgroundTimeLimit;
+ $fileName = $file->getName();
+ if( ! isset( self::$transcodeState[$fileName] ) ){
+ if ( $db === false ) {
+ $db = $file->repo->getSlaveDB();
+ }
+ // initialize the transcode state array
+ self::$transcodeState[ $fileName ] = array();
+ $res = $db->select( 'transcode',
+ '*',
+ array( 'transcode_image_name' => $fileName ),
+ __METHOD__,
+ array( 'LIMIT' => 100 )
+ );
+ $overTimeout = array();
+ $over = $db->timestamp(time() - (2 * $wgTranscodeBackgroundTimeLimit));
+ // Populate the per transcode state cache
+ foreach ( $res as $row ) {
+ // strip the out the "transcode_" from keys
+ $trascodeState = array();
+ foreach( $row as $k => $v ){
+ $trascodeState[ str_replace( 'transcode_', '', $k ) ] = $v;
+ }
+ self::$transcodeState[ $fileName ][ $row->transcode_key ] = $trascodeState;
+ if ( $row->transcode_time_startwork != NULL
+ && $row->transcode_time_startwork < $over
+ && $row->transcode_time_success == NULL
+ && $row->transcode_time_error == NULL ) {
+ $overTimeout[] = $row->transcode_key;
+ }
+ }
+ if ( $overTimeout ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update(
+ 'transcode',
+ array(
+ 'transcode_time_error' => $dbw->timestamp(),
+ 'transcode_error' => 'timeout'
+ ),
+ array(
+ 'transcode_image_name' => $fileName,
+ 'transcode_key' => $overTimeout
+ ),
+ __METHOD__,
+ array( 'LIMIT' => count( $overTimeout ) )
+ );
+ }
+ }
+ $sorted = self::$transcodeState[ $fileName ];
+ uksort( $sorted, 'strnatcmp' );
+ return $sorted;
+ }
+
+ /**
+ * Remove any transcode files and db states associated with a given $file
+ * Note that if you want to see them again, you must re-queue them by calling
+ * startJobQueue() or updateJobQueue().
+ *
+ * also remove the transcode files:
+ * @param $file File Object
+ * @param $transcodeKey String Optional transcode key to remove only this key
+ */
+ public static function removeTranscodes( &$file, $transcodeKey = false ){
+
+ // if transcode key is non-false, non-null:
+ if( $transcodeKey ){
+ // only remove the requested $transcodeKey
+ $removeKeys = array( $transcodeKey );
+ } else {
+ // Remove any existing files ( regardless of their state )
+ $res = $file->repo->getMasterDB()->select( 'transcode',
+ array( 'transcode_key' ),
+ array( 'transcode_image_name' => $file->getName() )
+ );
+ $removeKeys = array();
+ foreach( $res as $transcodeRow ){
+ $removeKeys[] = $transcodeRow->transcode_key;
+ }
+ }
+
+ // Remove files by key:
+ $urlsToPurge = array();
+ foreach ( $removeKeys as $tKey ) {
+ $urlsToPurge[] = self::getTranscodedUrlForFile( $file, $tKey );
+ $filePath = self::getDerivativeFilePath( $file, $tKey );
+ if( $file->repo->fileExists( $filePath ) ){
+ wfSuppressWarnings();
+ $res = $file->repo->quickPurge( $filePath );
+ wfRestoreWarnings();
+ if( !$res ){
+ wfDebug( "Could not delete file $filePath\n" );
+ }
+ }
+ }
+
+ SquidUpdate::purge( $urlsToPurge );
+
+ // Build the sql query:
+ $dbw = wfGetDB( DB_MASTER );
+ $deleteWhere = array( 'transcode_image_name' => $file->getName() );
+ // Check if we are removing a specific transcode key
+ if( $transcodeKey !== false ){
+ $deleteWhere['transcode_key'] = $transcodeKey;
+ }
+ // Remove the db entries
+ $dbw->delete( 'transcode', $deleteWhere, __METHOD__ );
+
+ // Purge the cache for pages that include this video:
+ $titleObj = $file->getTitle();
+ self::invalidatePagesWithFile( $titleObj );
+
+ // Remove from local WebVideoTranscode cache:
+ self::clearTranscodeCache( $titleObj->getDBkey() );
+ }
+
+ /**
+ * @param $titleObj Title
+ */
+ public static function invalidatePagesWithFile( &$titleObj ){
+ wfDebug("WebVideoTranscode:: Invalidate pages that include: " . $titleObj->getDBkey() . "\n" );
+ // Purge the main image page:
+ $titleObj->invalidateCache();
+
+ // TODO if the video is used in over 500 pages add to 'job queue'
+ // TODO interwiki invalidation ?
+ $limit = 500;
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->select(
+ array( 'imagelinks', 'page' ),
+ array( 'page_namespace', 'page_title' ),
+ array( 'il_to' => $titleObj->getDBkey(), 'il_from = page_id' ),
+ __METHOD__,
+ array( 'LIMIT' => $limit + 1 )
+ );
+ foreach ( $res as $page ) {
+ $title = Title::makeTitle( $page->page_namespace, $page->page_title );
+ $title->invalidateCache();
+ }
+ }
+
+ /**
+ * Add a source to the sources list if the transcode job is ready
+ *
+ * If the source is not found, it will not be used yet...
+ * Missing transcodes should be added by write tasks, not read tasks!
+ */
+ public static function addSourceIfReady( &$file, &$sources, $transcodeKey, $dataPrefix = '' ){
+ // Check if the transcode is ready:
+ if( self::isTranscodeReady( $file, $transcodeKey ) ){
+ $sources[] = self::getDerivativeSourceAttributes( $file, $transcodeKey, $dataPrefix );
+ }
+ }
+
+ /**
+ * Get the primary "source" asset used for other derivatives
+ * @param $file File
+ * @param $options array
+ * @return array
+ */
+ static public function getPrimarySourceAttributes( $file, $options = array() ){
+ global $wgLang;
+ $src = in_array( 'fullurl', $options)? wfExpandUrl( $file->getUrl() ) : $file->getUrl();
+
+ $bitrate = $file->getHandler()->getBitrate( $file );
+ $metadataType = $file->getHandler()->getMetadataType( $file );
+
+ // Give grep a chance to find the usages: timedmedia-ogg, timedmedia-webm,
+ // timedmedia-mp4, timedmedia-flac, timedmedia-wav
+ if( $file->getHandler()->isAudio( $file ) ){
+ $title = wfMessage( 'timedmedia-source-audio-file-desc',
+ wfMessage( 'timedmedia-' . $metadataType )->text() )
+ ->params( $wgLang->formatBitrate( $bitrate ) )->text();
+ } else {
+ $title = wfMessage( 'timedmedia-source-file-desc',
+ wfMessage( 'timedmedia-' . $metadataType )->text() )
+ ->numParams( $file->getWidth(), $file->getHeight() )
+ ->params( $wgLang->formatBitrate( $bitrate ) )->text();
+ }
+
+ // Give grep a chance to find the usages: timedmedia-ogg, timedmedia-webm,
+ // timedmedia-mp4, timedmedia-flac, timedmedia-wav
+ $source = array(
+ 'src' => $src,
+ 'type' => $file->getHandler()->getWebType( $file ),
+ 'title' => $title,
+ "shorttitle" => wfMessage(
+ 'timedmedia-source-file',
+ wfMessage( 'timedmedia-' . $metadataType )->text()
+ )->text(),
+ "width" => intval( $file->getWidth() ),
+ "height" => intval( $file->getHeight() ),
+ );
+
+ if( $bitrate ){
+ $source["bandwidth"] = round ( $bitrate );
+ }
+
+ // For video include framerate:
+ if( !$file->getHandler()->isAudio( $file ) ){
+ $framerate = $file->getHandler()->getFramerate( $file );
+ if( $framerate ){
+ $source[ "framerate" ] = floatval( $framerate );
+ }
+ }
+ return $source;
+ }
+
+ /**
+ * Get derivative "source" attributes
+ * @param $file File
+ * @param $transcodeKey string
+ * @param $options array
+ * @return array
+ */
+ static public function getDerivativeSourceAttributes($file, $transcodeKey, $options = array() ){
+ $fileName = $file->getTitle()->getDbKey();
+
+ $src = self::getTranscodedUrlForFile( $file, $transcodeKey );
+
+ if( $file->getHandler()->isAudio( $file ) ){
+ $width = $height = 0;
+ } else {
+ list( $width, $height ) = WebVideoTranscode::getMaxSizeTransform(
+ $file,
+ self::$derivativeSettings[$transcodeKey]['maxSize']
+ );
+ }
+
+ $framerate = ( isset( self::$derivativeSettings[$transcodeKey]['framerate'] ) )?
+ self::$derivativeSettings[$transcodeKey]['framerate'] :
+ $file->getHandler()->getFramerate( $file );
+ // Setup the url src:
+ $src = in_array( 'fullurl', $options) ? wfExpandUrl( $src ) : $src;
+ $fields = array(
+ 'src' => $src,
+ 'title' => wfMessage( 'timedmedia-derivative-desc-' . $transcodeKey )->text(),
+ 'type' => self::$derivativeSettings[ $transcodeKey ][ 'type' ],
+ "shorttitle" => wfMessage( 'timedmedia-derivative-' . $transcodeKey )->text(),
+ "transcodekey" => $transcodeKey,
+
+ // Add data attributes per emerging DASH / webTV adaptive streaming attributes
+ // eventually we will define a manifest xml entry point.
+ "width" => intval( $width ),
+ "height" => intval( $height ),
+ );
+
+ // a "ready" transcode should have a bitrate:
+ if ( isset( self::$transcodeState[$fileName] ) ) {
+ $fields["bandwidth"] = intval(
+ self::$transcodeState[$fileName][ $transcodeKey ]['final_bitrate']
+ );
+ }
+
+ if ( !$file->getHandler()->isAudio( $file ) ) {
+ $fields += array( "framerate" => floatval( $framerate ) );
+ }
+ return $fields;
+ }
+
+ /**
+ * Queue up all enabled transcodes if missing.
+ * @param $file File object
+ */
+ public static function startJobQueue( File $file ) {
+ global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet;
+ $keys = array_merge( $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet );
+
+ // 'Natural sort' puts the transcodes in ascending order by resolution,
+ // which roughly gives us fastest-to-slowest order.
+ natsort($keys);
+
+ foreach ( $keys as $tKey ) {
+ // Note the job queue will de-duplicate and handle various errors, so we
+ // can just blast out the full list here.
+ self::updateJobQueue( $file, $tKey );
+ }
+ }
+
+ /**
+ * Make sure all relevant transcodes for the given file are tracked in the
+ * transcodes table; add entries for any missing ones.
+ *
+ * @param $file File object
+ */
+ public static function cleanupTranscodes( File $file ) {
+ global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet;
+
+ $fileName = $file->getTitle()->getDbKey();
+ $db = $file->repo->getMasterDB();
+
+ $transcodeState = self::getTranscodeState( $file, $db );
+
+ $keys = array_merge( $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet );
+ foreach ( $keys as $transcodeKey ) {
+ if ( !self::isTranscodeEnabled( $file, $transcodeKey ) ) {
+ // This transcode is no longer enabled or erroneously included...
+ // Leave it in place, allowing it to be removed manually;
+ // it won't be used in playback and should be doing no harm.
+ continue;
+ }
+ if ( !isset( $transcodeState[ $transcodeKey ] ) ) {
+ $db->insert(
+ 'transcode',
+ array(
+ 'transcode_image_name' => $fileName,
+ 'transcode_key' => $transcodeKey,
+ 'transcode_time_addjob' => null,
+ 'transcode_error' => "",
+ 'transcode_final_bitrate' => 0
+ ),
+ __METHOD__,
+ array( 'IGNORE' )
+ );
+ }
+ }
+ }
+
+ /**
+ * Check if the given transcode key is appropriate for the file.
+ *
+ * @param $file File object
+ * @param $transcodeKey String transcode key
+ * @return boolean
+ */
+ public static function isTranscodeEnabled( File $file, $transcodeKey ) {
+ global $wgEnabledTranscodeSet, $wgEnabledAudioTranscodeSet;
+
+ $audio = $file->getHandler()->isAudio( $file );
+ if ( $audio ) {
+ $keys = $wgEnabledAudioTranscodeSet;
+ } else {
+ $keys = $wgEnabledTranscodeSet;
+ }
+
+ if ( in_array( $transcodeKey, $keys ) ) {
+ $settings = self::$derivativeSettings[$transcodeKey];
+ if ( $audio ) {
+ $sourceCodecs = $file->getHandler()->getStreamTypes( $file );
+ $sourceCodec = $sourceCodecs ? strtolower( $sourceCodecs[0] ) : '';
+ return ( $sourceCodec !== $settings['audioCodec'] );
+ } else if ( self::isTargetLargerThanFile( $file, $settings['maxSize'] ) ) {
+ // Are we the smallest enabled transcode for this type?
+ // Then go ahead and make a wee little transcode for compat.
+ return self::isSmallestTranscodeForCodec( $transcodeKey );
+ } else {
+ return true;
+ }
+ } else {
+ // Transcode key is invalid or has been disabled.
+ return false;
+ }
+ }
+
+ /**
+ * Update the job queue if the file is not already in the job queue:
+ * @param $file File object
+ * @param $transcodeKey String transcode key
+ */
+ public static function updateJobQueue( &$file, $transcodeKey ){
+ $fileName = $file->getTitle()->getDbKey();
+ $db = $file->repo->getMasterDB();
+
+ $transcodeState = self::getTranscodeState( $file, $db );
+
+ if ( !self::isTranscodeEnabled( $file, $transcodeKey ) ) {
+ return;
+ }
+
+ // If the job hasn't been added yet, attempt to do so
+ if ( !isset( $transcodeState[ $transcodeKey ] ) ) {
+ $db->insert(
+ 'transcode',
+ array(
+ 'transcode_image_name' => $fileName,
+ 'transcode_key' => $transcodeKey,
+ 'transcode_time_addjob' => $db->timestamp(),
+ 'transcode_error' => "",
+ 'transcode_final_bitrate' => 0
+ ),
+ __METHOD__,
+ array( 'IGNORE' )
+ );
+
+ if ( !$db->affectedRows() ) {
+ // There is already a row for that job added by another request, no need to continue
+ return;
+ }
+
+ $job = new WebVideoTranscodeJob( $file->getTitle(), array(
+ 'transcodeMode' => 'derivative',
+ 'transcodeKey' => $transcodeKey,
+ ) );
+
+ if ( $job->insert() ) {
+ // Clear the state cache ( now that we have updated the page )
+ self::clearTranscodeCache( $fileName );
+ } else {
+ // Adding job failed, update transcode row
+ $db->update(
+ 'transcode',
+ array(
+ 'transcode_time_error' => $db->timestamp(),
+ 'transcode_error' => "Failed to insert Job."
+ ),
+ array(
+ 'transcode_image_name' => $fileName,
+ 'transcode_key' => $transcodeKey,
+ ),
+ __METHOD__,
+ array( 'LIMIT' => 1 )
+ );
+ }
+ }
+ }
+
+ /**
+ * Transforms the size per a given "maxSize"
+ * if maxSize is > file, file size is used
+ * @param $file File
+ * @param $targetMaxSize int
+ * @return array
+ */
+ public static function getMaxSizeTransform( &$file, $targetMaxSize ){
+ $maxSize = self::getMaxSize( $targetMaxSize );
+ $sourceWidth = intval( $file->getWidth() );
+ $sourceHeight = intval( $file->getHeight() );
+ if ( $sourceHeight === 0 ) {
+ // Audio file
+ return array( 0, 0 );
+ }
+ $sourceAspect = $sourceWidth / $sourceHeight;
+ $targetWidth = $sourceWidth;
+ $targetHeight = $sourceHeight;
+ if ( $sourceAspect <= $maxSize['aspect'] ) {
+ if ( $sourceHeight > $maxSize['height'] ) {
+ $targetHeight = $maxSize['height'];
+ $targetWidth = intval( $targetHeight * $sourceAspect );
+ }
+ } else {
+ if ( $sourceWidth > $maxSize['width'] ) {
+ $targetWidth = $maxSize['width'];
+ $targetHeight = intval( $targetWidth / $sourceAspect );
+ //some players do not like uneven frame sizes
+ }
+ }
+ //some players do not like uneven frame sizes
+ $targetWidth += $targetWidth%2;
+ $targetHeight += $targetHeight%2;
+ return array( $targetWidth, $targetHeight );
+ }
+
+ /**
+ * Test if a given transcode target is larger than the source file
+ *
+ * @param $file File object
+ * @param $targetMaxSize string
+ * @return bool
+ */
+ public static function isTargetLargerThanFile( &$file, $targetMaxSize ){
+ $maxSize = self::getMaxSize( $targetMaxSize );
+ $sourceWidth = $file->getWidth();
+ $sourceHeight = $file->getHeight();
+ $sourceAspect = intval( $sourceWidth ) / intval( $sourceHeight );
+ if ( $sourceAspect <= $maxSize['aspect'] ) {
+ return ( $maxSize['height'] > $sourceHeight );
+ } else {
+ return ( $maxSize['width'] > $sourceWidth );
+ }
+ }
+
+ /**
+ * Is the given transcode key the smallest configured transcode for
+ * its video codec?
+ */
+ public static function isSmallestTranscodeForCodec( $transcodeKey ) {
+ global $wgEnabledTranscodeSet;
+
+ $settings = self::$derivativeSettings[$transcodeKey];
+ $vcodec = $settings['videoCodec'];
+ $maxSize = self::getMaxSize( $settings['maxSize'] );
+
+ foreach ( $wgEnabledTranscodeSet as $tKey ) {
+ $tsettings = self::$derivativeSettings[$tKey];
+ if ( $tsettings['videoCodec'] === $vcodec ) {
+ $tmaxSize = self::getMaxSize( $tsettings['maxSize'] );
+ if ( $tmaxSize['width'] < $maxSize['width'] ) {
+ return false;
+ }
+ if ( $tmaxSize['height'] < $maxSize['height'] ) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Return maxSize array for given maxSize setting
+ *
+ * @param $targetMaxSize string
+ * @return array
+ */
+ public static function getMaxSize( $targetMaxSize ){
+ $maxSize = array();
+ $targetMaxSize = explode( 'x', $targetMaxSize );
+ $maxSize['width'] = intval( $targetMaxSize[0] );
+ if ( count( $targetMaxSize ) == 1 ) {
+ $maxSize['height'] = intval( $targetMaxSize[0] );
+ } else {
+ $maxSize['height'] = intval( $targetMaxSize[1] );
+ }
+ // check for zero size ( audio )
+ if( $maxSize['width'] === 0 || $maxSize['height'] == 0 ){
+ return 0;
+ }
+ $maxSize['aspect'] = $maxSize['width'] / $maxSize['height'];
+ return $maxSize;
+ }
+}
diff --git a/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscodeJob.php b/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscodeJob.php
new file mode 100644
index 00000000..d437d9c7
--- /dev/null
+++ b/extensions/TimedMediaHandler/WebVideoTranscode/WebVideoTranscodeJob.php
@@ -0,0 +1,965 @@
+<?php
+/**
+ * Job for transcode jobs
+ *
+ * @file
+ * @ingroup JobQueue
+ */
+
+/**
+ * Job for web video transcode
+ *
+ * Support two modes
+ * 1) non-free media transcode ( delays the media file being inserted, adds note to talk page once ready)
+ * 2) derivatives for video ( makes new sources for the asset )
+ *
+ * @ingroup JobQueue
+ */
+
+class WebVideoTranscodeJob extends Job {
+ var $targetEncodeFile = null;
+ var $sourceFilePath = null;
+
+ /**
+ * @var File
+ */
+ var $file;
+
+ public function __construct( $title, $params, $id = 0 ) {
+ parent::__construct( 'webVideoTranscode', $title, $params, $id );
+ $this->removeDuplicates = true;
+ }
+
+ /**
+ * Local function to debug output ( jobs don't have access to the maintenance output class )
+ * @param $msg string
+ */
+ private function output( $msg ){
+ print $msg . "\n";
+ }
+
+ /**
+ * @return File
+ */
+ private function getFile() {
+ if( !$this->file ){
+ $this->file = wfLocalFile( $this->title );
+ }
+ return $this->file;
+ }
+
+ /**
+ * @return string
+ */
+ private function getTargetEncodePath(){
+ if( !$this->targetEncodeFile ){
+ $file = $this->getFile();
+ $transcodeKey = $this->params[ 'transcodeKey' ];
+ $this->targetEncodeFile = WebVideoTranscode::getTargetEncodeFile( $file, $transcodeKey );
+ $this->targetEncodeFile->bind( $this );
+ }
+ return $this->targetEncodeFile->getPath();
+ }
+ /**
+ * purge temporary encode target
+ */
+ private function purgeTargetEncodeFile () {
+ if ( $this->targetEncodeFile ) {
+ $this->targetEncodeFile->purge();
+ $this->targetEncodeFile = null;
+ }
+ }
+
+ /**
+ * @return string|bool
+ */
+ private function getSourceFilePath(){
+ if( !$this->sourceFilePath ){
+ $file = $this->getFile();
+ $this->source = $file->repo->getLocalReference( $file->getPath() );
+ if ( !$this->source ) {
+ $this->sourceFilePath = false;
+ } else {
+ $this->sourceFilePath = $this->source->getPath();
+ }
+ }
+ return $this->sourceFilePath;
+ }
+
+ /**
+ * Update the transcode table with failure time and error
+ * @param $transcodeKey string
+ * @param $error string
+ *
+ */
+ private function setTranscodeError( $transcodeKey, $error ){
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->update(
+ 'transcode',
+ array(
+ 'transcode_time_error' => $dbw->timestamp(),
+ 'transcode_error' => $error
+ ),
+ array(
+ 'transcode_image_name' => $this->getFile()->getName(),
+ 'transcode_key' => $transcodeKey
+ ),
+ __METHOD__
+ );
+ $this->setLastError( $error );
+ }
+
+ /**
+ * Run the transcode request
+ * @return boolean success
+ */
+ public function run() {
+ global $wgVersion, $wgFFmpeg2theoraLocation;
+ // get a local pointer to the file
+ $file = $this->getFile();
+
+ // Validate the file exists:
+ if( !$file ){
+ $this->output( $this->title . ': File not found ' );
+ return false;
+ }
+
+ // Validate the transcode key param:
+ $transcodeKey = $this->params['transcodeKey'];
+ // Build the destination target
+ if( ! isset( WebVideoTranscode::$derivativeSettings[ $transcodeKey ] )){
+ $error = "Transcode key $transcodeKey not found, skipping";
+ $this->output( $error );
+ $this->setLastError( $error );
+ return false;
+ }
+
+ // Validate the source exists:
+ if( !$this->getSourceFilePath() || !is_file( $this->getSourceFilePath() ) ){
+ $status = $this->title . ': Source not found ' . $this->getSourceFilePath();
+ $this->output( $status );
+ $this->setTranscodeError( $transcodeKey, $status );
+ return false;
+ }
+
+ $options = WebVideoTranscode::$derivativeSettings[ $transcodeKey ];
+
+ if ( isset( $options[ 'novideo' ] ) ) {
+ $this->output( "Encoding to audio codec: " . $options['audioCodec'] );
+ } else {
+ $this->output( "Encoding to codec: " . $options['videoCodec'] );
+ }
+
+ $dbw = wfGetDB( DB_MASTER );
+
+ // Check if we have "already started" the transcode ( possible error )
+ $dbStartTime = $dbw->selectField( 'transcode', 'transcode_time_startwork',
+ array(
+ 'transcode_image_name' => $this->getFile()->getName(),
+ 'transcode_key' => $transcodeKey
+ ),
+ __METHOD__
+ );
+ if( ! is_null( $dbStartTime ) ){
+ $error = 'Error, running transcode job, for job that has already started';
+ $this->output( $error );
+ return true;
+ }
+
+ // Update the transcode table letting it know we have "started work":
+ $jobStartTimeCache = $dbw->timestamp();
+ $dbw->update(
+ 'transcode',
+ array( 'transcode_time_startwork' => $jobStartTimeCache ),
+ array(
+ 'transcode_image_name' => $this->getFile()->getName(),
+ 'transcode_key' => $transcodeKey
+ ),
+ __METHOD__
+ );
+ // Avoid contention and "server has gone away" errors as
+ // the transcode will take a very long time in some cases
+ $dbw->commit( __METHOD__, 'flush' );
+
+ // Check the codec see which encode method to call;
+ if ( isset( $options[ 'novideo' ] ) ) {
+ $status = $this->ffmpegEncode( $options );
+ } elseif( $options['videoCodec'] == 'theora' && $wgFFmpeg2theoraLocation !== false ){
+ $status = $this->ffmpeg2TheoraEncode( $options );
+ } elseif( $options['videoCodec'] == 'vp8' || $options['videoCodec'] == 'vp9' || $options['videoCodec'] == 'h264' || ( $options['videoCodec'] == 'theora' && $wgFFmpeg2theoraLocation === false ) ){
+ // Check for twopass:
+ if( isset( $options['twopass'] ) ){
+ // ffmpeg requires manual two pass
+ $status = $this->ffmpegEncode( $options, 1 );
+ if( $status && !is_string($status) ){
+ $status = $this->ffmpegEncode( $options, 2 );
+ }
+ } else {
+ $status = $this->ffmpegEncode( $options );
+ }
+ } else {
+ wfDebug( 'Error unknown codec:' . $options['videoCodec'] );
+ $status = 'Error unknown target encode codec:' . $options['videoCodec'];
+ }
+
+ // Remove any log files all useful info should be in status and or we are done with 2 passs encoding
+ $this->removeFffmpgeLogFiles();
+
+ // Do a quick check to confirm the job was not restarted or removed while we were transcoding
+ // Confirm the in memory $jobStartTimeCache matches db start time
+ $dbStartTime = $dbw->selectField( 'transcode', 'transcode_time_startwork',
+ array(
+ 'transcode_image_name' => $this->getFile()->getName(),
+ 'transcode_key' => $transcodeKey
+ )
+ );
+
+ // Check for ( hopefully rare ) issue of or job restarted while transcode in progress
+ if( $dbw->timestamp( $jobStartTimeCache ) != $dbw->timestamp( $dbStartTime ) ){
+ $this->output('Possible Error, transcode task restarted, removed, or completed while transcode was in progress');
+ // if an error; just error out, we can't remove temp files or update states, because the new job may be doing stuff.
+ if( $status !== true ){
+ $this->setTranscodeError( $transcodeKey, $status );
+ return false;
+ }
+ // else just continue with db updates, and when the new job comes around it won't start because it will see
+ // that the job has already been started.
+ }
+
+ // If status is oky and target does not exist, reset status
+ if( $status === true && !is_file( $this->getTargetEncodePath() ) ) {
+ $status = 'Target does not exist: ' . $this->getTargetEncodePath();
+ }
+ // If status is ok and target is larger than 0 bytes
+ if( $status === true && filesize( $this->getTargetEncodePath() ) > 0 ){
+ $file = $this->getFile();
+ $storeOptions = null;
+ if ( version_compare( $wgVersion, '1.23c', '>' ) &&
+ strpos( $options['type'], '/ogg' ) !== false &&
+ $file->getLength()
+ ) {
+ // Ogg files need a duration header for firefox
+ $storeOptions['headers']['X-Content-Duration'] = floatval( $file->getLength() );
+ }
+
+ // Copy derivative from the FS into storage at $finalDerivativeFilePath
+ $result = $file->getRepo()->quickImport(
+ $this->getTargetEncodePath(), // temp file
+ WebVideoTranscode::getDerivativeFilePath( $file, $transcodeKey ), // storage
+ $storeOptions
+ );
+ if ( !$result->isOK() ) {
+ // no need to invalidate all pages with video. Because all pages remain valid ( no $transcodeKey derivative )
+ // just clear the file page ( so that the transcode table shows the error )
+ $this->title->invalidateCache();
+ $this->setTranscodeError( $transcodeKey, $result->getWikiText() );
+ $status = false;
+ } else {
+ $bitrate = round( intval( filesize( $this->getTargetEncodePath() ) / $file->getLength() ) * 8 );
+ //wfRestoreWarnings();
+ // Update the transcode table with success time:
+ $dbw->update(
+ 'transcode',
+ array(
+ 'transcode_error' => '',
+ 'transcode_time_success' => $dbw->timestamp(),
+ 'transcode_final_bitrate' => $bitrate
+ ),
+ array(
+ 'transcode_image_name' => $this->getFile()->getName(),
+ 'transcode_key' => $transcodeKey,
+ ),
+ __METHOD__
+ );
+ $dbw->commit( __METHOD__, 'flush' );
+ WebVideoTranscode::invalidatePagesWithFile( $this->title );
+ }
+ } else {
+ // Update the transcode table with failure time and error
+ $this->setTranscodeError( $transcodeKey, $status );
+ // no need to invalidate all pages with video. Because all pages remain valid ( no $transcodeKey derivative )
+ // just clear the file page ( so that the transcode table shows the error )
+ $this->title->invalidateCache();
+ }
+ //done with encoding target, clean up
+ $this->purgeTargetEncodeFile();
+
+ // Clear the webVideoTranscode cache ( so we don't keep out dated table cache around )
+ WebVideoTranscode::clearTranscodeCache( $this->title->getDBkey() );
+
+ $url = WebVideoTranscode::getTranscodedUrlForFile( $file, $transcodeKey );
+ SquidUpdate::purge( array( $url ) );
+
+ if ($status !== true) {
+ $this->setLastError( $status );
+ }
+ return $status === true;
+ }
+
+ function removeFffmpgeLogFiles(){
+ $path = $this->getTargetEncodePath();
+ $dir = dirname( $path );
+ if ( is_dir( $dir ) ) {
+ $dh = opendir( $dir );
+ if ( $dh ) {
+ while ( ($file = readdir($dh)) !== false ) {
+ $log_path = "$dir/$file";
+ $ext = strtolower( pathinfo( $log_path, PATHINFO_EXTENSION ) );
+ if( $ext == 'log' && substr( $log_path, 0 , strlen($path) ) == $path ){
+ wfSuppressWarnings();
+ unlink( $log_path );
+ wfRestoreWarnings();
+ }
+ }
+ closedir( $dh );
+ }
+ }
+ }
+
+ /**
+ * Utility helper for ffmpeg and ffmpeg2theora mapping
+ * @param $options array
+ * @param $pass int
+ * @return bool|string
+ */
+ function ffmpegEncode( $options, $pass=0 ){
+ global $wgFFmpegLocation, $wgTranscodeBackgroundMemoryLimit;
+
+ if( !is_file( $this->getSourceFilePath() ) ) {
+ return "source file is missing, " . $this->getSourceFilePath() . ". Encoding failed.";
+ }
+
+ // Set up the base command
+ $cmd = wfEscapeShellArg( $wgFFmpegLocation ) . ' -y -i ' . wfEscapeShellArg( $this->getSourceFilePath() );
+
+
+ if( isset( $options['vpre'] ) ){
+ $cmd.= ' -vpre ' . wfEscapeShellArg( $options['vpre'] );
+ }
+
+ if ( isset( $options['novideo'] ) ) {
+ $cmd.= " -vn ";
+ } elseif( $options['videoCodec'] == 'vp8' || $options['videoCodec'] == 'vp9' ){
+ $cmd.= $this->ffmpegAddWebmVideoOptions( $options, $pass );
+ } elseif( $options['videoCodec'] == 'h264'){
+ $cmd.= $this->ffmpegAddH264VideoOptions( $options, $pass );
+ } elseif( $options['videoCodec'] == 'theora'){
+ $cmd.= $this->ffmpegAddTheoraVideoOptions( $options, $pass );
+ }
+ // Add size options:
+ $cmd .= $this->ffmpegAddVideoSizeOptions( $options ) ;
+
+ // Check for start time
+ if( isset( $options['starttime'] ) ){
+ $cmd.= ' -ss ' . wfEscapeShellArg( $options['starttime'] );
+ } else {
+ $options['starttime'] = 0;
+ }
+ // Check for end time:
+ if( isset( $options['endtime'] ) ){
+ $cmd.= ' -t ' . intval( $options['endtime'] ) - intval($options['starttime'] ) ;
+ }
+
+ if ( $pass == 1 || isset( $options['noaudio'] ) ) {
+ $cmd.= ' -an';
+ } else {
+ $cmd.= $this->ffmpegAddAudioOptions( $options, $pass );
+ }
+
+ if ( $pass != 0 ) {
+ $cmd.=" -pass " .wfEscapeShellArg( $pass ) ;
+ $cmd.=" -passlogfile " . wfEscapeShellArg( $this->getTargetEncodePath() .'.log' );
+ }
+ // And the output target:
+ if ($pass == 1) {
+ $cmd.= ' /dev/null';
+ } else{
+ $cmd.= " " . $this->getTargetEncodePath();
+ }
+
+ $this->output( "Running cmd: \n\n" .$cmd . "\n" );
+
+ // Right before we output remove the old file
+ $retval = 0;
+ $shellOutput = $this->runShellExec( $cmd, $retval );
+
+ if( $retval != 0 ){
+ return $cmd .
+ "\n\nExitcode: $retval\nMemory: $wgTranscodeBackgroundMemoryLimit\n\n" .
+ $shellOutput;
+ }
+ return true;
+ }
+
+ /**
+ * Adds ffmpeg shell options for h264
+ *
+ * @param $options
+ * @param $pass
+ * @return string
+ */
+ function ffmpegAddH264VideoOptions( $options, $pass ){
+ global $wgFFmpegThreads;
+ // Set the codec:
+ $cmd= " -threads " . intval( $wgFFmpegThreads ) . " -vcodec libx264";
+ // Check for presets:
+ if( isset( $options['preset'] ) ){
+ // Add the two vpre types:
+ switch( $options['preset'] ){
+ case 'ipod320':
+ $cmd .= " -profile:v baseline -preset slow -coder 0 -bf 0 -weightb 1 -level 13 -maxrate 768k -bufsize 3M";
+ break;
+ case '720p':
+ case 'ipod640':
+ $cmd .= " -profile:v baseline -preset slow -coder 0 -bf 0 -refs 1 -weightb 1 -level 31 -maxrate 10M -bufsize 10M";
+ break;
+ default:
+ // in the default case just pass along the preset to ffmpeg
+ $cmd.= " -vpre " . wfEscapeShellArg( $options['preset'] );
+ break;
+ }
+ }
+ if( isset( $options['videoBitrate'] ) ){
+ $cmd.= " -b " . wfEscapeShellArg ( $options['videoBitrate'] );
+ }
+ // Output mp4
+ $cmd.=" -f mp4";
+ return $cmd;
+ }
+
+ function ffmpegAddVideoSizeOptions( $options ){
+ $cmd = '';
+ // Get a local pointer to the file object
+ $file = $this->getFile();
+
+ // Check for aspect ratio ( we don't do anything with this right now)
+ if ( isset( $options['aspect'] ) ) {
+ $aspectRatio = $options['aspect'];
+ } else {
+ $aspectRatio = $file->getWidth() . ':' . $file->getHeight();
+ }
+ if (isset( $options['maxSize'] )) {
+ // Get size transform ( if maxSize is > file, file size is used:
+
+ list( $width, $height ) = WebVideoTranscode::getMaxSizeTransform( $file, $options['maxSize'] );
+ $cmd.= ' -s ' . intval( $width ) . 'x' . intval( $height );
+ } elseif (
+ (isset( $options['width'] ) && $options['width'] > 0 )
+ &&
+ (isset( $options['height'] ) && $options['height'] > 0 )
+ ){
+ $cmd.= ' -s ' . intval( $options['width'] ) . 'x' . intval( $options['height'] );
+ }
+
+ // Handle crop:
+ $optionMap = array(
+ 'cropTop' => '-croptop',
+ 'cropBottom' => '-cropbottom',
+ 'cropLeft' => '-cropleft',
+ 'cropRight' => '-cropright'
+ );
+ foreach( $optionMap as $name => $cmdArg ){
+ if( isset($options[$name]) ){
+ $cmd.= " $cmdArg " . wfEscapeShellArg( $options[$name] );
+ }
+ }
+ return $cmd;
+ }
+ /**
+ * Adds ffmpeg shell options for webm
+ *
+ * @param $options
+ * @param $pass
+ * @return string
+ */
+ function ffmpegAddWebmVideoOptions( $options, $pass ){
+ global $wgFFmpegThreads;
+
+ // Get a local pointer to the file object
+ $file = $this->getFile();
+
+ $cmd =' -threads ' . intval( $wgFFmpegThreads );
+
+ // check for presets:
+ if( isset($options['preset']) ){
+ if ($options['preset'] == "360p") {
+ $cmd.= " -vpre libvpx-360p";
+ } elseif ( $options['preset'] == "720p" ) {
+ $cmd.= " -vpre libvpx-720p";
+ } elseif ( $options['preset'] == "1080p" ) {
+ $cmd.= " -vpre libvpx-1080p";
+ }
+ }
+
+ // Add the boiler plate vp8 ffmpeg command:
+ $cmd.=" -skip_threshold 0 -bufsize 6000k -rc_init_occupancy 4000";
+
+ // Check for video quality:
+ if ( isset( $options['videoQuality'] ) && $options['videoQuality'] >= 0 ) {
+ // Map 0-10 to 63-0, higher values worse quality
+ $quality = 63 - intval( intval( $options['videoQuality'] )/10 * 63 );
+ $cmd .= " -qmin " . wfEscapeShellArg( $quality );
+ $cmd .= " -qmax " . wfEscapeShellArg( $quality );
+ }
+
+ // Check for video bitrate:
+ if ( isset( $options['videoBitrate'] ) ) {
+ $cmd.= " -qmin 1 -qmax 51";
+ $cmd.= " -vb " . wfEscapeShellArg( $options['videoBitrate'] * 1000 );
+ }
+ // Set the codec:
+ if ( $options['videoCodec'] === 'vp9' ) {
+ $cmd.= " -vcodec libvpx-vp9";
+ if ( isset( $options['tileColumns'] ) ) {
+ $cmd.= ' -tile-columns ' . wfEscapeShellArg( $options['tileColumns'] );
+ }
+ } else {
+ $cmd.= " -vcodec libvpx";
+ }
+
+ // Check for keyframeInterval
+ if( isset( $options['keyframeInterval'] ) ){
+ $cmd.= ' -g ' . wfEscapeShellArg( $options['keyframeInterval'] );
+ $cmd.= ' -keyint_min ' . wfEscapeShellArg( $options['keyframeInterval'] );
+ }
+ if( isset( $options['deinterlace'] ) ){
+ $cmd.= ' -deinterlace';
+ }
+
+ // Output WebM
+ $cmd.=" -f webm";
+
+ return $cmd;
+ }
+
+ /**
+ * Adds ffmpeg/avconv shell options for ogg
+ *
+ * Used only when $wgFFmpeg2theoraLocation set to false.
+ * Warning: does not create Ogg skeleton metadata track.
+ *
+ * @param $options
+ * @param $pass
+ * @return string
+ */
+ function ffmpegAddTheoraVideoOptions( $options, $pass ){
+ global $wgFFmpegThreads;
+
+ // Get a local pointer to the file object
+ $file = $this->getFile();
+
+ $cmd =' -threads ' . intval( $wgFFmpegThreads );
+
+ // Check for video quality:
+ if ( isset( $options['videoQuality'] ) && $options['videoQuality'] >= 0 ) {
+ // Map 0-10 to 63-0, higher values worse quality
+ $quality = 63 - intval( intval( $options['videoQuality'] )/10 * 63 );
+ $cmd .= " -qmin " . wfEscapeShellArg( $quality );
+ $cmd .= " -qmax " . wfEscapeShellArg( $quality );
+ }
+
+ // Check for video bitrate:
+ if ( isset( $options['videoBitrate'] ) ) {
+ $cmd.= " -qmin 1 -qmax 51";
+ $cmd.= " -vb " . wfEscapeShellArg( $options['videoBitrate'] * 1000 );
+ }
+ // Set the codec:
+ $cmd.= " -vcodec theora";
+
+ // Check for keyframeInterval
+ if( isset( $options['keyframeInterval'] ) ){
+ $cmd.= ' -g ' . wfEscapeShellArg( $options['keyframeInterval'] );
+ $cmd.= ' -keyint_min ' . wfEscapeShellArg( $options['keyframeInterval'] );
+ }
+ if( isset( $options['deinterlace'] ) ){
+ $cmd.= ' -deinterlace';
+ }
+ if( isset( $options['framerate'] ) ) {
+ $cmd.= ' -r ' . wfEscapeShellArg( $options['framerate'] );
+ }
+
+ // Output Ogg
+ $cmd.=" -f ogg";
+
+ return $cmd;
+ }
+
+ /**
+ * @param $options array
+ * @param $pass
+ * @return string
+ */
+ function ffmpegAddAudioOptions( $options, $pass ){
+ $cmd ='';
+ if( isset( $options['audioQuality'] ) ){
+ $cmd.= " -aq " . wfEscapeShellArg( $options['audioQuality'] );
+ }
+ if( isset( $options['audioBitrate'] )){
+ $cmd.= ' -ab ' . intval( $options['audioBitrate'] ) * 1000;
+ }
+ if( isset( $options['samplerate'] ) ){
+ $cmd.= " -ar " . wfEscapeShellArg( $options['samplerate'] );
+ }
+ if( isset( $options['channels'] ) ){
+ $cmd.= " -ac " . wfEscapeShellArg( $options['channels'] );
+ }
+
+ if( isset( $options['audioCodec'] ) ){
+ $encoders = array(
+ 'vorbis' => 'libvorbis',
+ 'opus' => 'libopus',
+ 'mp3' => 'libmp3lame',
+ );
+ if ( isset( $encoders[ $options['audioCodec'] ] ) ) {
+ $codec = $encoders[ $options['audioCodec'] ];
+ } else {
+ $codec = $options['audioCodec'];
+ }
+ $cmd.= " -acodec " . wfEscapeShellArg( $codec );
+ if ( $codec === 'aac' ) {
+ // the aac encoder is currently "experimental" in libav 9? :P
+ $cmd .= ' -strict experimental';
+ }
+ } else {
+ // if no audio codec set use vorbis :
+ $cmd.= " -acodec libvorbis ";
+ }
+ return $cmd;
+ }
+
+ /**
+ * ffmpeg2Theora mapping is much simpler since it is the basis of the the firefogg API
+ * @param $options array
+ * @return bool|string
+ */
+ function ffmpeg2TheoraEncode( $options ){
+ global $wgFFmpeg2theoraLocation, $wgTranscodeBackgroundMemoryLimit;
+
+ if( !is_file( $this->getSourceFilePath() ) ) {
+ return "source file is missing, " . $this->getSourceFilePath() . ". Encoding failed.";
+ }
+
+ // Set up the base command
+ $cmd = wfEscapeShellArg( $wgFFmpeg2theoraLocation ) . ' ' . wfEscapeShellArg( $this->getSourceFilePath() );
+
+ $file = $this->getFile();
+
+ if( isset( $options['maxSize'] ) ){
+ list( $width, $height ) = WebVideoTranscode::getMaxSizeTransform( $file, $options['maxSize'] );
+ $options['width'] = $width;
+ $options['height'] = $height;
+ $options['aspect'] = $width . ':' . $height;
+ unset( $options['maxSize'] );
+ }
+
+ // Add in the encode settings
+ foreach( $options as $key => $val ){
+ if( isset( self::$foggMap[$key] ) ){
+ if( is_array( self::$foggMap[$key] ) ){
+ $cmd.= ' '. implode(' ', self::$foggMap[$key] );
+ } elseif ($val == 'true' || $val === true){
+ $cmd.= ' '. self::$foggMap[$key];
+ } elseif ($val == 'false' || $val === false){
+ //ignore "false" flags
+ } else {
+ //normal get/set value
+ $cmd.= ' '. self::$foggMap[$key] . ' ' . wfEscapeShellArg( $val );
+ }
+ }
+ }
+
+ // Add the output target:
+ $outputFile = $this->getTargetEncodePath();
+ $cmd.= ' -o ' . wfEscapeShellArg ( $outputFile );
+
+ $this->output( "Running cmd: \n\n" .$cmd . "\n" );
+
+ $retval = 0;
+ $shellOutput = $this->runShellExec( $cmd, $retval );
+
+ // ffmpeg2theora returns 0 status on some errors, so also check for file
+ if( $retval != 0 || !is_file( $outputFile ) || filesize( $outputFile ) === 0 ){
+ return $cmd .
+ "\n\nExitcode: $retval\nMemory: $wgTranscodeBackgroundMemoryLimit\n\n" .
+ $shellOutput;
+ }
+ return true;
+ }
+
+ /**
+ * Runs the shell exec command.
+ * if $wgEnableBackgroundTranscodeJobs is enabled will mannage a background transcode task
+ * else it just directly passes off to wfShellExec
+ *
+ * @param $cmd String Command to be run
+ * @param $retval String, refrence variable to return the exit code
+ * @return string
+ */
+ public function runShellExec( $cmd, &$retval ){
+ global $wgTranscodeBackgroundTimeLimit,
+ $wgTranscodeBackgroundMemoryLimit,
+ $wgTranscodeBackgroundSizeLimit,
+ $wgEnableNiceBackgroundTranscodeJobs;
+
+ // For profiling
+ $caller = wfGetCaller();
+
+ // Check if background tasks are enabled
+ if( $wgEnableNiceBackgroundTranscodeJobs === false ){
+ // Directly execute the shell command:
+ $limits = array(
+ "filesize" => $wgTranscodeBackgroundSizeLimit,
+ "memory" => $wgTranscodeBackgroundMemoryLimit,
+ "time" => $wgTranscodeBackgroundTimeLimit
+ );
+ return wfShellExec( $cmd . ' 2>&1', $retval , array(), $limits,
+ array( 'profileMethod' => $caller ) );
+ }
+
+ $encodingLog = $this->getTargetEncodePath() . '.stdout.log';
+ $retvalLog = $this->getTargetEncodePath() . '.retval.log';
+ // Check that we can actually write to these files
+ //( no point in running the encode if we can't write )
+ wfSuppressWarnings();
+ if( ! touch( $encodingLog) || ! touch( $retvalLog ) ){
+ wfRestoreWarnings();
+ $retval = 1;
+ return "Error could not write to target location";
+ }
+ wfRestoreWarnings();
+
+ // Fork out a process for running the transcode
+ $pid = pcntl_fork();
+ if ($pid == -1) {
+ $errorMsg = '$wgEnableNiceBackgroundTranscodeJobs enabled but failed pcntl_fork';
+ $retval = 1;
+ $this->output( $errorMsg);
+ return $errorMsg;
+ } elseif ( $pid == 0) {
+ // we are the child
+ $this->runChildCmd( $cmd, $retval, $encodingLog, $retvalLog, $caller );
+ // dont remove any temp files in the child process, this is done
+ // once the parent is finished
+ $this->targetEncodeFile->preserve();
+ if ( $this->source instanceof TempFSFile ) {
+ $this->source->preserve();
+ }
+ // exit with the same code as the transcode:
+ exit( $retval );
+ } else {
+ // we are the parent monitor and return status
+ return $this->monitorTranscode($pid, $retval, $encodingLog, $retvalLog);
+ }
+ }
+
+ /**
+ * @param $cmd
+ * @param $retval
+ * @param $encodingLog
+ * @param $retvalLog
+ * @param string $caller The calling method
+ */
+ public function runChildCmd( $cmd, &$retval, $encodingLog, $retvalLog, $caller ){
+ global $wgTranscodeBackgroundTimeLimit,
+ $wgTranscodeBackgroundMemoryLimit,
+ $wgTranscodeBackgroundSizeLimit;
+ // In theory we should use pcntl_exec but not sure how to get the stdout, ensure
+ // we don't max php memory with the same protections provided by wfShellExec.
+
+ // pcntl_exec requires a direct path to the exe and arguments as an array:
+ //$cmd = explode(' ', $cmd );
+ //$baseCmd = array_shift( $cmd );
+ //print "run:" . $baseCmd . " args: " . print_r( $cmd, true );
+ //$status = pcntl_exec($baseCmd , $cmd );
+
+ // Directly execute the shell command:
+ //global $wgTranscodeBackgroundPriority;
+ //$status = wfShellExec( 'nice -n ' . $wgTranscodeBackgroundPriority . ' '. $cmd . ' 2>&1', $retval );
+ $limits = array(
+ "filesize" => $wgTranscodeBackgroundSizeLimit,
+ "memory" => $wgTranscodeBackgroundMemoryLimit,
+ "time" => $wgTranscodeBackgroundTimeLimit
+ );
+ $status = wfShellExec( $cmd . ' 2>&1', $retval , array(), $limits,
+ array( 'profileMethod' => $caller ) );
+
+ // Output the status:
+ wfSuppressWarnings();
+ file_put_contents( $encodingLog, $status );
+ // Output the retVal to the $retvalLog
+ file_put_contents( $retvalLog, $retval );
+ wfRestoreWarnings();
+ }
+
+ /**
+ * @param $pid
+ * @param $retval
+ * @param $encodingLog
+ * @param $retvalLog
+ * @return string
+ */
+ public function monitorTranscode( $pid, &$retval, $encodingLog, $retvalLog ){
+ global $wgTranscodeBackgroundTimeLimit, $wgLang;
+ $errorMsg = '';
+ $loopCount = 0;
+ $oldFileSize = 0;
+ $startTime = time();
+ $fileIsNotGrowing = false;
+
+ $this->output( "Encoding with pid: $pid \npcntl_waitpid: " . pcntl_waitpid( $pid, $status, WNOHANG OR WUNTRACED) .
+ "\nisProcessRunning: " . self::isProcessRunningKillZombie( $pid ) . "\n" );
+
+ // Check that the child process is still running ( note this does not work well with pcntl_waitpid
+ // for some reason :(
+ while( self::isProcessRunningKillZombie( $pid ) ) {
+ //$this->output( "$pid is running" );
+
+ // Check that the target file is growing ( every 5 seconds )
+ if( $loopCount == 10 ){
+ // only run check if we are outputing to target file
+ // ( two pass encoding does not output to target on first pass )
+ clearstatcache();
+ $newFileSize = is_file( $this->getTargetEncodePath() ) ? filesize( $this->getTargetEncodePath() ) : 0;
+ // Don't start checking for file growth until we have an initial positive file size:
+ if( $newFileSize > 0 ){
+ $this->output( $wgLang->formatSize( $newFileSize ). ' Total size, encoding ' .
+ $wgLang->formatSize( ( $newFileSize - $oldFileSize ) / 5 ) . ' per second' );
+ if( $newFileSize == $oldFileSize ){
+ if( $fileIsNotGrowing ){
+ $errorMsg = "Target File is not increasing in size, kill process.";
+ $this->output( $errorMsg );
+ // file is not growing in size, kill proccess
+ $retval = 1;
+
+ //posix_kill( $pid, 9);
+ self::killProcess( $pid );
+ break;
+ }
+ // Wait an additional 5 seconds of the file not growing to confirm
+ // the transcode is frozen.
+ $fileIsNotGrowing = true;
+ } else {
+ $fileIsNotGrowing = false;
+ }
+ $oldFileSize = $newFileSize;
+ }
+ // reset the loop counter
+ $loopCount = 0;
+ }
+
+ // Check if we have global job run-time has been exceeded:
+ if ( $wgTranscodeBackgroundTimeLimit && time() - $startTime > $wgTranscodeBackgroundTimeLimit ){
+ $errorMsg = "Encoding exceeded max job run time ( "
+ . TimedMediaHandler::seconds2npt( $wgTranscodeBackgroundTimeLimit ) . " ), kill process.";
+ $this->output( $errorMsg );
+ // File is not growing in size, kill proccess
+ $retval = 1;
+ //posix_kill( $pid, 9);
+ self::killProcess( $pid );
+ break;
+ }
+
+ // Sleep for one second before repeating loop
+ $loopCount++;
+ sleep( 1 );
+ }
+
+ $returnPcntl = pcntl_wexitstatus( $status );
+ // check status
+ wfSuppressWarnings();
+ $returnCodeFile = file_get_contents( $retvalLog );
+ wfRestoreWarnings();
+ //$this->output( "TranscodeJob:: Child pcntl return:". $returnPcntl . ' Log file exit code:' . $returnCodeFile . "\n" );
+
+ // File based exit code seems more reliable than pcntl_wexitstatus
+ $retval = $returnCodeFile;
+
+ // return the encoding log contents ( will be inserted into error table if an error )
+ // ( will be ignored and removed if success )
+ if( $errorMsg!= '' ){
+ $errorMsg.="\n\n";
+ }
+ return $errorMsg . file_get_contents( $encodingLog );
+ }
+
+ /**
+ * check if proccess is running and not a zombie
+ * @param $pid int
+ * @return bool
+ */
+ public static function isProcessRunningKillZombie( $pid ){
+ exec( "ps $pid", $processState );
+ if( !isset( $processState[1] ) ){
+ return false;
+ }
+ if( strpos( $processState[1], '<defunct>' ) !== false ){
+ // posix kill does not seem to work
+ //posix_kill( $pid, 9);
+ self::killProcess( $pid );
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Kill Application PID
+ *
+ * @param $pid int
+ * @return bool
+ */
+ public static function killProcess( $pid ){
+ exec( "kill -9 $pid" );
+ exec( "ps $pid", $processState );
+ if( isset( $processState[1] ) ){
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Mapping between firefogg api and ffmpeg2theora command line
+ *
+ * This lets us share a common api between firefogg and WebVideoTranscode
+ * also see: http://firefogg.org/dev/index.html
+ */
+ public static $foggMap = array(
+ // video
+ 'width' => "--width",
+ 'height' => "--height",
+ 'maxSize' => "--max_size",
+ 'noUpscaling' => "--no-upscaling",
+ 'videoQuality'=> "-v",
+ 'videoBitrate' => "-V",
+ 'twopass' => "--two-pass",
+ 'optimize' => "--optimize",
+ 'framerate' => "-F",
+ 'aspect' => "--aspect",
+ 'starttime' => "--starttime",
+ 'endtime' => "--endtime",
+ 'cropTop' => "--croptop",
+ 'cropBottom' => "--cropbottom",
+ 'cropLeft' => "--cropleft",
+ 'cropRight' => "--cropright",
+ 'keyframeInterval'=> "--keyint",
+ 'denoise' => array("--pp", "de"),
+ 'deinterlace' => "--deinterlace",
+ 'novideo' => array("--novideo", "--no-skeleton"),
+ 'bufDelay' => "--buf-delay",
+ // audio
+ 'audioQuality' => "-a",
+ 'audioBitrate' => "-A",
+ 'samplerate' => "-H",
+ 'channels' => "-c",
+ 'noaudio' => "--noaudio",
+ // metadata
+ 'artist' => "--artist",
+ 'title' => "--title",
+ 'date' => "--date",
+ 'location' => "--location",
+ 'organization' => "--organization",
+ 'copyright' => "--copyright",
+ 'license' => "--license",
+ 'contact' => "--contact"
+ );
+
+}
diff --git a/extensions/TimedMediaHandler/archives/transcode_name_key.sql b/extensions/TimedMediaHandler/archives/transcode_name_key.sql
new file mode 100644
index 00000000..85b00858
--- /dev/null
+++ b/extensions/TimedMediaHandler/archives/transcode_name_key.sql
@@ -0,0 +1,3 @@
+-- Add unique constrain on name/key
+DROP INDEX /*i*/transcode_name_inx ON /*_*/transcode;
+CREATE UNIQUE INDEX /*i*/transcode_name_key ON /*_*/transcode (transcode_image_name,transcode_key);
diff --git a/extensions/TimedMediaHandler/composer.json b/extensions/TimedMediaHandler/composer.json
new file mode 100644
index 00000000..3d55a97d
--- /dev/null
+++ b/extensions/TimedMediaHandler/composer.json
@@ -0,0 +1,10 @@
+{
+ "require-dev": {
+ "jakub-onderka/php-parallel-lint": "0.9.*"
+ },
+ "scripts": {
+ "test": [
+ "parallel-lint . --exclude vendor"
+ ]
+ }
+}
diff --git a/extensions/TimedMediaHandler/gitinfo.json b/extensions/TimedMediaHandler/gitinfo.json
new file mode 100644
index 00000000..d26a9734
--- /dev/null
+++ b/extensions/TimedMediaHandler/gitinfo.json
@@ -0,0 +1 @@
+{"headSHA1": "7cab54e2e482d51df69e4b9c880182b23cabf0bc\n", "head": "7cab54e2e482d51df69e4b9c880182b23cabf0bc\n", "remoteURL": "https://gerrit.wikimedia.org/r/mediawiki/extensions/TimedMediaHandler", "branch": "7cab54e2e482d51df69e4b9c880182b23cabf0bc\n", "headCommitDate": "1453929642"} \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/handlers/FLACHandler/FLACHandler.php b/extensions/TimedMediaHandler/handlers/FLACHandler/FLACHandler.php
new file mode 100644
index 00000000..f08c9b90
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/FLACHandler/FLACHandler.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * FLAC handler
+ */
+class FLACHandler extends ID3Handler {
+
+ /**
+ * @param $file File
+ * @return string
+ */
+ function getMetadataType( $file ) {
+ return 'flac';
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getWebType( $file ) {
+ return 'audio/flac';
+ }
+
+ /**
+ * @param $file File
+ * @return array|bool
+ */
+ function getStreamTypes( $file ) {
+ $streamTypes = array();
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return false;
+ }
+
+ if( isset( $metadata['audio'] ) && $metadata['audio']['dataformat'] == 'flac' ){
+ $streamTypes[] = 'FLAC';
+ }
+
+ return $streamTypes;
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getShortDesc( $file ) {
+ global $wgLang;
+
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return parent::getShortDesc( $file );
+ }
+ return wfMessage( 'timedmedia-flac-short-audio',
+ $wgLang->formatTimePeriod( $this->getLength( $file ) ) )->text();
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getLongDesc( $file ) {
+ global $wgLang;
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return parent::getLongDesc( $file );
+ }
+ return wfMessage('timedmedia-flac-long-audio',
+ $wgLang->formatTimePeriod( $this->getLength($file) ),
+ $wgLang->formatBitrate( $this->getBitRate( $file ) )
+ )->text();
+
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/handlers/ID3Handler/ID3Handler.php b/extensions/TimedMediaHandler/handlers/ID3Handler/ID3Handler.php
new file mode 100644
index 00000000..1e3ae4fb
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/ID3Handler/ID3Handler.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * getID3 Metadata handler
+ */
+class ID3Handler extends TimedMediaHandler {
+ // XXX match GETID3_VERSION ( too bad version is not a getter )
+ const METADATA_VERSION = 2;
+
+ /**
+ * @param $path string
+ * @return array
+ */
+ protected function getID3( $path ) {
+ // Create new id3 object:
+ $getID3 = new getID3();
+
+ // Don't grab stuff we don't use:
+ $getID3->option_tag_id3v1 = false; // Read and process ID3v1 tags
+ $getID3->option_tag_id3v2 = false; // Read and process ID3v2 tags
+ $getID3->option_tag_lyrics3 = false; // Read and process Lyrics3 tags
+ $getID3->option_tag_apetag = false; // Read and process APE tags
+ $getID3->option_tags_process = false; // Copy tags to root key 'tags' and encode to $this->encoding
+ $getID3->option_tags_html = false; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
+
+ // Analyze file to get metadata structure:
+ $id3 = $getID3->analyze( $path );
+
+ // remove file paths
+ unset( $id3['filename'] );
+ unset( $id3['filepath'] );
+ unset( $id3['filenamepath']);
+
+ // Update the version
+ $id3['version'] = self::METADATA_VERSION;
+
+ return $id3;
+ }
+
+ /**
+ * @param $file File
+ * @param $path string
+ * @return string
+ */
+ function getMetadata( $file, $path ) {
+ $id3 = $this->getID3( $path );
+ return serialize( $id3 );
+ }
+
+ /**
+ * @param $metadata
+ * @return bool|mixed
+ */
+ function unpackMetadata( $metadata ) {
+ wfSuppressWarnings();
+ $unser = unserialize( $metadata );
+ wfRestoreWarnings();
+ if ( isset( $unser['version'] ) && $unser['version'] == self::METADATA_VERSION ) {
+ return $unser;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param $file File
+ * @return mixed
+ */
+ function getBitrate( $file ){
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) || !isset( $metadata['bitrate'] ) ) {
+ return 0;
+ } else {
+ return $metadata['bitrate'];
+ }
+ }
+
+ /**
+ * @param $file File
+ * @return int
+ */
+ function getLength( $file ) {
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) || !isset( $metadata['playtime_seconds'] ) ) {
+ return 0;
+ } else {
+ return $metadata['playtime_seconds'];
+ }
+ }
+
+ /**
+ * @param $file File
+ * @return bool|int
+ */
+ function getFramerate( $file ){
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return 0;
+ } else {
+ // return the frame rate of the first found video stream:
+ if( isset( $metadata['video'] )
+ && isset( $metadata['video']['frame_rate'] ) ) {
+ return $metadata['video']['frame_rate'];
+ }
+ return false;
+ }
+ }
+}
diff --git a/extensions/TimedMediaHandler/handlers/Mp4Handler/Mp4Handler.php b/extensions/TimedMediaHandler/handlers/Mp4Handler/Mp4Handler.php
new file mode 100644
index 00000000..897e1017
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/Mp4Handler/Mp4Handler.php
@@ -0,0 +1,139 @@
+<?php
+/**
+ * MP4 handler
+ */
+class Mp4Handler extends ID3Handler {
+
+ /**
+ * @param $path string
+ * @return array
+ */
+ protected function getID3( $path ) {
+ $id3 = parent::getID3( $path );
+ // Unset some parts of id3 that are too detailed and matroska specific:
+ unset( $id3['quicktime'] );
+ return $id3;
+ }
+
+ /**
+ * Get the "media size"
+ * @param $file File
+ * @param $path string
+ * @param $metadata bool
+ * @return array|bool
+ */
+ function getImageSize( $file, $path, $metadata = false ) {
+ // Just return the size of the first video stream
+ if ( $metadata === false ) {
+ $metadata = $file->getMetadata();
+ }
+ $metadata = $this->unpackMetadata( $metadata );
+ if ( isset( $metadata['error'] ) ) {
+ return false;
+ }
+ if( isset( $metadata['video']['resolution_x'])
+ &&
+ isset( $metadata['video']['resolution_y'])
+ ){
+ return array (
+ $metadata['video']['resolution_x'],
+ $metadata['video']['resolution_y']
+ );
+ }
+ return array( false, false );
+ }
+
+ /**
+ * @param $image
+ * @return string
+ */
+ function getMetadataType( $image ) {
+ return 'mp4';
+ }
+ /**
+ * @param $file File
+ */
+ function getWebType( $file ) {
+ /**
+ * h.264 profile types:
+ H.264 Simple baseline profile video (main and extended video compatible) level 3 and Low-Complexity AAC audio in MP4 container:
+ type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
+
+ H.264 Extended profile video (baseline-compatible) level 3 and Low-Complexity AAC audio in MP4 container:
+ type='video/mp4; codecs="avc1.58A01E, mp4a.40.2"'
+
+ H.264 Main profile video level 3 and Low-Complexity AAC audio in MP4 container
+ type='video/mp4; codecs="avc1.4D401E, mp4a.40.2"'
+
+ H.264 ‘High’ profile video (incompatible with main, baseline, or extended profiles) level 3 and Low-Complexity AAC audio in MP4 container
+ type='video/mp4; codecs="avc1.64001E, mp4a.40.2"'
+ */
+ // all h.264 encodes are currently simple profile
+ return 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
+ }
+ /**
+ * @param $file File
+ * @return array|bool
+ */
+ function getStreamTypes( $file ) {
+ $streamTypes = array();
+ $metadata = self::unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return false;
+ }
+ if( isset( $metadata['audio'] ) && $metadata['audio']['dataformat'] == 'mp4' ){
+ if( isset( $metadata['audio']['codec'] )
+ &&
+ strpos( $metadata['audio']['codec'] , 'AAC' ) !== false
+ ){
+ $streamTypes[] = 'AAC';
+ } else {
+ $streamTypes[] = $metadata['audio']['codec'];
+ }
+ }
+ // id3 gives 'V_VP8' for what we call VP8
+ if( $metadata['video']['dataformat'] == 'quicktime' ){
+ $streamTypes[] = 'h.264';
+ }
+
+ return $streamTypes;
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getShortDesc( $file ) {
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return parent::getShortDesc( $file );
+ }
+ return wfMessage( 'timedmedia-mp4-short-video', implode( '/', $streamTypes )
+ )->timeperiodParams(
+ $this->getLength( $file )
+ )->text();
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getLongDesc( $file ) {
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return parent::getLongDesc( $file );
+ }
+ return wfMessage('timedmedia-mp4-long-video',
+ implode( '/', $streamTypes )
+ )->timeperiodParams(
+ $this->getLength( $file )
+ )->bitrateParams(
+ $this->getBitRate( $file )
+ )->numParams(
+ $file->getWidth(),
+ $file->getHeight()
+ )->text();
+
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg.php b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg.php
new file mode 100644
index 00000000..ca281e22
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg.php
@@ -0,0 +1,631 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------------+
+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
+// | Copyright (c) 2005-2007 |
+// | David Grant <david@grant.org.uk> |
+// | Tim Starling <tstarling@wikimedia.org> |
+// +----------------------------------------------------------------------------+
+// | This library is free software; you can redistribute it and/or |
+// | modify it under the terms of the GNU Lesser General Public |
+// | License as published by the Free Software Foundation; either |
+// | version 2.1 of the License, or (at your option) any later version. |
+// | |
+// | This library is distributed in the hope that it will be useful, |
+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | Lesser General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU Lesser General Public |
+// | License along with this library; if not, write to the Free Software |
+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
+// +----------------------------------------------------------------------------+
+
+/**
+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @category File
+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
+ * @link http://pear.php.net/package/File_Ogg
+ * @package File_Ogg
+ * @version CVS: $Id: Ogg.php,v 1.14 2005/11/19 09:06:30 djg Exp $
+ */
+
+/**
+ * @access public
+ */
+define("OGG_STREAM_VORBIS", 1);
+/**
+ * @access public
+ */
+define("OGG_STREAM_THEORA", 2);
+/**
+ * @access public
+ */
+define("OGG_STREAM_SPEEX", 3);
+/**
+ * @access public
+ */
+define("OGG_STREAM_FLAC", 4);
+/**
+ * @access public
+ */
+define("OGG_STREAM_OPUS", 5);
+
+/**
+ * Capture pattern to determine if a file is an Ogg physical stream.
+ *
+ * @access private
+ */
+define("OGG_CAPTURE_PATTERN", "OggS");
+/**
+ * Maximum size of an Ogg stream page plus four. This value is specified to allow
+ * efficient parsing of the physical stream. The extra four is a paranoid measure
+ * to make sure a capture pattern is not split into two parts accidentally.
+ *
+ * @access private
+ */
+define("OGG_MAXIMUM_PAGE_SIZE", 65311);
+/**
+ * Capture pattern for an Ogg Vorbis logical stream.
+ *
+ * @access private
+ */
+define("OGG_STREAM_CAPTURE_VORBIS", "vorbis");
+/**
+ * Capture pattern for an Ogg Speex logical stream.
+ * @access private
+ */
+define("OGG_STREAM_CAPTURE_SPEEX", "Speex ");
+/**
+ * Capture pattern for an Ogg FLAC logical stream.
+ *
+ * @access private
+ */
+define("OGG_STREAM_CAPTURE_FLAC", "FLAC");
+/**
+ * Capture pattern for an Ogg Theora logical stream.
+ *
+ * @access private
+ */
+define("OGG_STREAM_CAPTURE_THEORA", "theora");
+/**
+ * Capture pattern for an Ogg Opus logical stream.
+ * @access private
+ */
+define("OGG_STREAM_CAPTURE_OPUS", "OpusHead");
+/**
+ * Error thrown if the file location passed is nonexistant or unreadable.
+ *
+ * @access private
+ */
+define("OGG_ERROR_INVALID_FILE", 1);
+/**
+ * Error thrown if the user attempts to extract an unsupported logical stream.
+ *
+ * @access private
+ */
+define("OGG_ERROR_UNSUPPORTED", 2);
+/**
+ * Error thrown if the user attempts to extract an logical stream with no
+ * corresponding serial number.
+ *
+ * @access private
+ */
+define("OGG_ERROR_BAD_SERIAL", 3);
+/**
+ * Error thrown if the stream appears to be corrupted.
+ *
+ * @access private
+ */
+define("OGG_ERROR_UNDECODABLE", 4);
+
+
+/**
+ * Class for parsing a ogg bitstream.
+ *
+ * This class provides a means to access several types of logical bitstreams (e.g. Vorbis)
+ * within a Ogg physical bitstream.
+ *
+ * @link http://www.xiph.org/ogg/doc/
+ * @package File_Ogg
+ */
+class File_Ogg
+{
+ /**
+ * File pointer to Ogg container.
+ *
+ * This is the file pointer used for extracting data from the Ogg stream. It is
+ * the result of a standard fopen call.
+ *
+ * @var pointer
+ * @access private
+ */
+ var $_filePointer;
+
+ /**
+ * The container for all logical streams.
+ *
+ * List of all of the unique streams in the Ogg physical stream. The key
+ * used is the unique serial number assigned to the logical stream by the
+ * encoding application.
+ *
+ * @var array
+ * @access private
+ */
+ var $_streamList = array();
+ var $_streams = array();
+
+ /**
+ * Length in seconds of each stream group
+ */
+ var $_groupLengths = array();
+
+ /**
+ * Total length in seconds of the entire file
+ */
+ var $_totalLength;
+ var $_startOffset = false;
+
+ /**
+ * Maximum number of pages to store detailed metadata for, per stream.
+ * We can't store every page because there could be millions, causing an OOM.
+ * This must be big enough so that all the codecs can get the metadata they
+ * need without re-reading the file.
+ */
+ var $_maxPageCacheSize = 4;
+
+ /**
+ * Returns an interface to an Ogg physical stream.
+ *
+ * This method takes the path to a local file and examines it for a physical
+ * ogg bitsream. After instantiation, the user should query the object for
+ * the logical bitstreams held within the ogg container.
+ *
+ * @access public
+ * @param string $fileLocation The path of the file to be examined.
+ */
+ function __construct($fileLocation)
+ {
+ clearstatcache();
+ if (! file_exists($fileLocation)) {
+ throw new OggException("Couldn't Open File. Check File Path.", OGG_ERROR_INVALID_FILE);
+ }
+
+ // Open this file as a binary, and split the file into streams.
+ $this->_filePointer = fopen($fileLocation, "rb");
+ if (!is_resource($this->_filePointer))
+ throw new OggException("Couldn't Open File. Check File Permissions.", OGG_ERROR_INVALID_FILE);
+
+ // Check for a stream at the start
+ $magic = fread($this->_filePointer, strlen(OGG_CAPTURE_PATTERN));
+ if ($magic !== OGG_CAPTURE_PATTERN) {
+ throw new OggException("Couldn't read file: Incorrect magic number.", OGG_ERROR_UNDECODABLE);
+ }
+ fseek($this->_filePointer, 0, SEEK_SET);
+
+ $this->_splitStreams();
+ fclose($this->_filePointer);
+ }
+
+ /**
+ * Little-endian equivalent for bin2hex
+ * @static
+ */
+ static function _littleEndianBin2Hex( $bin ) {
+ $bigEndian = bin2hex( $bin );
+ // Reverse entire string
+ $reversed = strrev( $bigEndian );
+ // Swap nibbles back
+ for ( $i = 0; $i < strlen( $bigEndian ); $i += 2 ) {
+ $temp = $reversed[$i];
+ $reversed[$i] = $reversed[$i+1];
+ $reversed[$i+1] = $temp;
+ }
+ return $reversed;
+ }
+
+
+ /**
+ * Read a binary structure from a file. An array of unsigned integers are read.
+ * Large integers are upgraded to floating point on overflow.
+ *
+ * Format is big-endian as per Theora bit packing convention, this function
+ * won't work for Vorbis.
+ *
+ * @param resource $file
+ * @param array $fields Associative array mapping name to length in bits
+ */
+ static function _readBigEndian($file, $fields)
+ {
+ $bufferLength = ceil(array_sum($fields) / 8);
+ $buffer = fread($file, $bufferLength);
+ if (strlen($buffer) != $bufferLength) {
+ throw new OggException('Unexpected end of file', OGG_ERROR_UNDECODABLE);
+ }
+ $bytePos = 0;
+ $bitPos = 0;
+ $byteValue = ord($buffer[0]);
+ $output = array();
+ foreach ($fields as $name => $width) {
+ if ($width % 8 == 0 && $bitPos == 0) {
+ // Byte aligned case
+ $bytes = $width / 8;
+ $endBytePos = $bytePos + $bytes;
+ $value = 0;
+ while ($bytePos < $endBytePos) {
+ $value = ($value * 256) + ord($buffer[$bytePos]);
+ $bytePos++;
+ }
+ if ($bytePos < strlen($buffer)) {
+ $byteValue = ord($buffer[$bytePos]);
+ }
+ } else {
+ // General case
+ $bitsRemaining = $width;
+ $value = 0;
+ while ($bitsRemaining > 0) {
+ $bitsToRead = min($bitsRemaining, 8 - $bitPos);
+ $byteValue <<= $bitsToRead;
+ $overflow = ($byteValue & 0xff00) >> 8;
+ $byteValue &= $byteValue & 0xff;
+
+ $bitPos += $bitsToRead;
+ $bitsRemaining -= $bitsToRead;
+ $value += $overflow * pow(2, $bitsRemaining);
+
+ if ($bitPos >= 8) {
+ $bitPos = 0;
+ $bytePos++;
+ if ($bitsRemaining <= 0) {
+ break;
+ }
+ $byteValue = ord($buffer[$bytePos]);
+ }
+ }
+ }
+ $output[$name] = $value;
+ assert($bytePos <= $bufferLength);
+ }
+ return $output;
+ }
+
+ /**
+ * Read a binary structure from a file. An array of unsigned integers are read.
+ * Large integers are upgraded to floating point on overflow.
+ *
+ * Format is little-endian as per Vorbis bit packing convention.
+ *
+ * @param resource $file
+ * @param array $fields Associative array mapping name to length in bits
+ */
+ static function _readLittleEndian( $file, $fields ) {
+ $bufferLength = ceil(array_sum($fields) / 8);
+ $buffer = fread($file, $bufferLength);
+ if (strlen($buffer) != $bufferLength) {
+ throw new OggException('Unexpected end of file', OGG_ERROR_UNDECODABLE);
+ }
+
+ $bytePos = 0;
+ $bitPos = 0;
+ $byteValue = ord($buffer[0]) << 8;
+ $output = array();
+ foreach ($fields as $name => $width) {
+ if ($width % 8 == 0 && $bitPos == 0) {
+ // Byte aligned case
+ $bytes = $width / 8;
+ $value = 0;
+ for ($i = 0; $i < $bytes; $i++, $bytePos++) {
+ $value += pow(256, $i) * ord($buffer[$bytePos]);
+ }
+ if ($bytePos < strlen($buffer)) {
+ $byteValue = ord($buffer[$bytePos]) << 8;
+ }
+ } else {
+ // General case
+ $bitsRemaining = $width;
+ $value = 0;
+ while ($bitsRemaining > 0) {
+ $bitsToRead = min($bitsRemaining, 8 - $bitPos);
+ $byteValue >>= $bitsToRead;
+ $overflow = ($byteValue & 0xff) >> (8 - $bitsToRead);
+ $byteValue &= 0xff00;
+
+ $value += $overflow * pow(2, $width - $bitsRemaining);
+ $bitPos += $bitsToRead;
+ $bitsRemaining -= $bitsToRead;
+
+ if ($bitPos >= 8) {
+ $bitPos = 0;
+ $bytePos++;
+ if ($bitsRemaining <= 0) {
+ break;
+ }
+ $byteValue = ord($buffer[$bytePos]) << 8;
+ }
+ }
+ }
+ $output[$name] = $value;
+ assert($bytePos <= $bufferLength);
+ }
+ return $output;
+ }
+
+
+ /**
+ * @access private
+ */
+ function _decodePageHeader($pageData, $pageOffset, $groupId)
+ {
+ // Extract the various bits and pieces found in each packet header.
+ if (substr($pageData, 0, 4) != OGG_CAPTURE_PATTERN)
+ return (false);
+
+ $stream_version = unpack("C1data", substr($pageData, 4, 1));
+ if ($stream_version['data'] != 0x00)
+ return (false);
+
+ $header_flag = unpack("Cdata", substr($pageData, 5, 1));
+
+ // Exact granule position
+ $abs_granule_pos = self::_littleEndianBin2Hex( substr($pageData, 6, 8));
+
+ // Approximate (floating point) granule position
+ $pos = unpack("Va/Vb", substr($pageData, 6, 8));
+ $approx_granule_pos = $pos['a'] + $pos['b'] * pow(2, 32);
+
+ // Serial number for the current datastream.
+ $stream_serial = unpack("Vdata", substr($pageData, 14, 4));
+ $page_sequence = unpack("Vdata", substr($pageData, 18, 4));
+ $checksum = unpack("Vdata", substr($pageData, 22, 4));
+ $page_segments = unpack("Cdata", substr($pageData, 26, 1));
+ $segments_total = 0;
+ for ($i = 0; $i < $page_segments['data']; ++$i) {
+ $segment_length = unpack("Cdata", substr($pageData, 26 + ($i + 1), 1));
+ $segments_total += $segment_length['data'];
+ }
+ $pageFinish = $pageOffset + 27 + $page_segments['data'] + $segments_total;
+ $page = array(
+ 'stream_version' => $stream_version['data'],
+ 'header_flag' => $header_flag['data'],
+ 'abs_granule_pos' => $abs_granule_pos,
+ 'approx_granule_pos' => $approx_granule_pos,
+ 'checksum' => sprintf("%u", $checksum['data']),
+ 'segments' => $page_segments['data'],
+ 'head_offset' => $pageOffset,
+ 'body_offset' => $pageOffset + 27 + $page_segments['data'],
+ 'body_finish' => $pageFinish,
+ 'data_length' => $pageFinish - $pageOffset,
+ 'group' => $groupId,
+ );
+ if ( !isset( $this->_streamList[$stream_serial['data']] ) ) {
+ $this->_streamList[$stream_serial['data']] = array(
+ 'pages' => array(),
+ 'data_length' => 0,
+ 'first_granule_pos' => null,
+ 'last_granule_pos' => null,
+ );
+ }
+ $stream =& $this->_streamList[$stream_serial['data']];
+ if ( count( $stream['pages'] ) < $this->_maxPageCacheSize ) {
+ $stream['pages'][$page_sequence['data']] = $page;
+ }
+ $stream['last_page'] = $page;
+ $stream['data_length'] += $page['data_length'];
+
+ # Reject -1 as a granule pos, that means no segment finished in the packet
+ if ( $abs_granule_pos !== 'ffffffffffffffff' ) {
+ if ( $stream['first_granule_pos'] === null ) {
+ $stream['first_granule_pos'] = $abs_granule_pos;
+ }
+ $stream['last_granule_pos'] = $abs_granule_pos;
+ }
+
+ $pageData = null;
+ return $page;
+ }
+
+ /**
+ * @access private
+ */
+ function _splitStreams()
+ {
+ // Loop through the physical stream until there are no more pages to read.
+ $groupId = 0;
+ $openStreams = 0;
+ $this_page_offset = 0;
+ while (!feof($this->_filePointer)) {
+ $pageData = fread($this->_filePointer, 282);
+ if (strval($pageData) === '') {
+ break;
+ }
+ $page = $this->_decodePageHeader($pageData, $this_page_offset, $groupId);
+ if ($page === false) {
+ throw new OggException("Cannot decode Ogg file: Invalid page at offset $this_page_offset", OGG_ERROR_UNDECODABLE);
+ }
+
+ // Keep track of multiplexed groups
+ if ($page['header_flag'] & 2/*bos*/) {
+ $openStreams++;
+ } elseif ($page['header_flag'] & 4/*eos*/) {
+ $openStreams--;
+ if (!$openStreams) {
+ // End of group
+ $groupId++;
+ }
+ }
+ if ($openStreams < 0) {
+ throw new OggException("Unexpected end of stream", OGG_ERROR_UNDECODABLE);
+ }
+
+ $this_page_offset = $page['body_finish'];
+ fseek( $this->_filePointer, $this_page_offset, SEEK_SET );
+ }
+ // Loop through the streams, and find out what type of stream is available.
+ $groupLengths = array();
+ foreach ($this->_streamList as $stream_serial => $streamData) {
+ fseek($this->_filePointer, $streamData['pages'][0]['body_offset'], SEEK_SET);
+ $pattern = fread($this->_filePointer, 8);
+ if (preg_match("/" . OGG_STREAM_CAPTURE_VORBIS . "/", $pattern)) {
+ $this->_streamList[$stream_serial]['stream_type'] = OGG_STREAM_VORBIS;
+ $stream = new File_Ogg_Vorbis($stream_serial, $streamData, $this->_filePointer);
+ } elseif (preg_match("/" . OGG_STREAM_CAPTURE_SPEEX . "/", $pattern)) {
+ $this->_streamList[$stream_serial]['stream_type'] = OGG_STREAM_SPEEX;
+ $stream = new File_Ogg_Speex($stream_serial, $streamData, $this->_filePointer);
+ } elseif (preg_match("/" . OGG_STREAM_CAPTURE_FLAC . "/", $pattern)) {
+ $this->_streamList[$stream_serial]['stream_type'] = OGG_STREAM_FLAC;
+ $stream = new File_Ogg_Flac($stream_serial, $streamData, $this->_filePointer);
+ } elseif (preg_match("/" . OGG_STREAM_CAPTURE_THEORA . "/", $pattern)) {
+ $this->_streamList[$stream_serial]['stream_type'] = OGG_STREAM_THEORA;
+ $stream = new File_Ogg_Theora($stream_serial, $streamData, $this->_filePointer);
+ } elseif (preg_match("/" . OGG_STREAM_CAPTURE_OPUS . "/", $pattern)) {
+ $this->_streamList[$stream_serial]['stream_type'] = OGG_STREAM_OPUS;
+ $stream = new File_Ogg_Opus($stream_serial, $streamData, $this->_filePointer);
+ } else {
+ $streamData['stream_type'] = "unknown";
+ $stream = false;
+ }
+
+ if ($stream) {
+ $this->_streams[$stream_serial] = $stream;
+ $group = $streamData['pages'][0]['group'];
+ if (isset($groupLengths[$group])) {
+ $groupLengths[$group] = max($groupLengths[$group], $stream->getLength());
+ } else {
+ $groupLengths[$group] = $stream->getLength();
+ }
+ //just store the startOffset for the first stream:
+ if( $this->_startOffset === false ){
+ $this->_startOffset = $stream->getStartOffset();
+ }
+
+ }
+ }
+ $this->_groupLengths = $groupLengths;
+ $this->_totalLength = array_sum( $groupLengths );
+ unset($this->_streamList);
+ }
+
+ /**
+ * Returns the overead percentage used by the Ogg headers.
+ *
+ * This function returns the percentage of the total stream size
+ * used for Ogg headers.
+ *
+ * @return float
+ */
+ function getOverhead() {
+ $header_size = 0;
+ $stream_size = 0;
+ foreach ($this->_streams as $serial => $stream) {
+ foreach ($stream->_streamList as $offset => $stream_data) {
+ $header_size += $stream_data['body_offset'] - $stream_data['head_offset'];
+ $stream_size = $stream_data['body_finish'];
+ }
+ }
+ return sprintf("%0.2f", ($header_size / $stream_size) * 100);
+ }
+
+ /**
+ * Returns the appropriate logical bitstream that corresponds to the provided serial.
+ *
+ * This function returns a logical bitstream contained within the Ogg physical
+ * stream, corresponding to the serial used as the offset for that bitstream.
+ * The returned stream may be Vorbis, Speex, FLAC or Theora, although the only
+ * usable bitstream is Vorbis.
+ *
+ * @return File_Ogg_Bitstream
+ */
+ function &getStream($streamSerial)
+ {
+ if (! array_key_exists($streamSerial, $this->_streams))
+ throw new OggException("The stream number is invalid.", OGG_ERROR_BAD_SERIAL);
+
+ return $this->_streams[$streamSerial];
+ }
+
+ /**
+ * This function returns true if a logical bitstream of the requested type can be found.
+ *
+ * This function checks the contents of this ogg physical bitstream for of logical
+ * bitstream corresponding to the supplied type. If one is found, the function returns
+ * true, otherwise it return false.
+ *
+ * @param int $streamType
+ * @return boolean
+ */
+ function hasStream($streamType)
+ {
+ foreach ($this->_streams as $stream) {
+ if ($stream['stream_type'] == $streamType)
+ return (true);
+ }
+ return (false);
+ }
+
+ /**
+ * Returns an array of logical streams inside this physical bitstream.
+ *
+ * This function returns an array of logical streams found within this physical
+ * bitstream. If a filter is provided, only logical streams of the requested type
+ * are returned, as an array of serial numbers. If no filter is provided, this
+ * function returns a two-dimensional array, with the stream type as the primary key,
+ * and a value consisting of an array of stream serial numbers.
+ *
+ * @param int $filter
+ * @return array
+ */
+ function listStreams($filter = null)
+ {
+ $streams = array();
+ // Loops through the streams and assign them to an appropriate index,
+ // ready for filtering the second part of this function.
+ foreach ($this->_streams as $serial => $stream) {
+ $stream_type = 0;
+ switch (get_class($stream)) {
+ case "file_ogg_flac":
+ $stream_type = OGG_STREAM_FLAC;
+ break;
+ case "file_ogg_speex":
+ $stream_type = OGG_STREAM_SPEEX;
+ break;
+ case "file_ogg_theora":
+ $stream_type = OGG_STREAM_THEORA;
+ break;
+ case "file_ogg_vorbis":
+ $stream_type = OGG_STREAM_VORBIS;
+ break;
+ }
+ if (! isset($streams[$stream_type]))
+ // Initialise the result list for this stream type.
+ $streams[$stream_type] = array();
+
+ $streams[$stream_type][] = $serial;
+ }
+
+ // Perform filtering.
+ if (is_null($filter))
+ return ($streams);
+ elseif (isset($streams[$filter]))
+ return ($streams[$filter]);
+ else
+ return array();
+ }
+ /**
+ * getStartOffset
+ *
+ * @return unknown
+ */
+ function getStartOffset(){
+ if( $this->_startOffset === false)
+ return 0;
+ return $this->_startOffset;
+ }
+ /**
+ * Get the total length of the group of streams
+ */
+ function getLength() {
+ return $this->_totalLength;
+ }
+}
+?>
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Bitstream.php b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Bitstream.php
new file mode 100644
index 00000000..1a462232
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Bitstream.php
@@ -0,0 +1,125 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------------+
+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
+// | Copyright (c) 2005-2007 |
+// | David Grant <david@grant.org.uk> |
+// | Tim Starling <tstarling@wikimedia.org> |
+// +----------------------------------------------------------------------------+
+// | This library is free software; you can redistribute it and/or |
+// | modify it under the terms of the GNU Lesser General Public |
+// | License as published by the Free Software Foundation; either |
+// | version 2.1 of the License, or (at your option) any later version. |
+// | |
+// | This library is distributed in the hope that it will be useful, |
+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | Lesser General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU Lesser General Public |
+// | License along with this library; if not, write to the Free Software |
+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
+// +----------------------------------------------------------------------------+
+
+
+/**
+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @category File
+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
+ * @link http://pear.php.net/package/File_Ogg
+ * @package File_Ogg
+ * @version CVS: $Id: Bitstream.php,v 1.3 2005/11/08 19:36:18 djg Exp $
+ */
+class File_Ogg_Bitstream
+{
+ /**
+ * The serial number of this logical stream.
+ *
+ * @var int
+ * @access private
+ */
+ var $_streamSerial;
+ /**
+ * @access private
+ */
+ var $_streamData;
+ /**
+ * @access private
+ */
+ var $_filePointer;
+ /**
+ * The number of bits used in this stream.
+ *
+ * @var int
+ * @access private
+ */
+ var $_streamSize;
+
+ /**
+ * The last granule position in the stream
+ * @var int
+ * @access private
+ */
+ var $_lastGranulePos;
+
+ /**
+ * Constructor for a generic logical stream.
+ *
+ * @param int $streamSerial Serial number of the logical stream.
+ * @param array $streamData Data for the requested logical stream.
+ * @param string $filePath Location of a file on the filesystem.
+ * @param pointer $filePointer File pointer for the current physical stream.
+ * @access private
+ */
+ function __construct($streamSerial, $streamData, $filePointer)
+ {
+ $this->_streamSerial = $streamSerial;
+ $this->_streamData = $streamData;
+ $this->_filePointer = $filePointer;
+ $this->_firstGranulePos = $streamData['first_granule_pos'];
+ $this->_lastGranulePos = $streamData['last_granule_pos'];
+ $this->_streamSize = $streamData['data_length'];
+ $this->_group = $streamData['pages'][0]['group'];
+ }
+
+ /**
+ * Gives the serial number of this stream.
+ *
+ * The stream serial number is of fairly academic importance, as it makes little
+ * difference to the end user. The serial number is used by the Ogg physical
+ * stream to distinguish between concurrent logical streams.
+ *
+ * @return int
+ * @access public
+ */
+ function getSerial()
+ {
+ return ($this->_streamSerial);
+ }
+
+ /**
+ * Gives the size (in bits) of this stream.
+ *
+ * This function returns the size of the Vorbis stream within the Ogg
+ * physical stream.
+ *
+ * @return int
+ * @access public
+ */
+ function getSize()
+ {
+ return ($this->_streamSize);
+ }
+
+ /**
+ * Get the multiplexed group ID
+ */
+ function getGroup()
+ {
+ return $this->_group;
+ }
+
+}
+
+?>
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Flac.php b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Flac.php
new file mode 100644
index 00000000..6838ba68
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Flac.php
@@ -0,0 +1,133 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------------+
+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
+// | Copyright (c) 2005-2007 |
+// | David Grant <david@grant.org.uk> |
+// | Tim Starling <tstarling@wikimedia.org> |
+// +----------------------------------------------------------------------------+
+// | This library is free software; you can redistribute it and/or |
+// | modify it under the terms of the GNU Lesser General Public |
+// | License as published by the Free Software Foundation; either |
+// | version 2.1 of the License, or (at your option) any later version. |
+// | |
+// | This library is distributed in the hope that it will be useful, |
+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | Lesser General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU Lesser General Public |
+// | License along with this library; if not, write to the Free Software |
+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
+// +----------------------------------------------------------------------------+
+
+
+/**
+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @category File
+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
+ * @link http://pear.php.net/package/File_Ogg
+ * @link http://flac.sourceforge.net/documentation.html
+ * @package File_Ogg
+ * @version CVS: $Id: Flac.php,v 1.9 2005/11/16 20:43:27 djg Exp $
+ */
+class File_Ogg_Flac extends File_Ogg_Media
+{
+ /**
+ * @access private
+ */
+ function __construct($streamSerial, $streamData, $filePointer)
+ {
+ parent::__construct($streamSerial, $streamData, $filePointer);
+ $this->_decodeHeader();
+ $this->_decodeCommentsHeader();
+ $this->_streamLength = $this->_streamInfo['total_samples']
+ / $this->_streamInfo['sample_rate'];
+ }
+
+ /**
+ * Get a short string describing the type of the stream
+ * @return string
+ */
+ function getType() {
+ return 'FLAC';
+ }
+
+ /**
+ * @access private
+ * @param int $packetType
+ * @param int $pageOffset
+ */
+ function _decodeHeader()
+ {
+ fseek($this->_filePointer, $this->_streamData['pages'][0]['body_offset'], SEEK_SET);
+ // Check if this is the correct header.
+ $packet = unpack("Cdata", fread($this->_filePointer, 1));
+ if ($packet['data'] != 0x7f)
+ throw new OggException("Stream Undecodable", OGG_ERROR_UNDECODABLE);
+
+ // The following four characters should be "FLAC".
+ if (fread($this->_filePointer, 4) != 'FLAC')
+ throw new OggException("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE);
+
+ $version = unpack("Cmajor/Cminor", fread($this->_filePointer, 2));
+ $this->_version = "{$version['major']}.{$version['minor']}";
+ if ($version['major'] > 1) {
+ throw new OggException("Cannot decode a version {$version['major']} FLAC stream", OGG_ERROR_UNDECODABLE);
+ }
+ $h = File_Ogg::_readBigEndian( $this->_filePointer,
+ array(
+ // Ogg-specific
+ 'num_headers' => 16,
+ 'flac_native_sig' => 32,
+ // METADATA_BLOCK_HEADER
+ 'is_last' => 1,
+ 'type' => 7,
+ 'length' => 24,
+ ));
+
+ // METADATA_BLOCK_STREAMINFO
+ // The variable names are canonical, and come from the FLAC source (format.h)
+ $this->_streamInfo = File_Ogg::_readBigEndian( $this->_filePointer,
+ array(
+ 'min_blocksize' => 16,
+ 'max_blocksize' => 16,
+ 'min_framesize' => 24,
+ 'max_framesize' => 24,
+ 'sample_rate' => 20,
+ 'channels' => 3,
+ 'bits_per_sample' => 5,
+ 'total_samples' => 36,
+ ));
+ $this->_streamInfo['md5sum'] = bin2hex(fread($this->_filePointer, 16));
+ }
+
+ /**
+ * Get an associative array containing header information about the stream
+ * @access public
+ * @return array
+ */
+ function getHeader()
+ {
+ return $this->_streamInfo;
+ }
+
+ function _decodeCommentsHeader()
+ {
+ fseek($this->_filePointer, $this->_streamData['pages'][1]['body_offset'], SEEK_SET);
+ $blockHeader = File_Ogg::_readBigEndian( $this->_filePointer,
+ array(
+ 'last_block' => 1,
+ 'block_type' => 7,
+ 'length' => 24
+ )
+ );
+ if ($blockHeader['block_type'] != 4) {
+ throw new OggException("Stream Undecodable", OGG_ERROR_UNDECODABLE);
+ }
+
+ $this->_decodeBareCommentsHeader();
+ }
+}
+?>
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Media.php b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Media.php
new file mode 100644
index 00000000..67ddaece
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Media.php
@@ -0,0 +1,262 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------------+
+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
+// | Copyright (c) 2005-2007 |
+// | David Grant <david@grant.org.uk> |
+// | Tim Starling <tstarling@wikimedia.org> |
+// +----------------------------------------------------------------------------+
+// | This library is free software; you can redistribute it and/or |
+// | modify it under the terms of the GNU Lesser General Public |
+// | License as published by the Free Software Foundation; either |
+// | version 2.1 of the License, or (at your option) any later version. |
+// | |
+// | This library is distributed in the hope that it will be useful, |
+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | Lesser General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU Lesser General Public |
+// | License along with this library; if not, write to the Free Software |
+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
+// +----------------------------------------------------------------------------+
+
+
+/**
+ * Parent class for media bitstreams
+ * Contains some functions common to various media formats
+ */
+abstract class File_Ogg_Media extends File_Ogg_Bitstream
+{
+ /**
+ * Maximum size of header comment to parse.
+ * Set to 1 MB by default. Make sure this is less than your PHP memory_limit.
+ */
+ const COMMENT_MAX_SIZE = 1000000;
+
+ /**
+ * Array to hold each of the comments.
+ *
+ * @access private
+ * @var array
+ */
+ var $_comments = array();
+
+ /**
+ * Vendor string for the stream.
+ *
+ * @access private
+ * @var string
+ */
+ var $_vendor;
+
+ /**
+ * Length of the stream in seconds
+ */
+ var $_streamLength;
+
+ /* Start offset of the stream in seconds */
+ var $_startOffset = 0;
+
+ /**
+ * Get a short string describing the type of the stream
+ * @return string
+ */
+ abstract function getType();
+
+ /**
+ * Get the 6-byte identification string expected in the common header
+ * @return string
+ */
+ function getIdentificationString()
+ {
+ return '';
+ }
+
+ /**
+ * @access private
+ * @param int $packetType
+ * @param int $pageOffset
+ */
+ function _decodeCommonHeader($packetType, $pageOffset)
+ {
+ fseek($this->_filePointer, $this->_streamData['pages'][$pageOffset]['body_offset'], SEEK_SET);
+ if ($packetType !== false) {
+ // Check if this is the correct header.
+ $packet = unpack("Cdata", fread($this->_filePointer, 1));
+ if ($packet['data'] != $packetType)
+ throw new OggException("Stream Undecodable", OGG_ERROR_UNDECODABLE);
+
+ // The following six characters should be equal to getIdentificationString()
+ $id = $this->getIdentificationString();
+ if ($id !== '' && fread($this->_filePointer, strlen($id)) !== $id)
+ throw new OggException("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE);
+ } // else seek only, no common header
+ }
+
+ /**
+ * Parse a Vorbis-style comments header.
+ *
+ * This function parses the comments header. The comments header contains a series of
+ * UTF-8 comments related to the audio encoded in the stream. This header also contains
+ * a string to identify the encoding software. More details on the comments header can
+ * be found at the following location: http://xiph.org/vorbis/doc/v-comment.html
+ *
+ * @access private
+ */
+ function _decodeBareCommentsHeader()
+ {
+ // Decode the vendor string length as a 32-bit unsigned integer.
+ $vendor_len = unpack("Vdata", fread($this->_filePointer, 4));
+ if ( $vendor_len['data'] > 0 ) {
+ // Retrieve the vendor string from the stream.
+ $this->_vendor = fread($this->_filePointer, $vendor_len['data']);
+ } else {
+ $this->_vendor = '';
+ }
+ // Decode the size of the comments list as a 32-bit unsigned integer.
+ $comment_list_length = unpack("Vdata", fread($this->_filePointer, 4));
+ // Iterate through the comments list.
+ for ($i = 0; $i < $comment_list_length['data']; ++$i) {
+ // Unpack the length of this comment.
+ $comment_length = unpack("Vdata", fread($this->_filePointer, 4));
+
+ // If the comment length is greater than specified limit, skip it.
+ if ( $comment_length['data'] > self::COMMENT_MAX_SIZE ) {
+ continue;
+ }
+
+ // Comments are in the format 'ARTIST=Super Furry Animals', so split it on the equals character.
+ // NOTE: Equals characters are strictly prohibited in either the COMMENT or DATA parts.
+ $comment = explode("=", fread($this->_filePointer, $comment_length['data']));
+ $comment_title = (string) $comment[0];
+ $comment_value = (string) $comment[1];
+
+ // Check if the comment type (e.g. ARTIST) already exists. If it does,
+ // take the new value, and the existing value (or array) and insert it
+ // into a new array. This is important, since each comment type may have
+ // multiple instances (e.g. ARTIST for a collaboration) and we should not
+ // overwrite the previous value.
+ if (isset($this->_comments[$comment_title])) {
+ if (is_array($this->_comments[$comment_title]))
+ $this->_comments[$comment_title][] = $comment_value;
+ else
+ $this->_comments[$comment_title] = array($this->_comments[$comment_title], $comment_value);
+ } else
+ $this->_comments[$comment_title] = $comment_value;
+ }
+ }
+
+ /**
+ * Number of channels used in this stream
+ *
+ * This function returns the number of channels used in this stream. This
+ * can range from 1 to 255, but will likely be 2 (stereo) or 1 (mono).
+ *
+ * @access public
+ * @return int
+ * @see File_Ogg_Vorbis::isMono()
+ * @see File_Ogg_Vorbis::isStereo()
+ * @see File_Ogg_Vorbis::isQuadrophonic()
+ */
+ function getChannels()
+ {
+ return ($this->_channels);
+ }
+
+ /**
+ * Provides a list of the comments extracted from the Vorbis stream.
+ *
+ * It is recommended that the user fully inspect the array returned by this function
+ * rather than blindly requesting a comment in false belief that it will always
+ * be present. Whilst the Vorbis specification dictates a number of popular
+ * comments (e.g. TITLE, ARTIST, etc.) for use in Vorbis streams, they are not
+ * guaranteed to appear.
+ *
+ * @access public
+ * @return array
+ */
+ function getCommentList()
+ {
+ return (array_keys($this->_comments));
+ }
+
+ /**
+ * Provides an interface to the numerous comments located with a Vorbis stream.
+ *
+ * A Vorbis stream may contain one or more instances of each comment, so the user
+ * should check the variable type before printing out the result of this method.
+ * The situation in which multiple instances of a comment occurring are not as
+ * rare as one might think, since they are conceivable at least for ARTIST comments
+ * in the situation where a track is a duet.
+ *
+ * @access public
+ * @param string $commentTitle Comment title to search for, e.g. TITLE.
+ * @param string $separator String to separate multiple values.
+ * @return string
+ */
+ function getField($commentTitle, $separator = ", ")
+ {
+ if (isset($this->_comments[$commentTitle])) {
+ if (is_array($this->_comments[$commentTitle]))
+ return (implode($separator, $this->_comments[$commentTitle]));
+ else
+ return ($this->_comments[$commentTitle]);
+ } else
+ // The comment doesn't exist in this file. The user should've called getCommentList first.
+ return ("");
+ }
+
+ /**
+ * Get the entire comments array.
+ * May return an empty array if the bitstream does not support comments.
+ *
+ * @access public
+ * @return array
+ */
+ function getComments() {
+ return $this->_comments;
+ }
+
+ /**
+ * Vendor of software used to encode this stream.
+ *
+ * Gives the vendor string for the software used to encode this stream.
+ * It is common to find libVorbis here. The majority of encoders appear
+ * to use libvorbis from Xiph.org.
+ *
+ * @access public
+ * @return string
+ */
+ function getVendor()
+ {
+ return ($this->_vendor);
+ }
+
+ /**
+ * Get an associative array containing header information about the stream
+ * @access public
+ * @return array
+ */
+ function getHeader()
+ {
+ return array();
+ }
+
+ /**
+ * Get the length of the stream in seconds
+ * @return float
+ */
+ function getLength()
+ {
+ return $this->_streamLength;
+ }
+ /**
+ * Get the start offset of the stream in seconds
+ *
+ * @return float
+ */
+ function getStartOffset(){
+ return $this->_startOffset;
+ }
+}
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Opus.php b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Opus.php
new file mode 100644
index 00000000..2c23d928
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Opus.php
@@ -0,0 +1,126 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------------+
+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
+// | Copyright (c) 2013 |
+// | Jan Gerber <jgerber@wikimedia.org> |
+// +----------------------------------------------------------------------------+
+// | This library is free software; you can redistribute it and/or |
+// | modify it under the terms of the GNU Lesser General Public |
+// | License as published by the Free Software Foundation; either |
+// | version 2.1 of the License, or (at your option) any later version. |
+// | |
+// | This library is distributed in the hope that it will be useful, |
+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | Lesser General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU Lesser General Public |
+// | License along with this library; if not, write to the Free Software |
+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
+// +----------------------------------------------------------------------------+
+
+
+define( 'OGG_OPUS_COMMENTS_PAGE_OFFSET', 1 );
+
+/**
+ * @author Jan Gerber <jgerber@wikimedia.org>
+ * @category File
+ * @copyright Jan Gerber <jgerber@wikimedia.org>
+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
+ * @link http://pear.php.net/package/File_Ogg
+ * @link http://www.opus-codec.org/
+ * @package File_Ogg
+ * @version 1
+ */
+class File_Ogg_Opus extends File_Ogg_Media
+{
+ /**
+ * @access private
+ */
+ function __construct($streamSerial, $streamData, $filePointer)
+ {
+ parent::__construct($streamSerial, $streamData, $filePointer);
+ $this->_decodeHeader();
+ $this->_decodeCommentsHeader();
+
+ $endSec = $this->getSecondsFromGranulePos( $this->_lastGranulePos );
+ $startSec = $this->getSecondsFromGranulePos( $this->_firstGranulePos );
+
+ if( $startSec > 1){
+ $this->_streamLength = $endSec - $startSec;
+ $this->_startOffset = $startSec;
+ }else{
+ $this->_streamLength = $endSec;
+ }
+ $this->_avgBitrate = $this->_streamLength ? ($this->_streamSize * 8) / $this->_streamLength : 0;
+ }
+
+ function getSecondsFromGranulePos( $granulePos ){
+ return (( '0x' . substr( $granulePos, 0, 8 ) ) * pow(2, 32)
+ + ( '0x' . substr( $granulePos, 8, 8 ) )
+ - $this->_header['pre_skip'])
+ / 48000;
+ }
+
+ /**
+ * Get a short string describing the type of the stream
+ * @return string
+ */
+ function getType()
+ {
+ return 'Opus';
+ }
+
+ /**
+ * Decode the stream header
+ * @access private
+ */
+ function _decodeHeader()
+ {
+ fseek($this->_filePointer, $this->_streamData['pages'][0]['body_offset'], SEEK_SET);
+ // The first 8 characters should be "OpusHead".
+ if (fread($this->_filePointer, 8) != 'OpusHead')
+ throw new OggException("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE);
+
+ $this->_header = File_Ogg::_readLittleEndian($this->_filePointer, array(
+ 'opus_version' => 8,
+ 'nb_channels' => 8,
+ 'pre_skip' => 16,
+ 'audio_sample_rate' => 32,
+ 'output_gain' => 16,
+ 'channel_mapping_family'=> 8,
+ ));
+ $this->_channels = $this->_header['nb_channels'];
+ }
+
+ /**
+ * Get an associative array containing header information about the stream
+ * @access public
+ * @return array
+ */
+ function getHeader() {
+ return $this->_header;
+ }
+
+ function getSampleRate()
+ {
+ //Opus always outputs 48kHz, the header only lists
+ //the samplerate of the source as reference
+ return 48000;
+ }
+
+ /**
+ * Decode the comments header
+ * @access private
+ */
+ function _decodeCommentsHeader()
+ {
+ $id = 'OpusTags';
+ $this->_decodeCommonHeader(false, OGG_OPUS_COMMENTS_PAGE_OFFSET);
+ if(fread($this->_filePointer, strlen($id)) !== $id)
+ throw new OggException("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE);
+ $this->_decodeBareCommentsHeader();
+ }
+}
+?>
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Speex.php b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Speex.php
new file mode 100644
index 00000000..42f9b0eb
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Speex.php
@@ -0,0 +1,122 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------------+
+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
+// | Copyright (c) 2005-2007 |
+// | David Grant <david@grant.org.uk> |
+// | Tim Starling <tstarling@wikimedia.org> |
+// +----------------------------------------------------------------------------+
+// | This library is free software; you can redistribute it and/or |
+// | modify it under the terms of the GNU Lesser General Public |
+// | License as published by the Free Software Foundation; either |
+// | version 2.1 of the License, or (at your option) any later version. |
+// | |
+// | This library is distributed in the hope that it will be useful, |
+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | Lesser General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU Lesser General Public |
+// | License along with this library; if not, write to the Free Software |
+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
+// +----------------------------------------------------------------------------+
+
+
+/**
+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @category File
+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
+ * @link http://pear.php.net/package/File_Ogg
+ * @link http://www.speex.org/docs.html
+ * @package File_Ogg
+ * @version CVS: $Id: Speex.php,v 1.10 2005/11/16 20:43:27 djg Exp $
+ */
+class File_Ogg_Speex extends File_Ogg_Media
+{
+ /**
+ * @access private
+ */
+ function __construct($streamSerial, $streamData, $filePointer)
+ {
+ parent::__construct($streamSerial, $streamData, $filePointer);
+ $this->_decodeHeader();
+ $this->_decodeCommentsHeader();
+ $endSec =
+ (( '0x' . substr( $this->_lastGranulePos, 0, 8 ) ) * pow(2, 32)
+ + ( '0x' . substr( $this->_lastGranulePos, 8, 8 ) ))
+ / $this->_header['rate'];
+
+ $startSec =
+ (( '0x' . substr( $this->_firstGranulePos, 0, 8 ) ) * pow(2, 32)
+ + ( '0x' . substr( $this->_firstGranulePos, 8, 8 ) ))
+ / $this->_header['rate'];
+
+ //make sure the offset is worth taking into account oggz_chop related hack
+ if( $startSec > 1){
+ $this->_streamLength = $endSec - $startSec;
+ $this->_startOffset = $startSec;
+ }else{
+ $this->_streamLength = $endSec;
+ }
+ }
+
+ /**
+ * Get a short string describing the type of the stream
+ * @return string
+ */
+ function getType()
+ {
+ return 'Speex';
+ }
+
+ /**
+ * Decode the stream header
+ * @access private
+ */
+ function _decodeHeader()
+ {
+ fseek($this->_filePointer, $this->_streamData['pages'][0]['body_offset'], SEEK_SET);
+ // The first 8 characters should be "Speex ".
+ if (fread($this->_filePointer, 8) != 'Speex ')
+ throw new OggException("Stream is undecodable due to a malformed header.", OGG_ERROR_UNDECODABLE);
+
+ $this->_version = fread($this->_filePointer, 20);
+ $this->_header = File_Ogg::_readLittleEndian($this->_filePointer, array(
+ 'speex_version_id' => 32,
+ 'header_size' => 32,
+ 'rate' => 32,
+ 'mode' => 32,
+ 'mode_bitstream_version'=> 32,
+ 'nb_channels' => 32,
+ 'bitrate' => 32,
+ 'frame_size' => 32,
+ 'vbr' => 32,
+ 'frames_per_packet' => 32,
+ 'extra_headers' => 32,
+ 'reserved1' => 32,
+ 'reserved2' => 32
+ ));
+ $this->_header['speex_version'] = $this->_version;
+ }
+
+ /**
+ * Get an associative array containing header information about the stream
+ * @access public
+ * @return array
+ */
+ function getHeader() {
+ return $this->_header;
+ }
+
+ /**
+ * Decode the comments header
+ * @access private
+ */
+ function _decodeCommentsHeader()
+ {
+ fseek($this->_filePointer, $this->_streamData['pages'][1]['body_offset'], SEEK_SET);
+ $this->_decodeBareCommentsHeader();
+ }
+}
+?>
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Theora.php b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Theora.php
new file mode 100644
index 00000000..b801ea26
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Theora.php
@@ -0,0 +1,240 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------------+
+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
+// | Copyright (c) 2005-2007 |
+// | David Grant <david@grant.org.uk> |
+// | Tim Starling <tstarling@wikimedia.org> |
+// +----------------------------------------------------------------------------+
+// | This library is free software; you can redistribute it and/or |
+// | modify it under the terms of the GNU Lesser General Public |
+// | License as published by the Free Software Foundation; either |
+// | version 2.1 of the License, or (at your option) any later version. |
+// | |
+// | This library is distributed in the hope that it will be useful, |
+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | Lesser General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU Lesser General Public |
+// | License along with this library; if not, write to the Free Software |
+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
+// +----------------------------------------------------------------------------+
+
+
+define( 'OGG_THEORA_IDENTIFICATION_HEADER', 0x80 );
+define( 'OGG_THEORA_COMMENTS_HEADER', 0x81 );
+define( 'OGG_THEORA_IDENTIFICATION_PAGE_OFFSET', 0 );
+define( 'OGG_THEORA_COMMENTS_PAGE_OFFSET', 1 );
+
+
+/**
+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @category File
+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
+ * @link http://pear.php.net/package/File_Ogg
+ * @link http://www.xiph.org/theora/
+ * @package File_Ogg
+ * @version CVS: $Id: Theora.php,v 1.9 2005/11/16 20:43:27 djg Exp $
+ */
+class File_Ogg_Theora extends File_Ogg_Media
+{
+ /**
+ * @access private
+ */
+ function __construct($streamSerial, $streamData, $filePointer)
+ {
+ parent::__construct($streamSerial, $streamData, $filePointer);
+ $this->_decodeIdentificationHeader();
+ $this->_decodeCommentsHeader();
+ $endSec = $this->getSecondsFromGranulePos( $this->_lastGranulePos );
+
+ $startSec = $this->getSecondsFromGranulePos( $this->_firstGranulePos );
+
+ //make sure the offset is worth taking into account oggz_chop related hack
+ if( $startSec > 1){
+ $this->_streamLength = $endSec - $startSec;
+ $this->_startOffset = $startSec;
+ }else{
+ $this->_streamLength = $endSec;
+ }
+
+ $this->_avgBitrate = $this->_streamLength ? ($this->_streamSize * 8) / $this->_streamLength : 0;
+ }
+ function getSecondsFromGranulePos($granulePos){
+ // Calculate GranulePos seconds
+ // First make some "numeric strings"
+ // These might not fit into PHP's integer type, but they will fit into
+ // the 53-bit mantissa of a double-precision number
+ $topWord = floatval( base_convert( substr( $granulePos, 0, 8 ), 16, 10 ) );
+ $bottomWord = floatval( base_convert( substr( $granulePos, 8, 8 ), 16, 10 ) );
+ // Calculate the keyframe position by shifting right by KFGSHIFT
+ // We don't use PHP's shift operators because they're terribly broken
+ // This is made slightly simpler by the fact that KFGSHIFT < 32
+ $keyFramePos = $topWord / pow(2, $this->_kfgShift - 32) +
+ floor( $bottomWord / pow(2, $this->_kfgShift) );
+ // Calculate the frame offset by masking off the top 64-KFGSHIFT bits
+ // This requires a bit of floating point trickery
+ $offset = fmod( $bottomWord, pow(2, $this->_kfgShift) );
+ // They didn't teach you that one at school did they?
+ // Now put it together with the frame rate to calculate time in seconds
+ return ( $keyFramePos + $offset ) / $this->_frameRate;
+ }
+ /**
+ * Get the 6-byte identification string expected in the common header
+ */
+ function getIdentificationString()
+ {
+ return OGG_STREAM_CAPTURE_THEORA;
+ }
+
+ /**
+ * Parse the identification header in a Theora stream.
+ * @access private
+ */
+ function _decodeIdentificationHeader()
+ {
+ $this->_decodeCommonHeader(OGG_THEORA_IDENTIFICATION_HEADER, OGG_THEORA_IDENTIFICATION_PAGE_OFFSET);
+ $h = File_Ogg::_readBigEndian( $this->_filePointer, array(
+ 'VMAJ' => 8,
+ 'VMIN' => 8,
+ 'VREV' => 8,
+ 'FMBW' => 16,
+ 'FMBH' => 16,
+ 'PICW' => 24,
+ 'PICH' => 24,
+ 'PICX' => 8,
+ 'PICY' => 8,
+ 'FRN' => 32,
+ 'FRD' => 32,
+ 'PARN' => 24,
+ 'PARD' => 24,
+ 'CS' => 8,
+ 'NOMBR' => 24,
+ 'QUAL' => 6,
+ 'KFGSHIFT' => 5,
+ 'PF' => 2));
+ if ( !$h ) {
+ throw new OggException("Stream is undecodable due to a truncated header.", OGG_ERROR_UNDECODABLE);
+ }
+
+ // Theora version
+ // Seems overly strict but this is what the spec says
+ // VREV is for backwards-compatible changes, apparently
+ if ( $h['VMAJ'] != 3 || $h['VMIN'] != 2 ) {
+ throw new OggException("Stream is undecodable due to an invalid theora version.", OGG_ERROR_UNDECODABLE);
+ }
+ $this->_theoraVersion = "{$h['VMAJ']}.{$h['VMIN']}.{$h['VREV']}";
+
+ // Frame height/width
+ if ( !$h['FMBW'] || !$h['FMBH'] ) {
+ throw new OggException("Stream is undecodable because it has frame size of zero.", OGG_ERROR_UNDECODABLE);
+ }
+ $this->_frameWidth = $h['FMBW'] * 16;
+ $this->_frameHeight = $h['FMBH'] * 16;
+
+ // Picture height/width
+ if ( $h['PICW'] > $this->_frameWidth || $h['PICH'] > $this->_frameHeight ) {
+ throw new OggException("Stream is undecodable because the picture width is greater than the frame width.", OGG_ERROR_UNDECODABLE);
+ }
+ $this->_pictureWidth = $h['PICW'];
+ $this->_pictureHeight = $h['PICH'];
+
+ // Picture offset
+ $this->_offsetX = $h['PICX'];
+ $this->_offsetY = $h['PICY'];
+ // Frame rate
+ $this->_frameRate = $h['FRD'] == 0 ? 0 : $h['FRN'] / $h['FRD'];
+ // Physical aspect ratio
+ if ( !$h['PARN'] || !$h['PARD'] ) {
+ $this->_physicalAspectRatio = 1;
+ } else {
+ $this->_physicalAspectRatio = $h['PARN'] / $h['PARD'];
+ }
+
+ // Color space
+ $colorSpaces = array(
+ 0 => 'Undefined',
+ 1 => 'Rec. 470M',
+ 2 => 'Rec. 470BG',
+ );
+ if ( isset( $colorSpaces[$h['CS']] ) ) {
+ $this->_colorSpace = $colorSpaces[$h['CS']];
+ } else {
+ $this->_colorSpace = 'Unknown (reserved)';
+ }
+
+ $this->_nomBitrate = $h['NOMBR'];
+
+ $this->_quality = $h['QUAL'];
+ $this->_kfgShift = $h['KFGSHIFT'];
+
+ $pixelFormats = array(
+ 0 => '4:2:0',
+ 1 => 'Unknown (reserved)',
+ 2 => '4:2:2',
+ 3 => '4:4:4',
+ );
+ $this->_pixelFormat = $pixelFormats[$h['PF']];
+
+ switch ( $h['PF'] ) {
+ case 0:
+ $h['NSBS'] =
+ floor( ($h['FMBW'] + 1) / 2 ) *
+ floor( ($h['FMBH'] + 1) / 2 ) + 2 *
+ floor( ($h['FMBW'] + 3) / 4 ) *
+ floor( ($h['FMBH'] + 3) / 4 );
+ $h['NBS'] = 6 * $h['FMBW'] * $h['FMBH'];
+ break;
+ case 2:
+ $h['NSBS'] =
+ floor( ($h['FMBW'] + 1) / 2 ) *
+ floor( ($h['FMBH'] + 1) / 2 ) + 2 *
+ floor( ($h['FMBW'] + 3) / 4 ) *
+ floor( ($h['FMBH'] + 1) / 2 );
+ $h['NBS'] = 8 * $h['FMBW'] * $h['FMBH'];
+ break;
+ case 3:
+ $h['NSBS'] =
+ 3 * floor( ($h['FMBW'] + 1) / 2 ) *
+ floor( ($h['FMBH'] + 1) / 2 );
+ $h['NBS'] = 12 * $h['FMBW'] * $h['FMBH'];
+ break;
+ default:
+ $h['NSBS'] = $h['NBS'] = 0;
+ }
+ $h['NMBS'] = $h['FMBW'] * $h['FMBH'];
+
+ $this->_idHeader = $h;
+ }
+
+ /**
+ * Get an associative array containing header information about the stream
+ * @access public
+ * @return array
+ */
+ function getHeader() {
+ return $this->_idHeader;
+ }
+
+ /**
+ * Get a short string describing the type of the stream
+ * @return string
+ */
+ function getType() {
+ return 'Theora';
+ }
+
+ /**
+ * Decode the comments header
+ * @access private
+ */
+ function _decodeCommentsHeader()
+ {
+ $this->_decodeCommonHeader(OGG_THEORA_COMMENTS_HEADER, OGG_THEORA_COMMENTS_PAGE_OFFSET);
+ $this->_decodeBareCommentsHeader();
+ }
+
+}
+?>
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Vorbis.php b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Vorbis.php
new file mode 100644
index 00000000..06c2c180
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/Ogg/Vorbis.php
@@ -0,0 +1,790 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4: */
+// +----------------------------------------------------------------------------+
+// | File_Ogg PEAR Package for Accessing Ogg Bitstreams |
+// | Copyright (c) 2005-2007 |
+// | David Grant <david@grant.org.uk> |
+// | Tim Starling <tstarling@wikimedia.org> |
+// +----------------------------------------------------------------------------+
+// | This library is free software; you can redistribute it and/or |
+// | modify it under the terms of the GNU Lesser General Public |
+// | License as published by the Free Software Foundation; either |
+// | version 2.1 of the License, or (at your option) any later version. |
+// | |
+// | This library is distributed in the hope that it will be useful, |
+// | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | Lesser General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU Lesser General Public |
+// | License along with this library; if not, write to the Free Software |
+// | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
+// +----------------------------------------------------------------------------+
+
+
+/**
+ * Check number for the first header in a Vorbis stream.
+ *
+ * @access private
+ */
+define("OGG_VORBIS_IDENTIFICATION_HEADER", 1);
+/**
+ * Check number for the second header in a Vorbis stream.
+ *
+ * @access private
+ */
+define("OGG_VORBIS_COMMENTS_HEADER", 3);
+/**
+ * Check number for the third header in a Vorbis stream.
+ *
+ * @access private
+ */
+define("OGG_VORBIS_SETUP_HEADER", 5);
+/**
+ * Error thrown if the stream appears to be corrupted.
+ *
+ * @access private
+ */
+define("OGG_VORBIS_ERROR_UNDECODABLE", OGG_ERROR_UNDECODABLE);
+/**
+ * Error thrown if the user attempts to extract a comment using a comment key
+ * that does not exist.
+ *
+ * @access private
+ */
+define("OGG_VORBIS_ERROR_INVALID_COMMENT", 2);
+
+define("OGG_VORBIS_IDENTIFICATION_PAGE_OFFSET", 0);
+define("OGG_VORBIS_COMMENTS_PAGE_OFFSET", 1);
+
+/**
+ * Error thrown if the user attempts to write a comment containing an illegal
+ * character
+ *
+ * @access private
+ */
+define("OGG_VORBIS_ERROR_ILLEGAL_COMMENT", 3);
+
+/**
+ * Extract the contents of a Vorbis logical stream.
+ *
+ * This class provides an interface to a Vorbis logical stream found within
+ * a Ogg stream. A variety of information may be extracted, including comment
+ * tags, running time, and bitrate. For more information, please see the following
+ * links.
+ *
+ * @author David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @category File
+ * @copyright David Grant <david@grant.org.uk>, Tim Starling <tstarling@wikimedia.org>
+ * @license http://www.gnu.org/copyleft/lesser.html GNU LGPL
+ * @link http://pear.php.net/package/File_Ogg
+ * @link http://www.xiph.org/vorbis/doc/
+ * @package File_Ogg
+ * @version CVS: $Id: Vorbis.php,v 1.13 2005/11/19 09:06:32 djg Exp $
+ */
+class File_Ogg_Vorbis extends File_Ogg_Media
+{
+
+ /**
+ * Version of vorbis specification used.
+ *
+ * @access private
+ * @var int
+ */
+ var $_version;
+
+ /**
+ * Number of channels in the vorbis stream.
+ *
+ * @access private
+ * @var int
+ */
+ var $_channels;
+
+ /**
+ * Number of samples per second in the vorbis stream.
+ *
+ * @access private
+ * @var int
+ */
+ var $_sampleRate;
+
+ /**
+ * Minimum bitrate for the vorbis stream.
+ *
+ * @access private
+ * @var int
+ */
+ var $_minBitrate;
+
+ /**
+ * Maximum bitrate for the vorbis stream.
+ *
+ * @access private
+ * @var int
+ */
+ var $_maxBitrate;
+
+ /**
+ * Nominal bitrate for the vorbis stream.
+ *
+ * @access private
+ * @var int
+ */
+ var $_nomBitrate;
+
+ /**
+ * Average bitrate for the vorbis stream.
+ *
+ * @access private
+ * @var float
+ */
+ var $_avgBitrate;
+
+ /**
+ * The length of this stream in seconds.
+ *
+ * @access private
+ * @var int
+ */
+ var $_streamLength;
+
+ /**
+ * the start offset of this stream in seconds
+ */
+ var $_startOffset;
+ /**
+ * Constructor for accessing a Vorbis logical stream.
+ *
+ * This method is the constructor for the native-PHP interface to a Vorbis logical
+ * stream, embedded within an Ogg physical stream.
+ *
+ * @param int $streamSerial Serial number of the logical stream.
+ * @param array $streamData Data for the requested logical stream.
+ * @param string $filePath Location of a file on the filesystem.
+ * @param pointer $filePointer File pointer for the current physical stream.
+ * @access private
+ */
+ function __construct($streamSerial, $streamData, $filePointer)
+ {
+ parent::__construct($streamSerial, $streamData, $filePointer);
+ $this->_decodeIdentificationHeader();
+ $this->_decodeCommentsHeader(OGG_VORBIS_COMMENTS_HEADER, OGG_VORBIS_COMMENTS_PAGE_OFFSET);
+
+ $endSec = $this->getSecondsFromGranulePos( $this->_lastGranulePos );
+ $startSec = $this->getSecondsFromGranulePos( $this->_firstGranulePos );
+
+ //make sure the offset is worth taking into account oggz_chop related hack
+ if( $startSec > 1){
+ $this->_streamLength = $endSec - $startSec;
+ $this->_startOffset = $startSec;
+ }else{
+ $this->_streamLength = $endSec;
+ }
+
+ $this->_avgBitrate = $this->_streamLength ? ($this->_streamSize * 8) / $this->_streamLength : 0;
+ }
+ function getSecondsFromGranulePos( $granulePos ){
+ return (( '0x' . substr( $granulePos, 0, 8 ) ) * pow(2, 32)
+ + ( '0x' . substr( $granulePos, 8, 8 ) ))
+ / $this->_idHeader['audio_sample_rate'];
+ }
+ /**
+ * Get a short string describing the type of the stream
+ */
+ function getType()
+ {
+ return 'Vorbis';
+ }
+
+ /**
+ * Parse the identification header (the first of three headers) in a Vorbis stream.
+ *
+ * This function parses the identification header. The identification header
+ * contains simple audio characteristics, such as sample rate and number of
+ * channels. There are a number of error-checking provisions laid down in the Vorbis
+ * specification to ensure the stream is pure.
+ *
+ * @access private
+ */
+ function _decodeIdentificationHeader()
+ {
+ $this->_decodeCommonHeader(OGG_VORBIS_IDENTIFICATION_HEADER, OGG_VORBIS_IDENTIFICATION_PAGE_OFFSET);
+
+ $h = File_Ogg::_readLittleEndian($this->_filePointer, array(
+ 'vorbis_version' => 32,
+ 'audio_channels' => 8,
+ 'audio_sample_rate' => 32,
+ 'bitrate_maximum' => 32,
+ 'bitrate_nominal' => 32,
+ 'bitrate_minimum' => 32,
+ 'blocksize_0' => 4,
+ 'blocksize_1' => 4,
+ 'framing_flag' => 1
+ ));
+
+ // The Vorbis stream version must be 0.
+ if ($h['vorbis_version'] == 0)
+ $this->_version = $h['vorbis_version'];
+ else
+ throw new OggException("Stream is undecodable due to an invalid vorbis stream version.", OGG_VORBIS_ERROR_UNDECODABLE);
+
+ // The number of channels MUST be greater than 0.
+ if ($h['audio_channels'] == 0)
+ throw new OggException("Stream is undecodable due to zero channels.", OGG_VORBIS_ERROR_UNDECODABLE);
+ else
+ $this->_channels = $h['audio_channels'];
+
+ // The sample rate MUST be greater than 0.
+ if ($h['audio_sample_rate'] == 0)
+ throw new OggException("Stream is undecodable due to a zero sample rate.", OGG_VORBIS_ERROR_UNDECODABLE);
+ else
+ $this->_sampleRate = $h['audio_sample_rate'];
+
+ // Extract the various bitrates
+ $this->_maxBitrate = $h['bitrate_maximum'];
+ $this->_nomBitrate = $h['bitrate_nominal'];
+ $this->_minBitrate = $h['bitrate_minimum'];
+
+ // Powers of two between 6 and 13 inclusive.
+ $valid_block_sizes = array(64, 128, 256, 512, 1024, 2048, 4096, 8192);
+
+ // blocksize_0 MUST be a valid blocksize.
+ $blocksize_0 = pow(2, $h['blocksize_0']);
+ if (FALSE == in_array($blocksize_0, $valid_block_sizes))
+ throw new OggException("Stream is undecodable because blocksize_0 is $blocksize_0, which is not a valid size.", OGG_VORBIS_ERROR_UNDECODABLE);
+
+ // Extract bits 5 to 8 from the character data.
+ // blocksize_1 MUST be a valid blocksize.
+ $blocksize_1 = pow(2, $h['blocksize_1']);
+ if (FALSE == in_array($blocksize_1, $valid_block_sizes))
+ throw new OggException("Stream is undecodable because blocksize_1 is not a valid size.", OGG_VORBIS_ERROR_UNDECODABLE);
+
+ // blocksize 0 MUST be less than or equal to blocksize 1.
+ if ($blocksize_0 > $blocksize_1)
+ throw new OggException("Stream is undecodable because blocksize_0 is not less than or equal to blocksize_1.", OGG_VORBIS_ERROR_UNDECODABLE);
+
+ // The framing bit MUST be set to mark the end of the identification header.
+ // Some encoders are broken though -- TS
+ /*
+ if ($h['framing_flag'] == 0)
+ throw new OggException("Stream in undecodable because the framing bit is not non-zero.", OGG_VORBIS_ERROR_UNDECODABLE);
+ */
+
+ $this->_idHeader = $h;
+ }
+
+ /**
+ * Decode the comments header
+ * @access private
+ * @param int $packetType
+ * @param int $pageOffset
+ */
+ function _decodeCommentsHeader($packetType, $pageOffset)
+ {
+ $this->_decodeCommonHeader($packetType, $pageOffset);
+ $this->_decodeBareCommentsHeader();
+ // The framing bit MUST be set to mark the end of the comments header.
+ $framing_bit = unpack("Cdata", fread($this->_filePointer, 1));
+ if ($framing_bit['data'] != 1)
+ throw new OggException("Stream Undecodable", OGG_VORBIS_ERROR_UNDECODABLE);
+ }
+
+ /**
+ * Get the 6-byte identification string expected in the common header
+ */
+ function getIdentificationString() {
+ return OGG_STREAM_CAPTURE_VORBIS;
+ }
+
+ /**
+ * Version of the Vorbis specification referred to in the encoding of this stream.
+ *
+ * This method returns the version of the Vorbis specification (currently 0 (ZERO))
+ * referred to by the encoder of this stream. The Vorbis specification is well-
+ * defined, and thus one does not expect this value to change on a frequent basis.
+ *
+ * @access public
+ * @return int
+ */
+ function getEncoderVersion()
+ {
+ return ($this->_version);
+ }
+
+ /**
+ * Samples per second.
+ *
+ * This function returns the number of samples used per second in this
+ * recording. Probably the most common value here is 44,100.
+ *
+ * @return int
+ * @access public
+ */
+ function getSampleRate()
+ {
+ return ($this->_sampleRate);
+ }
+
+ /**
+ * Various bitrate measurements
+ *
+ * Gives an array of the values of four different types of bitrates for this
+ * stream. The nominal, maximum and minimum values are found within the file,
+ * whereas the average value is computed.
+ *
+ * @access public
+ * @return array
+ */
+ function getBitrates()
+ {
+ return (array("nom" => $this->_nomBitrate, "max" => $this->_maxBitrate, "min" => $this->_minBitrate, "avg" => $this->_avgBitrate));
+ }
+
+ /**
+ * Gives the most accurate bitrate measurement from this stream.
+ *
+ * This function returns the most accurate bitrate measurement for this
+ * recording, depending on values set in the stream header.
+ *
+ * @access public
+ * @return float
+ */
+ function getBitrate()
+ {
+ if ($this->_avgBitrate != 0)
+ return ($this->_avgBitrate);
+ elseif ($this->_nomBitrate != 0)
+ return ($this->_nomBitrate);
+ else
+ return (($this->_minBitrate + $this->_maxBitrate) / 2);
+ }
+
+ /**
+ * Gives the length (in seconds) of this stream.
+ *
+ * @access public
+ * @return int
+ */
+ function getLength()
+ {
+ return ($this->_streamLength);
+ }
+ /**
+ * Get the start offset of the stream in seconds
+ * @access public
+ * @return int
+ */
+ function getStartOffset(){
+ return ($this->_startOffset);
+ }
+ /**
+ * States whether this logical stream was encoded in mono.
+ *
+ * @access public
+ * @return boolean
+ */
+ function isMono()
+ {
+ return ($this->_channels == 1);
+ }
+
+ /**
+ * States whether this logical stream was encoded in stereo.
+ *
+ * @access public
+ * @return boolean
+ */
+ function isStereo()
+ {
+ return ($this->_channels == 2);
+ }
+
+ /**
+ * States whether this logical stream was encoded in quadrophonic sound.
+ *
+ * @access public
+ * @return boolean
+ */
+ function isQuadrophonic()
+ {
+ return ($this->_channels == 4);
+ }
+
+ /**
+ * The title of this track, e.g. "What's Up Pussycat?".
+ *
+ * @access public
+ * @return string
+ */
+ function getTitle()
+ {
+ return ($this->getField("TITLE"));
+ }
+
+ /**
+ * Set the title of this track.
+ *
+ * @access public
+ * @param string $title
+ * @param boolean $replace
+ */
+ function setTitle($title, $replace = true)
+ {
+ $this->setField("TITLE", $title, $replace);
+ }
+
+ /**
+ * The version of the track, such as a remix.
+ *
+ * @access public
+ * @return string
+ */
+ function getVersion()
+ {
+ return $this->getField("VERSION");
+ }
+
+ /**
+ * Set the version of this track.
+ *
+ * @access public
+ * @param string $version
+ * @param boolean $replace
+ */
+ function setVersion($version, $replace = true)
+ {
+ $this->setField("VERSION", $version, $replace);
+ }
+
+ /**
+ * The album or collection from which this track comes.
+ *
+ * @access public
+ * @return string
+ */
+ function getAlbum()
+ {
+ return ($this->getField("ALBUM"));
+ }
+
+ /**
+ * Set the album or collection for this track.
+ *
+ * @access public
+ * @param string $album
+ * @param boolean $replace
+ */
+ function setAlbum($album, $replace = true)
+ {
+ $this->setField("ALBUM", $album, $replace);
+ }
+
+ /**
+ * The number of this track if it is part of a larger collection.
+ *
+ * @access public
+ * @return string
+ */
+ function getTrackNumber()
+ {
+ return ($this->getField("TRACKNUMBER"));
+ }
+
+ /**
+ * Set the number of this relative to the collection.
+ *
+ * @access public
+ * @param int $number
+ * @param boolean $replace
+ */
+ function setTrackNumber($number, $replace = true)
+ {
+ $this->setField("TRACKNUMBER", $number, $replace);
+ }
+
+ /**
+ * The artist responsible for this track.
+ *
+ * This function returns the name of the artist responsible for this
+ * recording, which may be either a solo-artist, duet or group.
+ *
+ * @access public
+ * @return string
+ */
+ function getArtist()
+ {
+ return ($this->getField("ARTIST"));
+ }
+
+ /**
+ * Set the artist of this track.
+ *
+ * @access public
+ * @param string $artist
+ * @param boolean $replace
+ */
+ function setArtist($artist, $replace = true)
+ {
+ $this->setField("ARTIST", $artist, $replace = true);
+ }
+
+ /**
+ * The performer of this track, such as an orchestra
+ *
+ * @access public
+ * @return string
+ */
+ function getPerformer()
+ {
+ return ($this->getField("PERFORMER"));
+ }
+
+ /**
+ * Set the performer of this track.
+ *
+ * @access public
+ * @param string $performer
+ * @param boolean $replace
+ */
+ function setPerformer($performer, $replace = true)
+ {
+ $this->setField("PERFORMER", $performer, $replace);
+ }
+
+ /**
+ * The copyright attribution for this track.
+ *
+ * @access public
+ * @return string
+ */
+ function getCopyright()
+ {
+ return ($this->getField("COPYRIGHT"));
+ }
+
+ /**
+ * Set the copyright attribution for this track.
+ *
+ * @access public
+ * @param string $copyright
+ * @param boolean $replace
+ */
+ function setCopyright($copyright, $replace = true)
+ {
+ $this->setField("COPYRIGHT", $copyright, $replace);
+ }
+
+ /**
+ * The rights of distribution for this track.
+ *
+ * This funtion returns the license for this track, and may include
+ * copyright information, or a creative commons statement.
+ *
+ * @access public
+ * @return string
+ */
+ function getLicense()
+ {
+ return ($this->getField("LICENSE"));
+ }
+
+ /**
+ * Set the distribution rights for this track.
+ *
+ * @access public
+ * @param string $license
+ * @param boolean $replace
+ */
+ function setLicense($license, $replace = true)
+ {
+ $this->setField("LICENSE", $license, $replace);
+ }
+
+ /**
+ * The organisation responsible for this track.
+ *
+ * This function returns the name of the organisation responsible for
+ * the production of this track, such as the record label.
+ *
+ * @access public
+ * @return string
+ */
+ function getOrganization()
+ {
+ return ($this->getField("ORGANIZATION"));
+ }
+
+ /**
+ * Set the organisation responsible for this track.
+ *
+ * @access public
+ * @param string $organization
+ * @param boolean $replace
+ */
+ function setOrganziation($organization, $replace = true)
+ {
+ $this->setField("ORGANIZATION", $organization, $replace);
+ }
+
+ /**
+ * A short description of the contents of this track.
+ *
+ * This function returns a short description of this track, which might
+ * contain extra information that doesn't fit anywhere else.
+ *
+ * @access public
+ * @return string
+ */
+ function getDescription()
+ {
+ return ($this->getField("DESCRIPTION"));
+ }
+
+ /**
+ * Set the description of this track.
+ *
+ * @access public
+ * @param string $description
+ * @param boolean $replace
+ */
+ function setDescription($description, $replace = true)
+ {
+ $this->setField("DESCRIPTION", $replace);
+ }
+
+ /**
+ * The genre of this recording (e.g. Rock)
+ *
+ * This function returns the genre of this recording. There are no pre-
+ * defined genres, so this is completely up to the tagging software.
+ *
+ * @access public
+ * @return string
+ */
+ function getGenre()
+ {
+ return ($this->getField("GENRE"));
+ }
+
+ /**
+ * Set the genre of this track.
+ *
+ * @access public
+ * @param string $genre
+ * @param boolean $replace
+ */
+ function setGenre($genre, $replace = true)
+ {
+ $this->setField("GENRE", $genre, $replace);
+ }
+
+ /**
+ * The date of the recording of this track.
+ *
+ * This function returns the date on which this recording was made. There
+ * is no specification for the format of this date.
+ *
+ * @access public
+ * @return string
+ */
+ function getDate()
+ {
+ return ($this->getField("DATE"));
+ }
+
+ /**
+ * Set the date of recording for this track.
+ *
+ * @access public
+ * @param string $date
+ * @param boolean $replace
+ */
+ function setDate($date, $replace = true)
+ {
+ $this->setField("DATE", $date, $replace);
+ }
+
+ /**
+ * Where this recording was made.
+ *
+ * This function returns where this recording was made, such as a recording
+ * studio, or concert venue.
+ *
+ * @access public
+ * @return string
+ */
+ function getLocation()
+ {
+ return ($this->getField("LOCATION"));
+ }
+
+ /**
+ * Set the location of the recording of this track.
+ *
+ * @access public
+ * @param string $location
+ * @param boolean $replace
+ */
+ function setLocation($location, $replace = true)
+ {
+ $this->setField("LOCATION", $location, $replace);
+ }
+
+ /**
+ * @access public
+ * @return string
+ */
+ function getContact()
+ {
+ return ($this->getField("CONTACT"));
+ }
+
+ /**
+ * Set the contact information for this track.
+ *
+ * @access public
+ * @param string $contact
+ * @param boolean $replace
+ */
+ function setContact($contact, $replace = true)
+ {
+ $this->setField("CONTACT", $contact, $replace);
+ }
+
+ /**
+ * International Standard Recording Code.
+ *
+ * Returns the International Standard Recording Code. This code can be
+ * validated using the Validate_ISPN package.
+ *
+ * @access public
+ * @return string
+ */
+ function getIsrc()
+ {
+ return ($this->getField("ISRC"));
+ }
+
+ /**
+ * Set the ISRC for this track.
+ *
+ * @access public
+ * @param string $isrc
+ * @param boolean $replace
+ */
+ function setIsrc($isrc, $replace = true)
+ {
+ $this->setField("ISRC", $isrc, $replace);
+ }
+
+ /**
+ * Get an associative array containing header information about the stream
+ * @access public
+ * @return array
+ */
+ function getHeader() {
+ return $this->_idHeader;
+ }
+}
+?>
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/README b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/README
new file mode 100644
index 00000000..963ca07c
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/File_Ogg/File/README
@@ -0,0 +1,2 @@
+This was originally a fork of the File_Ogg package in PEAR.
+
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/OggException.php b/extensions/TimedMediaHandler/handlers/OggHandler/OggException.php
new file mode 100644
index 00000000..a09d36da
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/OggException.php
@@ -0,0 +1,4 @@
+<?php
+
+class OggException extends Exception {
+}
diff --git a/extensions/TimedMediaHandler/handlers/OggHandler/OggHandler.php b/extensions/TimedMediaHandler/handlers/OggHandler/OggHandler.php
new file mode 100644
index 00000000..83e1a0e7
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/OggHandler/OggHandler.php
@@ -0,0 +1,379 @@
+<?php
+/**
+ * ogg handler
+ */
+class OggHandlerTMH extends TimedMediaHandler {
+ const METADATA_VERSION = 2;
+
+ /**
+ * @param $image File
+ * @param $path string
+ * @return string
+ */
+ function getMetadata( $image, $path ) {
+ $metadata = array( 'version' => self::METADATA_VERSION );
+
+ try {
+ $f = new File_Ogg( $path );
+ $streams = array();
+ foreach ( $f->listStreams() as $streamIDs ) {
+ foreach ( $streamIDs as $streamID ) {
+ $stream = $f->getStream( $streamID );
+ $streams[$streamID] = array(
+ 'serial' => $stream->getSerial(),
+ 'group' => $stream->getGroup(),
+ 'type' => $stream->getType(),
+ 'vendor' => $stream->getVendor(),
+ 'length' => $stream->getLength(),
+ 'size' => $stream->getSize(),
+ 'header' => $stream->getHeader(),
+ 'comments' => $stream->getComments()
+ );
+ }
+ }
+ $metadata['streams'] = $streams;
+ $metadata['length'] = $f->getLength();
+ // Get the offset of the file (in cases where the file is a segment copy)
+ $metadata['offset'] = $f->getStartOffset();
+ } catch ( OggException $e ) {
+ // File not found, invalid stream, etc.
+ $metadata['error'] = array(
+ 'message' => $e->getMessage(),
+ 'code' => $e->getCode()
+ );
+ }
+ return serialize( $metadata );
+ }
+
+ /**
+ * Display metadata box on file description page.
+ *
+ * This is pretty basic, it puts data from all the streams together,
+ * and only outputs a couple of the most commonly used ogg "comments",
+ * with comments from all the streams combined
+ *
+ * @param File $file
+ * @param bool|IContextSource $context Context to use (optional)
+ * @return array|bool
+ */
+ public function formatMetadata( $file, $context = false ) {
+ $meta = $this->getCommonMetaArray( $file );
+ if ( count( $meta ) === 0 ) {
+ return false;
+ }
+ return $this->formatMetadataHelper( $meta, $context );
+ }
+
+ /**
+ * Get some basic metadata properties that are common across file types.
+ *
+ * @param File $file
+ * @return array Array of metadata. See MW's FormatMetadata class for format.
+ */
+ public function getCommonMetaArray( File $file ) {
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) || !isset( $metadata['streams'] ) ) {
+ return array();
+ }
+
+ // See http://www.xiph.org/vorbis/doc/v-comment.html
+ // http://age.hobba.nl/audio/mirroredpages/ogg-tagging.html
+ $metadataMap = array(
+ 'title' => 'ObjectName',
+ 'artist' => 'Artist',
+ 'performer' => 'Artist',
+ 'description' => 'ImageDescription',
+ 'license' => 'UsageTerms',
+ 'copyright' => 'Copyright',
+ 'organization' => 'dc-publisher',
+ 'date' => 'DateTimeDigitized',
+ 'location' => 'LocationDest',
+ 'contact' => 'Contact',
+ 'encoded_using' => 'Software',
+ 'encoder' => 'Software',
+ // OpenSubtitles.org hash. Identifies source video.
+ 'source_ohash' => 'OriginalDocumentID',
+ 'comment' => 'UserComment',
+ 'language' => 'LanguageCode',
+ );
+
+ $props = array();
+
+ foreach( $metadata['streams'] as $stream ) {
+ if ( isset( $stream['vendor'] ) ) {
+ if ( !isset( $props['Software'] ) ) {
+ $props['Software'] = array();
+ }
+ $props['Software'][] = trim( $stream['vendor'] );
+ }
+ if ( !isset( $stream['comments'] ) ) {
+ continue;
+ }
+ foreach( $stream['comments'] as $name => $rawValue ) {
+ // $value will be an array if the file has
+ // a multiple tags with the same name. Otherwise it
+ // is a string.
+ foreach( (array) $rawValue as $value ) {
+ $trimmedValue = trim( $value );
+ if ( $trimmedValue === '' ) {
+ continue;
+ }
+ $lowerName = strtolower( $name );
+ if ( isset( $metadataMap[$lowerName] ) ) {
+ $convertedName = $metadataMap[$lowerName];
+ if ( !isset( $props[$convertedName] ) ) {
+ $props[$convertedName] = array();
+ }
+ $props[$convertedName][] = $trimmedValue;
+ }
+ }
+ }
+
+ }
+ // properties might be duplicated across streams
+ foreach( $props as &$type ) {
+ $type = array_unique( $type );
+ $type = array_values( $type );
+ }
+
+ return $props;
+ }
+
+ /**
+ * Get the "media size"
+ *
+ * @param $file File
+ * @param $path string
+ * @param $metadata bool
+ * @return array|bool
+ */
+ function getImageSize( $file, $path, $metadata = false ) {
+ global $wgMediaVideoTypes;
+ // Just return the size of the first video stream
+ if ( $metadata === false ) {
+ $metadata = $file->getMetadata();
+ }
+ $metadata = $this->unpackMetadata( $metadata );
+ if ( isset( $metadata['error'] ) || !isset( $metadata['streams'] ) ) {
+ return false;
+ }
+ foreach ( $metadata['streams'] as $stream ) {
+ if ( in_array( $stream['type'], $wgMediaVideoTypes ) ) {
+ $pictureWidth = $stream['header']['PICW'];
+ $parNumerator = $stream['header']['PARN'];
+ $parDenominator = $stream['header']['PARD'];
+ if( $parNumerator && $parDenominator ) {
+ // Compensate for non-square pixel aspect ratios
+ $pictureWidth = $pictureWidth * $parNumerator / $parDenominator;
+ }
+ return array(
+ intval( $pictureWidth ),
+ intval( $stream['header']['PICH'] )
+ );
+ }
+ }
+ return array( false, false );
+ }
+
+ /**
+ * @param $metadata
+ * @return bool|mixed
+ */
+ function unpackMetadata( $metadata ) {
+ wfSuppressWarnings();
+ $unser = unserialize( $metadata );
+ wfRestoreWarnings();
+ if ( isset( $unser['version'] ) && $unser['version'] == self::METADATA_VERSION ) {
+ return $unser;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * @param $image
+ * @return string
+ */
+ function getMetadataType( $image ) {
+ return 'ogg';
+ }
+ /**
+ * @param $file File
+ */
+ function getWebType( $file ) {
+ $baseType = ( $file->getWidth() == 0 && $file->getHeight() == 0 )? 'audio' : 'video';
+ $baseType .= '/ogg';
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return $baseType;
+ }
+ $codecs = strtolower( implode( ", ", $streamTypes ) );
+ return $baseType . '; codecs="' . $codecs . '"';
+ }
+ /**
+ * @param $file File
+ * @return array|bool
+ */
+ function getStreamTypes( $file ) {
+ $streamTypes = array();
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return false;
+ }
+ foreach ( $metadata['streams'] as $stream ) {
+ $streamTypes[] = $stream['type'];
+ }
+ return array_unique( $streamTypes );
+ }
+
+ /**
+ * @param $file File
+ * @return int
+ */
+ function getOffset( $file ){
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) || !isset( $metadata['offset']) ) {
+ return 0;
+ } else {
+ return $metadata['offset'];
+ }
+ }
+
+ /**
+ * @param $file File
+ * @return int
+ */
+ function getLength( $file ) {
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return 0;
+ } else {
+ return $metadata['length'];
+ }
+ }
+
+ /**
+ * Get useful response headers for GET/HEAD requests for a file with the given metadata
+ * @param $metadata mixed Result this handlers getMetadata() for a file
+ * @return Array
+ */
+ public function getStreamHeaders( $metadata ) {
+ $metadata = $this->unpackMetadata( $metadata );
+ if ( $metadata && !isset( $metadata['error'] ) && isset( $metadata['length'] ) ) {
+ return array( 'X-Content-Duration' => floatval( $metadata[ 'length' ] ) );
+ }
+ return array();
+ }
+
+ /**
+ * @param $file File
+ * @return float|int
+ */
+ function getFramerate( $file ){
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return 0;
+ } else {
+ // Return the first found theora stream framerate:
+ foreach ( $metadata['streams'] as $stream ) {
+ if( $stream['type'] == 'Theora' ){
+ return $stream['header']['FRN'] / $stream['header']['FRD'];
+ }
+ }
+ return 0;
+ }
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getShortDesc( $file ) {
+ global $wgLang, $wgMediaAudioTypes, $wgMediaVideoTypes;
+
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return parent::getShortDesc( $file );
+ }
+ if ( array_intersect( $streamTypes, $wgMediaVideoTypes ) ) {
+ // Count multiplexed audio/video as video for short descriptions
+ $msg = 'timedmedia-ogg-short-video';
+ } elseif ( array_intersect( $streamTypes, $wgMediaAudioTypes ) ) {
+ $msg = 'timedmedia-ogg-short-audio';
+ } else {
+ $msg = 'timedmedia-ogg-short-general';
+ }
+ return wfMessage( $msg, implode( '/', $streamTypes ),
+ $wgLang->formatTimePeriod( $this->getLength( $file ) ) )->text();
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getLongDesc( $file ) {
+ global $wgLang, $wgMediaVideoTypes, $wgMediaAudioTypes;
+
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ $unpacked = $this->unpackMetadata( $file->getMetadata() );
+ if ( isset( $unpacked['error']['message'] ) ) {
+ return wfMessage( 'timedmedia-ogg-long-error', $unpacked['error']['message'] )->text();
+ } else {
+ return wfMessage( 'timedmedia-ogg-long-no-streams' )->text();
+ }
+ }
+ if ( array_intersect( $streamTypes,$wgMediaVideoTypes ) ) {
+ if ( array_intersect( $streamTypes, $wgMediaAudioTypes ) ) {
+ $msg = 'timedmedia-ogg-long-multiplexed';
+ } else {
+ $msg = 'timedmedia-ogg-long-video';
+ }
+ } elseif ( array_intersect( $streamTypes, $wgMediaAudioTypes ) ) {
+ $msg = 'timedmedia-ogg-long-audio';
+ } else {
+ $msg = 'timedmedia-ogg-long-general';
+ }
+ $size = 0;
+ $unpacked = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$unpacked || isset( $metadata['error'] ) ) {
+ $length = 0;
+ } else {
+ $length = $this->getLength( $file );
+ foreach ( $unpacked['streams'] as $stream ) {
+ if( isset( $stream['size'] ) )
+ $size += $stream['size'];
+ }
+ }
+ return wfMessage(
+ $msg,
+ implode( '/', $streamTypes ),
+ $wgLang->formatTimePeriod( $length ),
+ $wgLang->formatBitrate( $this->getBitRate( $file ) )
+ )->numParams(
+ $file->getWidth(),
+ $file->getHeight()
+ )->text();
+ }
+
+ /**
+ * @param $file File
+ * @return float|int
+ */
+ function getBitRate( &$file ){
+ $size = 0;
+ $unpacked = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$unpacked || isset( $unpacked['error'] ) ) {
+ $length = 0;
+ } else {
+ $length = $this->getLength( $file );
+ if ( isset( $unpacked['streams'] ) ) {
+ foreach ( $unpacked['streams'] as $stream ) {
+ if( isset( $stream['size'] ) )
+ $size += $stream['size'];
+ }
+ }
+ }
+ return $length == 0 ? 0 : $size / $length * 8;
+ }
+}
diff --git a/extensions/TimedMediaHandler/handlers/TextHandler/TextHandler.php b/extensions/TimedMediaHandler/handlers/TextHandler/TextHandler.php
new file mode 100644
index 00000000..3c229d5f
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/TextHandler/TextHandler.php
@@ -0,0 +1,305 @@
+<?php
+/**
+ * Timed Text handling for mediaWiki
+ *
+ * Timed text support is presently fairly limited. Unlike Ogg and WebM handlers,
+ * timed text does not extend the TimedMediaHandler class.
+ *
+ * TODO On "new" timedtext language save purge all pages where file exists
+ */
+
+
+/**
+ * Subclass ApiMain but query other db
+ */
+class ForeignApiQueryAllPages extends ApiQueryAllPages {
+ public function __construct( $mDb, $query, $moduleName ) {
+ global $wgTimedTextForeignNamespaces;
+
+ $this->foreignDb = $mDb;
+
+ $wikiID = $this->foreignDb->getWikiID();
+ if ( isset( $wgTimedTextForeignNamespaces[ $wikiID ] ) ) {
+ $this->foreignNs = $wgTimedTextForeignNamespaces[ $wikiID ];
+ } else {
+ $this->foreignNs = NS_TIMEDTEXT;
+ }
+ parent::__construct( $query, $moduleName, 'ap' );
+ }
+
+ protected function getDB() {
+ return $this->foreignDb;
+ }
+
+ protected function parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues ) {
+ // foreignnNs might not be defined localy,
+ // catch the undefined error here
+ if ( $valueName == 'apnamespace'
+ && $value == $this->foreignNs
+ && $allowMultiple == false
+ ) {
+ return $this->foreignNs;
+ }
+ return parent::parseMultiValue( $valueName, $value, $allowMultiple, $allowedValues );
+ }
+
+ /**
+ * An alternative to titleToKey() that doesn't trim trailing spaces
+ *
+ *
+ * @FIXME: I'M A BIG HACK
+ *
+ * @param string $titlePart Title part with spaces
+ * @return string Title part with underscores
+ */
+ public function titlePartToKey( $titlePart, $defaultNamespace = NS_MAIN ) {
+ return substr( $this->titleToKey( $titlePart . 'x' ), 0, -1 );
+ }
+}
+
+class TextHandler {
+ var $remoteNs = null;//lazy init remote Namespace number
+
+ /**
+ * @var File
+ */
+ protected $file;
+
+ function __construct( $file ){
+ $this->file = $file;
+ }
+
+ /**
+ * Get the timed text tracks elements as an associative array
+ * @return array|mixed
+ */
+ function getTracks(){
+ if( $this->file->isLocal() ){
+ return $this->getLocalTextSources();
+ } elseif ( $this->file->getRepo() instanceof ForeignDBViaLBRepo ){
+ return $this->getForeignDBTextSources();
+ } else {
+ return $this->getRemoteTextSources();
+ }
+ }
+
+ /**
+ * @return bool|int|null
+ */
+ function getTimedTextNamespace(){
+ global $wgEnableLocalTimedText;
+ if( $this->file->isLocal() ) {
+ if ( $wgEnableLocalTimedText ) {
+ return NS_TIMEDTEXT;
+ } else {
+ return false;
+ }
+ } elseif( $this->file->repo instanceof ForeignDBViaLBRepo ){
+ global $wgTimedTextForeignNamespaces;
+ $wikiID = $this->file->getRepo()->getSlaveDB()->getWikiID();
+ if ( isset( $wgTimedTextForeignNamespaces[ $wikiID ] ) ) {
+ return $wgTimedTextForeignNamespaces[ $wikiID ];
+ }
+ // failed to get namespace via ForeignDBViaLBRepo, return NS_TIMEDTEXT
+ return NS_TIMEDTEXT;
+ } else {
+ if( $this->remoteNs !== null ){
+ return $this->remoteNs;
+ }
+ // Get the namespace data from the image api repo:
+ // fetchImageQuery query caches results
+ $data = $this->file->getRepo()->fetchImageQuery( array(
+ 'meta' =>'siteinfo',
+ 'siprop' => 'namespaces'
+ ));
+
+ if( isset( $data['query'] ) && isset( $data['query']['namespaces'] ) ){
+ // get the ~last~ timed text namespace defined
+ foreach( $data['query']['namespaces'] as $ns ){
+ if( $ns['*'] == 'TimedText' ){
+ $this->remoteNs = $ns['id'];
+ }
+ }
+ }
+ // Return the remote Ns
+ return $this->remoteNs;
+ }
+ }
+
+ /**
+ * @return array|bool
+ */
+ function getTextPagesQuery(){
+ $ns = $this->getTimedTextNamespace();
+ if( $ns === false ){
+ wfDebug("Repo: " . $this->file->repo->getName() . " does not have a TimedText namesapce \n");
+ // No timed text namespace, don't try to look up timed text tracks
+ return false;
+ }
+ return array(
+ 'action' => 'query',
+ 'list' => 'allpages',
+ 'apnamespace' => $ns,
+ 'aplimit' => 300,
+ 'apprefix' => $this->file->getTitle()->getDBkey()
+ );
+ }
+
+ /**
+ * @return array|mixed
+ */
+ function getRemoteTextSources(){
+ global $wgMemc;
+ // Use descriptionCacheExpiry as our expire for timed text tracks info
+ if ( $this->file->getRepo()->descriptionCacheExpiry > 0 ) {
+ wfDebug("Attempting to get text tracks from cache...");
+ $key = $this->file->getRepo()->getLocalCacheKey( 'RemoteTextTracks', 'url', $this->file->getName() );
+ $obj = $wgMemc->get($key);
+ if ($obj) {
+ wfDebug("success!\n");
+ return $obj;
+ }
+ wfDebug("miss\n");
+ }
+ wfDebug("Get text tracks from remote api \n");
+ $query = $this->getTextPagesQuery();
+
+ // Error in getting timed text namespace return empty array;
+ if( $query === false ){
+ return array();
+ }
+ $data = $this->file->getRepo()->fetchImageQuery( $query );
+ $textTracks = $this->getTextTracksFromData( $data );
+ if ( $data && $this->file->repo->descriptionCacheExpiry > 0 ) {
+ $wgMemc->set( $key, $textTracks, $this->file->repo->descriptionCacheExpiry );
+ }
+ return $textTracks;
+ }
+
+ /**
+ * @return array
+ */
+ function getLocalTextSources(){
+ global $wgEnableLocalTimedText;
+ if ( $wgEnableLocalTimedText ) {
+ // Init $this->textTracks
+ $params = new FauxRequest( $this->getTextPagesQuery() );
+ $api = new ApiMain( $params );
+ $api->execute();
+ if ( defined( 'ApiResult::META_CONTENT' ) ) {
+ $data = $api->getResult()->getResultData( null, array( 'Strip' => 'all' ) );
+ } else {
+ $data = $api->getResultData();
+ }
+ wfDebug(print_r($data, true));
+ // Get the list of language Names
+ return $this->getTextTracksFromData( $data );
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * @return array|mixed
+ */
+ function getForeignDBTextSources(){
+ // Init $this->textTracks
+ $params = new FauxRequest( $this->getTextPagesQuery() );
+ $api = new ApiMain( $params );
+ $api->profileIn();
+ $query = new ApiQuery( $api, 'foo', 'bar' );
+ $query->profileIn();
+ $module = new ForeignApiQueryAllPages( $this->file->getRepo()->getSlaveDB(), $query, 'allpages' );
+ $module->profileIn();
+ $module->execute();
+ $module->profileOut();
+ $query->profileOut();
+ $api->profileOut();
+
+ if ( defined( 'ApiResult::META_CONTENT' ) ) {
+ $data = $module->getResult()->getResultData( null, array( 'Strip' => 'all' ) );
+ } else {
+ $data = $module->getResultData();
+ }
+ // Get the list of language Names
+ return $this->getTextTracksFromData( $data );
+ }
+
+ /**
+ * @param $data
+ * @return array
+ */
+ function getTextTracksFromData( $data ){
+ $textTracks = array();
+ $providerName = $this->file->repo->getName();
+ // commons is called shared in production. normalize it to wikimediacommons
+ if( $providerName == 'shared' ){
+ $providerName = 'wikimediacommons';
+ }
+ // Provider name should be the same as the interwiki map
+ // @@todo more testing with this:
+
+ $langNames = Language::fetchLanguageNames( null, 'mw' );
+ if( $data['query'] && $data['query']['allpages'] ){
+ foreach( $data['query']['allpages'] as $page ){
+ $subTitle = Title::newFromText( $page['title'] ) ;
+ $tileParts = explode( '.', $page['title'] );
+ if( count( $tileParts) >= 3 ){
+ $timedTextExtension = array_pop( $tileParts );
+ $languageKey = array_pop( $tileParts );
+ $contentType = $this->getContentType( $timedTextExtension );
+ } else {
+ continue;
+ }
+ // If there is no valid language continue:
+ if( !isset( $langNames[ $languageKey ] ) ){
+ continue;
+ }
+ $namespacePrefix = "TimedText:";
+ $textTracks[] = array(
+ 'kind' => 'subtitles',
+ 'data-mwtitle' => $namespacePrefix . $subTitle->getDBkey(),
+ 'data-mwprovider' => $providerName,
+ 'type' => $contentType,
+ // @todo Should eventually add special entry point and output proper WebVTT format:
+ // http://www.whatwg.org/specs/web-apps/current-work/webvtt.html
+ 'src' => $this->getFullURL( $page['title'], $contentType ),
+ 'srclang' => $languageKey,
+ 'data-dir' => Language::factory( $languageKey )->getDir(),
+ 'label' => wfMessage('timedmedia-subtitle-language',
+ $langNames[ $languageKey ],
+ $languageKey )->text()
+ );
+ }
+ }
+ return $textTracks;
+ }
+
+ function getContentType( $timedTextExtension ) {
+ if ( $timedTextExtension === 'srt' ) {
+ return 'text/x-srt';
+ } else if ( $timedTextExtension === 'vtt' ) {
+ return 'text/vtt';
+ }
+ return '';
+ }
+
+ function getFullURL( $pageTitle, $contentType ){
+ if( $this->file->isLocal() ) {
+ $subTitle = Title::newFromText( $pageTitle ) ;
+ return $subTitle->getFullURL( array(
+ 'action' => 'raw',
+ 'ctype' => $contentType
+ ));
+ //} elseif( $this->file->repo instanceof ForeignDBViaLBRepo ){
+ } else {
+ $query = 'title=' . wfUrlencode( $pageTitle ) . '&';
+ $query .= wfArrayToCgi( array(
+ 'action' => 'raw',
+ 'ctype' => $contentType
+ ) );
+ // Note: This will return false if scriptDirUrl is not set for repo.
+ return $this->file->repo->makeUrl( $query );
+ }
+ }
+}
diff --git a/extensions/TimedMediaHandler/handlers/WAVHandler/WAVHandler.php b/extensions/TimedMediaHandler/handlers/WAVHandler/WAVHandler.php
new file mode 100644
index 00000000..9fae12b8
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/WAVHandler/WAVHandler.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * WAV handler
+ */
+class WAVHandler extends ID3Handler {
+
+ /**
+ * @param $file File
+ * @return string
+ */
+ function getMetadataType( $file ) {
+ return 'wav';
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getWebType( $file ) {
+ return 'audio/wav';
+ }
+
+ function verifyUpload( $filename ) {
+ $metadata = $this->getID3( $filename );
+
+ if(
+ isset( $metadata['audio'] )
+ && $metadata['audio']['dataformat'] == 'wav'
+ && ( $metadata['audio']['codec'] == 'Pulse Code Modulation (PCM)' || $metadata['audio']['codec'] == 'IEEE Float' )
+ ){
+ return Status::newGood();
+ }
+
+ return Status::newFatal( 'timedmedia-wav-pcm-required' );
+ }
+ /**
+ * @param $file File
+ * @return array|bool
+ */
+ function getStreamTypes( $file ) {
+ $streamTypes = array();
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return false;
+ }
+
+ if( isset( $metadata['audio'] ) && $metadata['audio']['dataformat'] == 'wav' ){
+ $streamTypes[] = 'WAV';
+ }
+
+ return $streamTypes;
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getShortDesc( $file ) {
+ global $wgLang;
+
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return parent::getShortDesc( $file );
+ }
+ return wfMessage( 'timedmedia-wav-short-audio',
+ $wgLang->formatTimePeriod( $this->getLength( $file ) ) )->text();
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getLongDesc( $file ) {
+ global $wgLang;
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return parent::getLongDesc( $file );
+ }
+ return wfMessage('timedmedia-wav-long-audio',
+ $wgLang->formatTimePeriod( $this->getLength($file) ),
+ $wgLang->formatBitrate( $this->getBitRate( $file ) )
+ )->text();
+
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/handlers/WebMHandler/WebMHandler.php b/extensions/TimedMediaHandler/handlers/WebMHandler/WebMHandler.php
new file mode 100644
index 00000000..ebdad0d1
--- /dev/null
+++ b/extensions/TimedMediaHandler/handlers/WebMHandler/WebMHandler.php
@@ -0,0 +1,175 @@
+<?php
+/**
+ * WebM handler
+ */
+class WebMHandler extends ID3Handler {
+
+ /**
+ * @param $path string
+ * @return array
+ */
+ protected function getID3( $path ) {
+ $id3 = parent::getID3( $path );
+ // Unset some parts of id3 that are too detailed and matroska specific:
+ unset( $id3['matroska'] );
+ return $id3;
+ }
+
+ /**
+ * Get the "media size"
+ * @param $file File
+ * @param $path string
+ * @param $metadata bool
+ * @return array|bool
+ */
+ function getImageSize( $file, $path, $metadata = false ) {
+ // Just return the size of the first video stream
+ if ( $metadata === false ) {
+ $metadata = $file->getMetadata();
+ }
+ $metadata = $this->unpackMetadata( $metadata );
+ if ( isset( $metadata['error'] ) ) {
+ return false;
+ }
+
+ $size = array( false, false );
+ // display_x/display_y is only set if DisplayUnit
+ // is pixels, otherwise display_aspect_ratio is set
+ if ( isset( $metadata['video']['display_x'] )
+ &&
+ isset( $metadata['video']['display_y'] )
+ ){
+ $size = array (
+ $metadata['video']['display_x'],
+ $metadata['video']['display_y']
+ );
+ }
+ elseif ( isset( $metadata['video']['resolution_x'] )
+ &&
+ isset( $metadata['video']['resolution_y'] )
+ ){
+ $size = array (
+ $metadata['video']['resolution_x'],
+ $metadata['video']['resolution_y']
+ );
+ if ( isset($metadata['video']['crop_top']) ) {
+ $size[1] -= $metadata['video']['crop_top'];
+ }
+ if ( isset($metadata['video']['crop_bottom']) ) {
+ $size[1] -= $metadata['video']['crop_bottom'];
+ }
+ if ( isset($metadata['video']['crop_left']) ) {
+ $size[0] -= $metadata['video']['crop_left'];
+ }
+ if ( isset($metadata['video']['crop_right']) ) {
+ $size[0] -= $metadata['video']['crop_right'];
+ }
+ }
+ if ( $size[0] && $size[1] && isset( $metadata['video']['display_aspect_ratio'] ) ) {
+ //for wide images (i.e. 16:9) take native height as base
+ if ( $metadata['video']['display_aspect_ratio'] >= 1 ) {
+ $size[0] = intval( $size[1] * $metadata['video']['display_aspect_ratio'] );
+ } else { //for tall images (i.e. 9:16) take width as base
+ $size[1] = intval( $size[0] / $metadata['video']['display_aspect_ratio'] );
+ }
+ }
+ return $size;
+ }
+
+ /**
+ * @param $file
+ * @return string
+ */
+ function getMetadataType( $file ) {
+ return 'webm';
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getWebType( $file ) {
+ $baseType = ( $file->getWidth() == 0 && $file->getHeight() == 0 )? 'audio' : 'video';
+
+ $streams = $this->getStreamTypes( $file );
+ if ( !$streams ) {
+ return $baseType . '/webm';
+ }
+
+ $codecs = strtolower( implode( ', ', $streams ) );
+
+ return $baseType . '/webm; codecs="' . $codecs . '"';
+ }
+
+ /**
+ * @param $file File
+ * @return array|bool
+ */
+ function getStreamTypes( $file ) {
+ $streamTypes = array();
+ $metadata = $this->unpackMetadata( $file->getMetadata() );
+ if ( !$metadata || isset( $metadata['error'] ) ) {
+ return false;
+ }
+ // id3 gives 'V_VP8' for what we call VP8
+ if( isset( $metadata['video'] ) && $metadata['video']['dataformat'] == 'vp8' ){
+ $streamTypes[] = 'VP8';
+ } elseif( isset( $metadata['video'] ) &&
+ ( $metadata['video']['dataformat'] === 'vp9'
+ || $metadata['video']['dataformat'] === 'V_VP9'
+ ) ) {
+ // Currently getID3 calls it V_VP9. That will probably change to vp9
+ // once getID3 actually gets support for the codec.
+ $streamTypes[] = 'VP9';
+ }
+ if( isset( $metadata['audio'] ) && $metadata['audio']['dataformat'] == 'vorbis' ){
+ $streamTypes[] = 'Vorbis';
+ } elseif ( isset( $metadata['audio'] ) &&
+ ( $metadata['audio']['dataformat'] == 'opus'
+ || $metadata['audio']['dataformat'] == 'A_OPUS'
+ ) ) {
+ // Currently getID3 calls it A_OPUS. That will probably change to 'opus'
+ // once getID3 actually gets support for the codec.
+ $streamTypes[] = 'Opus';
+ }
+
+ return $streamTypes;
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getShortDesc( $file ) {
+ global $wgLang;
+
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return parent::getShortDesc( $file );
+ }
+ return wfMessage( 'timedmedia-webm-short-video', implode( '/', $streamTypes ),
+ $wgLang->formatTimePeriod( $this->getLength( $file ) ) )->text();
+ }
+
+ /**
+ * @param $file File
+ * @return String
+ */
+ function getLongDesc( $file ) {
+ global $wgLang;
+ $streamTypes = $this->getStreamTypes( $file );
+ if ( !$streamTypes ) {
+ return parent::getLongDesc( $file );
+ }
+ return wfMessage('timedmedia-webm-long-video',
+ implode( '/', $streamTypes ),
+ $wgLang->formatTimePeriod( $this->getLength($file) ),
+ $wgLang->formatBitrate( $this->getBitRate( $file ) )
+ )->numParams(
+ $file->getWidth(),
+ $file->getHeight()
+ )->text();
+
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/i18n/ady-cyrl.json b/extensions/TimedMediaHandler/i18n/ady-cyrl.json
new file mode 100644
index 00000000..a76e7faa
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ady-cyrl.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "GR44 Luc",
+ "TheRossatron"
+ ]
+ },
+ "timedmedia-no-player-js": "Къытфэгъэгъу, е уи броузерым и JavaScript гъэкIосагъэ, е гъэлъэгъуалъэ тэрэз тетэп.<br />\n<a href=\"$1\">Клипыр къипщэн</a> е <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">гъэлъэгъуалъэ тебгъэуцон</a> плъэкIыщт, уи броузерым ущеплъынэу.",
+ "timedmedia-source-file": "Лъапсэу $1",
+ "timedmedia-source-audio-file-desc": "Оригинал $1-файлыр ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/aeb-latn.json b/extensions/TimedMediaHandler/i18n/aeb-latn.json
new file mode 100644
index 00000000..65d57191
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/aeb-latn.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Csisc"
+ ]
+ },
+ "timedmedia-source-file": "$1 is-sūrs",
+ "timedmedia-source-audio-file-desc": "Ficyēy $1 aşlī ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/af.json b/extensions/TimedMediaHandler/i18n/af.json
new file mode 100644
index 00000000..7708e9ae
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/af.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Naudefj",
+ "SPQRobin",
+ "Arnobarnard"
+ ]
+ },
+ "timedmedia-desc": "Hanteer Ogg Theora- en Vorbis-lêers met 'n JavaScript-mediaspeler",
+ "timedmedia-ogg-short-audio": "Ogg $1 klanklêer, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 video lêer, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 medialêer, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 klanklêer, lengte $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 videolêer, lengte $2, $4×$5 pixels, $3",
+ "timedmedia-ogg-long-general": "Ogg medialêer, lengte $2, $3",
+ "timedmedia-ogg-long-error": "Ongeldige Ogg-lêer: $1",
+ "timedmedia-no-player-js": "Jammer, u blaaier het of JavaScript gedeaktiveer of het nie enige ondersteunde speler nie.<br />\nU kan <a href=\"$1\">die knipsel aflaai</a> of <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">'n speler aflaai</a> om die knipsel te speel in u blaaier.",
+ "timedmedia-more": "Meer…",
+ "timedmedia-dismiss": "Sluit",
+ "timedmedia-download": "Laai lêer af",
+ "timedmedia-desc-link": "Aangaande die lêer",
+ "timedmedia-minutes": "{{PLURAL:$1|$1 minuut|$1 minute}}",
+ "timedmedia-source-file": "Bron van $1",
+ "timedmedia-source-audio-file-desc": "Oorspronklike $1-lêer ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/akz.json b/extensions/TimedMediaHandler/i18n/akz.json
new file mode 100644
index 00000000..641c0b9f
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/akz.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ulohnanne"
+ ]
+ },
+ "timedmedia-more": "Maatàasasi..."
+}
diff --git a/extensions/TimedMediaHandler/i18n/aln.json b/extensions/TimedMediaHandler/i18n/aln.json
new file mode 100644
index 00000000..67645c86
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/aln.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mdupont"
+ ]
+ },
+ "timedmedia-desc": "Mbajtës për mediat në kohën e duhur (video, audio, timedText) me transcoding të ZQM Theora / Vorbis",
+ "timedmedia-ogg-short-audio": "Ogg tingull $1 fotografi, $2",
+ "timedmedia-ogg-short-video": "video file Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 media file, $2",
+ "timedmedia-ogg-long-audio": "ZQM file $1 shëndoshë, gjatë $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 video file, gjatë $2, $4 × $5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "ZQM multiplexed audio / video file, $1, gjatë $2, $4 × $5 pixels, $3 e përgjithshme",
+ "timedmedia-ogg-long-general": "Ogg media file, gjatë $2, $3",
+ "timedmedia-ogg-long-error": "E pavlefshme Ogg file: $1",
+ "timedmedia-no-player-js": "Na vjen keq, browser-i juaj ose ka JavaScript paaftë ose nuk ka asnjë lojtar të mbështetur. <br /> Ju mund të <a href=\"$1\">shkarkoni clip</a> ose <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">shkarkoni një lojtar</a> për të luajtur clip në shfletuesin tuaj.",
+ "timedmedia-more": "Më shumë ...",
+ "timedmedia-dismiss": "Afër",
+ "timedmedia-download": "Shkarko file",
+ "timedmedia-desc-link": "Për këtë fotografi",
+ "timedmedia-oggThumb-version": "OggHandler kërkon version oggThumb $1 ose më vonë.",
+ "timedmedia-oggThumb-failed": "oggThumb dështuar për të krijuar tablo."
+}
diff --git a/extensions/TimedMediaHandler/i18n/an.json b/extensions/TimedMediaHandler/i18n/an.json
new file mode 100644
index 00000000..8bee5529
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/an.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Juanpabl"
+ ]
+ },
+ "timedmedia-desc": "Maneyador de fichers sincronizatos (vidio, son y texto sincronizato) con transcodificación Ogg Theora/Vorbis",
+ "timedmedia-ogg-short-audio": "Fichero de son ogg $1, $2",
+ "timedmedia-ogg-short-video": "Fichero de vidio ogg $1, $2",
+ "timedmedia-ogg-short-general": "Fichero multimedia ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Fichero de son ogg $1, durada $2, $3",
+ "timedmedia-ogg-long-video": "Fichero de vidio ogg $1, durada $2, $4×$5 píxels, $3",
+ "timedmedia-ogg-long-multiplexed": "fichero ogg multiplexato audio/vidio, $1, durada $2, $4×$5 píxels, $3 total",
+ "timedmedia-ogg-long-general": "fichero ogg multimedia durada $2, $3",
+ "timedmedia-ogg-long-error": "Fichero ogg no conforme: $1",
+ "timedmedia-more": "Más…",
+ "timedmedia-dismiss": "Zarrar",
+ "timedmedia-download": "Escargar fichero",
+ "timedmedia-desc-link": "Información sobre este fichero"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ang.json b/extensions/TimedMediaHandler/i18n/ang.json
new file mode 100644
index 00000000..077e8718
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ang.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gott wisst"
+ ]
+ },
+ "timedmedia-source-file": "$1 fruma",
+ "timedmedia-source-audio-file-desc": "Frumlicu $1 ymele ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ar.json b/extensions/TimedMediaHandler/i18n/ar.json
new file mode 100644
index 00000000..bcb7c11c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ar.json
@@ -0,0 +1,67 @@
+{
+ "@metadata": {
+ "authors": [
+ "Alnokta",
+ "Asaifm",
+ "Meno25",
+ "OsamaK",
+ "روخو",
+ "Abanima"
+ ]
+ },
+ "timedmedia-desc": "مداول للصوتيات والمرئيات والنصوص المؤقتة والذي لديه القدرة على دعم ملفات بصيغة WebM وOgg Theora وVorbis وsrt",
+ "timedmedia-ogg-short-audio": "Ogg $1 ملف صوت، $2",
+ "timedmedia-ogg-short-video": "Ogg $1 ملف فيديو، $2",
+ "timedmedia-ogg-short-general": "Ogg $1 ملف ميديا، $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 ملف صوت، الطول $2، $3",
+ "timedmedia-ogg-long-video": "Ogg $1 ملف فيديو، الطول $2، $4×$5 بكسل، $3",
+ "timedmedia-ogg-long-multiplexed": "ملف Ogg مالتي بليكسد أوديو/فيديو، $1، الطول $2، $4×$5 بكسل، $3 إجمالي",
+ "timedmedia-ogg-long-general": "ملف ميديا Ogg، الطول $2، $3",
+ "timedmedia-ogg-long-error": "ملف Ogg غير صحيح: $1",
+ "timedmedia-webm-short-video": "نسق WebM، $1 ملف فيديو $2",
+ "timedmedia-webm-long-video": "ملف صوت/فيديو بنسق WebM , $1, الطول $2, $4×$5 بكسل، $3 إجمالا",
+ "timedmedia-no-player-js": "عذرا، متصفحك إما انه لا يدعم الجافا سكريبت أو انها معطلة.<br />\nتستطيع <a href=\"$1\">تحميل المقطع</a> أو <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">تحميل مشغل</a> يستطيع تشغيل المقطع على متصفحك.",
+ "timedmedia-more": "المزيد...",
+ "timedmedia-dismiss": "أغلق",
+ "timedmedia-download": "نزل الملف",
+ "timedmedia-play-media": "تشغيل الوسائط",
+ "timedmedia-desc-link": "عن هذا الملف",
+ "timedmedia-status": "الحالة",
+ "timedmedia-status-unknown": "حالة غير معروفة",
+ "timedmedia-actions": "الإجراءات",
+ "timedmedia-direct-link": "تحميل المشتق",
+ "timedmedia-not-ready": "غير جاهز",
+ "timedmedia-percent-done": "وصل لنسبة $1% انتهى",
+ "timedmedia-in-job-queue": "تمت الإضافة إلى طابور المهام منذ $1",
+ "timedmedia-days": "{{PLURAL:$1|يوم واحد|يومين|$1 أيام|$1 يوماً|$1 يوم}}",
+ "timedmedia-hours": "{{PLURAL:$1|ساعة واحدة|ساعتين|$1 ساعات|$1 ساعة}}",
+ "timedmedia-minutes": "{{PLURAL:$1|دقيقة واحدة|دقيقتين|$1 دقائق|$1 دقيقة}}",
+ "timedmedia-seconds": "{{PLURAL:$1|ثانية واحدة|ثانيتين|$1 ثوان|$1 ثانية}}",
+ "timedmedia-ogg": "أو جي جي",
+ "timedmedia-source-file": "$1 مصدر",
+ "timedmedia-source-file-desc": "الأصل ملف $1، $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "الملف $1 الأصلي ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "انخفاض عرض النطاق الترددي أوج فيديو (160P)",
+ "timedmedia-derivative-desc-720p.ogv": "تحميل أوج فيديو بجودة عالية (720P)",
+ "timedmedia-subtitle-new": "أنشئ ترجمة جديدة أو حرر ترجمة موجودة",
+ "timedmedia-subtitle-new-desc": "قم بإختيار اللغة وإضغط على زر '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "اذهب",
+ "timedmedia-subtitle-language": "$1 ($2) ترجمات",
+ "timedmedia-subtitle-no-video": "لا يوجد فيديو مقترن بصفحة ترجمة أو نصوص الفيديو الحالية.",
+ "timedmedia-subtitle-no-subtitles": "لا توجد نصوص أو ترجمات في $1 لهذا الفيديو، يمكنك [{{fullurl:{{FULLPAGENAME}}|action=edit}} تعديل هذه الصفحة] وإضافتهم.",
+ "timedmedia-subtitle-remote-link": "يمكنك [$1 مطالعة صفحة الوصف] لهذا الملف على $2",
+ "timedmediahandler": "معالج الميديا الزمنية",
+ "timedmedia-videos": "{{PLURAL:$1|ملف فيديو واحد|ملفا فيديو|$1 ملفات فيديو|$1 ملف فيديو}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|ملف|ملفا|$1 ملفات|$1 ملف}} فيديو Ogg",
+ "timedmedia-webm-videos": "{{PLURAL:$1|ملف|ملفا|$1 ملفات|$1 ملف}} فيديو WebM",
+ "timedmedia-file": "ملف",
+ "timedmedia-audios": "{{PLURAL:$1|ملف صوتي واحد|$1 ملف صوتي}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|ملف صوتي واحد بصيغة أوغ|$1 ملف صوتي بصيغة أوغ}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|ملف|ملفا|$1 ملفات|$1 ملف}} صوتي FLAC",
+ "timedmedia-wav-audios": "{{PLURAL:$1|ملف|ملفا|$1 ملفات|$1 ملف}} صوتي WAV",
+ "orphanedtimedtext": "صفحات TimedText يتيمة",
+ "orphanedtimedtext-summary": "قائمة بصفحات [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] التي ليس لديها ملف موافق.",
+ "orphanedtimedtext-unsupported": "هذه الصفحة الخاصة لا تدعمها إلا قواعد بيانات MySQL",
+ "orphanedtimedtext-notimedtext": "TimedText غير مفعل على هذا الويكي",
+ "apihelp-transcodereset-param-title": "عنوان ملف الميديا."
+}
diff --git a/extensions/TimedMediaHandler/i18n/arc.json b/extensions/TimedMediaHandler/i18n/arc.json
new file mode 100644
index 00000000..7f2df877
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/arc.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Basharh"
+ ]
+ },
+ "timedmedia-more": "ܝܬܝܪ…"
+}
diff --git a/extensions/TimedMediaHandler/i18n/arq.json b/extensions/TimedMediaHandler/i18n/arq.json
new file mode 100644
index 00000000..a4b24de3
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/arq.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Oldstoneage"
+ ]
+ },
+ "timedmedia-no-player-js": "اعدُرنا، الفلّاك فيه JavaScript محبّس ولا ما فيه حتا قرّاي موالم.<br />\nتنجم <a href=\"$1\">تتيليشارجي الفيديو</a> ولا <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">نزّل عندك قرّاي يكون موالم</a> باش تفوّت الفيديو فل فلّاك تاعك.",
+ "timedmedia-source-file": "$1 مصدر",
+ "timedmedia-source-audio-file-desc": "فيشي $1 أصلي ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/arz.json b/extensions/TimedMediaHandler/i18n/arz.json
new file mode 100644
index 00000000..db3b7f88
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/arz.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ghaly",
+ "Meno25",
+ "Ramsis II"
+ ]
+ },
+ "timedmedia-desc": "متحكم لملفات أو جى جى ثيورا و فوربيس، مع بلاير جافاسكريبت",
+ "timedmedia-ogg-short-audio": "Ogg $1 ملف صوت، $2",
+ "timedmedia-ogg-short-video": "Ogg $1 ملف فيديو, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 ملف ميديا، $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 ملف صوت، الطول $2، $3",
+ "timedmedia-ogg-long-video": "Ogg $1 ملف فيديو، الطول $2، $4×$5 بكسل، $3",
+ "timedmedia-ogg-long-multiplexed": "ملف Ogg مالتى بليكسد أوديو/فيديو، $1، الطول $2، $4×$5 بكسل، $3 إجمالي",
+ "timedmedia-ogg-long-general": "ملف ميديا Ogg، الطول $2، $3",
+ "timedmedia-ogg-long-error": "ملف ogg مش صحيح: $1",
+ "timedmedia-more": "أكتر...",
+ "timedmedia-dismiss": "اقفل",
+ "timedmedia-download": "نزل الملف",
+ "timedmedia-desc-link": "عن الملف دا",
+ "timedmedia-source-file": "$1 مصدر",
+ "timedmedia-source-audio-file-desc": "الملف $1 الأصل ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/as.json b/extensions/TimedMediaHandler/i18n/as.json
new file mode 100644
index 00000000..519fccc6
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/as.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "IKHazarika"
+ ]
+ },
+ "timedmedia-no-player-js": "দুঃখিত, আপুনাৰ ব্ৰাইজাৰত নাইবা জাভা-স্ক্ৰিপ্ট নিষ্ক্ৰিয় কৰা হৈ আছে অথবা কোনো সমৰ্থিত প্লেয়াৰ নাই। </br>\nআপুনাৰ ব্ৰাউজাৰত ক্লিপটো প্লে' কৰিবলৈ <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">প্লে'য়াৰ এটা ডাউনল'ড কৰক</a> অথবা <a href=\"$1\">ক্লিপটো ডাউনল'ড কৰক</a> ।",
+ "timedmedia-source-file": "$1 উৎস",
+ "timedmedia-source-audio-file-desc": "প্ৰকৃত $1 ফাইল ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ast.json b/extensions/TimedMediaHandler/i18n/ast.json
new file mode 100644
index 00000000..2ff3d0af
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ast.json
@@ -0,0 +1,122 @@
+{
+ "@metadata": {
+ "authors": [
+ "Esbardu",
+ "Xuacu"
+ ]
+ },
+ "timedmedia-desc": "Remanador de soníu, videu y testu cronometráu, con sofitu pa los formatos WebM, Ogg Theora, Vorbis y srt",
+ "timedmedia-ogg-short-audio": "Archivu de soníu ogg $1, $2",
+ "timedmedia-ogg-short-video": "Archivu de videu ogg $1, $2",
+ "timedmedia-ogg-short-general": "Archivu multimedia ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Archivu de soníu ogg $1, llonxitú $2, $3",
+ "timedmedia-ogg-long-video": "Archivu de videu ogg $1, llonxitú $2, $4×$5 píxeles, $3",
+ "timedmedia-ogg-long-multiplexed": "Ficheru de soníu/videu ogg multiplexáu, $1, llonxitú $2, $4×$5 píxeles, $3",
+ "timedmedia-ogg-long-general": "Archivu multimedia ogg, llonxitú $2, $3",
+ "timedmedia-ogg-long-error": "Ficheru Ogg inválidu: $1",
+ "timedmedia-ogg-long-no-streams": "Ficheru multimedia Ogg. Atención: Nun se reconoció nengún codec de los usaos nesti ficheru.",
+ "timedmedia-webm-short-video": "Ficheru de videu WebM $1, $2",
+ "timedmedia-webm-long-video": "Ficheru de soníu/videu WebM, $1, llonxitú $2, $4 × $5 pixels, $3 total",
+ "timedmedia-flac-short-audio": "Ficheru de soníu FLAC, $1",
+ "timedmedia-flac-long-audio": "Ficheru de soníu FLAC, duración $1, $2 total",
+ "timedmedia-wav-short-audio": "Ficheru de soníu WAV, $1",
+ "timedmedia-wav-long-audio": "Ficheru de soníu WAV, duración $1, $2 total",
+ "timedmedia-wav-pcm-required": "Namái pue xubir WAV tipu PCM (Pulse Code Modulation).",
+ "timedmedia-mp4-short-video": "Archivu de videu MP4 $1, $2",
+ "timedmedia-mp4-long-video": "Ficheru de soníu/videu MP4, $1, llonxitú $2, $4 × $5 pixels, $3 total",
+ "timedmedia-no-player-js": "Sentimoslo, o'l to navegador tien desactiváu JavaScript o nun tienes un reproductor compatible.<br />\nPues <a href=\"$1\">descargar el clip</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">descargar un reproductor</a> pa reproducir el clip nel to navegador.",
+ "timedmedia-more": "Más...",
+ "timedmedia-dismiss": "Zarrar",
+ "timedmedia-download": "Descargar archivu",
+ "timedmedia-play-media": "Reproducir el mediu",
+ "timedmedia-desc-link": "Tocante a esti archivu",
+ "timedmedia-oggThumb-version": "OggHandler requier oggThumb version $1 o mayor.",
+ "timedmedia-oggThumb-failed": "oggThumb nun pudo crear la miniatura.",
+ "timedmedia-status-header": "Estáu de trescodificación",
+ "timedmedia-update-status": "Anovar l'estáu de trescodificación",
+ "timedmedia-status": "Estáu",
+ "timedmedia-status-unknown": "Estáu desconocíu",
+ "timedmedia-transcodebitrate": "Tasa de bits",
+ "timedmedia-transcodeduration": "Tiempu de codificación",
+ "timedmedia-transcodeinfo": "Formatu",
+ "timedmedia-actions": "Aiciones",
+ "timedmedia-direct-link": "Descargar",
+ "timedmedia-not-ready": "Nun ta preparáu",
+ "timedmedia-completed-on": "Completada a les $1",
+ "timedmedia-error-on": "Error a les $1",
+ "timedmedia-started-transcode": "Principió hai $1. $2",
+ "timedmedia-percent-done": "Fecho alredor del $1%",
+ "timedmedia-in-job-queue": "Amestáu a la cola de trabayos hai $1",
+ "timedmedia-unknown-target-size": "Tamañu del destín desconocíu; $1 codificáu",
+ "timedmedia-days": "{{PLURAL:$1|1 día|$1 díes}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 hora|$1 hores}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minutu|$1 minutos}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 segundu|$1 segundos}}",
+ "timedmedia-reset": "Reaniciar la trescodificación",
+ "timedmedia-reset-confirm": "Al reaniciar esta trescodificación desaniciará tolos ficheros esistentes (si los hai), y volverá a amestar la trescodificación a la cola de trabayos. Llevará un tiempu volver a trescodificar.<br /><br />\n¿Ta seguru de que quier siguir?",
+ "timedmedia-reset-error": "Error al reaniciar el trabayu de trescodificación.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Fonte $1",
+ "timedmedia-source-file-desc": "Ficheru $1 orixinal, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Ficheru $1 orixinal ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Videu Ogg d'anchu de banda baxu (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "Videu Ogg tresmitible pela web (240P)",
+ "timedmedia-derivative-desc-360p.ogv": "Videu Ogg tresmitible pela web (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Videu Ogg tresmitible pela web (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Videu Ogg descargable d'alta calida (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Videu Ogg descargable'n Full HD (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Videu WebM tresmitible pela web (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Videu WebM tresmitible pela web (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Videu WebM tresmitible pela web (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Videu WebM descargable d'alta calida (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "WebM descargable'n Full HD (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "WebM descargable'n Full 4K (2160P)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "WebM VP9 tresmitible pela web (360P)",
+ "timedmedia-derivative-desc-480p.vp9.webm": "WebM VP9 tresmitible pela web (480P)",
+ "timedmedia-derivative-desc-720p.vp9.webm": "WebM VP9 tresmitible'n HD (720P)",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "WebM VP9 tresmitible'n Full HD (1080P)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "WebM VP9 tresmitible'n Full 4K (2160P)",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 compatible colos preseos (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 tresmitible pela web (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 de calidá HD (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4 de calidá Full HD (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "MP4 de calidá Full 4K (2160P)",
+ "timedmedia-subtitle-new": "Crear una traducción nueva o editar la esistente",
+ "timedmedia-subtitle-new-desc": "Seleicione la llingua y calque nel botón '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Dir",
+ "timedmedia-subtitle-language": "Subtítulos en $1 ($2)",
+ "timedmedia-subtitle-no-video": "Nun hai nengún videu asociáu cola páxina de subtítulos actual",
+ "timedmedia-subtitle-no-subtitles": "Anguaño nun hai subtítulos en $1 pa esti videu, pue [{{fullurl:{{FULLPAGENAME}}|action=edit}} editar esta páxina] p'amestalos",
+ "timedmedia-subtitle-remote": "El testu cronometráu d'esti ficheru ta agospiáu en $1",
+ "timedmedia-subtitle-remote-link": "Pue [$1 ver la páxina de descripción] d'esti ficheru en $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 videu|$1 videos}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 videu|$1 videos}} Ogg",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 videu|$1 videos}} WebM",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 trescodificación|$1 trescodificaciones}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 trescodificación activa|$1 trescodificaciones actives}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 trescodificación|$1 trescodificaciones}} na cola",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 trescodificación fallida|$1 trescodificaciones fallíes}}",
+ "timedmedia-file": "Ficheru",
+ "timedmedia-audios": "{{PLURAL:$1|$1 ficheru de soníu|$1 ficheros de soníu}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 ficheru de soníu Ogg|$1 ficheros de soníu Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 ficheru de soníu FLAC|$1 ficheros de soníu FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 ficheru de soníu WAV|$1 ficheros de soníu WAV}}",
+ "right-transcode-reset": "Reaniciar los videos fallíos o trescodificaos pa que vuelvan a ponese na cola de trabayos.",
+ "right-transcode-status": "Ver [[Special:TimedMediaHandler|información sobre l'actividá de trescodificación actual]]",
+ "action-transcode-status": "ver l'estáu actual de la trescodificación",
+ "orphanedtimedtext": "Páxines güérfanes de TimedText",
+ "orphanedtimedtext-summary": "Llista de páxines de [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] que nun tienen el correspondiente ficheru.",
+ "orphanedtimedtext-unsupported": "Esta páxina especial sólo tien sofitu con bases de datos MySQL.",
+ "orphanedtimedtext-notimedtext": "TimedText nun ta activáu nesta wiki.",
+ "apihelp-query+transcodestatus-description": "Recibir l'estáu de transcode pa una páxina de ficheru determinada.",
+ "apihelp-query+transcodestatus-example-1": "Recibir l'estáu de transcode pa [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "Estende imageinfo pa incluir la información de fonte de videu (derivaos)",
+ "apihelp-query+videoinfo-param-prop": "Que información de videu algamar:\n;timestamp:Amiesta la marca d'hora de la versión xubida.\n;user:Amiesta l'usuariu que xubió la versión del videu.\n;userid:Amiesta la ID del usuariu que xubió la versión del videu.\n;comment:Comentariu de la versión.\n;parsedcomment:Comentariu analizáu na versión.\n;canonicaltitle:Amiesta'l títulu canónicu del ficheru de videu.\n;url:Da la URL del videu y la páxina de descripción.\n;size:Amiesta'l tamañu del videu en bytes, l'altor y anchor. Si ye aplicable, amiéstase la cuenta de páxines y duración.\n;dimensions:Alcuñu pa \"size\".\n;sha1:Amiesta'l hash SHA-1 del videu.\n;mime:Amiesta'l tipu MIME del videu.\n;thumbmime:Amiesta'l tipu MIME de la miniatura del videu (rique url y parámetru $1urlwidth).\n;mediatype:Amiesta'l tipu de mediu del videu.\n;metadata:Llista de metadatos Exif de la versión del videu.\n;commonmetadata:Llista de metadatos xenéricos del formatu de ficheru de la versión del videu.\n;extmetadata:Llista de metadatos con formatu combinaos dende fontes diverses. Los resultaos tán en formatu HTML.\n;archivename:Amiesta'l nome de la versión d'archivu pa versiones distintes de la última.\n;bitdepth:Amiesta la fondura de bit de la versión.\n;uploadwarning:Usáu pola páxina [[Special:Upload]] p'algamar información d'un ficheru esistente. Nun ta previstu pa usase fuera del nucleu de MediaWiki.\n;derivatives:Amiesta una tabla colos diferentes formatos y calidaes disponibles d'un ficheru de soníu o videu.",
+ "apihelp-query+videoinfo-example-1": "Buscar información tocante a [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "Los usuarios col permisu 'transcode-reset' pueden reaniciar y volver a executar un trabayu transcode.",
+ "apihelp-transcodereset-param-title": "Títulu del ficheru de multimedia.",
+ "apihelp-transcodereset-param-transcodekey": "La clave del transcode que quies reaniciar. Cuéyela de [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Reaniciar tolos transcodes de [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "Reaniciar la clave transcode '360_560kbs.webm' de [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/av.json b/extensions/TimedMediaHandler/i18n/av.json
new file mode 100644
index 00000000..2a3131e3
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/av.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gazimagomedov"
+ ]
+ },
+ "timedmedia-source-file": "$1 ицц",
+ "timedmedia-source-audio-file-desc": "Аслияб $1-файл ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/avk.json b/extensions/TimedMediaHandler/i18n/avk.json
new file mode 100644
index 00000000..313cd0c9
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/avk.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sab"
+ ]
+ },
+ "timedmedia-download": "Iyeltakkalvajara",
+ "timedmedia-desc-link": "Icde bat iyeltak"
+}
diff --git a/extensions/TimedMediaHandler/i18n/awa.json b/extensions/TimedMediaHandler/i18n/awa.json
new file mode 100644
index 00000000..fe0c3d1a
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/awa.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "1AnuraagPandey"
+ ]
+ },
+ "timedmedia-no-player-js": "क्षमा करें, आपके ब्राउज़र में या तो जावास्क्रिप्ट अक्षम है या समर्थित प्लेयर नहीं है।<br />\nआप <a href=\"$1\">क्लिप को डाउनलोड</a> कर सकते हैं अथवा क्लिप को अपने ब्राउज़र में चलाने के लिए <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">एक प्लेयर डाउनलोड</a> कर सकते हैं।",
+ "timedmedia-source-file": "$1 स्रोत",
+ "timedmedia-source-audio-file-desc": "मूल $1 फ़ाइल ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/az.json b/extensions/TimedMediaHandler/i18n/az.json
new file mode 100644
index 00000000..f54d2aed
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/az.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cekli829",
+ "Dağlı95",
+ "Wertuose"
+ ]
+ },
+ "timedmedia-no-player-js": "Bağışlayın, sizin veb brauzeriniz JavaScript texnologiyasını dəstəkləmir və ya bu əlavə deaktiv edilib.\nSiz dinləmək istədiyiniz faylı <a href=\"$1\">yükləyə</a> və ya brauzerinizə, <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">lazımlı əlavəni</a> quraşdıra bilərsiz.",
+ "timedmedia-status": "Status",
+ "timedmedia-source-file": "$1 mənbəyi",
+ "timedmedia-source-audio-file-desc": "Orijinal $1-fayl ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/azb.json b/extensions/TimedMediaHandler/i18n/azb.json
new file mode 100644
index 00000000..d0c5b700
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/azb.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amir a57",
+ "Koroğlu"
+ ]
+ },
+ "timedmedia-no-player-js": "اوزگونلوک‌له، سیزین داراییجی‌نیزین جاوا ایسکریپت یازیلیمی چالیشماییر، یا دا سیزین دارییجی‌نیز بو یازیلیم‌دان آرداغلامیر.<br />\nسیز <a href=\"$1\">بو ویدیونو ایندیریب</a> یا دا <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">بیر اوینادیجی</a> ایندیره‌بیلرسینیز.",
+ "timedmedia-source-file": "$1 کوک",
+ "timedmedia-source-audio-file-desc": "اصلی $1 فایل ( $2 )"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ba.json b/extensions/TimedMediaHandler/i18n/ba.json
new file mode 100644
index 00000000..10f406c5
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ba.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Haqmar",
+ "Рустам Нурыев"
+ ]
+ },
+ "timedmedia-days": "{{PLURAL:$1|1=$1 көн|$1 көн}}",
+ "timedmedia-hours": "{{PLURAL:$1|1=$1 сәғәт|$1 сәғәт}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1=$1 минут|$1 минут}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1=$1 секунд|$1 секунд}}",
+ "timedmedia-source-file": "$1 сығанаҡ",
+ "timedmedia-source-audio-file-desc": "Оригинал $1-файл ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/bcc.json b/extensions/TimedMediaHandler/i18n/bcc.json
new file mode 100644
index 00000000..11fbd1a8
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/bcc.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mostafadaneshvar",
+ "Baloch Afghanistan"
+ ]
+ },
+ "timedmedia-desc": "دسگیره په فایلان Ogg Theora و Vorbis, گون پخش کنوک جاوا اسکرسیپت",
+ "timedmedia-ogg-short-audio": "فایل صوتی Ogg $1، $2",
+ "timedmedia-ogg-short-video": "فایل تصویری Ogg $1، $2",
+ "timedmedia-ogg-short-general": "فایل مدیا Ogg $1، $2",
+ "timedmedia-ogg-long-audio": "اوجی جی $1 فایل صوتی, طول $2, $3",
+ "timedmedia-ogg-long-video": "اوجی جی $1 فایل ویدیو, طول $2, $4×$5 پیکسل, $3",
+ "timedmedia-ogg-long-multiplexed": "اوجی جی چند دابی فایل صوت/تصویر, $1, طول $2, $4×$5 پیکسل, $3 کل",
+ "timedmedia-ogg-long-general": "اوجی جی فایل مدیا, طول $2, $3",
+ "timedmedia-ogg-long-error": "نامعتبرین فایل اوجی جی: $1",
+ "timedmedia-more": "گیشتیر...",
+ "timedmedia-dismiss": "بستین",
+ "timedmedia-download": "ئیر کورتین پایلی",
+ "timedmedia-desc-link": "ای فایل باره",
+ "timedmedia-subtitle-new-go": "برا",
+ "orphanedtimedtext": "یتیم TimedText دیمان",
+ "orphanedtimedtext-summary": "ها دیمانی لیست که [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] متناظرین پایل ندارنت ."
+}
diff --git a/extensions/TimedMediaHandler/i18n/bcl.json b/extensions/TimedMediaHandler/i18n/bcl.json
new file mode 100644
index 00000000..36042848
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/bcl.json
@@ -0,0 +1,90 @@
+{
+ "@metadata": {
+ "authors": [
+ "Filipinayzd",
+ "Geopoet"
+ ]
+ },
+ "timedmedia-desc": "Parakapot para sa audio, bidyo asin pinag-orasan na teksto, na igwa nin pormat kan suporta para sa WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 sagunson nin tanog, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 sagunson nin bidyo, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 sagunson nin midya, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 sagunson nin tanog, an laba $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 sagunson nin bidyo, an laba $2, $4 x $5 piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg pinaghalong sagunson nin audio/bidyo, $1, an laba $2, $4 x $5 piksel, $3",
+ "timedmedia-ogg-long-general": "Ogg sagunson nin midya, an laba $2, $3",
+ "timedmedia-ogg-long-error": "Imbalidong sagunson nin Ogg: $1",
+ "timedmedia-webm-short-video": "Webm $1 sagunson nin bidyo, $2",
+ "timedmedia-webm-long-video": "WebM sagunson nin audio/bidyo, $1, an laba $2, $4 x $5 piksel, $3 sa bilog na kagabsan",
+ "timedmedia-flac-short-audio": "FLAC sagunson nin audio, $1",
+ "timedmedia-flac-long-audio": "FLAC sagunson nin audio, an laba $1, $2 sa bilog na kagabsan",
+ "timedmedia-wav-short-audio": "WAV sagunson nin audio, $1",
+ "timedmedia-wav-long-audio": "WAV sagunson nin audio, an laba $1, $2 sa bilog na kagabsan",
+ "timedmedia-wav-pcm-required": "Ika makakarga sana nin PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "MP$ $1 sagunson nin bidyo, $2",
+ "timedmedia-mp4-long-video": "MP4 sagunson nin audio/bidyo, $1, an laba $2, $4 x $5 piksel, $3 sa bilog na kagabsan",
+ "timedmedia-no-player-js": "Sori po, an saimong pangilyaw baya pinagpundo an JavaScript o mayo gayod nin arinmang pinagsuportaran na parapaandar. <br /> Ika <a href=\"$1\">makakapagkarga nin klip</a> o baya <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">magkarga nin sarong parapaandar</a> tanganing paandaron an klip kan saimong kilyawan.",
+ "timedmedia-more": "Dakolon pa..",
+ "timedmedia-dismiss": "Isara",
+ "timedmedia-download": "Ikarga an sagunson",
+ "timedmedia-play-media": "Paandaron an midya",
+ "timedmedia-desc-link": "Mapanungod kaining sagunson",
+ "timedmedia-oggThumb-version": "OggHandler minahagad sa oggThumb bersyon na $1 o kahurihi.",
+ "timedmedia-oggThumb-failed": "oggThumb nagpalya sa pagmukna kan sadit na ladawan",
+ "timedmedia-status-header": "Kamugtakan kan panggantaw na kodigo",
+ "timedmedia-update-status": "Sumpayan an kamugtakan kan panggantaw na kodigo",
+ "timedmedia-status": "Kamugtakan",
+ "timedmedia-status-unknown": "Bakong aram na kamugtakan",
+ "timedmedia-transcodeinfo": "Deribatibong deskripsyon kan panggantaw na kodigo",
+ "timedmedia-actions": "Mga aksyon",
+ "timedmedia-direct-link": "Ikarga an deribatibo",
+ "timedmedia-not-ready": "Dae pa handa",
+ "timedmedia-completed-on": "Pinagkumpletong panggantaw na kodigo $1",
+ "timedmedia-error-on": "Kasalaan sa panggantaw na kodigo sa $1",
+ "timedmedia-started-transcode": "An panggantaw na kodigo pinagpoonan mga $1 an nakaagi. $2",
+ "timedmedia-percent-done": "Haros $1% an tapos na",
+ "timedmedia-in-job-queue": "Pinagdugang sa haralatan nin Trabaho mga $1 an nakaagi",
+ "timedmedia-unknown-target-size": "Dae aram an sukol kan target, $1 pinagkodigo na",
+ "timedmedia-days": "{{PLURAL:$1|1 aldaw|$1 mga aldaw}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 oras|$1 mga oras}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuto|$1 minutos}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 segundo|$1 segundos}}",
+ "timedmedia-reset": "Pakibaguha an panggantaw na kodigo",
+ "timedmedia-reset-confirm": "Sa pagbabago kaining panggantaw na kodigo magtatangkas nin arinman na eksistidong sagunson (kun yaon), asin magdudugang otro kan panggantaw na kodigo sa haralatan nin trabaho. Ini minakaipo nin nagkapirang oras tangani na otrong ipaggantaw an kodigo. <br /><br /> Segurado ka na muya mong magpadagos?",
+ "timedmedia-reset-error": "Kasalaan sa pagbabago kan trabaho nin panggantaw na kodigo.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 pinagkuanan",
+ "timedmedia-source-file-desc": "Orihinal $1 na sagunson, $2 x $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Orihinal $1 na sagunson ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Hababaong kalawigan Ogg bidyo (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Maantabayanan sa Web na bidyo kan Ogg (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Maantabayanan sa Web na bidyo kan Ogg (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Halangkaw na kalidad na maikakargang bidyo kan Ogg (720P)",
+ "timedmedia-derivative-desc-160p.webm": "Maantabayanan sa Web na bidyo kan WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Maantabayanan sa Web na bidyo kan WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Maantabayanan sa Web na bidyo kan WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Halangkaw na kalidad na maikakargang bidyo kan WebM (720P)",
+ "timedmedia-derivative-desc-320p.mp4": "Masayon sa aparato MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Maantabayanan sa Web na MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD na kalidad MP4 (720P)",
+ "timedmedia-subtitle-new": "Magmukna nin baguhong dakit-taramon o liwaton an eksistido na",
+ "timedmedia-subtitle-new-desc": "Magpili nin lengguwahe asin pinduton an '''{{int:Timedmedia-subtitle-new-go}}''' na dutdutan",
+ "timedmedia-subtitle-new-go": "Magduman",
+ "timedmedia-subtitle-language": "$1 ($2) mga sub-titulo",
+ "timedmedia-subtitle-no-video": "Mayo tabing bidyo na asosyado na igwa nin sa ngunyan na subtitulo kan pahina",
+ "timedmedia-subtitle-no-subtitles": "Mayo tabi nin sa ngunyan na mga subtitulo sa $1 para kaining bidyo, ika tabi [{{fullurl:{{FULLPAGENAME}}|action=edit}} makapagliwat kaining pahina] tanganing maidugang sinda",
+ "timedmedia-subtitle-remote": "Pinag-orasang teksto para kaining sagunson iyo an pinagbunsod sa $1",
+ "timedmedia-subtitle-remote-link": "Ika tabi [$1 makakatanaw sa pahina kan deskripsyon] para kaining sagunson sa $2",
+ "timedmediahandler": "Pinag-orasan na Parakapot kan Midya",
+ "timedmedia-videos": "{{PLURAL:$1|$1 bidyo|$1 mga bidyo}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg bidyo|$1 Ogg mga bidyo}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM bidyo|$1 WebM mga bidyo}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 panggantaw na kodigo|$1 panggantaw na mga kodigo}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 nagdadalagan na panggantaw na kodigo|$1 nagdadalagan na panggantaw na mga kodigo}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 pinaghahalat na panggantaw na kodigo|$1 pinaghahalat na panggantaw na mga kodigo}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 nagpalyang panggantaw na kodigo|$1 nagpalyang panggantaw na mga kodigo}}",
+ "timedmedia-file": "Sagunson",
+ "right-transcode-reset": "An pagbágo nagpalya o an pinaggantaw na kodigong mga bidyo kaya sinda pinagsingit giraray sa haralatan kan trabaho.",
+ "right-transcode-status": "Patanaw [[Special:TimedMediaHandler|impormasyon mapanungod sa ngunyan na aktibidad kan panggantaw na kodigo]]",
+ "action-transcode-status": "tanawon an sa ngunyan na kamugtakan kan panggangtaw na kodigo"
+}
diff --git a/extensions/TimedMediaHandler/i18n/be-tarask.json b/extensions/TimedMediaHandler/i18n/be-tarask.json
new file mode 100644
index 00000000..1bd50c1d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/be-tarask.json
@@ -0,0 +1,71 @@
+{
+ "@metadata": {
+ "authors": [
+ "EugeneZelenko",
+ "Jim-by",
+ "Red Winged Duck",
+ "Wizardist"
+ ]
+ },
+ "timedmedia-desc": "Апрацоўшчык аўдыё, відэа і субтытраў у фарматах WebM, Ogg Theora, Vorbis і SRT",
+ "timedmedia-ogg-short-audio": "Аўдыё-файл Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Відэа-файл у фармаце Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Мэдыяфайл Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "аўдыё-файл Ogg $1, даўжыня $2, $3",
+ "timedmedia-ogg-long-video": "відэа-файл Ogg $1, даўжыня $2, $4×$5 піксэляў, $3",
+ "timedmedia-ogg-long-multiplexed": "мультыплексны аўдыё/відэа-файл Ogg, $1, даўжыня $2, $4×$5 піксэляў, усяго $3",
+ "timedmedia-ogg-long-general": "мэдыяфайл Ogg, даўжыня $2, $3",
+ "timedmedia-ogg-long-error": "Няслушны файл у фармаце Ogg: $1",
+ "timedmedia-webm-short-video": "WebM $1 відэафайл, $2",
+ "timedmedia-webm-long-video": "Аўдыё/відэа-файл WebM, $1, працягласьць $2, $4×$5 піксэлаў, усяго $3",
+ "timedmedia-flac-short-audio": "Аўдыёфайл FLAC, $1",
+ "timedmedia-flac-long-audio": "Аўдыёфайл FLAC, працягласьць $1, усяго $2",
+ "timedmedia-mp4-short-video": "MP4 $1 відэафайл, $2",
+ "timedmedia-no-player-js": "Прабачце, але ў Вашым браўзэры адключаны JavaScript альбо няма неабходнага прайгравальніка.<br />\nВы можаце <a href=\"$1\">загрузіць кліп</a> ці <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">загрузіць прайгравальнік</a> для прайграваньня кліпу ў Вашым браўзэры.",
+ "timedmedia-more": "Болей…",
+ "timedmedia-dismiss": "Назад",
+ "timedmedia-download": "Загрузіць файл",
+ "timedmedia-play-media": "Прайграць",
+ "timedmedia-desc-link": "Інфармацыя пра гэты файл",
+ "timedmedia-oggThumb-version": "OggHandler патрабуе oggThumb вэрсіі $1 ці больш позьняй.",
+ "timedmedia-oggThumb-failed": "oggThumb не атрымалася стварыць мініятуру.",
+ "timedmedia-status-header": "Статус транскадаваньня",
+ "timedmedia-update-status": "Абнавіць статус транскадаваньня",
+ "timedmedia-status": "Статус",
+ "timedmedia-status-unknown": "Статус невядомы",
+ "timedmedia-transcodeinfo": "Фармат",
+ "timedmedia-actions": "Дзеяньні",
+ "timedmedia-direct-link": "Спампаваць",
+ "timedmedia-not-ready": "Не гатовы",
+ "timedmedia-completed-on": "Завершана $1",
+ "timedmedia-error-on": "Памылка ў $1",
+ "timedmedia-started-transcode": "Пачалося $1 таму. $2",
+ "timedmedia-percent-done": "Гатова каля $1%",
+ "timedmedia-in-job-queue": "Дададзена ў чаргу заданьняў $1 таму",
+ "timedmedia-unknown-target-size": "Выніковы памер невядомы, $1 закадавана",
+ "timedmedia-days": "$1 {{PLURAL:$1|дзень|дні|дзён}}",
+ "timedmedia-hours": "$1 {{PLURAL:$1|гадзіну|гадзіны|гадзінаў}}",
+ "timedmedia-minutes": "$1 {{PLURAL:$1|хвіліну|хвіліны|хвілінаў}}",
+ "timedmedia-seconds": "$1 {{PLURAL:$1|сэкунду|сэкунды|сэкундаў}}",
+ "timedmedia-reset": "Перазапусьціць транскадаваньне",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Крыніца $1",
+ "timedmedia-source-file-desc": "Арыгінал у $1, $2×$3 ($4)",
+ "timedmedia-source-audio-file-desc": "Арыгінал у $1 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Нізкапаточнае Ogg-відэа (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Паточнае Ogg-відэа (360 пкс)",
+ "timedmedia-derivative-desc-480p.ogv": "Паточнае Ogg-відэа (480 пкс)",
+ "timedmedia-derivative-desc-720p.ogv": "Высакаякаснае Ogg-відэа для загрузкі (720p)",
+ "timedmedia-derivative-desc-360p.webm": "Паточны WebM (360p)",
+ "timedmedia-derivative-desc-480p.webm": "Паточны WebM (480p)",
+ "timedmedia-derivative-desc-720p.webm": "Высакаякаснае WebM-відэа для загрузкі (720p)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 HD-якасьці (720P)",
+ "timedmedia-subtitle-new": "Стварыць новы пераклад ці рэдагаваць існуючы",
+ "timedmedia-subtitle-new-go": "Пачаць",
+ "timedmedia-subtitle-language": "Субтытры ($2) на $1",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1}} відэа",
+ "timedmedia-file": "Файл",
+ "right-transcode-reset": "скіданьне няўдалых або транскадаваных відэа, каб яны ізноў трапілі ў чаргу заданьняў",
+ "right-transcode-status": "прагляд [[Special:TimedMediaHandler|зьвестак пра актуальны стан перакадаваньня]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/be.json b/extensions/TimedMediaHandler/i18n/be.json
new file mode 100644
index 00000000..d24bc36e
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/be.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Чаховіч Уладзіслаў"
+ ]
+ },
+ "timedmedia-no-player-js": "На жаль, у вашым браўзеры адключаны JavaScript, ці не маецца патрабаванага прайгравальніка.<br />\nВы можаце <a href=\"$1\">загрузіць ролік</a> ці <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">загрузіць прайгравальнік</a> для прайгравання роліка ў браўзеры.",
+ "timedmedia-source-file": "Крыніца $1",
+ "timedmedia-source-audio-file-desc": "Арыгінальны $1-файл ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/bg.json b/extensions/TimedMediaHandler/i18n/bg.json
new file mode 100644
index 00000000..0ef16819
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/bg.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borislav",
+ "DCLXVI",
+ "Spiritia",
+ "StanProg"
+ ]
+ },
+ "timedmedia-desc": "Приложение за файлове тип Ogg Theora и Vorbis, с плейър на JavaScript",
+ "timedmedia-ogg-short-audio": "Ogg $1 звуков файл, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 видео файл, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 звуков файл, продължителност $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 видео файл, продължителност $2, $4×$5 пиксела, $3",
+ "timedmedia-ogg-long-general": "Мултимедиен файл в ogg формат с дължина $2, $3",
+ "timedmedia-ogg-long-error": "Невалиден ogg файл: $1",
+ "timedmedia-no-player-js": "За съжаление, браузъра ви има изключен JavaScript или не разполага с необходимия плейър.<br />\nМожете да <a href=\"$1\">изтеглите клипа</a> или <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">да изтеглите плейър</a> за да пуснете клипа в браузъра си.",
+ "timedmedia-more": "Повече...",
+ "timedmedia-dismiss": "Затваряне",
+ "timedmedia-download": "Изтегляне на файла",
+ "timedmedia-desc-link": "Информация за файла",
+ "timedmedia-source-file": "Източник на $1",
+ "timedmedia-source-audio-file-desc": "Оригинален $1-файл ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/bgn.json b/extensions/TimedMediaHandler/i18n/bgn.json
new file mode 100644
index 00000000..da70a08d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/bgn.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Baloch Afghanistan",
+ "Ibrahim khashrowdi"
+ ]
+ },
+ "timedmedia-no-player-js": "بخشایت اۆڑی، شمی بروزیر ئی سرا جاوا اسکریپت ئی سافٹ ایر پئال نه اینت ، و یا که شمی بروزیر شه ای پورمت ئا پُشتیوانی ئه نه کنت .<br />\nشما ئه توانیت <a href=\"$1\">که ای ویڈیو ئا ائیر بکنیت</a> و یا <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">یک پخش کنۆک</a> ئی په ای ویڈیو یی اجرا ئا ائیر بکنیت.",
+ "timedmedia-source-file": "$1 زهي",
+ "timedmedia-source-audio-file-desc": "اورجینال $1 فایل ( $2 )"
+}
diff --git a/extensions/TimedMediaHandler/i18n/bho.json b/extensions/TimedMediaHandler/i18n/bho.json
new file mode 100644
index 00000000..b562c221
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/bho.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "SatyamMishra"
+ ]
+ },
+ "timedmedia-source-audio-file-desc": "ओरिजनल $1 फाइल ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/bn.json b/extensions/TimedMediaHandler/i18n/bn.json
new file mode 100644
index 00000000..d69249bb
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/bn.json
@@ -0,0 +1,48 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bellayet",
+ "Zaheen",
+ "Aftab1995",
+ "Aftabuzzaman"
+ ]
+ },
+ "timedmedia-ogg-short-audio": "অগ $1 সাউন্ড ফাইল, $2",
+ "timedmedia-ogg-short-video": "অগ $1 ভিডিও ফাইল, $2",
+ "timedmedia-ogg-short-general": "অগ $1 মিডিয়া ফাইল, $2",
+ "timedmedia-ogg-long-audio": "অগ $1 সাউন্ড ফাইল, দৈর্ঘ্য $2, $3",
+ "timedmedia-ogg-long-video": "অগ $1 ভিডিও ফাইল, দৈর্ঘ্য $2, $4×$5 পিক্সেল, $3",
+ "timedmedia-ogg-long-multiplexed": "অগ মাল্টিপ্লেক্সকৃত অডিও/ভিডিও ফাইল, $1, দৈর্ঘ্য $2, $4×$5 পিক্সেল, $3 সামগ্রিক",
+ "timedmedia-ogg-long-general": "অগ মিডিয়া ফাইল, দৈর্ঘ্য $2, $3",
+ "timedmedia-ogg-long-error": "অবৈধ অগ ফাইল: $1",
+ "timedmedia-mp4-short-video": "MP4 $1 ভিডিও ফাইল, $2",
+ "timedmedia-mp4-long-video": "MP4 অডিও/ভিডিও ফাইল, $1, দৈর্ঘ্য $2, $4 × $5 পিক্সেল, $3 সামগ্রিক",
+ "timedmedia-no-player-js": "দুঃখিত, আপনার ব্রাউজারে জাভাস্ক্রিপ্ট নিষ্ক্রিয় করা আছে অথবা কোনো সমর্থিত প্লেয়ার নেই। <br />\nআপনি আপনার ব্রাউজারে ক্লিপটি চালানোর জন্য <a href=\"$1\">ক্লিপটি ডাউনলোড করতে পারেন</a> বা <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">একটি প্লেয়ার ডাউনলোড</a> করতে পারেন।",
+ "timedmedia-more": "আরও...",
+ "timedmedia-dismiss": "বন্ধ",
+ "timedmedia-download": "ফাইল ডাউনলোড করুন",
+ "timedmedia-play-media": "মিডিয়া চালান",
+ "timedmedia-desc-link": "এই ফাইলের বৃত্তান্ত",
+ "timedmedia-status-header": "ট্রান্সকোড অবস্থা",
+ "timedmedia-update-status": "ট্রান্সকোড অবস্থা হালনাগাদ করুন",
+ "timedmedia-status": "অবস্থা",
+ "timedmedia-status-unknown": "অবস্থা অজানা",
+ "timedmedia-transcodeinfo": "ব্যুৎপন্ন বর্ণনা ট্রান্সকোড",
+ "timedmedia-actions": "কার্য",
+ "timedmedia-direct-link": "ব্যুৎপন্ন ডাউনলোড করুন",
+ "timedmedia-not-ready": "তৈরি নয়",
+ "timedmedia-percent-done": "প্রায় $1% করা হয়েছে",
+ "timedmedia-days": "{{PLURAL:$1|১ দিন|$1 দিন}}",
+ "timedmedia-hours": "{{PLURAL:$1|১ ঘণ্টা|$1 ঘণ্টা}}",
+ "timedmedia-minutes": "{{PLURAL:$1|১ মিনিট|$1 মিনিট}}",
+ "timedmedia-seconds": "{{PLURAL:$1|১ সেকেন্ড|$1 সেকেন্ড}}",
+ "timedmedia-source-file": "$1 উৎস",
+ "timedmedia-source-audio-file-desc": "মূল $1 ফাইল ($2)",
+ "timedmedia-derivative-desc-240p.ogv": "ওয়েব স্ট্রিমযোগ্য অগ ভিডিও (২৪০P)",
+ "timedmedia-subtitle-new-go": "যাও",
+ "timedmedia-subtitle-language": "$1 ($2) সাবটাইটেল",
+ "timedmedia-videos": "{{PLURAL:$1|$1টি ভিডিও}}",
+ "timedmedia-file": "ফাইল",
+ "timedmedia-audios": "{{PLURAL:$1|$1টি অডিও ফাইল}}",
+ "action-transcode-status": "বর্তমান ট্রান্সকোডিংয়ের অবস্থা দেখুন"
+}
diff --git a/extensions/TimedMediaHandler/i18n/br.json b/extensions/TimedMediaHandler/i18n/br.json
new file mode 100644
index 00000000..dd74c0c5
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/br.json
@@ -0,0 +1,51 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fohanno",
+ "Fulup",
+ "Y-M D"
+ ]
+ },
+ "timedmedia-desc": "Skor video, son ha testenn sinkronelaet gant ar furmadoù WebM, Ogg Theora hag SRT skoret",
+ "timedmedia-ogg-short-audio": "Restr son Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Restr video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Restr media Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Restr son Ogg $1, pad $2, $3",
+ "timedmedia-ogg-long-video": "Restr video Ogg $1, pad $2, $4×$5 piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Restr Ogg klevet/video liesplezhet $1, pad $2, $4×$5 piksel, $3 hollad",
+ "timedmedia-ogg-long-general": "Restr media Ogg, pad $2, $3",
+ "timedmedia-ogg-long-error": "Restr ogg direizh : $1",
+ "timedmedia-webm-short-video": "Restr video WebM $1, $2",
+ "timedmedia-webm-long-video": "Restr video/son WebM, $1, pad $2, $4 × $5 piksel, $3 en holl",
+ "timedmedia-no-player-js": "Ho tigarez, pe eo diweredekaet JavaScript war ho merdeer pen n'eo ket skoret lenner ebet gantañ.<br />\n<a href=\"$1\">Pellgargañ ar c'hlip</a> a c'hallit pe <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">pellgargañ ul lenner</a> da lenn ar c'hlip gant ho merdeer.",
+ "timedmedia-more": "Muioc'h...",
+ "timedmedia-dismiss": "Serriñ",
+ "timedmedia-download": "Pellgargañ ar restr",
+ "timedmedia-play-media": "Lenn ar media",
+ "timedmedia-desc-link": "Diwar-benn ar restr-mañ",
+ "timedmedia-oggThumb-version": "Rekis eo stumm $1 oggThumb, pe nevesoc'h, evit implijout OggHandler.",
+ "timedmedia-oggThumb-failed": "N'eo ket deuet a-benn oggThumb da grouiñ ar munud.",
+ "timedmedia-status": "Statud",
+ "timedmedia-status-unknown": "Statud dianav",
+ "timedmedia-actions": "Oberoù",
+ "timedmedia-not-ready": "N'eo ket prest",
+ "timedmedia-percent-done": "War-dro $1 % zo bet graet",
+ "timedmedia-days": "{{PLURAL:$1|1 devezh|$1 devezh}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 eurvezh|$1 eurvezh}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 vunutenn|$1 munutenn}}",
+ "timedmedia-seconds": "$1 {{PLURAL:$1|eilenn|eilenn}}",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Mammenn $1",
+ "timedmedia-source-file-desc": "Orin $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Restr orin $1 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Video Ogg izelgas (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Video Ogg lennus war-eeun war ar Gwiad (360p)",
+ "timedmedia-derivative-desc-480p.ogv": "Video Ogg lennus war-eeun war ar Gwiad (480p)",
+ "timedmedia-derivative-desc-720p.ogv": "Video Ogg da bellgargañ gant ur c'halite a-feson (720p)",
+ "timedmedia-derivative-desc-360p.webm": "WebM lennus war-eeun eus ar Gwiad (360p)",
+ "timedmedia-derivative-desc-480p.webm": "WebM lennus war-eeun eus ar Gwiad (480p)",
+ "timedmedia-derivative-desc-720p.webm": "Video WebM da bellgargañ gant ur c'halite a-feson (720p)",
+ "timedmedia-subtitle-new-go": "Mont",
+ "timedmedia-subtitle-language": "istitloù e $1 ($2)",
+ "timedmedia-file": "Restr"
+}
diff --git a/extensions/TimedMediaHandler/i18n/bs.json b/extensions/TimedMediaHandler/i18n/bs.json
new file mode 100644
index 00000000..144f854e
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/bs.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "CERminator",
+ "Palapa",
+ "Semso98"
+ ]
+ },
+ "timedmedia-desc": "Upravljač za zvuk, video i vremenski tekst sa podrškom formata za WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 zvučna datoteka, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 video datoteka, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 medijalna datoteka, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 zvučna datoteka, dužina $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 video datoteka, dužina $2, $4×$5 piksela, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg multipleksna zvučna/video datoteka, $1, dužina $2, $4×$5 piksela, $3 sveukupno",
+ "timedmedia-ogg-long-general": "Ogg medijalna datoteka, dužina $2, $3",
+ "timedmedia-ogg-long-error": "Nevaljana ogg datoteka: $1",
+ "timedmedia-wav-long-audio": "WAV audio datoteka, dužina $1, $2 sveukupno",
+ "timedmedia-wav-pcm-required": "Možete postaviti samo PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-no-player-js": "Žao nam je, vaš preglednik ili je onemogućio JavaScript ili nema nijednog podržanog playera.<br />\nMožete <a href=\"$1\">učitati klip</a> ili <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">učitati player</a> za reproduciranje klipa u vašem pregledniku.",
+ "timedmedia-more": "Više...",
+ "timedmedia-dismiss": "Zatvori",
+ "timedmedia-download": "Učitaj datoteku",
+ "timedmedia-desc-link": "O ovoj datoteci",
+ "timedmedia-oggThumb-version": "OggHandler zahtijeva oggThumb verziju $1 ili kasniju.",
+ "timedmedia-oggThumb-failed": "oggThumb nije uspio napraviti smanjeni pregled.",
+ "timedmedia-source-file": "$1 izvor",
+ "timedmedia-source-file-desc": "Originalna $1 datoteka, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Originalna $1 datoteka ($2)",
+ "timedmedia-subtitle-language": "$1 ($2) podnaslovi"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ca.json b/extensions/TimedMediaHandler/i18n/ca.json
new file mode 100644
index 00000000..6a72f2d0
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ca.json
@@ -0,0 +1,44 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aleator",
+ "Alvaro Vidal-Abarca",
+ "Paucabot",
+ "Pitort",
+ "SMP",
+ "Toniher",
+ "Vriullop",
+ "Joan manel",
+ "Macofe"
+ ]
+ },
+ "timedmedia-desc": "Gestor de fitxers de vídeo, àudio i text sincronitzat amb suport pels formats WebM, Ogg Theora, Vorbi i srt",
+ "timedmedia-ogg-short-audio": "Fitxer OGG d'àudio $1, $2",
+ "timedmedia-ogg-short-video": "Fitxer OGG de vídeo $1, $2",
+ "timedmedia-ogg-short-general": "Fitxer multimèdia OGG $1, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 fitxer de so, llargada $2, $3",
+ "timedmedia-ogg-long-video": "Fitxer OGG de vídeo $1, llargada $2, $4×$5 píxels, $3",
+ "timedmedia-ogg-long-multiplexed": "Arxiu àudio/vídeo multiplex, $1, llargada $2, $4×$5 píxels, $3 de mitjana",
+ "timedmedia-ogg-long-general": "Fitxer multimèdia OGG, llargada $2, $3",
+ "timedmedia-ogg-long-error": "Fitxer OGG invàlid: $1",
+ "timedmedia-no-player-js": "Ho sentim, el vostre navegador té el JavaScript desactivat o bé no té cap reproductor compatible instal·lat.<br />\nPodeu <a href=\"<span class=\" notranslate\"=\"\" translate=\"no\">$1</span>\">descarregar el clip</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">descarregar un reproductor</a> per a veure el vídeo al vostre navegador.",
+ "timedmedia-more": "Més...",
+ "timedmedia-dismiss": "Tanca",
+ "timedmedia-download": "Descarrega el fitxer",
+ "timedmedia-desc-link": "Informació del fitxer",
+ "timedmedia-transcodeinfo": "Format",
+ "timedmedia-direct-link": "Descarregar",
+ "timedmedia-days": "{{PLURAL:$1|1 dia|$1 dies}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 hora|$1 hores}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minut|$1 minuts}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 segon|$1 segons}}",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Font $1",
+ "timedmedia-source-file-desc": "Arxiu original $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Fitxer original $1 ($2)",
+ "timedmedia-subtitle-language": "$1 ($2) subtítols",
+ "timedmedia-videos": "{{PLURAL:$1|$1 vídeo|$1 vídeos}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 vídeo Ogg|$1 vídeos Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 vídeo WebM|$1 vídeosWebM}}",
+ "timedmedia-file": "Fitxer"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ce.json b/extensions/TimedMediaHandler/i18n/ce.json
new file mode 100644
index 00000000..e6af995d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ce.json
@@ -0,0 +1,85 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sasan700",
+ "Умар"
+ ]
+ },
+ "timedmedia-desc": "WebM, Ogg Theora, Vorbis, srt форматаш ловш аудио, видео а, субтитраш а кечерг",
+ "timedmedia-ogg-short-audio": "Аьзнийн файл Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Видео-файл Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Медиа-файл Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "аьзнийн файл Ogg $1, дохалла (хан) $2, $3",
+ "timedmedia-ogg-long-video": "видео-файл Ogg $1, йохалла $2, $4 × $5 {{PLURAL:$5|пиксель}}, $3",
+ "timedmedia-ogg-long-multiplexed": "мультиплекан аудио/видео-файл Ogg, $1, йохалла $2, $4×$5 пиксель, $3 ерриг",
+ "timedmedia-ogg-long-general": "медиа-файл Ogg, йохалла $2, $3",
+ "timedmedia-ogg-long-error": "нийса йоцу Ogg-файл: $1",
+ "timedmedia-ogg-long-no-streams": "Мультимедиа-файл ogg. ДӀахьедар: ХӀокху файлас лелош йолу цхьа кодек билгалйина яц.",
+ "timedmedia-webm-short-video": "WebM $1 видео-файл, $2",
+ "timedmedia-webm-long-video": "WebM аудио/видео файл, $1, йохалла $2, $4 × $5 {{PLURAL:$5|пиксель}}, ерриг $3",
+ "timedmedia-flac-short-audio": "Аудиофайл FLAC, $1",
+ "timedmedia-flac-long-audio": "Аудиофайл FLAC, йохалла — $1, битрейт — $2",
+ "timedmedia-wav-short-audio": "Аудиофайл FLAC, $1",
+ "timedmedia-wav-long-audio": "Аудиофайл WAV, йохалла — $1, битрейт — $2",
+ "timedmedia-wav-pcm-required": "Ахьа чуяккха мега PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "WebM $1 видео-файл, $2",
+ "timedmedia-mp4-long-video": "Аудио/видеофайл MP4 $1, йохалла — $2, $4 × $5 пиксель, битрейт — $3",
+ "timedmedia-more": "Дукха…",
+ "timedmedia-dismiss": "Къайлаяккха",
+ "timedmedia-download": "Файл чуяккхар",
+ "timedmedia-play-media": "Йолаялийта медиа-файл",
+ "timedmedia-desc-link": "ХӀокху файлах лаьцна хаам",
+ "timedmedia-oggThumb-failed": "oggThumb тар цаделира миниатюра кхолла.",
+ "timedmedia-status-header": "Юху кодяран хьал",
+ "timedmedia-update-status": "Юху кодяран статус карлаяккха",
+ "timedmedia-status": "Хьал",
+ "timedmedia-status-unknown": "Ца довза хьал",
+ "timedmedia-transcodeinfo": "Юху кодярах лаьцна",
+ "timedmedia-actions": "Дийраш",
+ "timedmedia-direct-link": "Чуяккха модифицироват йина вариант",
+ "timedmedia-not-ready": "Кийча яц",
+ "timedmedia-completed-on": "$1 юху кодяр чекхдели",
+ "timedmedia-error-on": "$1 юху кодъеш гӀалат",
+ "timedmedia-started-transcode": "Юху кодяр дола далийтина $1 хьалха. $2",
+ "timedmedia-percent-done": "Герггара хьесапехь $1% кхочушдина",
+ "timedmedia-in-job-queue": "Да дезарг $1 хьалхо рогӀе диллина",
+ "timedmedia-days": "{{PLURAL:$1|$1 де}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 сахьт}}",
+ "timedmedia-minutes": "{{PLURAL:$1|$1 минот}}",
+ "timedmedia-seconds": "{{PLURAL:$1|$1 секунд}}",
+ "timedmedia-reset": "Юху кодяр тӀехдалийтар",
+ "timedmedia-reset-error": "Юху кодъеш гӀалат.",
+ "timedmedia-source-file": "Хьост $1",
+ "timedmedia-source-file-desc": "Оригинал $1 файлан, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Оригиналан $1-файл ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg-видео дика йоцу (160p)",
+ "timedmedia-derivative-desc-360p.ogv": "МогӀаман Ogg-видео (360p)",
+ "timedmedia-derivative-desc-480p.ogv": "МогӀаман Ogg-видео (480p)",
+ "timedmedia-derivative-desc-720p.ogv": "Ogg-видео дика (720p)",
+ "timedmedia-derivative-desc-160p.webm": "МогӀаман WebM-видео (160p)",
+ "timedmedia-derivative-desc-360p.webm": "МогӀаман WebM-видео (360p)",
+ "timedmedia-derivative-desc-480p.webm": "МогӀаман WebM-видео (480p)",
+ "timedmedia-derivative-desc-720p.webm": "WebM-видео дика (720p)",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 (320P) кечяр",
+ "timedmedia-derivative-desc-480p.mp4": "МогӀаман MP4-видео (480p)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 HD-дикаллица (720P)",
+ "timedmedia-subtitle-new-go": "Кхочушдé",
+ "timedmedia-subtitle-language": "$1 ($2) субтитраш",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 видео-файл|$1 видео-файлаш}}",
+ "timedmedia-ogg-videos": "$1 Ogg видео{{PLURAL:$1|файл}}",
+ "timedmedia-webm-videos": "$1 WebM видео{{PLURAL:$1|файл}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 юху кодяр}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 юху кодяр доладалийтар}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 юху кодяран рогӀехь ю}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 кхочуш ца хилла юху кодяр}}",
+ "timedmedia-file": "Файл",
+ "timedmedia-audios": "{{PLURAL:$1|$1 аудио-файл|$1 аудио-файлаш}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 аудио-файл Ogg|$1 аудио-файлаш Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 аудио-файл FLAC|$1 аудио-файлаш FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 аудио-файл WAV|$1 аудио-файлаш WAV}}",
+ "right-transcode-reset": "Кхосса дика йоцу видеош уьш рогӀехь хилийта.",
+ "right-transcode-status": "Хьажа [[Special:TimedMediaHandler|юху код хийцаран хааме]]",
+ "orphanedtimedtext": "Яйна агӀонаш TimedText",
+ "orphanedtimedtext-notimedtext": "TimedText хӀокху вики чохь латина дац."
+}
diff --git a/extensions/TimedMediaHandler/i18n/ckb.json b/extensions/TimedMediaHandler/i18n/ckb.json
new file mode 100644
index 00000000..4a345dc0
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ckb.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Calak",
+ "Asoxor",
+ "Muhammed taha"
+ ]
+ },
+ "timedmedia-no-player-js": "ببوورە، وێبگەرەکەت یان JavaScript لە کار خستووە یان playerی پێویستی نییە.<br />\nدەتوانیت <a href=\"$1\">کلیپەکە داگریت</a> یان <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">playerێک داگریت</a> بۆ ئەوەی لە وێبگەڕەکەتدا بیخەیتە سەر.",
+ "timedmedia-source-file": "$1 سەرچاوە",
+ "timedmedia-source-audio-file-desc": "پەڕگەی $1 بنەڕەتی ($2)",
+ "right-transcode-reset": "ڕێکخستنەوەی ڤیدیۆ سەرنەکوتووەکان یان ترانسکۆدکراوەکان ھەتا دیسان بچنەوە ناو ڕیزی کارەوە.",
+ "right-transcode-status": "دیتنی [[تایبەت:TimedMediaHandler|زانیاری لەمەڕ چالاکیی ترانسکۆدی ھەنووکەیی]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/cs.json b/extensions/TimedMediaHandler/i18n/cs.json
new file mode 100644
index 00000000..69a2c0ca
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/cs.json
@@ -0,0 +1,75 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chmee2",
+ "Li-sung",
+ "Matěj Grabovský",
+ "Mormegil",
+ "Paxt",
+ "Matěj Suchánek"
+ ]
+ },
+ "timedmedia-desc": "Obsluha zvuků, videa a časovaného textu s podporou formátů WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Zvukový soubor ogg $1, $2",
+ "timedmedia-ogg-short-video": "Videosoubor ogg $1, $2",
+ "timedmedia-ogg-short-general": "Multimediální soubor ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Zvukový soubor ogg $1, délka $2, $3",
+ "timedmedia-ogg-long-video": "Videosoubor $1, délka $2, $4×$5 pixelů, $3",
+ "timedmedia-ogg-long-multiplexed": "multiplexovaný audio/video soubor Ogg, $1, délka $2, $4×$5 pixelů, celkem $3",
+ "timedmedia-ogg-long-general": "Soubor média ogg, délka $2, $3",
+ "timedmedia-ogg-long-error": "Chybný soubor ogg: $1",
+ "timedmedia-webm-short-video": "Videosoubor WebM $1, $2",
+ "timedmedia-webm-long-video": "audio/video soubor WebM, $1, délka $2, $4×$5 pixelů, celkem $3",
+ "timedmedia-wav-pcm-required": "Můžete načítat jen WAV soubory ve formátu PCM (pulse code modulation).",
+ "timedmedia-mp4-short-video": "Videosoubor MP4 $1, $2",
+ "timedmedia-mp4-long-video": "audio/video soubor MP4, $1, délka $2, $4×$5 pixelů, celkem $3",
+ "timedmedia-no-player-js": "Je mi líto, ale váš prohlížeč má buď vypnutý JavaScript, nebo nemáte žádný podporovaný přehrávač.<br />\nMůžete si <a href=\"$1\">stáhnout klip</a> nebo si <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">stáhnout přehrávač</a>, kterým si klip přehrajete v prohlížeči.",
+ "timedmedia-more": "Více...",
+ "timedmedia-dismiss": "Zavřít",
+ "timedmedia-download": "Stáhnout soubor",
+ "timedmedia-play-media": "Přehrát média",
+ "timedmedia-desc-link": "O tomto souboru",
+ "timedmedia-oggThumb-version": "OggHandler vyžaduje oggThumb verze $1 nebo novější.",
+ "timedmedia-oggThumb-failed": "oggThumb nedokázal vytvořit náhled.",
+ "timedmedia-status-header": "Stav transkódování",
+ "timedmedia-update-status": "Aktualizovat stav transkódování",
+ "timedmedia-status": "Stav",
+ "timedmedia-status-unknown": "Neznámý stav",
+ "timedmedia-actions": "Akce",
+ "timedmedia-not-ready": "Nepřipraveno",
+ "timedmedia-completed-on": "Transkódování dokončeno v $1",
+ "timedmedia-error-on": "Chyba transkódování v $1",
+ "timedmedia-started-transcode": "Transkódování začalo před $1. $2",
+ "timedmedia-percent-done": "Hotovo asi $1 %",
+ "timedmedia-in-job-queue": "Před $1 přidáno do fronty",
+ "timedmedia-unknown-target-size": "Neznámá výsledná velikost, zakódováno $1",
+ "timedmedia-days": "$1 {{PLURAL:$1|den|dny|dní}}",
+ "timedmedia-hours": "$1 {{PLURAL:$1|hodina|hodiny|hodin}}",
+ "timedmedia-minutes": "$1 {{PLURAL:$1|minuta|minuty|minut}}",
+ "timedmedia-seconds": "$1 {{PLURAL:$1|sekunda|sekundy|sekund}}",
+ "timedmedia-reset": "Obnovit transkódování",
+ "timedmedia-source-file": "Zdrojový soubor $1",
+ "timedmedia-source-audio-file-desc": "Původní soubor $1 ($2)",
+ "timedmedia-subtitle-new": "Vytvoření nového překladu nebo editace stávajícího",
+ "timedmedia-subtitle-new-desc": "Zvolte jazyk a stiskněte tlačítko '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Přejít",
+ "timedmedia-subtitle-language": "titulky v jazyce $1 ($2)",
+ "timedmedia-subtitle-no-video": "K aktuální stránce titulků nepatří žádné video.",
+ "timedmedia-subtitle-no-subtitles": "K tomuto videu momentálně neexistují titulky v jazyce $1, přidat je můžete [{{fullurl:{{FULLPAGENAME}}|action=edit}} editací této stránky]",
+ "timedmedia-subtitle-remote": "Synchronizovaný text k tomuto souboru je uložen na $1",
+ "timedmedia-subtitle-remote-link": "[$1 Stránku s popisem tohoto souboru] si můžete prohlédnout na $2",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video|$1 videa|$1 videí}}",
+ "timedmedia-ogg-videos": "$1 {{PLURAL:$1|video|videa|videí}} Ogg",
+ "timedmedia-webm-videos": "$1 {{PLURAL:$1|video|videa|videí}} WebM",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transkódování}}",
+ "timedmedia-derivative-state-active": "$1 {{PLURAL:$1|probíhající|probíhající|probíhajících}} transkódování",
+ "timedmedia-derivative-state-queued": "$1 {{PLURAL:$1|naplánované|naplánovaná|naplánovaných}} transkódování",
+ "timedmedia-derivative-state-failed": "$1 {{PLURAL:$1|neúspěšné|neúspěšná|neúspěšných}} transkódování",
+ "timedmedia-file": "Soubor",
+ "timedmedia-audios": "{{PLURAL:$1|$1 zvukový soubor|$1 zvukové soubory|$1 zvukových souborů}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 zvukový soubor|$1 zvukové soubory|$1 zvukových souborů}} Ogg",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 zvukový soubor|$1 zvukové soubory|$1 zvukových souborů}} FLAC",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 zvukový soubor|$1 zvukové soubory|$1 zvukových souborů}} WAV",
+ "right-transcode-status": "Zobrazení [[Special:TimedMediaHandler|informací o probíhajícím transkódování]]",
+ "action-transcode-status": "vidět aktuální stav transkódování"
+}
diff --git a/extensions/TimedMediaHandler/i18n/cu.json b/extensions/TimedMediaHandler/i18n/cu.json
new file mode 100644
index 00000000..5221b9ed
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/cu.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "ОйЛ"
+ ]
+ },
+ "timedmedia-dismiss": "ꙁакрꙑи",
+ "timedmedia-source-file": "$1 кладѧꙃь",
+ "timedmedia-file": "дѣло"
+}
diff --git a/extensions/TimedMediaHandler/i18n/cv.json b/extensions/TimedMediaHandler/i18n/cv.json
new file mode 100644
index 00000000..93c188e0
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/cv.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chuvash2014"
+ ]
+ },
+ "timedmedia-more": "Нумайрах…"
+}
diff --git a/extensions/TimedMediaHandler/i18n/cy.json b/extensions/TimedMediaHandler/i18n/cy.json
new file mode 100644
index 00000000..5ffa296c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/cy.json
@@ -0,0 +1,50 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lloffiwr",
+ "Ham II",
+ "Xxglennxx"
+ ]
+ },
+ "timedmedia-ogg-short-audio": "Ffeil sain Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Ffeil fideo Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Ffeil gyfrwng Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Ffeil sain Ogg $1, yn para $2, $3",
+ "timedmedia-ogg-long-video": "Ffeil fideo Ogg $1, yn para $2, $4 × $5 picsel, $3",
+ "timedmedia-ogg-long-error": "Ffeil Ogg annilys: $1",
+ "timedmedia-more": "Mwy…",
+ "timedmedia-dismiss": "Caeer",
+ "timedmedia-download": "Lawrlwytho ffeil",
+ "timedmedia-play-media": "Chwarae'r ffeil gyfrwng",
+ "timedmedia-desc-link": "Ynglŷn â'r ffeil hon",
+ "timedmedia-status-header": "Statws trawsgodio",
+ "timedmedia-update-status": "Diweddaru'r statws trawsgodio",
+ "timedmedia-status": "Statws",
+ "timedmedia-status-unknown": "Statws anhysbys",
+ "timedmedia-actions": "Gweithredoedd",
+ "timedmedia-not-ready": "Ddim yn barod",
+ "timedmedia-started-transcode": "Dechreuodd y trawsgodio $1 yn ôl. $2",
+ "timedmedia-percent-done": "Tua $1% wedi ei wneud",
+ "timedmedia-in-job-queue": "Ychwanegwyd i'r ciw tasgiau $1 yn ôl",
+ "timedmedia-unknown-target-size": "Maint anhysbys i'r gwrthrych, $1 wedi ei amgodio",
+ "timedmedia-days": "{{PLURAL:$1|$1 diwrnod|diwrnod|deuddydd|tridiau|$1 diwrnod}}",
+ "timedmedia-hours": "{{PLURAL:$1|$1 awr}}",
+ "timedmedia-minutes": "{{PLURAL:$1|$1 munud|$1 munud|$1 funud|$1 munud}}",
+ "timedmedia-seconds": "{{PLURAL:$1|$1 eiliad}}",
+ "timedmedia-reset": "Ailosod y trawsgodio",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "ffynhonnell $1",
+ "timedmedia-source-file-desc": "Y ffeil $1 gwreiddiol, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Y ffeil $1 gwreiddiol ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Fideo Ogg (160P) o led band isel",
+ "timedmedia-subtitle-new-desc": "Dewiswch iaith a gwasgu'r botwm '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Gwneler",
+ "timedmedia-subtitle-language": "Isdeitlau $1 ($2)",
+ "timedmedia-subtitle-remote-link": "Gallwch [$1 weld tudalen ddisgrifio'r] ffeil hon ar $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 fideo}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 fideo Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 fideo WebM}}",
+ "timedmedia-file": "Ffeil",
+ "action-transcode-status": "gweld statws presennol y trawsgodio"
+}
diff --git a/extensions/TimedMediaHandler/i18n/da.json b/extensions/TimedMediaHandler/i18n/da.json
new file mode 100644
index 00000000..c9864945
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/da.json
@@ -0,0 +1,100 @@
+{
+ "@metadata": {
+ "authors": [
+ "Byrial",
+ "Christian List",
+ "Fnielsen",
+ "HenrikKbh",
+ "Jon Harald Søby",
+ "Peter Alberti",
+ "Simeondahl",
+ "Steenth"
+ ]
+ },
+ "timedmedia-desc": "Understøttelse for lyd, video og tidsbestemt txt med formaterne WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 lydfil, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 videofil, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 mediafil, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 lydfil, længde $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 videofil, længde $2, $4×$5 pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "Sammensat Ogg-lyd- og -videofil, $1, længde $2, $4×$5 pixel, $3 samlet",
+ "timedmedia-ogg-long-general": "Ogg mediafil, længde $2, $3",
+ "timedmedia-ogg-long-error": "Ugyldig Ogg-fil: $1",
+ "timedmedia-webm-short-video": "WebM $1 videofil, $2",
+ "timedmedia-webm-long-video": "WebM audio/video fil, $1, længde $2, $4 × $5 pixel, $3 samlet",
+ "timedmedia-flac-short-audio": "FLAC lydfil, $1",
+ "timedmedia-flac-long-audio": "FLAC lydfil, varighed $1, $2 samlet",
+ "timedmedia-wav-short-audio": "WAV lydfil, $1",
+ "timedmedia-wav-long-audio": "WAV lydfil, varighed $1, $2 samlet",
+ "timedmedia-wav-pcm-required": "Du kan kun uploade PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "Mp4 $1 videofil, $2",
+ "timedmedia-mp4-long-video": "Mp4-fil for audio/video, $1, længde $2, $4 × $5 pixel, $3 samlet",
+ "timedmedia-no-player-js": "Beklager, men din browser har enten deaktiveret JavaScript eller har ikke en afspiller, som vi understøtter.<br />\nDu kan enten <a href=\"$1\">hente klippet</a> eller <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">hente en afspiller</a> til at afspille klippet i din browser.",
+ "timedmedia-more": "Mere...",
+ "timedmedia-dismiss": "Luk",
+ "timedmedia-download": "Download fil",
+ "timedmedia-play-media": "Afspil medier",
+ "timedmedia-desc-link": "Om denne fil",
+ "timedmedia-oggThumb-version": "OggHandler kræver oggThumb version $1 eller nyere.",
+ "timedmedia-oggThumb-failed": "oggThumb kunne ikke oprette et miniaturebillede.",
+ "timedmedia-status-header": "Transcode status",
+ "timedmedia-update-status": "Opdater transcode status",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Ukendt status",
+ "timedmedia-transcodeinfo": "Afledt transcode beskrivelse",
+ "timedmedia-actions": "Handlinger",
+ "timedmedia-direct-link": "Hent derivat",
+ "timedmedia-not-ready": "Ikke klar",
+ "timedmedia-completed-on": "Gennemført transcode $1",
+ "timedmedia-error-on": "Fejl i omkodning ved $1",
+ "timedmedia-started-transcode": "Kode startet $1 siden. $2",
+ "timedmedia-percent-done": "Cirka $1 % udført",
+ "timedmedia-in-job-queue": "Føjet til jobkøen $1 siden",
+ "timedmedia-unknown-target-size": "Ukendt mål størrelse, $1 kodet",
+ "timedmedia-days": "{{PLURAL:$1|$1 dag|$1 dage}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 time|$1 timer}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minut|$1 minutter}}",
+ "timedmedia-seconds": "{{PLURAL:$1|$1 sekund|$1 sekunder}}",
+ "timedmedia-reset": "Nulstil transkode",
+ "timedmedia-reset-confirm": "Nulstilling af denne omkodning vil fjerne alle eksisterende filer (hvis der er nogen), og vil genindsætte omkodningen i jobkøen. Det vil tage nogen tid at omkode forfra.<br /><br />\nEr du sikker på, du vil fortsætte?",
+ "timedmedia-reset-error": "Fejl ved nulstilling af kode job.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 kilde",
+ "timedmedia-source-file-desc": "Original $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Original $1 file ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Lav båndbredde Ogg video (160 P)",
+ "timedmedia-derivative-desc-360p.ogv": "Web streambar Ogg video (360 P)",
+ "timedmedia-derivative-desc-480p.ogv": "Web streambar Ogg video (480 P)",
+ "timedmedia-derivative-desc-720p.ogv": "Højkvalitets hentbar Ogg video (720P)",
+ "timedmedia-derivative-desc-160p.webm": "Web streambar WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Web streambar WebM (360 P)",
+ "timedmedia-derivative-desc-480p.webm": "Web streambar WebM (480 P)",
+ "timedmedia-derivative-desc-720p.webm": "Højkvalitets hentbar WebM (720 P)",
+ "timedmedia-derivative-desc-320p.mp4": "enhedsvenlig MP4 (320 P)",
+ "timedmedia-derivative-desc-480p.mp4": "Web streambar MP4 (480 P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD-kvalitet MP4 (720 P)",
+ "timedmedia-subtitle-new": "Opret nye oversættelse eller rediger eksisterende",
+ "timedmedia-subtitle-new-desc": "Vælg sprog og tryk på '''{{int:Timedmedia-undertitlen-ny-gå}}'' ' knappen",
+ "timedmedia-subtitle-new-go": "Kør",
+ "timedmedia-subtitle-language": "$1( $2 ) undertekster",
+ "timedmedia-subtitle-no-video": "Der er ingen video tilknyttet den aktuelle undertitel side",
+ "timedmedia-subtitle-no-subtitles": "Der er i øjeblikket ingen undertekster i $1 denne video du kan [{{fullurl: {{FULLPAGENAME}} |action = Rediger}} redigere denne side] for at tilføje dem",
+ "timedmedia-subtitle-remote": "Tidsbestemte tekst for denne fil er placeret på $1",
+ "timedmedia-subtitle-remote-link": "Du kan [$1 se beskrivelses siden] til denne fil på $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video|$1 videoer}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg video|$1 Ogg videoer}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM video|$1 WebM videoer}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transkode|$1 transkoder}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 kørende transcode|$1 kørende transcodes}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transkode i kø|$1 transkoder i kø}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transkode mislykket|$1 transkoder mislykkedes}}",
+ "timedmedia-file": "Fil",
+ "timedmedia-audios": "{{PLURAL:$1|$1 lydfil|$1 lydfiler}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg-lydfil|$1 Ogg-lydfiler}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC-lydfil|$1 FLAC-lydfiler}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV-lydfil|$1 WAV-lydfiler}}",
+ "right-transcode-reset": "Nulstil mislykkedes eller transkodede videoer så de er sat ind i jobkøen igen.",
+ "right-transcode-status": "Vis [[Special:TimedMediaHandler|information om den aktuelle omkodningsaktivitet]]",
+ "action-transcode-status": "få vist den aktuelle transkode status"
+}
diff --git a/extensions/TimedMediaHandler/i18n/de-formal.json b/extensions/TimedMediaHandler/i18n/de-formal.json
new file mode 100644
index 00000000..be6d0c9d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/de-formal.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kghbln"
+ ]
+ },
+ "timedmedia-no-player-js": "Entschuldige, aber für Ihren Browser ist entweder die Nutzung von JavaScript deaktiviert oder er verfügt über keine unterstützte Abspielsoftware.<br />\nSie können <a href=\"$1\">den Clip herunterladen</a> oder <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">eine Abspielsoftware herunterladen</a>, um den Clip im Browser abspielen zu können."
+}
diff --git a/extensions/TimedMediaHandler/i18n/de.json b/extensions/TimedMediaHandler/i18n/de.json
new file mode 100644
index 00000000..cffaf6e2
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/de.json
@@ -0,0 +1,130 @@
+{
+ "@metadata": {
+ "authors": [
+ "Filzstift",
+ "G.Hagedorn",
+ "Geitost",
+ "Kghbln",
+ "Leithian",
+ "Les Meloures",
+ "Metalhead64",
+ "MichaelFrey",
+ "Raimond Spekking",
+ "The Evil IP address",
+ "Umherirrender"
+ ]
+ },
+ "extensionname-timedmedia": "TimedMediaHandler",
+ "timedmedia-desc": "Stellt ein Steuerungsprogramm für zeitgesteuerte Medien (Video, Audio, timedText) bereit, welches die Formate WebM, Ogg Theora, Ogg Vorbis und SubRip unterstützt",
+ "timedmedia-ogg-short-audio": "Ogg-$1-Audiodatei, $2",
+ "timedmedia-ogg-short-video": "Ogg-$1-Videodatei, $2",
+ "timedmedia-ogg-short-general": "Ogg-$1-Mediadatei, $2",
+ "timedmedia-ogg-long-audio": "Ogg-$1-Audiodatei, Länge: $2, $3",
+ "timedmedia-ogg-long-video": "Ogg-$1-Videodatei, Länge: $2, $4×$5 Pixel, $3 insgesamt",
+ "timedmedia-ogg-long-multiplexed": "Ogg-Audio-/Video-Datei, $1, Länge: $2, $4×$5 Pixel, $3 insgesamt",
+ "timedmedia-ogg-long-general": "Ogg-Mediadatei, Länge: $2, $3",
+ "timedmedia-ogg-long-error": "Ungültige Ogg-Datei: $1",
+ "timedmedia-ogg-long-no-streams": "OGG-Mediendatei. Warnung: Keine der in dieser Datei verwendeten Codecs wurden erkannt.",
+ "timedmedia-webm-short-video": "WebM-$1-Videodatei, $2",
+ "timedmedia-webm-long-video": "WebM-Audio-/Video-Datei, $1, Länge: $2, $4×$5 Pixel, $3 insgesamt",
+ "timedmedia-flac-short-audio": "FLAC-Audiodatei, $1",
+ "timedmedia-flac-long-audio": "FLAC-Audiodatei, Länge: $1, $2 insgesamt",
+ "timedmedia-wav-short-audio": "WAV-Audiodatei, $1",
+ "timedmedia-wav-long-audio": "WAV-Audiodatei, Länge: $1, $2 insgesamt",
+ "timedmedia-wav-pcm-required": "Du kannst nur PCM-WAV-Dateien hochladen (Pulse Code Modulation).",
+ "timedmedia-mp4-short-video": "MP4-$1-Videodatei, $2",
+ "timedmedia-mp4-long-video": "MP4-Audio-/Video-Datei, $1, Länge $2, $4 × $5 Pixel, $3 insgesamt",
+ "timedmedia-no-player-js": "Entschuldige, aber für deinen Browser ist entweder die Nutzung von JavaScript deaktiviert oder er verfügt über keine unterstützte Abspielsoftware.<br />\nDu kannst <a href=\"$1\">den Clip herunterladen</a> oder <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">eine Abspielsoftware herunterladen</a>, um den Clip im Browser abspielen zu können.",
+ "timedmedia-more": "Optionen …",
+ "timedmedia-dismiss": "Schließen",
+ "timedmedia-download": "Datei herunterladen",
+ "timedmedia-play-media": "Mediendatei abspielen",
+ "timedmedia-desc-link": "Über diese Datei",
+ "timedmedia-oggThumb-version": "OggHandler erfordert oggThumb in der Version $1 oder höher.",
+ "timedmedia-oggThumb-failed": "oggThumb konnte kein Miniaturbild erstellen.",
+ "timedmedia-status-header": "Transkodierungstatus",
+ "timedmedia-update-status": "Transkodierungstatus aktualisieren",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Unbekannter Status",
+ "timedmedia-transcodebitrate": "Bitrate",
+ "timedmedia-transcodeduration": "Kodierungszeit",
+ "timedmedia-transcodeinfo": "Format",
+ "timedmedia-actions": "Aktionen",
+ "timedmedia-direct-link": "Herunterladen",
+ "timedmedia-not-ready": "Nicht bereit",
+ "timedmedia-completed-on": "Abgeschlossen um $1",
+ "timedmedia-error-on": "Fehler um $1",
+ "timedmedia-started-transcode": "Gestartet vor $1. $2",
+ "timedmedia-percent-done": "Ungefähr $1 % sind erledigt",
+ "timedmedia-in-job-queue": "Vor $1 der Auftragswarteschlange hinzugefügt",
+ "timedmedia-unknown-target-size": "Unbekannte Zielgröße, $1 codiert",
+ "timedmedia-days": "{{PLURAL:$1|1 Tag|$1 Tagen}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 Stunde|$1 Stunden}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 Minute|$1 Minuten}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 Sekunde|$1 Sekunden}}",
+ "timedmedia-reset": "Umschlüsselung zurücksetzen",
+ "timedmedia-reset-confirm": "Das Zurücksetzen dieser Umschlüsselung wird, sofern vorhanden, die bestehende Datei entfernen und die Umschlüsselung erneut der Auftragswarteschlange hinzufügen. Die erneute Umschlüsselung wird einige Zeit dauern.<br /><br />Soll dies tatsächlich gemacht werden?",
+ "timedmedia-reset-error": "Fehler beim Zurücksetzen der Umschlüsselung",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Quelle ($1)",
+ "timedmedia-source-file-desc": "Original $1-Datei, $2 x $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Ursprüngliche $1-Datei ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg (160p)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg-Videodatei mit niedriger Datenübertragungsrate (160p)",
+ "timedmedia-derivative-desc-240p.ogv": "Webstreamfähiges OGG-Video (240p)",
+ "timedmedia-derivative-desc-360p.ogv": "Webstreamingfähige Ogg-Videodatei (360p)",
+ "timedmedia-derivative-desc-480p.ogv": "Webstreamingfähige Ogg-Videodatei (480p)",
+ "timedmedia-derivative-desc-720p.ogv": "Qualitativ hochwertige Ogg-Videodatei (720p)",
+ "timedmedia-derivative-desc-1080p.ogv": "Herunterladbares Full-HD-OGG-Video (1080p)",
+ "timedmedia-derivative-desc-160p.webm": "Webstreamingfähige WebM-Videodatei (160p)",
+ "timedmedia-derivative-desc-360p.webm": "Webstreamingfähige WebM-Videodatei (360p)",
+ "timedmedia-derivative-desc-480p.webm": "Webstreamingfähige WebM-Videodatei (480p)",
+ "timedmedia-derivative-desc-720p.webm": "Qualitativ hochwertige WebM-Videodatei (720p)",
+ "timedmedia-derivative-desc-1080p.webm": "Herunterladbares Full-HD-WebM-Video (1080p)",
+ "timedmedia-derivative-desc-2160p.webm": "Herunterladbares Full-4K-WebM-Video (2160P)",
+ "timedmedia-derivative-360p.vp9.webm": "VP9 360P",
+ "timedmedia-derivative-desc-360p.vp9.webm": "Webstreamfähiges WebM-VP9-Video (360P)",
+ "timedmedia-derivative-480p.vp9.webm": "VP9 480P",
+ "timedmedia-derivative-desc-480p.vp9.webm": "Webstreamfähiges WebM-VP9-Video (480P)",
+ "timedmedia-derivative-720p.vp9.webm": "VP9 720P",
+ "timedmedia-derivative-desc-720p.vp9.webm": "HD-streamfähiges WebM-VP9-Video (720P)",
+ "timedmedia-derivative-1080p.vp9.webm": "VP9 1080P",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "Full-HD-streamfähiges WebM-VP9-Video (1080P)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "Streamfähiges Full-4K-WebM-VP9-Video (2160P)",
+ "timedmedia-derivative-desc-320p.mp4": "Gerätefreundliche MP4-Datei (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Webstreamingfähige MP4-Datei (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4-Datei in HD-Qualität (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Full-HD-Qualität-MP4-Video (1080p)",
+ "timedmedia-derivative-desc-2160p.mp4": "Full-4K-Qualitäts-MP4-Video (2160P)",
+ "timedmedia-subtitle-new": "Neue Übersetzung erstellen oder vorhandene bearbeiten",
+ "timedmedia-subtitle-new-desc": "Wähle eine Sprache aus und klicke auf '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Los",
+ "timedmedia-subtitle-language": "$1 ($2) Untertitel",
+ "timedmedia-subtitle-no-video": "Der aktuellen Seite mit Untertiteln ist kein Video zugeordnet.",
+ "timedmedia-subtitle-no-subtitles": "Derzeit gibt es keine Untertitel auf $1 für dieses Video. Zum Hinzufügen von Untertiteln kann [{{fullurl:{{FULLPAGENAME}}|action=edit}} diese Seite] bearbeitet werden.",
+ "timedmedia-subtitle-remote": "timedText für diese Datei befindet sich auf $1",
+ "timedmedia-subtitle-remote-link": "Du kannst [$1 die Beschreibungsseite] für diese Datei auf $2 ansehen",
+ "timedmediahandler": "Steuerungsprogramm für zeitgesteuerte Medien",
+ "timedmedia-videos": "{{PLURAL:$1|Ein Video|$1 Videos}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|Ein Ogg-Video|$1 Ogg-Videos}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|Ein WebM-Video|$1 WebM-Videos}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|Eine Umschlüsselung|$1 Umschlüsselungen}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|Eine laufende Umschlüsselung|$1 laufende Umschlüsselungen}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|Eine Umschlüsselung|$1 Umschlüsselungen}} in der Warteschlange",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|Eine fehlgeschlagene Umschlüsselung|$1 fehlgeschlagene Umschlüsselungen}}",
+ "timedmedia-file": "Datei",
+ "timedmedia-audios": "{{PLURAL:$1|Eine Audiodatei|$1 Audiodateien}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|Eine OGG-Audiodatei|$1 OGG-Audiodateien}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|Eine FLAC-Audiodatei|$1 FLAC-Audiodateien}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|Eine WAV-Audiodatei|$1 WAV-Audiodateien}}",
+ "right-transcode-reset": "Fehlgeschlagene oder erfolgreiche Umschlüsselungen von Video-Dateien zurücksetzen, um sie erneut in die Auftragswarteschlange einzureihen",
+ "right-transcode-status": "[[Special:TimedMediaHandler|Informationen über aktuelle Umschlüsselungen]] betrachten",
+ "action-transcode-status": "den aktuellen Transkodierungstatus anzusehen",
+ "orphanedtimedtext": "Verwaiste TimedText-Seiten",
+ "orphanedtimedtext-summary": "Liste der [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]]-Seiten, die keine entsprechende Datei haben.",
+ "orphanedtimedtext-unsupported": "Diese Spezialseite wird nur auf MySQL-Datenbanken unterstützt.",
+ "orphanedtimedtext-notimedtext": "TimedText ist auf diesem Wiki nicht aktiviert.",
+ "apihelp-query+transcodestatus-example-1": "Ruft den Transkodierungsstatus für [[:File:Clip.webm]] ab",
+ "apihelp-transcodereset-param-title": "Der Titel der Mediendatei.",
+ "apihelp-transcodereset-example-1": "Setzt alle Umschlüsselungen für [[:File:Clip.webm]] zurück"
+}
diff --git a/extensions/TimedMediaHandler/i18n/din.json b/extensions/TimedMediaHandler/i18n/din.json
new file mode 100644
index 00000000..194e1a5e
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/din.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dinkawiki"
+ ]
+ },
+ "timedmedia-source-file": "$1 tënëyök"
+}
diff --git a/extensions/TimedMediaHandler/i18n/diq.json b/extensions/TimedMediaHandler/i18n/diq.json
new file mode 100644
index 00000000..1b1ba84c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/diq.json
@@ -0,0 +1,41 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aspar",
+ "Erdemaslancan",
+ "Gorizon",
+ "Marmase",
+ "Mirzali",
+ "Xoser"
+ ]
+ },
+ "timedmedia-desc": "Qen dê dosyayan dê WebM, Ogg Theora, Vorbis, srt rêxo desti veng dekerdış u nuşte ronayış",
+ "timedmedia-ogg-short-audio": "Ogg $1 dosyaya vengi, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 dosyaya filmi, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 dosyaya medyayi, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 dosyaya medyayi, mudde $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 dosyaya filmi, mudde $2, $4×$5 piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg dosyaya filmi/vengi yo multiexed, $1, mudde $2, $4×$5 piksel, $3 bıumumi",
+ "timedmedia-ogg-long-general": "Ogg dosyaya medyayi, mudde $2, $3",
+ "timedmedia-ogg-long-error": "dosyaya oggi yo nemeqbul: $1",
+ "timedmedia-more": "hema....",
+ "timedmedia-dismiss": "Racnê",
+ "timedmedia-download": "dosya biyar war",
+ "timedmedia-play-media": "Medya bıcıne",
+ "timedmedia-desc-link": "Heqa na dosya de",
+ "timedmedia-status": "Weziyet",
+ "timedmedia-status-unknown": "Weziyeto nêzanaye",
+ "timedmedia-transcodeinfo": "Şınasiya babetê transkodi",
+ "timedmedia-actions": "Kerdışi",
+ "timedmedia-not-ready": "Hazır niyo",
+ "timedmedia-days": "{{PLURAL:$1|1 roce|$1 roci}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 seate|$1 seati}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 deqa|$1 deqey}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 saniya|$1 saniyey}}",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 çıme",
+ "timedmedia-source-audio-file-desc": "Dosyaya $1 oricinale ($2)",
+ "timedmedia-subtitle-new-go": "Şo",
+ "timedmediahandler": "Programê kontroliê zemanê kontrolbiyayey",
+ "timedmedia-file": "Dosya"
+}
diff --git a/extensions/TimedMediaHandler/i18n/dsb.json b/extensions/TimedMediaHandler/i18n/dsb.json
new file mode 100644
index 00000000..6b65986b
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/dsb.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michawiki"
+ ]
+ },
+ "timedmedia-desc": "Wóźeński program za awdio, wideo a timedText, z formatoweju pódpěru za WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 awdiodataja, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 wideodataja, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 medijowa dataja, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 awdiodataja, dłujkosć $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 wideodataja, dłujkosć $2, $4×$5 pikselow, $3",
+ "timedmedia-ogg-long-multiplexed": "ogg multipleksowa awdio-/wideodataja, $1, dłujkosć $2, $4×$5 pikselow, $3 dogromady",
+ "timedmedia-ogg-long-general": "Ogg medijowa dataja, dłujkosć $2, $3",
+ "timedmedia-ogg-long-error": "Njepłaśiwa Ogg-dataja: $1",
+ "timedmedia-webm-short-video": "WebM $1 wideodataja, $2",
+ "timedmedia-webm-long-video": "WebM dataja awdio/wideo, $1, dłujkosć $2, $4 x $5, $3 dogromady",
+ "timedmedia-no-player-js": "Twój wobglědowak jo bóžko pak JavaScript znjemóžnił abo njama njepódpěrany wótegrawak.<br />\nMóžoš <a href=\"$1\">klip ześěgnuś</a> abo <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">wótgrawak ześěgnuś</a>, aby klip w swójom wobglědowaku wótegrał.",
+ "timedmedia-more": "Wěcej...",
+ "timedmedia-dismiss": "Zacyniś",
+ "timedmedia-download": "Dataju ześěgnuś",
+ "timedmedia-play-media": "Medijowu dataju wótegraś",
+ "timedmedia-desc-link": "Wó toś tej dataji",
+ "timedmedia-oggThumb-version": "OggHandler trjeba wersiju $1 oggThumb abo nowšu.",
+ "timedmedia-oggThumb-failed": "oggThumb njejo mógł wobrazk napóraś.",
+ "timedmedia-source-file": "Žrědło ($1)",
+ "timedmedia-source-file-desc": "Originalna $1-dataja, $2 × $3 ($4)",
+ "timedmedia-derivative-desc-160p.ogv": "Niska šyrokosć pasma Ogg-widea (200p)",
+ "timedmedia-subtitle-language": "$1 ($2) pódtitele"
+}
diff --git a/extensions/TimedMediaHandler/i18n/dty.json b/extensions/TimedMediaHandler/i18n/dty.json
new file mode 100644
index 00000000..905f6b6d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/dty.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "जनक राज भट्ट",
+ "रमेश सिंह बोहरा",
+ "राम प्रसाद जोशी"
+ ]
+ },
+ "timedmedia-no-player-js": "माफ गर्या, तमरो ब्राउजरमी या त जावास्क्रिप्ट अक्षम छ या समर्थित प्लेयर छैन ।<br />\nतमी <a href=\"$1\">क्लिपलाई डाउनलोड</a> गद्द सक्द्याहौ अथवा क्लिपलाई आफ्नो ब्राउजरमी चलाउनको लागि <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">एक प्लेयर डाउनलोड</a> गद्द सक्द्या हौ ।",
+ "timedmedia-source-file": "$1 श्रोत",
+ "timedmedia-source-audio-file-desc": "खास $1 चित्र ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ee.json b/extensions/TimedMediaHandler/i18n/ee.json
new file mode 100644
index 00000000..993eb5df
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ee.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aguve"
+ ]
+ },
+ "timedmedia-no-player-js": "Tafltsɛ, YavaSkript mele sisi internet-dɔwɔnua dzi alo ƒonu aɖeke meli si ate ŋu aƒoe o.<br />\nÀte ŋu <a href=\"$1\">awɔ video kpui sia ƒe kɔpi le</a> alo <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">wɔ ƒonu aɖe ƒe kɔpi</a> nàtsɔ aƒo video kpui sia le wò internet-dɔwɔnua me.",
+ "timedmedia-source-file": "Tsoƒe $1"
+}
diff --git a/extensions/TimedMediaHandler/i18n/el.json b/extensions/TimedMediaHandler/i18n/el.json
new file mode 100644
index 00000000..f1791421
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/el.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "Consta",
+ "Dead3y3",
+ "Omnipaedista",
+ "ZaDiak",
+ "Evropi",
+ "Geraki"
+ ]
+ },
+ "timedmedia-desc": "Χειριστής για αρχεία Ogg Theora και Vorbis, με αναπαραγωγέα JavaScript",
+ "timedmedia-ogg-short-audio": "Αρχείο ήχου Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Αρχείο βίντεο Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Αρχείο μέσων Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Αρχείο ήχου Ogg $1, διάρκεια $2, $3",
+ "timedmedia-ogg-long-video": "Αρχείο βίντεο Ogg $1, διάρκεια $2, $4×$5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "Αρχείο πολυπλεκτικού ήχου/βίντεο Ogg, $1, διάρκεια $2, $4×$5 pixels, $3 ολικά",
+ "timedmedia-ogg-long-general": "Αρχείο μέσων Ogg, διάρκεια $2, $3",
+ "timedmedia-ogg-long-error": "Άκυρο αρχείο ogg: $1",
+ "timedmedia-no-player-js": "Συγνώμη, το πρόγραμμα περιήγησής σας είτε έχει την JavaScript απενεργοποιημένη ή δεν έχει οποιοδήποτε υποστηριζόμενο player.<br />\nΜπορείτε να <a href=\"$1\">κατεβάστε το κλιπ</a> ή να <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">κάνετε λήψη ενός player</a> για να αναπαράγετε το κλιπ στον browser σας.",
+ "timedmedia-more": "Περισσότερα...",
+ "timedmedia-dismiss": "Κλείσιμο",
+ "timedmedia-download": "Κατεβάστε το αρχείο",
+ "timedmedia-desc-link": "Σχετικά με αυτό το αρχείο",
+ "timedmedia-source-file": "Πηγή $1",
+ "timedmedia-source-audio-file-desc": "Πρωτότυπο αρχείο $1 ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/en-gb.json b/extensions/TimedMediaHandler/i18n/en-gb.json
new file mode 100644
index 00000000..001bb5cc
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/en-gb.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shirayuki",
+ "Captaindogfish"
+ ]
+ },
+ "timedmedia-ogg-long-no-streams": "Ogg media file. Warning: None of the codecs used in this file are recognised.",
+ "timedmedia-derivative-desc-1080p.ogv": "Full HD downloadable Ogg video (1080P)",
+ "timedmedia-derivative-desc-1080p.webm": "Full HD downloadable WebM (1080P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Full HD quality MP4 (1080P)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/en.json b/extensions/TimedMediaHandler/i18n/en.json
new file mode 100644
index 00000000..b17d0665
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/en.json
@@ -0,0 +1,154 @@
+{
+ "@metadata": {
+ "authors": []
+ },
+ "extensionname-timedmedia": "TimedMediaHandler",
+ "timedmedia-desc": "Handler for audio, video and timed text, with format support for WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 sound file, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 video file, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 media file, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 sound file, length $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 video file, length $2, $4 × $5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg multiplexed audio/video file, $1, length $2, $4 × $5 pixels, $3 overall",
+ "timedmedia-ogg-long-general": "Ogg media file, length $2, $3",
+ "timedmedia-ogg-long-error": "Invalid Ogg file: $1",
+ "timedmedia-ogg-long-no-streams": "Ogg media file. Warning: None of the codecs used in this file are recognized.",
+ "timedmedia-webm-short-video": "WebM $1 video file, $2",
+ "timedmedia-webm-long-video": "WebM audio/video file, $1, length $2, $4 × $5 pixels, $3 overall",
+ "timedmedia-flac-short-audio": "FLAC audio file, $1",
+ "timedmedia-flac-long-audio": "FLAC audio file, length $1, $2 overall",
+ "timedmedia-wav-short-audio": "WAV audio file, $1",
+ "timedmedia-wav-long-audio": "WAV audio file, length $1, $2 overall",
+ "timedmedia-wav-pcm-required": "You can only upload PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "MP4 $1 video file, $2",
+ "timedmedia-mp4-long-video": "MP4 audio/video file, $1, length $2, $4 × $5 pixels, $3 overall",
+ "timedmedia-no-player-js": "Sorry, your browser either has JavaScript disabled or does not have any supported player.<br />\nYou can <a href=\"$1\">download the clip</a> or <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">download a player</a> to play the clip in your browser.",
+ "timedmedia-more": "More…",
+ "timedmedia-dismiss": "Close",
+ "timedmedia-download": "Download file",
+ "timedmedia-play-media": "Play media",
+ "timedmedia-desc-link": "About this file",
+ "timedmedia-oggThumb-version": "OggHandler requires oggThumb version $1 or later.",
+ "timedmedia-oggThumb-failed": "oggThumb failed to create the thumbnail.",
+ "timedmedia-status-header": "Transcode status",
+ "timedmedia-update-status": "Update transcode status",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Unknown status",
+ "timedmedia-transcodebitrate": "Bitrate",
+ "timedmedia-transcodeduration": "Encode time",
+ "timedmedia-transcodeinfo": "Format",
+ "timedmedia-actions": "Actions",
+ "timedmedia-direct-link": "Download",
+ "timedmedia-not-ready": "Not ready",
+ "timedmedia-completed-on": "Completed $1",
+ "timedmedia-error-on": "Error on $1",
+ "timedmedia-started-transcode": "Started $1 ago. $2",
+ "timedmedia-percent-done": "About $1% done",
+ "timedmedia-in-job-queue": "Added to Job queue $1 ago",
+ "timedmedia-unknown-target-size": "Unknown target size, $1 encoded",
+ "timedmedia-days": "{{PLURAL:$1|1 day|$1 days}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 hour|$1 hours}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minute|$1 minutes}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 second|$1 seconds}}",
+ "timedmedia-reset": "Reset transcode",
+ "timedmedia-reset-confirm": "Resetting this transcode will remove any existing file (if present), and it will re-add the transcode to the job queue. It will take some time to re-transcode.<br /><br />\nAre you sure you want to proceed?",
+ "timedmedia-reset-error": "Error in resetting transcode job.",
+ "timedmedia-ogg": "Ogg",
+ "timedmedia-webm": "WebM",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-wav": "WAV",
+ "timedmedia-flac": "FLAC",
+ "timedmedia-source-file": "$1 source",
+ "timedmedia-source-file-desc": "Original $1 file, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Original $1 file ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160P",
+ "timedmedia-derivative-desc-160p.ogv": "Low bandwidth Ogg video (160P)",
+ "timedmedia-derivative-240p.ogv": "Ogg 240P",
+ "timedmedia-derivative-desc-240p.ogv": "Web streamable Ogg video (240P)",
+ "timedmedia-derivative-360p.ogv": "Ogg 360P",
+ "timedmedia-derivative-desc-360p.ogv": "Web streamable Ogg video (360P)",
+ "timedmedia-derivative-480p.ogv": "Ogg 480P",
+ "timedmedia-derivative-desc-480p.ogv": "Web streamable Ogg video (480P)",
+ "timedmedia-derivative-720p.ogv": "Ogg 720P",
+ "timedmedia-derivative-desc-720p.ogv": "High quality downloadable Ogg video (720P)",
+ "timedmedia-derivative-1080p.ogv": "Ogg 1080P",
+ "timedmedia-derivative-desc-1080p.ogv": "Full HD downloadable Ogg video (1080P)",
+ "timedmedia-derivative-160p.webm": "WebM 160P",
+ "timedmedia-derivative-desc-160p.webm": "Web streamable WebM (160P)",
+ "timedmedia-derivative-360p.webm": "WebM 360P",
+ "timedmedia-derivative-desc-360p.webm": "Web streamable WebM (360P)",
+ "timedmedia-derivative-480p.webm": "WebM 480P",
+ "timedmedia-derivative-desc-480p.webm": "Web streamable WebM (480P)",
+ "timedmedia-derivative-720p.webm": "WebM 720P",
+ "timedmedia-derivative-desc-720p.webm": "High quality downloadable WebM (720P)",
+ "timedmedia-derivative-1080p.webm": "WebM 1080P",
+ "timedmedia-derivative-desc-1080p.webm": "Full HD downloadable WebM (1080P)",
+ "timedmedia-derivative-2160p.webm": "WebM 2160P",
+ "timedmedia-derivative-desc-2160p.webm": "Full 4K downloadable WebM (2160P)",
+ "timedmedia-derivative-360p.vp9.webm": "VP9 360P",
+ "timedmedia-derivative-desc-360p.vp9.webm": "Web streamable WebM VP9 (360P)",
+ "timedmedia-derivative-480p.vp9.webm": "VP9 480P",
+ "timedmedia-derivative-desc-480p.vp9.webm": "Web streamable WebM VP9 (480P)",
+ "timedmedia-derivative-720p.vp9.webm": "VP9 720P",
+ "timedmedia-derivative-desc-720p.vp9.webm": "HD streamable WebM VP9 (720P)",
+ "timedmedia-derivative-1080p.vp9.webm": "VP9 1080P",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "Full HD streamable WebM VP9 (1080P)",
+ "timedmedia-derivative-2160p.vp9.webm": "VP9 2160P",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "Full 4K streamable WebM VP9 (2160P)",
+ "timedmedia-derivative-320p.mp4": "H264 320P",
+ "timedmedia-derivative-desc-320p.mp4": "Device-friendly MP4 (320P)",
+ "timedmedia-derivative-480p.mp4": "H264 480P",
+ "timedmedia-derivative-desc-480p.mp4": "Web streamable MP4 (480P)",
+ "timedmedia-derivative-720p.mp4": "H264 720P",
+ "timedmedia-derivative-desc-720p.mp4": "HD quality MP4 (720P)",
+ "timedmedia-derivative-1080p.mp4": "H264 1080P",
+ "timedmedia-derivative-desc-1080p.mp4": "Full HD quality MP4 (1080P)",
+ "timedmedia-derivative-2160p.mp4": "H264 2160P",
+ "timedmedia-derivative-desc-2160p.mp4": "Full 4K quality MP4 (2160P)",
+ "timedmedia-derivative-ogg": "Ogg Vorbis",
+ "timedmedia-derivative-desc-ogg": "Ogg Vorbis",
+ "timedmedia-derivative-opus": "Opus",
+ "timedmedia-derivative-desc-opus": "Opus",
+ "timedmedia-derivative-mp3": "MP3",
+ "timedmedia-derivative-desc-mp3": "MP3",
+ "timedmedia-derivative-m4a": "AAC",
+ "timedmedia-derivative-desc-m4a": "AAC",
+ "timedmedia-subtitle-new": "Create new translation or edit existing",
+ "timedmedia-subtitle-new-desc": "Select language and press the '''{{int:Timedmedia-subtitle-new-go}}''' button",
+ "timedmedia-subtitle-new-go": "Go",
+ "timedmedia-subtitle-language": "$1 ($2) subtitles",
+ "timedmedia-subtitle-no-video": "There is no video associated with the current subtitle page.",
+ "timedmedia-subtitle-no-subtitles": "There are currently no subtitles in $1 for this video, you can [{{fullurl:{{FULLPAGENAME}}|action=edit}} edit this page] to add them.",
+ "timedmedia-subtitle-remote": "Timed text for this file is hosted on $1",
+ "timedmedia-subtitle-remote-link": "You can [$1 view the description page] for this file on $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video|$1 videos}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg video|$1 Ogg videos}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM video|$1 WebM videos}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcode|$1 transcodes}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 running transcode|$1 running transcodes}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 queued transcode|$1 queued transcodes}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 failed transcode|$1 failed transcodes}}",
+ "timedmedia-file": "File",
+ "timedmedia-audios": "{{PLURAL:$1|$1 audio file|$1 audio files}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg audio file|$1 Ogg audio files}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC audio file|$1 FLAC audio files}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV audio file|$1 WAV audio files}}",
+ "right-transcode-reset": "Reset failed or transcoded videos so they are inserted into the job queue again",
+ "right-transcode-status": "View [[Special:TimedMediaHandler|information about the current transcode activity]]",
+ "action-transcode-status": "view the current transcoding status",
+ "orphanedtimedtext": "Orphaned TimedText pages",
+ "orphanedtimedtext-summary": "List of [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] pages which do not have a corresponding file.",
+ "orphanedtimedtext-unsupported": "This special page is only supported on MySQL databases.",
+ "orphanedtimedtext-notimedtext": "TimedText is not enabled on this wiki.",
+ "apihelp-query+transcodestatus-description": "Get transcode status for a given file page.",
+ "apihelp-query+transcodestatus-example-1": "Get transcode status for [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "Extends imageinfo to include video source (derivatives) information",
+ "apihelp-query+videoinfo-param-prop": "What video information to get:\n;timestamp:Adds timestamp for the uploaded version.\n;user:Adds the user who uploaded the video version.\n;userid:Add the user ID that uploaded the video version.\n;comment:Comment on the version.\n;parsedcomment:Parse the comment on the version.\n;canonicaltitle:Adds the canonical title of the video file.\n;url:Gives URL to the video and the description page.\n;size:Adds the size of the video in bytes, its height and its width. Page count and duration are added if applicable.\n;dimensions:Alias for size.\n;sha1:Adds SHA-1 hash for the video.\n;mime:Adds MIME type of the video.\n;thumbmime:Adds MIME type of the video thumbnail (requires url and param $1urlwidth).\n;mediatype:Adds the media type of the video.\n;metadata:Lists Exif metadata for the version of the video.\n;commonmetadata:Lists file format generic metadata for the version of the video.\n;extmetadata:Lists formatted metadata combined from multiple sources. Results are HTML formatted.\n;archivename:Adds the filename of the archive version for non-latest versions.\n;bitdepth:Adds the bit depth of the version.\n;uploadwarning:Used by the [[Special:Upload]] page to get information about an existing file. Not intended for use outside MediaWiki core.\n;derivatives:Adds an array of the different format and quality versions of an audio or video file that are available.",
+ "apihelp-query+videoinfo-example-1": "Fetch information about [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "Users with the 'transcode-reset' right can reset and re-run a transcode job.",
+ "apihelp-transcodereset-param-title": "The media file title.",
+ "apihelp-transcodereset-param-transcodekey": "The transcode key you wish to reset. Fetch from [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Reset all transcodes for [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "Reset the '360_560kbs.webm' transcode key for [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/eo.json b/extensions/TimedMediaHandler/i18n/eo.json
new file mode 100644
index 00000000..436317ea
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/eo.json
@@ -0,0 +1,26 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amikeco",
+ "ArnoLagrange",
+ "Yekrats",
+ "KuboF"
+ ]
+ },
+ "timedmedia-desc": "Traktilo por sondosieroj, videoj, kaj horloĝigita teksto, kun formatsubteno por WebM kaj Ogg Theora kaj Vobis kaj srt.",
+ "timedmedia-ogg-short-audio": "Ogg $1 sondosiero, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 videodosiero, $2",
+ "timedmedia-ogg-short-general": "Media Ogg-dosiero $1, $2",
+ "timedmedia-ogg-long-audio": "Aŭda Ogg-dosiero $1, longeco $2, $3 entute",
+ "timedmedia-ogg-long-video": "Video Ogg-dosiero $1, longeco $2, $4×$5 pikseloj, $3 entute",
+ "timedmedia-ogg-long-multiplexed": "Kunigita aŭdio/video Ogg-dosiero, $1, longeco $2, $4×$5 pikseloj, $3 entute",
+ "timedmedia-ogg-long-general": "Ogg-mediodosiero, longeco $2, $3",
+ "timedmedia-ogg-long-error": "Malvalida Ogg-dosiero: $1",
+ "timedmedia-no-player-js": "Pardonu, estas malŝaltita Ĝavoskripto en via foliumilo aŭ ĝi enhavas neniun subtenatan ludilon<br />\nVi povas <a href=\"$1\">elŝuti la videaĵon</a> aŭ <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">elŝuti ludilon</a> por povi ludi la videaĵon en via foliumilo.",
+ "timedmedia-more": "Pli...",
+ "timedmedia-dismiss": "Fermi",
+ "timedmedia-download": "Alŝuti dosieron",
+ "timedmedia-desc-link": "Pri ĉi tiu dosiero",
+ "timedmedia-source-file": "Fonta $1-dosiero",
+ "timedmedia-source-audio-file-desc": "Origina $1-dosiero ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/es.json b/extensions/TimedMediaHandler/i18n/es.json
new file mode 100644
index 00000000..962436fb
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/es.json
@@ -0,0 +1,117 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aleator",
+ "Armando-Martin",
+ "Ciencia Al Poder",
+ "Crazymadlover",
+ "Jewbask",
+ "Maor X",
+ "Muro de Aguas",
+ "Remember the dot",
+ "Rodrigo Molinero",
+ "Rzuwig",
+ "Sanbec",
+ "Spacebirdy",
+ "Translationista",
+ "Fitoschido",
+ "Macofe"
+ ]
+ },
+ "timedmedia-desc": "Manipulador de sonido, vídeo y texto sincronizado, con soporte para los formatos WebM, Ogg Theora, Vorbis y srt",
+ "timedmedia-ogg-short-audio": "Archivo de sonido Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Archivo de video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Archivo Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Archivo de sonido Ogg $1, tamaño $2, $3",
+ "timedmedia-ogg-long-video": "Archivo de video Ogg $1, tamaño $2, $4×$5 píxeles, $3",
+ "timedmedia-ogg-long-multiplexed": "Archivo Ogg de audio/video multiplexado, $1, tamaño $2, $4×$5 píxeles, $3 en todo",
+ "timedmedia-ogg-long-general": "Archivo Ogg. tamaño $2, $3",
+ "timedmedia-ogg-long-error": "Archivo Ogg no válido: $1",
+ "timedmedia-webm-short-video": "Archivo de vídeo WebM $1, $2",
+ "timedmedia-webm-long-video": "Archivo de audio/vídeo WebM, $1 , longitud $2 , $4 × $5 píxeles, $3 total",
+ "timedmedia-flac-short-audio": "Archivo de audio FLAC, $1",
+ "timedmedia-flac-long-audio": "Archivo de audio FLAC, duración: $1, $2 en general",
+ "timedmedia-wav-short-audio": "Archivo de audio WAV, $1",
+ "timedmedia-wav-long-audio": "Archivo de audio WAV, duración: $1, $2 en general",
+ "timedmedia-wav-pcm-required": "Solo puedes cargar WAV del tipo PCM (''Pulse Code Modulation'', por sus siglas en inglés).",
+ "timedmedia-mp4-short-video": "Archivo de vídeo MP4 $1, $2",
+ "timedmedia-mp4-long-video": "Archivo de audio/vídeo MP4, $1 , longitud $2 , $4 × $5 píxeles, $3 total",
+ "timedmedia-no-player-js": "Tu navegador tiene JavaScript desactivado o no tiene un reproductor compatible.<br />\nPuedes <a href=\"$1\">descargar el vídeo</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">descargar un reproductor</a> para ver el vídeo en tu navegador.",
+ "timedmedia-more": "Opciones...",
+ "timedmedia-dismiss": "Cerrar",
+ "timedmedia-download": "Descargar archivo",
+ "timedmedia-play-media": "Reproducir contenido multimedia",
+ "timedmedia-desc-link": "Sobre este archivo",
+ "timedmedia-oggThumb-version": "OggHandler requiere una versión oggThumb $1 o posterior.",
+ "timedmedia-oggThumb-failed": "oggThumb no pudo crear la imagen miniatura.",
+ "timedmedia-status-header": "Estado de transcodificación",
+ "timedmedia-update-status": "Actualizar el estado de transcodificación",
+ "timedmedia-status": "Estado",
+ "timedmedia-status-unknown": "Estado desconocido",
+ "timedmedia-transcodeduration": "Tiempo de codificación",
+ "timedmedia-transcodeinfo": "Formato",
+ "timedmedia-actions": "Acciones",
+ "timedmedia-direct-link": "Descarga",
+ "timedmedia-not-ready": "No está listo",
+ "timedmedia-completed-on": "Completada $1",
+ "timedmedia-error-on": "Error a las $1",
+ "timedmedia-started-transcode": "Comenzada hace $1. $2",
+ "timedmedia-percent-done": "Aproximadamente $1 % completado",
+ "timedmedia-in-job-queue": "Añadido a la cola de trabajos hace $1",
+ "timedmedia-unknown-target-size": "Tamaño de archivo de destino desconocido, $1 codificado",
+ "timedmedia-days": "{{PLURAL:$1|1 día|$1 días}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 hora|$1 horas}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuto|$1 minutos}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 segundo|$1 segundos}}",
+ "timedmedia-reset": "Reiniciar la transcodificación",
+ "timedmedia-reset-confirm": "Restablecer esta transcodificación eliminará cualquier archivo existente (si existe), y volverá a añadir la transcodificación a la cola de trabajos. Llevará algún tiempo repetir la transcodificación.<br /><br />\n¿Estás seguro de que quieres continuar?",
+ "timedmedia-reset-error": "Error al restablecer el trabajo de transcodificación.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Fuente $1",
+ "timedmedia-source-file-desc": "Archivo $1 original, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Archivo $1 original ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Video en formato Ogg de bajo ancho de banda (160 P)",
+ "timedmedia-derivative-desc-360p.ogv": "Vídeo Ogg para la web (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Vídeo Ogg para la web (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Vídeo Ogg de alta calidad que se puede descargar (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Video ogg descargable Full HD (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM para la web (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM para la web (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM para la web (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM de alta calidad que se puede descargar (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "WebM descargable Full HD (1080P)",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 para dispositivos móviles (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 para la web (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 de calidad HD (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4 calidad Full HD (1080P)",
+ "timedmedia-subtitle-new": "Crear una nueva traducción o editar una existente",
+ "timedmedia-subtitle-new-desc": "Selecciona el idioma y pulsa el botón '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Ir",
+ "timedmedia-subtitle-language": "Subtítulos en $1 ($2)",
+ "timedmedia-subtitle-no-video": "No hay ningún video asociado con la página actual de subtítulos",
+ "timedmedia-subtitle-no-subtitles": "Actualmente no hay subtítulos en $1 para este video, puede [{{fullurl: {{FULLPAGENAME}} |action = edit}} editar esta página] para agregarlos",
+ "timedmedia-subtitle-remote": "El texto programado para este archivo está alojado en $1",
+ "timedmedia-subtitle-remote-link": "Puedes [$1 ver la página de descripción] de este archivo en $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 vídeo|$1 vídeos}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 vídeo Ogg|$1 vídeos Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 vídeo WebM|$1 vídeos WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcodificación|$1 transcodificaciones}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transcodificación activa|$1 transcodificaciones activas}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transcodificación|$1 transcodificaciones}} en la cola",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transcodificación fallida|$1 transcodificaciones fallidas}}",
+ "timedmedia-file": "Archivo",
+ "timedmedia-audios": "{{PLURAL:$1|$1 archivo|$1 archivos}} de audio",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 archivo|$1 archivos}} de audio Ogg",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 archivo|$1 archivos}} de audio FLAC",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 archivo|$1 archivos}} de audio WAV",
+ "right-transcode-reset": "Reiniciar los vídeos erróneos o transcodificados por lo que se vuelven a colocar en la cola de trabajo",
+ "right-transcode-status": "Ver [[Special:TimedMediaHandler|información sobre la actividad de transcodificación actual]]",
+ "action-transcode-status": "ver el estado de transcodificación actual",
+ "orphanedtimedtext": "Páginas TimedText huérfanas",
+ "orphanedtimedtext-summary": "Lista de páginas [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] que no tienen un archivo correspondiente.",
+ "orphanedtimedtext-unsupported": "Esta página especial sólo está soportada en base de datos MySQL.",
+ "orphanedtimedtext-notimedtext": "TimedText no se activó en este wiki.",
+ "apihelp-query+videoinfo-example-1": "Obtener información sobre [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-param-title": "El título del archivo multimedia."
+}
diff --git a/extensions/TimedMediaHandler/i18n/et.json b/extensions/TimedMediaHandler/i18n/et.json
new file mode 100644
index 00000000..ce910777
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/et.json
@@ -0,0 +1,122 @@
+{
+ "@metadata": {
+ "authors": [
+ "Avjoska",
+ "Pikne",
+ "Silvar"
+ ]
+ },
+ "timedmedia-desc": "WebM-, srt- ning Theora- ja Vorbis-tüüpi Ogg-vormingu toega heli-, video- ja ajastatud teksti käsitseja",
+ "timedmedia-ogg-short-audio": "$1-tüüpi Ogg-helifail, $2",
+ "timedmedia-ogg-short-video": "$1-tüüpi Ogg-videofail, $2",
+ "timedmedia-ogg-short-general": "$1-tüüpi Ogg-fail, $2",
+ "timedmedia-ogg-long-audio": "$1-tüüpi Ogg-helifail, kestus: $2, $3",
+ "timedmedia-ogg-long-video": "$1-tüüpi Ogg-videofail, kestus: $2, $4×$5 pikslit, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg-liitfail (heli ja video), $1, kestus: $2, $4×$5 pikslit, üldbitikiirus: $3",
+ "timedmedia-ogg-long-general": "Ogg-fail, kestus: $2, $3",
+ "timedmedia-ogg-long-error": "Vigane Ogg-fail: $1",
+ "timedmedia-ogg-long-no-streams": "Ogg-meediafail. Hoiatus: Selles failis ei kasutata ühtegi tuvastatud kodekit.",
+ "timedmedia-webm-short-video": "$1-tüüpi WebM-videofail, $2",
+ "timedmedia-webm-long-video": "WebM-fail (heli ja video), $1, kestus: $2, $4×$5 pikslit, üldbitikiirus: $3",
+ "timedmedia-flac-short-audio": "FLAC-helifail, $1",
+ "timedmedia-flac-long-audio": "FLAC-helifail, kestus: $1, üldbitikiirus: $2",
+ "timedmedia-wav-short-audio": "WAV-helifail, $1",
+ "timedmedia-wav-long-audio": "WAV-helifail, kestus: $1, üldbitikiirus: $2",
+ "timedmedia-wav-pcm-required": "Saad üles laadida ainult impulssmodulatsiooniga (PCM) WAV-faile.",
+ "timedmedia-mp4-short-video": "$1-tüüpi MP4-videofail, $2",
+ "timedmedia-mp4-long-video": "MP4-fail (heli ja video), $1, kestus: $2, $4×$5 pikslit, üldbitikiirus: $3",
+ "timedmedia-no-player-js": "Kahjuks on sinu veebilehitsejas JavaScript keelatud või puudub sul sobiv esitustarkvara.<br />\nSaad <a href=\"$1\">lõigu alla laadida</a> või <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">laadida alla tarkvara</a>, millega lõik veebilehitsejas esitada.",
+ "timedmedia-more": "Lisa...",
+ "timedmedia-dismiss": "Sule",
+ "timedmedia-download": "Laadi fail alla",
+ "timedmedia-play-media": "Esita meediafail",
+ "timedmedia-desc-link": "Info faili kohta",
+ "timedmedia-oggThumb-version": "OggHandleri jaoks on vaja oggThumbi versiooni $1 või hilisemat.",
+ "timedmedia-oggThumb-failed": "oggThumb ei saanud pisipildi loomisega hakkama.",
+ "timedmedia-status-header": "Ümberkodeeringu olek",
+ "timedmedia-update-status": "Värskenda ümberkodeeringu olekut",
+ "timedmedia-status": "Olek",
+ "timedmedia-status-unknown": "Tundmatu olek",
+ "timedmedia-transcodebitrate": "Bitikiirus",
+ "timedmedia-transcodeduration": "Kodeerimisaeg",
+ "timedmedia-transcodeinfo": "Vorming",
+ "timedmedia-actions": "Toimingud",
+ "timedmedia-direct-link": "Allalaadimine",
+ "timedmedia-not-ready": "Ei ole valmis",
+ "timedmedia-completed-on": "Valmimisaeg: $1",
+ "timedmedia-error-on": "Tõrkeaeg: $1",
+ "timedmedia-started-transcode": "Alustatud $1 tagasi. $2",
+ "timedmedia-percent-done": "Umbes $1% valmis",
+ "timedmedia-in-job-queue": "Lisatud tööjärge $1 tagasi",
+ "timedmedia-unknown-target-size": "Sihtsuurus teadmata, $1 kodeeritud",
+ "timedmedia-days": "{{PLURAL:$1|1 päev|$1 päeva}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 tund|$1 tundi}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minut|$1 minutit}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 sekund|$1 sekundit}}",
+ "timedmedia-reset": "Lähtesta ümberkodeering",
+ "timedmedia-reset-confirm": "Ümberkodeeringu lähtestamisel eemaldatakse kõik olemasolevad failid (kui neid on) ja see lisatakse uuesti tööjärge. Uus ümberkodeering kestab mõnda aega.<br /><br />\nKas oled kindel, et tahad jätkata?",
+ "timedmedia-reset-error": "Ümberkodeeringu lähtestamisel ilmnes tõrge.",
+ "timedmedia-source-file": "Allikas ($1)",
+ "timedmedia-source-file-desc": "Algne $1-fail, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Algne $1-fail ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Väikse ribalaiusega Ogg-video (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "Võrgus voogedastatav Ogg-video (240P)",
+ "timedmedia-derivative-desc-360p.ogv": "Võrgus voogedastatav Ogg-video (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Võrgus voogedastatav Ogg-video (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Kõrge kvaliteediga allalaaditav Ogg-video (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Täiskõrglahutusega allalaaditav Ogg-video (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Võrgus voogedastatav WebM-video (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Võrgus voogedastatav WebM-video (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Võrgus voogedastatav WebM-video (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Kõrge kvaliteediga allalaaditav WebM-video (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "Täiskõrglahutusega allalaaditav WebM-video (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "Allalaaditav 4K-täislahutusega WebM-video (2160P)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "Võrgus voogedastatav VP9-tüüpi WebM-video (360P)",
+ "timedmedia-derivative-desc-480p.vp9.webm": "Võrgus voogedastatav VP9-tüüpi WebM-video (480P)",
+ "timedmedia-derivative-desc-720p.vp9.webm": "Kõrglahutusega voogedastatav VP9-tüüpi WebM-video (720P)",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "Täiskõrglahutusega voogedastatav VP9-tüüpi WebM-video (1080P)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "Voogedastatav 4K-täislahutusega VP9-tüüpi WebM-video (2160P)",
+ "timedmedia-derivative-desc-320p.mp4": "Seadmetele sobiv MP4-video (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Võrgus voogedastatav MP4-video (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "Kõrglahutusega MP4-video (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Täiskõrglahutusega MP4-kvaliteetvideo (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "4K-täislahutusega MP4-kvaliteetvideo (2160P)",
+ "timedmedia-subtitle-new": "Uue tõlkega alustamine või olemasoleva muutmine",
+ "timedmedia-subtitle-new-desc": "Vali keel ja klõpsa nuppu '''{{int:Timedmedia-subtitle-new-go}}'''.",
+ "timedmedia-subtitle-new-go": "Mine",
+ "timedmedia-subtitle-language": "$1 ($2) alltiitrid",
+ "timedmedia-subtitle-no-video": "Puudub selle alltiitrite leheküljega seotud video.",
+ "timedmedia-subtitle-no-subtitles": "Selle video alltiitrid puuduvad praegu selles keeles ($1). Saad seda lehekülge [{{fullurl:{{FULLPAGENAME}}|action=edit}} redigeerida], et need lisada.",
+ "timedmedia-subtitle-remote": "Selle faili ajastatud tekst on hoidlas $1",
+ "timedmedia-subtitle-remote-link": "Selle faili [$1 kirjelduslehekülge] saad vaadata hoidlas $2.",
+ "timedmediahandler": "Ajastatud meediafailide töötleja",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video|$1 videot}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg-video|$1 Ogg-videot}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM-video|$1 WebM-videot}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|Üks ümberkodeering|$1 ümberkodeeringut}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|Üks|$1}} täitmisel {{PLURAL:$1|ümberkodeering|ümberkodeeringut}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|Üks|$1}} ootel {{PLURAL:$1|ümberkodeering|ümberkodeeringut}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|Üks|$1}} ebaõnnestunud {{PLURAL:$1|ümberkodeering|ümberkodeeringut}}",
+ "timedmedia-file": "Fail",
+ "timedmedia-audios": "{{PLURAL:$1|$1 helifail|$1 helifaili}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg-helifail|$1 Ogg-helifaili}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC-helifail|$1 FLAC-helifaili}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV-helifail|$1 WAV-helifaili}}",
+ "right-transcode-reset": "Lähtestada ebaõnnestunud või ümberkodeeritud videoid, nii et need lisatakse uuesti tööjärge",
+ "right-transcode-status": "Vaadata [[Special:TimedMediaHandler|teavet praegu aktiivsete ümberkodeeringute kohta]]",
+ "action-transcode-status": "vaadata praegust ümberkodeeringute olekut",
+ "orphanedtimedtext": "Ajastatud teksti orbleheküljed",
+ "orphanedtimedtext-summary": "Loend nimeruumi [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] lehekülgedest, millele vastav fail puudub.",
+ "orphanedtimedtext-unsupported": "Seda erilehekülge toetatakse ainult MySQL-andmebaasides.",
+ "orphanedtimedtext-notimedtext": "Ajastatud tekst pole selles vikis lubatud.",
+ "apihelp-query+transcodestatus-description": "Antud faili ümberkodeerimise oleku hankimine.",
+ "apihelp-query+transcodestatus-example-1": "Hangi faili [[:File:Clip.webm|Clip.webm]] ümberkodeerimise olek",
+ "apihelp-query+videoinfo-description": "Laiendab moodulit \"imageinfo\", kaasa arvatakse teave video allika (tuletiste) kohta.",
+ "apihelp-query+videoinfo-param-prop": "Millist teavet video kohta hankida:\n;timestamp: Lisab üles laaditud versiooni ajatempli.\n;user: Lisab kasutaja, kes videoversiooni üles laadis.\n;userid: Lisab videoversiooni üles laadinud kasutaja identifikaatori.\n;comment: Lisab versioonikommentaari.\n;parsedcomment: Parsib versioonikommentaari.\n;canonicaltitle: Lisab videofaili kanoonilise pealkirja.\n;url: Tagastab videofaili ja kirjelduslehekülje internetiaadressi.\n;size: Lisab video suuruse baitides ning selle kõrguse ja laiuse. Lehekülgede arv ja kestus lisatakse, kui see on kohane.\n;dimensions: Elemendi \"size\" rööpnimi.\n;sha1: Lisab video SHA-1 räsiväärtuse.\n;mime: Lisab video MIME tüübi.\n;thumbmime: Lisab video pisipildi MIME tüübi (vaja elementi \"url\" ja parameetrit \"$1urlwidth\").\n;mediatype: Lisab video meediatüübi.\n;metadata: Loetleb videoversiooni Exif-metaandmed.\n;commonmetadata: Loetleb videoversiooni failivormingu üldised metaandmed.\n;extmetadata: Loetleb mitme allika vormindatud ühendmetaandmed. Tulemused on HTML-vormingus.\n;archivename: Lisab praegusest versioonist vanemate arhiiviversioonide failinimed.\n;bitdepth: Lisab versiooni bitisügavuse.\n;uploadwarning: Kasutab lehekülg [[Special:Upload]], et saada teavet olemasoleva faili kohta. Pole mõeldud kasutamiseks väljaspool MediaWiki keskosa.\n;derivatives: Lisab heli- või videofaili erinevaid saadaolevaid vorminguid ja kvaliteediversioone sisaldava massiivi.",
+ "apihelp-query+videoinfo-example-1": "Faili [[:File:Folgers.ogv|Folgers.ogv]] teabe väljavõtt",
+ "apihelp-transcodereset-description": "Kasutajad, kellel on õigus \"transcode-reset\", saavad ümberkodeerimistööd lähtestada ja uuesti käitada.",
+ "apihelp-transcodereset-param-title": "Meediafaili pealkiri.",
+ "apihelp-transcodereset-param-transcodekey": "Lähtestatava ümberkodeerimise võti. Leitav päringuga [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Lähtesta kõik faili [[:File:Clip.webm|Clip.webm]] ümberkodeeringud",
+ "apihelp-transcodereset-example-2": "Lähtesta faili [[:File:Clip.webm|Clip.webm]] ümberkodeerimisvõti '360_560kbs.webm'"
+}
diff --git a/extensions/TimedMediaHandler/i18n/eu.json b/extensions/TimedMediaHandler/i18n/eu.json
new file mode 100644
index 00000000..fb5ff526
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/eu.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "An13sa",
+ "Joxemai",
+ "Theklan",
+ "පසිඳු කාවින්ද",
+ "Subi",
+ "Sator"
+ ]
+ },
+ "timedmedia-desc": "Ogg Theora eta Vorbis fitxategientzako edukiontzia, JavaScript playerrarekin",
+ "timedmedia-ogg-short-audio": "Ogg $1 soinu fitxategia, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 bideo fitxategia, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 media fitxategia, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 soinu fitxategia, $2 iraupea, $3",
+ "timedmedia-ogg-long-error": "ogg fitxategi okerra: $1",
+ "timedmedia-more": "Gehiago...",
+ "timedmedia-dismiss": "Itxi",
+ "timedmedia-download": "Fitxategia jaitsi",
+ "timedmedia-desc-link": "Fitxategi honen inguruan",
+ "timedmedia-status": "Egoera",
+ "timedmedia-transcodeinfo": "Formatua",
+ "timedmedia-direct-link": "Jaitsi",
+ "timedmedia-source-file": "$1 iturri",
+ "timedmedia-source-audio-file-desc": "Jatorrizko $1 fitxategia ($2)",
+ "timedmedia-subtitle-new-go": "Joan",
+ "timedmedia-file": "Fitxategia"
+}
diff --git a/extensions/TimedMediaHandler/i18n/fa.json b/extensions/TimedMediaHandler/i18n/fa.json
new file mode 100644
index 00000000..2a3a549c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/fa.json
@@ -0,0 +1,123 @@
+{
+ "@metadata": {
+ "authors": [
+ "Alireza",
+ "Armin1392",
+ "Calak",
+ "Ebraminio",
+ "Huji",
+ "Mahdiz",
+ "Mjbmr",
+ "Reza1615",
+ "جواد",
+ "پاناروما",
+ "Mehran"
+ ]
+ },
+ "extensionname-timedmedia": "هدایت‌کننده رسانهٔ زمان‌دار",
+ "timedmedia-desc": "به دست گیرندهٔ پرونده‌های صوتی، تصویری و متن‌های زمان‌بندی شده با پشتیبانی از Ogg Theora ،Vorbis و srt",
+ "timedmedia-ogg-short-audio": "پرونده صوتی Ogg $1، $2",
+ "timedmedia-ogg-short-video": "پرونده تصویری Ogg $1، $2",
+ "timedmedia-ogg-short-general": "پرونده Ogg $1، $2",
+ "timedmedia-ogg-long-audio": "پرونده صوتی Ogg $1، مدت $2، $3",
+ "timedmedia-ogg-long-video": "پرونده تصویری Ogg $1، مدت $2 ، $4×$5 پیکسل، $3",
+ "timedmedia-ogg-long-multiplexed": "پرونده صوتی/تصویری پیچیده Ogg، $1، مدت $2، $4×$5 پیکسل، $3 در مجموع",
+ "timedmedia-ogg-long-general": "پرونده Ogg، مدت $2، $3",
+ "timedmedia-ogg-long-error": "پروندهٔ Ogg نامجاز: $1",
+ "timedmedia-ogg-long-no-streams": "پروندهٔ رسانه‌ای Ogg. هشدار: هیچ‌یک از این کدک‌های استفاده‌شده در این پرونده‌ها شناخته‌شده نیستند.",
+ "timedmedia-webm-short-video": "رسانهٔ وب $1 پروندهٔ ویدئویی، $2",
+ "timedmedia-webm-long-video": "رسانهٔ وب پروندهٔ صوتی/تصویری، $1، مدت $2، $4 × $5 پیکسل، $3 کلی",
+ "timedmedia-flac-short-audio": "پروندهٔ صوتی اف‌ال‌ای‌سی، $1",
+ "timedmedia-flac-long-audio": "پروندهٔ صوتی اف‌ال‌ای‌سی، مدت $1، $2 کلی",
+ "timedmedia-wav-short-audio": "پروندهٔ صوتی WAV، $1",
+ "timedmedia-wav-long-audio": "پروندهٔ صوتی WAV، مدت $1، $2 کلی",
+ "timedmedia-wav-pcm-required": "شما فقط می توانید PCM و WAV را بار کنید.",
+ "timedmedia-mp4-short-video": "MP4 $1 پروندهٔ ویدئویی، $2",
+ "timedmedia-mp4-long-video": "پرونده‌های صوتی یا تصویری با قالب $1، زمان $2، $4 × $5 پیکسل و $3 به طورکلی",
+ "timedmedia-no-player-js": "با عرض پوزش، نرم افزار جاوا اسکریپت برروی مرورگر شما فعال نیست، و یا مرورگر شما از این نرم افزار پشتیبانی نمی کند.<br />\nشما میتوانید <a href=\"$1\">این ویدیو را دانلود</a> و یا <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">یک پخش کننده</a> برای اجرای این ویدیو دانلود نمایید.",
+ "timedmedia-more": "بیشتر...",
+ "timedmedia-dismiss": "بستن",
+ "timedmedia-download": "دریافت پرونده",
+ "timedmedia-play-media": "پخش رسانه",
+ "timedmedia-desc-link": "دربارهٔ این پرونده",
+ "timedmedia-oggThumb-version": "نگهدارندهٔ Ogg به بند‌انگشتی Ogg نسخهٔ $1 یا بالاتر نیاز دارد.",
+ "timedmedia-oggThumb-failed": "بندانگشتی Ogg در ساخت بندانگشتی با خطا مواجه شد.",
+ "timedmedia-status-header": "وضعیت فراکد",
+ "timedmedia-update-status": "وضعیت به‌روزرسانی فراکد",
+ "timedmedia-status": "وضعیت",
+ "timedmedia-status-unknown": "وضعیت ناشناخته",
+ "timedmedia-transcodeinfo": "توضیحات اشتقاقی فراکد",
+ "timedmedia-actions": "فعالیت‌ها",
+ "timedmedia-direct-link": "دریافت اشتقاقی",
+ "timedmedia-not-ready": "آماده نیست",
+ "timedmedia-completed-on": "تکمیل فراکد $1",
+ "timedmedia-error-on": "خطا در فراکد در $1",
+ "timedmedia-started-transcode": "فراکد $1 پیش آغاز شد. $2",
+ "timedmedia-percent-done": "حدود $1% انجام شده",
+ "timedmedia-in-job-queue": "اضافه‌شد به صف کار $1 پیش",
+ "timedmedia-unknown-target-size": "اندازهٔ هدف ناشناخته، $1 رمزی",
+ "timedmedia-days": "{{PLURAL:$1|1 روز|$1 روز}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 ساعت|$1 ساعت}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 دقیقه|$1 دقیقه}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 ثانیه|$1 ثانیه}}",
+ "timedmedia-reset": "تنظیم مجدد فراکد",
+ "timedmedia-reset-confirm": "تنظیم مجدد فراکد پرونده‌های موجود را حذف خواهد کرد و فراکد را در صف کار خواهد افزود. این کار مقداری زمان لازم دارد.<br /><br />\nآیا می‌خواهید ادامه دهید؟",
+ "timedmedia-reset-error": "خطا در بازنشانی کار فراکد.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 مبدأ",
+ "timedmedia-source-file-desc": "اصلی $1 پرونده، $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "اصلی $1 پرونده ( $2 )",
+ "timedmedia-derivative-desc-160p.ogv": "ویدئو Ogg با پهنای باند کم (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "ویدیوی آگ قابل بخش در وب (۲۴۰ نقطه)",
+ "timedmedia-derivative-desc-360p.ogv": "ویدئو Ogg با پهنای وب (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "ویدئو Ogg با پهنای وب (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "ویدئو Ogg قابل بارگیری با کیفیت بالا (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "ویدیوی آگ کاملاً اچ‌دی (۱۰۸۰ پیکسل)",
+ "timedmedia-derivative-desc-160p.webm": "رسانه وب با پهنای وب (160P)",
+ "timedmedia-derivative-desc-360p.webm": "رسانه وب با پهنای وب (360P)",
+ "timedmedia-derivative-desc-480p.webm": "رسانه وب با پهنای وب (480P)",
+ "timedmedia-derivative-desc-720p.webm": "رسانه وب قابل بارگیری با کیفیت بالا (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "ویدیوی وب‌ام کاملاً اچ‌دی (۱۰۸۰ پیکسل)",
+ "timedmedia-derivative-desc-320p.mp4": "ابزار سازگار با MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "پهنای وب MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "کیفیت بالا MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "ویدیوی ام‌پی۴ کاملاً اچ‌دی (۱۰۸۰ پیکسل)",
+ "timedmedia-subtitle-new": "ترجمه جدیدی را ایجاد کنید یا در صورت وجود آن را ویرایش کنید.",
+ "timedmedia-subtitle-new-desc": " زبان را انتخاب کنید و دکمهٔ '''{{int:Timedmedia-subtitle-new-go}}''' را بفشارید",
+ "timedmedia-subtitle-new-go": "برو",
+ "timedmedia-subtitle-language": "$1 ($2) زیرنویس‌ها",
+ "timedmedia-subtitle-no-video": "هیچ ویدئویی مرتبط با زیرعنوان این صفحه موجود نیست",
+ "timedmedia-subtitle-no-subtitles": "در حال حاضر زیرنویسی برای $1 در این ویدیو وجود ندارد، می‌توانید این صفحه را برای افزودن آن‌ها [{{fullurl:{{FULLPAGENAME}}|action=edit}} ویرایش کنید].",
+ "timedmedia-subtitle-remote": "متن زمان‌دار برای پرونده ذخیره شده در $1",
+ "timedmedia-subtitle-remote-link": "شما می توانید [$1 توضیحات صفحه مشاهده کنید] برای این پرونده در $2",
+ "timedmediahandler": "هدایت‌کننده رسانهٔ زمان‌دار",
+ "timedmedia-videos": "{{PLURAL:$1|$1 ویدئو|$1 ویدئو}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 ویدئو Ogg|$1 ویدئو Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 ویدئو WebM|$1 ویدئو WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 فراکدها|$1 فراکدها}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 درحال اجرای فراکدها|$1 در حال اجرای فراکدها}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 صف فراکدها|$1 صف فراکدها}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 فراکدهای اشتباه|$1 فراکدهای اشتباه}}",
+ "timedmedia-file": "پرونده",
+ "timedmedia-audios": "{{PLURAL:$1|$1 پوشهٔ صوتی|$1 پوشه‌های صوتی}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 پوشهٔ صوتی آگ|$1 پوشه‌های صوتی آگ}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1پوشه‌ٔ صوتی اف‌ال‌ای‌سی|$1پوشه‌های صوتی اف‌ال‌ای‌سی}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 پوشه‌ٔ صوتی دبلیو‌ای‌وی|$1 پوشه‌های صوتی دبلیو‌ای‌وی}}",
+ "right-transcode-reset": "تنظیم مجدد انجام‌نشده‌ها یا ویدئوهای فراکدشده اعمال شد. در نتیجه مجدداً آنها در صف کار قرار گرفتند.",
+ "right-transcode-status": "مشاهدهٔ [[Special:TimedMediaHandler|اطلاعات در مورد فعالیت فراکد]]",
+ "action-transcode-status": "نمایش وضعیت فراکدگذاری کنونی",
+ "orphanedtimedtext": "صفحه‌های TimedText یتیم",
+ "orphanedtimedtext-summary": "فهرست صفحه‌های [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] که دارای پروندهٔ متناظر نیستند.",
+ "orphanedtimedtext-unsupported": "این صفحهٔ خاص فقط در پایگاه داده‌های مای‌اس‌کیوال حمایت شده‌است.",
+ "orphanedtimedtext-notimedtext": "TimedText در این ویکی فعال نشده است.",
+ "apihelp-query+transcodestatus-description": "گرفتن وضعیت کذگذاری برای یک صفحه مشخص شده.",
+ "apihelp-query+transcodestatus-example-1": "گرفتن وضعیت کدگذاری [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "گسترش اطلاعات تصویری به شامل شدن اطلاعات منبع تصویر (اشتقاق‌شده‌ها)",
+ "apihelp-query+videoinfo-param-prop": "چه اطلاعاتی دریافت می‌شود:\n;timestamp:مهرزمانی به نسخهٔ بارگذاری شده می‌افزاید.\n;user:کاربری که تصویر را بارگذاری کرده را می‌افزاید.\n;userid:شناسهٔ کاربری که ویدیو را بارگذاری کرده است که نسخهٔ ویدیویی را بارگذاری کرده است می‌افزاید.\n;comment:توضیحات نسخه.\n;parsedcomment:تجزیه توضیحات نسخه.\n;canonicaltitle:عنوان متمرکز پرونده ویدیویی.\n;url:نشانی اینترنتی از ویدیوی و صفحهٔ توضیحات.\n;size:حجم ویدیو به بایت، طول و عرض آن را می‌افزاید. تعداد صفحه و طول اگر قابل اطلاق باشد.\n;dimensions:نام مستعار برای اندازه.\n;sha1:افزود SHA-1 hash برای ویدئو.\n;mime:افزود نوع MIME برای ویدئو.\n;thumbmime:افزود نوع MIME برای بندانگشتی ویدئو (نیازمند نشانی و متغییر $1urlwidth).\n;mediatype:نوع رسانهٔ ویدئو را افزود.\n;metadata:فراداده‌های Exif برای نسخهٔ ویدیو فهرست می‌کند.\n;commonmetadata:فراداده‌های عمومی برای نسخهٔ قالب پرونده ویدیو فهرست می‌کند.\n;extmetadata:فراداده‌های ترکیبی قالب‌دهی شده از چندین منبع را فهرست می‌کند. نتیجه اج‌تی‌ام‌ال قالب‌دهی شده است.\n;archivename:نام پرونده نسخهٔ بایگانی‌شده را برای نسخه‌های غیر آخرین می‌افزاید.\n;bitdepth:عمق بیتی نسخه را می‌افزاید.\n;uploadwarning:استفاده شده توسط صفحه [[Special:Upload]] برای دریافت اطلاعاتی از یک پرونده موجود. برای استفاده بیرون از هستهٔ‌ مدیاویکی نیست.\n;derivatives:آرایه‌ای از قالب‌ها و کیفیت نسخه‌های یک پرونده صدا یا تصویری که پرونده‌ای که موجود است می‌افزاید.",
+ "apihelp-query+videoinfo-example-1": "واکشی اطلاعاتی درباره [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "کاربرهیی که دسترسی 'transcode-reset' می‌توانند یک کار کدگذاری را از نو کنند.",
+ "apihelp-transcodereset-param-title": "عنوان پرونده.",
+ "apihelp-transcodereset-param-transcodekey": "کلید کدگذاری که می‌خواهید از نو شود. گرفتن از [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "از نو کردن کدگذاری‌ها برای [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "از نو کردن کلید کدگذاری '360_560kbs.webm' برای [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/fi.json b/extensions/TimedMediaHandler/i18n/fi.json
new file mode 100644
index 00000000..ef19cca9
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/fi.json
@@ -0,0 +1,78 @@
+{
+ "@metadata": {
+ "authors": [
+ "Agony",
+ "Beluga",
+ "Crt",
+ "Nike",
+ "Pxos",
+ "Str4nd",
+ "VezonThunder",
+ "Pitke"
+ ]
+ },
+ "timedmedia-desc": "Käsittelijä äänelle, videolle ja tekstitykselle. Tukee muotoja WebM, Ogg Theora, Vorbis ja srt.",
+ "timedmedia-ogg-short-audio": "Ogg $1 -äänitiedosto, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 -videotiedosto, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 -mediatiedosto, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 -äänitiedosto, $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 -videotiedosto, $2, $4×$5, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg-tiedosto limitetty kuva ja ääni, $1, $2, $4×$5, $3",
+ "timedmedia-ogg-long-general": "Ogg-tiedosto, $2, $3",
+ "timedmedia-ogg-long-error": "Kelvoton Ogg-tiedosto: $1",
+ "timedmedia-webm-short-video": "WebM $1 -videotiedosto, $2",
+ "timedmedia-webm-long-video": "WebM-ääni-/videotiedosto, $1, pituus $2, $4×$5 pikseliä, yhteensä $3",
+ "timedmedia-mp4-short-video": "MP4 $1 -videotiedosto, $2",
+ "timedmedia-mp4-long-video": "MP4-ääni-/videotiedosto, $1, pituus $2, $4×$5 pikseliä, yhteensä $3",
+ "timedmedia-no-player-js": "Valitettavasti selaimessasi on joko JavaScript pois päältä tai sille ei ole tuettua soitinta.<br />\nVoit <a href=\"$1\">ladata leikkeen</a> tai <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">ladata soittimen</a> toistaaksesi sen selaimessasi.",
+ "timedmedia-more": "Lisää…",
+ "timedmedia-dismiss": "Sulje",
+ "timedmedia-download": "Lataa",
+ "timedmedia-play-media": "Toista mediaa",
+ "timedmedia-desc-link": "Tiedoston tiedot",
+ "timedmedia-oggThumb-version": "OggHandler vaatii oggThumbin version $1 tai uudemman.",
+ "timedmedia-oggThumb-failed": "oggThumb epäonnistui pikkukuvan luomisessa.",
+ "timedmedia-status": "Tila",
+ "timedmedia-status-unknown": "Tuntematon tila",
+ "timedmedia-transcodeinfo": "Muoto",
+ "timedmedia-actions": "Toiminnot",
+ "timedmedia-direct-link": "Lataa",
+ "timedmedia-not-ready": "Ei valmis",
+ "timedmedia-completed-on": "Valmistui $1",
+ "timedmedia-started-transcode": "Alkoi $1 sitten. $2",
+ "timedmedia-percent-done": "Noin $1% valmiina",
+ "timedmedia-in-job-queue": "Lisättiin työjonoon $1 sitten",
+ "timedmedia-days": "{{PLURAL:$1|1 päivä|$1 päivää}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 tunti|$1 tuntia}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuutti|$1 minuuttia}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 sekunti|$1 sekuntia}}",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Lähde $1",
+ "timedmedia-source-file-desc": "Alkuperäinen $1-tiedosto, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Alkuperäinen $1-tiedosto ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Pienen kaistanleveyden Ogg-video (160p)",
+ "timedmedia-derivative-desc-240p.ogv": "Streamautuva Ogg-video (240p)",
+ "timedmedia-derivative-desc-360p.ogv": "verkossa suoratoistettavaa Ogg-videota (360p)",
+ "timedmedia-derivative-desc-480p.ogv": "Verkossa suoratoistettava Ogg-video (480p)",
+ "timedmedia-derivative-desc-720p.ogv": "Korkealaatuinen ladattava Ogg-video (720p)",
+ "timedmedia-derivative-desc-160p.webm": "Verkossa suoratoistettava WebM-video (160p)",
+ "timedmedia-derivative-desc-360p.webm": "Verkossa suoratoistettava WebM-video (360p)",
+ "timedmedia-derivative-desc-480p.webm": "Verkossa suoratoistettava WebM-video (480p)",
+ "timedmedia-derivative-desc-720p.webm": "Korkealaatuinen ladattava WebM-video (720p)",
+ "timedmedia-derivative-360p.vp9.webm": "VP9 360P",
+ "timedmedia-derivative-480p.vp9.webm": "VP9 480P",
+ "timedmedia-derivative-desc-320p.mp4": "Laiteystävällinen MP4 (320p)",
+ "timedmedia-derivative-desc-480p.mp4": "Verkossa suoratoistettava MP4 (480p)",
+ "timedmedia-derivative-desc-720p.mp4": "HD-laatuinen MP4 (720p)",
+ "timedmedia-subtitle-new": "Luo uusi käännös tai muokkaa aiempaa",
+ "timedmedia-subtitle-new-desc": "Valitse kieli ja napsauta '''{{int:Timedmedia-subtitle-new-go}}'''.",
+ "timedmedia-subtitle-new-go": "Siirry",
+ "timedmedia-subtitle-language": "$1 ($2) kuvatekstit",
+ "timedmedia-subtitle-no-video": "Tähän tekstityssivuun ei liity videota",
+ "timedmedia-subtitle-no-subtitles": "Tälle videolle ei tällä hetkellä ole tekstityksiä kielellä $1. Voit [{{fullurl:{{FULLPAGENAME}}|action=edit}} muokata tätä sivua] lisätäksesi ne.",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video|$1 videota}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg-video|$1 Ogg-videota}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM-video|$1 WebM-videota}}",
+ "timedmedia-file": "Tiedosto"
+}
diff --git a/extensions/TimedMediaHandler/i18n/fo.json b/extensions/TimedMediaHandler/i18n/fo.json
new file mode 100644
index 00000000..a96f3de3
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/fo.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Spacebirdy",
+ "EileenSanda"
+ ]
+ },
+ "timedmedia-no-player-js": "Halt okkum til góðar, tín brovsari hevur antin gjørt JavaScript óvirkið ella hevur ongan avspælara ið virkar her.<br />\nTú kanst <a href=\"$1\">taka klippið niður</a> ella <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">taka niður ein avspælara</a> sum kann spæla klippið í tínum internetkaga.",
+ "timedmedia-more": "Meira...",
+ "timedmedia-source-file": "$1 kelda",
+ "timedmedia-source-audio-file-desc": "Uppruna $1 fíla ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/fr.json b/extensions/TimedMediaHandler/i18n/fr.json
new file mode 100644
index 00000000..e252d5c4
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/fr.json
@@ -0,0 +1,150 @@
+{
+ "@metadata": {
+ "authors": [
+ "Boniface",
+ "Brunoperel",
+ "Crochet.david",
+ "Erkethan",
+ "Gomoko",
+ "Grondin",
+ "Hashar",
+ "Hello71",
+ "IAlex",
+ "Jean-Frédéric",
+ "McDutchie",
+ "Od1n",
+ "Peter17",
+ "Rzuwig",
+ "Seb35",
+ "Sherbrooke",
+ "Shirayuki",
+ "Urhixidur",
+ "Verdy p",
+ "Framafan",
+ "Wladek92"
+ ]
+ },
+ "timedmedia-desc": "Gestionnaire pour les vidéos, enregistrements sonores et textes synchronisés, avec le support des formats WebM, Ogg Theora, Vorbis et srt",
+ "timedmedia-ogg-short-audio": "Fichier son Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Fichier vidéo Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Fichier média Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Fichier son Ogg $1, durée $2, $3",
+ "timedmedia-ogg-long-video": "Fichier vidéo Ogg $1, durée $2, $4 × $5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "Fichier multiplexé audio/vidéo Ogg, $1, durée $2, $4&nbsp;×&nbsp;$5 pixels, $3 au total",
+ "timedmedia-ogg-long-general": "Fichier média Ogg, durée $2, $3",
+ "timedmedia-ogg-long-error": "Fichier Ogg invalide : $1",
+ "timedmedia-ogg-long-no-streams": "Fichier de média ogg. Attention : Aucun des codecs utilisés dans ce fichier n’est reconnu.",
+ "timedmedia-webm-short-video": "Fichier vidéo WebM $1, $2",
+ "timedmedia-webm-long-video": "Fichier audio/vidéo WebM, $1, longueur $2, $4 x $5 pixels, $3 l'ensemble",
+ "timedmedia-flac-short-audio": "Fichier audio FLAC, $1",
+ "timedmedia-flac-long-audio": "Fichier audio FLAC, durée $1, débit $2 sur l’ensemble",
+ "timedmedia-wav-short-audio": "Fichier audio WAV, $1",
+ "timedmedia-wav-long-audio": "Fichier audio WAV, durée $1, $2 sur l’ensemble",
+ "timedmedia-wav-pcm-required": "Vous ne pouvez télécharger que des WAV PCM (Modulation d’impulsion codée).",
+ "timedmedia-mp4-short-video": "Fichier vidéo MP4 $1, $2",
+ "timedmedia-mp4-long-video": "Fichier audio/vidéo MP4, $1, taille $2, $4 x $5 pixels, $3 au total",
+ "timedmedia-no-player-js": "Désolé, soit votre navigateur a JavaScript désactivé, soit il ne dispose d’aucun lecteur pris en charge.<br />\nVous pouvez <a href=\"$1\">télécharger le clip</a> ou <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">télécharger un lecteur</a> pour lire le clip dans votre navigateur.",
+ "timedmedia-more": "Plus…",
+ "timedmedia-dismiss": "Fermer",
+ "timedmedia-download": "Télécharger le fichier",
+ "timedmedia-play-media": "Lire le média",
+ "timedmedia-desc-link": "À propos de ce fichier",
+ "timedmedia-oggThumb-version": "OggHandler nécessite oggThumb, version $1 ou supérieure.",
+ "timedmedia-oggThumb-failed": "oggThumb n’a pas réussi à créer la miniature.",
+ "timedmedia-status-header": "Statut de transcodage",
+ "timedmedia-update-status": "Mettre à jour le statut de transcodage",
+ "timedmedia-status": "Statut",
+ "timedmedia-status-unknown": "État inconnu",
+ "timedmedia-transcodebitrate": "Débit en bits",
+ "timedmedia-transcodeduration": "Durée de l'encodage",
+ "timedmedia-transcodeinfo": "Transcode la description dérivée",
+ "timedmedia-actions": "Actions",
+ "timedmedia-direct-link": "Télécharger",
+ "timedmedia-not-ready": "Pas prêt",
+ "timedmedia-completed-on": "$1 terminé",
+ "timedmedia-error-on": "Erreur sur $1",
+ "timedmedia-started-transcode": "Démarré depuis $1. $2",
+ "timedmedia-percent-done": "Environ $1 % complété",
+ "timedmedia-in-job-queue": "Ajouté à la file d’attente des travaux il y a $1",
+ "timedmedia-unknown-target-size": "Taille de la cible inconnue, $1 encodé",
+ "timedmedia-days": "{{PLURAL:$1|1 jour|$1 jours}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 heure|$1 heures}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minute|$1 minutes}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 seconde|$1 secondes}}",
+ "timedmedia-reset": "Réinitialiser le transcodage",
+ "timedmedia-reset-confirm": "Remettre à zéro ce transcodage supprimera tout fichier existant (s’il y en a) et ajoutera de nouveau le transcodage à la file de travaux. Cela prendra un certain temps pour être transcodé de nouveau. <br /><br />\nÊtes-vous sûr de vouloir continuer ?",
+ "timedmedia-reset-error": "Erreur en réinitialisant le travail de transcodage.",
+ "timedmedia-ogg": "Ogg",
+ "timedmedia-webm": "WebM",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Source $1",
+ "timedmedia-source-file-desc": "Original fichier $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Fichier original $1 ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160p",
+ "timedmedia-derivative-desc-160p.ogv": "Vidéo Ogg bas débit (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "Vidéo Ogg en flux continu sur le web (240P)",
+ "timedmedia-derivative-360p.ogv": "Ogg 360p",
+ "timedmedia-derivative-desc-360p.ogv": "Vidéo Ogg lisible en continu sur le Web (360p)",
+ "timedmedia-derivative-480p.ogv": "Ogg 480p",
+ "timedmedia-derivative-desc-480p.ogv": "Vidéo Ogg lisible en continu sur le web (480p)",
+ "timedmedia-derivative-720p.ogv": "Ogg 720p",
+ "timedmedia-derivative-desc-720p.ogv": "Vidéo Ogg téléchargeable de grande qualité (720p)",
+ "timedmedia-derivative-desc-1080p.ogv": "Vidéo Ogg téléchargeable en HD total (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM lisible en continu depuis le web (160p)",
+ "timedmedia-derivative-360p.webm": "WebM 360p",
+ "timedmedia-derivative-desc-360p.webm": "WebM lisible en continu depuis le web (360p)",
+ "timedmedia-derivative-480p.webm": "WebM 480p",
+ "timedmedia-derivative-desc-480p.webm": "WebM lisible en continu depuis le web (480p)",
+ "timedmedia-derivative-720p.webm": "WebM 720p",
+ "timedmedia-derivative-desc-720p.webm": "Vidéo WebM téléchargeable de grande qualité (720p)",
+ "timedmedia-derivative-desc-1080p.webm": "WebM téléchargeable en HD total (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "WebM télécharheable en 4K total (2160P)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "WebM VP9 (360P) lisible en continu sur le web",
+ "timedmedia-derivative-desc-480p.vp9.webm": "WebM VP9 (480P) lisible en continu sur le web",
+ "timedmedia-derivative-desc-720p.vp9.webm": "WebM VP9 haute définition (720P) lisible en continu sur le web",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "WebM VP9 en haute définition totale (1080P) lisible en continu sur le web",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "WebM VP9 4K complet (2160P) lisible en continu sur le web",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 compatible matériel (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 pour flux web (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 qualité HD (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4 de qualité HD total (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "MP4 de qualité haute définition 4K",
+ "timedmedia-subtitle-new": "Créer une nouvelle traduction ou modifier une traduction existante",
+ "timedmedia-subtitle-new-desc": "Sélectionnez la langue et appuyez sur le bouton '''{{int:Timedmedia-subtitle-new-go}}'''.",
+ "timedmedia-subtitle-new-go": "Aller",
+ "timedmedia-subtitle-language": "sous-titres en $1 ($2)",
+ "timedmedia-subtitle-no-video": "Il n’y a aucune vidéo associée à la page actuelle de sous-titre",
+ "timedmedia-subtitle-no-subtitles": "Il n’y a actuellement aucun sous-titres en $1 pour cette vidéo, vous pouvez [{{fullurl: {{FULLPAGENAME}} | action=edit}} modifier cette page] pour les ajouter",
+ "timedmedia-subtitle-remote": "Le texte prévu pour ce fichier est hébergé sur $1",
+ "timedmedia-subtitle-remote-link": "Vous pouvez [$1 voir la page de description] de ce fichier sur $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 vidéo|$1 vidéos}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 vidéo Ogg|$1 vidéos Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 vidéo WebM|$1 vidéos WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcodage|$1 transcodages}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transcodage en cours|$1 transcodages en cours}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transcodage en file d'attente|$1 transcodages en file d'attente}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transcodage échoué|$1 transcodages échoués}}",
+ "timedmedia-file": "Fichier",
+ "timedmedia-audios": "{{PLURAL:$1|$1 fichier audio|$1 fichiers audio}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 fichier audio Ogg|$1 fichiers audio Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 fichier audio FLAC|$1 fichiers audio FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 fichier audio WAV|$1 fichiers audio WAV}}",
+ "right-transcode-reset": "Réinitialiser les vidéos en échec ou transcodées pour qu’elles soient de nouveau insérées dans la file des travaux",
+ "right-transcode-status": "Afficher [[Special:TimedMediaHandler|l'information sur l'activité de transcodage actuelle]]",
+ "action-transcode-status": "afficher l’état de transcodage actuel",
+ "orphanedtimedtext": "Pages orphelines de TimedText",
+ "orphanedtimedtext-summary": "Liste des pages [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] qui n’ont pas de fichier correspondant.",
+ "orphanedtimedtext-unsupported": "Cette page spéciale n’est supportée que sur les bases de données MySQL.",
+ "orphanedtimedtext-notimedtext": "TimedText n’est pas activé sur ce wiki.",
+ "apihelp-query+transcodestatus-description": "Obtenir l’état de transcodage pour une page de fichier donné.",
+ "apihelp-query+transcodestatus-example-1": "Obtenir l’état de transcodage pour [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "Étends imageinfo pour inclure les informations sur la source (et dérivées) vidéo",
+ "apihelp-query+videoinfo-param-prop": "Quelles informations obtenir sur la vidéo :\n;timestamp:Ajoute l’horodatage pour la version téléchargée.\n;user:Ajoute l’utilisateur qui a téléchargé la version de la vidéo.\n;userid:Ajouter l’ID de l’utilisateur qui a téléchargé la version de la vidéo.\n;comment:Commentaire sur la version.\n;parsedcomment:Analyser le commentaire sur la version.\n;canonicaltitle:Ajoute le titre canonique du fichier vidéo.\n;url:Fournit l’URL de la vidéo et la page de description.\n;size:Ajoute la taille de la vidéo en octets, sa hauteur et sa largeur. Le compteur de page et la durée sont ajoutés le cas échéant.\n;dimensions:Alias pour la taille.\n;sha1:Ajoute le hachage SHA-1 pour la vidéo.\n;mime:Ajoute le type MIME de la vidéo.\n;thumbmime:Ajoute le type MIME de la vignette de la vidéo (nécessite l’URL et le paramètre $1urlwidth).\n;mediatype:Ajoute le type de média de la vidéo.\n;metadata:Liste les métadonnées Exif pour la version de la vidéo.\n;commonmetadata:Liste les métadonnées génériques du format de fichier pour la version de la vidéo.\n;extmetadata:Liste les métadonnées mises en forme combinées depuis plusieurs sources. Les résultats sont au format HTML.\n;archivename:Ajoute le nom de fichier de la version d’archive pour les versions hors la dernière.\n;bitdepth:Ajoute la profondeur en bits de la version.\n;uploadwarning:Utilisé par la page [[Special:Upload]] pour obtenir des informations sur un fichier existant. Non prévu pour être utilisé hors du cœur de MédiaWiki.\n;derivatives:Ajoute un tableau des différentes versions de format et de qualité d’un fichier audio ou vidéo disponibles.",
+ "apihelp-query+videoinfo-example-1": "Récupérer des informations sur [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "Les utilisateurs avec le droit 'transcode-reset' peuvent réinitialiser et relancer une tâche de transcodage.",
+ "apihelp-transcodereset-param-title": "Le titre du fichier média.",
+ "apihelp-transcodereset-param-transcodekey": "La clé du transcodage que vous voulez réinitialiser. Récupéré depuis [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Réinitialiser tous les codes de transcodage de [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "Réinitialiser la clé de transcodage '360_560kbs.webm' pour [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/frp.json b/extensions/TimedMediaHandler/i18n/frp.json
new file mode 100644
index 00000000..ecf9cbc8
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/frp.json
@@ -0,0 +1,38 @@
+{
+ "@metadata": {
+ "authors": [
+ "ChrisPtDe"
+ ]
+ },
+ "timedmedia-desc": "Assistance por los fichiérs mèdia que dèfilont (ôdiô, vidèô et tèxto sincronisâ) avouéc transcodâjo en WebM, Ogg Theora, Vorbis et srt.",
+ "timedmedia-ogg-short-audio": "Fichiér son Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Fichiér vidèô Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Fichiér mèdia Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Fichiér son Ogg $1, temps $2, $3",
+ "timedmedia-ogg-long-video": "Fichiér vidèô Ogg $1, temps $2, $4×$5 pixèls, $3",
+ "timedmedia-ogg-long-multiplexed": "Fichiér multiplèxo ôdiô / vidèô Ogg, $1, temps $2, $4×$5 pixèls, $3",
+ "timedmedia-ogg-long-general": "Fichiér mèdia Ogg, temps $2, $3",
+ "timedmedia-ogg-long-error": "Fichiér Ogg envalido : $1",
+ "timedmedia-webm-short-video": "Fichiér vidèô WebM $1, $2",
+ "timedmedia-webm-long-video": "Fichiér ôdiô / vidèô WebM, $1, longior $2, $4 x $5 pixèls, en tot $3",
+ "timedmedia-more": "De ples...",
+ "timedmedia-dismiss": "Cllôre",
+ "timedmedia-download": "Tèlèchargiér lo fichiér",
+ "timedmedia-play-media": "Liére lo mèdia",
+ "timedmedia-desc-link": "Sur ceti fichiér",
+ "timedmedia-oggThumb-version": "OggHandler at fôta d’oggThumb, vèrsion $1 ou ben ples novèla.",
+ "timedmedia-oggThumb-failed": "oggThumb at pas reussi a fâre la figura.",
+ "timedmedia-status": "statut",
+ "timedmedia-status-unknown": "statut encognu",
+ "timedmedia-actions": "Accions",
+ "timedmedia-not-ready": "Pas prèst",
+ "timedmedia-percent-done": "A pou prés $1 % complètâ",
+ "timedmedia-days": "$1 jorn{{PLURAL:$1||s}}",
+ "timedmedia-hours": "$1 hor{{PLURAL:$1|a|es}}",
+ "timedmedia-minutes": "$1 menut{{PLURAL:$1|a|es}}",
+ "timedmedia-seconds": "$1 second{{PLURAL:$1|a|es}}",
+ "timedmedia-source-file": "Sôrsa $1",
+ "timedmedia-source-file-desc": "Originâl $1, $2 × $3 ($4)",
+ "timedmedia-subtitle-language": "sot-titros en $1 ($2)",
+ "timedmedia-file": "Fichiér"
+}
diff --git a/extensions/TimedMediaHandler/i18n/frr.json b/extensions/TimedMediaHandler/i18n/frr.json
new file mode 100644
index 00000000..8a1f77a8
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/frr.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Murma174"
+ ]
+ },
+ "timedmedia-no-player-js": "Bi dan browser as det brüken faan JavaScript deaktiwiaret wurden of hi koon det ianfach ei ufspele.<br />\nDü könst <a href=\"$1\">det video deelloose</a> of <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">en software deelloose</a>, am det video uun dan browser uftuspelin.",
+ "timedmedia-source-file": "$1-kwel",
+ "timedmedia-source-audio-file-desc": "Originaal $1-datei ($2)",
+ "timedmediahandler": "Timed Media Handler"
+}
diff --git a/extensions/TimedMediaHandler/i18n/fur.json b/extensions/TimedMediaHandler/i18n/fur.json
new file mode 100644
index 00000000..b80405f4
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/fur.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Klenje"
+ ]
+ },
+ "timedmedia-desc": "Gjestôr pai files audio, video e di test cul timp, cun supuart pai formâts WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "File audio Ogg $1, $2",
+ "timedmedia-ogg-short-video": "File video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "File multimediâl Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "File audio Ogg $1, durade $2, $3",
+ "timedmedia-ogg-long-video": "File video Ogg $1, durade $2, dimensions $4×$5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "File audio/video multiplexed Ogg $1, lungjece $2, dimensions $4×$5 pixels, in dut $3",
+ "timedmedia-ogg-long-general": "File multimediâl Ogg, durade $2, $3",
+ "timedmedia-ogg-long-error": "File ogg no valit: $1",
+ "timedmedia-webm-short-video": "File video WebM $1, $2",
+ "timedmedia-more": "Altri...",
+ "timedmedia-dismiss": "Siere",
+ "timedmedia-download": "Discjame il file",
+ "timedmedia-desc-link": "Informazions su chest file",
+ "timedmedia-status": "Stât",
+ "timedmedia-actions": "Azions"
+}
diff --git a/extensions/TimedMediaHandler/i18n/fy.json b/extensions/TimedMediaHandler/i18n/fy.json
new file mode 100644
index 00000000..747f3b0b
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/fy.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robin0van0der0vliet"
+ ]
+ },
+ "timedmedia-more": "Mear…",
+ "timedmedia-dismiss": "Slute",
+ "timedmedia-days": "{{PLURAL:$1|1 dei|$1 dagen}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 oere|$1 oere}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minút|$1 minuten}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 sekonde|$1 sekonden}}",
+ "timedmedia-source-file": "$1 boarne",
+ "timedmedia-source-audio-file-desc": "Orizjineel $1-triem ($2)",
+ "timedmedia-file": "Triem"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ga.json b/extensions/TimedMediaHandler/i18n/ga.json
new file mode 100644
index 00000000..d59b6164
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ga.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Spacebirdy",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "timedmedia-more": "Níos mó...",
+ "timedmedia-dismiss": "Dún",
+ "timedmedia-actions": "Gníomhartha",
+ "timedmedia-subtitle-new-go": "Gabh",
+ "timedmedia-file": "Comhad"
+}
diff --git a/extensions/TimedMediaHandler/i18n/gl.json b/extensions/TimedMediaHandler/i18n/gl.json
new file mode 100644
index 00000000..8c40d72d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/gl.json
@@ -0,0 +1,125 @@
+{
+ "@metadata": {
+ "authors": [
+ "Toliño",
+ "Xosé",
+ "Banjo",
+ "Elisardojm"
+ ]
+ },
+ "timedmedia-desc": "Manipulador de son, vídeo e texto sincronizado, con soporte para os formatos WebM, Ogg Theora, Vorbis e srt",
+ "timedmedia-ogg-short-audio": "Ficheiro de son Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Ficheiro de vídeo Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Ficheiro multimedia Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Ficheiro de son Ogg $1, duración $2, $3",
+ "timedmedia-ogg-long-video": "Ficheiro de vídeo Ogg $1, duración $2, $4×$5 píxeles, $3",
+ "timedmedia-ogg-long-multiplexed": "Ficheiro de son/vídeo Ogg multiplex, $1, duración $2, $4×$5 píxeles, $3 total",
+ "timedmedia-ogg-long-general": "Ficheiro multimedia Ogg, duración $2, $3",
+ "timedmedia-ogg-long-error": "Ficheiro Ogg non válido: $1",
+ "timedmedia-ogg-long-no-streams": "Ficheiro multimedia Ogg. Atención: Non se recoñece ningún dos codecs usados neste ficheiro.",
+ "timedmedia-webm-short-video": "Ficheiro de vídeo WebM $1, $2",
+ "timedmedia-webm-long-video": "Ficheiro WebM de son/vídeo, $1, duración $2, $4×$5 píxeles, $3 total",
+ "timedmedia-flac-short-audio": "Ficheiro de son FLAC, $1",
+ "timedmedia-flac-long-audio": "Ficheiro de son FLAC, duración $1, $2 total",
+ "timedmedia-wav-short-audio": "Ficheiro de son WAV, $1",
+ "timedmedia-wav-long-audio": "Ficheiro de son WAV, duración $1, $2 total",
+ "timedmedia-wav-pcm-required": "Unicamente pode cargar WAV PCM (modulación por código de pulsos).",
+ "timedmedia-mp4-short-video": "Ficheiro de vídeo MP4 $1, $2",
+ "timedmedia-mp4-long-video": "Ficheiro MP4 de son/vídeo, $1, duración $2, $4×$5 píxeles, $3 total",
+ "timedmedia-no-player-js": "Sentímolo, o seu navegador ten o JavaScript desactivado ou non conta con ningún reprodutor dos soportados.<br />\nPode <a href=\"$1\">descargar o vídeo</a> ou <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">descargar un reprodutor</a> para reproducir o vídeo no seu navegador.",
+ "timedmedia-more": "Máis...",
+ "timedmedia-dismiss": "Pechar",
+ "timedmedia-download": "Descargar o ficheiro",
+ "timedmedia-play-media": "Reproducir o contido",
+ "timedmedia-desc-link": "Acerca deste ficheiro",
+ "timedmedia-oggThumb-version": "O OggHandler necesita a versión $1 ou unha posterior do oggThumb.",
+ "timedmedia-oggThumb-failed": "Houbo un erro por parte do oggThumb ao crear a miniatura.",
+ "timedmedia-status-header": "Estado da transcodificación",
+ "timedmedia-update-status": "Actualizar o estado de transcodificación",
+ "timedmedia-status": "Estado",
+ "timedmedia-status-unknown": "Estado descoñecido",
+ "timedmedia-transcodebitrate": "Taxa de transferencia",
+ "timedmedia-transcodeduration": "Tempo de codificación",
+ "timedmedia-transcodeinfo": "Formato",
+ "timedmedia-actions": "Accións",
+ "timedmedia-direct-link": "Descargar",
+ "timedmedia-not-ready": "Aínda non está preparado",
+ "timedmedia-completed-on": "Completado o $1",
+ "timedmedia-error-on": "Erro en $1",
+ "timedmedia-started-transcode": "Comezou hai $1. $2",
+ "timedmedia-percent-done": "Preto do $1% feito",
+ "timedmedia-in-job-queue": "Engadido á cola de traballos hai $1",
+ "timedmedia-unknown-target-size": "Tamaño de destino descoñecido; $1 codificados",
+ "timedmedia-days": "{{PLURAL:$1|1 día|$1 días}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 hora|$1 horas}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuto|$1 minutos}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 segundo|$1 segundos}}",
+ "timedmedia-reset": "Restablecer a transcodificación",
+ "timedmedia-reset-confirm": "Ao restablecer a transcodificación eliminarase calquera ficheiro existente e volverá engadir a transcodificación á cola de traballos. A nova transcodificación levará bastante tempo.<br /><br />\nEstá seguro de querer continuar?",
+ "timedmedia-reset-error": "Erro no restablecemento do traballo de transcodificación.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Fonte $1",
+ "timedmedia-source-file-desc": "Ficheiro $1 orixinal, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Ficheiro $1 orixinal ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160P",
+ "timedmedia-derivative-desc-160p.ogv": "Vídeo Ogg de baixo ancho de banda (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "Vídeo Ogg para a web (240P)",
+ "timedmedia-derivative-desc-360p.ogv": "Vídeo Ogg para a web (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Vídeo Ogg para a web (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Vídeo Ogg de alta calidade que se pode descargar (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Vídeo Ogg descargable en Full HD (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM para a web (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM para a web (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM para a web (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM de alta calidade que se pode descargar (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "WebM descargable en Full HD (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "WebM descargable en 4K (2160P)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "WebM VP9 (360P) visualizable na rede",
+ "timedmedia-derivative-desc-480p.vp9.webm": "WebM VP9 (480P) visualizable na rede",
+ "timedmedia-derivative-desc-720p.vp9.webm": "WebM VP9 de alta definición (720P) visualizable na rede",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "WebM VP9 de alta definición total (1080P) visualizable na rede",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "WebM VP9 4K completa (2160P) visualizable na rede",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 compatible con dispositivos móbiles (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 para a web (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 de calidade HD (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4 de calidade Full HD (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "MP4 de calidade de alta definición 4K",
+ "timedmedia-subtitle-new": "Crear unha nova tradución ou editar a actual",
+ "timedmedia-subtitle-new-desc": "Seleccione a lingua e prema no botón \"'''{{int:Timedmedia-subtitle-new-go}}'''\"",
+ "timedmedia-subtitle-new-go": "Continuar",
+ "timedmedia-subtitle-language": "Subtítulos en $1 ($2)",
+ "timedmedia-subtitle-no-video": "Non hai ningún vídeo asociado coa páxina de subtítulos actual",
+ "timedmedia-subtitle-no-subtitles": "Actualmente non hai subtítulos en $1 para este vídeo; pode [{{fullurl:{{FULLPAGENAME}}|action=edit}} editar esta páxina] para engadilos",
+ "timedmedia-subtitle-remote": "Os subtítulos deste ficheiro están aloxados en $1",
+ "timedmedia-subtitle-remote-link": "Pode [$1 ollar a páxina de descrición] deste ficheiro en $2",
+ "timedmediahandler": "Extensión TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 vídeo|$1 vídeos}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 vídeo Ogg|$1 vídeos Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 vídeo WebM|$1 vídeos WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcodificación|$1 transcodificacións}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transcodificación activa|$1 transcodificacións activas}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transcodificación|$1 transcodificacións}} na cola",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transcodificación fallida|$1 transcodificacións fallidas}}",
+ "timedmedia-file": "Ficheiro",
+ "timedmedia-audios": "{{PLURAL:$1|$1 ficheiro|$1 ficheiros}} de son",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 ficheiro|$1 ficheiros}} de son Ogg",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 ficheiro|$1 ficheiros}} de son FLAC",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 ficheiro|$1 ficheiros}} de son WAV",
+ "right-transcode-reset": "Restablecer os vídeos transcodificados erroneamente para incluílos de novo na cola de traballo.",
+ "right-transcode-status": "Ollar a [[Special:TimedMediaHandler|información sobre a actividade de transcodificación actual]]",
+ "action-transcode-status": "ollar o estado da transcodificación actual",
+ "orphanedtimedtext": "Páxinas orfas de TimedText",
+ "orphanedtimedtext-summary": "Lista de páxinas [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] que non teñen un ficheiro correspondente.",
+ "orphanedtimedtext-unsupported": "Esta páxina especial só está soportada en bases de datos MySQL.",
+ "orphanedtimedtext-notimedtext": "TimedText non se activou nesta wiki.",
+ "apihelp-query+transcodestatus-description": "Obter o estado de transcode para unha páxina de ficheiro dado.",
+ "apihelp-query+transcodestatus-example-1": "Obter o estado transcode para [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "Estende a información da imaxe para incluír a información da fonte de vídeo (derivado)",
+ "apihelp-query+videoinfo-param-prop": "Que información de vídeo obter:\n;timestamp:Engade o selo de tempo da versión subida.\n;user:Engade o usuario que subiu a versión de vídeo.\n;userid:Engade o identificador de usuario que subiu a versión de vídeo.\n;comment:Comentario da versión.\n;parsedcomment:Comentario analizado na versión.\n;canonicaltitle:Engade o título canónico do ficheiro de vídeo.\n;url:Devolve a URL ó vídeo e a páxina de descrición.\n;size:Engade o tamaño do vídeo en bytes, a súa altura e anchura. O contador de páxina e duración tamén se engaden se é aplicable.\n;dimensions:Alias para \"size\".\n;sha1:Engade a función hash SHA-1 do vídeo.\n;mime:Engade o tipo MIME do vídeo.\n;thumbmime:Engade o tipo MIME da miniatura do vídeo (requie url e parámetro $1urlwidth).\n;mediatype:Engade o tipo de medio multimedia do vídeo.\n;metadata:Lista os metadatos Exif da versión do vídeo.\n;commonmetadata:Lista os metadatos formateados combinados desde varias fontes. Os resultados están formateados en HTML.\n;archivename:Engade o nome de ficheiro da versión para versións anteriores á última.\n;bitdepth:Engade a profundidade de bit da versión.\n;uploadwarning:Usado pola páxina [[Special:Upload]] para obter información sobre un ficheiro xa existente. Non previsto para usar fóra do núcleo MediaWiki.\n;derivatives:Engade unha matriz dos diferentes formatos e calidades dispoñibles dun audio ou vídeo.",
+ "apihelp-query+videoinfo-example-1": "Buscar información sobre [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "Usuarios co permiso 'transcode-reset' poden reiniciar e reexecutar un traballo transcode.",
+ "apihelp-transcodereset-param-title": "Título do ficheiro multimedia.",
+ "apihelp-transcodereset-param-transcodekey": "A chave transcode que quere resetear. Collida de [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Resetear todos os transcodes para [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "Resetear a clave transcode '360_560kbs.webm' de [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/gom-deva.json b/extensions/TimedMediaHandler/i18n/gom-deva.json
new file mode 100644
index 00000000..f72dab88
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/gom-deva.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Darshan kandolkar",
+ "Supriya kankumbikar",
+ "Vaishali Parab"
+ ]
+ },
+ "timedmedia-no-player-js": "माफ करचें, तुमच्या ब्रावजरांत एक तर जावास्क्रिप्ट दुबळें आसा वा समर्थीत प्लेयर ना।<br />\nतुमी <a href=\"$1\">क्लीप डाउनलोड</a> करुं शकतात वा क्लीप तुमच्या ब्रावजरान चलोवपाक <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">एक प्लेयर डाउनलोड</a> करुं शकतात.",
+ "timedmedia-source-file": "$1 उगम",
+ "timedmedia-source-audio-file-desc": "मूळ $1 फायल ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/gom-latn.json b/extensions/TimedMediaHandler/i18n/gom-latn.json
new file mode 100644
index 00000000..1bffb01a
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/gom-latn.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "The Discoverer"
+ ]
+ },
+ "timedmedia-no-player-js": "Maf korchem, tujea browserant ek tor JavaScript dublem asa vo somorthit player nam.<br />\nTum <a href=\"$1\">clipik download</a> korunk shoktai vo clip tujea browseran cholovpak <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">ek playerak download</a> korunk shoktai.",
+ "timedmedia-source-file": "$1 strot",
+ "timedmedia-source-file-desc": "Mul $1 fail, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Mul $1 fail ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/grc.json b/extensions/TimedMediaHandler/i18n/grc.json
new file mode 100644
index 00000000..ce201686
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/grc.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Crazymadlover",
+ "Flyax",
+ "Omnipaedista"
+ ]
+ },
+ "timedmedia-ogg-long-error": "Ἄκυρα ἀρχεῖα ogg: $1",
+ "timedmedia-more": "πλέον...",
+ "timedmedia-dismiss": "Κλῄειν",
+ "timedmedia-source-file": "$1 Πηγή"
+}
diff --git a/extensions/TimedMediaHandler/i18n/gsw.json b/extensions/TimedMediaHandler/i18n/gsw.json
new file mode 100644
index 00000000..fb38ce89
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/gsw.json
@@ -0,0 +1,62 @@
+{
+ "@metadata": {
+ "authors": [
+ "Als-Chlämens",
+ "Als-Holder",
+ "Melancholie"
+ ]
+ },
+ "timedmedia-desc": "Stellt e Styyrigsprogramm fir zytgstyyrti Medie (Video, Audio, timedText) zur Verfiegig, wo d Format WebM, Ogg Theora, Ogg Vorbis un SubRip unterstützt",
+ "timedmedia-ogg-short-audio": "Ogg-$1-Audiodatei, $2",
+ "timedmedia-ogg-short-video": "Ogg-$1-Videodatei, $2",
+ "timedmedia-ogg-short-general": "Ogg-$1-Mediadatei, $2",
+ "timedmedia-ogg-long-audio": "Ogg-$1-Audiodatei, Längi: $2, $3",
+ "timedmedia-ogg-long-video": "Ogg-$1-Videodatei, Längi: $2, $4×$5 Pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg-Audio-/Video-Datei, $1, Längi: $2, $4×$5 Pixel, $3",
+ "timedmedia-ogg-long-general": "Ogg-Mediadatei, Längi: $2, $3",
+ "timedmedia-ogg-long-error": "Uugiltigi Ogg-Datei: $1",
+ "timedmedia-webm-short-video": "WebM-$1-Videodatei, $2",
+ "timedmedia-webm-long-video": "WebM-Audio-/Video-Datei, $1, Längei: $2, $4×$5 Pixel, $3 insgsamt",
+ "timedmedia-no-player-js": "Excusez, aber Dyy Browser het entwäder JavaScript deaktiviert oder kei unterstitzti Abspilsoftware.<br />\nDu chasch <a href=\"$1\">dr Clip abelade</a> oder <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">e Abspielsoftware abelade</a> go dr Clip im Browser abspile.",
+ "timedmedia-more": "Meh …",
+ "timedmedia-dismiss": "Zuemache",
+ "timedmedia-download": "Datei spychere",
+ "timedmedia-play-media": "Mediedatei abspiile",
+ "timedmedia-desc-link": "Iber die Datei",
+ "timedmedia-oggThumb-version": "OggHandler brucht oggThumb in dr Version $1 oder hecher.",
+ "timedmedia-oggThumb-failed": "oggThumb het kei Miniaturbild chenne aalege.",
+ "timedmedia-status-header": "Umschlüsseligsstatus",
+ "timedmedia-update-status": "Umschlüsseligsstatus aktualisiere",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Status nit bekannt",
+ "timedmedia-transcodeinfo": "Abgleiteti Beschryybig umschlüssle",
+ "timedmedia-actions": "Aktione",
+ "timedmedia-direct-link": "Ableitig abelade",
+ "timedmedia-not-ready": "Nit parat",
+ "timedmedia-completed-on": "Umschlüsselig vo $1 abgschlosse",
+ "timedmedia-error-on": "Fääler bim Umschlüssle in $1.",
+ "timedmedia-started-transcode": "Umschlüsselig het vor $1 aagfange. $2",
+ "timedmedia-percent-done": "Öbe $1 % fertig",
+ "timedmedia-in-job-queue": "Vor $1 zur Ufftragswarteschlange dezuegfiegt worde",
+ "timedmedia-unknown-target-size": "Unbekannti Ziilgrößi, $1 codiert",
+ "timedmedia-days": "{{PLURAL:$1|1 Tag|$1 Täg}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 Stund|$1 Stunde}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 Minut|$1 Minute}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 Sekund|$1 Sekunde}}",
+ "timedmedia-reset": "Umschlüsselig zruggsetze",
+ "timedmedia-reset-confirm": "S Zruggsetze vo dere Umschlüsselig wird (wänn's vorhande isch), die aktuelli Datei ussenee un d Umschlüsselig no emool uff d Ufftragswarteschlange dezuefiege. E nöii Umschlüsselig wird e Wyyl goo.<br /><br /> Söll des würkli gmacht werde?",
+ "timedmedia-reset-error": "Fääler bim Zruggsetze vo de Umschlüsselig.",
+ "timedmedia-source-file": "Quell ($1)",
+ "timedmedia-source-file-desc": "Original $1, $2 x $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Urspringligi $1-Datei ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg-Videodatei mit niidriger Dateübertragigsrate (160p)",
+ "timedmedia-derivative-desc-360p.ogv": "Webstreamingfähigi Ogg-Videodatei (360p)",
+ "timedmedia-derivative-desc-480p.ogv": "Webstreamingfähigi Ogg-Videodatei (480p)",
+ "timedmedia-derivative-desc-720p.ogv": "Qualitativ hochwertigi Ogg-Videodatei (720p)",
+ "timedmedia-derivative-desc-360p.webm": "Webstreamingfähigi WebM-Videodatei (360p)",
+ "timedmedia-derivative-desc-480p.webm": "Webstreamingfähigi WebM-Videodatei (480p)",
+ "timedmedia-derivative-desc-720p.webm": "Qualitativ hochwertigi WebM-Videodatei (720p)",
+ "timedmedia-subtitle-language": "$1 ($2) Untertitel",
+ "timedmedia-subtitle-no-video": "Dere Untertitel-Syte isch kei Video zuegordnet.",
+ "timedmedia-subtitle-no-subtitles": "Es git uff $1 zurzit kei Untertitel für des Video. Bim dezuefiege vo Untertitel cha [{{fullurl:{{FULLPAGENAME}}|action=edit}} die Syte] bearbeitet werde."
+}
diff --git a/extensions/TimedMediaHandler/i18n/gu.json b/extensions/TimedMediaHandler/i18n/gu.json
new file mode 100644
index 00000000..7c73dd97
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/gu.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "KartikMistry",
+ "Arbhatt",
+ "Dsvyas",
+ "NehalDaveND",
+ "Ashok modhvadia"
+ ]
+ },
+ "timedmedia-no-player-js": "માફ કરશો, તમારા બ્રાઉઝરમાં જાવાસ્ક્રિપ્ટ સક્રિય નથી અથવા તો સપોર્ટેડ પ્લેયર નથી.<br />\nતમે <a href=\"$1\">ક્લિપ ડાઉનલોડ</a> કરી શકો છો અથવા આ ક્લિપને તમારા બ્રાઉઝરમાં ચલાવવા માટે <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">એક પ્લેયર ડાઉનલોડ</a> કરી શકો છો.",
+ "timedmedia-more": "વધુ...",
+ "timedmedia-dismiss": "બંધ કરો",
+ "timedmedia-download": "ફાઈલ ડાઉનલોડ કરો",
+ "timedmedia-status": "સ્થિતિ",
+ "timedmedia-status-unknown": "અજ્ઞાત સ્થિતિ",
+ "timedmedia-actions": "ક્રિયાઓ",
+ "timedmedia-not-ready": "તૈયાર નથી",
+ "timedmedia-source-file": "$1 સ્રોત",
+ "timedmedia-source-audio-file-desc": "મુળ આવૃત્તિ $1 ફાઇલ ($2)",
+ "timedmedia-subtitle-new-go": "જાઓ",
+ "timedmedia-file": "ફાઇલ"
+}
diff --git a/extensions/TimedMediaHandler/i18n/gv.json b/extensions/TimedMediaHandler/i18n/gv.json
new file mode 100644
index 00000000..66353585
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/gv.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "MacTire02"
+ ]
+ },
+ "timedmedia-desc-link": "Mychione y choadan shoh"
+}
diff --git a/extensions/TimedMediaHandler/i18n/he.json b/extensions/TimedMediaHandler/i18n/he.json
new file mode 100644
index 00000000..29cddf15
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/he.json
@@ -0,0 +1,125 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amire80",
+ "Guycn2",
+ "Rotem Liss",
+ "Rotemliss",
+ "YaronSh"
+ ]
+ },
+ "timedmedia-desc": "מטפל במדיה מתוזמנת – וידאו, שמע, טקסט מתוזמן – עם תמיכה בתסדירי WebM&rlm;, Ogg Theora&rlm;, Vorbis ו־srt",
+ "timedmedia-ogg-short-audio": "קובץ שמע $1 של Ogg, $2",
+ "timedmedia-ogg-short-video": "קובץ וידאו $1 של Ogg, $2",
+ "timedmedia-ogg-short-general": "קובץ מדיה $1 של Ogg, $2",
+ "timedmedia-ogg-long-audio": "קובץ שמע $1 של Ogg, באורך $2, $3",
+ "timedmedia-ogg-long-video": "קובץ וידאו $1 של Ogg, באורך $2, $4×$5 פיקסלים, $3",
+ "timedmedia-ogg-long-multiplexed": "קובץ Ogg מרובב של שמע ווידאו, $1, באורך $2, $4×$5 פיקסלים, $3 בסך הכול",
+ "timedmedia-ogg-long-general": "קובץ מדיה של Ogg, באורך $2, $3",
+ "timedmedia-ogg-long-error": "קובץ ogg בלתי תקין: $1",
+ "timedmedia-ogg-long-no-streams": "קובץ מדיה Ogg. אזהרה: אף אחד מהקודקים בקובץ הזה אינו מוּכּר.",
+ "timedmedia-webm-short-video": "קובץ וידאו WebM $1&rlm;, $2",
+ "timedmedia-webm-long-video": "קובץ שמע ווידאו WebM&rlm;, $1, באורך $2&rlm;, $4 × $5 פיקסלים, $3 סך הכול",
+ "timedmedia-flac-short-audio": "קובץ שמע FLAC‏, $1",
+ "timedmedia-flac-long-audio": "קובץ שמע FLAC‏, אורך $1, סך הכול $2",
+ "timedmedia-wav-short-audio": "קובץ שמע WAV‏, $1",
+ "timedmedia-wav-long-audio": "קובץ שמע WAV, אורך $1, סך הכול $2",
+ "timedmedia-wav-pcm-required": "אפשר להעלות רק קובצי WAV בתסדיר PCM‏ (Pulse Code Modulation).",
+ "timedmedia-mp4-short-video": "קובץ וידאו MP4 $1&rlm;, $2",
+ "timedmedia-mp4-long-video": "קובץ שמע ווידאו של MP4&rlm;, $1, באורך $2, $4 × $5 פיסקלים, $3 בסך הכול",
+ "timedmedia-no-player-js": "מצטערים, בדפדפן שלך לא מופעלת תמיכה ב־JavaScript או שאין בו נגן נתמך.<br />\nבאפשרותך <a href=\"$1\">להוריד למחשב את הסרטון</a> או <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">להוריד נגן</a> שינגן את הסרטון בדפדפן שלך.",
+ "timedmedia-more": "עוד…",
+ "timedmedia-dismiss": "סגירה",
+ "timedmedia-download": "הורדת הקובץ",
+ "timedmedia-play-media": "לנגן את המדיה",
+ "timedmedia-desc-link": "אודות הקובץ",
+ "timedmedia-oggThumb-version": "OggHandler דורש oggThumb מגרסה $1 או גרסה חדשה יותר.",
+ "timedmedia-oggThumb-failed": "oggThumb לא הצליח ליצור תמונה מוקטנת.",
+ "timedmedia-status-header": "מצב המרה משנית",
+ "timedmedia-update-status": "עדכון מצב המרה משנית",
+ "timedmedia-status": "מצב",
+ "timedmedia-status-unknown": "מצב לא ידוע",
+ "timedmedia-transcodebitrate": "קצב ביטים",
+ "timedmedia-transcodeduration": "זמן קידוד",
+ "timedmedia-transcodeinfo": "תסדיר",
+ "timedmedia-actions": "פעולות",
+ "timedmedia-direct-link": "הורדה",
+ "timedmedia-not-ready": "לא מוכן",
+ "timedmedia-completed-on": "הושלם ב־$1",
+ "timedmedia-error-on": "שגיאה ב־$1",
+ "timedmedia-started-transcode": "התחילה לפני $1‏. $2",
+ "timedmedia-percent-done": "בערך $1% נעשה",
+ "timedmedia-in-job-queue": "נוסף לתור משימות לפני $1",
+ "timedmedia-unknown-target-size": "גודל יעד אינו ידוע, קודדו $1",
+ "timedmedia-days": "{{PLURAL:$1|יום אחד|יומיים|$1 ימים}}",
+ "timedmedia-hours": "{{PLURAL:$1|שעה אחת|שעתיים|$1 שעות}}",
+ "timedmedia-minutes": "{{PLURAL:$1|דקה אחת|$1 דקות}}",
+ "timedmedia-seconds": "{{PLURAL:$1|שנייה אחת|$1 שניות}}",
+ "timedmedia-reset": "אתחול המרה משנית",
+ "timedmedia-reset-confirm": "אתחול ההמרה הזאת ימחק כל קובץ קיים (אם יש כזה) ויוסיף שוב את ההמרה המשנית לתור המשימות. ייקח זמן כדי לבצע את ההמרה המשנית שוב.<br /><br />להמשיך?",
+ "timedmedia-reset-error": "שגיאה באתחול משימת המרה משנית",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "ממקור $1",
+ "timedmedia-source-file-desc": "קובץ $1 מקורי, $2 × $3&rlm; ($4)",
+ "timedmedia-source-audio-file-desc": "קובץ $1 מקורי ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "וידאו Ogg (160P)&lrm; לרוחב פס נמוך",
+ "timedmedia-derivative-desc-240p.ogv": "וידאו Ogg (240P)&lrm; לנגינה שוטפת מהרשת",
+ "timedmedia-derivative-desc-360p.ogv": "וידאו Ogg (360P)&lrm; לנגינה שוטפת מהרשת",
+ "timedmedia-derivative-desc-480p.ogv": "וידאו Ogg (480P)&lrm; לנגינה שוטפת מהרשת",
+ "timedmedia-derivative-desc-720p.ogv": "וידאו Ogg (720P)&lrm; באיכות גבוהה שניתן להורדה",
+ "timedmedia-derivative-desc-1080p.ogv": "וידאו Ogg שאפשר להוריד באיכות HD מלאה (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM להזרמה ברשת (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM ניתן לשידור שטף ברשת (360P)",
+ "timedmedia-derivative-desc-480p.webm": "וידאו WebM (480P)&lrm; לנגינה שוטפת מהרשת",
+ "timedmedia-derivative-desc-720p.webm": "וידאו WebM (720P)&lrm; באיכות גבוהה שניתן להורדה",
+ "timedmedia-derivative-desc-1080p.webm": "קובץ WebM שאפשר להוריד באיכות HD מלאה (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "קובץ WebM שאפשר להוריד באיכות 4K מלאה (2160P)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "WebM VP9 ניתן להזרמה ברשת (360P)",
+ "timedmedia-derivative-desc-480p.vp9.webm": "WebM VP9 ניתן להזרמה ברשת (480P)",
+ "timedmedia-derivative-desc-720p.vp9.webm": "WebM VP9 באיכות HD ניתן להזרמה ברשת (720P)",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "WebM VP9 באיכות HD מלאה ניתן להזרמה ברשת (1080P)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "WebM VP9 באיכות 4K מלאה ניתן להזרמה ברשת (2160P)",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 ידידותי למכשיר (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "וידאו WebM (480P)&lrm; לנגינה שוטפת מהרשת",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 באיכות גבוהה (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "קובץ MP4 שאפשר להוריד באיכות HD מלאה (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "MP4 באיכות 4K מלאה (2160P)",
+ "timedmedia-subtitle-new": "יצירת תרגום חדש או עריכת תרגום קיים",
+ "timedmedia-subtitle-new-desc": "נא לבחור שפה וללחוץ על כפתור '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "מעבר",
+ "timedmedia-subtitle-language": "כתוביות ב{{GRAMMAR:תחילית|$1}} ($2)",
+ "timedmedia-subtitle-no-video": "אין וידאו שמשויך לדף הכתוביות הנוכחי",
+ "timedmedia-subtitle-no-subtitles": "אין כעת כתוביות עבור השפה הבאה: $1. אפשר [{{fullurl:{{FULLPAGENAME}}|action=edit}} לערוך את הדף הזה] ולהוסיף אותן",
+ "timedmedia-subtitle-remote": "טקסט מתוזמן עבור קובץ זה מאוחסן ב{{GRAMMAR:תחילית|$1}}",
+ "timedmedia-subtitle-remote-link": "אפשר [$1 להציג את דף התיאור] של הקובץ הזה בדף $2",
+ "timedmediahandler": "מדיה מתוזמנת",
+ "timedmedia-videos": "{{PLURAL:$1|סרט אחד|$1 סרטים}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|סרט Ogg אחד|$1 סרטי Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|סרט WebM אחד|$1 סרטי WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|המרה משנית אחת|$1 המרות משניות}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|המרה משנית אחת רצה|$1 המרות משניות רצות}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|המרה משנית אחת בתור|$1 המרות משניות בתור}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|המרות משנית אחת נכשלה|$1 המרות משניות נכשלו}}",
+ "timedmedia-file": "קובץ",
+ "timedmedia-audios": "{{PLURAL:$1|קובץ שמע אחד|$1 קובצי שמע}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|קובץ שמע Ogg אחד|$1 קובצי שמע Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|קובץ שמע FLAC אחד|$1 קובצי שמע FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|קובץ שמע WAV אחד|$1 קובצי שמע WAV}}",
+ "right-transcode-reset": "אתחול סרטים שקידוד המשנה שלהם הושלם או נכשל כך שהם מוכנסים מחדש לתור המשימות.",
+ "right-transcode-status": "הצגת [[Special:TimedMediaHandler|מידע על פעילות המרת־המשנה הנוכחית]]",
+ "action-transcode-status": "להציג את מצב המרת־המשנה",
+ "orphanedtimedtext": "דפי טקסט מתוזמן יתומים",
+ "orphanedtimedtext-summary": "רשימה של כל דפי [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] שלא משויך להם קובץ.",
+ "orphanedtimedtext-unsupported": "הדף המיוחד הזה נתמך רק במסדי נתונים MySQL.",
+ "orphanedtimedtext-notimedtext": "ההרחבה TimedText אינה מופעלת בוויקי הזה.",
+ "apihelp-query+transcodestatus-description": "קבלת מצב ההמרה המשנית עבור דף הקובץ הנתון.",
+ "apihelp-query+transcodestatus-example-1": "קבלת מצב ההמרה המשנית עבור [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "הרחבת imageinfo להכללת מידע על מקור הווידאו (נגזרות)",
+ "apihelp-query+videoinfo-param-prop": "איזה מידע לקבל על הווידאו:\n;timestamp:הוספת חותם זמן לגרסה שהולתה.\n;user:הוספת המשתמש שהעלה את גרסת הווידאו.\n;userid:הוספת מזהה המשתמש שהעלה את גרסת הווידאו.\n;comment:הערה על הגרסה.\n;parsedcomment:פענוח ההערה על הגרסה.\n;canonicaltitle:הוספת הכותרת הקנונית של שם קובץ הווידאו.\n;url:הוספת URL לווידאו ולדף התיאור.\n;size:הוספת הגודל של הווידאו בבתים, הגובה שלו והרוחב שלו. ספירת דפים ומשך מוספים כשזה מתאים.\n;dimensions:אותו דבר כמו size.\n;sha1:הוספת גיבוב SHA-1 של הווידאו.\n;mime:הוספת סוג MIME של הווידאו.\n;thumbmime:הוספת סוג MIME של התמונה הממוזערת של הווידאו (נדרש url והפרמטר $1urlwidth).\n;mediatype:הוספת סוג המדיה של הווידאו.\n;metadata:רשימת מטא־נתוני EXIF לגרסה של הווידאו.\n;commonmetadata:רשימת מטא־נתונים כללים של תסדיר הקובץ עבור גרסת הווידאו.\n;extmetadata:רשימת מטא־נתונים מעוצבים משולבים ממספר מקורות התוצאות מעוצבות עם HTML.\n;archivename:הוספת שם הקובץ של גרסת הארכיון עבור הגרסאות שאינן הגרסה האחרונה.\n;bitdepth:עומק הביטים של הגרסה.\n;uploadwarning:משמש את הדף [[Special:Upload]] כדי לקבל מידע על קובץ קיים. לא מיועד לשימוש מחוץ לליבת MediaWiki.\n;derivatives:הוספת מערך של גרסאות זמינות שונות מבחינת תסדיר ואיכות של קובץ שמע או וידאו.",
+ "apihelp-query+videoinfo-example-1": "אחזור מידע על [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "משתמשים עם ההרשאה 'transcode-reset' יכולים לאפס ולהריץ מלחדש משימת המרת־משנה.",
+ "apihelp-transcodereset-param-title": "כותרת קובץ המדיה.",
+ "apihelp-transcodereset-param-transcodekey": "מפתח המרת־המשנה שברצונך לאפס. יש לאחזר אותו מ־[[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "איפוס כל המרות־המשנה עבור [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "איפוס מפתח המרת המשנה '<span dir=\"ltr\">360_560kbs.webm</span>' עבור [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/hi.json b/extensions/TimedMediaHandler/i18n/hi.json
new file mode 100644
index 00000000..08ef0a1d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/hi.json
@@ -0,0 +1,39 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kaustubh",
+ "Shyam",
+ "Siddhartha Ghai",
+ "संजीव कुमार",
+ "NehalDaveND"
+ ]
+ },
+ "timedmedia-desc": "ऑग थियोरा और वॉर्बिस फ़ाईल्सके लिये चालक, जावास्क्रीप्ट प्लेयर के साथ",
+ "timedmedia-ogg-short-audio": "ऑग $1 ध्वनी फ़ाईल, $2",
+ "timedmedia-ogg-short-video": "ऑग $1 चलतचित्र फ़ाईल, $2",
+ "timedmedia-ogg-short-general": "ऑग $1 मीडिया फ़ाईल, $2",
+ "timedmedia-ogg-long-audio": "ऑग $1 ध्वनी फ़ाईल, लंबाई $2, $3",
+ "timedmedia-ogg-long-video": "ऑग $1 चलतचित्र फ़ाईल, लंबाई $2, $4×$5 पीक्सेल्स, $3",
+ "timedmedia-ogg-long-multiplexed": "ऑग ध्वनी/चित्र फ़ाईल, $1, लंबाई $2, $4×$5 पिक्सेल्स, $3 कुल",
+ "timedmedia-ogg-long-general": "ऑग मीडिया फ़ाईल, लंबाई $2, $3",
+ "timedmedia-ogg-long-error": "गलत ऑग फ़ाईल: $1",
+ "timedmedia-no-player-js": "क्षमा करें, आपके ब्राउज़र में या तो जावास्क्रिप्ट अक्षम है या समर्थित प्लेयर नहीं है।<br />\nआप <a href=\"$1\">क्लिप को डाउनलोड</a> कर सकते हैं अथवा क्लिप को अपने ब्राउज़र में चलाने के लिए <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">एक प्लेयर डाउनलोड</a> कर सकते हैं।",
+ "timedmedia-more": "और...",
+ "timedmedia-dismiss": "बंद करें",
+ "timedmedia-download": "फ़ाईल डाउनलोड करें",
+ "timedmedia-desc-link": "इस फ़ाईलके बारे में",
+ "timedmedia-status": "स्थिति",
+ "timedmedia-status-unknown": "अज्ञात स्थिति",
+ "timedmedia-actions": "क्रियाएँ",
+ "timedmedia-source-file": "$1 स्रोत",
+ "timedmedia-source-audio-file-desc": "मूल $1 फ़ाइल ($2)",
+ "timedmedia-derivative-desc-1080p.ogv": "पूर्ण उच्च परिभाषा डाउनलोड करने योग्य ओजीजी वीडियो (१०८०पी)",
+ "timedmedia-derivative-desc-1080p.webm": "पूर्ण उच्च परिभाषा के साथ डाउनलोड करने योग्य वेब-एम (१०८०पी)",
+ "timedmedia-derivative-desc-1080p.mp4": "पूर्ण उच्च परिभाषा गुणवता एमपी४ (१०८०पी)",
+ "timedmedia-subtitle-new-go": "जाएँ",
+ "timedmedia-file": "फ़ाइल",
+ "timedmedia-audios": "{{PLURAL:$1|$1 ऑडियो फ़ाइल|$1 ऑडियो फ़ाइलें}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg ऑडियो फ़ाइल|$1 Ogg ऑडियो फ़ाइलें}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC ऑडियो फ़ाइल|$1 FLAC ऑडियो फ़ाइलें}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV ऑडियो फ़ाइल|$1 WAV ऑडियो फ़ाइलें}}"
+}
diff --git a/extensions/TimedMediaHandler/i18n/hr.json b/extensions/TimedMediaHandler/i18n/hr.json
new file mode 100644
index 00000000..b8d63e0f
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/hr.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "CERminator",
+ "Dalibor Bosits",
+ "Ex13",
+ "SpeedyGonsales",
+ "Roberta F.",
+ "Fraxinus",
+ "Teoo3"
+ ]
+ },
+ "timedmedia-desc": "Poslužitelj za Ogg Theora i Vorbis datoteke, s JavaScript preglednikom",
+ "timedmedia-ogg-short-audio": "Ogg $1 zvučna datoteka, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 video datoteka, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 medijska datoteka, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 zvučna datoteka, duljine $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 video datoteka, duljine $2, $4x$5 piksela, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg multipleksirana zvučna/video datoteka, $1, duljine $2, $4×$5 piksela, $3 ukupno",
+ "timedmedia-ogg-long-general": "Ogg medijska datoteka, duljine $2, $3",
+ "timedmedia-ogg-long-error": "nevaljana ogg datoteka: $1",
+ "timedmedia-no-player-js": "Nažalost, u Vašem pregledniku isključen je JavaScript, ili nije dostupan na ovom projektu.<br />\nMožete <a href=\"<span class=\" notranslate\"=\"\" translate=\"no\">$1</span>\">preuzeti videozapis</a> ili <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">učitati player</a> za reproduciranje videozapisa u pregledniku.",
+ "timedmedia-more": "Više...",
+ "timedmedia-dismiss": "Zatvori",
+ "timedmedia-download": "Snimi datoteku",
+ "timedmedia-desc-link": "O ovoj datoteci",
+ "timedmedia-source-file": "Izvor $1",
+ "timedmedia-source-audio-file-desc": "Originalna $1 datoteka ($2)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "Full 4K streamable WebM VP9 (2160P)",
+ "timedmedia-derivative-desc-2160p.mp4": "MP4 pune 4K kvalitete (2160P)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/hrx.json b/extensions/TimedMediaHandler/i18n/hrx.json
new file mode 100644
index 00000000..80513f50
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/hrx.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Midnight Gambler"
+ ]
+ },
+ "timedmedia-source-file": "Quell ($1)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/hsb.json b/extensions/TimedMediaHandler/i18n/hsb.json
new file mode 100644
index 00000000..094def43
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/hsb.json
@@ -0,0 +1,83 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dundak",
+ "Michawiki",
+ "Reedy"
+ ]
+ },
+ "timedmedia-desc": "Wodźenski program za awdio, widejo a timedText z podpěru za formaty WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Awdiodataja Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Widejodataja Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Ogg medijowa dataja $1, $2",
+ "timedmedia-ogg-long-audio": "Ogg-awdiodataja $1, dołhosć: $2, $3",
+ "timedmedia-ogg-long-video": "Ogg-widejodataja $1, dołhosć: $2, $4×$5 pikselow, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg multipleksna awdio-/widejodataja, $1, dołhosć: $2, $4×$5 pikselow, $3",
+ "timedmedia-ogg-long-general": "Ogg medijowa dataja, dołhosć: $2, $3",
+ "timedmedia-ogg-long-error": "Njepłaćiwa Ogg-dataja: $1",
+ "timedmedia-webm-short-video": "Widejodataja WebM $1, $2",
+ "timedmedia-webm-long-video": "Awdio-/widejodataja WebM, $1, dołhosć $2, $4 x $5 pikselow, $3 dohromady",
+ "timedmedia-mp4-short-video": "MP4 $1 widejodataja, $2",
+ "timedmedia-mp4-long-video": "MP4 awdio-/widejodataja, $1, dołhosć $2, $4 × $5 pikselow, $3 dohromady",
+ "timedmedia-no-player-js": "Twój wobhladowak je pak JavaScript znjemóžnił pak nima podpěrowany wothrawak.<br />\nMóžeš <a href=\"$1\">klip sćahnyć</a> abo <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">wothrawak sćahnyć</a>, zo by klip w swojim wobhladowaku wothrawał.",
+ "timedmedia-more": "Wjace ...",
+ "timedmedia-dismiss": "Začinić",
+ "timedmedia-download": "Dataju sćahnyć",
+ "timedmedia-play-media": "Medijowu dataju wothrać",
+ "timedmedia-desc-link": "Wo tutej dataji",
+ "timedmedia-oggThumb-version": "OggHandler trjeba wersiju $1 oggThumb abo nowšu.",
+ "timedmedia-oggThumb-failed": "oggThumb njemóžeše wobrazk wutworić.",
+ "timedmedia-status-header": "Překodowanski status",
+ "timedmedia-update-status": "Překodowanski status aktualizować",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Njeznaty status",
+ "timedmedia-transcodeinfo": "Wotwodźene wopisanje překodować",
+ "timedmedia-actions": "Akcije",
+ "timedmedia-direct-link": "Wotwodźenje sćahnyć",
+ "timedmedia-not-ready": "Nic hotowy",
+ "timedmedia-completed-on": "Překodowanje $1 wotzamknjene",
+ "timedmedia-error-on": "Zmylk při překodowanju $1",
+ "timedmedia-started-transcode": "Překodowanje před $1 startowane. $2",
+ "timedmedia-percent-done": "Na wšě $1% sčinjene",
+ "timedmedia-in-job-queue": "Před $1 čakanskemu rynčkej přidaty",
+ "timedmedia-unknown-target-size": "Njeznata cilowa wulkosć, $1 kodowane",
+ "timedmedia-days": "{{PLURAL:$1|1 dźeń|$1 dnjej|$1 dny|$1 dnjow}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 hodźina|$1 hodźinje|$1 hodźiny|$1 hodźin}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 mjeńšina|$1 mjeńšinje|$1 mjeńšiny|$1 mjeńšin}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 sekunda|$1 sekundźe|$1 sekundy|$1 sekundow}}",
+ "timedmedia-reset": "Překodowanje wróćo stajić",
+ "timedmedia-reset-confirm": "Wróćostajenje tutoho překodowanja wotstroni eksistowacu dataju (jeli tajka eksistuje), a budźe překodowanje znowa čakanskemu rynčkej přidawać. Nowe překodowanje budźe někotry čas trać.<br /><br />\nChceš woprawdźe pokročować?",
+ "timedmedia-reset-error": "Zmylk při wróćostajenju překodowanja.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Žórło ($1)",
+ "timedmedia-source-file-desc": "Originalna dataja $1, $2 x $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Originalna $1-dataja ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg-widejo z niskej šěrokosću pasma (160p)",
+ "timedmedia-derivative-desc-360p.ogv": "Ogg-widejo (360p), kotrež da so přez Web přenjesć",
+ "timedmedia-derivative-desc-480p.ogv": "Ogg-widejo (480p), kotrež da so přez Web přenjesć",
+ "timedmedia-derivative-desc-720p.ogv": "Sćahujomne Ogg-widejo wysokeje kwality (720p)",
+ "timedmedia-derivative-desc-160p.webm": "WebM-widejo (160p), kotrež da so přez Web přenjesć",
+ "timedmedia-derivative-desc-360p.webm": "WebM-widejo (360p), kotrež da so přez Web přenjesć",
+ "timedmedia-derivative-desc-480p.webm": "WebM-widejo (480p), kotrež da so přez Web přenjesć",
+ "timedmedia-derivative-desc-720p.webm": "Sćahujomna WebM-dataja wysokeje kwality (720p)",
+ "timedmedia-derivative-desc-320p.mp4": "Gratapřećelny MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4-dataja, kotraž da so přez Web přenjesć",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 w HD-kwaliće (720P)",
+ "timedmedia-subtitle-new": "Nowy přełožk wutworić abo eksistowacy wobdźěłać",
+ "timedmedia-subtitle-new-desc": "Wubjer rěč a klikń na tłóčatko '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "W porjadku",
+ "timedmedia-subtitle-language": "$1 ($2) podtitule",
+ "timedmedia-subtitle-no-video": "Widejo zwjazane z aktuelnej stronu podtitulow njeje",
+ "timedmedia-subtitle-no-subtitles": "Tuchwilu podtitule w $1 zu tute widejo njejsu, móžeš [{{fullurl:{{FULLPAGENAME}}|action=edit}} tutu stronu wobdźěłać], zo by je přidał",
+ "timedmedia-subtitle-remote": "timedText za tutu dataju je na $1",
+ "timedmedia-subtitle-remote-link": "Móžeš sej [$1 wopisansku stronu] za tutu dataja na $2 wobhladać",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 widejo|$1 wideji|$1 wideja|$1 widejow}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg-widejo|$1 Ogg-wideji|$1 Ogg-wideja|$1 Ogg-widejow}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM-widejo|$1 WebM-wideji|$1 WebM-wideja|$1 WebM-widejow}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 překodowanje|$1 překodowani|$1 překodowanja|$1 překodowanjow}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 běžne překodowanje|$1 běžnej překodowani|$1 běžne překodowanja|$1 běžnych překodowanjow}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 překodowanje|$1 překodowani|$1 překodowanja|$1 překodowanjow}} w čakanskim rynku",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 zwrěsćene překodowanje|$1 zwrěsćenej překodowani|$1 zwrěsćene překodowanja|$1 zwrěsćenych překodowanjow}}",
+ "timedmedia-file": "Dataja"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ht.json b/extensions/TimedMediaHandler/i18n/ht.json
new file mode 100644
index 00000000..54b45469
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ht.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tisave"
+ ]
+ },
+ "timedmedia-no-player-js": "Eskize, men swa JavaScript navigatè ou deyaktive oswa li pa gen okenn mwayen pou ouvri fichye sa a.<br />\nOu ka <a href=\"$1\">telechaje fichye a</a> oswa <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">chèche yon lojisyèl</a> pou ouvri fichye a nan navigatè ou.",
+ "timedmedia-source-file": "Referans $1"
+}
diff --git a/extensions/TimedMediaHandler/i18n/hu.json b/extensions/TimedMediaHandler/i18n/hu.json
new file mode 100644
index 00000000..dbe3df87
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/hu.json
@@ -0,0 +1,37 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dani",
+ "Glanthor Reviol",
+ "Tgr",
+ "Csega",
+ "Samat",
+ "Dj"
+ ]
+ },
+ "timedmedia-desc": "JavaScript nyelven írt lejátszó Ogg Theora és Vorbis fájlokhoz",
+ "timedmedia-ogg-short-audio": "Ogg $1 hangfájl, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 videofájl, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 médiafájl, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 hangfájl, hossza: $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 videófájl, hossza $2, $4×$5 képpont, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg egyesített audió- és videófájl, $1, hossz: $2, $4×$5 képpont, $3 összesen",
+ "timedmedia-ogg-long-general": "Ogg médiafájl, hossza: $2, $3",
+ "timedmedia-ogg-long-error": "Érvénytelen ogg fájl: $1",
+ "timedmedia-no-player-js": "Sajnáljuk, a böngésződben vagy le van tiltva a JavaScript, vagy nincs egyetlen támogatott lejátszója sem.<br />\n<a href=\"$1\">Letöltheted a klipet</a>, vagy <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">letölthetsz egy lejátszót</a> a böngészőben való megtekintéshez.",
+ "timedmedia-more": "Tovább...",
+ "timedmedia-dismiss": "Bezárás",
+ "timedmedia-download": "Fájl letöltése",
+ "timedmedia-play-media": "Média lejátszása",
+ "timedmedia-desc-link": "Fájlinformációk",
+ "timedmedia-oggThumb-version": "Az OggHandlerhez $1 vagy későbbi verziójú oggThumb szükséges.",
+ "timedmedia-oggThumb-failed": "Az oggThumb nem tudta elkészíteni a bélyegképet.",
+ "timedmedia-source-file": "Forrás ($1)",
+ "timedmedia-source-file-desc": "Eredeti $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Eredeti $1 fájl ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Alacsony sávszélességű Ogg videó (160P)",
+ "timedmedia-derivative-desc-720p.ogv": "Magas minőségű, letölthető Ogg videó (720P)",
+ "timedmedia-derivative-desc-720p.webm": "Magas minőségű, letölthető WebM (720P)",
+ "right-transcode-status": "[[Special:TimedMediaHandler|a legutóbbi átkódolási események információinak]] megtekintése",
+ "orphanedtimedtext": "Árva TimedText lapok"
+}
diff --git a/extensions/TimedMediaHandler/i18n/hy.json b/extensions/TimedMediaHandler/i18n/hy.json
new file mode 100644
index 00000000..41aa6004
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/hy.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xelgen",
+ "Vahe Gharakhanyan"
+ ]
+ },
+ "timedmedia-no-player-js": "Ցավոք, ձեր վեբդիտարկիչում անջատված է JavaScript-ը կամ բացակայում է աջակցվող նվագարկիչ:<br />\nԴուք կարող եք <a href=\"<span class=\" notranslate\"=\"\" translate=\"no\">$1</span>\">ներբեռնել տեսահոլովակը</a> կամ <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">նվագարկիչ</a>:",
+ "timedmedia-source-file": "$1 աղբյուր",
+ "timedmedia-source-audio-file-desc": "Սկզբնական $1 նիշք ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ia.json b/extensions/TimedMediaHandler/i18n/ia.json
new file mode 100644
index 00000000..a24d1b20
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ia.json
@@ -0,0 +1,92 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie"
+ ]
+ },
+ "timedmedia-desc": "Gestor pro audio, video e texto synchronisate, con supporto del formatos WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "File audio Ogg $1, $2",
+ "timedmedia-ogg-short-video": "File video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "File media Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "File audio Ogg $1, duration $2, $3",
+ "timedmedia-ogg-long-video": "File video Ogg $1, duration $2, $4×$5 pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "File multiplexate audio/video Ogg, $1, duration $2, $4×$5 pixel, $3 in total",
+ "timedmedia-ogg-long-general": "File media Ogg, duration $2, $3",
+ "timedmedia-ogg-long-error": "File Ogg invalide: $1",
+ "timedmedia-webm-short-video": "File video WebM $1, $2",
+ "timedmedia-webm-long-video": "File audio/video WebM, $1, longitude $2, $4 × $5 pixels, $3 in total",
+ "timedmedia-flac-short-audio": "File audio FLAC, $1",
+ "timedmedia-flac-long-audio": "File audio FLAC, durata $1, $2 in total",
+ "timedmedia-wav-short-audio": "File audio WAV, $1",
+ "timedmedia-wav-long-audio": "File audio WAV, durata $1, $2 in total",
+ "timedmedia-wav-pcm-required": "Tu pote solmente incargar PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "File video MP4 $1, $2",
+ "timedmedia-mp4-long-video": "File audio/video MP4 $1, durata $2, dimensiones $4 × $5 pixels, $3 in total",
+ "timedmedia-no-player-js": "Pardono, tu systema o ha JavaScript disactivate o non ha un reproductor supportate.<br />\nTu pote <a href=\"$1\">discargar le clip</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">discargar un reproductor</a> pro reproducer le clip in tu navigator.",
+ "timedmedia-more": "Plus…",
+ "timedmedia-dismiss": "Clauder",
+ "timedmedia-download": "Discargar file",
+ "timedmedia-play-media": "Reproducer multimedia",
+ "timedmedia-desc-link": "A proposito de iste file",
+ "timedmedia-oggThumb-version": "OggHandler require oggThumb version $1 o plus recente.",
+ "timedmedia-oggThumb-failed": "oggThumb ha fallite de crear le miniatura.",
+ "timedmedia-status-header": "Stato de transcodification",
+ "timedmedia-update-status": "Actualisar stato de transcodification",
+ "timedmedia-status": "stato",
+ "timedmedia-status-unknown": "stato incognite",
+ "timedmedia-transcodeinfo": "Description del file transcodificate",
+ "timedmedia-actions": "actiones",
+ "timedmedia-direct-link": "Discargar file transcodificate",
+ "timedmedia-not-ready": "Non preste",
+ "timedmedia-completed-on": "Transcodification de $1 complete",
+ "timedmedia-error-on": "Error in transcodification a $1",
+ "timedmedia-started-transcode": "Le transcodification comenciava $1 retro. $2",
+ "timedmedia-percent-done": "Circa $1% complete",
+ "timedmedia-in-job-queue": "Addite al cauda de actiones $1 retro",
+ "timedmedia-unknown-target-size": "Dimension del destination incognite, $1 codificate",
+ "timedmedia-days": "{{PLURAL:$1|1 die|$1 dies}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 hora|$1 horas}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuta|$1 minutas}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 secunda|$1 secundas}}",
+ "timedmedia-reset": "Reinitialisar transcodification",
+ "timedmedia-reset-confirm": "Reinitialisar iste transcodification removera tote le files existente (si presente), e illo re-addera le transcodification al cauda de actiones. Le transcodification prendera un tempore. <br /><br />Es tu secur de voler continuar?",
+ "timedmedia-reset-error": "Error durante le reinitialisation del action de transcodification",
+ "timedmedia-source-file": "original $1",
+ "timedmedia-source-file-desc": "File $1 original, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "File $1 original ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Video Ogg a basse largor de banda (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Video Ogg transmissibile per fluxo web (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Video Ogg transmissibile per fluxo web (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Video Ogg discargabile de alte qualitate (720P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM transmissibile per fluxo web (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM transmissibile per fluxo web (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM transmissibile per fluxo web (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM discargabile de alte qualitate (720P)",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 pro dispositivos mobile (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 transmissibile per fluxo web (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 in qualitate HD (720P)",
+ "timedmedia-subtitle-new": "Crear un nove traduction o modificar le existente",
+ "timedmedia-subtitle-new-desc": "Selige un lingua e preme le button '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Va",
+ "timedmedia-subtitle-language": "$1 ($2) subtitulos",
+ "timedmedia-subtitle-no-video": "Il non ha video associate con le actual pagina de subtitulos",
+ "timedmedia-subtitle-no-subtitles": "Il ha actualmente nulle subtitulos in $1 pro iste video. Tu pote [{{fullurl:{{FULLPAGENAME}}|action=edit}} modificar iste pagina] pro adder los.",
+ "timedmedia-subtitle-remote": "Le subtitulos pro iste file es albergate sur $1",
+ "timedmedia-subtitle-remote-link": "Tu pote [$1 vider le pagina de description] pro iste file sur $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video|$1 videos}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 video Ogg|$1 videos Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 video WebM|$1 videos WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcodification|$1 transcodificationes}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transcodification|$1 transcodificationes}} active",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transcodification|$1 transcodificationes}} in cauda",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transcodification|$1 transcodificationes}} fallite",
+ "timedmedia-file": "File",
+ "timedmedia-audios": "{{PLURAL:$1|$1 file audio|$1 files audio}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 file audio Ogg|$1 files audio Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 file audio FLAC|$1 files audio FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 file audio WAV|$1 files audio WAV}}",
+ "right-transcode-reset": "Reinitialisar le videos fallite o transcodificate de sorta que illos es re-inserite in le cauda de actiones",
+ "right-transcode-status": "View [[Special:TimedMediaHandler|information sur le activitate currente de transcodification]]",
+ "action-transcode-status": "vider le stato actual de transcodification"
+}
diff --git a/extensions/TimedMediaHandler/i18n/id.json b/extensions/TimedMediaHandler/i18n/id.json
new file mode 100644
index 00000000..48f6cc2a
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/id.json
@@ -0,0 +1,97 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bennylin",
+ "Farras",
+ "Irwangatot",
+ "IvanLanin",
+ "Iwan Novirion",
+ "Rex",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "timedmedia-desc": "Pemroses audio, video, dan teks berwaktu, dengan dukungan format WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Berkas suara $1 ogg, $2",
+ "timedmedia-ogg-short-video": "Berkas video $1 ogg, $2",
+ "timedmedia-ogg-short-general": "Berkas media $1 ogg, $2",
+ "timedmedia-ogg-long-audio": "Berkas suara $1 ogg, panjang $2, $3",
+ "timedmedia-ogg-long-video": "Berkas video $1 ogg, panjang $2, $4×$5 piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Berkas audio/video multiplexed ogg, $1, panjang $2, $4×$5 piksel, $3 keseluruhan",
+ "timedmedia-ogg-long-general": "Berkas media ogg, panjang $2, $3",
+ "timedmedia-ogg-long-error": "Berkas ogg tak valid: $1",
+ "timedmedia-webm-short-video": "Berkas video $1 WebM, $2",
+ "timedmedia-webm-long-video": "Berkas audio/video WebM, $1, lama $2, $4 × $5 piksel, $3 keseluruhan",
+ "timedmedia-no-player-js": "Maaf, peramban Anda memiliki JavaScript yang dinonaktifkan atau tidak memiliki pemutar media apapun.<br />\nAnda dapat <a href=\"$1\">mengunduh klip</a> atau <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">mengunduh pemutar</a> untuk memutar klip di peramban Anda.",
+ "timedmedia-more": "Lainnya...",
+ "timedmedia-dismiss": "Tutup",
+ "timedmedia-download": "Unduh berkas",
+ "timedmedia-play-media": "Putar media",
+ "timedmedia-desc-link": "Mengenai berkas ini",
+ "timedmedia-oggThumb-version": "OggHandler membutuhkan oggThumb versi $1 atau terbaru.",
+ "timedmedia-oggThumb-failed": "oggThumb gagal membuat miniatur gambar.",
+ "timedmedia-status-header": "Status transkoder",
+ "timedmedia-update-status": "Memperbarui status transkoder",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Status tidak diketahui",
+ "timedmedia-transcodeinfo": "Deskripsi turunan transkoder",
+ "timedmedia-actions": "Tindakan",
+ "timedmedia-direct-link": "Unduh turunan",
+ "timedmedia-not-ready": "Belum siap",
+ "timedmedia-completed-on": "Transkoder komplit $1",
+ "timedmedia-error-on": "Kesalahan dalam transkoder pada $1 .",
+ "timedmedia-started-transcode": "Transkoder mulai $1 yang lalu. $2",
+ "timedmedia-percent-done": "Sekitar $1% selesai",
+ "timedmedia-days": "{{PLURAL:$1|$1 hari}}",
+ "timedmedia-hours": "{{PLURAL:$1|$1 jam}}",
+ "timedmedia-minutes": "{{PLURAL:$1|$1 menit}}",
+ "timedmedia-seconds": "{{PLURAL:$1|$1 detik}}",
+ "timedmedia-reset": "Reset transkoder",
+ "timedmedia-ogg": "Ogg",
+ "timedmedia-webm": "WebM",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Sumber $1",
+ "timedmedia-source-file-desc": "$1 asli, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Berkas ($2) asli $1",
+ "timedmedia-derivative-160p.ogv": "Ogg 160p",
+ "timedmedia-derivative-desc-160p.ogv": "Video Ogg lebar pita rendah (160P)",
+ "timedmedia-derivative-360p.ogv": "Ogg 360p",
+ "timedmedia-derivative-desc-360p.ogv": "Video Ogg aliran web (360P)",
+ "timedmedia-derivative-480p.ogv": "Ogg 480p",
+ "timedmedia-derivative-desc-480p.ogv": "Video Ogg aliran web (480P)",
+ "timedmedia-derivative-720p.ogv": "Ogg 720p",
+ "timedmedia-derivative-desc-720p.ogv": "Video Ogg unduhan berkualitas tinggi (720P)",
+ "timedmedia-derivative-160p.webm": "WebM 160p",
+ "timedmedia-derivative-360p.webm": "WebM 360p",
+ "timedmedia-derivative-desc-360p.webm": "WebM aliran web (360P)",
+ "timedmedia-derivative-480p.webm": "WebM 480p",
+ "timedmedia-derivative-desc-480p.webm": "WebM aliran web (480P)",
+ "timedmedia-derivative-720p.webm": "WebM 720p",
+ "timedmedia-derivative-desc-720p.webm": "WebM unduhan berkualitas tinggi (720P)",
+ "timedmedia-derivative-320p.mp4": "H264 320p",
+ "timedmedia-derivative-480p.mp4": "H264 480p",
+ "timedmedia-derivative-720p.mp4": "H264 720p",
+ "timedmedia-derivative-ogg": "Ogg Vorbis",
+ "timedmedia-derivative-desc-ogg": "Ogg Vorbis",
+ "timedmedia-derivative-opus": "Opus",
+ "timedmedia-derivative-desc-opus": "Opus",
+ "timedmedia-derivative-mp3": "MP3",
+ "timedmedia-derivative-desc-mp3": "MP3",
+ "timedmedia-derivative-m4a": "AAC",
+ "timedmedia-derivative-desc-m4a": "AAC",
+ "timedmedia-subtitle-new-go": "Lanjut",
+ "timedmedia-subtitle-language": "Teks film $1 ($2)",
+ "timedmedia-subtitle-no-video": "Tidak ada video yang terkait dengan halaman subjudul ini",
+ "timedmedia-subtitle-no-subtitles": "Saat ini tidak ada subjudul $1 untuk video ini. Anda dapat [{{fullurl: {{FULLPAGENAME}}|action=edit}} menyunting halaman ini] untuk menambahkannya",
+ "timedmediahandler": "Daftar berkas media",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Video ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 Video WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transkoder}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transkoder aktif}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 antrian transkoder}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transkoder rusak}}",
+ "timedmedia-file": "Berkas",
+ "right-transcode-reset": "Reset transkoder rusak ataupun yang tidak sehingga kembali dimasukkan dalam antrian.",
+ "right-transcode-status": "Lihat [[Special:TimedMediaHandler|informasi tentang aktifitas transkoder terkini]]",
+ "action-transcode-status": "lihat status transkoder terkini"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ilo.json b/extensions/TimedMediaHandler/i18n/ilo.json
new file mode 100644
index 00000000..11ce2be8
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ilo.json
@@ -0,0 +1,89 @@
+{
+ "@metadata": {
+ "authors": [
+ "Lam-ang"
+ ]
+ },
+ "timedmedia-desc": "Panagtengngel para iti audio, video ken naorasan a testo, nga adda ti porma a suporta para iti WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 a mangeg a papeles, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 a video a papeles, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 a midia a papeles, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 a mangeg a papeles, kaatiddog $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 a video a papeles, kaatiddog $2, $4 × $5 a piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg multiplexed nga audio/video a papeles, $1, kaatiddog $2, $4 × $5 a piksel, $3 amin-amin",
+ "timedmedia-ogg-long-general": "Ogg midia a papeles, kaatiddog $2, $3",
+ "timedmedia-ogg-long-error": "Imbalido nga Ogg a papeles: $1",
+ "timedmedia-webm-short-video": "WebM $1 a video a papeles, $2",
+ "timedmedia-webm-long-video": "WebM nga audio/video a papeles, $1, kaatiddog $2, $4 × $5 a piksel, $3 amin-amin",
+ "timedmedia-flac-short-audio": "Mangeg a papeles ti FLAC, $1",
+ "timedmedia-flac-long-audio": "Mangeg a papeles ti FLAC, kaatiddog $1, $2 ti amin a dagup",
+ "timedmedia-wav-short-audio": "Mangeg a papeles ti WAV, $1",
+ "timedmedia-wav-long-audio": "Mangeg a papeles ti WAV, kaatiddog $1, $2 ti amin a dagup",
+ "timedmedia-wav-pcm-required": "Mabalinmo laeng ti agikarga ti PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "MP4 $1 a video apapeles, $2",
+ "timedmedia-mp4-long-video": "MP4 nga audio/video a papeles, $1, kaatiddog $2, $4 × $5 a piksel, $3 amin-amin",
+ "timedmedia-no-player-js": "Pasensia, ti pagbasabasam ket mabalin a nabaldado ti JavaScript wenno awan ti nasuportaran a mangay-ayam.<br />\nMabalinmo ti <a href=\"$1\">agikarga ti sigpit</a> wenno <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">agikarga ti maysa a magay-ayam</a> tapno maay-ayam ti sigpit iti pagbasabasam.",
+ "timedmedia-more": "Adu pay...",
+ "timedmedia-dismiss": "Irikep",
+ "timedmedia-download": "Ikarga ti papeles",
+ "timedmedia-play-media": "Ay-ayamen ti midia",
+ "timedmedia-desc-link": "Maipanggep ti daytoy a papeles",
+ "timedmedia-oggThumb-version": "Ti OggHandler ket masapulna ti oggThumb a bersion ti $1 wenno ti naududi.",
+ "timedmedia-oggThumb-failed": "Napaay ti oggThumb nga agaramid ti imahen.",
+ "timedmedia-status-header": "Kasasaad ti transkodigo",
+ "timedmedia-update-status": "Pabaruen ti kasasaad ti transkodigo",
+ "timedmedia-status": "Kasasaad",
+ "timedmedia-status-unknown": "Di ammo a kasasaad",
+ "timedmedia-transcodeinfo": "Deribatibo a deskripsion ti transkodigo",
+ "timedmedia-actions": "Dagiti aramid",
+ "timedmedia-direct-link": "Ikarga ti deribatibo",
+ "timedmedia-not-ready": "Saan pay a sisasagana",
+ "timedmedia-completed-on": "Nakompleto ti transkodigo $1",
+ "timedmedia-error-on": "Biddut iti transkodigo iti $1",
+ "timedmedia-started-transcode": "Ti transkodigo ket nairugi di $1. $2",
+ "timedmedia-percent-done": "Agarup a $1% ti nalapasen",
+ "timedmedia-in-job-queue": "Nagnayon idiay Pagurayan ti maaramid idi $1",
+ "timedmedia-unknown-target-size": "Di ammo a kadakkel ti puntaan, $1 ti nakodigo",
+ "timedmedia-days": "{{PLURAL:$1|1 nga aldaw|$1 nga al-aldaw}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 nga oras|$1 nga or-oras}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 a minuto|$1 a minutos}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 a segundo|$1 a seg-segundo}}",
+ "timedmedia-reset": "Iyasentar manen ti transkodigo",
+ "timedmedia-reset-confirm": "Ti papangyasentar ti daytoy a transkodigo ket mangikkat ti aniaman nga adda a papeles (no adda), ket manginayonto manen ti transkodigo iti pagurayan ti maaramid. <br /><br />\nSeguradoka kadi a kayatmo ti tumuloy?",
+ "timedmedia-reset-error": "Biddut ti panangiyasentar manen ti transkodigo a maaramid.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 taudan",
+ "timedmedia-source-file-desc": "Kasisigud a $1 a papeles, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Kasisigud a $1 a papeles ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ababa ti bandwidth a video ti Ogg (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Maiwaragawag ti web a video ti Ogg (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Maiwaragawag ti web a video ti Ogg (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Maikarga a nangato ti kalidadna a video ti Ogg (720P)",
+ "timedmedia-derivative-desc-160p.webm": "Maiwaragawag ti web a WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Maiwaragawag ti web a WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Maiwaragawag ti web a WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Maikarga a nangato ti kalidadna a WebM (720)",
+ "timedmedia-derivative-desc-320p.mp4": "Mannakigayyem a ramit ti MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Maiwaragawag ti web a Mp4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD ti kalidadna a MP4 (720P)",
+ "timedmedia-subtitle-new": "Agpartuat ti baro a panagipatarus wenno urnosen ti adda",
+ "timedmedia-subtitle-new-desc": "Agpili ti pagsasao ken pinduten ti '''{{int:Timedmedia-subtitle-new-go}}''' a buton",
+ "timedmedia-subtitle-new-go": "Inkan",
+ "timedmedia-subtitle-language": "Dagiti $1 ($2) a subtitulo",
+ "timedmedia-subtitle-no-video": "Awan ti video a mainanig iti agdama a subtitulo ti panid",
+ "timedmedia-subtitle-no-subtitles": "Awan dagiti agdama asubtitulo iti $1 para iti daytoy a video, mabalinmo ti [{{fullurl:{{FULLPAGENAME}}|action=edit}} agurnods ti daytoy a panid] tapno makanayonka kaniada",
+ "timedmedia-subtitle-remote": "Ti naorasan a testo para iti daytoy a papeles ket nanisangaili idiay $1",
+ "timedmedia-subtitle-remote-link": "Mabalinmo a [$1 kitaen ti deskripsion ti panid] para iti daytoy a papeles idiay $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 a video|dagiti $1 a video}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 nga Ogg a video|dagiti $1 nga Ogg a video}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 a WebM a video|dagiti $1 a WebM a video}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 a transkodigo|dagiti $1 a transkodigo}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 nga agtartaray a transkodigo|dagiti $1 nga agtartaray a transkodigo}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 a naiyur-uray a transkodigo|dagiti $1 a naiyur-uray a transkodigo}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 a napaay a transkodigo|dagiti $1 a napaay a transkodigo}}",
+ "timedmedia-file": "Papeles",
+ "right-transcode-reset": "Iyasentar manen ti napaay wenno dagiti naitranskodigo a video tapno maisengngatda manen ti pagurayan ti maaramid",
+ "right-transcode-status": "Kitaen ti [[Special:TimedMediaHandler|pakaammo a maipanggep ti agdama a tignay ti transkodigo]]",
+ "action-transcode-status": "kitaen ti agdama a kasasaad ti transkodigo"
+}
diff --git a/extensions/TimedMediaHandler/i18n/io.json b/extensions/TimedMediaHandler/i18n/io.json
new file mode 100644
index 00000000..8977382c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/io.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Malafaya"
+ ]
+ },
+ "timedmedia-ogg-long-error": "Ne-valida Ogg-arkivo: $1",
+ "timedmedia-more": "Plus…",
+ "timedmedia-dismiss": "Klozar",
+ "timedmedia-desc-link": "Pri ca arkivo"
+}
diff --git a/extensions/TimedMediaHandler/i18n/is.json b/extensions/TimedMediaHandler/i18n/is.json
new file mode 100644
index 00000000..3188925c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/is.json
@@ -0,0 +1,60 @@
+{
+ "@metadata": {
+ "authors": [
+ "S.Örvarr.S",
+ "Snævar",
+ "Spacebirdy"
+ ]
+ },
+ "timedmedia-desc": "Rekill fyrir hljóð, myndbönd og texta myndbanda með stuðningi við skráarsniðin WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 hljóðskrá, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 myndbandskrá, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 margmiðlunarskrá, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 hljóðskrá, lengd $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 myndbandskrá, lengd $2, $4×$5 dílar, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg myndbandaskrá, $1, lengd $2, $4 × $5 dílar, $3 samanlagt",
+ "timedmedia-ogg-long-general": "Ogg margmiðlunarskrá, lengd $2, $3",
+ "timedmedia-ogg-long-error": "Ógild Ogg skrá: $1",
+ "timedmedia-webm-short-video": "WebM $1 myndbandskrá, $2",
+ "timedmedia-webm-long-video": "WebM myndbandaskrá, $1, lengd $2, $4 × $5 dílar, $3 samanlagt",
+ "timedmedia-mp4-short-video": "MP4 $1 myndbandaskrá, $2",
+ "timedmedia-mp4-long-video": "MP4 myndbandaskrá, $1, lengd $2, $4 × $5 dílar, $3 samanlagt",
+ "timedmedia-no-player-js": "Því miður hefur vafrinn þinn annaðhvort óvirkan JavaScript eða engan studdann spilara.<br />\nÞú getur <a href=\"$1\">hlaðið niður skránni</a> eða <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">hlaðið niður spilara</a> til þess að spila skránna í vafranum.",
+ "timedmedia-more": "Meira...",
+ "timedmedia-dismiss": "Loka",
+ "timedmedia-download": "Sækja skrá",
+ "timedmedia-play-media": "Spila margmiðlunarskrá",
+ "timedmedia-desc-link": "Um þessa skrá",
+ "timedmedia-oggThumb-version": "OggHandler þarfnast oggThumb útgáfu $1 eða nýrri.",
+ "timedmedia-oggThumb-failed": "oggThumb mistókst að búa til smámynd.",
+ "timedmedia-status": "Staða",
+ "timedmedia-actions": "Aðgerðir",
+ "timedmedia-direct-link": "Sækja eftirgerð",
+ "timedmedia-not-ready": "Ekki tilbúin",
+ "timedmedia-percent-done": "Um $1% lokið",
+ "timedmedia-unknown-target-size": "Óþekkt markstærð, $1 kóðað",
+ "timedmedia-days": "$1 {{PLURAL:$1|dagur|dagar}}",
+ "timedmedia-hours": "$1 {{PLURAL:$1|klukkutími|klukkutímar}}",
+ "timedmedia-minutes": "$1 {{PLURAL:$1|mínúta|mínútur}}",
+ "timedmedia-seconds": "$1 {{PLURAL:$1|sekúnda|sekúndur}}",
+ "timedmedia-source-file": "$1 uppruni",
+ "timedmedia-source-file-desc": "Upphafleg $1 skrá, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Upphafleg $1 skrá ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg myndband fyrir litla bandbreidd (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Ogg myndbands streymi (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Ogg myndbands streymi (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Hágæða niðurhalanlegt Ogg myndband (720P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM myndbands streymi (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM myndbands streymi (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM myndbands streymi (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Hágæða niðurhalanlegt WebM myndband (720P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 myndbands streymi (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "Háskerpu MP4 (720P)",
+ "timedmedia-subtitle-new-desc": "Veldu tungumálið og smelltu á '''{{int:Timedmedia-subtitle-new-go}}''' takkann",
+ "timedmedia-subtitle-new-go": "Áfram",
+ "timedmedia-subtitle-no-video": "Ekkert myndband tengist þessum myndbanda texta",
+ "timedmedia-videos": "{{PLURAL:$1|$1 myndband|$1 myndbönd}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg myndband|$1 Ogg myndbönd}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM myndband|$1 WebM myndbönd}}",
+ "timedmedia-file": "Skrá"
+}
diff --git a/extensions/TimedMediaHandler/i18n/it.json b/extensions/TimedMediaHandler/i18n/it.json
new file mode 100644
index 00000000..fe37c8b2
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/it.json
@@ -0,0 +1,108 @@
+{
+ "@metadata": {
+ "authors": [
+ ".anaconda",
+ "Beta16",
+ "BrokenArrow",
+ "Darth Kule",
+ "F. Cosoleto",
+ "Gianfranco",
+ "Raoli",
+ "Peg60"
+ ]
+ },
+ "timedmedia-desc": "Gestore per i file audio, video e con i sottotitoli; formati supportati: WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "File audio Ogg $1, $2",
+ "timedmedia-ogg-short-video": "File video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "File multimediale Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "File audio Ogg $1, durata $2, $3",
+ "timedmedia-ogg-long-video": "File video Ogg $1, durata $2, dimensioni $4×$5 pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "File audio/video multiplexed Ogg $1, durata $2, dimensioni $4×$5 pixel, complessivamente $3",
+ "timedmedia-ogg-long-general": "File multimediale Ogg, durata $2, $3",
+ "timedmedia-ogg-long-error": "File ogg non valido: $1",
+ "timedmedia-ogg-long-no-streams": "File multimediale Ogg. Attenzione: non è stato riconosciuto alcuno dei codec usati in questo file.",
+ "timedmedia-webm-short-video": "File video WebM $1, $2",
+ "timedmedia-webm-long-video": "File audio/video WebM $1, durata $2, dimensioni $4×$5 pixel, complessivamente $3",
+ "timedmedia-flac-short-audio": "File audio FLAC, $1",
+ "timedmedia-flac-long-audio": "File audio FLAC, durata $1, complessivamente $2",
+ "timedmedia-wav-short-audio": "File audio WAV, $1",
+ "timedmedia-wav-long-audio": "File audio WAV, durata $1, complessivamente $2",
+ "timedmedia-wav-pcm-required": "Puoi caricare solo PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "File video MP4 $1, $2",
+ "timedmedia-mp4-long-video": "File audio/video MP4 $1, durata $2, dimensioni $4×$5 pixel, complessivamente $3",
+ "timedmedia-no-player-js": "Si sta utilizzando un browser che ha JavaScript disattivato oppure non ha alcun riproduttore supportato.<br />\nÈ possibile <a href=\"$1\">scaricare il clip multimediale</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">un riproduttore</a> per riprodurre il clip nel proprio browser.",
+ "timedmedia-more": "Altro...",
+ "timedmedia-dismiss": "Chiudi",
+ "timedmedia-download": "Scarica il file",
+ "timedmedia-play-media": "Riproduci file multimediale",
+ "timedmedia-desc-link": "Informazioni su questo file",
+ "timedmedia-oggThumb-version": "OggHandler richiede la versione $1 o superiore di oggThumb.",
+ "timedmedia-oggThumb-failed": "oggThumb non è riuscito a creare la miniatura.",
+ "timedmedia-status-header": "Stato transcodifica",
+ "timedmedia-update-status": "Aggiorna stato transcodifica",
+ "timedmedia-status": "Stato",
+ "timedmedia-status-unknown": "Stato sconosciuto",
+ "timedmedia-transcodeinfo": "Formato",
+ "timedmedia-actions": "Azioni",
+ "timedmedia-direct-link": "Scarica",
+ "timedmedia-not-ready": "Non pronto",
+ "timedmedia-completed-on": "Completato $1",
+ "timedmedia-error-on": "Errore il $1",
+ "timedmedia-started-transcode": "Iniziato $1 fa. $2",
+ "timedmedia-percent-done": "$1% circa completato",
+ "timedmedia-in-job-queue": "Aggiunto alla coda di lavoro $1 fa",
+ "timedmedia-unknown-target-size": "Dimensioni di destinazione sconosciuta, $1 codificato",
+ "timedmedia-days": "{{PLURAL:$1|1 giorno|$1 giorni}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 ora|$1 ore}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuto|$1 minuti}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 secondo|$1 secondi}}",
+ "timedmedia-reset": "Resetta transcodifica",
+ "timedmedia-reset-confirm": "Resettando questa transcodifica tutti i file esistenti (se presenti) saranno cancellati e la transcodifica sarà nuovamente aggiunta alla coda di lavoro. Ci vorrà qualche tempo per rieseguire la transcodifica. <br /><br />\nContinuare?",
+ "timedmedia-reset-error": "Errore nel resettaggio della transcodifica.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Fonte $1",
+ "timedmedia-source-file-desc": "File originale $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "File originale $1 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Video Ogg a bassa larghezza di banda (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Video Ogg trasmettibile in streaming via Web (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Video Ogg trasmettibile in streaming via Web (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Video Ogg scaricabile in alta qualità (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Video Ogg scaricabile in Full HD (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM trasmettibile in streaming via Web (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM trasmettibile in streaming via Web (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM trasmettibile in streaming via Web (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM scaricabile in alta qualità (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "WebM scaricabile in Full HD (1080P)",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 per dispositivi compatibili (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 trasmettibile in streaming via Web (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 in qualità HD (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4 di qualità Full HD (1080P)",
+ "timedmedia-subtitle-new": "Creare una nuova traduzione o modificare esistenti",
+ "timedmedia-subtitle-new-desc": "Seleziona la lingua e premi il pulsante '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Vai",
+ "timedmedia-subtitle-language": "$1 ($2) sottotitoli",
+ "timedmedia-subtitle-no-video": "Non non c'è nessun video associato all'attuale pagina dei sottotitoli",
+ "timedmedia-subtitle-no-subtitles": "Non ci sono al momento sottotitoli in $1 per questo video, è possibile [{{fullurl:{{FULLPAGENAME}}|action=edit}} modificare questa pagina] per aggiungerli",
+ "timedmedia-subtitle-remote": "I sottotitoli per questo file sono ospitati su $1",
+ "timedmedia-subtitle-remote-link": "Puoi vedere la [$1 pagina di descrizione] per questo file su $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 video Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 video WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcodifica|$1 transcodifiche}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transcodifica|$1 transcodifiche}} in esecuzione",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transcodifica|$1 transcodifiche}} in coda",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transcodifica fallita|$1 transcodifiche fallite}}",
+ "timedmedia-file": "File",
+ "timedmedia-audios": "{{PLURAL:$1|$1 file audio}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 file audio Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 file audio FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 file audio WAV}}",
+ "right-transcode-reset": "Reimposta i video difettosi o transcodificati così che possano essere inclusi nuovamente in coda di lavoro.",
+ "right-transcode-status": "Visualizza [[Special:TimedMediaHandler|informazioni sull'attuale attività di transcodifica]]",
+ "action-transcode-status": "visualizzare l'attuale stato della transcodifica",
+ "orphanedtimedtext": "Pagine sottotitoli orfane",
+ "orphanedtimedtext-summary": "Elenco di pagine [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] che non hanno un file corrispondente.",
+ "orphanedtimedtext-unsupported": "Questa pagina speciale è supportata solo su database MySQL.",
+ "orphanedtimedtext-notimedtext": "TimedText non è abilitato su questo wiki."
+}
diff --git a/extensions/TimedMediaHandler/i18n/ja.json b/extensions/TimedMediaHandler/i18n/ja.json
new file mode 100644
index 00000000..291a5224
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ja.json
@@ -0,0 +1,91 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aotake",
+ "Fryed-peach",
+ "JtFuruhata",
+ "Kahusi",
+ "Shirayuki",
+ "青子守歌",
+ "Otokoume"
+ ]
+ },
+ "timedmedia-desc": "WebM、Ogg Theora、Vorbis、srt 形式に対応した、動画、音声、字幕のハンドラー",
+ "timedmedia-ogg-short-audio": "Ogg $1 音声ファイル、$2",
+ "timedmedia-ogg-short-video": "Ogg $1 動画ファイル、$2",
+ "timedmedia-ogg-short-general": "Ogg $1 メディアファイル、$2",
+ "timedmedia-ogg-long-audio": "Ogg $1 音声ファイル、長さ $2、$3",
+ "timedmedia-ogg-long-video": "Ogg $1 動画ファイル、長さ $2、$4 × $5 ピクセル、$3",
+ "timedmedia-ogg-long-multiplexed": "Ogg 多重音声/動画ファイル、$1、長さ $2、$4 × $5 ピクセル、全体で $3",
+ "timedmedia-ogg-long-general": "Ogg メディアファイル、長さ $2、$3",
+ "timedmedia-ogg-long-error": "無効な Ogg ファイル: $1",
+ "timedmedia-ogg-long-no-streams": "Ogg メディア ファイル。警告: このファイルで使用されているどのコーデックも認識できませんでした。",
+ "timedmedia-webm-short-video": "WebM $1 動画ファイル、$2",
+ "timedmedia-webm-long-video": "WebM 音声/動画ファイル、$1、長さ $2、$4 × $5 ピクセル、全体で $3",
+ "timedmedia-flac-short-audio": "FLAC 音声ファイル、$1",
+ "timedmedia-flac-long-audio": "FLAC 音声ファイル、長さ $1、全体で $2",
+ "timedmedia-wav-short-audio": "WAV 音声ファイル、$1",
+ "timedmedia-wav-long-audio": "WAV 音声ファイル、長さ $1、全体で $2",
+ "timedmedia-wav-pcm-required": "アップロードできるのは PCM (パルス符号変調) WAV のみです。",
+ "timedmedia-mp4-short-video": "MP4 $1 動画ファイル、$2",
+ "timedmedia-mp4-long-video": "MP4 音声/動画ファイル、$1、長さ $2、$4 × $5 ピクセル、全体で $3",
+ "timedmedia-no-player-js": "申し訳ありませんが、あなたのブラウザーではJavaScriptが無効になっているか、対応しているプレーヤーがありません。<br />\n再生するには、<a href=\"$1\">クリップをダウンロード</a>するか、<a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">プレーヤーをダウンロード</a>する必要があります。",
+ "timedmedia-more": "その他…",
+ "timedmedia-dismiss": "閉じる",
+ "timedmedia-download": "ファイルをダウンロードする",
+ "timedmedia-play-media": "メディアを再生する",
+ "timedmedia-desc-link": "ファイルの詳細",
+ "timedmedia-oggThumb-version": "OggHandler には oggThumb バージョン $1 またはそれ以降が必要です。",
+ "timedmedia-oggThumb-failed": "oggThumb によるサムネイル作成に失敗しました。",
+ "timedmedia-status": "状態",
+ "timedmedia-status-unknown": "不明な状態",
+ "timedmedia-transcodebitrate": "ビットレート",
+ "timedmedia-transcodeduration": "エンコード時間",
+ "timedmedia-transcodeinfo": "形式",
+ "timedmedia-actions": "操作",
+ "timedmedia-direct-link": "ダウンロード",
+ "timedmedia-not-ready": "準備ができていません",
+ "timedmedia-error-on": "$1 でのエラー",
+ "timedmedia-percent-done": "約 $1% 完了",
+ "timedmedia-in-job-queue": "$1前にジョブ キューに追加されました",
+ "timedmedia-days": "{{PLURAL:$1|$1 日}}",
+ "timedmedia-hours": "{{PLURAL:$1|$1 時間}}",
+ "timedmedia-minutes": "{{PLURAL:$1|$1 分}}",
+ "timedmedia-seconds": "{{PLURAL:$1|$1 秒}}",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 ソース",
+ "timedmedia-source-file-desc": "オリジナル $1 ファイル、$2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "オリジナル $1 ファイル ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "低帯域 Ogg 動画 (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "ウェブ ストリーミング可能 Ogg 動画 (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "ウェブ ストリーミング可能 Ogg 動画 (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "高品質ダウンロード可能 Ogg 動画 (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "フル HD ダウンロード可能 Ogg 動画 (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "ウェブ ストリーミング可能 WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "ウェブ ストリーミング可能 WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "ウェブ ストリーミング可能 WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "高品質ダウンロード可能 WebM (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "フル HD ダウンロード可能 WebM (1080P)",
+ "timedmedia-derivative-desc-320p.mp4": "デバイスフレンドリー MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "ウェブ ストリーミング可能 MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD 品質 MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "フル HD 品質 MP4 (1080P)",
+ "timedmedia-subtitle-new": "翻訳の新規作成、または既存の翻訳の編集",
+ "timedmedia-subtitle-new-desc": "言語を選択して、'''{{int:Timedmedia-subtitle-new-go}}'''ボタンを押してください。",
+ "timedmedia-subtitle-new-go": "実行",
+ "timedmedia-subtitle-language": "$1 ($2) 字幕",
+ "timedmedia-subtitle-no-video": "現在の字幕ページに関連付けられた動画はありません。",
+ "timedmedia-subtitle-no-subtitles": "現在、この動画には$1の字幕はありませんが、[{{fullurl:{{FULLPAGENAME}}|action=edit}} このページを編集]して追加できます。",
+ "timedmedia-subtitle-remote": "このファイルの字幕は$1でホストされています",
+ "timedmedia-subtitle-remote-link": "$2 でこのファイルの[$1 解説ページを閲覧]できます",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 件の動画}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 件の Ogg 動画}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 件の WebM 動画}}",
+ "timedmedia-file": "ファイル",
+ "timedmedia-audios": "{{PLURAL:$1|$1 件の音声ファイル}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 件の Ogg 音声ファイル}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 件の FLAC 音声ファイル}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 件の WAV 音声ファイル}}",
+ "apihelp-transcodereset-param-title": "メディアファイルのタイトル。"
+}
diff --git a/extensions/TimedMediaHandler/i18n/jut.json b/extensions/TimedMediaHandler/i18n/jut.json
new file mode 100644
index 00000000..c8c30c29
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/jut.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Huslåke",
+ "Jyllanj"
+ ]
+ },
+ "timedmedia-desc": "Håndlær før Ogg Theora og Vorbis filer, ve JavaScript spæler",
+ "timedmedia-ogg-short-audio": "Ogg $1 lydfile, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 videofil, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 mediafil, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 lydfil, længd $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 videofil, længd $2, $4×$5 pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "Sammelsatt Ogg-lyd- å -videofil, $1, længd $2, $4×$5 pixel, $3 sammeltj",
+ "timedmedia-ogg-long-general": "Ogg mediafil, længd $2, $3",
+ "timedmedia-ogg-long-error": "Udjylji Ogg-fil: $1",
+ "timedmedia-more": "Mier...",
+ "timedmedia-dismiss": "Lokk",
+ "timedmedia-download": "Lägg fil nier",
+ "timedmedia-desc-link": "Om fili"
+}
diff --git a/extensions/TimedMediaHandler/i18n/jv.json b/extensions/TimedMediaHandler/i18n/jv.json
new file mode 100644
index 00000000..0bb2c6ee
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/jv.json
@@ -0,0 +1,65 @@
+{
+ "@metadata": {
+ "authors": [
+ "Meursault2004",
+ "NoiX180",
+ "Pras"
+ ]
+ },
+ "timedmedia-desc": "Sing ngurusi berkas Ogg Theora lan Vorbis mawa pamain JavaScript",
+ "timedmedia-ogg-short-audio": "Berkas swara $1 ogg, $2",
+ "timedmedia-ogg-short-video": "Berkas vidéo $1 ogg, $2",
+ "timedmedia-ogg-short-general": "Berkas média $1 ogg, $2",
+ "timedmedia-ogg-long-audio": "Berkas swara $1 ogg, dawané $2, $3",
+ "timedmedia-ogg-long-video": "Berkas vidéo $1 ogg, dawané $2, $4×$5 piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Berkas audio/vidéo multiplexed ogg, $1, dawané $2, $4×$5 piksel, $3 gunggungé",
+ "timedmedia-ogg-long-general": "Berkas média ogg, dawané $2, $3",
+ "timedmedia-ogg-long-error": "Berkas ogg ora absah: $1",
+ "timedmedia-more": "Luwih akèh...",
+ "timedmedia-dismiss": "Tutup",
+ "timedmedia-download": "Undhuh berkas",
+ "timedmedia-play-media": "Puter média",
+ "timedmedia-desc-link": "Prekara berkas iki",
+ "timedmedia-oggThumb-version": "OggHandler mbutuhaké oggThumb vèrsi $1 utawa sakbanjuré.",
+ "timedmedia-oggThumb-failed": "oggTumb gagal nggawé gambar mini.",
+ "timedmedia-status-header": "Status transkodhé",
+ "timedmedia-update-status": "Anyari status transkodhé",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Status ora dingertèni",
+ "timedmedia-transcodeinfo": "Katrangan turunan transkodhé",
+ "timedmedia-actions": "Laku",
+ "timedmedia-direct-link": "Undhuh turunan",
+ "timedmedia-not-ready": "Durung siap",
+ "timedmedia-completed-on": "Nglengkapi transkodhé $1",
+ "timedmedia-error-on": "Kasalahan nèng transkodhé $1.",
+ "timedmedia-started-transcode": "Transkodhé lekas $1 kapungkur. $2",
+ "timedmedia-percent-done": "Kira-kira $1 rampung",
+ "timedmedia-in-job-queue": "Nambahaké nèng antrian Pakaryan $1 kapungkur",
+ "timedmedia-unknown-target-size": "Gedhé patujon oradingertèni, $1 kasandhèkaké",
+ "timedmedia-days": "{{PLURAL:$1|dina|dina}}",
+ "timedmedia-hours": "{{PLURAL:$1|jam|jam}}",
+ "timedmedia-minutes": "{{PLURAL:$1|menit|menit}}",
+ "timedmedia-seconds": "{{PLURAL:$1|detik|detik}}",
+ "timedmedia-reset": "Setèl ulang transkodhé",
+ "timedmedia-reset-error": "Kasalahan nalika nyetèl ulang tugas transkodhé.",
+ "timedmedia-source-file": "Sumber $1",
+ "timedmedia-source-file-desc": "$1 asli, $2 × $3 ($4)",
+ "timedmedia-derivative-desc-160p.ogv": "Vidio Ogg bandwidth cilik (160P)",
+ "timedmedia-derivative-desc-720p.ogv": "Vidio Ogg sing bisa diundhuh mawa kualitas dhuwur (720P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM sing bisa diundhuh mawa kualitas dhuwur (720P)",
+ "timedmedia-subtitle-new": "Gawé terjemahan anyar utawa sunting sing wis ana",
+ "timedmedia-subtitle-new-desc": "Ganti bagéyan '''$1''' nganggo [[:en:ISO 639|kodhé basa]] Sampéyan lan pencèt tombol '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Nuju",
+ "timedmedia-subtitle-language": "Subjudhul $1 ($2)",
+ "timedmedia-subtitle-no-video": "Ora ana vidio sing cocok karo kaca subjudhul saiki",
+ "timedmedia-subtitle-no-subtitles": "Sawetara durung ana subjudhul nèng $1 kanggo vidio iki, Sampéyan bisa [{{fullurl:{{FULLPAGENAME}}|action=edit}} nyunting kaca iki] kanggo nambahi",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 vidio|$1 vidio}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 vidio Ogg|$1 vidio Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 vidio WebM|$1 vidio WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transkodhé|$1 transkodhé}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transkodhé lumangsung|$1 transkodhé lumangsung}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transkodhé ngantri|$1 transkodhé ngantri}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transkodhé gagal|$1 transkodhé gagal}}",
+ "timedmedia-file": "Berkas"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ka.json b/extensions/TimedMediaHandler/i18n/ka.json
new file mode 100644
index 00000000..5c43ea7b
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ka.json
@@ -0,0 +1,89 @@
+{
+ "@metadata": {
+ "authors": [
+ "BRUTE",
+ "David1010",
+ "Malafaya",
+ "Tokoko",
+ "გიორგიმელა"
+ ]
+ },
+ "timedmedia-desc": "აუდიოს, ვიდეოს და სუბტიტრების დამამუშავებელი, შემდეგი ფორმატების მხარდაჭერით: WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 ხმოვანი ფაილი, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 ვიდეო ფაილი, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 მედია ფაილი, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 ხმოვანი ფაილი, სიგრძე $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 ვიდეო ფაილი, სიგრძე $2, $4 × $5 პიქსელი, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg მულტიპლექსური აუდიო/ვიდეო ფაილი, $1, სიგრძე $2, $4 × $5 პიქსელი, $3 სრული",
+ "timedmedia-ogg-long-general": "Ogg მედია ფაილი, სიგრძე $2, $3",
+ "timedmedia-ogg-long-error": "არასწორი Ogg-ფაილი: $1",
+ "timedmedia-webm-short-video": "WebM $1 ვიდეო ფაილი, $2",
+ "timedmedia-webm-long-video": "WebM აუდიო/ვიდეო ფაილი, $1, სიგრძე $2, $4 × $5 პიქსელი, $3 სრული",
+ "timedmedia-flac-short-audio": "FLAC აუდიო ფაილი, $1",
+ "timedmedia-wav-short-audio": "WAV აუდიო ფაილი, $1",
+ "timedmedia-mp4-short-video": "MP4 $1 ვიდეო ფაილი, $2",
+ "timedmedia-mp4-long-video": "MP4 აუდიო/ვიდეო ფაილი, $1, სიგრძე $2, $4 × $5 პიქსელი, $3 სრული",
+ "timedmedia-no-player-js": "სამწუხაროდ, თქვენ ბრაუზერში გამორთულია JavaScript ან არ არის საჭირო დამკვრელი.<br />\nთქვენ შეგიძლიათ <a href=\"$1\">გადმოწეროთ კლიპი</a> ან <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">გადმოწეროთ დამკვრელი</a> კლიპის ბრაუზერში დასაკრავად.",
+ "timedmedia-more": "მეტი...",
+ "timedmedia-dismiss": "დახურვა",
+ "timedmedia-download": "ფაილის ჩამოტვირთვა",
+ "timedmedia-play-media": "მედია-ფაილის დაკვრა",
+ "timedmedia-desc-link": "ამ ფაილის შესახებ",
+ "timedmedia-oggThumb-version": "OggHandler-ს სჭირდება oggThumb-ის ვერსია $1 ან უფრო გვიანდელი.",
+ "timedmedia-oggThumb-failed": "oggThumb-მა ვერ მოახერხა მინიატიურის შექმნა.",
+ "timedmedia-status-header": "დეკოდირების სტატუსი",
+ "timedmedia-update-status": "დეკოდირების სტატუსის განახლება",
+ "timedmedia-status": "სტატუსი",
+ "timedmedia-status-unknown": "უცნობი სტატუსი",
+ "timedmedia-transcodeinfo": "ფორმატი",
+ "timedmedia-actions": "მოქმედება",
+ "timedmedia-direct-link": "გადმოწერა",
+ "timedmedia-not-ready": "არაა მზად",
+ "timedmedia-completed-on": "$1-ის დეკოდირება დასრულებულია",
+ "timedmedia-error-on": "შეცდომა დეკოდირებისას $1-ზე.",
+ "timedmedia-started-transcode": "დეკოდირება გაშვებულია $1 წინ. $2",
+ "timedmedia-percent-done": "დაახლოებით $1% შესრულებულია",
+ "timedmedia-in-job-queue": "დამატებულია დავალებების რიგში $1 წინ",
+ "timedmedia-unknown-target-size": "უცნობი სამიზნო ზომა, $1 კოდირებისას",
+ "timedmedia-days": "{{PLURAL:$1|1 დღე|$1 დღე}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 საათი|$1 საათი}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 წუთი|$1 წუთი}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 წამი|$1 წამი}}",
+ "timedmedia-reset": "დეკოდირების თავიდან დაყენება",
+ "timedmedia-reset-confirm": "დეკოდირების თავიდან დაყენება წაშლის არსებულ ფაილს (თუკი ის არსებობს) და დეკოდირება კვლავ დაემატება დავალებების რიგში. განმეორებით დეკოდირებას დაჭირდება გარკვეული დრო. <br /><br />\nდარწმუნებული ხართ, რომ გსურთ გააგრძელოთ?",
+ "timedmedia-reset-error": "შეცდომა დეკოდირების თავიდან დაყენებისას.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "წყარო $1",
+ "timedmedia-source-file-desc": "ორიგინალი $1 ფაილი, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "ორიგინალი $1 ფაილი ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "დაბალი ხარისხის Ogg-ვიდეო (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "ვებ-ნაკადური Ogg-ვიდეო (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "ვებ-ნაკადური Ogg-ვიდეო (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "მაღალი ხარისხის გადმოწერადი Ogg-ვიდეო (720P)",
+ "timedmedia-derivative-desc-160p.webm": "ვებ-ნაკადური WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "ვებ-ნაკადური WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "ვებ-ნაკადური WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "მაღალი ხარისხის გადმოწერადი WebM (720P)",
+ "timedmedia-derivative-desc-320p.mp4": "მეგობრული-მოწყობილობა MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "ვებ-ნაკადური MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD ხარისხი MP4 (720P)",
+ "timedmedia-subtitle-new": "შექმენით ახალი თარგმანი ან დაარედაქტირეთ არსებული",
+ "timedmedia-subtitle-new-desc": "აირჩიეთ ენა და დააჭირეთ ღილაკს '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "მიდი",
+ "timedmedia-subtitle-language": "$1 ($2) სუბტიტრები",
+ "timedmedia-subtitle-no-video": "აქ არ არის ვიდეო, რომელიც დაკავშირებულია სუბტიტრების მიმდინარე გვერდთან",
+ "timedmedia-subtitle-no-subtitles": "ამჟამად $1 სუბტიტრები ამ ვიდეოსათვის არ არის, თქვენ შეგიძლიათ [{{fullurl:{{FULLPAGENAME}}|action=edit}} შეცვალოთ ეს გვერდი] მათ დასამატებლად",
+ "timedmedia-subtitle-remote": "ამ ფაილის დროებითი ტექსტი განთავსებულია $1-ზე",
+ "timedmedia-subtitle-remote-link": "თქვენ შეგიძლიათ [$1 იხილოთ ამ ფაილის აღწერის გვერდი] $2-ზე",
+ "timedmediahandler": "დროული მედია მართვის პროგრამა",
+ "timedmedia-videos": "{{PLURAL:$1|$1 ვიდეო|$1 ვიდეო}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg ვიდეო|$1 Ogg ვიდეო}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM ვიდეო|$1 WebM ვიდეო}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 დეკოდირებული|$1 დეკოდირებული}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|მიმდინარეობს $1 დეკოდირება|მიმდინარეობს $1 დეკოდირება}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|რიგშია $1 დეკოდირება|რიგშია $1 დეკოდირება}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 დეკოდირება ჩაიშალა|$1 დეკოდირება ჩაიშალა}}",
+ "timedmedia-file": "ფაილი",
+ "right-transcode-status": "იხილეთ [[Special:TimedMediaHandler|ინფორმაცია მიმდინარე დეკოდირების შესახებ]]",
+ "action-transcode-status": "იხილეთ მიმდინარე დეკოდირების სტატუსი"
+}
diff --git a/extensions/TimedMediaHandler/i18n/khw.json b/extensions/TimedMediaHandler/i18n/khw.json
new file mode 100644
index 00000000..821b2a13
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/khw.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Rachitrali"
+ ]
+ },
+ "timedmedia-no-player-js": "معذرت، تہ براؤزرا جاواسکرپٹ فعال نیکی یا کیہ معاون پلیئر شامل نیکی۔<br />\nھیہ کلپو تان براؤزرا چلئیکو بچے تو ھیہ <a href=\"$1\">کلپو ڈاؤنلوڈ</a> کورے یا </a> or <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\">پلیئر ڈاؤنلوڈ</a> کورے۔",
+ "timedmedia-source-file": "$1 مسودہ",
+ "timedmedia-source-audio-file-desc": "اصلی $1 فائل($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/kk-arab.json b/extensions/TimedMediaHandler/i18n/kk-arab.json
new file mode 100644
index 00000000..e348e4d2
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/kk-arab.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": [],
+ "timedmedia-ogg-short-audio": "Ogg $1 دىبىس فايلى, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 بەينە فايلى, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 تاسپا فايلى, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 دىبىس فايلى, ۇزاقتىعى $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 بەينە فايلى, ۇزاقتىعى $2, $4 × $5 پىيكسەل, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg قۇرامدى دىبىس/بەينە فايلى, $1, ۇزاقتىعى $2, $4 × $5 پىيكسەل, $3 نە بارلىعى",
+ "timedmedia-ogg-long-general": "Ogg تاسپا فايلى, ۇزاقتىعى $2, $3",
+ "timedmedia-ogg-long-error": "جارامسىز ogg فايلى: $1",
+ "timedmedia-more": "كوبىرەك...",
+ "timedmedia-dismiss": "جابۋ",
+ "timedmedia-download": "فايلدى جۇكتەۋ",
+ "timedmedia-desc-link": "بۇل فايل تۋرالى"
+}
diff --git a/extensions/TimedMediaHandler/i18n/kk-cyrl.json b/extensions/TimedMediaHandler/i18n/kk-cyrl.json
new file mode 100644
index 00000000..c378cf48
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/kk-cyrl.json
@@ -0,0 +1,56 @@
+{
+ "@metadata": {
+ "authors": [
+ "Arystanbek"
+ ]
+ },
+ "timedmedia-ogg-short-audio": "Ogg $1 дыбыс файлы, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 бейне файлы, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 таспа файлы, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 дыбыс файлы, ұзақтығы $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 бейне файлы, ұзақтығы $2, $4 × $5 пиксел, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg құрамды дыбыс/бейне файлы, $1, ұзақтығы $2, $4 × $5 пиксел, $3 не барлығы",
+ "timedmedia-ogg-long-general": "Ogg таспа файлы, ұзақтығы $2, $3",
+ "timedmedia-ogg-long-error": "Жарамсыз ogg файлы: $1",
+ "timedmedia-webm-short-video": "WebM $1 видео файл, $2",
+ "timedmedia-flac-short-audio": "FLAC аудио файл, $1",
+ "timedmedia-flac-long-audio": "FLAC аудио файл, ұзындығы $1, битрейт — $2",
+ "timedmedia-wav-short-audio": "WAV аудио файл, $1",
+ "timedmedia-wav-long-audio": "WAV аудио файл, $1 ұзындығы $1, битрейт — $2",
+ "timedmedia-mp4-short-video": "MP4 $1 видео файл, $2",
+ "timedmedia-more": "Көбірек...",
+ "timedmedia-dismiss": "Жабу",
+ "timedmedia-download": "Файлды жүктеу",
+ "timedmedia-play-media": "Медианы көрсету",
+ "timedmedia-desc-link": "Бұл файл туралы",
+ "timedmedia-status": "Статусы",
+ "timedmedia-status-unknown": "Белгісіз статус",
+ "timedmedia-actions": "Әрекеттер",
+ "timedmedia-not-ready": "Дайын емес",
+ "timedmedia-days": "{{PLURAL:$1|1 күн|$1 күн}}",
+ "timedmedia-hours": "{{PLURAL:$1|бір сағат|$1 сағат}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 минут|$1 минут}}",
+ "timedmedia-seconds": "{{PLURAL:$1|$ секунт|секунт}}",
+ "timedmedia-source-file": "$1 қайнар",
+ "timedmedia-derivative-desc-160p.ogv": "Төменгі сапалы Ogg видео (160P)",
+ "timedmedia-derivative-desc-720p.ogv": "Жоғары сападағы жүктелінетін Ogg видео (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Толық HD жұктелінетін Ogg видео (1080P)",
+ "timedmedia-derivative-desc-720p.webm": "Жоғары сападағы жүктелінетін WebM (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "Толық HD жұктелінетін WebM (1080P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD сапа MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Толық HD сапа MP4 (1080P)",
+ "timedmedia-subtitle-new": "Жаңа аударма бастау немесе барын өңдеу",
+ "timedmedia-subtitle-new-desc": "Тілді таңдаңыз және '''{{int:Timedmedia-subtitle-new-go}}''' батырмасын басыңыз",
+ "timedmedia-subtitle-new-go": "Өту",
+ "timedmedia-subtitle-language": "$1 ($2) субтитрлер",
+ "timedmedia-videos": "{{PLURAL:$1|$1 видео|$1 видеолар}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg видео|$1 Ogg видеолар}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM видео|$1 WebM видеолар}}",
+ "timedmedia-file": "Файл",
+ "timedmedia-audios": "{{PLURAL:$1|$1 аудио файл|$1 аудио файлдар}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg аудио файл|$1 Ogg аудио файлдар}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC аудио файл|$1 FLAC аудио файлдар}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV аудио файл|$1 WAV аудио файлдар}}",
+ "right-transcode-status": "[[Special:TimedMediaHandler|information about the current transcode activity]] көру",
+ "apihelp-transcodereset-param-title": "Медиа файл тақырыбы."
+}
diff --git a/extensions/TimedMediaHandler/i18n/kk-latn.json b/extensions/TimedMediaHandler/i18n/kk-latn.json
new file mode 100644
index 00000000..ef140659
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/kk-latn.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": [],
+ "timedmedia-ogg-short-audio": "Ogg $1 dıbıs faýlı, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 beýne faýlı, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 taspa faýlı, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 dıbıs faýlı, uzaqtığı $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 beýne faýlı, uzaqtığı $2, $4 × $5 pïksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg quramdı dıbıs/beýne faýlı, $1, uzaqtığı $2, $4 × $5 pïksel, $3 ne barlığı",
+ "timedmedia-ogg-long-general": "Ogg taspa faýlı, uzaqtığı $2, $3",
+ "timedmedia-ogg-long-error": "Jaramsız ogg faýlı: $1",
+ "timedmedia-more": "Köbirek...",
+ "timedmedia-dismiss": "Jabw",
+ "timedmedia-download": "Faýldı jüktew",
+ "timedmedia-desc-link": "Bul faýl twralı"
+}
diff --git a/extensions/TimedMediaHandler/i18n/km.json b/extensions/TimedMediaHandler/i18n/km.json
new file mode 100644
index 00000000..47cf1d5e
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/km.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Chhorran",
+ "Lovekhmer",
+ "T-Rithy",
+ "Thearith",
+ "គីមស៊្រុន"
+ ]
+ },
+ "timedmedia-desc": "គាំទ្រចំពោះ Ogg Theora និង Vorbis files, ជាមួយ ឧបករណ៍អាន JavaScript",
+ "timedmedia-ogg-short-audio": "ឯកសារ សំឡេង Ogg $1, $2",
+ "timedmedia-ogg-short-video": "ឯកសារវីដេអូ Ogg $1, $2",
+ "timedmedia-ogg-short-general": "ឯកសារមេឌាOgg $1, $2",
+ "timedmedia-ogg-long-audio": "ឯកសារសំឡេងប្រភេទOgg $1, រយៈពេល$2 និងទំហំ$3",
+ "timedmedia-ogg-long-video": "ឯកសារវីដេអូប្រភេទOgg $1, រយៈពេល$2, $4×$5px, $3",
+ "timedmedia-ogg-long-multiplexed": "ឯកសារអូឌីយ៉ូ/វីដេអូចម្រុះប្រភេទOgg , $1, រយៈពេល$2, $4×$5px, ប្រហែល$3",
+ "timedmedia-ogg-long-general": "ឯកសារមេឌាប្រភេទOgg, រយៈពេល$2, $3",
+ "timedmedia-ogg-long-error": "ឯកសារ ogg មិនមាន សុពលភាព ៖ $1",
+ "timedmedia-more": "បន្ថែម...",
+ "timedmedia-dismiss": "បិទ",
+ "timedmedia-download": "ទាញយកឯកសារ",
+ "timedmedia-desc-link": "អំពីឯកសារនេះ"
+}
diff --git a/extensions/TimedMediaHandler/i18n/kn.json b/extensions/TimedMediaHandler/i18n/kn.json
new file mode 100644
index 00000000..4b39e37d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/kn.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "VASANTH S.N.",
+ "Omshivaprakash"
+ ]
+ },
+ "timedmedia-more": "ಹೆಚ್ಚು...",
+ "timedmedia-dismiss": "ಮುಚ್ಚಿ",
+ "timedmedia-desc-link": "ಈ ಆಟದ ಬಗ್ಗೆ",
+ "timedmedia-status": "ಸ್ಥಾನಮಾನ",
+ "timedmedia-actions": "ಕ್ರಿಯೆಗಳು",
+ "timedmedia-source-file": "$1 ಮೂಲ",
+ "timedmedia-source-audio-file-desc": "ಅಸಲು $1 ಕಡತ ($2)",
+ "timedmedia-subtitle-new-go": "ಹೋಗು",
+ "timedmedia-file": "ಕಡತ"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ko.json b/extensions/TimedMediaHandler/i18n/ko.json
new file mode 100644
index 00000000..b0d45e53
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ko.json
@@ -0,0 +1,104 @@
+{
+ "@metadata": {
+ "authors": [
+ "ITurtle",
+ "Kwj2772",
+ "Priviet",
+ "ToePeu",
+ "아라",
+ "Hym411",
+ "Revi",
+ "IRTC1015",
+ "Hwangjy9",
+ "Kurousagi"
+ ]
+ },
+ "timedmedia-desc": "WebM, OGG Theora, Vorbis, srt를 위한 포맷 지원과 소리, 동영상과 자막을 위한 핸들러",
+ "timedmedia-ogg-short-audio": "Ogg $1 소리 파일, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 동영상 파일, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 미디어 파일, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 소리 파일, 길이 $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 동영상 파일, 길이 $2, $4 × $5 픽셀, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg 다중 소리/동영상 파일, $1, 길이 $2, $4 × $5 픽셀, 대략 $3",
+ "timedmedia-ogg-long-general": "Ogg 미디어 파일, 길이 $2, $3",
+ "timedmedia-ogg-long-error": "잘못된 Ogg 파일: $1",
+ "timedmedia-ogg-long-no-streams": "Ogg 미디어 파일입니다. 경고: 이 파일에 사용된 코덱을 알 수 없습니다.",
+ "timedmedia-webm-short-video": "WebM $1 동영상 파일, $2",
+ "timedmedia-webm-long-video": "WebM 소리/동영상 파일, $1, 길이 $2, $4 × $5픽셀, 대략 $3",
+ "timedmedia-flac-short-audio": "FLAC 소리 파일, $1",
+ "timedmedia-flac-long-audio": "FLAC 소리 파일, 길이 $1, 대략 $2",
+ "timedmedia-wav-short-audio": "WAV 소리 파일, $1",
+ "timedmedia-wav-long-audio": "WAV 소리 파일, 길이 $1, 대략 $2",
+ "timedmedia-wav-pcm-required": "PCM(펄스 부호 변조) WAV만 올릴 수 있습니다.",
+ "timedmedia-mp4-short-video": "MP4 $1 동영상 파일, $2",
+ "timedmedia-mp4-long-video": "MP4 소리/동영상 파일, $1, 길이 $2, $4 × $5픽셀, 대략 $3",
+ "timedmedia-no-player-js": "죄송합니다, 시스템은 자바스크립트를 지원하지 않거나 지원하는 미디어 플레이어가 설치되어 있지 않습니다.<br />\n<a href=\"$1\">미디어 클립을 다운로드</a>하거나, <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">미디어 플레이어를 다운로드</a>할 수 있습니다.",
+ "timedmedia-more": "더 보기…",
+ "timedmedia-dismiss": "닫기",
+ "timedmedia-download": "파일 다운로드",
+ "timedmedia-play-media": "미디어 재생",
+ "timedmedia-desc-link": "이 파일에 대한 정보",
+ "timedmedia-oggThumb-version": "OggHandler는 oggThumb 버전 $1 이상이 필요합니다.",
+ "timedmedia-oggThumb-failed": "oggThumb가 섬네일을 만들지 못했습니다.",
+ "timedmedia-status-header": "코드 변환 상태",
+ "timedmedia-update-status": "코드 변환 상태 업데이트",
+ "timedmedia-status": "상태",
+ "timedmedia-status-unknown": "알 수 없는 상태",
+ "timedmedia-transcodeinfo": "형식",
+ "timedmedia-actions": "동작",
+ "timedmedia-direct-link": "다운로드",
+ "timedmedia-not-ready": "준비하지 않음",
+ "timedmedia-completed-on": "$1 완료",
+ "timedmedia-error-on": "$1에 오류",
+ "timedmedia-started-transcode": "$1 전에 시작되었습니다. $2",
+ "timedmedia-percent-done": "약 $1% 완료",
+ "timedmedia-in-job-queue": "$1 전에 작업 대기열에 추가됨",
+ "timedmedia-unknown-target-size": "알 수 없는 대상 크기, $1 인코드함",
+ "timedmedia-days": "{{PLURAL:$1|1일|$1일}}",
+ "timedmedia-hours": "{{PLURAL:$1|1시간|$1시간}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1분|$1분}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1초|$1초}}",
+ "timedmedia-reset": "코드 변환 초기화",
+ "timedmedia-reset-confirm": "코드 변환을 초기화하면 기존 파일이 (있는 경우) 제거되며, 작업 대기열로 코드 변환을 다시 추가합니다. 다시 변환하는 데 다소 시간이 걸릴 것입니다. <br /><br />\n계속하겠습니까?",
+ "timedmedia-reset-error": "코드 변환 작업을 초기화하는 데 오류가 났습니다.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 원본",
+ "timedmedia-source-file-desc": "원본 $1 파일, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "원본 $1 파일 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "낮은 대역폭 Ogg 비디오 (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "웹 스트리밍 가능 Ogg 동영상 (240P)",
+ "timedmedia-derivative-desc-360p.ogv": "웹 스트리밍 가능 Ogg 동영상 (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "웹 스트리밍 가능 Ogg 동영상 (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "고화질 다운로드 가능 Ogg 동영상 (720P)",
+ "timedmedia-derivative-desc-160p.webm": "웹 스트리밍 가능 WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "웹 스트리밍 가능 WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "웹 스트리밍 가능 WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "고화질 다운로드 가능 WebM (720P)",
+ "timedmedia-derivative-desc-320p.mp4": "장치 친화적 MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "웹 스트리밍 가능 MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD 품질 MP4 (720P)",
+ "timedmedia-subtitle-new": "새 번역 만들기 또는 기존 번역 편집",
+ "timedmedia-subtitle-new-desc": "언어를 선택하고 '''{{int:Timedmedia-subtitle-new-go}}''' 버튼을 누르세요",
+ "timedmedia-subtitle-new-go": "가기",
+ "timedmedia-subtitle-language": "$1 ($2) 자막",
+ "timedmedia-subtitle-no-video": "현재 자막 페이지와 관련된 동영상이 없습니다",
+ "timedmedia-subtitle-no-subtitles": "현재 이 동영상에 대한 $1에 자막이 없습니다, 추가하려면 [{{fullurl:{{FULLPAGENAME}}|action=edit}} 이 문서를 편집할] 수 있습니다.",
+ "timedmedia-subtitle-remote": "이 파일에 대한 자막은 $1에 호스트했습니다",
+ "timedmedia-subtitle-remote-link": "$2에 이 파일에 대한 [$1 설명 문서를 볼] 수 있습니다",
+ "timedmediahandler": "자막미디어핸들러",
+ "timedmedia-videos": "{{PLURAL:$1|동영상 $1개}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|Ogg 동영상 $1개}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|WebM 동영상 $1개}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|코드 변환 $1개}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|실행 중인 코드 변환 $1개}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|대기 중인 코드 변환 $1개}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|실패한 코드 변환 $1개}}",
+ "timedmedia-file": "파일",
+ "timedmedia-audios": "{{PLURAL:$1|오디오 파일 $1개}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|Ogg 오디오 파일 $1개}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|FLAC 오디오 파일 $1개}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|WAV 오디오 파일 $1개}}",
+ "right-transcode-reset": "변환됐거나 실패한 비디오를 작업 대기열에 다시 추가되도록 초기화",
+ "right-transcode-status": "[[Special:TimedMediaHandler|현재 코드 변환 활동에 대한 정보]] 보기",
+ "action-transcode-status": "현재 코드 변환 상태 보기"
+}
diff --git a/extensions/TimedMediaHandler/i18n/krc.json b/extensions/TimedMediaHandler/i18n/krc.json
new file mode 100644
index 00000000..e27d9595
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/krc.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Iltever"
+ ]
+ },
+ "timedmedia-no-player-js": "Джарсыугъа, сизни браузеригизде JavaScript джукъланыбды неда керекли ойнатыучу джокъду.<br />\nСиз <a href=\"$1\">клипни эндирирге</a> неда клипни браузерде ойнатыр ючюн <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">ойнатыучу эндирирге</a> боллукъсуз.",
+ "timedmedia-more": "Энтда…",
+ "timedmedia-source-file": "$1 къайнагъы",
+ "timedmedia-source-audio-file-desc": "Оригинал $1-файл ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/krj.json b/extensions/TimedMediaHandler/i18n/krj.json
new file mode 100644
index 00000000..32fffc84
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/krj.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jose77"
+ ]
+ },
+ "timedmedia-more": "Raku pa..."
+}
diff --git a/extensions/TimedMediaHandler/i18n/ksh.json b/extensions/TimedMediaHandler/i18n/ksh.json
new file mode 100644
index 00000000..0dacd011
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ksh.json
@@ -0,0 +1,81 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "timedmedia-desc": "E Projamm (<i lang=\"en\">handler</i>) för Meedije met Zickaandeil\n— Viddejos, Tondatteieje, <i lang=\"en\">timedText</i> (Ongertittelle) —\nmet Ongershtözung för de Fommaate <i lang=\"en\">WebM</i>, <i lang=\"en\">Ogg Theora</i>, <i lang=\"en\">Vorbis</i> un <i lang=\"en\">srt</i>.",
+ "timedmedia-ogg-short-audio": "<i lang=\"en\">Ogg $1</i> Tondatei, $2",
+ "timedmedia-ogg-short-video": "<i lang=\"en\">Ogg $1</i> Viddejodatei, $2",
+ "timedmedia-ogg-short-general": "<i lang=\"en\">Ogg $1</i> Medijedatei, $2",
+ "timedmedia-ogg-long-audio": "<i lang=\"en\">Ogg $1</i> Tondatei fum Ömfang $2, $3",
+ "timedmedia-ogg-long-video": "<i lang=\"en\">Ogg $1</i> Viddejodatei fum Ömfang $2 un {{PLURAL:$4|ein Pixel|$4 Pixelle|kei Pixel}} × {{PLURAL:$5|ei Pixel|$4 Pixelle|kei Pixel}}, $3",
+ "timedmedia-ogg-long-multiplexed": "<i lang=\"en\">Ogg</i> jemultipex Ton- un Viddejodatei, $1, fum Ömfang $2 un {{PLURAL:$4|ein Pixel|$4 Pixelle|kei Pixel}} × {{PLURAL:$5|ei Pixel|$4 Pixelle|kei Pixel}}, $3 ennsjesammp",
+ "timedmedia-ogg-long-general": "<i lang=\"en\">Ogg</i> Medijedatei fum Ömfang $2, $3",
+ "timedmedia-ogg-long-error": "En kapodde <i lang=\"en\">Ogg</i>-Dattei: $1",
+ "timedmedia-webm-short-video": "En $1 Viddejo-Dattei em WebM-Fommaat vun $2",
+ "timedmedia-webm-long-video": "Ene Viddejo udder en Toondattei em WebM-Fommaat, $1, $2 jruuß, $4 × $5 Pixelle, $3 enßjesammp",
+ "timedmedia-no-player-js": "Schad, Dinge Brauser hät entweder JavaSkrepp ußjeschalldt udder kein zopaß Projramm zom Afschpelle.<br />Do kanns jäz <a href=\"$1\">dat Stöck eronger laade</a> udder <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">e Afspeller-Projramm eronger laade</a>, öm dat Schtök en Dingem Brauser afzeschpelle.",
+ "timedmedia-more": "Enshtelle&nbsp;…",
+ "timedmedia-dismiss": "Zohmaache!",
+ "timedmedia-download": "Dattei eronger lahde",
+ "timedmedia-play-media": "Afshpelle",
+ "timedmedia-desc-link": "Övver di Dattei",
+ "timedmedia-oggThumb-version": "Dä <code lang=\"en\">OggHandler</code> bruch <code lang=\"en\">oggThumb</code> in dä Version $1 udder hüüter.",
+ "timedmedia-oggThumb-failed": "<code lang=\"en\">oggThumb</code> kunnt kei MiniBelldsche maache.",
+ "timedmedia-status": "Zohschtand",
+ "timedmedia-status-unknown": "Onbikannte Zohschtand",
+ "timedmedia-direct-link": "Afflähjer eronger lahde",
+ "timedmedia-not-ready": "Nit parraht",
+ "timedmedia-started-transcode": "De Ömwandlong hät vör $1 bejonne. $2 sin jedonn.",
+ "timedmedia-percent-done": "öm de $1% jedonn",
+ "timedmedia-in-job-queue": "En de Waadeschlang met de Aufjahbe jedonn vör $1",
+ "timedmedia-days": "{{PLURAL:$1|einem Daach|$1 Dääsch|keinem Daach}}",
+ "timedmedia-hours": "{{PLURAL:$1|eine Schtond|$1 Schtonde|keinem Schtond}}",
+ "timedmedia-minutes": "{{PLURAL:$1|eine Menutt|$1 Menutte|keine Menutt}}",
+ "timedmedia-seconds": "{{PLURAL:$1|eine Sekund|$1 Sekunde|keine Sekund}}",
+ "timedmedia-ogg": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"\">Ogg</i>",
+ "timedmedia-webm": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"\">WebM</i>",
+ "timedmedia-mp4": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Moving Picture Experts Group - „Expäätejropp för bewääschte Belder“ - Väsjohn 4\">MP4</i>",
+ "timedmedia-wav": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"RIFF WAVE - Resource Interchange File Format - för de Wälle vun Töhn\">WAV</i>",
+ "timedmedia-flac": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Free Lossless Audio Codec „Freije verloßfreie Kodehrer un Dekodehrer vun Töhn“\">FLAC</i>",
+ "timedmedia-source-file": "Quell-Dattei em $1-Fommaat",
+ "timedmedia-source-file-desc": "Ojinahl $1-Dattei, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Ojinahl $1-Dattei ($2)",
+ "timedmedia-derivative-160p.ogv": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Ogg Vorbis\">Ogg</i> 160P",
+ "timedmedia-derivative-desc-160p.ogv": "En Viddejo-Dattei met winnesch Bandbreide (160P) em <i lang=\"en\">Ogg</i>-Fommaat",
+ "timedmedia-derivative-360p.ogv": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Ogg Vorbis\">Ogg</i> 360P",
+ "timedmedia-derivative-desc-360p.ogv": "En Viddejo-Dattei em <i lang=\"en\">Ogg</i>-Fommaat (360p) för ene Dahteshtrohm övver et Nez",
+ "timedmedia-derivative-480p.ogv": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Ogg Vorbis\">Ogg</i> 480P",
+ "timedmedia-derivative-desc-480p.ogv": "En Viddejo-Dattei (met 480p) em <i lang=\"en\">Ogg</i>-Fommaat för ene Dahteshtrohm övver et Nez",
+ "timedmedia-derivative-720p.ogv": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Ogg Vorbis\">Ogg</i> 720P",
+ "timedmedia-derivative-desc-720p.ogv": "En Viddejo-Dattei met huhe Qualiteit (met 720p) em <i lang=\"en\">Ogg</i>-Fommaat zom eronger laade",
+ "timedmedia-derivative-1080p.ogv": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Ogg Vorbis\">Ogg</i> 1080P",
+ "timedmedia-derivative-desc-1080p.ogv": "Full HD downloadable <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Ogg Vorbis\">Ogg</i> video (1080P)",
+ "timedmedia-derivative-160p.webm": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"WebM\">WebM</i> 160P",
+ "timedmedia-derivative-desc-160p.webm": "Web streamable <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"WebM\">WebM</i> (160P)",
+ "timedmedia-derivative-360p.webm": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"WebM\">WebM</i> 360P",
+ "timedmedia-derivative-desc-360p.webm": "Ene WebM Viddejo (met 360p) för ene Dahteshtrohm övver et Nez",
+ "timedmedia-derivative-480p.webm": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"WebM\">WebM</i> 480P",
+ "timedmedia-derivative-desc-480p.webm": "Ene WebM Viddejo (met 480p) för ene Dahteshtrohm övver et Nez",
+ "timedmedia-derivative-720p.webm": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"WebM\">WebM</i> 720P",
+ "timedmedia-derivative-desc-720p.webm": "En <i lang=\"en\">WebM</i> Viddejo-Dattei met huhe Qualiteit (met 720p) zom eronger laade",
+ "timedmedia-derivative-1080p.webm": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"WebM\">WebM</i> 1080P",
+ "timedmedia-derivative-desc-1080p.webm": "Full HD downloadable <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"WebM\">WebM</i> (1080P)",
+ "timedmedia-derivative-desc-320p.mp4": "Device-friendly <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Moving Picture Experts Group - „Expäätejropp för bewääschte Belder“ - Väsjohn 4\">MP4</i> (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Web streamable <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Moving Picture Experts Group - „Expäätejropp för bewääschte Belder“ - Väsjohn 4\">MP4</i> (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD quality <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Moving Picture Experts Group - „Expäätejropp för bewääschte Belder“ - Väsjohn 4\">MP4</i> (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Full HD quality <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Moving Picture Experts Group - „Expäätejropp för bewääschte Belder“ - Väsjohn 4\">MP4</i> (1080P)",
+ "timedmedia-derivative-mp3": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Moving Picture Experts Group - „Expäätejropp för bewääschte Belder“ - Väsjohn 3\">MP3</i>",
+ "timedmedia-derivative-desc-mp3": "<i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Moving Picture Experts Group - „Expäätejropp för bewääschte Belder“ - Väsjohn 3\">MP3</i>",
+ "timedmedia-subtitle-new": "Maach en neue Övversäzong udder änder ein, di et alld jitt",
+ "timedmedia-subtitle-new-desc": "Söhg en Schprohch uß un klegg op „{{int:Timedmedia-subtitle-new-go}}“",
+ "timedmedia-subtitle-new-go": "Lohß Jonn!",
+ "timedmedia-subtitle-language": "Ongertittele en $1 ($2)",
+ "timedmedia-file": "Dattei",
+ "timedmedia-audios": "{{PLURAL:$1|Ein Tohndattei|$1 Tohndatteije|kein Tohndattei}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|Ein Tohndattei|$1 Tohndatteije|kein Tohndattei}} em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Ogg Vorbis\">Ogg</i>-Fommaht",
+ "timedmedia-flac-audios": "{{PLURAL:$1|Ein Tohndattei|$1 Tohndatteije|kein Tohndattei}} em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"Free Lossless Audio Codec „Freije verloßfreie Kodehrer un Dekodehrer vun Töhn“\">FLAC</i>-Fommaht",
+ "timedmedia-wav-audios": "{{PLURAL:$1|Ein Tohndattei|$1 Tohndatteije|kein Tohndattei}} em <i lang=\"en\" xml:lang=\"en\" dir=\"ltr\" title=\"RIFF WAVE - Resource Interchange File Format - för de Wälle vun Töhn\">WAV</i>-Fommaht",
+ "apihelp-transcodereset-param-title": "De Övverschreff vun dä Mehdijedattei."
+}
diff --git a/extensions/TimedMediaHandler/i18n/ku-latn.json b/extensions/TimedMediaHandler/i18n/ku-latn.json
new file mode 100644
index 00000000..48f4f644
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ku-latn.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bikarhêner",
+ "George Animal"
+ ]
+ },
+ "timedmedia-more": "Zêdetir...",
+ "timedmedia-dismiss": "Bigre",
+ "timedmedia-download": "Dosyeyê daxe",
+ "timedmedia-desc-link": "Di derbarê vê dosyeyê de",
+ "timedmedia-source-file": "çavkanî $1",
+ "timedmedia-source-audio-file-desc": "Dosyeye orijînal a $1 ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ky.json b/extensions/TimedMediaHandler/i18n/ky.json
new file mode 100644
index 00000000..79dce232
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ky.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Janatkg"
+ ]
+ },
+ "timedmedia-source-file": "$1 булактан"
+}
diff --git a/extensions/TimedMediaHandler/i18n/la.json b/extensions/TimedMediaHandler/i18n/la.json
new file mode 100644
index 00000000..ae42c49c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/la.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "SPQRobin",
+ "UV"
+ ]
+ },
+ "timedmedia-more": "Plus…"
+}
diff --git a/extensions/TimedMediaHandler/i18n/lad.json b/extensions/TimedMediaHandler/i18n/lad.json
new file mode 100644
index 00000000..082e7dcb
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/lad.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Menachem.Moreira",
+ "Universal Life"
+ ]
+ },
+ "timedmedia-subtitle-new-go": "Ir",
+ "timedmedia-file": "Dosya"
+}
diff --git a/extensions/TimedMediaHandler/i18n/lb.json b/extensions/TimedMediaHandler/i18n/lb.json
new file mode 100644
index 00000000..0a3c78c8
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/lb.json
@@ -0,0 +1,73 @@
+{
+ "@metadata": {
+ "authors": [
+ "Les Meloures",
+ "Robby"
+ ]
+ },
+ "timedmedia-desc": "Steierungsprogramm fir Audio, Video an 'timed text', mat Ënnerstëtzung vun de Formater WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg-$1-Tounfichier, $2",
+ "timedmedia-ogg-short-video": "Ogg-$1-Videofichier, $2",
+ "timedmedia-ogg-short-general": "Ogg-$1-Mediefichier, $2",
+ "timedmedia-ogg-long-audio": "tmh-$1-Tounfichier, Dauer: $2, $3",
+ "timedmedia-ogg-long-video": "Ogg-$1-Videofichier, Dauer: $2, $4×$5 Pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg-Toun-/Video-Fichier, $1, Dauer: $2, $4×$5 Pixel, $3",
+ "timedmedia-ogg-long-general": "Ogg Media-Fichier, Dauer $2, $3",
+ "timedmedia-ogg-long-error": "Ongëltegen Ogg-Fichier: $1",
+ "timedmedia-webm-short-video": "WebM $1 Video Fichier, $2",
+ "timedmedia-webm-long-video": "WebM-Audio/Video-Fichier, $1, Dauer $2, $4×$5 Pixel, $3 am Ganzen",
+ "timedmedia-flac-short-audio": "FLAC-Audiofichier, $1",
+ "timedmedia-flac-long-audio": "FLAC-audiofichier, Längt $1, $2 am Ganzen",
+ "timedmedia-wav-short-audio": "WAV-Audiofichier, $1",
+ "timedmedia-mp4-short-video": "MP4 $1 Videofichier, $2",
+ "timedmedia-no-player-js": "Pardon, Äre Browser huet entweder JavaScript ausgeschalt oder en huet kee Player-Programm deen ënnerstëtzt gëtt.<br />\nDir kënnt <a href=\"$1\"> de Clip eroflueden</a> oder <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">e Player-Programm erofluede</a> fir de Clip an Ärem Browser ze spillen.",
+ "timedmedia-more": "Méi ...",
+ "timedmedia-dismiss": "Zoumaachen",
+ "timedmedia-download": "Fichier eroflueden",
+ "timedmedia-desc-link": "Iwwer dëse Fichier",
+ "timedmedia-oggThumb-version": "Den OggHandler brauch d'Versioun $1 (oder méi eng nei Versioun) vun OggThumb.",
+ "timedmedia-oggThumb-failed": "oggThumb konnt d'Miniaturbild (thumbnail) net uleeën.",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Onbekannte Status",
+ "timedmedia-transcodeinfo": "Format",
+ "timedmedia-actions": "Aktiounen",
+ "timedmedia-direct-link": "Eroflueden",
+ "timedmedia-not-ready": "Net fäerdeg",
+ "timedmedia-completed-on": "Fäerdeg den $1",
+ "timedmedia-error-on": "Feeler op $1",
+ "timedmedia-started-transcode": "Ugefaang viru(n) $1. $2",
+ "timedmedia-percent-done": "Ongeféier $1% fäerdeg",
+ "timedmedia-days": "{{PLURAL:$1|1 Dag|$1 Deeg}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 Stonn|$1 Stonnen}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 Minutt|$1 Minutten}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 Sekonn|$1 Sekonnen}}",
+ "timedmedia-reset": "Transcode zrécksetzen",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Quell ($1)",
+ "timedmedia-source-file-desc": "Original $1 Fichier, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Original $1 Fichier ($2)",
+ "timedmedia-derivative-desc-240p.ogv": "Ogg-Video (240P) deen iwwer de Web gestreamt gi kann",
+ "timedmedia-derivative-360p.vp9.webm": "VP9 360P",
+ "timedmedia-derivative-480p.vp9.webm": "VP9 480P",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "Komplette streamfäege 4K-WebM-VP9-Video (2160P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD-Qualitéit MP4 (720P)",
+ "timedmedia-derivative-desc-2160p.mp4": "Komplette 4K MP4-Qualitéitsvideo (2160P)",
+ "timedmedia-subtitle-new": "Nei Iwwersetzung maachen oder eng déi et gëtt änneren",
+ "timedmedia-subtitle-new-desc": "Sicht d'Sprooch eraus an dréckt de Knäppchen ''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Lass",
+ "timedmedia-subtitle-language": "$1 ($2) Ënnertitelen",
+ "timedmedia-subtitle-no-video": "Et ass kee Video mat der aktueller Säit vun Ënnertitelen associéiert.",
+ "timedmedia-subtitle-no-subtitles": "Et sinn elo keng Ënnertitelen op $1 fir dëse Video, Dir kënnt [{{fullurl:{{FULLPAGENAME}}|action=edit}} dës Säit änneren] fir se derbäizesetzen",
+ "timedmedia-subtitle-remote-link": "Dir kënnt [$1 d'Beschreiwungssäit] fir dëse Fichier op $2 gesinn",
+ "timedmedia-videos": "{{PLURAL:$1|$1 Video|$1 Videoen}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg Video|$1 Ogg Videoen}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM Video|$1 WebM Videoen}}",
+ "timedmedia-file": "Fichier",
+ "timedmedia-audios": "{{PLURAL:$1|$1 Audio-Fichier|$1 Audio-Fichieren}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg Audio-Fichier|$1 Ogg Audio-Fichieren}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC Audio-Fichier|$1 FLAC Audio-Fichieren}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV Audio-Fichier|$1 WAV Audio-Fichieren}}",
+ "orphanedtimedtext-unsupported": "Dës Spezialsäit funktionéiert nëmme mat MySQL Datebanken.",
+ "orphanedtimedtext-notimedtext": "TimedText ass op dëser Wiki net aktivéiert.",
+ "apihelp-transcodereset-param-title": "Den Titel vum Mediefichier."
+}
diff --git a/extensions/TimedMediaHandler/i18n/lfn.json b/extensions/TimedMediaHandler/i18n/lfn.json
new file mode 100644
index 00000000..23c9c268
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/lfn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Malafaya"
+ ]
+ },
+ "timedmedia-more": "Plu…"
+}
diff --git a/extensions/TimedMediaHandler/i18n/li.json b/extensions/TimedMediaHandler/i18n/li.json
new file mode 100644
index 00000000..2f63a4cd
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/li.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Matthias",
+ "Ooswesthoesbes"
+ ]
+ },
+ "timedmedia-desc": "Handelt Ogg Theora- en Vorbis-bestande aaf met 'n JavaScript-mediaspeler",
+ "timedmedia-ogg-short-audio": "Ogg $1 geluidsbestandj, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 videobestandj, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 mediabestandj, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 geluidsbestandj, lingdje $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 videobestandj, lingdje $2, $4×$5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg gemultiplexeerd geluids-/videobestandj, $1, lingdje $2, $4×$5 pixels, $3 totaal",
+ "timedmedia-ogg-long-general": "Ogg mediabestandj, lingdje $2, $3",
+ "timedmedia-ogg-long-error": "Óngeljig oggg-bestandj: $1",
+ "timedmedia-more": "Mieë...",
+ "timedmedia-dismiss": "Sloet",
+ "timedmedia-download": "Bestandj downloade",
+ "timedmedia-desc-link": "Euver dit bestandj"
+}
diff --git a/extensions/TimedMediaHandler/i18n/lrc.json b/extensions/TimedMediaHandler/i18n/lrc.json
new file mode 100644
index 00000000..b897768a
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/lrc.json
@@ -0,0 +1,44 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bonevarluri",
+ "Mogoeilor"
+ ]
+ },
+ "timedmedia-ogg-short-audio": "جانیا دنگ اوگ $1،$2",
+ "timedmedia-ogg-short-video": "Ogg $1 جانیا ویدیو, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 جانیا وارسگر , $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 جانیا دنگ , درازا $2, $3",
+ "timedmedia-ogg-long-error": "جانیا دنگ اوگ نامعتور:$1",
+ "timedmedia-webm-short-video": "WebM $1 جانیا ویدیو, $2",
+ "timedmedia-flac-short-audio": "FLAC جانیا دنگدار , $1",
+ "timedmedia-wav-short-audio": "WAV جانیا دنگدار, $1",
+ "timedmedia-wav-pcm-required": "شما فقط تونیت پی سی ام نه سوار بکید",
+ "timedmedia-mp4-short-video": "MP4 $1 جانیا ویدیو, $2",
+ "timedmedia-no-player-js": "د بدبختی دوارته نیئر د لحاظ جاوا نیسسه ناکشتگر بیه یا شایت حامیندار هیچ دنگیاری نئ.<br />\nشما می تونیت<a href=\"$1\">کلیپ نه بگریت</a> یا<a <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">یه گل دنگیار نه بگریت</a> سی یه که کلیپ نه د دوارته نیئرتو به ونیت..",
+ "timedmedia-more": "بیشتر....",
+ "timedmedia-dismiss": "بسن",
+ "timedmedia-download": "گرتن جانیا",
+ "timedmedia-play-media": "روشن کردن وارسگر",
+ "timedmedia-desc-link": "دباره ای جانیا",
+ "timedmedia-status": "حال وبال",
+ "timedmedia-status-unknown": "حال و بال نادیار",
+ "timedmedia-actions": "کنشگریا",
+ "timedmedia-not-ready": "آماده نئ",
+ "timedmedia-percent-done": "د حدود $1% انجوم بی",
+ "timedmedia-days": "{{PLURAL:$1|1 روز|$1 روز}}",
+ "timedmedia-hours": "{{PLURAL:$1|$1 ساعت|$1 ساعت یا}}",
+ "timedmedia-minutes": "{{PLURAL:$1|$1 دیقه|$1 دیقه یا}}",
+ "timedmedia-seconds": "{{PLURAL:$1|$1 ثانیه|$1 ثانیه یا}}",
+ "timedmedia-source-file": "سرچشمه $1",
+ "timedmedia-source-file-desc": "اصلی $1 جانیا, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "جانیا اصلی$1 ($2)",
+ "timedmedia-subtitle-new-go": "رؤ",
+ "timedmedia-subtitle-language": "$1 ($2) زیرنیس",
+ "timedmedia-videos": "{{PLURAL:$1|$1 ویدیو|$1 ویدیویا}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg ویدیو|$1 Ogg ویدیویا}}",
+ "timedmedia-file": "جانیا",
+ "timedmedia-audios": "{{PLURAL:$1|$1 جانیا دنگدار|$1 جانیایا دنگدار}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 جانیا دنگ نگدار اُگ|$1 جانیایا دنگدار اُگ}}",
+ "apihelp-transcodereset-param-title": "داسون جانیا وارسگر."
+}
diff --git a/extensions/TimedMediaHandler/i18n/lt.json b/extensions/TimedMediaHandler/i18n/lt.json
new file mode 100644
index 00000000..bee1ed8d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/lt.json
@@ -0,0 +1,123 @@
+{
+ "@metadata": {
+ "authors": [
+ "Homo",
+ "Matasg",
+ "Hugo.arg",
+ "Albertas"
+ ]
+ },
+ "timedmedia-desc": "Audio, video ir teksto su laiku doroklė, kuri palaiko WebM, Ogg Theora, Vorbis, srt formatus",
+ "timedmedia-ogg-short-audio": "Ogg $1 garso byla, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 video byla, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 medija byla, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 garso byla, ilgis $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 video byla, ilgis $2, $4×$5 pikseliai, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg sutankinta audio/video byla, $1, ilgis $2, $4×$5 pikseliai, $3 viso",
+ "timedmedia-ogg-long-general": "Ogg media byla, ilgis $2, $3",
+ "timedmedia-ogg-long-error": "Bloga ogg byla: $1",
+ "timedmedia-ogg-long-no-streams": "Ogg medijos failas. Įspėjimas: nei vienas faile naudojamas kodavimo standartas nebuvo atpažintas.",
+ "timedmedia-webm-short-video": "WebM $1 video failas, $2",
+ "timedmedia-webm-long-video": "WebM audio/video failas, $1, ilgio $2, $4 × $5 pikselių, $3 išviso",
+ "timedmedia-flac-short-audio": "FLAC audio failas, $1",
+ "timedmedia-flac-long-audio": "FLAC audio failas, ilgio $1, $2 iš viso",
+ "timedmedia-wav-short-audio": "WAV audio failas, $1",
+ "timedmedia-wav-long-audio": "WAV audio failas, ilgio $1, $2 iš viso",
+ "timedmedia-wav-pcm-required": "Galite įkelti tik PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "MP4 $1 video failas, $2",
+ "timedmedia-mp4-long-video": "MP4 audio/video failas, $1, ilgio $2, $4 × $5 pikselių, $3 iš viso",
+ "timedmedia-no-player-js": "Atsiprašome, bet jūsų naršyklėje arba išjungtas JavaScript, arba neturi jokio palaikomo grotuvo.<br />\nJūs galite <a href=\"$1\">atsisiųsti įrašą</a> arba <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">grotuvą</a>, kad galėtumėte leisti įrašą savo naršyklėje.",
+ "timedmedia-more": "Daugiau...",
+ "timedmedia-dismiss": "Uždaryti",
+ "timedmedia-download": "Atsisiųsti bylą",
+ "timedmedia-play-media": "Groti mediją",
+ "timedmedia-desc-link": "Apie šią bylą",
+ "timedmedia-oggThumb-version": "OggHandler reikalauja oggThumb $1 versijos arba vėlesnės.",
+ "timedmedia-oggThumb-failed": "oggThumb nepavyko sukurti miniatiūros.",
+ "timedmedia-status-header": "Perkodavimo statusas",
+ "timedmedia-update-status": "Atnaujinti perkodavimo statusą",
+ "timedmedia-status": "Būsena",
+ "timedmedia-status-unknown": "Nežinomas statusas",
+ "timedmedia-transcodebitrate": "Kokybė",
+ "timedmedia-transcodeduration": "Kodavimo laikas",
+ "timedmedia-transcodeinfo": "Formatas",
+ "timedmedia-actions": "Veiksmai",
+ "timedmedia-direct-link": "Atsisiųsti",
+ "timedmedia-not-ready": "Neparuošta",
+ "timedmedia-completed-on": "Baigta $1",
+ "timedmedia-error-on": "Klaida $1",
+ "timedmedia-started-transcode": "Pradėta prieš $1. $2",
+ "timedmedia-percent-done": "Atlikta apie $1%",
+ "timedmedia-in-job-queue": "Pridėta prie darbų eilės prieš $1",
+ "timedmedia-unknown-target-size": "Nežinomas rezultato dydis, $1 užkoduota",
+ "timedmedia-days": "{{PLURAL:$1|1 diena|$1 dienos}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 valanda|$1 valandos}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minutė|$1 minutės}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 sekundė|$1 sekundės}}",
+ "timedmedia-reset": "Atstatyti perkodavimą",
+ "timedmedia-reset-confirm": "Šio perkodavimo atstatymas pašalins visus egzistuojančius failus (jeigu jų yra) ir vėl pridės perkodavimą į darbų eilę. Perkodavimas užtruks kažkiek laiko.<br /><br />\nAr tikrai norite tęsti?",
+ "timedmedia-reset-error": "Klaida perkodavimo atstatymo užduotyje.",
+ "timedmedia-source-file": "$1 šaltinis",
+ "timedmedia-source-file-desc": "Originalus $1 failas, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Pirminė $1 rinkmena ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Žemo pralaidumo Ogg video (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "Internetu transliuotinas Ogg video (240P)",
+ "timedmedia-derivative-desc-360p.ogv": "Internetu transliuotinas Ogg video (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Internetu transliuotinas Ogg video (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Aukštos kokybės atsisiųstinas Ogg video (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Visiškai aukštos kokybės atsisiųstinas Ogg video (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Internetu transliuotinas WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Internetu transliuotinas WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Internetu transliuotinas WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Aukštos kokybės atsisiųstinas WebM (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "Visiškai aukštos kokybės atsisiųstinas WebM (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "Pilnai 4K atsisiųstinas WebM (2160P)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "Internetu transliuotinas WebM VP9 (360P)",
+ "timedmedia-derivative-desc-480p.vp9.webm": "Internetu transliuotinas WebM VP9 (480P)",
+ "timedmedia-derivative-desc-720p.vp9.webm": "Aukštos kokybės transliuotinas WebM VP9 (720P)",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "Visiškai aukštos kokybės transliuotinas WebM VP9 (1080P)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "Pilnai 4K transliuotinas WebM VP9 (2160P)",
+ "timedmedia-derivative-desc-320p.mp4": "Įrenginiams draugiškas MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Internetu transliuotinas MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "Aukštos kokybės MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Visiškai aukštos kokybės MP4 (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "Pilnos 4K kokybės MP4 (2160P)",
+ "timedmedia-subtitle-new": "Sukurti naują vertimą arba redaguoti egzistuojantį",
+ "timedmedia-subtitle-new-desc": "Pasirinkite kalbą ir paspauskite '''{{int:Timedmedia-subtitle-new-go}}''' mygtuką",
+ "timedmedia-subtitle-new-go": "Vykdyti",
+ "timedmedia-subtitle-language": "$1 ($2) subtitrai",
+ "timedmedia-subtitle-no-video": "Nėra video, susieto su dabartiniu subtitrų puslapiu.",
+ "timedmedia-subtitle-no-subtitles": "Kol kas šiam video nėra subtitrų $1, bet Jūs galite [{{fullurl:{{FULLPAGENAME}}|action=edit}} redaguoti šį puslapį], norėdami juos pridėti.",
+ "timedmedia-subtitle-remote": "Šio failo tekstas su laiku yra patalpintas $1",
+ "timedmedia-subtitle-remote-link": "Galite [$1 peržiūrėti šio failo aprašymo puslapį] $2",
+ "timedmediahandler": "MedijosSuLaikuDoroklis",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video|$1 video failai}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg video|$1 Ogg video failai}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM video|$1 WebM video failai}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 perkodavimas|$1 perkodavimai}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 vykdomas perkodavimas|$1 vykdomi perkodavimai}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 ieškomas perkodavimas|$1 ieškomi perkodavimai}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 nepavykęs perkodavimas|$1 nepavykę perkodavimai}}",
+ "timedmedia-file": "Failas",
+ "timedmedia-audios": "{{PLURAL:$1|$1 audio failas|$1 audio failai}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg audio failas|$1 Ogg audio failai}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC audio failas|$1 FLAC audio failai}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV audio failas|$1 WAV audio failai}}",
+ "right-transcode-reset": "Atstatymas nepavyko arba video failai buvo perkoduoti, todėl jie vėl buvo pridėti į darbų eilę",
+ "right-transcode-status": "Peržiūrėti [[Special:TimedMediaHandler|informaciją apie dabartines perkodavimo veiklas]]",
+ "action-transcode-status": "peržiūrėti dabartinę perkodavimo būseną",
+ "orphanedtimedtext": "Pamesto teksto su laiku puslapiai",
+ "orphanedtimedtext-summary": "Sąrašas [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] puslapių, kurie neturi atitinkamų failų.",
+ "orphanedtimedtext-unsupported": "Šis specialus puslapis palaiko tik MySQL duomenų bazes.",
+ "orphanedtimedtext-notimedtext": "Tekstas su laiku nėra aktyvuotas šiame vikyje.",
+ "apihelp-query+transcodestatus-description": "Gauti perkodavimo statusą pateiktajam failo puslapiui.",
+ "apihelp-query+transcodestatus-example-1": "Gauti perkodavimo būseną [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "Papildo paveikslėlio informaciją, kad būtų pridėta video šaltinio (išvestinio) informacija",
+ "apihelp-query+videoinfo-param-prop": "Kurią video informaciją norite gauti:\n;timestamp:Prideda įkeltosios versijos laiko žymę.\n;user:Prideda naudotoją, kuris įkėlė video versiją.\n;userid:Prideda ID naudotojo, kuris įkėlė video versiją.\n;comment:Versijos komentaras.\n;parsedcomment:Apdorotas versijos komentaras.\n;canonicaltitle:Prideda kanoninį video failo pavadinimą.\n;url:Pateikia URL, nukreipiantį į video ir aprašymo puslapį.\n;size:Prideda video dydį baitais, jo aukštį ir plotį. Puslapio skaitliukas ir trukmė yra pridedami, jeigu prieinama.\n;dimensions:Dydžio alternatyva.\n;sha1:Prideda video SHA-1 maišos funkcijos reikšmę.\n;mime:Prideda video MIME tipą.\n;thumbmime:Prideda video MIME tipo miniatiūrą (reikalauja URL ir parametro $1urlwidth).\n;mediatype:Prideda video medijos tipą.\n;metadata:Pateikia video versijos Exif metaduomenų sąrašą.\n;commonmetadata:Pateikia video versijos failo formatų bendrų metaduomenų sąrašą.\n;extmetadata:Pateikia formatuotų metaduomenų sąrašą, sukombinuotą iš skirtingų šaltinių. Rezultatas yra suformatuotas HTML.\n;archivename:Prideda ne paskutinių versijų archyvo failo vardą.\n;bitdepth:Prideda versijos bitų gilumą.\n;uploadwarning:Naudojamas [[Special:Upload]] puslapyje gauti informacijai apie egzistuojantį failą. Nėra skirtas naudojimui MediaWiki branduolio išorėje.\n;derivatives:Prideda skirtingų prieinamų audio ir video failų formatų ir kokybės versijų sąrašą.",
+ "apihelp-query+videoinfo-example-1": "Gauti informaciją apie [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "Naudotojai turintys 'perkodavimo-atsatymo' teises gali atstatyti ir pakartotinai paleisti perkodavimo užduotį.",
+ "apihelp-transcodereset-param-title": "Medijos failo pavadinimas.",
+ "apihelp-transcodereset-param-transcodekey": "Perkodavimo raktas, kurį norite atstatyti. Galite paimti iš [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Atstatyti visus [[:File:Clip.webm]] perkodavimus",
+ "apihelp-transcodereset-example-2": "Atstatyti '360_560kbs.webm' perkodavimo raktą [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/luz.json b/extensions/TimedMediaHandler/i18n/luz.json
new file mode 100644
index 00000000..4ab30bc0
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/luz.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "علی ساکی لرستانی"
+ ]
+ },
+ "timedmedia-no-player-js": "ۉاسی ۉبخشیت،مرۉرگر ایشا ۉھ صۉرت جاۉا اسکریپت غیرفعال ۉابیدھ ۉ هیچ پلیر پشتیبانی نارھ.<br /> ایشا ۉا کلیژ ری ای ایترید <a href=\"$1\">download the clip</a> or <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">download a player</a> کلیپنه مئنه مرۉرگر خۉتۉن پخش کنیت.",
+ "timedmedia-source-file": "$1 سرچشمه",
+ "timedmedia-source-audio-file-desc": "اصلی $1 فایل ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/lv.json b/extensions/TimedMediaHandler/i18n/lv.json
new file mode 100644
index 00000000..9554b20b
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/lv.json
@@ -0,0 +1,22 @@
+{
+ "@metadata": {
+ "authors": [
+ "Papuass",
+ "Xil",
+ "Silraks"
+ ]
+ },
+ "timedmedia-more": "Vairāk...",
+ "timedmedia-dismiss": "Aizvērt",
+ "timedmedia-download": "Lejupielādēt failu",
+ "timedmedia-desc-link": "Par šo failu",
+ "timedmedia-status": "Statuss",
+ "timedmedia-status-unknown": "Nezināms statuss",
+ "timedmedia-transcodeinfo": "Formāts",
+ "timedmedia-actions": "Darbības",
+ "timedmedia-direct-link": "Lejupielādēt",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 avots",
+ "timedmedia-subtitle-new-go": "Aiziet!",
+ "timedmedia-subtitle-language": "$1 ($2) subtitri"
+}
diff --git a/extensions/TimedMediaHandler/i18n/mai.json b/extensions/TimedMediaHandler/i18n/mai.json
new file mode 100644
index 00000000..7d189ffd
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/mai.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "बिप्लब आनन्द"
+ ]
+ },
+ "timedmedia-no-player-js": "क्षमा करू, अहाँके ब्राउजर में या त जावास्क्रिप्ट अक्षम अछि या समर्थित प्लेयर नै अछि।<br />\nअहाँ <a href=\"$1\">क्लिपके डाउनलोड</a> कैर सकै छी वा क्लिपके अपन ब्राउजरमें चलावाक लेल <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">एक प्लेयर डाउनलोड</a> कैर सकै छी।",
+ "timedmedia-source-file": "$1 स्रोत",
+ "timedmedia-source-audio-file-desc": "मूल $1 फाइल ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/mg.json b/extensions/TimedMediaHandler/i18n/mg.json
new file mode 100644
index 00000000..ed53f4f9
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/mg.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jagwar"
+ ]
+ },
+ "timedmedia-no-player-js": "Miala tsiny indrindra, na tsy mampiasa JavaScript ny mpitety tranonkalanao, na tsy manana mpamaky zaka ilay izy.<br />\nAzonao atao ny <a href=\"$1\">mampidina ilay kilipy</a> na <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">mampidina mpamaky iray</a> hamakiana ilay kilipy eo amin'ny mpitetinao.",
+ "timedmedia-source-file": "Fango $1",
+ "timedmedia-source-audio-file-desc": "Rakitra niaviana $1 ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/min.json b/extensions/TimedMediaHandler/i18n/min.json
new file mode 100644
index 00000000..5b8b13a5
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/min.json
@@ -0,0 +1,30 @@
+{
+ "@metadata": {
+ "authors": [
+ "Iwan Novirion"
+ ]
+ },
+ "timedmedia-transcodeinfo": "Deskripsi turunan transkoder",
+ "timedmedia-ogg": "Ogg",
+ "timedmedia-webm": "WebM",
+ "timedmedia-derivative-160p.ogv": "Ogg 160p",
+ "timedmedia-derivative-360p.ogv": "Ogg 360p",
+ "timedmedia-derivative-480p.ogv": "Ogg 480p",
+ "timedmedia-derivative-720p.ogv": "Ogg 720p",
+ "timedmedia-derivative-160p.webm": "WebM 160p",
+ "timedmedia-derivative-360p.webm": "WebM 360p",
+ "timedmedia-derivative-480p.webm": "WebM 480p",
+ "timedmedia-derivative-720p.webm": "WebM 720p",
+ "timedmedia-derivative-320p.mp4": "H264 320p",
+ "timedmedia-derivative-480p.mp4": "H264 480p",
+ "timedmedia-derivative-720p.mp4": "H264 720p",
+ "timedmedia-derivative-ogg": "Ogg Vorbis",
+ "timedmedia-derivative-desc-ogg": "Ogg Vorbis",
+ "timedmedia-derivative-opus": "Opus",
+ "timedmedia-derivative-desc-opus": "Opus",
+ "timedmedia-derivative-mp3": "MP3",
+ "timedmedia-derivative-desc-mp3": "MP3",
+ "timedmedia-derivative-m4a": "AAC",
+ "timedmedia-derivative-desc-m4a": "AAC",
+ "timedmediahandler": "Daftar berkas media"
+}
diff --git a/extensions/TimedMediaHandler/i18n/mk.json b/extensions/TimedMediaHandler/i18n/mk.json
new file mode 100644
index 00000000..69ba9495
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/mk.json
@@ -0,0 +1,144 @@
+{
+ "@metadata": {
+ "authors": [
+ "Bjankuloski06",
+ "Brest"
+ ]
+ },
+ "extensionname-timedmedia": "Титлови",
+ "timedmedia-desc": "Обработувач за аудио, видео и титлови, со поддршка за форматите WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 звучна податотека, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 видеоснимка, $2",
+ "timedmedia-ogg-short-general": "Мултимедијална податотека Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 звучна податотека, времетраење $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 видео податотека, времетраење $2, $4 × $5 пиксели, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg мултиплексирана аудио/видео снимка, $1, времетраење $2, $4 × $5 пиксели, вкупно $3",
+ "timedmedia-ogg-long-general": "Мултимедијална податотека Ogg, времетраење $2, $3",
+ "timedmedia-ogg-long-error": "Оштетена Ogg-податотека: $1",
+ "timedmedia-ogg-long-no-streams": "Ogg-податотека. Предупредување: Не препознав ниеден од користените кодеци.",
+ "timedmedia-webm-short-video": "WebM $1 видеоснимка, $2",
+ "timedmedia-webm-long-video": "WebM аудио/видео снимка, $1, времетраење: $2, $4 × $5 пиксели, вкупно $3",
+ "timedmedia-flac-short-audio": "Аудиоподатотека FLAC, $1",
+ "timedmedia-flac-long-audio": "Аудиоподатотека FLAC, времетраење: $1, вкупно $2",
+ "timedmedia-wav-short-audio": "Аудиоподатотека WAV, $1",
+ "timedmedia-wav-long-audio": "Аудиоподатотека WAV, времетраење: $1, вкупно $2",
+ "timedmedia-wav-pcm-required": "Можете да подигате само WAV-податотеки со PCM (импулсна кодна модулација).",
+ "timedmedia-mp4-short-video": "MP4 $1 видеоснимка, $2",
+ "timedmedia-mp4-long-video": "MP4 аудио/видео снимка, $1, времетраење $2, $4 × $5 пиксели, вкупно $3",
+ "timedmedia-no-player-js": "За жал, вашиот прелистувач или има оневозможено JavaScript, или нема ниту еден поддржан изведувач.<br />\nМожете да го <a href=\"$1\">преземете клипот</a> или <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">да преземете изведувач</a> за да ја пуштите снимката во вашиот прелистувач.",
+ "timedmedia-more": "Повеќе...",
+ "timedmedia-dismiss": "Затвори",
+ "timedmedia-download": "Преземи податотека",
+ "timedmedia-play-media": "Пушти снимка",
+ "timedmedia-desc-link": "Информации за податотеката",
+ "timedmedia-oggThumb-version": "OggHandler бара oggThumb верзија $1 или понова.",
+ "timedmedia-oggThumb-failed": "oggThumb не успеа да ја создаде минијатурата.",
+ "timedmedia-status-header": "Статус на прекодирањето",
+ "timedmedia-update-status": "Поднови статус на прекодирање",
+ "timedmedia-status": "статус",
+ "timedmedia-status-unknown": "Непознат статус",
+ "timedmedia-transcodebitrate": "Пропусност",
+ "timedmedia-transcodeduration": "Траење на прекодирањето",
+ "timedmedia-transcodeinfo": "Формат",
+ "timedmedia-actions": "Дејства",
+ "timedmedia-direct-link": "Преземање",
+ "timedmedia-not-ready": "Не е готово",
+ "timedmedia-completed-on": "Завршено на $1",
+ "timedmedia-error-on": "Грешка на $1",
+ "timedmedia-started-transcode": "Започнато пред $1. $2",
+ "timedmedia-percent-done": "Сработено: околу $1%",
+ "timedmedia-in-job-queue": "Додадено во редицата на задачи пред $1",
+ "timedmedia-unknown-target-size": "Непозната целна големина. $1 е шифрирано",
+ "timedmedia-days": "{{PLURAL:$1|еден ден|$1 дена}}",
+ "timedmedia-hours": "{{PLURAL:$1|еден час|$1 часа}}",
+ "timedmedia-minutes": "{{PLURAL:$1|една минута|$1 минути}}",
+ "timedmedia-seconds": "{{PLURAL:$1|една секунда|$1 секунди}}",
+ "timedmedia-reset": "Одново",
+ "timedmedia-reset-confirm": "Враќајќи го ова прекодирање одново ќе ја отстраните постоечката податотека (ако ја има) и ќе го вратите прекодирањето во редицата на задачи. Повторното прекодирање ќе потрае. <br /><br />Дали сте сигурни дека сакате да продолжите?",
+ "timedmedia-reset-error": "Грешка при повторното пуштање на транскодирањето.",
+ "timedmedia-ogg": "Ogg",
+ "timedmedia-webm": "WebM",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Извор на $1",
+ "timedmedia-source-file-desc": "Оригинална $1-податотека, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Оригинална $1-податотека ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160п",
+ "timedmedia-derivative-desc-160p.ogv": "Нископропусно Ogg-видео (160п)",
+ "timedmedia-derivative-240p.ogv": "Ogg 240 п",
+ "timedmedia-derivative-desc-240p.ogv": "Ogg-видео за емитување (240 пиксели)",
+ "timedmedia-derivative-360p.ogv": "Ogg 360п",
+ "timedmedia-derivative-desc-360p.ogv": "Ogg-видео за емитување (360 пиксели)",
+ "timedmedia-derivative-480p.ogv": "Ogg 480п",
+ "timedmedia-derivative-desc-480p.ogv": "Ogg-видео за емитување (480 пиксели)",
+ "timedmedia-derivative-720p.ogv": "Ogg 720п",
+ "timedmedia-derivative-desc-720p.ogv": "Висококвалитетно Ogg-видео за преземање (720п)",
+ "timedmedia-derivative-1080p.ogv": "Ogg 1080п",
+ "timedmedia-derivative-desc-1080p.ogv": "Високоразделна Ogg-видеоснимка за преземање (1080п)",
+ "timedmedia-derivative-160p.webm": "WebM 160п",
+ "timedmedia-derivative-desc-160p.webm": "WebM за каналско емитување (160п)",
+ "timedmedia-derivative-360p.webm": "WebM 360п",
+ "timedmedia-derivative-desc-360p.webm": "WebM за каналско емитување (360п)",
+ "timedmedia-derivative-480p.webm": "WebM 480п",
+ "timedmedia-derivative-desc-480p.webm": "WebM за каналско емитување (480п)",
+ "timedmedia-derivative-720p.webm": "WebM 720п",
+ "timedmedia-derivative-desc-720p.webm": "Висококвалитетен WebM за преземање (720п)",
+ "timedmedia-derivative-1080p.webm": "WebM 1080п",
+ "timedmedia-derivative-desc-1080p.webm": "Полноразделна WebM-видеоснимка за преземање (1080п)",
+ "timedmedia-derivative-desc-2160p.webm": "Полноразделна 4К WebM-видеоснимка за преземање (2160п)",
+ "timedmedia-derivative-360p.vp9.webm": "VP9 360п",
+ "timedmedia-derivative-desc-360p.vp9.webm": "WebM за каналско емитување (360п)",
+ "timedmedia-derivative-480p.vp9.webm": "VP9 480п",
+ "timedmedia-derivative-desc-480p.vp9.webm": "WebM за каналско емитување (480п)",
+ "timedmedia-derivative-720p.vp9.webm": "VP9 720п",
+ "timedmedia-derivative-desc-720p.vp9.webm": "WebM за високоразделно каналско емитување (720п)",
+ "timedmedia-derivative-1080p.vp9.webm": "VP9 1080п",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "WebM за полноразделно каналско емитување (1080п)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "Полноразделна 4К WebM VP9 видеоснимка за преземање (2160п)",
+ "timedmedia-derivative-320p.mp4": "H264 320п",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 за уреди (320п)",
+ "timedmedia-derivative-480p.mp4": "H264 480п",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 за каналско емитување (480п)",
+ "timedmedia-derivative-720p.mp4": "H264 720п",
+ "timedmedia-derivative-desc-720p.mp4": "MP4-снимка со HD-квалитет (720п)",
+ "timedmedia-derivative-1080p.mp4": "H264 1080п",
+ "timedmedia-derivative-desc-1080p.mp4": "Високоразделба MP4-видеоснимка (1080п) за преземање",
+ "timedmedia-derivative-desc-2160p.mp4": "Полноразделна 4К квалитетна MP4-видеоснимка (2160п)",
+ "timedmedia-subtitle-new": "Создај нов превод или измени постоечки",
+ "timedmedia-subtitle-new-desc": "Изберете јазик и стиснете на копчето '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Дај",
+ "timedmedia-subtitle-language": "$1 ($2) титлови",
+ "timedmedia-subtitle-no-video": "Нема видеоснимка поврзана со тековната страница со титлови",
+ "timedmedia-subtitle-no-subtitles": "Моментално нема $1 титлови за оваа видеоснимка. Можете да ги додадете [{{fullurl:{{FULLPAGENAME}}|action=edit}} уредувајќи ја страницава]",
+ "timedmedia-subtitle-remote": "Титловите на податотекава се вдомени во $1",
+ "timedmedia-subtitle-remote-link": "Можете да ја [$1 погледате описната страница] на податотекава на $2",
+ "timedmediahandler": "Титлови",
+ "timedmedia-videos": "{{PLURAL:$1|$1 видео|$1 видеа}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg-видео|$1 Ogg-видеа}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM-видео|$1 WebM-видеа}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 прекодирање|$1 прекодирања}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 прекодирање во тек|$1 прекодирања во тек}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 прекодирање во редица на чекање|$1 прекодирања во редица на чекање}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 неуспешно прекодирање|$1 неуспешни прекодирања}}",
+ "timedmedia-file": "Податотека",
+ "timedmedia-audios": "{{PLURAL:$1|Една аудиоснимка|$1 аудиоснимки}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|Една Ogg-аудиоснимка|$1 Ogg-аудиоснимки}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|Една FLAC-аудиоснимка|$1 FLAC-аудиоснимки}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|Една WAV-аудиоснимка|$1 WAV-аудиоснимки}}",
+ "right-transcode-reset": "Презадавањето не успеа или има прекодирани видеа, па затоа повторно се ставени во редицата на задачи.",
+ "right-transcode-status": "Преглед на [[Special:TimedMediaHandler|информации за тековните активности во прекодирањето]]",
+ "action-transcode-status": "преглед на тековниот статус на прекодирањето",
+ "orphanedtimedtext": "Осамени страници со титлови",
+ "orphanedtimedtext-summary": "Список на страници со [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] што немаат своја податотека.",
+ "orphanedtimedtext-unsupported": "Оваа службена страница е поддржана само на MySQL-бази.",
+ "orphanedtimedtext-notimedtext": "Титловите не се овозможени на ова вики.",
+ "apihelp-query+transcodestatus-description": "Дај статус на прекодирањето на дадена податочна страница.",
+ "apihelp-query+transcodestatus-example-1": "Дај статус на прекодирањето на [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "Ги дополнува информациите со податок за изворот на видеото (изведени)",
+ "apihelp-query+videoinfo-param-prop": "Кои информации за видеото да се дадат:\n;timestamp: Додава датум и време за подигнатата верзија.\n;user: Го додава корисникот што ја подигнал верзијата на видеото.\n;userid: Ја додава назнаката на корисникот што го подигнал видеото.\n;comment: Коментар на верзијата.\n;parsedcomment: Расчленување на коментарот на верзијата.\n;canonicaltitle: Го додава канонскиот наслов на видеоподатотеката.\n;url: Дава URL-адреса на видеото и описната страница.\n;size: Ја додава зафатнината на видеото во бајти, неговата висина и ширина. Ќе се додаде и бројот на страници и времетраењето, ако се применливи.\n;dimensions: Алијас за зафатнина.\n;sha1: Додава тараба SHA-1 за видеото.\n;mime: Додава MIME-тип на видеото.\n;thumbmime: Додава MIME-тип ан минијатурата на видеото (бара URL-адреса и параметарот $1urlwidth).\n;mediatype: Го додава медиумскиот тип на видеото.\n;metadata: Испишува Exif-метаподатоци за верзијата на видеото.\n;commonmetadata: Испишува општи метаподатоци на податочниот формат за верзијата на видеото.\n;extmetadata: Испишува форматирани метаподатоци собрани од повеќе извори. Резултатите се форматирани во HTML.\n;archivename: Го додава податотечното име на архивската верзија за сите верзии освен најновата.\n;bitdepth: Ја додава битовата длабочина на верзијата.\n;uploadwarning: Се користи на страницата [[Special:Upload]] за добивање на информации за постоечка податотека. Не е предвидено за употреба вон јадрото на МедијаВики.\n;derivatives: Додава низа од различниот формат и расположивите квалитети на аудио- или видеоподатотеката.",
+ "apihelp-query+videoinfo-example-1": "Дај информации за [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "Корисниците со правото „transcode-reset“ можат да ги враќаат по основно прекодирањата и да ги вршат одново.",
+ "apihelp-transcodereset-param-title": "Наслов на податотеката.",
+ "apihelp-transcodereset-param-transcodekey": "Клучот на прекодирањето што сакате да го презададете. Преземи од [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Врати ги по основно сите прекодирања на [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "Врати го по основно клучот „360_560kbs.webm“ за прекодирањето на [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ml.json b/extensions/TimedMediaHandler/i18n/ml.json
new file mode 100644
index 00000000..0b04df45
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ml.json
@@ -0,0 +1,124 @@
+{
+ "@metadata": {
+ "authors": [
+ "Praveenp",
+ "Shijualex",
+ "Vssun",
+ "Santhosh.thottingal"
+ ]
+ },
+ "timedmedia-desc": "ഓഗ് തിയോറ, വോർബിസ്, എസ്.ആർ.ടി, വെബ്എം തുടങ്ങിയവയ്ക്കുള്ള പിന്തുണയടക്കമുള്ള ശബ്ദ, ചലച്ചിത്ര, സമയമനുസരിച്ച് പ്രദർശിപ്പിക്കുന്ന എഴുത്തുകൾ എന്നിവയ്ക്കുള്ള കൈകാര്യോപകരണം",
+ "timedmedia-ogg-short-audio": "ഓഗ് $1 ശബ്ദപ്രമാണം, $2",
+ "timedmedia-ogg-short-video": "ഓഗ് $1 വീഡിയോ പ്രമാണം, $2",
+ "timedmedia-ogg-short-general": "ഓഗ് $1 മീഡിയ പ്രമാണം, $2",
+ "timedmedia-ogg-long-audio": "ഓഗ് $1 ശബ്ദ പ്രമാണം, ദൈർഘ്യം $2, $3",
+ "timedmedia-ogg-long-video": "ഓഗ് $1 വീഡിയോ പ്രമാണം, ദൈർഘ്യം $2, $4×$5 ബിന്ദു, $3",
+ "timedmedia-ogg-long-multiplexed": "ഓഗ് മൾട്ടിപ്ലക്സ്‌‌ഡ് ശബ്ദ/ചലച്ചിത്ര പ്രമാണം, $1, ദൈർഘ്യം $2, $4×$5 ബിന്ദു, ആകെക്കൂടി $3",
+ "timedmedia-ogg-long-general": "ഓഗ് മീഡിയ പ്രമാണം, ദൈർഘ്യം $2, $3",
+ "timedmedia-ogg-long-error": "അസാധുവായ ഓഗ് പ്രമാണം: $1",
+ "timedmedia-ogg-long-no-streams": "ഓഗ് മീഡിയ പ്രമാണം. മുന്നറിയിപ്പ്: ഈ പ്രമാണത്തിൽ ഉപയോഗിച്ചിരിക്കുന്ന കോഡെകുകളൊന്നും തിരിച്ചറിഞ്ഞിട്ടില്ല.",
+ "timedmedia-webm-short-video": "വെബ്എം $1 ചലച്ചിത്രപ്രമാണം, $2",
+ "timedmedia-webm-long-video": "വെബ്എം ശബ്ദ/ചലച്ചിത്ര പ്രമാണം, $1, ദൈർഘ്യം $2, $4 × $5 ബിന്ദു, ആകെക്കൂടി $3",
+ "timedmedia-flac-short-audio": "ഫ്ലാക് ശബ്ദപ്രമാണം, $1",
+ "timedmedia-flac-long-audio": "ഫ്ലാക് ശബ്ദപ്രമാണം, ദൈർഘ്യം $1, ആകെ $2",
+ "timedmedia-wav-short-audio": "വേവ് ശബ്ദപ്രമാണം, $1",
+ "timedmedia-wav-long-audio": "വേവ് ശബ്ദപ്രമാണം, ദൈർഘ്യം $1, ആകെ $2",
+ "timedmedia-wav-pcm-required": "പി.സി.എം. (പൾസ് ഓഡിയോ മോഡുലേഷൻ) വേവ് മാത്രമേ അപ്‌ലോഡ് ചെയ്യാനാവൂ.",
+ "timedmedia-mp4-short-video": "എംപി4 $1 വീഡിയോ പ്രമാണം, $2",
+ "timedmedia-mp4-long-video": "എംപി4 ശബ്ദ/ചലച്ചിത്ര പ്രമാണം, $1, ദൈർഘ്യം $2, $4 × $5 ബിന്ദു, ആകെക്കൂടി $3",
+ "timedmedia-no-player-js": "ക്ഷമിക്കുക, താങ്കളുടെ ബ്രൗസറിൽ ജാവാസ്ക്രിപ്റ്റ് സജ്ജമാക്കിയിട്ടില്ല അല്ലെങ്കിൽ പിന്തുണയുള്ള പ്ലേയർ ലഭ്യമല്ല.<br />\nതാങ്കൾക്ക് <a href=\"$1\">ചലച്ചിത്രഭാഗം ഡൗൺലോഡ് ചെയ്യാവുന്നതാണ്</a> അല്ലെങ്കിൽ ബ്രൗസറിൽ പ്രവർത്തിപ്പിക്കാനായി <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">ഒരു പ്ലേയർ ഡൗൺലോഡ് ചെയ്യാവുന്നതാണ്</a>.",
+ "timedmedia-more": "കൂടുതൽ...",
+ "timedmedia-dismiss": "അടയ്ക്കുക",
+ "timedmedia-download": "പ്രമാണം ഡൗൺലോഡ് ചെയ്യുക",
+ "timedmedia-play-media": "മീഡിയ പ്രവർത്തിപ്പിക്കുക",
+ "timedmedia-desc-link": "ഈ പ്രമാണത്തെക്കുറിച്ച്",
+ "timedmedia-oggThumb-version": "ഓഗ്-തമ്പ് പതിപ്പ് $1 അല്ലെങ്കിൽ പുതിയത് ഓഗ്-ഹാൻഡ്ലറിനാവശ്യമാണ്.",
+ "timedmedia-oggThumb-failed": "ലഘുചിത്രം സൃഷ്ടിക്കുന്നതിൽ ഓഗ്-തമ്പ് പരാജയപ്പെട്ടു.",
+ "timedmedia-status-header": "ട്രാൻസ്‌കോഡ് സ്ഥിതി",
+ "timedmedia-update-status": "ട്രാൻസ്‌കോഡ് സ്ഥിതി പുതുക്കുക",
+ "timedmedia-status": "സ്ഥിതി",
+ "timedmedia-status-unknown": "അപരിചിതമായ സ്ഥിതി",
+ "timedmedia-transcodeinfo": "ട്രാൻസ്‌കോഡ് വ്യുൽപ്പന്നത്തിന്റെ വിവരണം",
+ "timedmedia-actions": "പ്രവൃത്തികൾ",
+ "timedmedia-direct-link": "വ്യുൽപ്പന്നം ഡൗൺലോഡ് ചെയ്യുക",
+ "timedmedia-not-ready": "തയ്യാറായിട്ടില്ല",
+ "timedmedia-completed-on": "ട്രാൻസ്‌കോഡ് ചെയ്യൽ പൂർത്തിയായി $1",
+ "timedmedia-error-on": "ട്രാൻസ്‌കോഡ് ചെയ്യലിൽ $1 എന്ന സമയത്ത് പിഴവുണ്ടായി",
+ "timedmedia-started-transcode": "ട്രാൻസ്‌കോഡ് ചെയ്യൽ $1 മുമ്പ് ആരംഭിച്ചു. $2",
+ "timedmedia-percent-done": "ഏകദേശം $1% പൂർത്തിയായി",
+ "timedmedia-in-job-queue": "ജോബ് ക്യൂവിലേയ്ക്ക് $1 മുമ്പ് ചേർത്തു",
+ "timedmedia-unknown-target-size": "ലക്ഷ്യമിടുന്ന വലിപ്പം അറിയില്ല, $1 എൻകോഡ് ചെയ്തു",
+ "timedmedia-days": "{{PLURAL:$1|ഒരു ദിവസം|$1 ദിവസം}}",
+ "timedmedia-hours": "{{PLURAL:$1|ഒരു മണിക്കൂർ|$1 മണിക്കൂർ}}",
+ "timedmedia-minutes": "{{PLURAL:$1|ഒരു മിനിറ്റ്|$1 മിനിറ്റ്}}",
+ "timedmedia-seconds": "{{PLURAL:$1|ഒരു സെക്കന്റ്|$1 സെക്കന്റ്}}",
+ "timedmedia-reset": "ട്രാൻസ്‌കോഡ് ചെയ്യൽ പുനഃസജ്ജീകരിക്കുക",
+ "timedmedia-reset-confirm": "ഈ ട്രാൻസ്‌കോഡ് ചെയ്യൽ പുനഃസജ്ജീകരിക്കുമ്പോൾ നിലവിലുള്ള ഫയൽ (അങ്ങനെയൊന്നുണ്ടെങ്കിൽ) നീക്കം ചെയ്യപ്പെടും, ഒപ്പം അത് ജോബ് ക്യൂവിലേയ്ക്ക് ട്രാൻസ്‌കോഡ് ചെയ്യാൻ വീണ്ടും ചേർക്കപ്പെടുകയും ചെയ്യും. വീണ്ടും-ട്രാൻസ്‌കോഡ് ചെയ്യാൻ അല്പസമയമെടുക്കുന്നതാണ്. <br /><br />\nതുടരണമെന്ന് താങ്കൾക്കുറപ്പാണോ?",
+ "timedmedia-reset-error": "ട്രാൻസ്‌കോഡ് ചെയ്യൽ പുനഃസജ്ജീകരിക്കുന്നതിൽ പിഴവുണ്ടായി.",
+ "timedmedia-ogg": "ഓഗ്",
+ "timedmedia-webm": "വെബ്എം",
+ "timedmedia-mp4": "എംപി4",
+ "timedmedia-source-file": "$1 സ്രോതസ്സ്",
+ "timedmedia-source-file-desc": "യഥാർത്ഥ പ്രമാണം $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "യഥാർത്ഥ പ്രമാണം $1 ($2)",
+ "timedmedia-derivative-160p.ogv": "ഓഗ് 160പി",
+ "timedmedia-derivative-desc-160p.ogv": "കുറഞ്ഞ ബാൻഡ്‌വിഡ്ത് ഓഗ് ചലച്ചിത്രം (160ബി)",
+ "timedmedia-derivative-desc-240p.ogv": "വെബിലൂടെ എടുക്കാവുന്ന ഓഗ് ചലച്ചിത്രം (240P)",
+ "timedmedia-derivative-360p.ogv": "ഓഗ് 360പി",
+ "timedmedia-derivative-desc-360p.ogv": "വെബിലൂടെ എടുക്കാവുന്ന ഓഗ് ചലച്ചിത്രം (360ബി)",
+ "timedmedia-derivative-480p.ogv": "ഓഗ് 480പി",
+ "timedmedia-derivative-desc-480p.ogv": "വെബിലൂടെ എടുക്കാവുന്ന ഓഗ് ചലച്ചിത്രം (480ബി)",
+ "timedmedia-derivative-720p.ogv": "ഓഗ് 720പി",
+ "timedmedia-derivative-desc-720p.ogv": "ഉന്നത ഗുണമേന്മയിൽ ഡൗൺലോഡ് ചെയ്യാവുന്ന ഓഗ് ചലച്ചിത്രം (720ബി)",
+ "timedmedia-derivative-desc-1080p.ogv": "പൂർണ്ണ എച്ച്.ഡി. ഡൗൺലോഡ് ചെയ്യാവുന്ന ഓഗ് ചലച്ചിത്രം (1080 പി)",
+ "timedmedia-derivative-160p.webm": "വെബ്എം 160പി",
+ "timedmedia-derivative-desc-160p.webm": "വെബിലൂടെ എടുക്കാവുന്ന വെബ്എം (160ബി)",
+ "timedmedia-derivative-360p.webm": "വെബ്എം 360പി",
+ "timedmedia-derivative-desc-360p.webm": "വെബിലൂടെ എടുക്കാവുന്ന വെബ്എം (360ബി)",
+ "timedmedia-derivative-480p.webm": "വെബ്എം 480പി",
+ "timedmedia-derivative-desc-480p.webm": "വെബിലൂടെ എടുക്കാവുന്ന വെബ്എം (360ബി)",
+ "timedmedia-derivative-720p.webm": "വെബ്എം 720പി",
+ "timedmedia-derivative-desc-720p.webm": "ഉന്നത ഗുണമേന്മയിൽ ഡൗൺലോഡ് ചെയ്യാവുന്ന വെബ്എം (720ബി)",
+ "timedmedia-derivative-desc-1080p.webm": "പൂർണ്ണ എച്ച്.ഡി. ഡൗൺലോഡ് ചെയ്യാവുന്ന വെബ്എം (1080 പി)",
+ "timedmedia-derivative-desc-320p.mp4": "ഉപകരണ-സുഹൃദ് എംപി4 (320ബി)",
+ "timedmedia-derivative-desc-480p.mp4": "വെബിലൂടെ എടുക്കാവുന്ന എംപി4 (480ബി)",
+ "timedmedia-derivative-desc-720p.mp4": "എച്ച്.ഡി. ഗുണമേന്മയുള്ള എംപി4 (720ബി)",
+ "timedmedia-derivative-desc-1080p.mp4": "പൂർണ്ണ എച്ച്.ഡി. ഡൗൺലോഡ് ചെയ്യാവുന്ന എംപി4 (1080 പി)",
+ "timedmedia-derivative-ogg": "ഓഗ് വോർബിസ്",
+ "timedmedia-derivative-desc-ogg": "ഓഗ് വോർബിസ്",
+ "timedmedia-derivative-opus": "ഓപസ്",
+ "timedmedia-derivative-desc-opus": "ഓപസ്",
+ "timedmedia-derivative-mp3": "എം.പി.3",
+ "timedmedia-derivative-desc-mp3": "എം.പി.3",
+ "timedmedia-derivative-m4a": "എ.എ.സി.",
+ "timedmedia-derivative-desc-m4a": "എ.എ.സി.",
+ "timedmedia-subtitle-new": "പുതിയ പരിഭാഷ തുടങ്ങുക അല്ലെങ്കിൽ നിലവിലുള്ളത് തിരുത്തുക",
+ "timedmedia-subtitle-new-desc": "ഭാഷ തിരഞ്ഞെടുത്ത്, '''{{int:Timedmedia-subtitle-new-go}}''' ബട്ടൺ അമർത്തുക",
+ "timedmedia-subtitle-new-go": "പോകൂ",
+ "timedmedia-subtitle-language": "$1 ($2) സംഭാഷണരേഖകൾ",
+ "timedmedia-subtitle-no-video": "ഇപ്പോഴത്തെ സംഭാഷണരേഖാ താളുമായി ചലച്ചിത്രങ്ങളൊന്നും ചേർത്തിട്ടില്ല",
+ "timedmedia-subtitle-no-subtitles": "ഈ ചലച്ചിത്രത്തിന് $1 ഭാഷയിൽ ഇപ്പോൾ സംഭാഷണരേഖയൊന്നും ഇല്ല, താങ്കൾക്ക് [{{fullurl:{{FULLPAGENAME}}|action=edit}} ഈ താൾ തിരുത്തി] അവ കൂട്ടിച്ചേർക്കാവുന്നതാണ്",
+ "timedmedia-subtitle-remote": "ഈ പ്രമാണത്തിനുള്ള സമയമനുസരിച്ചുള്ള എഴുത്ത് $1-ൽ ഹോസ്റ്റ് ചെയ്തിട്ടുണ്ട്.",
+ "timedmedia-subtitle-remote-link": "ഈ പ്രമാണത്തിനുള്ള [$1 വിവരണ താൾ] $2-ൽ താങ്കൾക്ക് കാണാവുന്നതാണ്",
+ "timedmediahandler": "മീഡിയ സമയമനുസരിച്ച് കൈകാര്യം ചെയ്യാനുള്ളയുപകരണം",
+ "timedmedia-videos": "{{PLURAL:$1|ഒരു ചലച്ചിത്രം|$1 ചലച്ചിത്രങ്ങൾ}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|ഒരു ഓഗ് ചലച്ചിത്രം|$1 ഓഗ് ചലച്ചിത്രങ്ങൾ}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|ഒരു വെബ്എം ചലച്ചിത്രം|$1 വെബ്എം ചലച്ചിത്രങ്ങൾ}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|ഒരു ട്രാൻസ്കോഡ്|$1 ട്രാൻസ്കോഡുകൾ}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|ഒരെണ്ണം ട്രാൻസ്കോഡ് ചെയ്യുന്നു|$1 എണ്ണം ട്രാൻസ്കോഡ് ചെയ്യുന്നു}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|ഒരെണ്ണം ട്രാൻസ്കോഡ് ചെയ്യാനായി ഉണ്ട്|$1 എണ്ണം ട്രാൻസ്കോഡ് ചെയ്യാനായി ഉണ്ട്}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|ഒരെണ്ണം ട്രാൻസ്കോഡ് ചെയ്യുന്നത് പരാജയപ്പെട്ടു|$1 എണ്ണം ട്രാൻസ്കോഡ് ചെയ്യുന്നത് പരാജയപ്പെട്ടു}}",
+ "timedmedia-file": "പ്രമാണം",
+ "timedmedia-audios": "{{PLURAL:$1|ഒരു ശബ്ദപ്രമാണം|$1 ശബ്ദപ്രമാണങ്ങൾ}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|ഒരു ഓഗ് (Ogg) ശബ്ദപ്രമാണം|$1 ഓഗ് (Ogg) ശബ്ദപ്രമാണങ്ങൾ}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|ഒരു ഫ്ലാക് (FLAC) ശബ്ദപ്രമാണം|$1 ഫ്ലാക് (FLAC) ശബ്ദപ്രമാണങ്ങൾ}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|ഒരു വേവ് (WAV) ശബ്ദപ്രമാണം|$1 വേവ് (WAV) ശബ്ദപ്രമാണങ്ങൾ}}",
+ "right-transcode-reset": "പുനഃക്രമീകരണം പരാജയപ്പെട്ടു അല്ലെങ്കിൽ ട്രാൻസ്കോഡ് ചെയ്ത ചലച്ചിത്രങ്ങൾ ജോബ് ക്യൂവിലേയ്ക്ക് വീണ്ടും ചേർത്തു",
+ "right-transcode-status": "[[Special:TimedMediaHandler|ഇപ്പോഴത്തെ ട്രാൻസ്കോഡ് പ്രവർത്തനത്തിന്റെ വിവരങ്ങൾ]] കാണുക",
+ "action-transcode-status": "ഇപ്പോഴത്തെ ട്രാൻസ്കോഡിങ് സ്ഥിതി കാണുക",
+ "orphanedtimedtext": "ഉപയോഗിക്കപ്പെടാത്ത സമയാനുസൃതയെഴുത്ത് താളുകൾ",
+ "orphanedtimedtext-summary": "ബന്ധപ്പെട്ട പ്രമാണങ്ങൾ ഇല്ലാത്ത [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] താളുകളുടെ പട്ടിക.",
+ "orphanedtimedtext-unsupported": "മൈഎസ്ക്യുഎൽ ഡേറ്റാബേസുകളെ മാത്രമേ ഈ പ്രത്യേകതാൾ പിന്തുണയ്ക്കുന്നുള്ളു.",
+ "orphanedtimedtext-notimedtext": "സമയാനുസൃതയെഴുത്ത് ഈ വിക്കിയിൽ സജ്ജമാക്കിയിട്ടില്ല.",
+ "apihelp-transcodereset-param-title": "മീഡിയ പ്രമാണത്തിന്റെ തലക്കെട്ട്."
+}
diff --git a/extensions/TimedMediaHandler/i18n/mr.json b/extensions/TimedMediaHandler/i18n/mr.json
new file mode 100644
index 00000000..0be5fe88
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/mr.json
@@ -0,0 +1,28 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kaustubh",
+ "V.narsikar",
+ "Htt"
+ ]
+ },
+ "timedmedia-desc": "ऑग थियोरा व वॉर्बिस संचिकांसाठीचा चालक, जावास्क्रीप्ट प्लेयर सकट",
+ "timedmedia-ogg-short-audio": "ऑग $1 ध्वनी संचिका, $2",
+ "timedmedia-ogg-short-video": "ऑग $1 चलतचित्र संचिका, $2",
+ "timedmedia-ogg-short-general": "ऑग $1 मीडिया संचिका, $2",
+ "timedmedia-ogg-long-audio": "ऑग $1 ध्वनी संचिका, लांबी $2, $3",
+ "timedmedia-ogg-long-video": "ऑग $1 चलतचित्र संचिका, लांबी $2, $4×$5 पीक्सेल्स, $3",
+ "timedmedia-ogg-long-multiplexed": "ऑग ध्वनी/चित्र संचिका, $1, लांबी $2, $4×$5 पिक्सेल्स, $3 एकूण",
+ "timedmedia-ogg-long-general": "ऑग मीडिया संचिका, लांबी $2, $3",
+ "timedmedia-ogg-long-error": "चुकीची ऑग संचिका: $1",
+ "timedmedia-more": "आणखी...",
+ "timedmedia-dismiss": "बंद करा",
+ "timedmedia-download": "संचिका अधिभारण करा",
+ "timedmedia-desc-link": "या संचिकेबद्दलची माहिती",
+ "timedmedia-source-file": "$1 स्रोत",
+ "timedmedia-source-audio-file-desc": "मूळ $1 संचिका ($2)",
+ "timedmediahandler": "टाईम्डमिडियाहॅंडलर",
+ "timedmedia-videos": "{{PLURAL:$1|$1 व्हीडिओ}}",
+ "timedmedia-audios": "{{PLURAL:$1|$1 ध्वनी संचिका}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg ध्वनी संचिका}}"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ms.json b/extensions/TimedMediaHandler/i18n/ms.json
new file mode 100644
index 00000000..504aa6f0
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ms.json
@@ -0,0 +1,97 @@
+{
+ "@metadata": {
+ "authors": [
+ "Anakmalaysia",
+ "Aviator"
+ ]
+ },
+ "timedmedia-desc": "Pemproses audio, video dan teks bermasa, dengan sokongan format untuk WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "fail bunyi Ogg $1, $2",
+ "timedmedia-ogg-short-video": "fail video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "fail media Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "fail bunyi Ogg $1, tempoh $2, $3",
+ "timedmedia-ogg-long-video": "fail video Ogg $1, tempoh $2, $4×$5 piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "fail audio/video multipleks Ogg, $1, tempoh $2, $4×$5 piksel, keseluruhan $3",
+ "timedmedia-ogg-long-general": "fail media Ogg, tempoh $2, $3",
+ "timedmedia-ogg-long-error": "Fail Ogg tidak sah: $1",
+ "timedmedia-webm-short-video": "fail video WebM $1, $2",
+ "timedmedia-webm-long-video": "fail audio/video webM, $1, tempoh $2, $4×$5 piksel, $3 keseluruhannya",
+ "timedmedia-flac-short-audio": "Fail audio FLAC, $1",
+ "timedmedia-flac-long-audio": "Fail audio FLAC, tempoh $1, $2 keseluruhannya",
+ "timedmedia-wav-short-audio": "Fail audio WAV, $1",
+ "timedmedia-wav-long-audio": "Fail audio WAV, tempoh $1, $2 keseluruhannya",
+ "timedmedia-wav-pcm-required": "Anda boleh memuat naik WAV PCM (Pulse Code Modulation) sahaja.",
+ "timedmedia-mp4-short-video": "fail video MP4 $1, $2",
+ "timedmedia-mp4-long-video": "fail audio/video MP4, $1, tempoh $2, $4×$5 piksel, $3 keseluruhannya",
+ "timedmedia-no-player-js": "Maaf, pelayar anda sama ada telah dimatikan JavaScript-nya ataupun tidak mempunyai sebarang pemain yang disokong.<br />\nAnda boleh <a href=\"$1\">memuat turun sedutan</a> itu atau <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">memuat turun pemain</a> yang boleh memutarkan sedutan berkenaan dalam pelayar anda.",
+ "timedmedia-more": "Lagi…",
+ "timedmedia-dismiss": "Tutup",
+ "timedmedia-download": "Muat turun fail",
+ "timedmedia-play-media": "Mainkan media",
+ "timedmedia-desc-link": "Perihal fail ini",
+ "timedmedia-oggThumb-version": "OggHandler memerlukan oggThumb versi $1 ke atas.",
+ "timedmedia-oggThumb-failed": "oggThumb gagal mencipta gambar kenit.",
+ "timedmedia-status-header": "Status transkod",
+ "timedmedia-update-status": "Kemaskinikan status transkod",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Status tidak diketahui",
+ "timedmedia-transcodeinfo": "Keterangan hasil terbitan transkod",
+ "timedmedia-actions": "Tindakan",
+ "timedmedia-direct-link": "Muat turun terbitan",
+ "timedmedia-not-ready": "Belum sedia",
+ "timedmedia-completed-on": "Pentranskodan selesai pada $1",
+ "timedmedia-error-on": "Ralat dalam transkod pada $1",
+ "timedmedia-started-transcode": "Pentranskodan bermula $1 lalu. $2",
+ "timedmedia-percent-done": "Kira-kira $1% selesai",
+ "timedmedia-in-job-queue": "Ditambahkan ke dalam baris gilir kerja $1 lalu",
+ "timedmedia-unknown-target-size": "Saiz sasaran tidak diketahui, $1 dikodkan",
+ "timedmedia-days": "$1 hari",
+ "timedmedia-hours": "$1 jam",
+ "timedmedia-minutes": "$1 minit",
+ "timedmedia-seconds": "$1 saat",
+ "timedmedia-reset": "Set semula transkod",
+ "timedmedia-reset-confirm": "Mengeset semula transkod ini akan membuang sebarang fail yang sedia ada (jika ada), lalu menambahkan semula transkod ke dalam baris gilir tugas. Pentranskodan semula akan memakan masa.<br /><br />Adakah anda tetap ingin melakukannya?",
+ "timedmedia-reset-error": "Ralat ketika mengeset semula tugas pentranskodan.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Sumber $1",
+ "timedmedia-source-file-desc": "Fail $1 asli, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Fail $1 asli ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Video Ogg lebar jalur rendah (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Video Ogg boleh strim web (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Video Ogg boleh strim web (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Video Ogg boleh muat turun bermutu tinggi (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "video Ogg HD sepenuhnya yang boleh dimuat turun (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM boleh strim web (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM boleh strim web (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM boleh strim web (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Video WebM boleh muat turun bermutu tinggi (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "WebM HD sepenuhnya yang boleh dimuat turun (1080P)",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 mesra peranti (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 boleh strim web (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 bermutu HD (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4 bermutu HD sepenuhnya (1080P)",
+ "timedmedia-subtitle-new": "Buat terjemahan baru atau sunting terjemahan sedia ada",
+ "timedmedia-subtitle-new-desc": "Pilih bahasa dan tekan butang '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Pergi",
+ "timedmedia-subtitle-language": "Sari kata $1 ($2)",
+ "timedmedia-subtitle-no-video": "Tiada video yang berkaitan dengan halaman sari kata ini",
+ "timedmedia-subtitle-no-subtitles": "Sekarang, tiada sari kata dalam $1 bagi video ini; anda boleh [{{fullurl:{{FULLPAGENAME}}|action=edit}} menyunting halaman ini] untuk menambahkannya",
+ "timedmedia-subtitle-remote": "Teks termasa untuk fail ini dihoskan di $1",
+ "timedmedia-subtitle-remote-link": "Anda boleh [$1 membaca halaman keterangan] untuk fail ini di $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "$1 video",
+ "timedmedia-ogg-videos": "$1 video Ogg",
+ "timedmedia-webm-videos": "$1 video WebM",
+ "timedmedia-derivative-state-transcodes": "$1 transkod",
+ "timedmedia-derivative-state-active": "$1 transkod aktif",
+ "timedmedia-derivative-state-queued": "$1 transkod berbaris",
+ "timedmedia-derivative-state-failed": "$1 transkod gagal",
+ "timedmedia-file": "Fail",
+ "timedmedia-audios": "$1 fail audio",
+ "timedmedia-ogg-audios": "$1 fail audio Ogg",
+ "timedmedia-flac-audios": "$1 fail audio FLAC",
+ "timedmedia-wav-audios": "$1 fail audio WAV",
+ "right-transcode-reset": "Mengeset semula video-video yang gagal atau ditranskodkan supaya dimasukkan semula ke dalam barisan gilir.",
+ "right-transcode-status": "Melihat [[Special:TimedMediaHandler|maklumat tentang kegiatan transkod semasa]]",
+ "action-transcode-status": "melihat status pentranskodan semasa"
+}
diff --git a/extensions/TimedMediaHandler/i18n/mt.json b/extensions/TimedMediaHandler/i18n/mt.json
new file mode 100644
index 00000000..a60fd776
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/mt.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Leli Forte"
+ ]
+ },
+ "timedmedia-no-player-js": "Jiddispjaċina li l-browser tiegħek jew m'għandux JavaScript attivat jew m'għandu l-ebda player supportat.<br />\nTista' <a href=\"$1\"> tniżżel il-vidjow</a> jew <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">tniżżel player</a> biex tara l-vidjow fuq il-browser tiegħek.",
+ "timedmedia-more": "Aktar",
+ "timedmedia-source-file": "Sors $1",
+ "timedmedia-source-audio-file-desc": "Fajl oriġinali $1 ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/myv.json b/extensions/TimedMediaHandler/i18n/myv.json
new file mode 100644
index 00000000..35b195ae
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/myv.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Botuzhaleny-sodamo"
+ ]
+ },
+ "timedmedia-more": "Седе ламо...",
+ "timedmedia-dismiss": "Пекстамс",
+ "timedmedia-download": "Таргамо файла",
+ "timedmedia-play-media": "Седямо медия",
+ "timedmedia-desc-link": "Те файладонть",
+ "timedmedia-source-file": "$1 лисьмапря"
+}
diff --git a/extensions/TimedMediaHandler/i18n/mzn.json b/extensions/TimedMediaHandler/i18n/mzn.json
new file mode 100644
index 00000000..f383daec
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/mzn.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "محک"
+ ]
+ },
+ "timedmedia-no-player-js": "بَخشِنّی، جاوا اسکریپت ِنرم افزار شمه بروزر دله فعال نی‌یه، یا شمه بروزر این نرم افزار ره ساپورت نکانده.<br />\nشما توندی <a href=\"$1\">این ویدیو ره دانلود</a> و یا <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">اتا پلیر</a> این ویدیو ره هارشی‌ین وسّه دانلود هاکنین.",
+ "timedmedia-source-file": "$1 مبدأ",
+ "timedmedia-source-audio-file-desc": "اصلی $1 پرونده ( $2 )"
+}
diff --git a/extensions/TimedMediaHandler/i18n/nah.json b/extensions/TimedMediaHandler/i18n/nah.json
new file mode 100644
index 00000000..5c41b6ca
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/nah.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Fluence",
+ "Taresi"
+ ]
+ },
+ "timedmedia-more": "Huehca ōmpa...",
+ "timedmedia-download": "Tictemōz tlahcuilōlli",
+ "timedmedia-desc-link": "Inīn tlahcuilōltechcopa",
+ "timedmedia-source-file": "$1 mēyalli"
+}
diff --git a/extensions/TimedMediaHandler/i18n/nap.json b/extensions/TimedMediaHandler/i18n/nap.json
new file mode 100644
index 00000000..c9953c8f
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/nap.json
@@ -0,0 +1,122 @@
+{
+ "@metadata": {
+ "authors": [
+ "C.R.",
+ "Chelin",
+ "Candalua"
+ ]
+ },
+ "timedmedia-desc": "Gestore p' 'e file audio, video e teste temporizzate, cu 'e formate supportate pe WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "File audio Ogg $1, $2",
+ "timedmedia-ogg-short-video": "File video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "File multimediale Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "File audio Ogg $1, durata $2, $3",
+ "timedmedia-ogg-long-video": "File video Ogg $1, durata $2, dimenziune $4×$5 pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "File multiplexed audie e video Ogg $1, lunghezze $2, $4 x $5 pixel, $3 in totale",
+ "timedmedia-ogg-long-general": "File media Ogg, lunghezze $2, $3",
+ "timedmedia-ogg-long-error": "Ogg file invalide: $1",
+ "timedmedia-ogg-long-no-streams": "File multimediale Ogg. Attenziò: nun è stato ricanusciuto nisciuno codec ausato ind'a stu file.",
+ "timedmedia-webm-short-video": "WebM $1 file video, $2",
+ "timedmedia-webm-long-video": "File WebM audio/video, $1, lunghezze $2, $4 × $5 pixel, $3 in totale",
+ "timedmedia-flac-short-audio": "File audio FLAC, $1",
+ "timedmedia-flac-long-audio": "File audio FLAC, lunghezze $1, in totale $2",
+ "timedmedia-wav-short-audio": "File audio WAV, $1",
+ "timedmedia-wav-long-audio": "File audio WAV, lunghezze $1, in totale $2",
+ "timedmedia-wav-pcm-required": "Putite surtanto carrecà WAV 'e tipo PCM (Codece 'e Modulazione Pulsate).",
+ "timedmedia-mp4-short-video": "MP4 $1 file video, $2",
+ "timedmedia-mp4-long-video": "File MP4 audio/video, $1, lunghezze $2, $4 × $5 pixel, $3 in totale",
+ "timedmedia-no-player-js": "Spiacente, 'o browser vuosto tene 'o JavaScript stutato o nun tène nu secutore suppurtato.<br />\nPutite <a href=\"$1\">scarrecà 'o video</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">scarrecà nu secutore</a> pe' putè miette 'o play ô video int' 'o browser vuosto.",
+ "timedmedia-more": "Ato...",
+ "timedmedia-dismiss": "Chiure",
+ "timedmedia-download": "Scarreca 'o file",
+ "timedmedia-play-media": "Secuta 'u media",
+ "timedmedia-desc-link": "'Mfurmaziune ncopp'a stu file",
+ "timedmedia-oggThumb-version": "OggHandler vulesse 'a verziona 'e oggThumb $1 o cchiù nnanz.",
+ "timedmedia-oggThumb-failed": "oggThumn ha fallite a ccrià 'e miniature.",
+ "timedmedia-status-header": "Stato d' 'a codifeca",
+ "timedmedia-update-status": "Agghiuorna 'o stato d' 'a codifeca",
+ "timedmedia-status": "Stato",
+ "timedmedia-status-unknown": "Stato scanusciuto",
+ "timedmedia-transcodebitrate": "Bitrate",
+ "timedmedia-transcodeduration": "Tiempo 'e codifeca",
+ "timedmedia-transcodeinfo": "Furmato",
+ "timedmedia-actions": "Aziune",
+ "timedmedia-direct-link": "Scarreca",
+ "timedmedia-not-ready": "Nun è pronto",
+ "timedmedia-completed-on": "$1 fernuto",
+ "timedmedia-error-on": "Errore dint' 'o $1",
+ "timedmedia-started-transcode": "Accummenciato $1 fa. $2",
+ "timedmedia-percent-done": "Cchiù o meno $1% fatto",
+ "timedmedia-in-job-queue": "Ghiuonta a 'a Fatica misa ncóra $1 fà",
+ "timedmedia-unknown-target-size": "Diminziona 'e destinazione scanusciuta, $1 encoded",
+ "timedmedia-days": "{{PLURAL:$1|1 juorno|$1 ghiuorne}}",
+ "timedmedia-hours": "{{PLURAL:$1|n'ora|$1 ore}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuto|$1 minute}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 secondo|$1 seconde}}",
+ "timedmedia-reset": "Azzere 'a transcodifeca",
+ "timedmedia-reset-confirm": "Resettanno sta transcodifica tuttuquante 'e file ch'esisteno mò (si ce stanno), e po' azzeccasse 'a transcodifica int'a 'o codece d' 'a fatica. Se pigliasse nu poco 'e tiempo pe' puté ffà 'o re-transcode. <br /><br />\nSite sicuro/a ca vulite ghì annanze?",
+ "timedmedia-reset-error": "Errore pe' tramente ca se steva azzeranno 'a fatica 'e transcodifeca.",
+ "timedmedia-source-file": "$1 funte",
+ "timedmedia-source-file-desc": "File origgenale $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "File origgenale $1 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg video cu banda vascia (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "Ogg video ca se putesse mannà pe' webstreaming (240P)",
+ "timedmedia-derivative-desc-360p.ogv": "Ogg video ca se putesse mannà pe' webstreaming (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Ogg video ca se putesse mannà pe' webstreaming (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Ogg video 'e qualità auta scarrecabbele (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Video Ogg scarrecabbele 'n Full HD (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Flusso web WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Flusse web WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Flusse web WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Ogg video 'e qualità auta scarrecabbele WebM (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "Video Ogg scarrecabbele 'n Full HD WebM (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "WebM scarrecabbele 'n Full 4K (2160P)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "Flusse web WebM VP9 (360P)",
+ "timedmedia-derivative-desc-480p.vp9.webm": "Flusse web WebM (480P)",
+ "timedmedia-derivative-desc-720p.vp9.webm": "Flusse HD WebM VP9 (720P)",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "Flusse Full HD WebM VP9 (1080P)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "WebM VP9 'e qualità Full 4K (2160P)",
+ "timedmedia-derivative-desc-320p.mp4": "Semprice pe' ll'apparicchie MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Flusse web WebM (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "Qualità HD MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4 'e qualità Full HD (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "MP4 'e qualità Full 4K (2160P)",
+ "timedmedia-subtitle-new": "Crìa na traduzione o cagna chella esistente",
+ "timedmedia-subtitle-new-desc": "Sceglie na lengua e clicca 'o buttone '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Vàje",
+ "timedmedia-subtitle-language": "$1 ($2) sottotitele",
+ "timedmedia-subtitle-no-video": "Nun ce stanno video ssuocie ch' 'e sottotitole d' 'e paggene 'e mò.",
+ "timedmedia-subtitle-no-subtitles": "Nun ce stanno mò sottotitule dint'a $1 pe' stu video, putite [{{fullurl:{{FULLPAGENAME}}|action=cagnà}} 'a paggena] pe' putè azzeccà chiste.",
+ "timedmedia-subtitle-remote": "'O testo temporizzate pe' stu file fuje ospitato ncopp'a $1",
+ "timedmedia-subtitle-remote-link": "Putite [$1 vedé 'a paggena 'e descrizione] 'e stu file ncopp'a $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 video Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 video WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcodifica|$1 transcodifiche}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transcodifica|$1 transcodifiche}} in esecuzzione",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transcodifica|$1 transcodifiche}} in coda",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 guastaje transcodifeca|$1 guastaje 'e transcodifiche}}",
+ "timedmedia-file": "File",
+ "timedmedia-audios": "{{PLURAL:$1|$1 file audio}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 file audio Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 file audio FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 file audio WAV}}",
+ "right-transcode-reset": "Appiccia n'ata vota 'e transcodifiche guaste 'e video ca songo state mise dint'a córa 'e fatiche n'ata vota",
+ "right-transcode-status": "Vide [[Special:TimedMediaHandler|'e nfurmaziune ncopp' 'a transcodifeca 'e mò]]",
+ "action-transcode-status": "vide 'o stato 'e transcodifeca 'e mo",
+ "orphanedtimedtext": "Paggene TimedText (sottotitule) urfanielle",
+ "orphanedtimedtext-summary": "Elenco 'e pagine [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] ca nun teneno 'o file currispunnente.",
+ "orphanedtimedtext-unsupported": "Sta paggena speciale è surtanto suppurtata dint' 'e database MySQL.",
+ "orphanedtimedtext-notimedtext": "'O TimedText (sottotitule) nun songo abbiàte dint'a stu wiki.",
+ "apihelp-query+transcodestatus-description": "Piglia 'o stato 'e transcodifeca pe' na paggena data.",
+ "apihelp-query+transcodestatus-example-1": "Piglia 'o stato transcode pe' [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "Spanne imageinfo pe' putè nzertà 'e nfurmaziune fonte 'e video (derivative)",
+ "apihelp-query+videoinfo-param-prop": "Che nfurmaziune se pigliasse 'o video:\n;timestamp:Azzecca 'a timestamp p' 'e verziune carrecate.\n;user:Azzecca l'utente c'avesse fatto l'upload dint'a verziona 'e video.\n;userid:Azzecca l'ID utente ca carrecaje sta verziona 'e video.\n;comment:Nu cummento ncopp' 'a verziona.\n;parsedcomment:Passa-scagna 'o cummento dint'a verziona.\n;canonicaltitle:Azzecca 'o titulo canonico 'e stu file 'e video.\n;url:Mpizzasse n'URL dint'o video e 'a paggena 'e descriziona.\n;size:Azzeccasse 'a pesantezza d' 'o file comm'a nu valore 'n byte, l'auto e 'o luongo suojo. 'O cunt' 'e paggene e 'a durata songo azzeccate si apprecabbele.\n;dimensions:Aliasse pe diminziona.\n;sha1:Azzecca nu hash SHA-1 p' 'o video video.\n;mime:Azzecca 'o tipo MIME d' 'o video.\n;thumbmime:Azzecca 'o tipo MIME p' 'o video thumbnail (servesse n'url e 'o param $1urlwidth).\n;mediatype:Azzecca 'o tipo 'e media dint' 'o video.\n;metadata:Elenca 'e metadate Exif p' 'a verziona d' 'o video.\n;commonmetadata:Elenca nu furmat' 'e file generico 'e metadate p' 'a verziona d' 'o video.\n;extmetadata:Elenca 'e date furmattate metadata cumbinate 'a fonte differente. 'E risultate songo HTML furmattate.\n;archivename:Azzecca 'o filename (nomm' 'e file) 'e sta verziona archivio pe' verziune ca nun fossero ll'urdema.\n;bitdepth:Azzecca 'o prufunno 'e bit d' 'a verziona.\n;uploadwarning:Ausato p' 'a paggena [[Special:Upload]] pe' se piglià nfurmaziune ncopp'a nu file ch'esiste mò. Nun ce buò stu coso pe' putè ausà 'o file for' 'o core 'e MediaWiki.\n;derivatives:Azzecca n'array 'e furmate differente cu qualità e verziune 'audio o video ca fosse mò a disposizione.",
+ "apihelp-query+videoinfo-example-1": "Arrepiglia mò 'e nfurmaziune ncopp' 'o [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "Utente c' 'o deritto 'e 'transcode-reset' putessero resettà e secutà n'ata vota na fatica 'e transcodifeca.",
+ "apihelp-transcodereset-param-title": "'O titolo d' 'o file media.",
+ "apihelp-transcodereset-param-transcodekey": "'A chiave 'e transcodifeca ca vulite re-appiccià. Arrepiglia mò [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Re-appiccia tuttuquante transcodes pe' [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "Re-appiccia 'a chiave 'e transcodifeca '360_560kbs.webm' pe' [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/nb.json b/extensions/TimedMediaHandler/i18n/nb.json
new file mode 100644
index 00000000..7a32ec0a
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/nb.json
@@ -0,0 +1,105 @@
+{
+ "@metadata": {
+ "authors": [
+ "Danmichaelo",
+ "Laaknor",
+ "Nghtwlkr"
+ ]
+ },
+ "timedmedia-desc": "Håndteringsprogram for lyd, video og tidsbestemt tekst, med formatstøtte for WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 lydfil, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 videofil, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 mediefil, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 lydfil, lengde $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 videofil, lengde $2, $4×$5 piksler, $3",
+ "timedmedia-ogg-long-multiplexed": "Sammensatt ogg lyd-/videofil, $1, lengde $2, $4×$5 piksler, $3 til sammen",
+ "timedmedia-ogg-long-general": "Ogg mediefil, lengde $2, $3",
+ "timedmedia-ogg-long-error": "Ugyldig Ogg-fil: $1",
+ "timedmedia-ogg-long-no-streams": "Ogg-mediafil. Advarsel: Ingen av omkoderne brukt i denne filen ble gjenkjent.",
+ "timedmedia-webm-short-video": "WebM $1 videofil, $2",
+ "timedmedia-webm-long-video": "WebM lyd-/videofil, $1, lengde $2, $4 × $5 piksler, $3 til sammen",
+ "timedmedia-flac-short-audio": "FLAC-lydfil, $1",
+ "timedmedia-flac-long-audio": "FLAC-lydfil, varighet $1, $2 totalt",
+ "timedmedia-wav-short-audio": "WAV-lydfil, $1",
+ "timedmedia-wav-long-audio": "WAV-lydfil, varighet $1, $2 totalt",
+ "timedmedia-wav-pcm-required": "Du kan kun laste opp PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "MP4 $1 videofil, $2",
+ "timedmedia-mp4-long-video": "MP4-fil for lyd/video, $1, lengde $2, $4 × $5 piksler, $3 totalt",
+ "timedmedia-no-player-js": "Beklager, nettleseren din har enten deaktivert JavaScript eller har ingen støttet spiller.<br />\nDu kan <a href=\"$1\">laste ned klippet</a> eller <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">laste ned en spiller</a> for å spille av klippet i nettleseren din.",
+ "timedmedia-more": "Mer …",
+ "timedmedia-dismiss": "Lukk",
+ "timedmedia-download": "Last ned fil",
+ "timedmedia-play-media": "Spill av media",
+ "timedmedia-desc-link": "Om denne filen",
+ "timedmedia-oggThumb-version": "OggHandler krever oggThumb versjon $1 eller senere.",
+ "timedmedia-oggThumb-failed": "oggThumb klarte ikke å opprette miniatyrbildet.",
+ "timedmedia-status-header": "Omkodingsstatus",
+ "timedmedia-update-status": "Oppdater omkodingsstatus",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Ukjent status",
+ "timedmedia-transcodeinfo": "Beskrivelse",
+ "timedmedia-actions": "Handlinger",
+ "timedmedia-direct-link": "Last ned utgave",
+ "timedmedia-not-ready": "Ikke klar",
+ "timedmedia-completed-on": "Omkoding ferdig $1",
+ "timedmedia-error-on": "Omkoding feilet den $1",
+ "timedmedia-started-transcode": "Omkoding startet for $1 siden. $2",
+ "timedmedia-percent-done": "Rundt $1% ferdig",
+ "timedmedia-in-job-queue": "Lagt til i jobbkø for $1 siden",
+ "timedmedia-unknown-target-size": "Ukjent målstørrelse, $1 ferdig kodet",
+ "timedmedia-days": "{{PLURAL:$1|1 dag|$1 dager}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 time|$1 timer}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minutt|$1 minutter}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 sekund|$1 sekunder}}",
+ "timedmedia-reset": "Nullstill omkoding",
+ "timedmedia-reset-confirm": "Nullstilling av denne omkodingsjobben vil slette eksisterende filer (hvis det er noen), og gjeninnsette omkodingsjobben i jobbkøen. Dette vil naturligvis ta noe tid.<br /><br />\nEr du sikker på at du ønsker å fortsette?",
+ "timedmedia-reset-error": "Det oppsto en feil ved forsøk på å nullstille omkodingsjobben.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 kilde",
+ "timedmedia-source-file-desc": "Original $1-fil, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Original $1-fil ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg-video for lav båndbredde (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Nett-strømbar Ogg-video (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Nett-strømbar Ogg-video (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Høykvalitets nedlastbar Ogg-video (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Nedlastbar Ogg-video i full HD (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Nett-strømbar WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Nett-strømbar WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Nett-strømbar WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Høykvalitets nedlastbar WebM (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "Nedlastbar WebM-video i full HD (1080P)",
+ "timedmedia-derivative-desc-320p.mp4": "Mobilvennlig MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Nett-strømbar MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD-kvalitet MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4-video i full HD (1080P)",
+ "timedmedia-subtitle-new": "Opprett ny oversettelse eller rediger eksisterende",
+ "timedmedia-subtitle-new-desc": "Velg språk eller trykk på '''{{int:Timedmedia-subtitle-new-go}}'''-knappen",
+ "timedmedia-subtitle-new-go": "Kjør",
+ "timedmedia-subtitle-language": "$1 ($2) undertekster",
+ "timedmedia-subtitle-no-video": "Det finnes ingen video koblet til den aktuelle undertekstsiden",
+ "timedmedia-subtitle-no-subtitles": "Det er for øyeblikket ingen undertekster på $1 for denne videoen. Du kan [{{fullurl:{{FULLPAGENAME}}|action=edit}} redigere denne siden] for å legge de til",
+ "timedmedia-subtitle-remote": "Undertekster (timed text) for denne filen befinner seg på $1",
+ "timedmedia-subtitle-remote-link": "Du kan [$1 vise beskrivelsessiden] for denne filen på $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video|$1 videoer}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg-video|$1 Ogg-videoer}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM-video|$1 WebM-videoer}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 omkoding|$1 omkodinger}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 pågående omkoding|$1 pågående omkodinger}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 omkoding|$1 omkodinger}} i kø",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 omkoding|$1 omkodinger}} feilet",
+ "timedmedia-file": "Fil",
+ "timedmedia-audios": "{{PLURAL:$1|$1 lydfil|$1 lydfiler}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg-lydfil|$1 Ogg-lydfiler}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC-lydfil|$1 FLAC-lydfiler}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV-lydfil|$1 WAV-lydfiler}}",
+ "right-transcode-reset": "Nullstill feilede eller omkodede videoer så de blir gjeninnsatt i jobbkøen.",
+ "right-transcode-status": "Vis [[Special:TimedMediaHandler|informasjon om pågående omkodinger]]",
+ "action-transcode-status": "vise pågående omkodingsstatus",
+ "orphanedtimedtext": "Foreldreløse TimedText-sider",
+ "orphanedtimedtext-summary": "Liste over [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]]-sider som ikke har tilknytning til noen fil.",
+ "orphanedtimedtext-unsupported": "Denne spesialsiden er kun støttet for MySQL-databaser.",
+ "orphanedtimedtext-notimedtext": "TimedText er ikke påskrudd på denne wikien.",
+ "apihelp-query+transcodestatus-description": "Hent transkodingsstatus for en gitt filside.",
+ "apihelp-query+transcodestatus-example-1": "Hent transkodingsstatus for [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/nds-nl.json b/extensions/TimedMediaHandler/i18n/nds-nl.json
new file mode 100644
index 00000000..f785cf7c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/nds-nl.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Servien"
+ ]
+ },
+ "timedmedia-desc": "Haandelt audio, video en ondertitels aof mit ondersteuning veur WebM, Ogg Theora, Vorbis en srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 geluudsbestaand, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 videobestaand, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 mediabestaand, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 geluudsbestaand, lengte $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 videobestaand, lengte $2, $4×$5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg-emultiplext geluuds-/videobestaand, $1, lengte $2, $4×$5 pixels, $3 totaal",
+ "timedmedia-ogg-long-general": "Ogg-mediabestaand, lengte $2, $3",
+ "timedmedia-ogg-long-error": "Ongeldig Ogg-bestaand: $1",
+ "timedmedia-no-player-js": "Joew systeem hef JavaScript uutstaon of der is gien ondersteunde mediaspeuler.<br />\nJe kunnen <a href=\"$1\">de klip neerlaojen</a> of <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">n mediaspeuler neerlaojen</a> um de klip aof te speulen in joew webkieker.",
+ "timedmedia-more": "Meer...",
+ "timedmedia-dismiss": "Sluten",
+ "timedmedia-download": "Bestaand neerlaojen",
+ "timedmedia-desc-link": "Over dit bestaand",
+ "timedmedia-source-file": "Bron van $1",
+ "timedmedia-source-audio-file-desc": "Oorspronkelik $1-bestaand ($2)",
+ "timedmediahandler": "Timed Media Handler"
+}
diff --git a/extensions/TimedMediaHandler/i18n/nds.json b/extensions/TimedMediaHandler/i18n/nds.json
new file mode 100644
index 00000000..b8404001
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/nds.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Slomox"
+ ]
+ },
+ "timedmedia-desc": "Stüürprogramm för Ogg-Theora- un Vorbis Datein, mitsamt en Afspeler in JavaScript",
+ "timedmedia-ogg-short-audio": "Ogg-$1-Toondatei, $2",
+ "timedmedia-ogg-short-video": "Ogg-$1-Videodatei, $2",
+ "timedmedia-ogg-short-general": "Ogg-$1-Mediendatei, $2",
+ "timedmedia-ogg-long-audio": "Ogg-$1-Toondatei, $2 lang, $3",
+ "timedmedia-ogg-long-video": "Ogg-$1-Videodatei, $2 lang, $4×$5 Pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg-Multiplexed-Audio-/Video-Datei, $1, $2 lang, $4×$5 Pixels, $3 alltohoop",
+ "timedmedia-ogg-long-general": "Ogg-Mediendatei, $2 lang, $3",
+ "timedmedia-ogg-long-error": "Kaputte Ogg-Datei: $1",
+ "timedmedia-more": "Mehr...",
+ "timedmedia-dismiss": "Dichtmaken",
+ "timedmedia-download": "Datei dalladen",
+ "timedmedia-desc-link": "Över disse Datei"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ne.json b/extensions/TimedMediaHandler/i18n/ne.json
new file mode 100644
index 00000000..acf3a5d1
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ne.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "सरोज कुमार ढकाल",
+ "बिप्लब आनन्द",
+ "NehalDaveND",
+ "राम प्रसाद जोशी"
+ ]
+ },
+ "timedmedia-ogg-short-audio": "Ogg $1 ध्वनि फाइल, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 विडियो फाइल, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 मीडिया फाइल, $2",
+ "timedmedia-no-player-js": "माफ गर्नुहोला, तपाईंको ब्राउजरमा या त जावास्क्रिप्ट अक्षम छ या समर्थित प्लेयर छैन ।<br />\nतपाईं <a href=\"$1\">क्लिपलाई डाउनलोड</a> गर्न सक्नुहुन्छ अथवा क्लिपलाई आफ्नो ब्राउजरमा चलाउनको लागि <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">एक प्लेयर डाउनलोड</a> गर्न सक्नु हुन्छ ।",
+ "timedmedia-more": "थप...",
+ "timedmedia-dismiss": "बन्ध गर्ने",
+ "timedmedia-download": "डाउनलोड गर्ने फाइल",
+ "timedmedia-status": "स्थिति",
+ "timedmedia-status-unknown": "अज्ञात स्थिति",
+ "timedmedia-actions": "कार्यहरु",
+ "timedmedia-source-file": "$1 श्रोत",
+ "timedmedia-source-file-desc": "मूल $1 फाईल, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "मूल $1 फाईल ($2)",
+ "timedmedia-subtitle-new-go": "जाने",
+ "timedmedia-file": "फाइल"
+}
diff --git a/extensions/TimedMediaHandler/i18n/nl.json b/extensions/TimedMediaHandler/i18n/nl.json
new file mode 100644
index 00000000..cfe2115f
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/nl.json
@@ -0,0 +1,108 @@
+{
+ "@metadata": {
+ "authors": [
+ "McDutchie",
+ "SPQRobin",
+ "Siebrand",
+ "Romaine"
+ ]
+ },
+ "timedmedia-desc": "Handelt audio, video en ondertitels af met ondersteuning voor WebM, Ogg Theora, Vorbis en srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 geluidsbestand, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 videobestand, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 mediabestand, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 geluidsbestand, lengte $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 videobestand, lengte $2, $4×$5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg gemultiplexed geluids/videobestand, $1, lengte $2, $4×$5 pixels, $3 totaal",
+ "timedmedia-ogg-long-general": "Ogg mediabestand, lengte $2, $3",
+ "timedmedia-ogg-long-error": "Ongeldig Ogg-bestand: $1",
+ "timedmedia-webm-short-video": "WebM $1 videobestand, $2",
+ "timedmedia-webm-long-video": "WebM audio/videobestand, $1, lengte $2, $4x$5 pixels, $3 totaal",
+ "timedmedia-flac-short-audio": "FLAC-audiobestand, $1",
+ "timedmedia-flac-long-audio": "FLAC-audiobestand, lengte $1, $2 gemiddeld",
+ "timedmedia-wav-short-audio": "WAV-audiobestand, $1",
+ "timedmedia-wav-long-audio": "WAV-audiobestand, lengte $1, $2 gemiddeld",
+ "timedmedia-wav-pcm-required": "U kunt alleen PCM (Pulse Code Modulation) WAV uploaden.",
+ "timedmedia-mp4-short-video": "MP4 $1 videobestand, $2",
+ "timedmedia-mp4-long-video": "MP4 audio/videobestand, $1, lengte $2, $4x$5 pixels, $3 totaal",
+ "timedmedia-no-player-js": "Uw systeem heeft JavaScript uitgeschakeld of er is geen ondersteunde mediaspeler.<br />\nU kunt <a href=\"$1\">de clip downloaden</a> of <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">een mediaspeler downloaden</a> om de clip af te spelen in uw browser.",
+ "timedmedia-more": "Meer…",
+ "timedmedia-dismiss": "Sluiten",
+ "timedmedia-download": "Bestand downloaden",
+ "timedmedia-play-media": "Media afspelen",
+ "timedmedia-desc-link": "Over dit bestand",
+ "timedmedia-oggThumb-version": "OggHandler vereist oggThumb versie $1 of hoger.",
+ "timedmedia-oggThumb-failed": "oggThumb kon geen miniatuur aanmaken.",
+ "timedmedia-status-header": "Conversiestatus",
+ "timedmedia-update-status": "Conversiestatus bijwerken",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Onbekende status",
+ "timedmedia-transcodeinfo": "Beschrijving van afgeleide conversie",
+ "timedmedia-actions": "Handelingen",
+ "timedmedia-direct-link": "Afgeleid werk downloaden",
+ "timedmedia-not-ready": "Niet klaar",
+ "timedmedia-completed-on": "Conversie voltooid op $1",
+ "timedmedia-error-on": "Fout in de conversie om $1",
+ "timedmedia-started-transcode": "De conversie is $1 geleden begonnen. $2",
+ "timedmedia-percent-done": "Ongeveer $1% afgerond",
+ "timedmedia-in-job-queue": "$1 geleden toegevoegd aan de Job queue",
+ "timedmedia-unknown-target-size": "Onbekende doelgrootte, $1 gecodeerd",
+ "timedmedia-days": "{{PLURAL:$1|1 dag|$1 dagen}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 uur|$1 uur}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuut|$1 minuten}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 seconde|$1 seconden}}",
+ "timedmedia-reset": "Transcodering opnieuw instellen",
+ "timedmedia-reset-confirm": "Door de transcodering opnieuw in te stellen worden alle bestanden bestanden (als aanwezig) verwijderd en de transcodering wordt opnieuw toegevoegd aan de wachtrij. Transcoderen kost tijd.<br /><br />\nWeet u zeker dat u wilt doorgaan?",
+ "timedmedia-reset-error": "Er is een fout opgetreden tijdens het opnieuw instellen van de transcoderingstaak.",
+ "timedmedia-ogg": "Ogg",
+ "timedmedia-webm": "WebM",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Bron van $1",
+ "timedmedia-source-file-desc": "Origineel $1-bestand, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Origineel $1-bestand ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160P",
+ "timedmedia-derivative-desc-160p.ogv": "Lage bandbreedte Ogg video (160P)",
+ "timedmedia-derivative-360p.ogv": "Ogg 360P",
+ "timedmedia-derivative-desc-360p.ogv": "Te webstreamen Ogg video (360P)",
+ "timedmedia-derivative-480p.ogv": "Ogg 480P",
+ "timedmedia-derivative-desc-480p.ogv": "Te webstreamen Ogg video (480P)",
+ "timedmedia-derivative-720p.ogv": "Ogg 720P",
+ "timedmedia-derivative-desc-720p.ogv": "Hoge kwaliteit downloadbare Ogg video (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Full HD downloadbare Ogg video (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Web streamable WebM (160P)",
+ "timedmedia-derivative-360p.webm": "WebM 360P",
+ "timedmedia-derivative-desc-360p.webm": "Te webstreamen WebM (360P)",
+ "timedmedia-derivative-480p.webm": "WebM 480P",
+ "timedmedia-derivative-desc-480p.webm": "Te webstreamen WebM (480P)",
+ "timedmedia-derivative-720p.webm": "WebM 720P",
+ "timedmedia-derivative-desc-720p.webm": "Hoge kwaliteit downloadbare WebM (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "Full HD downloadbare WebM (1080P)",
+ "timedmedia-derivative-desc-320p.mp4": "Apparaatvriendelijke MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Te webstreamen MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD-kwaliteit MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Full HD-kwaliteit MP4 (1080P)",
+ "timedmedia-subtitle-new": "Nieuw vertaling maken of bestaande bewerken",
+ "timedmedia-subtitle-new-desc": "Selecteer een taal en klik op de knop '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "OK",
+ "timedmedia-subtitle-language": "Ondertitels in $1 ($2)",
+ "timedmedia-subtitle-no-video": "Er is geen video gekoppeld aan de huidige ondertitelpagina",
+ "timedmedia-subtitle-no-subtitles": "Er zijn op het moment geen ondertitels in het $1 voor deze video. U kunt [{{fullurl:{{FULLPAGENAME}}|action=edit}} deze pagina bewerken] om ze toe te voegen",
+ "timedmedia-subtitle-remote": "De ondertitels voor dit bestand komen van $1",
+ "timedmedia-subtitle-remote-link": "U kunt de [$1 beschrijvingspagina voor dit bestand] bekijken op $2",
+ "timedmediahandler": "Timed Media Handler",
+ "timedmedia-videos": "{{PLURAL:$1|één video|$1 video's}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|één Oggvideo|$1 Oggvideo's}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|één WebM-video|$1 WebM-video's}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|één transcodering|$1 transcoderingen}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|één lopende transcodering|$1 lopende transcoderingen}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|één transcodering|$1 transcoderingen}} in de wachtrij",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|één mislukte transcodering|$1 mislukte transcoderingen}}",
+ "timedmedia-file": "Bestand",
+ "timedmedia-audios": "{{PLURAL:$1|$1 audiobestand|$1 audiobestanden}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg audiobestand|$1 Ogg audiobestanden}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC audiobestand|$1 FLAC audiobestanden}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV audiobestand|$1 WAV audiobestanden}}",
+ "right-transcode-reset": "Video's waarvoor transcoderen mislukt is of die al getranscodeerd zijn opnieuw in de jobqueue plaatsen.",
+ "right-transcode-status": "[[Special:TimedMediaHandler|Gegevens over de huidige transcoderingsactiviteit]] bekijken",
+ "action-transcode-status": "huidige transcoderingsstatus te bekijken"
+}
diff --git a/extensions/TimedMediaHandler/i18n/nn.json b/extensions/TimedMediaHandler/i18n/nn.json
new file mode 100644
index 00000000..cc6a3761
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/nn.json
@@ -0,0 +1,41 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eirik",
+ "Harald Khan",
+ "Njardarlogar",
+ "Ranveig"
+ ]
+ },
+ "timedmedia-desc": "Handteringsprogram for ljod, video og tidbunden tekst, med formatstøtte for WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1-lydfil, $2",
+ "timedmedia-ogg-short-video": "Ogg $1-videofil, $2",
+ "timedmedia-ogg-short-general": "Ogg $1-mediafil, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1-lydfil, lengd $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1-videofil, lengd $2, $4×$5 pikslar, $3",
+ "timedmedia-ogg-long-multiplexed": "Samansett ogg lyd-/videofil, $1, lengd $2, $4×$5 pikslar, $3 til saman",
+ "timedmedia-ogg-long-general": "Ogg mediafil, lengd $2, $3",
+ "timedmedia-ogg-long-error": "Ugyldig Ogg-fil: $1",
+ "timedmedia-no-player-js": "Orsak. Nettleseren din har anten ikkje JavaScript aktiv eller har ingen støtta spelar.<br />\nDu kan <a href=\"$1\">laste ned klippet</a> eller <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">laste ned ein spelar</a> for å spele av klippet i nettlesaren din.",
+ "timedmedia-more": "Meir...",
+ "timedmedia-dismiss": "Lat att",
+ "timedmedia-download": "Last ned fila",
+ "timedmedia-play-media": "Spel av media",
+ "timedmedia-desc-link": "Om denne fila",
+ "timedmedia-actions": "Handlingar",
+ "timedmedia-not-ready": "Ikkje ferdig",
+ "timedmedia-days": "{{PLURAL:$1|1 dag|$1 dagar}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 time|$1 timar}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minutt|$1 minutt}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 sekund|$1 sekund}}",
+ "timedmedia-source-file": "$1-kjelde",
+ "timedmedia-source-file-desc": "Opphavleg $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Opphavleg $1-fil ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg-video med låg bandbreidd (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Ogg-video som kan strøymast på nett (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Ogg-video som kan strøymast på nett (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Ogg-video av høg kvalitet som kan lastast ned (720P)",
+ "timedmedia-subtitle-new": "Lag ny omsetjing eller endra eksisterande",
+ "timedmedia-subtitle-new-desc": "Byt ut '''$1'''-delen med [[:en:ISO 639|språkkoden]] din og trykk på '''{{int:Timedmedia-subtitle-new-go}}'''-knappen",
+ "timedmedia-subtitle-new-go": "Gå"
+}
diff --git a/extensions/TimedMediaHandler/i18n/oc.json b/extensions/TimedMediaHandler/i18n/oc.json
new file mode 100644
index 00000000..892307d8
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/oc.json
@@ -0,0 +1,31 @@
+{
+ "@metadata": {
+ "authors": [
+ "Cedric31"
+ ]
+ },
+ "timedmedia-desc": "Supòrt pels fichièrs Ogg Theora e Vorbis, amb un lector Javascript",
+ "timedmedia-ogg-short-audio": "Fichièr son Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Fichièr vidèo Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Fichièr mèdia Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Fichièr son Ogg $1, durada $2, $3",
+ "timedmedia-ogg-long-video": "Fichièr vidèo Ogg $1, durada $2, $4×$5 pixèls, $3",
+ "timedmedia-ogg-long-multiplexed": "Fichièr multiplexat àudio/vidèo Ogg, $1, durada $2, $4×$5 pixèls, $3",
+ "timedmedia-ogg-long-general": "Fichièr mèdia Ogg, durada $2, $3",
+ "timedmedia-ogg-long-error": "Fichièr Ogg invalid : $1",
+ "timedmedia-webm-short-video": "Fichièr vidèo WebM $1, $2",
+ "timedmedia-webm-long-video": "Fichièr àudio/vidèo WebM, $1, longor $2, $4 x $5 pixèls, $3 l'ensemble",
+ "timedmedia-flac-short-audio": "Fichièr àudio FLAC, $1",
+ "timedmedia-flac-long-audio": "Fichièr àudio FLAC, durada $1, debit $2 sus l’ensemble",
+ "timedmedia-wav-short-audio": "Fichièr àudio WAV, $1",
+ "timedmedia-no-player-js": "O planhèm, siá vòstre navigador a JavaScript de desactivat, siá dispausa pas de cap de lector de pres en carga.<br />\nPodètz <a href=\"$1\">telecargar lo clip</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">telecargar un lector</a> per legir lo clip dins vòstre navigador.",
+ "timedmedia-more": "Mai…",
+ "timedmedia-dismiss": "Tampar",
+ "timedmedia-download": "Telecargar lo fichièr",
+ "timedmedia-desc-link": "A prepaus d'aqueste fichièr",
+ "timedmedia-source-file": "Font $1",
+ "timedmedia-source-audio-file-desc": "Fichièr original $1 ($2)",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-file": "Fichièr",
+ "right-transcode-reset": "Reïnicializar las vidèos en fracàs o transcodadas per que sián inseridas tornamai dins la fila dels trabalhs"
+}
diff --git a/extensions/TimedMediaHandler/i18n/olo.json b/extensions/TimedMediaHandler/i18n/olo.json
new file mode 100644
index 00000000..7e3ad6b5
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/olo.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mashoi7"
+ ]
+ },
+ "timedmedia-no-player-js": "Pahakse mielekse sinun livaimes libo JavaScript ei ole käytös, libo sit ei ole tuvettuu soitindu.<br />\nVoit <a href=\"$1\">lad'd'ata palan</a> libo <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">lad'd'ata soittimen</a> ku soittua pala sinun livaimes.",
+ "timedmedia-more": "Enämbi...",
+ "timedmedia-dismiss": "Salbua",
+ "timedmedia-play-media": "Soita medii",
+ "timedmedia-desc-link": "Täh failah näh",
+ "timedmedia-status": "Stuatussu",
+ "timedmedia-status-unknown": "Tundematoi stuatussu",
+ "timedmedia-source-file": "$1 lähteh",
+ "timedmedia-source-audio-file-desc": "Alguperäine $1 failu ($2)",
+ "timedmedia-subtitle-new-go": "Mene",
+ "timedmedia-file": "Failu"
+}
diff --git a/extensions/TimedMediaHandler/i18n/or.json b/extensions/TimedMediaHandler/i18n/or.json
new file mode 100644
index 00000000..c2df361d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/or.json
@@ -0,0 +1,85 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jnanaranjan Sahu",
+ "Psubhashish"
+ ]
+ },
+ "timedmedia-desc": "ଅଡିଓ, ଭିଡ଼ିଓ ଏବଂ ସାମୟିକ ଲେଖା ଗୁଡିକ ପାଇଁ ୱେବଏମ, ଓଜିଜି ଥିଓରା, ଭୋରବିସ, ଏସଆରଟି (WebM, Ogg Theora, Vorbis, srt) ସହାୟତା ଥିବା ପରିଚାଳନା କାରୀ",
+ "timedmedia-ogg-short-audio": "Ogg $1 ଶବ୍ଦ ଫାଇଲ, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 ଭିଡ଼ିଓ ଫାଇଲ, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 ମିଡ଼ିଆ ଫାଇଲ, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 ଶବ୍ଦ ଫାଇଲ, ଲମ୍ବ $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 ଭିଡ଼ିଓ, ଲମ୍ବ $2, $4×$5 ପିକ୍ସେଲ, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg ମଲଟିପ୍ଲେକ୍ସ ଧ୍ୱନି/ଚିତ୍ର ଫାଇଲ, $1, ଲମ୍ବ $2, $4×$5 ପିକ୍ସେଲ, ମୋଟ $3",
+ "timedmedia-ogg-long-general": "Ogg ମିଡ଼ିଆ ଫାଇଲ, ଲମ୍ବ $2, $3",
+ "timedmedia-ogg-long-error": "ଅବୈଧ ogg ଫାଇଲ: $1",
+ "timedmedia-webm-short-video": "Ogg $1 ଭିଡ଼ିଓ ଫାଇଲ, $2",
+ "timedmedia-webm-long-video": "ogg ଅଡିଓ/ଭିଡ଼ିଓ ଫାଇଲ, $1, ଲମ୍ବ $2, $4×$5 ପିକ୍ସେଲ, ମୋଟ $3",
+ "timedmedia-mp4-short-video": "MP4 $1 ଭିଡ଼ିଓ ଫାଇଲ, $2",
+ "timedmedia-mp4-long-video": "MP4 ଅଡିଓ/ଭିଡ଼ିଓ ଫାଇଲ, $1, ଲମ୍ବ $2, $4×$5 ପିକ୍ସେଲ, ମୋଟ $3",
+ "timedmedia-no-player-js": "ଦୁଖୀତଃ, ଆପଣଙ୍କ ବ୍ରାଉଜରରେ ଜାଭାସ୍କ୍ରିପ୍ଟ ଅଚଳ ହୋଇଯାଇଛି କିମ୍ବା କିଛି ଖାପଖାଉଥିବା ପ୍ଲେଆର ନାହିଁ । <br />\nଆପଣ ଏହି ଭିଡ଼ିଓଟିକୁ ଆପଣଙ୍କ ବ୍ରାଉଜରରେ ଚଲାଇବା ପାଇଁ<a href=\"$1\">ଭିଡିଓ କ୍ଲିପଟିକୁ ଡାଉନଲୋଡ କରିପାରିବେ</a> କିମ୍ବା <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">ଭିଡ଼ିଓ ପ୍ଲେୟାର ମଧ୍ୟ ଡାଉନଲୋଡ କରିପାରିବେ</a> ।",
+ "timedmedia-more": "ଅଧିକ...",
+ "timedmedia-dismiss": "ବନ୍ଦ କରିବେ",
+ "timedmedia-download": "ଫାଇଲ ଡାଉନଲୋଡ଼",
+ "timedmedia-play-media": "ମେଡିଆଟିକୁ ଚଲେଇବେ",
+ "timedmedia-desc-link": "ଏହି ଫାଇଲ ବିଷୟରେ",
+ "timedmedia-oggThumb-version": "oggପରିଚାଳନାକାରୀ $1 ସଂସ୍କରଣ କିମ୍ବା ତାଠୁ ନୂତନତମ oggଥମ୍ବନେଲ ଆବଶ୍ୟକ କରେ",
+ "timedmedia-oggThumb-failed": "oggThumb ଛୋଟଛବି ତିଆରି କରିପାରିଲା ନାହିଁ ।",
+ "timedmedia-status-header": "ଟ୍ରାନ୍ସକୋଡ ଅବସ୍ଥା",
+ "timedmedia-update-status": "ଟ୍ରାନ୍ସକୋଡ ଅବସ୍ଥା ଅପଡେଟ କରିବେ",
+ "timedmedia-status": "ଅବସ୍ଥା",
+ "timedmedia-status-unknown": "ଅଜଣା ଅବସ୍ଥା",
+ "timedmedia-transcodeinfo": "ଟ୍ରାନ୍ସକୋଡ ଭଜନର ବିବରଣୀ",
+ "timedmedia-actions": "କାମସବୁ",
+ "timedmedia-direct-link": "ଭାଜକଗୁଡିକୁ ଡାଉନଲୋଡ କରିବେ",
+ "timedmedia-not-ready": "ପ୍ରସ୍ତୁତ ହୋଇନାହିଁ",
+ "timedmedia-completed-on": "$1 ଟ୍ରାନ୍ସକୋଡ ଶେଷହେଲା",
+ "timedmedia-error-on": "$1 ଟ୍ରାନ୍ସକୋଡରେ ଅସୁବିଧା ।",
+ "timedmedia-started-transcode": "ଟ୍ରାନ୍ସକୋଡ $1ରୁ ଆରମ୍ଭ ହେଲା । $2",
+ "timedmedia-percent-done": "ହାରାହାରି $1% ସରିଛି",
+ "timedmedia-in-job-queue": "$1 ପୃର୍ବରୁ କାମରେ ଯୋଡାଗଲା",
+ "timedmedia-unknown-target-size": "ଅଜଣା ଆକାର, $1 ଏନକୋଡ ହେଲା",
+ "timedmedia-days": "{{PLURAL:$1|$1 ଦିନ|$1 ଦିନଗୁଡିକ}}",
+ "timedmedia-hours": "($1 {{PLURAL:$1|ଘଣ୍ଟା| ଘଣ୍ଟା}})",
+ "timedmedia-minutes": "$1 {{PLURAL:$1|ମିନିଟ|ମିନିଟଗୁଡିକ}}",
+ "timedmedia-seconds": "{{PLURAL:$1|ସେକେଣ୍ଡ|ସେକଣ୍ଡ}}",
+ "timedmedia-reset": "ଟ୍ରାନ୍ସକୋଡ ପୁନଃସ୍ଥାପନ କରିବେ",
+ "timedmedia-reset-confirm": "ଟ୍ରାନ୍ସକୋଡ ପୁନଃସ୍ଥାପନା କରିବାଦ୍ଵାରା ଅଗରୁଥିବା ଫାଇଲ ହଟିଯିବ, ଏବଂ ଏହା ପ୍ରକ୍ରିୟାରେ ଟ୍ରାନ୍ସକୋଡକୁ ଆଉଥରେ ଯୋଡିଦେବ । ଏହା ପୁନଃ ଟ୍ରାନ୍ସକୋଡ ପାଇଁ କିଛି ସମୟ ନେବ ।\nଆପଣ ପ୍ରକ୍ରିୟାକୁ ଚାଲୁରଖିବା ପାଇଁ ନିଶ୍ଚିତ ?",
+ "timedmedia-reset-error": "ଟ୍ରାନ୍ସକୋଡ ପୁନଃସ୍ଥାପନ କରିବାରେ ଅସୁବଧା ଉପୁଜିଲା",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 ଉତ୍ସ",
+ "timedmedia-source-file-desc": "ମୂଳ $1 ଫାଇଲ, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "ମୂଳ $1 ଫାଇଲ ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "କମ ବ୍ୟାଣ୍ଡୱିଥ ogg ଭିଡ଼ିଓ (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "ୱେବରେ ସିଧାଚାଲିଲା ଭଳି Ogg ଭିଡିଓ (360p)",
+ "timedmedia-derivative-desc-480p.ogv": "ୱେବରେ ସିଧାଚାଲିଲା ଭଳି Ogg ଭିଡିଓ (480p)",
+ "timedmedia-derivative-desc-720p.ogv": "ୱେବରେ ସିଧାଚାଲିଲା ଭଳି Ogg ଭିଡିଓ (720p)",
+ "timedmedia-derivative-desc-160p.webm": "ୱେବରେ ସିଧାଚାଲିଲା ଭଳି WebM ଭିଡିଓ (160p)",
+ "timedmedia-derivative-desc-360p.webm": "ୱେବରେ ସିଧାଚାଲିଲା ଭଳି WebM ଭିଡିଓ (360p)",
+ "timedmedia-derivative-desc-480p.webm": "ୱେବରେ ସିଧାଚାଲିଲା ଭଳି WebM ଭିଡିଓ (480p)",
+ "timedmedia-derivative-desc-720p.webm": "ଭଲ ପ୍ରକାରଥିବା ଏବଂ ଡାଉନଲୋଡ ହୋଇପାରୁଥିବା WebM(720P)",
+ "timedmedia-derivative-desc-320p.mp4": "ଯନ୍ତ୍ର-ସହାୟକ ଏମପି4(320P)",
+ "timedmedia-derivative-desc-480p.mp4": "ୱେବରେ ସିଧାଚାଲିଲା ଭଳି MP4 ଭିଡିଓ (480p)",
+ "timedmedia-derivative-desc-720p.mp4": "ଏଚଡ଼ି ପ୍ରକାରର MP4 (720P)",
+ "timedmedia-subtitle-new": "ନୂଆ ଅନୁବାଦ ଆରମ୍ଭ କରିବେ କିମ୍ବା ଆଗରୁଥିବା ଅନୁବାଦକୁ ବଦଳାଇବେ",
+ "timedmedia-subtitle-new-desc": "ଭାଷା ଚୟନ କରନ୍ତୁ ଏବଂ {{int:Timedmedia-subtitle-new-go}}'''ବଟନ ଦବାନ୍ତୁ",
+ "timedmedia-subtitle-new-go": "ଯିବେ",
+ "timedmedia-subtitle-language": "$1 ($2) ସବଟାଇଟଲ",
+ "timedmedia-subtitle-no-video": "ବର୍ତମାନର ସବଟାଇଟଲ ପୃଷ୍ଠା ସହ କୌଣସି ଭିଡିଓ ସଂଶ୍ଳିଷ୍ଟ ନାହିଁ",
+ "timedmedia-subtitle-no-subtitles": "ବର୍ତମାନ $1ରେ ଏହି ଭିଡିଓ ପାଇଁ କୌଣସି ସବଟାଇଟଲ ନାହିଁ, ଆପଣ [{{fullurl:{{FULLPAGENAME}}|action=edit}} ବଦଳାଇ] ଏହାକୁ ଯୋଡି ପାରିବେ",
+ "timedmedia-subtitle-remote": "ଏହି ଫାଇଲ ପାଇଁ ସାମୟିକ ଲେଖାଗୁଡିକ $1ରେ ଅଛି",
+ "timedmedia-subtitle-remote-link": "ଆପଣ $2ରେ ଥିବା ଏହି ଫାଇଲ ପାଇଁ [$1 ବିବରଣୀ ପୃଷ୍ଠା ଦେଖିପାରିବେ]",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 ଭିଡିଓ|$1 ଭିଡିଓ ଗୁଡିକ}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg ଭିଡିଓ|$1 Ogg ଭିଡିଓ ଗୁଡିକ}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM ଭିଡିଓ|$1 WebM ଭିଡିଓ ଗୁଡିକ}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 ଟ୍ରାନ୍ସକୋଡ|$1 ଟ୍ରାନ୍ସକୋଡଗୁଡିକ}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 ଚାଲୁଥିବା ଟ୍ରାନ୍ସକୋଡ|$1 ଚାଲୁଥିବା ଟ୍ରାନ୍ସକୋଡଗୁଡିକ}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 ଧାଡିରେ ଥିବା ଟ୍ରାନ୍ସକୋଡ|$1 ଧାଡିରେ ଥିବା ଟ୍ରାନ୍ସକୋଡଗୁଡିକ}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 ବିଫଳ ଟ୍ରାନ୍ସକୋଡ|$1 ବିଫଳ ଟ୍ରାନ୍ସକୋଡଗୁଡିକ}}",
+ "timedmedia-file": "ଫାଇଲ",
+ "right-transcode-reset": "ବିଫଳ ହୋଇଥିବା କିମ୍ବା ଟ୍ରାନ୍ସକୋଡ ଭିଡିଓଗୁଡିକ ପୁନଃସ୍ଥାପନ କରିବେ ଯାହାଫଳରେକି ସେଗୁଡିକ ପୁଣି ପ୍ରକ୍ରିୟାକରଣ ହେବ ।",
+ "right-transcode-status": "[[Special:TimedMediaHandler|ଏବେକାର ଟ୍ରାନ୍ସକୋଡ ଗତିବିଧି]] ଦେଖିବେ",
+ "action-transcode-status": "ଏବେକାର ଟ୍ରାନ୍ସକୋଡ ସ୍ଥିତି ଦେଖିବେ"
+}
diff --git a/extensions/TimedMediaHandler/i18n/os.json b/extensions/TimedMediaHandler/i18n/os.json
new file mode 100644
index 00000000..b5da6ba3
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/os.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Amikeco"
+ ]
+ },
+ "timedmedia-more": "Фылдæр…",
+ "timedmedia-download": "Файл æрбавгæн"
+}
diff --git a/extensions/TimedMediaHandler/i18n/pa.json b/extensions/TimedMediaHandler/i18n/pa.json
new file mode 100644
index 00000000..80ffc841
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/pa.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gman124",
+ "Babanwalia",
+ "Satdeep gill"
+ ]
+ },
+ "timedmedia-no-player-js": "ਮੁਆਫ਼ ਕਰਨਾ, ਜਾਂ ਤਾਂ ਤੁਹਾਡੇ ਬਰਾਊਜ਼ਰ ਉੱਤੇ ਜਾਵਾਸਕ੍ਰਿਪਟ ਚਾਲੂ ਨਹੀਂ ਜਾਂ ਫ਼ਿਰ ਕੋਈ ਹੋਰ ਸਹਾਇਕ ਪਲੇਅਰ ਮੌਜੂਦ ਨਹੀਂ ਹੈ।<br />\nਤੁਸੀਂ <a href=\"$1\">ਕਲਿੱਪ ਡਾਊਨਲੋਡ ਕਰ ਸਕਦੇ ਹੋ</a> ਜਾਂ <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">ਕੋਈ ਪਲੇਅਰ ਡਾਊਨਲੋਡ ਕਰਕੇ</a> ਇਹ ਕਲਿੱਪ ਆਪਣੇ ਬਰਾਊਜ਼ਰ ਵਿੱਚ ਚਲਾ ਸਕਦੇ ਹੋ।",
+ "timedmedia-more": "ਹੋਰ...",
+ "timedmedia-source-file": "$1 ਸਰੋਤ",
+ "timedmedia-source-audio-file-desc": "ਮੂਲ $1 ਫ਼ਾਈਲ ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/pdc.json b/extensions/TimedMediaHandler/i18n/pdc.json
new file mode 100644
index 00000000..d213f28c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/pdc.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Xqt"
+ ]
+ },
+ "timedmedia-more": "Mehr…",
+ "timedmedia-download": "Feil runnerlaade"
+}
diff --git a/extensions/TimedMediaHandler/i18n/pfl.json b/extensions/TimedMediaHandler/i18n/pfl.json
new file mode 100644
index 00000000..f4d3bbb6
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/pfl.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Manuae"
+ ]
+ },
+ "timedmedia-no-player-js": "Endwedda hoschd JavaScript abgschdeld odda de Browsa hodd kä unnaschdizdi Abschbielsofdwaa.<br />\nKonschd <a href=\"$1\">de Glibb runnalaade</a> odda ä <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">Abschbielsofdwaa</a> umde Glibb oagugge zu kenne.",
+ "timedmedia-source-file": "$1 Gwell",
+ "timedmedia-source-audio-file-desc": "Uaschbringlischi $1-Dadai ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/pl.json b/extensions/TimedMediaHandler/i18n/pl.json
new file mode 100644
index 00000000..cbd0fac5
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/pl.json
@@ -0,0 +1,101 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ankry",
+ "Chrumps",
+ "Derbeth",
+ "Faren",
+ "Leinad",
+ "Matma Rex",
+ "Przemub",
+ "Rzuwig",
+ "Sp5uhe"
+ ]
+ },
+ "timedmedia-desc": "Obsługa plików audio, wideo i napisów filmowych w formatach WebM, Ogg Theora, Vorbis i srt",
+ "timedmedia-ogg-short-audio": "Plik dźwiękowy Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Plik wideo Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Plik multimedialny Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "plik dźwiękowy Ogg $1, długość $2, $3",
+ "timedmedia-ogg-long-video": "plik wideo Ogg $1, długość $2, rozdzielczość $4×$5, $3",
+ "timedmedia-ogg-long-multiplexed": "plik audio/wideo Ogg, $1, długość $2, rozdzielczość $4×$5, ogółem $3",
+ "timedmedia-ogg-long-general": "plik multimedialny Ogg, długość $2, $3",
+ "timedmedia-ogg-long-error": "niepoprawny plik Ogg: $1",
+ "timedmedia-webm-short-video": "WebM $1 plik wideo, $2",
+ "timedmedia-webm-long-video": "WebM plik audio-wideo, $1, długość $2, $4 × $5 pikseli, ogółem $3",
+ "timedmedia-flac-short-audio": "Plik audio FLAC, $1",
+ "timedmedia-flac-long-audio": "Plik dźwiękowy FLAC, długość $1, przepływność $2",
+ "timedmedia-wav-short-audio": "Plik audio WAV, $1",
+ "timedmedia-wav-long-audio": "Plik dźwiękowy WAV, długość $1, przepływność $2",
+ "timedmedia-no-player-js": "Niestety, Twoja przeglądarka ma wyłączoną obsługę JavaScript lub nie wspiera odtwarzania.<br />\nMożesz <a href=\"$1\">pobrać plik</a> lub <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">pobrać odtwarzacz</a> pozwalający oglądać wideo w przeglądarce.",
+ "timedmedia-more": "Więcej...",
+ "timedmedia-dismiss": "Zamknij",
+ "timedmedia-download": "Pobierz plik",
+ "timedmedia-play-media": "Odtwórz plik multimedialny",
+ "timedmedia-desc-link": "Właściwości pliku",
+ "timedmedia-oggThumb-version": "OggHandler wymaga oggThumb w wersji $1 lub późniejszej.",
+ "timedmedia-oggThumb-failed": "oggThumb nie udało się utworzyć miniaturki.",
+ "timedmedia-status-header": "Status konwersji",
+ "timedmedia-update-status": "Zaktualizuj status konwersji",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Status nieznany",
+ "timedmedia-transcodeduration": "Czas kodowania",
+ "timedmedia-transcodeinfo": "Format",
+ "timedmedia-actions": "Operacje",
+ "timedmedia-direct-link": "Pobierz",
+ "timedmedia-not-ready": "Niegotowe",
+ "timedmedia-completed-on": "Ukończono $1",
+ "timedmedia-error-on": "Błąd o $1",
+ "timedmedia-started-transcode": "Konwersja rozpoczęła się $1 temu. $2",
+ "timedmedia-percent-done": "Ukończono ok. $1%",
+ "timedmedia-in-job-queue": "Dodano do kolejki $1 temu",
+ "timedmedia-unknown-target-size": "Rozmiar docelowy nieznany, $1 zakodowane",
+ "timedmedia-days": "$1 {{PLURAL:$1|dzień|dni}}",
+ "timedmedia-hours": "$1 {{PLURAL:$1|godzina|godziny|godzin}}",
+ "timedmedia-minutes": "$1 {{PLURAL:$1|minuta|minuty|minut}}",
+ "timedmedia-seconds": "$1 {{PLURAL:$1|sekunda|sekundy|sekund}}",
+ "timedmedia-reset": "Resetuj konwersję",
+ "timedmedia-reset-confirm": "Reset konwersji spowoduje usunięcie obecnego pliku (jeżeli takowy istnieje) i doda ją ponownie do kolejki. Zabierze to trochę czasu. <br /><br />\nCzy na pewno chcesz kontynuować?",
+ "timedmedia-reset-error": "Błąd w resecie konwersji.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Źródło $1",
+ "timedmedia-source-file-desc": "Oryginalny plik $1, $2 x $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Oryginalny plik $1 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg video o niskiej przepustowości (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Ogg video o przepustowości sieciowej (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Ogg video o przepustowości sieciowej (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Ogg video o wysokiej jakości (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Do pobrania wideo Ogg z Full HD (1080p)",
+ "timedmedia-derivative-desc-160p.webm": "WebM w jakości sieciowej (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM w jakości sieciowej (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM w jakości sieciowej (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM o wysokiej jakości (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "Do pobrania WebM Full HD (1080p)",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 odpowiednie dla tego urządzenia (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 w jakości sieciowej (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 w jakości HD (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Jakości Full HD (1080p) MP4",
+ "timedmedia-subtitle-new": "Utwórz nowe tłumaczenie lub edytuj istniejące",
+ "timedmedia-subtitle-new-go": "Przejdź",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 film|$1 filmy|$1 filmów}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 film Ogg|$1 filmy Ogg|$1 filmów Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 film WebM|$1 filmy WebM|$1 filmów WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transkodowanie|$1 transkodowania|$1 transkodowań}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 trwające transkodowanie|$1 trwające transkodowania|$1 trwających transkodowań}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transkodowanie|$1 transkodowania|$1 transkodowań}} w kolejce",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 nieudane transkodowanie|$1 nieudane transkodowania|$1 nieudanych transkodowań}}",
+ "timedmedia-file": "Plik",
+ "timedmedia-audios": "{{PLURAL:$1|$1 plik dźwiękowy|$1 pliki dźwiękowe|plików dźwiękowych}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 plik dźwiękowy|$1 pliki dźwiękowe|plików dźwiękowych}} Ogg",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 plik dźwiękowy|$1 pliki dźwiękowe|plików dźwiękowych}} FLAC",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 plik dźwiękowy|$1 pliki dźwiękowe|plików dźwiękowych}} WAV",
+ "right-transcode-reset": "Resetowanie błędnych lub transkodowanych filmów, które zostały ponownie umieszczone w kolejce zadań",
+ "right-transcode-status": "Podgląd [[Special:TimedMediaHandler|informacji o aktualnym statusie transkodowania]]",
+ "action-transcode-status": "zobaczenia aktualnego statusu transkodowania",
+ "orphanedtimedtext": "Osierocone strony TimedText",
+ "orphanedtimedtext-unsupported": "To strona specjalna jest obsługiwana tylko przez bazy danych MySQL.",
+ "orphanedtimedtext-notimedtext": "TimedText nie jest włączony w tej wiki.",
+ "apihelp-query+videoinfo-example-1": "Pobierz informacji o [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-param-title": "Tytuł pliku multimedialnego."
+}
diff --git a/extensions/TimedMediaHandler/i18n/pms.json b/extensions/TimedMediaHandler/i18n/pms.json
new file mode 100644
index 00000000..62681327
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/pms.json
@@ -0,0 +1,96 @@
+{
+ "@metadata": {
+ "authors": [
+ "Borichèt",
+ "Bèrto 'd Sèra",
+ "Dragonòt",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "timedmedia-desc": "Gestor për ij son, filmà e test a sincronisà, con manteniment dij formà për WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Registrassion Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Film Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Archivi Multimojen Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Registrassion Ogg $1, ch'a dura $2, $3",
+ "timedmedia-ogg-long-video": "Film Ogg $1, ch'a dura $2, formà $4×$5 px, $3",
+ "timedmedia-ogg-long-multiplexed": "Archivi audio/video multiplessà Ogg, $1, ch'a dura $2, formà $4×$5 px, $3 an tut",
+ "timedmedia-ogg-long-general": "Archivi multimojen Ogg, ch'a dura $2, $3",
+ "timedmedia-ogg-long-error": "Archivi ogg nen bon: $1",
+ "timedmedia-webm-short-video": "Archivi filmà WebM $1, $2",
+ "timedmedia-webm-long-video": "WebM archivi sonor/filmà, $1, longheur $2, $4 x $5 pontin, $3 an tut",
+ "timedmedia-flac-short-audio": "Archivi sonor FLAC, $1",
+ "timedmedia-flac-long-audio": "Archivi sonor FLAC, durà $1, ritm $2 an sël total",
+ "timedmedia-wav-short-audio": "Archivi sonor WAV, $1",
+ "timedmedia-wav-long-audio": "Archivi sonor WAV, durà $1, $2 sël total",
+ "timedmedia-wav-pcm-required": "A peul mach carié dij WAV PCM (Modolassion d'ampulsion codificà).",
+ "timedmedia-mp4-short-video": "Archivi filmà MP4 $1, $2",
+ "timedmedia-mp4-long-video": "MP4 archivi sonor/filmà, $1, longheur $2, $4 x $5 pontin, $3 an tut",
+ "timedmedia-no-player-js": "Darmagi, sò navigador a l'ha JavaScript disabilità o a manten pa ël riprodutor.<br />\nA peul <a href=\"$1\">dëscarié la senëtta</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">dëscarié un riprodutor</a> për visualisé la senëtta su sò navigador.",
+ "timedmedia-more": "Dë pì...",
+ "timedmedia-dismiss": "sëré",
+ "timedmedia-download": "Dëscarié l'archivi",
+ "timedmedia-play-media": "Lese ël mojen",
+ "timedmedia-desc-link": "Rësgoard a st'archivi",
+ "timedmedia-oggThumb-version": "OggHandler a ciama la version $1 d'oggThumb o pi agiornà.",
+ "timedmedia-oggThumb-failed": "oggThumb a l'ha falì a creé la figurin-a.",
+ "timedmedia-status-header": "Statù ëd trascodìfica",
+ "timedmedia-update-status": "Agiorné lë statù ëd trascodìfica",
+ "timedmedia-status": "Stat",
+ "timedmedia-status-unknown": "Stat pa conossù",
+ "timedmedia-transcodeinfo": "Descrission derivà da la trascodìfica",
+ "timedmedia-actions": "Assion",
+ "timedmedia-direct-link": "Dëscarié ël derivà",
+ "timedmedia-not-ready": "Pa pront",
+ "timedmedia-completed-on": "Trascodìfica completà $1",
+ "timedmedia-error-on": "Eror ant la trascodìfica ëd $1",
+ "timedmedia-started-transcode": "Trascodìfica ancaminà $1 fà. $2",
+ "timedmedia-percent-done": "Sirca $1% fàit",
+ "timedmedia-in-job-queue": "Giontà a la coa dij Travaj $1 fà",
+ "timedmedia-unknown-target-size": "Dimension ëd la destinassion pa conossùa, $1 codificà",
+ "timedmedia-days": "{{PLURAL:$1|1 di|$1 di}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 ora|$1 ore}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuta|$1 minute}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 second|$1 second}}",
+ "timedmedia-reset": "Amposté torna la trascodìfica",
+ "timedmedia-reset-confirm": "Amposté torna sa trascodìfica a tramuderà tut archivi esistent (s'a-i na j'é) e a gionterà torna la trascodìfica a la coa dij travaj. A-i andrà dël temp a trascodifiché torna. <br /><br />\nÉ-lo sigur ëd vorèj continué?",
+ "timedmedia-reset-error": "Eror an ampostand torna ël travaj ëd trascodìfica.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 sorziss",
+ "timedmedia-source-file-desc": "Archivi original $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Archivi original $1 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Larghëssa ëd banda bassa Ogg video (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Web streamable Ogg video (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Filmà Ogg lesìbil an continuà an sl'aragnà (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Filmà Ogg dëscariàbil d'àuta qualità (720P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM lesìbil an continuà an sl'aragnà (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM lesìbil an continuà an sl'aragnà (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM lesìbil an continuà an sl'aragnà (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM dëscariàbil d'àuta qualità (720P)",
+ "timedmedia-derivative-desc-320p.mp4": "Dispositiv compatìbil MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 lesìbil an continuà an sl'aragnà (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 an qualità HD (720P)",
+ "timedmedia-subtitle-new": "Creé na neuva tradussion o modifichene un-a esistenta",
+ "timedmedia-subtitle-new-desc": "Ch'a selession-a la lenga e ch'a sgnaca an sël boton '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Va",
+ "timedmedia-subtitle-language": "$1 ($2) sot-tìtoj",
+ "timedmedia-subtitle-no-video": "A-i é gnun filmà associà con la pagina corenta dël sot-tìtol",
+ "timedmedia-subtitle-no-subtitles": "A-i é al moment gnun sot-tìtoj an $1 për ës filmà, a peul [{{fullurl:{{FULLPAGENAME}}|action=edit}} modifiché costa pàgina] për gionteje",
+ "timedmedia-subtitle-remote": "Ël test previst për cost archivi a l'é ospità dzor $1",
+ "timedmedia-subtitle-remote-link": "A peul [$1 vëdde la pàgina ëd descrission] ëd s'archivi dzor $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 filmà}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 filmà Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 filmà WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 trascodìfica|$1 trascodìfiche}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 trascodìfica|$1 trascodìfiche}} an esecussion",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 trascodìfica|$1 trascodìfiche}} an coa",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 trascodìfica falìa|$1 trascodìfiche falìe}}",
+ "timedmedia-file": "Archivi",
+ "timedmedia-audios": "{{PLURAL:$1|$1 archivi sonor}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 archivi sonor Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 archivi sonor FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 archivi sonor WAV}}",
+ "right-transcode-reset": "Amposté torna ij filmà falì o trascodificà për ch'a sio torna anserì ant la coa dij travaj.",
+ "right-transcode-status": "Smon-e [[Special:TimedMediaHandler|l'anformassion a propòsit ëd l'atività corenta ëd trascodìfica]]",
+ "action-transcode-status": "varda lë stat ëd trascodìfica corent"
+}
diff --git a/extensions/TimedMediaHandler/i18n/pnb.json b/extensions/TimedMediaHandler/i18n/pnb.json
new file mode 100644
index 00000000..3ff940e9
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/pnb.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Khalid Mahmood"
+ ]
+ },
+ "timedmedia-no-player-js": "تواڈے براؤزر تے جاواسکرپٹ کم نہیں کر ریا یا فیر ہور پلئیر نہیں <br />\nتسیں <a href=\"$1\">کلپ ڈاؤنلوڈ کرسکدے او</a> یا <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">یا اپنے براؤزر وچ کلپ چلان لئی پلیئر ڈاؤنلوڈ کرو</a> .",
+ "timedmedia-source-file": "$1 مڈھ",
+ "timedmedia-source-audio-file-desc": "اصلی$1 فائل ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ps.json b/extensions/TimedMediaHandler/i18n/ps.json
new file mode 100644
index 00000000..f602ceb3
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ps.json
@@ -0,0 +1,29 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ahmed-Najib-Biabani-Ibrahimkhel"
+ ]
+ },
+ "timedmedia-ogg-short-audio": "Ogg $1 غږيزه دوتنه، $2",
+ "timedmedia-ogg-short-video": "Ogg $1 ويډيويي دوتنه، $2",
+ "timedmedia-ogg-short-general": "Ogg $1 رسنيزه دوتنه، $2",
+ "timedmedia-no-player-js": "بخښنه دې وي، يا خو ستاسې په کتنمل باندې جاواسکرېپټ ناچارن دی او يا هم تاسې کوم ملاتړلی غږونکی نه لری.<br />\nتاسې <a href=\"$1\">کلېپ ښکته کولی شئ</a> او يا هم يو داسې <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">غږونکی ښکته کړئ</a> چې کلېپ په کتنمل باندې وغږوي.",
+ "timedmedia-more": "نور...",
+ "timedmedia-dismiss": "تړل",
+ "timedmedia-download": "دوتنه ښکته کول",
+ "timedmedia-play-media": "رسنۍ غږول",
+ "timedmedia-desc-link": "د همدې دوتنې په اړه",
+ "timedmedia-status": "دريځ",
+ "timedmedia-transcodeinfo": "بڼه",
+ "timedmedia-actions": "چارې",
+ "timedmedia-direct-link": "ښکته کول",
+ "timedmedia-days": "{{PLURAL:$1|1 ورځ|$1 ورځې}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 گړۍ|$1 گړۍ}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 دقيقه|دقيقې}}",
+ "timedmedia-source-file": "$1 سرچينه",
+ "timedmedia-source-audio-file-desc": "اصلي $1 دوتنه ($2)",
+ "timedmedia-subtitle-new-go": "ورځه",
+ "timedmedia-videos": "{{PLURAL:$1|$1 ويډيو|$1 ويډيوگانې}}",
+ "timedmedia-file": "دوتنه",
+ "timedmedia-audios": "{{PLURAL:$1|$1 غږيزه دوتنه|$1 غږيزې دوتنې}}"
+}
diff --git a/extensions/TimedMediaHandler/i18n/pt-br.json b/extensions/TimedMediaHandler/i18n/pt-br.json
new file mode 100644
index 00000000..99b96b5e
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/pt-br.json
@@ -0,0 +1,40 @@
+{
+ "@metadata": {
+ "authors": [
+ "Eduardo.mps",
+ "Giro720",
+ "Luckas",
+ "Opraco",
+ "Guilhermemau",
+ "Fasouzafreitas"
+ ]
+ },
+ "timedmedia-desc": "Manipulador para arquivos Ogg Theora e Vorbis, com reprodutor JavaScript",
+ "timedmedia-ogg-short-audio": "Arquivo de áudio Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Arquivo de vídeo Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Arquivo multimídia Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "arquivo de áudio Ogg $1, $2 de duração, $3",
+ "timedmedia-ogg-long-video": "Vídeo Ogg $1, $2 de duração, $4×$5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "Áudio/vídeo Ogg multifacetado, $1, $2 de duração, $4×$5 pixels, $3 no todo",
+ "timedmedia-ogg-long-general": "Multimídia Ogg, $2 de duração, $3",
+ "timedmedia-ogg-long-error": "Arquivo ogg inválido: $1",
+ "timedmedia-no-player-js": "Desculpe, seu navegador ou está com JavaScript desabilitado ou não tem nenhum \"player\" suportado.<br />\nVocê pode <a href=\"$1\">descarregar o clipe</a> ou <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">descarregar um \"player\"</a> para executar o clipe em seu navegador.",
+ "timedmedia-more": "Mais...",
+ "timedmedia-dismiss": "Fechar",
+ "timedmedia-download": "Descarregar arquivo",
+ "timedmedia-desc-link": "Sobre este arquivo",
+ "timedmedia-oggThumb-version": "O oggHandler requer o oggThumb versão $1 ou posterior.",
+ "timedmedia-oggThumb-failed": "O oggThumb não conseguiu criar a miniatura.",
+ "timedmedia-actions": "Ações",
+ "timedmedia-days": "{{PLURAL:$1|1 dia|$1 dias}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 hora|$1 horas}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuto|$1 minutos}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 segundo|$1 segundos}}",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Fonte $1",
+ "timedmedia-source-audio-file-desc": "Arquivo $1 original ($2)",
+ "timedmedia-derivative-desc-1080p.webm": "WebM para download de Full HD (1080p)",
+ "timedmedia-derivative-desc-1080p.mp4": "Qualidade total do HD MP4 (1080 P)",
+ "timedmedia-subtitle-new-go": "Ir",
+ "timedmedia-file": "Arquivo"
+}
diff --git a/extensions/TimedMediaHandler/i18n/pt.json b/extensions/TimedMediaHandler/i18n/pt.json
new file mode 100644
index 00000000..379e2271
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/pt.json
@@ -0,0 +1,102 @@
+{
+ "@metadata": {
+ "authors": [
+ "Giro720",
+ "Hamilton Abreu",
+ "Luckas",
+ "Malafaya",
+ "Opraco",
+ "Vitorvicentevalente",
+ "Waldir",
+ "555",
+ "Tooguether",
+ "Macofe",
+ "Fúlvio"
+ ]
+ },
+ "timedmedia-desc": "Tratamento de áudio, vídeo e legendagem, nos formatos WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Áudio Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Vídeo Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Multimédia Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "áudio Ogg $1, $2 de duração, $3",
+ "timedmedia-ogg-long-video": "Vídeo Ogg $1, $2 de duração, $4×$5 pixels, $3",
+ "timedmedia-ogg-long-multiplexed": "Áudio/vídeo Ogg multifacetado, $1, $2 de duração, $4×$5 pixels, $3 no todo",
+ "timedmedia-ogg-long-general": "Multimédia Ogg, $2 de duração, $3",
+ "timedmedia-ogg-long-error": "Ficheiro ogg inválido: $1",
+ "timedmedia-ogg-long-no-streams": "Arquivo de mídia OGG. Aviso: Nenhum dos codecs utilizados neste arquivo são reconhecidos.",
+ "timedmedia-webm-short-video": "Vídeo WebM $1, $2",
+ "timedmedia-webm-long-video": "Áudio/vídeo WebM, $1, $2 de duração, $4 × $5 pixels, $3 no todo",
+ "timedmedia-flac-short-audio": "Ficheiro de áudio FLAC, $1",
+ "timedmedia-flac-long-audio": "Ficheiro de áudio FLAC, duração $1, $2",
+ "timedmedia-wav-short-audio": "Ficheiro de áudio WAV, $1",
+ "timedmedia-wav-long-audio": "Ficheiro de áudio WAV, duração $1, $2",
+ "timedmedia-mp4-short-video": "Vídeo MP4 $1, $2",
+ "timedmedia-mp4-long-video": "Áudio/vídeo MP$, $1, duração $2, $4 × $5 pixels, $3",
+ "timedmedia-no-player-js": "Desculpe, mas ou o seu navegador está com o JavaScript desactivado ou não tem nenhum dos leitores suportados.<br />\nPode fazer a <a href=\"$1\">descarga do vídeo</a> ou o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">de um leitor</a> para assistir ao vídeo no seu navegador.",
+ "timedmedia-more": "Mais...",
+ "timedmedia-dismiss": "Fechar",
+ "timedmedia-download": "Fazer descarga do ficheiro",
+ "timedmedia-play-media": "Reproduzir conteúdo",
+ "timedmedia-desc-link": "Sobre este ficheiro",
+ "timedmedia-oggThumb-version": "O oggHandler requer a versão $1 do oggThumb ou posterior.",
+ "timedmedia-oggThumb-failed": "O oggThumb não conseguiu criar a miniatura.",
+ "timedmedia-status-header": "Estado da transcodificação",
+ "timedmedia-update-status": "Actualizar o estado da transcodificação",
+ "timedmedia-status": "Estado",
+ "timedmedia-status-unknown": "Estado desconhecido",
+ "timedmedia-transcodeinfo": "Formato",
+ "timedmedia-actions": "Acções",
+ "timedmedia-direct-link": "Descarregar",
+ "timedmedia-not-ready": "Ainda não está pronto",
+ "timedmedia-completed-on": "Concluída a $1",
+ "timedmedia-error-on": "Erro em $1",
+ "timedmedia-started-transcode": "Iniciou há $1. $2",
+ "timedmedia-percent-done": "O progresso é cerca de $1%",
+ "timedmedia-in-job-queue": "Adicionado à fila de tarefas há $1",
+ "timedmedia-unknown-target-size": "Dimensão do destino desconhecida; $1 codificados",
+ "timedmedia-days": "{{PLURAL:$1|1 dia|$1 dias}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 hora|$1 horas}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuto|$1 minutos}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 segundo|$1 segundos}}",
+ "timedmedia-reset": "Reiniciar transcodificação",
+ "timedmedia-reset-confirm": "Reiniciar esta transcodificação elimina qualquer ficheiro existente e volta a adicionar a transcodificação à fila de tarefas. A nova transcodificação irá demorar algum tempo. <br /><br />Tem a certeza de que pretende continuar?",
+ "timedmedia-reset-error": "Ocorreu um erro ao reiniciar a tarefa de transcodificação",
+ "timedmedia-source-file": "Fonte $1",
+ "timedmedia-source-file-desc": "Ficheiro $1 original, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Ficheiro $1 original ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Vídeo Ogg de baixa largura de banda (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Vídeo Ogg para web streaming (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Vídeo Ogg para web streaming (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Vídeo Ogg de alta qualidade para download (720 P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM para web streaming (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM para web streaming (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM de alta qualidade para download (720P)",
+ "timedmedia-derivative-desc-720p.mp4": "Qualidade HD MP4 (720P)",
+ "timedmedia-subtitle-new": "Criar nova tradução ou editar existente",
+ "timedmedia-subtitle-new-desc": "Seleccione o idioma e pressione o botão '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Enviar",
+ "timedmedia-subtitle-language": "Legendas em $1 ($2)",
+ "timedmedia-subtitle-no-video": "Não existe nenhum vídeo associado à actual página de legendas",
+ "timedmedia-subtitle-no-subtitles": "Neste momento não existem legendas em $1 para este vídeo. Pode [{{fullurl:{{FULLPAGENAME}}|action=edit}} editar a página] e adicioná-las.",
+ "timedmedia-subtitle-remote": "A legenda para este ficheiro está hospedada em $1",
+ "timedmedia-subtitle-remote-link": "Pode [$1 ver a página de descrição] para este ficheiro em $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 vídeo|$1 vídeos}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 vídeo ogg|$1 vídeos ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 vídeo WebM|$1 vídeos WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcodificação|$1 transcodificações}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transcodificação em andamento|$1 transcodificações em andamento}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transcodificação em espera|$1 transcodificações em espera}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transcodificação falhada|$1 transcodificações falhadas}}",
+ "timedmedia-file": "Ficheiro",
+ "timedmedia-audios": "{{PLURAL:$1|$1 ficheiro de áudio|$1 ficheiros de áudio}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 ficheiro de áudio Ogg|$1 ficheiros de áudio Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 ficheiro de áudio FLAC|$1 ficheiros de áudio FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 ficheiro de áudio WAV|$1 ficheiros de áudio WAV}}",
+ "right-transcode-status": "Ver [[Special:TimedMediaHandler|informação sobre a actividade actual de transcodificação]]",
+ "action-transcode-status": "ver o estado actual de transcodificação",
+ "orphanedtimedtext": "Páginas Legendagem órfãs",
+ "orphanedtimedtext-summary": "Lista de páginas [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] que não têm um ficheiro correspondente.",
+ "orphanedtimedtext-unsupported": "Esta página especial só é suportada nas bases de dados MySQL.",
+ "orphanedtimedtext-notimedtext": "O domínio Legendagem não está habilitado nesta wiki."
+}
diff --git a/extensions/TimedMediaHandler/i18n/qqq.json b/extensions/TimedMediaHandler/i18n/qqq.json
new file mode 100644
index 00000000..4fe17fe8
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/qqq.json
@@ -0,0 +1,172 @@
+{
+ "@metadata": {
+ "authors": [
+ "Aotake",
+ "BrokenArrow",
+ "EugeneZelenko",
+ "Fryed-peach",
+ "Jon Harald Søby",
+ "Meno25",
+ "Minh Nguyen",
+ "Mormegil",
+ "Purodha",
+ "Raymond",
+ "Shirayuki",
+ "Siebrand",
+ "Umherirrender",
+ "아라",
+ "Liuxinyu970226",
+ "Amire80",
+ "Robby"
+ ]
+ },
+ "extensionname-timedmedia": "{{optional}}",
+ "timedmedia-desc": "{{desc|name=Timed Media Handler|url=https://www.mediawiki.org/wiki/Extension:TimedMediaHandler}}",
+ "timedmedia-ogg-short-audio": "File details for Ogg sound (audio) files, short version.\nParameters:\n* $1 - stream type name. Any one of the following: Vorbis, Speex, FLAC\n* $2 - duration of the sound/audio (localized) - e.g. 1m34s\n{{Related|Timedmedia-ogg-short}}",
+ "timedmedia-ogg-short-video": "File details for Ogg video files, short version.\nParameters:\n* $1 - stream type name: Theora\n* $2 - duration of the video (localized) - e.g. 1m34s\n{{Related|Timedmedia-ogg-short}}",
+ "timedmedia-ogg-short-general": "File details for generic (non-audio, non-video) Ogg files, short version.\nParameters:\n* $1 - stream type name\n* $2 - duration of the media (localized) - e.g. 1m34s\n{{Related|Timedmedia-ogg-short}}",
+ "timedmedia-ogg-long-audio": "File details for Ogg sound (audio) files, long version.\n\nShown after the filename in the image description page.\n\nParameters:\n* $1 - stream type name. Any one of the following: Vorbis, Speex, FLAC\n* $2 - duration of the sound (localized) - e.g. 1m34s\n* $3 - bit-rate of the sound (localized) - e.g. 97kbps\n{{Related|Timedmedia-ogg-long}}",
+ "timedmedia-ogg-long-video": "File details for Ogg video files, long version.\n\nShown after the filename in the image description page.\n\nParameters:\n* $1 - stream type name: Theora\n* $2 - duration of the video (localized) - e.g. 1m34s\n* $3 - bit-rate of the video (localized) - e.g. 97kbps\n* $4 - width of the video (in pixels)\n* $5 - height of the video (in pixels)\n{{Related|Timedmedia-ogg-long}}",
+ "timedmedia-ogg-long-multiplexed": "{{doc-important|Start with a lowercase letter, unless the first word is \"Ogg\".}}\nFile details for Ogg multiplexed audio/video files, long version.\n\nShown after the filename in the image description page.\n\nParameters:\n* $1 - stream type names, slash-separated - e.g. Theora/Vorbis\n* $2 - duration (localized) - e.g. 1m34s\n* $3 - bit-rate (localized) - e.g. 97kbps\n* $4 - width of the video (in pixels)\n* $5 - height of the video (in pixels)\n{{Related|Timedmedia-ogg-long}}",
+ "timedmedia-ogg-long-general": "File details for Ogg generic (non-video, non-audio) files, long version.\n\nShown after the filename in the image description page.\n\nParameters:\n* $1 - (Unused)\n* $2 - duration (localized) - e.g. 1m34s\n* $3 - bit-rate (localized) - e.g. 97kbps\n{{Related|Timedmedia-ogg-long}}",
+ "timedmedia-ogg-long-error": "Used as error message. Parameters:\n* $1 - error message. e.g. File not found, invalid stream, etc.",
+ "timedmedia-ogg-long-no-streams": "Similar to {{msg-mw|timedmedia-ogg-long-error}}. Used as the long description for an ogg media file if there are no streams in the file using a recognized codec. This can be caused by an invalid ogg file, or by one using an obscure type of data (e.g. dirac video with no audio).",
+ "timedmedia-webm-short-video": "File details for WebM video files, short version.\nParameters:\n* $1 - stream type names (slash separated) - e.g. Vorbis/VP8\n* $2 - duration of the video (localized) - e.g. 1m34s\nSee also:\n* {{msg-mw|Timedmedia-webm-long-video}}",
+ "timedmedia-webm-long-video": "File details for WebM multiplexed audio/video files, long version.\n\nShown after the filename in the image description page.\n\nParameters:\n* $1 - stream type names (slash separated) - e.g. Vorbis/VP8\n* $2 - duration (localized) - e.g. 1m34s\n* $3 - bit-rate (localized) - e.g. 97kbps\n* $4 - width of the video (in pixels)\n* $5 - height of the video (in pixels)\nSee also:\n* {{msg-mw|Timedmedia-webm-short-video}}",
+ "timedmedia-flac-short-audio": "File details for FLAC audio files, short version.\nParameters:\n* $1 - duration of the audio (localized) - e.g. 1m34s\n\nPrimarily used on [[Special:Search]] results pages, i.e.\n https://commons.wikimedia.org/w/index.php?title=Special%3ASearch&profile=advanced&search=What%27s+a+love+dart&fulltext=Search&ns6=1&profile=advanced\n\nSee also:\n* {{msg-mw|Timedmedia-flac-long-audio}}\n* {{msg-mw|Timedmedia-ogg-short-audio}}",
+ "timedmedia-flac-long-audio": "File details for FLAC files, long version.\n\nShown after the filename in the image description page.\n\nParameters:\n* $1 - duration (localized) - e.g. 1m34s\n* $2 - bit-rate (localized) - e.g. 97kbps\nSee also:\n* {{msg-mw|Timedmedia-flac-short-audio}}",
+ "timedmedia-wav-short-audio": "File details for WAV audio files, short version.\nParameters:\n* $1 - duration of the audio (localized) - e.g. 1m34s\nSee also:\n* {{msg-mw|Timedmedia-wav-long-audio}}",
+ "timedmedia-wav-long-audio": "File details for WAV files, long version.\nShown after the filename in the image description page.\n\nParameters:\n* $1 - duration of the audio (localized) - e.g. 1m34s\n* $2 - bit-rate (localized) - e.g. 97kbps\nSee also:\n* {{msg-mw|Timedmedia-wav-short-audio}}",
+ "timedmedia-wav-pcm-required": "Message shown at upload if user tries to upload a WAV file using a codec that is not PCM",
+ "timedmedia-mp4-short-video": "File details for MP4 video files, short version.\nParameters:\n* $1 - stream type names (slash separated) - e.g. AAC/h.264\n* $2 - duration of the video (localized) - e.g. 1m34s\nSee also:\n* {{msg-mw|Timedmedia-mp4-long-video}}",
+ "timedmedia-mp4-long-video": "File details for MP4 multiplexed audio/video files, long version.\n\nShown after the filename in the image description page.\n\nParameters:\n* $1 - stream type names (slash separated) - e.g. AAC/h.264\n* $2 - duration (localized) - e.g. 1m34s\n* $3 - bit-rate (localized) - e.g. 97kbps\n* $4 - width of the video (in pixels)\n* $5 - height of the video (in pixels)\nSee also:\n* {{msg-mw|Timedmedia-mp4-short-video}}",
+ "timedmedia-no-player-js": "Used as fallback text displayed for browsers without js and without video tag support.\n\nParameters:\n* $1 - media source URL",
+ "timedmedia-more": "Unused at this time.\n{{Identical|More...}}",
+ "timedmedia-dismiss": "Unused at this time.\n{{Identical|Close}}",
+ "timedmedia-download": "Used as tooltip for the Download button.\n{{Identical|Download}}",
+ "timedmedia-play-media": "Used as tooltip for the link.",
+ "timedmedia-desc-link": "Unused at this time.\n{{Identical|About this file}}",
+ "timedmedia-oggThumb-version": "Used as error message when the specified option is invalid. Parameters:\n* $1 - version number \"0.9\" (hard-coded)",
+ "timedmedia-oggThumb-failed": "{{doc-important|Do not translate <code>oggThumb</code>.}}\nUsed as error message when executing oggThumb.",
+ "timedmedia-status-header": "Used as section heading.",
+ "timedmedia-update-status": "Used as text for the link which is used to purge.",
+ "timedmedia-status": "Used as column header.\n{{Identical|Status}}",
+ "timedmedia-status-unknown": "Used as status message on error.\n{{Identical|Unknown status}}",
+ "timedmedia-transcodebitrate": "A table column header for description of transcode bitrate",
+ "timedmedia-transcodeduration": "A table column header for description of transcode encoding time",
+ "timedmedia-transcodeinfo": "A table column header for description of Transcode derivative\n{{Identical|Format}}",
+ "timedmedia-actions": "Used as column header.\n{{Identical|Action}}",
+ "timedmedia-direct-link": "Used as column header.\n{{Identical|Download}}",
+ "timedmedia-not-ready": "State of a given transcode job being not yet complete or not yet ready",
+ "timedmedia-completed-on": "Completed transcode message. Parameters:\n* $1 - the timestamp (time and date) that the transcode was completed",
+ "timedmedia-error-on": "Parameters:\n* $1 - timestamp",
+ "timedmedia-started-transcode": "Status update for Transcodes. Parameters:\n* $1 - time passed since transcoded started (e.g. \"{{int:timedmedia-minutes|1}}{{int:comma-separator}}{{int:timedmedia-seconds|42}}\"), uses the following messages:\n** {{msg-mw|Timedmedia-days}}\n** {{msg-mw|Timedmedia-hours}}\n** {{msg-mw|Timedmedia-minutes}}\n** {{msg-mw|Timedmedia-seconds}}\n** {{msg-mw|Comma-separator}}\n* $2 - percentage of transcode complete",
+ "timedmedia-percent-done": "Commented out at this time.\n\nStatus update for Transcodes. Parameters:\n* $1 - percentage of the file transcoded so far\nSee also:\n* {{msg-mw|timedmedia-unknown-target-size}}",
+ "timedmedia-in-job-queue": "Shown on the file description page in the {{msg-mw|timedmedia-status-header}} section.\n\nParameters:\n* $1 - the time the media has been in the job queue (e.g. \"{{int:timedmedia-minutes|1}}{{int:comma-separator}}{{int:timedmedia-seconds|42}}\"), uses the following messages:\n** {{msg-mw|Timedmedia-days}}\n** {{msg-mw|Timedmedia-hours}}\n** {{msg-mw|Timedmedia-minutes}}\n** {{msg-mw|Timedmedia-seconds}}\n** {{msg-mw|Comma-separator}}",
+ "timedmedia-unknown-target-size": "Commented out at this time.\n\nStatus update for Transcodes. Parameters:\n* $1 - the number of bytes of the file transcoded so far (localized)\nSee also:\n* {{msg-mw|Timedmedia-percent-done}}",
+ "timedmedia-days": "Used as the duration, as <code>$1</code> in the following messages:\n* {{msg-mw|Timedmedia-in-job-queue}}\n* {{msg-mw|Timedmedia-started-transcode}}\nParameters:\n* $1 - number of days\n{{Related|Timedmedia-days}}\n{{Identical|Day}}",
+ "timedmedia-hours": "Used as the duration, as <code>$1</code> in the following messages:\n* {{msg-mw|Timedmedia-in-job-queue}}\n* {{msg-mw|Timedmedia-started-transcode}}\nParameters:\n* $1 - number of hours\n{{Related|Timedmedia-days}}\n{{Identical|Hour}}",
+ "timedmedia-minutes": "Used as the duration, as <code>$1</code> in the following messages:\n* {{msg-mw|Timedmedia-in-job-queue}}\n* {{msg-mw|Timedmedia-started-transcode}}\nParameters:\n* $1 - minutes\n{{Related|Timedmedia-days}}\n{{Identical|Minute}}",
+ "timedmedia-seconds": "Used as the duration, as <code>$1</code> in the following messages:\n* {{msg-mw|Timedmedia-in-job-queue}}\n* {{msg-mw|Timedmedia-started-transcode}}\nParameters:\n* $1 - number of seconds\n{{Related|Timedmedia-days}}\n{{Identical|Second}}",
+ "timedmedia-reset": "Used as action link text and as dialog title.\n\nThe contents of the dialog is {{msg-mw|Timedmedia-reset-confirm}}.",
+ "timedmedia-reset-confirm": "Used as confirmation message in the dialog which has the title {{msg-mw|Timedmedia-reset}}.",
+ "timedmedia-reset-error": "Used as generic error message.",
+ "timedmedia-ogg": "{{optional}}\nUsed as <code>$1</code> in the following messages:\n* {{msg-mw|Timedmedia-source-audio-file-desc}}\n* {{msg-mw|Timedmedia-source-file-desc}}\n* {{msg-mw|Timedmedia-source-file}}",
+ "timedmedia-webm": "{{optional}}\nUsed as <code>$1</code> in the following messages:\n* {{msg-mw|Timedmedia-source-audio-file-desc}}\n* {{msg-mw|Timedmedia-source-file-desc}}\n* {{msg-mw|Timedmedia-source-file}}",
+ "timedmedia-mp4": "{{Optional}}\nUsed as <code>$1</code> in the following messages:\n* {{msg-mw|Timedmedia-source-audio-file-desc}}\n* {{msg-mw|Timedmedia-source-file-desc}}\n* {{msg-mw|Timedmedia-source-file}}",
+ "timedmedia-wav": "{{Optional}}\nUsed as <code>$1</code> in the following messages:\n* {{msg-mw|Timedmedia-source-audio-file-desc}}\n* {{msg-mw|Timedmedia-source-file-desc}}\n* {{msg-mw|Timedmedia-source-file}}",
+ "timedmedia-flac": "{{Optional}}\n\nUsed as <code>$1</code> in the following messages:\n* {{msg-mw|Timedmedia-source-audio-file-desc}}\n* {{msg-mw|Timedmedia-source-file-desc}}\n* {{msg-mw|Timedmedia-source-file}}",
+ "timedmedia-source-file": "The source file. Parameters:\n* $1 - file type; any one of the following messages:\n** {{msg-mw|Timedmedia-ogg}}\n** {{msg-mw|Timedmedia-webm}}\n** {{msg-mw|Timedmedia-mp4}}\n** {{msg-mw|Timedmedia-flac}}\n** {{msg-mw|Timedmedia-wav}}\nSee also:\n* {{msg-mw|Timedmedia-source-audio-file-desc}}\n* {{msg-mw|Timedmedia-source-file-desc}}\n{{Identical|Source}}",
+ "timedmedia-source-file-desc": "Source file description. This is a file title in the primary source attributes of a timed media file. I can look like \"''Original Ogg file, 640 × 480 (10 Mbps)''\".\n\nParameters:\n* $1 - file type; any one of the following messages:\n** {{msg-mw|Timedmedia-ogg}}\n** {{msg-mw|Timedmedia-webm}}\n** {{msg-mw|Timedmedia-mp4}}\n** {{msg-mw|Timedmedia-flac}}\n** {{msg-mw|Timedmedia-wav}}\n* $2 - resolution width\n* $3 - resolution height\n* $4 - human readable bitrate\nSee also:\n* {{msg-mw|Timedmedia-source-audio-file-desc}} - for audio file",
+ "timedmedia-source-audio-file-desc": "Source file description. Parameters:\n* $1 - file type; any one of the following messages:\n** {{msg-mw|Timedmedia-ogg}}\n** {{msg-mw|Timedmedia-webm}}\n** {{msg-mw|Timedmedia-mp4}}\n** {{msg-mw|Timedmedia-flac}}\n** {{msg-mw|Timedmedia-wav}}\n* $2 - human readable bitrate\nSee also:\n* {{msg-mw|Timedmedia-source-file-desc}} - for video file",
+ "timedmedia-derivative-160p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-160p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-240p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-240p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-360p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-360p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-480p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-480p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-720p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-720p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-1080p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-1080p.ogv": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-160p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-160p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-360p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-360p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-480p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-480p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-720p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-720p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-1080p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-1080p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-2160p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-2160p.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-360p.vp9.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-360p.vp9.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-480p.vp9.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-480p.vp9.webm": "A type of media format encoding",
+ "timedmedia-derivative-720p.vp9.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-720p.vp9.webm": "A type of media format encoding",
+ "timedmedia-derivative-1080p.vp9.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-2160p.vp9.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-320p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-320p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-480p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-480p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-720p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-720p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-1080p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-1080p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-2160p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-desc-2160p.mp4": "{{optional}} A type of media format encoding",
+ "timedmedia-derivative-ogg": "{{optional}} Short form of a media format.",
+ "timedmedia-derivative-desc-ogg": "{{optional}} Media format.",
+ "timedmedia-derivative-opus": "{{optional}} Short form of a media format.",
+ "timedmedia-derivative-desc-opus": "{{optional}} Media format.",
+ "timedmedia-derivative-mp3": "{{optional}} Short form of a media format.",
+ "timedmedia-derivative-desc-mp3": "{{optional}} Media format.",
+ "timedmedia-derivative-m4a": "{{optional}} Short form of a media format.",
+ "timedmedia-derivative-desc-m4a": "{{optional}} Media format.",
+ "timedmedia-subtitle-new": "Used as page title.",
+ "timedmedia-subtitle-new-desc": "Refers to {{msg-mw|Timedmedia-subtitle-new-go}}.",
+ "timedmedia-subtitle-new-go": "Used as label for the Submit button.\n\nPreceded by (and used in) the description {{msg-mw|Timedmedia-subtitle-new-desc}}.\n{{Identical|Go}}",
+ "timedmedia-subtitle-language": "Subtitle names. Parameters are:\n* $1 - subtitle language\n* $2 - subtitle key\n{{Identical|Subtitle}}",
+ "timedmedia-subtitle-no-video": "Message for a TimedText page without an associated video file",
+ "timedmedia-subtitle-no-subtitles": "Parameters:\n* $1 is a language name.",
+ "timedmedia-subtitle-remote": "Used as page title. Parameters:\n* $1 - the display name of the repository\nThe page body for this page title is:\n* {{msg-mw|timedmedia-subtitle-remote-link}}",
+ "timedmedia-subtitle-remote-link": "Used as page body. Parameters:\n* $1 - the description URL of the file\n* $2 - the display name of the repository\nThe page title for this message is:\n* {{msg-mw|timedmedia-subtitle-remote}}",
+ "timedmediahandler": "{{doc-special|TimedMediaHandler}}",
+ "timedmedia-videos": "Number of videos on [[Special:TimedMediaHandler]]. Parameters:\n* $1 - number of videos\n{{Related|Timedmedia-format-type}}\n{{Identical|Video}}",
+ "timedmedia-ogg-videos": "Number of Ogg videos on [[Special:TimedMediaHandler]]. Parameters:\n* $1 - number of videos\n{{Related|Timedmedia-format-type}}",
+ "timedmedia-webm-videos": "Number of WebM videos on [[Special:TimedMediaHandler]]. Parameters:\n* $1 - number of videos\n{{Related|Timedmedia-format-type}}",
+ "timedmedia-derivative-state-transcodes": "Number of transcodes. Parameters:\n* $1 - number of transcodes",
+ "timedmedia-derivative-state-active": "currently active transcoes\nParameters are:\n* $1 number of transcodes",
+ "timedmedia-derivative-state-queued": "queued transcode jobs\nParameters are:\n* $1 number of transcodes",
+ "timedmedia-derivative-state-failed": "failed transcode jobs\nParameters are:\n* $1 number of transcodes",
+ "timedmedia-file": "Used as table column header.\n{{Identical|File}}",
+ "timedmedia-audios": "Number of audio files on [[Special:TimedMediaHandler]]. Parameters:\n* $1 - number of audio files\n{{Related|Timedmedia-format-type}}",
+ "timedmedia-ogg-audios": "Number of ogg audio files, displayed on [[Special:TimedMediaHandler]]. Parameters:\n* $1 - the number of files\n{{Related|Timedmedia-format-type}}",
+ "timedmedia-flac-audios": "Number of FLAC audio files, displayed on [[Special:TimedMediaHandler]]. Parameters:\n* $1 - the number of files\n{{Related|Timedmedia-format-type}}",
+ "timedmedia-wav-audios": "Number of WAV audio files, displayed on [[Special:TimedMediaHandler]]. Parameters:\n* $1 - the number of files\n{{Related|Timedmedia-format-type}}",
+ "right-transcode-reset": "{{doc-right|transcode-reset}}",
+ "right-transcode-status": "{{doc-right|transcode-status}}",
+ "action-transcode-status": "{{doc-action|transcode-status}}",
+ "orphanedtimedtext": "{{doc-special|OrphanedTimedText}}",
+ "orphanedtimedtext-summary": "Summary of Special:OrphanedTimedText.",
+ "orphanedtimedtext-unsupported": "Shown if Special:OrphanedTimedText isn't supported for the current database back-end.",
+ "orphanedtimedtext-notimedtext": "Shown on Special:OrphanedTimedText if the TimedText namespace is disabled on that wiki (i.e. $wgEnableLocalTimedText is set to false). Note, do not use <nowiki>{{ns:TimedText}}</nowiki> in this message.",
+ "apihelp-query+transcodestatus-description": "{{doc-apihelp-description|query+transcodestatus}}",
+ "apihelp-query+transcodestatus-example-1": "{{doc-apihelp-example|query+transcodestatus}}",
+ "apihelp-query+videoinfo-description": "{{doc-apihelp-description|query+videoinfo}}",
+ "apihelp-query+videoinfo-param-prop": "{{doc-apihelp-param|query+videoinfo|prop}}",
+ "apihelp-query+videoinfo-example-1": "{{doc-apihelp-example|query+videoinfo}}",
+ "apihelp-transcodereset-description": "{{doc-apihelp-description|transcodereset}}",
+ "apihelp-transcodereset-param-title": "{{doc-apihelp-param|transcodereset|title}}",
+ "apihelp-transcodereset-param-transcodekey": "{{doc-apihelp-param|transcodereset|transcodekey}}",
+ "apihelp-transcodereset-example-1": "{{doc-apihelp-example|transcodereset}}",
+ "apihelp-transcodereset-example-2": "{{doc-apihelp-example|transcodereset}}"
+}
diff --git a/extensions/TimedMediaHandler/i18n/qu.json b/extensions/TimedMediaHandler/i18n/qu.json
new file mode 100644
index 00000000..4942568f
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/qu.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "AlimanRuna"
+ ]
+ },
+ "timedmedia-no-player-js": "Way way, wamp'unaykipiqa JavaScript nisqaman ama nisqam icha q'imisqa purichiq manam kanchu.<br />\n<a href=\"$1\">Widyuta chaqnamuyta</a> icha <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">purichiqta chaqnamuyta</a> atinki widyuta wamp'unaykipi purichinaykipaq.",
+ "timedmedia-more": "Astawan...",
+ "timedmedia-dismiss": "Wichq'ay",
+ "timedmedia-download": "Willañiqita chaqnamuy",
+ "timedmedia-desc-link": "Kay willañiqimanta",
+ "timedmedia-source-file": "$1 pukyu",
+ "timedmedia-source-audio-file-desc": "Qallariy $1 willañiqi ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ro.json b/extensions/TimedMediaHandler/i18n/ro.json
new file mode 100644
index 00000000..4162d861
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ro.json
@@ -0,0 +1,93 @@
+{
+ "@metadata": {
+ "authors": [
+ "Firilacroco",
+ "KlaudiuMihaila",
+ "Mihai",
+ "Minisarm",
+ "Stelistcristi",
+ "ImGelu"
+ ]
+ },
+ "timedmedia-desc": "Gestionar pentru fișiere audio, video și subtitrări sincronizate, cu suport pentru formatele WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "fișier audio ogg $1, $2",
+ "timedmedia-ogg-short-video": "fișier video ogg $1, $2",
+ "timedmedia-ogg-short-general": "fișier media ogg $1, $2",
+ "timedmedia-ogg-long-audio": "fișier audio ogg $1, lungime $2, $3",
+ "timedmedia-ogg-long-video": "fișier video ogg $1, lungime $2, $4×$5 pixeli, $3",
+ "timedmedia-ogg-long-multiplexed": "fișier multiplexat audio/video ogg, $1, lungime $2, $4×$5 pixeli, $3",
+ "timedmedia-ogg-long-general": "fișier media ogg, lungime $2, $3",
+ "timedmedia-ogg-long-error": "fișier ogg incorect: $1",
+ "timedmedia-webm-short-video": "fișier video WebM $1, $2",
+ "timedmedia-webm-long-video": "fișier audio/video WebM, $1, lungime $2, $4 × $5 pixeli, $3 per ansamblu",
+ "timedmedia-flac-short-audio": "fișier audio FLAC, $1",
+ "timedmedia-flac-long-audio": "fișier audio FLAC, lungime $1, $2 per ansmablu",
+ "timedmedia-mp4-short-video": "fișier video MP4 $1, $2",
+ "timedmedia-mp4-long-video": "fișier audio/video MP4, $1, lungime $2, $4 × $5 pixeli, $3 per ansamblu",
+ "timedmedia-no-player-js": "Ne pare rău, însă navigatorul dumneavoastră fie are JavaScript dezactivat, fie nu conține niciun player suportat.<br />\nPuteți <a href=\"$1\">descărca clipul</a> sau puteți <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">descărca un player</a> pentru a-l reda direct în navigator.",
+ "timedmedia-more": "Mai mult…",
+ "timedmedia-dismiss": "Închide",
+ "timedmedia-download": "Descarcă fișierul",
+ "timedmedia-play-media": "Redă fișierul media",
+ "timedmedia-desc-link": "Despre acest fișier",
+ "timedmedia-oggThumb-version": "OggHandler necesită oggThumb, versiunea $1 sau mai recentă.",
+ "timedmedia-oggThumb-failed": "oggThumb nu a reușit să creeze miniatura.",
+ "timedmedia-status-header": "Starea codificării",
+ "timedmedia-update-status": "Actualizează starea codificării",
+ "timedmedia-status": "Stare",
+ "timedmedia-status-unknown": "Stare necunoscută",
+ "timedmedia-transcodebitrate": "Rată de bit",
+ "timedmedia-transcodeinfo": "Format",
+ "timedmedia-actions": "Acțiuni",
+ "timedmedia-direct-link": "Descarcă",
+ "timedmedia-not-ready": "Nu este gata",
+ "timedmedia-completed-on": "Finalizat $1",
+ "timedmedia-error-on": "Eroare la $1",
+ "timedmedia-started-transcode": "Pornită acum $1. $2",
+ "timedmedia-percent-done": "Aproximativ $1% finalizat",
+ "timedmedia-in-job-queue": "Adăugat la șirul de sarcini acum $1",
+ "timedmedia-unknown-target-size": "Dimensiune finală necunoscută, $1 codificați",
+ "timedmedia-days": "{{PLURAL:$1|o zi|$1 zile|$1 de zile}}",
+ "timedmedia-hours": "{{PLURAL:$1|o oră|$1 ore|$1 de ore}}",
+ "timedmedia-minutes": "{{PLURAL:$1|un minut|$1 minute|$1 de minute}}",
+ "timedmedia-seconds": "{{PLURAL:$1|o secundă|$1 secunde|$1 de secunde}}",
+ "timedmedia-reset": "Reinițializează codificarea",
+ "timedmedia-reset-confirm": "Reinițializarea acestei codificări va elimina orice fișier existent (dacă există) și va readăuga codificarea la șirul de sarcini. Va dura ceva timp pentru a recodifica. <br /><br />\nSunteți sigur că doriți să continuați?",
+ "timedmedia-reset-error": "Eroare la reinițializarea codificării.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Sursă $1",
+ "timedmedia-source-file-desc": "Fișier $1 original, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Fișier $1 original ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Videoclip Ogg cu lățime de bandă mică (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Videoclip Ogg pentru redare pe web (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Videoclip Ogg pentru redare pe web (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Videoclip Ogg descărcabil, de înaltă calitate (720P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM pentru redare pe web (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM pentru redare pe web (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM pentru redare pe web (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM descărcabil, de înaltă calitate (720P)",
+ "timedmedia-derivative-480p.vp9.webm": "VP9 480P",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 prietenos cu dispozitivele (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 pentru redare pe web (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 de calitate HD (720P)",
+ "timedmedia-subtitle-new": "Creare traducere nouă sau modificare una existentă",
+ "timedmedia-subtitle-new-desc": "Alegeți limba și apăsați butonul '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Du-te",
+ "timedmedia-subtitle-language": "Subtitrare în $1 ($2)",
+ "timedmedia-subtitle-no-video": "Nu există niciun videoclip asociat cu pagina curentă de subtitrare",
+ "timedmedia-subtitle-no-subtitles": "Nu există în acest moment subtitrări în limba $1 pentru acest videoclip. Puteți [{{fullurl:{{FULLPAGENAME}}|action=edit}} modifica această pagină] pentru a le adăuga.",
+ "timedmedia-subtitle-remote": "Subtitrarea sincronizată a acestui fișier este găzduită la $1",
+ "timedmedia-subtitle-remote-link": "Puteți [$1 vizualiza pagina descriptivă] a acestui fișier la $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 videoclip|$1 videoclipuri|$1 de videoclipuri}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 videoclip Ogg|$1 videoclipuri Ogg|$1 de videoclipuri Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 videoclip WebM|$1 videoclipuri WebM|$1 de videoclipuri WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 codificare|$1 codificări|$1 de codificări}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 codificare în curs|$1 codificări în curs|$1 de codificări în curs}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 codificare în așteptare|$1 codificări în așteptare|$1 de codificări în așteptare}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 codificare eșuată|$1 codificări eșuate|$1 de codificări eșuate}}",
+ "timedmedia-file": "Fișier",
+ "right-transcode-reset": "Reinițializează videoclipuri nereușit codificate pentru ca acestea să fie readăugate la șirul de sarcini.",
+ "right-transcode-status": "Vizualizează [[Special:TimedMediaHandler|informații despre activitatea curentă de codificare]]",
+ "action-transcode-status": "vizualizați statutul actual al codificării"
+}
diff --git a/extensions/TimedMediaHandler/i18n/roa-tara.json b/extensions/TimedMediaHandler/i18n/roa-tara.json
new file mode 100644
index 00000000..a972d6b7
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/roa-tara.json
@@ -0,0 +1,91 @@
+{
+ "@metadata": {
+ "authors": [
+ "Joetaras"
+ ]
+ },
+ "timedmedia-desc": "Gestore pe le file audio, video e teste temporizzate, cu le formate supportate pe WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "File audie Ogg $1, $2",
+ "timedmedia-ogg-short-video": "File video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "File media Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "File audie Ogg $1, lunghezze $2, $3",
+ "timedmedia-ogg-long-video": "File video Ogg $1, lunghezze $2, $4 x $5 pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "File multiplexed audie e video Ogg $1, lunghezze $2, $4 x $5 pixel, $3 in totale",
+ "timedmedia-ogg-long-general": "File media Ogg, lunghezze $2, $3",
+ "timedmedia-ogg-long-error": "Ogg file invalide: $1",
+ "timedmedia-webm-short-video": "WebM $1 file video, $2",
+ "timedmedia-webm-long-video": "File WebM audio/video, $1, lunghezze $2, $4 × $5 pixel, $3 in totale",
+ "timedmedia-flac-short-audio": "File audio FLAC, $1",
+ "timedmedia-flac-long-audio": "File audio FLAC, lunghezze $1, in totale $2",
+ "timedmedia-wav-short-audio": "File audio WAV, $1",
+ "timedmedia-wav-long-audio": "File audio WAV, lunghezze $1, in totale $2",
+ "timedmedia-wav-pcm-required": "Tu puè sulamende carecà WAV de tipe PCM (Codece de Modulazione Pulsate).",
+ "timedmedia-mp4-short-video": "MP4 $1 file video, $2",
+ "timedmedia-mp4-long-video": "File MP4 audio/video, $1, lunghezze $2, $4 × $5 pixel, $3 in totale",
+ "timedmedia-no-player-js": "Ne dispiace, 'u browser tune tène 'u JavaScript disabbilitate o non ge tène 'n'esecutore supportate.<br />\nTu puè <a href=\"$1\">scarecà 'u video</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">scarecà 'n'esecutore</a> pe 'ndrucà 'u video sus a 'u browser tune.",
+ "timedmedia-more": "De cchiù...",
+ "timedmedia-dismiss": "Chiude",
+ "timedmedia-download": "Scareche stu file",
+ "timedmedia-play-media": "Esegue 'u media",
+ "timedmedia-desc-link": "'Mbormaziune sus a stu file",
+ "timedmedia-oggThumb-version": "OggHandler vole 'a versine de oggThumb $1 o cchiù ierte.",
+ "timedmedia-oggThumb-failed": "oggThumn ha fallite a ccrejà le miniature.",
+ "timedmedia-status-header": "State d'a codifeche",
+ "timedmedia-update-status": "Aggiorne 'u state d'a codifeche",
+ "timedmedia-status": "State",
+ "timedmedia-status-unknown": "State scanusciute",
+ "timedmedia-transcodebitrate": "Bitrate",
+ "timedmedia-transcodeduration": "Tiembe de codifiche",
+ "timedmedia-transcodeinfo": "Formate",
+ "timedmedia-actions": "Aziune",
+ "timedmedia-direct-link": "Scareche",
+ "timedmedia-not-ready": "Non g'è pronde",
+ "timedmedia-completed-on": "Combletate $1",
+ "timedmedia-error-on": "Errore sus a $1",
+ "timedmedia-started-transcode": "Accumenzate $1 fà. $2",
+ "timedmedia-percent-done": "Cchiù o mene $1% fatte",
+ "timedmedia-in-job-queue": "Aggiunde a 'a Fatìe in code $1 fà",
+ "timedmedia-unknown-target-size": "Dimenzione d'a destinazione scanusciute, $1 codificate",
+ "timedmedia-days": "{{PLURAL:$1|1 sciurne|$1 sciurne}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 ore|$1 ore}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minute|$1 minute}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 seconde|$1 seconde}}",
+ "timedmedia-reset": "Azzere 'a transcodifeche",
+ "timedmedia-reset-confirm": "Stoche azzere sta transcodifiche ca adda luà ogne file esistende (ce presende), e pò aggiunge 'a transcodifiche jndr'à code d'a fatìe. Cchiù vote accumenze 'a transcodifiche. <br /><br />\nSì secure ca vuè ccu vvè nnande?",
+ "timedmedia-reset-error": "Errore mendre ste azzerave 'a fatìe de transcodifiche.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 sorgende",
+ "timedmedia-source-file-desc": "File origgenale $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "File origgenale $1 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg video cu banda vasce (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Ogg video cu streaming web (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Ogg video cu streaming web (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Ogg video de qualitate ierte scarecabbele (720P)",
+ "timedmedia-derivative-desc-160p.webm": "Flusse web WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Flusse web WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Flusse web WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM de qualitate ierte scarecabbele (720P)",
+ "timedmedia-derivative-desc-320p.mp4": "Dispositive-amiche MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Streaming web MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "Qualitate HD MP4 (720P)",
+ "timedmedia-subtitle-new": "Ccreje 'na traduziona nove o ne cange une esistende",
+ "timedmedia-subtitle-new-desc": "Scacchie 'na lènghe e cazze 'u buttone '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Véje",
+ "timedmedia-subtitle-language": "$1 ($2) sottotitele",
+ "timedmedia-subtitle-no-video": "Non ge stonne video associate cu 'u sottotitole d'a pàgene de mò",
+ "timedmedia-subtitle-no-subtitles": "Non ge stonne sottotitole pe mò jndr'à $1 pe stu video, tu puè [{{fullurl:{{FULLPAGENAME}}|action=edit}} cangià sta pàgene] o aggiungerle",
+ "timedmedia-subtitle-remote": "'U teste temborizzate pe stu file jè ospitate sus a $1",
+ "timedmedia-subtitle-remote-link": "Tu puè [$1 'ndrucà 'a pàgene de descrizione] pe stu file sus a $2",
+ "timedmediahandler": "Gestore TimedMedia",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Video Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 Video WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcodifiche}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transcodifiche in esecuzione}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transcodifiche in code}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transcodifiche fallite}}",
+ "timedmedia-file": "File",
+ "right-transcode-reset": "Azzeramende fallite o le video transcodificate onne state sckaffate cchiù de 'na vote jndr'à code d'a fatìe.",
+ "right-transcode-status": "'Ndruche [[Special:TimedMediaHandler|le 'mbormaziune sus a l'attività de transcodifiche de mò]]",
+ "action-transcode-status": "'ndruche 'u state de mò d'a transcodifeche"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ru.json b/extensions/TimedMediaHandler/i18n/ru.json
new file mode 100644
index 00000000..d4bf8e64
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ru.json
@@ -0,0 +1,111 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ahonc",
+ "Amire80",
+ "Eleferen",
+ "Kaganer",
+ "Kalan",
+ "Kv75",
+ "MaxSem",
+ "Okras",
+ "Александр Сигачёв",
+ "NBS"
+ ]
+ },
+ "timedmedia-desc": "Обработчик для аудио, видео и субтитров, с поддержкой форматов: WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Звуковой файл Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Видео-файл Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Медиафайл Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Звуковой файл Ogg $1, длительность $2, $3",
+ "timedmedia-ogg-long-video": "видео-файл Ogg $1, длительность $2, $4 × $5 {{PLURAL:$5|пиксель|пикселя|пикселей}}, $3",
+ "timedmedia-ogg-long-multiplexed": "мультиплексный аудио/видеофайл Ogg, $1, длительность $2, $4 × $5 {{PLURAL:$5|пиксель|пикселя|пикселей}}, $3 всего",
+ "timedmedia-ogg-long-general": "медиафайл Ogg, длительность $2, $3",
+ "timedmedia-ogg-long-error": "неправильный Ogg-файл: $1",
+ "timedmedia-ogg-long-no-streams": "Мультимедиа-файл ogg. Предупреждение: Ни один из кодеков, используемых в этом файле, не определён.",
+ "timedmedia-webm-short-video": "WebM $1 видео-файл, $2",
+ "timedmedia-webm-long-video": "WebM аудио/видео файл, $1, продолжительность $2, $4 × $5 {{PLURAL:$5|пиксель|пикселя|пикселей}}, всего $3",
+ "timedmedia-flac-short-audio": "Аудиофайл FLAC, $1",
+ "timedmedia-flac-long-audio": "Аудиофайл FLAC, длина — $1, битрейт — $2",
+ "timedmedia-wav-short-audio": "Аудиофайл WAV, $1",
+ "timedmedia-wav-long-audio": "Аудиофайл WAV, длина — $1, битрейт — $2",
+ "timedmedia-wav-pcm-required": "Вы можете загрузить только PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "MP4 $1 видео-файл, $2",
+ "timedmedia-mp4-long-video": "Аудио/видеофайл MP4 $1, длина — $2, $4 × $5 пикселей, битрейт — $3",
+ "timedmedia-no-player-js": "К сожалению, в вашем браузере отключён JavaScript, или не имеется требуемого проигрывателя.<br />\nВы можете <a href=\"$1\">загрузить ролик</a> или <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">загрузить проигрыватель</a> для воспроизведения ролика в браузере.",
+ "timedmedia-more": "Больше…",
+ "timedmedia-dismiss": "Скрыть",
+ "timedmedia-download": "Загрузить файл",
+ "timedmedia-play-media": "Воспроизвести медиафайл",
+ "timedmedia-desc-link": "Информация об этом файле",
+ "timedmedia-oggThumb-version": "OggHandler требует oggThumb версии $1 или более поздней.",
+ "timedmedia-oggThumb-failed": "oggThumb не удалось создать миниатюру.",
+ "timedmedia-status-header": "Состояние декодирования",
+ "timedmedia-update-status": "Обновить статус декодирования",
+ "timedmedia-status": "Состояние",
+ "timedmedia-status-unknown": "Неизвестное состояние",
+ "timedmedia-transcodeinfo": "Формат",
+ "timedmedia-actions": "Действия",
+ "timedmedia-direct-link": "Скачать",
+ "timedmedia-not-ready": "Не готов",
+ "timedmedia-completed-on": "Завершено $1",
+ "timedmedia-error-on": "Ошибка $1",
+ "timedmedia-started-transcode": "Запущено $1 назад. $2",
+ "timedmedia-percent-done": "Примерно $1% выполнено",
+ "timedmedia-in-job-queue": "Добавлено в очередь заданий $1 назад",
+ "timedmedia-unknown-target-size": "Неизвестный целевой размер, $1 при кодировке",
+ "timedmedia-days": "{{PLURAL:$1|$1 день|$1 дня|$1 дней}}",
+ "timedmedia-hours": "{{PLURAL:$1|$1 час|$1 часа|$1 часов}}",
+ "timedmedia-minutes": "{{PLURAL:$1|$1 минута|$1 минуты|$1 минут}}",
+ "timedmedia-seconds": "{{PLURAL:$1|$1 секунда|$1 секунды|$1 секунд}}",
+ "timedmedia-reset": "Перезапуск декодирования",
+ "timedmedia-reset-confirm": "Перезапуск декодирования удалит существующий файл (если он существует), и декодирование вновь будет добавлено в очередь заданий. Повторное декодирование займет некоторое время. <br /><br />\nВы уверены, что хотите продолжить?",
+ "timedmedia-reset-error": "Ошибка при перезапуске декодирования.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Источник $1",
+ "timedmedia-source-file-desc": "Оригинал $1 файла, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Оригинальный $1-файл ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg-видео низкого качества (160p)",
+ "timedmedia-derivative-desc-360p.ogv": "Потоковое Ogg-видео (360p)",
+ "timedmedia-derivative-desc-480p.ogv": "Потоковое Ogg-видео (480p)",
+ "timedmedia-derivative-desc-720p.ogv": "Ogg-видео высокого качества (720p)",
+ "timedmedia-derivative-desc-1080p.ogv": "Скачиваемое Ogg-видео в формате Full HD (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Потоковое WebM-видео (160p)",
+ "timedmedia-derivative-desc-360p.webm": "Потоковое WebM-видео (360p)",
+ "timedmedia-derivative-desc-480p.webm": "Потоковое WebM-видео (480p)",
+ "timedmedia-derivative-desc-720p.webm": "WebM-видео высокого качества (720p)",
+ "timedmedia-derivative-desc-1080p.webm": "Скачиваемое WebM-видео в формате Full HD (1080P)",
+ "timedmedia-derivative-desc-320p.mp4": "Адаптированный для устройства MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Потоковое MP4-видео (480p)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 в HD-качестве (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4-видео в формате Full HD (1080P)",
+ "timedmedia-subtitle-new": "Создать новый перевод или редактировать существующий",
+ "timedmedia-subtitle-new-desc": "Выберите язык и нажмите кнопку '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Выполнить",
+ "timedmedia-subtitle-language": "$1 ($2) субтитры",
+ "timedmedia-subtitle-no-video": "Нет видео, связанного с текущей страницей субтитров",
+ "timedmedia-subtitle-no-subtitles": "В настоящее время нет субтитров на $1 для этого видео, Вы можете [{{fullurl:{{FULLPAGENAME}}|action=edit}} изменить эту страницу] для их добавления",
+ "timedmedia-subtitle-remote": "Субтитры для этого файла размещены на $1",
+ "timedmedia-subtitle-remote-link": "Вы можете [$1 посмотреть страницу описания] этого файла на $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "$1 видео{{PLURAL:$1|файл|файла|файлов}}",
+ "timedmedia-ogg-videos": "$1 Ogg видео{{PLURAL:$1|файл|файла|файлов}}",
+ "timedmedia-webm-videos": "$1 WebM видео{{PLURAL:$1|файл|файла|файлов}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 декодирование|$1 декодирования|$1 декодирований}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 запущенное декодирование|$1 запущенных декодирования|$1 запущенных декодирований}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 поставленное в очередь декодирование|$1 поставленных в очередь декодирования|$1 поставленных в очередь декодирований}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 неудавшееся декодирование|$1 неудавшихся декодирования|$1 неудавшихся декодирований}}",
+ "timedmedia-file": "Файл",
+ "timedmedia-audios": "{{PLURAL:$1|$1 аудиофайл|$1 аудиофайла|$1 аудиофайлов̟}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 аудиофайл Ogg|$1 аудиофайла Ogg|$1 аудиофайлов Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 аудиофайл FLAC|$1 аудиофайла FLAC|$1 аудиофайлов FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 аудиофайл WAV|$1 аудиофайла WAV|$1 аудиофайлов WAV}}",
+ "right-transcode-reset": "сброс неудавшихся или транскодированных видео, чтобы они встали в очередь заданий снова",
+ "right-transcode-status": "просмотр [[Special:TimedMediaHandler|информации о текущем ходе перекодирования]]",
+ "action-transcode-status": "просмотр текущего статуса перекодирования",
+ "orphanedtimedtext": "Потерянные страницы TimedText",
+ "orphanedtimedtext-summary": "Список страниц [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]], которые не имеют соответствующего файла.",
+ "orphanedtimedtext-unsupported": "Это спецстраница поддерживается только для баз данных MySQL.",
+ "orphanedtimedtext-notimedtext": "TimedText не включен в этой вики.",
+ "apihelp-transcodereset-param-title": "Заголовок медиафайла."
+}
diff --git a/extensions/TimedMediaHandler/i18n/rue.json b/extensions/TimedMediaHandler/i18n/rue.json
new file mode 100644
index 00000000..66934a9c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/rue.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gazeb"
+ ]
+ },
+ "timedmedia-more": "Веце...",
+ "timedmedia-dismiss": "Заперти",
+ "timedmedia-file": "Файл"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sa.json b/extensions/TimedMediaHandler/i18n/sa.json
new file mode 100644
index 00000000..f3634735
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sa.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Shubha",
+ "NehalDaveND"
+ ]
+ },
+ "timedmedia-more": "अधिकम्.....",
+ "timedmedia-dismiss": "पिदधातु",
+ "timedmedia-download": "सञ्चिकायाः अवारोपणम्",
+ "timedmedia-desc-link": "अस्याः सञ्चिकायाः विषये",
+ "timedmedia-status": "स्थितिः",
+ "timedmedia-status-unknown": "अज्ञातस्थितिः",
+ "timedmedia-actions": "क्रियाः",
+ "timedmedia-source-file": "$1 स्रोतः",
+ "timedmedia-source-audio-file-desc": "मूलम् $1 सञ्चिका ($2)",
+ "timedmedia-subtitle-new-go": "गम्यताम्",
+ "timedmedia-file": "सञ्चिका"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sah.json b/extensions/TimedMediaHandler/i18n/sah.json
new file mode 100644
index 00000000..0bee4097
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sah.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "HalanTul"
+ ]
+ },
+ "timedmedia-desc": "Обработчик файлов Ogg Theora и Vorbis с использованием JavaScript-проигрывателя",
+ "timedmedia-ogg-short-audio": "Звуковой файл Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Видео-файл Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Медиа-файл Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "звуковой файл Ogg $1, уһуна $2, $3",
+ "timedmedia-ogg-long-video": "видео-файл Ogg $1, уһуна $2, $4×$5 пииксэллээх, $3",
+ "timedmedia-ogg-long-multiplexed": "мультиплексный аудио/видео-файл Ogg, $1, уһуна $2, $4×$5 пииксэллээх, барыта $3",
+ "timedmedia-ogg-long-general": "медиа-файл Ogg, уһуна $2, $3",
+ "timedmedia-ogg-long-error": "сыыһа Ogg-файл: $1",
+ "timedmedia-no-player-js": "Хомойуох иһин, браузергар JavaScript араарылла сылдьар, эбэтэр ону үлэлэтэр тэрил суох эбит.<br />\nЭн <a href=\"$1\">ролигы хачайданан ылан көрүөххүн</a> биитэр <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">оонньотор тэрили хачайданан</a> браузергар көрүөххүн сөп.",
+ "timedmedia-more": "Өссө...",
+ "timedmedia-dismiss": "Кистээ/сап",
+ "timedmedia-download": "Билэни хачайдаа",
+ "timedmedia-desc-link": "Бу билэ туһунан",
+ "timedmedia-source-file": "Ылыллыбыт сирэ $1",
+ "timedmedia-source-audio-file-desc": "Дьиҥнээх $1-билэ ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/scn.json b/extensions/TimedMediaHandler/i18n/scn.json
new file mode 100644
index 00000000..77993f87
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/scn.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pippinu",
+ "Sarvaturi"
+ ]
+ },
+ "timedmedia-no-player-js": "Purtroppu lu tò browser o havi lu JavaScript disattivatu o nun havi nuddu litturi suppurtatu.<br />\nTi poi <a href=\"$1\">scarricari lu spizzuni</a> o puru <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">scarricari nu litturi</a> p'arriprudùciri lu spizzuni ntô tò browser.",
+ "timedmedia-source-file": "Surgenti $1",
+ "timedmedia-source-audio-file-desc": "File $1 origginali ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sco.json b/extensions/TimedMediaHandler/i18n/sco.json
new file mode 100644
index 00000000..a05c7efb
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sco.json
@@ -0,0 +1,16 @@
+{
+ "@metadata": {
+ "authors": [
+ "John Reid",
+ "AmaryllisGardener"
+ ]
+ },
+ "timedmedia-ogg-long-no-streams": "Ogg media file. Warnishment: Nane o the codecs uised in this file ar recognized.",
+ "timedmedia-no-player-js": "Sorry, yer brouser either haes JavaScript disabled or daes nae hae ony supportit player.<br />\nYe can <a href=\"$1\">dounload the clip</a> or <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">dounload a player</a> tae play the clip in yer brouser.",
+ "timedmedia-source-file": "$1 soorce",
+ "timedmedia-source-audio-file-desc": "Oreeginal $1 file ($2)",
+ "timedmedia-audios": "{{PLURAL:$1|$1 audio file|$1 audio files}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg audio file|$1 Ogg audio files}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC audio file|$1 FLAC audio files}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV audio file|$1 WAV audio files}}"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sdh.json b/extensions/TimedMediaHandler/i18n/sdh.json
new file mode 100644
index 00000000..d4ff6455
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sdh.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kurdbuddha"
+ ]
+ },
+ "timedmedia-file": "پەڕگە"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sgs.json b/extensions/TimedMediaHandler/i18n/sgs.json
new file mode 100644
index 00000000..702050e7
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sgs.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hugo.arg"
+ ]
+ },
+ "timedmedia-download": "Atsėsiōstė faila",
+ "timedmedia-source-file": "$1 kėlmie",
+ "timedmedia-source-audio-file-desc": "Pėrms $1 skvarmou ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/shn.json b/extensions/TimedMediaHandler/i18n/shn.json
new file mode 100644
index 00000000..5e27c963
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/shn.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Saimawnkham"
+ ]
+ },
+ "timedmedia-source-file": "ငဝ်ႈငႃႇ $1",
+ "timedmedia-source-audio-file-desc": "ၾၢႆႇငဝ်ႈတိုၼ်း $1 ၾၢႆႇ ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/shy-latn.json b/extensions/TimedMediaHandler/i18n/shy-latn.json
new file mode 100644
index 00000000..ec64ab0c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/shy-latn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Vikoula5"
+ ]
+ },
+ "timedmedia-days": "{{PLURAL:$1|1 ass|$1 ussan}}"
+}
diff --git a/extensions/TimedMediaHandler/i18n/si.json b/extensions/TimedMediaHandler/i18n/si.json
new file mode 100644
index 00000000..05795ef3
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/si.json
@@ -0,0 +1,85 @@
+{
+ "@metadata": {
+ "authors": [
+ "නන්දිමිතුරු",
+ "පසිඳු කාවින්ද",
+ "Susith Chandira Gts",
+ "හරිත"
+ ]
+ },
+ "timedmedia-desc": "Ogg Theora සහ Vorbis ගොනු සඳහා හසුරුවනය, ජාවාස්ක්‍රිප්ට් ප්ලේයර් සමඟ",
+ "timedmedia-ogg-short-audio": "Ogg $1 ශ්‍රව්‍ය ගොනුව, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 දෘශ්‍ය ගොනුව, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 මාධ්‍ය ගොනුව, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 ශ්‍රව්‍ය ගොනුව, ප්‍රවර්තනය $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 දෘශ්‍ය ගොනුව, ප්‍රවර්තනය $2, $4×$5 පික්සල්, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg බහුපථකාරක ශ්‍රව්‍ය/දෘශ්‍ය ගොනුව, $1, ප්‍රවර්තනය $2, $4×$5 පික්සල්, $3 සමස්ත",
+ "timedmedia-ogg-long-general": "Ogg මාධ්‍ය ගොනුව, ප්‍රවර්තනය $2, $3",
+ "timedmedia-ogg-long-error": "අනීතික ogg ගොනුව: $1",
+ "timedmedia-webm-short-video": "WebM $1 විදෘශ්‍ය ගොනුව, $2",
+ "timedmedia-webm-long-video": "WebM ශ්‍රව්‍ය/දෘශ්‍ය ගොනුව, $1, දිග $2, $4 × $5 පික්සල්, $3 සමස්ථය",
+ "timedmedia-mp4-short-video": "MP4 $1 දෘශ්‍ය ගොනුව, $2",
+ "timedmedia-mp4-long-video": "MP4 ශ්‍රව්‍ය/දෘශ්‍ය ගොනුව, $1, දිග $2, $4 × $5 පික්සල්, $3 සමස්ථය",
+ "timedmedia-no-player-js": "සමාවන්න, ඔබේ ගවේෂකයේ ජාවාස්ක්‍රිප්ට් අක්‍රීය වී ඇත නැතහොත් කිසිදු අනුග්‍රහය දක්වන ප්ලේයරයක් ඔබ සතුව නැත.<br />\nඔබේ ගවේෂකයෙහි වීඩියෝව ධාවනය කිරීමට <a href=\"$1\">වීඩියෝව බාගත කිරීම</a> හෝ <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">ප්ලේයරය බාගත කිරීම</a> සිදු කළ හැකිය.",
+ "timedmedia-more": "ඉතිරිය…",
+ "timedmedia-dismiss": "වසන්න",
+ "timedmedia-download": "ගොනුව බා ගන්න",
+ "timedmedia-play-media": "මාධ්‍ය වයන්න",
+ "timedmedia-desc-link": "මෙම ගොනුව පිළිබඳ",
+ "timedmedia-oggThumb-version": "OggHandler සඳහා oggThumb $1 සංස්කරණය හෝ අලුත් එකක් අවැසිය.",
+ "timedmedia-oggThumb-failed": "සංක්ෂිප්තය තැනුමට oggThumb අසමත්විය.",
+ "timedmedia-status-header": "Transcode තත්වය",
+ "timedmedia-update-status": "transcode තත්වය යාවත්කාලීන කරන්න",
+ "timedmedia-status": "තත්වය",
+ "timedmedia-status-unknown": "නොදන්නා තත්වය",
+ "timedmedia-transcodeinfo": "Transcode ව්‍යුත්පන්න විස්තරය",
+ "timedmedia-actions": "කාර්යයන්",
+ "timedmedia-direct-link": "ව්‍යුත්පන්නය බාගන්න",
+ "timedmedia-not-ready": "සුදානම් නැත",
+ "timedmedia-completed-on": "$1 transcode සම්පූර්ණ කරන ලදී",
+ "timedmedia-error-on": "$1 හී transcode දෝෂයක්.",
+ "timedmedia-started-transcode": "$1 පෙර Transcode ආරම්භ කරන ලදී. $2",
+ "timedmedia-percent-done": "$1% පමණ ඉවරයි",
+ "timedmedia-in-job-queue": "$1 පෙර කෘත්‍ය පෙලට එක් කරන ලදී",
+ "timedmedia-unknown-target-size": "නොදන්නා ඉලක්කගත ප්‍රමාණය, $1 කේතාංකනය කරන ලදී",
+ "timedmedia-days": "{{PLURAL:$1|දවස|$1 දවස්}}",
+ "timedmedia-hours": "{{PLURAL:$1|පැය|$1 පැය}}",
+ "timedmedia-minutes": "{{PLURAL:$1|මිනිත්තුව|$1 මිනිත්තු}}",
+ "timedmedia-seconds": "{{PLURAL:$1|තත්පරය|$1 තත්පර}}",
+ "timedmedia-reset": "transcode යළි සකසන්න",
+ "timedmedia-reset-error": "transcode කෘත්‍ය යළි සැකසීමේ දෝෂය.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 මූලාශ්‍රය",
+ "timedmedia-source-file-desc": "නියම $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "නියම $1 ගොනුව ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "අවම කලාප පළල Ogg විදෘශ්‍ය (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "ජාල ශ්‍රෝතමය Ogg වීඩියෝව (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "ජාල ශ්‍රෝතමය Ogg වීඩියෝව (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "උසස් ගුණත්වයේ බාගතහැකි Ogg වීඩියෝව (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "බාගත කළහැකි Full HD Ogg වීඩියෝ පට (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "ජාල ශ්‍රෝතමය WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "ජාල ශ්‍රෝතමය WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "ජාල ශ්‍රෝතමය WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "උසස් ගුණත්වයේ බාගතහැකි WebM (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "බාගත කළහැකි Full HD WebM (1080P)",
+ "timedmedia-derivative-desc-320p.mp4": "උපාංග-හිතකාමී MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "ජාල ශ්‍රෝතමය MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD ගුණත්වයේ MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Full HD තත්වයේ MP4 (1080P)",
+ "timedmedia-subtitle-new": "නව පරිවර්තනයක් තනන්න හෝ පවත්නා එකක් සංස්කරණය කරන්න",
+ "timedmedia-subtitle-new-go": "යන්න",
+ "timedmedia-subtitle-language": "$1 ($2) උපශීර්ෂ",
+ "timedmedia-subtitle-no-video": "වත්මන් උපසිරුස පිටුව සමඟ කිසිදු වීඩියෝවක් සම්බන්ධ නොවේ.",
+ "timedmedia-subtitle-remote": "මෙම ගොනුව සඳහා කාලිත පෙළ $1 හී සත්කාර ලබා ඇත",
+ "timedmedia-subtitle-remote-link": "ඔබට මෙම ගොනුව සඳහා [$1 විස්තර පිටුව] $2 හිදී බලාගත හැක",
+ "timedmediahandler": "කාලිතමාධ්‍යහසුරවනය",
+ "timedmedia-videos": "{{PLURAL:$1|වීඩියෝ}} $1 ක්",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|Ogg වීඩියෝ}} $1 ක්",
+ "timedmedia-webm-videos": "{{PLURAL:$1|WebM වීඩියෝ}} $1 ක්",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcode|$1 transcodes}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|ධාවනය වන transcode}} $1",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|පෙළගස්වා ඇති transcode}} $1",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|අසමත් වූ transcode}} $1",
+ "timedmedia-file": "ගොනුව",
+ "action-transcode-status": "වත්මන් අනු ලැකීම් තත්වය නරඹන්න"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sk.json b/extensions/TimedMediaHandler/i18n/sk.json
new file mode 100644
index 00000000..0a1480c4
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sk.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Helix84",
+ "TomášPolonec",
+ "Wizzard"
+ ]
+ },
+ "timedmedia-desc": "Obsluha súborov Ogg Theora a Vorbis s JavaScriptovým prehrávačom",
+ "timedmedia-ogg-short-audio": "Zvukový súbor ogg $1, $2",
+ "timedmedia-ogg-short-video": "Video súbor ogg $1, $2",
+ "timedmedia-ogg-short-general": "Multimediálny súbor ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Zvukový súbor ogg $1, dĺžka $2, $3",
+ "timedmedia-ogg-long-video": "Video súbor ogg $1, dĺžka $2, $4×$5 pixelov, $3",
+ "timedmedia-ogg-long-multiplexed": "Multiplexovaný zvukový/video súbor ogg, $1, dĺžka $2, $4×$5 pixelov, $3 celkom",
+ "timedmedia-ogg-long-general": "Multimediálny súbor ogg, dĺžka $2, $3",
+ "timedmedia-ogg-long-error": "Neplatný súbor ogg: $1",
+ "timedmedia-no-player-js": "Je nám ľúto, ale váš prehliadač má buď vypnutý JavaScript, alebo nemáte žiadny podporovaný prehrávač.<br />\nMôžete si <a href=\"$1\">stiahnuť klip</a> alebo si <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">stiahnuť prehrávač</a>, ktorým si klip prehrajete v prehliadači.",
+ "timedmedia-more": "viac...",
+ "timedmedia-dismiss": "Zatvoriť",
+ "timedmedia-download": "Stiahnuť súbor",
+ "timedmedia-desc-link": "O tomto súbore",
+ "timedmedia-source-file": "Zdroj $1",
+ "timedmedia-source-audio-file-desc": "Pôvodný súbor $1 ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sl.json b/extensions/TimedMediaHandler/i18n/sl.json
new file mode 100644
index 00000000..d298dd7a
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sl.json
@@ -0,0 +1,96 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dbc334",
+ "Eleassar",
+ "Rzuwig"
+ ]
+ },
+ "timedmedia-desc": "Upravljavec zvoka, videa in časovnega besedila s podprtimi oblikami WebM, Ogg Theora, Vorbis in SubRip",
+ "timedmedia-ogg-short-audio": "avdiodatoteka Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Videodatoteka Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Predstavnostna datoteka Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "avdiodatoteka Ogg $1, dolžine $2, $3",
+ "timedmedia-ogg-long-video": "videodatoteka ogg $1, dolžine $2, $4 × $5 pik, $3",
+ "timedmedia-ogg-long-multiplexed": "multipleksna avdio-/videodatoteka Ogg, $1, dolžine $2, $4 × $5 pik, skupaj $3",
+ "timedmedia-ogg-long-general": "predstavnostna datoteka Ogg, dolžine $2, $3",
+ "timedmedia-ogg-long-error": "Neveljavna datoteka Ogg: $1",
+ "timedmedia-webm-short-video": "Videodatoteka WebM $1, $2",
+ "timedmedia-webm-long-video": "Avdio-/videodatoteka WebM, $1, dolžine $2, $4 × $5 pik, skupaj $3",
+ "timedmedia-flac-short-audio": "Datoteka z zvokom FLAC, $1",
+ "timedmedia-flac-long-audio": "Datoteka z zvokom FLAC, dolžine $1, skupno $2",
+ "timedmedia-wav-short-audio": "Datoteka z zvokom WAV, $1",
+ "timedmedia-wav-long-audio": "Datoteka z zvokom WAV, dolžine $1, skupno $2",
+ "timedmedia-wav-pcm-required": "Naložite lahko samo PCM (Pulse Code Modulation) WAV.",
+ "timedmedia-mp4-short-video": "Videodatoteka MP4 $1, $2",
+ "timedmedia-mp4-long-video": "Avdio-/videodatoteka MP4, $1, dolžine $2, $4 × $5 pik, skupaj $3",
+ "timedmedia-no-player-js": "Oprostite, vaš brskalnik ima onemogočen JavaScript ali pa nima nobenega podprtega predvajalnika.<br />\nPosnetek lahko <a href=\"$1\">snamete</a> ali <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">prenesete predvajalnik</a> za predvajanje posnetka v svojem brskalniku.",
+ "timedmedia-more": "Več ...",
+ "timedmedia-dismiss": "Zapri",
+ "timedmedia-download": "Prenesi",
+ "timedmedia-play-media": "Predvajaj",
+ "timedmedia-desc-link": "O datoteki",
+ "timedmedia-oggThumb-version": "OggHandler potrebuje oggThumb različice $1 ali več.",
+ "timedmedia-oggThumb-failed": "OggThumbu ni uspelo ustvariti predogledne sličice.",
+ "timedmedia-status-header": "Stanje prekodiranja",
+ "timedmedia-update-status": "Posodobi stanje prekodiranja",
+ "timedmedia-status": "Stanje",
+ "timedmedia-status-unknown": "Neznano stanje",
+ "timedmedia-transcodeinfo": "Oblika",
+ "timedmedia-actions": "Dejanja",
+ "timedmedia-direct-link": "Prenos",
+ "timedmedia-not-ready": "Ni pripravljeno",
+ "timedmedia-completed-on": "Končano $1",
+ "timedmedia-error-on": "Napaka dne $1",
+ "timedmedia-started-transcode": "Začeto pred $1. $2",
+ "timedmedia-percent-done": "Končanih približno $1 %",
+ "timedmedia-in-job-queue": "Dodano v čakalno vrsto pred $1",
+ "timedmedia-unknown-target-size": "Neznana ciljna velikost, prekodirano $1",
+ "timedmedia-days": "$1 {{PLURAL:$1|dan|dneva|dnevi|dni}}",
+ "timedmedia-hours": "$1 {{PLURAL:$1|ura|uri|ure|ur}}",
+ "timedmedia-minutes": "$1 {{PLURAL:$1|minuta|minuti|minute|minut}}",
+ "timedmedia-seconds": "$1 {{PLURAL:$1|sekunda|sekundi|sekunde|sekund}}",
+ "timedmedia-reset": "Ponastavi prekodiranje",
+ "timedmedia-reset-confirm": "Ob ponastavitvi tega prekodiranja se bodo izbrisale vse obstoječe datoteke (če obstajajo), prekodiranje pa se bo ponovno dodalo v čakalno vrsto. Ponovno prekodiranje bo vzelo nekaj časa. <br /><br />Ste prepričani, da želite nadaljevati?",
+ "timedmedia-reset-error": "Napaka pri ponastavljanju prekodiranja.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "vir $1",
+ "timedmedia-source-file-desc": "Izvirna datoteka $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Izvirna datoteka $1 ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160P",
+ "timedmedia-derivative-desc-160p.ogv": "Video Ogg za majhno pasovno širino (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Spletni pretočni video Ogg (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Spletni pretočni video Ogg (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Visokokakovostni prenosni video Ogg (720P)",
+ "timedmedia-derivative-desc-160p.webm": "Spletni pretočni WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM za pretakanje preko spleta (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM za pretakanje preko spleta (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Visokokakovostni WebM za prenos (720P)",
+ "timedmedia-derivative-desc-320p.mp4": "Napravam prijazni MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Spletni pretočni WebM (160P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 kakovosti HD (720P)",
+ "timedmedia-subtitle-new": "Ustvarite nov prevod ali uredite obstoječega",
+ "timedmedia-subtitle-new-desc": "Izberite jezik in pritisnite gumb '''{{int:Timedmedia-subtitle-new-go}}'''.",
+ "timedmedia-subtitle-new-go": "Pojdi",
+ "timedmedia-subtitle-language": "podnapisi v jeziku: $1 ($2)",
+ "timedmedia-subtitle-no-video": "S trenutno podnaslovno stranjo ni povezan noben videoposnetek",
+ "timedmedia-subtitle-no-subtitles": "V jeziku $1 trenutno ni nobenih podnapisov za ta video; stran lahko [{{fullurl:{{FULLPAGENAME}}|action=edit}} odprete za urejanje] in jih dodate.",
+ "timedmedia-subtitle-remote": "Časovno besedilo datoteke gostuje na $1",
+ "timedmedia-subtitle-remote-link": "[$1 Ogledate si lahko opisno stran] datoteke na $2",
+ "timedmediahandler": "Upravljavec časovne predstavnosti",
+ "timedmedia-videos": "{{PLURAL:$1|$ video|$ videa|$ videi|$ videov}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 video Ogg|$1 videa Ogg|$1 videi Ogg|$1 videov Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 video WebM|$1 videa WebM|$1 videi WebM|$1 videov WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|eno prekodiranje|dve prekodiranji|$1 prekodiranja|$1 prekodiranj}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|eno tekoče prekodiranje|dve tekoči prekodiranji|$1 prekodiranja|$1 prekodiranj}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|eno čakajoče prekodiranje|dve čakajoči prekodiranji|$1 čakajoča prekodiranja|$1 čakajočih prekodiranj}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|eno neuspelo prekodiranje|dve neuspeli prekodiranji|$1 neuspela prekodiranja|$1 neuspelih prekodiranj}}",
+ "timedmedia-file": "Datoteka:",
+ "timedmedia-audios": "$1 {{PLURAL:$1|zvočna datoteka|zvočni datoteki|zvočne datoteke|zvočnih datotek}}",
+ "timedmedia-ogg-audios": "$1 {{PLURAL:$1|zvočna datoteka|zvočni datoteki|zvočne datoteke|zvočnih datotek}} Ogg",
+ "timedmedia-flac-audios": "$1 {{PLURAL:$1|zvočna datoteka|zvočni datoteki|zvočne datoteke|zvočnih datotek}} FLAC",
+ "timedmedia-wav-audios": "$1 {{PLURAL:$1|zvočna datoteka|zvočni datoteki|zvočne datoteke|zvočnih datotek}} WAV",
+ "right-transcode-reset": "Ponastavitev neuspelih ali pretvorjenih videov, da so ponovno vstavljeni v čakalno vrsto opravil",
+ "right-transcode-status": "Ogled [[Special:TimedMediaHandler|informacij o trenutni dejavnosti pretvarjanja]]",
+ "action-transcode-status": "ogled trenutnega stanja pretvorbe"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sq.json b/extensions/TimedMediaHandler/i18n/sq.json
new file mode 100644
index 00000000..bad879c1
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sq.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Dori",
+ "Liridon"
+ ]
+ },
+ "timedmedia-ogg-short-audio": "Skedë zanore Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Skedë pamore Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Skedë mediatike Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "Skedë zanore Ogg $1, kohëzgjatja $2, $3",
+ "timedmedia-ogg-long-video": "Skedë pamore Ogg $1, kohëzgjatja $2, $4×$5 pixel, $3",
+ "timedmedia-no-player-js": "Na vjen keq, browser-i juaj ose ka të çaktivizuar JavaScript ose nuk ka mbështetje për ndonjë player.<br />\nJu mund të <a href=\"$1\">shkarkoni klipin</a> ose <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">shkarkoni një player</a> për të luajtur klipin në shfletuesin tuaj.",
+ "timedmedia-more": "Më shumë...",
+ "timedmedia-dismiss": "Mbylle",
+ "timedmedia-download": "Shkarko skedën",
+ "timedmedia-desc-link": "Rreth kësaj skede",
+ "timedmedia-source-file": "$1 burimi",
+ "timedmedia-source-audio-file-desc": "Skedari $1 orgjinal ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sr-ec.json b/extensions/TimedMediaHandler/i18n/sr-ec.json
new file mode 100644
index 00000000..b6a3a4df
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sr-ec.json
@@ -0,0 +1,55 @@
+{
+ "@metadata": {
+ "authors": [
+ "Milicevic01",
+ "Millosh",
+ "Rancher",
+ "Sasa Stefanovic",
+ "Михајло Анђелковић"
+ ]
+ },
+ "timedmedia-desc": "Обрађивач за звук, видео и усклађени текст, с подршком за формате WebM, Ogg Theora, Vorbis и SRT",
+ "timedmedia-ogg-short-audio": "Ogg $1 звучна датотека, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 видео-снимак, $2.",
+ "timedmedia-ogg-short-general": "Ogg $1 медијска датотека, $2.",
+ "timedmedia-ogg-long-audio": "Ogg $1 звучна датотека, трајање $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 видео-снимак, трајање $2, $4 × $5 пиксела, $3.",
+ "timedmedia-ogg-long-multiplexed": "Мултиплексирани .ogg аудио/видео снимак, $1, трајање $2, $4 × $5 пиксела, $3.",
+ "timedmedia-ogg-long-general": "Ogg медијска датотека, трајање $2, $3.",
+ "timedmedia-ogg-long-error": "Неисправна .ogg датотека: $1.",
+ "timedmedia-no-player-js": "Жао нам је, али вашем прегледачу је онемогућена јаваскрипта или немате одговарајући плејер.<br />\nМожете <a href=\"$1\">преузети клип</a> или <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">преузети плејер</a> да репродукујете клип у вашем прегледачу.",
+ "timedmedia-more": "Више...",
+ "timedmedia-dismiss": "Затвори",
+ "timedmedia-download": "Преузми датотеку",
+ "timedmedia-desc-link": "Подаци о овој датотеци",
+ "timedmedia-days": "{{PLURAL:$1|1 дан|$1 дана}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 сат|$1 сата|$1 сати}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 минут|$1 минута}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 секунд|$1 секунде|$1 секунди}}",
+ "timedmedia-reset": "Поништи прекодирање",
+ "timedmedia-reset-confirm": "Поништавање овог прекодирања ће уклонити постојећу датотеку (ако постоји) и вратити прекодирање на списак задатака. Ова радња може да потраје. <br /><br />\nЖелите ли да наставите?",
+ "timedmedia-reset-error": "Грешка при поништавању задатака за прекодирање.",
+ "timedmedia-ogg": "Ogg",
+ "timedmedia-webm": "WebM",
+ "timedmedia-flac": "FLAC",
+ "timedmedia-source-file": "Изворни $1",
+ "timedmedia-source-file-desc": "Изворни $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Тип датотеке $1 ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160п",
+ "timedmedia-derivative-desc-160p.ogv": "Нископропусни .ogg видео (160п)",
+ "timedmedia-derivative-360p.ogv": "Ogg 360п",
+ "timedmedia-derivative-desc-360p.ogv": "Ogg видео за емитовање (360п)",
+ "timedmedia-derivative-480p.ogv": "Ogg 480п",
+ "timedmedia-derivative-desc-480p.ogv": "Ogg видео за емитовање (480п)",
+ "timedmedia-derivative-720p.ogv": "Ogg 720п",
+ "timedmedia-derivative-desc-720p.ogv": "Висококвалитетни .ogg видео за преузимање (720п)",
+ "timedmedia-derivative-360p.webm": "WebM 360п",
+ "timedmedia-derivative-desc-360p.webm": "WebM за емитовање (360п)",
+ "timedmedia-derivative-480p.webm": "WebM 480п",
+ "timedmedia-derivative-desc-480p.webm": "WebM за емитовање (480п)",
+ "timedmedia-derivative-720p.webm": "WebM 720п",
+ "timedmedia-derivative-desc-720p.webm": "Висококвалитетни WebM за преузимање (720п)",
+ "timedmedia-subtitle-language": "$1 ($2) титлови",
+ "timedmedia-subtitle-no-video": "Нема видео-снимака повезаних са текућом страницом с титловима",
+ "timedmedia-subtitle-no-subtitles": "Тренутно нема $1 титлова за овај видео-снимак. Можете да их додате тако што ћете [{{fullurl:{{FULLPAGENAME}}|action=edit}} уредити страницу]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sr-el.json b/extensions/TimedMediaHandler/i18n/sr-el.json
new file mode 100644
index 00000000..936e1e92
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sr-el.json
@@ -0,0 +1,53 @@
+{
+ "@metadata": {
+ "authors": [
+ "Michaello",
+ "Milicevic01",
+ "Rancher"
+ ]
+ },
+ "timedmedia-desc": "Obrađivač za zvuk, video i usklađeni tekst, s podrškom za formate WebM, Ogg Theora, Vorbis i SRT",
+ "timedmedia-ogg-short-audio": "Ogg $1 zvučna datoteka, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 video-snimak, $2.",
+ "timedmedia-ogg-short-general": "Ogg $1 medijska datoteka, $2.",
+ "timedmedia-ogg-long-audio": "Ogg $1 zvučna datoteka, dužina $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 video-snimak, trajanje $2, $4 × $5 piksela, $3.",
+ "timedmedia-ogg-long-multiplexed": "Multipleksirani .ogg audio/video snimak, $1, trajanje $2, $4 × $5 piksela, $3.",
+ "timedmedia-ogg-long-general": "Ogg medijska datoteka, dužina $2, $3.",
+ "timedmedia-ogg-long-error": "Neispravna .ogg datoteka: $1.",
+ "timedmedia-no-player-js": "Žao nam je, ali vašem pregledaču je onemogućena javaskripta ili nemate odgovarajući plejer.<br />\nMožete <a href=\"$1\">preuzeti klip</a> ili <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">preuzeti plejer</a> da reprodukujete klip u vašem pregledaču.",
+ "timedmedia-more": "Više...",
+ "timedmedia-dismiss": "Zatvori",
+ "timedmedia-download": "Preuzmi datoteku",
+ "timedmedia-desc-link": "Podaci o ovoj datoteci",
+ "timedmedia-days": "{{PLURAL:$1|1 dan|$1 dana}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 sat|$1 sata|$1 sati}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minut|$1 minuta}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 sekund|$1 sekunde|$1 sekundi}}",
+ "timedmedia-reset": "Poništi prekodiranje",
+ "timedmedia-reset-confirm": "Poništavanje ovog prekodiranja će ukloniti postojeću datoteku (ako postoji) i vratiti prekodiranje na spisak zadataka. Ova radnja može da potraje. <br /><br />\nŽelite li da nastavite?",
+ "timedmedia-reset-error": "Greška pri poništavanju zadataka za prekodiranje.",
+ "timedmedia-ogg": "Ogg",
+ "timedmedia-webm": "WebM",
+ "timedmedia-source-file": "Izvorni $1",
+ "timedmedia-source-file-desc": "Izvorni $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Tip datoteke $1 ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160p",
+ "timedmedia-derivative-desc-160p.ogv": "Niskopropusni .ogg video (160p)",
+ "timedmedia-derivative-360p.ogv": "Ogg 360p",
+ "timedmedia-derivative-desc-360p.ogv": "Ogg video za emitovanje (360p)",
+ "timedmedia-derivative-480p.ogv": "Ogg 480p",
+ "timedmedia-derivative-desc-480p.ogv": "Ogg video za emitovanje (480p)",
+ "timedmedia-derivative-720p.ogv": "Ogg 720p",
+ "timedmedia-derivative-desc-720p.ogv": "Visokokvalitetni .ogg video za preuzimanje (720p)",
+ "timedmedia-derivative-360p.webm": "WebM 360p",
+ "timedmedia-derivative-desc-360p.webm": "WebM za emitovanje (360p)",
+ "timedmedia-derivative-480p.webm": "WebM 480p",
+ "timedmedia-derivative-desc-480p.webm": "WebM za emitovanje (480p)",
+ "timedmedia-derivative-720p.webm": "WebM 720p",
+ "timedmedia-derivative-desc-720p.webm": "Visokokvalitetni WebM za preuzimanje (720p)",
+ "timedmedia-subtitle-language": "$1 ($2) titlovi",
+ "timedmedia-subtitle-no-video": "Nema video-snimaka povezanih sa tekućom stranicom s titlovima",
+ "timedmedia-subtitle-no-subtitles": "Trenutno nema $1 titlova za ovaj video-snimak. Možete da ih dodate tako što ćete [{{fullurl:{{FULLPAGENAME}}|action=edit}} urediti stranicu]",
+ "timedmedia-file": "Datoteka"
+}
diff --git a/extensions/TimedMediaHandler/i18n/stq.json b/extensions/TimedMediaHandler/i18n/stq.json
new file mode 100644
index 00000000..9657a896
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/stq.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pyt"
+ ]
+ },
+ "timedmedia-desc": "Stjuurengsprogramm foar Ogg Theora- un Vorbis-Doatäie, inklusive n JavaScript-Ouspielsoftware",
+ "timedmedia-ogg-short-audio": "Ogg-$1-Audiodoatäi, $2",
+ "timedmedia-ogg-short-video": "Ogg-$1-Videodoatäi, $2",
+ "timedmedia-ogg-short-general": "Ogg-$1-Mediadoatäi, $2",
+ "timedmedia-ogg-long-audio": "Ogg-$1-Audiodoatäi, Loangte: $2, $3",
+ "timedmedia-ogg-long-video": "Ogg-$1-Videodoatäi, Loangte: $2, $4×$5 Pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg-Audio-/Video-Doatäi, $1, Loangte: $2, $4×$5 Pixel, $3",
+ "timedmedia-ogg-long-general": "Ogg-Mediadoatäi, Loangte: $2, $3",
+ "timedmedia-ogg-long-error": "Uungultige Ogg-Doatäi: $1",
+ "timedmedia-more": "Optione …",
+ "timedmedia-dismiss": "Sluute",
+ "timedmedia-download": "Doatäi spiekerje",
+ "timedmedia-desc-link": "Uur disse Doatäi"
+}
diff --git a/extensions/TimedMediaHandler/i18n/su.json b/extensions/TimedMediaHandler/i18n/su.json
new file mode 100644
index 00000000..2fddd5c2
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/su.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kandar"
+ ]
+ },
+ "timedmedia-ogg-short-audio": "Koropak sora $1 ogg, $2",
+ "timedmedia-ogg-short-video": "Koropak vidéo $1 ogg, $2",
+ "timedmedia-ogg-short-general": "Koropak média $1 ogg, $2",
+ "timedmedia-ogg-long-audio": "Koropak sora $1 ogg, lilana $2, $3",
+ "timedmedia-ogg-long-video": "Koropak vidéo $1 ogg, lilana $2, $4×$5 piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Koropak sora/vidéo ogg multipléks, $1, lilana $2, $4×$5 piksel, $3 gembleng",
+ "timedmedia-ogg-long-general": "Koropak média ogg, lilana $2, $3",
+ "timedmedia-ogg-long-error": "Koropak ogg teu valid: $1",
+ "timedmedia-more": "Lianna...",
+ "timedmedia-dismiss": "Tutup",
+ "timedmedia-download": "Bedol",
+ "timedmedia-desc-link": "Ngeunaan ieu koropak"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sv.json b/extensions/TimedMediaHandler/i18n/sv.json
new file mode 100644
index 00000000..dbba4c91
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sv.json
@@ -0,0 +1,125 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ainali",
+ "Jon Harald Søby",
+ "Jopparn",
+ "Lejonel",
+ "Lokal Profil",
+ "Rotsee",
+ "Skalman",
+ "WikiPhoenix",
+ "Abbedabb"
+ ]
+ },
+ "timedmedia-desc": "Hanterare för ljud-, video- och tidsbestämd text, med stöd för format WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 ljudfil, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 videofil, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 mediafil, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 ljudfil, längd $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 videofil, längd $2, $4×$5 pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg multiplexad ljud/video-fil, $1, längd $2, $4×$5 pixel, $3 totalt",
+ "timedmedia-ogg-long-general": "Ogg mediafil, längd $2, $3",
+ "timedmedia-ogg-long-error": "Felaktig Ogg-fil: $1",
+ "timedmedia-ogg-long-no-streams": "Ogg-mediafil. Varning: Ingen av de omkodare som används i denna fil kunde identifieras.",
+ "timedmedia-webm-short-video": "WebM $1 videofil, $2",
+ "timedmedia-webm-long-video": "WebM-fil för ljud/video, $1, längd $2, $4 × $5 pixlar, $3 totalt",
+ "timedmedia-flac-short-audio": "FLAC-ljudfil, $1",
+ "timedmedia-flac-long-audio": "FLAC-ljudfil, längd $1, $2 totalt",
+ "timedmedia-wav-short-audio": "WAV-ljudfil, $1",
+ "timedmedia-wav-long-audio": "WAV-ljudfil, längd $1, $2 total",
+ "timedmedia-wav-pcm-required": "Du kan enbart ladda upp PCM (Pulskodsmodulerad) WAV",
+ "timedmedia-mp4-short-video": "MP4 $1 videofil, $2",
+ "timedmedia-mp4-long-video": "MP4-fil för ljud/video, $1, längd $2, $4 × $5 pixlar, $3 totalt",
+ "timedmedia-no-player-js": "Tyvärr, din webbläsare har antingen JavaScript inaktiverat eller inte någon spelare som stöds.<br />\nDu kan <a href=\"$1\">ladda ner klippet</a> eller <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">hämta en spelare</a> för att spela upp klippet i din webbläsare.",
+ "timedmedia-more": "Mer...",
+ "timedmedia-dismiss": "Stäng",
+ "timedmedia-download": "Ladda ner filen",
+ "timedmedia-play-media": "Spela upp media",
+ "timedmedia-desc-link": "Om filen",
+ "timedmedia-oggThumb-version": "OggHandler kräver oggThumb version $1 eller senare.",
+ "timedmedia-oggThumb-failed": "oggThumb misslyckades med att skapa miniatyrbilden.",
+ "timedmedia-status-header": "Transkodningsstatus",
+ "timedmedia-update-status": "Uppdatera transkodningsstatus",
+ "timedmedia-status": "Status",
+ "timedmedia-status-unknown": "Okänd status",
+ "timedmedia-transcodebitrate": "Bithastighet",
+ "timedmedia-transcodeduration": "Kodningstid",
+ "timedmedia-transcodeinfo": "Format",
+ "timedmedia-actions": "Åtgärder",
+ "timedmedia-direct-link": "Ladda ned",
+ "timedmedia-not-ready": "Inte redo",
+ "timedmedia-completed-on": "Slutfördes $1",
+ "timedmedia-error-on": "Fel $1",
+ "timedmedia-started-transcode": "Startade $1 sedan. $2",
+ "timedmedia-percent-done": "Ungefär $1% klar",
+ "timedmedia-in-job-queue": "Lades till i jobbkön för $1sedan",
+ "timedmedia-unknown-target-size": "Okänd målstorlek, $1-kodad",
+ "timedmedia-days": "{{PLURAL:$1|1 dag|$1 dagar}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 timme|$1 timmar}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minut|$1 minuter}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 sekund|$1 sekunder}}",
+ "timedmedia-reset": "Nollställ transkodningen",
+ "timedmedia-reset-confirm": "Nollställning av denna transkodning tar bort alla befintliga filer (om närvarande), och lägger åter till transkodningen till jobbkön. Det kommer att ta tid att om-transkoda.<br /><br />\nÄr du säker på att du vill fortsätta?",
+ "timedmedia-reset-error": "Fel i nollställningen av transkod-jobbet.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 Källa",
+ "timedmedia-source-file-desc": "Ursprunglig $1-fil, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Ursprunglig $1-fil ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Låg bandbredd Ogg-video (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Webbströmningsbar Ogg-video (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Webbströmningsbar Ogg-video (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Högkvalitets nedladdningsbar Ogg-video (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Nedladdningsbar Ogg-video i full HD (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Webbströmningsbar WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Webbströmningsbar WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Webbströmningsbar WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Högkvalitets nedladdningsbar WebM (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "Nedladdningsbar WebM i full HD (1080P)",
+ "timedmedia-derivative-360p.vp9.webm": "VP9 360P",
+ "timedmedia-derivative-480p.vp9.webm": "VP9 480P",
+ "timedmedia-derivative-720p.vp9.webm": "VP9 720P",
+ "timedmedia-derivative-1080p.vp9.webm": "VP9 1080P",
+ "timedmedia-derivative-desc-320p.mp4": "Enhetsvänlig MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "Webbströmningsbar MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "HD-kvalitet MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4 med kvalitet i full HD (1080P)",
+ "timedmedia-subtitle-new": "Skapa ny översättning eller redigera befintlig",
+ "timedmedia-subtitle-new-desc": "Välj språk och tryck på knappen '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Gå",
+ "timedmedia-subtitle-language": "$1 ($2) undertexter",
+ "timedmedia-subtitle-no-video": "Det finns ingen video som är associerade med den aktuella undertextssidan",
+ "timedmedia-subtitle-no-subtitles": "Det finns för närvarande ingen textning på $1 för denna video, du kan [{{fullurl:{{FULLPAGENAME}}|action=edit}} redigera denna sida] för att lägga till dem",
+ "timedmedia-subtitle-remote": "Undertexter (timed text) för denna fil finns på $1",
+ "timedmedia-subtitle-remote-link": "Du kan [$1 visa beskrivningssidan] för denna fil på $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 videoklipp|$1 videoklipp}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg-video|$1 Ogg-videor}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM-video|$1 WebM-videor}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transkodning|$1 transkodningar}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 aktiv transkodning|$1 aktiva transkodningar}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 köad transkodning|$1 köade transkodningar}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 misslyckad transkodning|$1 misslyckade transkodningar}}",
+ "timedmedia-file": "Fil",
+ "timedmedia-audios": "{{PLURAL:$1|$1 ljudfil|$1 ljudfiler}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg-ljudfil|$1 Ogg-ljudfiler}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC-ljudfil|$1 FLAC-ljudfiler}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV-ljudfil|$1 WAV-ljudfiler}}",
+ "right-transcode-reset": "Återställ misslyckade eller transkodade videor så att de åter infogas i jobbkön.",
+ "right-transcode-status": "Visa [[Special:TimedMediaHandler|information om den aktuella transkodningsaktivitetet]]",
+ "action-transcode-status": "visa den aktuella transkodningsstatusen",
+ "orphanedtimedtext": "Föräldralösa TimedText-sidor",
+ "orphanedtimedtext-summary": "Lista över [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] sidor som inte har en motsvarande fil.",
+ "orphanedtimedtext-unsupported": "Denna special-sida har bara stöd på MySQL-databaser.",
+ "orphanedtimedtext-notimedtext": "TimedText är inte aktiverat på denna wiki.",
+ "apihelp-query+transcodestatus-description": "Hämta transkodningsstatusen för en viss filsida.",
+ "apihelp-query+transcodestatus-example-1": "Hämta transkodningsstatusen för [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "Utökar imageinfo till att inkludera källinformation för video (derivat)",
+ "apihelp-query+videoinfo-param-prop": "Vilken videoinformation att hämta:\n;timestamp:Lägger till tidsstämpeln för den uppladdade versionen.\n;user:Lägger till användaren som laddade upp videoversionen.\n;userid:Lägger till användar-ID:et som laddade upp videoversionen.\n;comment:Kommentar för versionen.\n;parsedcomment:Tolka kommentaren för versionen.\n;canonicaltitle:Lägger till den kanoniska titeln för videofilen.\n;url:Ger URL:en till videon och beskrivningssidan.\n;size:Lägger till storleken på videon i bytes, dess höjd och vidd. Sidantal och varaktighet om applicerbart.\n;dimensions:Alias för size.\n;sha1:Lägger till SHA-1-hash för videon.\n;mime:Lägger till MIME-typ för videon.\n;thumbmime:Lägger till MIME-typ för videons miniatyr (kräver url och parametern $1urlwidth).\n;mediatype:Lägger till mediatyp för videon.\n;metadata:Listar Exif-metadata för versionen av videon.\n;commonmetadata:Listar filformatgenerisk metadata för versionen av videon.\n;extmetadata:Listar formaterad metadata kombinerad från flera källor. Resultaten är HTML-formaterade.\n;archivename:Lägger till filnamn för arkivversionen för icke-senaste versioner.\n;bitdepth:Lägger till bitdjup för versionen.\n;uploadwarning:Används av [[Special:Upload]]-sidan för att få information om en existerande fil. Ej avsedd för bruk utanför Mediawiki core.\n;derivatives:Lägger till en lista för de olika format- och kvalitetsversionerna för en audio- eller videofil som är tillgängliga.",
+ "apihelp-query+videoinfo-example-1": "Hämta information om [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "Användare med \"transcode-reset\"-rättigheten kan återställa och köra om ett transkodningsjobb.",
+ "apihelp-transcodereset-param-title": "Mediefilens titel.",
+ "apihelp-transcodereset-param-transcodekey": "Den transkodningsnyckel du önskar återställa. Hämta från [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Återställ alla transkodningar för [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "Återställ \"360_560kbs.webm\"-transkodningsnyckeln för [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/sw.json b/extensions/TimedMediaHandler/i18n/sw.json
new file mode 100644
index 00000000..51d86efc
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/sw.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Stephenwanjau"
+ ]
+ },
+ "timedmedia-download": "Pakua faili",
+ "timedmedia-desc-link": "Kuhusu faili hii",
+ "timedmedia-status": "Hali",
+ "timedmedia-actions": "Vitendo",
+ "timedmedia-not-ready": "Haiko tayari",
+ "timedmedia-subtitle-new-go": "Nenda",
+ "timedmedia-file": "Faili"
+}
diff --git a/extensions/TimedMediaHandler/i18n/szl.json b/extensions/TimedMediaHandler/i18n/szl.json
new file mode 100644
index 00000000..105eeaa9
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/szl.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Krol111"
+ ]
+ },
+ "timedmedia-source-file": "Zdrzůdło ($1)",
+ "timedmedia-source-audio-file-desc": "Uoryginalny plik $1 ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ta.json b/extensions/TimedMediaHandler/i18n/ta.json
new file mode 100644
index 00000000..69410ef5
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ta.json
@@ -0,0 +1,32 @@
+{
+ "@metadata": {
+ "authors": [
+ "Balajijagadesh",
+ "Karthi.dr",
+ "Shanmugamp7",
+ "மதனாஹரன்",
+ "Jayarathina"
+ ]
+ },
+ "timedmedia-ogg-long-general": "Ogg ஊடக கோப்பு, நீளம் $2 , $3",
+ "timedmedia-ogg-long-error": "செல்லாத ogg கோப்பு: $1",
+ "timedmedia-no-player-js": "மன்னிக்கவும், உங்கள் உலாவியில் ஜாவாஸ்கிரிப்ட் முடக்கப்பட்டிருக்கின்றது அல்லது தகுந்த இயக்கி இல்லை.<br />\nநீங்கள் <a href=\"$1\">இக்கோப்பினை தரவிரக்கம் செய்யலாம்</a> அல்லது <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">தகுந்த இயக்கியினை தரவிரக்கம் செய்து</a> இதனை உங்கள் உலாவியில் ஓட்டலாம்.",
+ "timedmedia-more": "மேலும்...",
+ "timedmedia-dismiss": "மூடுக",
+ "timedmedia-download": "கோப்பை பதிவிறக்கம் செய்",
+ "timedmedia-play-media": "ஊடகத்தை ஓடவிடு",
+ "timedmedia-desc-link": "இந்தக் கோப்பைப் பற்றி",
+ "timedmedia-status": "நிலை",
+ "timedmedia-status-unknown": "அறியப்படாத நிலை",
+ "timedmedia-actions": "செயல்கள்",
+ "timedmedia-not-ready": "தயாராக இல்லை",
+ "timedmedia-percent-done": "ஏறத்தாழ $1% முடிந்தது",
+ "timedmedia-mp4": "எம்பி4",
+ "timedmedia-source-file": "$1 மூலம்",
+ "timedmedia-source-file-desc": "மூல $1, $2 × $3 ($4)",
+ "timedmedia-subtitle-new": "புதிய மொழிபெயர்ப்பை உருவாக்கவும் அல்லது உள்ளதைத் தொகுக்கவும்",
+ "timedmedia-subtitle-new-go": "செல்",
+ "timedmedia-subtitle-language": "$1 ($2) துணைத்தலைப்புக்கள்",
+ "timedmedia-videos": "{{PLURAL:$1|$1 காணொளி|$1 காணொளிகள்}}",
+ "timedmedia-file": "கோப்பு"
+}
diff --git a/extensions/TimedMediaHandler/i18n/tcy.json b/extensions/TimedMediaHandler/i18n/tcy.json
new file mode 100644
index 00000000..622447e7
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/tcy.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "VASANTH S.N."
+ ]
+ },
+ "timedmedia-source-file": "$1 ಮೂಲ",
+ "timedmedia-source-audio-file-desc": "ಮೂಲ $1 ಕಡತ ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/te.json b/extensions/TimedMediaHandler/i18n/te.json
new file mode 100644
index 00000000..96cc2e73
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/te.json
@@ -0,0 +1,37 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kiranmayee",
+ "Veeven",
+ "వైజాసత్య",
+ "రహ్మానుద్దీన్"
+ ]
+ },
+ "timedmedia-ogg-short-audio": "Ogg $1 శ్రావ్యక ఫైలు, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 వీడియో ఫైలు, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 మీడియా ఫైలు, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 శ్రవణ ఫైలు, నిడివి $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 వీడియో ఫైలు, నిడివి $2, $4×$5 పిక్సెళ్ళు, $3",
+ "timedmedia-ogg-long-multiplexed": "ఓగ్ మల్టిప్లెక్సుడ్ శ్రవణ/దృశ్యక ఫైలు, $1, నిడివి $2, $4×$5 పిక్సెళ్ళు, $3 మొత్తం",
+ "timedmedia-ogg-long-general": "Ogg మీడియా ఫైలు, నిడివి $2, $3",
+ "timedmedia-ogg-long-error": "తప్పుడు ogg ఫైలు: $1",
+ "timedmedia-no-player-js": "క్షమించాలి, మీ విహారిణిలో జావాస్క్రిప్ట్ అచేతనంగా ఉంది లేదా మీ విహారిణికి తగిన దృశ్యచాలకం అందుబాటులో లేదు.<br />\nమీరు <a href=\"$1\">మీరు వీడియో క్లిప్ ని దించుకోవచ్చు</a> లేదా <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">దృశ్యచాలకాన్ని</a> దింపుకొని ఈ వీడియో క్లిప్ ను మీ విహారిణిలో చూడవచ్చు.",
+ "timedmedia-more": "మరిన్ని...",
+ "timedmedia-dismiss": "మూసివేయి",
+ "timedmedia-download": "ఫైలుని దిగుమతి చేసుకోండి",
+ "timedmedia-desc-link": "ఈ ఫైలు గురించి",
+ "timedmedia-status": "స్థితి",
+ "timedmedia-status-unknown": "తెలియని స్థితి",
+ "timedmedia-actions": "చర్యలు",
+ "timedmedia-days": "{{PLURAL:$1|1 రోజు|$1 రోజులు}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 గంట|$1 గంటలు}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 నిమిషం|$1 నిమిషాలు}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 క్షణం|$1 క్షణాలు}}",
+ "timedmedia-source-file": "$1 మూలం",
+ "timedmedia-source-file-desc": "అసలు $1 దస్త్రం, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "అసలు $1 దస్త్రం ($2)",
+ "timedmedia-subtitle-new-go": "వెళ్ళు",
+ "timedmedia-subtitle-language": "$1 ($2) ఉపశీర్షికలు",
+ "timedmedia-videos": "{{PLURAL:$1|$1 వీడియో|$1 వీడియోలు}}",
+ "timedmedia-file": "దస్త్రం"
+}
diff --git a/extensions/TimedMediaHandler/i18n/tg-cyrl.json b/extensions/TimedMediaHandler/i18n/tg-cyrl.json
new file mode 100644
index 00000000..abfda498
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/tg-cyrl.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ibrahim"
+ ]
+ },
+ "timedmedia-desc": "Ба дастгирандае барои парвандаҳои Ogg Theora ва Vorbis, бо пахшкунандаи JavaScript",
+ "timedmedia-ogg-short-audio": "Ogg $1 парвандаи савтӣ, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 парвандаи наворӣ, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 парвандаи расона, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 парвандаи савтӣ, тӯл $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 парвандаи наворӣ, тӯл $2, $4×$5 пикселҳо, $3",
+ "timedmedia-ogg-long-multiplexed": "Парвандаи Ogg савтӣ/наворӣ печида, $1, тӯл $2, $4×$5 пикселҳо, дар маҷмӯъ $3",
+ "timedmedia-ogg-long-general": "Парвандаи расонаи Ogg, тӯл $2, $3",
+ "timedmedia-ogg-long-error": "Парвандаи ғайримиҷози ogg: $1",
+ "timedmedia-more": "Бештар...",
+ "timedmedia-dismiss": "Бастан",
+ "timedmedia-download": "Боргирии парванда",
+ "timedmedia-desc-link": "Дар бораи ин парванда"
+}
diff --git a/extensions/TimedMediaHandler/i18n/tg-latn.json b/extensions/TimedMediaHandler/i18n/tg-latn.json
new file mode 100644
index 00000000..b32a59aa
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/tg-latn.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Liangent"
+ ]
+ },
+ "timedmedia-desc": "Ba dastgirandae baroi parvandahoi Ogg Theora va Vorbis, bo paxşkunandai JavaScript",
+ "timedmedia-ogg-short-audio": "Ogg $1 parvandai savtī, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 parvandai navorī, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 parvandai rasona, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 parvandai savtī, tūl $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 parvandai navorī, tūl $2, $4×$5 pikselho, $3",
+ "timedmedia-ogg-long-multiplexed": "Parvandai Ogg savtī/navorī pecida, $1, tūl $2, $4×$5 pikselho, dar maçmū' $3",
+ "timedmedia-ogg-long-general": "Parvandai rasonai Ogg, tūl $2, $3",
+ "timedmedia-ogg-long-error": "Parvandai ƣajrimiçozi ogg: $1",
+ "timedmedia-more": "Beştar...",
+ "timedmedia-dismiss": "Bastan",
+ "timedmedia-download": "Borgiriji parvanda",
+ "timedmedia-desc-link": "Dar borai in parvanda"
+}
diff --git a/extensions/TimedMediaHandler/i18n/tk.json b/extensions/TimedMediaHandler/i18n/tk.json
new file mode 100644
index 00000000..7b0d49a8
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/tk.json
@@ -0,0 +1,20 @@
+{
+ "@metadata": {
+ "authors": [
+ "Hanberke"
+ ]
+ },
+ "timedmedia-desc": "Ogg Theora we Vorbis faýllary üçin işleýji, JavaScript pleýeri bilen bilelikde",
+ "timedmedia-ogg-short-audio": "Ogg $1 ses faýly, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 wideo faýly, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 media faýly, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 ses faýly, uzynlyk $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 wideo faýly, uzynlyk $2, $4×$5 piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg multipleks audio/wideo faýly, $1, uzynlyk $2, $4×$5 piksel, $3 jemi",
+ "timedmedia-ogg-long-general": "Ogg media faýly, uzynlyk $2, $3",
+ "timedmedia-ogg-long-error": "Nädogry ogg faýly: $1",
+ "timedmedia-more": "Has köp...",
+ "timedmedia-dismiss": "Ýap",
+ "timedmedia-download": "Faýl düşür",
+ "timedmedia-desc-link": "Bu faýl hakda"
+}
diff --git a/extensions/TimedMediaHandler/i18n/tl.json b/extensions/TimedMediaHandler/i18n/tl.json
new file mode 100644
index 00000000..9aa38812
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/tl.json
@@ -0,0 +1,84 @@
+{
+ "@metadata": {
+ "authors": [
+ "AnakngAraw",
+ "Sky Harbor"
+ ]
+ },
+ "timedmedia-desc": "Tagahawak para sa audio, bidyo at inoorasang teksto, na may pagtangkilik ng anyo para sa WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "$1 na talaksang pangtunog ng Ogg, $2",
+ "timedmedia-ogg-short-video": "$1 talaksang pampalabas (''video'') ng Ogg, $2",
+ "timedmedia-ogg-short-general": "$1 talaksang pangmidya ng Ogg, $2",
+ "timedmedia-ogg-long-audio": "$1 talaksang pantunog ng Ogg, haba $2, $3",
+ "timedmedia-ogg-long-video": "$1 talaksan ng palabas ng Ogg, haba $2, $4×$5 mga piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "magkasanib at nagsasabayang talaksang nadirinig o audio/palabas ng Ogg, $1, haba $2, $4×$5 mga piksel, $3 sa kalahatan",
+ "timedmedia-ogg-long-general": "Talaksang pangmidya ng ''Ogg'', haba $2, $3",
+ "timedmedia-ogg-long-error": "Hindi tanggap na talaksang ''ogg'': $1",
+ "timedmedia-webm-short-video": "$1 na talaksan ng bidyo ng WebM, $2",
+ "timedmedia-webm-long-video": "Talaksang pamparinig/bidyo ng WebM, $1, haba $2, $4 × $5 mga piksel, $3 lahat-lahat",
+ "timedmedia-no-player-js": "Paumahin, ang pantingin-tingin mo ay maaaring may hindi gumaganang JavaScript o walang anumang tinatangkilik na pampaandar.<br />\nMaaari kang <a href=\"$1\">magkargang pababa ng kaputol</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">magkargang pababa ng isang pampaandar</a> upang mapaandar ang kaputol sa loob ng iyong pantingin-tingin.",
+ "timedmedia-more": "Marami pa…",
+ "timedmedia-dismiss": "Isara",
+ "timedmedia-download": "Ikarga ang talaksan",
+ "timedmedia-play-media": "Paandarin ang midya",
+ "timedmedia-desc-link": "Tungkol sa talaksang ito",
+ "timedmedia-oggThumb-version": "Nangangailangan ang OggHandler ng bersyong $1 o mas luma ng oggThumb.",
+ "timedmedia-oggThumb-failed": "Nabigong lumikha ang oggThumb ng munting larawan.",
+ "timedmedia-status-header": "Katayuan ng transkodigo",
+ "timedmedia-update-status": "Isapanahon ang katayuan ng transkodigo",
+ "timedmedia-status": "Katayuan",
+ "timedmedia-status-unknown": "Hindi alam na katayuan",
+ "timedmedia-transcodeinfo": "Paglalarawan sa hinangong transkodigo",
+ "timedmedia-actions": "Mga kilos",
+ "timedmedia-direct-link": "Ikargang paibaba ang hinango",
+ "timedmedia-not-ready": "Hindi nakahanda",
+ "timedmedia-completed-on": "Nabuo ang transkodigo noong $1",
+ "timedmedia-error-on": "Kamalian sa transkodigo noong $1.",
+ "timedmedia-started-transcode": "Nagsimula ang transkodigo noong $1 na ang nakalilipas. $2",
+ "timedmedia-percent-done": "Halos $1% na ang natatapos",
+ "timedmedia-in-job-queue": "Idinagdag sa pila ng Gawain noong $1 na ang nakalilipas",
+ "timedmedia-unknown-target-size": "Hindi nalalaman na puntiryang sukat, $1 naisakodigo",
+ "timedmedia-days": "{{PLURAL:$1|araw|$1 mga araw}}",
+ "timedmedia-hours": "{{PLURAL:$1|horas|$1 mga oras}}",
+ "timedmedia-minutes": "{{PLURAL:$1|minuto|$1 mga minuto}}",
+ "timedmedia-seconds": "{{PLURAL:$1|segundo|$1 mga segundo}}",
+ "timedmedia-reset": "Itakdang muli ang transkodigo",
+ "timedmedia-reset-confirm": "Ang muling pagtatakda ng transkodigong ito ay magtatanggal ng anumang umiiral na talaksan (kung naroroon), at muling nitong idaragdag ang transkodigo sa pila ng trabaho. Gugugol ito ng ilang panahon upang muling maitranskodigo. <br /><br />\nNakatitiyak ka ba na nais mong magpatuloy?",
+ "timedmedia-reset-error": "Kamalian sa gawain ng muling pagtatakda ng transkodigo.",
+ "timedmedia-ogg": "Ogg",
+ "timedmedia-webm": "WebM",
+ "timedmedia-source-file": "$1 pinagkukunan",
+ "timedmedia-source-file-desc": "Orihinal na $1, $2 × $3 ( $4)",
+ "timedmedia-source-audio-file-desc": "Orihinal na talaksang $1 ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160P",
+ "timedmedia-derivative-desc-160p.ogv": "Mababang lapad ng paha ng bidyo ng Ogg (160P)",
+ "timedmedia-derivative-360p.ogv": "Ogg 360P",
+ "timedmedia-derivative-desc-360p.ogv": "Mapapaanod sa Web na bidyo ng Ogg (360P)",
+ "timedmedia-derivative-480p.ogv": "Ogg 480P",
+ "timedmedia-derivative-desc-480p.ogv": "Mapapaanod sa Web na bidyo ng Ogg (480P)",
+ "timedmedia-derivative-720p.ogv": "Ogg 720P",
+ "timedmedia-derivative-desc-720p.ogv": "Mataas na uri ng bidyo ng Ogg na maikakargang paibaba (720P)",
+ "timedmedia-derivative-160p.webm": "WebM 160P",
+ "timedmedia-derivative-desc-160p.webm": "Mapapaanod sa Web na WebM (160P)",
+ "timedmedia-derivative-360p.webm": "WebM 360P",
+ "timedmedia-derivative-desc-360p.webm": "Mapapaanod sa Web na WebM (360P)",
+ "timedmedia-derivative-480p.webm": "WebM 480P",
+ "timedmedia-derivative-desc-480p.webm": "Mapapaanod sa Web na WebM (480P)",
+ "timedmedia-derivative-720p.webm": "WebM 720P",
+ "timedmedia-derivative-desc-720p.webm": "Mataas na uri ng WebM na maikakargang paibaba (720P)",
+ "timedmedia-subtitle-new": "Lumikha ng bagong salinwika o baguhin ang umiiral na",
+ "timedmedia-subtitle-new-desc": "Palitan ang bahaging '''$1''' ng iyong [[:en:ISO 639|kodigo ng wika]] at pindutin ang pindutang '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Gawin",
+ "timedmedia-subtitle-language": "$1 ($2) kabahaging mga pamagat",
+ "timedmedia-subtitle-no-video": "Walang bidyo na may kaugnayan sa pangkasalukuyang pahina ng kabahaging pamagat",
+ "timedmedia-subtitle-no-subtitles": "Kasalukuyang walang mga kabahaging pamagat sa loob ng $1 para sa bidyong ito, maaari mong [{{fullurl:{{FULLPAGENAME}}|action=edit}} baguhin ang pahinang ito] upang maidagdag ang mga ito",
+ "timedmediahandler": "Inoorasang Panghawak ng Midya",
+ "timedmedia-videos": "{{PLURAL:$1|$1 bidyo|$1 mga bidyo}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 bidyo ng Ogg|$1 mga bidyo ng Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 bidyo ng WebM|$1 mga bidyo ng WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transkodigo|$1 mga transkodigo}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 tumatakbong transkodigo|$1 tumatakbong mga transkodigo}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 nakapilang transkodigo|$1 nakapilang mga transkodigo}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 nabigong transkodigo|$1 nabigong mga transkodigo}}",
+ "timedmedia-file": "Talaksan"
+}
diff --git a/extensions/TimedMediaHandler/i18n/tly.json b/extensions/TimedMediaHandler/i18n/tly.json
new file mode 100644
index 00000000..8123d4cc
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/tly.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Erdemaslancan"
+ ]
+ },
+ "timedmedia-subtitle-new-go": "Давардеј"
+}
diff --git a/extensions/TimedMediaHandler/i18n/tr.json b/extensions/TimedMediaHandler/i18n/tr.json
new file mode 100644
index 00000000..e3e00c8f
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/tr.json
@@ -0,0 +1,80 @@
+{
+ "@metadata": {
+ "authors": [
+ "Erkan Yilmaz",
+ "Incelemeelemani",
+ "Joseph",
+ "Mach",
+ "Runningfridgesrule",
+ "Srhat",
+ "Sayginer",
+ "Stultiwikia",
+ "Mavrikant"
+ ]
+ },
+ "timedmedia-desc": "Ses işleyicisi, video ve zamanlanmış metin formatları için WebM, Ogg Theora, Vorbis, srt desteği",
+ "timedmedia-ogg-short-audio": "Ogg $1 ses dosyası, $2",
+ "timedmedia-ogg-short-video": "Ogg $1 video dosyası, $2",
+ "timedmedia-ogg-short-general": "Ogg $1 medya dosyası, $2",
+ "timedmedia-ogg-long-audio": "Ogg $1 ses dosyası, süre $2, $3",
+ "timedmedia-ogg-long-video": "Ogg $1 video dosyası, süre $2, $4×$5 piksel, $3",
+ "timedmedia-ogg-long-multiplexed": "Ogg çok düzeyli ses/video dosyası, $1, süre $2, $4×$5 piksel, $3 genelde",
+ "timedmedia-ogg-long-general": "Ogg medya dosyası, süre $2, $3",
+ "timedmedia-ogg-long-error": "Geçersiz ogg dosyası: $1",
+ "timedmedia-webm-short-video": "WebM $1 video dosyası, $2",
+ "timedmedia-webm-long-video": "WebM ses/video dosyası, $1, süre $2, $4 × $5 piksel, $3 tümü",
+ "timedmedia-flac-short-audio": "FLAC ses dosyası, $1",
+ "timedmedia-flac-long-audio": "FLAC ses dosyası, süre $1, $2 tümü",
+ "timedmedia-wav-short-audio": "WAV ses dosyası, $1",
+ "timedmedia-wav-long-audio": "WAV ses dosyası, süre $1, $2 tümü",
+ "timedmedia-wav-pcm-required": "Yalnızca PCM (Darbeli Kod Modülasyonu) WAV yükleyebilirsiniz.",
+ "timedmedia-mp4-short-video": "MP4 $1 video dosyası, $2",
+ "timedmedia-mp4-long-video": "MP4 ses/video dosyası, $1, süre $2, $4 × $5 piksel, $3 tümü",
+ "timedmedia-no-player-js": "Üzgünüz, tarayıcınızda JavaScript devredışı veya yüklü bir oynatıcı yok.<br />\nİsterseniz <a href=\"$1\">klibi indirebilir</a> veya tarayıcınız için <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">oynatıcıyı buradan indirebilirsiniz</a>.",
+ "timedmedia-more": "Daha...",
+ "timedmedia-dismiss": "Kapat",
+ "timedmedia-download": "Dosya indir",
+ "timedmedia-play-media": "Medyayı oynat",
+ "timedmedia-desc-link": "Bu dosya hakkında",
+ "timedmedia-oggThumb-version": "OggHandler $1 veya daha yeni sürüm oggThumb gerektirir.",
+ "timedmedia-oggThumb-failed": "oggThumb küçük resim oluşturamadı.",
+ "timedmedia-status-header": "Transkodu durumu",
+ "timedmedia-update-status": "Transkodu durumunu güncelle",
+ "timedmedia-status": "Durum",
+ "timedmedia-status-unknown": "Bilinmeyen durum",
+ "timedmedia-transcodeinfo": "Format",
+ "timedmedia-actions": "İşlemler",
+ "timedmedia-direct-link": "Türevi indir",
+ "timedmedia-not-ready": "Hazır değil",
+ "timedmedia-completed-on": "Tamamlanan transkodu $1",
+ "timedmedia-error-on": "$1 üzerinde çapraz kodlama hatası",
+ "timedmedia-started-transcode": "$1 öncesinde transkod başlangıcı. $2",
+ "timedmedia-percent-done": "Tamamlanan $1% hakkında",
+ "timedmedia-in-job-queue": "$1 önce iş kuyruğuna eklendi",
+ "timedmedia-unknown-target-size": "$1 kodlamasında, bilinmeyen hedef boyutu",
+ "timedmedia-days": "{{PLURAL:$1|1 gün|$1 gün}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 saat|$1 saat}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 dakika|$1 dakika}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 saniye|$1 saniye}}",
+ "timedmedia-reset": "Transkodu sıfırla",
+ "timedmedia-reset-confirm": "Bu transkodu sıfırladığınız takdirde (eğer varsa), mevcut dosyalar kaldırılacak ve yeniden iş kuyruğuna alınacaktır. Bu yeniden kodlama biraz zaman alacaktır.<br /><br />\nDevam etmek istediğinize emin misiniz?",
+ "timedmedia-reset-error": "Transkodlama işinde sıfırlama hatası.",
+ "timedmedia-source-file": "$1 kaynağı",
+ "timedmedia-source-file-desc": "Orijinal $1 dosyası, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Orijinal $1 dosyası ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg videosu düşük bant genişliği (160P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Full HD indirilebilir Ogg video (1080P)",
+ "timedmedia-derivative-desc-1080p.webm": "Full HD indirilebilir WebM (1080P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Full HD kalitede MP4 (1080P)",
+ "timedmedia-subtitle-new-go": "Git",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video|$1 video}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg videosu|$1 Ogg videosu}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM videosu|$1 WebM videosu}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transkod|$1 transkod}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 çalışan transkod|$1 çalışan transkod}}",
+ "timedmedia-file": "Dosya",
+ "timedmedia-audios": "{{PLURAL:$1|$1 ses dosyası|$1 ses dosyası}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 Ogg ses dosyası|$1 Ogg ses dosyası}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 FLAC ses dosyası|$1 FLAC ses dosyası}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 WAV ses dosyası|$1 WAV ses dosyası}}"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ts.json b/extensions/TimedMediaHandler/i18n/ts.json
new file mode 100644
index 00000000..240bfe4c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ts.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Thuvack"
+ ]
+ },
+ "timedmedia-more": "Swinwana…",
+ "timedmedia-dismiss": "Pfala"
+}
diff --git a/extensions/TimedMediaHandler/i18n/tt-cyrl.json b/extensions/TimedMediaHandler/i18n/tt-cyrl.json
new file mode 100644
index 00000000..e9224c6c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/tt-cyrl.json
@@ -0,0 +1,17 @@
+{
+ "@metadata": {
+ "authors": [
+ "Ильнар",
+ "Derslek"
+ ]
+ },
+ "timedmedia-no-player-js": "Кызганычка каршы сезнең браузерда JavaScript сүндерелгән, яисә кирәкле уйнаткыч юк.<br />\nСез <a href=\"$1\">роликны</a> йөкли яисә аны браузерда уйнатыр өчен<a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">уйнаткыч кушымта</a> йөкли аласыз.",
+ "timedmedia-more": "Тулырак...",
+ "timedmedia-dismiss": "Ябу",
+ "timedmedia-download": "Файлны алу",
+ "timedmedia-desc-link": "Файл турында мәгълүмат",
+ "timedmedia-oggThumb-version": "OggHandler $1 юрамасыннан да югарырак oggThumb тәэминатын сорый.",
+ "timedmedia-oggThumb-failed": "oggThumb нигезендә миниатюраны ясап булмады.",
+ "timedmedia-source-file": "$1-нче чыганак",
+ "timedmedia-source-audio-file-desc": "Оригиналь $1-файл ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/tzm.json b/extensions/TimedMediaHandler/i18n/tzm.json
new file mode 100644
index 00000000..cf77a584
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/tzm.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Tifinaghes"
+ ]
+ },
+ "timedmedia-mp4": "MP4"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ug-arab.json b/extensions/TimedMediaHandler/i18n/ug-arab.json
new file mode 100644
index 00000000..05e95334
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ug-arab.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "Sahran"
+ ]
+ },
+ "timedmedia-dismiss": "ياپ",
+ "timedmedia-status": "ھالەت",
+ "timedmedia-actions": "مەشغۇلات",
+ "timedmedia-not-ready": "تەييار ئەمەس",
+ "timedmedia-subtitle-new-go": "يۆتكەل",
+ "timedmedia-file": "ھۆججەت"
+}
diff --git a/extensions/TimedMediaHandler/i18n/uk.json b/extensions/TimedMediaHandler/i18n/uk.json
new file mode 100644
index 00000000..a70bd282
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/uk.json
@@ -0,0 +1,134 @@
+{
+ "@metadata": {
+ "authors": [
+ "AS",
+ "Ahonc",
+ "Andriykopanytsia",
+ "AtUkr",
+ "Base",
+ "NickK",
+ "Olvin",
+ "Prima klasy4na",
+ "Steve.rusyn",
+ "SteveR",
+ "Тест",
+ "Ата",
+ "Piramidion",
+ "Dars"
+ ]
+ },
+ "timedmedia-desc": "Оброблювач для аудіо, відео і субтитрів з підтримкою форматів WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "Звуковий файл Ogg $1, $2",
+ "timedmedia-ogg-short-video": "Відео-файл Ogg $1, $2",
+ "timedmedia-ogg-short-general": "Файл Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "звуковий файл Ogg $1, довжина $2, $3",
+ "timedmedia-ogg-long-video": "відео-файл Ogg $1, довжина $2, $4×$5 пікселів, $3",
+ "timedmedia-ogg-long-multiplexed": "мультиплексний аудіо/відео-файл ogg, $1, довжина $2, $4×$5 пікселів, $3 усього",
+ "timedmedia-ogg-long-general": "медіа-файл Ogg, довжина $2, $3",
+ "timedmedia-ogg-long-error": "Неправильний Ogg-файл: $1",
+ "timedmedia-ogg-long-no-streams": "Медіафайл Ogg. Застереження: Не розпізнано жоден з кодеків, використаних у цьому файлі.",
+ "timedmedia-webm-short-video": "WebM $1 відео-файл, $2",
+ "timedmedia-webm-long-video": "WebM аудіо/відео файл, $1, тривалість $2, $4 × $5 {{PLURAL:$5|піксель|пікселі|пікселів}}, всього $3",
+ "timedmedia-flac-short-audio": "FLAC аудіо-файл,$1",
+ "timedmedia-flac-long-audio": "FLAC аудіо-файл, тривалість $1, $2 швидкість",
+ "timedmedia-wav-short-audio": "Аудіо-файл WAV, $1",
+ "timedmedia-wav-long-audio": "Аудіо-файл WAV, тривалість $1, $2 швидкість",
+ "timedmedia-wav-pcm-required": "Ви можете тільки завантажити PCM (імпульсно-кодова модуляція) WAV.",
+ "timedmedia-mp4-short-video": "MP4 $1 відео-файл, $2",
+ "timedmedia-mp4-long-video": "MP4 аудіо/відео файл, $1, тривалість $2, $4 × $5 {{PLURAL:$5|піксель|пікселі|пікселів}}, всього $3",
+ "timedmedia-no-player-js": "На жаль, у Вашому браузері вимкнено JavaScript і не підтримується жодного програвача.<br />\nВи можете <a href=\"$1\">завантажити ролик</a> або <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">завантажити програвач</a> для відтворенні ролику у браузері.",
+ "timedmedia-more": "Більше…",
+ "timedmedia-dismiss": "Закрити",
+ "timedmedia-download": "Завантажити файл",
+ "timedmedia-play-media": "Відтворити",
+ "timedmedia-desc-link": "Інформація про цей файл",
+ "timedmedia-oggThumb-version": "OggHandler вимагає oggThumb версії $1 або більш пізньої.",
+ "timedmedia-oggThumb-failed": "oggThumb не вдалось створити мініатюру.",
+ "timedmedia-status-header": "Статус декодування",
+ "timedmedia-update-status": "Оновити статус декодування",
+ "timedmedia-status": "Статус",
+ "timedmedia-status-unknown": "Невідомий статус",
+ "timedmedia-transcodebitrate": "Бітрейт",
+ "timedmedia-transcodeduration": "Час кодування",
+ "timedmedia-transcodeinfo": "Формат",
+ "timedmedia-actions": "Дії",
+ "timedmedia-direct-link": "Завантажити",
+ "timedmedia-not-ready": "Не готово",
+ "timedmedia-completed-on": "Завершено $1",
+ "timedmedia-error-on": "Помилка на $1.",
+ "timedmedia-started-transcode": "Розпочато $1 назад. $2",
+ "timedmedia-percent-done": "Приблизно $1% готово",
+ "timedmedia-in-job-queue": "Додано до черги завдань $1 назад",
+ "timedmedia-unknown-target-size": "Невідомий цільовий розмір, $1 при кодуванні",
+ "timedmedia-days": "$1 {{PLURAL:$1|день|дні|днів}}",
+ "timedmedia-hours": "$1 {{PLURAL:$1|гадину|години|годин}}",
+ "timedmedia-minutes": "$1 {{PLURAL:$1|хвилину|хвилини|хвилин}}",
+ "timedmedia-seconds": "$1 {{PLURAL:$1|секунду|секунди|секунд}}",
+ "timedmedia-reset": "Перезапуск декодування",
+ "timedmedia-reset-confirm": "Перезапуск декодування видалить наявний файл (якщо він існує), і декодування знов буде додано в чергу завдань. Повторне декодування займе якийсь час. <br /><br />\nВи упевнені, що хочете продовжити?",
+ "timedmedia-reset-error": "Помилка при перезапуску декодування.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Джерело $1",
+ "timedmedia-source-file-desc": "Оригінальний $1 файл, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "Оригінальний $1 файл ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Ogg-відео низької якості (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "Потокове Ogg-відео (240P)",
+ "timedmedia-derivative-desc-360p.ogv": "Потокове Ogg-відео (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Потокове Ogg-відео (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Високоякісне Ogg-відео (720P) для завантаження",
+ "timedmedia-derivative-desc-1080p.ogv": "Скачуване Ogg-відео у форматі Full HD (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Потокове WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "Потокове WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "Потокове WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "Високоякісне WebM (720P) для завантаження",
+ "timedmedia-derivative-desc-1080p.webm": "Скачуване WebM-відео у форматі Full HD (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "Скачуване WebM-відео у форматі Full 4K (2160P)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "Потокове WebM VP9 (360P)",
+ "timedmedia-derivative-desc-480p.vp9.webm": "Потокове WebM VP9 (480P)",
+ "timedmedia-derivative-desc-720p.vp9.webm": "Потокове WebM VP9 у форматі HD (720P)",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "Потокове WebM VP9 у форматі Full HD (1080P)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "Потокове WebM-відео у форматі Full 4K (2160P)",
+ "timedmedia-derivative-desc-320p.mp4": "Сумісний з MP$ (320P) пристрій",
+ "timedmedia-derivative-desc-480p.mp4": "Веб-потокове MP4 (480 Р)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 якості HD (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4-відео у форматі Full HD (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "MP4-відео у форматі Full 4K (2160P)",
+ "timedmedia-subtitle-new": "Створити новий переклад або відредагувати існуючий",
+ "timedmedia-subtitle-new-desc": "Виберіть мову та натисніть '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Перейти",
+ "timedmedia-subtitle-language": "$1 ($2) субтитри",
+ "timedmedia-subtitle-no-video": "Немає відео, пов'язаного з поточною сторінкою субтитрів",
+ "timedmedia-subtitle-no-subtitles": "В даний час немає субтитрів на $1 для цього відео, Ви можете [{{fullurl:{{FULLPAGENAME}}|action=edit}} змінити цю сторінку] для їх додавання",
+ "timedmedia-subtitle-remote": "Текст до цього файлу розміщений на $1",
+ "timedmedia-subtitle-remote-link": "Ви можете [$1 переглянути опис сторінки] для цього файлу на $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 відео}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 Ogg відео}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 WebM відео}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|1=$1 перекодування|$1 перекодувань}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|1=$1 працюючі перекодування|$1 працюючих перекодувань}}",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|1=$1 перекодування в черзі|$1 перекодувань в черзі}}",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|1=$1 невдалі перекодування|$1 невдалих перекодувань}}",
+ "timedmedia-file": "Файл",
+ "timedmedia-audios": "{{PLURAL:$1|$1 аудіо-файл|$1 аудіо-файлів̟|$1 аудіо-файли}}",
+ "timedmedia-ogg-audios": "{{PLURAL:$1|$1 аудіо-файл Ogg|$1 аудіо-файлів Ogg|$1 аудіо-файли Ogg}}",
+ "timedmedia-flac-audios": "{{PLURAL:$1|$1 аудіо-файл FLAC|$1 аудіо-файлів FLAC|$1 аудіо-файли FLAC}}",
+ "timedmedia-wav-audios": "{{PLURAL:$1|$1 аудіо-файл WAV|$1 аудіо-файлів WAV|$1 аудіо-файли WAV}}",
+ "right-transcode-reset": "скидання невдалих або перекодованих відео із повторним занесенням їх в чергу завдань",
+ "right-transcode-status": "перегляд [[Special:TimedMediaHandler|інформації про поточну діяльність з перекодування]]",
+ "action-transcode-status": "Перегляд поточного стану перекодування",
+ "orphanedtimedtext": "Сторінки-сироти TimedText",
+ "orphanedtimedtext-summary": "Список сторінок [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]], які не мають відповідного файлу.",
+ "orphanedtimedtext-unsupported": "Ця спеціальна сторінка підтримується лише базами даних MySQL.",
+ "orphanedtimedtext-notimedtext": "TimedText не увімкнений у цій вікі.",
+ "apihelp-query+transcodestatus-description": "Отримати транскод-статус для даної сторінки файлу.",
+ "apihelp-query+transcodestatus-example-1": "Отримати транскод-статус для [[:File:Clip.webm]]",
+ "apihelp-query+videoinfo-description": "Розширює imageinfo і включає інформацію джерела відео (похідні)",
+ "apihelp-query+videoinfo-param-prop": "Яку інформацію про відео отримувати:\n;timestamp:Додає часову мітку завантаженої версії.\n;user:Додає користувача, який завантажив версію відео.\n;userid:Додає ID користувача, який завантажив версію відео.\n;comment:Коментар до версії.\n;parsedcomment:Парсинг коментаря до версії.\n;canonicaltitle:Додає канонічний заголовок відеофайлу.\n;url:Дає URL на відео та сторінку опису.\n;size:Додає розміри відео у байтах, його висоту і ширину. Номер сторінки і тривалість додаються за можливості.\n;dimensions:Аліас розміру.\n;sha1:Додає геш SHA-1 відео.\n;mime:Додає MIME-тип відео.\n;thumbmime:Додає MIME-тип мініатюри відео (вимагає url і параметр $1urlwidth).\n;mediatype:Додає медіатип відео.\n;metadata:Виводить список Exif-метаданих версії відео.\n;commonmetadata:Виводить список метаданих формату файлу версії відео.\n;extmetadata:Виводить список форматованих метаданих, скомбінованих з кількох джерел. Результати відформатовані в HTML.\n;archivename:Додає назву файлу архівованої версії для не останніх версій.\n;bitdepth:Додає бітову глибину версії.\n;uploadwarning:Використовується сторінкою [[Special:Upload]] для отримання інформації про наявний файл. Не призначено для використання поза ядром MediaWiki.\n;derivatives:Додає масив доступних версій іншого формату і якості аудіо- чи відеофайлу.",
+ "apihelp-query+videoinfo-example-1": "Витяг інформації про [[:File:Folgers.ogv]]",
+ "apihelp-transcodereset-description": "Користувачі з правом «transcode-reset» можуть скинути і повторити задачу перекодування.",
+ "apihelp-transcodereset-param-title": "Заголовок медіафайлу.",
+ "apihelp-transcodereset-param-transcodekey": "Перекодувати ключ, який Ви хочете скинути. Вибірка з [[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]].",
+ "apihelp-transcodereset-example-1": "Скинути усі перекодування для [[:File:Clip.webm]]",
+ "apihelp-transcodereset-example-2": "Скинути ключ перекодування «360_560kbs.webm» для [[:File:Clip.webm]]"
+}
diff --git a/extensions/TimedMediaHandler/i18n/ur.json b/extensions/TimedMediaHandler/i18n/ur.json
new file mode 100644
index 00000000..7b58606a
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/ur.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "පසිඳු කාවින්ද",
+ "Muhammad Shuaib",
+ "عثمان خان شاہ"
+ ]
+ },
+ "timedmedia-no-player-js": "معذرت، آپ کے براؤزر میں جاواسکرپٹ فعال نہیں یا کوئی معاون پلیئر شامل نہیں ہے۔<br />\nاس کلپ کو اپنے براؤزر میں چلانے کے لیے آپ <a href=\"$1\">کلپ کو ڈاؤنلوڈ</a> کرلیں یا </a> or <a href=\"//www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download\">پلیئر ڈاؤنلوڈ</a> کرلیں۔",
+ "timedmedia-more": "مزید...",
+ "timedmedia-dismiss": "بند",
+ "timedmedia-download": "فائل ڈاؤن لوڈ ، اتارنا",
+ "timedmedia-play-media": "کھیلنے کے میڈیا",
+ "timedmedia-desc-link": "اس فائل کے بارے میں",
+ "timedmedia-status": "حیثیت",
+ "timedmedia-status-unknown": "نامعلوم مقام",
+ "timedmedia-actions": "اعمال",
+ "timedmedia-source-file": "$1 مسودہ",
+ "timedmedia-source-audio-file-desc": "اصلی $1 ملف ($2)",
+ "timedmedia-file": "فائل"
+}
diff --git a/extensions/TimedMediaHandler/i18n/vec.json b/extensions/TimedMediaHandler/i18n/vec.json
new file mode 100644
index 00000000..c567687b
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/vec.json
@@ -0,0 +1,85 @@
+{
+ "@metadata": {
+ "authors": [
+ "Candalua",
+ "GatoSelvadego"
+ ]
+ },
+ "timedmedia-desc": "Gestor pa' i file audio, video e có sototitołi; formati suportai: WebM, Ogg Theora, Vorbis, srt",
+ "timedmedia-ogg-short-audio": "File audio Ogg $1, $2",
+ "timedmedia-ogg-short-video": "File video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "File multimedial Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "File audio Ogg $1, durata $2, $3",
+ "timedmedia-ogg-long-video": "File video Ogg $1, durata $2, dimensioni $4×$5 pixel, $3",
+ "timedmedia-ogg-long-multiplexed": "File audio/video multiplexed Ogg $1, durata $2, dimensioni $4×$5 pixel, conplessivamente $3",
+ "timedmedia-ogg-long-general": "File multimedial Ogg, durata $2, $3",
+ "timedmedia-ogg-long-error": "File ogg mìa valido: $1",
+ "timedmedia-webm-short-video": "File video WebM $1, $2",
+ "timedmedia-webm-long-video": "File audio/video WebM $1, durata $2, dimension $4×$5 pixel, conplesivamente $3",
+ "timedmedia-mp4-short-video": "File video MP4 $1, $2",
+ "timedmedia-mp4-long-video": "File audio/video MP4 $1, durata $2, dimension $4×$5 pixel, conplesivamente $3",
+ "timedmedia-no-player-js": "El to browser el gà JavaScript destacà, opure no'l gà nissun riprodutor suportà.<br />\nTe pol <a href=\"$1\">descargar el file multimediale</a> o <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">un riprodutor</a> par farlo 'ndar sul to browser.",
+ "timedmedia-more": "Altro...",
+ "timedmedia-dismiss": "Sara",
+ "timedmedia-download": "Descarga el file",
+ "timedmedia-play-media": "Riproduxi el file multimediałe",
+ "timedmedia-desc-link": "Informazion su sto file",
+ "timedmedia-oggThumb-version": "Par OggHandler ghe vole oggThumb version $1 o sucessiva.",
+ "timedmedia-oggThumb-failed": "oggThumb no'l xe stà bon de crear la miniadura.",
+ "timedmedia-status-header": "Stato transcodifega",
+ "timedmedia-update-status": "Axorna stato transcodifega",
+ "timedmedia-status": "Stato",
+ "timedmedia-status-unknown": "Stato sconosùo",
+ "timedmedia-transcodeinfo": "Descrision derivà dal Transcodexe",
+ "timedmedia-actions": "Asion",
+ "timedmedia-direct-link": "Descarga derivà",
+ "timedmedia-not-ready": "Nó pronto",
+ "timedmedia-completed-on": "Transodifega conpletà $1",
+ "timedmedia-error-on": "Eror inte ła transcodifega so $1.",
+ "timedmedia-started-transcode": "Transcodifega tacà $1 fa. $2",
+ "timedmedia-percent-done": "$1% sirca conpletà",
+ "timedmedia-in-job-queue": "Xontà a ła coa de laoro $1 fa",
+ "timedmedia-unknown-target-size": "Dimension de destinasion sconosùa, $1 codifegà",
+ "timedmedia-days": "{{PLURAL:$1|1 xorno|$1 xorni}}",
+ "timedmedia-hours": "{{PLURAL:$1|1 ora|$1 ore}}",
+ "timedmedia-minutes": "{{PLURAL:$1|1 minuto|$1 minuti}}",
+ "timedmedia-seconds": "{{PLURAL:$1|1 secondo|$1 secondi}}",
+ "timedmedia-reset": "Rexeta transcodifega",
+ "timedmedia-reset-confirm": "Resetando sta transcodifica tuti i file esistenti (se presenti) i sarà scancelà e la transcodifica la sarà de novo zontà a la coa de laoro. Ghe vorà un po' de tenpo par rifar la transcodifica. <br /><br />\nVuto 'ndar vanti?",
+ "timedmedia-reset-error": "Eror inte'l resetajo de ła transcodifega.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Fonte $1",
+ "timedmedia-source-file-desc": "File orixenałe $1, $2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "File originale $1 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "Video Ogg a basa larghesa de banda (160P)",
+ "timedmedia-derivative-desc-360p.ogv": "Video Ogg trasmetibiłe in streaming via Web (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Video Ogg trasmetibiłe in streaming via Web (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "Video Ogg descargabiłe in alta cuałità (720P)",
+ "timedmedia-derivative-desc-160p.webm": "WebM trasmetibiłe in streaming via Web (160P)",
+ "timedmedia-derivative-desc-360p.webm": "WebM trasmetibiłe in streaming via Web (360P)",
+ "timedmedia-derivative-desc-480p.webm": "WebM trasmetibiłe in streaming via Web (480P)",
+ "timedmedia-derivative-desc-720p.webm": "WebM descargabiłe in alta cuałità (720P)",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 par dispoxitivi conpatibiłi (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 trasmetibiłe in streaming via Web (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 in cuałità HD (720P)",
+ "timedmedia-subtitle-new": "Crear na nova tradusion o canbiar una de chełe che ghe xe xà",
+ "timedmedia-subtitle-new-desc": "Siegli la lengua e struca el boton '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Và",
+ "timedmedia-subtitle-language": "$1 ($2) sototitołi",
+ "timedmedia-subtitle-no-video": "Nó ghe xe nisun video asocià a l'atuałe pàjina de i sototitołi",
+ "timedmedia-subtitle-no-subtitles": "Nó ghe xe al momento sototitołi in $1 par sto video, xe posibiłe [{{fullurl:{{FULLPAGENAME}}|action=edit}} canbiar sta pàjina] par xontarli",
+ "timedmedia-subtitle-remote": "I sototitołi par sto file i se cata so $1",
+ "timedmedia-subtitle-remote-link": "Te poi vardar ła [$1 pàjina de descrision] par sto file so $2",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "{{PLURAL:$1|$1 video}}",
+ "timedmedia-ogg-videos": "{{PLURAL:$1|$1 video Ogg}}",
+ "timedmedia-webm-videos": "{{PLURAL:$1|$1 video WebM}}",
+ "timedmedia-derivative-state-transcodes": "{{PLURAL:$1|$1 transcodifega|$1 transcodifeghe}}",
+ "timedmedia-derivative-state-active": "{{PLURAL:$1|$1 transcodifega|$1 transcodifeghe}} in execusion",
+ "timedmedia-derivative-state-queued": "{{PLURAL:$1|$1 transcodifega|$1 transcodifeghe}} in coa",
+ "timedmedia-derivative-state-failed": "{{PLURAL:$1|$1 transcodifega nó riusia|$1 transcodifeghe nó riusie}}",
+ "timedmedia-file": "File",
+ "right-transcode-reset": "Reinposta i video difetoxi o transcodifegai cusì che i posa esar incluxi de novo in coa de laoro.",
+ "right-transcode-status": "Vixuałixa [[Special:TimedMediaHandler|informasion so l'atuałe atività de transcodifega]]",
+ "action-transcode-status": "mostrar l'atuałe stato de ła transcodifega"
+}
diff --git a/extensions/TimedMediaHandler/i18n/vep.json b/extensions/TimedMediaHandler/i18n/vep.json
new file mode 100644
index 00000000..9046204e
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/vep.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Игорь Бродский"
+ ]
+ },
+ "timedmedia-more": "Enamba...",
+ "timedmedia-dismiss": "Peitta",
+ "timedmedia-download": "Jügutoitta fail",
+ "timedmedia-desc-link": "Informacii neciš failas"
+}
diff --git a/extensions/TimedMediaHandler/i18n/vi.json b/extensions/TimedMediaHandler/i18n/vi.json
new file mode 100644
index 00000000..63187717
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/vi.json
@@ -0,0 +1,130 @@
+{
+ "@metadata": {
+ "authors": [
+ "Minh Nguyen",
+ "Vinhtantran",
+ "පසිඳු කාවින්ද",
+ "Trần Nguyễn Minh Huy",
+ "Max20091"
+ ]
+ },
+ "timedmedia-desc": "Bộ trình bày các tập tin âm thanh, video, và phụ đề hỗ trợ WebM, Ogg Theora, Vorbis, và srt",
+ "timedmedia-ogg-short-audio": "Tập tin âm thanh Ogg $1, $2",
+ "timedmedia-ogg-short-video": "tập tin video Ogg $1, $2",
+ "timedmedia-ogg-short-general": "tập tin Ogg $1, $2",
+ "timedmedia-ogg-long-audio": "tập tin âm thanh Ogg $1, dài $2, $3",
+ "timedmedia-ogg-long-video": "tập tin video Ogg $1, dài $2, $4×$5 điểm ảnh, $3",
+ "timedmedia-ogg-long-multiplexed": "tập tin Ogg có âm thanh và video ghép kênh, $1, dài $2, $4×$5 điểm ảnh, $3 tất cả",
+ "timedmedia-ogg-long-general": "tập tin phương tiện Ogg, dài $2, $3",
+ "timedmedia-ogg-long-error": "Tập tin Ogg có lỗi: $1",
+ "timedmedia-ogg-long-no-streams": "Tập tin phương tiện Ogg. Chú ý: Không có công nhận codec nào trong tập tin này.",
+ "timedmedia-webm-short-video": "tập tin video WebM $1, $2",
+ "timedmedia-webm-long-video": "tập tin WebM có âm thanh và video ghép kênh, $1, dài $2, $4×$5 điểm ảnh, $3 tất cả",
+ "timedmedia-flac-short-audio": "tập tin âm thanh FLAC, $1",
+ "timedmedia-flac-long-audio": "tập tin âm thanh FLAC, dài $1, $2 tất cả",
+ "timedmedia-wav-short-audio": "tập tin âm thanh WAV, $1",
+ "timedmedia-wav-long-audio": "tập tin âm thanh WAV, dài $1, $2 tất cả",
+ "timedmedia-wav-pcm-required": "Bạn chỉ có thể tải lên các tập tin WAV PCM (Pulse Code Modulation).",
+ "timedmedia-mp4-short-video": "tập tin video MP4 $1, $2",
+ "timedmedia-mp4-long-video": "tập tin âm thanh/video MP4, $1, dài $2, $4×$5 điểm ảnh, $3 tất cả",
+ "timedmedia-no-player-js": "Rất tiếc, hoặc JavaScript bị tắt trong trình duyệt của bạn hoặc trình duyệt không có trình chơi nào được hỗ trợ.<br />\nBạn có thể <a href=\"$1\">tải về đoạn âm hoặc đoạn video</a> hay <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download?uselang=vi\">tải về một trình chơi</a> để chơi đoạn âm hoặc đoạn video trong trình duyệt.",
+ "timedmedia-more": "Thêm nữa…",
+ "timedmedia-dismiss": "Đóng",
+ "timedmedia-download": "Tải tập tin xuống",
+ "timedmedia-play-media": "Chơi phương tiện",
+ "timedmedia-desc-link": "Chi tiết của tập tin này",
+ "timedmedia-oggThumb-version": "OggHandler cần oggThumb, phiên bản $1 trở lên.",
+ "timedmedia-oggThumb-failed": "oggThumb bị thất bại trong việc tạo hình thu nhỏ.",
+ "timedmedia-status-header": "Trạng thái chuyển mã",
+ "timedmedia-update-status": "Cập nhật trạng thái chuyển mã",
+ "timedmedia-status": "Trạng thái",
+ "timedmedia-status-unknown": "Trạng thái không rõ",
+ "timedmedia-transcodebitrate": "Tốc độ bit",
+ "timedmedia-transcodeduration": "Thời gian mã hóa",
+ "timedmedia-transcodeinfo": "Định dạng",
+ "timedmedia-actions": "Tác vụ",
+ "timedmedia-direct-link": "Tải về",
+ "timedmedia-not-ready": "Chưa sẵn",
+ "timedmedia-completed-on": "Hoàn tất vào $1",
+ "timedmedia-error-on": "Lỗi vào $1",
+ "timedmedia-started-transcode": "Bắt đầu cách đây $1. $2",
+ "timedmedia-percent-done": "Hoàn tất khoảng $1%",
+ "timedmedia-in-job-queue": "Đã thêm vào hàng đợi việc cách đây $1",
+ "timedmedia-unknown-target-size": "Tập tin đích có kích thước không rõ, đã chuyển mã $1",
+ "timedmedia-days": "$1 ngày",
+ "timedmedia-hours": "$1 giờ",
+ "timedmedia-minutes": "$1 phút",
+ "timedmedia-seconds": "$1 giây",
+ "timedmedia-reset": "Đặt lại chuyển mã",
+ "timedmedia-reset-confirm": "Việc đặt lại chuyển mã sẽ xóa tập tin nào hiện có, nếu có, và sẽ lại thêm việc chuyển mã vào hàng đợi việc. Việc chuyển mã lại sẽ mất một chút thì giờ.<br /><br />\nBạn có chắc chắn muốn tiếp tục?",
+ "timedmedia-reset-error": "Lỗi khi đặt lại việc chuyển mã.",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "Tập tin $1 gốc",
+ "timedmedia-source-file-desc": "tập tin $1 gốc, $2×$3 ($4)",
+ "timedmedia-source-audio-file-desc": "Tập tin $1 gốc ($2)",
+ "timedmedia-derivative-160p.ogv": "Ogg 160p",
+ "timedmedia-derivative-desc-160p.ogv": "Video Ogg băng thông thấp (160p)",
+ "timedmedia-derivative-desc-240p.ogv": "Video Ogg có thể truyền dòng trên Web (240p)",
+ "timedmedia-derivative-360p.ogv": "Ogg 360p",
+ "timedmedia-derivative-desc-360p.ogv": "Video Ogg có thể truyền dòng trên Web (360p)",
+ "timedmedia-derivative-480p.ogv": "Ogg 480p",
+ "timedmedia-derivative-desc-480p.ogv": "Video Ogg có thể truyền dòng trên Web (480p)",
+ "timedmedia-derivative-720p.ogv": "Ogg 720p",
+ "timedmedia-derivative-desc-720p.ogv": "Video Ogg chất lượng cao có thể tải về (720p)",
+ "timedmedia-derivative-1080p.ogv": "Ogg 1080p",
+ "timedmedia-derivative-desc-1080p.ogv": "Video Ogg HD đầy đủ có thể tải về (1080p)",
+ "timedmedia-derivative-160p.webm": "WebM 160p",
+ "timedmedia-derivative-desc-160p.webm": "WebM có thể truyền dòng trên Web (160p)",
+ "timedmedia-derivative-360p.webm": "WebM 360p",
+ "timedmedia-derivative-desc-360p.webm": "WebM có thể truyền dòng trên Web (360p)",
+ "timedmedia-derivative-480p.webm": "WebM 480p",
+ "timedmedia-derivative-desc-480p.webm": "WebM có thể truyền dòng trên Web (480p)",
+ "timedmedia-derivative-720p.webm": "WebM 720p",
+ "timedmedia-derivative-desc-720p.webm": "WebM chất lượng cao có thể tải về (720p)",
+ "timedmedia-derivative-1080p.webm": "WebM 1080p",
+ "timedmedia-derivative-desc-1080p.webm": "WebM HD đầy đủ có thể tải về (1080p)",
+ "timedmedia-derivative-desc-2160p.webm": "WebM 4K đầy đủ có thể tải về (2160p)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "WebM VP9 có thể truyền dòng trên Web (360p)",
+ "timedmedia-derivative-desc-480p.vp9.webm": "WebM VP9 có thể truyền dòng trên Web (480p)",
+ "timedmedia-derivative-desc-720p.vp9.webm": "WebM HD có thể truyền dòng trên Web (720p)",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "WebM VP9 HD đầy đủ có thể truyền dòng (1080p)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "WebM VP9 4K đầy đủ có thể truyền dòng (2160p)",
+ "timedmedia-derivative-320p.mp4": "H.264 320p",
+ "timedmedia-derivative-desc-320p.mp4": "MP4 thích hợp với thiết bị (320p)",
+ "timedmedia-derivative-480p.mp4": "H.264 480p",
+ "timedmedia-derivative-desc-480p.mp4": "MP4 có thể truyền dòng trên Web (480p)",
+ "timedmedia-derivative-720p.mp4": "H.264 720p",
+ "timedmedia-derivative-desc-720p.mp4": "MP4 chất lượng HD (720p)",
+ "timedmedia-derivative-1080p.mp4": "H.264 1080p",
+ "timedmedia-derivative-desc-1080p.mp4": "MP4 HD đầy đủ (1080p)",
+ "timedmedia-derivative-desc-2160p.mp4": "MP4 4K đầy đủ (2160p)",
+ "timedmedia-subtitle-new": "Tạo bản dịch mới hoặc sửa đổi bản dịch đã tồn tại",
+ "timedmedia-subtitle-new-desc": "Chọn ngôn ngữ và bấm nút '''{{int:Timedmedia-subtitle-new-go}}'''",
+ "timedmedia-subtitle-new-go": "Tạo",
+ "timedmedia-subtitle-language": "Tiểu đề $1 ($2)",
+ "timedmedia-subtitle-no-video": "Không có video nào ứng với trang tiểu đề này",
+ "timedmedia-subtitle-no-subtitles": "Hiện không có tiểu đề nào cho video này bằng $1. Bạn có thể [{{fullurl:{{FULLPAGENAME}}|action=edit}} sửa đổi trang này] để thêm tiểu đề.",
+ "timedmedia-subtitle-remote": "Văn bản đồng bộ của tập tin này được cung cấp từ $1",
+ "timedmedia-subtitle-remote-link": "Bạn có thể [$1 xem trang miêu tả] tập tin này trên $2",
+ "timedmediahandler": "Bộ xử lý phương tiện đồng bộ",
+ "timedmedia-videos": "$1 video",
+ "timedmedia-ogg-videos": "$1 video Ogg",
+ "timedmedia-webm-videos": "$1 video WebM",
+ "timedmedia-derivative-state-transcodes": "$1 tập tin chuyển mã",
+ "timedmedia-derivative-state-active": "$1 tập tin đang chuyển mã",
+ "timedmedia-derivative-state-queued": "$1 tập tin chuyển mã trong hàng đợi",
+ "timedmedia-derivative-state-failed": "$1 tập tin chuyển mã thất bại",
+ "timedmedia-file": "Tập tin",
+ "timedmedia-audios": "$1 tập tin âm thanh",
+ "timedmedia-ogg-audios": "$1 tập tin âm thanh Ogg",
+ "timedmedia-flac-audios": "$1 tập tin âm thanh FLAC",
+ "timedmedia-wav-audios": "$1 tập tin âm thanh WAV",
+ "right-transcode-reset": "Đặt lại các video hỏng hoặc đã chuyển mã để chèn chúng nó lại vào hàng đợi việc.",
+ "right-transcode-status": "Xem [[Special:TimedMediaHandler|thông tin về hoạt động chuyển mã đang xảy ra]]",
+ "action-transcode-status": "xem trạng thái chuyển mã hiện tại",
+ "orphanedtimedtext": "Các trang TimedText mồ côi",
+ "orphanedtimedtext-summary": "Danh sách trang [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] không có tập tin tương ứng.",
+ "orphanedtimedtext-unsupported": "Trang đặc biệt này chỉ được hỗ trợ trên cơ sở dữ liệu MySQL.",
+ "orphanedtimedtext-notimedtext": "TimedText không được kích hoạt trên wiki này.",
+ "apihelp-transcodereset-param-title": "Tên tập tin phương tiện."
+}
diff --git a/extensions/TimedMediaHandler/i18n/vo.json b/extensions/TimedMediaHandler/i18n/vo.json
new file mode 100644
index 00000000..b20db88e
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/vo.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "Malafaya",
+ "Smeira"
+ ]
+ },
+ "timedmedia-more": "Pluikos...",
+ "timedmedia-dismiss": "Färmükön",
+ "timedmedia-download": "Donükön ragivi",
+ "timedmedia-desc-link": "Tefü ragiv at",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-audio-file-desc": "Ragiv: $1 rigik ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/vro.json b/extensions/TimedMediaHandler/i18n/vro.json
new file mode 100644
index 00000000..2222475c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/vro.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Võrok"
+ ]
+ },
+ "timedmedia-no-player-js": "Kah'os om suq võrgokaejan JavaScript keelet vai olõ-õi sul tarvilist näütämistarkvarra.<br />\nSaat <a href=\"$1\">lõigu alla laatiq</a> vai <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">laatiq alla tarkvara</a>, minka lõiku võrgokaejan näüdädäq.",
+ "timedmedia-source-file": "Läteq $1",
+ "timedmedia-source-audio-file-desc": "Alguperäne $1-fail ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/wa.json b/extensions/TimedMediaHandler/i18n/wa.json
new file mode 100644
index 00000000..81ee357d
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/wa.json
@@ -0,0 +1,4 @@
+{
+ "@metadata": [],
+ "timedmedia-dismiss": "Clôre"
+}
diff --git a/extensions/TimedMediaHandler/i18n/war.json b/extensions/TimedMediaHandler/i18n/war.json
new file mode 100644
index 00000000..2b28e939
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/war.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "JinJian"
+ ]
+ },
+ "timedmedia-source-file": "$1 tinitikangan",
+ "timedmedia-source-audio-file-desc": "Orihinal $1 file ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/wuu.json b/extensions/TimedMediaHandler/i18n/wuu.json
new file mode 100644
index 00000000..f61881e2
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/wuu.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Poiuyt"
+ ]
+ },
+ "timedmedia-no-player-js": "对弗起,你个浏览器禁用仔JavaScript或呒不任何支持个播放器。<br />\n你可以<a href=\"$1\">下载箇只片段</a>或<a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">下载一只播放器</a>好勒浏览器里播放片段。",
+ "timedmedia-source-file": "$1原始文件",
+ "timedmedia-source-audio-file-desc": "原始$1文件 ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/xmf.json b/extensions/TimedMediaHandler/i18n/xmf.json
new file mode 100644
index 00000000..208dab64
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/xmf.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Silovan"
+ ]
+ },
+ "timedmedia-no-player-js": "თქვან ბრაუზერს გოთიშილ რე JavaScript ვარდა ვა რე ოხვილური პროგრამა.<br />\nთქვა შეგილებუნა <a href=\"$1\">გეგნოჭარათ კლიპი</a> ვარდა <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">გეგნოჭარათ პროგრამა</a> კლიპიშ ბრაუზერს ორჩქილეთ/ოძირაფალო.",
+ "timedmedia-source-file": "წყუ $1",
+ "timedmedia-source-audio-file-desc": "ორიგინალი $1 ფაილი ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/yi.json b/extensions/TimedMediaHandler/i18n/yi.json
new file mode 100644
index 00000000..693e8639
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/yi.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "פוילישער",
+ "පසිඳු කාවින්ද"
+ ]
+ },
+ "timedmedia-no-player-js": "אנטשולדיגט, אײַער בלעטערער אדער האט JavaScript אומאקטיווירט אדער האט נישט קיין געשטיצטן שפילער.<br />\nאיר קענט <a href=\"$1\">אראפלאדן דעם פילמקליפ</a> אדער <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">אראפלאדן א שפילער</a> צו שפילן דעם קליפ אין אײַער בלעטערער.",
+ "timedmedia-dismiss": "שליסן",
+ "timedmedia-download": "אראָפלאָדן טעקע",
+ "timedmedia-status": "סטאַטוס",
+ "timedmedia-source-file": "$1 מקור",
+ "timedmedia-source-audio-file-desc": "אריגינעלע $1 טעקע ($2)",
+ "timedmedia-file": "טעקע"
+}
diff --git a/extensions/TimedMediaHandler/i18n/yue.json b/extensions/TimedMediaHandler/i18n/yue.json
new file mode 100644
index 00000000..9cb1e97c
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/yue.json
@@ -0,0 +1,24 @@
+{
+ "@metadata": {
+ "authors": [
+ "Yueman",
+ "CRCHF"
+ ]
+ },
+ "timedmedia-desc": "Ogg Theora 同 Vorbis 檔案嘅處理器,加埋 JavaScript 播放器",
+ "timedmedia-ogg-short-audio": "Ogg $1 聲檔,$2",
+ "timedmedia-ogg-short-video": "Ogg $1 畫檔,$2",
+ "timedmedia-ogg-short-general": "Ogg $1 媒檔,$2",
+ "timedmedia-ogg-long-audio": "Ogg $1 聲檔,長度$2,$3",
+ "timedmedia-ogg-long-video": "Ogg $1 畫檔,長度$2,$4×$5像素,$3",
+ "timedmedia-ogg-long-multiplexed": "Ogg 多工聲/畫檔,$1,長度$2,$4×$5像素,總共$3",
+ "timedmedia-ogg-long-general": "Ogg 媒檔,長度$2,$3",
+ "timedmedia-ogg-long-error": "無效嘅ogg檔: $1",
+ "timedmedia-no-player-js": "對唔住,你個瀏覽器無開到 JavaScript 或者無支援嘅播放程式。<br />\n你可以 <a href=\"$1\">下載條片</a> 或者 <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">下載播放程式</a> 等你個瀏覽器都可以播。",
+ "timedmedia-more": "更多...",
+ "timedmedia-dismiss": "閂",
+ "timedmedia-download": "下載檔案",
+ "timedmedia-desc-link": "關於呢個檔案",
+ "timedmedia-source-file": "$1 來源檔",
+ "timedmedia-source-audio-file-desc": "原本 $1 檔案 ($2)"
+}
diff --git a/extensions/TimedMediaHandler/i18n/zh-hans.json b/extensions/TimedMediaHandler/i18n/zh-hans.json
new file mode 100644
index 00000000..cd324e67
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/zh-hans.json
@@ -0,0 +1,137 @@
+{
+ "@metadata": {
+ "authors": [
+ "Byfserag",
+ "Gaoxuewei",
+ "Hzy980512",
+ "Liangent",
+ "Liuxinyu970226",
+ "Shizhao",
+ "Xiaomingyan",
+ "Yfdyh000",
+ "乌拉跨氪"
+ ]
+ },
+ "extensionname-timedmedia": "TimedMediaHandler",
+ "timedmedia-desc": "音频、视频和字幕的处理程序,支持WebM,Ogg Theora、Vorbis,srt格式",
+ "timedmedia-ogg-short-audio": "Ogg $1声音文件,$2",
+ "timedmedia-ogg-short-video": "Ogg $1视频文件,$2",
+ "timedmedia-ogg-short-general": "Ogg $1媒体文件,$2",
+ "timedmedia-ogg-long-audio": "Ogg $1声音文件,长度$2,$3",
+ "timedmedia-ogg-long-video": "Ogg $1视频文件,长度$2,$4 × $5像素,$3",
+ "timedmedia-ogg-long-multiplexed": "Ogg多工声音/视频文件,$1,长度$2,$4 × $5像素,共$3",
+ "timedmedia-ogg-long-general": "Ogg媒体文件,长度$2,$3",
+ "timedmedia-ogg-long-error": "无效的ogg文件:$1",
+ "timedmedia-ogg-long-no-streams": "Ogg媒体文件。警告:没有认可用于此文件的编解码器。",
+ "timedmedia-webm-short-video": "WebM $1视频文件,$2",
+ "timedmedia-webm-long-video": "WebM音频/视频文件,$1,长度$2,$4 × $5像素,共$3",
+ "timedmedia-flac-short-audio": "FLAC音频文件,$1",
+ "timedmedia-flac-long-audio": "FLAC音频文件,长度$1,码率$2",
+ "timedmedia-wav-short-audio": "WAV音频文件,$1",
+ "timedmedia-wav-long-audio": "WAV音频文件,总共长$1,码率$2",
+ "timedmedia-wav-pcm-required": "您只能上传脉冲编码调制(PCM)WAV。",
+ "timedmedia-mp4-short-video": "MP4 $1视频文件,$2",
+ "timedmedia-mp4-long-video": "MP4音频/视频文件,$1,长度$2,$4 × $5像素,$3 overall",
+ "timedmedia-no-player-js": "抱歉,您的浏览器禁用了JavaScript或没有任何可支持的播放器。<br />\n您可以<a href=\"$1\">下载这个片段</a>或<a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">下载一个播放器</a>以在浏览器中播放片段。",
+ "timedmedia-more": "更多...",
+ "timedmedia-dismiss": "关闭",
+ "timedmedia-download": "下载文件",
+ "timedmedia-play-media": "播放媒体",
+ "timedmedia-desc-link": "关于该文件",
+ "timedmedia-oggThumb-version": "OggHandler需要oggThumb $1或者之后的版本。",
+ "timedmedia-oggThumb-failed": "oggThumb未能创建缩略图。",
+ "timedmedia-status-header": "转码状态",
+ "timedmedia-update-status": "更新转码状态",
+ "timedmedia-status": "状态",
+ "timedmedia-status-unknown": "未知状态",
+ "timedmedia-transcodebitrate": "比特率",
+ "timedmedia-transcodeduration": "编码时间",
+ "timedmedia-transcodeinfo": "格式",
+ "timedmedia-actions": "操作",
+ "timedmedia-direct-link": "下载",
+ "timedmedia-not-ready": "未就绪",
+ "timedmedia-completed-on": "已完成$1",
+ "timedmedia-error-on": "于$1错误",
+ "timedmedia-started-transcode": "于$1前开始。$2",
+ "timedmedia-percent-done": "大约$1%已完成",
+ "timedmedia-in-job-queue": "添加到工作队列在$1前",
+ "timedmedia-unknown-target-size": "未知目标大小,$1已编码",
+ "timedmedia-days": "$1天",
+ "timedmedia-hours": "{{PLURAL:$1|$1小时}}",
+ "timedmedia-minutes": "$1分",
+ "timedmedia-seconds": "$1秒",
+ "timedmedia-reset": "重置转码",
+ "timedmedia-reset-confirm": "重置转码将会尽可能移除所有现有文件,并将其重新加入到转码工作队列。这将需要一些时间来重新转码。<br /><br />\n您确定要继续吗?",
+ "timedmedia-reset-error": "重置转码工作时发生错误。",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1原始文件",
+ "timedmedia-source-file-desc": "原始$1文件,$2 × $3($4)",
+ "timedmedia-source-audio-file-desc": "原始$1文件 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "低带宽Ogg视频(160P)",
+ "timedmedia-derivative-desc-240p.ogv": "Web流媒体Ogg视频(240P)",
+ "timedmedia-derivative-desc-360p.ogv": "Web流媒体Ogg视频(360P)",
+ "timedmedia-derivative-desc-480p.ogv": "Web流媒体Ogg视频(480P)",
+ "timedmedia-derivative-desc-720p.ogv": "高清可下载Ogg视频(720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "全高清可下载 Ogg 视频 (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "Web流媒体WebM(160P)",
+ "timedmedia-derivative-desc-360p.webm": "Web流媒体WebM(360P)",
+ "timedmedia-derivative-desc-480p.webm": "Web流媒体WebM(480P)",
+ "timedmedia-derivative-desc-720p.webm": "高清可下载WebM视频(720P)",
+ "timedmedia-derivative-desc-1080p.webm": "全高清可下载 WebM (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "全高清可下载 WebM (2160P)",
+ "timedmedia-derivative-360p.vp9.webm": "VP9 360P",
+ "timedmedia-derivative-desc-360p.vp9.webm": "Web流媒体WebM VP9(360P)",
+ "timedmedia-derivative-480p.vp9.webm": "VP9 480P",
+ "timedmedia-derivative-desc-480p.vp9.webm": "Web流媒体WebM VP9(480P)",
+ "timedmedia-derivative-720p.vp9.webm": "VP9 720P",
+ "timedmedia-derivative-desc-720p.vp9.webm": "高清流媒体WebM VP9(720P)",
+ "timedmedia-derivative-1080p.vp9.webm": "VP9 1080P",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "全高清流媒体WebM VP9(1080P)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "全高清流媒体WebM VP9(2160P)",
+ "timedmedia-derivative-desc-320p.mp4": "设备友好MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "网页流媒体MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "高清MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "全高清画质 MP4 (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "全高清画质 MP4 (2160P)",
+ "timedmedia-derivative-ogg": "Ogg Vorbis",
+ "timedmedia-derivative-desc-ogg": "Ogg Vorbis",
+ "timedmedia-derivative-desc-mp3": "MP3",
+ "timedmedia-subtitle-new": "创建新翻译或编辑现有翻译",
+ "timedmedia-subtitle-new-desc": "选择语言然后按'''{{int:Timedmedia-subtitle-new-go}}'''按钮",
+ "timedmedia-subtitle-new-go": "提交",
+ "timedmedia-subtitle-language": "$1($2)字幕",
+ "timedmedia-subtitle-no-video": "当前字幕页面没有关联的视频",
+ "timedmedia-subtitle-no-subtitles": "当前没有这个视频的$1字幕,您可以[{{fullurl:{{FULLPAGENAME}}|action=edit}} 编辑这个页面]以添加",
+ "timedmedia-subtitle-remote": "本文件的字幕文件位于$1",
+ "timedmedia-subtitle-remote-link": "你可以在$2查看该文件的[$1 说明页面]",
+ "timedmediahandler": "定时媒体处理程序",
+ "timedmedia-videos": "$1个视频",
+ "timedmedia-ogg-videos": "$1个Ogg视频",
+ "timedmedia-webm-videos": "$1个WebM视频",
+ "timedmedia-derivative-state-transcodes": "$1次转码",
+ "timedmedia-derivative-state-active": "$1个正在运行的转码任务",
+ "timedmedia-derivative-state-queued": "$1个队列中的转码任务",
+ "timedmedia-derivative-state-failed": "$1次转码失败",
+ "timedmedia-file": "文件",
+ "timedmedia-audios": "$1个音频文件",
+ "timedmedia-ogg-audios": "$1个Ogg音频文件",
+ "timedmedia-flac-audios": "$1个FLAC音频文件",
+ "timedmedia-wav-audios": "$1个WAV音频文件",
+ "right-transcode-reset": "重置已失败或已转码的视频将其再次加入到作业队列中。",
+ "right-transcode-status": "查看[[Special:TimedMediaHandler|当前转码活动的信息]]",
+ "action-transcode-status": "查看当前的转码状态",
+ "orphanedtimedtext": "孤立的TimedText页面",
+ "orphanedtimedtext-summary": "没有对应文件的[[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]]页面的列表。",
+ "orphanedtimedtext-unsupported": "此特殊页面只支持MySQL数据库。",
+ "orphanedtimedtext-notimedtext": "TimedText在此wiki未启用。",
+ "apihelp-query+transcodestatus-description": "获取指定文件页面的转码状态。",
+ "apihelp-query+transcodestatus-example-1": "获得[[:File:Clip.webm]]的译码状态",
+ "apihelp-query+videoinfo-description": "扩展图像信息以包含视频源(图像来源)信息",
+ "apihelp-query+videoinfo-param-prop": "要获取的视频信息:\n;timestamp:为上传版本添加时间戳。\n;user:添加上传视频版本的用户。\n;userid:添加上传视频版本的用户ID。\n;comment:对版本的注释。\n;parsedcomment:解析对版本的注释。\n;canonicaltitle:添加视频文件的规范标题。\n;url:提供至视频的URL及其说明页面。\n;size:添加视频大小(字节)、高度和宽度。如有需要会添加页面计数和持续时间。\n;dimensions:大小别名。\n;sha1:为视频添加SHA-1哈希值。\n;mime:添加视频的MIME类型。\n;thumbmime:添加视频缩略图的MIME类型(需要url和参数$1urlwidth)。\n;mediatype:添加视频媒体类型。\n;metadata:列举视频版本的EXIF元数据。\n;commonmetadata:列举特定文件格式的视频版本的元数据。\n;extmetadata:列举格式化元数据\n;archivename:为非最新版本添加存档版本的文件名。\n;bitdepth:添加版本的位深度。\n;uploadwarning:被[[Special:Upload]]页面使用以获取有关现有文件的信息。不适用于MediaWiki核心以外代码。\n;derivatives:添加不同格式的阵列与音频或视频文件的可用高质量版本。",
+ "apihelp-query+videoinfo-example-1": "检索有关[[:File:Folgers.ogv]]的信息",
+ "apihelp-transcodereset-description": "具有“transcode-reset”权限的用户可以重置和重新运行转码任务。",
+ "apihelp-transcodereset-param-title": "媒体文件标题。",
+ "apihelp-transcodereset-param-transcodekey": "您希望重置的转码关键字。从[[Special:ApiHelp/query+transcodestatus|action=query&prop=transcodestatus]]获取。",
+ "apihelp-transcodereset-example-1": "重置[[:File:Clip.webm]]的所有译码",
+ "apihelp-transcodereset-example-2": "重置[[:File:Clip.webm]]的“360_560kbs.webm”转码关键字"
+}
diff --git a/extensions/TimedMediaHandler/i18n/zh-hant.json b/extensions/TimedMediaHandler/i18n/zh-hant.json
new file mode 100644
index 00000000..c80a3438
--- /dev/null
+++ b/extensions/TimedMediaHandler/i18n/zh-hant.json
@@ -0,0 +1,119 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gaoxuewei",
+ "Justincheng12345",
+ "Liuxinyu970226",
+ "Mark85296341",
+ "Simon Shek",
+ "LNDDYL",
+ "Cwlin0416"
+ ]
+ },
+ "timedmedia-desc": "音訊、影片與字幕處理程式,支援的格式包含 WebM,Ogg Theora、Vorbis,srt",
+ "timedmedia-ogg-short-audio": "Ogg $1 聲音檔案,$2",
+ "timedmedia-ogg-short-video": "Ogg $1 影片檔,$2",
+ "timedmedia-ogg-short-general": "Ogg $1 媒體檔案,$2",
+ "timedmedia-ogg-long-audio": "Ogg $1 聲音檔案,長度 $2,$3",
+ "timedmedia-ogg-long-video": "Ogg $1 影片檔案,長度 $2,$4 × $5 像素,$3",
+ "timedmedia-ogg-long-multiplexed": "Ogg 多工音訊/影片檔案,$1,長度 $2,$4 × $5 畫素,共 $3",
+ "timedmedia-ogg-long-general": "Ogg 媒體檔案,長度 $2,$3",
+ "timedmedia-ogg-long-error": "無效的 Ogg 檔案:$1",
+ "timedmedia-ogg-long-no-streams": "Ogg 媒體檔案。 警告:無法辨識此檔案中使用的編碼。",
+ "timedmedia-webm-short-video": "WebM $1 影片檔,$2",
+ "timedmedia-webm-long-video": "WebM 音訊/影片檔案,$1,長度 $2,$4 × $5 畫素,共 $3",
+ "timedmedia-flac-short-audio": "FLAC 音訊檔案,$1",
+ "timedmedia-flac-long-audio": "FLAC 音頻檔案,長度 $1,共 $2",
+ "timedmedia-wav-short-audio": "WAV 音訊檔案,$1",
+ "timedmedia-wav-long-audio": "WAV 音訊檔案,長度 $1,共 $2",
+ "timedmedia-wav-pcm-required": "您僅可上傳 PCM (Pulse Code Modulation) WAV。",
+ "timedmedia-mp4-short-video": "MP4 $1 影片檔,$2",
+ "timedmedia-mp4-long-video": "MP4 音訊/影片檔案,$1,長度 $2,$4 × $5 畫素,共 $3",
+ "timedmedia-no-player-js": "抱歉,您的瀏覽器未開啟 JavaScript 或沒有支援的播放程式。<br />\n您可 <a href=\"$1\">下載該片段</a> 或 <a href=\"https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:TimedMediaHandler/Client_download\">下載播放器</a> 以在您的瀏覽器中播放。",
+ "timedmedia-more": "更多...",
+ "timedmedia-dismiss": "關閉",
+ "timedmedia-download": "下載檔案",
+ "timedmedia-play-media": "播放媒體",
+ "timedmedia-desc-link": "關於這個檔案",
+ "timedmedia-oggThumb-version": "OggHandler 需要使用 oggThumb 版本 $1 或更新的版本。",
+ "timedmedia-oggThumb-failed": "oggThumb 建立縮圖失敗。",
+ "timedmedia-status-header": "轉碼狀態",
+ "timedmedia-update-status": "更新轉碼狀態",
+ "timedmedia-status": "狀態",
+ "timedmedia-status-unknown": "不明狀態",
+ "timedmedia-transcodebitrate": "位元率",
+ "timedmedia-transcodeduration": "編碼時間",
+ "timedmedia-transcodeinfo": "格式",
+ "timedmedia-actions": "動作",
+ "timedmedia-direct-link": "下載",
+ "timedmedia-not-ready": "尚未就緒",
+ "timedmedia-completed-on": "已完成 $1",
+ "timedmedia-error-on": "於 $1 發生錯誤。",
+ "timedmedia-started-transcode": "已於 $1 前開始。$2",
+ "timedmedia-percent-done": "大約已完成 $1%",
+ "timedmedia-in-job-queue": "已於 $1 前新增至工作序列",
+ "timedmedia-unknown-target-size": "不明目標大小,已編碼 $1",
+ "timedmedia-days": "$1 天",
+ "timedmedia-hours": "$1 小時",
+ "timedmedia-minutes": "$1 分",
+ "timedmedia-seconds": "$1 秒",
+ "timedmedia-reset": "重設轉碼",
+ "timedmedia-reset-confirm": "重設轉碼會移除所有已存在的檔案,並重新將檔案加入轉碼工作序列。這需要花費一些時間來重新轉碼。<br /><br />\n您確定要繼續嗎?",
+ "timedmedia-reset-error": "重設轉碼工作時發生錯誤。",
+ "timedmedia-mp4": "MP4",
+ "timedmedia-source-file": "$1 來源檔案",
+ "timedmedia-source-file-desc": "$1 原始檔案,$2 × $3 ($4)",
+ "timedmedia-source-audio-file-desc": "原始 $1 檔案 ($2)",
+ "timedmedia-derivative-desc-160p.ogv": "低頻寬 Ogg 影片 (160P)",
+ "timedmedia-derivative-desc-240p.ogv": "網站可串流 Ogg 影片 (240P)",
+ "timedmedia-derivative-desc-360p.ogv": "網站可串流 Ogg 影片 (360P)",
+ "timedmedia-derivative-desc-480p.ogv": "網站可串流 Ogg 影片 (480P)",
+ "timedmedia-derivative-desc-720p.ogv": "高畫質可下載 Ogg 影片 (720P)",
+ "timedmedia-derivative-desc-1080p.ogv": "Full HD 可下載 Ogg 影像 (1080P)",
+ "timedmedia-derivative-desc-160p.webm": "網站可串流 WebM (160P)",
+ "timedmedia-derivative-desc-360p.webm": "網站可串流 WebM (360P)",
+ "timedmedia-derivative-desc-480p.webm": "網站可串流 WebM (480P)",
+ "timedmedia-derivative-desc-720p.webm": "高畫質可下載 WebM (720P)",
+ "timedmedia-derivative-desc-1080p.webm": "Full HD 可下載 WebM (1080P)",
+ "timedmedia-derivative-desc-2160p.webm": "Full HD 可下載 WebM (2160P)",
+ "timedmedia-derivative-desc-360p.vp9.webm": "網站可串流 WebM VP9 (360P)",
+ "timedmedia-derivative-desc-480p.vp9.webm": "網站可串流 WebM VP9 (480P)",
+ "timedmedia-derivative-desc-720p.vp9.webm": "HD 網站可串流 WebM VP9 (720P)",
+ "timedmedia-derivative-desc-1080p.vp9.webm": "Full HD 網站可串流 WebM VP9 (1080P)",
+ "timedmedia-derivative-desc-2160p.vp9.webm": "Full 4K 網站可串流 WebM VP9 (2160P)",
+ "timedmedia-derivative-desc-320p.mp4": "行動裝置易用 MP4 (320P)",
+ "timedmedia-derivative-desc-480p.mp4": "網站可串流 MP4 (480P)",
+ "timedmedia-derivative-desc-720p.mp4": "高清品質 MP4 (720P)",
+ "timedmedia-derivative-desc-1080p.mp4": "Full HD 品質 MP4 (1080P)",
+ "timedmedia-derivative-desc-2160p.mp4": "Full 4K 品質 MP4 (2160P)",
+ "timedmedia-subtitle-new": "建立新翻譯或編輯現有翻譯",
+ "timedmedia-subtitle-new-desc": "請選擇語言後點選 '''{{int:Timedmedia-subtitle-new-go}}''' 按鈕",
+ "timedmedia-subtitle-new-go": "執行",
+ "timedmedia-subtitle-language": "$1 ($2) 字幕",
+ "timedmedia-subtitle-no-video": "目前沒有與字幕頁面相關的影片。",
+ "timedmedia-subtitle-no-subtitles": "此影片目前沒有 $1 的字幕,您可 [{{fullurl:{{FULLPAGENAME}}|action=edit}} 編輯此頁面] 來增加字幕。",
+ "timedmedia-subtitle-remote": "此檔案的字幕位於 $1",
+ "timedmedia-subtitle-remote-link": "您可於 $2 檢視此檔案的 [$1 描述頁面]",
+ "timedmediahandler": "TimedMediaHandler",
+ "timedmedia-videos": "$1 個影片",
+ "timedmedia-ogg-videos": "$1 個 Ogg 影片",
+ "timedmedia-webm-videos": "$1 個 WebM 影片",
+ "timedmedia-derivative-state-transcodes": "$1 個轉碼工作",
+ "timedmedia-derivative-state-active": "$1 個正在執行的轉碼工作",
+ "timedmedia-derivative-state-queued": "$1 個在序列中的轉碼工作",
+ "timedmedia-derivative-state-failed": "$1 次轉碼失敗",
+ "timedmedia-file": "檔案",
+ "timedmedia-audios": "$1 個音訊檔案",
+ "timedmedia-ogg-audios": "$1 個 Ogg 音訊檔案",
+ "timedmedia-flac-audios": "$1 個 FLAC 音訊檔案",
+ "timedmedia-wav-audios": "$1 個 WAV 音訊檔案",
+ "right-transcode-reset": "重設已失敗或已輚碼的影片,將其重新排入序列中。",
+ "right-transcode-status": "檢視 [[Special:TimedMediaHandler|目前轉碼活動的資訊]]",
+ "action-transcode-status": "檢視目前轉碼狀態",
+ "orphanedtimedtext": "孤立的 TimedText 頁面",
+ "orphanedtimedtext-summary": "未關聯任何檔案的 [[{{#special:AllPages/TimedText:}}|{{ns:TimedText}}]] 頁面清單。",
+ "orphanedtimedtext-unsupported": "此特殊頁面僅支援使用 MySQL 資料庫。",
+ "orphanedtimedtext-notimedtext": "此 Wiki 未開啟 TimedText 功能。",
+ "apihelp-query+transcodestatus-description": "取得指定檔案頁面的轉碼狀態。",
+ "apihelp-query+transcodestatus-example-1": "取得 [[:File:Clip.webm]] 的轉碼狀態"
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/getid3.lib.php b/extensions/TimedMediaHandler/libs/getid3/getid3.lib.php
new file mode 100644
index 00000000..16d5318a
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/getid3.lib.php
@@ -0,0 +1,1346 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// //
+// getid3.lib.php - part of getID3() //
+// See readme.txt for more details //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_lib
+{
+
+ public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') {
+ $returnstring = '';
+ for ($i = 0; $i < strlen($string); $i++) {
+ if ($hex) {
+ $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT);
+ } else {
+ $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '');
+ }
+ if ($spaces) {
+ $returnstring .= ' ';
+ }
+ }
+ if (!empty($htmlencoding)) {
+ if ($htmlencoding === true) {
+ $htmlencoding = 'UTF-8'; // prior to getID3 v1.9.0 the function's 4th parameter was boolean
+ }
+ $returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding);
+ }
+ return $returnstring;
+ }
+
+ public static function trunc($floatnumber) {
+ // truncates a floating-point number at the decimal point
+ // returns int (if possible, otherwise float)
+ if ($floatnumber >= 1) {
+ $truncatednumber = floor($floatnumber);
+ } elseif ($floatnumber <= -1) {
+ $truncatednumber = ceil($floatnumber);
+ } else {
+ $truncatednumber = 0;
+ }
+ if (self::intValueSupported($truncatednumber)) {
+ $truncatednumber = (int) $truncatednumber;
+ }
+ return $truncatednumber;
+ }
+
+
+ public static function safe_inc(&$variable, $increment=1) {
+ if (isset($variable)) {
+ $variable += $increment;
+ } else {
+ $variable = $increment;
+ }
+ return true;
+ }
+
+ public static function CastAsInt($floatnum) {
+ // convert to float if not already
+ $floatnum = (float) $floatnum;
+
+ // convert a float to type int, only if possible
+ if (self::trunc($floatnum) == $floatnum) {
+ // it's not floating point
+ if (self::intValueSupported($floatnum)) {
+ // it's within int range
+ $floatnum = (int) $floatnum;
+ }
+ }
+ return $floatnum;
+ }
+
+ public static function intValueSupported($num) {
+ // check if integers are 64-bit
+ static $hasINT64 = null;
+ if ($hasINT64 === null) { // 10x faster than is_null()
+ $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1
+ if (!$hasINT64 && !defined('PHP_INT_MIN')) {
+ define('PHP_INT_MIN', ~PHP_INT_MAX);
+ }
+ }
+ // if integers are 64-bit - no other check required
+ if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) {
+ return true;
+ }
+ return false;
+ }
+
+ public static function DecimalizeFraction($fraction) {
+ list($numerator, $denominator) = explode('/', $fraction);
+ return $numerator / ($denominator ? $denominator : 1);
+ }
+
+
+ public static function DecimalBinary2Float($binarynumerator) {
+ $numerator = self::Bin2Dec($binarynumerator);
+ $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator)));
+ return ($numerator / $denominator);
+ }
+
+
+ public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) {
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
+ if (strpos($binarypointnumber, '.') === false) {
+ $binarypointnumber = '0.'.$binarypointnumber;
+ } elseif ($binarypointnumber{0} == '.') {
+ $binarypointnumber = '0'.$binarypointnumber;
+ }
+ $exponent = 0;
+ while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) {
+ if (substr($binarypointnumber, 1, 1) == '.') {
+ $exponent--;
+ $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3);
+ } else {
+ $pointpos = strpos($binarypointnumber, '.');
+ $exponent += ($pointpos - 1);
+ $binarypointnumber = str_replace('.', '', $binarypointnumber);
+ $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1);
+ }
+ }
+ $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT);
+ return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent);
+ }
+
+
+ public static function Float2BinaryDecimal($floatvalue) {
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
+ $maxbits = 128; // to how many bits of precision should the calculations be taken?
+ $intpart = self::trunc($floatvalue);
+ $floatpart = abs($floatvalue - $intpart);
+ $pointbitstring = '';
+ while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) {
+ $floatpart *= 2;
+ $pointbitstring .= (string) self::trunc($floatpart);
+ $floatpart -= self::trunc($floatpart);
+ }
+ $binarypointnumber = decbin($intpart).'.'.$pointbitstring;
+ return $binarypointnumber;
+ }
+
+
+ public static function Float2String($floatvalue, $bits) {
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
+ switch ($bits) {
+ case 32:
+ $exponentbits = 8;
+ $fractionbits = 23;
+ break;
+
+ case 64:
+ $exponentbits = 11;
+ $fractionbits = 52;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ if ($floatvalue >= 0) {
+ $signbit = '0';
+ } else {
+ $signbit = '1';
+ }
+ $normalizedbinary = self::NormalizeBinaryPoint(self::Float2BinaryDecimal($floatvalue), $fractionbits);
+ $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent
+ $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT);
+ $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT);
+
+ return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false);
+ }
+
+
+ public static function LittleEndian2Float($byteword) {
+ return self::BigEndian2Float(strrev($byteword));
+ }
+
+
+ public static function BigEndian2Float($byteword) {
+ // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic
+ // http://www.psc.edu/general/software/packages/ieee/ieee.html
+ // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html
+
+ $bitword = self::BigEndian2Bin($byteword);
+ if (!$bitword) {
+ return 0;
+ }
+ $signbit = $bitword{0};
+
+ switch (strlen($byteword) * 8) {
+ case 32:
+ $exponentbits = 8;
+ $fractionbits = 23;
+ break;
+
+ case 64:
+ $exponentbits = 11;
+ $fractionbits = 52;
+ break;
+
+ case 80:
+ // 80-bit Apple SANE format
+ // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
+ $exponentstring = substr($bitword, 1, 15);
+ $isnormalized = intval($bitword{16});
+ $fractionstring = substr($bitword, 17, 63);
+ $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383);
+ $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring);
+ $floatvalue = $exponent * $fraction;
+ if ($signbit == '1') {
+ $floatvalue *= -1;
+ }
+ return $floatvalue;
+ break;
+
+ default:
+ return false;
+ break;
+ }
+ $exponentstring = substr($bitword, 1, $exponentbits);
+ $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits);
+ $exponent = self::Bin2Dec($exponentstring);
+ $fraction = self::Bin2Dec($fractionstring);
+
+ if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) {
+ // Not a Number
+ $floatvalue = false;
+ } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) {
+ if ($signbit == '1') {
+ $floatvalue = '-infinity';
+ } else {
+ $floatvalue = '+infinity';
+ }
+ } elseif (($exponent == 0) && ($fraction == 0)) {
+ if ($signbit == '1') {
+ $floatvalue = -0;
+ } else {
+ $floatvalue = 0;
+ }
+ $floatvalue = ($signbit ? 0 : -0);
+ } elseif (($exponent == 0) && ($fraction != 0)) {
+ // These are 'unnormalized' values
+ $floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * self::DecimalBinary2Float($fractionstring);
+ if ($signbit == '1') {
+ $floatvalue *= -1;
+ }
+ } elseif ($exponent != 0) {
+ $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + self::DecimalBinary2Float($fractionstring));
+ if ($signbit == '1') {
+ $floatvalue *= -1;
+ }
+ }
+ return (float) $floatvalue;
+ }
+
+
+ public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) {
+ $intvalue = 0;
+ $bytewordlen = strlen($byteword);
+ if ($bytewordlen == 0) {
+ return false;
+ }
+ for ($i = 0; $i < $bytewordlen; $i++) {
+ if ($synchsafe) { // disregard MSB, effectively 7-bit bytes
+ //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems
+ $intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7);
+ } else {
+ $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i));
+ }
+ }
+ if ($signed && !$synchsafe) {
+ // synchsafe ints are not allowed to be signed
+ if ($bytewordlen <= PHP_INT_SIZE) {
+ $signMaskBit = 0x80 << (8 * ($bytewordlen - 1));
+ if ($intvalue & $signMaskBit) {
+ $intvalue = 0 - ($intvalue & ($signMaskBit - 1));
+ }
+ } else {
+ throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in self::BigEndian2Int()');
+ break;
+ }
+ }
+ return self::CastAsInt($intvalue);
+ }
+
+
+ public static function LittleEndian2Int($byteword, $signed=false) {
+ return self::BigEndian2Int(strrev($byteword), false, $signed);
+ }
+
+
+ public static function BigEndian2Bin($byteword) {
+ $binvalue = '';
+ $bytewordlen = strlen($byteword);
+ for ($i = 0; $i < $bytewordlen; $i++) {
+ $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT);
+ }
+ return $binvalue;
+ }
+
+
+ public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) {
+ if ($number < 0) {
+ throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers');
+ }
+ $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF);
+ $intstring = '';
+ if ($signed) {
+ if ($minbytes > PHP_INT_SIZE) {
+ throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits in self::BigEndian2String()');
+ }
+ $number = $number & (0x80 << (8 * ($minbytes - 1)));
+ }
+ while ($number != 0) {
+ $quotient = ($number / ($maskbyte + 1));
+ $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring;
+ $number = floor($quotient);
+ }
+ return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT);
+ }
+
+
+ public static function Dec2Bin($number) {
+ while ($number >= 256) {
+ $bytes[] = (($number / 256) - (floor($number / 256))) * 256;
+ $number = floor($number / 256);
+ }
+ $bytes[] = $number;
+ $binstring = '';
+ for ($i = 0; $i < count($bytes); $i++) {
+ $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring;
+ }
+ return $binstring;
+ }
+
+
+ public static function Bin2Dec($binstring, $signed=false) {
+ $signmult = 1;
+ if ($signed) {
+ if ($binstring{0} == '1') {
+ $signmult = -1;
+ }
+ $binstring = substr($binstring, 1);
+ }
+ $decvalue = 0;
+ for ($i = 0; $i < strlen($binstring); $i++) {
+ $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i);
+ }
+ return self::CastAsInt($decvalue * $signmult);
+ }
+
+
+ public static function Bin2String($binstring) {
+ // return 'hi' for input of '0110100001101001'
+ $string = '';
+ $binstringreversed = strrev($binstring);
+ for ($i = 0; $i < strlen($binstringreversed); $i += 8) {
+ $string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string;
+ }
+ return $string;
+ }
+
+
+ public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) {
+ $intstring = '';
+ while ($number > 0) {
+ if ($synchsafe) {
+ $intstring = $intstring.chr($number & 127);
+ $number >>= 7;
+ } else {
+ $intstring = $intstring.chr($number & 255);
+ $number >>= 8;
+ }
+ }
+ return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT);
+ }
+
+
+ public static function array_merge_clobber($array1, $array2) {
+ // written by kchireability*com
+ // taken from http://www.php.net/manual/en/function.array-merge-recursive.php
+ if (!is_array($array1) || !is_array($array2)) {
+ return false;
+ }
+ $newarray = $array1;
+ foreach ($array2 as $key => $val) {
+ if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
+ $newarray[$key] = self::array_merge_clobber($newarray[$key], $val);
+ } else {
+ $newarray[$key] = $val;
+ }
+ }
+ return $newarray;
+ }
+
+
+ public static function array_merge_noclobber($array1, $array2) {
+ if (!is_array($array1) || !is_array($array2)) {
+ return false;
+ }
+ $newarray = $array1;
+ foreach ($array2 as $key => $val) {
+ if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) {
+ $newarray[$key] = self::array_merge_noclobber($newarray[$key], $val);
+ } elseif (!isset($newarray[$key])) {
+ $newarray[$key] = $val;
+ }
+ }
+ return $newarray;
+ }
+
+
+ public static function ksort_recursive(&$theArray) {
+ ksort($theArray);
+ foreach ($theArray as $key => $value) {
+ if (is_array($value)) {
+ self::ksort_recursive($theArray[$key]);
+ }
+ }
+ return true;
+ }
+
+ public static function fileextension($filename, $numextensions=1) {
+ if (strstr($filename, '.')) {
+ $reversedfilename = strrev($filename);
+ $offset = 0;
+ for ($i = 0; $i < $numextensions; $i++) {
+ $offset = strpos($reversedfilename, '.', $offset + 1);
+ if ($offset === false) {
+ return '';
+ }
+ }
+ return strrev(substr($reversedfilename, 0, $offset));
+ }
+ return '';
+ }
+
+
+ public static function PlaytimeString($seconds) {
+ $sign = (($seconds < 0) ? '-' : '');
+ $seconds = round(abs($seconds));
+ $H = (int) floor( $seconds / 3600);
+ $M = (int) floor(($seconds - (3600 * $H) ) / 60);
+ $S = (int) round( $seconds - (3600 * $H) - (60 * $M) );
+ return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
+ }
+
+
+ public static function DateMac2Unix($macdate) {
+ // Macintosh timestamp: seconds since 00:00h January 1, 1904
+ // UNIX timestamp: seconds since 00:00h January 1, 1970
+ return self::CastAsInt($macdate - 2082844800);
+ }
+
+
+ public static function FixedPoint8_8($rawdata) {
+ return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8));
+ }
+
+
+ public static function FixedPoint16_16($rawdata) {
+ return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16));
+ }
+
+
+ public static function FixedPoint2_30($rawdata) {
+ $binarystring = self::BigEndian2Bin($rawdata);
+ return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30));
+ }
+
+
+ public static function CreateDeepArray($ArrayPath, $Separator, $Value) {
+ // assigns $Value to a nested array path:
+ // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt')
+ // is the same as:
+ // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt'))));
+ // or
+ // $foo['path']['to']['my'] = 'file.txt';
+ $ArrayPath = ltrim($ArrayPath, $Separator);
+ if (($pos = strpos($ArrayPath, $Separator)) !== false) {
+ $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value);
+ } else {
+ $ReturnedArray[$ArrayPath] = $Value;
+ }
+ return $ReturnedArray;
+ }
+
+ public static function array_max($arraydata, $returnkey=false) {
+ $maxvalue = false;
+ $maxkey = false;
+ foreach ($arraydata as $key => $value) {
+ if (!is_array($value)) {
+ if ($value > $maxvalue) {
+ $maxvalue = $value;
+ $maxkey = $key;
+ }
+ }
+ }
+ return ($returnkey ? $maxkey : $maxvalue);
+ }
+
+ public static function array_min($arraydata, $returnkey=false) {
+ $minvalue = false;
+ $minkey = false;
+ foreach ($arraydata as $key => $value) {
+ if (!is_array($value)) {
+ if ($value > $minvalue) {
+ $minvalue = $value;
+ $minkey = $key;
+ }
+ }
+ }
+ return ($returnkey ? $minkey : $minvalue);
+ }
+
+ public static function XML2array($XMLstring) {
+ if (function_exists('simplexml_load_string')
+ && function_exists('get_object_vars')
+ && function_exists('libxml_disable_entity_loader')
+ ) {
+ $loader = libxml_disable_entity_loader(true);
+ $XMLobject = simplexml_load_string($XMLstring);
+ $return = self::SimpleXMLelement2array($XMLobject);
+ libxml_disable_entity_loader($loader);
+ return $return;
+ }
+ return false;
+ }
+
+ public static function SimpleXMLelement2array($XMLobject) {
+ if (!is_object($XMLobject) && !is_array($XMLobject)) {
+ return $XMLobject;
+ }
+ $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject);
+ foreach ($XMLarray as $key => $value) {
+ $XMLarray[$key] = self::SimpleXMLelement2array($value);
+ }
+ return $XMLarray;
+ }
+
+
+ // Allan Hansen <ahartemis*dk>
+ // self::md5_data() - returns md5sum for a file from startuing position to absolute end position
+ public static function hash_data($file, $offset, $end, $algorithm) {
+ static $tempdir = '';
+ if (!self::intValueSupported($end)) {
+ return false;
+ }
+ switch ($algorithm) {
+ case 'md5':
+ $hash_function = 'md5_file';
+ $unix_call = 'md5sum';
+ $windows_call = 'md5sum.exe';
+ $hash_length = 32;
+ break;
+
+ case 'sha1':
+ $hash_function = 'sha1_file';
+ $unix_call = 'sha1sum';
+ $windows_call = 'sha1sum.exe';
+ $hash_length = 40;
+ break;
+
+ default:
+ throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()');
+ break;
+ }
+ $size = $end - $offset;
+ while (true) {
+ if (GETID3_OS_ISWINDOWS) {
+
+ // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data
+ // Fall back to create-temp-file method:
+ if ($algorithm == 'sha1') {
+ break;
+ }
+
+ $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call);
+ foreach ($RequiredFiles as $required_file) {
+ if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) {
+ // helper apps not available - fall back to old method
+ break 2;
+ }
+ }
+ $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | ';
+ $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | ';
+ $commandline .= GETID3_HELPERAPPSDIR.$windows_call;
+
+ } else {
+
+ $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | ';
+ $commandline .= 'tail -c'.$size.' | ';
+ $commandline .= $unix_call;
+
+ }
+ if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
+ //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm');
+ break;
+ }
+ return substr(`$commandline`, 0, $hash_length);
+ }
+
+ if (empty($tempdir)) {
+ // yes this is ugly, feel free to suggest a better way
+ require_once(dirname(__FILE__).'/getid3.php');
+ $getid3_temp = new getID3();
+ $tempdir = $getid3_temp->tempdir;
+ unset($getid3_temp);
+ }
+ // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir
+ if (($data_filename = tempnam($tempdir, 'gI3')) === false) {
+ // can't find anywhere to create a temp file, just fail
+ return false;
+ }
+
+ // Init
+ $result = false;
+
+ // copy parts of file
+ try {
+ self::CopyFileParts($file, $data_filename, $offset, $end - $offset);
+ $result = $hash_function($data_filename);
+ } catch (Exception $e) {
+ throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage());
+ }
+ unlink($data_filename);
+ return $result;
+ }
+
+ public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) {
+ if (!self::intValueSupported($offset + $length)) {
+ throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit');
+ }
+ if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) {
+ if (($fp_dest = fopen($filename_dest, 'wb'))) {
+ if (fseek($fp_src, $offset, SEEK_SET) == 0) {
+ $byteslefttowrite = $length;
+ while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) {
+ $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite);
+ $byteslefttowrite -= $byteswritten;
+ }
+ return true;
+ } else {
+ throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source);
+ }
+ fclose($fp_dest);
+ } else {
+ throw new Exception('failed to create file for writing '.$filename_dest);
+ }
+ fclose($fp_src);
+ } else {
+ throw new Exception('failed to open file for reading '.$filename_source);
+ }
+ return false;
+ }
+
+ public static function iconv_fallback_int_utf8($charval) {
+ if ($charval < 128) {
+ // 0bbbbbbb
+ $newcharstring = chr($charval);
+ } elseif ($charval < 2048) {
+ // 110bbbbb 10bbbbbb
+ $newcharstring = chr(($charval >> 6) | 0xC0);
+ $newcharstring .= chr(($charval & 0x3F) | 0x80);
+ } elseif ($charval < 65536) {
+ // 1110bbbb 10bbbbbb 10bbbbbb
+ $newcharstring = chr(($charval >> 12) | 0xE0);
+ $newcharstring .= chr(($charval >> 6) | 0xC0);
+ $newcharstring .= chr(($charval & 0x3F) | 0x80);
+ } else {
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
+ $newcharstring = chr(($charval >> 18) | 0xF0);
+ $newcharstring .= chr(($charval >> 12) | 0xC0);
+ $newcharstring .= chr(($charval >> 6) | 0xC0);
+ $newcharstring .= chr(($charval & 0x3F) | 0x80);
+ }
+ return $newcharstring;
+ }
+
+ // ISO-8859-1 => UTF-8
+ public static function iconv_fallback_iso88591_utf8($string, $bom=false) {
+ if (function_exists('utf8_encode')) {
+ return utf8_encode($string);
+ }
+ // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xEF\xBB\xBF";
+ }
+ for ($i = 0; $i < strlen($string); $i++) {
+ $charval = ord($string{$i});
+ $newcharstring .= self::iconv_fallback_int_utf8($charval);
+ }
+ return $newcharstring;
+ }
+
+ // ISO-8859-1 => UTF-16BE
+ public static function iconv_fallback_iso88591_utf16be($string, $bom=false) {
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xFE\xFF";
+ }
+ for ($i = 0; $i < strlen($string); $i++) {
+ $newcharstring .= "\x00".$string{$i};
+ }
+ return $newcharstring;
+ }
+
+ // ISO-8859-1 => UTF-16LE
+ public static function iconv_fallback_iso88591_utf16le($string, $bom=false) {
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xFF\xFE";
+ }
+ for ($i = 0; $i < strlen($string); $i++) {
+ $newcharstring .= $string{$i}."\x00";
+ }
+ return $newcharstring;
+ }
+
+ // ISO-8859-1 => UTF-16LE (BOM)
+ public static function iconv_fallback_iso88591_utf16($string) {
+ return self::iconv_fallback_iso88591_utf16le($string, true);
+ }
+
+ // UTF-8 => ISO-8859-1
+ public static function iconv_fallback_utf8_iso88591($string) {
+ if (function_exists('utf8_decode')) {
+ return utf8_decode($string);
+ }
+ // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support)
+ $newcharstring = '';
+ $offset = 0;
+ $stringlength = strlen($string);
+ while ($offset < $stringlength) {
+ if ((ord($string{$offset}) | 0x07) == 0xF7) {
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 12) &
+ ((ord($string{($offset + 2)}) & 0x3F) << 6) &
+ (ord($string{($offset + 3)}) & 0x3F);
+ $offset += 4;
+ } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
+ // 1110bbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 6) &
+ (ord($string{($offset + 2)}) & 0x3F);
+ $offset += 3;
+ } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
+ // 110bbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
+ (ord($string{($offset + 1)}) & 0x3F);
+ $offset += 2;
+ } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
+ // 0bbbbbbb
+ $charval = ord($string{$offset});
+ $offset += 1;
+ } else {
+ // error? throw some kind of warning here?
+ $charval = false;
+ $offset += 1;
+ }
+ if ($charval !== false) {
+ $newcharstring .= (($charval < 256) ? chr($charval) : '?');
+ }
+ }
+ return $newcharstring;
+ }
+
+ // UTF-8 => UTF-16BE
+ public static function iconv_fallback_utf8_utf16be($string, $bom=false) {
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xFE\xFF";
+ }
+ $offset = 0;
+ $stringlength = strlen($string);
+ while ($offset < $stringlength) {
+ if ((ord($string{$offset}) | 0x07) == 0xF7) {
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 12) &
+ ((ord($string{($offset + 2)}) & 0x3F) << 6) &
+ (ord($string{($offset + 3)}) & 0x3F);
+ $offset += 4;
+ } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
+ // 1110bbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 6) &
+ (ord($string{($offset + 2)}) & 0x3F);
+ $offset += 3;
+ } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
+ // 110bbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
+ (ord($string{($offset + 1)}) & 0x3F);
+ $offset += 2;
+ } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
+ // 0bbbbbbb
+ $charval = ord($string{$offset});
+ $offset += 1;
+ } else {
+ // error? throw some kind of warning here?
+ $charval = false;
+ $offset += 1;
+ }
+ if ($charval !== false) {
+ $newcharstring .= (($charval < 65536) ? self::BigEndian2String($charval, 2) : "\x00".'?');
+ }
+ }
+ return $newcharstring;
+ }
+
+ // UTF-8 => UTF-16LE
+ public static function iconv_fallback_utf8_utf16le($string, $bom=false) {
+ $newcharstring = '';
+ if ($bom) {
+ $newcharstring .= "\xFF\xFE";
+ }
+ $offset = 0;
+ $stringlength = strlen($string);
+ while ($offset < $stringlength) {
+ if ((ord($string{$offset}) | 0x07) == 0xF7) {
+ // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 12) &
+ ((ord($string{($offset + 2)}) & 0x3F) << 6) &
+ (ord($string{($offset + 3)}) & 0x3F);
+ $offset += 4;
+ } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) {
+ // 1110bbbb 10bbbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) &
+ ((ord($string{($offset + 1)}) & 0x3F) << 6) &
+ (ord($string{($offset + 2)}) & 0x3F);
+ $offset += 3;
+ } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) {
+ // 110bbbbb 10bbbbbb
+ $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) &
+ (ord($string{($offset + 1)}) & 0x3F);
+ $offset += 2;
+ } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) {
+ // 0bbbbbbb
+ $charval = ord($string{$offset});
+ $offset += 1;
+ } else {
+ // error? maybe throw some warning here?
+ $charval = false;
+ $offset += 1;
+ }
+ if ($charval !== false) {
+ $newcharstring .= (($charval < 65536) ? self::LittleEndian2String($charval, 2) : '?'."\x00");
+ }
+ }
+ return $newcharstring;
+ }
+
+ // UTF-8 => UTF-16LE (BOM)
+ public static function iconv_fallback_utf8_utf16($string) {
+ return self::iconv_fallback_utf8_utf16le($string, true);
+ }
+
+ // UTF-16BE => UTF-8
+ public static function iconv_fallback_utf16be_utf8($string) {
+ if (substr($string, 0, 2) == "\xFE\xFF") {
+ // strip BOM
+ $string = substr($string, 2);
+ }
+ $newcharstring = '';
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::BigEndian2Int(substr($string, $i, 2));
+ $newcharstring .= self::iconv_fallback_int_utf8($charval);
+ }
+ return $newcharstring;
+ }
+
+ // UTF-16LE => UTF-8
+ public static function iconv_fallback_utf16le_utf8($string) {
+ if (substr($string, 0, 2) == "\xFF\xFE") {
+ // strip BOM
+ $string = substr($string, 2);
+ }
+ $newcharstring = '';
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::LittleEndian2Int(substr($string, $i, 2));
+ $newcharstring .= self::iconv_fallback_int_utf8($charval);
+ }
+ return $newcharstring;
+ }
+
+ // UTF-16BE => ISO-8859-1
+ public static function iconv_fallback_utf16be_iso88591($string) {
+ if (substr($string, 0, 2) == "\xFE\xFF") {
+ // strip BOM
+ $string = substr($string, 2);
+ }
+ $newcharstring = '';
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::BigEndian2Int(substr($string, $i, 2));
+ $newcharstring .= (($charval < 256) ? chr($charval) : '?');
+ }
+ return $newcharstring;
+ }
+
+ // UTF-16LE => ISO-8859-1
+ public static function iconv_fallback_utf16le_iso88591($string) {
+ if (substr($string, 0, 2) == "\xFF\xFE") {
+ // strip BOM
+ $string = substr($string, 2);
+ }
+ $newcharstring = '';
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::LittleEndian2Int(substr($string, $i, 2));
+ $newcharstring .= (($charval < 256) ? chr($charval) : '?');
+ }
+ return $newcharstring;
+ }
+
+ // UTF-16 (BOM) => ISO-8859-1
+ public static function iconv_fallback_utf16_iso88591($string) {
+ $bom = substr($string, 0, 2);
+ if ($bom == "\xFE\xFF") {
+ return self::iconv_fallback_utf16be_iso88591(substr($string, 2));
+ } elseif ($bom == "\xFF\xFE") {
+ return self::iconv_fallback_utf16le_iso88591(substr($string, 2));
+ }
+ return $string;
+ }
+
+ // UTF-16 (BOM) => UTF-8
+ public static function iconv_fallback_utf16_utf8($string) {
+ $bom = substr($string, 0, 2);
+ if ($bom == "\xFE\xFF") {
+ return self::iconv_fallback_utf16be_utf8(substr($string, 2));
+ } elseif ($bom == "\xFF\xFE") {
+ return self::iconv_fallback_utf16le_utf8(substr($string, 2));
+ }
+ return $string;
+ }
+
+ public static function iconv_fallback($in_charset, $out_charset, $string) {
+
+ if ($in_charset == $out_charset) {
+ return $string;
+ }
+
+ // iconv() availble
+ if (function_exists('iconv')) {
+ if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) {
+ switch ($out_charset) {
+ case 'ISO-8859-1':
+ $converted_string = rtrim($converted_string, "\x00");
+ break;
+ }
+ return $converted_string;
+ }
+
+ // iconv() may sometimes fail with "illegal character in input string" error message
+ // and return an empty string, but returning the unconverted string is more useful
+ return $string;
+ }
+
+
+ // iconv() not available
+ static $ConversionFunctionList = array();
+ if (empty($ConversionFunctionList)) {
+ $ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8';
+ $ConversionFunctionList['ISO-8859-1']['UTF-16'] = 'iconv_fallback_iso88591_utf16';
+ $ConversionFunctionList['ISO-8859-1']['UTF-16BE'] = 'iconv_fallback_iso88591_utf16be';
+ $ConversionFunctionList['ISO-8859-1']['UTF-16LE'] = 'iconv_fallback_iso88591_utf16le';
+ $ConversionFunctionList['UTF-8']['ISO-8859-1'] = 'iconv_fallback_utf8_iso88591';
+ $ConversionFunctionList['UTF-8']['UTF-16'] = 'iconv_fallback_utf8_utf16';
+ $ConversionFunctionList['UTF-8']['UTF-16BE'] = 'iconv_fallback_utf8_utf16be';
+ $ConversionFunctionList['UTF-8']['UTF-16LE'] = 'iconv_fallback_utf8_utf16le';
+ $ConversionFunctionList['UTF-16']['ISO-8859-1'] = 'iconv_fallback_utf16_iso88591';
+ $ConversionFunctionList['UTF-16']['UTF-8'] = 'iconv_fallback_utf16_utf8';
+ $ConversionFunctionList['UTF-16LE']['ISO-8859-1'] = 'iconv_fallback_utf16le_iso88591';
+ $ConversionFunctionList['UTF-16LE']['UTF-8'] = 'iconv_fallback_utf16le_utf8';
+ $ConversionFunctionList['UTF-16BE']['ISO-8859-1'] = 'iconv_fallback_utf16be_iso88591';
+ $ConversionFunctionList['UTF-16BE']['UTF-8'] = 'iconv_fallback_utf16be_utf8';
+ }
+ if (isset($ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)])) {
+ $ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)];
+ return self::$ConversionFunction($string);
+ }
+ throw new Exception('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset);
+ }
+
+
+ public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') {
+ $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string
+ $HTMLstring = '';
+
+ switch ($charset) {
+ case '1251':
+ case '1252':
+ case '866':
+ case '932':
+ case '936':
+ case '950':
+ case 'BIG5':
+ case 'BIG5-HKSCS':
+ case 'cp1251':
+ case 'cp1252':
+ case 'cp866':
+ case 'EUC-JP':
+ case 'EUCJP':
+ case 'GB2312':
+ case 'ibm866':
+ case 'ISO-8859-1':
+ case 'ISO-8859-15':
+ case 'ISO8859-1':
+ case 'ISO8859-15':
+ case 'KOI8-R':
+ case 'koi8-ru':
+ case 'koi8r':
+ case 'Shift_JIS':
+ case 'SJIS':
+ case 'win-1251':
+ case 'Windows-1251':
+ case 'Windows-1252':
+ $HTMLstring = htmlentities($string, ENT_COMPAT, $charset);
+ break;
+
+ case 'UTF-8':
+ $strlen = strlen($string);
+ for ($i = 0; $i < $strlen; $i++) {
+ $char_ord_val = ord($string{$i});
+ $charval = 0;
+ if ($char_ord_val < 0x80) {
+ $charval = $char_ord_val;
+ } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) {
+ $charval = (($char_ord_val & 0x07) << 18);
+ $charval += ((ord($string{++$i}) & 0x3F) << 12);
+ $charval += ((ord($string{++$i}) & 0x3F) << 6);
+ $charval += (ord($string{++$i}) & 0x3F);
+ } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) {
+ $charval = (($char_ord_val & 0x0F) << 12);
+ $charval += ((ord($string{++$i}) & 0x3F) << 6);
+ $charval += (ord($string{++$i}) & 0x3F);
+ } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) {
+ $charval = (($char_ord_val & 0x1F) << 6);
+ $charval += (ord($string{++$i}) & 0x3F);
+ }
+ if (($charval >= 32) && ($charval <= 127)) {
+ $HTMLstring .= htmlentities(chr($charval));
+ } else {
+ $HTMLstring .= '&#'.$charval.';';
+ }
+ }
+ break;
+
+ case 'UTF-16LE':
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::LittleEndian2Int(substr($string, $i, 2));
+ if (($charval >= 32) && ($charval <= 127)) {
+ $HTMLstring .= chr($charval);
+ } else {
+ $HTMLstring .= '&#'.$charval.';';
+ }
+ }
+ break;
+
+ case 'UTF-16BE':
+ for ($i = 0; $i < strlen($string); $i += 2) {
+ $charval = self::BigEndian2Int(substr($string, $i, 2));
+ if (($charval >= 32) && ($charval <= 127)) {
+ $HTMLstring .= chr($charval);
+ } else {
+ $HTMLstring .= '&#'.$charval.';';
+ }
+ }
+ break;
+
+ default:
+ $HTMLstring = 'ERROR: Character set "'.$charset.'" not supported in MultiByteCharString2HTML()';
+ break;
+ }
+ return $HTMLstring;
+ }
+
+
+
+ public static function RGADnameLookup($namecode) {
+ static $RGADname = array();
+ if (empty($RGADname)) {
+ $RGADname[0] = 'not set';
+ $RGADname[1] = 'Track Gain Adjustment';
+ $RGADname[2] = 'Album Gain Adjustment';
+ }
+
+ return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : '');
+ }
+
+
+ public static function RGADoriginatorLookup($originatorcode) {
+ static $RGADoriginator = array();
+ if (empty($RGADoriginator)) {
+ $RGADoriginator[0] = 'unspecified';
+ $RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer';
+ $RGADoriginator[2] = 'set by user';
+ $RGADoriginator[3] = 'determined automatically';
+ }
+
+ return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : '');
+ }
+
+
+ public static function RGADadjustmentLookup($rawadjustment, $signbit) {
+ $adjustment = $rawadjustment / 10;
+ if ($signbit == 1) {
+ $adjustment *= -1;
+ }
+ return (float) $adjustment;
+ }
+
+
+ public static function RGADgainString($namecode, $originatorcode, $replaygain) {
+ if ($replaygain < 0) {
+ $signbit = '1';
+ } else {
+ $signbit = '0';
+ }
+ $storedreplaygain = intval(round($replaygain * 10));
+ $gainstring = str_pad(decbin($namecode), 3, '0', STR_PAD_LEFT);
+ $gainstring .= str_pad(decbin($originatorcode), 3, '0', STR_PAD_LEFT);
+ $gainstring .= $signbit;
+ $gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT);
+
+ return $gainstring;
+ }
+
+ public static function RGADamplitude2dB($amplitude) {
+ return 20 * log10($amplitude);
+ }
+
+
+ public static function GetDataImageSize($imgData, &$imageinfo=array()) {
+ static $tempdir = '';
+ if (empty($tempdir)) {
+ // yes this is ugly, feel free to suggest a better way
+ require_once(dirname(__FILE__).'/getid3.php');
+ $getid3_temp = new getID3();
+ $tempdir = $getid3_temp->tempdir;
+ unset($getid3_temp);
+ }
+ $GetDataImageSize = false;
+ if ($tempfilename = tempnam($tempdir, 'gI3')) {
+ if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) {
+ fwrite($tmp, $imgData);
+ fclose($tmp);
+ $GetDataImageSize = @getimagesize($tempfilename, $imageinfo);
+ }
+ unlink($tempfilename);
+ }
+ return $GetDataImageSize;
+ }
+
+ public static function ImageExtFromMime($mime_type) {
+ // temporary way, works OK for now, but should be reworked in the future
+ return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type);
+ }
+
+ public static function ImageTypesLookup($imagetypeid) {
+ static $ImageTypesLookup = array();
+ if (empty($ImageTypesLookup)) {
+ $ImageTypesLookup[1] = 'gif';
+ $ImageTypesLookup[2] = 'jpeg';
+ $ImageTypesLookup[3] = 'png';
+ $ImageTypesLookup[4] = 'swf';
+ $ImageTypesLookup[5] = 'psd';
+ $ImageTypesLookup[6] = 'bmp';
+ $ImageTypesLookup[7] = 'tiff (little-endian)';
+ $ImageTypesLookup[8] = 'tiff (big-endian)';
+ $ImageTypesLookup[9] = 'jpc';
+ $ImageTypesLookup[10] = 'jp2';
+ $ImageTypesLookup[11] = 'jpx';
+ $ImageTypesLookup[12] = 'jb2';
+ $ImageTypesLookup[13] = 'swc';
+ $ImageTypesLookup[14] = 'iff';
+ }
+ return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : '');
+ }
+
+ public static function CopyTagsToComments(&$ThisFileInfo) {
+
+ // Copy all entries from ['tags'] into common ['comments']
+ if (!empty($ThisFileInfo['tags'])) {
+ foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) {
+ foreach ($tagarray as $tagname => $tagdata) {
+ foreach ($tagdata as $key => $value) {
+ if (!empty($value)) {
+ if (empty($ThisFileInfo['comments'][$tagname])) {
+
+ // fall through and append value
+
+ } elseif ($tagtype == 'id3v1') {
+
+ $newvaluelength = strlen(trim($value));
+ foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
+ $oldvaluelength = strlen(trim($existingvalue));
+ if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) {
+ // new value is identical but shorter-than (or equal-length to) one already in comments - skip
+ break 2;
+ }
+ }
+
+ } elseif (!is_array($value)) {
+
+ $newvaluelength = strlen(trim($value));
+ foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) {
+ $oldvaluelength = strlen(trim($existingvalue));
+ if (($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) {
+ $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value);
+ break 2;
+ }
+ }
+
+ }
+ if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) {
+ $value = (is_string($value) ? trim($value) : $value);
+ $ThisFileInfo['comments'][$tagname][] = $value;
+ }
+ }
+ }
+ }
+ }
+
+ // Copy to ['comments_html']
+ foreach ($ThisFileInfo['comments'] as $field => $values) {
+ if ($field == 'picture') {
+ // pictures can take up a lot of space, and we don't need multiple copies of them
+ // let there be a single copy in [comments][picture], and not elsewhere
+ continue;
+ }
+ foreach ($values as $index => $value) {
+ if (is_array($value)) {
+ $ThisFileInfo['comments_html'][$field][$index] = $value;
+ } else {
+ $ThisFileInfo['comments_html'][$field][$index] = str_replace('&#0;', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding']));
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+
+ public static function EmbeddedLookup($key, $begin, $end, $file, $name) {
+
+ // Cached
+ static $cache;
+ if (isset($cache[$file][$name])) {
+ return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
+ }
+
+ // Init
+ $keylength = strlen($key);
+ $line_count = $end - $begin - 7;
+
+ // Open php file
+ $fp = fopen($file, 'r');
+
+ // Discard $begin lines
+ for ($i = 0; $i < ($begin + 3); $i++) {
+ fgets($fp, 1024);
+ }
+
+ // Loop thru line
+ while (0 < $line_count--) {
+
+ // Read line
+ $line = ltrim(fgets($fp, 1024), "\t ");
+
+ // METHOD A: only cache the matching key - less memory but slower on next lookup of not-previously-looked-up key
+ //$keycheck = substr($line, 0, $keylength);
+ //if ($key == $keycheck) {
+ // $cache[$file][$name][$keycheck] = substr($line, $keylength + 1);
+ // break;
+ //}
+
+ // METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key
+ //$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1));
+ $explodedLine = explode("\t", $line, 2);
+ $ThisKey = (isset($explodedLine[0]) ? $explodedLine[0] : '');
+ $ThisValue = (isset($explodedLine[1]) ? $explodedLine[1] : '');
+ $cache[$file][$name][$ThisKey] = trim($ThisValue);
+ }
+
+ // Close and return
+ fclose($fp);
+ return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : '');
+ }
+
+ public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) {
+ global $GETID3_ERRORARRAY;
+
+ if (file_exists($filename)) {
+ if (include_once($filename)) {
+ return true;
+ } else {
+ $diemessage = basename($sourcefile).' depends on '.$filename.', which has errors';
+ }
+ } else {
+ $diemessage = basename($sourcefile).' depends on '.$filename.', which is missing';
+ }
+ if ($DieOnFailure) {
+ throw new Exception($diemessage);
+ } else {
+ $GETID3_ERRORARRAY[] = $diemessage;
+ }
+ return false;
+ }
+
+ public static function trimNullByte($string) {
+ return trim($string, "\x00");
+ }
+
+ public static function getFileSizeSyscall($path) {
+ $filesize = false;
+
+ if (GETID3_OS_ISWINDOWS) {
+ if (class_exists('COM')) { // From PHP 5.3.15 and 5.4.5, COM and DOTNET is no longer built into the php core.you have to add COM support in php.ini:
+ $filesystem = new COM('Scripting.FileSystemObject');
+ $file = $filesystem->GetFile($path);
+ $filesize = $file->Size();
+ unset($filesystem, $file);
+ } else {
+ $commandline = 'for %I in ('.escapeshellarg($path).') do @echo %~zI';
+ }
+ } else {
+ $commandline = 'ls -l '.escapeshellarg($path).' | awk \'{print $5}\'';
+ }
+ if (isset($commandline)) {
+ $output = trim(`$commandline`);
+ if (ctype_digit($output)) {
+ $filesize = (float) $output;
+ }
+ }
+ return $filesize;
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/getid3.php b/extensions/TimedMediaHandler/libs/getid3/getid3.php
new file mode 100644
index 00000000..be0dd5f0
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/getid3.php
@@ -0,0 +1,1776 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// //
+// Please see readme.txt for more information //
+// ///
+/////////////////////////////////////////////////////////////////
+
+// define a constant rather than looking up every time it is needed
+if (!defined('GETID3_OS_ISWINDOWS')) {
+ define('GETID3_OS_ISWINDOWS', (stripos(PHP_OS, 'WIN') === 0));
+}
+// Get base path of getID3() - ONCE
+if (!defined('GETID3_INCLUDEPATH')) {
+ define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR);
+}
+
+// attempt to define temp dir as something flexible but reliable
+$temp_dir = ini_get('upload_tmp_dir');
+if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) {
+ $temp_dir = '';
+}
+if (!$temp_dir && function_exists('sys_get_temp_dir')) {
+ // PHP v5.2.1+
+ // sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts
+ $temp_dir = sys_get_temp_dir();
+}
+$temp_dir = realpath($temp_dir);
+$open_basedir = ini_get('open_basedir');
+if ($open_basedir) {
+ // e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/"
+ $temp_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $temp_dir);
+ $open_basedir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $open_basedir);
+ if (substr($temp_dir, -1, 1) != DIRECTORY_SEPARATOR) {
+ $temp_dir .= DIRECTORY_SEPARATOR;
+ }
+ $found_valid_tempdir = false;
+ $open_basedirs = explode(PATH_SEPARATOR, $open_basedir);
+ foreach ($open_basedirs as $basedir) {
+ if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) {
+ $basedir .= DIRECTORY_SEPARATOR;
+ }
+ if (preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) {
+ $found_valid_tempdir = true;
+ break;
+ }
+ }
+ if (!$found_valid_tempdir) {
+ $temp_dir = '';
+ }
+ unset($open_basedirs, $found_valid_tempdir, $basedir);
+}
+if (!$temp_dir) {
+ $temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir
+}
+// $temp_dir = '/something/else/'; // feel free to override temp dir here if it works better for your system
+define('GETID3_TEMP_DIR', $temp_dir);
+unset($open_basedir, $temp_dir);
+
+// End: Defines
+
+
+class getID3
+{
+ // public: Settings
+ public $encoding = 'UTF-8'; // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE
+ public $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252'
+
+ // public: Optional tag checks - disable for speed.
+ public $option_tag_id3v1 = true; // Read and process ID3v1 tags
+ public $option_tag_id3v2 = true; // Read and process ID3v2 tags
+ public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags
+ public $option_tag_apetag = true; // Read and process APE tags
+ public $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding
+ public $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities
+
+ // public: Optional tag/comment calucations
+ public $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc
+
+ // public: Optional handling of embedded attachments (e.g. images)
+ public $option_save_attachments = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility
+
+ // public: Optional calculations
+ public $option_md5_data = false; // Get MD5 sum of data part - slow
+ public $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG
+ public $option_sha1_data = false; // Get SHA1 sum of data part - slow
+ public $option_max_2gb_check = null; // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX)
+
+ // public: Read buffer size in bytes
+ public $option_fread_buffer_size = 32768;
+
+ // Public variables
+ public $filename; // Filename of file being analysed.
+ public $fp; // Filepointer to file being analysed.
+ public $info; // Result array.
+ public $tempdir = GETID3_TEMP_DIR;
+
+ // Protected variables
+ protected $startup_error = '';
+ protected $startup_warning = '';
+ protected $memory_limit = 0;
+
+ const VERSION = '1.9.6-20130603';
+ const FREAD_BUFFER_SIZE = 32768;
+
+ const ATTACHMENTS_NONE = false;
+ const ATTACHMENTS_INLINE = true;
+
+ // public: constructor
+ public function __construct() {
+
+ // Check for PHP version
+ $required_php_version = '5.0.5';
+ if (version_compare(PHP_VERSION, $required_php_version, '<')) {
+ $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION;
+ return false;
+ }
+
+ // Check memory
+ $this->memory_limit = ini_get('memory_limit');
+ if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) {
+ // could be stored as "16M" rather than 16777216 for example
+ $this->memory_limit = $matches[1] * 1048576;
+ } elseif (preg_match('#([0-9]+)G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0
+ // could be stored as "2G" rather than 2147483648 for example
+ $this->memory_limit = $matches[1] * 1073741824;
+ }
+ if ($this->memory_limit <= 0) {
+ // memory limits probably disabled
+ } elseif ($this->memory_limit <= 4194304) {
+ $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini';
+ } elseif ($this->memory_limit <= 12582912) {
+ $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini';
+ }
+
+ // Check safe_mode off
+ if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
+ $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.');
+ }
+
+ if (intval(ini_get('mbstring.func_overload')) > 0) {
+ $this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.');
+ }
+
+ // Check for magic_quotes_runtime
+ if (function_exists('get_magic_quotes_runtime')) {
+ if (get_magic_quotes_runtime()) {
+ return $this->startup_error('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).');
+ }
+ }
+
+ // Check for magic_quotes_gpc
+ if (function_exists('magic_quotes_gpc')) {
+ if (get_magic_quotes_gpc()) {
+ return $this->startup_error('magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).');
+ }
+ }
+
+ // Load support library
+ if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) {
+ $this->startup_error .= 'getid3.lib.php is missing or corrupt';
+ }
+
+ if ($this->option_max_2gb_check === null) {
+ $this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647);
+ }
+
+
+ // Needed for Windows only:
+ // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC
+ // as well as other helper functions such as head, tail, md5sum, etc
+ // This path cannot contain spaces, but the below code will attempt to get the
+ // 8.3-equivalent path automatically
+ // IMPORTANT: This path must include the trailing slash
+ if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) {
+
+ $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path
+
+ if (!is_dir($helperappsdir)) {
+ $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist';
+ } elseif (strpos(realpath($helperappsdir), ' ') !== false) {
+ $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir));
+ $path_so_far = array();
+ foreach ($DirPieces as $key => $value) {
+ if (strpos($value, ' ') !== false) {
+ if (!empty($path_so_far)) {
+ $commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far));
+ $dir_listing = `$commandline`;
+ $lines = explode("\n", $dir_listing);
+ foreach ($lines as $line) {
+ $line = trim($line);
+ if (preg_match('#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(<DIR>|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) {
+ list($dummy, $date, $time, $ampm, $filesize, $shortname, $filename) = $matches;
+ if ((strtoupper($filesize) == '<DIR>') && (strtolower($filename) == strtolower($value))) {
+ $value = $shortname;
+ }
+ }
+ }
+ } else {
+ $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.';
+ }
+ }
+ $path_so_far[] = $value;
+ }
+ $helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far);
+ }
+ define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR);
+ }
+
+ return true;
+ }
+
+ public function version() {
+ return self::VERSION;
+ }
+
+ public function fread_buffer_size() {
+ return $this->option_fread_buffer_size;
+ }
+
+
+ // public: setOption
+ public function setOption($optArray) {
+ if (!is_array($optArray) || empty($optArray)) {
+ return false;
+ }
+ foreach ($optArray as $opt => $val) {
+ if (isset($this->$opt) === false) {
+ continue;
+ }
+ $this->$opt = $val;
+ }
+ return true;
+ }
+
+
+ public function openfile($filename) {
+ try {
+ if (!empty($this->startup_error)) {
+ throw new getid3_exception($this->startup_error);
+ }
+ if (!empty($this->startup_warning)) {
+ $this->warning($this->startup_warning);
+ }
+
+ // init result array and set parameters
+ $this->filename = $filename;
+ $this->info = array();
+ $this->info['GETID3_VERSION'] = $this->version();
+ $this->info['php_memory_limit'] = $this->memory_limit;
+
+ // remote files not supported
+ if (preg_match('/^(ht|f)tp:\/\//', $filename)) {
+ throw new getid3_exception('Remote files are not supported - please copy the file locally first');
+ }
+
+ $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename);
+ $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename);
+
+ // open local file
+ if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) {
+ // great
+ } else {
+ throw new getid3_exception('Could not open "'.$filename.'" (does not exist, or is not a file)');
+ }
+
+ $this->info['filesize'] = filesize($filename);
+ // set redundant parameters - might be needed in some include file
+ $this->info['filename'] = basename($filename);
+ $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename)));
+ $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename'];
+
+
+ // option_max_2gb_check
+ if ($this->option_max_2gb_check) {
+ // PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB)
+ // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize
+ // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer
+ $fseek = fseek($this->fp, 0, SEEK_END);
+ if (($fseek < 0) || (($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) ||
+ ($this->info['filesize'] < 0) ||
+ (ftell($this->fp) < 0)) {
+ $real_filesize = getid3_lib::getFileSizeSyscall($this->info['filenamepath']);
+
+ if ($real_filesize === false) {
+ unset($this->info['filesize']);
+ fclose($this->fp);
+ throw new getid3_exception('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.');
+ } elseif (getid3_lib::intValueSupported($real_filesize)) {
+ unset($this->info['filesize']);
+ fclose($this->fp);
+ throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org');
+ }
+ $this->info['filesize'] = $real_filesize;
+ $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.');
+ }
+ }
+
+ // set more parameters
+ $this->info['avdataoffset'] = 0;
+ $this->info['avdataend'] = $this->info['filesize'];
+ $this->info['fileformat'] = ''; // filled in later
+ $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used
+ $this->info['video']['dataformat'] = ''; // filled in later, unset if not used
+ $this->info['tags'] = array(); // filled in later, unset if not used
+ $this->info['error'] = array(); // filled in later, unset if not used
+ $this->info['warning'] = array(); // filled in later, unset if not used
+ $this->info['comments'] = array(); // filled in later, unset if not used
+ $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired
+
+ return true;
+
+ } catch (Exception $e) {
+ $this->error($e->getMessage());
+ }
+ return false;
+ }
+
+ // public: analyze file
+ public function analyze($filename) {
+ try {
+ if (!$this->openfile($filename)) {
+ return $this->info;
+ }
+
+ // Handle tags
+ foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
+ $option_tag = 'option_tag_'.$tag_name;
+ if ($this->$option_tag) {
+ $this->include_module('tag.'.$tag_name);
+ try {
+ $tag_class = 'getid3_'.$tag_name;
+ $tag = new $tag_class($this);
+ $tag->Analyze();
+ }
+ catch (getid3_exception $e) {
+ throw $e;
+ }
+ }
+ }
+ if (isset($this->info['id3v2']['tag_offset_start'])) {
+ $this->info['avdataoffset'] = max($this->info['avdataoffset'], $this->info['id3v2']['tag_offset_end']);
+ }
+ foreach (array('id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) {
+ if (isset($this->info[$tag_key]['tag_offset_start'])) {
+ $this->info['avdataend'] = min($this->info['avdataend'], $this->info[$tag_key]['tag_offset_start']);
+ }
+ }
+
+ // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier
+ if (!$this->option_tag_id3v2) {
+ fseek($this->fp, 0, SEEK_SET);
+ $header = fread($this->fp, 10);
+ if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) {
+ $this->info['id3v2']['header'] = true;
+ $this->info['id3v2']['majorversion'] = ord($header{3});
+ $this->info['id3v2']['minorversion'] = ord($header{4});
+ $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
+ }
+ }
+
+ // read 32 kb file data
+ fseek($this->fp, $this->info['avdataoffset'], SEEK_SET);
+ $formattest = fread($this->fp, 32774);
+
+ // determine format
+ $determined_format = $this->GetFileFormat($formattest, $filename);
+
+ // unable to determine file format
+ if (!$determined_format) {
+ fclose($this->fp);
+ return $this->error('unable to determine file format');
+ }
+
+ // check for illegal ID3 tags
+ if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) {
+ if ($determined_format['fail_id3'] === 'ERROR') {
+ fclose($this->fp);
+ return $this->error('ID3 tags not allowed on this file type.');
+ } elseif ($determined_format['fail_id3'] === 'WARNING') {
+ $this->warning('ID3 tags not allowed on this file type.');
+ }
+ }
+
+ // check for illegal APE tags
+ if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) {
+ if ($determined_format['fail_ape'] === 'ERROR') {
+ fclose($this->fp);
+ return $this->error('APE tags not allowed on this file type.');
+ } elseif ($determined_format['fail_ape'] === 'WARNING') {
+ $this->warning('APE tags not allowed on this file type.');
+ }
+ }
+
+ // set mime type
+ $this->info['mime_type'] = $determined_format['mime_type'];
+
+ // supported format signature pattern detected, but module deleted
+ if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) {
+ fclose($this->fp);
+ return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.');
+ }
+
+ // module requires iconv support
+ // Check encoding/iconv support
+ if (!empty($determined_format['iconv_req']) && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) {
+ $errormessage = 'iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. ';
+ if (GETID3_OS_ISWINDOWS) {
+ $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32';
+ } else {
+ $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch';
+ }
+ return $this->error($errormessage);
+ }
+
+ // include module
+ include_once(GETID3_INCLUDEPATH.$determined_format['include']);
+
+ // instantiate module class
+ $class_name = 'getid3_'.$determined_format['module'];
+ if (!class_exists($class_name)) {
+ return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.');
+ }
+ $class = new $class_name($this);
+ $class->Analyze();
+ unset($class);
+
+ // close file
+ fclose($this->fp);
+
+ // process all tags - copy to 'tags' and convert charsets
+ if ($this->option_tags_process) {
+ $this->HandleAllTags();
+ }
+
+ // perform more calculations
+ if ($this->option_extra_info) {
+ $this->ChannelsBitratePlaytimeCalculations();
+ $this->CalculateCompressionRatioVideo();
+ $this->CalculateCompressionRatioAudio();
+ $this->CalculateReplayGain();
+ $this->ProcessAudioStreams();
+ }
+
+ // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
+ if ($this->option_md5_data) {
+ // do not calc md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too
+ if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) {
+ $this->getHashdata('md5');
+ }
+ }
+
+ // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags
+ if ($this->option_sha1_data) {
+ $this->getHashdata('sha1');
+ }
+
+ // remove undesired keys
+ $this->CleanUp();
+
+ } catch (Exception $e) {
+ $this->error('Caught exception: '.$e->getMessage());
+ }
+
+ // return info array
+ return $this->info;
+ }
+
+
+ // private: error handling
+ public function error($message) {
+ $this->CleanUp();
+ if (!isset($this->info['error'])) {
+ $this->info['error'] = array();
+ }
+ $this->info['error'][] = $message;
+ return $this->info;
+ }
+
+
+ // private: warning handling
+ public function warning($message) {
+ $this->info['warning'][] = $message;
+ return true;
+ }
+
+
+ // private: CleanUp
+ private function CleanUp() {
+
+ // remove possible empty keys
+ $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate');
+ foreach ($AVpossibleEmptyKeys as $dummy => $key) {
+ if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) {
+ unset($this->info['audio'][$key]);
+ }
+ if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) {
+ unset($this->info['video'][$key]);
+ }
+ }
+
+ // remove empty root keys
+ if (!empty($this->info)) {
+ foreach ($this->info as $key => $value) {
+ if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) {
+ unset($this->info[$key]);
+ }
+ }
+ }
+
+ // remove meaningless entries from unknown-format files
+ if (empty($this->info['fileformat'])) {
+ if (isset($this->info['avdataoffset'])) {
+ unset($this->info['avdataoffset']);
+ }
+ if (isset($this->info['avdataend'])) {
+ unset($this->info['avdataend']);
+ }
+ }
+
+ // remove possible duplicated identical entries
+ if (!empty($this->info['error'])) {
+ $this->info['error'] = array_values(array_unique($this->info['error']));
+ }
+ if (!empty($this->info['warning'])) {
+ $this->info['warning'] = array_values(array_unique($this->info['warning']));
+ }
+
+ // remove "global variable" type keys
+ unset($this->info['php_memory_limit']);
+
+ return true;
+ }
+
+
+ // return array containing information about all supported formats
+ public function GetFileFormatArray() {
+ static $format_info = array();
+ if (empty($format_info)) {
+ $format_info = array(
+
+ // Audio formats
+
+ // AC-3 - audio - Dolby AC-3 / Dolby Digital
+ 'ac3' => array(
+ 'pattern' => '^\x0B\x77',
+ 'group' => 'audio',
+ 'module' => 'ac3',
+ 'mime_type' => 'audio/ac3',
+ ),
+
+ // AAC - audio - Advanced Audio Coding (AAC) - ADIF format
+ 'adif' => array(
+ 'pattern' => '^ADIF',
+ 'group' => 'audio',
+ 'module' => 'aac',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_ape' => 'WARNING',
+ ),
+
+/*
+ // AA - audio - Audible Audiobook
+ 'aa' => array(
+ 'pattern' => '^.{4}\x57\x90\x75\x36',
+ 'group' => 'audio',
+ 'module' => 'aa',
+ 'mime_type' => 'audio/audible',
+ ),
+*/
+ // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3)
+ 'adts' => array(
+ 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]',
+ 'group' => 'audio',
+ 'module' => 'aac',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_ape' => 'WARNING',
+ ),
+
+
+ // AU - audio - NeXT/Sun AUdio (AU)
+ 'au' => array(
+ 'pattern' => '^\.snd',
+ 'group' => 'audio',
+ 'module' => 'au',
+ 'mime_type' => 'audio/basic',
+ ),
+
+ // AVR - audio - Audio Visual Research
+ 'avr' => array(
+ 'pattern' => '^2BIT',
+ 'group' => 'audio',
+ 'module' => 'avr',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // BONK - audio - Bonk v0.9+
+ 'bonk' => array(
+ 'pattern' => '^\x00(BONK|INFO|META| ID3)',
+ 'group' => 'audio',
+ 'module' => 'bonk',
+ 'mime_type' => 'audio/xmms-bonk',
+ ),
+
+ // DSS - audio - Digital Speech Standard
+ 'dss' => array(
+ 'pattern' => '^[\x02-\x03]ds[s2]',
+ 'group' => 'audio',
+ 'module' => 'dss',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // DTS - audio - Dolby Theatre System
+ 'dts' => array(
+ 'pattern' => '^\x7F\xFE\x80\x01',
+ 'group' => 'audio',
+ 'module' => 'dts',
+ 'mime_type' => 'audio/dts',
+ ),
+
+ // FLAC - audio - Free Lossless Audio Codec
+ 'flac' => array(
+ 'pattern' => '^fLaC',
+ 'group' => 'audio',
+ 'module' => 'flac',
+ 'mime_type' => 'audio/x-flac',
+ ),
+
+ // LA - audio - Lossless Audio (LA)
+ 'la' => array(
+ 'pattern' => '^LA0[2-4]',
+ 'group' => 'audio',
+ 'module' => 'la',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // LPAC - audio - Lossless Predictive Audio Compression (LPAC)
+ 'lpac' => array(
+ 'pattern' => '^LPAC',
+ 'group' => 'audio',
+ 'module' => 'lpac',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // MIDI - audio - MIDI (Musical Instrument Digital Interface)
+ 'midi' => array(
+ 'pattern' => '^MThd',
+ 'group' => 'audio',
+ 'module' => 'midi',
+ 'mime_type' => 'audio/midi',
+ ),
+
+ // MAC - audio - Monkey's Audio Compressor
+ 'mac' => array(
+ 'pattern' => '^MAC ',
+ 'group' => 'audio',
+ 'module' => 'monkey',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+// has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available
+// // MOD - audio - MODule (assorted sub-formats)
+// 'mod' => array(
+// 'pattern' => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)',
+// 'group' => 'audio',
+// 'module' => 'mod',
+// 'option' => 'mod',
+// 'mime_type' => 'audio/mod',
+// ),
+
+ // MOD - audio - MODule (Impulse Tracker)
+ 'it' => array(
+ 'pattern' => '^IMPM',
+ 'group' => 'audio',
+ 'module' => 'mod',
+ //'option' => 'it',
+ 'mime_type' => 'audio/it',
+ ),
+
+ // MOD - audio - MODule (eXtended Module, various sub-formats)
+ 'xm' => array(
+ 'pattern' => '^Extended Module',
+ 'group' => 'audio',
+ 'module' => 'mod',
+ //'option' => 'xm',
+ 'mime_type' => 'audio/xm',
+ ),
+
+ // MOD - audio - MODule (ScreamTracker)
+ 's3m' => array(
+ 'pattern' => '^.{44}SCRM',
+ 'group' => 'audio',
+ 'module' => 'mod',
+ //'option' => 's3m',
+ 'mime_type' => 'audio/s3m',
+ ),
+
+ // MPC - audio - Musepack / MPEGplus
+ 'mpc' => array(
+ 'pattern' => '^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])',
+ 'group' => 'audio',
+ 'module' => 'mpc',
+ 'mime_type' => 'audio/x-musepack',
+ ),
+
+ // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS)
+ 'mp3' => array(
+ 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]',
+ 'group' => 'audio',
+ 'module' => 'mp3',
+ 'mime_type' => 'audio/mpeg',
+ ),
+
+ // OFR - audio - OptimFROG
+ 'ofr' => array(
+ 'pattern' => '^(\*RIFF|OFR)',
+ 'group' => 'audio',
+ 'module' => 'optimfrog',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // RKAU - audio - RKive AUdio compressor
+ 'rkau' => array(
+ 'pattern' => '^RKA',
+ 'group' => 'audio',
+ 'module' => 'rkau',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // SHN - audio - Shorten
+ 'shn' => array(
+ 'pattern' => '^ajkg',
+ 'group' => 'audio',
+ 'module' => 'shorten',
+ 'mime_type' => 'audio/xmms-shn',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org)
+ 'tta' => array(
+ 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)'
+ 'group' => 'audio',
+ 'module' => 'tta',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // VOC - audio - Creative Voice (VOC)
+ 'voc' => array(
+ 'pattern' => '^Creative Voice File',
+ 'group' => 'audio',
+ 'module' => 'voc',
+ 'mime_type' => 'audio/voc',
+ ),
+
+ // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF)
+ 'vqf' => array(
+ 'pattern' => '^TWIN',
+ 'group' => 'audio',
+ 'module' => 'vqf',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // WV - audio - WavPack (v4.0+)
+ 'wv' => array(
+ 'pattern' => '^wvpk',
+ 'group' => 'audio',
+ 'module' => 'wavpack',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+
+ // Audio-Video formats
+
+ // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio
+ 'asf' => array(
+ 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C',
+ 'group' => 'audio-video',
+ 'module' => 'asf',
+ 'mime_type' => 'video/x-ms-asf',
+ 'iconv_req' => false,
+ ),
+
+ // BINK - audio/video - Bink / Smacker
+ 'bink' => array(
+ 'pattern' => '^(BIK|SMK)',
+ 'group' => 'audio-video',
+ 'module' => 'bink',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // FLV - audio/video - FLash Video
+ 'flv' => array(
+ 'pattern' => '^FLV\x01',
+ 'group' => 'audio-video',
+ 'module' => 'flv',
+ 'mime_type' => 'video/x-flv',
+ ),
+
+ // MKAV - audio/video - Mastroka
+ 'matroska' => array(
+ 'pattern' => '^\x1A\x45\xDF\xA3',
+ 'group' => 'audio-video',
+ 'module' => 'matroska',
+ 'mime_type' => 'video/x-matroska', // may also be audio/x-matroska
+ ),
+
+ // MPEG - audio/video - MPEG (Moving Pictures Experts Group)
+ 'mpeg' => array(
+ 'pattern' => '^\x00\x00\x01(\xBA|\xB3)',
+ 'group' => 'audio-video',
+ 'module' => 'mpeg',
+ 'mime_type' => 'video/mpeg',
+ ),
+
+ // NSV - audio/video - Nullsoft Streaming Video (NSV)
+ 'nsv' => array(
+ 'pattern' => '^NSV[sf]',
+ 'group' => 'audio-video',
+ 'module' => 'nsv',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*))
+ 'ogg' => array(
+ 'pattern' => '^OggS',
+ 'group' => 'audio',
+ 'module' => 'ogg',
+ 'mime_type' => 'application/ogg',
+ 'fail_id3' => 'WARNING',
+ 'fail_ape' => 'WARNING',
+ ),
+
+ // QT - audio/video - Quicktime
+ 'quicktime' => array(
+ 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)',
+ 'group' => 'audio-video',
+ 'module' => 'quicktime',
+ 'mime_type' => 'video/quicktime',
+ ),
+
+ // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF)
+ 'riff' => array(
+ 'pattern' => '^(RIFF|SDSS|FORM)',
+ 'group' => 'audio-video',
+ 'module' => 'riff',
+ 'mime_type' => 'audio/x-wave',
+ 'fail_ape' => 'WARNING',
+ ),
+
+ // Real - audio/video - RealAudio, RealVideo
+ 'real' => array(
+ 'pattern' => '^(\\.RMF|\\.ra)',
+ 'group' => 'audio-video',
+ 'module' => 'real',
+ 'mime_type' => 'audio/x-realaudio',
+ ),
+
+ // SWF - audio/video - ShockWave Flash
+ 'swf' => array(
+ 'pattern' => '^(F|C)WS',
+ 'group' => 'audio-video',
+ 'module' => 'swf',
+ 'mime_type' => 'application/x-shockwave-flash',
+ ),
+
+ // TS - audio/video - MPEG-2 Transport Stream
+ 'ts' => array(
+ 'pattern' => '^(\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G". Check for at least 10 packets matching this pattern
+ 'group' => 'audio-video',
+ 'module' => 'ts',
+ 'mime_type' => 'video/MP2T',
+ ),
+
+
+ // Still-Image formats
+
+ // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4)
+ 'bmp' => array(
+ 'pattern' => '^BM',
+ 'group' => 'graphic',
+ 'module' => 'bmp',
+ 'mime_type' => 'image/bmp',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // GIF - still image - Graphics Interchange Format
+ 'gif' => array(
+ 'pattern' => '^GIF',
+ 'group' => 'graphic',
+ 'module' => 'gif',
+ 'mime_type' => 'image/gif',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // JPEG - still image - Joint Photographic Experts Group (JPEG)
+ 'jpg' => array(
+ 'pattern' => '^\xFF\xD8\xFF',
+ 'group' => 'graphic',
+ 'module' => 'jpg',
+ 'mime_type' => 'image/jpeg',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // PCD - still image - Kodak Photo CD
+ 'pcd' => array(
+ 'pattern' => '^.{2048}PCD_IPI\x00',
+ 'group' => 'graphic',
+ 'module' => 'pcd',
+ 'mime_type' => 'image/x-photo-cd',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // PNG - still image - Portable Network Graphics (PNG)
+ 'png' => array(
+ 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A',
+ 'group' => 'graphic',
+ 'module' => 'png',
+ 'mime_type' => 'image/png',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // SVG - still image - Scalable Vector Graphics (SVG)
+ 'svg' => array(
+ 'pattern' => '(<!DOCTYPE svg PUBLIC |xmlns="http:\/\/www\.w3\.org\/2000\/svg")',
+ 'group' => 'graphic',
+ 'module' => 'svg',
+ 'mime_type' => 'image/svg+xml',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // TIFF - still image - Tagged Information File Format (TIFF)
+ 'tiff' => array(
+ 'pattern' => '^(II\x2A\x00|MM\x00\x2A)',
+ 'group' => 'graphic',
+ 'module' => 'tiff',
+ 'mime_type' => 'image/tiff',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // EFAX - still image - eFax (TIFF derivative)
+ 'efax' => array(
+ 'pattern' => '^\xDC\xFE',
+ 'group' => 'graphic',
+ 'module' => 'efax',
+ 'mime_type' => 'image/efax',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // Data formats
+
+ // ISO - data - International Standards Organization (ISO) CD-ROM Image
+ 'iso' => array(
+ 'pattern' => '^.{32769}CD001',
+ 'group' => 'misc',
+ 'module' => 'iso',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ 'iconv_req' => false,
+ ),
+
+ // RAR - data - RAR compressed data
+ 'rar' => array(
+ 'pattern' => '^Rar\!',
+ 'group' => 'archive',
+ 'module' => 'rar',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // SZIP - audio/data - SZIP compressed data
+ 'szip' => array(
+ 'pattern' => '^SZ\x0A\x04',
+ 'group' => 'archive',
+ 'module' => 'szip',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // TAR - data - TAR compressed data
+ 'tar' => array(
+ 'pattern' => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}',
+ 'group' => 'archive',
+ 'module' => 'tar',
+ 'mime_type' => 'application/x-tar',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // GZIP - data - GZIP compressed data
+ 'gz' => array(
+ 'pattern' => '^\x1F\x8B\x08',
+ 'group' => 'archive',
+ 'module' => 'gzip',
+ 'mime_type' => 'application/x-gzip',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // ZIP - data - ZIP compressed data
+ 'zip' => array(
+ 'pattern' => '^PK\x03\x04',
+ 'group' => 'archive',
+ 'module' => 'zip',
+ 'mime_type' => 'application/zip',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+
+ // Misc other formats
+
+ // PAR2 - data - Parity Volume Set Specification 2.0
+ 'par2' => array (
+ 'pattern' => '^PAR2\x00PKT',
+ 'group' => 'misc',
+ 'module' => 'par2',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // PDF - data - Portable Document Format
+ 'pdf' => array(
+ 'pattern' => '^\x25PDF',
+ 'group' => 'misc',
+ 'module' => 'pdf',
+ 'mime_type' => 'application/pdf',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // MSOFFICE - data - ZIP compressed data
+ 'msoffice' => array(
+ 'pattern' => '^\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', // D0CF11E == DOCFILE == Microsoft Office Document
+ 'group' => 'misc',
+ 'module' => 'msoffice',
+ 'mime_type' => 'application/octet-stream',
+ 'fail_id3' => 'ERROR',
+ 'fail_ape' => 'ERROR',
+ ),
+
+ // CUE - data - CUEsheet (index to single-file disc images)
+ 'cue' => array(
+ 'pattern' => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents
+ 'group' => 'misc',
+ 'module' => 'cue',
+ 'mime_type' => 'application/octet-stream',
+ ),
+
+ );
+ }
+
+ return $format_info;
+ }
+
+
+
+ public function GetFileFormat(&$filedata, $filename='') {
+ // this function will determine the format of a file based on usually
+ // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG,
+ // and in the case of ISO CD image, 6 bytes offset 32kb from the start
+ // of the file).
+
+ // Identify file format - loop through $format_info and detect with reg expr
+ foreach ($this->GetFileFormatArray() as $format_name => $info) {
+ // The /s switch on preg_match() forces preg_match() NOT to treat
+ // newline (0x0A) characters as special chars but do a binary match
+ if (!empty($info['pattern']) && preg_match('#'.$info['pattern'].'#s', $filedata)) {
+ $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
+ return $info;
+ }
+ }
+
+
+ if (preg_match('#\.mp[123a]$#i', $filename)) {
+ // Too many mp3 encoders on the market put gabage in front of mpeg files
+ // use assume format on these if format detection failed
+ $GetFileFormatArray = $this->GetFileFormatArray();
+ $info = $GetFileFormatArray['mp3'];
+ $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
+ return $info;
+ } elseif (preg_match('/\.cue$/i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) {
+ // there's not really a useful consistent "magic" at the beginning of .cue files to identify them
+ // so until I think of something better, just go by filename if all other format checks fail
+ // and verify there's at least one instance of "TRACK xx AUDIO" in the file
+ $GetFileFormatArray = $this->GetFileFormatArray();
+ $info = $GetFileFormatArray['cue'];
+ $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php';
+ return $info;
+ }
+
+ return false;
+ }
+
+
+ // converts array to $encoding charset from $this->encoding
+ public function CharConvert(&$array, $encoding) {
+
+ // identical encoding - end here
+ if ($encoding == $this->encoding) {
+ return;
+ }
+
+ // loop thru array
+ foreach ($array as $key => $value) {
+
+ // go recursive
+ if (is_array($value)) {
+ $this->CharConvert($array[$key], $encoding);
+ }
+
+ // convert string
+ elseif (is_string($value)) {
+ $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value));
+ }
+ }
+ }
+
+
+ public function HandleAllTags() {
+
+ // key name => array (tag name, character encoding)
+ static $tags;
+ if (empty($tags)) {
+ $tags = array(
+ 'asf' => array('asf' , 'UTF-16LE'),
+ 'midi' => array('midi' , 'ISO-8859-1'),
+ 'nsv' => array('nsv' , 'ISO-8859-1'),
+ 'ogg' => array('vorbiscomment' , 'UTF-8'),
+ 'png' => array('png' , 'UTF-8'),
+ 'tiff' => array('tiff' , 'ISO-8859-1'),
+ 'quicktime' => array('quicktime' , 'UTF-8'),
+ 'real' => array('real' , 'ISO-8859-1'),
+ 'vqf' => array('vqf' , 'ISO-8859-1'),
+ 'zip' => array('zip' , 'ISO-8859-1'),
+ 'riff' => array('riff' , 'ISO-8859-1'),
+ 'lyrics3' => array('lyrics3' , 'ISO-8859-1'),
+ 'id3v1' => array('id3v1' , $this->encoding_id3v1),
+ 'id3v2' => array('id3v2' , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8
+ 'ape' => array('ape' , 'UTF-8'),
+ 'cue' => array('cue' , 'ISO-8859-1'),
+ 'matroska' => array('matroska' , 'UTF-8'),
+ 'flac' => array('vorbiscomment' , 'UTF-8'),
+ 'divxtag' => array('divx' , 'ISO-8859-1'),
+ );
+ }
+
+ // loop through comments array
+ foreach ($tags as $comment_name => $tagname_encoding_array) {
+ list($tag_name, $encoding) = $tagname_encoding_array;
+
+ // fill in default encoding type if not already present
+ if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) {
+ $this->info[$comment_name]['encoding'] = $encoding;
+ }
+
+ // copy comments if key name set
+ if (!empty($this->info[$comment_name]['comments'])) {
+ foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) {
+ foreach ($valuearray as $key => $value) {
+ if (is_string($value)) {
+ $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed!
+ }
+ if ($value) {
+ $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value;
+ }
+ }
+ if ($tag_key == 'picture') {
+ unset($this->info[$comment_name]['comments'][$tag_key]);
+ }
+ }
+
+ if (!isset($this->info['tags'][$tag_name])) {
+ // comments are set but contain nothing but empty strings, so skip
+ continue;
+ }
+
+ if ($this->option_tags_html) {
+ foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) {
+ foreach ($valuearray as $key => $value) {
+ if (is_string($value)) {
+ //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding);
+ $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('&#0;', '', trim(getid3_lib::MultiByteCharString2HTML($value, $encoding)));
+ } else {
+ $this->info['tags_html'][$tag_name][$tag_key][$key] = $value;
+ }
+ }
+ }
+ }
+
+ $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted!
+ }
+
+ }
+
+ // pictures can take up a lot of space, and we don't need multiple copies of them
+ // let there be a single copy in [comments][picture], and not elsewhere
+ if (!empty($this->info['tags'])) {
+ $unset_keys = array('tags', 'tags_html');
+ foreach ($this->info['tags'] as $tagtype => $tagarray) {
+ foreach ($tagarray as $tagname => $tagdata) {
+ if ($tagname == 'picture') {
+ foreach ($tagdata as $key => $tagarray) {
+ $this->info['comments']['picture'][] = $tagarray;
+ if (isset($tagarray['data']) && isset($tagarray['image_mime'])) {
+ if (isset($this->info['tags'][$tagtype][$tagname][$key])) {
+ unset($this->info['tags'][$tagtype][$tagname][$key]);
+ }
+ if (isset($this->info['tags_html'][$tagtype][$tagname][$key])) {
+ unset($this->info['tags_html'][$tagtype][$tagname][$key]);
+ }
+ }
+ }
+ }
+ }
+ foreach ($unset_keys as $unset_key) {
+ // remove possible empty keys from (e.g. [tags][id3v2][picture])
+ if (empty($this->info[$unset_key][$tagtype]['picture'])) {
+ unset($this->info[$unset_key][$tagtype]['picture']);
+ }
+ if (empty($this->info[$unset_key][$tagtype])) {
+ unset($this->info[$unset_key][$tagtype]);
+ }
+ if (empty($this->info[$unset_key])) {
+ unset($this->info[$unset_key]);
+ }
+ }
+ // remove duplicate copy of picture data from (e.g. [id3v2][comments][picture])
+ if (isset($this->info[$tagtype]['comments']['picture'])) {
+ unset($this->info[$tagtype]['comments']['picture']);
+ }
+ if (empty($this->info[$tagtype]['comments'])) {
+ unset($this->info[$tagtype]['comments']);
+ }
+ if (empty($this->info[$tagtype])) {
+ unset($this->info[$tagtype]);
+ }
+ }
+ }
+ return true;
+ }
+
+
+ public function getHashdata($algorithm) {
+ switch ($algorithm) {
+ case 'md5':
+ case 'sha1':
+ break;
+
+ default:
+ return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()');
+ break;
+ }
+
+ if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) {
+
+ // We cannot get an identical md5_data value for Ogg files where the comments
+ // span more than 1 Ogg page (compared to the same audio data with smaller
+ // comments) using the normal getID3() method of MD5'ing the data between the
+ // end of the comments and the end of the file (minus any trailing tags),
+ // because the page sequence numbers of the pages that the audio data is on
+ // do not match. Under normal circumstances, where comments are smaller than
+ // the nominal 4-8kB page size, then this is not a problem, but if there are
+ // very large comments, the only way around it is to strip off the comment
+ // tags with vorbiscomment and MD5 that file.
+ // This procedure must be applied to ALL Ogg files, not just the ones with
+ // comments larger than 1 page, because the below method simply MD5's the
+ // whole file with the comments stripped, not just the portion after the
+ // comments block (which is the standard getID3() method.
+
+ // The above-mentioned problem of comments spanning multiple pages and changing
+ // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but
+ // currently vorbiscomment only works on OggVorbis files.
+
+ if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) {
+
+ $this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)');
+ $this->info[$algorithm.'_data'] = false;
+
+ } else {
+
+ // Prevent user from aborting script
+ $old_abort = ignore_user_abort(true);
+
+ // Create empty file
+ $empty = tempnam(GETID3_TEMP_DIR, 'getID3');
+ touch($empty);
+
+ // Use vorbiscomment to make temp file without comments
+ $temp = tempnam(GETID3_TEMP_DIR, 'getID3');
+ $file = $this->info['filenamepath'];
+
+ if (GETID3_OS_ISWINDOWS) {
+
+ if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) {
+
+ $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"';
+ $VorbisCommentError = `$commandline`;
+
+ } else {
+
+ $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR;
+
+ }
+
+ } else {
+
+ $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1';
+ $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1';
+ $VorbisCommentError = `$commandline`;
+
+ }
+
+ if (!empty($VorbisCommentError)) {
+
+ $this->info['warning'][] = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError;
+ $this->info[$algorithm.'_data'] = false;
+
+ } else {
+
+ // Get hash of newly created file
+ switch ($algorithm) {
+ case 'md5':
+ $this->info[$algorithm.'_data'] = md5_file($temp);
+ break;
+
+ case 'sha1':
+ $this->info[$algorithm.'_data'] = sha1_file($temp);
+ break;
+ }
+ }
+
+ // Clean up
+ unlink($empty);
+ unlink($temp);
+
+ // Reset abort setting
+ ignore_user_abort($old_abort);
+
+ }
+
+ } else {
+
+ if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) {
+
+ // get hash from part of file
+ $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm);
+
+ } else {
+
+ // get hash from whole file
+ switch ($algorithm) {
+ case 'md5':
+ $this->info[$algorithm.'_data'] = md5_file($this->info['filenamepath']);
+ break;
+
+ case 'sha1':
+ $this->info[$algorithm.'_data'] = sha1_file($this->info['filenamepath']);
+ break;
+ }
+ }
+
+ }
+ return true;
+ }
+
+
+ public function ChannelsBitratePlaytimeCalculations() {
+
+ // set channelmode on audio
+ if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) {
+ // ignore
+ } elseif ($this->info['audio']['channels'] == 1) {
+ $this->info['audio']['channelmode'] = 'mono';
+ } elseif ($this->info['audio']['channels'] == 2) {
+ $this->info['audio']['channelmode'] = 'stereo';
+ }
+
+ // Calculate combined bitrate - audio + video
+ $CombinedBitrate = 0;
+ $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0);
+ $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0);
+ if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) {
+ $this->info['bitrate'] = $CombinedBitrate;
+ }
+ //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) {
+ // // for example, VBR MPEG video files cannot determine video bitrate:
+ // // should not set overall bitrate and playtime from audio bitrate only
+ // unset($this->info['bitrate']);
+ //}
+
+ // video bitrate undetermined, but calculable
+ if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) {
+ // if video bitrate not set
+ if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) {
+ // AND if audio bitrate is set to same as overall bitrate
+ if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) {
+ // AND if playtime is set
+ if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) {
+ // AND if AV data offset start/end is known
+ // THEN we can calculate the video bitrate
+ $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']);
+ $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate'];
+ }
+ }
+ }
+ }
+
+ if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) {
+ $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate'];
+ }
+
+ if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) {
+ $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds'];
+ }
+ if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) {
+ if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) {
+ // audio only
+ $this->info['audio']['bitrate'] = $this->info['bitrate'];
+ } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) {
+ // video only
+ $this->info['video']['bitrate'] = $this->info['bitrate'];
+ }
+ }
+
+ // Set playtime string
+ if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) {
+ $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']);
+ }
+ }
+
+
+ public function CalculateCompressionRatioVideo() {
+ if (empty($this->info['video'])) {
+ return false;
+ }
+ if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) {
+ return false;
+ }
+ if (empty($this->info['video']['bits_per_sample'])) {
+ return false;
+ }
+
+ switch ($this->info['video']['dataformat']) {
+ case 'bmp':
+ case 'gif':
+ case 'jpeg':
+ case 'jpg':
+ case 'png':
+ case 'tiff':
+ $FrameRate = 1;
+ $PlaytimeSeconds = 1;
+ $BitrateCompressed = $this->info['filesize'] * 8;
+ break;
+
+ default:
+ if (!empty($this->info['video']['frame_rate'])) {
+ $FrameRate = $this->info['video']['frame_rate'];
+ } else {
+ return false;
+ }
+ if (!empty($this->info['playtime_seconds'])) {
+ $PlaytimeSeconds = $this->info['playtime_seconds'];
+ } else {
+ return false;
+ }
+ if (!empty($this->info['video']['bitrate'])) {
+ $BitrateCompressed = $this->info['video']['bitrate'];
+ } else {
+ return false;
+ }
+ break;
+ }
+ $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate;
+
+ $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed;
+ return true;
+ }
+
+
+ public function CalculateCompressionRatioAudio() {
+ if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) {
+ return false;
+ }
+ $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16));
+
+ if (!empty($this->info['audio']['streams'])) {
+ foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) {
+ if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) {
+ $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16));
+ }
+ }
+ }
+ return true;
+ }
+
+
+ public function CalculateReplayGain() {
+ if (isset($this->info['replay_gain'])) {
+ if (!isset($this->info['replay_gain']['reference_volume'])) {
+ $this->info['replay_gain']['reference_volume'] = (double) 89.0;
+ }
+ if (isset($this->info['replay_gain']['track']['adjustment'])) {
+ $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment'];
+ }
+ if (isset($this->info['replay_gain']['album']['adjustment'])) {
+ $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment'];
+ }
+
+ if (isset($this->info['replay_gain']['track']['peak'])) {
+ $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']);
+ }
+ if (isset($this->info['replay_gain']['album']['peak'])) {
+ $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']);
+ }
+ }
+ return true;
+ }
+
+ public function ProcessAudioStreams() {
+ if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) {
+ if (!isset($this->info['audio']['streams'])) {
+ foreach ($this->info['audio'] as $key => $value) {
+ if ($key != 'streams') {
+ $this->info['audio']['streams'][0][$key] = $value;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ public function getid3_tempnam() {
+ return tempnam($this->tempdir, 'gI3');
+ }
+
+ public function include_module($name) {
+ //if (!file_exists($this->include_path.'module.'.$name.'.php')) {
+ if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) {
+ throw new getid3_exception('Required module.'.$name.'.php is missing.');
+ }
+ include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php');
+ return true;
+ }
+
+}
+
+
+abstract class getid3_handler
+{
+ protected $getid3; // pointer
+
+ protected $data_string_flag = false; // analyzing filepointer or string
+ protected $data_string = ''; // string to analyze
+ protected $data_string_position = 0; // seek position in string
+ protected $data_string_length = 0; // string length
+
+ private $dependency_to = null;
+
+
+ public function __construct(getID3 $getid3, $call_module=null) {
+ $this->getid3 = $getid3;
+
+ if ($call_module) {
+ $this->dependency_to = str_replace('getid3_', '', $call_module);
+ }
+ }
+
+
+ // Analyze from file pointer
+ abstract public function Analyze();
+
+
+ // Analyze from string instead
+ public function AnalyzeString($string) {
+ // Enter string mode
+ $this->setStringMode($string);
+
+ // Save info
+ $saved_avdataoffset = $this->getid3->info['avdataoffset'];
+ $saved_avdataend = $this->getid3->info['avdataend'];
+ $saved_filesize = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call
+
+ // Reset some info
+ $this->getid3->info['avdataoffset'] = 0;
+ $this->getid3->info['avdataend'] = $this->getid3->info['filesize'] = $this->data_string_length;
+
+ // Analyze
+ $this->Analyze();
+
+ // Restore some info
+ $this->getid3->info['avdataoffset'] = $saved_avdataoffset;
+ $this->getid3->info['avdataend'] = $saved_avdataend;
+ $this->getid3->info['filesize'] = $saved_filesize;
+
+ // Exit string mode
+ $this->data_string_flag = false;
+ }
+
+ public function setStringMode($string) {
+ $this->data_string_flag = true;
+ $this->data_string = $string;
+ $this->data_string_length = strlen($string);
+ }
+
+ protected function ftell() {
+ if ($this->data_string_flag) {
+ return $this->data_string_position;
+ }
+ return ftell($this->getid3->fp);
+ }
+
+ protected function fread($bytes) {
+ if ($this->data_string_flag) {
+ $this->data_string_position += $bytes;
+ return substr($this->data_string, $this->data_string_position - $bytes, $bytes);
+ }
+ $pos = $this->ftell() + $bytes;
+ if (!getid3_lib::intValueSupported($pos)) {
+ throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10);
+ }
+ return fread($this->getid3->fp, $bytes);
+ }
+
+ protected function fseek($bytes, $whence=SEEK_SET) {
+ if ($this->data_string_flag) {
+ switch ($whence) {
+ case SEEK_SET:
+ $this->data_string_position = $bytes;
+ break;
+
+ case SEEK_CUR:
+ $this->data_string_position += $bytes;
+ break;
+
+ case SEEK_END:
+ $this->data_string_position = $this->data_string_length + $bytes;
+ break;
+ }
+ return 0;
+ } else {
+ $pos = $bytes;
+ if ($whence == SEEK_CUR) {
+ $pos = $this->ftell() + $bytes;
+ } elseif ($whence == SEEK_END) {
+ $pos = $this->info['filesize'] + $bytes;
+ }
+ if (!getid3_lib::intValueSupported($pos)) {
+ throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10);
+ }
+ }
+ return fseek($this->getid3->fp, $bytes, $whence);
+ }
+
+ protected function feof() {
+ if ($this->data_string_flag) {
+ return $this->data_string_position >= $this->data_string_length;
+ }
+ return feof($this->getid3->fp);
+ }
+
+ final protected function isDependencyFor($module) {
+ return $this->dependency_to == $module;
+ }
+
+ protected function error($text)
+ {
+ $this->getid3->info['error'][] = $text;
+
+ return false;
+ }
+
+ protected function warning($text)
+ {
+ return $this->getid3->warning($text);
+ }
+
+ protected function notice($text)
+ {
+ // does nothing for now
+ }
+
+ public function saveAttachment($name, $offset, $length, $image_mime=null) {
+ try {
+
+ // do not extract at all
+ if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) {
+
+ $attachment = null; // do not set any
+
+ // extract to return array
+ } elseif ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) {
+
+ $this->fseek($offset);
+ $attachment = $this->fread($length); // get whole data in one pass, till it is anyway stored in memory
+ if ($attachment === false || strlen($attachment) != $length) {
+ throw new Exception('failed to read attachment data');
+ }
+
+ // assume directory path is given
+ } else {
+
+ // set up destination path
+ $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
+ if (!is_dir($dir) || !is_writable($dir)) { // check supplied directory
+ throw new Exception('supplied path ('.$dir.') does not exist, or is not writable');
+ }
+ $dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : '');
+
+ // create dest file
+ if (($fp_dest = fopen($dest, 'wb')) == false) {
+ throw new Exception('failed to create file '.$dest);
+ }
+
+ // copy data
+ $this->fseek($offset);
+ $buffersize = ($this->data_string_flag ? $length : $this->getid3->fread_buffer_size());
+ $bytesleft = $length;
+ while ($bytesleft > 0) {
+ if (($buffer = $this->fread(min($buffersize, $bytesleft))) === false || ($byteswritten = fwrite($fp_dest, $buffer)) === false || ($byteswritten === 0)) {
+ throw new Exception($buffer === false ? 'not enough data to read' : 'failed to write to destination file, may be not enough disk space');
+ }
+ $bytesleft -= $byteswritten;
+ }
+
+ fclose($fp_dest);
+ $attachment = $dest;
+
+ }
+
+ } catch (Exception $e) {
+
+ // close and remove dest file if created
+ if (isset($fp_dest) && is_resource($fp_dest)) {
+ fclose($fp_dest);
+ unlink($dest);
+ }
+
+ // do not set any is case of error
+ $attachment = null;
+ $this->warning('Failed to extract attachment '.$name.': '.$e->getMessage());
+
+ }
+
+ // seek to the end of attachment
+ $this->fseek($offset + $length);
+
+ return $attachment;
+ }
+
+}
+
+
+class getid3_exception extends Exception
+{
+ public $message;
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/license.txt b/extensions/TimedMediaHandler/libs/getid3/license.txt
new file mode 100644
index 00000000..f349faab
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/license.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License. \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.audio-video.matroska.php b/extensions/TimedMediaHandler/libs/getid3/module.audio-video.matroska.php
new file mode 100644
index 00000000..3c1921fb
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.audio-video.matroska.php
@@ -0,0 +1,1771 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.matriska.php //
+// module for analyzing Matroska containers //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+define('EBML_ID_CHAPTERS', 0x0043A770); // [10][43][A7][70] -- A system to define basic menus and partition data. For more detailed information, look at the Chapters Explanation.
+define('EBML_ID_SEEKHEAD', 0x014D9B74); // [11][4D][9B][74] -- Contains the position of other level 1 elements.
+define('EBML_ID_TAGS', 0x0254C367); // [12][54][C3][67] -- Element containing elements specific to Tracks/Chapters. A list of valid tags can be found <http://www.matroska.org/technical/specs/tagging/index.html>.
+define('EBML_ID_INFO', 0x0549A966); // [15][49][A9][66] -- Contains miscellaneous general information and statistics on the file.
+define('EBML_ID_TRACKS', 0x0654AE6B); // [16][54][AE][6B] -- A top-level block of information with many tracks described.
+define('EBML_ID_SEGMENT', 0x08538067); // [18][53][80][67] -- This element contains all other top-level (level 1) elements. Typically a Matroska file is composed of 1 segment.
+define('EBML_ID_ATTACHMENTS', 0x0941A469); // [19][41][A4][69] -- Contain attached files.
+define('EBML_ID_EBML', 0x0A45DFA3); // [1A][45][DF][A3] -- Set the EBML characteristics of the data to follow. Each EBML document has to start with this.
+define('EBML_ID_CUES', 0x0C53BB6B); // [1C][53][BB][6B] -- A top-level element to speed seeking access. All entries are local to the segment.
+define('EBML_ID_CLUSTER', 0x0F43B675); // [1F][43][B6][75] -- The lower level element containing the (monolithic) Block structure.
+define('EBML_ID_LANGUAGE', 0x02B59C); // [22][B5][9C] -- Specifies the language of the track in the Matroska languages form.
+define('EBML_ID_TRACKTIMECODESCALE', 0x03314F); // [23][31][4F] -- The scale to apply on this track to work at normal speed in relation with other tracks (mostly used to adjust video speed when the audio length differs).
+define('EBML_ID_DEFAULTDURATION', 0x03E383); // [23][E3][83] -- Number of nanoseconds (i.e. not scaled) per frame.
+define('EBML_ID_CODECNAME', 0x058688); // [25][86][88] -- A human-readable string specifying the codec.
+define('EBML_ID_CODECDOWNLOADURL', 0x06B240); // [26][B2][40] -- A URL to download about the codec used.
+define('EBML_ID_TIMECODESCALE', 0x0AD7B1); // [2A][D7][B1] -- Timecode scale in nanoseconds (1.000.000 means all timecodes in the segment are expressed in milliseconds).
+define('EBML_ID_COLOURSPACE', 0x0EB524); // [2E][B5][24] -- Same value as in AVI (32 bits).
+define('EBML_ID_GAMMAVALUE', 0x0FB523); // [2F][B5][23] -- Gamma Value.
+define('EBML_ID_CODECSETTINGS', 0x1A9697); // [3A][96][97] -- A string describing the encoding setting used.
+define('EBML_ID_CODECINFOURL', 0x1B4040); // [3B][40][40] -- A URL to find information about the codec used.
+define('EBML_ID_PREVFILENAME', 0x1C83AB); // [3C][83][AB] -- An escaped filename corresponding to the previous segment.
+define('EBML_ID_PREVUID', 0x1CB923); // [3C][B9][23] -- A unique ID to identify the previous chained segment (128 bits).
+define('EBML_ID_NEXTFILENAME', 0x1E83BB); // [3E][83][BB] -- An escaped filename corresponding to the next segment.
+define('EBML_ID_NEXTUID', 0x1EB923); // [3E][B9][23] -- A unique ID to identify the next chained segment (128 bits).
+define('EBML_ID_CONTENTCOMPALGO', 0x0254); // [42][54] -- The compression algorithm used. Algorithms that have been specified so far are:
+define('EBML_ID_CONTENTCOMPSETTINGS', 0x0255); // [42][55] -- Settings that might be needed by the decompressor. For Header Stripping (ContentCompAlgo=3), the bytes that were removed from the beggining of each frames of the track.
+define('EBML_ID_DOCTYPE', 0x0282); // [42][82] -- A string that describes the type of document that follows this EBML header ('matroska' in our case).
+define('EBML_ID_DOCTYPEREADVERSION', 0x0285); // [42][85] -- The minimum DocType version an interpreter has to support to read this file.
+define('EBML_ID_EBMLVERSION', 0x0286); // [42][86] -- The version of EBML parser used to create the file.
+define('EBML_ID_DOCTYPEVERSION', 0x0287); // [42][87] -- The version of DocType interpreter used to create the file.
+define('EBML_ID_EBMLMAXIDLENGTH', 0x02F2); // [42][F2] -- The maximum length of the IDs you'll find in this file (4 or less in Matroska).
+define('EBML_ID_EBMLMAXSIZELENGTH', 0x02F3); // [42][F3] -- The maximum length of the sizes you'll find in this file (8 or less in Matroska). This does not override the element size indicated at the beginning of an element. Elements that have an indicated size which is larger than what is allowed by EBMLMaxSizeLength shall be considered invalid.
+define('EBML_ID_EBMLREADVERSION', 0x02F7); // [42][F7] -- The minimum EBML version a parser has to support to read this file.
+define('EBML_ID_CHAPLANGUAGE', 0x037C); // [43][7C] -- The languages corresponding to the string, in the bibliographic ISO-639-2 form.
+define('EBML_ID_CHAPCOUNTRY', 0x037E); // [43][7E] -- The countries corresponding to the string, same 2 octets as in Internet domains.
+define('EBML_ID_SEGMENTFAMILY', 0x0444); // [44][44] -- A randomly generated unique ID that all segments related to each other must use (128 bits).
+define('EBML_ID_DATEUTC', 0x0461); // [44][61] -- Date of the origin of timecode (value 0), i.e. production date.
+define('EBML_ID_TAGLANGUAGE', 0x047A); // [44][7A] -- Specifies the language of the tag specified, in the Matroska languages form.
+define('EBML_ID_TAGDEFAULT', 0x0484); // [44][84] -- Indication to know if this is the default/original language to use for the given tag.
+define('EBML_ID_TAGBINARY', 0x0485); // [44][85] -- The values of the Tag if it is binary. Note that this cannot be used in the same SimpleTag as TagString.
+define('EBML_ID_TAGSTRING', 0x0487); // [44][87] -- The value of the Tag.
+define('EBML_ID_DURATION', 0x0489); // [44][89] -- Duration of the segment (based on TimecodeScale).
+define('EBML_ID_CHAPPROCESSPRIVATE', 0x050D); // [45][0D] -- Some optional data attached to the ChapProcessCodecID information. For ChapProcessCodecID = 1, it is the "DVD level" equivalent.
+define('EBML_ID_CHAPTERFLAGENABLED', 0x0598); // [45][98] -- Specify wether the chapter is enabled. It can be enabled/disabled by a Control Track. When disabled, the movie should skip all the content between the TimeStart and TimeEnd of this chapter.
+define('EBML_ID_TAGNAME', 0x05A3); // [45][A3] -- The name of the Tag that is going to be stored.
+define('EBML_ID_EDITIONENTRY', 0x05B9); // [45][B9] -- Contains all information about a segment edition.
+define('EBML_ID_EDITIONUID', 0x05BC); // [45][BC] -- A unique ID to identify the edition. It's useful for tagging an edition.
+define('EBML_ID_EDITIONFLAGHIDDEN', 0x05BD); // [45][BD] -- If an edition is hidden (1), it should not be available to the user interface (but still to Control Tracks).
+define('EBML_ID_EDITIONFLAGDEFAULT', 0x05DB); // [45][DB] -- If a flag is set (1) the edition should be used as the default one.
+define('EBML_ID_EDITIONFLAGORDERED', 0x05DD); // [45][DD] -- Specify if the chapters can be defined multiple times and the order to play them is enforced.
+define('EBML_ID_FILEDATA', 0x065C); // [46][5C] -- The data of the file.
+define('EBML_ID_FILEMIMETYPE', 0x0660); // [46][60] -- MIME type of the file.
+define('EBML_ID_FILENAME', 0x066E); // [46][6E] -- Filename of the attached file.
+define('EBML_ID_FILEREFERRAL', 0x0675); // [46][75] -- A binary value that a track/codec can refer to when the attachment is needed.
+define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file.
+define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible.
+define('EBML_ID_CONTENTENCALGO', 0x07E1); // [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values:
+define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the the data was encrypted with.
+define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents.
+define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with.
+define('EBML_ID_CONTENTSIGALGO', 0x07E5); // [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
+define('EBML_ID_CONTENTSIGHASHALGO', 0x07E6); // [47][E6] -- The hash algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values:
+define('EBML_ID_MUXINGAPP', 0x0D80); // [4D][80] -- Muxing application or library ("libmatroska-0.4.3").
+define('EBML_ID_SEEK', 0x0DBB); // [4D][BB] -- Contains a single seek entry to an EBML element.
+define('EBML_ID_CONTENTENCODINGORDER', 0x1031); // [50][31] -- Tells when this modification was used during encoding/muxing starting with 0 and counting upwards. The decoder/demuxer has to start with the highest order number it finds and work its way down. This value has to be unique over all ContentEncodingOrder elements in the segment.
+define('EBML_ID_CONTENTENCODINGSCOPE', 0x1032); // [50][32] -- A bit field that describes which elements have been modified in this way. Values (big endian) can be OR'ed. Possible values:
+define('EBML_ID_CONTENTENCODINGTYPE', 0x1033); // [50][33] -- A value describing what kind of transformation has been done. Possible values:
+define('EBML_ID_CONTENTCOMPRESSION', 0x1034); // [50][34] -- Settings describing the compression used. Must be present if the value of ContentEncodingType is 0 and absent otherwise. Each block must be decompressable even if no previous block is available in order not to prevent seeking.
+define('EBML_ID_CONTENTENCRYPTION', 0x1035); // [50][35] -- Settings describing the encryption used. Must be present if the value of ContentEncodingType is 1 and absent otherwise.
+define('EBML_ID_CUEREFNUMBER', 0x135F); // [53][5F] -- Number of the referenced Block of Track X in the specified Cluster.
+define('EBML_ID_NAME', 0x136E); // [53][6E] -- A human-readable track name.
+define('EBML_ID_CUEBLOCKNUMBER', 0x1378); // [53][78] -- Number of the Block in the specified Cluster.
+define('EBML_ID_TRACKOFFSET', 0x137F); // [53][7F] -- A value to add to the Block's Timecode. This can be used to adjust the playback offset of a track.
+define('EBML_ID_SEEKID', 0x13AB); // [53][AB] -- The binary ID corresponding to the element name.
+define('EBML_ID_SEEKPOSITION', 0x13AC); // [53][AC] -- The position of the element in the segment in octets (0 = first level 1 element).
+define('EBML_ID_STEREOMODE', 0x13B8); // [53][B8] -- Stereo-3D video mode.
+define('EBML_ID_OLDSTEREOMODE', 0x13B9); // [53][B9] -- Bogus StereoMode value used in old versions of libmatroska. DO NOT USE. (0: mono, 1: right eye, 2: left eye, 3: both eyes).
+define('EBML_ID_PIXELCROPBOTTOM', 0x14AA); // [54][AA] -- The number of video pixels to remove at the bottom of the image (for HDTV content).
+define('EBML_ID_DISPLAYWIDTH', 0x14B0); // [54][B0] -- Width of the video frames to display.
+define('EBML_ID_DISPLAYUNIT', 0x14B2); // [54][B2] -- Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches).
+define('EBML_ID_ASPECTRATIOTYPE', 0x14B3); // [54][B3] -- Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed).
+define('EBML_ID_DISPLAYHEIGHT', 0x14BA); // [54][BA] -- Height of the video frames to display.
+define('EBML_ID_PIXELCROPTOP', 0x14BB); // [54][BB] -- The number of video pixels to remove at the top of the image.
+define('EBML_ID_PIXELCROPLEFT', 0x14CC); // [54][CC] -- The number of video pixels to remove on the left of the image.
+define('EBML_ID_PIXELCROPRIGHT', 0x14DD); // [54][DD] -- The number of video pixels to remove on the right of the image.
+define('EBML_ID_FLAGFORCED', 0x15AA); // [55][AA] -- Set if that track MUST be used during playback. There can be many forced track for a kind (audio, video or subs), the player should select the one which language matches the user preference or the default + forced track. Overlay MAY happen between a forced and non-forced track of the same kind.
+define('EBML_ID_MAXBLOCKADDITIONID', 0x15EE); // [55][EE] -- The maximum value of BlockAddID. A value 0 means there is no BlockAdditions for this track.
+define('EBML_ID_WRITINGAPP', 0x1741); // [57][41] -- Writing application ("mkvmerge-0.3.3").
+define('EBML_ID_CLUSTERSILENTTRACKS', 0x1854); // [58][54] -- The list of tracks that are not used in that part of the stream. It is useful when using overlay tracks on seeking. Then you should decide what track to use.
+define('EBML_ID_CLUSTERSILENTTRACKNUMBER', 0x18D7); // [58][D7] -- One of the track number that are not used from now on in the stream. It could change later if not specified as silent in a further Cluster.
+define('EBML_ID_ATTACHEDFILE', 0x21A7); // [61][A7] -- An attached file.
+define('EBML_ID_CONTENTENCODING', 0x2240); // [62][40] -- Settings for one content encoding like compression or encryption.
+define('EBML_ID_BITDEPTH', 0x2264); // [62][64] -- Bits per sample, mostly used for PCM.
+define('EBML_ID_CODECPRIVATE', 0x23A2); // [63][A2] -- Private data only known to the codec.
+define('EBML_ID_TARGETS', 0x23C0); // [63][C0] -- Contain all UIDs where the specified meta data apply. It is void to describe everything in the segment.
+define('EBML_ID_CHAPTERPHYSICALEQUIV', 0x23C3); // [63][C3] -- Specify the physical equivalent of this ChapterAtom like "DVD" (60) or "SIDE" (50), see complete list of values.
+define('EBML_ID_TAGCHAPTERUID', 0x23C4); // [63][C4] -- A unique ID to identify the Chapter(s) the tags belong to. If the value is 0 at this level, the tags apply to all chapters in the Segment.
+define('EBML_ID_TAGTRACKUID', 0x23C5); // [63][C5] -- A unique ID to identify the Track(s) the tags belong to. If the value is 0 at this level, the tags apply to all tracks in the Segment.
+define('EBML_ID_TAGATTACHMENTUID', 0x23C6); // [63][C6] -- A unique ID to identify the Attachment(s) the tags belong to. If the value is 0 at this level, the tags apply to all the attachments in the Segment.
+define('EBML_ID_TAGEDITIONUID', 0x23C9); // [63][C9] -- A unique ID to identify the EditionEntry(s) the tags belong to. If the value is 0 at this level, the tags apply to all editions in the Segment.
+define('EBML_ID_TARGETTYPE', 0x23CA); // [63][CA] -- An informational string that can be used to display the logical level of the target like "ALBUM", "TRACK", "MOVIE", "CHAPTER", etc (see TargetType).
+define('EBML_ID_TRACKTRANSLATE', 0x2624); // [66][24] -- The track identification for the given Chapter Codec.
+define('EBML_ID_TRACKTRANSLATETRACKID', 0x26A5); // [66][A5] -- The binary value used to represent this track in the chapter codec data. The format depends on the ChapProcessCodecID used.
+define('EBML_ID_TRACKTRANSLATECODEC', 0x26BF); // [66][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu).
+define('EBML_ID_TRACKTRANSLATEEDITIONUID', 0x26FC); // [66][FC] -- Specify an edition UID on which this translation applies. When not specified, it means for all editions found in the segment.
+define('EBML_ID_SIMPLETAG', 0x27C8); // [67][C8] -- Contains general information about the target.
+define('EBML_ID_TARGETTYPEVALUE', 0x28CA); // [68][CA] -- A number to indicate the logical level of the target (see TargetType).
+define('EBML_ID_CHAPPROCESSCOMMAND', 0x2911); // [69][11] -- Contains all the commands associated to the Atom.
+define('EBML_ID_CHAPPROCESSTIME', 0x2922); // [69][22] -- Defines when the process command should be handled (0: during the whole chapter, 1: before starting playback, 2: after playback of the chapter).
+define('EBML_ID_CHAPTERTRANSLATE', 0x2924); // [69][24] -- A tuple of corresponding ID used by chapter codecs to represent this segment.
+define('EBML_ID_CHAPPROCESSDATA', 0x2933); // [69][33] -- Contains the command information. The data should be interpreted depending on the ChapProcessCodecID value. For ChapProcessCodecID = 1, the data correspond to the binary DVD cell pre/post commands.
+define('EBML_ID_CHAPPROCESS', 0x2944); // [69][44] -- Contains all the commands associated to the Atom.
+define('EBML_ID_CHAPPROCESSCODECID', 0x2955); // [69][55] -- Contains the type of the codec used for the processing. A value of 0 means native Matroska processing (to be defined), a value of 1 means the DVD command set is used. More codec IDs can be added later.
+define('EBML_ID_CHAPTERTRANSLATEID', 0x29A5); // [69][A5] -- The binary value used to represent this segment in the chapter codec data. The format depends on the ChapProcessCodecID used.
+define('EBML_ID_CHAPTERTRANSLATECODEC', 0x29BF); // [69][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu).
+define('EBML_ID_CHAPTERTRANSLATEEDITIONUID', 0x29FC); // [69][FC] -- Specify an edition UID on which this correspondance applies. When not specified, it means for all editions found in the segment.
+define('EBML_ID_CONTENTENCODINGS', 0x2D80); // [6D][80] -- Settings for several content encoding mechanisms like compression or encryption.
+define('EBML_ID_MINCACHE', 0x2DE7); // [6D][E7] -- The minimum number of frames a player should be able to cache during playback. If set to 0, the reference pseudo-cache system is not used.
+define('EBML_ID_MAXCACHE', 0x2DF8); // [6D][F8] -- The maximum cache size required to store referenced frames in and the current frame. 0 means no cache is needed.
+define('EBML_ID_CHAPTERSEGMENTUID', 0x2E67); // [6E][67] -- A segment to play in place of this chapter. Edition ChapterSegmentEditionUID should be used for this segment, otherwise no edition is used.
+define('EBML_ID_CHAPTERSEGMENTEDITIONUID', 0x2EBC); // [6E][BC] -- The edition to play from the segment linked in ChapterSegmentUID.
+define('EBML_ID_TRACKOVERLAY', 0x2FAB); // [6F][AB] -- Specify that this track is an overlay track for the Track specified (in the u-integer). That means when this track has a gap (see SilentTracks) the overlay track should be used instead. The order of multiple TrackOverlay matters, the first one is the one that should be used. If not found it should be the second, etc.
+define('EBML_ID_TAG', 0x3373); // [73][73] -- Element containing elements specific to Tracks/Chapters.
+define('EBML_ID_SEGMENTFILENAME', 0x3384); // [73][84] -- A filename corresponding to this segment.
+define('EBML_ID_SEGMENTUID', 0x33A4); // [73][A4] -- A randomly generated unique ID to identify the current segment between many others (128 bits).
+define('EBML_ID_CHAPTERUID', 0x33C4); // [73][C4] -- A unique ID to identify the Chapter.
+define('EBML_ID_TRACKUID', 0x33C5); // [73][C5] -- A unique ID to identify the Track. This should be kept the same when making a direct stream copy of the Track to another file.
+define('EBML_ID_ATTACHMENTLINK', 0x3446); // [74][46] -- The UID of an attachment that is used by this codec.
+define('EBML_ID_CLUSTERBLOCKADDITIONS', 0x35A1); // [75][A1] -- Contain additional blocks to complete the main one. An EBML parser that has no knowledge of the Block structure could still see and use/skip these data.
+define('EBML_ID_CHANNELPOSITIONS', 0x347B); // [7D][7B] -- Table of horizontal angles for each successive channel, see appendix.
+define('EBML_ID_OUTPUTSAMPLINGFREQUENCY', 0x38B5); // [78][B5] -- Real output sampling frequency in Hz (used for SBR techniques).
+define('EBML_ID_TITLE', 0x3BA9); // [7B][A9] -- General name of the segment.
+define('EBML_ID_CHAPTERDISPLAY', 0x00); // [80] -- Contains all possible strings to use for the chapter display.
+define('EBML_ID_TRACKTYPE', 0x03); // [83] -- A set of track types coded on 8 bits (1: video, 2: audio, 3: complex, 0x10: logo, 0x11: subtitle, 0x12: buttons, 0x20: control).
+define('EBML_ID_CHAPSTRING', 0x05); // [85] -- Contains the string to use as the chapter atom.
+define('EBML_ID_CODECID', 0x06); // [86] -- An ID corresponding to the codec, see the codec page for more info.
+define('EBML_ID_FLAGDEFAULT', 0x08); // [88] -- Set if that track (audio, video or subs) SHOULD be used if no language found matches the user preference.
+define('EBML_ID_CHAPTERTRACKNUMBER', 0x09); // [89] -- UID of the Track to apply this chapter too. In the absense of a control track, choosing this chapter will select the listed Tracks and deselect unlisted tracks. Absense of this element indicates that the Chapter should be applied to any currently used Tracks.
+define('EBML_ID_CLUSTERSLICES', 0x0E); // [8E] -- Contains slices description.
+define('EBML_ID_CHAPTERTRACK', 0x0F); // [8F] -- List of tracks on which the chapter applies. If this element is not present, all tracks apply
+define('EBML_ID_CHAPTERTIMESTART', 0x11); // [91] -- Timecode of the start of Chapter (not scaled).
+define('EBML_ID_CHAPTERTIMEEND', 0x12); // [92] -- Timecode of the end of Chapter (timecode excluded, not scaled).
+define('EBML_ID_CUEREFTIME', 0x16); // [96] -- Timecode of the referenced Block.
+define('EBML_ID_CUEREFCLUSTER', 0x17); // [97] -- Position of the Cluster containing the referenced Block.
+define('EBML_ID_CHAPTERFLAGHIDDEN', 0x18); // [98] -- If a chapter is hidden (1), it should not be available to the user interface (but still to Control Tracks).
+define('EBML_ID_FLAGINTERLACED', 0x1A); // [9A] -- Set if the video is interlaced.
+define('EBML_ID_CLUSTERBLOCKDURATION', 0x1B); // [9B] -- The duration of the Block (based on TimecodeScale). This element is mandatory when DefaultDuration is set for the track. When not written and with no DefaultDuration, the value is assumed to be the difference between the timecode of this Block and the timecode of the next Block in "display" order (not coding order). This element can be useful at the end of a Track (as there is not other Block available), or when there is a break in a track like for subtitle tracks.
+define('EBML_ID_FLAGLACING', 0x1C); // [9C] -- Set if the track may contain blocks using lacing.
+define('EBML_ID_CHANNELS', 0x1F); // [9F] -- Numbers of channels in the track.
+define('EBML_ID_CLUSTERBLOCKGROUP', 0x20); // [A0] -- Basic container of information containing a single Block or BlockVirtual, and information specific to that Block/VirtualBlock.
+define('EBML_ID_CLUSTERBLOCK', 0x21); // [A1] -- Block containing the actual data to be rendered and a timecode relative to the Cluster Timecode.
+define('EBML_ID_CLUSTERBLOCKVIRTUAL', 0x22); // [A2] -- A Block with no data. It must be stored in the stream at the place the real Block should be in display order.
+define('EBML_ID_CLUSTERSIMPLEBLOCK', 0x23); // [A3] -- Similar to Block but without all the extra information, mostly used to reduced overhead when no extra feature is needed.
+define('EBML_ID_CLUSTERCODECSTATE', 0x24); // [A4] -- The new codec state to use. Data interpretation is private to the codec. This information should always be referenced by a seek entry.
+define('EBML_ID_CLUSTERBLOCKADDITIONAL', 0x25); // [A5] -- Interpreted by the codec as it wishes (using the BlockAddID).
+define('EBML_ID_CLUSTERBLOCKMORE', 0x26); // [A6] -- Contain the BlockAdditional and some parameters.
+define('EBML_ID_CLUSTERPOSITION', 0x27); // [A7] -- Position of the Cluster in the segment (0 in live broadcast streams). It might help to resynchronise offset on damaged streams.
+define('EBML_ID_CODECDECODEALL', 0x2A); // [AA] -- The codec can decode potentially damaged data.
+define('EBML_ID_CLUSTERPREVSIZE', 0x2B); // [AB] -- Size of the previous Cluster, in octets. Can be useful for backward playing.
+define('EBML_ID_TRACKENTRY', 0x2E); // [AE] -- Describes a track with all elements.
+define('EBML_ID_CLUSTERENCRYPTEDBLOCK', 0x2F); // [AF] -- Similar to SimpleBlock but the data inside the Block are Transformed (encrypt and/or signed).
+define('EBML_ID_PIXELWIDTH', 0x30); // [B0] -- Width of the encoded video frames in pixels.
+define('EBML_ID_CUETIME', 0x33); // [B3] -- Absolute timecode according to the segment time base.
+define('EBML_ID_SAMPLINGFREQUENCY', 0x35); // [B5] -- Sampling frequency in Hz.
+define('EBML_ID_CHAPTERATOM', 0x36); // [B6] -- Contains the atom information to use as the chapter atom (apply to all tracks).
+define('EBML_ID_CUETRACKPOSITIONS', 0x37); // [B7] -- Contain positions for different tracks corresponding to the timecode.
+define('EBML_ID_FLAGENABLED', 0x39); // [B9] -- Set if the track is used.
+define('EBML_ID_PIXELHEIGHT', 0x3A); // [BA] -- Height of the encoded video frames in pixels.
+define('EBML_ID_CUEPOINT', 0x3B); // [BB] -- Contains all information relative to a seek point in the segment.
+define('EBML_ID_CRC32', 0x3F); // [BF] -- The CRC is computed on all the data of the Master element it's in, regardless of its position. It's recommended to put the CRC value at the beggining of the Master element for easier reading. All level 1 elements should include a CRC-32.
+define('EBML_ID_CLUSTERBLOCKADDITIONID', 0x4B); // [CB] -- The ID of the BlockAdditional element (0 is the main Block).
+define('EBML_ID_CLUSTERLACENUMBER', 0x4C); // [CC] -- The reverse number of the frame in the lace (0 is the last frame, 1 is the next to last, etc). While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback.
+define('EBML_ID_CLUSTERFRAMENUMBER', 0x4D); // [CD] -- The number of the frame to generate from this lace with this delay (allow you to generate many frames from the same Block/Frame).
+define('EBML_ID_CLUSTERDELAY', 0x4E); // [CE] -- The (scaled) delay to apply to the element.
+define('EBML_ID_CLUSTERDURATION', 0x4F); // [CF] -- The (scaled) duration to apply to the element.
+define('EBML_ID_TRACKNUMBER', 0x57); // [D7] -- The track number as used in the Block Header (using more than 127 tracks is not encouraged, though the design allows an unlimited number).
+define('EBML_ID_CUEREFERENCE', 0x5B); // [DB] -- The Clusters containing the required referenced Blocks.
+define('EBML_ID_VIDEO', 0x60); // [E0] -- Video settings.
+define('EBML_ID_AUDIO', 0x61); // [E1] -- Audio settings.
+define('EBML_ID_CLUSTERTIMESLICE', 0x68); // [E8] -- Contains extra time information about the data contained in the Block. While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback.
+define('EBML_ID_CUECODECSTATE', 0x6A); // [EA] -- The position of the Codec State corresponding to this Cue element. 0 means that the data is taken from the initial Track Entry.
+define('EBML_ID_CUEREFCODECSTATE', 0x6B); // [EB] -- The position of the Codec State corresponding to this referenced element. 0 means that the data is taken from the initial Track Entry.
+define('EBML_ID_VOID', 0x6C); // [EC] -- Used to void damaged data, to avoid unexpected behaviors when using damaged data. The content is discarded. Also used to reserve space in a sub-element for later use.
+define('EBML_ID_CLUSTERTIMECODE', 0x67); // [E7] -- Absolute timecode of the cluster (based on TimecodeScale).
+define('EBML_ID_CLUSTERBLOCKADDID', 0x6E); // [EE] -- An ID to identify the BlockAdditional level.
+define('EBML_ID_CUECLUSTERPOSITION', 0x71); // [F1] -- The position of the Cluster containing the required Block.
+define('EBML_ID_CUETRACK', 0x77); // [F7] -- The track for which a position is given.
+define('EBML_ID_CLUSTERREFERENCEPRIORITY', 0x7A); // [FA] -- This frame is referenced and has the specified cache priority. In cache only a frame of the same or higher priority can replace this frame. A value of 0 means the frame is not referenced.
+define('EBML_ID_CLUSTERREFERENCEBLOCK', 0x7B); // [FB] -- Timecode of another frame used as a reference (ie: B or P frame). The timecode is relative to the block it's attached to.
+define('EBML_ID_CLUSTERREFERENCEVIRTUAL', 0x7D); // [FD] -- Relative position of the data that should be in position of the virtual block.
+
+
+/**
+* @tutorial http://www.matroska.org/technical/specs/index.html
+*
+* @todo Rewrite EBML parser to reduce it's size and honor default element values
+* @todo After rewrite implement stream size calculation, that will provide additional useful info and enable AAC/FLAC audio bitrate detection
+*/
+class getid3_matroska extends getid3_handler
+{
+ // public options
+ public static $hide_clusters = true; // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE]
+ public static $parse_whole_file = false; // true to parse the whole file, not only header [default: FALSE]
+
+ // private parser settings/placeholders
+ private $EBMLbuffer = '';
+ private $EBMLbuffer_offset = 0;
+ private $EBMLbuffer_length = 0;
+ private $current_offset = 0;
+ private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID);
+
+ public function Analyze()
+ {
+ $info = &$this->getid3->info;
+
+ // parse container
+ try {
+ $this->parseEBML($info);
+ } catch (Exception $e) {
+ $info['error'][] = 'EBML parser: '.$e->getMessage();
+ }
+
+ // calculate playtime
+ if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
+ foreach ($info['matroska']['info'] as $key => $infoarray) {
+ if (isset($infoarray['Duration'])) {
+ // TimecodeScale is how many nanoseconds each Duration unit is
+ $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000);
+ break;
+ }
+ }
+ }
+
+ // extract tags
+ if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) {
+ foreach ($info['matroska']['tags'] as $key => $infoarray) {
+ $this->ExtractCommentsSimpleTag($infoarray);
+ }
+ }
+
+ // process tracks
+ if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
+ foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) {
+
+ $track_info = array();
+ $track_info['dataformat'] = self::CodecIDtoCommonName($trackarray['CodecID']);
+ $track_info['default'] = (isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true);
+ if (isset($trackarray['Name'])) { $track_info['name'] = $trackarray['Name']; }
+
+ switch ($trackarray['TrackType']) {
+
+ case 1: // Video
+ $track_info['resolution_x'] = $trackarray['PixelWidth'];
+ $track_info['resolution_y'] = $trackarray['PixelHeight'];
+ $track_info['display_unit'] = self::displayUnit(isset($trackarray['DisplayUnit']) ? $trackarray['DisplayUnit'] : 0);
+ $track_info['display_x'] = (isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth']);
+ $track_info['display_y'] = (isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight']);
+
+ if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; }
+ if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; }
+ if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; }
+ if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; }
+ if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); }
+ if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; }
+
+ switch ($trackarray['CodecID']) {
+ case 'V_MS/VFW/FOURCC':
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
+ $this->warning('Unable to parse codec private data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"');
+ break;
+ }
+ $parsed = getid3_riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']);
+ $track_info['codec'] = getid3_riff::fourccLookup($parsed['fourcc']);
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
+ break;
+
+ /*case 'V_MPEG4/ISO/AVC':
+ $h264['profile'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 1, 1));
+ $h264['level'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 3, 1));
+ $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 4, 1));
+ $h264['NALUlength'] = ($rn & 3) + 1;
+ $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 5, 1));
+ $nsps = ($rn & 31);
+ $offset = 6;
+ for ($i = 0; $i < $nsps; $i ++) {
+ $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
+ $h264['SPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
+ $offset += 2 + $length;
+ }
+ $npps = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 1));
+ $offset += 1;
+ for ($i = 0; $i < $npps; $i ++) {
+ $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2));
+ $h264['PPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length);
+ $offset += 2 + $length;
+ }
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $h264;
+ break;*/
+ }
+
+ $info['video']['streams'][] = $track_info;
+ break;
+
+ case 2: // Audio
+ $track_info['sample_rate'] = (isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0);
+ $track_info['channels'] = (isset($trackarray['Channels']) ? $trackarray['Channels'] : 1);
+ $track_info['language'] = (isset($trackarray['Language']) ? $trackarray['Language'] : 'eng');
+ if (isset($trackarray['BitDepth'])) { $track_info['bits_per_sample'] = $trackarray['BitDepth']; }
+ if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; }
+
+ switch ($trackarray['CodecID']) {
+ case 'A_PCM/INT/LIT':
+ case 'A_PCM/INT/BIG':
+ $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth'];
+ break;
+
+ case 'A_AC3':
+ case 'A_DTS':
+ case 'A_MPEG/L3':
+ case 'A_MPEG/L2':
+ case 'A_FLAC':
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']).'.php', __FILE__, false)) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.'.$track_info['dataformat'].'.php"');
+ break;
+ }
+
+ if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set');
+ break;
+ }
+
+ // create temp instance
+ $getid3_temp = new getID3();
+ if ($track_info['dataformat'] != 'flac') {
+ $getid3_temp->openfile($this->getid3->filename);
+ }
+ $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'];
+ if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') {
+ $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length'];
+ }
+
+ // analyze
+ $class = 'getid3_'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']);
+ $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat'];
+ $getid3_audio = new $class($getid3_temp, __CLASS__);
+ if ($track_info['dataformat'] == 'flac') {
+ $getid3_audio->AnalyzeString($trackarray['CodecPrivate']);
+ }
+ else {
+ $getid3_audio->Analyze();
+ }
+ if (!empty($getid3_temp->info[$header_data_key])) {
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key];
+ if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
+ foreach ($getid3_temp->info['audio'] as $key => $value) {
+ $track_info[$key] = $value;
+ }
+ }
+ }
+ else {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because '.$class.'::Analyze() failed at offset '.$getid3_temp->info['avdataoffset']);
+ }
+
+ // copy errors and warnings
+ if (!empty($getid3_temp->info['error'])) {
+ foreach ($getid3_temp->info['error'] as $newerror) {
+ $this->warning($class.'() says: ['.$newerror.']');
+ }
+ }
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $newerror) {
+ if ($track_info['dataformat'] == 'mp3' && preg_match('/^Probable truncated file: expecting \d+ bytes of audio data, only found \d+ \(short by \d+ bytes\)$/', $newerror)) {
+ // LAME/Xing header is probably set, but audio data is chunked into Matroska file and near-impossible to verify if audio stream is complete, so ignore useless warning
+ continue;
+ }
+ $this->warning($class.'() says: ['.$newerror.']');
+ }
+ }
+ unset($getid3_temp, $getid3_audio);
+ break;
+
+ case 'A_AAC':
+ case 'A_AAC/MPEG2/LC':
+ case 'A_AAC/MPEG2/LC/SBR':
+ case 'A_AAC/MPEG4/LC':
+ case 'A_AAC/MPEG4/LC/SBR':
+ $this->warning($trackarray['CodecID'].' audio data contains no header, audio/video bitrates can\'t be calculated');
+ break;
+
+ case 'A_VORBIS':
+ if (!isset($trackarray['CodecPrivate'])) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data not set');
+ break;
+ }
+ $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1);
+ if ($vorbis_offset === false) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data does not contain "vorbis" keyword');
+ break;
+ }
+ $vorbis_offset -= 1;
+
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, false)) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.ogg.php"');
+ break;
+ }
+
+ // create temp instance
+ $getid3_temp = new getID3();
+
+ // analyze
+ $getid3_ogg = new getid3_ogg($getid3_temp);
+ $oggpageinfo['page_seqno'] = 0;
+ $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo);
+ if (!empty($getid3_temp->info['ogg'])) {
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg'];
+ if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) {
+ foreach ($getid3_temp->info['audio'] as $key => $value) {
+ $track_info[$key] = $value;
+ }
+ }
+ }
+
+ // copy errors and warnings
+ if (!empty($getid3_temp->info['error'])) {
+ foreach ($getid3_temp->info['error'] as $newerror) {
+ $this->warning('getid3_ogg() says: ['.$newerror.']');
+ }
+ }
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $newerror) {
+ $this->warning('getid3_ogg() says: ['.$newerror.']');
+ }
+ }
+
+ if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) {
+ $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal'];
+ }
+ unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset);
+ break;
+
+ case 'A_MS/ACM':
+ if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) {
+ $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"');
+ break;
+ }
+
+ $parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']);
+ foreach ($parsed as $key => $value) {
+ if ($key != 'raw') {
+ $track_info[$key] = $value;
+ }
+ }
+ $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed;
+ break;
+
+ default:
+ $this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"');
+ }
+
+ $info['audio']['streams'][] = $track_info;
+ break;
+ }
+ }
+
+ if (!empty($info['video']['streams'])) {
+ $info['video'] = self::getDefaultStreamInfo($info['video']['streams']);
+ }
+ if (!empty($info['audio']['streams'])) {
+ $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']);
+ }
+ }
+
+ // process attachments
+ if (isset($info['matroska']['attachments']) && $this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE) {
+ foreach ($info['matroska']['attachments'] as $i => $entry) {
+ if (strpos($entry['FileMimeType'], 'image/') === 0 && !empty($entry['FileData'])) {
+ $info['matroska']['comments']['picture'][] = array('data' => $entry['FileData'], 'image_mime' => $entry['FileMimeType'], 'filename' => $entry['FileName']);
+ }
+ }
+ }
+
+ // determine mime type
+ if (!empty($info['video']['streams'])) {
+ $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska');
+ } elseif (!empty($info['audio']['streams'])) {
+ $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska');
+ } elseif (isset($info['mime_type'])) {
+ unset($info['mime_type']);
+ }
+
+ return true;
+ }
+
+ private function parseEBML(&$info) {
+ // http://www.matroska.org/technical/specs/index.html#EBMLBasics
+ $this->current_offset = $info['avdataoffset'];
+
+ while ($this->getEBMLelement($top_element, $info['avdataend'])) {
+ switch ($top_element['id']) {
+
+ case EBML_ID_EBML:
+ $info['fileformat'] = 'matroska';
+ $info['matroska']['header']['offset'] = $top_element['offset'];
+ $info['matroska']['header']['length'] = $top_element['length'];
+
+ while ($this->getEBMLelement($element_data, $top_element['end'], true)) {
+ switch ($element_data['id']) {
+
+ case EBML_ID_EBMLVERSION:
+ case EBML_ID_EBMLREADVERSION:
+ case EBML_ID_EBMLMAXIDLENGTH:
+ case EBML_ID_EBMLMAXSIZELENGTH:
+ case EBML_ID_DOCTYPEVERSION:
+ case EBML_ID_DOCTYPEREADVERSION:
+ $element_data['data'] = getid3_lib::BigEndian2Int($element_data['data']);
+ break;
+
+ case EBML_ID_DOCTYPE:
+ $element_data['data'] = getid3_lib::trimNullByte($element_data['data']);
+ $info['matroska']['doctype'] = $element_data['data'];
+ break;
+
+ case EBML_ID_CRC32: // not useful, ignore
+ $this->current_offset = $element_data['end'];
+ unset($element_data);
+ break;
+
+ default:
+ $this->unhandledElement('header', __LINE__, $element_data);
+ }
+ if (!empty($element_data)) {
+ unset($element_data['offset'], $element_data['end']);
+ $info['matroska']['header']['elements'][] = $element_data;
+ }
+ }
+ break;
+
+ case EBML_ID_SEGMENT:
+ $info['matroska']['segment'][0]['offset'] = $top_element['offset'];
+ $info['matroska']['segment'][0]['length'] = $top_element['length'];
+
+ while ($this->getEBMLelement($element_data, $top_element['end'])) {
+ if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
+ $info['matroska']['segments'][] = $element_data;
+ }
+ switch ($element_data['id']) {
+
+ case EBML_ID_SEEKHEAD: // Contains the position of other level 1 elements.
+
+ while ($this->getEBMLelement($seek_entry, $element_data['end'])) {
+ switch ($seek_entry['id']) {
+
+ case EBML_ID_SEEK: // Contains a single seek entry to an EBML element
+ while ($this->getEBMLelement($sub_seek_entry, $seek_entry['end'], true)) {
+
+ switch ($sub_seek_entry['id']) {
+
+ case EBML_ID_SEEKID:
+ $seek_entry['target_id'] = self::EBML2Int($sub_seek_entry['data']);
+ $seek_entry['target_name'] = self::EBMLidName($seek_entry['target_id']);
+ break;
+
+ case EBML_ID_SEEKPOSITION:
+ $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($sub_seek_entry['data']);
+ break;
+
+ default:
+ $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); }
+ }
+
+ if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required
+ $info['matroska']['seek'][] = $seek_entry;
+ }
+ break;
+
+ default:
+ $this->unhandledElement('seekhead', __LINE__, $seek_entry);
+ }
+ }
+ break;
+
+ case EBML_ID_TRACKS: // A top-level block of information with many tracks described.
+ $info['matroska']['tracks'] = $element_data;
+
+ while ($this->getEBMLelement($track_entry, $element_data['end'])) {
+ switch ($track_entry['id']) {
+
+ case EBML_ID_TRACKENTRY: //subelements: Describes a track with all elements.
+
+ while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS, EBML_ID_CODECPRIVATE))) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_TRACKNUMBER:
+ case EBML_ID_TRACKUID:
+ case EBML_ID_TRACKTYPE:
+ case EBML_ID_MINCACHE:
+ case EBML_ID_MAXCACHE:
+ case EBML_ID_MAXBLOCKADDITIONID:
+ case EBML_ID_DEFAULTDURATION: // nanoseconds per frame
+ $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
+ break;
+
+ case EBML_ID_TRACKTIMECODESCALE:
+ $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
+ break;
+
+ case EBML_ID_CODECID:
+ case EBML_ID_LANGUAGE:
+ case EBML_ID_NAME:
+ case EBML_ID_CODECNAME:
+ $track_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
+ break;
+
+ case EBML_ID_CODECPRIVATE:
+ $track_entry[$subelement['id_name']] = $this->readEBMLelementData($subelement['length'], true);
+ break;
+
+ case EBML_ID_FLAGENABLED:
+ case EBML_ID_FLAGDEFAULT:
+ case EBML_ID_FLAGFORCED:
+ case EBML_ID_FLAGLACING:
+ case EBML_ID_CODECDECODEALL:
+ $track_entry[$subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($subelement['data']);
+ break;
+
+ case EBML_ID_VIDEO:
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_PIXELWIDTH:
+ case EBML_ID_PIXELHEIGHT:
+ case EBML_ID_PIXELCROPBOTTOM:
+ case EBML_ID_PIXELCROPTOP:
+ case EBML_ID_PIXELCROPLEFT:
+ case EBML_ID_PIXELCROPRIGHT:
+ case EBML_ID_DISPLAYWIDTH:
+ case EBML_ID_DISPLAYHEIGHT:
+ case EBML_ID_DISPLAYUNIT:
+ case EBML_ID_ASPECTRATIOTYPE:
+ case EBML_ID_STEREOMODE:
+ case EBML_ID_OLDSTEREOMODE:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_FLAGINTERLACED:
+ $track_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_GAMMAVALUE:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
+ break;
+
+ case EBML_ID_COLOURSPACE:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('track.video', __LINE__, $sub_subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_AUDIO:
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CHANNELS:
+ case EBML_ID_BITDEPTH:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_SAMPLINGFREQUENCY:
+ case EBML_ID_OUTPUTSAMPLINGFREQUENCY:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHANNELPOSITIONS:
+ $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('track.audio', __LINE__, $sub_subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_CONTENTENCODINGS:
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'])) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CONTENTENCODING:
+
+ while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CONTENTCOMPRESSION, EBML_ID_CONTENTENCRYPTION))) {
+ switch ($sub_sub_subelement['id']) {
+
+ case EBML_ID_CONTENTENCODINGORDER:
+ case EBML_ID_CONTENTENCODINGSCOPE:
+ case EBML_ID_CONTENTENCODINGTYPE:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CONTENTCOMPRESSION:
+
+ while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
+ switch ($sub_sub_sub_subelement['id']) {
+
+ case EBML_ID_CONTENTCOMPALGO:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CONTENTCOMPSETTINGS:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
+ break;
+
+ default:
+ $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_CONTENTENCRYPTION:
+
+ while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
+ switch ($sub_sub_sub_subelement['id']) {
+
+ case EBML_ID_CONTENTENCALGO:
+ case EBML_ID_CONTENTSIGALGO:
+ case EBML_ID_CONTENTSIGHASHALGO:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CONTENTENCKEYID:
+ case EBML_ID_CONTENTSIGNATURE:
+ case EBML_ID_CONTENTSIGKEYID:
+ $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
+ break;
+
+ default:
+ $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement);
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement);
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement);
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('track', __LINE__, $subelement);
+ }
+ }
+
+ $info['matroska']['tracks']['tracks'][] = $track_entry;
+ break;
+
+ default:
+ $this->unhandledElement('tracks', __LINE__, $track_entry);
+ }
+ }
+ break;
+
+ case EBML_ID_INFO: // Contains miscellaneous general information and statistics on the file.
+ $info_entry = array();
+
+ while ($this->getEBMLelement($subelement, $element_data['end'], true)) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_TIMECODESCALE:
+ $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
+ break;
+
+ case EBML_ID_DURATION:
+ $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']);
+ break;
+
+ case EBML_ID_DATEUTC:
+ $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
+ $info_entry[$subelement['id_name'].'_unix'] = self::EBMLdate2unix($info_entry[$subelement['id_name']]);
+ break;
+
+ case EBML_ID_SEGMENTUID:
+ case EBML_ID_PREVUID:
+ case EBML_ID_NEXTUID:
+ $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
+ break;
+
+ case EBML_ID_SEGMENTFAMILY:
+ $info_entry[$subelement['id_name']][] = getid3_lib::trimNullByte($subelement['data']);
+ break;
+
+ case EBML_ID_SEGMENTFILENAME:
+ case EBML_ID_PREVFILENAME:
+ case EBML_ID_NEXTFILENAME:
+ case EBML_ID_TITLE:
+ case EBML_ID_MUXINGAPP:
+ case EBML_ID_WRITINGAPP:
+ $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']);
+ $info['matroska']['comments'][strtolower($subelement['id_name'])][] = $info_entry[$subelement['id_name']];
+ break;
+
+ case EBML_ID_CHAPTERTRANSLATE:
+ $chaptertranslate_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CHAPTERTRANSLATEEDITIONUID:
+ $chaptertranslate_entry[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERTRANSLATECODEC:
+ $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERTRANSLATEID:
+ $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('info.chaptertranslate', __LINE__, $sub_subelement);
+ }
+ }
+ $info_entry[$subelement['id_name']] = $chaptertranslate_entry;
+ break;
+
+ default:
+ $this->unhandledElement('info', __LINE__, $subelement);
+ }
+ }
+ $info['matroska']['info'][] = $info_entry;
+ break;
+
+ case EBML_ID_CUES: // A top-level element to speed seeking access. All entries are local to the segment. Should be mandatory for non "live" streams.
+ if (self::$hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway
+ $this->current_offset = $element_data['end'];
+ break;
+ }
+ $cues_entry = array();
+
+ while ($this->getEBMLelement($subelement, $element_data['end'])) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_CUEPOINT:
+ $cuepoint_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CUETRACKPOSITIONS))) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CUETRACKPOSITIONS:
+ $cuetrackpositions_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
+ switch ($sub_sub_subelement['id']) {
+
+ case EBML_ID_CUETRACK:
+ case EBML_ID_CUECLUSTERPOSITION:
+ case EBML_ID_CUEBLOCKNUMBER:
+ case EBML_ID_CUECODECSTATE:
+ $cuetrackpositions_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement);
+ }
+ }
+ $cuepoint_entry[$sub_subelement['id_name']][] = $cuetrackpositions_entry;
+ break;
+
+ case EBML_ID_CUETIME:
+ $cuepoint_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement);
+ }
+ }
+ $cues_entry[] = $cuepoint_entry;
+ break;
+
+ default:
+ $this->unhandledElement('cues', __LINE__, $subelement);
+ }
+ }
+ $info['matroska']['cues'] = $cues_entry;
+ break;
+
+ case EBML_ID_TAGS: // Element containing elements specific to Tracks/Chapters.
+ $tags_entry = array();
+
+ while ($this->getEBMLelement($subelement, $element_data['end'], false)) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_TAG:
+ $tag_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], false)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_TARGETS:
+ $targets_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) {
+ switch ($sub_sub_subelement['id']) {
+
+ case EBML_ID_TARGETTYPEVALUE:
+ $targets_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ $targets_entry[strtolower($sub_sub_subelement['id_name']).'_long'] = self::TargetTypeValue($targets_entry[$sub_sub_subelement['id_name']]);
+ break;
+
+ case EBML_ID_TARGETTYPE:
+ $targets_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
+ break;
+
+ case EBML_ID_TAGTRACKUID:
+ case EBML_ID_TAGEDITIONUID:
+ case EBML_ID_TAGCHAPTERUID:
+ case EBML_ID_TAGATTACHMENTUID:
+ $targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement);
+ }
+ }
+ $tag_entry[$sub_subelement['id_name']] = $targets_entry;
+ break;
+
+ case EBML_ID_SIMPLETAG:
+ $tag_entry[$sub_subelement['id_name']][] = $this->HandleEMBLSimpleTag($sub_subelement['end']);
+ break;
+
+ default:
+ $this->unhandledElement('tags.tag', __LINE__, $sub_subelement);
+ }
+ }
+ $tags_entry[] = $tag_entry;
+ break;
+
+ default:
+ $this->unhandledElement('tags', __LINE__, $subelement);
+ }
+ }
+ $info['matroska']['tags'] = $tags_entry;
+ break;
+
+ case EBML_ID_ATTACHMENTS: // Contain attached files.
+
+ while ($this->getEBMLelement($subelement, $element_data['end'])) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_ATTACHEDFILE:
+ $attachedfile_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_FILEDATA))) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_FILEDESCRIPTION:
+ case EBML_ID_FILENAME:
+ case EBML_ID_FILEMIMETYPE:
+ $attachedfile_entry[$sub_subelement['id_name']] = $sub_subelement['data'];
+ break;
+
+ case EBML_ID_FILEDATA:
+ $attachedfile_entry['data_offset'] = $this->current_offset;
+ $attachedfile_entry['data_length'] = $sub_subelement['length'];
+
+ $attachedfile_entry[$sub_subelement['id_name']] = $this->saveAttachment(
+ $attachedfile_entry['FileName'],
+ $attachedfile_entry['data_offset'],
+ $attachedfile_entry['data_length']);
+
+ $this->current_offset = $sub_subelement['end'];
+ break;
+
+ case EBML_ID_FILEUID:
+ $attachedfile_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement);
+ }
+ }
+ $info['matroska']['attachments'][] = $attachedfile_entry;
+ break;
+
+ default:
+ $this->unhandledElement('attachments', __LINE__, $subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_CHAPTERS:
+
+ while ($this->getEBMLelement($subelement, $element_data['end'])) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_EDITIONENTRY:
+ $editionentry_entry = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CHAPTERATOM))) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_EDITIONUID:
+ $editionentry_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_EDITIONFLAGHIDDEN:
+ case EBML_ID_EDITIONFLAGDEFAULT:
+ case EBML_ID_EDITIONFLAGORDERED:
+ $editionentry_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERATOM:
+ $chapteratom_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CHAPTERTRACK, EBML_ID_CHAPTERDISPLAY))) {
+ switch ($sub_sub_subelement['id']) {
+
+ case EBML_ID_CHAPTERSEGMENTUID:
+ case EBML_ID_CHAPTERSEGMENTEDITIONUID:
+ $chapteratom_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data'];
+ break;
+
+ case EBML_ID_CHAPTERFLAGENABLED:
+ case EBML_ID_CHAPTERFLAGHIDDEN:
+ $chapteratom_entry[$sub_sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERUID:
+ case EBML_ID_CHAPTERTIMESTART:
+ case EBML_ID_CHAPTERTIMEEND:
+ $chapteratom_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']);
+ break;
+
+ case EBML_ID_CHAPTERTRACK:
+ $chaptertrack_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
+ switch ($sub_sub_sub_subelement['id']) {
+
+ case EBML_ID_CHAPTERTRACKNUMBER:
+ $chaptertrack_entry[$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement);
+ }
+ }
+ $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry;
+ break;
+
+ case EBML_ID_CHAPTERDISPLAY:
+ $chapterdisplay_entry = array();
+
+ while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) {
+ switch ($sub_sub_sub_subelement['id']) {
+
+ case EBML_ID_CHAPSTRING:
+ case EBML_ID_CHAPLANGUAGE:
+ case EBML_ID_CHAPCOUNTRY:
+ $chapterdisplay_entry[$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data'];
+ break;
+
+ default:
+ $this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement);
+ }
+ }
+ $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry;
+ break;
+
+ default:
+ $this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement);
+ }
+ }
+ $editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry;
+ break;
+
+ default:
+ $this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement);
+ }
+ }
+ $info['matroska']['chapters'][] = $editionentry_entry;
+ break;
+
+ default:
+ $this->unhandledElement('chapters', __LINE__, $subelement);
+ }
+ }
+ break;
+
+ case EBML_ID_CLUSTER: // The lower level element containing the (monolithic) Block structure.
+ $cluster_entry = array();
+
+ while ($this->getEBMLelement($subelement, $element_data['end'], array(EBML_ID_CLUSTERSILENTTRACKS, EBML_ID_CLUSTERBLOCKGROUP, EBML_ID_CLUSTERSIMPLEBLOCK))) {
+ switch ($subelement['id']) {
+
+ case EBML_ID_CLUSTERTIMECODE:
+ case EBML_ID_CLUSTERPOSITION:
+ case EBML_ID_CLUSTERPREVSIZE:
+ $cluster_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']);
+ break;
+
+ case EBML_ID_CLUSTERSILENTTRACKS:
+ $cluster_silent_tracks = array();
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CLUSTERSILENTTRACKNUMBER:
+ $cluster_silent_tracks[] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement);
+ }
+ }
+ $cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks;
+ break;
+
+ case EBML_ID_CLUSTERBLOCKGROUP:
+ $cluster_block_group = array('offset' => $this->current_offset);
+
+ while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CLUSTERBLOCK))) {
+ switch ($sub_subelement['id']) {
+
+ case EBML_ID_CLUSTERBLOCK:
+ $cluster_block_group[$sub_subelement['id_name']] = $this->HandleEMBLClusterBlock($sub_subelement, EBML_ID_CLUSTERBLOCK, $info);
+ break;
+
+ case EBML_ID_CLUSTERREFERENCEPRIORITY: // unsigned-int
+ case EBML_ID_CLUSTERBLOCKDURATION: // unsigned-int
+ $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']);
+ break;
+
+ case EBML_ID_CLUSTERREFERENCEBLOCK: // signed-int
+ $cluster_block_group[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data'], false, true);
+ break;
+
+ case EBML_ID_CLUSTERCODECSTATE:
+ $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']);
+ break;
+
+ default:
+ $this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement);
+ }
+ }
+ $cluster_entry[$subelement['id_name']][] = $cluster_block_group;
+ break;
+
+ case EBML_ID_CLUSTERSIMPLEBLOCK:
+ $cluster_entry[$subelement['id_name']][] = $this->HandleEMBLClusterBlock($subelement, EBML_ID_CLUSTERSIMPLEBLOCK, $info);
+ break;
+
+ default:
+ $this->unhandledElement('cluster', __LINE__, $subelement);
+ }
+ $this->current_offset = $subelement['end'];
+ }
+ if (!self::$hide_clusters) {
+ $info['matroska']['cluster'][] = $cluster_entry;
+ }
+
+ // check to see if all the data we need exists already, if so, break out of the loop
+ if (!self::$parse_whole_file) {
+ if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) {
+ if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) {
+ if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) {
+ return;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('segment', __LINE__, $element_data);
+ }
+ }
+ break;
+
+ default:
+ $this->unhandledElement('root', __LINE__, $top_element);
+ }
+ }
+ }
+
+ private function EnsureBufferHasEnoughData($min_data=1024) {
+ if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) {
+ $read_bytes = max($min_data, $this->getid3->fread_buffer_size());
+
+ try {
+ $this->fseek($this->current_offset);
+ $this->EBMLbuffer_offset = $this->current_offset;
+ $this->EBMLbuffer = $this->fread($read_bytes);
+ $this->EBMLbuffer_length = strlen($this->EBMLbuffer);
+ } catch (getid3_exception $e) {
+ $this->warning('EBML parser: '.$e->getMessage());
+ return false;
+ }
+
+ if ($this->EBMLbuffer_length == 0 && $this->feof()) {
+ return $this->error('EBML parser: ran out of file at offset '.$this->current_offset);
+ }
+ }
+ return true;
+ }
+
+ private function readEBMLint() {
+ $actual_offset = $this->current_offset - $this->EBMLbuffer_offset;
+
+ // get length of integer
+ $first_byte_int = ord($this->EBMLbuffer[$actual_offset]);
+ if (0x80 & $first_byte_int) {
+ $length = 1;
+ } elseif (0x40 & $first_byte_int) {
+ $length = 2;
+ } elseif (0x20 & $first_byte_int) {
+ $length = 3;
+ } elseif (0x10 & $first_byte_int) {
+ $length = 4;
+ } elseif (0x08 & $first_byte_int) {
+ $length = 5;
+ } elseif (0x04 & $first_byte_int) {
+ $length = 6;
+ } elseif (0x02 & $first_byte_int) {
+ $length = 7;
+ } elseif (0x01 & $first_byte_int) {
+ $length = 8;
+ } else {
+ throw new Exception('invalid EBML integer (leading 0x00) at '.$this->current_offset);
+ }
+
+ // read
+ $int_value = self::EBML2Int(substr($this->EBMLbuffer, $actual_offset, $length));
+ $this->current_offset += $length;
+
+ return $int_value;
+ }
+
+ private function readEBMLelementData($length, $check_buffer=false) {
+ if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) {
+ return false;
+ }
+ $data = substr($this->EBMLbuffer, $this->current_offset - $this->EBMLbuffer_offset, $length);
+ $this->current_offset += $length;
+ return $data;
+ }
+
+ private function getEBMLelement(&$element, $parent_end, $get_data=false) {
+ if ($this->current_offset >= $parent_end) {
+ return false;
+ }
+
+ if (!$this->EnsureBufferHasEnoughData()) {
+ $this->current_offset = PHP_INT_MAX; // do not exit parser right now, allow to finish current loop to gather maximum information
+ return false;
+ }
+
+ $element = array();
+
+ // set offset
+ $element['offset'] = $this->current_offset;
+
+ // get ID
+ $element['id'] = $this->readEBMLint();
+
+ // get name
+ $element['id_name'] = self::EBMLidName($element['id']);
+
+ // get length
+ $element['length'] = $this->readEBMLint();
+
+ // get end offset
+ $element['end'] = $this->current_offset + $element['length'];
+
+ // get raw data
+ $dont_parse = (in_array($element['id'], $this->unuseful_elements) || $element['id_name'] == dechex($element['id']));
+ if (($get_data === true || (is_array($get_data) && !in_array($element['id'], $get_data))) && !$dont_parse) {
+ $element['data'] = $this->readEBMLelementData($element['length'], $element);
+ }
+
+ return true;
+ }
+
+ private function unhandledElement($type, $line, $element) {
+ // warn only about unknown and missed elements, not about unuseful
+ if (!in_array($element['id'], $this->unuseful_elements)) {
+ $this->warning('Unhandled '.$type.' element ['.basename(__FILE__).':'.$line.'] ('.$element['id'].'::'.$element['id_name'].' ['.$element['length'].' bytes]) at '.$element['offset']);
+ }
+
+ // increase offset for unparsed elements
+ if (!isset($element['data'])) {
+ $this->current_offset = $element['end'];
+ }
+ }
+
+ private function ExtractCommentsSimpleTag($SimpleTagArray) {
+ if (!empty($SimpleTagArray['SimpleTag'])) {
+ foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) {
+ if (!empty($SimpleTagData['TagName']) && !empty($SimpleTagData['TagString'])) {
+ $this->getid3->info['matroska']['comments'][strtolower($SimpleTagData['TagName'])][] = $SimpleTagData['TagString'];
+ }
+ if (!empty($SimpleTagData['SimpleTag'])) {
+ $this->ExtractCommentsSimpleTag($SimpleTagData);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private function HandleEMBLSimpleTag($parent_end) {
+ $simpletag_entry = array();
+
+ while ($this->getEBMLelement($element, $parent_end, array(EBML_ID_SIMPLETAG))) {
+ switch ($element['id']) {
+
+ case EBML_ID_TAGNAME:
+ case EBML_ID_TAGLANGUAGE:
+ case EBML_ID_TAGSTRING:
+ case EBML_ID_TAGBINARY:
+ $simpletag_entry[$element['id_name']] = $element['data'];
+ break;
+
+ case EBML_ID_SIMPLETAG:
+ $simpletag_entry[$element['id_name']][] = $this->HandleEMBLSimpleTag($element['end']);
+ break;
+
+ case EBML_ID_TAGDEFAULT:
+ $simpletag_entry[$element['id_name']] = (bool)getid3_lib::BigEndian2Int($element['data']);
+ break;
+
+ default:
+ $this->unhandledElement('tag.simpletag', __LINE__, $element);
+ }
+ }
+
+ return $simpletag_entry;
+ }
+
+ private function HandleEMBLClusterBlock($element, $block_type, &$info) {
+ // http://www.matroska.org/technical/specs/index.html#block_structure
+ // http://www.matroska.org/technical/specs/index.html#simpleblock_structure
+
+ $block_data = array();
+ $block_data['tracknumber'] = $this->readEBMLint();
+ $block_data['timecode'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(2), false, true);
+ $block_data['flags_raw'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1));
+
+ if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) {
+ $block_data['flags']['keyframe'] = (($block_data['flags_raw'] & 0x80) >> 7);
+ //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0x70) >> 4);
+ }
+ else {
+ //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0xF0) >> 4);
+ }
+ $block_data['flags']['invisible'] = (bool)(($block_data['flags_raw'] & 0x08) >> 3);
+ $block_data['flags']['lacing'] = (($block_data['flags_raw'] & 0x06) >> 1); // 00=no lacing; 01=Xiph lacing; 11=EBML lacing; 10=fixed-size lacing
+ if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) {
+ $block_data['flags']['discardable'] = (($block_data['flags_raw'] & 0x01));
+ }
+ else {
+ //$block_data['flags']['reserved2'] = (($block_data['flags_raw'] & 0x01) >> 0);
+ }
+ $block_data['flags']['lacing_type'] = self::BlockLacingType($block_data['flags']['lacing']);
+
+ // Lace (when lacing bit is set)
+ if ($block_data['flags']['lacing'] > 0) {
+ $block_data['lace_frames'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1)) + 1; // Number of frames in the lace-1 (uint8)
+ if ($block_data['flags']['lacing'] != 0x02) {
+ for ($i = 1; $i < $block_data['lace_frames']; $i ++) { // Lace-coded size of each frame of the lace, except for the last one (multiple uint8). *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace).
+ if ($block_data['flags']['lacing'] == 0x03) { // EBML lacing
+ $block_data['lace_frames_size'][$i] = $this->readEBMLint(); // TODO: read size correctly, calc size for the last frame. For now offsets are deteminded OK with readEBMLint() and that's the most important thing.
+ }
+ else { // Xiph lacing
+ $block_data['lace_frames_size'][$i] = 0;
+ do {
+ $size = getid3_lib::BigEndian2Int($this->readEBMLelementData(1));
+ $block_data['lace_frames_size'][$i] += $size;
+ }
+ while ($size == 255);
+ }
+ }
+ if ($block_data['flags']['lacing'] == 0x01) { // calc size of the last frame only for Xiph lacing, till EBML sizes are now anyway determined incorrectly
+ $block_data['lace_frames_size'][] = $element['end'] - $this->current_offset - array_sum($block_data['lace_frames_size']);
+ }
+ }
+ }
+
+ if (!isset($info['matroska']['track_data_offsets'][$block_data['tracknumber']])) {
+ $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['offset'] = $this->current_offset;
+ $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length'] = $element['end'] - $this->current_offset;
+ //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] = 0;
+ }
+ //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] += $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length'];
+ //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['duration'] = $block_data['timecode'] * ((isset($info['matroska']['info'][0]['TimecodeScale']) ? $info['matroska']['info'][0]['TimecodeScale'] : 1000000) / 1000000000);
+
+ // set offset manually
+ $this->current_offset = $element['end'];
+
+ return $block_data;
+ }
+
+ private static function EBML2Int($EBMLstring) {
+ // http://matroska.org/specs/
+
+ // Element ID coded with an UTF-8 like system:
+ // 1xxx xxxx - Class A IDs (2^7 -2 possible values) (base 0x8X)
+ // 01xx xxxx xxxx xxxx - Class B IDs (2^14-2 possible values) (base 0x4X 0xXX)
+ // 001x xxxx xxxx xxxx xxxx xxxx - Class C IDs (2^21-2 possible values) (base 0x2X 0xXX 0xXX)
+ // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - Class D IDs (2^28-2 possible values) (base 0x1X 0xXX 0xXX 0xXX)
+ // Values with all x at 0 and 1 are reserved (hence the -2).
+
+ // Data size, in octets, is also coded with an UTF-8 like system :
+ // 1xxx xxxx - value 0 to 2^7-2
+ // 01xx xxxx xxxx xxxx - value 0 to 2^14-2
+ // 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2
+ // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2
+ // 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2
+ // 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2
+ // 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2
+ // 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2
+
+ $first_byte_int = ord($EBMLstring[0]);
+ if (0x80 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x7F);
+ } elseif (0x40 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x3F);
+ } elseif (0x20 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x1F);
+ } elseif (0x10 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x0F);
+ } elseif (0x08 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x07);
+ } elseif (0x04 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x03);
+ } elseif (0x02 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x01);
+ } elseif (0x01 & $first_byte_int) {
+ $EBMLstring[0] = chr($first_byte_int & 0x00);
+ }
+
+ return getid3_lib::BigEndian2Int($EBMLstring);
+ }
+
+ private static function EBMLdate2unix($EBMLdatestamp) {
+ // Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC)
+ // 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC
+ return round(($EBMLdatestamp / 1000000000) + 978307200);
+ }
+
+ public static function TargetTypeValue($target_type) {
+ // http://www.matroska.org/technical/specs/tagging/index.html
+ static $TargetTypeValue = array();
+ if (empty($TargetTypeValue)) {
+ $TargetTypeValue[10] = 'A: ~ V:shot'; // the lowest hierarchy found in music or movies
+ $TargetTypeValue[20] = 'A:subtrack/part/movement ~ V:scene'; // corresponds to parts of a track for audio (like a movement)
+ $TargetTypeValue[30] = 'A:track/song ~ V:chapter'; // the common parts of an album or a movie
+ $TargetTypeValue[40] = 'A:part/session ~ V:part/session'; // when an album or episode has different logical parts
+ $TargetTypeValue[50] = 'A:album/opera/concert ~ V:movie/episode/concert'; // the most common grouping level of music and video (equals to an episode for TV series)
+ $TargetTypeValue[60] = 'A:edition/issue/volume/opus ~ V:season/sequel/volume'; // a list of lower levels grouped together
+ $TargetTypeValue[70] = 'A:collection ~ V:collection'; // the high hierarchy consisting of many different lower items
+ }
+ return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type);
+ }
+
+ public static function BlockLacingType($lacingtype) {
+ // http://matroska.org/technical/specs/index.html#block_structure
+ static $BlockLacingType = array();
+ if (empty($BlockLacingType)) {
+ $BlockLacingType[0x00] = 'no lacing';
+ $BlockLacingType[0x01] = 'Xiph lacing';
+ $BlockLacingType[0x02] = 'fixed-size lacing';
+ $BlockLacingType[0x03] = 'EBML lacing';
+ }
+ return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype);
+ }
+
+ public static function CodecIDtoCommonName($codecid) {
+ // http://www.matroska.org/technical/specs/codecid/index.html
+ static $CodecIDlist = array();
+ if (empty($CodecIDlist)) {
+ $CodecIDlist['A_AAC'] = 'aac';
+ $CodecIDlist['A_AAC/MPEG2/LC'] = 'aac';
+ $CodecIDlist['A_AC3'] = 'ac3';
+ $CodecIDlist['A_DTS'] = 'dts';
+ $CodecIDlist['A_FLAC'] = 'flac';
+ $CodecIDlist['A_MPEG/L1'] = 'mp1';
+ $CodecIDlist['A_MPEG/L2'] = 'mp2';
+ $CodecIDlist['A_MPEG/L3'] = 'mp3';
+ $CodecIDlist['A_PCM/INT/LIT'] = 'pcm'; // PCM Integer Little Endian
+ $CodecIDlist['A_PCM/INT/BIG'] = 'pcm'; // PCM Integer Big Endian
+ $CodecIDlist['A_QUICKTIME/QDMC'] = 'quicktime'; // Quicktime: QDesign Music
+ $CodecIDlist['A_QUICKTIME/QDM2'] = 'quicktime'; // Quicktime: QDesign Music v2
+ $CodecIDlist['A_VORBIS'] = 'vorbis';
+ $CodecIDlist['V_MPEG1'] = 'mpeg';
+ $CodecIDlist['V_THEORA'] = 'theora';
+ $CodecIDlist['V_REAL/RV40'] = 'real';
+ $CodecIDlist['V_REAL/RV10'] = 'real';
+ $CodecIDlist['V_REAL/RV20'] = 'real';
+ $CodecIDlist['V_REAL/RV30'] = 'real';
+ $CodecIDlist['V_QUICKTIME'] = 'quicktime'; // Quicktime
+ $CodecIDlist['V_MPEG4/ISO/AP'] = 'mpeg4';
+ $CodecIDlist['V_MPEG4/ISO/ASP'] = 'mpeg4';
+ $CodecIDlist['V_MPEG4/ISO/AVC'] = 'h264';
+ $CodecIDlist['V_MPEG4/ISO/SP'] = 'mpeg4';
+ $CodecIDlist['V_VP8'] = 'vp8';
+ $CodecIDlist['V_MS/VFW/FOURCC'] = 'riff';
+ $CodecIDlist['A_MS/ACM'] = 'riff';
+ }
+ return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid);
+ }
+
+ private static function EBMLidName($value) {
+ static $EBMLidList = array();
+ if (empty($EBMLidList)) {
+ $EBMLidList[EBML_ID_ASPECTRATIOTYPE] = 'AspectRatioType';
+ $EBMLidList[EBML_ID_ATTACHEDFILE] = 'AttachedFile';
+ $EBMLidList[EBML_ID_ATTACHMENTLINK] = 'AttachmentLink';
+ $EBMLidList[EBML_ID_ATTACHMENTS] = 'Attachments';
+ $EBMLidList[EBML_ID_AUDIO] = 'Audio';
+ $EBMLidList[EBML_ID_BITDEPTH] = 'BitDepth';
+ $EBMLidList[EBML_ID_CHANNELPOSITIONS] = 'ChannelPositions';
+ $EBMLidList[EBML_ID_CHANNELS] = 'Channels';
+ $EBMLidList[EBML_ID_CHAPCOUNTRY] = 'ChapCountry';
+ $EBMLidList[EBML_ID_CHAPLANGUAGE] = 'ChapLanguage';
+ $EBMLidList[EBML_ID_CHAPPROCESS] = 'ChapProcess';
+ $EBMLidList[EBML_ID_CHAPPROCESSCODECID] = 'ChapProcessCodecID';
+ $EBMLidList[EBML_ID_CHAPPROCESSCOMMAND] = 'ChapProcessCommand';
+ $EBMLidList[EBML_ID_CHAPPROCESSDATA] = 'ChapProcessData';
+ $EBMLidList[EBML_ID_CHAPPROCESSPRIVATE] = 'ChapProcessPrivate';
+ $EBMLidList[EBML_ID_CHAPPROCESSTIME] = 'ChapProcessTime';
+ $EBMLidList[EBML_ID_CHAPSTRING] = 'ChapString';
+ $EBMLidList[EBML_ID_CHAPTERATOM] = 'ChapterAtom';
+ $EBMLidList[EBML_ID_CHAPTERDISPLAY] = 'ChapterDisplay';
+ $EBMLidList[EBML_ID_CHAPTERFLAGENABLED] = 'ChapterFlagEnabled';
+ $EBMLidList[EBML_ID_CHAPTERFLAGHIDDEN] = 'ChapterFlagHidden';
+ $EBMLidList[EBML_ID_CHAPTERPHYSICALEQUIV] = 'ChapterPhysicalEquiv';
+ $EBMLidList[EBML_ID_CHAPTERS] = 'Chapters';
+ $EBMLidList[EBML_ID_CHAPTERSEGMENTEDITIONUID] = 'ChapterSegmentEditionUID';
+ $EBMLidList[EBML_ID_CHAPTERSEGMENTUID] = 'ChapterSegmentUID';
+ $EBMLidList[EBML_ID_CHAPTERTIMEEND] = 'ChapterTimeEnd';
+ $EBMLidList[EBML_ID_CHAPTERTIMESTART] = 'ChapterTimeStart';
+ $EBMLidList[EBML_ID_CHAPTERTRACK] = 'ChapterTrack';
+ $EBMLidList[EBML_ID_CHAPTERTRACKNUMBER] = 'ChapterTrackNumber';
+ $EBMLidList[EBML_ID_CHAPTERTRANSLATE] = 'ChapterTranslate';
+ $EBMLidList[EBML_ID_CHAPTERTRANSLATECODEC] = 'ChapterTranslateCodec';
+ $EBMLidList[EBML_ID_CHAPTERTRANSLATEEDITIONUID] = 'ChapterTranslateEditionUID';
+ $EBMLidList[EBML_ID_CHAPTERTRANSLATEID] = 'ChapterTranslateID';
+ $EBMLidList[EBML_ID_CHAPTERUID] = 'ChapterUID';
+ $EBMLidList[EBML_ID_CLUSTER] = 'Cluster';
+ $EBMLidList[EBML_ID_CLUSTERBLOCK] = 'ClusterBlock';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKADDID] = 'ClusterBlockAddID';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONAL] = 'ClusterBlockAdditional';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONID] = 'ClusterBlockAdditionID';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONS] = 'ClusterBlockAdditions';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKDURATION] = 'ClusterBlockDuration';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKGROUP] = 'ClusterBlockGroup';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKMORE] = 'ClusterBlockMore';
+ $EBMLidList[EBML_ID_CLUSTERBLOCKVIRTUAL] = 'ClusterBlockVirtual';
+ $EBMLidList[EBML_ID_CLUSTERCODECSTATE] = 'ClusterCodecState';
+ $EBMLidList[EBML_ID_CLUSTERDELAY] = 'ClusterDelay';
+ $EBMLidList[EBML_ID_CLUSTERDURATION] = 'ClusterDuration';
+ $EBMLidList[EBML_ID_CLUSTERENCRYPTEDBLOCK] = 'ClusterEncryptedBlock';
+ $EBMLidList[EBML_ID_CLUSTERFRAMENUMBER] = 'ClusterFrameNumber';
+ $EBMLidList[EBML_ID_CLUSTERLACENUMBER] = 'ClusterLaceNumber';
+ $EBMLidList[EBML_ID_CLUSTERPOSITION] = 'ClusterPosition';
+ $EBMLidList[EBML_ID_CLUSTERPREVSIZE] = 'ClusterPrevSize';
+ $EBMLidList[EBML_ID_CLUSTERREFERENCEBLOCK] = 'ClusterReferenceBlock';
+ $EBMLidList[EBML_ID_CLUSTERREFERENCEPRIORITY] = 'ClusterReferencePriority';
+ $EBMLidList[EBML_ID_CLUSTERREFERENCEVIRTUAL] = 'ClusterReferenceVirtual';
+ $EBMLidList[EBML_ID_CLUSTERSILENTTRACKNUMBER] = 'ClusterSilentTrackNumber';
+ $EBMLidList[EBML_ID_CLUSTERSILENTTRACKS] = 'ClusterSilentTracks';
+ $EBMLidList[EBML_ID_CLUSTERSIMPLEBLOCK] = 'ClusterSimpleBlock';
+ $EBMLidList[EBML_ID_CLUSTERTIMECODE] = 'ClusterTimecode';
+ $EBMLidList[EBML_ID_CLUSTERTIMESLICE] = 'ClusterTimeSlice';
+ $EBMLidList[EBML_ID_CODECDECODEALL] = 'CodecDecodeAll';
+ $EBMLidList[EBML_ID_CODECDOWNLOADURL] = 'CodecDownloadURL';
+ $EBMLidList[EBML_ID_CODECID] = 'CodecID';
+ $EBMLidList[EBML_ID_CODECINFOURL] = 'CodecInfoURL';
+ $EBMLidList[EBML_ID_CODECNAME] = 'CodecName';
+ $EBMLidList[EBML_ID_CODECPRIVATE] = 'CodecPrivate';
+ $EBMLidList[EBML_ID_CODECSETTINGS] = 'CodecSettings';
+ $EBMLidList[EBML_ID_COLOURSPACE] = 'ColourSpace';
+ $EBMLidList[EBML_ID_CONTENTCOMPALGO] = 'ContentCompAlgo';
+ $EBMLidList[EBML_ID_CONTENTCOMPRESSION] = 'ContentCompression';
+ $EBMLidList[EBML_ID_CONTENTCOMPSETTINGS] = 'ContentCompSettings';
+ $EBMLidList[EBML_ID_CONTENTENCALGO] = 'ContentEncAlgo';
+ $EBMLidList[EBML_ID_CONTENTENCKEYID] = 'ContentEncKeyID';
+ $EBMLidList[EBML_ID_CONTENTENCODING] = 'ContentEncoding';
+ $EBMLidList[EBML_ID_CONTENTENCODINGORDER] = 'ContentEncodingOrder';
+ $EBMLidList[EBML_ID_CONTENTENCODINGS] = 'ContentEncodings';
+ $EBMLidList[EBML_ID_CONTENTENCODINGSCOPE] = 'ContentEncodingScope';
+ $EBMLidList[EBML_ID_CONTENTENCODINGTYPE] = 'ContentEncodingType';
+ $EBMLidList[EBML_ID_CONTENTENCRYPTION] = 'ContentEncryption';
+ $EBMLidList[EBML_ID_CONTENTSIGALGO] = 'ContentSigAlgo';
+ $EBMLidList[EBML_ID_CONTENTSIGHASHALGO] = 'ContentSigHashAlgo';
+ $EBMLidList[EBML_ID_CONTENTSIGKEYID] = 'ContentSigKeyID';
+ $EBMLidList[EBML_ID_CONTENTSIGNATURE] = 'ContentSignature';
+ $EBMLidList[EBML_ID_CRC32] = 'CRC32';
+ $EBMLidList[EBML_ID_CUEBLOCKNUMBER] = 'CueBlockNumber';
+ $EBMLidList[EBML_ID_CUECLUSTERPOSITION] = 'CueClusterPosition';
+ $EBMLidList[EBML_ID_CUECODECSTATE] = 'CueCodecState';
+ $EBMLidList[EBML_ID_CUEPOINT] = 'CuePoint';
+ $EBMLidList[EBML_ID_CUEREFCLUSTER] = 'CueRefCluster';
+ $EBMLidList[EBML_ID_CUEREFCODECSTATE] = 'CueRefCodecState';
+ $EBMLidList[EBML_ID_CUEREFERENCE] = 'CueReference';
+ $EBMLidList[EBML_ID_CUEREFNUMBER] = 'CueRefNumber';
+ $EBMLidList[EBML_ID_CUEREFTIME] = 'CueRefTime';
+ $EBMLidList[EBML_ID_CUES] = 'Cues';
+ $EBMLidList[EBML_ID_CUETIME] = 'CueTime';
+ $EBMLidList[EBML_ID_CUETRACK] = 'CueTrack';
+ $EBMLidList[EBML_ID_CUETRACKPOSITIONS] = 'CueTrackPositions';
+ $EBMLidList[EBML_ID_DATEUTC] = 'DateUTC';
+ $EBMLidList[EBML_ID_DEFAULTDURATION] = 'DefaultDuration';
+ $EBMLidList[EBML_ID_DISPLAYHEIGHT] = 'DisplayHeight';
+ $EBMLidList[EBML_ID_DISPLAYUNIT] = 'DisplayUnit';
+ $EBMLidList[EBML_ID_DISPLAYWIDTH] = 'DisplayWidth';
+ $EBMLidList[EBML_ID_DOCTYPE] = 'DocType';
+ $EBMLidList[EBML_ID_DOCTYPEREADVERSION] = 'DocTypeReadVersion';
+ $EBMLidList[EBML_ID_DOCTYPEVERSION] = 'DocTypeVersion';
+ $EBMLidList[EBML_ID_DURATION] = 'Duration';
+ $EBMLidList[EBML_ID_EBML] = 'EBML';
+ $EBMLidList[EBML_ID_EBMLMAXIDLENGTH] = 'EBMLMaxIDLength';
+ $EBMLidList[EBML_ID_EBMLMAXSIZELENGTH] = 'EBMLMaxSizeLength';
+ $EBMLidList[EBML_ID_EBMLREADVERSION] = 'EBMLReadVersion';
+ $EBMLidList[EBML_ID_EBMLVERSION] = 'EBMLVersion';
+ $EBMLidList[EBML_ID_EDITIONENTRY] = 'EditionEntry';
+ $EBMLidList[EBML_ID_EDITIONFLAGDEFAULT] = 'EditionFlagDefault';
+ $EBMLidList[EBML_ID_EDITIONFLAGHIDDEN] = 'EditionFlagHidden';
+ $EBMLidList[EBML_ID_EDITIONFLAGORDERED] = 'EditionFlagOrdered';
+ $EBMLidList[EBML_ID_EDITIONUID] = 'EditionUID';
+ $EBMLidList[EBML_ID_FILEDATA] = 'FileData';
+ $EBMLidList[EBML_ID_FILEDESCRIPTION] = 'FileDescription';
+ $EBMLidList[EBML_ID_FILEMIMETYPE] = 'FileMimeType';
+ $EBMLidList[EBML_ID_FILENAME] = 'FileName';
+ $EBMLidList[EBML_ID_FILEREFERRAL] = 'FileReferral';
+ $EBMLidList[EBML_ID_FILEUID] = 'FileUID';
+ $EBMLidList[EBML_ID_FLAGDEFAULT] = 'FlagDefault';
+ $EBMLidList[EBML_ID_FLAGENABLED] = 'FlagEnabled';
+ $EBMLidList[EBML_ID_FLAGFORCED] = 'FlagForced';
+ $EBMLidList[EBML_ID_FLAGINTERLACED] = 'FlagInterlaced';
+ $EBMLidList[EBML_ID_FLAGLACING] = 'FlagLacing';
+ $EBMLidList[EBML_ID_GAMMAVALUE] = 'GammaValue';
+ $EBMLidList[EBML_ID_INFO] = 'Info';
+ $EBMLidList[EBML_ID_LANGUAGE] = 'Language';
+ $EBMLidList[EBML_ID_MAXBLOCKADDITIONID] = 'MaxBlockAdditionID';
+ $EBMLidList[EBML_ID_MAXCACHE] = 'MaxCache';
+ $EBMLidList[EBML_ID_MINCACHE] = 'MinCache';
+ $EBMLidList[EBML_ID_MUXINGAPP] = 'MuxingApp';
+ $EBMLidList[EBML_ID_NAME] = 'Name';
+ $EBMLidList[EBML_ID_NEXTFILENAME] = 'NextFilename';
+ $EBMLidList[EBML_ID_NEXTUID] = 'NextUID';
+ $EBMLidList[EBML_ID_OUTPUTSAMPLINGFREQUENCY] = 'OutputSamplingFrequency';
+ $EBMLidList[EBML_ID_PIXELCROPBOTTOM] = 'PixelCropBottom';
+ $EBMLidList[EBML_ID_PIXELCROPLEFT] = 'PixelCropLeft';
+ $EBMLidList[EBML_ID_PIXELCROPRIGHT] = 'PixelCropRight';
+ $EBMLidList[EBML_ID_PIXELCROPTOP] = 'PixelCropTop';
+ $EBMLidList[EBML_ID_PIXELHEIGHT] = 'PixelHeight';
+ $EBMLidList[EBML_ID_PIXELWIDTH] = 'PixelWidth';
+ $EBMLidList[EBML_ID_PREVFILENAME] = 'PrevFilename';
+ $EBMLidList[EBML_ID_PREVUID] = 'PrevUID';
+ $EBMLidList[EBML_ID_SAMPLINGFREQUENCY] = 'SamplingFrequency';
+ $EBMLidList[EBML_ID_SEEK] = 'Seek';
+ $EBMLidList[EBML_ID_SEEKHEAD] = 'SeekHead';
+ $EBMLidList[EBML_ID_SEEKID] = 'SeekID';
+ $EBMLidList[EBML_ID_SEEKPOSITION] = 'SeekPosition';
+ $EBMLidList[EBML_ID_SEGMENT] = 'Segment';
+ $EBMLidList[EBML_ID_SEGMENTFAMILY] = 'SegmentFamily';
+ $EBMLidList[EBML_ID_SEGMENTFILENAME] = 'SegmentFilename';
+ $EBMLidList[EBML_ID_SEGMENTUID] = 'SegmentUID';
+ $EBMLidList[EBML_ID_SIMPLETAG] = 'SimpleTag';
+ $EBMLidList[EBML_ID_CLUSTERSLICES] = 'ClusterSlices';
+ $EBMLidList[EBML_ID_STEREOMODE] = 'StereoMode';
+ $EBMLidList[EBML_ID_OLDSTEREOMODE] = 'OldStereoMode';
+ $EBMLidList[EBML_ID_TAG] = 'Tag';
+ $EBMLidList[EBML_ID_TAGATTACHMENTUID] = 'TagAttachmentUID';
+ $EBMLidList[EBML_ID_TAGBINARY] = 'TagBinary';
+ $EBMLidList[EBML_ID_TAGCHAPTERUID] = 'TagChapterUID';
+ $EBMLidList[EBML_ID_TAGDEFAULT] = 'TagDefault';
+ $EBMLidList[EBML_ID_TAGEDITIONUID] = 'TagEditionUID';
+ $EBMLidList[EBML_ID_TAGLANGUAGE] = 'TagLanguage';
+ $EBMLidList[EBML_ID_TAGNAME] = 'TagName';
+ $EBMLidList[EBML_ID_TAGTRACKUID] = 'TagTrackUID';
+ $EBMLidList[EBML_ID_TAGS] = 'Tags';
+ $EBMLidList[EBML_ID_TAGSTRING] = 'TagString';
+ $EBMLidList[EBML_ID_TARGETS] = 'Targets';
+ $EBMLidList[EBML_ID_TARGETTYPE] = 'TargetType';
+ $EBMLidList[EBML_ID_TARGETTYPEVALUE] = 'TargetTypeValue';
+ $EBMLidList[EBML_ID_TIMECODESCALE] = 'TimecodeScale';
+ $EBMLidList[EBML_ID_TITLE] = 'Title';
+ $EBMLidList[EBML_ID_TRACKENTRY] = 'TrackEntry';
+ $EBMLidList[EBML_ID_TRACKNUMBER] = 'TrackNumber';
+ $EBMLidList[EBML_ID_TRACKOFFSET] = 'TrackOffset';
+ $EBMLidList[EBML_ID_TRACKOVERLAY] = 'TrackOverlay';
+ $EBMLidList[EBML_ID_TRACKS] = 'Tracks';
+ $EBMLidList[EBML_ID_TRACKTIMECODESCALE] = 'TrackTimecodeScale';
+ $EBMLidList[EBML_ID_TRACKTRANSLATE] = 'TrackTranslate';
+ $EBMLidList[EBML_ID_TRACKTRANSLATECODEC] = 'TrackTranslateCodec';
+ $EBMLidList[EBML_ID_TRACKTRANSLATEEDITIONUID] = 'TrackTranslateEditionUID';
+ $EBMLidList[EBML_ID_TRACKTRANSLATETRACKID] = 'TrackTranslateTrackID';
+ $EBMLidList[EBML_ID_TRACKTYPE] = 'TrackType';
+ $EBMLidList[EBML_ID_TRACKUID] = 'TrackUID';
+ $EBMLidList[EBML_ID_VIDEO] = 'Video';
+ $EBMLidList[EBML_ID_VOID] = 'Void';
+ $EBMLidList[EBML_ID_WRITINGAPP] = 'WritingApp';
+ }
+
+ return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value));
+ }
+
+ public static function displayUnit($value) {
+ // http://www.matroska.org/technical/specs/index.html#DisplayUnit
+ static $units = array(
+ 0 => 'pixels',
+ 1 => 'centimeters',
+ 2 => 'inches',
+ 3 => 'Display Aspect Ratio');
+
+ return (isset($units[$value]) ? $units[$value] : 'unknown');
+ }
+
+ private static function getDefaultStreamInfo($streams)
+ {
+ foreach (array_reverse($streams) as $stream) {
+ if ($stream['default']) {
+ break;
+ }
+ }
+
+ $unset = array('default', 'name');
+ foreach ($unset as $u) {
+ if (isset($stream[$u])) {
+ unset($stream[$u]);
+ }
+ }
+
+ $info = $stream;
+ $info['streams'] = $streams;
+
+ return $info;
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.audio-video.mpeg.php b/extensions/TimedMediaHandler/libs/getid3/module.audio-video.mpeg.php
new file mode 100644
index 00000000..999c5d9a
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.audio-video.mpeg.php
@@ -0,0 +1,296 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.mpeg.php //
+// module for analyzing MPEG files //
+// dependencies: module.audio.mp3.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
+
+define('GETID3_MPEG_VIDEO_PICTURE_START', "\x00\x00\x01\x00");
+define('GETID3_MPEG_VIDEO_USER_DATA_START', "\x00\x00\x01\xB2");
+define('GETID3_MPEG_VIDEO_SEQUENCE_HEADER', "\x00\x00\x01\xB3");
+define('GETID3_MPEG_VIDEO_SEQUENCE_ERROR', "\x00\x00\x01\xB4");
+define('GETID3_MPEG_VIDEO_EXTENSION_START', "\x00\x00\x01\xB5");
+define('GETID3_MPEG_VIDEO_SEQUENCE_END', "\x00\x00\x01\xB7");
+define('GETID3_MPEG_VIDEO_GROUP_START', "\x00\x00\x01\xB8");
+define('GETID3_MPEG_AUDIO_START', "\x00\x00\x01\xC0");
+
+
+class getid3_mpeg extends getid3_handler
+{
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ if ($info['avdataend'] <= $info['avdataoffset']) {
+ $info['error'][] = '"avdataend" ('.$info['avdataend'].') is unexpectedly less-than-or-equal-to "avdataoffset" ('.$info['avdataoffset'].')';
+ return false;
+ }
+ $info['fileformat'] = 'mpeg';
+ fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
+ $MPEGstreamData = fread($this->getid3->fp, min(100000, $info['avdataend'] - $info['avdataoffset']));
+ $MPEGstreamDataLength = strlen($MPEGstreamData);
+
+ $foundVideo = true;
+ $VideoChunkOffset = 0;
+ while (substr($MPEGstreamData, $VideoChunkOffset++, 4) !== GETID3_MPEG_VIDEO_SEQUENCE_HEADER) {
+ if ($VideoChunkOffset >= $MPEGstreamDataLength) {
+ $foundVideo = false;
+ break;
+ }
+ }
+ if ($foundVideo) {
+
+ // Start code 32 bits
+ // horizontal frame size 12 bits
+ // vertical frame size 12 bits
+ // pixel aspect ratio 4 bits
+ // frame rate 4 bits
+ // bitrate 18 bits
+ // marker bit 1 bit
+ // VBV buffer size 10 bits
+ // constrained parameter flag 1 bit
+ // intra quant. matrix flag 1 bit
+ // intra quant. matrix values 512 bits (present if matrix flag == 1)
+ // non-intra quant. matrix flag 1 bit
+ // non-intra quant. matrix values 512 bits (present if matrix flag == 1)
+
+ $info['video']['dataformat'] = 'mpeg';
+
+ $VideoChunkOffset += (strlen(GETID3_MPEG_VIDEO_SEQUENCE_HEADER) - 1);
+
+ $FrameSizeDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 3));
+ $VideoChunkOffset += 3;
+
+ $AspectRatioFrameRateDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 1));
+ $VideoChunkOffset += 1;
+
+ $assortedinformation = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 4));
+ $VideoChunkOffset += 4;
+
+ $info['mpeg']['video']['raw']['framesize_horizontal'] = ($FrameSizeDWORD & 0xFFF000) >> 12; // 12 bits for horizontal frame size
+ $info['mpeg']['video']['raw']['framesize_vertical'] = ($FrameSizeDWORD & 0x000FFF); // 12 bits for vertical frame size
+ $info['mpeg']['video']['raw']['pixel_aspect_ratio'] = ($AspectRatioFrameRateDWORD & 0xF0) >> 4;
+ $info['mpeg']['video']['raw']['frame_rate'] = ($AspectRatioFrameRateDWORD & 0x0F);
+
+ $info['mpeg']['video']['framesize_horizontal'] = $info['mpeg']['video']['raw']['framesize_horizontal'];
+ $info['mpeg']['video']['framesize_vertical'] = $info['mpeg']['video']['raw']['framesize_vertical'];
+
+ $info['mpeg']['video']['pixel_aspect_ratio'] = $this->MPEGvideoAspectRatioLookup($info['mpeg']['video']['raw']['pixel_aspect_ratio']);
+ $info['mpeg']['video']['pixel_aspect_ratio_text'] = $this->MPEGvideoAspectRatioTextLookup($info['mpeg']['video']['raw']['pixel_aspect_ratio']);
+ $info['mpeg']['video']['frame_rate'] = $this->MPEGvideoFramerateLookup($info['mpeg']['video']['raw']['frame_rate']);
+
+ $info['mpeg']['video']['raw']['bitrate'] = getid3_lib::Bin2Dec(substr($assortedinformation, 0, 18));
+ $info['mpeg']['video']['raw']['marker_bit'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 18, 1));
+ $info['mpeg']['video']['raw']['vbv_buffer_size'] = getid3_lib::Bin2Dec(substr($assortedinformation, 19, 10));
+ $info['mpeg']['video']['raw']['constrained_param_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 29, 1));
+ $info['mpeg']['video']['raw']['intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 30, 1));
+ if ($info['mpeg']['video']['raw']['intra_quant_flag']) {
+
+ // read 512 bits
+ $info['mpeg']['video']['raw']['intra_quant'] = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64));
+ $VideoChunkOffset += 64;
+
+ $info['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($info['mpeg']['video']['raw']['intra_quant'], 511, 1));
+ $info['mpeg']['video']['raw']['intra_quant'] = getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1)).substr(getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64)), 0, 511);
+
+ if ($info['mpeg']['video']['raw']['non_intra_quant_flag']) {
+ $info['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64);
+ $VideoChunkOffset += 64;
+ }
+
+ } else {
+
+ $info['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1));
+ if ($info['mpeg']['video']['raw']['non_intra_quant_flag']) {
+ $info['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64);
+ $VideoChunkOffset += 64;
+ }
+
+ }
+
+ if ($info['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits
+
+ $info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] cannot determine average bitrate of VBR MPEG video files';
+ $info['mpeg']['video']['bitrate_mode'] = 'vbr';
+
+ } else {
+
+ $info['mpeg']['video']['bitrate'] = $info['mpeg']['video']['raw']['bitrate'] * 400;
+ $info['mpeg']['video']['bitrate_mode'] = 'cbr';
+ $info['video']['bitrate'] = $info['mpeg']['video']['bitrate'];
+
+ }
+
+ $info['video']['resolution_x'] = $info['mpeg']['video']['framesize_horizontal'];
+ $info['video']['resolution_y'] = $info['mpeg']['video']['framesize_vertical'];
+ $info['video']['frame_rate'] = $info['mpeg']['video']['frame_rate'];
+ $info['video']['bitrate_mode'] = $info['mpeg']['video']['bitrate_mode'];
+ $info['video']['pixel_aspect_ratio'] = $info['mpeg']['video']['pixel_aspect_ratio'];
+ $info['video']['lossless'] = false;
+ $info['video']['bits_per_sample'] = 24;
+
+ } else {
+
+ $info['error'][] = 'Could not find start of video block in the first 100,000 bytes (or before end of file) - this might not be an MPEG-video file?';
+
+ }
+
+ //0x000001B3 begins the sequence_header of every MPEG video stream.
+ //But in MPEG-2, this header must immediately be followed by an
+ //extension_start_code (0x000001B5) with a sequence_extension ID (1).
+ //(This extension contains all the additional MPEG-2 stuff.)
+ //MPEG-1 doesn't have this extension, so that's a sure way to tell the
+ //difference between MPEG-1 and MPEG-2 video streams.
+
+ if (substr($MPEGstreamData, $VideoChunkOffset, 4) == GETID3_MPEG_VIDEO_EXTENSION_START) {
+ $info['video']['codec'] = 'MPEG-2';
+ } else {
+ $info['video']['codec'] = 'MPEG-1';
+ }
+
+
+ $AudioChunkOffset = 0;
+ while (true) {
+ while (substr($MPEGstreamData, $AudioChunkOffset++, 4) !== GETID3_MPEG_AUDIO_START) {
+ if ($AudioChunkOffset >= $MPEGstreamDataLength) {
+ break 2;
+ }
+ }
+
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info = $info;
+ $getid3_mp3 = new getid3_mp3($getid3_temp);
+ for ($i = 0; $i <= 7; $i++) {
+ // some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it up to 13 bytes (or more?) after
+ // I have no idea why or what the difference is, so this is a stupid hack.
+ // If anybody has any better idea of what's going on, please let me know - info@getid3.org
+ fseek($getid3_temp->fp, ftell($this->getid3->fp), SEEK_SET);
+ $getid3_temp->info = $info; // only overwrite real data if valid header found
+ if ($getid3_mp3->decodeMPEGaudioHeader(($AudioChunkOffset + 3) + 8 + $i, $getid3_temp->info, false)) {
+ $info = $getid3_temp->info;
+ $info['audio']['bitrate_mode'] = 'cbr';
+ $info['audio']['lossless'] = false;
+ unset($getid3_temp, $getid3_mp3);
+ break 2;
+ }
+ }
+ unset($getid3_temp, $getid3_mp3);
+ }
+
+ // Temporary hack to account for interleaving overhead:
+ if (!empty($info['video']['bitrate']) && !empty($info['audio']['bitrate'])) {
+ $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['video']['bitrate'] + $info['audio']['bitrate']);
+
+ // Interleaved MPEG audio/video files have a certain amount of overhead that varies
+ // by both video and audio bitrates, and not in any sensible, linear/logarithmic patter
+ // Use interpolated lookup tables to approximately guess how much is overhead, because
+ // playtime is calculated as filesize / total-bitrate
+ $info['playtime_seconds'] *= $this->MPEGsystemNonOverheadPercentage($info['video']['bitrate'], $info['audio']['bitrate']);
+
+ //switch ($info['video']['bitrate']) {
+ // case('5000000'):
+ // $multiplier = 0.93292642112380355828048824319889;
+ // break;
+ // case('5500000'):
+ // $multiplier = 0.93582895375200989965359777343219;
+ // break;
+ // case('6000000'):
+ // $multiplier = 0.93796247714820932532911373859139;
+ // break;
+ // case('7000000'):
+ // $multiplier = 0.9413264083635103463010117778776;
+ // break;
+ // default:
+ // $multiplier = 1;
+ // break;
+ //}
+ //$info['playtime_seconds'] *= $multiplier;
+ //$info['warning'][] = 'Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.';
+ if ($info['video']['bitrate'] < 50000) {
+ $info['warning'][] = 'Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.';
+ }
+ }
+
+ return true;
+ }
+
+
+ public function MPEGsystemNonOverheadPercentage($VideoBitrate, $AudioBitrate) {
+ $OverheadPercentage = 0;
+
+ $AudioBitrate = max(min($AudioBitrate / 1000, 384), 32); // limit to range of 32kbps - 384kbps (should be only legal bitrates, but maybe VBR?)
+ $VideoBitrate = max(min($VideoBitrate / 1000, 10000), 10); // limit to range of 10kbps - 10Mbps (beyond that curves flatten anyways, no big loss)
+
+
+ //OMBB[audiobitrate] = array(video-10kbps, video-100kbps, video-1000kbps, video-10000kbps)
+ $OverheadMultiplierByBitrate[32] = array(0, 0.9676287944368530, 0.9802276264360310, 0.9844916183244460, 0.9852821845179940);
+ $OverheadMultiplierByBitrate[48] = array(0, 0.9779100089209830, 0.9787770035359320, 0.9846738664076130, 0.9852683013799960);
+ $OverheadMultiplierByBitrate[56] = array(0, 0.9731249855367600, 0.9776624308938040, 0.9832606361852130, 0.9843922606633340);
+ $OverheadMultiplierByBitrate[64] = array(0, 0.9755642683275760, 0.9795256705493390, 0.9836573009193170, 0.9851122539404470);
+ $OverheadMultiplierByBitrate[96] = array(0, 0.9788025247497290, 0.9798553314148700, 0.9822956869792560, 0.9834815119124690);
+ $OverheadMultiplierByBitrate[128] = array(0, 0.9816940050925480, 0.9821675936072120, 0.9829756927470870, 0.9839763420152050);
+ $OverheadMultiplierByBitrate[160] = array(0, 0.9825894094561180, 0.9820913399073960, 0.9823907143253970, 0.9832821783651570);
+ $OverheadMultiplierByBitrate[192] = array(0, 0.9832038474336260, 0.9825731694317960, 0.9821028622712400, 0.9828262076447620);
+ $OverheadMultiplierByBitrate[224] = array(0, 0.9836516298538770, 0.9824718601823890, 0.9818302180625380, 0.9823735101626480);
+ $OverheadMultiplierByBitrate[256] = array(0, 0.9845863022094920, 0.9837229411967540, 0.9824521662210830, 0.9828645172100790);
+ $OverheadMultiplierByBitrate[320] = array(0, 0.9849565280263180, 0.9837683142805110, 0.9822885275960400, 0.9824424382727190);
+ $OverheadMultiplierByBitrate[384] = array(0, 0.9856094774357600, 0.9844573394432720, 0.9825970399837330, 0.9824673808303890);
+
+ $BitrateToUseMin = 32;
+ $BitrateToUseMax = 32;
+ $previousBitrate = 32;
+ foreach ($OverheadMultiplierByBitrate as $key => $value) {
+ if ($AudioBitrate >= $previousBitrate) {
+ $BitrateToUseMin = $previousBitrate;
+ }
+ if ($AudioBitrate < $key) {
+ $BitrateToUseMax = $key;
+ break;
+ }
+ $previousBitrate = $key;
+ }
+ $FactorA = ($BitrateToUseMax - $AudioBitrate) / ($BitrateToUseMax - $BitrateToUseMin);
+
+ $VideoBitrateLog10 = log10($VideoBitrate);
+ $VideoFactorMin1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][floor($VideoBitrateLog10)];
+ $VideoFactorMin2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][floor($VideoBitrateLog10)];
+ $VideoFactorMax1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][ceil($VideoBitrateLog10)];
+ $VideoFactorMax2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][ceil($VideoBitrateLog10)];
+ $FactorV = $VideoBitrateLog10 - floor($VideoBitrateLog10);
+
+ $OverheadPercentage = $VideoFactorMin1 * $FactorA * $FactorV;
+ $OverheadPercentage += $VideoFactorMin2 * (1 - $FactorA) * $FactorV;
+ $OverheadPercentage += $VideoFactorMax1 * $FactorA * (1 - $FactorV);
+ $OverheadPercentage += $VideoFactorMax2 * (1 - $FactorA) * (1 - $FactorV);
+
+ return $OverheadPercentage;
+ }
+
+
+ public function MPEGvideoFramerateLookup($rawframerate) {
+ $MPEGvideoFramerateLookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60);
+ return (isset($MPEGvideoFramerateLookup[$rawframerate]) ? (float) $MPEGvideoFramerateLookup[$rawframerate] : (float) 0);
+ }
+
+ public function MPEGvideoAspectRatioLookup($rawaspectratio) {
+ $MPEGvideoAspectRatioLookup = array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0);
+ return (isset($MPEGvideoAspectRatioLookup[$rawaspectratio]) ? (float) $MPEGvideoAspectRatioLookup[$rawaspectratio] : (float) 0);
+ }
+
+ public function MPEGvideoAspectRatioTextLookup($rawaspectratio) {
+ $MPEGvideoAspectRatioTextLookup = array('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved');
+ return (isset($MPEGvideoAspectRatioTextLookup[$rawaspectratio]) ? $MPEGvideoAspectRatioTextLookup[$rawaspectratio] : '');
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.audio-video.quicktime.php b/extensions/TimedMediaHandler/libs/getid3/module.audio-video.quicktime.php
new file mode 100644
index 00000000..e59d61cc
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.audio-video.quicktime.php
@@ -0,0 +1,2192 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.quicktime.php //
+// module for analyzing Quicktime and MP3-in-MP4 files //
+// dependencies: module.audio.mp3.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
+
+class getid3_quicktime extends getid3_handler
+{
+
+ public $ReturnAtomData = true;
+ public $ParseAllPossibleAtoms = false;
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $info['fileformat'] = 'quicktime';
+ $info['quicktime']['hinting'] = false;
+ $info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present
+
+ fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
+
+ $offset = 0;
+ $atomcounter = 0;
+
+ while ($offset < $info['avdataend']) {
+ if (!getid3_lib::intValueSupported($offset)) {
+ $info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions';
+ break;
+ }
+ fseek($this->getid3->fp, $offset, SEEK_SET);
+ $AtomHeader = fread($this->getid3->fp, 8);
+
+ $atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4));
+ $atomname = substr($AtomHeader, 4, 4);
+
+ // 64-bit MOV patch by jlegatektnc*com
+ if ($atomsize == 1) {
+ $atomsize = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 8));
+ }
+
+ $info['quicktime'][$atomname]['name'] = $atomname;
+ $info['quicktime'][$atomname]['size'] = $atomsize;
+ $info['quicktime'][$atomname]['offset'] = $offset;
+
+ if (($offset + $atomsize) > $info['avdataend']) {
+ $info['error'][] = 'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)';
+ return false;
+ }
+
+ if ($atomsize == 0) {
+ // Furthermore, for historical reasons the list of atoms is optionally
+ // terminated by a 32-bit integer set to 0. If you are writing a program
+ // to read user data atoms, you should allow for the terminating 0.
+ break;
+ }
+ switch ($atomname) {
+ case 'mdat': // Media DATa atom
+ // 'mdat' contains the actual data for the audio/video
+ if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) {
+
+ $info['avdataoffset'] = $info['quicktime'][$atomname]['offset'] + 8;
+ $OldAVDataEnd = $info['avdataend'];
+ $info['avdataend'] = $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size'];
+
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
+ $getid3_temp->info['avdataend'] = $info['avdataend'];
+ $getid3_mp3 = new getid3_mp3($getid3_temp);
+ if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode(fread($this->getid3->fp, 4)))) {
+ $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $value) {
+ $info['warning'][] = $value;
+ }
+ }
+ if (!empty($getid3_temp->info['mpeg'])) {
+ $info['mpeg'] = $getid3_temp->info['mpeg'];
+ if (isset($info['mpeg']['audio'])) {
+ $info['audio']['dataformat'] = 'mp3';
+ $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3')));
+ $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
+ $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
+ $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
+ $info['bitrate'] = $info['audio']['bitrate'];
+ }
+ }
+ }
+ unset($getid3_mp3, $getid3_temp);
+ $info['avdataend'] = $OldAVDataEnd;
+ unset($OldAVDataEnd);
+
+ }
+ break;
+
+ case 'free': // FREE space atom
+ case 'skip': // SKIP atom
+ case 'wide': // 64-bit expansion placeholder atom
+ // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
+ break;
+
+ default:
+ $atomHierarchy = array();
+ $info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, fread($this->getid3->fp, $atomsize), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms);
+ break;
+ }
+
+ $offset += $atomsize;
+ $atomcounter++;
+ }
+
+ if (!empty($info['avdataend_tmp'])) {
+ // this value is assigned to a temp value and then erased because
+ // otherwise any atoms beyond the 'mdat' atom would not get parsed
+ $info['avdataend'] = $info['avdataend_tmp'];
+ unset($info['avdataend_tmp']);
+ }
+
+ if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) {
+ $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
+ }
+ if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) {
+ $info['audio']['bitrate'] = $info['bitrate'];
+ }
+ if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) {
+ foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) {
+ $samples_per_second = $samples_count / $info['playtime_seconds'];
+ if ($samples_per_second > 240) {
+ // has to be audio samples
+ } else {
+ $info['video']['frame_rate'] = $samples_per_second;
+ break;
+ }
+ }
+ }
+ if (($info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) {
+ $info['fileformat'] = 'mp4';
+ $info['mime_type'] = 'audio/mp4';
+ unset($info['video']['dataformat']);
+ }
+
+ if (!$this->ReturnAtomData) {
+ unset($info['quicktime']['moov']);
+ }
+
+ if (empty($info['audio']['dataformat']) && !empty($info['quicktime']['audio'])) {
+ $info['audio']['dataformat'] = 'quicktime';
+ }
+ if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) {
+ $info['video']['dataformat'] = 'quicktime';
+ }
+
+ return true;
+ }
+
+ public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
+ // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm
+
+ $info = &$this->getid3->info;
+
+ $atom_parent = array_pop($atomHierarchy);
+ array_push($atomHierarchy, $atomname);
+ $atom_structure['hierarchy'] = implode(' ', $atomHierarchy);
+ $atom_structure['name'] = $atomname;
+ $atom_structure['size'] = $atomsize;
+ $atom_structure['offset'] = $baseoffset;
+//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8)).'<br>';
+//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8), false).'<br><br>';
+ switch ($atomname) {
+ case 'moov': // MOVie container atom
+ case 'trak': // TRAcK container atom
+ case 'clip': // CLIPping container atom
+ case 'matt': // track MATTe container atom
+ case 'edts': // EDiTS container atom
+ case 'tref': // Track REFerence container atom
+ case 'mdia': // MeDIA container atom
+ case 'minf': // Media INFormation container atom
+ case 'dinf': // Data INFormation container atom
+ case 'udta': // User DaTA container atom
+ case 'cmov': // Compressed MOVie container atom
+ case 'rmra': // Reference Movie Record Atom
+ case 'rmda': // Reference Movie Descriptor Atom
+ case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR)
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ break;
+
+ case 'ilst': // Item LiST container atom
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+
+ // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted
+ $allnumericnames = true;
+ foreach ($atom_structure['subatoms'] as $subatomarray) {
+ if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) {
+ $allnumericnames = false;
+ break;
+ }
+ }
+ if ($allnumericnames) {
+ $newData = array();
+ foreach ($atom_structure['subatoms'] as $subatomarray) {
+ foreach ($subatomarray['subatoms'] as $newData_subatomarray) {
+ unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']);
+ $newData[$subatomarray['name']] = $newData_subatomarray;
+ break;
+ }
+ }
+ $atom_structure['data'] = $newData;
+ unset($atom_structure['subatoms']);
+ }
+ break;
+
+ case "\x00\x00\x00\x01":
+ case "\x00\x00\x00\x02":
+ case "\x00\x00\x00\x03":
+ case "\x00\x00\x00\x04":
+ case "\x00\x00\x00\x05":
+ $atomname = getid3_lib::BigEndian2Int($atomname);
+ $atom_structure['name'] = $atomname;
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ break;
+
+ case 'stbl': // Sample TaBLe container atom
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ $isVideo = false;
+ $framerate = 0;
+ $framecount = 0;
+ foreach ($atom_structure['subatoms'] as $key => $value_array) {
+ if (isset($value_array['sample_description_table'])) {
+ foreach ($value_array['sample_description_table'] as $key2 => $value_array2) {
+ if (isset($value_array2['data_format'])) {
+ switch ($value_array2['data_format']) {
+ case 'avc1':
+ case 'mp4v':
+ // video data
+ $isVideo = true;
+ break;
+ case 'mp4a':
+ // audio data
+ break;
+ }
+ }
+ }
+ } elseif (isset($value_array['time_to_sample_table'])) {
+ foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) {
+ if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) {
+ $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3);
+ $framecount = $value_array2['sample_count'];
+ }
+ }
+ }
+ }
+ if ($isVideo && $framerate) {
+ $info['quicktime']['video']['frame_rate'] = $framerate;
+ $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate'];
+ }
+ if ($isVideo && $framecount) {
+ $info['quicktime']['video']['frame_count'] = $framecount;
+ }
+ break;
+
+
+ case 'aART': // Album ARTist
+ case 'catg': // CaTeGory
+ case 'covr': // COVeR artwork
+ case 'cpil': // ComPILation
+ case 'cprt': // CoPyRighT
+ case 'desc': // DESCription
+ case 'disk': // DISK number
+ case 'egid': // Episode Global ID
+ case 'gnre': // GeNRE
+ case 'keyw': // KEYWord
+ case 'ldes':
+ case 'pcst': // PodCaST
+ case 'pgap': // GAPless Playback
+ case 'purd': // PURchase Date
+ case 'purl': // Podcast URL
+ case 'rati':
+ case 'rndu':
+ case 'rpdu':
+ case 'rtng': // RaTiNG
+ case 'stik':
+ case 'tmpo': // TeMPO (BPM)
+ case 'trkn': // TRacK Number
+ case 'tves': // TV EpiSode
+ case 'tvnn': // TV Network Name
+ case 'tvsh': // TV SHow Name
+ case 'tvsn': // TV SeasoN
+ case 'akID': // iTunes store account type
+ case 'apID':
+ case 'atID':
+ case 'cmID':
+ case 'cnID':
+ case 'geID':
+ case 'plID':
+ case 'sfID': // iTunes store country
+ case 'alb': // ALBum
+ case 'art': // ARTist
+ case 'ART':
+ case 'aut':
+ case 'cmt': // CoMmenT
+ case 'com': // COMposer
+ case 'cpy':
+ case 'day': // content created year
+ case 'dir':
+ case 'ed1':
+ case 'ed2':
+ case 'ed3':
+ case 'ed4':
+ case 'ed5':
+ case 'ed6':
+ case 'ed7':
+ case 'ed8':
+ case 'ed9':
+ case 'enc':
+ case 'fmt':
+ case 'gen': // GENre
+ case 'grp': // GRouPing
+ case 'hst':
+ case 'inf':
+ case 'lyr': // LYRics
+ case 'mak':
+ case 'mod':
+ case 'nam': // full NAMe
+ case 'ope':
+ case 'PRD':
+ case 'prd':
+ case 'prf':
+ case 'req':
+ case 'src':
+ case 'swr':
+ case 'too': // encoder
+ case 'trk': // TRacK
+ case 'url':
+ case 'wrn':
+ case 'wrt': // WRiTer
+ case '----': // itunes specific
+ if ($atom_parent == 'udta') {
+ // User data atom handler
+ $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
+ $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
+ $atom_structure['data'] = substr($atom_data, 4);
+
+ $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
+ if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
+ $info['comments']['language'][] = $atom_structure['language'];
+ }
+ } else {
+ // Apple item list box atom handler
+ $atomoffset = 0;
+ if (substr($atom_data, 2, 2) == "\x10\xB5") {
+ // not sure what it means, but observed on iPhone4 data.
+ // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data
+ while ($atomoffset < strlen($atom_data)) {
+ $boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2));
+ $boxsmalltype = substr($atom_data, $atomoffset + 2, 2);
+ $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize);
+ switch ($boxsmalltype) {
+ case "\x10\xB5":
+ $atom_structure['data'] = $boxsmalldata;
+ break;
+ default:
+ $info['warning'][] = 'Unknown QuickTime smallbox type: "'.getid3_lib::PrintHexBytes($boxsmalltype).'" at offset '.$baseoffset;
+ $atom_structure['data'] = $atom_data;
+ break;
+ }
+ $atomoffset += (4 + $boxsmallsize);
+ }
+ } else {
+ while ($atomoffset < strlen($atom_data)) {
+ $boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4));
+ $boxtype = substr($atom_data, $atomoffset + 4, 4);
+ $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8);
+ if ($boxsize <= 1) {
+ $info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.$atomname.'" at offset: '.($atom_structure['offset'] + $atomoffset);
+ $atom_structure['data'] = null;
+ $atomoffset = strlen($atom_data);
+ break;
+ }
+ $atomoffset += $boxsize;
+
+ switch ($boxtype) {
+ case 'mean':
+ case 'name':
+ $atom_structure[$boxtype] = substr($boxdata, 4);
+ break;
+
+ case 'data':
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3));
+ switch ($atom_structure['flags_raw']) {
+ case 0: // data flag
+ case 21: // tmpo/cpil flag
+ switch ($atomname) {
+ case 'cpil':
+ case 'pcst':
+ case 'pgap':
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
+ break;
+
+ case 'tmpo':
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2));
+ break;
+
+ case 'disk':
+ case 'trkn':
+ $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2));
+ $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2));
+ $atom_structure['data'] = empty($num) ? '' : $num;
+ $atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total;
+ break;
+
+ case 'gnre':
+ $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
+ $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1);
+ break;
+
+ case 'rtng':
+ $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
+ $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]);
+ break;
+
+ case 'stik':
+ $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1));
+ $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]);
+ break;
+
+ case 'sfID':
+ $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
+ $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]);
+ break;
+
+ case 'egid':
+ case 'purl':
+ $atom_structure['data'] = substr($boxdata, 8);
+ break;
+
+ default:
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4));
+ }
+ break;
+
+ case 1: // text flag
+ case 13: // image flag
+ default:
+ $atom_structure['data'] = substr($boxdata, 8);
+ break;
+
+ }
+ break;
+
+ default:
+ $info['warning'][] = 'Unknown QuickTime box type: "'.getid3_lib::PrintHexBytes($boxtype).'" at offset '.$baseoffset;
+ $atom_structure['data'] = $atom_data;
+
+ }
+ }
+ }
+ }
+ $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']);
+ break;
+
+
+ case 'play': // auto-PLAY atom
+ $atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+
+ $info['quicktime']['autoplay'] = $atom_structure['autoplay'];
+ break;
+
+
+ case 'WLOC': // Window LOCation atom
+ $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
+ $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2));
+ break;
+
+
+ case 'LOOP': // LOOPing atom
+ case 'SelO': // play SELection Only atom
+ case 'AllF': // play ALL Frames atom
+ $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data);
+ break;
+
+
+ case 'name': //
+ case 'MCPS': // Media Cleaner PRo
+ case '@PRM': // adobe PReMiere version
+ case '@PRQ': // adobe PRemiere Quicktime version
+ $atom_structure['data'] = $atom_data;
+ break;
+
+
+ case 'cmvd': // Compressed MooV Data atom
+ // Code by ubergeekubergeek*tv based on information from
+ // http://developer.apple.com/quicktime/icefloe/dispatch012.html
+ $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
+
+ $CompressedFileData = substr($atom_data, 4);
+ if ($UncompressedHeader = @gzuncompress($CompressedFileData)) {
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms);
+ } else {
+ $info['warning'][] = 'Error decompressing compressed MOV atom at offset '.$atom_structure['offset'];
+ }
+ break;
+
+
+ case 'dcom': // Data COMpression atom
+ $atom_structure['compression_id'] = $atom_data;
+ $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data);
+ break;
+
+
+ case 'rdrf': // Reference movie Data ReFerence atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001);
+
+ $atom_structure['reference_type_name'] = substr($atom_data, 4, 4);
+ $atom_structure['reference_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ switch ($atom_structure['reference_type_name']) {
+ case 'url ':
+ $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12));
+ break;
+
+ case 'alis':
+ $atom_structure['file_alias'] = substr($atom_data, 12);
+ break;
+
+ case 'rsrc':
+ $atom_structure['resource_alias'] = substr($atom_data, 12);
+ break;
+
+ default:
+ $atom_structure['data'] = substr($atom_data, 12);
+ break;
+ }
+ break;
+
+
+ case 'rmqu': // Reference Movie QUality atom
+ $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data);
+ break;
+
+
+ case 'rmcs': // Reference Movie Cpu Speed atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ break;
+
+
+ case 'rmvc': // Reference Movie Version Check atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4);
+ $atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['gestalt_value'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+ $atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
+ break;
+
+
+ case 'rmcd': // Reference Movie Component check atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['component_type'] = substr($atom_data, 4, 4);
+ $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
+ $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
+ $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
+ $atom_structure['component_min_version'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4));
+ break;
+
+
+ case 'rmdr': // Reference Movie Data Rate atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['data_rate'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+
+ $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10;
+ break;
+
+
+ case 'rmla': // Reference Movie Language Atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+
+ $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
+ if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
+ $info['comments']['language'][] = $atom_structure['language'];
+ }
+ break;
+
+
+ case 'rmla': // Reference Movie Language Atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ break;
+
+
+ case 'ptv ': // Print To Video - defines a movie's full screen mode
+ // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm
+ $atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2));
+ $atom_structure['reserved_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000
+ $atom_structure['reserved_2'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000
+ $atom_structure['slide_show_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1));
+ $atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1));
+
+ $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag'];
+ $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag'];
+
+ $ptv_lookup[0] = 'normal';
+ $ptv_lookup[1] = 'double';
+ $ptv_lookup[2] = 'half';
+ $ptv_lookup[3] = 'full';
+ $ptv_lookup[4] = 'current';
+ if (isset($ptv_lookup[$atom_structure['display_size_raw']])) {
+ $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']];
+ } else {
+ $info['warning'][] = 'unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')';
+ }
+ break;
+
+
+ case 'stsd': // Sample Table Sample Description atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stsdEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4));
+ $stsdEntriesDataOffset += 4;
+ $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4);
+ $stsdEntriesDataOffset += 4;
+ $atom_structure['sample_description_table'][$i]['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6));
+ $stsdEntriesDataOffset += 6;
+ $atom_structure['sample_description_table'][$i]['reference_index'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2));
+ $stsdEntriesDataOffset += 2;
+ $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2));
+ $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2);
+
+ $atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2));
+ $atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2));
+ $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4);
+
+ switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) {
+
+ case "\x00\x00\x00\x00":
+ // audio tracks
+ $atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2));
+ $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2));
+ $atom_structure['sample_description_table'][$i]['audio_compression_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2));
+ $atom_structure['sample_description_table'][$i]['audio_packet_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2));
+ $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4));
+
+ // video tracks
+ // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html
+ $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
+ $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
+ $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
+ $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
+ $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
+ $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
+ $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 4));
+ $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36, 2));
+ $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 38, 4);
+ $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42, 2));
+ $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44, 2));
+
+ switch ($atom_structure['sample_description_table'][$i]['data_format']) {
+ case '2vuY':
+ case 'avc1':
+ case 'cvid':
+ case 'dvc ':
+ case 'dvcp':
+ case 'gif ':
+ case 'h263':
+ case 'jpeg':
+ case 'kpcd':
+ case 'mjpa':
+ case 'mjpb':
+ case 'mp4v':
+ case 'png ':
+ case 'raw ':
+ case 'rle ':
+ case 'rpza':
+ case 'smc ':
+ case 'SVQ1':
+ case 'SVQ3':
+ case 'tiff':
+ case 'v210':
+ case 'v216':
+ case 'v308':
+ case 'v408':
+ case 'v410':
+ case 'yuv2':
+ $info['fileformat'] = 'mp4';
+ $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
+// http://www.getid3.org/phpBB3/viewtopic.php?t=1550
+//if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers
+if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) {
+ // assume that values stored here are more important than values stored in [tkhd] atom
+ $info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width'];
+ $info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height'];
+ $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
+ $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
+}
+ break;
+
+ case 'qtvr':
+ $info['video']['dataformat'] = 'quicktimevr';
+ break;
+
+ case 'mp4a':
+ default:
+ $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
+ $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate'];
+ $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels'];
+ $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth'];
+ $info['audio']['codec'] = $info['quicktime']['audio']['codec'];
+ $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate'];
+ $info['audio']['channels'] = $info['quicktime']['audio']['channels'];
+ $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth'];
+ switch ($atom_structure['sample_description_table'][$i]['data_format']) {
+ case 'raw ': // PCM
+ case 'alac': // Apple Lossless Audio Codec
+ $info['audio']['lossless'] = true;
+ break;
+ default:
+ $info['audio']['lossless'] = false;
+ break;
+ }
+ break;
+ }
+ break;
+
+ default:
+ switch ($atom_structure['sample_description_table'][$i]['data_format']) {
+ case 'mp4s':
+ $info['fileformat'] = 'mp4';
+ break;
+
+ default:
+ // video atom
+ $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4));
+ $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4));
+ $atom_structure['sample_description_table'][$i]['video_frame_width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2));
+ $atom_structure['sample_description_table'][$i]['video_frame_height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2));
+ $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4));
+ $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4));
+ $atom_structure['sample_description_table'][$i]['video_data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4));
+ $atom_structure['sample_description_table'][$i]['video_frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2));
+ $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1));
+ $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']);
+ $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2));
+ $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2));
+
+ $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color');
+ $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']);
+
+ if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') {
+ $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format'];
+ $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']);
+ $info['quicktime']['video']['codec'] = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']);
+ $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'];
+ $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name'];
+
+ $info['video']['codec'] = $info['quicktime']['video']['codec'];
+ $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth'];
+ }
+ $info['video']['lossless'] = false;
+ $info['video']['pixel_aspect_ratio'] = (float) 1;
+ break;
+ }
+ break;
+ }
+ switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) {
+ case 'mp4a':
+ $info['audio']['dataformat'] = 'mp4';
+ $info['quicktime']['audio']['codec'] = 'mp4';
+ break;
+
+ case '3ivx':
+ case '3iv1':
+ case '3iv2':
+ $info['video']['dataformat'] = '3ivx';
+ break;
+
+ case 'xvid':
+ $info['video']['dataformat'] = 'xvid';
+ break;
+
+ case 'mp4v':
+ $info['video']['dataformat'] = 'mpeg4';
+ break;
+
+ case 'divx':
+ case 'div1':
+ case 'div2':
+ case 'div3':
+ case 'div4':
+ case 'div5':
+ case 'div6':
+ $info['video']['dataformat'] = 'divx';
+ break;
+
+ default:
+ // do nothing
+ break;
+ }
+ unset($atom_structure['sample_description_table'][$i]['data']);
+ }
+ break;
+
+
+ case 'stts': // Sample Table Time-to-Sample atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $sttsEntriesDataOffset = 8;
+ //$FrameRateCalculatorArray = array();
+ $frames_count = 0;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
+ $sttsEntriesDataOffset += 4;
+ $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4));
+ $sttsEntriesDataOffset += 4;
+
+ $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count'];
+
+ // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM
+ //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) {
+ // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'];
+ // if ($stts_new_framerate <= 60) {
+ // // some atoms have durations of "1" giving a very large framerate, which probably is not right
+ // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate);
+ // }
+ //}
+ //
+ //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count'];
+ }
+ $info['quicktime']['stts_framecount'][] = $frames_count;
+ //$sttsFramesTotal = 0;
+ //$sttsSecondsTotal = 0;
+ //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) {
+ // if (($frames_per_second > 60) || ($frames_per_second < 1)) {
+ // // not video FPS information, probably audio information
+ // $sttsFramesTotal = 0;
+ // $sttsSecondsTotal = 0;
+ // break;
+ // }
+ // $sttsFramesTotal += $frame_count;
+ // $sttsSecondsTotal += $frame_count / $frames_per_second;
+ //}
+ //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) {
+ // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) {
+ // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal;
+ // }
+ //}
+ break;
+
+
+ case 'stss': // Sample Table Sync Sample (key frames) atom
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stssEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4));
+ $stssEntriesDataOffset += 4;
+ }
+ }
+ break;
+
+
+ case 'stsc': // Sample Table Sample-to-Chunk atom
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stscEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
+ $stscEntriesDataOffset += 4;
+ $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
+ $stscEntriesDataOffset += 4;
+ $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4));
+ $stscEntriesDataOffset += 4;
+ }
+ }
+ break;
+
+
+ case 'stsz': // Sample Table SiZe atom
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $stszEntriesDataOffset = 12;
+ if ($atom_structure['sample_size'] == 0) {
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4));
+ $stszEntriesDataOffset += 4;
+ }
+ }
+ }
+ break;
+
+
+ case 'stco': // Sample Table Chunk Offset atom
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stcoEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4));
+ $stcoEntriesDataOffset += 4;
+ }
+ }
+ break;
+
+
+ case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files)
+ if ($ParseAllPossibleAtoms) {
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $stcoEntriesDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8));
+ $stcoEntriesDataOffset += 8;
+ }
+ }
+ break;
+
+
+ case 'dref': // Data REFerence atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $drefDataOffset = 8;
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++) {
+ $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4));
+ $drefDataOffset += 4;
+ $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4);
+ $drefDataOffset += 4;
+ $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1));
+ $drefDataOffset += 1;
+ $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000
+ $drefDataOffset += 3;
+ $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3));
+ $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3);
+
+ $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001);
+ }
+ break;
+
+
+ case 'gmin': // base Media INformation atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
+ $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
+ $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
+ $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2));
+ $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2));
+ break;
+
+
+ case 'smhd': // Sound Media information HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
+ break;
+
+
+ case 'vmhd': // Video Media information HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2));
+ $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2));
+ $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2));
+ $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2));
+
+ $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001);
+ break;
+
+
+ case 'hdlr': // HanDLeR reference atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['component_type'] = substr($atom_data, 4, 4);
+ $atom_structure['component_subtype'] = substr($atom_data, 8, 4);
+ $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4);
+ $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
+ $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24));
+
+ if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) {
+ $info['video']['dataformat'] = 'quicktimevr';
+ }
+ break;
+
+
+ case 'mdhd': // MeDia HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+ $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2));
+ $atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2));
+
+ if ($atom_structure['time_scale'] == 0) {
+ $info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero';
+ return false;
+ }
+ $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
+
+ $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
+ $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
+ $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
+ $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']);
+ if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) {
+ $info['comments']['language'][] = $atom_structure['language'];
+ }
+ break;
+
+
+ case 'pnot': // Preview atom
+ $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format"
+ $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00
+ $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT'
+ $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01
+
+ $atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']);
+ break;
+
+
+ case 'crgn': // Clipping ReGioN atom
+ $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box,
+ $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields
+ $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region.
+ break;
+
+
+ case 'load': // track LOAD settings atom
+ $atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
+ $atom_structure['preload_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['preload_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['default_hints_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+
+ $atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020);
+ $atom_structure['default_hints']['high_quality'] = (bool) ($atom_structure['default_hints_raw'] & 0x0100);
+ break;
+
+
+ case 'tmcd': // TiMe CoDe atom
+ case 'chap': // CHAPter list atom
+ case 'sync': // SYNChronization atom
+ case 'scpt': // tranSCriPT atom
+ case 'ssrc': // non-primary SouRCe atom
+ for ($i = 0; $i < (strlen($atom_data) % 4); $i++) {
+ $atom_structure['track_id'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $i * 4, 4));
+ }
+ break;
+
+
+ case 'elst': // Edit LiST atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) {
+ $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4));
+ $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4));
+ $atom_structure['edit_list'][$i]['media_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4));
+ }
+ break;
+
+
+ case 'kmat': // compressed MATte atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000
+ $atom_structure['matte_data_raw'] = substr($atom_data, 4);
+ break;
+
+
+ case 'ctab': // Color TABle atom
+ $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000
+ $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000
+ $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1;
+ for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) {
+ $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2));
+ $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2));
+ $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2));
+ $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2));
+ }
+ break;
+
+
+ case 'mvhd': // MoVie HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+ $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['preferred_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4));
+ $atom_structure['preferred_volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2));
+ $atom_structure['reserved'] = substr($atom_data, 26, 10);
+ $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4));
+ $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
+ $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4));
+ $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4));
+ $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
+ $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4));
+ $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4));
+ $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
+ $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4));
+ $atom_structure['preview_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 72, 4));
+ $atom_structure['preview_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 76, 4));
+ $atom_structure['poster_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 80, 4));
+ $atom_structure['selection_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 84, 4));
+ $atom_structure['selection_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 88, 4));
+ $atom_structure['current_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 92, 4));
+ $atom_structure['next_track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 96, 4));
+
+ if ($atom_structure['time_scale'] == 0) {
+ $info['error'][] = 'Corrupt Quicktime file: mvhd.time_scale == zero';
+ return false;
+ }
+ $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
+ $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
+ $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']);
+ $info['quicktime']['display_scale'] = $atom_structure['matrix_a'];
+ $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale'];
+ break;
+
+
+ case 'tkhd': // TracK HeaDer atom
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4));
+ $atom_structure['trackid'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4));
+ $atom_structure['reserved1'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4));
+ $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4));
+ $atom_structure['reserved2'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 8));
+ $atom_structure['layer'] = getid3_lib::BigEndian2Int(substr($atom_data, 32, 2));
+ $atom_structure['alternate_group'] = getid3_lib::BigEndian2Int(substr($atom_data, 34, 2));
+ $atom_structure['volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2));
+ $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2));
+// http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html
+// http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737
+ $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4));
+ $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4));
+ $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4));
+ $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4));
+ $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4));
+ $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4));
+ $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4));
+ $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4));
+ $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4));
+ $atom_structure['width'] = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4));
+ $atom_structure['height'] = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4));
+ $atom_structure['flags']['enabled'] = (bool) ($atom_structure['flags_raw'] & 0x0001);
+ $atom_structure['flags']['in_movie'] = (bool) ($atom_structure['flags_raw'] & 0x0002);
+ $atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004);
+ $atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x0008);
+ $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']);
+ $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']);
+
+ if ($atom_structure['flags']['enabled'] == 1) {
+ if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) {
+ $info['video']['resolution_x'] = $atom_structure['width'];
+ $info['video']['resolution_y'] = $atom_structure['height'];
+ }
+ $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']);
+ $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']);
+ $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x'];
+ $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y'];
+ } else {
+ // see: http://www.getid3.org/phpBB3/viewtopic.php?t=1295
+ //if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); }
+ //if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); }
+ //if (isset($info['quicktime']['video'])) { unset($info['quicktime']['video']); }
+ }
+ break;
+
+
+ case 'iods': // Initial Object DeScriptor atom
+ // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h
+ // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html
+ $offset = 0;
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3));
+ $offset += 3;
+ $atom_structure['mp4_iod_tag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
+ //$offset already adjusted by quicktime_read_mp4_descr_length()
+ $atom_structure['object_descriptor_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2));
+ $offset += 2;
+ $atom_structure['od_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['scene_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['audio_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['video_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['graphics_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+
+ $atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields
+ for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) {
+ $atom_structure['track'][$i]['ES_ID_IncTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1));
+ $offset += 1;
+ $atom_structure['track'][$i]['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset);
+ //$offset already adjusted by quicktime_read_mp4_descr_length()
+ $atom_structure['track'][$i]['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4));
+ $offset += 4;
+ }
+
+ $atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']);
+ $atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']);
+ break;
+
+ case 'ftyp': // FileTYPe (?) atom (for MP4 it seems)
+ $atom_structure['signature'] = substr($atom_data, 0, 4);
+ $atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4));
+ $atom_structure['fourcc'] = substr($atom_data, 8, 4);
+ break;
+
+ case 'mdat': // Media DATa atom
+ case 'free': // FREE space atom
+ case 'skip': // SKIP atom
+ case 'wide': // 64-bit expansion placeholder atom
+ // 'mdat' data is too big to deal with, contains no useful metadata
+ // 'free', 'skip' and 'wide' are just padding, contains no useful data at all
+
+ // When writing QuickTime files, it is sometimes necessary to update an atom's size.
+ // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom
+ // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime
+ // puts an 8-byte placeholder atom before any atoms it may have to update the size of.
+ // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the
+ // placeholder atom can be overwritten to obtain the necessary 8 extra bytes.
+ // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ).
+ break;
+
+
+ case 'nsav': // NoSAVe atom
+ // http://developer.apple.com/technotes/tn/tn2038.html
+ $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
+ break;
+
+ case 'ctyp': // Controller TYPe atom (seen on QTVR)
+ // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
+ // some controller names are:
+ // 0x00 + 'std' for linear movie
+ // 'none' for no controls
+ $atom_structure['ctyp'] = substr($atom_data, 0, 4);
+ $info['quicktime']['controller'] = $atom_structure['ctyp'];
+ switch ($atom_structure['ctyp']) {
+ case 'qtvr':
+ $info['video']['dataformat'] = 'quicktimevr';
+ break;
+ }
+ break;
+
+ case 'pano': // PANOrama track (seen on QTVR)
+ $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4));
+ break;
+
+ case 'hint': // HINT track
+ case 'hinf': //
+ case 'hinv': //
+ case 'hnti': //
+ $info['quicktime']['hinting'] = true;
+ break;
+
+ case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR)
+ for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) {
+ $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4));
+ }
+ break;
+
+
+ // Observed-but-not-handled atom types are just listed here to prevent warnings being generated
+ case 'FXTC': // Something to do with Adobe After Effects (?)
+ case 'PrmA':
+ case 'code':
+ case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html
+ case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html
+ // tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838]
+ // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html
+ // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html
+ case 'ctts':// STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
+ case 'cslg':// STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
+ case 'sdtp':// STSampleDependencyAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
+ case 'stps':// STPartialSyncSampleAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html
+ //$atom_structure['data'] = $atom_data;
+ break;
+
+ case 'xyz': // GPS latitude+longitude+altitude
+ $atom_structure['data'] = $atom_data;
+ if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) {
+ @list($all, $latitude, $longitude, $altitude) = $matches;
+ $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude);
+ $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude);
+ if (!empty($altitude)) {
+ $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude);
+ }
+ } else {
+ $info['warning'][] = 'QuickTime atom "xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.';
+ }
+ break;
+
+ case 'NCDT':
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
+ // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms);
+ break;
+ case 'NCTH': // Nikon Camera THumbnail image
+ case 'NCVW': // Nikon Camera preVieW image
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
+ if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) {
+ $atom_structure['data'] = $atom_data;
+ $atom_structure['image_mime'] = 'image/jpeg';
+ $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image'));
+ $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']);
+ }
+ break;
+ case 'NCHD': // MakerNoteVersion
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
+ $atom_structure['data'] = $atom_data;
+ break;
+ case 'NCTG': // NikonTags
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
+ $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data);
+ break;
+ case 'NCDB': // NikonTags
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html
+ $atom_structure['data'] = $atom_data;
+ break;
+
+ case "\x00\x00\x00\x00":
+ case 'meta': // METAdata atom
+ // some kind of metacontainer, may contain a big data dump such as:
+ // mdta keys  mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst   data DEApple 0  (data DE2011-05-11T17:54:04+0200 2  *data DE+52.4936+013.3897+040.247/   data DE4.3.1  data DEiPhone 4
+ // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
+
+ $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1));
+ $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3));
+ $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms);
+ break;
+
+ case 'data': // metaDATA atom
+ // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data
+ $atom_structure['language'] = substr($atom_data, 4 + 0, 2);
+ $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2));
+ $atom_structure['data'] = substr($atom_data, 4 + 4);
+ break;
+
+ default:
+ $info['warning'][] = 'Unknown QuickTime atom type: "'.$atomname.'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset;
+ $atom_structure['data'] = $atom_data;
+ break;
+ }
+ array_pop($atomHierarchy);
+ return $atom_structure;
+ }
+
+ public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) {
+//echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'<br><br>';
+ $atom_structure = false;
+ $subatomoffset = 0;
+ $subatomcounter = 0;
+ if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) {
+ return false;
+ }
+ while ($subatomoffset < strlen($atom_data)) {
+ $subatomsize = getid3_lib::BigEndian2Int(substr($atom_data, $subatomoffset + 0, 4));
+ $subatomname = substr($atom_data, $subatomoffset + 4, 4);
+ $subatomdata = substr($atom_data, $subatomoffset + 8, $subatomsize - 8);
+ if ($subatomsize == 0) {
+ // Furthermore, for historical reasons the list of atoms is optionally
+ // terminated by a 32-bit integer set to 0. If you are writing a program
+ // to read user data atoms, you should allow for the terminating 0.
+ return $atom_structure;
+ }
+
+ $atom_structure[$subatomcounter] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms);
+
+ $subatomoffset += $subatomsize;
+ $subatomcounter++;
+ }
+ return $atom_structure;
+ }
+
+
+ public function quicktime_read_mp4_descr_length($data, &$offset) {
+ // http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html
+ $num_bytes = 0;
+ $length = 0;
+ do {
+ $b = ord(substr($data, $offset++, 1));
+ $length = ($length << 7) | ($b & 0x7F);
+ } while (($b & 0x80) && ($num_bytes++ < 4));
+ return $length;
+ }
+
+
+ public function QuicktimeLanguageLookup($languageid) {
+ static $QuicktimeLanguageLookup = array();
+ if (empty($QuicktimeLanguageLookup)) {
+ $QuicktimeLanguageLookup[0] = 'English';
+ $QuicktimeLanguageLookup[1] = 'French';
+ $QuicktimeLanguageLookup[2] = 'German';
+ $QuicktimeLanguageLookup[3] = 'Italian';
+ $QuicktimeLanguageLookup[4] = 'Dutch';
+ $QuicktimeLanguageLookup[5] = 'Swedish';
+ $QuicktimeLanguageLookup[6] = 'Spanish';
+ $QuicktimeLanguageLookup[7] = 'Danish';
+ $QuicktimeLanguageLookup[8] = 'Portuguese';
+ $QuicktimeLanguageLookup[9] = 'Norwegian';
+ $QuicktimeLanguageLookup[10] = 'Hebrew';
+ $QuicktimeLanguageLookup[11] = 'Japanese';
+ $QuicktimeLanguageLookup[12] = 'Arabic';
+ $QuicktimeLanguageLookup[13] = 'Finnish';
+ $QuicktimeLanguageLookup[14] = 'Greek';
+ $QuicktimeLanguageLookup[15] = 'Icelandic';
+ $QuicktimeLanguageLookup[16] = 'Maltese';
+ $QuicktimeLanguageLookup[17] = 'Turkish';
+ $QuicktimeLanguageLookup[18] = 'Croatian';
+ $QuicktimeLanguageLookup[19] = 'Chinese (Traditional)';
+ $QuicktimeLanguageLookup[20] = 'Urdu';
+ $QuicktimeLanguageLookup[21] = 'Hindi';
+ $QuicktimeLanguageLookup[22] = 'Thai';
+ $QuicktimeLanguageLookup[23] = 'Korean';
+ $QuicktimeLanguageLookup[24] = 'Lithuanian';
+ $QuicktimeLanguageLookup[25] = 'Polish';
+ $QuicktimeLanguageLookup[26] = 'Hungarian';
+ $QuicktimeLanguageLookup[27] = 'Estonian';
+ $QuicktimeLanguageLookup[28] = 'Lettish';
+ $QuicktimeLanguageLookup[28] = 'Latvian';
+ $QuicktimeLanguageLookup[29] = 'Saamisk';
+ $QuicktimeLanguageLookup[29] = 'Lappish';
+ $QuicktimeLanguageLookup[30] = 'Faeroese';
+ $QuicktimeLanguageLookup[31] = 'Farsi';
+ $QuicktimeLanguageLookup[31] = 'Persian';
+ $QuicktimeLanguageLookup[32] = 'Russian';
+ $QuicktimeLanguageLookup[33] = 'Chinese (Simplified)';
+ $QuicktimeLanguageLookup[34] = 'Flemish';
+ $QuicktimeLanguageLookup[35] = 'Irish';
+ $QuicktimeLanguageLookup[36] = 'Albanian';
+ $QuicktimeLanguageLookup[37] = 'Romanian';
+ $QuicktimeLanguageLookup[38] = 'Czech';
+ $QuicktimeLanguageLookup[39] = 'Slovak';
+ $QuicktimeLanguageLookup[40] = 'Slovenian';
+ $QuicktimeLanguageLookup[41] = 'Yiddish';
+ $QuicktimeLanguageLookup[42] = 'Serbian';
+ $QuicktimeLanguageLookup[43] = 'Macedonian';
+ $QuicktimeLanguageLookup[44] = 'Bulgarian';
+ $QuicktimeLanguageLookup[45] = 'Ukrainian';
+ $QuicktimeLanguageLookup[46] = 'Byelorussian';
+ $QuicktimeLanguageLookup[47] = 'Uzbek';
+ $QuicktimeLanguageLookup[48] = 'Kazakh';
+ $QuicktimeLanguageLookup[49] = 'Azerbaijani';
+ $QuicktimeLanguageLookup[50] = 'AzerbaijanAr';
+ $QuicktimeLanguageLookup[51] = 'Armenian';
+ $QuicktimeLanguageLookup[52] = 'Georgian';
+ $QuicktimeLanguageLookup[53] = 'Moldavian';
+ $QuicktimeLanguageLookup[54] = 'Kirghiz';
+ $QuicktimeLanguageLookup[55] = 'Tajiki';
+ $QuicktimeLanguageLookup[56] = 'Turkmen';
+ $QuicktimeLanguageLookup[57] = 'Mongolian';
+ $QuicktimeLanguageLookup[58] = 'MongolianCyr';
+ $QuicktimeLanguageLookup[59] = 'Pashto';
+ $QuicktimeLanguageLookup[60] = 'Kurdish';
+ $QuicktimeLanguageLookup[61] = 'Kashmiri';
+ $QuicktimeLanguageLookup[62] = 'Sindhi';
+ $QuicktimeLanguageLookup[63] = 'Tibetan';
+ $QuicktimeLanguageLookup[64] = 'Nepali';
+ $QuicktimeLanguageLookup[65] = 'Sanskrit';
+ $QuicktimeLanguageLookup[66] = 'Marathi';
+ $QuicktimeLanguageLookup[67] = 'Bengali';
+ $QuicktimeLanguageLookup[68] = 'Assamese';
+ $QuicktimeLanguageLookup[69] = 'Gujarati';
+ $QuicktimeLanguageLookup[70] = 'Punjabi';
+ $QuicktimeLanguageLookup[71] = 'Oriya';
+ $QuicktimeLanguageLookup[72] = 'Malayalam';
+ $QuicktimeLanguageLookup[73] = 'Kannada';
+ $QuicktimeLanguageLookup[74] = 'Tamil';
+ $QuicktimeLanguageLookup[75] = 'Telugu';
+ $QuicktimeLanguageLookup[76] = 'Sinhalese';
+ $QuicktimeLanguageLookup[77] = 'Burmese';
+ $QuicktimeLanguageLookup[78] = 'Khmer';
+ $QuicktimeLanguageLookup[79] = 'Lao';
+ $QuicktimeLanguageLookup[80] = 'Vietnamese';
+ $QuicktimeLanguageLookup[81] = 'Indonesian';
+ $QuicktimeLanguageLookup[82] = 'Tagalog';
+ $QuicktimeLanguageLookup[83] = 'MalayRoman';
+ $QuicktimeLanguageLookup[84] = 'MalayArabic';
+ $QuicktimeLanguageLookup[85] = 'Amharic';
+ $QuicktimeLanguageLookup[86] = 'Tigrinya';
+ $QuicktimeLanguageLookup[87] = 'Galla';
+ $QuicktimeLanguageLookup[87] = 'Oromo';
+ $QuicktimeLanguageLookup[88] = 'Somali';
+ $QuicktimeLanguageLookup[89] = 'Swahili';
+ $QuicktimeLanguageLookup[90] = 'Ruanda';
+ $QuicktimeLanguageLookup[91] = 'Rundi';
+ $QuicktimeLanguageLookup[92] = 'Chewa';
+ $QuicktimeLanguageLookup[93] = 'Malagasy';
+ $QuicktimeLanguageLookup[94] = 'Esperanto';
+ $QuicktimeLanguageLookup[128] = 'Welsh';
+ $QuicktimeLanguageLookup[129] = 'Basque';
+ $QuicktimeLanguageLookup[130] = 'Catalan';
+ $QuicktimeLanguageLookup[131] = 'Latin';
+ $QuicktimeLanguageLookup[132] = 'Quechua';
+ $QuicktimeLanguageLookup[133] = 'Guarani';
+ $QuicktimeLanguageLookup[134] = 'Aymara';
+ $QuicktimeLanguageLookup[135] = 'Tatar';
+ $QuicktimeLanguageLookup[136] = 'Uighur';
+ $QuicktimeLanguageLookup[137] = 'Dzongkha';
+ $QuicktimeLanguageLookup[138] = 'JavaneseRom';
+ }
+ return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid');
+ }
+
+ public function QuicktimeVideoCodecLookup($codecid) {
+ static $QuicktimeVideoCodecLookup = array();
+ if (empty($QuicktimeVideoCodecLookup)) {
+ $QuicktimeVideoCodecLookup['.SGI'] = 'SGI';
+ $QuicktimeVideoCodecLookup['3IV1'] = '3ivx MPEG-4 v1';
+ $QuicktimeVideoCodecLookup['3IV2'] = '3ivx MPEG-4 v2';
+ $QuicktimeVideoCodecLookup['3IVX'] = '3ivx MPEG-4';
+ $QuicktimeVideoCodecLookup['8BPS'] = 'Planar RGB';
+ $QuicktimeVideoCodecLookup['avc1'] = 'H.264/MPEG-4 AVC';
+ $QuicktimeVideoCodecLookup['avr '] = 'AVR-JPEG';
+ $QuicktimeVideoCodecLookup['b16g'] = '16Gray';
+ $QuicktimeVideoCodecLookup['b32a'] = '32AlphaGray';
+ $QuicktimeVideoCodecLookup['b48r'] = '48RGB';
+ $QuicktimeVideoCodecLookup['b64a'] = '64ARGB';
+ $QuicktimeVideoCodecLookup['base'] = 'Base';
+ $QuicktimeVideoCodecLookup['clou'] = 'Cloud';
+ $QuicktimeVideoCodecLookup['cmyk'] = 'CMYK';
+ $QuicktimeVideoCodecLookup['cvid'] = 'Cinepak';
+ $QuicktimeVideoCodecLookup['dmb1'] = 'OpenDML JPEG';
+ $QuicktimeVideoCodecLookup['dvc '] = 'DVC-NTSC';
+ $QuicktimeVideoCodecLookup['dvcp'] = 'DVC-PAL';
+ $QuicktimeVideoCodecLookup['dvpn'] = 'DVCPro-NTSC';
+ $QuicktimeVideoCodecLookup['dvpp'] = 'DVCPro-PAL';
+ $QuicktimeVideoCodecLookup['fire'] = 'Fire';
+ $QuicktimeVideoCodecLookup['flic'] = 'FLC';
+ $QuicktimeVideoCodecLookup['gif '] = 'GIF';
+ $QuicktimeVideoCodecLookup['h261'] = 'H261';
+ $QuicktimeVideoCodecLookup['h263'] = 'H263';
+ $QuicktimeVideoCodecLookup['IV41'] = 'Indeo4';
+ $QuicktimeVideoCodecLookup['jpeg'] = 'JPEG';
+ $QuicktimeVideoCodecLookup['kpcd'] = 'PhotoCD';
+ $QuicktimeVideoCodecLookup['mjpa'] = 'Motion JPEG-A';
+ $QuicktimeVideoCodecLookup['mjpb'] = 'Motion JPEG-B';
+ $QuicktimeVideoCodecLookup['msvc'] = 'Microsoft Video1';
+ $QuicktimeVideoCodecLookup['myuv'] = 'MPEG YUV420';
+ $QuicktimeVideoCodecLookup['path'] = 'Vector';
+ $QuicktimeVideoCodecLookup['png '] = 'PNG';
+ $QuicktimeVideoCodecLookup['PNTG'] = 'MacPaint';
+ $QuicktimeVideoCodecLookup['qdgx'] = 'QuickDrawGX';
+ $QuicktimeVideoCodecLookup['qdrw'] = 'QuickDraw';
+ $QuicktimeVideoCodecLookup['raw '] = 'RAW';
+ $QuicktimeVideoCodecLookup['ripl'] = 'WaterRipple';
+ $QuicktimeVideoCodecLookup['rpza'] = 'Video';
+ $QuicktimeVideoCodecLookup['smc '] = 'Graphics';
+ $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 1';
+ $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 3';
+ $QuicktimeVideoCodecLookup['syv9'] = 'Sorenson YUV9';
+ $QuicktimeVideoCodecLookup['tga '] = 'Targa';
+ $QuicktimeVideoCodecLookup['tiff'] = 'TIFF';
+ $QuicktimeVideoCodecLookup['WRAW'] = 'Windows RAW';
+ $QuicktimeVideoCodecLookup['WRLE'] = 'BMP';
+ $QuicktimeVideoCodecLookup['y420'] = 'YUV420';
+ $QuicktimeVideoCodecLookup['yuv2'] = 'ComponentVideo';
+ $QuicktimeVideoCodecLookup['yuvs'] = 'ComponentVideoUnsigned';
+ $QuicktimeVideoCodecLookup['yuvu'] = 'ComponentVideoSigned';
+ }
+ return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : '');
+ }
+
+ public function QuicktimeAudioCodecLookup($codecid) {
+ static $QuicktimeAudioCodecLookup = array();
+ if (empty($QuicktimeAudioCodecLookup)) {
+ $QuicktimeAudioCodecLookup['.mp3'] = 'Fraunhofer MPEG Layer-III alias';
+ $QuicktimeAudioCodecLookup['aac '] = 'ISO/IEC 14496-3 AAC';
+ $QuicktimeAudioCodecLookup['agsm'] = 'Apple GSM 10:1';
+ $QuicktimeAudioCodecLookup['alac'] = 'Apple Lossless Audio Codec';
+ $QuicktimeAudioCodecLookup['alaw'] = 'A-law 2:1';
+ $QuicktimeAudioCodecLookup['conv'] = 'Sample Format';
+ $QuicktimeAudioCodecLookup['dvca'] = 'DV';
+ $QuicktimeAudioCodecLookup['dvi '] = 'DV 4:1';
+ $QuicktimeAudioCodecLookup['eqal'] = 'Frequency Equalizer';
+ $QuicktimeAudioCodecLookup['fl32'] = '32-bit Floating Point';
+ $QuicktimeAudioCodecLookup['fl64'] = '64-bit Floating Point';
+ $QuicktimeAudioCodecLookup['ima4'] = 'Interactive Multimedia Association 4:1';
+ $QuicktimeAudioCodecLookup['in24'] = '24-bit Integer';
+ $QuicktimeAudioCodecLookup['in32'] = '32-bit Integer';
+ $QuicktimeAudioCodecLookup['lpc '] = 'LPC 23:1';
+ $QuicktimeAudioCodecLookup['MAC3'] = 'Macintosh Audio Compression/Expansion (MACE) 3:1';
+ $QuicktimeAudioCodecLookup['MAC6'] = 'Macintosh Audio Compression/Expansion (MACE) 6:1';
+ $QuicktimeAudioCodecLookup['mixb'] = '8-bit Mixer';
+ $QuicktimeAudioCodecLookup['mixw'] = '16-bit Mixer';
+ $QuicktimeAudioCodecLookup['mp4a'] = 'ISO/IEC 14496-3 AAC';
+ $QuicktimeAudioCodecLookup['MS'."\x00\x02"] = 'Microsoft ADPCM';
+ $QuicktimeAudioCodecLookup['MS'."\x00\x11"] = 'DV IMA';
+ $QuicktimeAudioCodecLookup['MS'."\x00\x55"] = 'Fraunhofer MPEG Layer III';
+ $QuicktimeAudioCodecLookup['NONE'] = 'No Encoding';
+ $QuicktimeAudioCodecLookup['Qclp'] = 'Qualcomm PureVoice';
+ $QuicktimeAudioCodecLookup['QDM2'] = 'QDesign Music 2';
+ $QuicktimeAudioCodecLookup['QDMC'] = 'QDesign Music 1';
+ $QuicktimeAudioCodecLookup['ratb'] = '8-bit Rate';
+ $QuicktimeAudioCodecLookup['ratw'] = '16-bit Rate';
+ $QuicktimeAudioCodecLookup['raw '] = 'raw PCM';
+ $QuicktimeAudioCodecLookup['sour'] = 'Sound Source';
+ $QuicktimeAudioCodecLookup['sowt'] = 'signed/two\'s complement (Little Endian)';
+ $QuicktimeAudioCodecLookup['str1'] = 'Iomega MPEG layer II';
+ $QuicktimeAudioCodecLookup['str2'] = 'Iomega MPEG *layer II';
+ $QuicktimeAudioCodecLookup['str3'] = 'Iomega MPEG **layer II';
+ $QuicktimeAudioCodecLookup['str4'] = 'Iomega MPEG ***layer II';
+ $QuicktimeAudioCodecLookup['twos'] = 'signed/two\'s complement (Big Endian)';
+ $QuicktimeAudioCodecLookup['ulaw'] = 'mu-law 2:1';
+ }
+ return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : '');
+ }
+
+ public function QuicktimeDCOMLookup($compressionid) {
+ static $QuicktimeDCOMLookup = array();
+ if (empty($QuicktimeDCOMLookup)) {
+ $QuicktimeDCOMLookup['zlib'] = 'ZLib Deflate';
+ $QuicktimeDCOMLookup['adec'] = 'Apple Compression';
+ }
+ return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : '');
+ }
+
+ public function QuicktimeColorNameLookup($colordepthid) {
+ static $QuicktimeColorNameLookup = array();
+ if (empty($QuicktimeColorNameLookup)) {
+ $QuicktimeColorNameLookup[1] = '2-color (monochrome)';
+ $QuicktimeColorNameLookup[2] = '4-color';
+ $QuicktimeColorNameLookup[4] = '16-color';
+ $QuicktimeColorNameLookup[8] = '256-color';
+ $QuicktimeColorNameLookup[16] = 'thousands (16-bit color)';
+ $QuicktimeColorNameLookup[24] = 'millions (24-bit color)';
+ $QuicktimeColorNameLookup[32] = 'millions+ (32-bit color)';
+ $QuicktimeColorNameLookup[33] = 'black & white';
+ $QuicktimeColorNameLookup[34] = '4-gray';
+ $QuicktimeColorNameLookup[36] = '16-gray';
+ $QuicktimeColorNameLookup[40] = '256-gray';
+ }
+ return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid');
+ }
+
+ public function QuicktimeSTIKLookup($stik) {
+ static $QuicktimeSTIKLookup = array();
+ if (empty($QuicktimeSTIKLookup)) {
+ $QuicktimeSTIKLookup[0] = 'Movie';
+ $QuicktimeSTIKLookup[1] = 'Normal';
+ $QuicktimeSTIKLookup[2] = 'Audiobook';
+ $QuicktimeSTIKLookup[5] = 'Whacked Bookmark';
+ $QuicktimeSTIKLookup[6] = 'Music Video';
+ $QuicktimeSTIKLookup[9] = 'Short Film';
+ $QuicktimeSTIKLookup[10] = 'TV Show';
+ $QuicktimeSTIKLookup[11] = 'Booklet';
+ $QuicktimeSTIKLookup[14] = 'Ringtone';
+ $QuicktimeSTIKLookup[21] = 'Podcast';
+ }
+ return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid');
+ }
+
+ public function QuicktimeIODSaudioProfileName($audio_profile_id) {
+ static $QuicktimeIODSaudioProfileNameLookup = array();
+ if (empty($QuicktimeIODSaudioProfileNameLookup)) {
+ $QuicktimeIODSaudioProfileNameLookup = array(
+ 0x00 => 'ISO Reserved (0x00)',
+ 0x01 => 'Main Audio Profile @ Level 1',
+ 0x02 => 'Main Audio Profile @ Level 2',
+ 0x03 => 'Main Audio Profile @ Level 3',
+ 0x04 => 'Main Audio Profile @ Level 4',
+ 0x05 => 'Scalable Audio Profile @ Level 1',
+ 0x06 => 'Scalable Audio Profile @ Level 2',
+ 0x07 => 'Scalable Audio Profile @ Level 3',
+ 0x08 => 'Scalable Audio Profile @ Level 4',
+ 0x09 => 'Speech Audio Profile @ Level 1',
+ 0x0A => 'Speech Audio Profile @ Level 2',
+ 0x0B => 'Synthetic Audio Profile @ Level 1',
+ 0x0C => 'Synthetic Audio Profile @ Level 2',
+ 0x0D => 'Synthetic Audio Profile @ Level 3',
+ 0x0E => 'High Quality Audio Profile @ Level 1',
+ 0x0F => 'High Quality Audio Profile @ Level 2',
+ 0x10 => 'High Quality Audio Profile @ Level 3',
+ 0x11 => 'High Quality Audio Profile @ Level 4',
+ 0x12 => 'High Quality Audio Profile @ Level 5',
+ 0x13 => 'High Quality Audio Profile @ Level 6',
+ 0x14 => 'High Quality Audio Profile @ Level 7',
+ 0x15 => 'High Quality Audio Profile @ Level 8',
+ 0x16 => 'Low Delay Audio Profile @ Level 1',
+ 0x17 => 'Low Delay Audio Profile @ Level 2',
+ 0x18 => 'Low Delay Audio Profile @ Level 3',
+ 0x19 => 'Low Delay Audio Profile @ Level 4',
+ 0x1A => 'Low Delay Audio Profile @ Level 5',
+ 0x1B => 'Low Delay Audio Profile @ Level 6',
+ 0x1C => 'Low Delay Audio Profile @ Level 7',
+ 0x1D => 'Low Delay Audio Profile @ Level 8',
+ 0x1E => 'Natural Audio Profile @ Level 1',
+ 0x1F => 'Natural Audio Profile @ Level 2',
+ 0x20 => 'Natural Audio Profile @ Level 3',
+ 0x21 => 'Natural Audio Profile @ Level 4',
+ 0x22 => 'Mobile Audio Internetworking Profile @ Level 1',
+ 0x23 => 'Mobile Audio Internetworking Profile @ Level 2',
+ 0x24 => 'Mobile Audio Internetworking Profile @ Level 3',
+ 0x25 => 'Mobile Audio Internetworking Profile @ Level 4',
+ 0x26 => 'Mobile Audio Internetworking Profile @ Level 5',
+ 0x27 => 'Mobile Audio Internetworking Profile @ Level 6',
+ 0x28 => 'AAC Profile @ Level 1',
+ 0x29 => 'AAC Profile @ Level 2',
+ 0x2A => 'AAC Profile @ Level 4',
+ 0x2B => 'AAC Profile @ Level 5',
+ 0x2C => 'High Efficiency AAC Profile @ Level 2',
+ 0x2D => 'High Efficiency AAC Profile @ Level 3',
+ 0x2E => 'High Efficiency AAC Profile @ Level 4',
+ 0x2F => 'High Efficiency AAC Profile @ Level 5',
+ 0xFE => 'Not part of MPEG-4 audio profiles',
+ 0xFF => 'No audio capability required',
+ );
+ }
+ return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private');
+ }
+
+
+ public function QuicktimeIODSvideoProfileName($video_profile_id) {
+ static $QuicktimeIODSvideoProfileNameLookup = array();
+ if (empty($QuicktimeIODSvideoProfileNameLookup)) {
+ $QuicktimeIODSvideoProfileNameLookup = array(
+ 0x00 => 'Reserved (0x00) Profile',
+ 0x01 => 'Simple Profile @ Level 1',
+ 0x02 => 'Simple Profile @ Level 2',
+ 0x03 => 'Simple Profile @ Level 3',
+ 0x08 => 'Simple Profile @ Level 0',
+ 0x10 => 'Simple Scalable Profile @ Level 0',
+ 0x11 => 'Simple Scalable Profile @ Level 1',
+ 0x12 => 'Simple Scalable Profile @ Level 2',
+ 0x15 => 'AVC/H264 Profile',
+ 0x21 => 'Core Profile @ Level 1',
+ 0x22 => 'Core Profile @ Level 2',
+ 0x32 => 'Main Profile @ Level 2',
+ 0x33 => 'Main Profile @ Level 3',
+ 0x34 => 'Main Profile @ Level 4',
+ 0x42 => 'N-bit Profile @ Level 2',
+ 0x51 => 'Scalable Texture Profile @ Level 1',
+ 0x61 => 'Simple Face Animation Profile @ Level 1',
+ 0x62 => 'Simple Face Animation Profile @ Level 2',
+ 0x63 => 'Simple FBA Profile @ Level 1',
+ 0x64 => 'Simple FBA Profile @ Level 2',
+ 0x71 => 'Basic Animated Texture Profile @ Level 1',
+ 0x72 => 'Basic Animated Texture Profile @ Level 2',
+ 0x81 => 'Hybrid Profile @ Level 1',
+ 0x82 => 'Hybrid Profile @ Level 2',
+ 0x91 => 'Advanced Real Time Simple Profile @ Level 1',
+ 0x92 => 'Advanced Real Time Simple Profile @ Level 2',
+ 0x93 => 'Advanced Real Time Simple Profile @ Level 3',
+ 0x94 => 'Advanced Real Time Simple Profile @ Level 4',
+ 0xA1 => 'Core Scalable Profile @ Level1',
+ 0xA2 => 'Core Scalable Profile @ Level2',
+ 0xA3 => 'Core Scalable Profile @ Level3',
+ 0xB1 => 'Advanced Coding Efficiency Profile @ Level 1',
+ 0xB2 => 'Advanced Coding Efficiency Profile @ Level 2',
+ 0xB3 => 'Advanced Coding Efficiency Profile @ Level 3',
+ 0xB4 => 'Advanced Coding Efficiency Profile @ Level 4',
+ 0xC1 => 'Advanced Core Profile @ Level 1',
+ 0xC2 => 'Advanced Core Profile @ Level 2',
+ 0xD1 => 'Advanced Scalable Texture @ Level1',
+ 0xD2 => 'Advanced Scalable Texture @ Level2',
+ 0xE1 => 'Simple Studio Profile @ Level 1',
+ 0xE2 => 'Simple Studio Profile @ Level 2',
+ 0xE3 => 'Simple Studio Profile @ Level 3',
+ 0xE4 => 'Simple Studio Profile @ Level 4',
+ 0xE5 => 'Core Studio Profile @ Level 1',
+ 0xE6 => 'Core Studio Profile @ Level 2',
+ 0xE7 => 'Core Studio Profile @ Level 3',
+ 0xE8 => 'Core Studio Profile @ Level 4',
+ 0xF0 => 'Advanced Simple Profile @ Level 0',
+ 0xF1 => 'Advanced Simple Profile @ Level 1',
+ 0xF2 => 'Advanced Simple Profile @ Level 2',
+ 0xF3 => 'Advanced Simple Profile @ Level 3',
+ 0xF4 => 'Advanced Simple Profile @ Level 4',
+ 0xF5 => 'Advanced Simple Profile @ Level 5',
+ 0xF7 => 'Advanced Simple Profile @ Level 3b',
+ 0xF8 => 'Fine Granularity Scalable Profile @ Level 0',
+ 0xF9 => 'Fine Granularity Scalable Profile @ Level 1',
+ 0xFA => 'Fine Granularity Scalable Profile @ Level 2',
+ 0xFB => 'Fine Granularity Scalable Profile @ Level 3',
+ 0xFC => 'Fine Granularity Scalable Profile @ Level 4',
+ 0xFD => 'Fine Granularity Scalable Profile @ Level 5',
+ 0xFE => 'Not part of MPEG-4 Visual profiles',
+ 0xFF => 'No visual capability required',
+ );
+ }
+ return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile');
+ }
+
+
+ public function QuicktimeContentRatingLookup($rtng) {
+ static $QuicktimeContentRatingLookup = array();
+ if (empty($QuicktimeContentRatingLookup)) {
+ $QuicktimeContentRatingLookup[0] = 'None';
+ $QuicktimeContentRatingLookup[2] = 'Clean';
+ $QuicktimeContentRatingLookup[4] = 'Explicit';
+ }
+ return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid');
+ }
+
+ public function QuicktimeStoreAccountTypeLookup($akid) {
+ static $QuicktimeStoreAccountTypeLookup = array();
+ if (empty($QuicktimeStoreAccountTypeLookup)) {
+ $QuicktimeStoreAccountTypeLookup[0] = 'iTunes';
+ $QuicktimeStoreAccountTypeLookup[1] = 'AOL';
+ }
+ return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid');
+ }
+
+ public function QuicktimeStoreFrontCodeLookup($sfid) {
+ static $QuicktimeStoreFrontCodeLookup = array();
+ if (empty($QuicktimeStoreFrontCodeLookup)) {
+ $QuicktimeStoreFrontCodeLookup[143460] = 'Australia';
+ $QuicktimeStoreFrontCodeLookup[143445] = 'Austria';
+ $QuicktimeStoreFrontCodeLookup[143446] = 'Belgium';
+ $QuicktimeStoreFrontCodeLookup[143455] = 'Canada';
+ $QuicktimeStoreFrontCodeLookup[143458] = 'Denmark';
+ $QuicktimeStoreFrontCodeLookup[143447] = 'Finland';
+ $QuicktimeStoreFrontCodeLookup[143442] = 'France';
+ $QuicktimeStoreFrontCodeLookup[143443] = 'Germany';
+ $QuicktimeStoreFrontCodeLookup[143448] = 'Greece';
+ $QuicktimeStoreFrontCodeLookup[143449] = 'Ireland';
+ $QuicktimeStoreFrontCodeLookup[143450] = 'Italy';
+ $QuicktimeStoreFrontCodeLookup[143462] = 'Japan';
+ $QuicktimeStoreFrontCodeLookup[143451] = 'Luxembourg';
+ $QuicktimeStoreFrontCodeLookup[143452] = 'Netherlands';
+ $QuicktimeStoreFrontCodeLookup[143461] = 'New Zealand';
+ $QuicktimeStoreFrontCodeLookup[143457] = 'Norway';
+ $QuicktimeStoreFrontCodeLookup[143453] = 'Portugal';
+ $QuicktimeStoreFrontCodeLookup[143454] = 'Spain';
+ $QuicktimeStoreFrontCodeLookup[143456] = 'Sweden';
+ $QuicktimeStoreFrontCodeLookup[143459] = 'Switzerland';
+ $QuicktimeStoreFrontCodeLookup[143444] = 'United Kingdom';
+ $QuicktimeStoreFrontCodeLookup[143441] = 'United States';
+ }
+ return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid');
+ }
+
+ public function QuicktimeParseNikonNCTG($atom_data) {
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG
+ // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100
+ // Data is stored as records of:
+ // * 4 bytes record type
+ // * 2 bytes size of data field type:
+ // 0x0001 = flag (size field *= 1-byte)
+ // 0x0002 = char (size field *= 1-byte)
+ // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
+ // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
+ // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
+ // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????
+ // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????
+ // * 2 bytes data size field
+ // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15")
+ // all integers are stored BigEndian
+
+ $NCTGtagName = array(
+ 0x00000001 => 'Make',
+ 0x00000002 => 'Model',
+ 0x00000003 => 'Software',
+ 0x00000011 => 'CreateDate',
+ 0x00000012 => 'DateTimeOriginal',
+ 0x00000013 => 'FrameCount',
+ 0x00000016 => 'FrameRate',
+ 0x00000022 => 'FrameWidth',
+ 0x00000023 => 'FrameHeight',
+ 0x00000032 => 'AudioChannels',
+ 0x00000033 => 'AudioBitsPerSample',
+ 0x00000034 => 'AudioSampleRate',
+ 0x02000001 => 'MakerNoteVersion',
+ 0x02000005 => 'WhiteBalance',
+ 0x0200000b => 'WhiteBalanceFineTune',
+ 0x0200001e => 'ColorSpace',
+ 0x02000023 => 'PictureControlData',
+ 0x02000024 => 'WorldTime',
+ 0x02000032 => 'UnknownInfo',
+ 0x02000083 => 'LensType',
+ 0x02000084 => 'Lens',
+ );
+
+ $offset = 0;
+ $datalength = strlen($atom_data);
+ $parsed = array();
+ while ($offset < $datalength) {
+//echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'<br>';
+ $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4;
+ $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
+ $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2;
+ switch ($data_size_type) {
+ case 0x0001: // 0x0001 = flag (size field *= 1-byte)
+ $data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1));
+ $offset += ($data_size * 1);
+ break;
+ case 0x0002: // 0x0002 = char (size field *= 1-byte)
+ $data = substr($atom_data, $offset, $data_size * 1);
+ $offset += ($data_size * 1);
+ $data = rtrim($data, "\x00");
+ break;
+ case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB
+ $data = '';
+ for ($i = $data_size - 1; $i >= 0; $i--) {
+ $data .= substr($atom_data, $offset + ($i * 2), 2);
+ }
+ $data = getid3_lib::BigEndian2Int($data);
+ $offset += ($data_size * 2);
+ break;
+ case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD
+ $data = '';
+ for ($i = $data_size - 1; $i >= 0; $i--) {
+ $data .= substr($atom_data, $offset + ($i * 4), 4);
+ }
+ $data = getid3_lib::BigEndian2Int($data);
+ $offset += ($data_size * 4);
+ break;
+ case 0x0005: // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together
+ $data = array();
+ for ($i = 0; $i < $data_size; $i++) {
+ $numerator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4));
+ $denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4));
+ if ($denomninator == 0) {
+ $data[$i] = false;
+ } else {
+ $data[$i] = (double) $numerator / $denomninator;
+ }
+ }
+ $offset += (8 * $data_size);
+ if (count($data) == 1) {
+ $data = $data[0];
+ }
+ break;
+ case 0x0007: // 0x0007 = bytes (size field *= 1-byte), values are stored as ??????
+ $data = substr($atom_data, $offset, $data_size * 1);
+ $offset += ($data_size * 1);
+ break;
+ case 0x0008: // 0x0008 = ????? (size field *= 2-byte), values are stored as ??????
+ $data = substr($atom_data, $offset, $data_size * 2);
+ $offset += ($data_size * 2);
+ break;
+ default:
+echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'<br>';
+ break 2;
+ }
+
+ switch ($record_type) {
+ case 0x00000011: // CreateDate
+ case 0x00000012: // DateTimeOriginal
+ $data = strtotime($data);
+ break;
+ case 0x0200001e: // ColorSpace
+ switch ($data) {
+ case 1:
+ $data = 'sRGB';
+ break;
+ case 2:
+ $data = 'Adobe RGB';
+ break;
+ }
+ break;
+ case 0x02000023: // PictureControlData
+ $PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full');
+ $FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a');
+ $ToningEffect = array(0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a');
+ $data = array(
+ 'PictureControlVersion' => substr($data, 0, 4),
+ 'PictureControlName' => rtrim(substr($data, 4, 20), "\x00"),
+ 'PictureControlBase' => rtrim(substr($data, 24, 20), "\x00"),
+ //'?' => substr($data, 44, 4),
+ 'PictureControlAdjust' => $PictureControlAdjust[ord(substr($data, 48, 1))],
+ 'PictureControlQuickAdjust' => ord(substr($data, 49, 1)),
+ 'Sharpness' => ord(substr($data, 50, 1)),
+ 'Contrast' => ord(substr($data, 51, 1)),
+ 'Brightness' => ord(substr($data, 52, 1)),
+ 'Saturation' => ord(substr($data, 53, 1)),
+ 'HueAdjustment' => ord(substr($data, 54, 1)),
+ 'FilterEffect' => $FilterEffect[ord(substr($data, 55, 1))],
+ 'ToningEffect' => $ToningEffect[ord(substr($data, 56, 1))],
+ 'ToningSaturation' => ord(substr($data, 57, 1)),
+ );
+ break;
+ case 0x02000024: // WorldTime
+ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime
+ // timezone is stored as offset from GMT in minutes
+ $timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2));
+ if ($timezone & 0x8000) {
+ $timezone = 0 - (0x10000 - $timezone);
+ }
+ $timezone /= 60;
+
+ $dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1));
+ switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) {
+ case 2:
+ $datedisplayformat = 'D/M/Y'; break;
+ case 1:
+ $datedisplayformat = 'M/D/Y'; break;
+ case 0:
+ default:
+ $datedisplayformat = 'Y/M/D'; break;
+ }
+
+ $data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat);
+ break;
+ case 0x02000083: // LensType
+ $data = array(
+ //'_' => $data,
+ 'mf' => (bool) ($data & 0x01),
+ 'd' => (bool) ($data & 0x02),
+ 'g' => (bool) ($data & 0x04),
+ 'vr' => (bool) ($data & 0x08),
+ );
+ break;
+ }
+ $tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT));
+ $parsed[$tag_name] = $data;
+ }
+ return $parsed;
+ }
+
+
+ public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') {
+ static $handyatomtranslatorarray = array();
+ if (empty($handyatomtranslatorarray)) {
+ $handyatomtranslatorarray['cpy'] = 'copyright';
+ $handyatomtranslatorarray['day'] = 'creation_date'; // iTunes 4.0
+ $handyatomtranslatorarray['dir'] = 'director';
+ $handyatomtranslatorarray['ed1'] = 'edit1';
+ $handyatomtranslatorarray['ed2'] = 'edit2';
+ $handyatomtranslatorarray['ed3'] = 'edit3';
+ $handyatomtranslatorarray['ed4'] = 'edit4';
+ $handyatomtranslatorarray['ed5'] = 'edit5';
+ $handyatomtranslatorarray['ed6'] = 'edit6';
+ $handyatomtranslatorarray['ed7'] = 'edit7';
+ $handyatomtranslatorarray['ed8'] = 'edit8';
+ $handyatomtranslatorarray['ed9'] = 'edit9';
+ $handyatomtranslatorarray['fmt'] = 'format';
+ $handyatomtranslatorarray['inf'] = 'information';
+ $handyatomtranslatorarray['prd'] = 'producer';
+ $handyatomtranslatorarray['prf'] = 'performers';
+ $handyatomtranslatorarray['req'] = 'system_requirements';
+ $handyatomtranslatorarray['src'] = 'source_credit';
+ $handyatomtranslatorarray['wrt'] = 'writer';
+
+ // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
+ $handyatomtranslatorarray['nam'] = 'title'; // iTunes 4.0
+ $handyatomtranslatorarray['cmt'] = 'comment'; // iTunes 4.0
+ $handyatomtranslatorarray['wrn'] = 'warning';
+ $handyatomtranslatorarray['hst'] = 'host_computer';
+ $handyatomtranslatorarray['mak'] = 'make';
+ $handyatomtranslatorarray['mod'] = 'model';
+ $handyatomtranslatorarray['PRD'] = 'product';
+ $handyatomtranslatorarray['swr'] = 'software';
+ $handyatomtranslatorarray['aut'] = 'author';
+ $handyatomtranslatorarray['ART'] = 'artist';
+ $handyatomtranslatorarray['trk'] = 'track';
+ $handyatomtranslatorarray['alb'] = 'album'; // iTunes 4.0
+ $handyatomtranslatorarray['com'] = 'comment';
+ $handyatomtranslatorarray['gen'] = 'genre'; // iTunes 4.0
+ $handyatomtranslatorarray['ope'] = 'composer';
+ $handyatomtranslatorarray['url'] = 'url';
+ $handyatomtranslatorarray['enc'] = 'encoder';
+
+ // http://atomicparsley.sourceforge.net/mpeg-4files.html
+ $handyatomtranslatorarray['art'] = 'artist'; // iTunes 4.0
+ $handyatomtranslatorarray['aART'] = 'album_artist';
+ $handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0
+ $handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0
+ $handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0
+ $handyatomtranslatorarray['too'] = 'encoder'; // iTunes 4.0
+ $handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0
+ $handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0?
+ $handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0
+ $handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0
+ $handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0
+ $handyatomtranslatorarray['grp'] = 'grouping'; // iTunes 4.2
+ $handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9
+ $handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9
+ $handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9
+ $handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9
+ $handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9
+ $handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9
+ $handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0
+ $handyatomtranslatorarray['lyr'] = 'lyrics'; // iTunes 5.0
+ $handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0
+ $handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0
+ $handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0
+ $handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0
+ $handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2
+ $handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0
+
+ // http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
+
+
+
+ // boxnames:
+ /*
+ $handyatomtranslatorarray['iTunSMPB'] = 'iTunSMPB';
+ $handyatomtranslatorarray['iTunNORM'] = 'iTunNORM';
+ $handyatomtranslatorarray['Encoding Params'] = 'Encoding Params';
+ $handyatomtranslatorarray['replaygain_track_gain'] = 'replaygain_track_gain';
+ $handyatomtranslatorarray['replaygain_track_peak'] = 'replaygain_track_peak';
+ $handyatomtranslatorarray['replaygain_track_minmax'] = 'replaygain_track_minmax';
+ $handyatomtranslatorarray['MusicIP PUID'] = 'MusicIP PUID';
+ $handyatomtranslatorarray['MusicBrainz Artist Id'] = 'MusicBrainz Artist Id';
+ $handyatomtranslatorarray['MusicBrainz Album Id'] = 'MusicBrainz Album Id';
+ $handyatomtranslatorarray['MusicBrainz Album Artist Id'] = 'MusicBrainz Album Artist Id';
+ $handyatomtranslatorarray['MusicBrainz Track Id'] = 'MusicBrainz Track Id';
+ $handyatomtranslatorarray['MusicBrainz Disc Id'] = 'MusicBrainz Disc Id';
+
+ // http://age.hobba.nl/audio/tag_frame_reference.html
+ $handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
+ $handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355
+ */
+ }
+ $info = &$this->getid3->info;
+ $comment_key = '';
+ if ($boxname && ($boxname != $keyname)) {
+ $comment_key = (isset($handyatomtranslatorarray[$boxname]) ? $handyatomtranslatorarray[$boxname] : $boxname);
+ } elseif (isset($handyatomtranslatorarray[$keyname])) {
+ $comment_key = $handyatomtranslatorarray[$keyname];
+ }
+ if ($comment_key) {
+ if ($comment_key == 'picture') {
+ if (!is_array($data)) {
+ $image_mime = '';
+ if (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $data)) {
+ $image_mime = 'image/png';
+ } elseif (preg_match('#^\xFF\xD8\xFF#', $data)) {
+ $image_mime = 'image/jpeg';
+ } elseif (preg_match('#^GIF#', $data)) {
+ $image_mime = 'image/gif';
+ } elseif (preg_match('#^BM#', $data)) {
+ $image_mime = 'image/bmp';
+ }
+ $data = array('data'=>$data, 'image_mime'=>$image_mime);
+ }
+ }
+ $info['quicktime']['comments'][$comment_key][] = $data;
+ }
+ return true;
+ }
+
+ public function NoNullString($nullterminatedstring) {
+ // remove the single null terminator on null terminated strings
+ if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") {
+ return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1);
+ }
+ return $nullterminatedstring;
+ }
+
+ public function Pascal2String($pascalstring) {
+ // Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string
+ return substr($pascalstring, 1);
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.audio-video.riff.php b/extensions/TimedMediaHandler/libs/getid3/module.audio-video.riff.php
new file mode 100644
index 00000000..5ac5d1cd
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.audio-video.riff.php
@@ -0,0 +1,2435 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio-video.riff.php //
+// module for analyzing RIFF files //
+// multiple formats supported by this module: //
+// Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack v3, 8SVX //
+// dependencies: module.audio.mp3.php //
+// module.audio.ac3.php //
+// module.audio.dts.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+/**
+* @todo Parse AC-3/DTS audio inside WAVE correctly
+* @todo Rewrite RIFF parser totally
+*/
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true);
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true);
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true);
+
+class getid3_riff extends getid3_handler
+{
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ // initialize these values to an empty array, otherwise they default to NULL
+ // and you can't append array values to a NULL value
+ $info['riff'] = array('raw'=>array());
+
+ // Shortcuts
+ $thisfile_riff = &$info['riff'];
+ $thisfile_riff_raw = &$thisfile_riff['raw'];
+ $thisfile_audio = &$info['audio'];
+ $thisfile_video = &$info['video'];
+ $thisfile_audio_dataformat = &$thisfile_audio['dataformat'];
+ $thisfile_riff_audio = &$thisfile_riff['audio'];
+ $thisfile_riff_video = &$thisfile_riff['video'];
+
+ $Original['avdataoffset'] = $info['avdataoffset'];
+ $Original['avdataend'] = $info['avdataend'];
+
+ $this->fseek($info['avdataoffset']);
+ $RIFFheader = $this->fread(12);
+ $offset = $this->ftell();
+ $RIFFtype = substr($RIFFheader, 0, 4);
+ $RIFFsize = substr($RIFFheader, 4, 4);
+ $RIFFsubtype = substr($RIFFheader, 8, 4);
+
+ switch ($RIFFtype) {
+
+ case 'FORM': // AIFF, AIFC
+ $info['fileformat'] = 'aiff';
+ $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
+ $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
+ break;
+
+ case 'RIFF': // AVI, WAV, etc
+ case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com)
+ case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s
+ $info['fileformat'] = 'riff';
+ $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize);
+ if ($RIFFsubtype == 'RMP3') {
+ // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s
+ $RIFFsubtype = 'WAVE';
+ }
+ $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4));
+ if (($info['avdataend'] - $info['filesize']) == 1) {
+ // LiteWave appears to incorrectly *not* pad actual output file
+ // to nearest WORD boundary so may appear to be short by one
+ // byte, in which case - skip warning
+ $info['avdataend'] = $info['filesize'];
+ }
+
+ $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset
+ while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) {
+ try {
+ $this->fseek($nextRIFFoffset);
+ } catch (getid3_exception $e) {
+ if ($e->getCode() == 10) {
+ //$this->warning('RIFF parser: '.$e->getMessage());
+ $this->error('AVI extends beyond '.round(PHP_INT_MAX / 1073741824).'GB and PHP filesystem functions cannot read that far, playtime may be wrong');
+ $this->warning('[avdataend] value may be incorrect, multiple AVIX chunks may be present');
+ break;
+ } else {
+ throw $e;
+ }
+ }
+ $nextRIFFheader = $this->fread(12);
+ if ($nextRIFFoffset == ($info['avdataend'] - 1)) {
+ if (substr($nextRIFFheader, 0, 1) == "\x00") {
+ // RIFF padded to WORD boundary, we're actually already at the end
+ break;
+ }
+ }
+ $nextRIFFheaderID = substr($nextRIFFheader, 0, 4);
+ $nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4));
+ $nextRIFFtype = substr($nextRIFFheader, 8, 4);
+ $chunkdata = array();
+ $chunkdata['offset'] = $nextRIFFoffset + 8;
+ $chunkdata['size'] = $nextRIFFsize;
+ $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size'];
+
+ switch ($nextRIFFheaderID) {
+
+ case 'RIFF':
+ $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset);
+
+ if (!isset($thisfile_riff[$nextRIFFtype])) {
+ $thisfile_riff[$nextRIFFtype] = array();
+ }
+ $thisfile_riff[$nextRIFFtype][] = $chunkdata;
+ break;
+
+ case 'JUNK':
+ // ignore
+ $thisfile_riff[$nextRIFFheaderID][] = $chunkdata;
+ break;
+
+ case 'IDVX':
+ $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunkdata['size']));
+ break;
+
+ default:
+ if ($info['filesize'] == ($chunkdata['offset'] - 8 + 128)) {
+ $DIVXTAG = $nextRIFFheader.$this->fread(128 - 12);
+ if (substr($DIVXTAG, -7) == 'DIVXTAG') {
+ // DIVXTAG is supposed to be inside an IDVX chunk in a LIST chunk, but some bad encoders just slap it on the end of a file
+ $this->warning('Found wrongly-structured DIVXTAG at offset '.($this->ftell() - 128).', parsing anyway');
+ $info['divxtag']['comments'] = self::ParseDIVXTAG($DIVXTAG);
+ break 2;
+ }
+ }
+ $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file');
+ break 2;
+
+ }
+
+ }
+ if ($RIFFsubtype == 'WAVE') {
+ $thisfile_riff_WAVE = &$thisfile_riff['WAVE'];
+ }
+ break;
+
+ default:
+ $this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead');
+ unset($info['fileformat']);
+ return false;
+ }
+
+ $streamindex = 0;
+ switch ($RIFFsubtype) {
+ case 'WAVE':
+ if (empty($thisfile_audio['bitrate_mode'])) {
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ }
+ if (empty($thisfile_audio_dataformat)) {
+ $thisfile_audio_dataformat = 'wav';
+ }
+
+ if (isset($thisfile_riff_WAVE['data'][0]['offset'])) {
+ $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8;
+ $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size'];
+ }
+ if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) {
+
+ $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']);
+ $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
+ if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) {
+ $info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero';
+ return false;
+ }
+ $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw'];
+ unset($thisfile_riff_audio[$streamindex]['raw']);
+ $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
+
+ $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
+ if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') {
+ $info['warning'][] = 'Audio codec = '.$thisfile_audio['codec'];
+ }
+ $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
+
+ if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV)
+ $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
+ }
+
+ $thisfile_audio['lossless'] = false;
+ if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
+ switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
+
+ case 0x0001: // PCM
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ case 0x2000: // AC-3
+ $thisfile_audio_dataformat = 'ac3';
+ break;
+
+ default:
+ // do nothing
+ break;
+
+ }
+ }
+ $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag'];
+ $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
+ $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless'];
+ $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat;
+ }
+
+ if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) {
+
+ // shortcuts
+ $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data'];
+ $thisfile_riff_raw['rgad'] = array('track'=>array(), 'album'=>array());
+ $thisfile_riff_raw_rgad = &$thisfile_riff_raw['rgad'];
+ $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track'];
+ $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album'];
+
+ $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4));
+ $thisfile_riff_raw_rgad['nRadioRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 4, 2));
+ $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 6, 2));
+
+ $nRadioRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT);
+ $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT);
+ $thisfile_riff_raw_rgad_track['name'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3));
+ $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3));
+ $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1));
+ $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9));
+ $thisfile_riff_raw_rgad_album['name'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3));
+ $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3));
+ $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1));
+ $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9));
+
+ $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude'];
+ if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) {
+ $thisfile_riff['rgad']['track']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']);
+ $thisfile_riff['rgad']['track']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']);
+ $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']);
+ }
+ if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) {
+ $thisfile_riff['rgad']['album']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']);
+ $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']);
+ $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']);
+ }
+ }
+
+ if (isset($thisfile_riff_WAVE['fact'][0]['data'])) {
+ $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4));
+
+ // This should be a good way of calculating exact playtime,
+ // but some sample files have had incorrect number of samples,
+ // so cannot use this method
+
+ // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) {
+ // $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec'];
+ // }
+ }
+ if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) {
+ $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8);
+ }
+
+ if (isset($thisfile_riff_WAVE['bext'][0]['data'])) {
+ // shortcut
+ $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0];
+
+ $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256));
+ $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32));
+ $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32));
+ $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10);
+ $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8);
+ $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8));
+ $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1));
+ $thisfile_riff_WAVE_bext_0['reserved'] = substr($thisfile_riff_WAVE_bext_0['data'], 347, 254);
+ $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601)));
+ if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) {
+ if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) {
+ list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date;
+ list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time;
+ $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']);
+ } else {
+ $info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid';
+ }
+ } else {
+ $info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid';
+ }
+ $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author'];
+ $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title'];
+ }
+
+ if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) {
+ // shortcut
+ $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0];
+
+ $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2));
+ $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001);
+ if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) {
+ $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ? false : true;
+ $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004);
+ $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008);
+
+ $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2));
+ }
+ $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2));
+ $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2));
+ $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001);
+ $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002);
+ $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004);
+ }
+
+ if (isset($thisfile_riff_WAVE['cart'][0]['data'])) {
+ // shortcut
+ $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0];
+
+ $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4);
+ $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64));
+ $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64));
+ $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64));
+ $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64));
+ $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64));
+ $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64));
+ $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64));
+ $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10));
+ $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8));
+ $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10));
+ $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8));
+ $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64));
+ $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64));
+ $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64));
+ $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true);
+ for ($i = 0; $i < 8; $i++) {
+ $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8), 4);
+ $thisfile_riff_WAVE_cart_0['post_time'][$i]['timer_value'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8) + 4, 4));
+ }
+ $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024));
+ $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772)));
+
+ $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist'];
+ $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title'];
+ }
+
+ if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) {
+ // SoundMiner metadata
+
+ // shortcuts
+ $thisfile_riff_WAVE_SNDM_0 = &$thisfile_riff_WAVE['SNDM'][0];
+ $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0['data'];
+ $SNDM_startoffset = 0;
+ $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0['size'];
+
+ while ($SNDM_startoffset < $SNDM_endoffset) {
+ $SNDM_thisTagOffset = 0;
+ $SNDM_thisTagSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4));
+ $SNDM_thisTagOffset += 4;
+ $SNDM_thisTagKey = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4);
+ $SNDM_thisTagOffset += 4;
+ $SNDM_thisTagDataSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
+ $SNDM_thisTagOffset += 2;
+ $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2));
+ $SNDM_thisTagOffset += 2;
+ $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize);
+ $SNDM_thisTagOffset += $SNDM_thisTagDataSize;
+
+ if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) {
+ $info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
+ break;
+ } elseif ($SNDM_thisTagSize <= 0) {
+ $info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
+ break;
+ }
+ $SNDM_startoffset += $SNDM_thisTagSize;
+
+ $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText;
+ if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) {
+ $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText;
+ } else {
+ $info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')';
+ }
+ }
+
+ $tagmapping = array(
+ 'tracktitle'=>'title',
+ 'category' =>'genre',
+ 'cdtitle' =>'album',
+ 'tracktitle'=>'title',
+ );
+ foreach ($tagmapping as $fromkey => $tokey) {
+ if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) {
+ $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey];
+ }
+ }
+ }
+
+ if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) {
+ // requires functions simplexml_load_string and get_object_vars
+ if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) {
+ $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML;
+ if (isset($parsedXML['SPEED']['MASTER_SPEED'])) {
+ @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']);
+ $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000);
+ }
+ if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) {
+ @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']);
+ $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000);
+ }
+ if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) {
+ $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0'));
+ $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE'];
+ $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600);
+ $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60);
+ $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60));
+ $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate'];
+ $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f);
+ $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f));
+ }
+ unset($parsedXML);
+ }
+ }
+
+
+
+ if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) {
+ $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate'];
+ $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']);
+ }
+
+ if (!empty($info['wavpack'])) {
+ $thisfile_audio_dataformat = 'wavpack';
+ $thisfile_audio['bitrate_mode'] = 'vbr';
+ $thisfile_audio['encoder'] = 'WavPack v'.$info['wavpack']['version'];
+
+ // Reset to the way it was - RIFF parsing will have messed this up
+ $info['avdataend'] = $Original['avdataend'];
+ $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
+
+ $this->fseek($info['avdataoffset'] - 44);
+ $RIFFdata = $this->fread(44);
+ $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8;
+ $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44;
+
+ if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) {
+ $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
+ $this->fseek($info['avdataend']);
+ $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize);
+ }
+
+ // move the data chunk after all other chunks (if any)
+ // so that the RIFF parser doesn't see EOF when trying
+ // to skip over the data chunk
+ $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8);
+ $getid3_riff = new getid3_riff($this->getid3);
+ $getid3_riff->ParseRIFFdata($RIFFdata);
+ unset($getid3_riff);
+ }
+
+ if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) {
+ switch ($thisfile_riff_raw['fmt ']['wFormatTag']) {
+ case 0x0001: // PCM
+ if (!empty($info['ac3'])) {
+ // Dolby Digital WAV files masquerade as PCM-WAV, but they're not
+ $thisfile_audio['wformattag'] = 0x2000;
+ $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']);
+ $thisfile_audio['lossless'] = false;
+ $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
+ $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate'];
+ }
+ if (!empty($info['dts'])) {
+ // Dolby DTS files masquerade as PCM-WAV, but they're not
+ $thisfile_audio['wformattag'] = 0x2001;
+ $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']);
+ $thisfile_audio['lossless'] = false;
+ $thisfile_audio['bitrate'] = $info['dts']['bitrate'];
+ $thisfile_audio['sample_rate'] = $info['dts']['sample_rate'];
+ }
+ break;
+ case 0x08AE: // ClearJump LiteWave
+ $thisfile_audio['bitrate_mode'] = 'vbr';
+ $thisfile_audio_dataformat = 'litewave';
+
+ //typedef struct tagSLwFormat {
+ // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags
+ // DWORD m_dwScale; // scale factor for lossy compression
+ // DWORD m_dwBlockSize; // number of samples in encoded blocks
+ // WORD m_wQuality; // alias for the scale factor
+ // WORD m_wMarkDistance; // distance between marks in bytes
+ // WORD m_wReserved;
+ //
+ // //following paramters are ignored if CF_FILESRC is not set
+ // DWORD m_dwOrgSize; // original file size in bytes
+ // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file
+ // DWORD m_dwRiffChunkSize; // riff chunk size in the original file
+ //
+ // PCMWAVEFORMAT m_OrgWf; // original wave format
+ // }SLwFormat, *PSLwFormat;
+
+ // shortcut
+ $thisfile_riff['litewave']['raw'] = array();
+ $riff_litewave = &$thisfile_riff['litewave'];
+ $riff_litewave_raw = &$riff_litewave['raw'];
+
+ $flags = array(
+ 'compression_method' => 1,
+ 'compression_flags' => 1,
+ 'm_dwScale' => 4,
+ 'm_dwBlockSize' => 4,
+ 'm_wQuality' => 2,
+ 'm_wMarkDistance' => 2,
+ 'm_wReserved' => 2,
+ 'm_dwOrgSize' => 4,
+ 'm_bFactExists' => 2,
+ 'm_dwRiffChunkSize' => 4,
+ );
+ $litewave_offset = 18;
+ foreach ($flags as $flag => $length) {
+ $riff_litewave_raw[$flag] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length));
+ $litewave_offset += $length;
+ }
+
+ //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20));
+ $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality'];
+
+ $riff_litewave['flags']['raw_source'] = ($riff_litewave_raw['compression_flags'] & 0x01) ? false : true;
+ $riff_litewave['flags']['vbr_blocksize'] = ($riff_litewave_raw['compression_flags'] & 0x02) ? false : true;
+ $riff_litewave['flags']['seekpoints'] = (bool) ($riff_litewave_raw['compression_flags'] & 0x04);
+
+ $thisfile_audio['lossless'] = (($riff_litewave_raw['m_wQuality'] == 100) ? true : false);
+ $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor'];
+ break;
+
+ default:
+ break;
+ }
+ }
+ if ($info['avdataend'] > $info['filesize']) {
+ switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') {
+ case 'wavpack': // WavPack
+ case 'lpac': // LPAC
+ case 'ofr': // OptimFROG
+ case 'ofs': // OptimFROG DualStream
+ // lossless compressed audio formats that keep original RIFF headers - skip warning
+ break;
+
+ case 'litewave':
+ if (($info['avdataend'] - $info['filesize']) == 1) {
+ // LiteWave appears to incorrectly *not* pad actual output file
+ // to nearest WORD boundary so may appear to be short by one
+ // byte, in which case - skip warning
+ } else {
+ // Short by more than one byte, throw warning
+ $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
+ $info['avdataend'] = $info['filesize'];
+ }
+ break;
+
+ default:
+ if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) {
+ // output file appears to be incorrectly *not* padded to nearest WORD boundary
+ // Output less severe warning
+ $info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
+ $info['avdataend'] = $info['filesize'];
+ } else {
+ // Short by more than one byte, throw warning
+ $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)';
+ $info['avdataend'] = $info['filesize'];
+ }
+ break;
+ }
+ }
+ if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) {
+ if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) {
+ $info['avdataend']--;
+ $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
+ }
+ }
+ if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) {
+ unset($thisfile_audio['bits_per_sample']);
+ if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) {
+ $thisfile_audio['bitrate'] = $info['ac3']['bitrate'];
+ }
+ }
+ break;
+
+ case 'AVI ':
+ $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably
+ $thisfile_video['dataformat'] = 'avi';
+ $info['mime_type'] = 'video/avi';
+
+ if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) {
+ $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8;
+ if (isset($thisfile_riff['AVIX'])) {
+ $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size'];
+ } else {
+ $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size'];
+ }
+ if ($info['avdataend'] > $info['filesize']) {
+ $info['warning'][] = 'Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)';
+ $info['avdataend'] = $info['filesize'];
+ }
+ }
+
+ if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) {
+ //$bIndexType = array(
+ // 0x00 => 'AVI_INDEX_OF_INDEXES',
+ // 0x01 => 'AVI_INDEX_OF_CHUNKS',
+ // 0x80 => 'AVI_INDEX_IS_DATA',
+ //);
+ //$bIndexSubtype = array(
+ // 0x01 => array(
+ // 0x01 => 'AVI_INDEX_2FIELD',
+ // ),
+ //);
+ foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) {
+ $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data'];
+
+ $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($ahsisd, 0, 2));
+ $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = $this->EitherEndian2Int(substr($ahsisd, 2, 1));
+ $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = $this->EitherEndian2Int(substr($ahsisd, 3, 1));
+ $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = $this->EitherEndian2Int(substr($ahsisd, 4, 4));
+ $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($ahsisd, 8, 4);
+ $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = $this->EitherEndian2Int(substr($ahsisd, 12, 4));
+
+ //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name'] = $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']];
+ //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']];
+
+ unset($ahsisd);
+ }
+ }
+ if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) {
+ $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'];
+
+ // shortcut
+ $thisfile_riff_raw['avih'] = array();
+ $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih'];
+
+ $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L)
+ if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) {
+ $info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero';
+ return false;
+ }
+
+ $flags = array(
+ 'dwMaxBytesPerSec', // max. transfer rate
+ 'dwPaddingGranularity', // pad to multiples of this size; normally 2K.
+ 'dwFlags', // the ever-present flags
+ 'dwTotalFrames', // # frames in file
+ 'dwInitialFrames', //
+ 'dwStreams', //
+ 'dwSuggestedBufferSize', //
+ 'dwWidth', //
+ 'dwHeight', //
+ 'dwScale', //
+ 'dwRate', //
+ 'dwStart', //
+ 'dwLength', //
+ );
+ $avih_offset = 4;
+ foreach ($flags as $flag) {
+ $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4));
+ $avih_offset += 4;
+ }
+
+ $flags = array(
+ 'hasindex' => 0x00000010,
+ 'mustuseindex' => 0x00000020,
+ 'interleaved' => 0x00000100,
+ 'trustcktype' => 0x00000800,
+ 'capturedfile' => 0x00010000,
+ 'copyrighted' => 0x00020010,
+ );
+ foreach ($flags as $flag => $value) {
+ $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value);
+ }
+
+ // shortcut
+ $thisfile_riff_video[$streamindex] = array();
+ $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex];
+
+ if ($thisfile_riff_raw_avih['dwWidth'] > 0) {
+ $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth'];
+ $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width'];
+ }
+ if ($thisfile_riff_raw_avih['dwHeight'] > 0) {
+ $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight'];
+ $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height'];
+ }
+ if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) {
+ $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames'];
+ $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames'];
+ }
+
+ $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3);
+ $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate'];
+ }
+ if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) {
+ if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) {
+ for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) {
+ if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) {
+ $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'];
+ $strhfccType = substr($strhData, 0, 4);
+
+ if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) {
+ $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'];
+
+ // shortcut
+ $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex];
+
+ switch ($strhfccType) {
+ case 'auds':
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ $thisfile_audio_dataformat = 'wav';
+ if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) {
+ $streamindex = count($thisfile_riff_audio);
+ }
+
+ $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($strfData);
+ $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag'];
+
+ // shortcut
+ $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex];
+ $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex];
+
+ if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) {
+ unset($thisfile_audio_streams_currentstream['bits_per_sample']);
+ }
+ $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag'];
+ unset($thisfile_audio_streams_currentstream['raw']);
+
+ // shortcut
+ $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw'];
+
+ unset($thisfile_riff_audio[$streamindex]['raw']);
+ $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]);
+
+ $thisfile_audio['lossless'] = false;
+ switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) {
+ case 0x0001: // PCM
+ $thisfile_audio_dataformat = 'wav';
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ case 0x0050: // MPEG Layer 2 or Layer 1
+ $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2
+ break;
+
+ case 0x0055: // MPEG Layer 3
+ $thisfile_audio_dataformat = 'mp3';
+ break;
+
+ case 0x00FF: // AAC
+ $thisfile_audio_dataformat = 'aac';
+ break;
+
+ case 0x0161: // Windows Media v7 / v8 / v9
+ case 0x0162: // Windows Media Professional v9
+ case 0x0163: // Windows Media Lossess v9
+ $thisfile_audio_dataformat = 'wma';
+ break;
+
+ case 0x2000: // AC-3
+ $thisfile_audio_dataformat = 'ac3';
+ break;
+
+ case 0x2001: // DTS
+ $thisfile_audio_dataformat = 'dts';
+ break;
+
+ default:
+ $thisfile_audio_dataformat = 'wav';
+ break;
+ }
+ $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat;
+ $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless'];
+ $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
+ break;
+
+
+ case 'iavs':
+ case 'vids':
+ // shortcut
+ $thisfile_riff_raw['strh'][$i] = array();
+ $thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i];
+
+ $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4); // same as $strhfccType;
+ $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4);
+ $thisfile_riff_raw_strh_current['dwFlags'] = $this->EitherEndian2Int(substr($strhData, 8, 4)); // Contains AVITF_* flags
+ $thisfile_riff_raw_strh_current['wPriority'] = $this->EitherEndian2Int(substr($strhData, 12, 2));
+ $thisfile_riff_raw_strh_current['wLanguage'] = $this->EitherEndian2Int(substr($strhData, 14, 2));
+ $thisfile_riff_raw_strh_current['dwInitialFrames'] = $this->EitherEndian2Int(substr($strhData, 16, 4));
+ $thisfile_riff_raw_strh_current['dwScale'] = $this->EitherEndian2Int(substr($strhData, 20, 4));
+ $thisfile_riff_raw_strh_current['dwRate'] = $this->EitherEndian2Int(substr($strhData, 24, 4));
+ $thisfile_riff_raw_strh_current['dwStart'] = $this->EitherEndian2Int(substr($strhData, 28, 4));
+ $thisfile_riff_raw_strh_current['dwLength'] = $this->EitherEndian2Int(substr($strhData, 32, 4));
+ $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4));
+ $thisfile_riff_raw_strh_current['dwQuality'] = $this->EitherEndian2Int(substr($strhData, 40, 4));
+ $thisfile_riff_raw_strh_current['dwSampleSize'] = $this->EitherEndian2Int(substr($strhData, 44, 4));
+ $thisfile_riff_raw_strh_current['rcFrame'] = $this->EitherEndian2Int(substr($strhData, 48, 4));
+
+ $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strh_current['fccHandler']);
+ $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler'];
+ if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
+ $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']);
+ $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
+ }
+ $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
+ $thisfile_video['pixel_aspect_ratio'] = (float) 1;
+ switch ($thisfile_riff_raw_strh_current['fccHandler']) {
+ case 'HFYU': // Huffman Lossless Codec
+ case 'IRAW': // Intel YUV Uncompressed
+ case 'YUY2': // Uncompressed YUV 4:2:2
+ $thisfile_video['lossless'] = true;
+ break;
+
+ default:
+ $thisfile_video['lossless'] = false;
+ break;
+ }
+
+ switch ($strhfccType) {
+ case 'vids':
+ $thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($info['fileformat'] == 'riff'));
+ $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount'];
+
+ if ($thisfile_riff_video_current['codec'] == 'DV') {
+ $thisfile_riff_video_current['dv_type'] = 2;
+ }
+ break;
+
+ case 'iavs':
+ $thisfile_riff_video_current['dv_type'] = 1;
+ break;
+ }
+ break;
+
+ default:
+ $info['warning'][] = 'Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"';
+ break;
+
+ }
+ }
+ }
+
+ if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) {
+
+ $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'];
+ if (self::fourccLookup($thisfile_video['fourcc'])) {
+ $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_video['fourcc']);
+ $thisfile_video['codec'] = $thisfile_riff_video_current['codec'];
+ }
+
+ switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) {
+ case 'HFYU': // Huffman Lossless Codec
+ case 'IRAW': // Intel YUV Uncompressed
+ case 'YUY2': // Uncompressed YUV 4:2:2
+ $thisfile_video['lossless'] = true;
+ //$thisfile_video['bits_per_sample'] = 24;
+ break;
+
+ default:
+ $thisfile_video['lossless'] = false;
+ //$thisfile_video['bits_per_sample'] = 24;
+ break;
+ }
+
+ }
+ }
+ }
+ }
+ break;
+
+ case 'CDDA':
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ $thisfile_audio_dataformat = 'cda';
+ $thisfile_audio['lossless'] = true;
+ unset($info['mime_type']);
+
+ $info['avdataoffset'] = 44;
+
+ if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) {
+ // shortcut
+ $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0];
+
+ $thisfile_riff_CDDA_fmt_0['unknown1'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2));
+ $thisfile_riff_CDDA_fmt_0['track_num'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2));
+ $thisfile_riff_CDDA_fmt_0['disc_id'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4));
+ $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4));
+ $thisfile_riff_CDDA_fmt_0['playtime_frames'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4));
+ $thisfile_riff_CDDA_fmt_0['unknown6'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4));
+ $thisfile_riff_CDDA_fmt_0['unknown7'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4));
+
+ $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75;
+ $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75;
+ $info['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num'];
+ $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds'];
+
+ // hardcoded data for CD-audio
+ $thisfile_audio['sample_rate'] = 44100;
+ $thisfile_audio['channels'] = 2;
+ $thisfile_audio['bits_per_sample'] = 16;
+ $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample'];
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ }
+ break;
+
+
+ case 'AIFF':
+ case 'AIFC':
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ $thisfile_audio_dataformat = 'aiff';
+ $thisfile_audio['lossless'] = true;
+ $info['mime_type'] = 'audio/x-aiff';
+
+ if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) {
+ $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8;
+ $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size'];
+ if ($info['avdataend'] > $info['filesize']) {
+ if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) {
+ // structures rounded to 2-byte boundary, but dumb encoders
+ // forget to pad end of file to make this actually work
+ } else {
+ $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
+ }
+ $info['avdataend'] = $info['filesize'];
+ }
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) {
+
+ // shortcut
+ $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data'];
+
+ $thisfile_riff_audio['channels'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true);
+ $thisfile_riff_audio['total_samples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false);
+ $thisfile_riff_audio['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true);
+ $thisfile_riff_audio['sample_rate'] = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10));
+
+ if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) {
+ $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4);
+ $CodecNameSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false);
+ $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize);
+ switch ($thisfile_riff_audio['codec_name']) {
+ case 'NONE':
+ $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ case '':
+ switch ($thisfile_riff_audio['codec_fourcc']) {
+ // http://developer.apple.com/qa/snd/snd07.html
+ case 'sowt':
+ $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM';
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ case 'twos':
+ $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM';
+ $thisfile_audio['lossless'] = true;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name'];
+ $thisfile_audio['lossless'] = false;
+ break;
+ }
+ }
+
+ $thisfile_audio['channels'] = $thisfile_riff_audio['channels'];
+ if ($thisfile_riff_audio['bits_per_sample'] > 0) {
+ $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample'];
+ }
+ $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate'];
+ if ($thisfile_audio['sample_rate'] == 0) {
+ $info['error'][] = 'Corrupted AIFF file: sample_rate == zero';
+ return false;
+ }
+ $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate'];
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) {
+ $offset = 0;
+ $CommentCount = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
+ $offset += 2;
+ for ($i = 0; $i < $CommentCount; $i++) {
+ $info['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false);
+ $offset += 4;
+ $info['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true);
+ $offset += 2;
+ $CommentLength = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false);
+ $offset += 2;
+ $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength);
+ $offset += $CommentLength;
+
+ $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($info['comments_raw'][$i]['timestamp']);
+ $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment'];
+ }
+ }
+
+ $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
+ foreach ($CommentsChunkNames as $key => $value) {
+ if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
+ $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
+ }
+ }
+/*
+ if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) {
+ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_id3v2 = new getid3_id3v2($getid3_temp);
+ $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8;
+ if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
+ $info['id3v2'] = $getid3_temp->info['id3v2'];
+ }
+ unset($getid3_temp, $getid3_id3v2);
+ }
+*/
+ break;
+
+ case '8SVX':
+ $thisfile_audio['bitrate_mode'] = 'cbr';
+ $thisfile_audio_dataformat = '8svx';
+ $thisfile_audio['bits_per_sample'] = 8;
+ $thisfile_audio['channels'] = 1; // overridden below, if need be
+ $info['mime_type'] = 'audio/x-aiff';
+
+ if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) {
+ $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8;
+ $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size'];
+ if ($info['avdataend'] > $info['filesize']) {
+ $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found';
+ }
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) {
+ // shortcut
+ $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0];
+
+ $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4));
+ $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4));
+ $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4));
+ $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2));
+ $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1));
+ $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1));
+ $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4));
+
+ $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'];
+
+ switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) {
+ case 0:
+ $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)';
+ $thisfile_audio['lossless'] = true;
+ $ActualBitsPerSample = 8;
+ break;
+
+ case 1:
+ $thisfile_audio['codec'] = 'Fibonacci-delta encoding';
+ $thisfile_audio['lossless'] = false;
+ $ActualBitsPerSample = 4;
+ break;
+
+ default:
+ $info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"';
+ break;
+ }
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) {
+ $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4));
+ switch ($ChannelsIndex) {
+ case 6: // Stereo
+ $thisfile_audio['channels'] = 2;
+ break;
+
+ case 2: // Left channel only
+ case 4: // Right channel only
+ $thisfile_audio['channels'] = 1;
+ break;
+
+ default:
+ $info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"';
+ break;
+ }
+
+ }
+
+ $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment');
+ foreach ($CommentsChunkNames as $key => $value) {
+ if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) {
+ $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data'];
+ }
+ }
+
+ $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels'];
+ if (!empty($thisfile_audio['bitrate'])) {
+ $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8);
+ }
+ break;
+
+
+ case 'CDXA':
+ $info['mime_type'] = 'video/mpeg';
+ if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) {
+ if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, false)) {
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_mpeg = new getid3_mpeg($getid3_temp);
+ $getid3_mpeg->Analyze();
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['video'] = $getid3_temp->info['video'];
+ $info['mpeg'] = $getid3_temp->info['mpeg'];
+ $info['warning'] = $getid3_temp->info['warning'];
+ }
+ unset($getid3_temp, $getid3_mpeg);
+ }
+ }
+ break;
+
+
+ default:
+ $info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead';
+ unset($info['fileformat']);
+ break;
+ }
+
+ switch ($RIFFsubtype) {
+ case 'WAVE':
+ case 'AIFF':
+ case 'AIFC':
+ $ID3v2_key_good = 'id3 ';
+ $ID3v2_keys_bad = array('ID3 ', 'tag ');
+ foreach ($ID3v2_keys_bad as $ID3v2_key_bad) {
+ if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) {
+ $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad];
+ $info['warning'][] = 'mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"';
+ }
+ }
+
+ if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) {
+ getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true);
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_id3v2 = new getid3_id3v2($getid3_temp);
+ $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8;
+ if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) {
+ $info['id3v2'] = $getid3_temp->info['id3v2'];
+ }
+ unset($getid3_temp, $getid3_id3v2);
+ }
+ break;
+ }
+
+ if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) {
+ $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4));
+ }
+ if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) {
+ self::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']);
+ }
+ if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) {
+ self::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']);
+ }
+
+ if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) {
+ $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version'];
+ }
+
+ if (!isset($info['playtime_seconds'])) {
+ $info['playtime_seconds'] = 0;
+ }
+ if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
+ // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie
+ $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
+ } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) {
+ $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000);
+ }
+
+ if ($info['playtime_seconds'] > 0) {
+ if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
+
+ if (!isset($info['bitrate'])) {
+ $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
+ }
+
+ } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) {
+
+ if (!isset($thisfile_audio['bitrate'])) {
+ $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
+ }
+
+ } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) {
+
+ if (!isset($thisfile_video['bitrate'])) {
+ $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
+ }
+
+ }
+ }
+
+
+ if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) {
+
+ $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8);
+ $thisfile_audio['bitrate'] = 0;
+ $thisfile_video['bitrate'] = $info['bitrate'];
+ foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) {
+ $thisfile_video['bitrate'] -= $audioinfoarray['bitrate'];
+ $thisfile_audio['bitrate'] += $audioinfoarray['bitrate'];
+ }
+ if ($thisfile_video['bitrate'] <= 0) {
+ unset($thisfile_video['bitrate']);
+ }
+ if ($thisfile_audio['bitrate'] <= 0) {
+ unset($thisfile_audio['bitrate']);
+ }
+ }
+
+ if (isset($info['mpeg']['audio'])) {
+ $thisfile_audio_dataformat = 'mp'.$info['mpeg']['audio']['layer'];
+ $thisfile_audio['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ $thisfile_audio['channels'] = $info['mpeg']['audio']['channels'];
+ $thisfile_audio['bitrate'] = $info['mpeg']['audio']['bitrate'];
+ $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
+ if (!empty($info['mpeg']['audio']['codec'])) {
+ $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'].' '.$thisfile_audio['codec'];
+ }
+ if (!empty($thisfile_audio['streams'])) {
+ foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) {
+ if ($streamdata['dataformat'] == $thisfile_audio_dataformat) {
+ $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate'];
+ $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels'];
+ $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate'];
+ $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode'];
+ $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec'];
+ }
+ }
+ }
+ $getid3_mp3 = new getid3_mp3($this->getid3);
+ $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions();
+ unset($getid3_mp3);
+ }
+
+
+ if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) {
+ switch ($thisfile_audio_dataformat) {
+ case 'ac3':
+ // ignore bits_per_sample
+ break;
+
+ default:
+ $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample'];
+ break;
+ }
+ }
+
+
+ if (empty($thisfile_riff_raw)) {
+ unset($thisfile_riff['raw']);
+ }
+ if (empty($thisfile_riff_audio)) {
+ unset($thisfile_riff['audio']);
+ }
+ if (empty($thisfile_riff_video)) {
+ unset($thisfile_riff['video']);
+ }
+
+ return true;
+ }
+
+ public function ParseRIFF($startoffset, $maxoffset) {
+ $info = &$this->getid3->info;
+
+ $RIFFchunk = false;
+ $FoundAllChunksWeNeed = false;
+
+ try {
+ $this->fseek($startoffset);
+ $maxoffset = min($maxoffset, $info['avdataend']);
+ while ($this->ftell() < $maxoffset) {
+ $chunknamesize = $this->fread(8);
+ //$chunkname = substr($chunknamesize, 0, 4);
+ $chunkname = str_replace("\x00", '_', substr($chunknamesize, 0, 4)); // note: chunk names of 4 null bytes do appear to be legal (has been observed inside INFO and PRMI chunks, for example), but makes traversing array keys more difficult
+ $chunksize = $this->EitherEndian2Int(substr($chunknamesize, 4, 4));
+ //if (strlen(trim($chunkname, "\x00")) < 4) {
+ if (strlen($chunkname) < 4) {
+ $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.');
+ break;
+ }
+ if (($chunksize == 0) && ($chunkname != 'JUNK')) {
+ $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.');
+ break;
+ }
+ if (($chunksize % 2) != 0) {
+ // all structures are packed on word boundaries
+ $chunksize++;
+ }
+
+ switch ($chunkname) {
+ case 'LIST':
+ $listname = $this->fread(4);
+ if (preg_match('#^(movi|rec )$#i', $listname)) {
+ $RIFFchunk[$listname]['offset'] = $this->ftell() - 4;
+ $RIFFchunk[$listname]['size'] = $chunksize;
+
+ if (!$FoundAllChunksWeNeed) {
+ $WhereWeWere = $this->ftell();
+ $AudioChunkHeader = $this->fread(12);
+ $AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2);
+ $AudioChunkStreamType = substr($AudioChunkHeader, 2, 2);
+ $AudioChunkSize = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4));
+
+ if ($AudioChunkStreamType == 'wb') {
+ $FirstFourBytes = substr($AudioChunkHeader, 8, 4);
+ if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) {
+ // MP3
+ if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) {
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
+ $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
+ $getid3_mp3 = new getid3_mp3($getid3_temp);
+ $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false);
+ if (isset($getid3_temp->info['mpeg']['audio'])) {
+ $info['mpeg']['audio'] = $getid3_temp->info['mpeg']['audio'];
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
+ $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
+ $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
+ $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
+ //$info['bitrate'] = $info['audio']['bitrate'];
+ }
+ unset($getid3_temp, $getid3_mp3);
+ }
+
+ } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) {
+
+ // AC3
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $this->ftell() - 4;
+ $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize;
+ $getid3_ac3 = new getid3_ac3($getid3_temp);
+ $getid3_ac3->Analyze();
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['ac3'] = $getid3_temp->info['ac3'];
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $key => $value) {
+ $info['warning'][] = $value;
+ }
+ }
+ }
+ unset($getid3_temp, $getid3_ac3);
+ }
+ }
+ $FoundAllChunksWeNeed = true;
+ $this->fseek($WhereWeWere);
+ }
+ $this->fseek($chunksize - 4, SEEK_CUR);
+
+ } else {
+
+ if (!isset($RIFFchunk[$listname])) {
+ $RIFFchunk[$listname] = array();
+ }
+ $LISTchunkParent = $listname;
+ $LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize;
+ if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) {
+ $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk);
+ }
+
+ }
+ break;
+
+ default:
+ if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) {
+ $this->fseek($chunksize, SEEK_CUR);
+ break;
+ }
+ $thisindex = 0;
+ if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) {
+ $thisindex = count($RIFFchunk[$chunkname]);
+ }
+ $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8;
+ $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize;
+ switch ($chunkname) {
+ case 'data':
+ $info['avdataoffset'] = $this->ftell();
+ $info['avdataend'] = $info['avdataoffset'] + $chunksize;
+
+ $testData = $this->fread(36);
+ if ($testData === '') {
+ break;
+ }
+ if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) {
+
+ // Probably is MP3 data
+ if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) {
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
+ $getid3_temp->info['avdataend'] = $info['avdataend'];
+ $getid3_mp3 = new getid3_mp3($getid3_temp);
+ $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false);
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['mpeg'] = $getid3_temp->info['mpeg'];
+ }
+ unset($getid3_temp, $getid3_mp3);
+ }
+
+ } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) {
+
+ // This is probably AC-3 data
+ $getid3_temp = new getID3();
+ if ($isRegularAC3) {
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
+ $getid3_temp->info['avdataend'] = $info['avdataend'];
+ }
+ $getid3_ac3 = new getid3_ac3($getid3_temp);
+ if ($isRegularAC3) {
+ $getid3_ac3->Analyze();
+ } else {
+ // Dolby Digital WAV
+ // AC-3 content, but not encoded in same format as normal AC-3 file
+ // For one thing, byte order is swapped
+ $ac3_data = '';
+ for ($i = 0; $i < 28; $i += 2) {
+ $ac3_data .= substr($testData, 8 + $i + 1, 1);
+ $ac3_data .= substr($testData, 8 + $i + 0, 1);
+ }
+ $getid3_ac3->AnalyzeString($ac3_data);
+ }
+
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['ac3'] = $getid3_temp->info['ac3'];
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $newerror) {
+ $this->warning('getid3_ac3() says: ['.$newerror.']');
+ }
+ }
+ }
+ unset($getid3_temp, $getid3_ac3);
+
+ } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) {
+
+ // This is probably DTS data
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($this->getid3->filename);
+ $getid3_temp->info['avdataoffset'] = $info['avdataoffset'];
+ $getid3_dts = new getid3_dts($getid3_temp);
+ $getid3_dts->Analyze();
+ if (empty($getid3_temp->info['error'])) {
+ $info['audio'] = $getid3_temp->info['audio'];
+ $info['dts'] = $getid3_temp->info['dts'];
+ $info['playtime_seconds'] = $getid3_temp->info['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing
+ if (!empty($getid3_temp->info['warning'])) {
+ foreach ($getid3_temp->info['warning'] as $newerror) {
+ $this->warning('getid3_dts() says: ['.$newerror.']');
+ }
+ }
+ }
+
+ unset($getid3_temp, $getid3_dts);
+
+ } elseif (substr($testData, 0, 4) == 'wvpk') {
+
+ // This is WavPack data
+ $info['wavpack']['offset'] = $info['avdataoffset'];
+ $info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($testData, 4, 4));
+ $this->parseWavPackHeader(substr($testData, 8, 28));
+
+ } else {
+ // This is some other kind of data (quite possibly just PCM)
+ // do nothing special, just skip it
+ }
+ $nextoffset = $info['avdataend'];
+ $this->fseek($nextoffset);
+ break;
+
+ case 'iXML':
+ case 'bext':
+ case 'cart':
+ case 'fmt ':
+ case 'strh':
+ case 'strf':
+ case 'indx':
+ case 'MEXT':
+ case 'DISP':
+ // always read data in
+ case 'JUNK':
+ // should be: never read data in
+ // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc)
+ if ($chunksize < 1048576) {
+ if ($chunksize > 0) {
+ $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
+ if ($chunkname == 'JUNK') {
+ if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) {
+ // only keep text characters [chr(32)-chr(127)]
+ $info['riff']['comments']['junk'][] = trim($matches[1]);
+ }
+ // but if nothing there, ignore
+ // remove the key in either case
+ unset($RIFFchunk[$chunkname][$thisindex]['data']);
+ }
+ }
+ } else {
+ $this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data');
+ $this->fseek($chunksize, SEEK_CUR);
+ }
+ break;
+
+ //case 'IDVX':
+ // $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize));
+ // break;
+
+ default:
+ if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) {
+ $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset'];
+ $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size'];
+ unset($RIFFchunk[$chunkname][$thisindex]['offset']);
+ unset($RIFFchunk[$chunkname][$thisindex]['size']);
+ if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) {
+ unset($RIFFchunk[$chunkname][$thisindex]);
+ }
+ if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) {
+ unset($RIFFchunk[$chunkname]);
+ }
+ $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize);
+ } elseif ($chunksize < 2048) {
+ // only read data in if smaller than 2kB
+ $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize);
+ } else {
+ $this->fseek($chunksize, SEEK_CUR);
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ } catch (getid3_exception $e) {
+ if ($e->getCode() == 10) {
+ $this->warning('RIFF parser: '.$e->getMessage());
+ } else {
+ throw $e;
+ }
+ }
+
+ return $RIFFchunk;
+ }
+
+ public function ParseRIFFdata(&$RIFFdata) {
+ $info = &$this->getid3->info;
+ if ($RIFFdata) {
+ $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3');
+ $fp_temp = fopen($tempfile, 'wb');
+ $RIFFdataLength = strlen($RIFFdata);
+ $NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4);
+ for ($i = 0; $i < 4; $i++) {
+ $RIFFdata[($i + 4)] = $NewLengthString[$i];
+ }
+ fwrite($fp_temp, $RIFFdata);
+ fclose($fp_temp);
+
+ $getid3_temp = new getID3();
+ $getid3_temp->openfile($tempfile);
+ $getid3_temp->info['filesize'] = $RIFFdataLength;
+ $getid3_temp->info['filenamepath'] = $info['filenamepath'];
+ $getid3_temp->info['tags'] = $info['tags'];
+ $getid3_temp->info['warning'] = $info['warning'];
+ $getid3_temp->info['error'] = $info['error'];
+ $getid3_temp->info['comments'] = $info['comments'];
+ $getid3_temp->info['audio'] = (isset($info['audio']) ? $info['audio'] : array());
+ $getid3_temp->info['video'] = (isset($info['video']) ? $info['video'] : array());
+ $getid3_riff = new getid3_riff($getid3_temp);
+ $getid3_riff->Analyze();
+
+ $info['riff'] = $getid3_temp->info['riff'];
+ $info['warning'] = $getid3_temp->info['warning'];
+ $info['error'] = $getid3_temp->info['error'];
+ $info['tags'] = $getid3_temp->info['tags'];
+ $info['comments'] = $getid3_temp->info['comments'];
+ unset($getid3_riff, $getid3_temp);
+ unlink($tempfile);
+ }
+ return false;
+ }
+
+ public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) {
+ $RIFFinfoKeyLookup = array(
+ 'IARL'=>'archivallocation',
+ 'IART'=>'artist',
+ 'ICDS'=>'costumedesigner',
+ 'ICMS'=>'commissionedby',
+ 'ICMT'=>'comment',
+ 'ICNT'=>'country',
+ 'ICOP'=>'copyright',
+ 'ICRD'=>'creationdate',
+ 'IDIM'=>'dimensions',
+ 'IDIT'=>'digitizationdate',
+ 'IDPI'=>'resolution',
+ 'IDST'=>'distributor',
+ 'IEDT'=>'editor',
+ 'IENG'=>'engineers',
+ 'IFRM'=>'accountofparts',
+ 'IGNR'=>'genre',
+ 'IKEY'=>'keywords',
+ 'ILGT'=>'lightness',
+ 'ILNG'=>'language',
+ 'IMED'=>'orignalmedium',
+ 'IMUS'=>'composer',
+ 'INAM'=>'title',
+ 'IPDS'=>'productiondesigner',
+ 'IPLT'=>'palette',
+ 'IPRD'=>'product',
+ 'IPRO'=>'producer',
+ 'IPRT'=>'part',
+ 'IRTD'=>'rating',
+ 'ISBJ'=>'subject',
+ 'ISFT'=>'software',
+ 'ISGN'=>'secondarygenre',
+ 'ISHP'=>'sharpness',
+ 'ISRC'=>'sourcesupplier',
+ 'ISRF'=>'digitizationsource',
+ 'ISTD'=>'productionstudio',
+ 'ISTR'=>'starring',
+ 'ITCH'=>'encoded_by',
+ 'IWEB'=>'url',
+ 'IWRI'=>'writer',
+ '____'=>'comment',
+ );
+ foreach ($RIFFinfoKeyLookup as $key => $value) {
+ if (isset($RIFFinfoArray[$key])) {
+ foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) {
+ if (trim($commentdata['data']) != '') {
+ if (isset($CommentsTargetArray[$value])) {
+ $CommentsTargetArray[$value][] = trim($commentdata['data']);
+ } else {
+ $CommentsTargetArray[$value] = array(trim($commentdata['data']));
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ public static function parseWAVEFORMATex($WaveFormatExData) {
+ // shortcut
+ $WaveFormatEx['raw'] = array();
+ $WaveFormatEx_raw = &$WaveFormatEx['raw'];
+
+ $WaveFormatEx_raw['wFormatTag'] = substr($WaveFormatExData, 0, 2);
+ $WaveFormatEx_raw['nChannels'] = substr($WaveFormatExData, 2, 2);
+ $WaveFormatEx_raw['nSamplesPerSec'] = substr($WaveFormatExData, 4, 4);
+ $WaveFormatEx_raw['nAvgBytesPerSec'] = substr($WaveFormatExData, 8, 4);
+ $WaveFormatEx_raw['nBlockAlign'] = substr($WaveFormatExData, 12, 2);
+ $WaveFormatEx_raw['wBitsPerSample'] = substr($WaveFormatExData, 14, 2);
+ if (strlen($WaveFormatExData) > 16) {
+ $WaveFormatEx_raw['cbSize'] = substr($WaveFormatExData, 16, 2);
+ }
+ $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw);
+
+ $WaveFormatEx['codec'] = self::wFormatTagLookup($WaveFormatEx_raw['wFormatTag']);
+ $WaveFormatEx['channels'] = $WaveFormatEx_raw['nChannels'];
+ $WaveFormatEx['sample_rate'] = $WaveFormatEx_raw['nSamplesPerSec'];
+ $WaveFormatEx['bitrate'] = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8;
+ $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample'];
+
+ return $WaveFormatEx;
+ }
+
+ public function parseWavPackHeader($WavPackChunkData) {
+ // typedef struct {
+ // char ckID [4];
+ // long ckSize;
+ // short version;
+ // short bits; // added for version 2.00
+ // short flags, shift; // added for version 3.00
+ // long total_samples, crc, crc2;
+ // char extension [4], extra_bc, extras [3];
+ // } WavpackHeader;
+
+ // shortcut
+ $info = &$this->getid3->info;
+ $info['wavpack'] = array();
+ $thisfile_wavpack = &$info['wavpack'];
+
+ $thisfile_wavpack['version'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 0, 2));
+ if ($thisfile_wavpack['version'] >= 2) {
+ $thisfile_wavpack['bits'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 2, 2));
+ }
+ if ($thisfile_wavpack['version'] >= 3) {
+ $thisfile_wavpack['flags_raw'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 4, 2));
+ $thisfile_wavpack['shift'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 6, 2));
+ $thisfile_wavpack['total_samples'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 8, 4));
+ $thisfile_wavpack['crc1'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 12, 4));
+ $thisfile_wavpack['crc2'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 16, 4));
+ $thisfile_wavpack['extension'] = substr($WavPackChunkData, 20, 4);
+ $thisfile_wavpack['extra_bc'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 24, 1));
+ for ($i = 0; $i <= 2; $i++) {
+ $thisfile_wavpack['extras'][] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 25 + $i, 1));
+ }
+
+ // shortcut
+ $thisfile_wavpack['flags'] = array();
+ $thisfile_wavpack_flags = &$thisfile_wavpack['flags'];
+
+ $thisfile_wavpack_flags['mono'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001);
+ $thisfile_wavpack_flags['fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002);
+ $thisfile_wavpack_flags['raw_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004);
+ $thisfile_wavpack_flags['calc_noise'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008);
+ $thisfile_wavpack_flags['high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010);
+ $thisfile_wavpack_flags['3_byte_samples'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020);
+ $thisfile_wavpack_flags['over_20_bits'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040);
+ $thisfile_wavpack_flags['use_wvc'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080);
+ $thisfile_wavpack_flags['noiseshaping'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100);
+ $thisfile_wavpack_flags['very_fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200);
+ $thisfile_wavpack_flags['new_high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400);
+ $thisfile_wavpack_flags['cancel_extreme'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800);
+ $thisfile_wavpack_flags['cross_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000);
+ $thisfile_wavpack_flags['new_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000);
+ $thisfile_wavpack_flags['joint_stereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000);
+ $thisfile_wavpack_flags['extra_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000);
+ $thisfile_wavpack_flags['override_noiseshape'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000);
+ $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000);
+ $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000);
+ $thisfile_wavpack_flags['create_exe'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000);
+ }
+
+ return true;
+ }
+
+ public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) {
+
+ $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure
+ $parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels
+ $parsed['biHeight'] = substr($BITMAPINFOHEADER, 8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner
+ $parsed['biPlanes'] = substr($BITMAPINFOHEADER, 12, 2); // number of color planes on the target device. In most cases this value must be set to 1
+ $parsed['biBitCount'] = substr($BITMAPINFOHEADER, 14, 2); // Specifies the number of bits per pixels
+ $parsed['biSizeImage'] = substr($BITMAPINFOHEADER, 20, 4); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures)
+ $parsed['biXPelsPerMeter'] = substr($BITMAPINFOHEADER, 24, 4); // horizontal resolution, in pixels per metre, of the target device
+ $parsed['biYPelsPerMeter'] = substr($BITMAPINFOHEADER, 28, 4); // vertical resolution, in pixels per metre, of the target device
+ $parsed['biClrUsed'] = substr($BITMAPINFOHEADER, 32, 4); // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression
+ $parsed['biClrImportant'] = substr($BITMAPINFOHEADER, 36, 4); // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important
+ $parsed = array_map('getid3_lib::'.($littleEndian ? 'Little' : 'Big').'Endian2Int', $parsed);
+
+ $parsed['fourcc'] = substr($BITMAPINFOHEADER, 16, 4); // compression identifier
+
+ return $parsed;
+ }
+
+ public static function ParseDIVXTAG($DIVXTAG, $raw=false) {
+ // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/
+ // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip
+ // 'Byte Layout: '1111111111111111
+ // '32 for Movie - 1 '1111111111111111
+ // '28 for Author - 6 '6666666666666666
+ // '4 for year - 2 '6666666666662222
+ // '3 for genre - 3 '7777777777777777
+ // '48 for Comments - 7 '7777777777777777
+ // '1 for Rating - 4 '7777777777777777
+ // '5 for Future Additions - 0 '333400000DIVXTAG
+ // '128 bytes total
+
+ static $DIVXTAGgenre = array(
+ 0 => 'Action',
+ 1 => 'Action/Adventure',
+ 2 => 'Adventure',
+ 3 => 'Adult',
+ 4 => 'Anime',
+ 5 => 'Cartoon',
+ 6 => 'Claymation',
+ 7 => 'Comedy',
+ 8 => 'Commercial',
+ 9 => 'Documentary',
+ 10 => 'Drama',
+ 11 => 'Home Video',
+ 12 => 'Horror',
+ 13 => 'Infomercial',
+ 14 => 'Interactive',
+ 15 => 'Mystery',
+ 16 => 'Music Video',
+ 17 => 'Other',
+ 18 => 'Religion',
+ 19 => 'Sci Fi',
+ 20 => 'Thriller',
+ 21 => 'Western',
+ ),
+ $DIVXTAGrating = array(
+ 0 => 'Unrated',
+ 1 => 'G',
+ 2 => 'PG',
+ 3 => 'PG-13',
+ 4 => 'R',
+ 5 => 'NC-17',
+ );
+
+ $parsed['title'] = trim(substr($DIVXTAG, 0, 32));
+ $parsed['artist'] = trim(substr($DIVXTAG, 32, 28));
+ $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4)));
+ $parsed['comment'] = trim(substr($DIVXTAG, 64, 48));
+ $parsed['genre_id'] = intval(trim(substr($DIVXTAG, 112, 3)));
+ $parsed['rating_id'] = ord(substr($DIVXTAG, 115, 1));
+ //$parsed['padding'] = substr($DIVXTAG, 116, 5); // 5-byte null
+ //$parsed['magic'] = substr($DIVXTAG, 121, 7); // "DIVXTAG"
+
+ $parsed['genre'] = (isset($DIVXTAGgenre[$parsed['genre_id']]) ? $DIVXTAGgenre[$parsed['genre_id']] : $parsed['genre_id']);
+ $parsed['rating'] = (isset($DIVXTAGrating[$parsed['rating_id']]) ? $DIVXTAGrating[$parsed['rating_id']] : $parsed['rating_id']);
+
+ if (!$raw) {
+ unset($parsed['genre_id'], $parsed['rating_id']);
+ foreach ($parsed as $key => $value) {
+ if (!$value === '') {
+ unset($parsed['key']);
+ }
+ }
+ }
+
+ foreach ($parsed as $tag => $value) {
+ $parsed[$tag] = array($value);
+ }
+
+ return $parsed;
+ }
+
+ public static function waveSNDMtagLookup($tagshortname) {
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ \A9kwd keywords
+ \A9BPM bpm
+ \A9trt tracktitle
+ \A9des description
+ \A9gen category
+ \A9fin featuredinstrument
+ \A9LID longid
+ \A9bex bwdescription
+ \A9pub publisher
+ \A9cdt cdtitle
+ \A9alb library
+ \A9com composer
+
+ */
+
+ return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm');
+ }
+
+ public static function wFormatTagLookup($wFormatTag) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ 0x0000 Microsoft Unknown Wave Format
+ 0x0001 Pulse Code Modulation (PCM)
+ 0x0002 Microsoft ADPCM
+ 0x0003 IEEE Float
+ 0x0004 Compaq Computer VSELP
+ 0x0005 IBM CVSD
+ 0x0006 Microsoft A-Law
+ 0x0007 Microsoft mu-Law
+ 0x0008 Microsoft DTS
+ 0x0010 OKI ADPCM
+ 0x0011 Intel DVI/IMA ADPCM
+ 0x0012 Videologic MediaSpace ADPCM
+ 0x0013 Sierra Semiconductor ADPCM
+ 0x0014 Antex Electronics G.723 ADPCM
+ 0x0015 DSP Solutions DigiSTD
+ 0x0016 DSP Solutions DigiFIX
+ 0x0017 Dialogic OKI ADPCM
+ 0x0018 MediaVision ADPCM
+ 0x0019 Hewlett-Packard CU
+ 0x0020 Yamaha ADPCM
+ 0x0021 Speech Compression Sonarc
+ 0x0022 DSP Group TrueSpeech
+ 0x0023 Echo Speech EchoSC1
+ 0x0024 Audiofile AF36
+ 0x0025 Audio Processing Technology APTX
+ 0x0026 AudioFile AF10
+ 0x0027 Prosody 1612
+ 0x0028 LRC
+ 0x0030 Dolby AC2
+ 0x0031 Microsoft GSM 6.10
+ 0x0032 MSNAudio
+ 0x0033 Antex Electronics ADPCME
+ 0x0034 Control Resources VQLPC
+ 0x0035 DSP Solutions DigiREAL
+ 0x0036 DSP Solutions DigiADPCM
+ 0x0037 Control Resources CR10
+ 0x0038 Natural MicroSystems VBXADPCM
+ 0x0039 Crystal Semiconductor IMA ADPCM
+ 0x003A EchoSC3
+ 0x003B Rockwell ADPCM
+ 0x003C Rockwell Digit LK
+ 0x003D Xebec
+ 0x0040 Antex Electronics G.721 ADPCM
+ 0x0041 G.728 CELP
+ 0x0042 MSG723
+ 0x0050 MPEG Layer-2 or Layer-1
+ 0x0052 RT24
+ 0x0053 PAC
+ 0x0055 MPEG Layer-3
+ 0x0059 Lucent G.723
+ 0x0060 Cirrus
+ 0x0061 ESPCM
+ 0x0062 Voxware
+ 0x0063 Canopus Atrac
+ 0x0064 G.726 ADPCM
+ 0x0065 G.722 ADPCM
+ 0x0066 DSAT
+ 0x0067 DSAT Display
+ 0x0069 Voxware Byte Aligned
+ 0x0070 Voxware AC8
+ 0x0071 Voxware AC10
+ 0x0072 Voxware AC16
+ 0x0073 Voxware AC20
+ 0x0074 Voxware MetaVoice
+ 0x0075 Voxware MetaSound
+ 0x0076 Voxware RT29HW
+ 0x0077 Voxware VR12
+ 0x0078 Voxware VR18
+ 0x0079 Voxware TQ40
+ 0x0080 Softsound
+ 0x0081 Voxware TQ60
+ 0x0082 MSRT24
+ 0x0083 G.729A
+ 0x0084 MVI MV12
+ 0x0085 DF G.726
+ 0x0086 DF GSM610
+ 0x0088 ISIAudio
+ 0x0089 Onlive
+ 0x0091 SBC24
+ 0x0092 Dolby AC3 SPDIF
+ 0x0093 MediaSonic G.723
+ 0x0094 Aculab PLC Prosody 8kbps
+ 0x0097 ZyXEL ADPCM
+ 0x0098 Philips LPCBB
+ 0x0099 Packed
+ 0x00FF AAC
+ 0x0100 Rhetorex ADPCM
+ 0x0101 IBM mu-law
+ 0x0102 IBM A-law
+ 0x0103 IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM)
+ 0x0111 Vivo G.723
+ 0x0112 Vivo Siren
+ 0x0123 Digital G.723
+ 0x0125 Sanyo LD ADPCM
+ 0x0130 Sipro Lab Telecom ACELP NET
+ 0x0131 Sipro Lab Telecom ACELP 4800
+ 0x0132 Sipro Lab Telecom ACELP 8V3
+ 0x0133 Sipro Lab Telecom G.729
+ 0x0134 Sipro Lab Telecom G.729A
+ 0x0135 Sipro Lab Telecom Kelvin
+ 0x0140 Windows Media Video V8
+ 0x0150 Qualcomm PureVoice
+ 0x0151 Qualcomm HalfRate
+ 0x0155 Ring Zero Systems TUB GSM
+ 0x0160 Microsoft Audio 1
+ 0x0161 Windows Media Audio V7 / V8 / V9
+ 0x0162 Windows Media Audio Professional V9
+ 0x0163 Windows Media Audio Lossless V9
+ 0x0200 Creative Labs ADPCM
+ 0x0202 Creative Labs Fastspeech8
+ 0x0203 Creative Labs Fastspeech10
+ 0x0210 UHER Informatic GmbH ADPCM
+ 0x0220 Quarterdeck
+ 0x0230 I-link Worldwide VC
+ 0x0240 Aureal RAW Sport
+ 0x0250 Interactive Products HSX
+ 0x0251 Interactive Products RPELP
+ 0x0260 Consistent Software CS2
+ 0x0270 Sony SCX
+ 0x0300 Fujitsu FM Towns Snd
+ 0x0400 BTV Digital
+ 0x0401 Intel Music Coder
+ 0x0450 QDesign Music
+ 0x0680 VME VMPCM
+ 0x0681 AT&T Labs TPC
+ 0x08AE ClearJump LiteWave
+ 0x1000 Olivetti GSM
+ 0x1001 Olivetti ADPCM
+ 0x1002 Olivetti CELP
+ 0x1003 Olivetti SBC
+ 0x1004 Olivetti OPR
+ 0x1100 Lernout & Hauspie Codec (0x1100)
+ 0x1101 Lernout & Hauspie CELP Codec (0x1101)
+ 0x1102 Lernout & Hauspie SBC Codec (0x1102)
+ 0x1103 Lernout & Hauspie SBC Codec (0x1103)
+ 0x1104 Lernout & Hauspie SBC Codec (0x1104)
+ 0x1400 Norris
+ 0x1401 AT&T ISIAudio
+ 0x1500 Soundspace Music Compression
+ 0x181C VoxWare RT24 Speech
+ 0x1FC4 NCT Soft ALF2CD (www.nctsoft.com)
+ 0x2000 Dolby AC3
+ 0x2001 Dolby DTS
+ 0x2002 WAVE_FORMAT_14_4
+ 0x2003 WAVE_FORMAT_28_8
+ 0x2004 WAVE_FORMAT_COOK
+ 0x2005 WAVE_FORMAT_DNET
+ 0x674F Ogg Vorbis 1
+ 0x6750 Ogg Vorbis 2
+ 0x6751 Ogg Vorbis 3
+ 0x676F Ogg Vorbis 1+
+ 0x6770 Ogg Vorbis 2+
+ 0x6771 Ogg Vorbis 3+
+ 0x7A21 GSM-AMR (CBR, no SID)
+ 0x7A22 GSM-AMR (VBR, including SID)
+ 0xFFFE WAVE_FORMAT_EXTENSIBLE
+ 0xFFFF WAVE_FORMAT_DEVELOPMENT
+
+ */
+
+ return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag');
+ }
+
+ public static function fourccLookup($fourcc) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ swot http://developer.apple.com/qa/snd/snd07.html
+ ____ No Codec (____)
+ _BIT BI_BITFIELDS (Raw RGB)
+ _JPG JPEG compressed
+ _PNG PNG compressed W3C/ISO/IEC (RFC-2083)
+ _RAW Full Frames (Uncompressed)
+ _RGB Raw RGB Bitmap
+ _RL4 RLE 4bpp RGB
+ _RL8 RLE 8bpp RGB
+ 3IV1 3ivx MPEG-4 v1
+ 3IV2 3ivx MPEG-4 v2
+ 3IVX 3ivx MPEG-4
+ AASC Autodesk Animator
+ ABYR Kensington ?ABYR?
+ AEMI Array Microsystems VideoONE MPEG1-I Capture
+ AFLC Autodesk Animator FLC
+ AFLI Autodesk Animator FLI
+ AMPG Array Microsystems VideoONE MPEG
+ ANIM Intel RDX (ANIM)
+ AP41 AngelPotion Definitive
+ ASV1 Asus Video v1
+ ASV2 Asus Video v2
+ ASVX Asus Video 2.0 (audio)
+ AUR2 AuraVision Aura 2 Codec - YUV 4:2:2
+ AURA AuraVision Aura 1 Codec - YUV 4:1:1
+ AVDJ Independent JPEG Group\'s codec (AVDJ)
+ AVRN Independent JPEG Group\'s codec (AVRN)
+ AYUV 4:4:4 YUV (AYUV)
+ AZPR Quicktime Apple Video (AZPR)
+ BGR Raw RGB32
+ BLZ0 Blizzard DivX MPEG-4
+ BTVC Conexant Composite Video
+ BINK RAD Game Tools Bink Video
+ BT20 Conexant Prosumer Video
+ BTCV Conexant Composite Video Codec
+ BW10 Data Translation Broadway MPEG Capture
+ CC12 Intel YUV12
+ CDVC Canopus DV
+ CFCC Digital Processing Systems DPS Perception
+ CGDI Microsoft Office 97 Camcorder Video
+ CHAM Winnov Caviara Champagne
+ CJPG Creative WebCam JPEG
+ CLJR Cirrus Logic YUV 4:1:1
+ CMYK Common Data Format in Printing (Colorgraph)
+ CPLA Weitek 4:2:0 YUV Planar
+ CRAM Microsoft Video 1 (CRAM)
+ cvid Radius Cinepak
+ CVID Radius Cinepak
+ CWLT Microsoft Color WLT DIB
+ CYUV Creative Labs YUV
+ CYUY ATI YUV
+ D261 H.261
+ D263 H.263
+ DIB Device Independent Bitmap
+ DIV1 FFmpeg OpenDivX
+ DIV2 Microsoft MPEG-4 v1/v2
+ DIV3 DivX ;-) MPEG-4 v3.x Low-Motion
+ DIV4 DivX ;-) MPEG-4 v3.x Fast-Motion
+ DIV5 DivX MPEG-4 v5.x
+ DIV6 DivX ;-) (MS MPEG-4 v3.x)
+ DIVX DivX MPEG-4 v4 (OpenDivX / Project Mayo)
+ divx DivX MPEG-4
+ DMB1 Matrox Rainbow Runner hardware MJPEG
+ DMB2 Paradigm MJPEG
+ DSVD ?DSVD?
+ DUCK Duck TrueMotion 1.0
+ DPS0 DPS/Leitch Reality Motion JPEG
+ DPSC DPS/Leitch PAR Motion JPEG
+ DV25 Matrox DVCPRO codec
+ DV50 Matrox DVCPRO50 codec
+ DVC IEC 61834 and SMPTE 314M (DVC/DV Video)
+ DVCP IEC 61834 and SMPTE 314M (DVC/DV Video)
+ DVHD IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps
+ DVMA Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com)
+ DVSL IEC Standard DV compressed in SD (SDL)
+ DVAN ?DVAN?
+ DVE2 InSoft DVE-2 Videoconferencing
+ dvsd IEC 61834 and SMPTE 314M DVC/DV Video
+ DVSD IEC 61834 and SMPTE 314M DVC/DV Video
+ DVX1 Lucent DVX1000SP Video Decoder
+ DVX2 Lucent DVX2000S Video Decoder
+ DVX3 Lucent DVX3000S Video Decoder
+ DX50 DivX v5
+ DXT1 Microsoft DirectX Compressed Texture (DXT1)
+ DXT2 Microsoft DirectX Compressed Texture (DXT2)
+ DXT3 Microsoft DirectX Compressed Texture (DXT3)
+ DXT4 Microsoft DirectX Compressed Texture (DXT4)
+ DXT5 Microsoft DirectX Compressed Texture (DXT5)
+ DXTC Microsoft DirectX Compressed Texture (DXTC)
+ DXTn Microsoft DirectX Compressed Texture (DXTn)
+ EM2V Etymonix MPEG-2 I-frame (www.etymonix.com)
+ EKQ0 Elsa ?EKQ0?
+ ELK0 Elsa ?ELK0?
+ ESCP Eidos Escape
+ ETV1 eTreppid Video ETV1
+ ETV2 eTreppid Video ETV2
+ ETVC eTreppid Video ETVC
+ FLIC Autodesk FLI/FLC Animation
+ FLV1 Sorenson Spark
+ FLV4 On2 TrueMotion VP6
+ FRWT Darim Vision Forward Motion JPEG (www.darvision.com)
+ FRWU Darim Vision Forward Uncompressed (www.darvision.com)
+ FLJP D-Vision Field Encoded Motion JPEG
+ FPS1 FRAPS v1
+ FRWA SoftLab-Nsk Forward Motion JPEG w/ alpha channel
+ FRWD SoftLab-Nsk Forward Motion JPEG
+ FVF1 Iterated Systems Fractal Video Frame
+ GLZW Motion LZW (gabest@freemail.hu)
+ GPEG Motion JPEG (gabest@freemail.hu)
+ GWLT Microsoft Greyscale WLT DIB
+ H260 Intel ITU H.260 Videoconferencing
+ H261 Intel ITU H.261 Videoconferencing
+ H262 Intel ITU H.262 Videoconferencing
+ H263 Intel ITU H.263 Videoconferencing
+ H264 Intel ITU H.264 Videoconferencing
+ H265 Intel ITU H.265 Videoconferencing
+ H266 Intel ITU H.266 Videoconferencing
+ H267 Intel ITU H.267 Videoconferencing
+ H268 Intel ITU H.268 Videoconferencing
+ H269 Intel ITU H.269 Videoconferencing
+ HFYU Huffman Lossless Codec
+ HMCR Rendition Motion Compensation Format (HMCR)
+ HMRR Rendition Motion Compensation Format (HMRR)
+ I263 FFmpeg I263 decoder
+ IF09 Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane")
+ IUYV Interlaced version of UYVY (www.leadtools.com)
+ IY41 Interlaced version of Y41P (www.leadtools.com)
+ IYU1 12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard
+ IYU2 24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard
+ IYUV Planar YUV format (8-bpp Y plane, followed by 8-bpp 2\D72 U and V planes)
+ i263 Intel ITU H.263 Videoconferencing (i263)
+ I420 Intel Indeo 4
+ IAN Intel Indeo 4 (RDX)
+ ICLB InSoft CellB Videoconferencing
+ IGOR Power DVD
+ IJPG Intergraph JPEG
+ ILVC Intel Layered Video
+ ILVR ITU-T H.263+
+ IPDV I-O Data Device Giga AVI DV Codec
+ IR21 Intel Indeo 2.1
+ IRAW Intel YUV Uncompressed
+ IV30 Intel Indeo 3.0
+ IV31 Intel Indeo 3.1
+ IV32 Ligos Indeo 3.2
+ IV33 Ligos Indeo 3.3
+ IV34 Ligos Indeo 3.4
+ IV35 Ligos Indeo 3.5
+ IV36 Ligos Indeo 3.6
+ IV37 Ligos Indeo 3.7
+ IV38 Ligos Indeo 3.8
+ IV39 Ligos Indeo 3.9
+ IV40 Ligos Indeo Interactive 4.0
+ IV41 Ligos Indeo Interactive 4.1
+ IV42 Ligos Indeo Interactive 4.2
+ IV43 Ligos Indeo Interactive 4.3
+ IV44 Ligos Indeo Interactive 4.4
+ IV45 Ligos Indeo Interactive 4.5
+ IV46 Ligos Indeo Interactive 4.6
+ IV47 Ligos Indeo Interactive 4.7
+ IV48 Ligos Indeo Interactive 4.8
+ IV49 Ligos Indeo Interactive 4.9
+ IV50 Ligos Indeo Interactive 5.0
+ JBYR Kensington ?JBYR?
+ JPEG Still Image JPEG DIB
+ JPGL Pegasus Lossless Motion JPEG
+ KMVC Team17 Software Karl Morton\'s Video Codec
+ LSVM Vianet Lighting Strike Vmail (Streaming) (www.vianet.com)
+ LEAD LEAD Video Codec
+ Ljpg LEAD MJPEG Codec
+ MDVD Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de)
+ MJPA Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com)
+ MJPB Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com)
+ MMES Matrox MPEG-2 I-frame
+ MP2v Microsoft S-Mpeg 4 version 1 (MP2v)
+ MP42 Microsoft S-Mpeg 4 version 2 (MP42)
+ MP43 Microsoft S-Mpeg 4 version 3 (MP43)
+ MP4S Microsoft S-Mpeg 4 version 3 (MP4S)
+ MP4V FFmpeg MPEG-4
+ MPG1 FFmpeg MPEG 1/2
+ MPG2 FFmpeg MPEG 1/2
+ MPG3 FFmpeg DivX ;-) (MS MPEG-4 v3)
+ MPG4 Microsoft MPEG-4
+ MPGI Sigma Designs MPEG
+ MPNG PNG images decoder
+ MSS1 Microsoft Windows Screen Video
+ MSZH LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
+ M261 Microsoft H.261
+ M263 Microsoft H.263
+ M4S2 Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2)
+ m4s2 Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2)
+ MC12 ATI Motion Compensation Format (MC12)
+ MCAM ATI Motion Compensation Format (MCAM)
+ MJ2C Morgan Multimedia Motion JPEG2000
+ mJPG IBM Motion JPEG w/ Huffman Tables
+ MJPG Microsoft Motion JPEG DIB
+ MP42 Microsoft MPEG-4 (low-motion)
+ MP43 Microsoft MPEG-4 (fast-motion)
+ MP4S Microsoft MPEG-4 (MP4S)
+ mp4s Microsoft MPEG-4 (mp4s)
+ MPEG Chromatic Research MPEG-1 Video I-Frame
+ MPG4 Microsoft MPEG-4 Video High Speed Compressor
+ MPGI Sigma Designs MPEG
+ MRCA FAST Multimedia Martin Regen Codec
+ MRLE Microsoft Run Length Encoding
+ MSVC Microsoft Video 1
+ MTX1 Matrox ?MTX1?
+ MTX2 Matrox ?MTX2?
+ MTX3 Matrox ?MTX3?
+ MTX4 Matrox ?MTX4?
+ MTX5 Matrox ?MTX5?
+ MTX6 Matrox ?MTX6?
+ MTX7 Matrox ?MTX7?
+ MTX8 Matrox ?MTX8?
+ MTX9 Matrox ?MTX9?
+ MV12 Motion Pixels Codec (old)
+ MWV1 Aware Motion Wavelets
+ nAVI SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm)
+ NT00 NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com)
+ NUV1 NuppelVideo
+ NTN1 Nogatech Video Compression 1
+ NVS0 nVidia GeForce Texture (NVS0)
+ NVS1 nVidia GeForce Texture (NVS1)
+ NVS2 nVidia GeForce Texture (NVS2)
+ NVS3 nVidia GeForce Texture (NVS3)
+ NVS4 nVidia GeForce Texture (NVS4)
+ NVS5 nVidia GeForce Texture (NVS5)
+ NVT0 nVidia GeForce Texture (NVT0)
+ NVT1 nVidia GeForce Texture (NVT1)
+ NVT2 nVidia GeForce Texture (NVT2)
+ NVT3 nVidia GeForce Texture (NVT3)
+ NVT4 nVidia GeForce Texture (NVT4)
+ NVT5 nVidia GeForce Texture (NVT5)
+ PIXL MiroXL, Pinnacle PCTV
+ PDVC I-O Data Device Digital Video Capture DV codec
+ PGVV Radius Video Vision
+ PHMO IBM Photomotion
+ PIM1 MPEG Realtime (Pinnacle Cards)
+ PIM2 Pegasus Imaging ?PIM2?
+ PIMJ Pegasus Imaging Lossless JPEG
+ PVEZ Horizons Technology PowerEZ
+ PVMM PacketVideo Corporation MPEG-4
+ PVW2 Pegasus Imaging Wavelet Compression
+ Q1.0 Q-Team\'s QPEG 1.0 (www.q-team.de)
+ Q1.1 Q-Team\'s QPEG 1.1 (www.q-team.de)
+ QPEG Q-Team QPEG 1.0
+ qpeq Q-Team QPEG 1.1
+ RGB Raw BGR32
+ RGBA Raw RGB w/ Alpha
+ RMP4 REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com)
+ ROQV Id RoQ File Video Decoder
+ RPZA Quicktime Apple Video (RPZA)
+ RUD0 Rududu video codec (http://rududu.ifrance.com/rududu/)
+ RV10 RealVideo 1.0 (aka RealVideo 5.0)
+ RV13 RealVideo 1.0 (RV13)
+ RV20 RealVideo G2
+ RV30 RealVideo 8
+ RV40 RealVideo 9
+ RGBT Raw RGB w/ Transparency
+ RLE Microsoft Run Length Encoder
+ RLE4 Run Length Encoded (4bpp, 16-color)
+ RLE8 Run Length Encoded (8bpp, 256-color)
+ RT21 Intel Indeo RealTime Video 2.1
+ rv20 RealVideo G2
+ rv30 RealVideo 8
+ RVX Intel RDX (RVX )
+ SMC Apple Graphics (SMC )
+ SP54 Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2
+ SPIG Radius Spigot
+ SVQ3 Sorenson Video 3 (Apple Quicktime 5)
+ s422 Tekram VideoCap C210 YUV 4:2:2
+ SDCC Sun Communication Digital Camera Codec
+ SFMC CrystalNet Surface Fitting Method
+ SMSC Radius SMSC
+ SMSD Radius SMSD
+ smsv WorldConnect Wavelet Video
+ SPIG Radius Spigot
+ SPLC Splash Studios ACM Audio Codec (www.splashstudios.net)
+ SQZ2 Microsoft VXTreme Video Codec V2
+ STVA ST Microelectronics CMOS Imager Data (Bayer)
+ STVB ST Microelectronics CMOS Imager Data (Nudged Bayer)
+ STVC ST Microelectronics CMOS Imager Data (Bunched)
+ STVX ST Microelectronics CMOS Imager Data (Extended CODEC Data Format)
+ STVY ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data)
+ SV10 Sorenson Video R1
+ SVQ1 Sorenson Video
+ T420 Toshiba YUV 4:2:0
+ TM2A Duck TrueMotion Archiver 2.0 (www.duck.com)
+ TVJP Pinnacle/Truevision Targa 2000 board (TVJP)
+ TVMJ Pinnacle/Truevision Targa 2000 board (TVMJ)
+ TY0N Tecomac Low-Bit Rate Codec (www.tecomac.com)
+ TY2C Trident Decompression Driver
+ TLMS TeraLogic Motion Intraframe Codec (TLMS)
+ TLST TeraLogic Motion Intraframe Codec (TLST)
+ TM20 Duck TrueMotion 2.0
+ TM2X Duck TrueMotion 2X
+ TMIC TeraLogic Motion Intraframe Codec (TMIC)
+ TMOT Horizons Technology TrueMotion S
+ tmot Horizons TrueMotion Video Compression
+ TR20 Duck TrueMotion RealTime 2.0
+ TSCC TechSmith Screen Capture Codec
+ TV10 Tecomac Low-Bit Rate Codec
+ TY2N Trident ?TY2N?
+ U263 UB Video H.263/H.263+/H.263++ Decoder
+ UMP4 UB Video MPEG 4 (www.ubvideo.com)
+ UYNV Nvidia UYVY packed 4:2:2
+ UYVP Evans & Sutherland YCbCr 4:2:2 extended precision
+ UCOD eMajix.com ClearVideo
+ ULTI IBM Ultimotion
+ UYVY UYVY packed 4:2:2
+ V261 Lucent VX2000S
+ VIFP VFAPI Reader Codec (www.yks.ne.jp/~hori/)
+ VIV1 FFmpeg H263+ decoder
+ VIV2 Vivo H.263
+ VQC2 Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf)
+ VTLP Alaris VideoGramPiX
+ VYU9 ATI YUV (VYU9)
+ VYUY ATI YUV (VYUY)
+ V261 Lucent VX2000S
+ V422 Vitec Multimedia 24-bit YUV 4:2:2 Format
+ V655 Vitec Multimedia 16-bit YUV 4:2:2 Format
+ VCR1 ATI Video Codec 1
+ VCR2 ATI Video Codec 2
+ VCR3 ATI VCR 3.0
+ VCR4 ATI VCR 4.0
+ VCR5 ATI VCR 5.0
+ VCR6 ATI VCR 6.0
+ VCR7 ATI VCR 7.0
+ VCR8 ATI VCR 8.0
+ VCR9 ATI VCR 9.0
+ VDCT Vitec Multimedia Video Maker Pro DIB
+ VDOM VDOnet VDOWave
+ VDOW VDOnet VDOLive (H.263)
+ VDTZ Darim Vison VideoTizer YUV
+ VGPX Alaris VideoGramPiX
+ VIDS Vitec Multimedia YUV 4:2:2 CCIR 601 for V422
+ VIVO Vivo H.263 v2.00
+ vivo Vivo H.263
+ VIXL Miro/Pinnacle Video XL
+ VLV1 VideoLogic/PURE Digital Videologic Capture
+ VP30 On2 VP3.0
+ VP31 On2 VP3.1
+ VP6F On2 TrueMotion VP6
+ VX1K Lucent VX1000S Video Codec
+ VX2K Lucent VX2000S Video Codec
+ VXSP Lucent VX1000SP Video Codec
+ WBVC Winbond W9960
+ WHAM Microsoft Video 1 (WHAM)
+ WINX Winnov Software Compression
+ WJPG AverMedia Winbond JPEG
+ WMV1 Windows Media Video V7
+ WMV2 Windows Media Video V8
+ WMV3 Windows Media Video V9
+ WNV1 Winnov Hardware Compression
+ XYZP Extended PAL format XYZ palette (www.riff.org)
+ x263 Xirlink H.263
+ XLV0 NetXL Video Decoder
+ XMPG Xing MPEG (I-Frame only)
+ XVID XviD MPEG-4 (www.xvid.org)
+ XXAN ?XXAN?
+ YU92 Intel YUV (YU92)
+ YUNV Nvidia Uncompressed YUV 4:2:2
+ YUVP Extended PAL format YUV palette (www.riff.org)
+ Y211 YUV 2:1:1 Packed
+ Y411 YUV 4:1:1 Packed
+ Y41B Weitek YUV 4:1:1 Planar
+ Y41P Brooktree PC1 YUV 4:1:1 Packed
+ Y41T Brooktree PC1 YUV 4:1:1 with transparency
+ Y42B Weitek YUV 4:2:2 Planar
+ Y42T Brooktree UYUV 4:2:2 with transparency
+ Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera
+ Y800 Simple, single Y plane for monochrome images
+ Y8 Grayscale video
+ YC12 Intel YUV 12 codec
+ YUV8 Winnov Caviar YUV8
+ YUV9 Intel YUV9
+ YUY2 Uncompressed YUV 4:2:2
+ YUYV Canopus YUV
+ YV12 YVU12 Planar
+ YVU9 Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes)
+ YVYU YVYU 4:2:2 Packed
+ ZLIB Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm)
+ ZPEG Metheus Video Zipper
+
+ */
+
+ return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc');
+ }
+
+ private function EitherEndian2Int($byteword, $signed=false) {
+ if ($this->getid3->info['fileformat'] == 'riff') {
+ return getid3_lib::LittleEndian2Int($byteword, $signed);
+ }
+ return getid3_lib::BigEndian2Int($byteword, false, $signed);
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.audio.ac3.php b/extensions/TimedMediaHandler/libs/getid3/module.audio.ac3.php
new file mode 100644
index 00000000..9834feb5
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.audio.ac3.php
@@ -0,0 +1,473 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.ac3.php //
+// module for analyzing AC-3 (aka Dolby Digital) audio files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_ac3 extends getid3_handler
+{
+ private $AC3header = array();
+ private $BSIoffset = 0;
+
+ const syncword = "\x0B\x77";
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ ///AH
+ $info['ac3']['raw']['bsi'] = array();
+ $thisfile_ac3 = &$info['ac3'];
+ $thisfile_ac3_raw = &$thisfile_ac3['raw'];
+ $thisfile_ac3_raw_bsi = &$thisfile_ac3_raw['bsi'];
+
+
+ // http://www.atsc.org/standards/a_52a.pdf
+
+ $info['fileformat'] = 'ac3';
+
+ // An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames
+ // Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256
+ // new audio samples per channel. A synchronization information (SI) header at the beginning
+ // of each frame contains information needed to acquire and maintain synchronization. A
+ // bit stream information (BSI) header follows SI, and contains parameters describing the coded
+ // audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the
+ // end of each frame is an error check field that includes a CRC word for error detection. An
+ // additional CRC word is located in the SI header, the use of which, by a decoder, is optional.
+ //
+ // syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC
+
+ // syncinfo() {
+ // syncword 16
+ // crc1 16
+ // fscod 2
+ // frmsizecod 6
+ // } /* end of syncinfo */
+
+ $this->fseek($info['avdataoffset']);
+ $this->AC3header['syncinfo'] = $this->fread(5);
+
+ if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) {
+ $thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword;
+ $offset = 2;
+ } else {
+ if (!$this->isDependencyFor('matroska')) {
+ unset($info['fileformat'], $info['ac3']);
+ return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)).'"');
+ }
+ $offset = 0;
+ $this->fseek(-2, SEEK_CUR);
+ }
+
+ $info['audio']['dataformat'] = 'ac3';
+ $info['audio']['bitrate_mode'] = 'cbr';
+ $info['audio']['lossless'] = false;
+
+ $thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2));
+ $ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], ($offset + 2), 1));
+ $thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6;
+ $thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F);
+
+ $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']);
+ if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) {
+ $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate'];
+ }
+
+ $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']);
+ $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']);
+ $info['audio']['bitrate'] = $thisfile_ac3['bitrate'];
+
+ $this->AC3header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(15));
+ $ac3_bsi_offset = 0;
+
+ $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5);
+ if ($thisfile_ac3_raw_bsi['bsid'] > 8) {
+ // Decoders which can decode version 8 will thus be able to decode version numbers less than 8.
+ // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used.
+ // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8.
+ $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8');
+ unset($info['ac3']);
+ return false;
+ }
+
+ $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3);
+ $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3);
+
+ $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']);
+ $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']);
+ foreach($ac3_coding_mode as $key => $value) {
+ $thisfile_ac3[$key] = $value;
+ }
+ switch ($thisfile_ac3_raw_bsi['acmod']) {
+ case 0:
+ case 1:
+ $info['audio']['channelmode'] = 'mono';
+ break;
+ case 3:
+ case 4:
+ $info['audio']['channelmode'] = 'stereo';
+ break;
+ default:
+ $info['audio']['channelmode'] = 'surround';
+ break;
+ }
+ $info['audio']['channels'] = $thisfile_ac3['num_channels'];
+
+ if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) {
+ // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream.
+ $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2);
+ $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']);
+ }
+
+ if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) {
+ // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream.
+ $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2);
+ $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']);
+ }
+
+ if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) {
+ // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround.
+ $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2);
+ $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']);
+ }
+
+ $thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1);
+ $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon'];
+ if ($thisfile_ac3_raw_bsi['lfeon']) {
+ //$info['audio']['channels']++;
+ $info['audio']['channels'] .= '.1';
+ }
+
+ $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']);
+
+ // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
+ // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
+ $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5);
+ $thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB';
+
+ $thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['compre_flag']) {
+ $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8);
+ $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']);
+ }
+
+ $thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['langcode_flag']) {
+ $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8);
+ }
+
+ $thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['audprodie']) {
+ $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5);
+ $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2);
+
+ $thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB';
+ $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']);
+ }
+
+ if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) {
+ // If acmod is 0, then two completely independent program channels (dual mono)
+ // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case,
+ // a number of additional items are present in BSI or audblk to fully describe Ch2.
+
+ // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31.
+ // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent.
+ $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5);
+ $thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB';
+
+ $thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['compre_flag2']) {
+ $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8);
+ $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']);
+ }
+
+ $thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['langcode_flag2']) {
+ $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8);
+ }
+
+ $thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['audprodie2']) {
+ $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5);
+ $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2);
+
+ $thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB';
+ $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']);
+ }
+
+ }
+
+ $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1);
+
+ $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1);
+
+ $thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['timecode1_flag']) {
+ $thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14);
+ }
+
+ $thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['timecode2_flag']) {
+ $thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14);
+ }
+
+ $thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1);
+ if ($thisfile_ac3_raw_bsi['addbsi_flag']) {
+ $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6);
+
+ $this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length']));
+
+ $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8);
+ $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8;
+ }
+
+ return true;
+ }
+
+ private function readHeaderBSI($length) {
+ $data = substr($this->AC3header['bsi'], $this->BSIoffset, $length);
+ $this->BSIoffset += $length;
+
+ return bindec($data);
+ }
+
+ public static function sampleRateCodeLookup($fscod) {
+ static $sampleRateCodeLookup = array(
+ 0 => 48000,
+ 1 => 44100,
+ 2 => 32000,
+ 3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute.
+ );
+ return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false);
+ }
+
+ public static function serviceTypeLookup($bsmod, $acmod) {
+ static $serviceTypeLookup = array();
+ if (empty($serviceTypeLookup)) {
+ for ($i = 0; $i <= 7; $i++) {
+ $serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)';
+ $serviceTypeLookup[1][$i] = 'main audio service: music and effects (ME)';
+ $serviceTypeLookup[2][$i] = 'associated service: visually impaired (VI)';
+ $serviceTypeLookup[3][$i] = 'associated service: hearing impaired (HI)';
+ $serviceTypeLookup[4][$i] = 'associated service: dialogue (D)';
+ $serviceTypeLookup[5][$i] = 'associated service: commentary (C)';
+ $serviceTypeLookup[6][$i] = 'associated service: emergency (E)';
+ }
+
+ $serviceTypeLookup[7][1] = 'associated service: voice over (VO)';
+ for ($i = 2; $i <= 7; $i++) {
+ $serviceTypeLookup[7][$i] = 'main audio service: karaoke';
+ }
+ }
+ return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false);
+ }
+
+ public static function audioCodingModeLookup($acmod) {
+ // array(channel configuration, # channels (not incl LFE), channel order)
+ static $audioCodingModeLookup = array (
+ 0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'),
+ 1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'),
+ 2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'),
+ 3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'),
+ 4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'),
+ 5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'),
+ 6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'),
+ 7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR'),
+ );
+ return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false);
+ }
+
+ public static function centerMixLevelLookup($cmixlev) {
+ static $centerMixLevelLookup;
+ if (empty($centerMixLevelLookup)) {
+ $centerMixLevelLookup = array(
+ 0 => pow(2, -3.0 / 6), // 0.707 (-3.0 dB)
+ 1 => pow(2, -4.5 / 6), // 0.595 (-4.5 dB)
+ 2 => pow(2, -6.0 / 6), // 0.500 (-6.0 dB)
+ 3 => 'reserved'
+ );
+ }
+ return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false);
+ }
+
+ public static function surroundMixLevelLookup($surmixlev) {
+ static $surroundMixLevelLookup;
+ if (empty($surroundMixLevelLookup)) {
+ $surroundMixLevelLookup = array(
+ 0 => pow(2, -3.0 / 6),
+ 1 => pow(2, -6.0 / 6),
+ 2 => 0,
+ 3 => 'reserved'
+ );
+ }
+ return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false);
+ }
+
+ public static function dolbySurroundModeLookup($dsurmod) {
+ static $dolbySurroundModeLookup = array(
+ 0 => 'not indicated',
+ 1 => 'Not Dolby Surround encoded',
+ 2 => 'Dolby Surround encoded',
+ 3 => 'reserved'
+ );
+ return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false);
+ }
+
+ public static function channelsEnabledLookup($acmod, $lfeon) {
+ $lookup = array(
+ 'ch1'=>(bool) ($acmod == 0),
+ 'ch2'=>(bool) ($acmod == 0),
+ 'left'=>(bool) ($acmod > 1),
+ 'right'=>(bool) ($acmod > 1),
+ 'center'=>(bool) ($acmod & 0x01),
+ 'surround_mono'=>false,
+ 'surround_left'=>false,
+ 'surround_right'=>false,
+ 'lfe'=>$lfeon);
+ switch ($acmod) {
+ case 4:
+ case 5:
+ $lookup['surround_mono'] = true;
+ break;
+ case 6:
+ case 7:
+ $lookup['surround_left'] = true;
+ $lookup['surround_right'] = true;
+ break;
+ }
+ return $lookup;
+ }
+
+ public static function heavyCompression($compre) {
+ // The first four bits indicate gain changes in 6.02dB increments which can be
+ // implemented with an arithmetic shift operation. The following four bits
+ // indicate linear gain changes, and require a 5-bit multiply.
+ // We will represent the two 4-bit fields of compr as follows:
+ // X0 X1 X2 X3 . Y4 Y5 Y6 Y7
+ // The meaning of the X values is most simply described by considering X to represent a 4-bit
+ // signed integer with values from -8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The
+ // following table shows this in detail.
+
+ // Meaning of 4 msb of compr
+ // 7 +48.16 dB
+ // 6 +42.14 dB
+ // 5 +36.12 dB
+ // 4 +30.10 dB
+ // 3 +24.08 dB
+ // 2 +18.06 dB
+ // 1 +12.04 dB
+ // 0 +6.02 dB
+ // -1 0 dB
+ // -2 -6.02 dB
+ // -3 -12.04 dB
+ // -4 -18.06 dB
+ // -5 -24.08 dB
+ // -6 -30.10 dB
+ // -7 -36.12 dB
+ // -8 -42.14 dB
+
+ $fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT);
+ if ($fourbit{0} == '1') {
+ $log_gain = -8 + bindec(substr($fourbit, 1));
+ } else {
+ $log_gain = bindec(substr($fourbit, 1));
+ }
+ $log_gain = ($log_gain + 1) * getid3_lib::RGADamplitude2dB(2);
+
+ // The value of Y is a linear representation of a gain change of up to -6 dB. Y is considered to
+ // be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can
+ // represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain
+ // changes from -0.28 dB to -6.02 dB.
+
+ $lin_gain = (16 + ($compre & 0x0F)) / 32;
+
+ // The combination of X and Y values allows compr to indicate gain changes from
+ // 48.16 - 0.28 = +47.89 dB, to
+ // -42.14 - 6.02 = -48.16 dB.
+
+ return $log_gain - $lin_gain;
+ }
+
+ public static function roomTypeLookup($roomtyp) {
+ static $roomTypeLookup = array(
+ 0 => 'not indicated',
+ 1 => 'large room, X curve monitor',
+ 2 => 'small room, flat monitor',
+ 3 => 'reserved'
+ );
+ return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false);
+ }
+
+ public static function frameSizeLookup($frmsizecod, $fscod) {
+ $padding = (bool) ($frmsizecod % 2);
+ $framesizeid = floor($frmsizecod / 2);
+
+ static $frameSizeLookup = array();
+ if (empty($frameSizeLookup)) {
+ $frameSizeLookup = array (
+ 0 => array(128, 138, 192),
+ 1 => array(40, 160, 174, 240),
+ 2 => array(48, 192, 208, 288),
+ 3 => array(56, 224, 242, 336),
+ 4 => array(64, 256, 278, 384),
+ 5 => array(80, 320, 348, 480),
+ 6 => array(96, 384, 416, 576),
+ 7 => array(112, 448, 486, 672),
+ 8 => array(128, 512, 556, 768),
+ 9 => array(160, 640, 696, 960),
+ 10 => array(192, 768, 834, 1152),
+ 11 => array(224, 896, 974, 1344),
+ 12 => array(256, 1024, 1114, 1536),
+ 13 => array(320, 1280, 1392, 1920),
+ 14 => array(384, 1536, 1670, 2304),
+ 15 => array(448, 1792, 1950, 2688),
+ 16 => array(512, 2048, 2228, 3072),
+ 17 => array(576, 2304, 2506, 3456),
+ 18 => array(640, 2560, 2786, 3840)
+ );
+ }
+ if (($fscod == 1) && $padding) {
+ // frame lengths are padded by 1 word (16 bits) at 44100
+ $frameSizeLookup[$frmsizecod] += 2;
+ }
+ return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false);
+ }
+
+ public static function bitrateLookup($frmsizecod) {
+ $framesizeid = floor($frmsizecod / 2);
+
+ static $bitrateLookup = array(
+ 0 => 32000,
+ 1 => 40000,
+ 2 => 48000,
+ 3 => 56000,
+ 4 => 64000,
+ 5 => 80000,
+ 6 => 96000,
+ 7 => 112000,
+ 8 => 128000,
+ 9 => 160000,
+ 10 => 192000,
+ 11 => 224000,
+ 12 => 256000,
+ 13 => 320000,
+ 14 => 384000,
+ 15 => 448000,
+ 16 => 512000,
+ 17 => 576000,
+ 18 => 640000
+ );
+ return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false);
+ }
+
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.audio.dts.php b/extensions/TimedMediaHandler/libs/getid3/module.audio.dts.php
new file mode 100644
index 00000000..1c6b36f9
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.audio.dts.php
@@ -0,0 +1,291 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.dts.php //
+// module for analyzing DTS Audio files //
+// dependencies: NONE //
+// //
+/////////////////////////////////////////////////////////////////
+
+
+/**
+* @tutorial http://wiki.multimedia.cx/index.php?title=DTS
+*/
+
+class getid3_dts extends getid3_handler
+{
+ /**
+ * Default DTS syncword used in native .cpt or .dts formats
+ */
+ const syncword = "\x7F\xFE\x80\x01";
+
+ private $readBinDataOffset = 0;
+
+ /**
+ * Possible syncwords indicating bitstream encoding
+ */
+ public static $syncwords = array(
+ 0 => "\x7F\xFE\x80\x01", // raw big-endian
+ 1 => "\xFE\x7F\x01\x80", // raw little-endian
+ 2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian
+ 3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+ $info['fileformat'] = 'dts';
+
+ $this->fseek($info['avdataoffset']);
+ $DTSheader = $this->fread(20); // we only need 2 words magic + 6 words frame header, but these words may be normal 16-bit words OR 14-bit words with 2 highest bits set to zero, so 8 words can be either 8*16/8 = 16 bytes OR 8*16*(16/14)/8 = 18.3 bytes
+
+ // check syncword
+ $sync = substr($DTSheader, 0, 4);
+ if (($encoding = array_search($sync, self::$syncwords)) !== false) {
+
+ $info['dts']['raw']['magic'] = $sync;
+ $this->readBinDataOffset = 32;
+
+ } elseif ($this->isDependencyFor('matroska')) {
+
+ // Matroska contains DTS without syncword encoded as raw big-endian format
+ $encoding = 0;
+ $this->readBinDataOffset = 0;
+
+ } else {
+
+ unset($info['fileformat']);
+ return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"');
+
+ }
+
+ // decode header
+ $fhBS = '';
+ for ($word_offset = 0; $word_offset <= strlen($DTSheader); $word_offset += 2) {
+ switch ($encoding) {
+ case 0: // raw big-endian
+ $fhBS .= getid3_lib::BigEndian2Bin( substr($DTSheader, $word_offset, 2) );
+ break;
+ case 1: // raw little-endian
+ $fhBS .= getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2)));
+ break;
+ case 2: // 14-bit big-endian
+ $fhBS .= substr(getid3_lib::BigEndian2Bin( substr($DTSheader, $word_offset, 2) ), 2, 14);
+ break;
+ case 3: // 14-bit little-endian
+ $fhBS .= substr(getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2))), 2, 14);
+ break;
+ }
+ }
+
+ $info['dts']['raw']['frame_type'] = $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['deficit_samples'] = $this->readBinData($fhBS, 5);
+ $info['dts']['flags']['crc_present'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['pcm_sample_blocks'] = $this->readBinData($fhBS, 7);
+ $info['dts']['raw']['frame_byte_size'] = $this->readBinData($fhBS, 14);
+ $info['dts']['raw']['channel_arrangement'] = $this->readBinData($fhBS, 6);
+ $info['dts']['raw']['sample_frequency'] = $this->readBinData($fhBS, 4);
+ $info['dts']['raw']['bitrate'] = $this->readBinData($fhBS, 5);
+ $info['dts']['flags']['embedded_downmix'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['dynamicrange'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['timestamp'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['auxdata'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['hdcd'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['extension_audio'] = $this->readBinData($fhBS, 3);
+ $info['dts']['flags']['extended_coding'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['audio_sync_insertion'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['lfe_effects'] = $this->readBinData($fhBS, 2);
+ $info['dts']['flags']['predictor_history'] = (bool) $this->readBinData($fhBS, 1);
+ if ($info['dts']['flags']['crc_present']) {
+ $info['dts']['raw']['crc16'] = $this->readBinData($fhBS, 16);
+ }
+ $info['dts']['flags']['mri_perfect_reconst'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['encoder_soft_version'] = $this->readBinData($fhBS, 4);
+ $info['dts']['raw']['copy_history'] = $this->readBinData($fhBS, 2);
+ $info['dts']['raw']['bits_per_sample'] = $this->readBinData($fhBS, 2);
+ $info['dts']['flags']['surround_es'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['front_sum_diff'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['flags']['surround_sum_diff'] = (bool) $this->readBinData($fhBS, 1);
+ $info['dts']['raw']['dialog_normalization'] = $this->readBinData($fhBS, 4);
+
+
+ $info['dts']['bitrate'] = self::bitrateLookup($info['dts']['raw']['bitrate']);
+ $info['dts']['bits_per_sample'] = self::bitPerSampleLookup($info['dts']['raw']['bits_per_sample']);
+ $info['dts']['sample_rate'] = self::sampleRateLookup($info['dts']['raw']['sample_frequency']);
+ $info['dts']['dialog_normalization'] = self::dialogNormalization($info['dts']['raw']['dialog_normalization'], $info['dts']['raw']['encoder_soft_version']);
+ $info['dts']['flags']['lossless'] = (($info['dts']['raw']['bitrate'] == 31) ? true : false);
+ $info['dts']['bitrate_mode'] = (($info['dts']['raw']['bitrate'] == 30) ? 'vbr' : 'cbr');
+ $info['dts']['channels'] = self::numChannelsLookup($info['dts']['raw']['channel_arrangement']);
+ $info['dts']['channel_arrangement'] = self::channelArrangementLookup($info['dts']['raw']['channel_arrangement']);
+
+ $info['audio']['dataformat'] = 'dts';
+ $info['audio']['lossless'] = $info['dts']['flags']['lossless'];
+ $info['audio']['bitrate_mode'] = $info['dts']['bitrate_mode'];
+ $info['audio']['bits_per_sample'] = $info['dts']['bits_per_sample'];
+ $info['audio']['sample_rate'] = $info['dts']['sample_rate'];
+ $info['audio']['channels'] = $info['dts']['channels'];
+ $info['audio']['bitrate'] = $info['dts']['bitrate'];
+ if (isset($info['avdataend']) && !empty($info['dts']['bitrate']) && is_numeric($info['dts']['bitrate'])) {
+ $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($info['dts']['bitrate'] / 8);
+ if (($encoding == 2) || ($encoding == 3)) {
+ // 14-bit data packed into 16-bit words, so the playtime is wrong because only (14/16) of the bytes in the data portion of the file are used at the specified bitrate
+ $info['playtime_seconds'] *= (14 / 16);
+ }
+ }
+ return true;
+ }
+
+ private function readBinData($bin, $length) {
+ $data = substr($bin, $this->readBinDataOffset, $length);
+ $this->readBinDataOffset += $length;
+
+ return bindec($data);
+ }
+
+ public static function bitrateLookup($index) {
+ static $lookup = array(
+ 0 => 32000,
+ 1 => 56000,
+ 2 => 64000,
+ 3 => 96000,
+ 4 => 112000,
+ 5 => 128000,
+ 6 => 192000,
+ 7 => 224000,
+ 8 => 256000,
+ 9 => 320000,
+ 10 => 384000,
+ 11 => 448000,
+ 12 => 512000,
+ 13 => 576000,
+ 14 => 640000,
+ 15 => 768000,
+ 16 => 960000,
+ 17 => 1024000,
+ 18 => 1152000,
+ 19 => 1280000,
+ 20 => 1344000,
+ 21 => 1408000,
+ 22 => 1411200,
+ 23 => 1472000,
+ 24 => 1536000,
+ 25 => 1920000,
+ 26 => 2048000,
+ 27 => 3072000,
+ 28 => 3840000,
+ 29 => 'open',
+ 30 => 'variable',
+ 31 => 'lossless',
+ );
+ return (isset($lookup[$index]) ? $lookup[$index] : false);
+ }
+
+ public static function sampleRateLookup($index) {
+ static $lookup = array(
+ 0 => 'invalid',
+ 1 => 8000,
+ 2 => 16000,
+ 3 => 32000,
+ 4 => 'invalid',
+ 5 => 'invalid',
+ 6 => 11025,
+ 7 => 22050,
+ 8 => 44100,
+ 9 => 'invalid',
+ 10 => 'invalid',
+ 11 => 12000,
+ 12 => 24000,
+ 13 => 48000,
+ 14 => 'invalid',
+ 15 => 'invalid',
+ );
+ return (isset($lookup[$index]) ? $lookup[$index] : false);
+ }
+
+ public static function bitPerSampleLookup($index) {
+ static $lookup = array(
+ 0 => 16,
+ 1 => 20,
+ 2 => 24,
+ 3 => 24,
+ );
+ return (isset($lookup[$index]) ? $lookup[$index] : false);
+ }
+
+ public static function numChannelsLookup($index) {
+ switch ($index) {
+ case 0:
+ return 1;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return 2;
+ break;
+ case 5:
+ case 6:
+ return 3;
+ break;
+ case 7:
+ case 8:
+ return 4;
+ break;
+ case 9:
+ return 5;
+ break;
+ case 10:
+ case 11:
+ case 12:
+ return 6;
+ break;
+ case 13:
+ return 7;
+ break;
+ case 14:
+ case 15:
+ return 8;
+ break;
+ }
+ return false;
+ }
+
+ public static function channelArrangementLookup($index) {
+ static $lookup = array(
+ 0 => 'A',
+ 1 => 'A + B (dual mono)',
+ 2 => 'L + R (stereo)',
+ 3 => '(L+R) + (L-R) (sum-difference)',
+ 4 => 'LT + RT (left and right total)',
+ 5 => 'C + L + R',
+ 6 => 'L + R + S',
+ 7 => 'C + L + R + S',
+ 8 => 'L + R + SL + SR',
+ 9 => 'C + L + R + SL + SR',
+ 10 => 'CL + CR + L + R + SL + SR',
+ 11 => 'C + L + R+ LR + RR + OV',
+ 12 => 'CF + CR + LF + RF + LR + RR',
+ 13 => 'CL + C + CR + L + R + SL + SR',
+ 14 => 'CL + CR + L + R + SL1 + SL2 + SR1 + SR2',
+ 15 => 'CL + C+ CR + L + R + SL + S + SR',
+ );
+ return (isset($lookup[$index]) ? $lookup[$index] : 'user-defined');
+ }
+
+ public static function dialogNormalization($index, $version) {
+ switch ($version) {
+ case 7:
+ return 0 - $index;
+ break;
+ case 6:
+ return 0 - 16 - $index;
+ break;
+ }
+ return false;
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.audio.flac.php b/extensions/TimedMediaHandler/libs/getid3/module.audio.flac.php
new file mode 100644
index 00000000..6b9598c7
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.audio.flac.php
@@ -0,0 +1,442 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.flac.php //
+// module for analyzing FLAC and OggFLAC audio files //
+// dependencies: module.audio.ogg.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true);
+
+/**
+* @tutorial http://flac.sourceforge.net/format.html
+*/
+class getid3_flac extends getid3_handler
+{
+ const syncword = 'fLaC';
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $this->fseek($info['avdataoffset']);
+ $StreamMarker = $this->fread(4);
+ if ($StreamMarker != self::syncword) {
+ return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($StreamMarker).'"');
+ }
+ $info['fileformat'] = 'flac';
+ $info['audio']['dataformat'] = 'flac';
+ $info['audio']['bitrate_mode'] = 'vbr';
+ $info['audio']['lossless'] = true;
+
+ // parse flac container
+ return $this->parseMETAdata();
+ }
+
+ public function parseMETAdata() {
+ $info = &$this->getid3->info;
+ do {
+ $BlockOffset = $this->ftell();
+ $BlockHeader = $this->fread(4);
+ $LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1));
+ $LastBlockFlag = (bool) ($LBFBT & 0x80);
+ $BlockType = ($LBFBT & 0x7F);
+ $BlockLength = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3));
+ $BlockTypeText = self::metaBlockTypeLookup($BlockType);
+
+ if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) {
+ $this->error('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file');
+ break;
+ }
+ if ($BlockLength < 1) {
+ $this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid');
+ break;
+ }
+
+ $info['flac'][$BlockTypeText]['raw'] = array();
+ $BlockTypeText_raw = &$info['flac'][$BlockTypeText]['raw'];
+
+ $BlockTypeText_raw['offset'] = $BlockOffset;
+ $BlockTypeText_raw['last_meta_block'] = $LastBlockFlag;
+ $BlockTypeText_raw['block_type'] = $BlockType;
+ $BlockTypeText_raw['block_type_text'] = $BlockTypeText;
+ $BlockTypeText_raw['block_length'] = $BlockLength;
+ if ($BlockTypeText_raw['block_type'] != 0x06) { // do not read attachment data automatically
+ $BlockTypeText_raw['block_data'] = $this->fread($BlockLength);
+ }
+
+ switch ($BlockTypeText) {
+ case 'STREAMINFO': // 0x00
+ if (!$this->parseSTREAMINFO($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'PADDING': // 0x01
+ unset($info['flac']['PADDING']); // ignore
+ break;
+
+ case 'APPLICATION': // 0x02
+ if (!$this->parseAPPLICATION($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'SEEKTABLE': // 0x03
+ if (!$this->parseSEEKTABLE($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'VORBIS_COMMENT': // 0x04
+ if (!$this->parseVORBIS_COMMENT($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'CUESHEET': // 0x05
+ if (!$this->parseCUESHEET($BlockTypeText_raw['block_data'])) {
+ return false;
+ }
+ break;
+
+ case 'PICTURE': // 0x06
+ if (!$this->parsePICTURE()) {
+ return false;
+ }
+ break;
+
+ default:
+ $this->warning('Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockType.') at offset '.$BlockOffset);
+ }
+
+ unset($info['flac'][$BlockTypeText]['raw']);
+ $info['avdataoffset'] = $this->ftell();
+ }
+ while ($LastBlockFlag === false);
+
+ // handle tags
+ if (!empty($info['flac']['VORBIS_COMMENT']['comments'])) {
+ $info['flac']['comments'] = $info['flac']['VORBIS_COMMENT']['comments'];
+ }
+ if (!empty($info['flac']['VORBIS_COMMENT']['vendor'])) {
+ $info['audio']['encoder'] = str_replace('reference ', '', $info['flac']['VORBIS_COMMENT']['vendor']);
+ }
+
+ // copy attachments to 'comments' array if nesesary
+ if (isset($info['flac']['PICTURE']) && ($this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE)) {
+ foreach ($info['flac']['PICTURE'] as $entry) {
+ if (!empty($entry['data'])) {
+ $info['flac']['comments']['picture'][] = array('image_mime'=>$entry['image_mime'], 'data'=>$entry['data']);
+ }
+ }
+ }
+
+ if (isset($info['flac']['STREAMINFO'])) {
+ if (!$this->isDependencyFor('matroska')) {
+ $info['flac']['compressed_audio_bytes'] = $info['avdataend'] - $info['avdataoffset'];
+ }
+ $info['flac']['uncompressed_audio_bytes'] = $info['flac']['STREAMINFO']['samples_stream'] * $info['flac']['STREAMINFO']['channels'] * ($info['flac']['STREAMINFO']['bits_per_sample'] / 8);
+ if ($info['flac']['uncompressed_audio_bytes'] == 0) {
+ return $this->error('Corrupt FLAC file: uncompressed_audio_bytes == zero');
+ }
+ if (!empty($info['flac']['compressed_audio_bytes'])) {
+ $info['flac']['compression_ratio'] = $info['flac']['compressed_audio_bytes'] / $info['flac']['uncompressed_audio_bytes'];
+ }
+ }
+
+ // set md5_data_source - built into flac 0.5+
+ if (isset($info['flac']['STREAMINFO']['audio_signature'])) {
+
+ if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) {
+ $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)');
+ }
+ else {
+ $info['md5_data_source'] = '';
+ $md5 = $info['flac']['STREAMINFO']['audio_signature'];
+ for ($i = 0; $i < strlen($md5); $i++) {
+ $info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT);
+ }
+ if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) {
+ unset($info['md5_data_source']);
+ }
+ }
+ }
+
+ if (isset($info['flac']['STREAMINFO']['bits_per_sample'])) {
+ $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample'];
+ if ($info['audio']['bits_per_sample'] == 8) {
+ // special case
+ // must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value
+ // MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed
+ $this->warning('FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file');
+ }
+ }
+
+ return true;
+ }
+
+ private function parseSTREAMINFO($BlockData) {
+ $info = &$this->getid3->info;
+
+ $info['flac']['STREAMINFO'] = array();
+ $streaminfo = &$info['flac']['STREAMINFO'];
+
+ $streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2));
+ $streaminfo['max_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2));
+ $streaminfo['min_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3));
+ $streaminfo['max_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 7, 3));
+
+ $SRCSBSS = getid3_lib::BigEndian2Bin(substr($BlockData, 10, 8));
+ $streaminfo['sample_rate'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 0, 20));
+ $streaminfo['channels'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 20, 3)) + 1;
+ $streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23, 5)) + 1;
+ $streaminfo['samples_stream'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36));
+
+ $streaminfo['audio_signature'] = substr($BlockData, 18, 16);
+
+ if (!empty($streaminfo['sample_rate'])) {
+
+ $info['audio']['bitrate_mode'] = 'vbr';
+ $info['audio']['sample_rate'] = $streaminfo['sample_rate'];
+ $info['audio']['channels'] = $streaminfo['channels'];
+ $info['audio']['bits_per_sample'] = $streaminfo['bits_per_sample'];
+ $info['playtime_seconds'] = $streaminfo['samples_stream'] / $streaminfo['sample_rate'];
+ if ($info['playtime_seconds'] > 0) {
+ if (!$this->isDependencyFor('matroska')) {
+ $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds'];
+ }
+ else {
+ $this->warning('Cannot determine audio bitrate because total stream size is unknown');
+ }
+ }
+
+ } else {
+ return $this->error('Corrupt METAdata block: STREAMINFO');
+ }
+
+ return true;
+ }
+
+ private function parseAPPLICATION($BlockData) {
+ $info = &$this->getid3->info;
+
+ $ApplicationID = getid3_lib::BigEndian2Int(substr($BlockData, 0, 4));
+ $info['flac']['APPLICATION'][$ApplicationID]['name'] = self::applicationIDLookup($ApplicationID);
+ $info['flac']['APPLICATION'][$ApplicationID]['data'] = substr($BlockData, 4);
+
+ return true;
+ }
+
+ private function parseSEEKTABLE($BlockData) {
+ $info = &$this->getid3->info;
+
+ $offset = 0;
+ $BlockLength = strlen($BlockData);
+ $placeholderpattern = str_repeat("\xFF", 8);
+ while ($offset < $BlockLength) {
+ $SampleNumberString = substr($BlockData, $offset, 8);
+ $offset += 8;
+ if ($SampleNumberString == $placeholderpattern) {
+
+ // placeholder point
+ getid3_lib::safe_inc($info['flac']['SEEKTABLE']['placeholders'], 1);
+ $offset += 10;
+
+ } else {
+
+ $SampleNumber = getid3_lib::BigEndian2Int($SampleNumberString);
+ $info['flac']['SEEKTABLE'][$SampleNumber]['offset'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
+ $offset += 8;
+ $info['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 2));
+ $offset += 2;
+
+ }
+ }
+
+ return true;
+ }
+
+ private function parseVORBIS_COMMENT($BlockData) {
+ $info = &$this->getid3->info;
+
+ $getid3_ogg = new getid3_ogg($this->getid3);
+ if ($this->isDependencyFor('matroska')) {
+ $getid3_ogg->setStringMode($this->data_string);
+ }
+ $getid3_ogg->ParseVorbisComments();
+ if (isset($info['ogg'])) {
+ unset($info['ogg']['comments_raw']);
+ $info['flac']['VORBIS_COMMENT'] = $info['ogg'];
+ unset($info['ogg']);
+ }
+
+ unset($getid3_ogg);
+
+ return true;
+ }
+
+ private function parseCUESHEET($BlockData) {
+ $info = &$this->getid3->info;
+ $offset = 0;
+ $info['flac']['CUESHEET']['media_catalog_number'] = trim(substr($BlockData, $offset, 128), "\0");
+ $offset += 128;
+ $info['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
+ $offset += 8;
+ $info['flac']['CUESHEET']['flags']['is_cd'] = (bool) (getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)) & 0x80);
+ $offset += 1;
+
+ $offset += 258; // reserved
+
+ $info['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+
+ for ($track = 0; $track < $info['flac']['CUESHEET']['number_tracks']; $track++) {
+ $TrackSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
+ $offset += 8;
+ $TrackNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['sample_offset'] = $TrackSampleOffset;
+
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['isrc'] = substr($BlockData, $offset, 12);
+ $offset += 12;
+
+ $TrackFlagsRaw = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['is_audio'] = (bool) ($TrackFlagsRaw & 0x80);
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40);
+
+ $offset += 13; // reserved
+
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+
+ for ($index = 0; $index < $info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points']; $index++) {
+ $IndexSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8));
+ $offset += 8;
+ $IndexNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1));
+ $offset += 1;
+
+ $offset += 3; // reserved
+
+ $info['flac']['CUESHEET']['tracks'][$TrackNumber]['indexes'][$IndexNumber] = $IndexSampleOffset;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Parse METADATA_BLOCK_PICTURE flac structure and extract attachment
+ * External usage: audio.ogg
+ */
+ public function parsePICTURE() {
+ $info = &$this->getid3->info;
+
+ $picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $picture['type'] = self::pictureTypeLookup($picture['typeid']);
+ $picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4)));
+ $descr_length = getid3_lib::BigEndian2Int($this->fread(4));
+ if ($descr_length) {
+ $picture['description'] = $this->fread($descr_length);
+ }
+ $picture['width'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $picture['height'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $picture['color_depth'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $picture['colors_indexed'] = getid3_lib::BigEndian2Int($this->fread(4));
+ $data_length = getid3_lib::BigEndian2Int($this->fread(4));
+
+ if ($picture['image_mime'] == '-->') {
+ $picture['data'] = $this->fread($data_length);
+ } else {
+ $picture['data'] = $this->saveAttachment(
+ str_replace('/', '_', $picture['type']).'_'.$this->ftell(),
+ $this->ftell(),
+ $data_length,
+ $picture['image_mime']);
+ }
+
+ $info['flac']['PICTURE'][] = $picture;
+
+ return true;
+ }
+
+ public static function metaBlockTypeLookup($blocktype) {
+ static $lookup = array(
+ 0 => 'STREAMINFO',
+ 1 => 'PADDING',
+ 2 => 'APPLICATION',
+ 3 => 'SEEKTABLE',
+ 4 => 'VORBIS_COMMENT',
+ 5 => 'CUESHEET',
+ 6 => 'PICTURE',
+ );
+ return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved');
+ }
+
+ public static function applicationIDLookup($applicationid) {
+ // http://flac.sourceforge.net/id.html
+ static $lookup = array(
+ 0x41544348 => 'FlacFile', // "ATCH"
+ 0x42534F4C => 'beSolo', // "BSOL"
+ 0x42554753 => 'Bugs Player', // "BUGS"
+ 0x43756573 => 'GoldWave cue points (specification)', // "Cues"
+ 0x46696361 => 'CUE Splitter', // "Fica"
+ 0x46746F6C => 'flac-tools', // "Ftol"
+ 0x4D4F5442 => 'MOTB MetaCzar', // "MOTB"
+ 0x4D505345 => 'MP3 Stream Editor', // "MPSE"
+ 0x4D754D4C => 'MusicML: Music Metadata Language', // "MuML"
+ 0x52494646 => 'Sound Devices RIFF chunk storage', // "RIFF"
+ 0x5346464C => 'Sound Font FLAC', // "SFFL"
+ 0x534F4E59 => 'Sony Creative Software', // "SONY"
+ 0x5351455A => 'flacsqueeze', // "SQEZ"
+ 0x54745776 => 'TwistedWave', // "TtWv"
+ 0x55495453 => 'UITS Embedding tools', // "UITS"
+ 0x61696666 => 'FLAC AIFF chunk storage', // "aiff"
+ 0x696D6167 => 'flac-image application for storing arbitrary files in APPLICATION metadata blocks', // "imag"
+ 0x7065656D => 'Parseable Embedded Extensible Metadata (specification)', // "peem"
+ 0x71667374 => 'QFLAC Studio', // "qfst"
+ 0x72696666 => 'FLAC RIFF chunk storage', // "riff"
+ 0x74756E65 => 'TagTuner', // "tune"
+ 0x78626174 => 'XBAT', // "xbat"
+ 0x786D6364 => 'xmcd', // "xmcd"
+ );
+ return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved');
+ }
+
+ public static function pictureTypeLookup($type_id) {
+ static $lookup = array (
+ 0 => 'Other',
+ 1 => '32x32 pixels \'file icon\' (PNG only)',
+ 2 => 'Other file icon',
+ 3 => 'Cover (front)',
+ 4 => 'Cover (back)',
+ 5 => 'Leaflet page',
+ 6 => 'Media (e.g. label side of CD)',
+ 7 => 'Lead artist/lead performer/soloist',
+ 8 => 'Artist/performer',
+ 9 => 'Conductor',
+ 10 => 'Band/Orchestra',
+ 11 => 'Composer',
+ 12 => 'Lyricist/text writer',
+ 13 => 'Recording Location',
+ 14 => 'During recording',
+ 15 => 'During performance',
+ 16 => 'Movie/video screen capture',
+ 17 => 'A bright coloured fish',
+ 18 => 'Illustration',
+ 19 => 'Band/artist logotype',
+ 20 => 'Publisher/Studio logotype',
+ );
+ return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved');
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.audio.mp3.php b/extensions/TimedMediaHandler/libs/getid3/module.audio.mp3.php
new file mode 100644
index 00000000..e6ffea94
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.audio.mp3.php
@@ -0,0 +1,2009 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.mp3.php //
+// module for analyzing MP3 files //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+// number of frames to scan to determine if MPEG-audio sequence is valid
+// Lower this number to 5-20 for faster scanning
+// Increase this number to 50+ for most accurate detection of valid VBR/CBR
+// mpeg-audio streams
+define('GETID3_MP3_VALID_CHECK_FRAMES', 35);
+
+
+class getid3_mp3 extends getid3_handler
+{
+
+ public $allow_bruteforce = false; // forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, unrecommended, but may provide data from otherwise-unusuable files
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $initialOffset = $info['avdataoffset'];
+
+ if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) {
+ if ($this->allow_bruteforce) {
+ $info['error'][] = 'Rescanning file in BruteForce mode';
+ $this->getOnlyMPEGaudioInfoBruteForce($this->getid3->fp, $info);
+ }
+ }
+
+
+ if (isset($info['mpeg']['audio']['bitrate_mode'])) {
+ $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']);
+ }
+
+ if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) {
+
+ $synchoffsetwarning = 'Unknown data before synch ';
+ if (isset($info['id3v2']['headerlength'])) {
+ $synchoffsetwarning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, ';
+ } elseif ($initialOffset > 0) {
+ $synchoffsetwarning .= '(should be at '.$initialOffset.', ';
+ } else {
+ $synchoffsetwarning .= '(should be at beginning of file, ';
+ }
+ $synchoffsetwarning .= 'synch detected at '.$info['avdataoffset'].')';
+ if (isset($info['audio']['bitrate_mode']) && ($info['audio']['bitrate_mode'] == 'cbr')) {
+
+ if (!empty($info['id3v2']['headerlength']) && (($info['avdataoffset'] - $info['id3v2']['headerlength']) == $info['mpeg']['audio']['framelength'])) {
+
+ $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90-3.92) DLL in CBR mode.';
+ $info['audio']['codec'] = 'LAME';
+ $CurrentDataLAMEversionString = 'LAME3.';
+
+ } elseif (empty($info['id3v2']['headerlength']) && ($info['avdataoffset'] == $info['mpeg']['audio']['framelength'])) {
+
+ $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90 - 3.92) DLL in CBR mode.';
+ $info['audio']['codec'] = 'LAME';
+ $CurrentDataLAMEversionString = 'LAME3.';
+
+ }
+
+ }
+ $info['warning'][] = $synchoffsetwarning;
+
+ }
+
+ if (isset($info['mpeg']['audio']['LAME'])) {
+ $info['audio']['codec'] = 'LAME';
+ if (!empty($info['mpeg']['audio']['LAME']['long_version'])) {
+ $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['long_version'], "\x00");
+ } elseif (!empty($info['mpeg']['audio']['LAME']['short_version'])) {
+ $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['short_version'], "\x00");
+ }
+ }
+
+ $CurrentDataLAMEversionString = (!empty($CurrentDataLAMEversionString) ? $CurrentDataLAMEversionString : (isset($info['audio']['encoder']) ? $info['audio']['encoder'] : ''));
+ if (!empty($CurrentDataLAMEversionString) && (substr($CurrentDataLAMEversionString, 0, 6) == 'LAME3.') && !preg_match('[0-9\)]', substr($CurrentDataLAMEversionString, -1))) {
+ // a version number of LAME that does not end with a number like "LAME3.92"
+ // or with a closing parenthesis like "LAME3.88 (alpha)"
+ // or a version of LAME with the LAMEtag-not-filled-in-DLL-mode bug (3.90-3.92)
+
+ // not sure what the actual last frame length will be, but will be less than or equal to 1441
+ $PossiblyLongerLAMEversion_FrameLength = 1441;
+
+ // Not sure what version of LAME this is - look in padding of last frame for longer version string
+ $PossibleLAMEversionStringOffset = $info['avdataend'] - $PossiblyLongerLAMEversion_FrameLength;
+ fseek($this->getid3->fp, $PossibleLAMEversionStringOffset);
+ $PossiblyLongerLAMEversion_Data = fread($this->getid3->fp, $PossiblyLongerLAMEversion_FrameLength);
+ switch (substr($CurrentDataLAMEversionString, -1)) {
+ case 'a':
+ case 'b':
+ // "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example
+ // need to trim off "a" to match longer string
+ $CurrentDataLAMEversionString = substr($CurrentDataLAMEversionString, 0, -1);
+ break;
+ }
+ if (($PossiblyLongerLAMEversion_String = strstr($PossiblyLongerLAMEversion_Data, $CurrentDataLAMEversionString)) !== false) {
+ if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) {
+ $PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)"
+ if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) {
+ $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString;
+ }
+ }
+ }
+ }
+ if (!empty($info['audio']['encoder'])) {
+ $info['audio']['encoder'] = rtrim($info['audio']['encoder'], "\x00 ");
+ }
+
+ switch (isset($info['mpeg']['audio']['layer']) ? $info['mpeg']['audio']['layer'] : '') {
+ case 1:
+ case 2:
+ $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer'];
+ break;
+ }
+ if (isset($info['fileformat']) && ($info['fileformat'] == 'mp3')) {
+ switch ($info['audio']['dataformat']) {
+ case 'mp1':
+ case 'mp2':
+ case 'mp3':
+ $info['fileformat'] = $info['audio']['dataformat'];
+ break;
+
+ default:
+ $info['warning'][] = 'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"';
+ break;
+ }
+ }
+
+ if (empty($info['fileformat'])) {
+ unset($info['fileformat']);
+ unset($info['audio']['bitrate_mode']);
+ unset($info['avdataoffset']);
+ unset($info['avdataend']);
+ return false;
+ }
+
+ $info['mime_type'] = 'audio/mpeg';
+ $info['audio']['lossless'] = false;
+
+ // Calculate playtime
+ if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) {
+ $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate'];
+ }
+
+ $info['audio']['encoder_options'] = $this->GuessEncoderOptions();
+
+ return true;
+ }
+
+
+ public function GuessEncoderOptions() {
+ // shortcuts
+ $info = &$this->getid3->info;
+ if (!empty($info['mpeg']['audio'])) {
+ $thisfile_mpeg_audio = &$info['mpeg']['audio'];
+ if (!empty($thisfile_mpeg_audio['LAME'])) {
+ $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME'];
+ }
+ }
+
+ $encoder_options = '';
+ static $NamedPresetBitrates = array(16, 24, 40, 56, 112, 128, 160, 192, 256);
+
+ if (isset($thisfile_mpeg_audio['VBR_method']) && ($thisfile_mpeg_audio['VBR_method'] == 'Fraunhofer') && !empty($thisfile_mpeg_audio['VBR_quality'])) {
+
+ $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality'];
+
+ } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) {
+
+ $encoder_options = $thisfile_mpeg_audio_lame['preset_used'];
+
+ } elseif (!empty($thisfile_mpeg_audio_lame['vbr_quality'])) {
+
+ static $KnownEncoderValues = array();
+ if (empty($KnownEncoderValues)) {
+
+ //$KnownEncoderValues[abrbitrate_minbitrate][vbr_quality][raw_vbr_method][raw_noise_shaping][raw_stereo_mode][ath_type][lowpass_frequency] = 'preset name';
+ $KnownEncoderValues[0xFF][58][1][1][3][2][20500] = '--alt-preset insane'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues[0xFF][58][1][1][3][2][20600] = '--alt-preset insane'; // 3.90.2, 3.90.3, 3.91
+ $KnownEncoderValues[0xFF][57][1][1][3][4][20500] = '--alt-preset insane'; // 3.94, 3.95
+ $KnownEncoderValues['**'][78][3][2][3][2][19500] = '--alt-preset extreme'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues['**'][78][3][2][3][2][19600] = '--alt-preset extreme'; // 3.90.2, 3.91
+ $KnownEncoderValues['**'][78][3][1][3][2][19600] = '--alt-preset extreme'; // 3.90.3
+ $KnownEncoderValues['**'][78][4][2][3][2][19500] = '--alt-preset fast extreme'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues['**'][78][4][2][3][2][19600] = '--alt-preset fast extreme'; // 3.90.2, 3.90.3, 3.91
+ $KnownEncoderValues['**'][78][3][2][3][4][19000] = '--alt-preset standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues['**'][78][3][1][3][4][19000] = '--alt-preset standard'; // 3.90.3
+ $KnownEncoderValues['**'][78][4][2][3][4][19000] = '--alt-preset fast standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues['**'][78][4][1][3][4][19000] = '--alt-preset fast standard'; // 3.90.3
+ $KnownEncoderValues['**'][88][4][1][3][3][19500] = '--r3mix'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues['**'][88][4][1][3][3][19600] = '--r3mix'; // 3.90.2, 3.90.3, 3.91
+ $KnownEncoderValues['**'][67][4][1][3][4][18000] = '--r3mix'; // 3.94, 3.95
+ $KnownEncoderValues['**'][68][3][2][3][4][18000] = '--alt-preset medium'; // 3.90.3
+ $KnownEncoderValues['**'][68][4][2][3][4][18000] = '--alt-preset fast medium'; // 3.90.3
+
+ $KnownEncoderValues[0xFF][99][1][1][1][2][0] = '--preset studio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0xFF][58][2][1][3][2][20600] = '--preset studio'; // 3.90.3, 3.93.1
+ $KnownEncoderValues[0xFF][58][2][1][3][2][20500] = '--preset studio'; // 3.93
+ $KnownEncoderValues[0xFF][57][2][1][3][4][20500] = '--preset studio'; // 3.94, 3.95
+ $KnownEncoderValues[0xC0][88][1][1][1][2][0] = '--preset cd'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0xC0][58][2][2][3][2][19600] = '--preset cd'; // 3.90.3, 3.93.1
+ $KnownEncoderValues[0xC0][58][2][2][3][2][19500] = '--preset cd'; // 3.93
+ $KnownEncoderValues[0xC0][57][2][1][3][4][19500] = '--preset cd'; // 3.94, 3.95
+ $KnownEncoderValues[0xA0][78][1][1][3][2][18000] = '--preset hifi'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0xA0][58][2][2][3][2][18000] = '--preset hifi'; // 3.90.3, 3.93, 3.93.1
+ $KnownEncoderValues[0xA0][57][2][1][3][4][18000] = '--preset hifi'; // 3.94, 3.95
+ $KnownEncoderValues[0x80][67][1][1][3][2][18000] = '--preset tape'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0x80][67][1][1][3][2][15000] = '--preset radio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0x70][67][1][1][3][2][15000] = '--preset fm'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92
+ $KnownEncoderValues[0x70][58][2][2][3][2][16000] = '--preset tape/radio/fm'; // 3.90.3, 3.93, 3.93.1
+ $KnownEncoderValues[0x70][57][2][1][3][4][16000] = '--preset tape/radio/fm'; // 3.94, 3.95
+ $KnownEncoderValues[0x38][58][2][2][0][2][10000] = '--preset voice'; // 3.90.3, 3.93, 3.93.1
+ $KnownEncoderValues[0x38][57][2][1][0][4][15000] = '--preset voice'; // 3.94, 3.95
+ $KnownEncoderValues[0x38][57][2][1][0][4][16000] = '--preset voice'; // 3.94a14
+ $KnownEncoderValues[0x28][65][1][1][0][2][7500] = '--preset mw-us'; // 3.90, 3.90.1, 3.92
+ $KnownEncoderValues[0x28][65][1][1][0][2][7600] = '--preset mw-us'; // 3.90.2, 3.91
+ $KnownEncoderValues[0x28][58][2][2][0][2][7000] = '--preset mw-us'; // 3.90.3, 3.93, 3.93.1
+ $KnownEncoderValues[0x28][57][2][1][0][4][10500] = '--preset mw-us'; // 3.94, 3.95
+ $KnownEncoderValues[0x28][57][2][1][0][4][11200] = '--preset mw-us'; // 3.94a14
+ $KnownEncoderValues[0x28][57][2][1][0][4][8800] = '--preset mw-us'; // 3.94a15
+ $KnownEncoderValues[0x18][58][2][2][0][2][4000] = '--preset phon+/lw/mw-eu/sw'; // 3.90.3, 3.93.1
+ $KnownEncoderValues[0x18][58][2][2][0][2][3900] = '--preset phon+/lw/mw-eu/sw'; // 3.93
+ $KnownEncoderValues[0x18][57][2][1][0][4][5900] = '--preset phon+/lw/mw-eu/sw'; // 3.94, 3.95
+ $KnownEncoderValues[0x18][57][2][1][0][4][6200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a14
+ $KnownEncoderValues[0x18][57][2][1][0][4][3200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a15
+ $KnownEncoderValues[0x10][58][2][2][0][2][3800] = '--preset phone'; // 3.90.3, 3.93.1
+ $KnownEncoderValues[0x10][58][2][2][0][2][3700] = '--preset phone'; // 3.93
+ $KnownEncoderValues[0x10][57][2][1][0][4][5600] = '--preset phone'; // 3.94, 3.95
+ }
+
+ if (isset($KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
+
+ $encoder_options = $KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']];
+
+ } elseif (isset($KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) {
+
+ $encoder_options = $KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']];
+
+ } elseif ($info['audio']['bitrate_mode'] == 'vbr') {
+
+ // http://gabriel.mp3-tech.org/mp3infotag.html
+ // int Quality = (100 - 10 * gfp->VBR_q - gfp->quality)h
+
+
+ $LAME_V_value = 10 - ceil($thisfile_mpeg_audio_lame['vbr_quality'] / 10);
+ $LAME_q_value = 100 - $thisfile_mpeg_audio_lame['vbr_quality'] - ($LAME_V_value * 10);
+ $encoder_options = '-V'.$LAME_V_value.' -q'.$LAME_q_value;
+
+ } elseif ($info['audio']['bitrate_mode'] == 'cbr') {
+
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
+
+ } else {
+
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']);
+
+ }
+
+ } elseif (!empty($thisfile_mpeg_audio_lame['bitrate_abr'])) {
+
+ $encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr'];
+
+ } elseif (!empty($info['audio']['bitrate'])) {
+
+ if ($info['audio']['bitrate_mode'] == 'cbr') {
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
+ } else {
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']);
+ }
+
+ }
+ if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) {
+ $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min'];
+ }
+
+ if (!empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']) || !empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'])) {
+ $encoder_options .= ' --nogap';
+ }
+
+ if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) {
+ $ExplodedOptions = explode(' ', $encoder_options, 4);
+ if ($ExplodedOptions[0] == '--r3mix') {
+ $ExplodedOptions[1] = 'r3mix';
+ }
+ switch ($ExplodedOptions[0]) {
+ case '--preset':
+ case '--alt-preset':
+ case '--r3mix':
+ if ($ExplodedOptions[1] == 'fast') {
+ $ExplodedOptions[1] .= ' '.$ExplodedOptions[2];
+ }
+ switch ($ExplodedOptions[1]) {
+ case 'portable':
+ case 'medium':
+ case 'standard':
+ case 'extreme':
+ case 'insane':
+ case 'fast portable':
+ case 'fast medium':
+ case 'fast standard':
+ case 'fast extreme':
+ case 'fast insane':
+ case 'r3mix':
+ static $ExpectedLowpass = array(
+ 'insane|20500' => 20500,
+ 'insane|20600' => 20600, // 3.90.2, 3.90.3, 3.91
+ 'medium|18000' => 18000,
+ 'fast medium|18000' => 18000,
+ 'extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95
+ 'extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1
+ 'fast extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95
+ 'fast extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1
+ 'standard|19000' => 19000,
+ 'fast standard|19000' => 19000,
+ 'r3mix|19500' => 19500, // 3.90, 3.90.1, 3.92
+ 'r3mix|19600' => 19600, // 3.90.2, 3.90.3, 3.91
+ 'r3mix|18000' => 18000, // 3.94, 3.95
+ );
+ if (!isset($ExpectedLowpass[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']]) && ($thisfile_mpeg_audio_lame['lowpass_frequency'] < 22050) && (round($thisfile_mpeg_audio_lame['lowpass_frequency'] / 1000) < round($thisfile_mpeg_audio['sample_rate'] / 2000))) {
+ $encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency'];
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ if (isset($thisfile_mpeg_audio_lame['raw']['source_sample_freq'])) {
+ if (($thisfile_mpeg_audio['sample_rate'] == 44100) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 1)) {
+ $encoder_options .= ' --resample 44100';
+ } elseif (($thisfile_mpeg_audio['sample_rate'] == 48000) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 2)) {
+ $encoder_options .= ' --resample 48000';
+ } elseif ($thisfile_mpeg_audio['sample_rate'] < 44100) {
+ switch ($thisfile_mpeg_audio_lame['raw']['source_sample_freq']) {
+ case 0: // <= 32000
+ // may or may not be same as source frequency - ignore
+ break;
+ case 1: // 44100
+ case 2: // 48000
+ case 3: // 48000+
+ $ExplodedOptions = explode(' ', $encoder_options, 4);
+ switch ($ExplodedOptions[0]) {
+ case '--preset':
+ case '--alt-preset':
+ switch ($ExplodedOptions[1]) {
+ case 'fast':
+ case 'portable':
+ case 'medium':
+ case 'standard':
+ case 'extreme':
+ case 'insane':
+ $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
+ break;
+
+ default:
+ static $ExpectedResampledRate = array(
+ 'phon+/lw/mw-eu/sw|16000' => 16000,
+ 'mw-us|24000' => 24000, // 3.95
+ 'mw-us|32000' => 32000, // 3.93
+ 'mw-us|16000' => 16000, // 3.92
+ 'phone|16000' => 16000,
+ 'phone|11025' => 11025, // 3.94a15
+ 'radio|32000' => 32000, // 3.94a15
+ 'fm/radio|32000' => 32000, // 3.92
+ 'fm|32000' => 32000, // 3.90
+ 'voice|32000' => 32000);
+ if (!isset($ExpectedResampledRate[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio['sample_rate']])) {
+ $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
+ }
+ break;
+ }
+ break;
+
+ case '--r3mix':
+ default:
+ $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate'];
+ break;
+ }
+ break;
+ }
+ }
+ }
+ if (empty($encoder_options) && !empty($info['audio']['bitrate']) && !empty($info['audio']['bitrate_mode'])) {
+ //$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000);
+ $encoder_options = strtoupper($info['audio']['bitrate_mode']);
+ }
+
+ return $encoder_options;
+ }
+
+
+ public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) {
+ static $MPEGaudioVersionLookup;
+ static $MPEGaudioLayerLookup;
+ static $MPEGaudioBitrateLookup;
+ static $MPEGaudioFrequencyLookup;
+ static $MPEGaudioChannelModeLookup;
+ static $MPEGaudioModeExtensionLookup;
+ static $MPEGaudioEmphasisLookup;
+ if (empty($MPEGaudioVersionLookup)) {
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
+ $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray();
+ $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray();
+ $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
+ $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
+ }
+
+ if (fseek($this->getid3->fp, $offset, SEEK_SET) != 0) {
+ $info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset;
+ return false;
+ }
+ //$headerstring = fread($this->getid3->fp, 1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame
+ $headerstring = fread($this->getid3->fp, 226); // LAME header at offset 36 + 190 bytes of Xing/LAME data
+
+ // MP3 audio frame structure:
+ // $aa $aa $aa $aa [$bb $bb] $cc...
+ // where $aa..$aa is the four-byte mpeg-audio header (below)
+ // $bb $bb is the optional 2-byte CRC
+ // and $cc... is the audio data
+
+ $head4 = substr($headerstring, 0, 4);
+
+ static $MPEGaudioHeaderDecodeCache = array();
+ if (isset($MPEGaudioHeaderDecodeCache[$head4])) {
+ $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4];
+ } else {
+ $MPEGheaderRawArray = self::MPEGaudioHeaderDecode($head4);
+ $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray;
+ }
+
+ static $MPEGaudioHeaderValidCache = array();
+ if (!isset($MPEGaudioHeaderValidCache[$head4])) { // Not in cache
+ //$MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true); // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1)
+ $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false);
+ }
+
+ // shortcut
+ if (!isset($info['mpeg']['audio'])) {
+ $info['mpeg']['audio'] = array();
+ }
+ $thisfile_mpeg_audio = &$info['mpeg']['audio'];
+
+
+ if ($MPEGaudioHeaderValidCache[$head4]) {
+ $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray;
+ } else {
+ $info['error'][] = 'Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset;
+ return false;
+ }
+
+ if (!$FastMPEGheaderScan) {
+ $thisfile_mpeg_audio['version'] = $MPEGaudioVersionLookup[$thisfile_mpeg_audio['raw']['version']];
+ $thisfile_mpeg_audio['layer'] = $MPEGaudioLayerLookup[$thisfile_mpeg_audio['raw']['layer']];
+
+ $thisfile_mpeg_audio['channelmode'] = $MPEGaudioChannelModeLookup[$thisfile_mpeg_audio['raw']['channelmode']];
+ $thisfile_mpeg_audio['channels'] = (($thisfile_mpeg_audio['channelmode'] == 'mono') ? 1 : 2);
+ $thisfile_mpeg_audio['sample_rate'] = $MPEGaudioFrequencyLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['raw']['sample_rate']];
+ $thisfile_mpeg_audio['protection'] = !$thisfile_mpeg_audio['raw']['protection'];
+ $thisfile_mpeg_audio['private'] = (bool) $thisfile_mpeg_audio['raw']['private'];
+ $thisfile_mpeg_audio['modeextension'] = $MPEGaudioModeExtensionLookup[$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['modeextension']];
+ $thisfile_mpeg_audio['copyright'] = (bool) $thisfile_mpeg_audio['raw']['copyright'];
+ $thisfile_mpeg_audio['original'] = (bool) $thisfile_mpeg_audio['raw']['original'];
+ $thisfile_mpeg_audio['emphasis'] = $MPEGaudioEmphasisLookup[$thisfile_mpeg_audio['raw']['emphasis']];
+
+ $info['audio']['channels'] = $thisfile_mpeg_audio['channels'];
+ $info['audio']['sample_rate'] = $thisfile_mpeg_audio['sample_rate'];
+
+ if ($thisfile_mpeg_audio['protection']) {
+ $thisfile_mpeg_audio['crc'] = getid3_lib::BigEndian2Int(substr($headerstring, 4, 2));
+ }
+ }
+
+ if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) {
+ // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0
+ $info['warning'][] = 'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1';
+ $thisfile_mpeg_audio['raw']['bitrate'] = 0;
+ }
+ $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding'];
+ $thisfile_mpeg_audio['bitrate'] = $MPEGaudioBitrateLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['bitrate']];
+
+ if (($thisfile_mpeg_audio['bitrate'] == 'free') && ($offset == $info['avdataoffset'])) {
+ // only skip multiple frame check if free-format bitstream found at beginning of file
+ // otherwise is quite possibly simply corrupted data
+ $recursivesearch = false;
+ }
+
+ // For Layer 2 there are some combinations of bitrate and mode which are not allowed.
+ if (!$FastMPEGheaderScan && ($thisfile_mpeg_audio['layer'] == '2')) {
+
+ $info['audio']['dataformat'] = 'mp2';
+ switch ($thisfile_mpeg_audio['channelmode']) {
+
+ case 'mono':
+ if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) {
+ // these are ok
+ } else {
+ $info['error'][] = $thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';
+ return false;
+ }
+ break;
+
+ case 'stereo':
+ case 'joint stereo':
+ case 'dual channel':
+ if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) {
+ // these are ok
+ } else {
+ $info['error'][] = intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.';
+ return false;
+ }
+ break;
+
+ }
+
+ }
+
+
+ if ($info['audio']['sample_rate'] > 0) {
+ $thisfile_mpeg_audio['framelength'] = self::MPEGaudioFrameLength($thisfile_mpeg_audio['bitrate'], $thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['layer'], (int) $thisfile_mpeg_audio['padding'], $info['audio']['sample_rate']);
+ }
+
+ $nextframetestoffset = $offset + 1;
+ if ($thisfile_mpeg_audio['bitrate'] != 'free') {
+
+ $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
+
+ if (isset($thisfile_mpeg_audio['framelength'])) {
+ $nextframetestoffset = $offset + $thisfile_mpeg_audio['framelength'];
+ } else {
+ $info['error'][] = 'Frame at offset('.$offset.') is has an invalid frame length.';
+ return false;
+ }
+
+ }
+
+ $ExpectedNumberOfAudioBytes = 0;
+
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Variable-bitrate headers
+
+ if (substr($headerstring, 4 + 32, 4) == 'VBRI') {
+ // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36)
+ // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html
+
+ $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
+ $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer';
+ $info['audio']['codec'] = 'Fraunhofer';
+
+ $SideInfoData = substr($headerstring, 4 + 2, 32);
+
+ $FraunhoferVBROffset = 36;
+
+ $thisfile_mpeg_audio['VBR_encoder_version'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 4, 2)); // VbriVersion
+ $thisfile_mpeg_audio['VBR_encoder_delay'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 6, 2)); // VbriDelay
+ $thisfile_mpeg_audio['VBR_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 8, 2)); // VbriQuality
+ $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 10, 4)); // VbriStreamBytes
+ $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 14, 4)); // VbriStreamFrames
+ $thisfile_mpeg_audio['VBR_seek_offsets'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 18, 2)); // VbriTableSize
+ $thisfile_mpeg_audio['VBR_seek_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 20, 2)); // VbriTableScale
+ $thisfile_mpeg_audio['VBR_entry_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 22, 2)); // VbriEntryBytes
+ $thisfile_mpeg_audio['VBR_entry_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 24, 2)); // VbriEntryFrames
+
+ $ExpectedNumberOfAudioBytes = $thisfile_mpeg_audio['VBR_bytes'];
+
+ $previousbyteoffset = $offset;
+ for ($i = 0; $i < $thisfile_mpeg_audio['VBR_seek_offsets']; $i++) {
+ $Fraunhofer_OffsetN = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, $thisfile_mpeg_audio['VBR_entry_bytes']));
+ $FraunhoferVBROffset += $thisfile_mpeg_audio['VBR_entry_bytes'];
+ $thisfile_mpeg_audio['VBR_offsets_relative'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']);
+ $thisfile_mpeg_audio['VBR_offsets_absolute'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']) + $previousbyteoffset;
+ $previousbyteoffset += $Fraunhofer_OffsetN;
+ }
+
+
+ } else {
+
+ // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36)
+ // depending on MPEG layer and number of channels
+
+ $VBRidOffset = self::XingVBRidOffset($thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['channelmode']);
+ $SideInfoData = substr($headerstring, 4 + 2, $VBRidOffset - 4);
+
+ if ((substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing') || (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info')) {
+ // 'Xing' is traditional Xing VBR frame
+ // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.)
+ // 'Info' *can* legally be used to specify a VBR file as well, however.
+
+ // http://www.multiweb.cz/twoinches/MP3inside.htm
+ //00..03 = "Xing" or "Info"
+ //04..07 = Flags:
+ // 0x01 Frames Flag set if value for number of frames in file is stored
+ // 0x02 Bytes Flag set if value for filesize in bytes is stored
+ // 0x04 TOC Flag set if values for TOC are stored
+ // 0x08 VBR Scale Flag set if values for VBR scale is stored
+ //08..11 Frames: Number of frames in file (including the first Xing/Info one)
+ //12..15 Bytes: File length in Bytes
+ //16..115 TOC (Table of Contents):
+ // Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file.
+ // Each Byte has a value according this formula:
+ // (TOC[i] / 256) * fileLenInBytes
+ // So if song lasts eg. 240 sec. and you want to jump to 60. sec. (and file is 5 000 000 Bytes length) you can use:
+ // TOC[(60/240)*100] = TOC[25]
+ // and corresponding Byte in file is then approximately at:
+ // (TOC[25]/256) * 5000000
+ //116..119 VBR Scale
+
+
+ // should be safe to leave this at 'vbr' and let it be overriden to 'cbr' if a CBR preset/mode is used by LAME
+// if (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Xing') {
+ $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
+ $thisfile_mpeg_audio['VBR_method'] = 'Xing';
+// } else {
+// $ScanAsCBR = true;
+// $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
+// }
+
+ $thisfile_mpeg_audio['xing_flags_raw'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 4, 4));
+
+ $thisfile_mpeg_audio['xing_flags']['frames'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000001);
+ $thisfile_mpeg_audio['xing_flags']['bytes'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000002);
+ $thisfile_mpeg_audio['xing_flags']['toc'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000004);
+ $thisfile_mpeg_audio['xing_flags']['vbr_scale'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000008);
+
+ if ($thisfile_mpeg_audio['xing_flags']['frames']) {
+ $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 8, 4));
+ //$thisfile_mpeg_audio['VBR_frames']--; // don't count header Xing/Info frame
+ }
+ if ($thisfile_mpeg_audio['xing_flags']['bytes']) {
+ $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 12, 4));
+ }
+
+ //if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
+ if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) {
+
+ $framelengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames'];
+
+ if ($thisfile_mpeg_audio['layer'] == '1') {
+ // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
+ //$info['audio']['bitrate'] = ((($framelengthfloat / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12;
+ $info['audio']['bitrate'] = ($framelengthfloat / 4) * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 12;
+ } else {
+ // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
+ //$info['audio']['bitrate'] = (($framelengthfloat - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
+ $info['audio']['bitrate'] = $framelengthfloat * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 144;
+ }
+ $thisfile_mpeg_audio['framelength'] = floor($framelengthfloat);
+ }
+
+ if ($thisfile_mpeg_audio['xing_flags']['toc']) {
+ $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100);
+ for ($i = 0; $i < 100; $i++) {
+ $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData{$i});
+ }
+ }
+ if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) {
+ $thisfile_mpeg_audio['VBR_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 116, 4));
+ }
+
+
+ // http://gabriel.mp3-tech.org/mp3infotag.html
+ if (substr($headerstring, $VBRidOffset + 120, 4) == 'LAME') {
+
+ // shortcut
+ $thisfile_mpeg_audio['LAME'] = array();
+ $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME'];
+
+
+ $thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20);
+ $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9);
+
+ if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') {
+
+ // extra 11 chars are not part of version string when LAMEtag present
+ unset($thisfile_mpeg_audio_lame['long_version']);
+
+ // It the LAME tag was only introduced in LAME v3.90
+ // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933
+
+ // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html
+ // are assuming a 'Xing' identifier offset of 0x24, which is the case for
+ // MPEG-1 non-mono, but not for other combinations
+ $LAMEtagOffsetContant = $VBRidOffset - 0x24;
+
+ // shortcuts
+ $thisfile_mpeg_audio_lame['RGAD'] = array('track'=>array(), 'album'=>array());
+ $thisfile_mpeg_audio_lame_RGAD = &$thisfile_mpeg_audio_lame['RGAD'];
+ $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track'];
+ $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album'];
+ $thisfile_mpeg_audio_lame['raw'] = array();
+ $thisfile_mpeg_audio_lame_raw = &$thisfile_mpeg_audio_lame['raw'];
+
+ // byte $9B VBR Quality
+ // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications.
+ // Actually overwrites original Xing bytes
+ unset($thisfile_mpeg_audio['VBR_scale']);
+ $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1));
+
+ // bytes $9C-$A4 Encoder short VersionString
+ $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9);
+
+ // byte $A5 Info Tag revision + VBR method
+ $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1));
+
+ $thisfile_mpeg_audio_lame['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4;
+ $thisfile_mpeg_audio_lame_raw['vbr_method'] = $LAMEtagRevisionVBRmethod & 0x0F;
+ $thisfile_mpeg_audio_lame['vbr_method'] = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']);
+ $thisfile_mpeg_audio['bitrate_mode'] = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr'
+
+ // byte $A6 Lowpass filter value
+ $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100;
+
+ // bytes $A7-$AE Replay Gain
+ // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html
+ // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude"
+ if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') {
+ // LAME 3.94a16 and later - 9.23 fixed point
+ // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375
+ $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608);
+ } else {
+ // LAME 3.94a15 and earlier - 32-bit floating point
+ // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15
+ $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4));
+ }
+ if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) {
+ unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
+ } else {
+ $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']);
+ }
+
+ $thisfile_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2));
+ $thisfile_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2));
+
+
+ if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) {
+
+ $thisfile_mpeg_audio_lame_RGAD_track['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13;
+ $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10;
+ $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9;
+ $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF;
+ $thisfile_mpeg_audio_lame_RGAD_track['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']);
+ $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']);
+ $thisfile_mpeg_audio_lame_RGAD_track['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']);
+
+ if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
+ $info['replay_gain']['track']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
+ }
+ $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator'];
+ $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db'];
+ } else {
+ unset($thisfile_mpeg_audio_lame_RGAD['track']);
+ }
+ if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) {
+
+ $thisfile_mpeg_audio_lame_RGAD_album['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13;
+ $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10;
+ $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9;
+ $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF;
+ $thisfile_mpeg_audio_lame_RGAD_album['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']);
+ $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']);
+ $thisfile_mpeg_audio_lame_RGAD_album['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']);
+
+ if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) {
+ $info['replay_gain']['album']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'];
+ }
+ $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator'];
+ $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db'];
+ } else {
+ unset($thisfile_mpeg_audio_lame_RGAD['album']);
+ }
+ if (empty($thisfile_mpeg_audio_lame_RGAD)) {
+ unset($thisfile_mpeg_audio_lame['RGAD']);
+ }
+
+
+ // byte $AF Encoding flags + ATH Type
+ $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1));
+ $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10);
+ $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20);
+ $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40);
+ $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80);
+ $thisfile_mpeg_audio_lame['ath_type'] = $EncodingFlagsATHtype & 0x0F;
+
+ // byte $B0 if ABR {specified bitrate} else {minimal bitrate}
+ $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1));
+ if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR)
+ $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
+ } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR)
+ // ignore
+ } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate
+ $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'];
+ }
+
+ // bytes $B1-$B3 Encoder delays
+ $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3));
+ $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12;
+ $thisfile_mpeg_audio_lame['end_padding'] = $EncoderDelays & 0x000FFF;
+
+ // byte $B4 Misc
+ $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1));
+ $thisfile_mpeg_audio_lame_raw['noise_shaping'] = ($MiscByte & 0x03);
+ $thisfile_mpeg_audio_lame_raw['stereo_mode'] = ($MiscByte & 0x1C) >> 2;
+ $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5;
+ $thisfile_mpeg_audio_lame_raw['source_sample_freq'] = ($MiscByte & 0xC0) >> 6;
+ $thisfile_mpeg_audio_lame['noise_shaping'] = $thisfile_mpeg_audio_lame_raw['noise_shaping'];
+ $thisfile_mpeg_audio_lame['stereo_mode'] = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']);
+ $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality'];
+ $thisfile_mpeg_audio_lame['source_sample_freq'] = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']);
+
+ // byte $B5 MP3 Gain
+ $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true);
+ $thisfile_mpeg_audio_lame['mp3_gain_db'] = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain'];
+ $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6));
+
+ // bytes $B6-$B7 Preset and surround info
+ $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2));
+ // Reserved = ($PresetSurroundBytes & 0xC000);
+ $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800);
+ $thisfile_mpeg_audio_lame['surround_info'] = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']);
+ $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF);
+ $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame);
+ if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) {
+ $info['warning'][] = 'Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org';
+ }
+ if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) {
+ // this may change if 3.90.4 ever comes out
+ $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3';
+ }
+
+ // bytes $B8-$BB MusicLength
+ $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4));
+ $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']);
+
+ // bytes $BC-$BD MusicCRC
+ $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2));
+
+ // bytes $BE-$BF CRC-16 of Info Tag
+ $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2));
+
+
+ // LAME CBR
+ if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) {
+
+ $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
+ $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']);
+ $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate'];
+ //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) {
+ // $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min'];
+ //}
+
+ }
+
+ }
+ }
+
+ } else {
+
+ // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header)
+ $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
+ if ($recursivesearch) {
+ $thisfile_mpeg_audio['bitrate_mode'] = 'vbr';
+ if ($this->RecursiveFrameScanning($offset, $nextframetestoffset, true)) {
+ $recursivesearch = false;
+ $thisfile_mpeg_audio['bitrate_mode'] = 'cbr';
+ }
+ if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') {
+ $info['warning'][] = 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.';
+ }
+ }
+
+ }
+
+ }
+
+ if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($info['avdataend'] - $info['avdataoffset']))) {
+ if ($ExpectedNumberOfAudioBytes > ($info['avdataend'] - $info['avdataoffset'])) {
+ if (isset($info['fileformat']) && ($info['fileformat'] == 'riff')) {
+ // ignore, audio data is broken into chunks so will always be data "missing"
+ } elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) {
+ $info['warning'][] = 'Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)';
+ } else {
+ $info['warning'][] = 'Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)';
+ }
+ } else {
+ if ((($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes) == 1) {
+ // $prenullbytefileoffset = ftell($this->getid3->fp);
+ // fseek($this->getid3->fp, $info['avdataend'], SEEK_SET);
+ // $PossibleNullByte = fread($this->getid3->fp, 1);
+ // fseek($this->getid3->fp, $prenullbytefileoffset, SEEK_SET);
+ // if ($PossibleNullByte === "\x00") {
+ $info['avdataend']--;
+ // $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored';
+ // } else {
+ // $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
+ // }
+ } else {
+ $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)';
+ }
+ }
+ }
+
+ if (($thisfile_mpeg_audio['bitrate'] == 'free') && empty($info['audio']['bitrate'])) {
+ if (($offset == $info['avdataoffset']) && empty($thisfile_mpeg_audio['VBR_frames'])) {
+ $framebytelength = $this->FreeFormatFrameLength($offset, true);
+ if ($framebytelength > 0) {
+ $thisfile_mpeg_audio['framelength'] = $framebytelength;
+ if ($thisfile_mpeg_audio['layer'] == '1') {
+ // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12
+ $info['audio']['bitrate'] = ((($framebytelength / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12;
+ } else {
+ // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144
+ $info['audio']['bitrate'] = (($framebytelength - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144;
+ }
+ } else {
+ $info['error'][] = 'Error calculating frame length of free-format MP3 without Xing/LAME header';
+ }
+ }
+ }
+
+ if (isset($thisfile_mpeg_audio['VBR_frames']) ? $thisfile_mpeg_audio['VBR_frames'] : '') {
+ switch ($thisfile_mpeg_audio['bitrate_mode']) {
+ case 'vbr':
+ case 'abr':
+ $bytes_per_frame = 1152;
+ if (($thisfile_mpeg_audio['version'] == '1') && ($thisfile_mpeg_audio['layer'] == 1)) {
+ $bytes_per_frame = 384;
+ } elseif ((($thisfile_mpeg_audio['version'] == '2') || ($thisfile_mpeg_audio['version'] == '2.5')) && ($thisfile_mpeg_audio['layer'] == 3)) {
+ $bytes_per_frame = 576;
+ }
+ $thisfile_mpeg_audio['VBR_bitrate'] = (isset($thisfile_mpeg_audio['VBR_bytes']) ? (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / $bytes_per_frame) : 0);
+ if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) {
+ $info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate'];
+ $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion
+ }
+ break;
+ }
+ }
+
+ // End variable-bitrate headers
+ ////////////////////////////////////////////////////////////////////////////////////
+
+ if ($recursivesearch) {
+
+ if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) {
+ return false;
+ }
+
+ }
+
+
+ //if (false) {
+ // // experimental side info parsing section - not returning anything useful yet
+ //
+ // $SideInfoBitstream = getid3_lib::BigEndian2Bin($SideInfoData);
+ // $SideInfoOffset = 0;
+ //
+ // if ($thisfile_mpeg_audio['version'] == '1') {
+ // if ($thisfile_mpeg_audio['channelmode'] == 'mono') {
+ // // MPEG-1 (mono)
+ // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
+ // $SideInfoOffset += 9;
+ // $SideInfoOffset += 5;
+ // } else {
+ // // MPEG-1 (stereo, joint-stereo, dual-channel)
+ // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9);
+ // $SideInfoOffset += 9;
+ // $SideInfoOffset += 3;
+ // }
+ // } else { // 2 or 2.5
+ // if ($thisfile_mpeg_audio['channelmode'] == 'mono') {
+ // // MPEG-2, MPEG-2.5 (mono)
+ // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
+ // $SideInfoOffset += 8;
+ // $SideInfoOffset += 1;
+ // } else {
+ // // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel)
+ // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8);
+ // $SideInfoOffset += 8;
+ // $SideInfoOffset += 2;
+ // }
+ // }
+ //
+ // if ($thisfile_mpeg_audio['version'] == '1') {
+ // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) {
+ // for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) {
+ // $thisfile_mpeg_audio['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 2;
+ // }
+ // }
+ // }
+ // for ($granule = 0; $granule < (($thisfile_mpeg_audio['version'] == '1') ? 2 : 1); $granule++) {
+ // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) {
+ // $thisfile_mpeg_audio['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12);
+ // $SideInfoOffset += 12;
+ // $thisfile_mpeg_audio['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
+ // $SideInfoOffset += 9;
+ // $thisfile_mpeg_audio['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8);
+ // $SideInfoOffset += 8;
+ // if ($thisfile_mpeg_audio['version'] == '1') {
+ // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
+ // $SideInfoOffset += 4;
+ // } else {
+ // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9);
+ // $SideInfoOffset += 9;
+ // }
+ // $thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ //
+ // if ($thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] == '1') {
+ //
+ // $thisfile_mpeg_audio['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2);
+ // $SideInfoOffset += 2;
+ // $thisfile_mpeg_audio['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ //
+ // for ($region = 0; $region < 2; $region++) {
+ // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
+ // $SideInfoOffset += 5;
+ // }
+ // $thisfile_mpeg_audio['table_select'][$granule][$channel][2] = 0;
+ //
+ // for ($window = 0; $window < 3; $window++) {
+ // $thisfile_mpeg_audio['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3);
+ // $SideInfoOffset += 3;
+ // }
+ //
+ // } else {
+ //
+ // for ($region = 0; $region < 3; $region++) {
+ // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5);
+ // $SideInfoOffset += 5;
+ // }
+ //
+ // $thisfile_mpeg_audio['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4);
+ // $SideInfoOffset += 4;
+ // $thisfile_mpeg_audio['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3);
+ // $SideInfoOffset += 3;
+ // $thisfile_mpeg_audio['block_type'][$granule][$channel] = 0;
+ // }
+ //
+ // if ($thisfile_mpeg_audio['version'] == '1') {
+ // $thisfile_mpeg_audio['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ // }
+ // $thisfile_mpeg_audio['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ // $thisfile_mpeg_audio['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1);
+ // $SideInfoOffset += 1;
+ // }
+ // }
+ //}
+
+ return true;
+ }
+
+ public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) {
+ $info = &$this->getid3->info;
+ $firstframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
+ $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false);
+
+ for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) {
+ // check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch
+ if (($nextframetestoffset + 4) >= $info['avdataend']) {
+ // end of file
+ return true;
+ }
+
+ $nextframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
+ if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) {
+ if ($ScanAsCBR) {
+ // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header
+ if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) {
+ return false;
+ }
+ }
+
+
+ // next frame is OK, get ready to check the one after that
+ if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0)) {
+ $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength'];
+ } else {
+ $info['error'][] = 'Frame at offset ('.$offset.') is has an invalid frame length.';
+ return false;
+ }
+
+ } elseif (!empty($firstframetestarray['mpeg']['audio']['framelength']) && (($nextframetestoffset + $firstframetestarray['mpeg']['audio']['framelength']) > $info['avdataend'])) {
+
+ // it's not the end of the file, but there's not enough data left for another frame, so assume it's garbage/padding and return OK
+ return true;
+
+ } else {
+
+ // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence
+ $info['warning'][] = 'Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.';
+
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public function FreeFormatFrameLength($offset, $deepscan=false) {
+ $info = &$this->getid3->info;
+
+ fseek($this->getid3->fp, $offset, SEEK_SET);
+ $MPEGaudioData = fread($this->getid3->fp, 32768);
+
+ $SyncPattern1 = substr($MPEGaudioData, 0, 4);
+ // may be different pattern due to padding
+ $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3};
+ if ($SyncPattern2 === $SyncPattern1) {
+ $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3};
+ }
+
+ $framelength = false;
+ $framelength1 = strpos($MPEGaudioData, $SyncPattern1, 4);
+ $framelength2 = strpos($MPEGaudioData, $SyncPattern2, 4);
+ if ($framelength1 > 4) {
+ $framelength = $framelength1;
+ }
+ if (($framelength2 > 4) && ($framelength2 < $framelength1)) {
+ $framelength = $framelength2;
+ }
+ if (!$framelength) {
+
+ // LAME 3.88 has a different value for modeextension on the first frame vs the rest
+ $framelength1 = strpos($MPEGaudioData, substr($SyncPattern1, 0, 3), 4);
+ $framelength2 = strpos($MPEGaudioData, substr($SyncPattern2, 0, 3), 4);
+
+ if ($framelength1 > 4) {
+ $framelength = $framelength1;
+ }
+ if (($framelength2 > 4) && ($framelength2 < $framelength1)) {
+ $framelength = $framelength2;
+ }
+ if (!$framelength) {
+ $info['error'][] = 'Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset;
+ return false;
+ } else {
+ $info['warning'][] = 'ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)';
+ $info['audio']['codec'] = 'LAME';
+ $info['audio']['encoder'] = 'LAME3.88';
+ $SyncPattern1 = substr($SyncPattern1, 0, 3);
+ $SyncPattern2 = substr($SyncPattern2, 0, 3);
+ }
+ }
+
+ if ($deepscan) {
+
+ $ActualFrameLengthValues = array();
+ $nextoffset = $offset + $framelength;
+ while ($nextoffset < ($info['avdataend'] - 6)) {
+ fseek($this->getid3->fp, $nextoffset - 1, SEEK_SET);
+ $NextSyncPattern = fread($this->getid3->fp, 6);
+ if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2)) {
+ // good - found where expected
+ $ActualFrameLengthValues[] = $framelength;
+ } elseif ((substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2)) {
+ // ok - found one byte earlier than expected (last frame wasn't padded, first frame was)
+ $ActualFrameLengthValues[] = ($framelength - 1);
+ $nextoffset--;
+ } elseif ((substr($NextSyncPattern, 2, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 2, strlen($SyncPattern2)) == $SyncPattern2)) {
+ // ok - found one byte later than expected (last frame was padded, first frame wasn't)
+ $ActualFrameLengthValues[] = ($framelength + 1);
+ $nextoffset++;
+ } else {
+ $info['error'][] = 'Did not find expected free-format sync pattern at offset '.$nextoffset;
+ return false;
+ }
+ $nextoffset += $framelength;
+ }
+ if (count($ActualFrameLengthValues) > 0) {
+ $framelength = intval(round(array_sum($ActualFrameLengthValues) / count($ActualFrameLengthValues)));
+ }
+ }
+ return $framelength;
+ }
+
+ public function getOnlyMPEGaudioInfoBruteForce() {
+ $MPEGaudioHeaderDecodeCache = array();
+ $MPEGaudioHeaderValidCache = array();
+ $MPEGaudioHeaderLengthCache = array();
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
+ $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray();
+ $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray();
+ $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
+ $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
+ $LongMPEGversionLookup = array();
+ $LongMPEGlayerLookup = array();
+ $LongMPEGbitrateLookup = array();
+ $LongMPEGpaddingLookup = array();
+ $LongMPEGfrequencyLookup = array();
+ $Distribution['bitrate'] = array();
+ $Distribution['frequency'] = array();
+ $Distribution['layer'] = array();
+ $Distribution['version'] = array();
+ $Distribution['padding'] = array();
+
+ $info = &$this->getid3->info;
+ fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
+
+ $max_frames_scan = 5000;
+ $frames_scanned = 0;
+
+ $previousvalidframe = $info['avdataoffset'];
+ while (ftell($this->getid3->fp) < $info['avdataend']) {
+ set_time_limit(30);
+ $head4 = fread($this->getid3->fp, 4);
+ if (strlen($head4) < 4) {
+ break;
+ }
+ if ($head4{0} != "\xFF") {
+ for ($i = 1; $i < 4; $i++) {
+ if ($head4{$i} == "\xFF") {
+ fseek($this->getid3->fp, $i - 4, SEEK_CUR);
+ continue 2;
+ }
+ }
+ continue;
+ }
+ if (!isset($MPEGaudioHeaderDecodeCache[$head4])) {
+ $MPEGaudioHeaderDecodeCache[$head4] = self::MPEGaudioHeaderDecode($head4);
+ }
+ if (!isset($MPEGaudioHeaderValidCache[$head4])) {
+ $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$head4], false, false);
+ }
+ if ($MPEGaudioHeaderValidCache[$head4]) {
+
+ if (!isset($MPEGaudioHeaderLengthCache[$head4])) {
+ $LongMPEGversionLookup[$head4] = $MPEGaudioVersionLookup[$MPEGaudioHeaderDecodeCache[$head4]['version']];
+ $LongMPEGlayerLookup[$head4] = $MPEGaudioLayerLookup[$MPEGaudioHeaderDecodeCache[$head4]['layer']];
+ $LongMPEGbitrateLookup[$head4] = $MPEGaudioBitrateLookup[$LongMPEGversionLookup[$head4]][$LongMPEGlayerLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['bitrate']];
+ $LongMPEGpaddingLookup[$head4] = (bool) $MPEGaudioHeaderDecodeCache[$head4]['padding'];
+ $LongMPEGfrequencyLookup[$head4] = $MPEGaudioFrequencyLookup[$LongMPEGversionLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['sample_rate']];
+ $MPEGaudioHeaderLengthCache[$head4] = self::MPEGaudioFrameLength(
+ $LongMPEGbitrateLookup[$head4],
+ $LongMPEGversionLookup[$head4],
+ $LongMPEGlayerLookup[$head4],
+ $LongMPEGpaddingLookup[$head4],
+ $LongMPEGfrequencyLookup[$head4]);
+ }
+ if ($MPEGaudioHeaderLengthCache[$head4] > 4) {
+ $WhereWeWere = ftell($this->getid3->fp);
+ fseek($this->getid3->fp, $MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR);
+ $next4 = fread($this->getid3->fp, 4);
+ if ($next4{0} == "\xFF") {
+ if (!isset($MPEGaudioHeaderDecodeCache[$next4])) {
+ $MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4);
+ }
+ if (!isset($MPEGaudioHeaderValidCache[$next4])) {
+ $MPEGaudioHeaderValidCache[$next4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false);
+ }
+ if ($MPEGaudioHeaderValidCache[$next4]) {
+ fseek($this->getid3->fp, -4, SEEK_CUR);
+
+ getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]);
+ getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]);
+ getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]);
+ getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]);
+ getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]);
+ if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) {
+ $pct_data_scanned = (ftell($this->getid3->fp) - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']);
+ $info['warning'][] = 'too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
+ foreach ($Distribution as $key1 => $value1) {
+ foreach ($value1 as $key2 => $value2) {
+ $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned);
+ }
+ }
+ break;
+ }
+ continue;
+ }
+ }
+ unset($next4);
+ fseek($this->getid3->fp, $WhereWeWere - 3, SEEK_SET);
+ }
+
+ }
+ }
+ foreach ($Distribution as $key => $value) {
+ ksort($Distribution[$key], SORT_NUMERIC);
+ }
+ ksort($Distribution['version'], SORT_STRING);
+ $info['mpeg']['audio']['bitrate_distribution'] = $Distribution['bitrate'];
+ $info['mpeg']['audio']['frequency_distribution'] = $Distribution['frequency'];
+ $info['mpeg']['audio']['layer_distribution'] = $Distribution['layer'];
+ $info['mpeg']['audio']['version_distribution'] = $Distribution['version'];
+ $info['mpeg']['audio']['padding_distribution'] = $Distribution['padding'];
+ if (count($Distribution['version']) > 1) {
+ $info['error'][] = 'Corrupt file - more than one MPEG version detected';
+ }
+ if (count($Distribution['layer']) > 1) {
+ $info['error'][] = 'Corrupt file - more than one MPEG layer detected';
+ }
+ if (count($Distribution['frequency']) > 1) {
+ $info['error'][] = 'Corrupt file - more than one MPEG sample rate detected';
+ }
+
+
+ $bittotal = 0;
+ foreach ($Distribution['bitrate'] as $bitratevalue => $bitratecount) {
+ if ($bitratevalue != 'free') {
+ $bittotal += ($bitratevalue * $bitratecount);
+ }
+ }
+ $info['mpeg']['audio']['frame_count'] = array_sum($Distribution['bitrate']);
+ if ($info['mpeg']['audio']['frame_count'] == 0) {
+ $info['error'][] = 'no MPEG audio frames found';
+ return false;
+ }
+ $info['mpeg']['audio']['bitrate'] = ($bittotal / $info['mpeg']['audio']['frame_count']);
+ $info['mpeg']['audio']['bitrate_mode'] = ((count($Distribution['bitrate']) > 0) ? 'vbr' : 'cbr');
+ $info['mpeg']['audio']['sample_rate'] = getid3_lib::array_max($Distribution['frequency'], true);
+
+ $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
+ $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode'];
+ $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ $info['audio']['dataformat'] = 'mp'.getid3_lib::array_max($Distribution['layer'], true);
+ $info['fileformat'] = $info['audio']['dataformat'];
+
+ return true;
+ }
+
+
+ public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) {
+ // looks for synch, decodes MPEG audio header
+
+ $info = &$this->getid3->info;
+
+ static $MPEGaudioVersionLookup;
+ static $MPEGaudioLayerLookup;
+ static $MPEGaudioBitrateLookup;
+ if (empty($MPEGaudioVersionLookup)) {
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
+
+ }
+
+ fseek($this->getid3->fp, $avdataoffset, SEEK_SET);
+ $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset);
+ if ($sync_seek_buffer_size <= 0) {
+ $info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset;
+ return false;
+ }
+ $header = fread($this->getid3->fp, $sync_seek_buffer_size);
+ $sync_seek_buffer_size = strlen($header);
+ $SynchSeekOffset = 0;
+ while ($SynchSeekOffset < $sync_seek_buffer_size) {
+ if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) {
+
+ if ($SynchSeekOffset > $sync_seek_buffer_size) {
+ // if a synch's not found within the first 128k bytes, then give up
+ $info['error'][] = 'Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB';
+ if (isset($info['audio']['bitrate'])) {
+ unset($info['audio']['bitrate']);
+ }
+ if (isset($info['mpeg']['audio'])) {
+ unset($info['mpeg']['audio']);
+ }
+ if (empty($info['mpeg'])) {
+ unset($info['mpeg']);
+ }
+ return false;
+
+ } elseif (feof($this->getid3->fp)) {
+
+ $info['error'][] = 'Could not find valid MPEG audio synch before end of file';
+ if (isset($info['audio']['bitrate'])) {
+ unset($info['audio']['bitrate']);
+ }
+ if (isset($info['mpeg']['audio'])) {
+ unset($info['mpeg']['audio']);
+ }
+ if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) {
+ unset($info['mpeg']);
+ }
+ return false;
+ }
+ }
+
+ if (($SynchSeekOffset + 1) >= strlen($header)) {
+ $info['error'][] = 'Could not find valid MPEG synch before end of file';
+ return false;
+ }
+
+ if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected
+ if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) {
+ $FirstFrameThisfileInfo = $info;
+ $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset;
+ if (!$this->decodeMPEGaudioHeader($FirstFrameAVDataOffset, $FirstFrameThisfileInfo, false)) {
+ // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's
+ // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below
+ unset($FirstFrameThisfileInfo);
+ }
+ }
+
+ $dummy = $info; // only overwrite real data if valid header found
+ if ($this->decodeMPEGaudioHeader($avdataoffset + $SynchSeekOffset, $dummy, true)) {
+ $info = $dummy;
+ $info['avdataoffset'] = $avdataoffset + $SynchSeekOffset;
+ switch (isset($info['fileformat']) ? $info['fileformat'] : '') {
+ case '':
+ case 'id3':
+ case 'ape':
+ case 'mp3':
+ $info['fileformat'] = 'mp3';
+ $info['audio']['dataformat'] = 'mp3';
+ break;
+ }
+ if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) {
+ if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) {
+ // If there is garbage data between a valid VBR header frame and a sequence
+ // of valid MPEG-audio frames the VBR data is no longer discarded.
+ $info = $FirstFrameThisfileInfo;
+ $info['avdataoffset'] = $FirstFrameAVDataOffset;
+ $info['fileformat'] = 'mp3';
+ $info['audio']['dataformat'] = 'mp3';
+ $dummy = $info;
+ unset($dummy['mpeg']['audio']);
+ $GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength'];
+ $GarbageOffsetEnd = $avdataoffset + $SynchSeekOffset;
+ if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) {
+ $info = $dummy;
+ $info['avdataoffset'] = $GarbageOffsetEnd;
+ $info['warning'][] = 'apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd;
+ } else {
+ $info['warning'][] = 'using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')';
+ }
+ }
+ }
+ if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) {
+ // VBR file with no VBR header
+ $BitrateHistogram = true;
+ }
+
+ if ($BitrateHistogram) {
+
+ $info['mpeg']['audio']['stereo_distribution'] = array('stereo'=>0, 'joint stereo'=>0, 'dual channel'=>0, 'mono'=>0);
+ $info['mpeg']['audio']['version_distribution'] = array('1'=>0, '2'=>0, '2.5'=>0);
+
+ if ($info['mpeg']['audio']['version'] == '1') {
+ if ($info['mpeg']['audio']['layer'] == 3) {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0);
+ } elseif ($info['mpeg']['audio']['layer'] == 2) {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0, 384000=>0);
+ } elseif ($info['mpeg']['audio']['layer'] == 1) {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 64000=>0, 96000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 288000=>0, 320000=>0, 352000=>0, 384000=>0, 416000=>0, 448000=>0);
+ }
+ } elseif ($info['mpeg']['audio']['layer'] == 1) {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0, 176000=>0, 192000=>0, 224000=>0, 256000=>0);
+ } else {
+ $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 8000=>0, 16000=>0, 24000=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0);
+ }
+
+ $dummy = array('error'=>$info['error'], 'warning'=>$info['warning'], 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']);
+ $synchstartoffset = $info['avdataoffset'];
+ fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET);
+
+ // you can play with these numbers:
+ $max_frames_scan = 50000;
+ $max_scan_segments = 10;
+
+ // don't play with these numbers:
+ $FastMode = false;
+ $SynchErrorsFound = 0;
+ $frames_scanned = 0;
+ $this_scan_segment = 0;
+ $frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments);
+ $pct_data_scanned = 0;
+ for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) {
+ $frames_scanned_this_segment = 0;
+ if (ftell($this->getid3->fp) >= $info['avdataend']) {
+ break;
+ }
+ $scan_start_offset[$current_segment] = max(ftell($this->getid3->fp), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments)));
+ if ($current_segment > 0) {
+ fseek($this->getid3->fp, $scan_start_offset[$current_segment], SEEK_SET);
+ $buffer_4k = fread($this->getid3->fp, 4096);
+ for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) {
+ if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected
+ if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) {
+ $calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength'];
+ if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) {
+ $scan_start_offset[$current_segment] += $j;
+ break;
+ }
+ }
+ }
+ }
+ }
+ $synchstartoffset = $scan_start_offset[$current_segment];
+ while ($this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) {
+ $FastMode = true;
+ $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']];
+
+ if (empty($dummy['mpeg']['audio']['framelength'])) {
+ $SynchErrorsFound++;
+ $synchstartoffset++;
+ } else {
+ getid3_lib::safe_inc($info['mpeg']['audio']['bitrate_distribution'][$thisframebitrate]);
+ getid3_lib::safe_inc($info['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]);
+ getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]);
+ $synchstartoffset += $dummy['mpeg']['audio']['framelength'];
+ }
+ $frames_scanned++;
+ if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) {
+ $this_pct_scanned = (ftell($this->getid3->fp) - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']);
+ if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) {
+ // file likely contains < $max_frames_scan, just scan as one segment
+ $max_scan_segments = 1;
+ $frames_scan_per_segment = $max_frames_scan;
+ } else {
+ $pct_data_scanned += $this_pct_scanned;
+ break;
+ }
+ }
+ }
+ }
+ if ($pct_data_scanned > 0) {
+ $info['warning'][] = 'too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.';
+ foreach ($info['mpeg']['audio'] as $key1 => $value1) {
+ if (!preg_match('#_distribution$#i', $key1)) {
+ continue;
+ }
+ foreach ($value1 as $key2 => $value2) {
+ $info['mpeg']['audio'][$key1][$key2] = round($value2 / $pct_data_scanned);
+ }
+ }
+ }
+
+ if ($SynchErrorsFound > 0) {
+ $info['warning'][] = 'Found '.$SynchErrorsFound.' synch errors in histogram analysis';
+ //return false;
+ }
+
+ $bittotal = 0;
+ $framecounter = 0;
+ foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitratevalue => $bitratecount) {
+ $framecounter += $bitratecount;
+ if ($bitratevalue != 'free') {
+ $bittotal += ($bitratevalue * $bitratecount);
+ }
+ }
+ if ($framecounter == 0) {
+ $info['error'][] = 'Corrupt MP3 file: framecounter == zero';
+ return false;
+ }
+ $info['mpeg']['audio']['frame_count'] = getid3_lib::CastAsInt($framecounter);
+ $info['mpeg']['audio']['bitrate'] = ($bittotal / $framecounter);
+
+ $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate'];
+
+
+ // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently
+ $distinct_bitrates = 0;
+ foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitrate_value => $bitrate_count) {
+ if ($bitrate_count > 0) {
+ $distinct_bitrates++;
+ }
+ }
+ if ($distinct_bitrates > 1) {
+ $info['mpeg']['audio']['bitrate_mode'] = 'vbr';
+ } else {
+ $info['mpeg']['audio']['bitrate_mode'] = 'cbr';
+ }
+ $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode'];
+
+ }
+
+ break; // exit while()
+ }
+ }
+
+ $SynchSeekOffset++;
+ if (($avdataoffset + $SynchSeekOffset) >= $info['avdataend']) {
+ // end of file/data
+
+ if (empty($info['mpeg']['audio'])) {
+
+ $info['error'][] = 'could not find valid MPEG synch before end of file';
+ if (isset($info['audio']['bitrate'])) {
+ unset($info['audio']['bitrate']);
+ }
+ if (isset($info['mpeg']['audio'])) {
+ unset($info['mpeg']['audio']);
+ }
+ if (isset($info['mpeg']) && (!is_array($info['mpeg']) || empty($info['mpeg']))) {
+ unset($info['mpeg']);
+ }
+ return false;
+
+ }
+ break;
+ }
+
+ }
+ $info['audio']['channels'] = $info['mpeg']['audio']['channels'];
+ $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode'];
+ $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate'];
+ return true;
+ }
+
+
+ public static function MPEGaudioVersionArray() {
+ static $MPEGaudioVersion = array('2.5', false, '2', '1');
+ return $MPEGaudioVersion;
+ }
+
+ public static function MPEGaudioLayerArray() {
+ static $MPEGaudioLayer = array(false, 3, 2, 1);
+ return $MPEGaudioLayer;
+ }
+
+ public static function MPEGaudioBitrateArray() {
+ static $MPEGaudioBitrate;
+ if (empty($MPEGaudioBitrate)) {
+ $MPEGaudioBitrate = array (
+ '1' => array (1 => array('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000),
+ 2 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000),
+ 3 => array('free', 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000)
+ ),
+
+ '2' => array (1 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000),
+ 2 => array('free', 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000),
+ )
+ );
+ $MPEGaudioBitrate['2'][3] = $MPEGaudioBitrate['2'][2];
+ $MPEGaudioBitrate['2.5'] = $MPEGaudioBitrate['2'];
+ }
+ return $MPEGaudioBitrate;
+ }
+
+ public static function MPEGaudioFrequencyArray() {
+ static $MPEGaudioFrequency;
+ if (empty($MPEGaudioFrequency)) {
+ $MPEGaudioFrequency = array (
+ '1' => array(44100, 48000, 32000),
+ '2' => array(22050, 24000, 16000),
+ '2.5' => array(11025, 12000, 8000)
+ );
+ }
+ return $MPEGaudioFrequency;
+ }
+
+ public static function MPEGaudioChannelModeArray() {
+ static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono');
+ return $MPEGaudioChannelMode;
+ }
+
+ public static function MPEGaudioModeExtensionArray() {
+ static $MPEGaudioModeExtension;
+ if (empty($MPEGaudioModeExtension)) {
+ $MPEGaudioModeExtension = array (
+ 1 => array('4-31', '8-31', '12-31', '16-31'),
+ 2 => array('4-31', '8-31', '12-31', '16-31'),
+ 3 => array('', 'IS', 'MS', 'IS+MS')
+ );
+ }
+ return $MPEGaudioModeExtension;
+ }
+
+ public static function MPEGaudioEmphasisArray() {
+ static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17');
+ return $MPEGaudioEmphasis;
+ }
+
+ public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) {
+ return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15);
+ }
+
+ public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) {
+ if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) {
+ return false;
+ }
+
+ static $MPEGaudioVersionLookup;
+ static $MPEGaudioLayerLookup;
+ static $MPEGaudioBitrateLookup;
+ static $MPEGaudioFrequencyLookup;
+ static $MPEGaudioChannelModeLookup;
+ static $MPEGaudioModeExtensionLookup;
+ static $MPEGaudioEmphasisLookup;
+ if (empty($MPEGaudioVersionLookup)) {
+ $MPEGaudioVersionLookup = self::MPEGaudioVersionArray();
+ $MPEGaudioLayerLookup = self::MPEGaudioLayerArray();
+ $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray();
+ $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray();
+ $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray();
+ $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray();
+ $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray();
+ }
+
+ if (isset($MPEGaudioVersionLookup[$rawarray['version']])) {
+ $decodedVersion = $MPEGaudioVersionLookup[$rawarray['version']];
+ } else {
+ echo ($echoerrors ? "\n".'invalid Version ('.$rawarray['version'].')' : '');
+ return false;
+ }
+ if (isset($MPEGaudioLayerLookup[$rawarray['layer']])) {
+ $decodedLayer = $MPEGaudioLayerLookup[$rawarray['layer']];
+ } else {
+ echo ($echoerrors ? "\n".'invalid Layer ('.$rawarray['layer'].')' : '');
+ return false;
+ }
+ if (!isset($MPEGaudioBitrateLookup[$decodedVersion][$decodedLayer][$rawarray['bitrate']])) {
+ echo ($echoerrors ? "\n".'invalid Bitrate ('.$rawarray['bitrate'].')' : '');
+ if ($rawarray['bitrate'] == 15) {
+ // known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0
+ // let it go through here otherwise file will not be identified
+ if (!$allowBitrate15) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ if (!isset($MPEGaudioFrequencyLookup[$decodedVersion][$rawarray['sample_rate']])) {
+ echo ($echoerrors ? "\n".'invalid Frequency ('.$rawarray['sample_rate'].')' : '');
+ return false;
+ }
+ if (!isset($MPEGaudioChannelModeLookup[$rawarray['channelmode']])) {
+ echo ($echoerrors ? "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')' : '');
+ return false;
+ }
+ if (!isset($MPEGaudioModeExtensionLookup[$decodedLayer][$rawarray['modeextension']])) {
+ echo ($echoerrors ? "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')' : '');
+ return false;
+ }
+ if (!isset($MPEGaudioEmphasisLookup[$rawarray['emphasis']])) {
+ echo ($echoerrors ? "\n".'invalid Emphasis ('.$rawarray['emphasis'].')' : '');
+ return false;
+ }
+ // These are just either set or not set, you can't mess that up :)
+ // $rawarray['protection'];
+ // $rawarray['padding'];
+ // $rawarray['private'];
+ // $rawarray['copyright'];
+ // $rawarray['original'];
+
+ return true;
+ }
+
+ public static function MPEGaudioHeaderDecode($Header4Bytes) {
+ // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM
+ // A - Frame sync (all bits set)
+ // B - MPEG Audio version ID
+ // C - Layer description
+ // D - Protection bit
+ // E - Bitrate index
+ // F - Sampling rate frequency index
+ // G - Padding bit
+ // H - Private bit
+ // I - Channel Mode
+ // J - Mode extension (Only if Joint stereo)
+ // K - Copyright
+ // L - Original
+ // M - Emphasis
+
+ if (strlen($Header4Bytes) != 4) {
+ return false;
+ }
+
+ $MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4;
+ $MPEGrawHeader['version'] = (ord($Header4Bytes{1}) & 0x18) >> 3; // BB
+ $MPEGrawHeader['layer'] = (ord($Header4Bytes{1}) & 0x06) >> 1; // CC
+ $MPEGrawHeader['protection'] = (ord($Header4Bytes{1}) & 0x01); // D
+ $MPEGrawHeader['bitrate'] = (ord($Header4Bytes{2}) & 0xF0) >> 4; // EEEE
+ $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes{2}) & 0x0C) >> 2; // FF
+ $MPEGrawHeader['padding'] = (ord($Header4Bytes{2}) & 0x02) >> 1; // G
+ $MPEGrawHeader['private'] = (ord($Header4Bytes{2}) & 0x01); // H
+ $MPEGrawHeader['channelmode'] = (ord($Header4Bytes{3}) & 0xC0) >> 6; // II
+ $MPEGrawHeader['modeextension'] = (ord($Header4Bytes{3}) & 0x30) >> 4; // JJ
+ $MPEGrawHeader['copyright'] = (ord($Header4Bytes{3}) & 0x08) >> 3; // K
+ $MPEGrawHeader['original'] = (ord($Header4Bytes{3}) & 0x04) >> 2; // L
+ $MPEGrawHeader['emphasis'] = (ord($Header4Bytes{3}) & 0x03); // MM
+
+ return $MPEGrawHeader;
+ }
+
+ public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) {
+ static $AudioFrameLengthCache = array();
+
+ if (!isset($AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate])) {
+ $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = false;
+ if ($bitrate != 'free') {
+
+ if ($version == '1') {
+
+ if ($layer == '1') {
+
+ // For Layer I slot is 32 bits long
+ $FrameLengthCoefficient = 48;
+ $SlotLength = 4;
+
+ } else { // Layer 2 / 3
+
+ // for Layer 2 and Layer 3 slot is 8 bits long.
+ $FrameLengthCoefficient = 144;
+ $SlotLength = 1;
+
+ }
+
+ } else { // MPEG-2 / MPEG-2.5
+
+ if ($layer == '1') {
+
+ // For Layer I slot is 32 bits long
+ $FrameLengthCoefficient = 24;
+ $SlotLength = 4;
+
+ } elseif ($layer == '2') {
+
+ // for Layer 2 and Layer 3 slot is 8 bits long.
+ $FrameLengthCoefficient = 144;
+ $SlotLength = 1;
+
+ } else { // layer 3
+
+ // for Layer 2 and Layer 3 slot is 8 bits long.
+ $FrameLengthCoefficient = 72;
+ $SlotLength = 1;
+
+ }
+
+ }
+
+ // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding
+ if ($samplerate > 0) {
+ $NewFramelength = ($FrameLengthCoefficient * $bitrate) / $samplerate;
+ $NewFramelength = floor($NewFramelength / $SlotLength) * $SlotLength; // round to next-lower multiple of SlotLength (1 byte for Layer 2/3, 4 bytes for Layer I)
+ if ($padding) {
+ $NewFramelength += $SlotLength;
+ }
+ $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = (int) $NewFramelength;
+ }
+ }
+ }
+ return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate];
+ }
+
+ public static function ClosestStandardMP3Bitrate($bit_rate) {
+ static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000);
+ static $bit_rate_table = array (0=>'-');
+ $round_bit_rate = intval(round($bit_rate, -3));
+ if (!isset($bit_rate_table[$round_bit_rate])) {
+ if ($round_bit_rate > max($standard_bit_rates)) {
+ $bit_rate_table[$round_bit_rate] = round($bit_rate, 2 - strlen($bit_rate));
+ } else {
+ $bit_rate_table[$round_bit_rate] = max($standard_bit_rates);
+ foreach ($standard_bit_rates as $standard_bit_rate) {
+ if ($round_bit_rate >= $standard_bit_rate + (($bit_rate_table[$round_bit_rate] - $standard_bit_rate) / 2)) {
+ break;
+ }
+ $bit_rate_table[$round_bit_rate] = $standard_bit_rate;
+ }
+ }
+ }
+ return $bit_rate_table[$round_bit_rate];
+ }
+
+ public static function XingVBRidOffset($version, $channelmode) {
+ static $XingVBRidOffsetCache = array();
+ if (empty($XingVBRidOffset)) {
+ $XingVBRidOffset = array (
+ '1' => array ('mono' => 0x15, // 4 + 17 = 21
+ 'stereo' => 0x24, // 4 + 32 = 36
+ 'joint stereo' => 0x24,
+ 'dual channel' => 0x24
+ ),
+
+ '2' => array ('mono' => 0x0D, // 4 + 9 = 13
+ 'stereo' => 0x15, // 4 + 17 = 21
+ 'joint stereo' => 0x15,
+ 'dual channel' => 0x15
+ ),
+
+ '2.5' => array ('mono' => 0x15,
+ 'stereo' => 0x15,
+ 'joint stereo' => 0x15,
+ 'dual channel' => 0x15
+ )
+ );
+ }
+ return $XingVBRidOffset[$version][$channelmode];
+ }
+
+ public static function LAMEvbrMethodLookup($VBRmethodID) {
+ static $LAMEvbrMethodLookup = array(
+ 0x00 => 'unknown',
+ 0x01 => 'cbr',
+ 0x02 => 'abr',
+ 0x03 => 'vbr-old / vbr-rh',
+ 0x04 => 'vbr-new / vbr-mtrh',
+ 0x05 => 'vbr-mt',
+ 0x06 => 'vbr (full vbr method 4)',
+ 0x08 => 'cbr (constant bitrate 2 pass)',
+ 0x09 => 'abr (2 pass)',
+ 0x0F => 'reserved'
+ );
+ return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : '');
+ }
+
+ public static function LAMEmiscStereoModeLookup($StereoModeID) {
+ static $LAMEmiscStereoModeLookup = array(
+ 0 => 'mono',
+ 1 => 'stereo',
+ 2 => 'dual mono',
+ 3 => 'joint stereo',
+ 4 => 'forced stereo',
+ 5 => 'auto',
+ 6 => 'intensity stereo',
+ 7 => 'other'
+ );
+ return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : '');
+ }
+
+ public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) {
+ static $LAMEmiscSourceSampleFrequencyLookup = array(
+ 0 => '<= 32 kHz',
+ 1 => '44.1 kHz',
+ 2 => '48 kHz',
+ 3 => '> 48kHz'
+ );
+ return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : '');
+ }
+
+ public static function LAMEsurroundInfoLookup($SurroundInfoID) {
+ static $LAMEsurroundInfoLookup = array(
+ 0 => 'no surround info',
+ 1 => 'DPL encoding',
+ 2 => 'DPL2 encoding',
+ 3 => 'Ambisonic encoding'
+ );
+ return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved');
+ }
+
+ public static function LAMEpresetUsedLookup($LAMEtag) {
+
+ if ($LAMEtag['preset_used_id'] == 0) {
+ // no preset used (LAME >=3.93)
+ // no preset recorded (LAME <3.93)
+ return '';
+ }
+ $LAMEpresetUsedLookup = array();
+
+ ///// THIS PART CANNOT BE STATIC .
+ for ($i = 8; $i <= 320; $i++) {
+ switch ($LAMEtag['vbr_method']) {
+ case 'cbr':
+ $LAMEpresetUsedLookup[$i] = '--alt-preset '.$LAMEtag['vbr_method'].' '.$i;
+ break;
+ case 'abr':
+ default: // other VBR modes shouldn't be here(?)
+ $LAMEpresetUsedLookup[$i] = '--alt-preset '.$i;
+ break;
+ }
+ }
+
+ // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions()
+
+ // named alt-presets
+ $LAMEpresetUsedLookup[1000] = '--r3mix';
+ $LAMEpresetUsedLookup[1001] = '--alt-preset standard';
+ $LAMEpresetUsedLookup[1002] = '--alt-preset extreme';
+ $LAMEpresetUsedLookup[1003] = '--alt-preset insane';
+ $LAMEpresetUsedLookup[1004] = '--alt-preset fast standard';
+ $LAMEpresetUsedLookup[1005] = '--alt-preset fast extreme';
+ $LAMEpresetUsedLookup[1006] = '--alt-preset medium';
+ $LAMEpresetUsedLookup[1007] = '--alt-preset fast medium';
+
+ // LAME 3.94 additions/changes
+ $LAMEpresetUsedLookup[1010] = '--preset portable'; // 3.94a15 Oct 21 2003
+ $LAMEpresetUsedLookup[1015] = '--preset radio'; // 3.94a15 Oct 21 2003
+
+ $LAMEpresetUsedLookup[320] = '--preset insane'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[410] = '-V9';
+ $LAMEpresetUsedLookup[420] = '-V8';
+ $LAMEpresetUsedLookup[440] = '-V6';
+ $LAMEpresetUsedLookup[430] = '--preset radio'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[450] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[460] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[470] = '--r3mix'; // 3.94b1 Dec 18 2003
+ $LAMEpresetUsedLookup[480] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard'; // 3.94a15 Nov 12 2003
+ $LAMEpresetUsedLookup[490] = '-V1';
+ $LAMEpresetUsedLookup[500] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme'; // 3.94a15 Nov 12 2003
+
+ return (isset($LAMEpresetUsedLookup[$LAMEtag['preset_used_id']]) ? $LAMEpresetUsedLookup[$LAMEtag['preset_used_id']] : 'new/unknown preset: '.$LAMEtag['preset_used_id'].' - report to info@getid3.org');
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.audio.ogg.php b/extensions/TimedMediaHandler/libs/getid3/module.audio.ogg.php
new file mode 100644
index 00000000..a2a35aad
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.audio.ogg.php
@@ -0,0 +1,671 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.audio.ogg.php //
+// module for analyzing Ogg Vorbis, OggFLAC and Speex files //
+// dependencies: module.audio.flac.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true);
+
+class getid3_ogg extends getid3_handler
+{
+ // http://xiph.org/vorbis/doc/Vorbis_I_spec.html
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ $info['fileformat'] = 'ogg';
+
+ // Warn about illegal tags - only vorbiscomments are allowed
+ if (isset($info['id3v2'])) {
+ $info['warning'][] = 'Illegal ID3v2 tag present.';
+ }
+ if (isset($info['id3v1'])) {
+ $info['warning'][] = 'Illegal ID3v1 tag present.';
+ }
+ if (isset($info['ape'])) {
+ $info['warning'][] = 'Illegal APE tag present.';
+ }
+
+
+ // Page 1 - Stream Header
+
+ $this->fseek($info['avdataoffset']);
+
+ $oggpageinfo = $this->ParseOggPageHeader();
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
+
+ if ($this->ftell() >= $this->getid3->fread_buffer_size()) {
+ $info['error'][] = 'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)';
+ unset($info['fileformat']);
+ unset($info['ogg']);
+ return false;
+ }
+
+ $filedata = $this->fread($oggpageinfo['page_length']);
+ $filedataoffset = 0;
+
+ if (substr($filedata, 0, 4) == 'fLaC') {
+
+ $info['audio']['dataformat'] = 'flac';
+ $info['audio']['bitrate_mode'] = 'vbr';
+ $info['audio']['lossless'] = true;
+
+ } elseif (substr($filedata, 1, 6) == 'vorbis') {
+
+ $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
+
+ } elseif (substr($filedata, 0, 8) == 'Speex ') {
+
+ // http://www.speex.org/manual/node10.html
+
+ $info['audio']['dataformat'] = 'speex';
+ $info['mime_type'] = 'audio/speex';
+ $info['audio']['bitrate_mode'] = 'abr';
+ $info['audio']['lossless'] = false;
+
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex '
+ $filedataoffset += 8;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version'] = substr($filedata, $filedataoffset, 20);
+ $filedataoffset += 20;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+
+ $info['speex']['speex_version'] = trim($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']);
+ $info['speex']['sample_rate'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'];
+ $info['speex']['channels'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'];
+ $info['speex']['vbr'] = (bool) $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'];
+ $info['speex']['band_type'] = $this->SpeexBandModeLookup($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']);
+
+ $info['audio']['sample_rate'] = $info['speex']['sample_rate'];
+ $info['audio']['channels'] = $info['speex']['channels'];
+ if ($info['speex']['vbr']) {
+ $info['audio']['bitrate_mode'] = 'vbr';
+ }
+
+
+ } elseif (substr($filedata, 0, 8) == "fishead\x00") {
+
+ // Ogg Skeleton version 3.0 Format Specification
+ // http://xiph.org/ogg/doc/skeleton.html
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['version_major'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
+ $filedataoffset += 2;
+ $info['ogg']['skeleton']['fishead']['raw']['version_minor'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2));
+ $filedataoffset += 2;
+ $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fishead']['raw']['utc'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 20));
+ $filedataoffset += 20;
+
+ $info['ogg']['skeleton']['fishead']['version'] = $info['ogg']['skeleton']['fishead']['raw']['version_major'].'.'.$info['ogg']['skeleton']['fishead']['raw']['version_minor'];
+ $info['ogg']['skeleton']['fishead']['presentationtime'] = $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'];
+ $info['ogg']['skeleton']['fishead']['basetime'] = $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'];
+ $info['ogg']['skeleton']['fishead']['utc'] = $info['ogg']['skeleton']['fishead']['raw']['utc'];
+
+
+ $counter = 0;
+ do {
+ $oggpageinfo = $this->ParseOggPageHeader();
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno'].'.'.$counter++] = $oggpageinfo;
+ $filedata = $this->fread($oggpageinfo['page_length']);
+ $this->fseek($oggpageinfo['page_end_offset']);
+
+ if (substr($filedata, 0, 8) == "fisbone\x00") {
+
+ $filedataoffset = 8;
+ $info['ogg']['skeleton']['fisbone']['raw']['message_header_offset'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['skeleton']['fisbone']['raw']['serial_number'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['skeleton']['fisbone']['raw']['number_header_packets'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['skeleton']['fisbone']['raw']['granulerate_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fisbone']['raw']['granulerate_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fisbone']['raw']['basegranule'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $info['ogg']['skeleton']['fisbone']['raw']['preroll'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['skeleton']['fisbone']['raw']['granuleshift'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $info['ogg']['skeleton']['fisbone']['raw']['padding'] = substr($filedata, $filedataoffset, 3);
+ $filedataoffset += 3;
+
+ } elseif (substr($filedata, 1, 6) == 'theora') {
+
+ $info['video']['dataformat'] = 'theora';
+ $info['error'][] = 'Ogg Theora not correctly handled in this version of getID3 ['.$this->getid3->version().']';
+ //break;
+
+ } elseif (substr($filedata, 1, 6) == 'vorbis') {
+
+ $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo);
+
+ } else {
+ $info['error'][] = 'unexpected';
+ //break;
+ }
+ //} while ($oggpageinfo['page_seqno'] == 0);
+ } while (($oggpageinfo['page_seqno'] == 0) && (substr($filedata, 0, 8) != "fisbone\x00"));
+
+ $this->fseek($oggpageinfo['page_start_offset']);
+
+ $info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']';
+ //return false;
+
+ } else {
+
+ $info['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"';
+ unset($info['ogg']);
+ unset($info['mime_type']);
+ return false;
+
+ }
+
+ // Page 2 - Comment Header
+ $oggpageinfo = $this->ParseOggPageHeader();
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
+
+ switch ($info['audio']['dataformat']) {
+ case 'vorbis':
+ $filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1));
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 1, 6); // hard-coded to 'vorbis'
+
+ $this->ParseVorbisComments();
+ break;
+
+ case 'flac':
+ $flac = new getid3_flac($this->getid3);
+ if (!$flac->parseMETAdata()) {
+ $info['error'][] = 'Failed to parse FLAC headers';
+ return false;
+ }
+ unset($flac);
+ break;
+
+ case 'speex':
+ $this->fseek($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR);
+ $this->ParseVorbisComments();
+ break;
+ }
+
+
+ // Last Page - Number of Samples
+ if (!getid3_lib::intValueSupported($info['avdataend'])) {
+
+ $info['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)';
+
+ } else {
+
+ $this->fseek(max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0));
+ $LastChunkOfOgg = strrev($this->fread($this->getid3->fread_buffer_size()));
+ if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) {
+ $this->fseek($info['avdataend'] - ($LastOggSpostion + strlen('SggO')));
+ $info['avdataend'] = $this->ftell();
+ $info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader();
+ $info['ogg']['samples'] = $info['ogg']['pageheader']['eos']['pcm_abs_position'];
+ if ($info['ogg']['samples'] == 0) {
+ $info['error'][] = 'Corrupt Ogg file: eos.number of samples == zero';
+ return false;
+ }
+ if (!empty($info['audio']['sample_rate'])) {
+ $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']);
+ }
+ }
+
+ }
+
+ if (!empty($info['ogg']['bitrate_average'])) {
+ $info['audio']['bitrate'] = $info['ogg']['bitrate_average'];
+ } elseif (!empty($info['ogg']['bitrate_nominal'])) {
+ $info['audio']['bitrate'] = $info['ogg']['bitrate_nominal'];
+ } elseif (!empty($info['ogg']['bitrate_min']) && !empty($info['ogg']['bitrate_max'])) {
+ $info['audio']['bitrate'] = ($info['ogg']['bitrate_min'] + $info['ogg']['bitrate_max']) / 2;
+ }
+ if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) {
+ if ($info['audio']['bitrate'] == 0) {
+ $info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero';
+ return false;
+ }
+ $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']);
+ }
+
+ if (isset($info['ogg']['vendor'])) {
+ $info['audio']['encoder'] = preg_replace('/^Encoded with /', '', $info['ogg']['vendor']);
+
+ // Vorbis only
+ if ($info['audio']['dataformat'] == 'vorbis') {
+
+ // Vorbis 1.0 starts with Xiph.Org
+ if (preg_match('/^Xiph.Org/', $info['audio']['encoder'])) {
+
+ if ($info['audio']['bitrate_mode'] == 'abr') {
+
+ // Set -b 128 on abr files
+ $info['audio']['encoder_options'] = '-b '.round($info['ogg']['bitrate_nominal'] / 1000);
+
+ } elseif (($info['audio']['bitrate_mode'] == 'vbr') && ($info['audio']['channels'] == 2) && ($info['audio']['sample_rate'] >= 44100) && ($info['audio']['sample_rate'] <= 48000)) {
+ // Set -q N on vbr files
+ $info['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($info['ogg']['bitrate_nominal']);
+
+ }
+ }
+
+ if (empty($info['audio']['encoder_options']) && !empty($info['ogg']['bitrate_nominal'])) {
+ $info['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($info['ogg']['bitrate_nominal'] / 1000)).'kbps';
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) {
+ $info = &$this->getid3->info;
+ $info['audio']['dataformat'] = 'vorbis';
+ $info['audio']['lossless'] = false;
+
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis'
+ $filedataoffset += 6;
+ $info['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $info['audio']['channels'] = $info['ogg']['numberofchannels'];
+ $info['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ if ($info['ogg']['samplerate'] == 0) {
+ $info['error'][] = 'Corrupt Ogg file: sample rate == zero';
+ return false;
+ }
+ $info['audio']['sample_rate'] = $info['ogg']['samplerate'];
+ $info['ogg']['samples'] = 0; // filled in later
+ $info['ogg']['bitrate_average'] = 0; // filled in later
+ $info['ogg']['bitrate_max'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['bitrate_nominal'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['bitrate_min'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $info['ogg']['blocksize_small'] = pow(2, getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F);
+ $info['ogg']['blocksize_large'] = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4);
+ $info['ogg']['stop_bit'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet
+
+ $info['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr
+ if ($info['ogg']['bitrate_max'] == 0xFFFFFFFF) {
+ unset($info['ogg']['bitrate_max']);
+ $info['audio']['bitrate_mode'] = 'abr';
+ }
+ if ($info['ogg']['bitrate_nominal'] == 0xFFFFFFFF) {
+ unset($info['ogg']['bitrate_nominal']);
+ }
+ if ($info['ogg']['bitrate_min'] == 0xFFFFFFFF) {
+ unset($info['ogg']['bitrate_min']);
+ $info['audio']['bitrate_mode'] = 'abr';
+ }
+ return true;
+ }
+
+ public function ParseOggPageHeader() {
+ // http://xiph.org/ogg/vorbis/doc/framing.html
+ $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file
+
+ $filedata = $this->fread($this->getid3->fread_buffer_size());
+ $filedataoffset = 0;
+ while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) {
+ if (($this->ftell() - $oggheader['page_start_offset']) >= $this->getid3->fread_buffer_size()) {
+ // should be found before here
+ return false;
+ }
+ if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) {
+ if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === false)) {
+ // get some more data, unless eof, in which case fail
+ return false;
+ }
+ }
+ }
+ $filedataoffset += strlen('OggS') - 1; // page, delimited by 'OggS'
+
+ $oggheader['stream_structver'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $oggheader['flags_raw'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $oggheader['flags']['fresh'] = (bool) ($oggheader['flags_raw'] & 0x01); // fresh packet
+ $oggheader['flags']['bos'] = (bool) ($oggheader['flags_raw'] & 0x02); // first page of logical bitstream (bos)
+ $oggheader['flags']['eos'] = (bool) ($oggheader['flags_raw'] & 0x04); // last page of logical bitstream (eos)
+
+ $oggheader['pcm_abs_position'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8));
+ $filedataoffset += 8;
+ $oggheader['stream_serialno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $oggheader['page_seqno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $oggheader['page_checksum'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4));
+ $filedataoffset += 4;
+ $oggheader['page_segments'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $oggheader['page_length'] = 0;
+ for ($i = 0; $i < $oggheader['page_segments']; $i++) {
+ $oggheader['segment_table'][$i] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1));
+ $filedataoffset += 1;
+ $oggheader['page_length'] += $oggheader['segment_table'][$i];
+ }
+ $oggheader['header_end_offset'] = $oggheader['page_start_offset'] + $filedataoffset;
+ $oggheader['page_end_offset'] = $oggheader['header_end_offset'] + $oggheader['page_length'];
+ $this->fseek($oggheader['header_end_offset']);
+
+ return $oggheader;
+ }
+
+ // http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005
+ public function ParseVorbisComments() {
+ $info = &$this->getid3->info;
+
+ $OriginalOffset = $this->ftell();
+ $commentdataoffset = 0;
+ $VorbisCommentPage = 1;
+
+ switch ($info['audio']['dataformat']) {
+ case 'vorbis':
+ case 'speex':
+ $CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block
+ $this->fseek($CommentStartOffset);
+ $commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments'];
+ $commentdata = $this->fread(self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset);
+
+ if ($info['audio']['dataformat'] == 'vorbis') {
+ $commentdataoffset += (strlen('vorbis') + 1);
+ }
+ break;
+
+ case 'flac':
+ $CommentStartOffset = $info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4;
+ $this->fseek($CommentStartOffset);
+ $commentdata = $this->fread($info['flac']['VORBIS_COMMENT']['raw']['block_length']);
+ break;
+
+ default:
+ return false;
+ }
+
+ $VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
+ $commentdataoffset += 4;
+
+ $info['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize);
+ $commentdataoffset += $VendorSize;
+
+ $CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
+ $commentdataoffset += 4;
+ $info['avdataoffset'] = $CommentStartOffset + $commentdataoffset;
+
+ $basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT');
+ $ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw'];
+ for ($i = 0; $i < $CommentsCount; $i++) {
+
+ $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset;
+
+ if ($this->ftell() < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) {
+ if ($oggpageinfo = $this->ParseOggPageHeader()) {
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
+
+ $VorbisCommentPage++;
+
+ // First, save what we haven't read yet
+ $AsYetUnusedData = substr($commentdata, $commentdataoffset);
+
+ // Then take that data off the end
+ $commentdata = substr($commentdata, 0, $commentdataoffset);
+
+ // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
+ $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
+ $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
+
+ // Finally, stick the unused data back on the end
+ $commentdata .= $AsYetUnusedData;
+
+ //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
+ $commentdata .= $this->fread($this->OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1));
+ }
+
+ }
+ $ThisFileInfo_ogg_comments_raw[$i]['size'] = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4));
+
+ // replace avdataoffset with position just after the last vorbiscomment
+ $info['avdataoffset'] = $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + $ThisFileInfo_ogg_comments_raw[$i]['size'] + 4;
+
+ $commentdataoffset += 4;
+ while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) {
+ if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) {
+ $info['warning'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments';
+ break 2;
+ }
+
+ $VorbisCommentPage++;
+
+ $oggpageinfo = $this->ParseOggPageHeader();
+ $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo;
+
+ // First, save what we haven't read yet
+ $AsYetUnusedData = substr($commentdata, $commentdataoffset);
+
+ // Then take that data off the end
+ $commentdata = substr($commentdata, 0, $commentdataoffset);
+
+ // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct
+ $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
+ $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']);
+
+ // Finally, stick the unused data back on the end
+ $commentdata .= $AsYetUnusedData;
+
+ //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']);
+ if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) {
+ $info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
+ break;
+ }
+ $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1);
+ if ($readlength <= 0) {
+ $info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell();
+ break;
+ }
+ $commentdata .= $this->fread($readlength);
+
+ //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset'];
+ }
+ $ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset;
+ $commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']);
+ $commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size'];
+
+ if (!$commentstring) {
+
+ // no comment?
+ $info['warning'][] = 'Blank Ogg comment ['.$i.']';
+
+ } elseif (strstr($commentstring, '=')) {
+
+ $commentexploded = explode('=', $commentstring, 2);
+ $ThisFileInfo_ogg_comments_raw[$i]['key'] = strtoupper($commentexploded[0]);
+ $ThisFileInfo_ogg_comments_raw[$i]['value'] = (isset($commentexploded[1]) ? $commentexploded[1] : '');
+
+ if ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'METADATA_BLOCK_PICTURE') {
+
+ // http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
+ // The unencoded format is that of the FLAC picture block. The fields are stored in big endian order as in FLAC, picture data is stored according to the relevant standard.
+ // http://flac.sourceforge.net/format.html#metadata_block_picture
+ $flac = new getid3_flac($this->getid3);
+ $flac->setStringMode(base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']));
+ $flac->parsePICTURE();
+ $info['ogg']['comments']['picture'][] = $flac->getid3->info['flac']['PICTURE'][0];
+ unset($flac);
+
+ } elseif ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'COVERART') {
+
+ $data = base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']);
+ $this->notice('Found deprecated COVERART tag, it should be replaced in honor of METADATA_BLOCK_PICTURE structure');
+ /** @todo use 'coverartmime' where available */
+ $imageinfo = getid3_lib::GetDataImageSize($data);
+ if ($imageinfo === false || !isset($imageinfo['mime'])) {
+ $this->warning('COVERART vorbiscomment tag contains invalid image');
+ continue;
+ }
+
+ $ogg = new self($this->getid3);
+ $ogg->setStringMode($data);
+ $info['ogg']['comments']['picture'][] = array(
+ 'image_mime' => $imageinfo['mime'],
+ 'data' => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']),
+ );
+ unset($ogg);
+
+ } else {
+
+ $info['ogg']['comments'][strtolower($ThisFileInfo_ogg_comments_raw[$i]['key'])][] = $ThisFileInfo_ogg_comments_raw[$i]['value'];
+
+ }
+
+ } else {
+
+ $info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring;
+
+ }
+ unset($ThisFileInfo_ogg_comments_raw[$i]);
+ }
+ unset($ThisFileInfo_ogg_comments_raw);
+
+
+ // Replay Gain Adjustment
+ // http://privatewww.essex.ac.uk/~djmrob/replaygain/
+ if (isset($info['ogg']['comments']) && is_array($info['ogg']['comments'])) {
+ foreach ($info['ogg']['comments'] as $index => $commentvalue) {
+ switch ($index) {
+ case 'rg_audiophile':
+ case 'replaygain_album_gain':
+ $info['replay_gain']['album']['adjustment'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ case 'rg_radio':
+ case 'replaygain_track_gain':
+ $info['replay_gain']['track']['adjustment'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ case 'replaygain_album_peak':
+ $info['replay_gain']['album']['peak'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ case 'rg_peak':
+ case 'replaygain_track_peak':
+ $info['replay_gain']['track']['peak'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ case 'replaygain_reference_loudness':
+ $info['replay_gain']['reference_volume'] = (double) $commentvalue[0];
+ unset($info['ogg']['comments'][$index]);
+ break;
+
+ default:
+ // do nothing
+ break;
+ }
+ }
+ }
+
+ $this->fseek($OriginalOffset);
+
+ return true;
+ }
+
+ public static function SpeexBandModeLookup($mode) {
+ static $SpeexBandModeLookup = array();
+ if (empty($SpeexBandModeLookup)) {
+ $SpeexBandModeLookup[0] = 'narrow';
+ $SpeexBandModeLookup[1] = 'wide';
+ $SpeexBandModeLookup[2] = 'ultra-wide';
+ }
+ return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null);
+ }
+
+
+ public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) {
+ for ($i = 0; $i < $SegmentNumber; $i++) {
+ $segmentlength = 0;
+ foreach ($OggInfoArray['segment_table'] as $key => $value) {
+ $segmentlength += $value;
+ if ($value < 255) {
+ break;
+ }
+ }
+ }
+ return $segmentlength;
+ }
+
+
+ public static function get_quality_from_nominal_bitrate($nominal_bitrate) {
+
+ // decrease precision
+ $nominal_bitrate = $nominal_bitrate / 1000;
+
+ if ($nominal_bitrate < 128) {
+ // q-1 to q4
+ $qval = ($nominal_bitrate - 64) / 16;
+ } elseif ($nominal_bitrate < 256) {
+ // q4 to q8
+ $qval = $nominal_bitrate / 32;
+ } elseif ($nominal_bitrate < 320) {
+ // q8 to q9
+ $qval = ($nominal_bitrate + 256) / 64;
+ } else {
+ // q9 to q10
+ $qval = ($nominal_bitrate + 1300) / 180;
+ }
+ //return $qval; // 5.031324
+ //return intval($qval); // 5
+ return round($qval, 1); // 5 or 4.9
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.tag.id3v1.php b/extensions/TimedMediaHandler/libs/getid3/module.tag.id3v1.php
new file mode 100644
index 00000000..fd9069e0
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.tag.id3v1.php
@@ -0,0 +1,359 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+// //
+// module.tag.id3v1.php //
+// module for analyzing ID3v1 tags //
+// dependencies: NONE //
+// ///
+/////////////////////////////////////////////////////////////////
+
+
+class getid3_id3v1 extends getid3_handler
+{
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ if (!getid3_lib::intValueSupported($info['filesize'])) {
+ $info['warning'][] = 'Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB';
+ return false;
+ }
+
+ fseek($this->getid3->fp, -256, SEEK_END);
+ $preid3v1 = fread($this->getid3->fp, 128);
+ $id3v1tag = fread($this->getid3->fp, 128);
+
+ if (substr($id3v1tag, 0, 3) == 'TAG') {
+
+ $info['avdataend'] = $info['filesize'] - 128;
+
+ $ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30));
+ $ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30));
+ $ParsedID3v1['album'] = $this->cutfield(substr($id3v1tag, 63, 30));
+ $ParsedID3v1['year'] = $this->cutfield(substr($id3v1tag, 93, 4));
+ $ParsedID3v1['comment'] = substr($id3v1tag, 97, 30); // can't remove nulls yet, track detection depends on them
+ $ParsedID3v1['genreid'] = ord(substr($id3v1tag, 127, 1));
+
+ // If second-last byte of comment field is null and last byte of comment field is non-null
+ // then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number
+ if (($id3v1tag{125} === "\x00") && ($id3v1tag{126} !== "\x00")) {
+ $ParsedID3v1['track'] = ord(substr($ParsedID3v1['comment'], 29, 1));
+ $ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28);
+ }
+ $ParsedID3v1['comment'] = $this->cutfield($ParsedID3v1['comment']);
+
+ $ParsedID3v1['genre'] = $this->LookupGenreName($ParsedID3v1['genreid']);
+ if (!empty($ParsedID3v1['genre'])) {
+ unset($ParsedID3v1['genreid']);
+ }
+ if (isset($ParsedID3v1['genre']) && (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown'))) {
+ unset($ParsedID3v1['genre']);
+ }
+
+ foreach ($ParsedID3v1 as $key => $value) {
+ $ParsedID3v1['comments'][$key][0] = $value;
+ }
+
+ // ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces
+ $GoodFormatID3v1tag = $this->GenerateID3v1Tag(
+ $ParsedID3v1['title'],
+ $ParsedID3v1['artist'],
+ $ParsedID3v1['album'],
+ $ParsedID3v1['year'],
+ (isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false),
+ $ParsedID3v1['comment'],
+ (!empty($ParsedID3v1['track']) ? $ParsedID3v1['track'] : ''));
+ $ParsedID3v1['padding_valid'] = true;
+ if ($id3v1tag !== $GoodFormatID3v1tag) {
+ $ParsedID3v1['padding_valid'] = false;
+ $info['warning'][] = 'Some ID3v1 fields do not use NULL characters for padding';
+ }
+
+ $ParsedID3v1['tag_offset_end'] = $info['filesize'];
+ $ParsedID3v1['tag_offset_start'] = $ParsedID3v1['tag_offset_end'] - 128;
+
+ $info['id3v1'] = $ParsedID3v1;
+ }
+
+ if (substr($preid3v1, 0, 3) == 'TAG') {
+ // The way iTunes handles tags is, well, brain-damaged.
+ // It completely ignores v1 if ID3v2 is present.
+ // This goes as far as adding a new v1 tag *even if there already is one*
+
+ // A suspected double-ID3v1 tag has been detected, but it could be that
+ // the "TAG" identifier is a legitimate part of an APE or Lyrics3 tag
+ if (substr($preid3v1, 96, 8) == 'APETAGEX') {
+ // an APE tag footer was found before the last ID3v1, assume false "TAG" synch
+ } elseif (substr($preid3v1, 119, 6) == 'LYRICS') {
+ // a Lyrics3 tag footer was found before the last ID3v1, assume false "TAG" synch
+ } else {
+ // APE and Lyrics3 footers not found - assume double ID3v1
+ $info['warning'][] = 'Duplicate ID3v1 tag detected - this has been known to happen with iTunes';
+ $info['avdataend'] -= 128;
+ }
+ }
+
+ return true;
+ }
+
+ public static function cutfield($str) {
+ return trim(substr($str, 0, strcspn($str, "\x00")));
+ }
+
+ public static function ArrayOfGenres($allowSCMPXextended=false) {
+ static $GenreLookup = array(
+ 0 => 'Blues',
+ 1 => 'Classic Rock',
+ 2 => 'Country',
+ 3 => 'Dance',
+ 4 => 'Disco',
+ 5 => 'Funk',
+ 6 => 'Grunge',
+ 7 => 'Hip-Hop',
+ 8 => 'Jazz',
+ 9 => 'Metal',
+ 10 => 'New Age',
+ 11 => 'Oldies',
+ 12 => 'Other',
+ 13 => 'Pop',
+ 14 => 'R&B',
+ 15 => 'Rap',
+ 16 => 'Reggae',
+ 17 => 'Rock',
+ 18 => 'Techno',
+ 19 => 'Industrial',
+ 20 => 'Alternative',
+ 21 => 'Ska',
+ 22 => 'Death Metal',
+ 23 => 'Pranks',
+ 24 => 'Soundtrack',
+ 25 => 'Euro-Techno',
+ 26 => 'Ambient',
+ 27 => 'Trip-Hop',
+ 28 => 'Vocal',
+ 29 => 'Jazz+Funk',
+ 30 => 'Fusion',
+ 31 => 'Trance',
+ 32 => 'Classical',
+ 33 => 'Instrumental',
+ 34 => 'Acid',
+ 35 => 'House',
+ 36 => 'Game',
+ 37 => 'Sound Clip',
+ 38 => 'Gospel',
+ 39 => 'Noise',
+ 40 => 'Alt. Rock',
+ 41 => 'Bass',
+ 42 => 'Soul',
+ 43 => 'Punk',
+ 44 => 'Space',
+ 45 => 'Meditative',
+ 46 => 'Instrumental Pop',
+ 47 => 'Instrumental Rock',
+ 48 => 'Ethnic',
+ 49 => 'Gothic',
+ 50 => 'Darkwave',
+ 51 => 'Techno-Industrial',
+ 52 => 'Electronic',
+ 53 => 'Pop-Folk',
+ 54 => 'Eurodance',
+ 55 => 'Dream',
+ 56 => 'Southern Rock',
+ 57 => 'Comedy',
+ 58 => 'Cult',
+ 59 => 'Gangsta Rap',
+ 60 => 'Top 40',
+ 61 => 'Christian Rap',
+ 62 => 'Pop/Funk',
+ 63 => 'Jungle',
+ 64 => 'Native American',
+ 65 => 'Cabaret',
+ 66 => 'New Wave',
+ 67 => 'Psychedelic',
+ 68 => 'Rave',
+ 69 => 'Showtunes',
+ 70 => 'Trailer',
+ 71 => 'Lo-Fi',
+ 72 => 'Tribal',
+ 73 => 'Acid Punk',
+ 74 => 'Acid Jazz',
+ 75 => 'Polka',
+ 76 => 'Retro',
+ 77 => 'Musical',
+ 78 => 'Rock & Roll',
+ 79 => 'Hard Rock',
+ 80 => 'Folk',
+ 81 => 'Folk/Rock',
+ 82 => 'National Folk',
+ 83 => 'Swing',
+ 84 => 'Fast-Fusion',
+ 85 => 'Bebob',
+ 86 => 'Latin',
+ 87 => 'Revival',
+ 88 => 'Celtic',
+ 89 => 'Bluegrass',
+ 90 => 'Avantgarde',
+ 91 => 'Gothic Rock',
+ 92 => 'Progressive Rock',
+ 93 => 'Psychedelic Rock',
+ 94 => 'Symphonic Rock',
+ 95 => 'Slow Rock',
+ 96 => 'Big Band',
+ 97 => 'Chorus',
+ 98 => 'Easy Listening',
+ 99 => 'Acoustic',
+ 100 => 'Humour',
+ 101 => 'Speech',
+ 102 => 'Chanson',
+ 103 => 'Opera',
+ 104 => 'Chamber Music',
+ 105 => 'Sonata',
+ 106 => 'Symphony',
+ 107 => 'Booty Bass',
+ 108 => 'Primus',
+ 109 => 'Porn Groove',
+ 110 => 'Satire',
+ 111 => 'Slow Jam',
+ 112 => 'Club',
+ 113 => 'Tango',
+ 114 => 'Samba',
+ 115 => 'Folklore',
+ 116 => 'Ballad',
+ 117 => 'Power Ballad',
+ 118 => 'Rhythmic Soul',
+ 119 => 'Freestyle',
+ 120 => 'Duet',
+ 121 => 'Punk Rock',
+ 122 => 'Drum Solo',
+ 123 => 'A Cappella',
+ 124 => 'Euro-House',
+ 125 => 'Dance Hall',
+ 126 => 'Goa',
+ 127 => 'Drum & Bass',
+ 128 => 'Club-House',
+ 129 => 'Hardcore',
+ 130 => 'Terror',
+ 131 => 'Indie',
+ 132 => 'BritPop',
+ 133 => 'Negerpunk',
+ 134 => 'Polsk Punk',
+ 135 => 'Beat',
+ 136 => 'Christian Gangsta Rap',
+ 137 => 'Heavy Metal',
+ 138 => 'Black Metal',
+ 139 => 'Crossover',
+ 140 => 'Contemporary Christian',
+ 141 => 'Christian Rock',
+ 142 => 'Merengue',
+ 143 => 'Salsa',
+ 144 => 'Thrash Metal',
+ 145 => 'Anime',
+ 146 => 'JPop',
+ 147 => 'Synthpop',
+
+ 255 => 'Unknown',
+
+ 'CR' => 'Cover',
+ 'RX' => 'Remix'
+ );
+
+ static $GenreLookupSCMPX = array();
+ if ($allowSCMPXextended && empty($GenreLookupSCMPX)) {
+ $GenreLookupSCMPX = $GenreLookup;
+ // http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended
+ // Extended ID3v1 genres invented by SCMPX
+ // Note that 255 "Japanese Anime" conflicts with standard "Unknown"
+ $GenreLookupSCMPX[240] = 'Sacred';
+ $GenreLookupSCMPX[241] = 'Northern Europe';
+ $GenreLookupSCMPX[242] = 'Irish & Scottish';
+ $GenreLookupSCMPX[243] = 'Scotland';
+ $GenreLookupSCMPX[244] = 'Ethnic Europe';
+ $GenreLookupSCMPX[245] = 'Enka';
+ $GenreLookupSCMPX[246] = 'Children\'s Song';
+ $GenreLookupSCMPX[247] = 'Japanese Sky';
+ $GenreLookupSCMPX[248] = 'Japanese Heavy Rock';
+ $GenreLookupSCMPX[249] = 'Japanese Doom Rock';
+ $GenreLookupSCMPX[250] = 'Japanese J-POP';
+ $GenreLookupSCMPX[251] = 'Japanese Seiyu';
+ $GenreLookupSCMPX[252] = 'Japanese Ambient Techno';
+ $GenreLookupSCMPX[253] = 'Japanese Moemoe';
+ $GenreLookupSCMPX[254] = 'Japanese Tokusatsu';
+ //$GenreLookupSCMPX[255] = 'Japanese Anime';
+ }
+
+ return ($allowSCMPXextended ? $GenreLookupSCMPX : $GenreLookup);
+ }
+
+ public static function LookupGenreName($genreid, $allowSCMPXextended=true) {
+ switch ($genreid) {
+ case 'RX':
+ case 'CR':
+ break;
+ default:
+ if (!is_numeric($genreid)) {
+ return false;
+ }
+ $genreid = intval($genreid); // to handle 3 or '3' or '03'
+ break;
+ }
+ $GenreLookup = self::ArrayOfGenres($allowSCMPXextended);
+ return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false);
+ }
+
+ public static function LookupGenreID($genre, $allowSCMPXextended=false) {
+ $GenreLookup = self::ArrayOfGenres($allowSCMPXextended);
+ $LowerCaseNoSpaceSearchTerm = strtolower(str_replace(' ', '', $genre));
+ foreach ($GenreLookup as $key => $value) {
+ if (strtolower(str_replace(' ', '', $value)) == $LowerCaseNoSpaceSearchTerm) {
+ return $key;
+ }
+ }
+ return false;
+ }
+
+ public static function StandardiseID3v1GenreName($OriginalGenre) {
+ if (($GenreID = self::LookupGenreID($OriginalGenre)) !== false) {
+ return self::LookupGenreName($GenreID);
+ }
+ return $OriginalGenre;
+ }
+
+ public static function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track='') {
+ $ID3v1Tag = 'TAG';
+ $ID3v1Tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
+ $ID3v1Tag .= str_pad(trim(substr($artist, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
+ $ID3v1Tag .= str_pad(trim(substr($album, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
+ $ID3v1Tag .= str_pad(trim(substr($year, 0, 4)), 4, "\x00", STR_PAD_LEFT);
+ if (!empty($track) && ($track > 0) && ($track <= 255)) {
+ $ID3v1Tag .= str_pad(trim(substr($comment, 0, 28)), 28, "\x00", STR_PAD_RIGHT);
+ $ID3v1Tag .= "\x00";
+ if (gettype($track) == 'string') {
+ $track = (int) $track;
+ }
+ $ID3v1Tag .= chr($track);
+ } else {
+ $ID3v1Tag .= str_pad(trim(substr($comment, 0, 30)), 30, "\x00", STR_PAD_RIGHT);
+ }
+ if (($genreid < 0) || ($genreid > 147)) {
+ $genreid = 255; // 'unknown' genre
+ }
+ switch (gettype($genreid)) {
+ case 'string':
+ case 'integer':
+ $ID3v1Tag .= chr(intval($genreid));
+ break;
+ default:
+ $ID3v1Tag .= chr(255); // 'unknown' genre
+ break;
+ }
+
+ return $ID3v1Tag;
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/libs/getid3/module.tag.id3v2.php b/extensions/TimedMediaHandler/libs/getid3/module.tag.id3v2.php
new file mode 100644
index 00000000..b08f9f9a
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/module.tag.id3v2.php
@@ -0,0 +1,3414 @@
+<?php
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// See readme.txt for more details //
+/////////////////////////////////////////////////////////////////
+/// //
+// module.tag.id3v2.php //
+// module for analyzing ID3v2 tags //
+// dependencies: module.tag.id3v1.php //
+// ///
+/////////////////////////////////////////////////////////////////
+
+getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true);
+
+class getid3_id3v2 extends getid3_handler
+{
+ public $StartingOffset = 0;
+
+ public function Analyze() {
+ $info = &$this->getid3->info;
+
+ // Overall tag structure:
+ // +-----------------------------+
+ // | Header (10 bytes) |
+ // +-----------------------------+
+ // | Extended Header |
+ // | (variable length, OPTIONAL) |
+ // +-----------------------------+
+ // | Frames (variable length) |
+ // +-----------------------------+
+ // | Padding |
+ // | (variable length, OPTIONAL) |
+ // +-----------------------------+
+ // | Footer (10 bytes, OPTIONAL) |
+ // +-----------------------------+
+
+ // Header
+ // ID3v2/file identifier "ID3"
+ // ID3v2 version $04 00
+ // ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x)
+ // ID3v2 size 4 * %0xxxxxxx
+
+
+ // shortcuts
+ $info['id3v2']['header'] = true;
+ $thisfile_id3v2 = &$info['id3v2'];
+ $thisfile_id3v2['flags'] = array();
+ $thisfile_id3v2_flags = &$thisfile_id3v2['flags'];
+
+
+ fseek($this->getid3->fp, $this->StartingOffset, SEEK_SET);
+ $header = fread($this->getid3->fp, 10);
+ if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) {
+
+ $thisfile_id3v2['majorversion'] = ord($header{3});
+ $thisfile_id3v2['minorversion'] = ord($header{4});
+
+ // shortcut
+ $id3v2_majorversion = &$thisfile_id3v2['majorversion'];
+
+ } else {
+
+ unset($info['id3v2']);
+ return false;
+
+ }
+
+ if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists)
+
+ $info['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion'];
+ return false;
+
+ }
+
+ $id3_flags = ord($header{5});
+ switch ($id3v2_majorversion) {
+ case 2:
+ // %ab000000 in v2.2
+ $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
+ $thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression
+ break;
+
+ case 3:
+ // %abc00000 in v2.3
+ $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
+ $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
+ $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
+ break;
+
+ case 4:
+ // %abcd0000 in v2.4
+ $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation
+ $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header
+ $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator
+ $thisfile_id3v2_flags['isfooter'] = (bool) ($id3_flags & 0x10); // d - Footer present
+ break;
+ }
+
+ $thisfile_id3v2['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length
+
+ $thisfile_id3v2['tag_offset_start'] = $this->StartingOffset;
+ $thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength'];
+
+
+
+ // create 'encoding' key - used by getid3::HandleAllTags()
+ // in ID3v2 every field can have it's own encoding type
+ // so force everything to UTF-8 so it can be handled consistantly
+ $thisfile_id3v2['encoding'] = 'UTF-8';
+
+
+ // Frames
+
+ // All ID3v2 frames consists of one frame header followed by one or more
+ // fields containing the actual information. The header is always 10
+ // bytes and laid out as follows:
+ //
+ // Frame ID $xx xx xx xx (four characters)
+ // Size 4 * %0xxxxxxx
+ // Flags $xx xx
+
+ $sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header
+ if (!empty($thisfile_id3v2['exthead']['length'])) {
+ $sizeofframes -= ($thisfile_id3v2['exthead']['length'] + 4);
+ }
+ if (!empty($thisfile_id3v2_flags['isfooter'])) {
+ $sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio
+ }
+ if ($sizeofframes > 0) {
+
+ $framedata = fread($this->getid3->fp, $sizeofframes); // read all frames from file into $framedata variable
+
+ // if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x)
+ if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) {
+ $framedata = $this->DeUnsynchronise($framedata);
+ }
+ // [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead
+ // of on tag level, making it easier to skip frames, increasing the streamability
+ // of the tag. The unsynchronisation flag in the header [S:3.1] indicates that
+ // there exists an unsynchronised frame, while the new unsynchronisation flag in
+ // the frame header [S:4.1.2] indicates unsynchronisation.
+
+
+ //$framedataoffset = 10 + ($thisfile_id3v2['exthead']['length'] ? $thisfile_id3v2['exthead']['length'] + 4 : 0); // how many bytes into the stream - start from after the 10-byte header (and extended header length+4, if present)
+ $framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header
+
+
+ // Extended Header
+ if (!empty($thisfile_id3v2_flags['exthead'])) {
+ $extended_header_offset = 0;
+
+ if ($id3v2_majorversion == 3) {
+
+ // v2.3 definition:
+ //Extended header size $xx xx xx xx // 32-bit integer
+ //Extended Flags $xx xx
+ // %x0000000 %00000000 // v2.3
+ // x - CRC data present
+ //Size of padding $xx xx xx xx
+
+ $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), 0);
+ $extended_header_offset += 4;
+
+ $thisfile_id3v2['exthead']['flag_bytes'] = 2;
+ $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
+ $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
+
+ $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x8000);
+
+ $thisfile_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
+ $extended_header_offset += 4;
+
+ if ($thisfile_id3v2['exthead']['flags']['crc']) {
+ $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4));
+ $extended_header_offset += 4;
+ }
+ $extended_header_offset += $thisfile_id3v2['exthead']['padding_size'];
+
+ } elseif ($id3v2_majorversion == 4) {
+
+ // v2.4 definition:
+ //Extended header size 4 * %0xxxxxxx // 28-bit synchsafe integer
+ //Number of flag bytes $01
+ //Extended Flags $xx
+ // %0bcd0000 // v2.4
+ // b - Tag is an update
+ // Flag data length $00
+ // c - CRC data present
+ // Flag data length $05
+ // Total frame CRC 5 * %0xxxxxxx
+ // d - Tag restrictions
+ // Flag data length $01
+
+ $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), true);
+ $extended_header_offset += 4;
+
+ $thisfile_id3v2['exthead']['flag_bytes'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should always be 1
+ $extended_header_offset += 1;
+
+ $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes']));
+ $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes'];
+
+ $thisfile_id3v2['exthead']['flags']['update'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x40);
+ $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x20);
+ $thisfile_id3v2['exthead']['flags']['restrictions'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x10);
+
+ if ($thisfile_id3v2['exthead']['flags']['update']) {
+ $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 0
+ $extended_header_offset += 1;
+ }
+
+ if ($thisfile_id3v2['exthead']['flags']['crc']) {
+ $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 5
+ $extended_header_offset += 1;
+ $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $ext_header_chunk_length), true, false);
+ $extended_header_offset += $ext_header_chunk_length;
+ }
+
+ if ($thisfile_id3v2['exthead']['flags']['restrictions']) {
+ $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 1
+ $extended_header_offset += 1;
+
+ // %ppqrrstt
+ $restrictions_raw = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1));
+ $extended_header_offset += 1;
+ $thisfile_id3v2['exthead']['flags']['restrictions']['tagsize'] = ($restrictions_raw & 0xC0) >> 6; // p - Tag size restrictions
+ $thisfile_id3v2['exthead']['flags']['restrictions']['textenc'] = ($restrictions_raw & 0x20) >> 5; // q - Text encoding restrictions
+ $thisfile_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw & 0x18) >> 3; // r - Text fields size restrictions
+ $thisfile_id3v2['exthead']['flags']['restrictions']['imgenc'] = ($restrictions_raw & 0x04) >> 2; // s - Image encoding restrictions
+ $thisfile_id3v2['exthead']['flags']['restrictions']['imgsize'] = ($restrictions_raw & 0x03) >> 0; // t - Image size restrictions
+
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['tagsize'] = $this->LookupExtendedHeaderRestrictionsTagSizeLimits($thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']);
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['textenc'] = $this->LookupExtendedHeaderRestrictionsTextEncodings($thisfile_id3v2['exthead']['flags']['restrictions']['textenc']);
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['textsize'] = $this->LookupExtendedHeaderRestrictionsTextFieldSize($thisfile_id3v2['exthead']['flags']['restrictions']['textsize']);
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgenc'] = $this->LookupExtendedHeaderRestrictionsImageEncoding($thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']);
+ $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgsize'] = $this->LookupExtendedHeaderRestrictionsImageSizeSize($thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']);
+ }
+
+ if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) {
+ $info['warning'][] = 'ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')';
+ }
+ }
+
+ $framedataoffset += $extended_header_offset;
+ $framedata = substr($framedata, $extended_header_offset);
+ } // end extended header
+
+
+ while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse
+ if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) {
+ // insufficient room left in ID3v2 header for actual data - must be padding
+ $thisfile_id3v2['padding']['start'] = $framedataoffset;
+ $thisfile_id3v2['padding']['length'] = strlen($framedata);
+ $thisfile_id3v2['padding']['valid'] = true;
+ for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) {
+ if ($framedata{$i} != "\x00") {
+ $thisfile_id3v2['padding']['valid'] = false;
+ $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
+ $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
+ break;
+ }
+ }
+ break; // skip rest of ID3v2 header
+ }
+ if ($id3v2_majorversion == 2) {
+ // Frame ID $xx xx xx (three characters)
+ // Size $xx xx xx (24-bit integer)
+ // Flags $xx xx
+
+ $frame_header = substr($framedata, 0, 6); // take next 6 bytes for header
+ $framedata = substr($framedata, 6); // and leave the rest in $framedata
+ $frame_name = substr($frame_header, 0, 3);
+ $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0);
+ $frame_flags = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs
+
+ } elseif ($id3v2_majorversion > 2) {
+
+ // Frame ID $xx xx xx xx (four characters)
+ // Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+)
+ // Flags $xx xx
+
+ $frame_header = substr($framedata, 0, 10); // take next 10 bytes for header
+ $framedata = substr($framedata, 10); // and leave the rest in $framedata
+
+ $frame_name = substr($frame_header, 0, 4);
+ if ($id3v2_majorversion == 3) {
+ $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
+ } else { // ID3v2.4+
+ $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value)
+ }
+
+ if ($frame_size < (strlen($framedata) + 4)) {
+ $nextFrameID = substr($framedata, $frame_size, 4);
+ if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) {
+ // next frame is OK
+ } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) {
+ // MP3ext known broken frames - "ok" for the purposes of this test
+ } elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) {
+ $info['warning'][] = 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3';
+ $id3v2_majorversion = 3;
+ $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer
+ }
+ }
+
+
+ $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2));
+ }
+
+ if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) {
+ // padding encountered
+
+ $thisfile_id3v2['padding']['start'] = $framedataoffset;
+ $thisfile_id3v2['padding']['length'] = strlen($frame_header) + strlen($framedata);
+ $thisfile_id3v2['padding']['valid'] = true;
+
+ $len = strlen($framedata);
+ for ($i = 0; $i < $len; $i++) {
+ if ($framedata{$i} != "\x00") {
+ $thisfile_id3v2['padding']['valid'] = false;
+ $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i;
+ $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)';
+ break;
+ }
+ }
+ break; // skip rest of ID3v2 header
+ }
+
+ if ($frame_name == 'COM ') {
+ $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]';
+ $frame_name = 'COMM';
+ }
+ if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) {
+
+ unset($parsedFrame);
+ $parsedFrame['frame_name'] = $frame_name;
+ $parsedFrame['frame_flags_raw'] = $frame_flags;
+ $parsedFrame['data'] = substr($framedata, 0, $frame_size);
+ $parsedFrame['datalength'] = getid3_lib::CastAsInt($frame_size);
+ $parsedFrame['dataoffset'] = $framedataoffset;
+
+ $this->ParseID3v2Frame($parsedFrame);
+ $thisfile_id3v2[$frame_name][] = $parsedFrame;
+
+ $framedata = substr($framedata, $frame_size);
+
+ } else { // invalid frame length or FrameID
+
+ if ($frame_size <= strlen($framedata)) {
+
+ if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) {
+
+ // next frame is valid, just skip the current frame
+ $framedata = substr($framedata, $frame_size);
+ $info['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.';
+
+ } else {
+
+ // next frame is invalid too, abort processing
+ //unset($framedata);
+ $framedata = null;
+ $info['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.';
+
+ }
+
+ } elseif ($frame_size == strlen($framedata)) {
+
+ // this is the last frame, just skip
+ $info['warning'][] = 'This was the last ID3v2 frame.';
+
+ } else {
+
+ // next frame is invalid too, abort processing
+ //unset($framedata);
+ $framedata = null;
+ $info['warning'][] = 'Invalid ID3v2 frame size, aborting.';
+
+ }
+ if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) {
+
+ switch ($frame_name) {
+ case "\x00\x00".'MP':
+ case "\x00".'MP3':
+ case ' MP3':
+ case 'MP3e':
+ case "\x00".'MP':
+ case ' MP':
+ case 'MP3':
+ $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]';
+ break;
+
+ default:
+ $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).';
+ break;
+ }
+
+ } elseif (!isset($framedata) || ($frame_size > strlen($framedata))) {
+
+ $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).';
+
+ } else {
+
+ $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).';
+
+ }
+
+ }
+ $framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion));
+
+ }
+
+ }
+
+
+ // Footer
+
+ // The footer is a copy of the header, but with a different identifier.
+ // ID3v2 identifier "3DI"
+ // ID3v2 version $04 00
+ // ID3v2 flags %abcd0000
+ // ID3v2 size 4 * %0xxxxxxx
+
+ if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) {
+ $footer = fread($this->getid3->fp, 10);
+ if (substr($footer, 0, 3) == '3DI') {
+ $thisfile_id3v2['footer'] = true;
+ $thisfile_id3v2['majorversion_footer'] = ord($footer{3});
+ $thisfile_id3v2['minorversion_footer'] = ord($footer{4});
+ }
+ if ($thisfile_id3v2['majorversion_footer'] <= 4) {
+ $id3_flags = ord(substr($footer{5}));
+ $thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80);
+ $thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40);
+ $thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20);
+ $thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10);
+
+ $thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1);
+ }
+ } // end footer
+
+ if (isset($thisfile_id3v2['comments']['genre'])) {
+ foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) {
+ unset($thisfile_id3v2['comments']['genre'][$key]);
+ $thisfile_id3v2['comments'] = getid3_lib::array_merge_noclobber($thisfile_id3v2['comments'], array('genre'=>$this->ParseID3v2GenreString($value)));
+ }
+ }
+
+ if (isset($thisfile_id3v2['comments']['track'])) {
+ foreach ($thisfile_id3v2['comments']['track'] as $key => $value) {
+ if (strstr($value, '/')) {
+ list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]);
+ }
+ }
+ }
+
+ if (!isset($thisfile_id3v2['comments']['year']) && !empty($thisfile_id3v2['comments']['recording_time'][0]) && preg_match('#^([0-9]{4})#', trim($thisfile_id3v2['comments']['recording_time'][0]), $matches)) {
+ $thisfile_id3v2['comments']['year'] = array($matches[1]);
+ }
+
+
+ if (!empty($thisfile_id3v2['TXXX'])) {
+ // MediaMonkey does this, maybe others: write a blank RGAD frame, but put replay-gain adjustment values in TXXX frames
+ foreach ($thisfile_id3v2['TXXX'] as $txxx_array) {
+ switch ($txxx_array['description']) {
+ case 'replaygain_track_gain':
+ if (empty($info['replay_gain']['track']['adjustment']) && !empty($txxx_array['data'])) {
+ $info['replay_gain']['track']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
+ }
+ break;
+ case 'replaygain_track_peak':
+ if (empty($info['replay_gain']['track']['peak']) && !empty($txxx_array['data'])) {
+ $info['replay_gain']['track']['peak'] = floatval($txxx_array['data']);
+ }
+ break;
+ case 'replaygain_album_gain':
+ if (empty($info['replay_gain']['album']['adjustment']) && !empty($txxx_array['data'])) {
+ $info['replay_gain']['album']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data'])));
+ }
+ break;
+ }
+ }
+ }
+
+
+ // Set avdataoffset
+ $info['avdataoffset'] = $thisfile_id3v2['headerlength'];
+ if (isset($thisfile_id3v2['footer'])) {
+ $info['avdataoffset'] += 10;
+ }
+
+ return true;
+ }
+
+
+ public function ParseID3v2GenreString($genrestring) {
+ // Parse genres into arrays of genreName and genreID
+ // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)'
+ // ID3v2.4.x: '21' $00 'Eurodisco' $00
+ $clean_genres = array();
+ if (strpos($genrestring, "\x00") === false) {
+ $genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring);
+ }
+ $genre_elements = explode("\x00", $genrestring);
+ foreach ($genre_elements as $element) {
+ $element = trim($element);
+ if ($element) {
+ if (preg_match('#^[0-9]{1,3}#', $element)) {
+ $clean_genres[] = getid3_id3v1::LookupGenreName($element);
+ } else {
+ $clean_genres[] = str_replace('((', '(', $element);
+ }
+ }
+ }
+ return $clean_genres;
+ }
+
+
+ public function ParseID3v2Frame(&$parsedFrame) {
+
+ // shortcuts
+ $info = &$this->getid3->info;
+ $id3v2_majorversion = $info['id3v2']['majorversion'];
+
+ $parsedFrame['framenamelong'] = $this->FrameNameLongLookup($parsedFrame['frame_name']);
+ if (empty($parsedFrame['framenamelong'])) {
+ unset($parsedFrame['framenamelong']);
+ }
+ $parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']);
+ if (empty($parsedFrame['framenameshort'])) {
+ unset($parsedFrame['framenameshort']);
+ }
+
+ if ($id3v2_majorversion >= 3) { // frame flags are not part of the ID3v2.2 standard
+ if ($id3v2_majorversion == 3) {
+ // Frame Header Flags
+ // %abc00000 %ijk00000
+ $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation
+ $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation
+ $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only
+ $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression
+ $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption
+ $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity
+
+ } elseif ($id3v2_majorversion == 4) {
+ // Frame Header Flags
+ // %0abc0000 %0h00kmnp
+ $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation
+ $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation
+ $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only
+ $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity
+ $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression
+ $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption
+ $parsedFrame['flags']['Unsynchronisation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation
+ $parsedFrame['flags']['DataLengthIndicator'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator
+
+ // Frame-level de-unsynchronisation - ID3v2.4
+ if ($parsedFrame['flags']['Unsynchronisation']) {
+ $parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']);
+ }
+
+ if ($parsedFrame['flags']['DataLengthIndicator']) {
+ $parsedFrame['data_length_indicator'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4), 1);
+ $parsedFrame['data'] = substr($parsedFrame['data'], 4);
+ }
+ }
+
+ // Frame-level de-compression
+ if ($parsedFrame['flags']['compression']) {
+ $parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4));
+ if (!function_exists('gzuncompress')) {
+ $info['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"';
+ } else {
+ if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) {
+ //if ($decompresseddata = @gzuncompress($parsedFrame['data'])) {
+ $parsedFrame['data'] = $decompresseddata;
+ unset($decompresseddata);
+ } else {
+ $info['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"';
+ }
+ }
+ }
+ }
+
+ if (!empty($parsedFrame['flags']['DataLengthIndicator'])) {
+ if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) {
+ $info['warning'][] = 'ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data';
+ }
+ }
+
+ if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) {
+
+ $warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion';
+ switch ($parsedFrame['frame_name']) {
+ case 'WCOM':
+ $warning .= ' (this is known to happen with files tagged by RioPort)';
+ break;
+
+ default:
+ break;
+ }
+ $info['warning'][] = $warning;
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) { // 4.1 UFI Unique file identifier
+ // There may be more than one 'UFID' frame in a tag,
+ // but only one with the same 'Owner identifier'.
+ // <Header for 'Unique file identifier', ID: 'UFID'>
+ // Owner identifier <text string> $00
+ // Identifier <up to 64 bytes binary data>
+ $exploded = explode("\x00", $parsedFrame['data'], 2);
+ $parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : '');
+ $parsedFrame['data'] = (isset($exploded[1]) ? $exploded[1] : '');
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) { // 4.2.2 TXX User defined text information frame
+ // There may be more than one 'TXXX' frame in each tag,
+ // but only one with the same description.
+ // <Header for 'User defined text information frame', ID: 'TXXX'>
+ // Text encoding $xx
+ // Description <text string according to encoding> $00 (00)
+ // Value <text string according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['description'] = $frame_description;
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']));
+ }
+ //unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain
+
+
+ } elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame
+ // There may only be one text information frame of its kind in an tag.
+ // <Header for 'Text information frame', ID: 'T000' - 'TZZZ',
+ // excluding 'TXXX' described in 4.2.6.>
+ // Text encoding $xx
+ // Information <text string(s) according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ // ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with /
+ // This of course breaks when an artist name contains slash character, e.g. "AC/DC"
+ // MP3tag (maybe others) implement alternative system where multiple artists are null-separated, which makes more sense
+ // getID3 will split null-separated artists into multiple artists and leave slash-separated ones to the user
+ switch ($parsedFrame['encoding']) {
+ case 'UTF-16':
+ case 'UTF-16BE':
+ case 'UTF-16LE':
+ $wordsize = 2;
+ break;
+ case 'ISO-8859-1':
+ case 'UTF-8':
+ default:
+ $wordsize = 1;
+ break;
+ }
+ $Txxx_elements = array();
+ $Txxx_elements_start_offset = 0;
+ for ($i = 0; $i < strlen($parsedFrame['data']); $i += $wordsize) {
+ if (substr($parsedFrame['data'], $i, $wordsize) == str_repeat("\x00", $wordsize)) {
+ $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
+ $Txxx_elements_start_offset = $i + $wordsize;
+ }
+ }
+ $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset);
+ foreach ($Txxx_elements as $Txxx_element) {
+ $string = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $Txxx_element);
+ if (!empty($string)) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $string;
+ }
+ }
+ unset($string, $wordsize, $i, $Txxx_elements, $Txxx_element, $Txxx_elements_start_offset);
+ }
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) { // 4.3.2 WXX User defined URL link frame
+ // There may be more than one 'WXXX' frame in each tag,
+ // but only one with the same description
+ // <Header for 'User defined URL link frame', ID: 'WXXX'>
+ // Text encoding $xx
+ // Description <text string according to encoding> $00 (00)
+ // URL <text string>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding));
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ if ($frame_terminatorpos) {
+ // there are null bytes after the data - this is not according to spec
+ // only use data up to first null byte
+ $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos);
+ } else {
+ // no null bytes following data, just use all data
+ $frame_urldata = (string) $parsedFrame['data'];
+ }
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['url'] = $frame_urldata;
+ $parsedFrame['description'] = $frame_description;
+ if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames
+ // There may only be one URL link frame of its kind in a tag,
+ // except when stated otherwise in the frame description
+ // <Header for 'URL link frame', ID: 'W000' - 'WZZZ', excluding 'WXXX'
+ // described in 4.3.2.>
+ // URL <text string>
+
+ $parsedFrame['url'] = trim($parsedFrame['data']);
+ if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url'];
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only)
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) { // 4.4 IPL Involved people list (ID3v2.2 only)
+ // http://id3.org/id3v2.3.0#sec4.4
+ // There may only be one 'IPL' frame in each tag
+ // <Header for 'User defined URL link frame', ID: 'IPL'>
+ // Text encoding $xx
+ // People list strings <textstrings>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']);
+ $parsedFrame['data_raw'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+ // http://www.getid3.org/phpBB3/viewtopic.php?t=1369
+ // "this tag typically contains null terminated strings, which are associated in pairs"
+ // "there are users that use the tag incorrectly"
+ $IPLS_parts = array();
+ if (strpos($parsedFrame['data_raw'], "\x00") !== false) {
+ $IPLS_parts_unsorted = array();
+ if (((strlen($parsedFrame['data_raw']) % 2) == 0) && ((substr($parsedFrame['data_raw'], 0, 2) == "\xFF\xFE") || (substr($parsedFrame['data_raw'], 0, 2) == "\xFE\xFF"))) {
+ // UTF-16, be careful looking for null bytes since most 2-byte characters may contain one; you need to find twin null bytes, and on even padding
+ $thisILPS = '';
+ for ($i = 0; $i < strlen($parsedFrame['data_raw']); $i += 2) {
+ $twobytes = substr($parsedFrame['data_raw'], $i, 2);
+ if ($twobytes === "\x00\x00") {
+ $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
+ $thisILPS = '';
+ } else {
+ $thisILPS .= $twobytes;
+ }
+ }
+ if (strlen($thisILPS) > 2) { // 2-byte BOM
+ $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS);
+ }
+ } else {
+ // ISO-8859-1 or UTF-8 or other single-byte-null character set
+ $IPLS_parts_unsorted = explode("\x00", $parsedFrame['data_raw']);
+ }
+ if (count($IPLS_parts_unsorted) == 1) {
+ // just a list of names, e.g. "Dino Baptiste, Jimmy Copley, John Gordon, Bernie Marsden, Sharon Watson"
+ foreach ($IPLS_parts_unsorted as $key => $value) {
+ $IPLS_parts_sorted = preg_split('#[;,\\r\\n\\t]#', $value);
+ $position = '';
+ foreach ($IPLS_parts_sorted as $person) {
+ $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
+ }
+ }
+ } elseif ((count($IPLS_parts_unsorted) % 2) == 0) {
+ $position = '';
+ $person = '';
+ foreach ($IPLS_parts_unsorted as $key => $value) {
+ if (($key % 2) == 0) {
+ $position = $value;
+ } else {
+ $person = $value;
+ $IPLS_parts[] = array('position'=>$position, 'person'=>$person);
+ $position = '';
+ $person = '';
+ }
+ }
+ } else {
+ foreach ($IPLS_parts_unsorted as $key => $value) {
+ $IPLS_parts[] = array($value);
+ }
+ }
+
+ } else {
+ $IPLS_parts = preg_split('#[;,\\r\\n\\t]#', $parsedFrame['data_raw']);
+ }
+ $parsedFrame['data'] = $IPLS_parts;
+
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
+ }
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4 MCDI Music CD identifier
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) { // 4.5 MCI Music CD identifier
+ // There may only be one 'MCDI' frame in each tag
+ // <Header for 'Music CD identifier', ID: 'MCDI'>
+ // CD TOC <binary data>
+
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data'];
+ }
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5 ETCO Event timing codes
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) { // 4.6 ETC Event timing codes
+ // There may only be one 'ETCO' frame in each tag
+ // <Header for 'Event timing codes', ID: 'ETCO'>
+ // Time stamp format $xx
+ // Where time stamp format is:
+ // $01 (32-bit value) MPEG frames from beginning of file
+ // $02 (32-bit value) milliseconds from beginning of file
+ // Followed by a list of key events in the following format:
+ // Type of event $xx
+ // Time stamp $xx (xx ...)
+ // The 'Time stamp' is set to zero if directly at the beginning of the sound
+ // or after the previous event. All events MUST be sorted in chronological order.
+
+ $frame_offset = 0;
+ $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+
+ while ($frame_offset < strlen($parsedFrame['data'])) {
+ $parsedFrame['typeid'] = substr($parsedFrame['data'], $frame_offset++, 1);
+ $parsedFrame['type'] = $this->ETCOEventLookup($parsedFrame['typeid']);
+ $parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6 MLLT MPEG location lookup table
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) { // 4.7 MLL MPEG location lookup table
+ // There may only be one 'MLLT' frame in each tag
+ // <Header for 'Location lookup table', ID: 'MLLT'>
+ // MPEG frames between reference $xx xx
+ // Bytes between reference $xx xx xx
+ // Milliseconds between reference $xx xx xx
+ // Bits for bytes deviation $xx
+ // Bits for milliseconds dev. $xx
+ // Then for every reference the following data is included;
+ // Deviation in bytes %xxx....
+ // Deviation in milliseconds %xxx....
+
+ $frame_offset = 0;
+ $parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2));
+ $parsedFrame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3));
+ $parsedFrame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3));
+ $parsedFrame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1));
+ $parsedFrame['bitsformsdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1));
+ $parsedFrame['data'] = substr($parsedFrame['data'], 10);
+ while ($frame_offset < strlen($parsedFrame['data'])) {
+ $deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
+ }
+ $reference_counter = 0;
+ while (strlen($deviationbitstream) > 0) {
+ $parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation']));
+ $parsedFrame[$reference_counter]['msdeviation'] = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation']));
+ $deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']);
+ $reference_counter++;
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) { // 4.8 STC Synchronised tempo codes
+ // There may only be one 'SYTC' frame in each tag
+ // <Header for 'Synchronised tempo codes', ID: 'SYTC'>
+ // Time stamp format $xx
+ // Tempo data <binary data>
+ // Where time stamp format is:
+ // $01 (32-bit value) MPEG frames from beginning of file
+ // $02 (32-bit value) milliseconds from beginning of file
+
+ $frame_offset = 0;
+ $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $timestamp_counter = 0;
+ while ($frame_offset < strlen($parsedFrame['data'])) {
+ $parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ($parsedFrame[$timestamp_counter]['tempo'] == 255) {
+ $parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ }
+ $parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ $timestamp_counter++;
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription
+ // There may be more than one 'Unsynchronised lyrics/text transcription' frame
+ // in each tag, but only one with the same language and content descriptor.
+ // <Header for 'Unsynchronised lyrics/text transcription', ID: 'USLT'>
+ // Text encoding $xx
+ // Language $xx xx xx
+ // Content descriptor <text string according to encoding> $00 (00)
+ // Lyrics/text <full text string according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['data'] = $parsedFrame['data'];
+ $parsedFrame['language'] = $frame_language;
+ $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
+ $parsedFrame['description'] = $frame_description;
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9 SYLT Synchronised lyric/text
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) { // 4.10 SLT Synchronised lyric/text
+ // There may be more than one 'SYLT' frame in each tag,
+ // but only one with the same language and content descriptor.
+ // <Header for 'Synchronised lyrics/text', ID: 'SYLT'>
+ // Text encoding $xx
+ // Language $xx xx xx
+ // Time stamp format $xx
+ // $01 (32-bit value) MPEG frames from beginning of file
+ // $02 (32-bit value) milliseconds from beginning of file
+ // Content type $xx
+ // Content descriptor <text string according to encoding> $00 (00)
+ // Terminated text to be synced (typically a syllable)
+ // Sync identifier (terminator to above string) $00 (00)
+ // Time stamp $xx (xx ...)
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['contenttypeid'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['contenttype'] = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']);
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['language'] = $frame_language;
+ $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
+
+ $timestampindex = 0;
+ $frame_remainingdata = substr($parsedFrame['data'], $frame_offset);
+ while (strlen($frame_remainingdata)) {
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($frame_remainingdata, $this->TextEncodingTerminatorLookup($frame_textencoding));
+ if ($frame_terminatorpos === false) {
+ $frame_remainingdata = '';
+ } else {
+ if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset);
+
+ $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+ if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) {
+ // timestamp probably omitted for first data item
+ } else {
+ $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4));
+ $frame_remainingdata = substr($frame_remainingdata, 4);
+ }
+ $timestampindex++;
+ }
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10 COMM Comments
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) { // 4.11 COM Comments
+ // There may be more than one comment frame in each tag,
+ // but only one with the same language and content descriptor.
+ // <Header for 'Comment', ID: 'COMM'>
+ // Text encoding $xx
+ // Language $xx xx xx
+ // Short content descrip. <text string according to encoding> $00 (00)
+ // The actual text <full text string according to encoding>
+
+ if (strlen($parsedFrame['data']) < 5) {
+
+ $info['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset'];
+
+ } else {
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['language'] = $frame_language;
+ $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
+ $parsedFrame['description'] = $frame_description;
+ $parsedFrame['data'] = $frame_text;
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
+ }
+
+ }
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) { // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only)
+ // There may be more than one 'RVA2' frame in each tag,
+ // but only one with the same identification string
+ // <Header for 'Relative volume adjustment (2)', ID: 'RVA2'>
+ // Identification <text string> $00
+ // The 'identification' string is used to identify the situation and/or
+ // device where this adjustment should apply. The following is then
+ // repeated for every channel:
+ // Type of channel $xx
+ // Volume adjustment $xx xx
+ // Bits representing peak $xx
+ // Peak volume $xx (xx ...)
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00");
+ $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos);
+ if (ord($frame_idstring) === 0) {
+ $frame_idstring = '';
+ }
+ $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
+ $parsedFrame['description'] = $frame_idstring;
+ $RVA2channelcounter = 0;
+ while (strlen($frame_remainingdata) >= 5) {
+ $frame_offset = 0;
+ $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1));
+ $parsedFrame[$RVA2channelcounter]['channeltypeid'] = $frame_channeltypeid;
+ $parsedFrame[$RVA2channelcounter]['channeltype'] = $this->RVA2ChannelTypeLookup($frame_channeltypeid);
+ $parsedFrame[$RVA2channelcounter]['volumeadjust'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed
+ $frame_offset += 2;
+ $parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1));
+ if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) {
+ $info['warning'][] = 'ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value';
+ break;
+ }
+ $frame_bytespeakvolume = ceil($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] / 8);
+ $parsedFrame[$RVA2channelcounter]['peakvolume'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume));
+ $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume);
+ $RVA2channelcounter++;
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12 RVAD Relative volume adjustment (ID3v2.3 only)
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) { // 4.12 RVA Relative volume adjustment (ID3v2.2 only)
+ // There may only be one 'RVA' frame in each tag
+ // <Header for 'Relative volume adjustment', ID: 'RVA'>
+ // ID3v2.2 => Increment/decrement %000000ba
+ // ID3v2.3 => Increment/decrement %00fedcba
+ // Bits used for volume descr. $xx
+ // Relative volume change, right $xx xx (xx ...) // a
+ // Relative volume change, left $xx xx (xx ...) // b
+ // Peak volume right $xx xx (xx ...)
+ // Peak volume left $xx xx (xx ...)
+ // ID3v2.3 only, optional (not present in ID3v2.2):
+ // Relative volume change, right back $xx xx (xx ...) // c
+ // Relative volume change, left back $xx xx (xx ...) // d
+ // Peak volume right back $xx xx (xx ...)
+ // Peak volume left back $xx xx (xx ...)
+ // ID3v2.3 only, optional (not present in ID3v2.2):
+ // Relative volume change, center $xx xx (xx ...) // e
+ // Peak volume center $xx xx (xx ...)
+ // ID3v2.3 only, optional (not present in ID3v2.2):
+ // Relative volume change, bass $xx xx (xx ...) // f
+ // Peak volume bass $xx xx (xx ...)
+
+ $frame_offset = 0;
+ $frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1);
+ $parsedFrame['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1);
+ $parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8);
+ $parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['right'] === false) {
+ $parsedFrame['volumechange']['right'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['left'] === false) {
+ $parsedFrame['volumechange']['left'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ if ($id3v2_majorversion == 3) {
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
+ if (strlen($parsedFrame['data']) > 0) {
+ $parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1);
+ $parsedFrame['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1);
+ $parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['rightrear'] === false) {
+ $parsedFrame['volumechange']['rightrear'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['leftrear'] === false) {
+ $parsedFrame['volumechange']['leftrear'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ }
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
+ if (strlen($parsedFrame['data']) > 0) {
+ $parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1);
+ $parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['center'] === false) {
+ $parsedFrame['volumechange']['center'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ }
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset);
+ if (strlen($parsedFrame['data']) > 0) {
+ $parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1);
+ $parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ if ($parsedFrame['incdec']['bass'] === false) {
+ $parsedFrame['volumechange']['bass'] *= -1;
+ }
+ $frame_offset += $frame_bytesvolume;
+ $parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume));
+ $frame_offset += $frame_bytesvolume;
+ }
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) { // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only)
+ // There may be more than one 'EQU2' frame in each tag,
+ // but only one with the same identification string
+ // <Header of 'Equalisation (2)', ID: 'EQU2'>
+ // Interpolation method $xx
+ // $00 Band
+ // $01 Linear
+ // Identification <text string> $00
+ // The following is then repeated for every adjustment point
+ // Frequency $xx xx
+ // Volume adjustment $xx xx
+
+ $frame_offset = 0;
+ $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_idstring) === 0) {
+ $frame_idstring = '';
+ }
+ $parsedFrame['description'] = $frame_idstring;
+ $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00"));
+ while (strlen($frame_remainingdata)) {
+ $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2;
+ $parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true);
+ $frame_remainingdata = substr($frame_remainingdata, 4);
+ }
+ $parsedFrame['interpolationmethod'] = $frame_interpolationmethod;
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12 EQUA Equalisation (ID3v2.3 only)
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) { // 4.13 EQU Equalisation (ID3v2.2 only)
+ // There may only be one 'EQUA' frame in each tag
+ // <Header for 'Relative volume adjustment', ID: 'EQU'>
+ // Adjustment bits $xx
+ // This is followed by 2 bytes + ('adjustment bits' rounded up to the
+ // nearest byte) for every equalisation band in the following format,
+ // giving a frequency range of 0 - 32767Hz:
+ // Increment/decrement %x (MSB of the Frequency)
+ // Frequency (lower 15 bits)
+ // Adjustment $xx (xx ...)
+
+ $frame_offset = 0;
+ $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1);
+ $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8);
+
+ $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset);
+ while (strlen($frame_remainingdata) > 0) {
+ $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2));
+ $frame_incdec = (bool) substr($frame_frequencystr, 0, 1);
+ $frame_frequency = bindec(substr($frame_frequencystr, 1, 15));
+ $parsedFrame[$frame_frequency]['incdec'] = $frame_incdec;
+ $parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes));
+ if ($parsedFrame[$frame_frequency]['incdec'] === false) {
+ $parsedFrame[$frame_frequency]['adjustment'] *= -1;
+ }
+ $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13 RVRB Reverb
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) { // 4.14 REV Reverb
+ // There may only be one 'RVRB' frame in each tag.
+ // <Header for 'Reverb', ID: 'RVRB'>
+ // Reverb left (ms) $xx xx
+ // Reverb right (ms) $xx xx
+ // Reverb bounces, left $xx
+ // Reverb bounces, right $xx
+ // Reverb feedback, left to left $xx
+ // Reverb feedback, left to right $xx
+ // Reverb feedback, right to right $xx
+ // Reverb feedback, right to left $xx
+ // Premix left to right $xx
+ // Premix right to left $xx
+
+ $frame_offset = 0;
+ $parsedFrame['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['bouncesL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['bouncesR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['feedbackLL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['feedbackLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['feedbackRR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['feedbackRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['premixLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['premixRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14 APIC Attached picture
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) { // 4.15 PIC Attached picture
+ // There may be several pictures attached to one file,
+ // each in their individual 'APIC' frame, but only one
+ // with the same content descriptor
+ // <Header for 'Attached picture', ID: 'APIC'>
+ // Text encoding $xx
+ // ID3v2.3+ => MIME type <text string> $00
+ // ID3v2.2 => Image format $xx xx xx
+ // Picture type $xx
+ // Description <text string according to encoding> $00 (00)
+ // Picture data <binary data>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+
+ if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) {
+ $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3);
+ if (strtolower($frame_imagetype) == 'ima') {
+ // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted
+ // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoffØpacbell*net)
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_mimetype) === 0) {
+ $frame_mimetype = '';
+ }
+ $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype)));
+ if ($frame_imagetype == 'JPEG') {
+ $frame_imagetype = 'JPG';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ } else {
+ $frame_offset += 3;
+ }
+ }
+ if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) {
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_mimetype) === 0) {
+ $frame_mimetype = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ }
+
+ $frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+
+ if ($frame_offset >= $parsedFrame['datalength']) {
+ $info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset);
+ } else {
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ if ($id3v2_majorversion == 2) {
+ $parsedFrame['imagetype'] = $frame_imagetype;
+ } else {
+ $parsedFrame['mime'] = $frame_mimetype;
+ }
+ $parsedFrame['picturetypeid'] = $frame_picturetype;
+ $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype);
+ $parsedFrame['description'] = $frame_description;
+ $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)));
+ $parsedFrame['datalength'] = strlen($parsedFrame['data']);
+
+ $parsedFrame['image_mime'] = '';
+ $imageinfo = array();
+ $imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo);
+ if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) {
+ $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]);
+ if ($imagechunkcheck[0]) {
+ $parsedFrame['image_width'] = $imagechunkcheck[0];
+ }
+ if ($imagechunkcheck[1]) {
+ $parsedFrame['image_height'] = $imagechunkcheck[1];
+ }
+ }
+
+ do {
+ if ($this->getid3->option_save_attachments === false) {
+ // skip entirely
+ unset($parsedFrame['data']);
+ break;
+ }
+ if ($this->getid3->option_save_attachments === true) {
+ // great
+/*
+ } elseif (is_int($this->getid3->option_save_attachments)) {
+ if ($this->getid3->option_save_attachments < $parsedFrame['data_length']) {
+ // too big, skip
+ $info['warning'][] = 'attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)';
+ unset($parsedFrame['data']);
+ break;
+ }
+*/
+ } elseif (is_string($this->getid3->option_save_attachments)) {
+ $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR);
+ if (!is_dir($dir) || !is_writable($dir)) {
+ // cannot write, skip
+ $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)';
+ unset($parsedFrame['data']);
+ break;
+ }
+ }
+ // if we get this far, must be OK
+ if (is_string($this->getid3->option_save_attachments)) {
+ $destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset;
+ if (!file_exists($destination_filename) || is_writable($destination_filename)) {
+ file_put_contents($destination_filename, $parsedFrame['data']);
+ } else {
+ $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)';
+ }
+ $parsedFrame['data_filename'] = $destination_filename;
+ unset($parsedFrame['data']);
+ } else {
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ if (!isset($info['id3v2']['comments']['picture'])) {
+ $info['id3v2']['comments']['picture'] = array();
+ }
+ $info['id3v2']['comments']['picture'][] = array('data'=>$parsedFrame['data'], 'image_mime'=>$parsedFrame['image_mime']);
+ }
+ }
+ } while (false);
+ }
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) { // 4.16 GEO General encapsulated object
+ // There may be more than one 'GEOB' frame in each tag,
+ // but only one with the same content descriptor
+ // <Header for 'General encapsulated object', ID: 'GEOB'>
+ // Text encoding $xx
+ // MIME type <text string> $00
+ // Filename <text string according to encoding> $00 (00)
+ // Content description <text string according to encoding> $00 (00)
+ // Encapsulated object <binary data>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_mimetype) === 0) {
+ $frame_mimetype = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_filename) === 0) {
+ $frame_filename = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
+
+ $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset);
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['mime'] = $frame_mimetype;
+ $parsedFrame['filename'] = $frame_filename;
+ $parsedFrame['description'] = $frame_description;
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16 PCNT Play counter
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) { // 4.17 CNT Play counter
+ // There may only be one 'PCNT' frame in each tag.
+ // When the counter reaches all one's, one byte is inserted in
+ // front of the counter thus making the counter eight bits bigger
+ // <Header for 'Play counter', ID: 'PCNT'>
+ // Counter $xx xx xx xx (xx ...)
+
+ $parsedFrame['data'] = getid3_lib::BigEndian2Int($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17 POPM Popularimeter
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) { // 4.18 POP Popularimeter
+ // There may be more than one 'POPM' frame in each tag,
+ // but only one with the same email address
+ // <Header for 'Popularimeter', ID: 'POPM'>
+ // Email to user <text string> $00
+ // Rating $xx
+ // Counter $xx xx xx xx (xx ...)
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_emailaddress) === 0) {
+ $frame_emailaddress = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ $frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['counter'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
+ $parsedFrame['email'] = $frame_emailaddress;
+ $parsedFrame['rating'] = $frame_rating;
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18 RBUF Recommended buffer size
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) { // 4.19 BUF Recommended buffer size
+ // There may only be one 'RBUF' frame in each tag
+ // <Header for 'Recommended buffer size', ID: 'RBUF'>
+ // Buffer size $xx xx xx
+ // Embedded info flag %0000000x
+ // Offset to next tag $xx xx xx xx
+
+ $frame_offset = 0;
+ $parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3));
+ $frame_offset += 3;
+
+ $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1);
+ $parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) { // 4.20 Encrypted meta frame (ID3v2.2 only)
+ // There may be more than one 'CRM' frame in a tag,
+ // but only one with the same 'owner identifier'
+ // <Header for 'Encrypted meta frame', ID: 'CRM'>
+ // Owner identifier <textstring> $00 (00)
+ // Content/explanation <textstring> $00 (00)
+ // Encrypted datablock <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+ $parsedFrame['description'] = $frame_description;
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19 AENC Audio encryption
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) { // 4.21 CRA Audio encryption
+ // There may be more than one 'AENC' frames in a tag,
+ // but only one with the same 'Owner identifier'
+ // <Header for 'Audio encryption', ID: 'AENC'>
+ // Owner identifier <text string> $00
+ // Preview start $xx xx
+ // Preview length $xx xx
+ // Encryption info <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_ownerid) === 0) {
+ $frame_ownerid == '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset);
+ unset($parsedFrame['data']);
+
+
+ } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20 LINK Linked information
+ (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) { // 4.22 LNK Linked information
+ // There may be more than one 'LINK' frame in a tag,
+ // but only one with the same contents
+ // <Header for 'Linked information', ID: 'LINK'>
+ // ID3v2.3+ => Frame identifier $xx xx xx xx
+ // ID3v2.2 => Frame identifier $xx xx xx
+ // URL <text string> $00
+ // ID and additional data <text string(s)>
+
+ $frame_offset = 0;
+ if ($id3v2_majorversion == 2) {
+ $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ } else {
+ $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4);
+ $frame_offset += 4;
+ }
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_url) === 0) {
+ $frame_url = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ $parsedFrame['url'] = $frame_url;
+
+ $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset);
+ if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = utf8_encode($parsedFrame['url']);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) { // 4.21 POSS Position synchronisation frame (ID3v2.3+ only)
+ // There may only be one 'POSS' frame in each tag
+ // <Head for 'Position synchronisation', ID: 'POSS'>
+ // Time stamp format $xx
+ // Position $xx (xx ...)
+
+ $frame_offset = 0;
+ $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['position'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset));
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) { // 4.22 USER Terms of use (ID3v2.3+ only)
+ // There may be more than one 'Terms of use' frame in a tag,
+ // but only one with the same 'Language'
+ // <Header for 'Terms of use frame', ID: 'USER'>
+ // Text encoding $xx
+ // Language $xx xx xx
+ // The actual text <text string according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $frame_language = substr($parsedFrame['data'], $frame_offset, 3);
+ $frame_offset += 3;
+ $parsedFrame['language'] = $frame_language;
+ $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false);
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+ if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) {
+ $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']);
+ }
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) { // 4.23 OWNE Ownership frame (ID3v2.3+ only)
+ // There may only be one 'OWNE' frame in a tag
+ // <Header for 'Ownership frame', ID: 'OWNE'>
+ // Text encoding $xx
+ // Price paid <text string> $00
+ // Date of purch. <text string>
+ // Seller <text string according to encoding>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3);
+ $parsedFrame['pricepaid']['currency'] = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']);
+ $parsedFrame['pricepaid']['value'] = substr($frame_pricepaid, 3);
+
+ $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8);
+ if (!$this->IsValidDateStampString($parsedFrame['purchasedate'])) {
+ $parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4));
+ }
+ $frame_offset += 8;
+
+ $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset);
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) { // 4.24 COMR Commercial frame (ID3v2.3+ only)
+ // There may be more than one 'commercial frame' in a tag,
+ // but no two may be identical
+ // <Header for 'Commercial frame', ID: 'COMR'>
+ // Text encoding $xx
+ // Price string <text string> $00
+ // Valid until <text string>
+ // Contact URL <text string> $00
+ // Received as $xx
+ // Name of seller <text string according to encoding> $00 (00)
+ // Description <text string according to encoding> $00 (00)
+ // Picture MIME type <string> $00
+ // Seller logo <binary data>
+
+ $frame_offset = 0;
+ $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) {
+ $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding';
+ }
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+ $frame_rawpricearray = explode('/', $frame_pricestring);
+ foreach ($frame_rawpricearray as $key => $val) {
+ $frame_currencyid = substr($val, 0, 3);
+ $parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid);
+ $parsedFrame['price'][$frame_currencyid]['value'] = substr($val, 3);
+ }
+
+ $frame_datestring = substr($parsedFrame['data'], $frame_offset, 8);
+ $frame_offset += 8;
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_sellername) === 0) {
+ $frame_sellername = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset);
+ if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) {
+ $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00
+ }
+ $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_description) === 0) {
+ $frame_description = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding));
+
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $frame_sellerlogo = substr($parsedFrame['data'], $frame_offset);
+
+ $parsedFrame['encodingid'] = $frame_textencoding;
+ $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding);
+
+ $parsedFrame['pricevaliduntil'] = $frame_datestring;
+ $parsedFrame['contacturl'] = $frame_contacturl;
+ $parsedFrame['receivedasid'] = $frame_receivedasid;
+ $parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid);
+ $parsedFrame['sellername'] = $frame_sellername;
+ $parsedFrame['description'] = $frame_description;
+ $parsedFrame['mime'] = $frame_mimetype;
+ $parsedFrame['logo'] = $frame_sellerlogo;
+ unset($parsedFrame['data']);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) { // 4.25 ENCR Encryption method registration (ID3v2.3+ only)
+ // There may be several 'ENCR' frames in a tag,
+ // but only one containing the same symbol
+ // and only one containing the same owner identifier
+ // <Header for 'Encryption method registration', ID: 'ENCR'>
+ // Owner identifier <text string> $00
+ // Method symbol $xx
+ // Encryption data <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_ownerid) === 0) {
+ $frame_ownerid = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) { // 4.26 GRID Group identification registration (ID3v2.3+ only)
+
+ // There may be several 'GRID' frames in a tag,
+ // but only one containing the same symbol
+ // and only one containing the same owner identifier
+ // <Header for 'Group ID registration', ID: 'GRID'>
+ // Owner identifier <text string> $00
+ // Group symbol $xx
+ // Group dependent data <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_ownerid) === 0) {
+ $frame_ownerid = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) { // 4.27 PRIV Private frame (ID3v2.3+ only)
+ // The tag may contain more than one 'PRIV' frame
+ // but only with different contents
+ // <Header for 'Private frame', ID: 'PRIV'>
+ // Owner identifier <text string> $00
+ // The private data <binary data>
+
+ $frame_offset = 0;
+ $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset);
+ $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset);
+ if (ord($frame_ownerid) === 0) {
+ $frame_ownerid = '';
+ }
+ $frame_offset = $frame_terminatorpos + strlen("\x00");
+
+ $parsedFrame['ownerid'] = $frame_ownerid;
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) { // 4.28 SIGN Signature frame (ID3v2.4+ only)
+ // There may be more than one 'signature frame' in a tag,
+ // but no two may be identical
+ // <Header for 'Signature frame', ID: 'SIGN'>
+ // Group symbol $xx
+ // Signature <binary data>
+
+ $frame_offset = 0;
+ $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset);
+
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) { // 4.29 SEEK Seek frame (ID3v2.4+ only)
+ // There may only be one 'seek frame' in a tag
+ // <Header for 'Seek frame', ID: 'SEEK'>
+ // Minimum offset to next tag $xx xx xx xx
+
+ $frame_offset = 0;
+ $parsedFrame['data'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+
+
+ } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) { // 4.30 ASPI Audio seek point index (ID3v2.4+ only)
+ // There may only be one 'audio seek point index' frame in a tag
+ // <Header for 'Seek Point Index', ID: 'ASPI'>
+ // Indexed data start (S) $xx xx xx xx
+ // Indexed data length (L) $xx xx xx xx
+ // Number of index points (N) $xx xx
+ // Bits per index point (b) $xx
+ // Then for every index point the following data is included:
+ // Fraction at index (Fi) $xx (xx)
+
+ $frame_offset = 0;
+ $parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ $parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ $parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1));
+ $frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8);
+ for ($i = 0; $i < $frame_indexpoints; $i++) {
+ $parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint));
+ $frame_offset += $frame_bytesperpoint;
+ }
+ unset($parsedFrame['data']);
+
+ } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment
+ // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
+ // There may only be one 'RGAD' frame in a tag
+ // <Header for 'Replay Gain Adjustment', ID: 'RGAD'>
+ // Peak Amplitude $xx $xx $xx $xx
+ // Radio Replay Gain Adjustment %aaabbbcd %dddddddd
+ // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd
+ // a - name code
+ // b - originator code
+ // c - sign bit
+ // d - replay gain adjustment
+
+ $frame_offset = 0;
+ $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4));
+ $frame_offset += 4;
+ $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2));
+ $frame_offset += 2;
+ $parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3));
+ $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3));
+ $parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1));
+ $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9));
+ $parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3));
+ $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3));
+ $parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1));
+ $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9));
+ $parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']);
+ $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']);
+ $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']);
+ $parsedFrame['album']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']);
+ $parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']);
+ $parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']);
+
+ $info['replay_gain']['track']['peak'] = $parsedFrame['peakamplitude'];
+ $info['replay_gain']['track']['originator'] = $parsedFrame['track']['originator'];
+ $info['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment'];
+ $info['replay_gain']['album']['originator'] = $parsedFrame['album']['originator'];
+ $info['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment'];
+
+ unset($parsedFrame['data']);
+
+ }
+
+ return true;
+ }
+
+
+ public function DeUnsynchronise($data) {
+ return str_replace("\xFF\x00", "\xFF", $data);
+ }
+
+ public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) {
+ static $LookupExtendedHeaderRestrictionsTagSizeLimits = array(
+ 0x00 => 'No more than 128 frames and 1 MB total tag size',
+ 0x01 => 'No more than 64 frames and 128 KB total tag size',
+ 0x02 => 'No more than 32 frames and 40 KB total tag size',
+ 0x03 => 'No more than 32 frames and 4 KB total tag size',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : '');
+ }
+
+ public function LookupExtendedHeaderRestrictionsTextEncodings($index) {
+ static $LookupExtendedHeaderRestrictionsTextEncodings = array(
+ 0x00 => 'No restrictions',
+ 0x01 => 'Strings are only encoded with ISO-8859-1 or UTF-8',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : '');
+ }
+
+ public function LookupExtendedHeaderRestrictionsTextFieldSize($index) {
+ static $LookupExtendedHeaderRestrictionsTextFieldSize = array(
+ 0x00 => 'No restrictions',
+ 0x01 => 'No string is longer than 1024 characters',
+ 0x02 => 'No string is longer than 128 characters',
+ 0x03 => 'No string is longer than 30 characters',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : '');
+ }
+
+ public function LookupExtendedHeaderRestrictionsImageEncoding($index) {
+ static $LookupExtendedHeaderRestrictionsImageEncoding = array(
+ 0x00 => 'No restrictions',
+ 0x01 => 'Images are encoded only with PNG or JPEG',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : '');
+ }
+
+ public function LookupExtendedHeaderRestrictionsImageSizeSize($index) {
+ static $LookupExtendedHeaderRestrictionsImageSizeSize = array(
+ 0x00 => 'No restrictions',
+ 0x01 => 'All images are 256x256 pixels or smaller',
+ 0x02 => 'All images are 64x64 pixels or smaller',
+ 0x03 => 'All images are exactly 64x64 pixels, unless required otherwise',
+ );
+ return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : '');
+ }
+
+ public function LookupCurrencyUnits($currencyid) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+
+ AED Dirhams
+ AFA Afghanis
+ ALL Leke
+ AMD Drams
+ ANG Guilders
+ AOA Kwanza
+ ARS Pesos
+ ATS Schillings
+ AUD Dollars
+ AWG Guilders
+ AZM Manats
+ BAM Convertible Marka
+ BBD Dollars
+ BDT Taka
+ BEF Francs
+ BGL Leva
+ BHD Dinars
+ BIF Francs
+ BMD Dollars
+ BND Dollars
+ BOB Bolivianos
+ BRL Brazil Real
+ BSD Dollars
+ BTN Ngultrum
+ BWP Pulas
+ BYR Rubles
+ BZD Dollars
+ CAD Dollars
+ CDF Congolese Francs
+ CHF Francs
+ CLP Pesos
+ CNY Yuan Renminbi
+ COP Pesos
+ CRC Colones
+ CUP Pesos
+ CVE Escudos
+ CYP Pounds
+ CZK Koruny
+ DEM Deutsche Marks
+ DJF Francs
+ DKK Kroner
+ DOP Pesos
+ DZD Algeria Dinars
+ EEK Krooni
+ EGP Pounds
+ ERN Nakfa
+ ESP Pesetas
+ ETB Birr
+ EUR Euro
+ FIM Markkaa
+ FJD Dollars
+ FKP Pounds
+ FRF Francs
+ GBP Pounds
+ GEL Lari
+ GGP Pounds
+ GHC Cedis
+ GIP Pounds
+ GMD Dalasi
+ GNF Francs
+ GRD Drachmae
+ GTQ Quetzales
+ GYD Dollars
+ HKD Dollars
+ HNL Lempiras
+ HRK Kuna
+ HTG Gourdes
+ HUF Forints
+ IDR Rupiahs
+ IEP Pounds
+ ILS New Shekels
+ IMP Pounds
+ INR Rupees
+ IQD Dinars
+ IRR Rials
+ ISK Kronur
+ ITL Lire
+ JEP Pounds
+ JMD Dollars
+ JOD Dinars
+ JPY Yen
+ KES Shillings
+ KGS Soms
+ KHR Riels
+ KMF Francs
+ KPW Won
+ KWD Dinars
+ KYD Dollars
+ KZT Tenge
+ LAK Kips
+ LBP Pounds
+ LKR Rupees
+ LRD Dollars
+ LSL Maloti
+ LTL Litai
+ LUF Francs
+ LVL Lati
+ LYD Dinars
+ MAD Dirhams
+ MDL Lei
+ MGF Malagasy Francs
+ MKD Denars
+ MMK Kyats
+ MNT Tugriks
+ MOP Patacas
+ MRO Ouguiyas
+ MTL Liri
+ MUR Rupees
+ MVR Rufiyaa
+ MWK Kwachas
+ MXN Pesos
+ MYR Ringgits
+ MZM Meticais
+ NAD Dollars
+ NGN Nairas
+ NIO Gold Cordobas
+ NLG Guilders
+ NOK Krone
+ NPR Nepal Rupees
+ NZD Dollars
+ OMR Rials
+ PAB Balboa
+ PEN Nuevos Soles
+ PGK Kina
+ PHP Pesos
+ PKR Rupees
+ PLN Zlotych
+ PTE Escudos
+ PYG Guarani
+ QAR Rials
+ ROL Lei
+ RUR Rubles
+ RWF Rwanda Francs
+ SAR Riyals
+ SBD Dollars
+ SCR Rupees
+ SDD Dinars
+ SEK Kronor
+ SGD Dollars
+ SHP Pounds
+ SIT Tolars
+ SKK Koruny
+ SLL Leones
+ SOS Shillings
+ SPL Luigini
+ SRG Guilders
+ STD Dobras
+ SVC Colones
+ SYP Pounds
+ SZL Emalangeni
+ THB Baht
+ TJR Rubles
+ TMM Manats
+ TND Dinars
+ TOP Pa'anga
+ TRL Liras
+ TTD Dollars
+ TVD Tuvalu Dollars
+ TWD New Dollars
+ TZS Shillings
+ UAH Hryvnia
+ UGX Shillings
+ USD Dollars
+ UYU Pesos
+ UZS Sums
+ VAL Lire
+ VEB Bolivares
+ VND Dong
+ VUV Vatu
+ WST Tala
+ XAF Francs
+ XAG Ounces
+ XAU Ounces
+ XCD Dollars
+ XDR Special Drawing Rights
+ XPD Ounces
+ XPF Francs
+ XPT Ounces
+ YER Rials
+ YUM New Dinars
+ ZAR Rand
+ ZMK Kwacha
+ ZWD Zimbabwe Dollars
+
+ */
+
+ return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units');
+ }
+
+
+ public function LookupCurrencyCountry($currencyid) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ AED United Arab Emirates
+ AFA Afghanistan
+ ALL Albania
+ AMD Armenia
+ ANG Netherlands Antilles
+ AOA Angola
+ ARS Argentina
+ ATS Austria
+ AUD Australia
+ AWG Aruba
+ AZM Azerbaijan
+ BAM Bosnia and Herzegovina
+ BBD Barbados
+ BDT Bangladesh
+ BEF Belgium
+ BGL Bulgaria
+ BHD Bahrain
+ BIF Burundi
+ BMD Bermuda
+ BND Brunei Darussalam
+ BOB Bolivia
+ BRL Brazil
+ BSD Bahamas
+ BTN Bhutan
+ BWP Botswana
+ BYR Belarus
+ BZD Belize
+ CAD Canada
+ CDF Congo/Kinshasa
+ CHF Switzerland
+ CLP Chile
+ CNY China
+ COP Colombia
+ CRC Costa Rica
+ CUP Cuba
+ CVE Cape Verde
+ CYP Cyprus
+ CZK Czech Republic
+ DEM Germany
+ DJF Djibouti
+ DKK Denmark
+ DOP Dominican Republic
+ DZD Algeria
+ EEK Estonia
+ EGP Egypt
+ ERN Eritrea
+ ESP Spain
+ ETB Ethiopia
+ EUR Euro Member Countries
+ FIM Finland
+ FJD Fiji
+ FKP Falkland Islands (Malvinas)
+ FRF France
+ GBP United Kingdom
+ GEL Georgia
+ GGP Guernsey
+ GHC Ghana
+ GIP Gibraltar
+ GMD Gambia
+ GNF Guinea
+ GRD Greece
+ GTQ Guatemala
+ GYD Guyana
+ HKD Hong Kong
+ HNL Honduras
+ HRK Croatia
+ HTG Haiti
+ HUF Hungary
+ IDR Indonesia
+ IEP Ireland (Eire)
+ ILS Israel
+ IMP Isle of Man
+ INR India
+ IQD Iraq
+ IRR Iran
+ ISK Iceland
+ ITL Italy
+ JEP Jersey
+ JMD Jamaica
+ JOD Jordan
+ JPY Japan
+ KES Kenya
+ KGS Kyrgyzstan
+ KHR Cambodia
+ KMF Comoros
+ KPW Korea
+ KWD Kuwait
+ KYD Cayman Islands
+ KZT Kazakstan
+ LAK Laos
+ LBP Lebanon
+ LKR Sri Lanka
+ LRD Liberia
+ LSL Lesotho
+ LTL Lithuania
+ LUF Luxembourg
+ LVL Latvia
+ LYD Libya
+ MAD Morocco
+ MDL Moldova
+ MGF Madagascar
+ MKD Macedonia
+ MMK Myanmar (Burma)
+ MNT Mongolia
+ MOP Macau
+ MRO Mauritania
+ MTL Malta
+ MUR Mauritius
+ MVR Maldives (Maldive Islands)
+ MWK Malawi
+ MXN Mexico
+ MYR Malaysia
+ MZM Mozambique
+ NAD Namibia
+ NGN Nigeria
+ NIO Nicaragua
+ NLG Netherlands (Holland)
+ NOK Norway
+ NPR Nepal
+ NZD New Zealand
+ OMR Oman
+ PAB Panama
+ PEN Peru
+ PGK Papua New Guinea
+ PHP Philippines
+ PKR Pakistan
+ PLN Poland
+ PTE Portugal
+ PYG Paraguay
+ QAR Qatar
+ ROL Romania
+ RUR Russia
+ RWF Rwanda
+ SAR Saudi Arabia
+ SBD Solomon Islands
+ SCR Seychelles
+ SDD Sudan
+ SEK Sweden
+ SGD Singapore
+ SHP Saint Helena
+ SIT Slovenia
+ SKK Slovakia
+ SLL Sierra Leone
+ SOS Somalia
+ SPL Seborga
+ SRG Suriname
+ STD São Tome and Principe
+ SVC El Salvador
+ SYP Syria
+ SZL Swaziland
+ THB Thailand
+ TJR Tajikistan
+ TMM Turkmenistan
+ TND Tunisia
+ TOP Tonga
+ TRL Turkey
+ TTD Trinidad and Tobago
+ TVD Tuvalu
+ TWD Taiwan
+ TZS Tanzania
+ UAH Ukraine
+ UGX Uganda
+ USD United States of America
+ UYU Uruguay
+ UZS Uzbekistan
+ VAL Vatican City
+ VEB Venezuela
+ VND Viet Nam
+ VUV Vanuatu
+ WST Samoa
+ XAF Communauté Financière Africaine
+ XAG Silver
+ XAU Gold
+ XCD East Caribbean
+ XDR International Monetary Fund
+ XPD Palladium
+ XPF Comptoirs Français du Pacifique
+ XPT Platinum
+ YER Yemen
+ YUM Yugoslavia
+ ZAR South Africa
+ ZMK Zambia
+ ZWD Zimbabwe
+
+ */
+
+ return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country');
+ }
+
+
+
+ public static function LanguageLookup($languagecode, $casesensitive=false) {
+
+ if (!$casesensitive) {
+ $languagecode = strtolower($languagecode);
+ }
+
+ // http://www.id3.org/id3v2.4.0-structure.txt
+ // [4. ID3v2 frame overview]
+ // The three byte language field, present in several frames, is used to
+ // describe the language of the frame's content, according to ISO-639-2
+ // [ISO-639-2]. The language should be represented in lower case. If the
+ // language is not known the string "XXX" should be used.
+
+
+ // ISO 639-2 - http://www.id3.org/iso639-2.html
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ XXX unknown
+ xxx unknown
+ aar Afar
+ abk Abkhazian
+ ace Achinese
+ ach Acoli
+ ada Adangme
+ afa Afro-Asiatic (Other)
+ afh Afrihili
+ afr Afrikaans
+ aka Akan
+ akk Akkadian
+ alb Albanian
+ ale Aleut
+ alg Algonquian Languages
+ amh Amharic
+ ang English, Old (ca. 450-1100)
+ apa Apache Languages
+ ara Arabic
+ arc Aramaic
+ arm Armenian
+ arn Araucanian
+ arp Arapaho
+ art Artificial (Other)
+ arw Arawak
+ asm Assamese
+ ath Athapascan Languages
+ ava Avaric
+ ave Avestan
+ awa Awadhi
+ aym Aymara
+ aze Azerbaijani
+ bad Banda
+ bai Bamileke Languages
+ bak Bashkir
+ bal Baluchi
+ bam Bambara
+ ban Balinese
+ baq Basque
+ bas Basa
+ bat Baltic (Other)
+ bej Beja
+ bel Byelorussian
+ bem Bemba
+ ben Bengali
+ ber Berber (Other)
+ bho Bhojpuri
+ bih Bihari
+ bik Bikol
+ bin Bini
+ bis Bislama
+ bla Siksika
+ bnt Bantu (Other)
+ bod Tibetan
+ bra Braj
+ bre Breton
+ bua Buriat
+ bug Buginese
+ bul Bulgarian
+ bur Burmese
+ cad Caddo
+ cai Central American Indian (Other)
+ car Carib
+ cat Catalan
+ cau Caucasian (Other)
+ ceb Cebuano
+ cel Celtic (Other)
+ ces Czech
+ cha Chamorro
+ chb Chibcha
+ che Chechen
+ chg Chagatai
+ chi Chinese
+ chm Mari
+ chn Chinook jargon
+ cho Choctaw
+ chr Cherokee
+ chu Church Slavic
+ chv Chuvash
+ chy Cheyenne
+ cop Coptic
+ cor Cornish
+ cos Corsican
+ cpe Creoles and Pidgins, English-based (Other)
+ cpf Creoles and Pidgins, French-based (Other)
+ cpp Creoles and Pidgins, Portuguese-based (Other)
+ cre Cree
+ crp Creoles and Pidgins (Other)
+ cus Cushitic (Other)
+ cym Welsh
+ cze Czech
+ dak Dakota
+ dan Danish
+ del Delaware
+ deu German
+ din Dinka
+ div Divehi
+ doi Dogri
+ dra Dravidian (Other)
+ dua Duala
+ dum Dutch, Middle (ca. 1050-1350)
+ dut Dutch
+ dyu Dyula
+ dzo Dzongkha
+ efi Efik
+ egy Egyptian (Ancient)
+ eka Ekajuk
+ ell Greek, Modern (1453-)
+ elx Elamite
+ eng English
+ enm English, Middle (ca. 1100-1500)
+ epo Esperanto
+ esk Eskimo (Other)
+ esl Spanish
+ est Estonian
+ eus Basque
+ ewe Ewe
+ ewo Ewondo
+ fan Fang
+ fao Faroese
+ fas Persian
+ fat Fanti
+ fij Fijian
+ fin Finnish
+ fiu Finno-Ugrian (Other)
+ fon Fon
+ fra French
+ fre French
+ frm French, Middle (ca. 1400-1600)
+ fro French, Old (842- ca. 1400)
+ fry Frisian
+ ful Fulah
+ gaa Ga
+ gae Gaelic (Scots)
+ gai Irish
+ gay Gayo
+ gdh Gaelic (Scots)
+ gem Germanic (Other)
+ geo Georgian
+ ger German
+ gez Geez
+ gil Gilbertese
+ glg Gallegan
+ gmh German, Middle High (ca. 1050-1500)
+ goh German, Old High (ca. 750-1050)
+ gon Gondi
+ got Gothic
+ grb Grebo
+ grc Greek, Ancient (to 1453)
+ gre Greek, Modern (1453-)
+ grn Guarani
+ guj Gujarati
+ hai Haida
+ hau Hausa
+ haw Hawaiian
+ heb Hebrew
+ her Herero
+ hil Hiligaynon
+ him Himachali
+ hin Hindi
+ hmo Hiri Motu
+ hun Hungarian
+ hup Hupa
+ hye Armenian
+ iba Iban
+ ibo Igbo
+ ice Icelandic
+ ijo Ijo
+ iku Inuktitut
+ ilo Iloko
+ ina Interlingua (International Auxiliary language Association)
+ inc Indic (Other)
+ ind Indonesian
+ ine Indo-European (Other)
+ ine Interlingue
+ ipk Inupiak
+ ira Iranian (Other)
+ iri Irish
+ iro Iroquoian uages
+ isl Icelandic
+ ita Italian
+ jav Javanese
+ jaw Javanese
+ jpn Japanese
+ jpr Judeo-Persian
+ jrb Judeo-Arabic
+ kaa Kara-Kalpak
+ kab Kabyle
+ kac Kachin
+ kal Greenlandic
+ kam Kamba
+ kan Kannada
+ kar Karen
+ kas Kashmiri
+ kat Georgian
+ kau Kanuri
+ kaw Kawi
+ kaz Kazakh
+ kha Khasi
+ khi Khoisan (Other)
+ khm Khmer
+ kho Khotanese
+ kik Kikuyu
+ kin Kinyarwanda
+ kir Kirghiz
+ kok Konkani
+ kom Komi
+ kon Kongo
+ kor Korean
+ kpe Kpelle
+ kro Kru
+ kru Kurukh
+ kua Kuanyama
+ kum Kumyk
+ kur Kurdish
+ kus Kusaie
+ kut Kutenai
+ lad Ladino
+ lah Lahnda
+ lam Lamba
+ lao Lao
+ lat Latin
+ lav Latvian
+ lez Lezghian
+ lin Lingala
+ lit Lithuanian
+ lol Mongo
+ loz Lozi
+ ltz Letzeburgesch
+ lub Luba-Katanga
+ lug Ganda
+ lui Luiseno
+ lun Lunda
+ luo Luo (Kenya and Tanzania)
+ mac Macedonian
+ mad Madurese
+ mag Magahi
+ mah Marshall
+ mai Maithili
+ mak Macedonian
+ mak Makasar
+ mal Malayalam
+ man Mandingo
+ mao Maori
+ map Austronesian (Other)
+ mar Marathi
+ mas Masai
+ max Manx
+ may Malay
+ men Mende
+ mga Irish, Middle (900 - 1200)
+ mic Micmac
+ min Minangkabau
+ mis Miscellaneous (Other)
+ mkh Mon-Kmer (Other)
+ mlg Malagasy
+ mlt Maltese
+ mni Manipuri
+ mno Manobo Languages
+ moh Mohawk
+ mol Moldavian
+ mon Mongolian
+ mos Mossi
+ mri Maori
+ msa Malay
+ mul Multiple Languages
+ mun Munda Languages
+ mus Creek
+ mwr Marwari
+ mya Burmese
+ myn Mayan Languages
+ nah Aztec
+ nai North American Indian (Other)
+ nau Nauru
+ nav Navajo
+ nbl Ndebele, South
+ nde Ndebele, North
+ ndo Ndongo
+ nep Nepali
+ new Newari
+ nic Niger-Kordofanian (Other)
+ niu Niuean
+ nla Dutch
+ nno Norwegian (Nynorsk)
+ non Norse, Old
+ nor Norwegian
+ nso Sotho, Northern
+ nub Nubian Languages
+ nya Nyanja
+ nym Nyamwezi
+ nyn Nyankole
+ nyo Nyoro
+ nzi Nzima
+ oci Langue d'Oc (post 1500)
+ oji Ojibwa
+ ori Oriya
+ orm Oromo
+ osa Osage
+ oss Ossetic
+ ota Turkish, Ottoman (1500 - 1928)
+ oto Otomian Languages
+ paa Papuan-Australian (Other)
+ pag Pangasinan
+ pal Pahlavi
+ pam Pampanga
+ pan Panjabi
+ pap Papiamento
+ pau Palauan
+ peo Persian, Old (ca 600 - 400 B.C.)
+ per Persian
+ phn Phoenician
+ pli Pali
+ pol Polish
+ pon Ponape
+ por Portuguese
+ pra Prakrit uages
+ pro Provencal, Old (to 1500)
+ pus Pushto
+ que Quechua
+ raj Rajasthani
+ rar Rarotongan
+ roa Romance (Other)
+ roh Rhaeto-Romance
+ rom Romany
+ ron Romanian
+ rum Romanian
+ run Rundi
+ rus Russian
+ sad Sandawe
+ sag Sango
+ sah Yakut
+ sai South American Indian (Other)
+ sal Salishan Languages
+ sam Samaritan Aramaic
+ san Sanskrit
+ sco Scots
+ scr Serbo-Croatian
+ sel Selkup
+ sem Semitic (Other)
+ sga Irish, Old (to 900)
+ shn Shan
+ sid Sidamo
+ sin Singhalese
+ sio Siouan Languages
+ sit Sino-Tibetan (Other)
+ sla Slavic (Other)
+ slk Slovak
+ slo Slovak
+ slv Slovenian
+ smi Sami Languages
+ smo Samoan
+ sna Shona
+ snd Sindhi
+ sog Sogdian
+ som Somali
+ son Songhai
+ sot Sotho, Southern
+ spa Spanish
+ sqi Albanian
+ srd Sardinian
+ srr Serer
+ ssa Nilo-Saharan (Other)
+ ssw Siswant
+ ssw Swazi
+ suk Sukuma
+ sun Sudanese
+ sus Susu
+ sux Sumerian
+ sve Swedish
+ swa Swahili
+ swe Swedish
+ syr Syriac
+ tah Tahitian
+ tam Tamil
+ tat Tatar
+ tel Telugu
+ tem Timne
+ ter Tereno
+ tgk Tajik
+ tgl Tagalog
+ tha Thai
+ tib Tibetan
+ tig Tigre
+ tir Tigrinya
+ tiv Tivi
+ tli Tlingit
+ tmh Tamashek
+ tog Tonga (Nyasa)
+ ton Tonga (Tonga Islands)
+ tru Truk
+ tsi Tsimshian
+ tsn Tswana
+ tso Tsonga
+ tuk Turkmen
+ tum Tumbuka
+ tur Turkish
+ tut Altaic (Other)
+ twi Twi
+ tyv Tuvinian
+ uga Ugaritic
+ uig Uighur
+ ukr Ukrainian
+ umb Umbundu
+ und Undetermined
+ urd Urdu
+ uzb Uzbek
+ vai Vai
+ ven Venda
+ vie Vietnamese
+ vol Volapük
+ vot Votic
+ wak Wakashan Languages
+ wal Walamo
+ war Waray
+ was Washo
+ wel Welsh
+ wen Sorbian Languages
+ wol Wolof
+ xho Xhosa
+ yao Yao
+ yap Yap
+ yid Yiddish
+ yor Yoruba
+ zap Zapotec
+ zen Zenaga
+ zha Zhuang
+ zho Chinese
+ zul Zulu
+ zun Zuni
+
+ */
+
+ return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode');
+ }
+
+
+ public static function ETCOEventLookup($index) {
+ if (($index >= 0x17) && ($index <= 0xDF)) {
+ return 'reserved for future use';
+ }
+ if (($index >= 0xE0) && ($index <= 0xEF)) {
+ return 'not predefined synch 0-F';
+ }
+ if (($index >= 0xF0) && ($index <= 0xFC)) {
+ return 'reserved for future use';
+ }
+
+ static $EventLookup = array(
+ 0x00 => 'padding (has no meaning)',
+ 0x01 => 'end of initial silence',
+ 0x02 => 'intro start',
+ 0x03 => 'main part start',
+ 0x04 => 'outro start',
+ 0x05 => 'outro end',
+ 0x06 => 'verse start',
+ 0x07 => 'refrain start',
+ 0x08 => 'interlude start',
+ 0x09 => 'theme start',
+ 0x0A => 'variation start',
+ 0x0B => 'key change',
+ 0x0C => 'time change',
+ 0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)',
+ 0x0E => 'sustained noise',
+ 0x0F => 'sustained noise end',
+ 0x10 => 'intro end',
+ 0x11 => 'main part end',
+ 0x12 => 'verse end',
+ 0x13 => 'refrain end',
+ 0x14 => 'theme end',
+ 0x15 => 'profanity',
+ 0x16 => 'profanity end',
+ 0xFD => 'audio end (start of silence)',
+ 0xFE => 'audio file ends',
+ 0xFF => 'one more byte of events follows'
+ );
+
+ return (isset($EventLookup[$index]) ? $EventLookup[$index] : '');
+ }
+
+ public static function SYTLContentTypeLookup($index) {
+ static $SYTLContentTypeLookup = array(
+ 0x00 => 'other',
+ 0x01 => 'lyrics',
+ 0x02 => 'text transcription',
+ 0x03 => 'movement/part name', // (e.g. 'Adagio')
+ 0x04 => 'events', // (e.g. 'Don Quijote enters the stage')
+ 0x05 => 'chord', // (e.g. 'Bb F Fsus')
+ 0x06 => 'trivia/\'pop up\' information',
+ 0x07 => 'URLs to webpages',
+ 0x08 => 'URLs to images'
+ );
+
+ return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : '');
+ }
+
+ public static function APICPictureTypeLookup($index, $returnarray=false) {
+ static $APICPictureTypeLookup = array(
+ 0x00 => 'Other',
+ 0x01 => '32x32 pixels \'file icon\' (PNG only)',
+ 0x02 => 'Other file icon',
+ 0x03 => 'Cover (front)',
+ 0x04 => 'Cover (back)',
+ 0x05 => 'Leaflet page',
+ 0x06 => 'Media (e.g. label side of CD)',
+ 0x07 => 'Lead artist/lead performer/soloist',
+ 0x08 => 'Artist/performer',
+ 0x09 => 'Conductor',
+ 0x0A => 'Band/Orchestra',
+ 0x0B => 'Composer',
+ 0x0C => 'Lyricist/text writer',
+ 0x0D => 'Recording Location',
+ 0x0E => 'During recording',
+ 0x0F => 'During performance',
+ 0x10 => 'Movie/video screen capture',
+ 0x11 => 'A bright coloured fish',
+ 0x12 => 'Illustration',
+ 0x13 => 'Band/artist logotype',
+ 0x14 => 'Publisher/Studio logotype'
+ );
+ if ($returnarray) {
+ return $APICPictureTypeLookup;
+ }
+ return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : '');
+ }
+
+ public static function COMRReceivedAsLookup($index) {
+ static $COMRReceivedAsLookup = array(
+ 0x00 => 'Other',
+ 0x01 => 'Standard CD album with other songs',
+ 0x02 => 'Compressed audio on CD',
+ 0x03 => 'File over the Internet',
+ 0x04 => 'Stream over the Internet',
+ 0x05 => 'As note sheets',
+ 0x06 => 'As note sheets in a book with other sheets',
+ 0x07 => 'Music on other media',
+ 0x08 => 'Non-musical merchandise'
+ );
+
+ return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : '');
+ }
+
+ public static function RVA2ChannelTypeLookup($index) {
+ static $RVA2ChannelTypeLookup = array(
+ 0x00 => 'Other',
+ 0x01 => 'Master volume',
+ 0x02 => 'Front right',
+ 0x03 => 'Front left',
+ 0x04 => 'Back right',
+ 0x05 => 'Back left',
+ 0x06 => 'Front centre',
+ 0x07 => 'Back centre',
+ 0x08 => 'Subwoofer'
+ );
+
+ return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : '');
+ }
+
+ public static function FrameNameLongLookup($framename) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ AENC Audio encryption
+ APIC Attached picture
+ ASPI Audio seek point index
+ BUF Recommended buffer size
+ CNT Play counter
+ COM Comments
+ COMM Comments
+ COMR Commercial frame
+ CRA Audio encryption
+ CRM Encrypted meta frame
+ ENCR Encryption method registration
+ EQU Equalisation
+ EQU2 Equalisation (2)
+ EQUA Equalisation
+ ETC Event timing codes
+ ETCO Event timing codes
+ GEO General encapsulated object
+ GEOB General encapsulated object
+ GRID Group identification registration
+ IPL Involved people list
+ IPLS Involved people list
+ LINK Linked information
+ LNK Linked information
+ MCDI Music CD identifier
+ MCI Music CD Identifier
+ MLL MPEG location lookup table
+ MLLT MPEG location lookup table
+ OWNE Ownership frame
+ PCNT Play counter
+ PIC Attached picture
+ POP Popularimeter
+ POPM Popularimeter
+ POSS Position synchronisation frame
+ PRIV Private frame
+ RBUF Recommended buffer size
+ REV Reverb
+ RVA Relative volume adjustment
+ RVA2 Relative volume adjustment (2)
+ RVAD Relative volume adjustment
+ RVRB Reverb
+ SEEK Seek frame
+ SIGN Signature frame
+ SLT Synchronised lyric/text
+ STC Synced tempo codes
+ SYLT Synchronised lyric/text
+ SYTC Synchronised tempo codes
+ TAL Album/Movie/Show title
+ TALB Album/Movie/Show title
+ TBP BPM (Beats Per Minute)
+ TBPM BPM (beats per minute)
+ TCM Composer
+ TCMP Part of a compilation
+ TCO Content type
+ TCOM Composer
+ TCON Content type
+ TCOP Copyright message
+ TCP Part of a compilation
+ TCR Copyright message
+ TDA Date
+ TDAT Date
+ TDEN Encoding time
+ TDLY Playlist delay
+ TDOR Original release time
+ TDRC Recording time
+ TDRL Release time
+ TDTG Tagging time
+ TDY Playlist delay
+ TEN Encoded by
+ TENC Encoded by
+ TEXT Lyricist/Text writer
+ TFLT File type
+ TFT File type
+ TIM Time
+ TIME Time
+ TIPL Involved people list
+ TIT1 Content group description
+ TIT2 Title/songname/content description
+ TIT3 Subtitle/Description refinement
+ TKE Initial key
+ TKEY Initial key
+ TLA Language(s)
+ TLAN Language(s)
+ TLE Length
+ TLEN Length
+ TMCL Musician credits list
+ TMED Media type
+ TMOO Mood
+ TMT Media type
+ TOA Original artist(s)/performer(s)
+ TOAL Original album/movie/show title
+ TOF Original filename
+ TOFN Original filename
+ TOL Original Lyricist(s)/text writer(s)
+ TOLY Original lyricist(s)/text writer(s)
+ TOPE Original artist(s)/performer(s)
+ TOR Original release year
+ TORY Original release year
+ TOT Original album/Movie/Show title
+ TOWN File owner/licensee
+ TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group
+ TP2 Band/Orchestra/Accompaniment
+ TP3 Conductor/Performer refinement
+ TP4 Interpreted, remixed, or otherwise modified by
+ TPA Part of a set
+ TPB Publisher
+ TPE1 Lead performer(s)/Soloist(s)
+ TPE2 Band/orchestra/accompaniment
+ TPE3 Conductor/performer refinement
+ TPE4 Interpreted, remixed, or otherwise modified by
+ TPOS Part of a set
+ TPRO Produced notice
+ TPUB Publisher
+ TRC ISRC (International Standard Recording Code)
+ TRCK Track number/Position in set
+ TRD Recording dates
+ TRDA Recording dates
+ TRK Track number/Position in set
+ TRSN Internet radio station name
+ TRSO Internet radio station owner
+ TS2 Album-Artist sort order
+ TSA Album sort order
+ TSC Composer sort order
+ TSI Size
+ TSIZ Size
+ TSO2 Album-Artist sort order
+ TSOA Album sort order
+ TSOC Composer sort order
+ TSOP Performer sort order
+ TSOT Title sort order
+ TSP Performer sort order
+ TSRC ISRC (international standard recording code)
+ TSS Software/hardware and settings used for encoding
+ TSSE Software/Hardware and settings used for encoding
+ TSST Set subtitle
+ TST Title sort order
+ TT1 Content group description
+ TT2 Title/Songname/Content description
+ TT3 Subtitle/Description refinement
+ TXT Lyricist/text writer
+ TXX User defined text information frame
+ TXXX User defined text information frame
+ TYE Year
+ TYER Year
+ UFI Unique file identifier
+ UFID Unique file identifier
+ ULT Unsychronised lyric/text transcription
+ USER Terms of use
+ USLT Unsynchronised lyric/text transcription
+ WAF Official audio file webpage
+ WAR Official artist/performer webpage
+ WAS Official audio source webpage
+ WCM Commercial information
+ WCOM Commercial information
+ WCOP Copyright/Legal information
+ WCP Copyright/Legal information
+ WOAF Official audio file webpage
+ WOAR Official artist/performer webpage
+ WOAS Official audio source webpage
+ WORS Official Internet radio station homepage
+ WPAY Payment
+ WPB Publishers official webpage
+ WPUB Publishers official webpage
+ WXX User defined URL link frame
+ WXXX User defined URL link frame
+ TFEA Featured Artist
+ TSTU Recording Studio
+ rgad Replay Gain Adjustment
+
+ */
+
+ return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long');
+
+ // Last three:
+ // from Helium2 [www.helium2.com]
+ // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html
+ }
+
+
+ public static function FrameNameShortLookup($framename) {
+
+ $begin = __LINE__;
+
+ /** This is not a comment!
+
+ AENC audio_encryption
+ APIC attached_picture
+ ASPI audio_seek_point_index
+ BUF recommended_buffer_size
+ CNT play_counter
+ COM comment
+ COMM comment
+ COMR commercial_frame
+ CRA audio_encryption
+ CRM encrypted_meta_frame
+ ENCR encryption_method_registration
+ EQU equalisation
+ EQU2 equalisation
+ EQUA equalisation
+ ETC event_timing_codes
+ ETCO event_timing_codes
+ GEO general_encapsulated_object
+ GEOB general_encapsulated_object
+ GRID group_identification_registration
+ IPL involved_people_list
+ IPLS involved_people_list
+ LINK linked_information
+ LNK linked_information
+ MCDI music_cd_identifier
+ MCI music_cd_identifier
+ MLL mpeg_location_lookup_table
+ MLLT mpeg_location_lookup_table
+ OWNE ownership_frame
+ PCNT play_counter
+ PIC attached_picture
+ POP popularimeter
+ POPM popularimeter
+ POSS position_synchronisation_frame
+ PRIV private_frame
+ RBUF recommended_buffer_size
+ REV reverb
+ RVA relative_volume_adjustment
+ RVA2 relative_volume_adjustment
+ RVAD relative_volume_adjustment
+ RVRB reverb
+ SEEK seek_frame
+ SIGN signature_frame
+ SLT synchronised_lyric
+ STC synced_tempo_codes
+ SYLT synchronised_lyric
+ SYTC synchronised_tempo_codes
+ TAL album
+ TALB album
+ TBP bpm
+ TBPM bpm
+ TCM composer
+ TCMP part_of_a_compilation
+ TCO genre
+ TCOM composer
+ TCON genre
+ TCOP copyright_message
+ TCP part_of_a_compilation
+ TCR copyright_message
+ TDA date
+ TDAT date
+ TDEN encoding_time
+ TDLY playlist_delay
+ TDOR original_release_time
+ TDRC recording_time
+ TDRL release_time
+ TDTG tagging_time
+ TDY playlist_delay
+ TEN encoded_by
+ TENC encoded_by
+ TEXT lyricist
+ TFLT file_type
+ TFT file_type
+ TIM time
+ TIME time
+ TIPL involved_people_list
+ TIT1 content_group_description
+ TIT2 title
+ TIT3 subtitle
+ TKE initial_key
+ TKEY initial_key
+ TLA language
+ TLAN language
+ TLE length
+ TLEN length
+ TMCL musician_credits_list
+ TMED media_type
+ TMOO mood
+ TMT media_type
+ TOA original_artist
+ TOAL original_album
+ TOF original_filename
+ TOFN original_filename
+ TOL original_lyricist
+ TOLY original_lyricist
+ TOPE original_artist
+ TOR original_year
+ TORY original_year
+ TOT original_album
+ TOWN file_owner
+ TP1 artist
+ TP2 band
+ TP3 conductor
+ TP4 remixer
+ TPA part_of_a_set
+ TPB publisher
+ TPE1 artist
+ TPE2 band
+ TPE3 conductor
+ TPE4 remixer
+ TPOS part_of_a_set
+ TPRO produced_notice
+ TPUB publisher
+ TRC isrc
+ TRCK track_number
+ TRD recording_dates
+ TRDA recording_dates
+ TRK track_number
+ TRSN internet_radio_station_name
+ TRSO internet_radio_station_owner
+ TS2 album_artist_sort_order
+ TSA album_sort_order
+ TSC composer_sort_order
+ TSI size
+ TSIZ size
+ TSO2 album_artist_sort_order
+ TSOA album_sort_order
+ TSOC composer_sort_order
+ TSOP performer_sort_order
+ TSOT title_sort_order
+ TSP performer_sort_order
+ TSRC isrc
+ TSS encoder_settings
+ TSSE encoder_settings
+ TSST set_subtitle
+ TST title_sort_order
+ TT1 content_group_description
+ TT2 title
+ TT3 subtitle
+ TXT lyricist
+ TXX text
+ TXXX text
+ TYE year
+ TYER year
+ UFI unique_file_identifier
+ UFID unique_file_identifier
+ ULT unsychronised_lyric
+ USER terms_of_use
+ USLT unsynchronised_lyric
+ WAF url_file
+ WAR url_artist
+ WAS url_source
+ WCM commercial_information
+ WCOM commercial_information
+ WCOP copyright
+ WCP copyright
+ WOAF url_file
+ WOAR url_artist
+ WOAS url_source
+ WORS url_station
+ WPAY url_payment
+ WPB url_publisher
+ WPUB url_publisher
+ WXX url_user
+ WXXX url_user
+ TFEA featured_artist
+ TSTU recording_studio
+ rgad replay_gain_adjustment
+
+ */
+
+ return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short');
+ }
+
+ public static function TextEncodingTerminatorLookup($encoding) {
+ // http://www.id3.org/id3v2.4.0-structure.txt
+ // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
+ static $TextEncodingTerminatorLookup = array(
+ 0 => "\x00", // $00 ISO-8859-1. Terminated with $00.
+ 1 => "\x00\x00", // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
+ 2 => "\x00\x00", // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
+ 3 => "\x00", // $03 UTF-8 encoded Unicode. Terminated with $00.
+ 255 => "\x00\x00"
+ );
+ return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : '');
+ }
+
+ public static function TextEncodingNameLookup($encoding) {
+ // http://www.id3.org/id3v2.4.0-structure.txt
+ // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings:
+ static $TextEncodingNameLookup = array(
+ 0 => 'ISO-8859-1', // $00 ISO-8859-1. Terminated with $00.
+ 1 => 'UTF-16', // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00.
+ 2 => 'UTF-16BE', // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00.
+ 3 => 'UTF-8', // $03 UTF-8 encoded Unicode. Terminated with $00.
+ 255 => 'UTF-16BE'
+ );
+ return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1');
+ }
+
+ public static function IsValidID3v2FrameName($framename, $id3v2majorversion) {
+ switch ($id3v2majorversion) {
+ case 2:
+ return preg_match('#[A-Z][A-Z0-9]{2}#', $framename);
+ break;
+
+ case 3:
+ case 4:
+ return preg_match('#[A-Z][A-Z0-9]{3}#', $framename);
+ break;
+ }
+ return false;
+ }
+
+ public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) {
+ for ($i = 0; $i < strlen($numberstring); $i++) {
+ if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) {
+ if (($numberstring{$i} == '.') && $allowdecimal) {
+ // allowed
+ } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) {
+ // allowed
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public static function IsValidDateStampString($datestamp) {
+ if (strlen($datestamp) != 8) {
+ return false;
+ }
+ if (!self::IsANumber($datestamp, false)) {
+ return false;
+ }
+ $year = substr($datestamp, 0, 4);
+ $month = substr($datestamp, 4, 2);
+ $day = substr($datestamp, 6, 2);
+ if (($year == 0) || ($month == 0) || ($day == 0)) {
+ return false;
+ }
+ if ($month > 12) {
+ return false;
+ }
+ if ($day > 31) {
+ return false;
+ }
+ if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) {
+ return false;
+ }
+ if (($day > 29) && ($month == 2)) {
+ return false;
+ }
+ return true;
+ }
+
+ public static function ID3v2HeaderLength($majorversion) {
+ return (($majorversion == 2) ? 6 : 10);
+ }
+
+}
+
diff --git a/extensions/TimedMediaHandler/libs/getid3/readme.txt b/extensions/TimedMediaHandler/libs/getid3/readme.txt
new file mode 100644
index 00000000..ebd004eb
--- /dev/null
+++ b/extensions/TimedMediaHandler/libs/getid3/readme.txt
@@ -0,0 +1,591 @@
+/////////////////////////////////////////////////////////////////
+/// getID3() by James Heinrich <info@getid3.org> //
+// available at http://getid3.sourceforge.net //
+// or http://www.getid3.org //
+/////////////////////////////////////////////////////////////////
+// //
+// changelog.txt - part of getID3() //
+// See readme.txt for more details //
+// ///
+/////////////////////////////////////////////////////////////////
+
+ This code is released under the GNU GPL:
+ http://www.gnu.org/copyleft/gpl.html
+
+ +---------------------------------------------+
+ | If you do use this code somewhere, send me |
+ | an email and tell me how/where you used it. |
+ | |
+ | If you want to donate, there is a link on |
+ | http://www.getid3.org for PayPal donations. |
+ +---------------------------------------------+
+
+
+
+Quick Start
+===========================================================================
+
+Q: How can I check that getID3() works on my server/files?
+A: Unzip getID3() to a directory, then access /demos/demo.browse.php
+
+
+
+Support
+===========================================================================
+
+Q: I have a question, or I found a bug. What do I do?
+A: The preferred method of support requests and/or bug reports is the
+ forum at http://support.getid3.org/
+
+
+
+Sourceforge Notification
+===========================================================================
+
+It's highly recommended that you sign up for notification from
+Sourceforge for when new versions are released. Please visit:
+http://sourceforge.net/project/showfiles.php?group_id=55859
+and click the little "monitor package" icon/link. If you're
+previously signed up for the mailing list, be aware that it has
+been discontinued, only the automated Sourceforge notification
+will be used from now on.
+
+
+
+What does getID3() do?
+===========================================================================
+
+Reads & parses (to varying degrees):
+ € tags:
+ * APE (v1 and v2)
+ * ID3v1 (& ID3v1.1)
+ * ID3v2 (v2.4, v2.3, v2.2)
+ * Lyrics3 (v1 & v2)
+
+ € audio-lossy:
+ * MP3/MP2/MP1
+ * MPC / Musepack
+ * Ogg (Vorbis, OggFLAC, Speex)
+ * AC3
+ * DTS
+ * RealAudio
+ * Speex
+ * DSS
+ * VQF
+
+ € audio-lossless:
+ * AIFF
+ * AU
+ * Bonk
+ * CD-audio (*.cda)
+ * FLAC
+ * LA (Lossless Audio)
+ * LiteWave
+ * LPAC
+ * MIDI
+ * Monkey's Audio
+ * OptimFROG
+ * RKAU
+ * Shorten
+ * TTA
+ * VOC
+ * WAV (RIFF)
+ * WavPack
+
+ € audio-video:
+ * ASF: ASF, Windows Media Audio (WMA), Windows Media Video (WMV)
+ * AVI (RIFF)
+ * Flash
+ * Matroska (MKV)
+ * MPEG-1 / MPEG-2
+ * NSV (Nullsoft Streaming Video)
+ * Quicktime
+ * RealVideo
+
+ € still image:
+ * BMP
+ * GIF
+ * JPEG
+ * PNG
+ * TIFF
+ * SWF (Flash)
+ * PhotoCD
+
+ € data:
+ * ISO-9660 CD-ROM image (directory structure)
+ * SZIP (limited support)
+ * ZIP (directory structure)
+ * TAR
+ * CUE
+
+
+Writes:
+ * ID3v1 (& ID3v1.1)
+ * ID3v2 (v2.3 & v2.4)
+ * VorbisComment on OggVorbis
+ * VorbisComment on FLAC (not OggFLAC)
+ * APE v2
+ * Lyrics3 (delete only)
+
+
+
+Requirements
+===========================================================================
+
+* PHP 4.2.0 (or higher) for getID3() 1.7.x (and earlier)
+* PHP 5.3.0 (or higher) for getID3() 1.8.x (and up)
+* PHP 5.0.0 (or higher) for getID3() 2.0.x (and up)
+* at least 4MB memory for PHP. 8MB is highly recommended.
+ 12MB is required with all modules loaded.
+
+
+
+Usage
+===========================================================================
+
+See /demos/demo.basic.php for a very basic use of getID3() with no
+fancy output, just scanning one file.
+
+See structure.txt for the returned data structure.
+
+*> For an example of a complete directory-browsing, <*
+*> file-scanning implementation of getID3(), please run <*
+*> /demos/demo.browse.php <*
+
+See /demos/demo.mysql.php for a sample recursive scanning code that
+scans every file in a given directory, and all sub-directories, stores
+the results in a database and allows various analysis / maintenance
+operations
+
+To analyze remote files over HTTP or FTP you need to copy the file
+locally first before running getID3(). Your code would look something
+like this:
+
+// Copy remote file locally to scan with getID3()
+$remotefilename = 'http://www.example.com/filename.mp3';
+if ($fp_remote = fopen($remotefilename, 'rb')) {
+ $localtempfilename = tempnam('/tmp', 'getID3');
+ if ($fp_local = fopen($localtempfilename, 'wb')) {
+ while ($buffer = fread($fp_remote, 8192)) {
+ fwrite($fp_local, $buffer);
+ }
+ fclose($fp_local);
+
+ // Initialize getID3 engine
+ $getID3 = new getID3;
+
+ $ThisFileInfo = $getID3->analyze($filename);
+
+ // Delete temporary file
+ unlink($localtempfilename);
+ }
+ fclose($fp_remote);
+}
+
+
+See /demos/demo.write.php for how to write tags.
+
+
+
+What does the returned data structure look like?
+===========================================================================
+
+See structure.txt
+
+It is recommended that you look at the output of
+/demos/demo.browse.php scanning the file(s) you're interested in to
+confirm what data is actually returned for any particular filetype in
+general, and your files in particular, as the actual data returned
+may vary considerably depending on what information is available in
+the file itself.
+
+
+
+Notes
+===========================================================================
+
+getID3() 1.x:
+If the format parser encounters a critical problem, it will return
+something in $fileinfo['error'], describing the encountered error. If
+a less critical error or notice is generated it will appear in
+$fileinfo['warning']. Both keys may contain more than one warning or
+error. If something is returned in ['error'] then the file was not
+correctly parsed and returned data may or may not be correct and/or
+complete. If something is returned in ['warning'] (and not ['error'])
+then the data that is returned is OK - usually getID3() is reporting
+errors in the file that have been worked around due to known bugs in
+other programs. Some warnings may indicate that the data that is
+returned is OK but that some data could not be extracted due to
+errors in the file.
+
+getID3() 2.x:
+See above except errors are thrown (so you will only get one error).
+
+
+
+Disclaimer
+===========================================================================
+
+getID3() has been tested on many systems, on many types of files,
+under many operating systems, and is generally believe to be stable
+and safe. That being said, there is still the chance there is an
+undiscovered and/or unfixed bug that may potentially corrupt your
+file, especially within the writing functions. By using getID3() you
+agree that it's not my fault if any of your files are corrupted.
+In fact, I'm not liable for anything :)
+
+
+
+License
+===========================================================================
+
+GNU General Public License - see license.txt
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to:
+Free Software Foundation, Inc.
+59 Temple Place - Suite 330
+Boston, MA 02111-1307, USA.
+
+FAQ:
+Q: Can I use getID3() in my program? Do I need a commercial license?
+A: You're generally free to use getID3 however you see fit. The only
+ case in which you would require a commercial license is if you're
+ selling your closed-source program that integrates getID3. If you
+ sell your program including a copy of getID3, that's fine as long
+ as you include a copy of the sourcecode when you sell it. Or you
+ can distribute your code without getID3 and say "download it from
+ getid3.sourceforge.net"
+
+
+
+Why is it called "getID3()" if it does so much more than just that?
+===========================================================================
+
+v0.1 did in fact just do that. I don't have a copy of code that old, but I
+could essentially write it today with a one-line function:
+ function getID3($filename) { return unpack('a3TAG/a30title/a30artist/a30album/a4year/a28comment/c1track/c1genreid', substr(file_get_contents($filename), -128)); }
+
+
+Future Plans
+===========================================================================
+http://www.getid3.org/phpBB3/viewforum.php?f=7
+
+* Better support for MP4 container format
+* Scan for appended ID3v2 tag at end of file per ID3v2.4 specs (Section 5.0)
+* Support for JPEG-2000 (http://www.morgan-multimedia.com/jpeg2000_overview.htm)
+* Support for MOD (mod/stm/s3m/it/xm/mtm/ult/669)
+* Support for ACE (thanks Vince)
+* Support for Ogg other than Vorbis, Speex and OggFlac (ie. Ogg+Xvid)
+* Ability to create Xing/LAME VBR header for VBR MP3s that are missing VBR header
+* Ability to "clean" ID3v2 padding (replace invalid padding with valid padding)
+* Warn if MP3s change version mid-stream (in full-scan mode)
+* check for corrupt/broken mid-file MP3 streams in histogram scan
+* Support for lossless-compression formats
+ (http://www.firstpr.com.au/audiocomp/lossless/#Links)
+ (http://compression.ca/act-sound.html)
+ (http://web.inter.nl.net/users/hvdh/lossless/lossless.htm)
+* Support for RIFF-INFO chunks
+ * http://lotto.st-andrews.ac.uk/~njh/tag_interchange.html
+ (thanks Nick Humfrey <njhØsurgeradio*co*uk>)
+ * http://abcavi.narod.ru/sof/abcavi/infotags.htm
+ (thanks Kibi)
+* Better support for Bink video
+* http://www.hr/josip/DSP/AudioFile2.html
+* http://www.pcisys.net/~melanson/codecs/
+* Detect mp3PRO
+* Support for PSD
+* Support for JPC
+* Support for JP2
+* Support for JPX
+* Support for JB2
+* Support for IFF
+* Support for ICO
+* Support for ANI
+* Support for EXE (comments, author, etc) (thanks p*quaedackersØplanet*nl)
+* Support for DVD-IFO (region, subtitles, aspect ratio, etc)
+ (thanks p*quaedackersØplanet*nl)
+* More complete support for SWF - parsing encapsulated MP3 and/or JPEG content
+ (thanks n8n8Øyahoo*com)
+* Support for a2b
+* Optional scan-through-frames for AVI verification
+ (thanks rockcohenØmassive-interactive*nl)
+* Support for TTF (thanks infoØbutterflyx*com)
+* Support for DSS (http://www.getid3.org/phpBB3/viewtopic.php?t=171)
+* Support for SMAF (http://smaf-yamaha.com/what/demo.html)
+ http://www.getid3.org/phpBB3/viewtopic.php?t=182
+* Support for AMR (http://www.getid3.org/phpBB3/viewtopic.php?t=195)
+* Support for 3gpp (http://www.getid3.org/phpBB3/viewtopic.php?t=195)
+* Support for ID4 (http://www.wackysoft.cjb.net grizlyY2KØhotmail*com)
+* Parse XML data returned in Ogg comments
+* Parse XML data from Quicktime SMIL metafiles (klausrathØmac*com)
+* ID3v2 genre string creator function
+* More complete parsing of JPG
+* Support for all old-style ASF packets
+* ASF/WMA/WMV tag writing
+* Parse declared T??? ID3v2 text information frames, where appropriate
+ (thanks Christian Fritz for the idea)
+* Recognize encoder:
+ http://www.guerillasoft.com/EncSpot2/index.html
+ http://ff123.net/identify.html
+ http://www.hydrogenaudio.org/?act=ST&f=16&t=9414
+ http://www.hydrogenaudio.org/?showtopic=11785
+* Support for other OS/2 bitmap structures: Bitmap Array('BA'),
+ Color Icon('CI'), Color Pointer('CP'), Icon('IC'), Pointer ('PT')
+ http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
+* Support for WavPack RAW mode
+* ASF/WMA/WMV data packet parsing
+* ID3v2FrameFlagsLookupTagAlter()
+* ID3v2FrameFlagsLookupFileAlter()
+* obey ID3v2 tag alter/preserve/discard rules
+* http://www.geocities.com/SiliconValley/Sector/9654/Softdoc/Illyrium/Aolyr.htm
+* proper checking for LINK/LNK frame validity in ID3v2 writing
+* proper checking for ASPI-TLEN frame validity in ID3v2 writing
+* proper checking for COMR frame validity in ID3v2 writing
+* http://www.geocities.co.jp/SiliconValley-Oakland/3664/index.html
+* decode GEOB ID3v2 structure as encoded by RealJukebox,
+ decode NCON ID3v2 structure as encoded by MusicMatch
+ (probably won't happen - the formats are proprietary)
+
+
+
+Known Bugs/Issues in getID3() that may be fixed eventually
+===========================================================================
+http://www.getid3.org/phpBB3/viewtopic.php?t=25
+
+* Cannot determine bitrate for MPEG video with VBR video data
+ (need documentation)
+* Interlace/progressive cannot be determined for MPEG video
+ (need documentation)
+* MIDI playtime is sometimes inaccurate
+* AAC-RAW mode files cannot be identified
+* WavPack-RAW mode files cannot be identified
+* mp4 files report lots of "Unknown QuickTime atom type"
+ (need documentation)
+* Encrypted ASF/WMA/WMV files warn about "unhandled GUID
+ ASF_Content_Encryption_Object"
+* Bitrate split between audio and video cannot be calculated for
+ NSV, only the total bitrate. (need documentation)
+* All Ogg formats (Vorbis, OggFLAC, Speex) are affected by the
+ problem of large VorbisComments spanning multiple Ogg pages, but
+ but only OggVorbis files can be processed with vorbiscomment.
+* The version of "head" supplied with Mac OS 10.2.8 (maybe other
+ versions too) does only understands a single option (-n) and
+ therefore fails. getID3 ignores this and returns wrong md5_data.
+
+
+
+Known Bugs/Issues in getID3() that cannot be fixed
+--------------------------------------------------
+http://www.getid3.org/phpBB3/viewtopic.php?t=25
+
+* 32-bit PHP installations only:
+ Files larger than 2GB cannot always be parsed fully by getID3()
+ due to limitations in the 32-bit PHP filesystem functions.
+ NOTE: Since v1.7.8b3 there is partial support for larger-than-
+ 2GB files, most of which will parse OK, as long as no critical
+ data is located beyond the 2GB offset.
+ Known will-work:
+ * all file formats on 64-bit PHP
+ * ZIP (format doesn't support files >2GB)
+ * FLAC (current encoders don't support files >2GB)
+ Known will-not-work:
+ * ID3v1 tags (always located at end-of-file)
+ * Lyrics3 tags (always located at end-of-file)
+ * APE tags (always located at end-of-file)
+ Maybe-will-work:
+ * Quicktime (will work if needed metadata is before 2GB offset,
+ that is if the file has been hinted/optimized for streaming)
+ * RIFF.WAV (should work fine, but gives warnings about not being
+ able to parse all chunks)
+ * RIFF.AVI (playtime will probably be wrong, is only based on
+ "movi" chunk that fits in the first 2GB, should issue error
+ to show that playtime is incorrect. Other data should be mostly
+ correct, assuming that data is constant throughout the file)
+
+
+
+Known Bugs/Issues in other programs
+-----------------------------------
+http://www.getid3.org/phpBB3/viewtopic.php?t=25
+
+* Windows Media Player (up to v11) and iTunes (up to v10+) do
+ not correctly handle ID3v2.3 tags with UTF-16BE+BOM
+ encoding (they assume the data is UTF-16LE+BOM and either
+ crash (WMP) or output Asian character set (iTunes)
+* Winamp (up to v2.80 at least) does not support ID3v2.4 tags,
+ only ID3v2.3
+ see: http://forums.winamp.com/showthread.php?postid=387524
+* Some versions of Helium2 (www.helium2.com) do not write
+ ID3v2.4-compliant Frame Sizes, even though the tag is marked
+ as ID3v2.4) (detected by getID3())
+* MP3ext V3.3.17 places a non-compliant padding string at the end
+ of the ID3v2 header. This is supposedly fixed in v3.4b21 but
+ only if you manually add a registry key. This fix is not yet
+ confirmed. (detected by getID3())
+* CDex v1.40 (fixed by v1.50b7) writes non-compliant Ogg comment
+ strings, supposed to be in the format "NAME=value" but actually
+ written just "value" (detected by getID3())
+* Oggenc 0.9-rc3 flags the encoded file as ABR whether it's
+ actually ABR or VBR.
+* iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably
+ other versions are too) writes ID3v2.3 comment tags using a
+ frame name 'COM ' which is not valid for ID3v2.3+ (it's an
+ ID3v2.2-style frame name) (detected by getID3())
+* MP2enc does not encode mono CBR MP2 files properly (half speed
+ sound and double playtime)
+* MP2enc does not encode mono VBR MP2 files properly (actually
+ encoded as stereo)
+* tooLAME does not encode mono VBR MP2 files properly (actually
+ encoded as stereo)
+* AACenc encodes files in VBR mode (actually ABR) even if CBR is
+ specified
+* AAC/ADIF - bitrate_mode = cbr for vbr files
+* LAME 3.90-3.92 prepends one frame of null data (space for the
+ LAME/VBR header, but it never gets written) when encoding in CBR
+ mode with the DLL
+* Ahead Nero encodes TwinVQF with a DSIZ value (which is supposed
+ to be the filesize in bytes) of "0" for TwinVQF v1.0 and "1" for
+ TwinVQF v2.0 (detected by getID3())
+* Ahead Nero encodes TwinVQF files 1 second shorter than they
+ should be
+* AAC-ADTS files are always actually encoded VBR, even if CBR mode
+ is specified (the CBR-mode switches on the encoder enable ABR
+ mode, not CBR as such, but it's not possible to tell the
+ difference between such ABR files and true VBR)
+* STREAMINFO.audio_signature in OggFLAC is always null. "The reason
+ it's like that is because there is no seeking support in
+ libOggFLAC yet, so it has no way to go back and write the
+ computed sum after encoding. Seeking support in Ogg FLAC is the
+ #1 item for the next release." - Josh Coalson (FLAC developer)
+ NOTE: getID3() will calculate md5_data in a method similar to
+ other file formats, but that value cannot be compared to the
+ md5_data value from FLAC data in a FLAC file format.
+* STREAMINFO.audio_signature is not calculated in FLAC v0.3.0 &
+ v0.4.0 - getID3() will calculate md5_data in a method similar to
+ other file formats, but that value cannot be compared to the
+ md5_data value from FLAC v0.5.0+
+* RioPort (various versions including 2.0 and 3.11) tags ID3v2 with
+ a WCOM frame that has no data portion
+* Earlier versions of Coolplayer adds illegal ID3 tags to Ogg Vorbis
+ files, thus making them corrupt.
+* Meracl ID3 Tag Writer v1.3.4 (and older) incorrectly truncates the
+ last byte of data from an MP3 file when appending a new ID3v1 tag.
+ (detected by getID3())
+* Lossless-Audio files encoded with and without the -noseek switch
+ do actually differ internally and therefore cannot match md5_data
+* iTunes has been known to append a new ID3v1 tag on the end of an
+ existing ID3v1 tag when ID3v2 tag is also present
+ (detected by getID3())
+* MediaMonkey may write a blank RGAD ID3v2 frame but put actual
+ replay gain adjustments in a series of user-defined TXXX frames
+ (detected and handled by getID3() since v1.9.2)
+
+
+
+
+Reference material:
+===========================================================================
+
+[www.id3.org material now mirrored at http://id3lib.sourceforge.net/id3/]
+* http://www.id3.org/id3v2.4.0-structure.txt
+* http://www.id3.org/id3v2.4.0-frames.txt
+* http://www.id3.org/id3v2.4.0-changes.txt
+* http://www.id3.org/id3v2.3.0.txt
+* http://www.id3.org/id3v2-00.txt
+* http://www.id3.org/mp3frame.html
+* http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html <mathewhendry@hotmail.com>
+* http://www.dv.co.yu/mpgscript/mpeghdr.htm
+* http://www.mp3-tech.org/programmer/frame_header.html
+* http://users.belgacom.net/gc247244/extra/tag.html
+* http://gabriel.mp3-tech.org/mp3infotag.html
+* http://www.id3.org/iso4217.html
+* http://www.unicode.org/Public/MAPPINGS/ISO8859/8859-1.TXT
+* http://www.xiph.org/ogg/vorbis/doc/framing.html
+* http://www.xiph.org/ogg/vorbis/doc/v-comment.html
+* http://leknor.com/code/php/class.ogg.php.txt
+* http://www.id3.org/iso639-2.html
+* http://www.id3.org/lyrics3.html
+* http://www.id3.org/lyrics3200.html
+* http://www.psc.edu/general/software/packages/ieee/ieee.html
+* http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html
+* http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html
+* http://www.jmcgowan.com/avi.html
+* http://www.wotsit.org/
+* http://www.herdsoft.com/ti/davincie/davp3xo2.htm
+* http://www.mathdogs.com/vorbis-illuminated/bitstream-appendix.html
+* "Standard MIDI File Format" by Dustin Caldwell (from www.wotsit.org)
+* http://midistudio.com/Help/GMSpecs_Patches.htm
+* http://www.xiph.org/archives/vorbis/200109/0459.html
+* http://www.replaygain.org/
+* http://www.lossless-audio.com/
+* http://download.microsoft.com/download/winmediatech40/Doc/1.0/WIN98MeXP/EN-US/ASF_Specification_v.1.0.exe
+* http://mediaxw.sourceforge.net/files/doc/Active%20Streaming%20Format%20(ASF)%201.0%20Specification.pdf
+* http://www.uni-jena.de/~pfk/mpp/sv8/ (archived at http://www.hydrogenaudio.org/musepack/klemm/www.personal.uni-jena.de/~pfk/mpp/sv8/)
+* http://jfaul.de/atl/
+* http://www.uni-jena.de/~pfk/mpp/ (archived at http://www.hydrogenaudio.org/musepack/klemm/www.personal.uni-jena.de/~pfk/mpp/)
+* http://www.libpng.org/pub/png/spec/png-1.2-pdg.html
+* http://www.real.com/devzone/library/creating/rmsdk/doc/rmff.htm
+* http://www.fastgraph.com/help/bmp_os2_header_format.html
+* http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm
+* http://flac.sourceforge.net/format.html
+* http://www.research.att.com/projects/mpegaudio/mpeg2.html
+* http://www.audiocoding.com/wiki/index.php?page=AAC
+* http://libmpeg.org/mpeg4/doc/w2203tfs.pdf
+* http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt
+* http://developer.apple.com/techpubs/quicktime/qtdevdocs/RM/frameset.htm
+* http://www.nullsoft.com/nsv/
+* http://www.wotsit.org/download.asp?f=iso9660
+* http://sandbox.mc.edu/~bennet/cs110/tc/tctod.html
+* http://www.cdroller.com/htm/readdata.html
+* http://www.speex.org/manual/node10.html
+* http://www.harmony-central.com/Computer/Programming/aiff-file-format.doc
+* http://www.faqs.org/rfcs/rfc2361.html
+* http://ghido.shelter.ro/
+* http://www.ebu.ch/tech_t3285.pdf
+* http://www.sr.se/utveckling/tu/bwf
+* http://ftp.aessc.org/pub/aes46-2002.pdf
+* http://cartchunk.org:8080/
+* http://www.broadcastpapers.com/radio/cartchunk01.htm
+* http://www.hr/josip/DSP/AudioFile2.html
+* http://home.attbi.com/~chris.bagwell/AudioFormats-11.html
+* http://www.pure-mac.com/extkey.html
+* http://cesnet.dl.sourceforge.net/sourceforge/bonkenc/bonk-binary-format-0.9.txt
+* http://www.headbands.com/gspot/
+* http://www.openswf.org/spec/SWFfileformat.html
+* http://j-faul.virtualave.net/
+* http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html
+* http://cui.unige.ch/OSG/info/AudioFormats/ap11.html
+* http://sswf.sourceforge.net/SWFalexref.html
+* http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt
+* http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm
+* http://developer.apple.com/quicktime/icefloe/dispatch012.html
+* http://www.csdn.net/Dev/Format/graphics/PCD.htm
+* http://tta.iszf.irk.ru/
+* http://www.atsc.org/standards/a_52a.pdf
+* http://www.alanwood.net/unicode/
+* http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html
+* http://www.its.msstate.edu/net/real/reports/config/tags.stats
+* http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt
+* http://brennan.young.net/Comp/LiveStage/things.html
+* http://www.multiweb.cz/twoinches/MP3inside.htm
+* http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended
+* http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/
+* http://www.unicode.org/unicode/faq/utf_bom.html
+* http://tta.corecodec.org/?menu=format
+* http://www.scvi.net/nsvformat.htm
+* http://pda.etsi.org/pda/queryform.asp
+* http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm
+* http://trac.musepack.net/trac/wiki/SV8Specification
+* http://wyday.com/cuesharp/specification.php
+* http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/maintenance/cleanupTranscodes.php b/extensions/TimedMediaHandler/maintenance/cleanupTranscodes.php
new file mode 100644
index 00000000..01c7b004
--- /dev/null
+++ b/extensions/TimedMediaHandler/maintenance/cleanupTranscodes.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * cleanup transcodes no longer defined in $wgEnabledTranscodeSet
+ *
+ */
+$IP = getenv( 'MW_INSTALL_PATH' );
+if ( $IP === false ) {
+ $IP = dirname( __FILE__ ) . '/../../..';
+}
+require_once( "$IP/maintenance/Maintenance.php" );
+
+class CleanupTranscodes extends Maintenance {
+
+ public function __construct() {
+ parent::__construct();
+ $this->addOption( "key", "remove all transcodes for given key", false, true );
+ $this->addOption( "all", "remove all transcodes", false, false );
+ $this->mDescription = "cleanup transcodes left over after changing encoding profiles.";
+ }
+ public function execute() {
+ global $wgEnabledTranscodeSet;
+
+ if ( $this->hasOption( "all" ) ) {
+ $where = array();
+ } elseif ( $this->hasOption( "key" ) ) {
+ $where = array( 'transcode_key' => $this->getOption( 'key' ) );
+ } else {
+ $where = 'transcode_key NOT IN ("'. implode('", "', $wgEnabledTranscodeSet ).'")';
+ }
+ $this->output( "Cleanup transcodes:\n" );
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->select( 'transcode', '*', $where, __METHOD__ );
+ foreach ( $res as $row ) {
+ $this->output(
+ 'remove: '. $row->transcode_image_name . ' ' . $row->transcode_key . "\n"
+ );
+ $title = Title::newFromText( $row->transcode_image_name, NS_FILE );
+ $file = wfLocalFile( $title );
+ WebVideoTranscode::removeTranscodes( $file, $row->transcode_key );
+ }
+ $this->output( "Finished!\n" );
+ }
+}
+
+$maintClass = 'CleanupTranscodes'; // Tells it to run the class
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/extensions/TimedMediaHandler/maintenance/moveTranscoded.php b/extensions/TimedMediaHandler/maintenance/moveTranscoded.php
new file mode 100644
index 00000000..1ff6717c
--- /dev/null
+++ b/extensions/TimedMediaHandler/maintenance/moveTranscoded.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * move transcoded files from thumb to transcoded container
+ *
+ */
+$IP = getenv( 'MW_INSTALL_PATH' );
+if ( $IP === false ) {
+ $IP = dirname( __FILE__ ) . '/../../..';
+}
+require_once( "$IP/maintenance/Maintenance.php" );
+
+class MoveTranscoded extends Maintenance {
+
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "move transcoded files from thumb to transcoded container.";
+ }
+ public function execute() {
+ global $wgEnabledTranscodeSet;
+
+ $this->output( "Move transcoded files:\n" );
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->select( 'transcode', '*', array(), __METHOD__ );
+ foreach ( $res as $row ) {
+ $title = Title::newFromText( $row->transcode_image_name, NS_FILE );
+ $file = wfLocalFile( $title );
+ if ( !$file ) {
+ continue;
+ }
+ $oldPath = $file->getThumbPath( $file->getName() . '.' . $row->transcode_key );
+
+ $newPath = WebVideoTranscode::getDerivativeFilePath( $file, $row->transcode_key );
+ if ($oldPath != $newPath) {
+ if( $file->repo->fileExists( $oldPath ) ){
+ if( $file->repo->fileExists( $newPath ) ){
+ $res = $file->repo->quickPurge( $oldPath );
+ if( !$res ){
+ wfDebug( "Could not delete file $oldPath\n" );
+ } else {
+ $this->output( "deleted $oldPath, exists in transcoded container\n" );
+ }
+ } else {
+ $this->output( " $oldPath => $newPath\n" );
+ $file->repo->quickImport( $oldPath, $newPath );
+ $file->repo->quickPurge( $oldPath );
+ }
+ }
+ }
+
+ }
+ $this->output( "Finished!\n" );
+ }
+}
+
+$maintClass = 'MoveTranscoded'; // Tells it to run the class
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/extensions/TimedMediaHandler/maintenance/resetTranscodes.php b/extensions/TimedMediaHandler/maintenance/resetTranscodes.php
new file mode 100644
index 00000000..ca3493ed
--- /dev/null
+++ b/extensions/TimedMediaHandler/maintenance/resetTranscodes.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * reset stalled transcodes
+ *
+ */
+$IP = getenv( 'MW_INSTALL_PATH' );
+if ( $IP === false ) {
+ $IP = dirname( __FILE__ ) . '/../../..';
+}
+require_once( "$IP/maintenance/Maintenance.php" );
+
+class ResetTranscodes extends Maintenance {
+
+ public function __construct() {
+ parent::__construct();
+ $this->mDescription = "Reset stalled transcodes, that are no longer in the job queue.";
+ }
+ public function execute() {
+ global $wgEnabledTranscodeSet;
+ $where = array(
+ "transcode_time_startwork" => NULL,
+ "transcode_time_error" => NULL
+ );
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->select( 'transcode', '*', $where, __METHOD__ );
+ foreach ( $res as $row ) {
+ $title = Title::newFromText( $row->transcode_image_name, NS_FILE );
+ // re-insert WebVideoTranscodeJob,
+ // will only be added if not in queue
+ // due to deduplication
+ $job = new WebVideoTranscodeJob( $title, array(
+ 'transcodeMode' => 'derivative',
+ 'transcodeKey' => $row->transcode_key,
+ ) );
+ $job->insert();
+ }
+ }
+}
+
+$maintClass = 'ResetTranscodes'; // Tells it to run the class
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/extensions/TimedMediaHandler/maintenance/retryTranscodes.php b/extensions/TimedMediaHandler/maintenance/retryTranscodes.php
new file mode 100644
index 00000000..be1ab9ee
--- /dev/null
+++ b/extensions/TimedMediaHandler/maintenance/retryTranscodes.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Retry transcodes for a given key or error.
+ * This script can be used after updating/fixing
+ * the encoding pipeline to rerun transcodes
+ * that are known to work now.
+ *
+ */
+$IP = getenv( 'MW_INSTALL_PATH' );
+if ( $IP === false ) {
+ $IP = dirname( __FILE__ ) . '/../../..';
+}
+require_once( "$IP/maintenance/Maintenance.php" );
+
+class RetryTranscodes extends Maintenance {
+
+ public function __construct() {
+ parent::__construct();
+ $this->addOption( "key", "retry all failed transcodes for given key", false, true );
+ $this->addOption( "error", "retry all failed transcodes matching error substring", false, true);
+ $this->mDescription = "retry transcodes for given key or error";
+ }
+ public function execute() {
+ if ( !$this->hasOption( "error" ) && !$this->hasOption( "key" ) ) {
+ $this->output("You have to provide --key and/or --error\n");
+ return;
+ }
+ $dbw = wfGetDB( DB_MASTER );
+ $cond = array();
+ $cond[] = 'transcode_time_error IS NOT NULL';
+ if ( $this->hasOption( "key" ) ) {
+ $cond['transcode_key'] = $this->getOption( 'key' );
+ }
+ if ( $this->hasOption( "error" ) ) {
+ $cond[] = "transcode_error " . $dbw->buildLike( $dbw->anyString(),
+ $this->getOption( 'error' ), $dbw->anyString() );
+ }
+ do {
+ $res = $dbw->select( 'transcode', 'transcode_id',
+ $cond, __METHOD__, array( 'LIMIT' => 100 ) );
+ $ids = array();
+ foreach ( $res as $row ) {
+ $ids[] = $row->transcode_id;
+ }
+ if ( $ids ) {
+ $dbw->delete( 'transcode',
+ array( 'transcode_id' => $ids ), __METHOD__ );
+ wfWaitForSlaves();
+ }
+ } while ($ids);
+ }
+}
+
+$maintClass = 'RetryTranscodes'; // Tells it to run the class
+require_once( RUN_MAINTENANCE_IF_MAIN );
diff --git a/extensions/TimedMediaHandler/mwEmbedLoader.php b/extensions/TimedMediaHandler/mwEmbedLoader.php
new file mode 100644
index 00000000..ae03a3dd
--- /dev/null
+++ b/extensions/TimedMediaHandler/mwEmbedLoader.php
@@ -0,0 +1,24 @@
+<?php
+// This is a stub entry point to load.php This is need to support valid paths for the stand alone
+// mwEmbed module html test files.
+
+// This is useful for running stand alone test of mwEmbed components in the TimedMediaHandler
+// extension. ( ie MwEmbedModules/EmbedPlayer/tests/*.html files )
+
+$_GET['modules'] = 'startup';
+$_GET['only'] = 'scripts';
+
+// NOTE this won't work so well with symbolic links
+$loaderPath = dirname(__FILE__) . '/../../load.php';
+if( is_file( $loaderPath ) ){
+ chdir( dirname( $loaderPath ) );
+ include_once( $loaderPath );
+} else {
+ print "if( console && typeof console.log == 'function' ){ console.log('Error can't find load.php for stand alone tests' ) }";
+}
+// Bootstrap some js code to make the "loader" work in stand alone tests:
+// Note this has to be wrapped in a document.write to run after other document.writes
+$pageStartupScript = ResourceLoader::makeInlineScript(
+ Xml::encodeJsCall( 'mw.loader.go', array() )
+);
+echo Xml::encodeJsCall( 'document.write', array( $pageStartupScript ) );
diff --git a/extensions/TimedMediaHandler/package.json b/extensions/TimedMediaHandler/package.json
new file mode 100644
index 00000000..30067c35
--- /dev/null
+++ b/extensions/TimedMediaHandler/package.json
@@ -0,0 +1,14 @@
+{
+ "private": true,
+ "scripts": {
+ "test": "grunt test"
+ },
+ "devDependencies": {
+ "grunt": "0.4.5",
+ "grunt-cli": "0.1.13",
+ "grunt-contrib-jshint": "0.11.3",
+ "grunt-banana-checker": "0.2.2",
+ "grunt-jscs": "1.8.0",
+ "grunt-jsonlint": "1.0.4"
+ }
+}
diff --git a/extensions/TimedMediaHandler/resources/PopUpThumbVideo.css b/extensions/TimedMediaHandler/resources/PopUpThumbVideo.css
new file mode 100644
index 00000000..3ba0572a
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/PopUpThumbVideo.css
@@ -0,0 +1,29 @@
+.PopUpMediaTransform a .play-btn-large{
+ position : absolute;
+ top: 50%;
+ left : 50%;
+ width: 70px;
+ height: 53px;
+ margin-left: -35px;
+ margin-top: -25px;
+ /* @embed */
+ background-image:url('player_big_play_button.png');
+}
+.PopUpMediaTransform a .play-btn-large :hover{
+ /* @embed */
+ background-image:url('player_big_play_button_hover.png');
+}
+.PopUpMediaTransform {
+ position : relative;
+ display: inline-block;
+}
+/* Should hopefully be only visible to screen readers */
+.mw-tmh-playtext {
+ display: block;
+ height: 0;
+ overflow: hidden;
+}
+
+li.gallerybox div.thumb div.PopUpMediaTransform {
+ margin: 0 auto;
+}
diff --git a/extensions/TimedMediaHandler/resources/download_sprite.png b/extensions/TimedMediaHandler/resources/download_sprite.png
new file mode 100644
index 00000000..541d4a99
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/download_sprite.png
Binary files differ
diff --git a/extensions/TimedMediaHandler/resources/embedPlayerIframe.css b/extensions/TimedMediaHandler/resources/embedPlayerIframe.css
new file mode 100644
index 00000000..eb6e9003
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/embedPlayerIframe.css
@@ -0,0 +1,7 @@
+body {
+ margin-left: 0px;
+ margin-top: 0px;
+ margin-right: 0px;
+ margin-bottom: 0px;
+ overflow: hidden;
+}
diff --git a/extensions/TimedMediaHandler/resources/ext.tmh.OgvJsSupport.js b/extensions/TimedMediaHandler/resources/ext.tmh.OgvJsSupport.js
new file mode 100644
index 00000000..af3fd9f5
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/ext.tmh.OgvJsSupport.js
@@ -0,0 +1,67 @@
+( function( $, mw ) {
+
+ var support = mw.OgvJsSupport = {
+ /**
+ * Ensure that the OGVPlayer class is loaded before continuing.
+ *
+ * @return jQuery.Deferred
+ */
+ loadOgvJs: function() {
+ return $.Deferred( function( deferred ) {
+ if ( typeof OGVPlayer === 'undefined' ) {
+ mw.loader.using( 'ext.tmh.OgvJs', function() {
+ OGVLoader.base = support.basePath();
+ deferred.resolve();
+ } );
+ } else {
+ deferred.resolve();
+ }
+ });
+ },
+
+ /**
+ * Get the base path of ogv.js and friends.
+ *
+ * @return string
+ */
+ basePath: function() {
+ var ext = mw.config.get( 'wgExtensionAssetsPath' ),
+ binPlayers = ext + '/TimedMediaHandler/MwEmbedModules/EmbedPlayer/binPlayers';
+ return binPlayers + '/ogv.js';
+ },
+
+ /**
+ * Return a stub audio context
+ *
+ * This is used for iOS Safari to enable Web Audio by triggering an empty
+ * audio output channel during a user input event handler. Without that,
+ * audio is left disabled and won't work when we start things up after an
+ * asynchronous code load.
+ *
+ * @return AudioContext
+ */
+ initAudioContext: function() {
+ var AudioContext = window.AudioContext || window.webkitAudioContext;
+ if ( AudioContext ) {
+ var context = new AudioContext(),
+ node;
+ if ( context.createScriptProcessor ) {
+ node = context.createScriptProcessor( 1024, 0, 2 );
+ } else if ( context.createJavaScriptNode ) {
+ node = context.createJavaScriptNode( 1024, 0, 2 );
+ } else {
+ throw new Error( 'Bad version of web audio API?' );
+ }
+
+ // Don't actually run any audio, just start & stop the node
+ node.connect( context.destination );
+ node.disconnect();
+
+ return context;
+ } else {
+ return null;
+ }
+ }
+ };
+
+} )( jQuery, mediaWiki );
diff --git a/extensions/TimedMediaHandler/resources/ext.tmh.TimedTextSelector.js b/extensions/TimedMediaHandler/resources/ext.tmh.TimedTextSelector.js
new file mode 100644
index 00000000..b53bb6f8
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/ext.tmh.TimedTextSelector.js
@@ -0,0 +1,8 @@
+( function ( $, mw ) {
+ $( function () {
+ $( '#timedmedia-tt-go' ).click( function () {
+ window.location = mw.config.get( 'wgScript' ) + '?title=' + mw.util.wikiUrlencode( mw.config.get( 'wgPageName' ) ) + '.' + $( '#timedmedia-tt-input' ).val() + '.srt&action=edit';
+ } );
+ } );
+
+} )( jQuery, mediaWiki );
diff --git a/extensions/TimedMediaHandler/resources/ext.tmh.transcodetable.js b/extensions/TimedMediaHandler/resources/ext.tmh.transcodetable.js
new file mode 100644
index 00000000..a8c8f98d
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/ext.tmh.transcodetable.js
@@ -0,0 +1,90 @@
+/**
+* Javascript to support transcode table on image page
+*/
+( function ( mw, $ ) {
+ $( document ).ready( function () {
+ var errorPopup, $errorLink;
+
+ errorPopup = function () {
+ // pop up dialog
+ mw.addDialog( {
+ 'width': '640',
+ 'height': '480',
+ 'title': $(this).attr( 'title' ),
+ 'content': $('<textarea />')
+ .css( {
+ 'width':'99%',
+ 'height':'99%'
+ } )
+ .text( $(this).attr('data-error') )
+ } )
+ .css( 'overflow', 'hidden' );
+ return false;
+ };
+
+ // Old version. Need to keep for a little while in case of cached pages.
+ $( '.mw-filepage-transcodestatus .errorlink' ).click( errorPopup );
+ // New version.
+ $errorLink = $( '.mw-filepage-transcodestatus .mw-tmh-pseudo-error-link' );
+ $errorLink.wrapInner( function () {
+ var $this = $( this );
+ return $( '<a />' ).attr( {
+ href: '#',
+ title: $this.text(),
+ 'data-error': $this.attr( 'data-error' )
+ } ).click( errorPopup );
+ } );
+
+ // Reset transcode action:
+ $( '.mw-filepage-transcodereset a' ).click( function () {
+ var tKey = $( this ).attr( 'data-transcodekey' ),
+ buttons = {};
+
+ buttons[ mw.msg( 'mwe-ok' ) ] = function () {
+ var api,
+ _thisDialog = this,
+ cancelBtn = {};
+
+ // Only show cancel button while loading:
+ cancelBtn[ mw.msg( 'mwe-cancel' ) ] = function () {
+ $(this).dialog( 'close' );
+ };
+ $( _thisDialog ).dialog( 'option', 'buttons', cancelBtn );
+
+ $( this ).loadingSpinner();
+
+ api = new mw.Api();
+ api.postWithEditToken( {
+ 'action' : 'transcodereset',
+ 'transcodekey' : tKey,
+ 'title' : mw.config.get('wgPageName')
+ } ).done( function () {
+ // Refresh the page
+ location.reload();
+ } ).fail( function ( code, data ) {
+ if( data.error && data.error.info ){
+ $( _thisDialog ).text( data.error.info );
+ } else {
+ $( _thisDialog ).text( mw.msg( 'timedmedia-reset-error' ) );
+ }
+ var okBtn = {};
+ okBtn[ mw.msg('mwe-ok') ] = function() { $(this).dialog( 'close' ); };
+ $( _thisDialog ).dialog( 'option', 'buttons', okBtn );
+ } );
+ };
+ buttons[ mw.msg( 'mwe-cancel' ) ] = function () {
+ $( this ).dialog( 'close' );
+ };
+ // pop up dialog
+ mw.addDialog( {
+ 'width': '400',
+ 'height': '200',
+ 'title': mw.msg( 'timedmedia-reset' ),
+ 'content': mw.msg( 'timedmedia-reset-confirm' ),
+ 'buttons': buttons
+ } )
+ .css( 'overflow', 'hidden' );
+ return false;
+ });
+ });
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/resources/mw.MediaWikiPlayer.loader.js b/extensions/TimedMediaHandler/resources/mw.MediaWikiPlayer.loader.js
new file mode 100644
index 00000000..6167418b
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/mw.MediaWikiPlayer.loader.js
@@ -0,0 +1,8 @@
+( function ( mw, $ ) {
+ // Add MediaWikiSupportPlayer dependency on players with a mediaWiki title
+ $( mw ).bind( 'EmbedPlayerUpdateDependencies', function ( event, embedPlayer, dependencySet ) {
+ if ( $( embedPlayer ).attr( 'data-mwtitle' ) ) {
+ $.merge( dependencySet, ['mw.MediaWikiPlayerSupport'] );
+ }
+ } );
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/resources/mw.MediaWikiPlayerSupport.js b/extensions/TimedMediaHandler/resources/mw.MediaWikiPlayerSupport.js
new file mode 100644
index 00000000..16ce367c
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/mw.MediaWikiPlayerSupport.js
@@ -0,0 +1,380 @@
+( function ( mw, $ ) {
+ /**
+ * Merge in the default video attributes supported by embedPlayer:
+ */
+ mw.mergeConfig( 'EmbedPlayer.Attributes', {
+ // A apiTitleKey for looking up subtitles, credits and related videos
+ 'data-mwtitle': null,
+
+ // The apiProvider where to lookup the title key
+ 'data-mwprovider': null
+ } );
+
+ // Add mediaWiki player support to target embedPlayer
+ $( mw ).bind( 'EmbedPlayerNewPlayer', function ( event, embedPlayer ) {
+ mw.addMediaWikiPlayerSupport( embedPlayer );
+ });
+
+ /**
+ * Closure function wraps mediaWiki embedPlayer bindings
+ */
+ mw.addMediaWikiPlayerSupport = function ( embedPlayer ) {
+ var apiTitleKey, apiProvider, $creditsCache = false;
+ // Set some local variables:
+ if ( !embedPlayer['data-mwtitle'] ) {
+ return false;
+ } else {
+ apiTitleKey = embedPlayer['data-mwtitle'];
+ // legacy support ( set as attribute )
+ embedPlayer.apiTitleKey = apiTitleKey;
+ }
+ // Set local apiProvider via config if not defined
+ apiProvider = embedPlayer['data-mwprovider'];
+ if ( !apiProvider ) {
+ apiProvider = mw.config.get( 'EmbedPlayer.ApiProvider' );
+ }
+
+ /**
+ * Loads mediaWiki sources for a given embedPlayer
+ * @param {function} callback Function called once player sources have been added
+ */
+ function loadPlayerSources( callback ) {
+ // Setup the request
+ var request = {
+ 'prop': 'imageinfo',
+ // In case the user added File: or Image: to the apiKey:
+ 'titles': 'File:' + decodeURIComponent( apiTitleKey ).replace( /^(File:|Image:)/, '' ),
+ 'iiprop': 'url|size|dimensions|metadata',
+ 'iiurlwidth': embedPlayer.getWidth(),
+ 'redirects': true // automatically resolve redirects
+ };
+
+ // Run the request:
+ mw.getJSON( mw.getApiProviderURL( apiProvider ), request, function ( data ) {
+ var i, page, imageinfo;
+ if ( data.query.pages ) {
+ for ( i in data.query.pages ) {
+ if ( i === '-1' ) {
+ callback( false );
+ return ;
+ }
+ page = data.query.pages[i];
+ }
+ } else {
+ callback( false );
+ return ;
+ }
+ // Make sure we have imageinfo:
+ if ( !page.imageinfo || !page.imageinfo[0] ) {
+ callback( false );
+ return ;
+ }
+ imageinfo = page.imageinfo[0];
+
+ // TODO these should call public methods rather than update internals:
+
+ // Update the poster
+ embedPlayer.poster = imageinfo.thumburl;
+
+ // Add the media src
+ embedPlayer.mediaElement.tryAddSource(
+ $( '<source />' )
+ .attr( 'src', imageinfo.url )
+ .get( 0 )
+ );
+
+ // Set the duration
+ if ( imageinfo.metadata[2].name === 'length' ) {
+ embedPlayer.duration = imageinfo.metadata[2].value;
+ }
+
+ // Set the width height
+ // Make sure we have an accurate aspect ratio
+ if ( imageinfo.height !== 0 && imageinfo.width !== 0 ) {
+ embedPlayer.height = Math.floor( embedPlayer.width * ( imageinfo.height / imageinfo.width ) );
+ }
+
+ // Update the css for the player interface
+ $( embedPlayer ).css( 'height', embedPlayer.height );
+
+ callback();
+ });
+ }
+
+ /**
+ * Build a clip credit from the resource wikiText page
+ *
+ * TODO parse the resource page template
+ *
+ * @param {String} resourceHTML Resource wiki text page contents
+ */
+ function doCreditLine( resourceHTML, articleUrl ) {
+ var authUrl, $page, $author, $authorText, $links, $date, $authorLink,
+ imgSize = {},
+ // Get the title string ( again a "Title" like js object could help out here. )
+ titleStr = embedPlayer.apiTitleKey.replace( /_/g, ' ' ),
+ // Setup the initial credits line:
+ $creditLine = $( '<div />' );
+
+ // Add the title:
+ $creditLine.append(
+ $( '<span>' ).html(
+ mw.msg( 'mwe-embedplayer-credit-title',
+ // get the link
+ $( '<div>' ).append(
+ $( '<a/>' ).attr( {
+ 'href': articleUrl,
+ 'title': titleStr
+ } )
+ .text( titleStr )
+ )[0].innerHTML
+ )
+ )
+ );
+
+ // Parse some data from the page info template if possible:
+ $page = $( resourceHTML );
+
+ // Look for author:
+ $author = $page.find( '#fileinfotpl_aut' );
+ if ( $author.length ) {
+ // Get the real author sibling of fileinfotpl_aut
+ $authorText = $author.next();
+ // Remove white space:
+ $authorText.find( 'br' ).remove();
+
+ // Update link to be absolute per page url context:
+ $links = $authorText.find( 'a' );
+ if ( $links.length ) {
+ $links.each( function ( i, authorLink ) {
+ $authorLink = $( authorLink );
+ authUrl = $authorLink.attr( 'href' );
+ authUrl = mw.absoluteUrl( authUrl, articleUrl );
+ $authorLink.attr( 'href', authUrl );
+ });
+ }
+ $creditLine.append( $( '<br />' ),
+ mw.msg( 'mwe-embedplayer-credit-author', $authorText.html() )
+ );
+ }
+
+ // Look for date:
+ $date = $page.find( '#fileinfotpl_date' );
+ if ( $date.length ) {
+ // Get the real date sibling of fileinfotpl_date
+ $date = $date.next();
+
+ // remove white space:
+ $date.find( 'br' ).remove();
+ $creditLine.append( $( '<br />' ),
+ mw.msg( 'mwe-embedplayer-credit-date', $date.html() )
+ );
+ }
+
+ // Build out the image and credit line
+ if ( embedPlayer.isAudio() ) {
+ imgSize.height = imgSize.width = ( embedPlayer.controlBuilder.getOverlayWidth() < 250 ) ? 45 : 80;
+ } else {
+ imgSize.width = ( embedPlayer.controlBuilder.getOverlayWidth() < 250 ) ? 45 : 120;
+ imgSize.height = Math.floor( imgSize.width * ( embedPlayer.getHeight() / embedPlayer.getWidth() ) );
+ }
+ return $( '<div/>' ).addClass( 'creditline' )
+ .append(
+ $( '<a/>' ).attr( {
+ 'href': articleUrl,
+ 'title': titleStr
+ } ).html(
+ $( '<img/>' ).attr( {
+ 'border': 0,
+ 'src': embedPlayer.poster
+ } ).css( imgSize )
+ )
+ )
+ .append(
+ $creditLine
+ );
+ }
+
+ /**
+ * Issues a request to populate the credits box
+ */
+ function showCredits( $target, callback ) {
+ var apiUrl, fileTitle, request;
+ if ( $creditsCache ) {
+ $target.html( $creditsCache );
+ callback( true );
+ return;
+ }
+ // Setup shortcuts:
+ apiUrl = mw.getApiProviderURL( apiProvider );
+ fileTitle = 'File:' + decodeURIComponent( apiTitleKey ).replace( /^File:|^Image:/, '');
+
+ // Get the image page ( cache for 1 hour )
+ request = {
+ 'action': 'parse',
+ 'page': fileTitle,
+ 'smaxage': 3600,
+ 'maxage': 3600
+ };
+ mw.getJSON( apiUrl, request, function ( data ) {
+ var descUrl = apiUrl.replace( 'api.php', 'index.php');
+ descUrl += '?title=' + encodeURIComponent( fileTitle );
+ if ( data && data.parse && data.parse.text && data.parse.text['*'] ) {
+ // TODO improve provider 'concept' to support page title link
+ $creditsCache = doCreditLine( data.parse.text['*'], descUrl );
+ } else {
+ $creditsCache = doCreditLine( false, descUrl );
+ }
+ $target.html( $creditsCache );
+ callback( true );
+ } );
+ }
+ /**
+ * Adds embedPlayer Bindings
+ */
+
+ // Show credits when requested
+ $( embedPlayer ).bindQueueCallback( 'showCredits', function ( $target, callback ) {
+ if ( $target.data( 'playerId') !== embedPlayer.id ) {
+ // bad event trigger
+ return ;
+ }
+ // Only request the credits once:
+ showCredits( $target, callback );
+ });
+
+ // Show credits on clip complete:
+ $( embedPlayer ).bind( 'onEndedDone', function ( event, id ) {
+ if ( embedPlayer.id !== id ) {
+ // possible event trigger error. ( skip )
+ return ;
+ }
+ // dont show credits for audio elements,
+ // seek to begining instead
+ if ( embedPlayer.isAudio() ) {
+ embedPlayer.setCurrentTime( 0 );
+ return ;
+ }
+ var cb = embedPlayer.controlBuilder;
+ cb.checkMenuOverlay();
+ cb.showMenuOverlay();
+ cb.showMenuItem( 'credits' );
+ });
+
+ $( embedPlayer ).bind( 'showInlineDownloadLink', function () {
+ // Add recommend HTML5 player if we have non-native playback:
+ if ( embedPlayer.controlBuilder.checkNativeWarning( ) ) {
+ embedPlayer.controlBuilder.addWarningBinding(
+ 'EmbedPlayer.ShowNativeWarning',
+ mw.msg( 'mwe-embedplayer-for_best_experience',
+ $( '<div>' ).append(
+ $( '<a />' ).attr({
+ 'href': 'http://www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download',
+ 'target': '_new'
+ })
+ )[0].innerHTML
+ ),
+ true
+ );
+ }
+ });
+
+ $( embedPlayer ).bind( 'TimedText_BuildCCMenu', function ( event, $menu, id ) {
+ var _this,
+ pageTitle,
+ addTextPage,
+ $li;
+ if ( id !== embedPlayer.id ) {
+ _this = $( '#' + id )[0].timedText;
+ embedPlayer = _this.embedPlayer;
+ }
+ // Put in the "Make Transcript" link if config enabled and we have an api key
+ if ( embedPlayer.apiTitleKey ) {
+ // check if not already there:
+ if ( $menu.find( '.add-timed-text' ).length ) {
+ // add text link already present
+ return ;
+ }
+
+ pageTitle = 'TimedText:' +
+ decodeURIComponent( embedPlayer.apiTitleKey ).replace( /^File:|^Image:/, '' );
+ addTextPage = mw.getApiProviderURL( apiProvider )
+ .replace( 'api.php', 'index.php') +
+ '?title=' + encodeURIComponent( pageTitle );
+
+ $li = $.getLineItem( mw.msg( 'mwe-timedtext-upload-timed-text'), 'script', function () {
+ window.location = addTextPage;
+ });
+
+ $li.addClass( 'add-timed-text')
+ .find( 'a' )
+ .attr( {
+ 'href': addTextPage,
+ 'target': '_new'
+ } );
+ $menu.append(
+ $li
+ );
+ }
+ });
+
+ $( embedPlayer ).bindQueueCallback( 'checkPlayerSourcesEvent', function ( callback ) {
+ // Only load source if none are available:
+ if ( embedPlayer.mediaElement.sources.length === 0 ) {
+ loadPlayerSources( callback );
+ } else {
+ // No source to load, issue callback directly
+ callback();
+ }
+ } );
+ $( mw ).bindQueueCallback( 'TimedText_LoadTextSource', function ( source, callback ) {
+ if ( !source.mwtitle || !source.mwprovider ) {
+ callback();
+ return ;
+ }
+ // Load via api
+ var apiUrl = mw.getApiProviderURL( source.mwprovider ),
+ // Get the image page ( cache for 1 hour )
+ request = {
+ 'action': 'parse',
+ 'page': source.mwtitle,
+ 'smaxage': 3600,
+ 'maxage': 3600
+ };
+ mw.getJSON( apiUrl, request, function ( data ) {
+ if ( data && data.parse && data.parse.text && data.parse.text['*'] ) {
+ source.loaded = true;
+ source.mimeType = 'text/mw-srt';
+ source.captions = source.getCaptions( data.parse.text['*'] );
+ callback();
+ } else {
+ mw.log( 'Error: MediaWiki api error in getting timed text:', data );
+ callback();
+ }
+ });
+ });
+
+ $( embedPlayer ).bind( 'getShareIframeSrc', function ( event, callback, id ) {
+ if ( id !== embedPlayer.id ) {
+ embedPlayer = $( '#' + id )[0];
+ }
+ var iframeUrl = false;
+ // Do a special check for wikimediacommons provider as a known shared reop
+ if ( embedPlayer['data-mwprovider'] === 'wikimediacommons' ) {
+ iframeUrl = '//commons.wikimedia.org/wiki/File:' + decodeURIComponent( embedPlayer.apiTitleKey ).replace( /^(File:|Image:)/, '' );
+ } else {
+ // use the local wiki:
+ if ( mw.config.get( 'wgServer' ) && mw.config.get( 'wgArticlePath' ) ) {
+ iframeUrl = mw.config.get( 'wgServer' ) +
+ mw.config.get( 'wgArticlePath' ).replace( /\$1/, 'File:' +
+ decodeURIComponent( embedPlayer.apiTitleKey ).replace( /^(File:|Image:)/, '' ) );
+ }
+ }
+ if ( iframeUrl ) {
+ iframeUrl += '?embedplayer=yes';
+ }
+ callback( iframeUrl );
+ });
+ };
+
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/resources/mw.PopUpThumbVideo.js b/extensions/TimedMediaHandler/resources/mw.PopUpThumbVideo.js
new file mode 100644
index 00000000..c0aa30df
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/mw.PopUpThumbVideo.js
@@ -0,0 +1,44 @@
+/**
+* Simple script to add pop-up video dialog link support for video thumbnails
+*/
+( function ( mw, $ ) {
+ $( document ).ready( function () {
+ $('.PopUpMediaTransform a').each( function () {
+ var link, title,
+ parent = $( this ).parent();
+ if ( parent.attr( 'videopayload' ) ) {
+ $( this ).click( function ( /*event*/ ) {
+ var thisref = this;
+
+ mw.loader.using( 'mw.MwEmbedSupport', function () {
+ var $videoContainer = $( $( thisref ).parent().attr( 'videopayload' ) );
+ mw.addDialog({
+ 'width': 'auto',
+ 'height': 'auto',
+ 'title': mw.html.escape( $videoContainer.find( 'video, audio' ).attr( 'data-mwtitle' ) ),
+ 'content': $videoContainer,
+ 'close': function(){
+ // On close destroy the dialog rather than just hiding it,
+ // so it doesn't eat up resources or keep playing.
+ $( this ).remove();
+ return true;
+ },
+ 'open': function() {
+ $( this ).find( 'video, audio' ).embedPlayer();
+ }
+ })
+ .css( 'overflow', 'hidden' );
+ } );
+ // don't follow file link
+ return false;
+ } );
+ } else if ( parent.attr( 'data-videopayload' ) ) {
+ link = $( this ).attr( 'href' );
+ title = mw.Title.newFromImg( { src: link } );
+ if ( title && title.getPrefixedDb() !== mw.config.get( 'wgPageName' ) ) {
+ $( this ).attr( 'href', title.getUrl() );
+ }
+ } /* else fall back to linking directly to media file */
+ } );
+ } );
+} )( mediaWiki, jQuery );
diff --git a/extensions/TimedMediaHandler/resources/mw.TMHGalleryHook.js b/extensions/TimedMediaHandler/resources/mw.TMHGalleryHook.js
new file mode 100644
index 00000000..fd23690e
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/mw.TMHGalleryHook.js
@@ -0,0 +1,46 @@
+/**
+* Simple script to add pop-up video dialog link support for video thumbnails
+*/
+( function ( mw ) {
+ // Hook to allow dynamically resizing videos in image galleries
+ mw.hook( 'mediawiki.page.gallery.resize' ).add( function ( info ) {
+ var $mwPlayerContainer,
+ $popUp,
+ $tmhVideo,
+ $mwContainer = info.$imageDiv.find( '.mediaContainer' );
+ if ( info.resolved ) {
+ // Everything is already done here.
+ return;
+ }
+
+ $mwContainer = info.$imageDiv.find( '.mediaContainer' );
+ if ( $mwContainer.length ) {
+ // Add some padding, so caption doesn't overlap video controls if
+ // we are overlaying the caption on top of the image.
+ if ( !info.$outerDiv.parent().hasClass( 'mw-gallery-packed' ) ) {
+ info.$outerDiv.find( 'div.gallerytext' ).css( 'padding-bottom', '20px' );
+ }
+
+ info.$imageDiv.width( info.imgWidth );
+ $mwContainer.width( info.imgWidth );
+ $mwPlayerContainer = $mwContainer.children( '.mwPlayerContainer' );
+ if ( $mwPlayerContainer.length ) {
+ // Case 1: HTML5 player already loaded
+ $mwPlayerContainer.width( info.imgWidth ).height( info.imgHeight );
+ $mwPlayerContainer.find( 'img.playerPoster' ).width( info.imgWidth ).height( info.imgHeight );
+ } else {
+ // Case 2: Raw video element
+ $tmhVideo = info.$imageDiv.find( 'video' );
+ $tmhVideo.width( info.imgWidth ).height( info.imgHeight );
+ }
+ info.resolved = true;
+ return;
+ }
+
+ $popUp = info.$imageDiv.find( '.PopUpMediaTransform' );
+ if ( $popUp.length ) {
+ info.$imageDiv.width( info.imgWidth );
+ $popUp.add( $popUp.find( 'img' ) ).width( info.imgWidth ).height( info.imgHeight );
+ }
+ } );
+} )( mediaWiki );
diff --git a/extensions/TimedMediaHandler/resources/player_big_play_button.png b/extensions/TimedMediaHandler/resources/player_big_play_button.png
new file mode 100644
index 00000000..041fea9c
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/player_big_play_button.png
Binary files differ
diff --git a/extensions/TimedMediaHandler/resources/player_big_play_button_hover.png b/extensions/TimedMediaHandler/resources/player_big_play_button_hover.png
new file mode 100644
index 00000000..3517563e
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/player_big_play_button_hover.png
Binary files differ
diff --git a/extensions/TimedMediaHandler/resources/transcodeTable.css b/extensions/TimedMediaHandler/resources/transcodeTable.css
new file mode 100644
index 00000000..795ce134
--- /dev/null
+++ b/extensions/TimedMediaHandler/resources/transcodeTable.css
@@ -0,0 +1,14 @@
+.mw-filepage-transcodestatus .download-btn {
+ background-image: url('download_sprite.png');
+ width: 49px;
+ height: 36px;
+ background-repeat:no-repeat;
+ background-position: -50px;
+}
+.mw-filepage-transcodestatus .download-btn:hover {
+ background-position: 0 0;
+}
+.mw-filepage-transcodestatus .download-btn span {
+ /* Text hidden by the above image */
+ display: none;
+}
diff --git a/extensions/TimedMediaHandler/tests/phpunit/ApiTestCaseVideoUpload.php b/extensions/TimedMediaHandler/tests/phpunit/ApiTestCaseVideoUpload.php
new file mode 100644
index 00000000..9dd4cb52
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/ApiTestCaseVideoUpload.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * Abstract test class to support Video Tests with video uploads
+ * @author dale
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ exit;
+}
+
+// Include core class ApiTestCaseUpload ( not part of base autoLoader )
+global $IP;
+require_once( "$IP/tests/phpunit/includes/api/ApiTestCaseUpload.php" );
+
+abstract class ApiTestCaseVideoUpload extends ApiTestCaseUpload {
+ /**
+ * @return Array set of test files with associated metadata
+ */
+ static function mediaFilesProvider(){
+ return array(
+ array(
+ // Double wrap the file array to match phpunit data provider conventions
+ array(
+ 'mime' => 'application/ogg',
+ 'filePath' => dirname( __FILE__ ) . '/media/test5seconds.electricsheep.300x400.ogv',
+ "size" => 301477,
+ "width" => 400,
+ "height" => 300,
+ "mediatype" => "VIDEO",
+ "bandwidth" => 452216,
+ "framerate" => 30
+ )
+ ),
+ array(
+ array(
+ 'mime' => 'video/webm',
+ 'filePath' => dirname( __FILE__ ) . '/media/shuttle10seconds.1080x608.webm',
+ "size" => 699018,
+ "width" => 1080,
+ "height" => 608,
+ "mediatype" => "VIDEO",
+ "bandwidth" => 522142,
+ "framerate" => 29.97
+ )
+ )
+ );
+ }
+ /**
+ * Fixture -- run after every test
+ * Clean up temporary files etc.
+ *
+ */
+ protected function tearDown() {
+ parent::tearDown();
+
+ $testMediaFiles = $this->mediaFilesProvider();
+ foreach( $testMediaFiles as $file ){
+ $file = $file[0];
+ // Clean up and delete all files
+ $this->deleteFileByFilename( $file['filePath'] );
+ }
+ }
+
+ /**
+ * Do login
+ */
+ protected function doLogin( $user = 'sysop' ) {
+ $user = self::$users['uploader'];
+
+ $params = array(
+ 'action' => 'login',
+ 'lgname' => $user->username,
+ 'lgpassword' => $user->password
+ );
+ list( $result, , $session ) = $this->doApiRequest( $params );
+ $token = $result['login']['token'];
+
+ $params = array(
+ 'action' => 'login',
+ 'lgtoken' => $token,
+ 'lgname' => $user->username,
+ 'lgpassword' => $user->password
+ );
+ list( $result, , $session ) = $this->doApiRequest( $params, $session );
+ return $session;
+ }
+
+ /**
+ * uploads a file:
+ */
+ public function uploadFile( $file ){
+ global $wgUser;
+ // get a session object
+ $session = $this->doLogin();
+ // Update the global user:
+ $wgUser = self::$users['uploader']->getUser();
+
+ // Upload the media file:
+ $fileName = basename( $file['filePath'] );
+
+ // remove if already in thd db:
+ $this->deleteFileByFileName( $fileName );
+ $this->deleteFileByContent( $file['filePath'] );
+
+ if ( !$this->fakeUploadFile( 'file', $fileName, $file['mime'], $file['filePath'] ) ) {
+ $this->markTestIncomplete( "Couldn't upload file!\n" );
+ }
+
+ $params = array(
+ 'action' => 'upload',
+ 'filename' => $fileName,
+ 'file' => 'dummy content',
+ 'comment' => 'dummy comment',
+ 'text' => "This is the page text for $fileName",
+ // This uploadFile function supports video tests not a test upload warnings
+ 'ignorewarnings' => true
+ );
+
+ try{
+ list( $result, , ) = $this->doApiRequestWithToken( $params, $session );
+ } catch( Exception $e ) {
+ // Could not upload mark test that called uploadFile as incomplete
+ $this->markTestIncomplete( $e->getMessage() );
+ }
+
+ return $result;
+
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/tests/phpunit/README b/extensions/TimedMediaHandler/tests/phpunit/README
new file mode 100644
index 00000000..dd9eba39
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/README
@@ -0,0 +1,11 @@
+
+Some TimedMediaHandler testing notes:
+
+ We have a base class ApiTestCaseVideoUpload that establishes the uploads. Actual uploading
+ is tested in the core uploading support so we focus these tests on timed media handler functionality
+
+ We sometimes combine a few tests because fixtures don't play well with dataProvider
+ since the mediawiki test framework nukes the db every time you run the next test in
+ a given dataProvider data set.
+
+
diff --git a/extensions/TimedMediaHandler/tests/phpunit/TestApiUploadVideo.php b/extensions/TimedMediaHandler/tests/phpunit/TestApiUploadVideo.php
new file mode 100644
index 00000000..ebc38ddf
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/TestApiUploadVideo.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * TestApiUploadVideo test case.
+ *
+ * NOTE: This build heavily on ApiUploadTest ( would need to refactor ApiUploadTest for this to work better )
+ *
+ * @ingroup timedmedia
+ * @since 0.2
+ * @author Michael Dale
+ */
+
+/**
+ * @group Database
+ * @group Destructive
+ * @group medium
+ */
+class TestApiUploadVideo extends ApiTestCaseVideoUpload {
+
+ /**
+ * @dataProvider mediaFilesProvider
+ */
+ public function testUploadVideoFiles( $file ){
+
+ $result = $this->uploadFile( $file );
+
+ // Run asserts
+ $this->assertTrue( isset( $result['upload'] ) );
+ $this->assertEquals( 'Success', $result['upload']['result'] );
+ $this->assertEquals( filesize( $file['filePath'] ), ( int )$result['upload']['imageinfo']['size'] );
+ $this->assertEquals( $file['mime'], $result['upload']['imageinfo']['mime'] );
+
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/tests/phpunit/TestOggHandler.php b/extensions/TimedMediaHandler/tests/phpunit/TestOggHandler.php
new file mode 100644
index 00000000..3c058974
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/TestOggHandler.php
@@ -0,0 +1,67 @@
+<?php
+class TestOggHandler extends MediaWikiMediaTestCase {
+
+ /** @var OggHandlerTMH */
+ private $handler;
+
+ function getFilePath() {
+ return __DIR__ . '/media';
+ }
+
+ function setUp() {
+ parent::setUp();
+ $this->handler = new OggHandlerTMH;
+ }
+
+ /**
+ * @dataProvider providerGetCommonMetaArray
+ * @param $filename String name of file
+ * @param $expected Array
+ */
+ function testGetCommonMetaArray( $filename, $expected ) {
+ $testFile = $this->dataFile( $filename, 'application/ogg' );
+ $this->assertEquals( $expected, $this->handler->getCommonMetaArray( $testFile ) );
+ }
+
+ function providerGetCommonMetaArray() {
+ return array(
+ array( 'test5seconds.electricsheep.300x400.ogv',
+ array(
+ 'Software' => array( 'Lavf53.21.1' ),
+ 'ObjectName' => array( 'Electric Sheep' ),
+ 'UserComment' => array( '🐑' )
+ )
+ ),
+ array( 'doubleTag.oga',
+ array(
+ 'Artist' => array( 'Brian', 'Bawolff' ),
+ 'Software' => array( 'Lavf55.10.2' )
+ )
+ ),
+ array( 'broken-file.ogg',
+ array()
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider providerGetWebType
+ * @param $filename String name of file
+ * @param $expected String Mime type (including codecs)
+ */
+ function testGetWebType( $filename, $expected ) {
+ $testFile = $this->dataFile( $filename, 'application/ogg' );
+ $this->assertEquals( $expected, $this->handler->getWebType( $testFile ) );
+ }
+
+ function providerGetWebType() {
+ return array(
+ array( 'test5seconds.electricsheep.300x400.ogv', 'video/ogg; codecs="theora"' ),
+ array( 'doubleTag.oga', 'audio/ogg; codecs="vorbis"' ),
+ // XXX: This behaviour is somewhat questionable. It perhaps should be
+ // application/ogg in this case.
+ array( 'broken-file.ogg', 'audio/ogg' ),
+ );
+ }
+
+}
diff --git a/extensions/TimedMediaHandler/tests/phpunit/TestTimeParsing.php b/extensions/TimedMediaHandler/tests/phpunit/TestTimeParsing.php
new file mode 100644
index 00000000..b4ec6ba9
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/TestTimeParsing.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * TestTimeParsing test .
+ *
+ * @ingroup timedmedia
+ * @since 0.2
+ * @author Michael Dale
+ */
+
+
+class TestTimeParsing extends PHPUnit_Framework_TestCase {
+ /**
+ * Test time string to np2
+ */
+ function testSeconds2NptFormat() {
+ // Some time conversions:
+ $this->assertEquals( TimedMediaHandler::seconds2npt( 100 ), '0:1:40' );
+ $this->assertEquals( TimedMediaHandler::seconds2npt( 0 ), '0:0:0' );
+ $this->assertEquals( TimedMediaHandler::seconds2npt( 3601 ), '1:0:1' );
+
+ // Test failures:
+ $this->assertEquals( TimedMediaHandler::seconds2npt( 'foo' ), false );
+ $this->assertEquals( TimedMediaHandler::seconds2npt( -1 ), false );
+ }
+
+ /**
+ * Test time parsing to seconds
+ */
+ function testParseTimeString() {
+ // Some time conversions:
+ $this->assertEquals( TimedMediaHandler::parseTimeString( 100 ), 100 );
+ $this->assertEquals( TimedMediaHandler::parseTimeString( '1:0:0' ), 3600 );
+ $this->assertEquals( TimedMediaHandler::parseTimeString( -1 ), 0 );
+ // Test longer than duration check ( should return time -1 )
+ $this->assertEquals( TimedMediaHandler::parseTimeString( 10, 9 ), 8 );
+
+ // Test failures:
+ $this->assertEquals( TimedMediaHandler::parseTimeString( '1:1:1:1' ), false );
+ $this->assertEquals( TimedMediaHandler::parseTimeString( 'abc' ), false );
+
+ }
+} \ No newline at end of file
diff --git a/extensions/TimedMediaHandler/tests/phpunit/TestTimedMediaHandler.php b/extensions/TimedMediaHandler/tests/phpunit/TestTimedMediaHandler.php
new file mode 100644
index 00000000..2ca350a0
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/TestTimedMediaHandler.php
@@ -0,0 +1,47 @@
+<?php
+class TestTimedMediaHandler extends MediaWikiTestCase {
+
+ /** @var TimedMediaHandler */
+ private $handler;
+
+ function setUp() {
+ $this->handler = new TimedMediaHandler;
+ parent::setUp();
+ }
+
+ /**
+ * @dataProvider providerParseParamString
+ * @param $str String a thumbnail parameter string
+ * @param $expected Array Expected thumbnailing parameters
+ */
+ function testParseParamString( $str, $expected ) {
+ $result = $this->handler->parseParamString( $str );
+ $this->assertEquals( $result, $expected );
+ }
+
+ function providerParseParamString() {
+ return array(
+ array(
+ 'mid',
+ array(),
+ ),
+ array(
+ '220px-',
+ array( 'width' => 220 ),
+ ),
+ array(
+ 'seek=30',
+ array( 'thumbtime' => 30.0 ),
+ ),
+ array(
+ 'seek=15.72',
+ array( 'thumbtime' => 15.72 ),
+ ),
+ array(
+ '180px-seek=15',
+ array( 'thumbtime' => 15, 'width' => 180 ),
+ ),
+ );
+
+ }
+}
diff --git a/extensions/TimedMediaHandler/tests/phpunit/TestTimedMediaTransformOutput.php b/extensions/TimedMediaHandler/tests/phpunit/TestTimedMediaTransformOutput.php
new file mode 100644
index 00000000..9bcc89fb
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/TestTimedMediaTransformOutput.php
@@ -0,0 +1,142 @@
+<?php
+class TestTimedMediaTransformOutput extends MediaWikiMediaTestCase {
+
+ private $sortMethod;
+ private $thumbObj;
+
+ function getFilePath() {
+ return __DIR__ . '/media';
+ }
+
+ protected function setUp() {
+ parent::setUp();
+
+ // Disable video thumbnail generation. Not needed for this test.
+ $reflection = new ReflectionClass( $this->repo );
+ $reflectionProperty = $reflection->getProperty( 'transformVia404' );
+ $reflectionProperty->setAccessible( true );
+ $reflectionProperty->setValue( $this->repo, true );
+
+ $this->setMWGlobals( 'wgMinimumVideoPlayerSize', '400' );
+ }
+
+ /**
+ * @param $width int The requested width of the thumbnail
+ * @param $minVideoSize int The min width a non-pop up video is acceptable
+ * @param $expectPopup boolean Do we expect a pop up video
+ *
+ * @dataProvider providerIsPopUp
+ */
+ function testIsPopUp( $width, $minVideoSize, $expectPopup ) {
+ $this->setMwGlobals( 'wgMinimumVideoPlayerSize', $minVideoSize );
+
+ // Note this file has a width of 400px and a height of 300px
+ $file = $this->dataFile( 'test5seconds.electricsheep.300x400.ogv', 'application/ogg' );
+ $thumbnail = $file->transform( array( 'width' => $width ) );
+ $this->assertTrue( $thumbnail && !$thumbnail->isError() );
+
+ $reflection = new ReflectionClass( $thumbnail );
+ $reflMethod = $reflection->getMethod( 'useImagePopUp' );
+ $reflMethod->setAccessible( true );
+
+ $actual = $reflMethod->invoke( $thumbnail );
+ $this->assertEquals( $actual, $expectPopup );
+
+ }
+
+ function providerIsPopUp() {
+ return array(
+ array( 400, 800, false ),
+ array( 300, 800, true ),
+ array( 300, 200, false ),
+ array( 300, 300, false )
+ );
+ }
+
+ /**
+ * @param $thumbWidth int Requested width
+ * @param $sources array
+ * @param $sortedSources array
+ * @dataProvider providerSortMediaByBandwidth
+ */
+ function testSortMediaByBandwidth( $thumbWidth, $sources, $sortedSources ) {
+ $params = array(
+ 'width' => $thumbWidth,
+ 'height' => $thumbWidth * 9 / 16,
+ 'isVideo' => true,
+ 'fillwindow' => false,
+ 'file' => new FakeDimensionFile( array( 1820, 1024 ) )
+ );
+ $this->thumbObj = new TimedMediaTransformOutput( $params );
+
+ $reflection = new ReflectionClass( $this->thumbObj );
+ $this->sortMethod = $reflection->getMethod( 'sortMediaByBandwidth' );
+ $this->sortMethod->setAccessible( true );
+
+ usort( $sources, array( $this, 'callSortMethodHelper' ) );
+ $this->assertEquals( $sortedSources, $sources );
+ }
+
+ public function callSortMethodHelper( $a, $b ) {
+ return $this->sortMethod->invoke( $this->thumbObj, $a, $b );
+ }
+
+
+ function providerSortMediaByBandwidth() {
+ return array(
+ array(
+ 600,
+ array(
+ array( 'width' => 1000, 'bandwidth' => 2000 ),
+ array( 'width' => 1000, 'bandwidth' => 7000 ),
+ array( 'width' => 1000, 'bandwidth' => 1000 ),
+ ),
+ array(
+ array( 'width' => 1000, 'bandwidth' => 1000 ),
+ array( 'width' => 1000, 'bandwidth' => 2000 ),
+ array( 'width' => 1000, 'bandwidth' => 7000 ),
+ ),
+ ),
+ array(
+ 600,
+ array(
+ array( 'width' => 200, 'bandwidth' => 2000 ),
+ array( 'width' => 1000, 'bandwidth' => 7000 ),
+ array( 'width' => 200, 'bandwidth' => 1000 ),
+ ),
+ array(
+ array( 'width' => 1000, 'bandwidth' => 7000 ),
+ array( 'width' => 200, 'bandwidth' => 1000 ),
+ array( 'width' => 200, 'bandwidth' => 2000 ),
+ ),
+ ),
+ array(
+ /* Pop up viewer in this case */
+ 100,
+ array(
+ array( 'width' => 700, 'bandwidth' => 2000 ),
+ array( 'width' => 1000, 'bandwidth' => 7000 ),
+ array( 'width' => 700, 'bandwidth' => 1000 ),
+ ),
+ array(
+ array( 'width' => 1000, 'bandwidth' => 7000 ),
+ array( 'width' => 700, 'bandwidth' => 1000 ),
+ array( 'width' => 700, 'bandwidth' => 2000 ),
+ ),
+ ),
+ array(
+ 600,
+ array(
+ array( 'width' => 700, 'bandwidth' => 2000 ),
+ array( 'width' => 800, 'bandwidth' => 7000 ),
+ array( 'width' => 1000, 'bandwidth' => 1000 ),
+ ),
+ array(
+ array( 'width' => 1000, 'bandwidth' => 1000 ),
+ array( 'width' => 700, 'bandwidth' => 2000 ),
+ array( 'width' => 800, 'bandwidth' => 7000 ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/extensions/TimedMediaHandler/tests/phpunit/TestVideoThumbnail.php b/extensions/TimedMediaHandler/tests/phpunit/TestVideoThumbnail.php
new file mode 100644
index 00000000..b3c9ef87
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/TestVideoThumbnail.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * @ingroup timedmedia
+ * @author dale
+ * @group medium
+ */
+class TestVideoThumbnail extends ApiTestCaseVideoUpload {
+
+ /**
+ * Once video files are uploaded test thumbnail generating
+ *
+ * @dataProvider mediaFilesProvider
+ * Broken as per bug 61877
+ * @group Broken
+ */
+ function testApiThumbnails( $file ){
+ // Upload the file to the mediaWiki system
+ $result = $this->uploadFile( $file);
+
+ // Do a API request and check for valid thumbnails:
+ $fileName = basename( $file['filePath'] );
+ $params = array(
+ 'action' => 'query',
+ 'titles' => 'File:' . $fileName,
+ 'prop' => 'imageinfo',
+ 'iiprop' => "url|size|thumbmime",
+ );
+
+ // Do a request for a small ( 200px ) thumbnail
+ list($result,,) = $this->doApiRequest(
+ array_merge( $params, array(
+ 'iiurlwidth' => '200'
+ )
+ )
+ );
+
+ // Check The thumbnail output:
+ $this->assertTrue( isset( $result['query'] ) );
+
+ $page = current( $result['query']['pages'] );
+ $this->assertTrue( isset( $page['imageinfo'] ) );
+
+ $imageInfo = current( $page['imageinfo'] );
+
+ // Make sure we got a 200 wide pixel image:
+ $this->assertEquals( 200, ( int )$imageInfo['thumbwidth'] );
+
+ // Thumbnails should be image/jpeg:
+ $this->assertEquals( 'image/jpeg', $imageInfo['thumbmime'] );
+
+ // Make sure the thumbnail url is valid and the correct size ( assuming php has getimagesize function)
+ if( function_exists( 'getimagesize' ) ){
+ list($width ,,,) = getimagesize ( $imageInfo[ 'thumburl'] );
+ $this->assertEquals( 200, $width );
+ }
+
+ /**
+ * We combine tests because fixtures don't play well with dataProvider
+ * see README for more info
+ */
+
+ // Test a larger thumbnail with 1 second time offset
+ list( $result,, ) = $this->doApiRequest(
+ array_merge( $params, array(
+ 'iiurlwidth' => '600',
+ 'iiurlparam' => '1'
+ )
+ )
+ );
+ $page = current( $result['query']['pages'] );
+ $imageInfo = current( $page['imageinfo'] );
+ // Thumb should max out at source size ( no upscale )
+ $targetWidth = ( ( int )$file['width'] < 600 ) ? ( int )$file['width'] : 600;
+ $this->assertEquals( $targetWidth, ( int )$imageInfo['thumbwidth'] );
+ if( function_exists( 'getimagesize' ) ){
+ list( $srcImageWidth ,,,) = getimagesize ( $imageInfo[ 'thumburl'] );
+ $this->assertEquals( $targetWidth, $srcImageWidth );
+ }
+ }
+}
diff --git a/extensions/TimedMediaHandler/tests/phpunit/TestVideoTranscode.php b/extensions/TimedMediaHandler/tests/phpunit/TestVideoTranscode.php
new file mode 100644
index 00000000..af0e6f1f
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/TestVideoTranscode.php
@@ -0,0 +1,121 @@
+<?php
+/**
+ * @ingroup timedmedia
+ * @author michael dale
+ * @group medium
+ */
+class TestVideoTranscode extends ApiTestCaseVideoUpload {
+
+ /**
+ * Once video files are uploaded test transcoding
+ *
+ * Test if a transcode job is added for a file once requested
+ *
+ * @dataProvider mediaFilesProvider
+ * Broken as per bug 61878
+ * @group Broken
+ */
+ function testTranscodeJobs( $file ){
+ // Upload the file to the mediaWiki system
+ $result = $this->uploadFile( $file );
+
+ // Check for derivatives ( should trigger adding jobs )
+ $fileName = basename( $file['filePath'] );
+ $params = array(
+ 'action' => 'query',
+ 'titles' => 'File:' . $fileName,
+ 'prop' => 'videoinfo',
+ 'viprop' => "derivatives",
+ );
+ list($result,,) = $this->doApiRequest( $params );
+
+ // Get the $derivatives:
+ $derivatives = $this->getDerivativesFromResult( $result );
+ // Only the "source" asset will be present at first:
+ $source = current( $derivatives );
+
+ // Check that the source matches the api bandwidth property:
+ $this->assertEquals( $file['bandwidth'], $source['bandwidth'] );
+
+ // Check if the transcode jobs were added:
+ // get results: query jobs table
+ $db = wfGetDB( DB_MASTER );
+ $res = $db->select( 'transcode', '*', array(
+ 'transcode_image_name' => ucfirst( $fileName )
+ ) );
+ // Make sure we target at least one ogg and one webm:
+ $hasOgg = $hasWebM = false;
+ $targetEncodes = array();
+ foreach( $res as $row ){
+ $codec = WebVideoTranscode::$derivativeSettings[ $row->transcode_key ]['videoCodec'];
+ if( $codec == 'theora' ){
+ $hasOgg = true;
+ }
+ if( $codec == 'vp8' ){
+ $hasWebM = true;
+ }
+ $targetEncodes[ $row->transcode_key ] = $row;
+ };
+ // Make sure we have ogg and webm:
+ $this->assertTrue( $hasOgg && $hasWebM );
+
+ // Now run the transcode job queue
+ $this->runTranscodeJobs();
+
+ $res = $db->select( 'transcode', '*', array(
+ 'transcode_image_name' => ucfirst( $fileName )
+ ) );
+
+ // Now check if the derivatives were created:
+ list($result,,) = $this->doApiRequest( $params );
+ $derivatives = $this->getDerivativesFromResult( $result );
+
+ // Check that every requested encode was encoded:
+ foreach( $targetEncodes as $transcodeKey => $row ){
+ $targetEncodeFound = false;
+ foreach( $derivatives as $derv ){
+ // The transcode key is always the last part of the file name:
+ if( substr( $derv['src'], -1 * strlen( $transcodeKey ) ) == $transcodeKey ){
+ $targetEncodeFound = true;
+ }
+ }
+ // Test that target encode was found:
+ $this->assertTrue( $targetEncodeFound );
+ }
+
+ }
+
+ // Run Transcode job
+ function runTranscodeJobs(){
+ $dbw = wfGetDB( DB_MASTER );
+ $type = 'webVideoTranscode';
+ // Set the condition to only run the webVideoTranscode
+ $conds = array( "job_cmd" => $type );
+
+ while ( $dbw->selectField( 'job', 'job_id', $conds, 'runJobs.php' ) ) {
+ for ( ; ; ) {
+ $job = Job::pop_type( $type );
+ if ( !$job )
+ break;
+
+ wfWaitForSlaves( 5 );
+ $t = microtime( true );
+ $offset = $job->id;
+ $status = $job->run();
+ $t = microtime( true ) - $t;
+ $timeMs = intval( $t * 1000 );
+ }
+ }
+ }
+
+ function getDerivativesFromResult( $result ){
+ // Only the source should be listed initially:
+ $this->assertTrue( isset( $result['query']['pages'] ) );
+ $page = current( $result['query']['pages'] );
+
+ $videoInfo = current( $page['videoinfo'] );
+ $this->assertTrue( isset( $videoInfo['derivatives'] ) );
+
+ return $videoInfo['derivatives'];
+ }
+}
diff --git a/extensions/TimedMediaHandler/tests/phpunit/TestWebMHandler.php b/extensions/TimedMediaHandler/tests/phpunit/TestWebMHandler.php
new file mode 100644
index 00000000..2d73f46d
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/TestWebMHandler.php
@@ -0,0 +1,52 @@
+<?php
+class TestOggHandler extends MediaWikiMediaTestCase {
+
+ /** @var OggHandlerTMH */
+ private $handler;
+
+ function getFilePath() {
+ return __DIR__ . '/media';
+ }
+
+ function setUp() {
+ parent::setUp();
+ $this->handler = new WebMHandler;
+ }
+
+ /**
+ * @dataProvider providerGetStreamTypes
+ * @param $filename String name of file
+ * @param $expected array List of codecs in file
+ */
+ function testGetStreamTypes( $filename, $expected ) {
+ $testFile = $this->dataFile( $filename, 'video/webm' );
+ $this->assertEquals( $expected, $this->handler->getStreamTypes( $testFile ) );
+ }
+
+ function providerGetStreamTypes() {
+ return array(
+ array( 'shuttle10seconds.1080x608.webm', array( 'VP8' ) ),
+ array( 'VP9-tractor.webm', array( 'VP9' ) ),
+ array( 'bear-vp9-opus.webm', array( 'Opus', 'VP9' ) )
+ );
+ }
+
+
+ /**
+ * @dataProvider providerGetWebType
+ * @param $filename String name of file
+ * @param $expected String Mime type
+ */
+ function testGetWebType( $filename, $expected ) {
+ $testFile = $this->dataFile( $filename, 'video/webm' );
+ $this->assertEquals( $expected, $this->handler->getWebType( $testFile ) );
+ }
+
+ function providerGetWebType() {
+ return array(
+ array( 'shuttle10seconds.1080x608.webm', 'video/webm; codecs="vp8"' ),
+ array( 'VP9-tractor.webm', 'video/webm; codecs="vp9"' ),
+ array( 'bear-vp9-opus.webm', 'video/webm; codecs="opus, vp9"' )
+ );
+ }
+}
diff --git a/extensions/TimedMediaHandler/tests/phpunit/media/README b/extensions/TimedMediaHandler/tests/phpunit/media/README
new file mode 100644
index 00000000..b21871ea
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/media/README
@@ -0,0 +1,38 @@
+doubleTag.oga and broken-file.ogg were created by Brian Wolff and is released into the public domain
+
+VP9-tractor.webm is from http://base-n.de/webm/VP9%20Sample.html and was encoded from a public domain
+file located at http://media.xiph.org/video/derf/y4m/
+
+bear-vp9-opus.webm comes from the chromnium project at the url
+http://code.metager.de/source/raw/chromium/media/test/data/bear-vp9-opus.webm
+which has the following copyright notice:
+
+1 // Copyright 2014 The Chromium Authors. All rights reserved.
+2 //
+3 // Redistribution and use in source and binary forms, with or without
+4 // modification, are permitted provided that the following conditions are
+5 // met:
+6 //
+7 // * Redistributions of source code must retain the above copyright
+8 // notice, this list of conditions and the following disclaimer.
+9 // * Redistributions in binary form must reproduce the above
+10 // copyright notice, this list of conditions and the following disclaimer
+11 // in the documentation and/or other materials provided with the
+12 // distribution.
+13 // * Neither the name of Google Inc. nor the names of its
+14 // contributors may be used to endorse or promote products derived from
+15 // this software without specific prior written permission.
+16 //
+17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
diff --git a/extensions/TimedMediaHandler/tests/phpunit/media/VP9-tractor.webm b/extensions/TimedMediaHandler/tests/phpunit/media/VP9-tractor.webm
new file mode 100644
index 00000000..bbe96f5d
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/media/VP9-tractor.webm
Binary files differ
diff --git a/extensions/TimedMediaHandler/tests/phpunit/media/bear-vp9-opus.webm b/extensions/TimedMediaHandler/tests/phpunit/media/bear-vp9-opus.webm
new file mode 100644
index 00000000..80355cfa
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/media/bear-vp9-opus.webm
Binary files differ
diff --git a/extensions/TimedMediaHandler/tests/phpunit/media/broken-file.ogg b/extensions/TimedMediaHandler/tests/phpunit/media/broken-file.ogg
new file mode 100644
index 00000000..c9fc4fd5
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/media/broken-file.ogg
Binary files differ
diff --git a/extensions/TimedMediaHandler/tests/phpunit/media/doubleTag.oga b/extensions/TimedMediaHandler/tests/phpunit/media/doubleTag.oga
new file mode 100644
index 00000000..f7fac168
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/media/doubleTag.oga
Binary files differ
diff --git a/extensions/TimedMediaHandler/tests/phpunit/media/shuttle10seconds.1080x608.webm b/extensions/TimedMediaHandler/tests/phpunit/media/shuttle10seconds.1080x608.webm
new file mode 100644
index 00000000..a7b865b1
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/media/shuttle10seconds.1080x608.webm
Binary files differ
diff --git a/extensions/TimedMediaHandler/tests/phpunit/media/test5seconds.electricsheep.300x400.ogv b/extensions/TimedMediaHandler/tests/phpunit/media/test5seconds.electricsheep.300x400.ogv
new file mode 100644
index 00000000..a73ec5bf
--- /dev/null
+++ b/extensions/TimedMediaHandler/tests/phpunit/media/test5seconds.electricsheep.300x400.ogv
Binary files differ
diff --git a/extensions/TimedMediaHandler/version b/extensions/TimedMediaHandler/version
new file mode 100644
index 00000000..20e3a345
--- /dev/null
+++ b/extensions/TimedMediaHandler/version
@@ -0,0 +1,5 @@
+TimedMediaHandler: 7cab54e2e482d51df69e4b9c880182b23cabf0bc
+
+2016-01-27T22:15:53
+
+7cab54e