PageSourceSearch

https://radio-portal.su/plugins/slogin_auth/telegram/assets/widget-frame.js?015dcb

js radio-portal.su collected 2026-10-04 23:53:47 UTC 84,541 bytes, 2,405 lines download raw bytes

1// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
2// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
3
4// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
5
6// MIT license
7
8(function() {
9    var lastTime = 0;
10    var vendors = ['ms', 'moz', 'webkit', 'o'];
11    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
12        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
13        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
14                                   || window[vendors[x]+'CancelRequestAnimationFrame'];
15    }
16
17    if (!window.requestAnimationFrame)
18        window.requestAnimationFrame = function(callback, element) {
19            var currTime = new Date().getTime();
20            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
21            var id = window.setTimeout(function() { callback(currTime + timeToCall); },
22              timeToCall);
23            lastTime = currTime + timeToCall;
24            return id;
25        };
26
27    if (!window.cancelAnimationFrame)
28        window.cancelAnimationFrame = function(id) {
29            clearTimeout(id);
30        };
31}());
32
33
34
35/*! npm.im/iphone-inline-video 2.0.2 */
36
37var enableInlineVideo=function(){"use strict";/*! npm.im/intervalometer */
38function e(e,i,n,r){function t(n){d=i(t,r),e(n-(a||n)),a=n}var d,a;return{start:function(){d||t(0)},stop:function(){n(d),d=null,a=0}}}function i(i){return e(i,requestAnimationFrame,cancelAnimationFrame)}function n(e,i,n,r){function t(i){Boolean(e[n])===Boolean(r)&&i.stopImmediatePropagation(),delete e[n]}return e.addEventListener(i,t,!1),t}function r(e,i,n,r){function t(){return n[i]}function d(e){n[i]=e}r&&d(e[i]),Object.defineProperty(e,i,{get:t,set:d})}function t(e,i,n){n.addEventListener(i,function(){return e.dispatchEvent(new Event(i))})}function d(e,i){Promise.resolve().then(function(){e.dispatchEvent(new Event(i))})}function a(e){var i=new Audio;return t(e,"play",i),t(e,"playing",i),t(e,"pause",i),i.crossOrigin=e.crossOrigin,i.src=e.src||e.currentSrc||"data:",i}function o(e,i,n){(m||0)+200<Date.now()&&(e[b]=!0,m=Date.now()),n||(e.currentTime=i),w[++T%3]=100*i|0}function u(e){return e.driver.currentTime>=e.video.duration}function s(e){var i=this;i.video.readyState>=i.video.HAVE_FUTURE_DATA?(i.hasAudio||(i.driver.currentTime=i.video.currentTime+e*i.video.playbackRate/1e3,i.video.loop&&u(i)&&(i.driver.currentTime=0)),o(i.video,i.driver.currentTime)):i.video.networkState===i.video.NETWORK_IDLE&&0===i.video.buffered.length&&i.video.load(),i.video.ended&&(delete i.video[b],i.video.pause(!0))}function c(){var e=this,i=e[h];return e.webkitDisplayingFullscreen?void e[g]():("data:"!==i.driver.src&&i.driver.src!==e.src&&(o(e,0,!0),i.driver.src=e.src),void(e.paused&&(i.paused=!1,0===e.buffered.length&&e.load(),i.driver.play(),i.updater.start(),i.hasAudio||(d(e,"play"),i.video.readyState>=i.video.HAVE_ENOUGH_DATA&&d(e,"playing")))))}function v(e){var i=this,n=i[h];n.driver.pause(),n.updater.stop(),i.webkitDisplayingFullscreen&&i[E](),n.paused&&!e||(n.paused=!0,n.hasAudio||d(i,"pause"),i.ended&&(i[b]=!0,d(i,"ended")))}function p(e,n){var r=e[h]={};r.paused=!0,r.hasAudio=n,r.video=e,r.updater=i(s.bind(r)),n?r.driver=a(e):(e.addEventListener("canplay",function(){e.paused||d(e,"playing")}),r.driver={src:e.src||e.currentSrc||"data:",muted:!0,paused:!0,pause:function(){r.driver.paused=!0},play:function(){r.driver.paused=!1,u(r)&&o(e,0)},get ended(){return u(r)}}),e.addEventListener("emptied",function(){var i=!r.driver.src||"data:"===r.driver.src;r.driver.src&&r.driver.src!==e.src&&(o(e,0,!0),r.driver.src=e.src,i?r.driver.play():r.updater.stop())},!1),e.addEventListener("webkitbeginfullscreen",function(){e.paused?n&&0===r.driver.buffered.length&&r.driver.load():(e.pause(),e[g]())}),n&&(e.addEventListener("webkitendfullscreen",function(){r.driver.currentTime=e.currentTime}),e.addEventListener("seeking",function(){w.indexOf(100*e.currentTime|0)<0&&(r.driver.currentTime=e.currentTime)}))}function l(e){var i=e[h];e[g]=e.play,e[E]=e.pause,e.play=c,e.pause=v,r(e,"paused",i.driver),r(e,"muted",i.driver,!0),r(e,"playbackRate",i.driver,!0),r(e,"ended",i.driver),r(e,"loop",i.driver,!0),n(e,"seeking"),n(e,"seeked"),n(e,"timeupdate",b,!1),n(e,"ended",b,!1)}function f(e,i){if(void 0===i&&(i={}),!e[h]){if(!i.everywhere){if(!y)return;if(!(i.iPad||i.ipad?/iPhone|iPod|iPad/:/iPhone|iPod/).test(navigator.userAgent))return}!e.paused&&e.webkitDisplayingFullscreen&&e.pause(),p(e,!e.muted),l(e),e.classList.add("IIV"),e.muted&&e.autoplay&&e.play(),/iPhone|iPod|iPad/.test(navigator.platform)||console.warn("iphone-inline-video is not guaranteed to work in emulated environments")}}var m,y="object"==typeof document&&"object-fit"in document.head.style&&!matchMedia("(-webkit-video-playable-inline)").matches,h="bfred-it:iphone-inline-video",b="bfred-it:iphone-inline-video:event",g="bfred-it:iphone-inline-video:nativeplay",E="bfred-it:iphone-inline-video:nativepause",w=[],T=0;return f}();
39
40if (!Array.isArray) {
41  Array.isArray = function(arg) {
42    return Object.prototype.toString.call(arg) === '[object Array]';
43  };
44}
45
46(!this.CustomEvent || typeof this.CustomEvent === "object") && (function() {
47  this.CustomEvent = function CustomEvent(type, eventInitDict) {
48    var event;
49    eventInitDict = eventInitDict || {bubbles: false, cancelable: false, detail: undefined};
50
51    try {
52      event = document.createEvent('CustomEvent');
53      event.initCustomEvent(type, eventInitDict.bubbles, eventInitDict.cancelable, eventInitDict.detail);
54    } catch (error) {
55      event = document.createEvent('Event');
56      event.initEvent(type, eventInitDict.bubbles, eventInitDict.cancelable);
57      event.detail = eventInitDict.detail;
58    }
59
60    return event;
61  };
62})();
63
64var Keys = {
65  BACKSPACE: 8,
66  ESC: 27,
67  TAB: 9,
68  RETURN: 13,
69  LEFT: 37,
70  UP: 38,
71  RIGHT: 39,
72  DOWN: 40
73};
74
75var TWidget = {
76  options: {},
77  isFocused: false
78};
79function inFrame() {
80  return (window.parent != null && window != window.parent);
81}
82function inFullFrame() {
83  return inFrame() && TWidget.options.auto_height;
84}
85function isFocused() {
86  return inFrame() ? TWidget.isFocused : document.hasFocus();
87}
88
89function l(lang_key, params, def_value) {
90  if (typeof params === 'string') {
91    def_value = params;
92    params = {};
93  }
94  params = params || {};
95  var value = l._keys[lang_key] || def_value || lang_key;
96  value = value.replace(/\{([A-Za-z_\-\d]{1,32}):(.{1,256}?)\}/, function(lang_value, token, options) {
97    var number = +params[token] || 0;
98    var numeric_options = options.split('|');
99    var i;
100    if (!number) i = 0;
101    else if (number == 1) i = 1;
102    else i = 2;
103    if (typeof numeric_options[i] === 'undefined') {
104      i = 0;
105    }
106    var numeric_option = numeric_options[i] || '#';
107    return numeric_option.replace('#', number);
108  });
109  for (var param in params) {
110    value = value.replace('{' + param + '}', params[param]);
111  }
112  return value;
113}
114l._keys = {};
115l.add = function(lang_values) {
116  for (var lang_key in lang_values) {
117    l._keys[lang_key] = lang_values[lang_key];
118  }
119}
120
121var PostMessage = {
122  _callbacks: {},
123  _lastId: 0,
124  send: function(data, origin, callback) {
125    if (typeof origin === 'function') {
126      callback = origin; origin = null;
127    }
128    try {
129      if (callback) {
130        data._cb = ++PostMessage._lastId;
131        PostMessage._callbacks[data._cb] = callback;
132      }
133
134      window.parent.postMessage(JSON.stringify(data), origin || '*');
135    } catch(e) {
136      if (origin) alert('Bot domain invalid');
137    }
138  },
139  onMessage: function(event) {
140    if (event.source !== window.parent) return;
141    try {
142      var data = JSON.parse(event.data);
143    } catch(e) {
144      var data = {};
145    }
146    if (data.event == 'visible') {
147      if (!frameWasVisible) {
148        frameWasVisible = true;
149        TWidget.options.onVisible && TWidget.options.onVisible();
150      }
151      PostMessage.send({event: 'visible_off'});
152    }
153    else if (data.event == 'focus') {
154      TWidget.isFocused = data.has_focus;
155      triggerEvent(window, 'tg:focuschange');
156    }
157    else if (data.event == 'set_options') {
158      triggerEvent(window, 'tg:optionschange', {detail: data.options});
159    }
160    else if (data.event == 'visible') {
161      if (!frameWasVisible) {
162        frameWasVisible = true;
163        TWidget.options.onVisible && TWidget.options.onVisible();
164      }
165      PostMessage.send({event: 'visible_off'});
166    }
167    else if (data.event == 'callback') {
168      if (PostMessage._callbacks[data._cb]) {
169        PostMessage._callbacks[data._cb](data.value);
170        delete PostMessage._callbacks[data._cb];
171      } else {
172        console.warn('Callback #' + data._cb + ' not found');
173      }
174    }
175  }
176};
177
178var TPopups = {
179  _list: [],
180  _lastId: 0,
181  _inited: false,
182  init: function() {
183    if (!TPopups._inited) {
184      TPopups._inited = true;
185      addEvent(document, 'keydown', function(e) {
186        if (e.keyCode == Keys.ESC && TPopups._list.length > 0) {
187          e.stopImmediatePropagation();
188          e.preventDefault();
189          TPopups.close();
190        }
191      });
192    }
193  },
194  open: function(popup_el, options) {
195    TPopups.init();
196    popup_el = ge1(popup_el);
197    if (!popup_el) {
198      return popup_el;
199    }
200    options = options || {};
201    var popup_id = popup_el.__puid;
202    if (!popup_id) {
203      popup_id = ++TPopups._lastId;
204      popup_el.__puid = popup_id;
205    }
206    popup_el.__options = options;
207    var index = TPopups._list.indexOf(popup_id);
208    if (index >= 0) {
209      TPopups._list.splice(index, 1);
210    }
211    TPopups._list.push(popup_id);
212    document.body.style.overflow = 'hidden';
213    document.body.appendChild(popup_el);
214    removeClass(popup_el, 'hide');
215    TPopups.setPosition(popup_el);
216    if (document.activeElement) {
217      document.activeElement.blur();
218    }
219    if (ge1('.js-popup_box', popup_el)) {
220      addEvent(popup_el, 'click', function(e) {
221        if (elInBody(e.target) &&
222            !hasClass(e.target, 'js-popup_box') &&
223            !gpeByClass(e.target, 'js-popup_box')) {
224          TPopups.close(popup_el);
225        }
226      });
227    }
228    gec('.js-popup_close', function() {
229      addEvent(this, 'click', function() {
230        TPopups.close(popup_el);
231      });
232    }, popup_el);
233    triggerEvent(popup_el, 'tg:popupopen');
234    return popup_el;
235  },
236  close: function(popup_el) {
237    if (!TPopups._list.length) return false;
238    var popup_id;
239    if (popup_el) {
240      popup_id = popup_el.__puid;
241    } else {
242      popup_id = TPopups._list.pop();
243      gec('.js-popup_container', function() {
244        if (popup_id == this.__puid) {
245          popup_el = this;
246          return false;
247        }
248      });
249    }
250    if (!popup_el) {
251      return false;
252    }
253    var options = popup_el.__options;
254    var index = TPopups._list.indexOf(popup_id);
255    if (index >= 0) {
256      TPopups._list.splice(index, 1);
257    }
258    if (!TPopups._list.length) {
259      document.body.style.overflow = '';
260    }
261    removeEvent(popup_el, 'click');
262    gec('.js-popup_close', function() {
263      removeEvent(this, 'click');
264    }, popup_el);
265    addClass(popup_el, 'hide');
266    triggerEvent(popup_el, 'tg:popupclose');
267  },
268  closeAll: function() {
269    while (TPopups._list.length) {
270      TPopups.close();
271    }
272  },
273  setPosition: function(popul_el) {
274    var popup_box = ge1('.js-popup_box', popul_el);
275    if (!popup_box) return;
276    getCoords(function(coords) {
277      var style      = window.getComputedStyle(popul_el);
278      var contTop    = parseInt(style.paddingTop);
279      var contBottom = parseInt(style.paddingBottom);
280      var marginMax  = popul_el.offsetHeight - contTop - contBottom - coords.elHeight;
281      var frameTop   = coords.frameTop || 0;
282      var deltaY     = (coords.clientHeight - coords.elHeight) / 2;
283      var marginTop  = deltaY - contTop - frameTop;
284      marginTop = Math.max(0, Math.min(marginMax, marginTop));
285      popup_box.style.marginTop = marginTop + 'px';
286    }, popup_box);
287  },
288  show: function(html, buttons, options) {
289    options = options || {};
290    var popup_el = newEl('div', 'tgme_popup_container js-popup_container tgme_popup_alert hide', '<div class="tgme_popup js-popup_box"><div class="tgme_popup_body"><div class="tgme_popup_text js-popup_text"></div><div class="tgme_popup_buttons js-popup_buttons"></div></div></div></div>');
291    var text_el = ge1('.js-popup_text', popup_el);
292    var buttons_el = ge1('.js-popup_buttons', popup_el);
293    setHtml(text_el, html);
294    var enterBtn = null, onEnterPress = null;
295    for (var i = 0; i < buttons.length; i++) {
296      var btn = buttons[i];
297      var button_el = newEl('div', 'tgme_popup_button' + (btn.close ? ' js-popup_close' : ''), btn.label);
298      btn.el = button_el;
299      buttons_el.appendChild(button_el);
300      if (btn.enter) {
301        enterBtn = button_el;
302      }
303      if (btn.onPress) {
304        addEvent(button_el, 'click', btn.onPress);
305      }
306    }
307    if (enterBtn) {
308      onEnterPress = function(e) {
309        if (e.keyCode == Keys.RETURN) {
310          e.stopImmediatePropagation();
311          e.preventDefault();
312          triggerEvent(enterBtn, 'click');
313        }
314      };
315      addEvent(document, 'keydown', onEnterPress);
316    }
317    var onPopupClose = function(e) {
318      if (enterBtn && onEnterPress) {
319        removeEvent(document, 'keydown', onEnterPress);
320      }
321      for (var i = 0; i < buttons.length; i++) {
322        var btn = buttons[i];
323        if (btn.onPress) {
324          removeEvent(btn.el, 'click', btn.onPress);
325        }
326      }
327      removeEvent(popup_el, 'tg:popupclose', onPopupClose);
328      removeEl(popup_el);
329    };
330    addEvent(popup_el, 'tg:popupclose', onPopupClose);
331    return TPopups.open(popup_el);
332  }
333};
334
335function showAlert(html, onClose) {
336  return TPopups.show(html, [{
337    label: l('WEB_CLOSE', 'Close'),
338    enter: true,
339    close: true
340  }]);
341}
342
343function showConfirm(html, onConfirm, confirm_btn) {
344  var popup_el = TPopups.show(html, [{
345    label: l('WEB_CANCEL', 'Cancel'),
346    close: true
347  }, {
348    label: confirm_btn || l('WEB_OK', 'OK'),
349    onPress: function() {
350      onConfirm && onConfirm(popup_el);
351      TPopups.close(popup_el);
352    },
353    enter: true
354  }]);
355  return popup_el;
356}
357
358function addEvent(el, event, handler) {
359  gec(el, function() {
360    var events = event.split(/\s+/);
361    for (var i = 0; i < events.length; i++) {
362      if (this.addEventListener) {
363        this.addEventListener(events[i], handler, false);
364      } else {
365        this.attachEvent('on' + events[i], handler);
366      }
367    }
368  });
369}
370function removeEvent(el, event, handler) {
371  gec(el, function() {
372    var events = event.split(/\s+/);
373    for (var i = 0; i < events.length; i++) {
374      if (this.removeEventListener) {
375        this.removeEventListener(events[i], handler);
376      } else {
377        this.detachEvent('on' + events[i], handler);
378      }
379    }
380  });
381}
382function triggerEvent(el, event_type, init_dict) {
383  gec(el, function() {
384    var event = new CustomEvent(event_type, init_dict);
385    this.dispatchEvent(event);
386  });
387}
388
389function geById(el_or_id) {
390  if (typeof el_or_id == 'string' || el_or_id instanceof String) {
391    return document.getElementById(el_or_id);
392  } else if (el_or_id instanceof HTMLElement) {
393    return el_or_id;
394  }
395  return null;
396}
397
398function gec(el, callback, context) {
399  var list = ge(el, context);
400  for (var i = 0, l = list.length; i < l; i++) {
401    var result = callback.call(list[i], list[i], i, list);
402    if (result === false) {
403      break;
404    }
405  }
406}
407function ge(el, context) {
408  var list = [];
409  if (typeof el === 'string') {
410    list = (ge1(context) || document).querySelectorAll(el);
411  } else if (el instanceof Node || el instanceof Window) {
412    list = [el];
413  } else if (Array.isArray(el)) {
414    list = el;
415  } else if (el) {
416    console.warn('unknown type of el', el);
417    return [el];
418  }
419  if (list instanceof NodeList) {
420    list = Array.prototype.slice.call(list);
421  }
422  return list;
423}
424function ge1(el, context) {
425  if (typeof el === 'string') {
426    return (ge1(context) || document).querySelector(el);
427  } else if (el instanceof Node || el instanceof Window) {
428    return el;
429  } else if (el instanceof NodeList) {
430    return el.item(0);
431  } else if (el instanceof Array) {
432    return el[0];
433  } else if (el) {
434    console.warn('unknown type of el', el);
435    return el;
436  }
437  return null;
438}
439function newEl(tag, cl, html, styles) {
440  var el = document.createElement((tag || 'DIV').toUpperCase());
441  if (cl) el.className = cl;
442  if (styles) {
443    for (var k in styles) {
444      el.style[k] = styles[k];
445    }
446  }
447  if (html) {
448    el.innerHTML = html;
449  }
450  return el;
451}
452function gpeByClass(el, cl) {
453  if (!el) return null;
454  while (el = el.parentNode) {
455    if (hasClass(el, cl)) break;
456  }
457  return el || null;
458}
459function elInBody(el) {
460  if (!el) return false;
461  while (el = el.parentNode) {
462    if (el === document.body) return true;
463  }
464  return false;
465}
466
467function getCoords(callback, el) {
468  var rect = {};
469  if (el = ge1(el)) {
470    rect = el.getBoundingClientRect();
471  }
472  var docEl = document.documentElement;
473  var coords = {};
474  if (inFullFrame()) {
475    PostMessage.send({event: 'get_coords'}, function(coords) {
476      coords.inFrame = true;
477      if (el) {
478        coords.elTop = rect.top + coords.frameTop;
479        coords.elBottom = rect.bottom + coords.frameTop;
480        coords.elLeft = rect.left + coords.frameLeft;
481        coords.elRight = rect.right + coords.frameLeft;
482        coords.elWidth = rect.width;
483        coords.elHeight = rect.height;
484      }
485      callback && callback(coords);
486    });
487    return;
488  } else {
489    if (el) {
490      coords.elTop = rect.top;
491      coords.elBottom = rect.bottom;
492      coords.elLeft = rect.left;
493      coords.elRight = rect.right;
494      coords.elWidth = rect.width;
495      coords.elHeight = rect.height;
496    }
497    coords.scrollTop = window.pageYOffset;
498    coords.scrollLeft = window.pageXOffset;
499    coords.clientWidth = docEl.clientWidth;
500    coords.clientHeight = docEl.clientHeight;
501    callback && callback(coords);
502  }
503}
504function scrollToY(y) {
505  if (inFullFrame()) {
506    PostMessage.send({event: 'scroll_to', y: y});
507  } else {
508    window.scrollTo(0, y);
509  }
510}
511
512function addClass(el, cl) {
513  gec(el, function() {
514    var cls = cl.split(/\s+/);
515    for (var i = 0; i < cls.length; i++) {
516      this.classList.add(cls[i]);
517    }
518  });
519}
520function removeClass(el, cl) {
521  gec(el, function() {
522    var cls = cl.split(/\s+/);
523    for (var i = 0; i < cls.length; i++) {
524      this.classList.remove(cls[i]);
525    }
526  });
527}
528function toggleClass(el, cl, add) {
529  gec(el, function() {
530    var cls = cl.split(/\s+/);
531    for (var i = 0; i < cls.length; i++) {
532      cl = cls[i];
533      var add_cl = (typeof add !== 'undefined') ? add : !hasClass(this, cl);
534      add_cl ? this.classList.add(cl) : this.classList.remove(cl);
535    }
536  });
537}
538function hasClass(el, cl) {
539  var item = ge1(el);
540  return (item && item.classList && item.classList.contains(cl));
541}
542function removeEl(el) {
543  gec(el, function() {
544    if (this && this.parentNode) {
545      this.parentNode.removeChild(this);
546    }
547  });
548}
549function getHtml(el, context) {
550  var item = ge1(el, context);
551  return item ? item.innerHTML : null;
552}
553function setHtml(el, html) {
554  gec(el, function() {
555    if (this) {
556      this.innerHTML = html;
557    }
558  });
559}
560function getAttr(el, attr) {
561  var item = ge1(el);
562  return item ? item.getAttribute(attr) : null;
563}
564function setAttr(el, attr, value) {
565  gec(el, function() {
566    if (this) {
567      this.setAttribute(attr, value);
568    }
569  });
570}
571
572function isLSEnabled() {
573  try {
574    return window.localStorage ? true : false;
575  } catch (e) {
576    return false;
577  }
578}
579function parseHeaders(headers) {
580  var headers_strs = headers.replace(/^\s+|\s+$/g, '').split(/[\r\n]+/);
581  var headers_arr = [];
582  for (var i = 0; i < headers_strs.length; i++) {
583    var header_str = headers_strs[i];
584    var parts = header_str.split(': ');
585    var name = parts.shift().toLowerCase();
586    var value = parts.join(': ');
587    headers_arr.push({name: name, value: value});
588  }
589  return headers_arr;
590}
591function setLS(xhr) {
592  if (!isLSEnabled()) return;
593  try {
594    var headers = parseHeaders(xhr.getAllResponseHeaders());
595    for (var i = 0; i < headers.length; i++) {
596      var header = headers[i];
597      if (header.name == 'x-set-local-storage') {
598        var arr = header.value.split('=');
599        var key = decodeURIComponent(arr[0]);
600        var val = decodeURIComponent(arr[1]);
601        if (val.length) {
602          localStorage.setItem(key, val);
603        } else {
604          localStorage.removeItem(key);
605        }
606      }
607    }
608  } catch (e) {}
609}
610function getLSString() {
611  if (!isLSEnabled()) return false;
612  var arr = [];
613  for (var i = 0; i < localStorage.length; i++) {
614    var key = localStorage.key(i);
615    arr.push(encodeURIComponent(key) + '=' + encodeURIComponent(localStorage[key]));
616  }
617  return arr.join('; ');
618}
619
620function getXHR() {
621  if (navigator.appName == "Microsoft Internet Explorer"){
622    return new ActiveXObject("Microsoft.XMLHTTP");
623  } else {
624    return new XMLHttpRequest();
625  }
626}
627
628function xhrRequest(href, postdata, onCallback, retry_delay) {
629  var xhr = getXHR(), type = 'GET', data = null, ls_header;
630  if (postdata !== false) {
631    type = 'POST';
632    var data_arr = [];
633    for (var field in postdata) {
634      data_arr.push(encodeURIComponent(field) + '=' + encodeURIComponent(postdata[field]));
635    }
636    data = data_arr.join('&');
637  }
638  xhr.open(type, href);
639  if (postdata !== false) {
640    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
641  }
642  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
643  if (ls_header = getLSString()) {
644    xhr.setRequestHeader('X-Local-Storage', ls_header);
645  }
646  xhr.onerror = function() {
647    if (xhr._retried) return;
648    xhr._retried = true;
649    retry_delay = retry_delay || 1000;
650    if (retry_delay > 60000) {
651      onCallback && onCallback('Server unavailable');
652      return;
653    }
654    setTimeout(function() {
655      xhrRequest(href, postdata, onCallback, retry_delay * 2);
656    }, retry_delay);
657  };
658  xhr.onreadystatechange = function() {
659    if (xhr.readyState == 4) {
660      setLS(xhr);
661      if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
662        try {
663          var result = JSON.parse(xhr.responseText);
664        } catch(e) {
665          var result = {};
666        }
667        if (xhr.status == 401) { // Unauthorized
668          TWidgetAuth.reload();
669          return;
670        }
671        if (result.error && result.flood_wait) {
672          console.log('flood_wait', result.flood_wait);
673          setTimeout(function() {
674            xhrRequest(href, postdata, onCallback);
675          }, result.flood_wait * 1000);
676          return;
677        }
678        onCallback && onCallback(null, result);
679      } else {
680        xhr.onerror();
681      }
682    }
683  };
684  xhr.withCredentials = true;
685  xhr.send(data);
686  return xhr;
687}
688
689function xhrUploadRequest(href, params, onCallback, onProgress) {
690  var xhr = getXHR(), data = new FormData(), ls_header;
691  xhr.open('POST', href, true);
692  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
693  if (ls_header = getLSString()) {
694    xhr.setRequestHeader('X-Local-Storage', ls_header);
695  }
696  xhr.upload.addEventListener('progress', function(event) {
697    if (event.lengthComputable) {
698      onProgress && onProgress(event.loaded, event.total);
699    }
700  });
701  xhr.onerror = function() {
702    onCallback && onCallback('Server unavailable');
703  };
704  xhr.onreadystatechange = function() {
705    if (xhr.readyState == 4) {
706      setLS(xhr);
707      if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
708        try {
709          var result = JSON.parse(xhr.responseText);
710        } catch(e) {
711          var result = {};
712        }
713        if (result.error && result.flood_wait) {
714          console.log('flood_wait', result.flood_wait);
715          setTimeout(function() {
716            xhrUploadRequest(href, params, onCallback, onProgress);
717          }, result.flood_wait * 1000);
718          return;
719        }
720        onCallback && onCallback(null, result);
721      } else {
722        xhr.onerror();
723      }
724    }
725  };
726  for (var k in params) {
727    var value = params[k];
728    if (value instanceof File) {
729      data.append(k, value, value.name);
730    } else {
731      data.append(k, value);
732    }
733  }
734  xhr.withCredentials = true;
735  xhr.send(data);
736  return xhr;
737}
738
739window.TWidgetAuth = {
740  init: function(options) {
741    options = options || {};
742    TWidgetAuth.options = options;
743  },
744  apiRequest: function(method, params, callback) {
745    var options = TWidgetAuth.options || {};
746    if (!options.api_url) {
747      console.warn('API url not found');
748      return null;
749    }
750    params.method = method;
751    return xhrRequest(options.api_url, params, callback);
752  },
753  uploadRequest: function(params, onCallback, onProgress) {
754    var options = TWidgetAuth.options || {};
755    if (!options.upload_url) {
756      console.warn('Upload url not found');
757      return null;
758    }
759    return xhrUploadRequest(options.upload_url, params, onCallback, onProgress);
760  },
761  logIn: function() {
762    var options = TWidgetAuth.options || {};
763    if (!options.bot_id) {
764      console.warn('Bot id not found');
765      return;
766    }
767    if (TWidgetAuth.isLoggedIn()) {
768      return;
769    }
770    Telegram.Login.auth({bot_id: options.bot_id, lang: 'en'}, function(user) {
771      if (user) {
772        xhrRequest('/auth', user, function(err, result) {
773          if (result.ok) {
774            TWidgetAuth.reload(result.host);
775          } else {
776            location.reload();
777          }
778        });
779      }
780    });
781  },
782  reload: function(host, callback) {
783    var xhr = getXHR(), data = null, ls_header;
784    var url = location.href;
785    if (host) {
786      var a = newEl('a');
787      a.href = url; a.hostname = host; url = a.href;
788    }
789    xhr.open('GET', url);
790    xhr.setRequestHeader('X-Requested-With', 'relogin');
791    if (ls_header = getLSString()) {
792      xhr.setRequestHeader('X-Local-Storage', ls_header);
793    }
794    xhr.onreadystatechange = function() {
795      if (xhr.readyState == 4) {
796        setLS(xhr);
797        if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
798          document.open();
799          document.write(xhr.responseText);
800          document.close();
801          callback && callback();
802        } else {
803          location.reload();
804        }
805      }
806    };
807    xhr.onerror = function() {
808      location.reload();
809    };
810    xhr.withCredentials = true;
811    xhr.send();
812  },
813  isLoggedIn: function() {
814    var options = TWidgetAuth.options || {};
815    return options && !options.unauth;
816  }
817};
818window.apiRequest = TWidgetAuth.apiRequest;
819window.uploadRequest = TWidgetAuth.uploadRequest;
820
821function loadImage(file, callback) {
822  var image = new Image();
823  image.onload = function() {
824    var w = image.naturalWidth;
825    var h = image.naturalHeight;
826    callback && callback(null, {
827      url:    image.src,
828      width:  w,
829      height: h,
830      image:  image
831    });
832  };
833  image.onerror = function() {
834    callback && callback('LOAD_FAILED');
835  };
836  image.src = URL.createObjectURL(file);
837}
838
839function initWidgetFrame(options) {
840  TWidget.options = options || {};
841  if (window.devicePixelRatio >= 2) {
842    addClass(document.body, 'r2x');
843  }
844  if (TWidget.options.auto_height ||
845      TWidget.options.auto_width) {
846    addEvent(window, 'resize', checkFrameSize);
847    checkFrameSize();
848  }
849  addEvent(window, 'message', PostMessage.onMessage);
850  addEvent(window, 'focus blur', function() {
851    triggerEvent(window, 'tg:focuschange');
852  });
853  PostMessage.send({event: 'ready'});
854}
855
856var frameLastHeight = null,
857    frameLastWidth = null,
858    frameWasVisible = false;
859function checkFrameSize() {
860  var height, width, style;
861  if (document.body) {
862    if (window.getComputedStyle) {
863      style = window.getComputedStyle(document.body);
864      height = style.height;
865      if (height.substr(-2) == 'px') {
866        height = height.slice(0, -2);
867      }
868      width = style.width;
869      if (width.substr(-2) == 'px') {
870        width = width.slice(0, -2);
871      }
872    } else {
873      height = document.body.offsetHeight;
874      width = document.body.offsetWidth;
875    }
876    var data = {event: 'resize'}, resized = false;
877    if (TWidget.options.auto_height) {
878      height = Math.ceil(height);
879      if (height != frameLastHeight) {
880        frameLastHeight = height;
881        data.height = height;
882        resized = true;
883      }
884    }
885    if (TWidget.options.auto_width) {
886      width = Math.ceil(width);
887      if (width != frameLastWidth) {
888        frameLastWidth = width;
889        data.width = width;
890        resized = true;
891      }
892    }
893    if (resized) {
894      PostMessage.send(data);
895    }
896  }
897  requestAnimationFrame(checkFrameSize);
898}
899
900
901(function() {
902  var ua = navigator.userAgent.toLowerCase();
903  var browser = {
904    opera: (/opera/i.test(ua) || /opr/i.test(ua)),
905    msie: (/msie/i.test(ua) && !/opera/i.test(ua) || /trident\//i.test(ua)) || /edge/i.test(ua),
906    msie_edge: (/edge/i.test(ua) && !/opera/i.test(ua)),
907    mozilla: /firefox/i.test(ua),
908    chrome: /chrome/i.test(ua) && !/edge/i.test(ua),
909    safari: (!(/chrome/i.test(ua)) && /webkit|safari|khtml/i.test(ua)),
910    iphone: /iphone/i.test(ua),
911    ipod: /ipod/i.test(ua),
912    ipad: /ipad/i.test(ua),
913    android: /android/i.test(ua),
914    mobile: /iphone|ipod|ipad|opera mini|opera mobi|iemobile|android/i.test(ua),
915    safari_mobile: /iphone|ipod|ipad/i.test(ua),
916    opera_mobile: /opera mini|opera mobi/i.test(ua),
917    opera_mini: /opera mini/i.test(ua),
918    mac: /mac/i.test(ua),
919  };
920  var TBaseUrl = window.TBaseUrl || '//telegram.org/';
921
922  function formatDateTime(datetime) {
923    var date = new Date(datetime);
924    var cur_date = new Date();
925    if (cur_date.getFullYear() == date.getFullYear() &&
926        cur_date.getMonth() == date.getMonth() &&
927        cur_date.getDate() == date.getDate()) {
928      return formatTime(datetime);
929    }
930    return formatDate(datetime);
931  }
932
933  function formatDate(datetime) {
934    var date = new Date(datetime);
935    var cur_date = new Date();
936    var j = date.getDate();
937    var M = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][date.getMonth()];
938    var Y = date.getFullYear();
939    if (cur_date.getFullYear() == date.getFullYear()) {
940      return M + ' ' + j;
941    }
942    return M + ' ' + j + ', ' + Y;
943  }
944
945  function formatTime(datetime) {
946    var date = new Date(datetime);
947    var H = date.getHours();
948    if (H < 10) H = '0' + H;
949    var i = date.getMinutes();
950    if (i < 10) i = '0' + i;
951    return H + ':' + i;
952  }
953
954  function formatDuration(duration) {
955    duration = Math.floor(duration);
956    duration = Math.max(0, duration);
957    var duration_str = '';
958    if (duration >= 3600) {
959      var hours = Math.floor(duration / 3600);
960      duration_str += hours + ':';
961      var minutes = Math.floor((duration % 3600) / 60);
962      if (minutes < 10) minutes = '0' + minutes;
963    } else {
964      var minutes = Math.floor(duration / 60);
965    }
966    duration_str += minutes + ':';
967    var seconds = duration % 60;
968    if (seconds < 10) seconds = '0' + seconds;
969    duration_str += seconds;
970    return duration_str;
971  }
972
973  function doesSupportEmoji() {
974    var context, smile, canvas = document.createElement('canvas');
975    if (!canvas.getContext) return false;
976    context = canvas.getContext('2d');
977    if (typeof context.fillText != 'function') return false;
978    smile = '#' + String.fromCharCode(65039) + String.fromCharCode(8419);
979    context.textBaseline = 'top';
980    context.font = '32px Arial';
981    context.fillText(smile, 0, 0);
982    if (context.getImageData(16, 16, 1, 1).data[0] === 0) return false;
983    var div = document.createElement('div');
984    div.style.position = 'absolute';
985    div.style.overflow = 'hidden';
986    div.style.top = '-1000px';
987    var span = document.createElement('span');
988    div.style.fontSize = '16px';
989    span.innerHTML = smile;
990    div.appendChild(span);
991    document.body.insertBefore(div, document.body.firstChild);
992    var width = span.offsetWidth;
993    document.body.removeChild(div);
994    if (width < 18) return false;
995    return true;
996  }
997
998  function cloneArr(arrLike) {
999    return Array.prototype.slice.apply(arrLike);
1000  }
1001
1002  var loadedLibs = {};
1003  function loadLib(file, callback) {
1004    if (!loadedLibs[file]) {
1005      loadedLibs[file] = {
1006        loaded: null,
1007        callbacks: [callback]
1008      };
1009      var script = document.createElement('script');
1010      script.type = 'text/javascript';
1011      script.async = true;
1012      script.src = file;
1013      script.onerror = function() {
1014        loadedLibs[file].loaded = false;
1015        applyCallbacks(loadedLibs[file].callbacks, loadedLibs[file].loaded);
1016      }
1017      script.onload = function() {
1018        loadedLibs[file].loaded = true;
1019        applyCallbacks(loadedLibs[file].callbacks, loadedLibs[file].loaded);
1020      }
1021      var head = document.getElementsByTagName('head')[0];
1022      head.appendChild(script);
1023      return script;
1024    } else if (loadedLibs[file].loaded === null) {
1025      loadedLibs[file].callbacks.push(callback);
1026    } else {
1027      callback(loadedLibs[file].loaded);
1028    }
1029  };
1030
1031  var webpNativeSupport = null, webpFallbackSupport = null, webpImage = null, webpCallbacks = [];
1032  function applyCallbacks(callbacks) {
1033    var args = cloneArr(arguments); args.shift();
1034    for (var i = 0; i < callbacks.length; i++) {
1035      callbacks[i].apply(null, args);
1036    }
1037  }
1038  function doesSupportWebp(callback) {
1039    if (webpFallbackSupport !== null) {
1040      callback(webpNativeSupport, webpFallbackSupport);
1041    } else {
1042      webpCallbacks.push(callback);
1043      if (!webpImage) {
1044        webpImage = new Image();
1045        webpImage.onerror = webpImage.onload = function() {
1046          if (this.width === 2 && this.height === 1) {
1047            webpNativeSupport = true;
1048            webpFallbackSupport = false;
1049            applyCallbacks(webpCallbacks, webpNativeSupport, webpFallbackSupport);
1050          } else {
1051            webpNativeSupport = false;
1052            var script = document.createElement('script');
1053            script.type = 'text/javascript';
1054            script.async = true;
1055            script.src = TBaseUrl + 'js/libwebp-0.2.0.js';
1056            script.onerror = function() {
1057              webpFallbackSupport = false;
1058              applyCallbacks(webpCallbacks, webpNativeSupport, webpFallbackSupport);
1059            }
1060            script.onload = function() {
1061              webpFallbackSupport = true;
1062              applyCallbacks(webpCallbacks, webpNativeSupport, webpFallbackSupport);
1063            }
1064            var head = document.getElementsByTagName('head')[0];
1065            head.appendChild(script);
1066          }
1067        }
1068        webpImage.src = 'data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56
1068QAAAAA==';
1069      }
1070    }
1071  }
1072
1073  function getPngDataUrlFromWebp(data) {
1074    var decoder = new WebPDecoder();
1075    var config = decoder.WebPDecoderConfig;
1076    var buffer = config.j || config.output;
1077    var bitstream = config.input;
1078    if (!decoder.WebPInitDecoderConfig(config)) {
1079      throw new Error('[webpjs] Library version mismatch!');
1080    }
1081    var StatusCode = decoder.VP8StatusCode;
1082    status = decoder.WebPGetFeatures(data, data.length, bitstream);
1083    if (status != (StatusCode.VP8_STATUS_OK || 0)) {
1084      throw new Error('[webpjs] status error');
1085    }
1086    var mode = decoder.WEBP_CSP_MODE;
1087    buffer.colorspace = mode.MODE_RGBA;
1088    buffer.J = 4;
1089    try {
1090      status = decoder.WebPDecode(data, data.length, config);
1091    } catch (e) {
1092      status = e
1093    }
1094    var ok = (status == 0);
1095    if (!ok) {
1096      throw new Error('[webpjs] decoding failed');
1097    }
1098    var bitmap = buffer.c.RGBA.ma;
1099    if (!bitmap) {
1100      throw new Error('[webpjs] bitmap error');
1101    }
1102    var biHeight = buffer.height;
1103    var biWidth = buffer.width;
1104    var canvas = document.createElement('canvas');
1105    var context = canvas.getContext('2d');
1106    canvas.height = biHeight;
1107    canvas.width = biWidth;
1108    var output = context.createImageData(canvas.width, canvas.height);
1109    var outputData = output.data;
1110    for (var h = 0; h < biHeight; h++) {
1111      for (var w = 0; w < biWidth; w++) {
1112        outputData[0 + w * 4 + (biWidth * 4) * h] = bitmap[1 + w * 4 + (biWidth * 4) * h];
1113        outputData[1 + w * 4 + (biWidth * 4) * h] = bitmap[2 + w * 4 + (biWidth * 4) * h];
1114        outputData[2 + w * 4 + (biWidth * 4) * h] = bitmap[3 + w * 4 + (biWidth * 4) * h];
1115        outputData[3 + w * 4 + (biWidth * 4) * h] = bitmap[0 + w * 4 + (biWidth * 4) * h];
1116      }
1117    }
1118    context.putImageData(output, 0, 0);
1119    return canvas.toDataURL('image/png');
1120  }
1121
1122  function proccessWebpImage(imgEl, failed_callback, success_callback) {
1123    var imgEl = geById(imgEl);
1124    if (!imgEl || imgEl.__inited) return;
1125    imgEl.__inited = true;
1126    failed_callback = failed_callback || function(){};
1127    success_callback = success_callback || function(){};
1128    doesSupportWebp(function(nativeSupport, fallbackSupport) {
1129      if (nativeSupport) {
1130        success_callback();
1131        return;
1132      } else if (!fallbackSupport) {
1133        failed_callback();
1134        return;
1135      }
1136      if (hasClass(imgEl, 'webp_sticker_done')) {
1137        success_callback();
1138        return;
1139      }
1140      var isImage, src;
1141      if (imgEl.tagName && imgEl.tagName.toUpperCase() == 'IMG' && imgEl.src) {
1142        isImage = true;
1143        src = imgEl.src;
1144      } else {
1145        isImage = false;
1146        var bgImage;
1147        if (window.getComputedStyle) {
1148          bgImage = window.getComputedStyle(imgEl).backgroundImage;
1149        } else {
1150          bgImage = imgEl.style && imgEl.style.backgroundImage;
1151        }
1152        src = bgImage.slice(4, -1).replace(/["|']/g, '');
1153      }
1154      if (!src) {
1155        failed_callback();
1156        return;
1157      }
1158      var xhr = getXHR();
1159      xhr.open('get', src);
1160      if (xhr.overrideMimeType) {
1161        xhr.overrideMimeType('text/plain; charset=x-user-defined');
1162      } else {
1163        xhr.setRequestHeader('Accept-Charset', 'x-user-defined');
1164      }
1165      xhr.onreadystatechange = function() {
1166        if (xhr.readyState == 4) {
1167          if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
1168            var rlen = xhr.responseText.length, uarr = new Uint8Array(rlen);
1169            for (var i = 0; i < rlen; i++) {
1170              uarr[i] = xhr.responseText.charCodeAt(i);
1171            }
1172            try {
1173              var src = getPngDataUrlFromWebp(uarr);
1174              if (isImage) {
1175                imgEl.src = src;
1176              } else {
1177                imgEl.style.backgroundImage = "url('" + src + "')";
1178              }
1179              addClass(imgEl, 'webp_sticker_done');
1180              success_callback();
1181            } catch(e) {
1182              failed_callback();
1183            }
1184          } else {
1185            failed_callback();
1186          }
1187        }
1188      };
1189      xhr.send(null);
1190    });
1191  }
1192
1193  function checkVideo(el, error_callback) {
1194    var timeout, eventAdded;
1195    if (!eventAdded) {
1196      function destroyCheck() {
1197        clearTimeout(timeout);
1198        removeEvent(el, 'canplay', onCanPlay);
1199        removeEvent(el, 'error', onError);
1200      }
1201      function onCanPlay() {
1202        destroyCheck();
1203      }
1204      function onError() {
1205        destroyCheck();
1206        error_callback();
1207      }
1208      eventAdded = true;
1209      addEvent(el, 'canplay', onCanPlay);
1210      addEvent(el, 'error', onError);
1211    }
1212    if (el.readyState >= 2) {
1213      destroyCheck();
1214    } else {
1215      timeout = setTimeout(function() {
1216        checkVideo(el, error_callback);
1217      }, 50);
1218    }
1219  }
1220
1221  window.TPost = {
1222    init: function(postEl, options) {
1223      postEl = geById(postEl);
1224      options = options || {};
1225      if (!postEl || postEl.__inited) return;
1226      postEl.__inited = true;
1227      gec('time[datetime]', function() {
1228        var datetime = this.getAttribute('datetime');
1229        if (datetime) {
1230          if (hasClass(this, 'datetime')) {
1231            this.innerHTML = formatDate(datetime) + ' at ' + formatTime(datetime);
1232          } else if (hasClass(this, 'time')) {
1233            this.innerHTML = formatTime(datetime);
1234          } else {
1235            this.innerHTML = formatDateTime(datetime);
1236          }
1237        }
1238      }, postEl);
1239      gec('.js-message_footer.compact', function() {
1240        var timeEl = ge1('time[datetime]', this)
1241          , textEl = this.previousElementSibling;
1242        if (textEl && !textEl.__inited && hasClass(textEl, 'js-message_text')) {
1243          var text_rect = textEl.getBoundingClientRect();
1244          var tnode = textEl.firstChild;
1245          while (tnode && tnode.nodeType == tnode.ELEMENT_NODE) {
1246            tnode = tnode.firstChild;
1247          }
1248          if (tnode) {
1249            var r = document.createRange();
1250            r.setStart(tnode, 0);
1251            r.setEnd(tnode, 1);
1252            var char_rect = r.getBoundingClientRect();
1253            textEl.__inited = true;
1254            if (Math.abs(char_rect.right - text_rect.right) > 3) {
1255              var infoEl = ge1('.js-message_info', this);
1256              if (infoEl) {
1257                var shadowEl = document.createElement('span');
1258                shadowEl.style.display = 'inline-block';
1259                shadowEl.style.width = infoEl.offsetWidth + 'px';
1260                textEl.appendChild(shadowEl);
1261                addClass(textEl, 'before_footer');
1262              }
1263            }
1264          }
1265        }
1266      }, postEl);
1267      gec('.js-message_video_player', function() {
1268        TVideo.init(this);
1269      }, postEl);
1270      gec('.js-message_photo', function() {
1271        TPhoto.init(this);
1272      }, postEl);
1273      gec('.js-message_grouped_wrap', function() {
1274        TGrouped.init(this);
1275      }, postEl);
1276      gec('.js-message_roundvideo_player', function() {
1277        TRoundVideo.init(this);
1278      }, postEl);
1279      gec('.js-message_voice_player', function() {
1280        TVoice.init(this);
1281      }, postEl);
1282      gec('.js-sticker_image', function() {
1283        TSticker.init(this, function() {
1284          addClass(postEl, 'media_not_supported');
1285          removeClass(postEl, 'no_bubble');
1286        });
1287      }, postEl);
1288      gec('.js-sticker_thumb', function() {
1289        TSticker.init(this);
1290      }, postEl);
1291      gec('.js-tgsticker_image', function() {
1292        if (options.tgs_workers_limit) {
1293          RLottie.WORKERS_LIMIT = options.tgs_workers_limit;
1294        } else if (options.frame) {
1295          RLottie.WORKERS_LIMIT = 1;
1296        }
1297        RLottie.init(this, {
1298          playOnce: this.hasAttribute('data-play-once')
1299        });
1300      }, postEl);
1301    },
1302    view: function(postEl) {
1303      postEl = geById(postEl);
1304      if (!postEl) return;
1305      var view = postEl.getAttribute('data-view');
1306      if (view) {
1307        var xhr = getXHR();
1308        xhr.open('get', '/v/?views=' + encodeURIComponent(view));
1309        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
1310        xhr.send(null);
1311      }
1312    }
1313  };
1314
1315  var TPhoto = window.TPhoto = {
1316    init: function(photoEl) {
1317      photoEl = geById(photoEl);
1318      if (!photoEl || photoEl.__inited) return;
1319      photoEl.__inited = true;
1320      var inGroup = hasClass(photoEl, 'grouped_media_wrap')
1321        , opened
1322        , overTo;
1323      if (inGroup) {
1324        addEvent(photoEl, 'click', function togglePhoto(e) {
1325          if (e.metaKey || e.ctrlKey) return true;
1326          e.stopPropagation();
1327          if (!photoEl) return true;
1328          if (opened) {
1329            opened = false;
1330            removeClass(photoEl, 'active');
1331            overTo = setTimeout(function() {
1332              removeClass(photoEl, 'over');
1333            }, 200);
1334          } else {
1335            opened = true;
1336            clearTimeout(overTo);
1337            addClass(photoEl, 'over active');
1338          }
1339          e.preventDefault();
1340          return false;
1341        });
1342      }
1343    }
1344  };
1345
1346  var TVideo = window.TVideo = {
1347    init: function(playerEl) {
1348      playerEl = geById(playerEl);
1349      if (!playerEl || playerEl.__inited) return;
1350      playerEl.__inited = true;
1351      var videoEl = ge1('.js-message_video', playerEl)
1352        , videoBluredEl = ge1('.js-message_video_blured', playerEl)
1353        , playEl = ge1('.js-message_video_play', playerEl)
1354        , durationEl = ge1('.js-message_video_duration', playerEl)
1355        , inGroup = hasClass(playerEl, 'grouped_media_wrap')
1356        , looped
1357        , overTo;
1358      if (!videoEl) return;
1359
1360      looped = videoEl.hasAttribute('loop');
1361      if (inGroup) {
1362        addEvent(playerEl, 'click', function videoToggleInGroup(e) {
1363          if (e.metaKey || e.ctrlKey) return true;
1364          if (hasClass(e.target, 'message_media_view_in_telegram')) return true;
1365          e.stopPropagation();
1366          if (!playerEl) return true;
1367          if (hasClass(playerEl, 'active')) {
1368            removeClass(playerEl, 'active');
1369            overTo = setTimeout(function() {
1370              removeClass(playerEl, 'over');
1371            }, 200);
1372          } else {
1373            clearTimeout(overTo);
1374            addClass(playerEl, 'over active');
1375          }
1376          e.preventDefault();
1377          return false;
1378        });
1379      }
1380      if (videoEl.hasAttribute('playsinline')) {
1381        enableInlineVideo(videoEl);
1382        if (videoBluredEl) {
1383          enableInlineVideo(videoBluredEl);
1384        }
1385      }
1386      function fixControls() {
1387        if (videoEl.controls) videoEl.controls = false;
1388      }
1389      var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
1390      if (MutationObserver) {
1391        (new MutationObserver(fixControls)).observe(videoEl, {attributes: true});
1392      }
1393
1394      checkVideo(videoEl, function() {
1395        addClass(playerEl, 'not_supported');
1396      });
1397      addEvent(videoEl, 'play', function() {
1398        fixControls();
1399        addClass(playerEl, 'playing');
1400        if (inGroup) {
1401          clearTimeout(overTo);
1402          addClass(playerEl, 'over active');
1403        }
1404        if (videoBluredEl) {
1405          videoBluredEl.currentTime = videoEl.currentTime;
1406          if (!browser.mobile) {
1407            videoBluredEl.play();
1408          }
1409        }
1410        if (!looped) {
1411          triggerEvent(videoEl, 'tg:play', {bubbles: true});
1412        }
1413      });
1414      addEvent(document, 'tg:play', function(e) {
1415        if (e.target === videoEl || looped) return true;
1416        if (!videoEl.paused) {
1417          videoEl.pause();
1418          if (videoBluredEl) {
1419            videoBluredEl.pause();
1420          }
1421        }
1422      });
1423      addEvent(videoEl, 'pause', function() {
1424        fixControls();
1425        removeClass(playerEl, 'playing');
1426        if (inGroup) {
1427          removeClass(playerEl, 'active');
1428          overTo = setTimeout(function() {
1429            removeClass(playerEl, 'over');
1430          }, 200);
1431        }
1432        if (videoBluredEl) {
1433          videoBluredEl.currentTime = videoEl.currentTime;
1434          videoBluredEl.pause();
1435        }
1436        if (looped) {
1437          videoEl.play();
1438        }
1439      });
1440      addEvent(videoEl, 'timeupdate', function(e) {
1441        fixControls();
1442        if (videoBluredEl && videoBluredEl.currentTime != videoEl.currentTime) {
1443          videoBluredEl.currentTime = videoEl.currentTime;
1444        }
1445        if (durationEl && videoEl.duration) {
1446          var duration = Math.floor(videoEl.duration);
1447          durationEl.innerHTML = formatDuration(duration - videoEl.currentTime);
1448        }
1449      });
1450      addEvent(videoEl, 'ended load', function(e) {
1451        fixControls();
1452        if (durationEl && videoEl.duration) {
1453          var duration = Math.floor(videoEl.duration);
1454          durationEl.innerHTML = formatDuration(duration);
1455        }
1456      });
1457      if (looped) {
1458        addEvent(document, 'touchstart', function(){ videoEl.play(); });
1459      } else {
1460        addClass(playerEl, 'ready');
1461      }
1462      if (playEl) {
1463        addEvent(playEl, 'click', function toggleVideo(e) {
1464          if (e.metaKey || e.ctrlKey) return true;
1465          e.stopPropagation();
1466          if (!videoEl) return true;
1467          if (videoEl.paused) {
1468            videoEl.play();
1469            if (videoBluredEl) {
1470              videoBluredEl.play();
1471            }
1472          } else {
1473            videoEl.pause();
1474            if (videoBluredEl) {
1475              videoBluredEl.pause();
1476            }
1477          }
1478          e.preventDefault();
1479          return false;
1480        });
1481      }
1482    }
1483  };
1484
1485  var TGrouped = window.TGrouped = {
1486    init: function(groupedWrapEl) {
1487      groupedWrapEl = geById(groupedWrapEl);
1488      if (!groupedWrapEl || groupedWrapEl.__inited) return;
1489      groupedWrapEl.__inited = true;
1490      var groupedEl = ge1('.js-message_grouped', groupedWrapEl)
1491        , groupedLayerEl = ge1('.js-message_grouped_layer', groupedEl)
1492        , thumbsEl = groupedLayerEl.children
1493        , margin_w = +groupedWrapEl.getAttribute('data-margin-w') || 2
1494        , margin_h = +groupedWrapEl.getAttribute('data-margin-h') || 2;
1495      if (!thumbsEl.length) {
1496        return false;
1497      }
1498
1499      addEvent(window, 'resize', function() {
1500        if (groupedLayerEl.offsetWidth != groupedEl.offsetWidth) {
1501          recalcGrouped(groupedWrapEl.offsetWidth);
1502        }
1503      });
1504      recalcGrouped(groupedWrapEl.offsetWidth);
1505
1506      function updateThumb(thumbEl, x, y, width, height, th_width, th_height, position) {
1507        if (!thumbEl) return;
1508        var t = false, r = false, b = false, l = false;
1509        for (var i = 0; i < position.length; i++) {
1510          if      (position[i] == 't') t = true;
1511          else if (position[i] == 'r') r = true;
1512          else if (position[i] == 'b') b = true;
1513          else if (position[i] == 'l') l = true;
1514        }
1515        thumbEl.style.left = x + 'px';
1516        thumbEl.style.top = y + 'px';
1517        thumbEl.style.width = width + 'px';
1518        thumbEl.style.height = height + 'px';
1519        thumbEl.style.marginRight = (!r ? margin_w : 0) + 'px';
1520        thumbEl.style.marginBottom = (!b ? margin_h : 0) + 'px';
1521
1522        var th_ratio = th_width / th_height;
1523        var ratio    = +thumbEl.getAttribute('data-ratio') || 1.0;
1524        var mediaEl  = ge1('.grouped_media', thumbEl);
1525        var helperEl = ge1('.grouped_media_helper', thumbEl);
1526
1527        if (mediaEl) {
1528          var media_height = Math.ceil(width / ratio);
1529          var media_tb = height - media_height;
1530          if (media_tb < 0) {
1531            var media_t = Math.floor(media_tb / 2);
1532            var media_b = media_tb - media_t;
1533            mediaEl.style.left = 0;
1534            mediaEl.style.right = 0;
1535            mediaEl.style.top = media_t + 'px';
1536            mediaEl.style.bottom = media_b + 'px';
1537          } else {
1538            var media_width = Math.ceil(height * ratio);
1539            var media_lr = width - media_width;
1540            var media_l = Math.floor(media_lr / 2);
1541            var media_r = media_lr - media_l;
1542            mediaEl.style.top = 0;
1543            mediaEl.style.bottom = 0;
1544            mediaEl.style.left = media_l + 'px';
1545            mediaEl.style.right = media_r + 'px';
1546          }
1547        }
1548        if (helperEl) {
1549          var helper_height = Math.floor(th_width / ratio);
1550          var helper_tb = th_height - helper_height;
1551          if (helper_tb > 0) {
1552            var helper_t = Math.floor(helper_tb / 2);
1553            var helper_b = helper_tb - helper_t;
1554            helperEl.style.left = 0;
1555            helperEl.style.right = 0;
1556            helperEl.style.top = helper_t + 'px';
1557            helperEl.style.bottom = helper_b + 'px';
1558          } else {
1559            var helper_width = Math.ceil(th_height * ratio);
1560            var helper_lr = th_width - helper_width;
1561            var helper_l = Math.floor(helper_lr / 2);
1562            var helper_r = helper_lr - helper_l;
1563            helperEl.style.top = 0;
1564            helperEl.style.bottom = 0;
1565            helperEl.style.left = helper_l + 'px';
1566            helperEl.style.right = helper_r + 'px';
1567          }
1568        }
1569      }
1570
1571      function recalcGrouped(max_w) {
1572        var orients = '';
1573        var ratios = [];
1574        var cnt = thumbsEl.length;
1575
1576        var ratios_sum = 0;
1577        for (var i = 0; i < thumbsEl.length; i++) {
1578          var thumbEl = thumbsEl[i];
1579          var ratio = +thumbEl.getAttribute('data-ratio') || 1.0;
1580          orients += ratio > 1.2 ? 'w' : (ratio < 0.8 ? 'n' : 'q');
1581          ratios_sum += ratio;
1582          ratios.push(ratio);
1583        }
1584
1585        var avg_ratio = ratios.length ? ratios_sum / ratios.length : 1.0;
1586        var max_ratio = 0.75;
1587        var min_w     = 75;
1588        var max_h     = max_w / max_ratio;
1589
1590        var w, h, w0, w1, w2, h0, h1, h2, x, y, x1, x2, y1, y2,
1591            th_width, th_height;
1592
1593        if (cnt == 2) {
1594          if (orients == 'ww' &&
1595              avg_ratio > 1.4 * max_ratio &&
1596              (ratios[1] - ratios[0]) < 0.2) {
1597            // 2 wide pics are one below the other
1598            w = max_w;
1599            h = Math.min(w / ratios[0], Math.min(w / ratios[1], (max_h - margin_h) / 2.0));
1600            th_width  = max_w;
1601            th_height = 2 * h + margin_h;
1602            h0 = Math.floor(h);
1603            h1 = th_height - h0 - margin_h;
1604            y = h0 + margin_h;
1605            updateThumb(thumbsEl[0], 0, 0, w, h0, th_width, th_height, 'trl');
1606            updateThumb(thumbsEl[1], 0, y, w, h1, th_width, th_height, 'rbl');
1607          }
1608          else if (orients == 'ww' || orients == 'qq') {
1609            // 2 equal width pics
1610            w = (max_w - margin_w) / 2;
1611            h = Math.floor(Math.min(max_h, Math.min(w / ratios[0], w / ratios[1])));
1612            th_width  = max_w;
1613            th_height = h;
1614            w0 = Math.floor(w);
1615            w1 = max_w - w0 - margin_w;
1616            x = w0 + margin_w;
1617            updateThumb(thumbsEl[0], 0, 0, w0, h, th_width, th_height, 'tbl');
1618            updateThumb(thumbsEl[1], x, 0, w1, h, th_width, th_height, 'trb');
1619          }
1620          else {
1621            // so, we have one wide and one not wide (square or narrow)
1622            w0 = Math.floor((max_w - margin_w) / ratios[1] / (1 / ratios[0] + 1 / ratios[1]));
1623            w1 = max_w - w0 - margin_w;
1624            h = Math.floor(Math.min(max_h, Math.min(w0 / ratios[0], w1 / ratios[1])));
1625            th_width  = max_w;
1626            th_height = h;
1627            x = w0 + margin_w;
1628            updateThumb(thumbsEl[0], 0, 0, w0, h, th_width, th_height, 'tbl');
1629            updateThumb(thumbsEl[1], x, 0, w1, h, th_width, th_height, 'trb');
1630          }
1631        }
1632        else if (cnt == 3) {
1633          if (orients[0] == 'n') {
1634            // 2nd and 3rd photos are on the right part
1635            h0 = max_h;
1636            h2 = Math.floor(Math.min((max_h - margin_h) * 0.5, ratios[1] * (max_h - margin_h) / (ratios[2] + ratios[1])));
1637            h1 = max_h - h2 - margin_h;
1638            w1 = Math.floor(Math.max(min_w, Math.min((max_w - margin_w) * 0.5, Math.min(h2 * ratios[2], h1 * ratios[1]))));
1639            w0 = Math.min(Math.floor(h0 * ratios[0]), (max_w - w1 - margin_w));
1640            th_width  = w0 + w1 + margin_w;
1641            th_height = max_h;
1642            x = w0 + margin_w;
1643            y = h1 + margin_h;
1644            updateThumb(thumbsEl[0], 0, 0, w0, h0, th_width, th_height, 'tbl');
1645            updateThumb(thumbsEl[1], x, 0, w1, h1, th_width, th_height, 'tr');
1646            updateThumb(thumbsEl[2], x, y, w1, h2, th_width, th_height, 'rb');
1647          }
1648          else {
1649            // 2nd and 3rd photos are on the next line
1650            w0 = max_w;
1651            h0 = Math.floor(Math.min(w0 / ratios[0], (max_h - margin_h) * 0.66));
1652            w = (max_w - margin_w) / 2;
1653            h = Math.floor(Math.min(max_h - h0 - margin_h, Math.min(w / ratios[1], w / ratios[2])));
1654            th_width  = max_w;
1655            th_height = h0 + h + margin_h;
1656            w1 = Math.floor(w);
1657            w2 = max_w - w1 - margin_w;
1658            x = w1 + margin_w;
1659            y = h0 + margin_h;
1660            updateThumb(thumbsEl[0], 0, 0, w0, h0, th_width, th_height, 'tlr');
1661            updateThumb(thumbsEl[1], 0, y, w1, h, th_width, th_height, 'bl');
1662            updateThumb(thumbsEl[2], x, y, w2, h, th_width, th_height, 'rb');
1663          }
1664        }
1665        else if (cnt == 4) {
1666          if (orients == 'wwww' || orients[0] == 'w') {
1667            // 2nd, 3rd and 4th photos are on the next line
1668            w = max_w;
1669            h0 = Math.floor(Math.min(w / ratios[0], (max_h - margin_h) * 0.66));
1670            h = (max_w - 2 * margin_w) / (ratios[1] + ratios[2] + ratios[3]);
1671            w0 = Math.floor(Math.max(min_w, Math.min((max_w - 2 * margin_w) * 0.4, h * ratios[1])));
1672            w2 = Math.floor(Math.max(min_w, Math.min((max_w - 2 * margin_w) * 0.33, h * ratios[3])));
1673            w1 = w - w0 - w2 - 2 * margin_w;
1674            h = Math.floor(Math.min(max_h - h0 - margin_h, h));
1675            th_width  = max_w;
1676            th_height = h0 + h + margin_h;
1677            y = h0 + margin_h;
1678            x1 = w0 + margin_w;
1679            x2 = x1 + w1 + margin_w;
1680            updateThumb(thumbsEl[0], 0, 0, w, h0, th_width, th_height, 'tlr');
1681            updateThumb(thumbsEl[1], 0, y, w0, h, th_width, th_height, 'bl');
1682            updateThumb(thumbsEl[2], x1, y, w1, h, th_width, th_height, 'b');
1683            updateThumb(thumbsEl[3], x2, y, w2, h, th_width, th_height, 'rb');
1684          }
1685          else {
1686            // 2nd, 3rd and 4th photos are on the right part
1687            h = max_h;
1688            w0 = Math.floor(Math.min(h * ratios[0], (max_w - margin_w) * 0.66));
1689            w = Math.floor((max_h - 2 * margin_h) / (1 / ratios[1] + 1 / ratios[2] + 1 / ratios[3]));
1690            h0 = Math.floor(w / ratios[1]);
1691            h2 = Math.floor(w / ratios[3]);
1692            h1 = h - h0 - h2 - 2 * margin_h;
1693            w = Math.max(min_w, Math.min(max_w - w0 - margin_w, w));
1694            th_width  = w0 + w + margin_w;
1695            th_height = max_h;
1696            x = w0 + margin_w;
1697            y1 = h0 + margin_h;
1698            y2 = y1 + h1 + margin_h;
1699            updateThumb(thumbsEl[0], 0, 0, w0, h, th_width, th_height, 'tbl');
1700            updateThumb(thumbsEl[1], x, 0, w, h0, th_width, th_height, 'tr');
1701            updateThumb(thumbsEl[2], x, y1, w, h1, th_width, th_height, 'r');
1702            updateThumb(thumbsEl[3], x, y2, w, h2, th_width, th_height, 'rb');
1703          }
1704        }
1705        else {
1706          var ratios_cropped = [];
1707          for (var i = 0; i < ratios.length; i++) {
1708            var ratio = ratios[i];
1709            if (avg_ratio > 1.1) {
1710              ratio_cropped = Math.max(1.0, ratio);
1711            } else {
1712              ratio_cropped = Math.min(1.0, ratio);
1713            }
1714            ratio_cropped = Math.max(0.66667, Math.min(1.7, ratio_cropped));
1715            ratios_cropped.push(ratio_cropped);
1716          }
1717
1718          var multiHeight = function(ratios) {
1719            var ratios_sum = 0;
1720            for (var i = 0; i < ratios.length; i++) {
1721              var ratio = ratios[i];
1722              ratios_sum += ratio;
1723            }
1724            return (max_w - (ratios.length - 1) * margin_w) / ratios_sum;
1725          };
1726
1727          var tries = [];
1728          var first_line, second_line, third_line, fourth_line;
1729          // Two lines
1730          for (first_line = 1; first_line <= cnt - 1; first_line++) {
1731            second_line = cnt - first_line;
1732            if (first_line  > 3 ||
1733                second_line > 3) {
1734              continue;
1735            }
1736            tries.push([[first_line, second_line], [
1737              multiHeight(ratios_cropped.slice(0, first_line)),
1738              multiHeight(ratios_cropped.slice(first_line)),
1739            ]]);
1740          }
1741
1742          // Three lines
1743          for (first_line = 1; first_line <= cnt - 2; first_line++) {
1744            for (second_line = 1; second_line <= cnt - first_line - 1; second_line++) {
1745              third_line = cnt - first_line - second_line;
1746              if (first_line  > 3 ||
1747                  second_line > (avg_ratio < 0.85 ? 4 : 3) ||
1748                  third_line  > 3) {
1749                continue;
1750              }
1751              tries.push([[first_line, second_line, third_line], [
1752                multiHeight(ratios_cropped.slice(0, first_line)),
1753                multiHeight(ratios_cropped.slice(first_line, first_line + second_line)),
1754                multiHeight(ratios_cropped.slice(first_line + second_line)),
1755              ]]);
1756            }
1757          }
1758
1759          // Four lines
1760          for (first_line = 1; first_line <= cnt - 3; first_line++) {
1761            for (second_line = 1; second_line <= cnt - first_line - 2; second_line++) {
1762              for (third_line = 1; third_line <= cnt - first_line - second_line - 1; third_line++) {
1763                fourth_line = cnt - first_line - second_line - third_line;
1764                if (first_line  > 3 ||
1765                    second_line > 3 ||
1766                    third_line  > 3 ||
1767                    fourth_line > 3) {
1768                  continue;
1769                }
1770                tries.push([[first_line, second_line, third_line, fourth_line], [
1771                  multiHeight(ratios_cropped.slice(0, first_line)),
1772                  multiHeight(ratios_cropped.slice(first_line, first_line + second_line)),
1773                  multiHeight(ratios_cropped.slice(first_line + second_line, first_line + second_line + third_line)),
1774                  multiHeight(ratios_cropped.slice(first_line + second_line + third_line)),
1775                ]]);
1776              }
1777            }
1778          }
1779
1780          // Looking for minimum difference between thumbs block height and max_h (may probably be little over)
1781          var opt_i = false;
1782          var opt_conf = false;
1783          var opt_diff = false;
1784          var opt_h = false;
1785          for (var i = 0; i < tries.length; i++) {
1786            var conf_nums = tries[i][0];
1787            var heights = tries[i][1];
1788            var heights_sum = 0;
1789            var heights_min = Infinity;
1790            for (var j = 0; j < heights.length; j++) {
1791              heights_sum += heights[j];
1792              if (heights_min > heights[j]) {
1793                heights_min = heights[j];
1794              }
1795            }
1796            var conf_h = Math.floor(heights_sum + margin_h * (heights.length - 1));
1797            var conf_diff = Math.abs(conf_h - max_h);
1798            if (conf_nums.length > 1) {
1799              if (conf_nums[0] > conf_nums[1] ||
1800                  conf_nums[2] && conf_nums[1] > conf_nums[2] ||
1801                  conf_nums[3] && conf_nums[2] > conf_nums[3]) {
1802                conf_diff *= 1.5;
1803              }
1804            }
1805            if (heights_min < min_w) {
1806              conf_diff *= 1.5;
1807            }
1808            if (opt_conf === false || conf_diff < opt_diff) {
1809              opt_i = i;
1810              opt_conf = cloneArr(conf_nums);
1811              opt_diff = conf_diff;
1812              opt_h = conf_h;
1813            }
1814          }
1815
1816          // Generating optimal thumbs
1817          th_width  = max_w;
1818          th_height = opt_h;
1819          var thumbs_remain = cloneArr(thumbsEl);
1820          var ratios_remain = cloneArr(ratios_cropped);
1821          var chunks = cloneArr(opt_conf);
1822          var opt_heights = cloneArr(tries[opt_i][1]);
1823          var chunks_num = chunks.length;
1824          var last_row = chunks_num - 1;
1825          var sy = 0;
1826          for (var i = 0; i < chunks.length; i++) {
1827            var line_chunks_num = chunks[i];
1828            var line_thumbs = thumbs_remain.splice(0, line_chunks_num);
1829            var line_height = opt_heights.shift();
1830            var last_column = line_thumbs.length - 1;
1831            var h = Math.floor(line_height);
1832            var sx = 0;
1833            var t = '', r = '', b = '', l = '';
1834            if (i == 0) {
1835              t = 't';
1836            }
1837            if (i == last_row) {
1838              b = 'b';
1839              h = th_height - sy;
1840            }
1841            for (var j = 0; j < line_thumbs.length; j++) {
1842              var thumbEl = line_thumbs[j];
1843              var thumb_ratio = ratios_remain.shift();
1844              var w = Math.floor(thumb_ratio * h);
1845              if (j == 0) {
1846                l = 'l';
1847              }
1848              if (j == last_column) {
1849                r = 'r';
1850                w = th_width - sx;
1851              }
1852              updateThumb(thumbEl, sx, sy, w, h, th_width, th_height, t+r+b+l);
1853              sx += w + margin_w;
1854            }
1855            sy += h + margin_h;
1856          }
1857        }
1858
1859        groupedEl.style.paddingTop  = (th_height / th_width * 100) + '%';
1860        groupedLayerEl.style.width  = th_width + 'px';
1861        groupedLayerEl.style.height = th_height + 'px';
1862      }
1863    }
1864  };
1865
1866  var TRoundVideo = window.TRoundVideo = {
1867    init: function(playerEl) {
1868      playerEl = geById(playerEl);
1869      if (!playerEl || playerEl.__inited) return;
1870      playerEl.__inited = true;
1871      var videoEl = ge1('.js-message_roundvideo', playerEl)
1872        , playEl = ge1('.js-message_roundvideo_play', playerEl)
1873        , progressEl = ge1('.js-message_roundvideo_progress', playerEl)
1874        , durationEl = ge1('.js-message_roundvideo_duration', playerEl)
1875        , playing = false;
1876      if (!videoEl) return;
1877
1878      function autoplay() {
1879        if (!videoEl) return;
1880        removeEvent(document, 'touchstart', autoplay);
1881        removeClass(playerEl, 'playing');
1882        playing = false;
1883        videoEl.muted = true;
1884        videoEl.loop = true;
1885        videoEl.currentTime = 0;
1886        play();
1887        showProgress();
1888      }
1889      function showProgress() {
1890        if (!videoEl) return;
1891        if (playing && !videoEl.paused) {
1892          requestAnimationFrame(function(){ showProgress(); });
1893        }
1894        redrawProgress();
1895        if (videoEl.duration) {
1896          var duration = Math.floor(videoEl.duration);
1897          durationEl.innerHTML = formatDuration(duration - videoEl.currentTime);
1898        }
1899      }
1900      function redrawProgress(updateSVG) {
1901        if (!videoEl) return;
1902        var progress;
1903        if (playing) {
1904          progress = videoEl.currentTime / videoEl.duration;
1905        } else {
1906          progress = 0;
1907        }
1908        progress = Math.max(0, Math.min(progress, 1));
1909        var wrapWidth = playerEl.offsetWidth;
1910        if (wrapWidth) {
1911          var rd = progressEl.getAttribute('data-rd') || 3;
1912          var d = (wrapWidth - rd);
1913          var l = (d * Math.PI);
1914          progressEl.setAttribute('r', (d / 2));
1915          progressEl.setAttribute('stroke-dasharray', l);
1916          progressEl.setAttribute('stroke-dashoffset', l * (1 - progress));
1917          if (updateSVG) {
1918            progressEl.style.transform = !progressEl.style.transform ? 'rotateZ(270deg)' : '';
1919          }
1920        }
1921      }
1922      function play() {
1923        if (!videoEl) return;
1924        var video = videoEl;
1925        var isPlaying = (video.currentTime > 0) &&
1926                        !video.paused &&
1927                        !video.ended &&
1928                        (video.readyState > 2);
1929        if (!isPlaying) {
1930          video.play();
1931          if (playing) {
1932            triggerEvent(videoEl, 'tg:play', {bubbles: true});
1933          }
1934        }
1935      }
1936      addEvent(document, 'tg:play', function(e) {
1937        if (e.target === videoEl || !playing) return true;
1938        if (videoEl.paused) {
1939          play();
1940          showProgress();
1941        } else {
1942          autoplay();
1943        }
1944      });
1945      function pause() {
1946        if (!videoEl) return;
1947        videoEl.pause();
1948      }
1949      function toggle(e) {
1950        e.stopPropagation();
1951        if (!playing) {
1952          redrawProgress();
1953          addClass(playerEl, 'playing');
1954          playing = true;
1955          videoEl.muted = false;
1956          videoEl.loop = false;
1957          videoEl.currentTime = 0;
1958          play();
1959          showProgress();
1960        } else {
1961          if (videoEl.paused) {
1962            play();
1963            showProgress();
1964          } else {
1965            pause();
1966          }
1967        }
1968      }
1969
1970      enableInlineVideo(videoEl);
1971
1972      checkVideo(videoEl, function() {
1973        addClass(playerEl, 'not_supported');
1974      });
1975      autoplay();
1976      addEvent(document, 'touchstart', autoplay);
1977      addEvent(videoEl, 'ended', function() {
1978        autoplay();
1979      });
1980      addEvent(window, 'resize', function() {
1981        redrawProgress(true)
1982      });
1983      if (playEl) {
1984        addEvent(playEl, 'click', toggle);
1985      }
1986    }
1987  };
1988
1989  var TVoice = window.TVoice = {
1990    init: function(playerEl) {
1991      playerEl = geById(playerEl);
1992      if (!playerEl || playerEl.__inited) return;
1993      playerEl.__inited = true;
1994      var audioEl = ge1('.js-message_voice', playerEl)
1995        , durationEl = ge1('.js-message_voice_duration', playerEl)
1996        , progressEl = ge1('.js-message_voice_progress', playerEl)
1997        , progressWrapEl = ge1('.js-message_voice_progress_wrap', playerEl)
1998        , player = null
1999        , isOGG = audioEl.hasAttribute('data-ogg')
2000        , seekTo = null
2001        , seeking = false
2002        , disableClick = false;
2003      if (!audioEl) return;
2004
2005      function initPlayer() {
2006        addClass(playerEl, 'ready');
2007        addEvent(player, 'play', function() {
2008          addClass(playerEl, 'playing');
2009          triggerEvent(playerEl, 'tg:play', {bubbles: true});
2010        });
2011        addEvent(player, 'pause', function() {
2012          removeClass(playerEl, 'playing');
2013        });
2014        addEvent(player, 'ended', function() {
2015          player.currentTime = 0;
2016          showProgress();
2017        });
2018        addEvent(player, 'loadedmetadata', function() {
2019          showProgress();
2020        });
2021        addEvent(playerEl, 'click', toggle);
2022        addEvent(progressWrapEl, 'mousedown touchstart', seekStart);
2023        addEvent(document, 'tg:play', stop);
2024      }
2025      function toggle(e) {
2026        e.stopPropagation();
2027        if (!disableClick) {
2028          if (!player) return true;
2029          if (player.paused) {
2030            player.play();
2031            showProgress();
2032          } else {
2033            player.pause();
2034            showProgress();
2035          }
2036        } else {
2037          disableClick = false;
2038        }
2039        e.preventDefault();
2040        return false;
2041      }
2042      function stop(e) {
2043        if (e.target === playerEl || !player) return true;
2044        if (!player.paused) {
2045          player.pause();
2046          showProgress();
2047        }
2048        return false;
2049      }
2050      function seekStart(e) {
2051        if (player &&
2052            player.duration !== Infinity &&
2053            (!player.paused ||
2054             player.currentTime > 0 && player.currentTime < player.duration)) {
2055          e.preventDefault();
2056          seeking = true;
2057          disableClick = false;
2058          player.pause();
2059          addEvent(document, 'mousemove touchmove', seek);
2060          addEvent(document, 'mouseup mouseleave touchend touchcancel', seekEnd);
2061          seek(e);
2062        }
2063      }
2064      function seek(e) {
2065        if (!seeking) return;
2066        var px = e.pageX;
2067        var op = progressWrapEl;
2068        var x = op.offsetLeft;
2069        var w = op.offsetWidth;
2070        while (op = op.offsetParent) {
2071          x += op.offsetLeft;
2072        }
2073        var ct = Math.max(0, Math.min(px - x, w)) / w;
2074        seekTo = ct;
2075        showProgress();
2076      }
2077      function seekEnd(e) {
2078        if (!seeking) return;
2079        seek(e);
2080        var duration = Math.floor(player.duration);
2081        player.currentTime = seekTo * duration;
2082        seekTo = null;
2083        seeking = false;
2084        if (e.type.substr(0, 5) == 'mouse') {
2085          disableClick = true;
2086        }
2087        player.play();
2088        showProgress();
2089        removeEvent(document, 'mousemove touchmove', seek);
2090        removeEvent(document, 'mouseup touchend', seekEnd);
2091      }
2092      function showProgress() {
2093        if (!player) return;
2094        if (!player.paused) {
2095          requestAnimationFrame(function(){ showProgress(); });
2096        }
2097        if (player.duration && player.duration !== Infinity) {
2098          var duration = Math.floor(player.duration);
2099          if (seeking) {
2100            var currentTime = seekTo * duration;
2101          } else {
2102            var currentTime = Math.max(0, player.currentTime);
2103          }
2104          if (progressEl) {
2105            progressEl.style.width = Math.min(100, currentTime / duration * 100) + '%';
2106          }
2107          if (durationEl) {
2108            durationEl.innerHTML = formatDuration(duration - currentTime);
2109          }
2110        }
2111      }
2112      function redrawProgress() {
2113        if (!audioEl) return;
2114        var ss = progressWrapEl.getElementsByTagName('S');
2115        var ss_count = ss.length / 2;
2116        var waveform_str = audioEl.getAttribute('data-waveform') || '';
2117        var waveform = waveform_str.split(',');
2118        var lines_cnt = Math.floor((progressWrapEl.offsetWidth + 2) / 6);
2119        var p = waveform.length / lines_cnt;
2120        var values = [];
2121        var max_value = 0;
2122        for (var i = 0; i < lines_cnt; i++) {
2123          var ws = i * p;
2124          var we = ws + p;
2125          var wsi = Math.floor(ws);
2126          var wei = Math.floor(we);
2127          if (wsi == wei) {
2128            var value = waveform[wsi] * (we - ws);
2129          } else {
2130            var value = 0;
2131            for (var j = wsi; j <= wei; j++) {
2132              var wv = +waveform[j] || 0;
2133              if (j == wsi) {
2134                value += wv * (j + 1 - ws);
2135              } else if (j == wei) {
2136                value += wv * (we - j);
2137              } else {
2138                value += wv;
2139              }
2140            }
2141          }
2142          value = value / p;
2143          max_value = Math.max(value, max_value);
2144          values.push(value);
2145        }
2146        for (var i = 0; i < ss.length; i++) {
2147          var li = i % ss_count;
2148          if (li < lines_cnt) {
2149            var height = (values[li] / max_value) * 100;
2150            ss[i].style.height = height + '%';
2151            ss[i].style.display = '';
2152          } else {
2153            ss[i].style.display = 'none';
2154          }
2155        }
2156      }
2157
2158      loadLib(TBaseUrl + 'js/ogvjs/ogv-support.js', function(success) {
2159        if (!success) return;
2160        if (isOGG &&
2161            OGVCompat.hasWebAudio() &&
2162            OGVCompat.supported('OGVPlayer')) {
2163          loadLib(TBaseUrl + 'js/ogvjs/ogv.js', function(success) {
2164            if (!success) return;
2165            player = new OGVPlayer();
2166            player.src = audioEl.src;
2167            initPlayer();
2168          });
2169        } else {
2170          player = audioEl;
2171          initPlayer();
2172        }
2173      });
2174      addEvent(window, 'resize', function(){ redrawProgress() });
2175      redrawProgress();
2176    }
2177  };
2178
2179  var TSticker = window.TSticker = {
2180    init: proccessWebpImage
2181  };
2182
2183  window.TWidgetPost = {
2184    init: function(options) {
2185      if (!doesSupportEmoji()) {
2186        removeClass(document.body, 'emoji_default');
2187        addClass(document.body, 'emoji_image');
2188      }
2189      options = options || {};
2190      TWidgetPost.options = options;
2191
2192      gec('.js-widget_message', function() {
2193        TPost.init(this);
2194        addEvent(ge('.js-poll_option', this), 'click', TWidgetPost.eSelectPollOption);
2195        addEvent(ge('.js-poll_vote_btn', this), 'click', TWidgetPost.eSendVotes);
2196      });
2197      initWidgetFrame({
2198        auto_height: true,
2199        onVisible: function() {
2200          gec('.js-widget_message', function() {
2201            TPost.view(this);
2202          });
2203        }
2204      });
2205      addEvent(window, 'tg:optionschange', TWidgetPost.onOptionsChange);
2206    },
2207    onOptionsChange: function(e) {
2208      var new_options = e.detail, transition_off = false;
2209      if (typeof new_options.dark !== undefined) {
2210        transition_off = true;
2211        addClass(document.body, 'no_transitions');
2212        toggleClass(document.body, 'dark', !!new_options.dark);
2213        toggleClass(document.body, 'nodark', !new_options.dark);
2214      }
2215      if (transition_off) {
2216        setTimeout(function() {
2217          removeClass(document.body, 'no_transitions');
2218        }, 100);
2219      }
2220    },
2221    eSelectPollOption: function(e) {
2222      e.preventDefault();
2223      if (!TWidgetAuth.isLoggedIn()) {
2224        return TWidgetAuth.logIn();
2225      }
2226      var poll_el = gpeByClass(this, 'js-poll');
2227      if (!poll_el) {
2228        return false;
2229      }
2230      toggleClass(this, 'selected');
2231      toggleClass(poll_el, 'selected', ge('.js-poll_option.selected', poll_el).length > 0);
2232      if (!hasClass(poll_el, 'multiple')) {
2233        TWidgetPost.sendPollVote(poll_el, this);
2234      }
2235    },
2236    eSendVotes: function(e) {
2237      e.preventDefault();
2238      if (!TWidgetAuth.isLoggedIn()) {
2239        return TWidgetAuth.logIn();
2240      }
2241      var poll_el = gpeByClass(this, 'js-poll');
2242      if (!poll_el) {
2243        return false;
2244      }
2245      TWidgetPost.sendPollVote(poll_el, this);
2246    },
2247    sendPollVote: function(poll_el, option_el) {
2248      if (!poll_el || hasClass(poll_el, 'sending')) {
2249        return false;
2250      }
2251      var option_els = ge('.js-poll_option.selected', poll_el);
2252      var options = TWidgetPost.options || {};
2253      var post_el = gpeByClass(option_el, 'js-widget_message');
2254      if (!post_el) {
2255        return false;
2256      }
2257      var peer = getAttr(post_el, 'data-peer');
2258      var peer_hash = getAttr(post_el, 'data-peer-hash');
2259      var post_id = getAttr(post_el, 'data-post-id');
2260      if (!peer || !peer_hash || !post_id) {
2261        return false;
2262      }
2263      var poll_options = [];
2264      gec(option_els, function() {
2265        poll_options.push(getAttr(this, 'data-value'));
2266      });
2267      removeClass(poll_el, 'selected');
2268      addClass(poll_el, 'sending');
2269      apiRequest('sendVote', {
2270        peer: peer,
2271        peer_hash: peer_hash,
2272        post_id: post_id,
2273        options: poll_options.join(';')
2274      }, function(err, result) {
2275        removeClass(poll_el, 'sending');
2276        if (result.media_html) {
2277          var media_wrap = newEl('div', '', result.media_html);
2278          var media_html = getHtml('.js-poll', media_wrap);
2279          setHtml(poll_el, media_html);
2280          addEvent(ge('.js-poll_option', poll_el), 'click', TWidgetPost.eSelectPollOption);
2281          addEvent(ge('.js-poll_vote_btn', poll_el), 'click', TWidgetPost.eSendVotes);
2282        }
2283        toggleClass(poll_el, 'selected', ge('.js-poll_option.selected', poll_el).length > 0);
2284      });
2285    }
2286  };
2287
2288  var TWidgetLogin = {
2289    init: function(id, bot_id, params, init_auth, lang) {
2290      initWidgetFrame({
2291        auto_height: true,
2292        auto_width: true
2293      });
2294      TWidgetLogin.widgetEl = document.getElementById(id);
2295      TWidgetLogin.botId = bot_id;
2296      TWidgetLogin.params = params;
2297      TWidgetLogin.lang = lang;
2298      var params_encoded = '', params_arr = [];
2299      for (var k in params) {
2300        params_arr.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k]));
2301      }
2302      TWidgetLogin.paramsEncoded = params_arr.join('&');
2303      if (init_auth) {
2304        TWidgetLogin.getAuth(true);
2305      }
2306      addEvent(window, 'message', function (event) {
2307        try {
2308          var data = JSON.parse(event.data);
2309        } catch(e) {
2310          var data = {};
2311        }
2312        if (event.source !== TWidgetLogin.activePopup) return;
2313        if (data.event == 'auth_result') {
2314          TWidgetLogin.onAuth(data.origin, data.result);
2315        }
2316      });
2317    },
2318    auth: function() {
2319      var width = 550;
2320      var height = 470;
2321      var left = Math.max(0, (screen.width - width) / 2) + (screen.availLeft | 0),
2322          top = Math.max(0, (screen.height - height) / 2) + (screen.availTop | 0);
2323      function checkClose() {
2324        if (!TWidgetLogin.activePopup || TWidgetLogin.activePopup.closed) {
2325          return TWidgetLogin.onClose();
2326        }
2327        setTimeout(checkClose, 100);
2328      }
2329      TWidgetLogin.activePopup = window.open('https://oauth.telegram.org/auth?bot_id=' + TWidgetLogin.botId + (TWidgetLogin.paramsEncoded ? '&' + TWidgetLogin.paramsEncoded : ''), 'telegram_oauth', 'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',status=0,location=0,menubar=0,toolbar=0');
2330      TWidgetLogin.authFinished = false;
2331      if (TWidgetLogin.activePopup) {
2332        TWidgetLogin.activePopup.focus();
2333        checkClose();
2334      }
2335    },
2336    getAuth: function(init) {
2337      var xhr = getXHR();
2338      xhr.open('POST', 'https://oauth.telegram.org/auth/get?bot_id=' + TWidgetLogin.botId + (TWidgetLogin.lang ? '&lang=' + encodeURIComponent(TWidgetLogin.lang) : ''));
2339      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
2340      xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
2341      xhr.onreadystatechange = function() {
2342        if (xhr.readyState == 4) {
2343          if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
2344            try {
2345              var result = JSON.parse(xhr.responseText);
2346            } catch(e) {
2347              var result = {};
2348            }
2349            console.log(result);
2350            if (result.user) {
2351              TWidgetLogin.onAuth(result.origin, result.user, init);
2352            } else {
2353              TWidgetLogin.onAuth(result.origin, false, init);
2354            }
2355          } else {
2356            TWidgetLogin.onAuth('*', false, init);
2357          }
2358        }
2359      };
2360      xhr.onerror = function() {
2361        TWidgetLogin.onAuth('*', false, init);
2362      };
2363      xhr.withCredentials = true;
2364      xhr.send(TWidgetLogin.paramsEncoded);
2365    },
2366    onAuth: function(origin, authData, init) {
2367      if (TWidgetLogin.authFinished) return;
2368      if (authData) {
2369        var data = {event: 'auth_user', auth_data: authData};
2370      } else {
2371        var data = {event: 'unauthorized'};
2372      }
2373      if (init) {
2374        data.init = true;
2375      }
2376
2377      //Arkadiy
2378      SloginTelegram.auth(data);
2379
2380      TWidgetLogin.authFinished = true;
2381    },
2382    onClose: function() {
2383      TWidgetLogin.getAuth();
2384    }
2385  };
2386  window.TWidgetLogin = TWidgetLogin;
2387
2388  var TStats = {
2389    init: function () {
2390      if (!doesSupportEmoji()) {
2391        removeClass(document.body, 'emoji_default');
2392        addClass(document.body, 'emoji_image');
2393      }
2394      gec('.js-sticker_thumb', function() {
2395        TSticker.init(this);
2396      });
2397    }
2398  }
2399  window.TStats = TStats;
2400
2401  window.TWidget = {
2402    initFrame: initWidgetFrame
2403  };
2404
2405})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.