PageSourceSearch

https://meiobit.com/wp-content/plugins/tb-prebid/src/js/tb-prebid.main.js?cache-ver=20230310210330

js meiobit.com collected 2026-10-02 03:10:56 UTC 43,294 bytes, 1,172 lines download raw bytes

1function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
2
3/**
4 * TB Prebid
5 * Version: 2.0
6 * Description: Uma implementação do Tecnoblog para o Prebid
7 * Author: Matheus Pratta <https://matheus.io>
8 */
9(() => {
10  var _class, _temp, _class2, _temp2, _temp3, _temp4, _temp5;
11
12  // Stub vazio para quando a função não existe
13  const noop = () => {}; // Classe de Timer para ser usado pela API
14
15
16  const Timer = function Timer(callback, delay) {
17    let timerId,
18        start,
19        remaining = delay;
20    this.running = false;
21    this.finished = false;
22
23    let callbackHandle = () => {
24      this.running = false;
25      this.finished = true;
26      if (callback) callback();
27    };
28
29    this.pause = function () {
30      if (this.finished || !this.running) return;
31      window.clearTimeout(timerId);
32      remaining -= new Date() - start;
33      this.running = false;
34    };
35
36    this.resume = function () {
37      if (this.finished || this.running) return;
38      start = new Date();
39      window.clearTimeout(timerId);
40      timerId = window.setTimeout(callback, remaining);
41      this.running = true;
42    };
43
44    this.increaseBy = function (amount) {
45      this.pause();
46
47      if (!this.finished) {
48        this.remaining += amount;
49      } else {
50        this.remaining = amount;
51        this.finished = false;
52      }
53
54      this.resume();
55    };
56
57    this.resume();
58  }; // Classe de Eventos para serem usados pela API
59
60
61  const Events = (_temp = _class = class Events {
62    // Onde ficaram todos hooks
63    // Adiciona um listener
64    static on(eventCode, callback) {
65      // Cria a array de eventos se necessário usando a função clear
66      if (!Events.fetch(eventCode)) Events.clear(eventCode); // Insere o listener
67
68      Events.__events[eventCode.toLowerCase()].push(callback);
69    } // Obtém os listeners de um evento
70
71
72    static fetch(eventCode, defaultValue) {
73      // Obtém o listener ou default
74      return Events.__events[eventCode.toLowerCase()] || defaultValue;
75    } // Limpa um listener
76
77
78    static clear(eventCode) {
79      // Esvazia toda a array do listener
80      Events.__events[eventCode.toLowerCase()] = [];
81    } // Dispara um listener
82
83
84    static trigger(eventCode) {
85      // Pega a array de eventos
86      const eventHandlers = Events.fetch(eventCode, []); // Faz o disparo em cada um dos handlers
87
88      eventHandlers.map(handler => (handler || noop).apply({
89        eventCode: eventCode
90      }, Utils.argumentsToArray(arguments).slice(2)));
91    } // Dispara um listener e depois limpa o mesmo
92
93
94    static triggerAndClear(eventCode) {
95      // Faz o trigger
96      Events.trigger.apply(this, [eventCode].concat(Utils.argumentsToArray(arguments))); // Limpa o evento
97
98      Events.clear(eventCode);
99    }
100
101  }, _defineProperty(_class, "__events", {}), _temp); // Classe de Utilitários para serem usados pela API
102
103  const Utils = (_temp2 = _class2 = class Utils {
104    // Diz quanto tempo faz que o script está rodando
105    static getRunningTime() {
106      return (Date.now() - Utils.getRunningTimeStart) / 1000;
107    } // Converte um objeto de arguments para array
108
109
110    static argumentsToArray(args) {
111      let output = [];
112
113      for (let i = 0; i < args.length; i++) {
114        output.push(args[i]);
115      }
116
117      return output;
118    } // Detecta quando um determinado elemento terminou de carregar (enquanto baixa o HTML)
119
120
121    static trackElementLoading(element, callback) {
122      // Cria o código único do evento
123      const eventCode = `Utils.trackElementLoading::${element}`; // Insere o callback direto nos eventos
124
125      Events.on(eventCode, callback); // Testa se o elemento já existe
126
127      const elementExists = document.querySelector(element); // Se ele já existe, dá um trigger no evento e não executa mais nada
128
129      if (!!elementExists) {
130        Events.triggerAndClear(eventCode, elementExists);
131        return;
132      } // Caso não exista, a gente vai utilizar o MutationObserver. Primeiro passo é detectar e inicializar ele (caso não tenha sido):
133
134
135      if (window.MutationObserver) {
136        // Insere na lista de observações
137        if (!Utils.trackElementLoading.observerList) Utils.trackElementLoading.observerList = [];
138        Utils.trackElementLoading.observerList.push({
139          selector: element,
140          event: eventCode
141        }); // Inicializa o observer
142
143        if (!Utils.trackElementLoading.observer) {
144          Utils.trackElementLoading.observer = new MutationObserver(mutations => {
145            // Processa as mutações
146            for (let iMutation = 0; iMutation < mutations.length; iMutation++) {
147              for (let iNode = 0; iNode < mutations[iMutation].addedNodes.length; iNode++) {
148                // Este é o node que foi inserido
149                let addedNode = mutations[iMutation].addedNodes[iNode]; // Passa por cada um dos elementos sendo observados e checa se ele bate
150
151                for (let iObserved = 0; iObserved < Utils.trackElementLoading.observerList.length; iObserved++) {
152                  // Este é o seletor observado
153                  let observedSelector = Utils.trackElementLoading.observerList[iObserved]; // Testa se ele bate com o node
154
155                  if (observedSelector && addedNode.matches && addedNode.matches(observedSelector.selector)) {
156                    // Bateu! \õ/ agora vamos remover da lista em andamento e chamar o evento
157                    Utils.trackElementLoading.observerList[iObserved] = null;
158                    delete Utils.trackElementLoading.observerList[iObserved];
159                    Events.triggerAndClear(observedSelector.event, addedNode);
160                    break;
161                  }
162                }
163              }
164            } // Depois que processou as mutações, atualiza a lista de elementos sendo acompanhados para remover os itens vazios (excluídos)
165
166
167            Utils.trackElementLoading.observerList = Utils.trackElementLoading.observerList.filter(observer => !!observer); // Caso o observer não tenha mais nada pra observar, desconectamos e limpamos ele
168
169            if (Utils.trackElementLoading.observerList.length == 0) {
170              Utils.trackElementLoading.observer.disconnect();
171              Utils.trackElementLoading.observer = null;
172              delete Utils.trackElementLoading.observer;
173            }
174          }); // Começa a observar
175
176          this.trackElementLoading.observer.observe(document.documentElement, {
177            childList: true,
178            subtree: true
179          });
180        }
181      } else {
182        // Coloca o trigger para quando o documento der ready.
183        document.addEventListener('ready', () => {
184          // Detecta se o elemento carregou
185          const elementLoaded = document.querySelector(element); // Dispara o evento
186
187          if (!!elementLoaded) Events.triggerAndClear(eventCode, elementLoaded);
188        });
189      }
190    }
191
192  }, _defineProperty(_class2, "getRunningTimeStart", Date.now()), _temp2); // Eventos e debug
193
194  const Debug = function Debug() {
195    if (Debug.enabled) console.log.apply(console, [Debug.prefix, `[${Utils.getRunningTime().toFixed(3)}]`].concat(Utils.argumentsToArray(arguments)));
196  };
197
198  Debug.info = function () {
199    if (Debug.enabled) console.info.apply(console, [Debug.prefix, `[${Utils.getRunningTime().toFixed(3)}]`].concat(Utils.argumentsToArray(arguments)));
200  };
201
202  Debug.warn = function () {
203    console.warn.apply(console, [Debug.prefix, `[${Utils.getRunningTime().toFixed(3)}]`].concat(Utils.argumentsToArray(arguments)));
204  };
205
206  Debug.error = function () {
207    console.error.apply(console, [Debug.prefix, `[${Utils.getRunningTime().toFixed(3)}]`].concat(Utils.argumentsToArray(arguments)));
208  };
209
210  Debug.prefix = 'TB-Prebid';
211  Debug.enabled = ~document.location.hash.indexOf('debug'); // Classe para acompanhar visibilidade do usuário
212
213  const ActivityTracker = new (_temp3 = class ActivityTracker {
214    // Lista de eventos que são considerados ações do usuário
215    // Inicializa o tracker de atividades
216    constructor() {
217      _defineProperty(this, "validActivityEvents", ['mousedown', 'mousemove', 'mouseup', 'scroll', 'touchstart', 'touchmove', 'touch', 'keydown', 'ke
217ypress', 'keyup']);
218
219      _defineProperty(this, "isCurrentlyActive", false);
220
221      _defineProperty(this, "inactivityTimeout", 6000);
222
223      _defineProperty(this, "handleActivitySignalIsProcessing", false);
224
225      _defineProperty(this, "handleActivitySignalInactiveTimeout", null);
226
227      // Faz hook na janela e no documento para processar os eventos de atividade
228      this.validActivityEvents.map(eventName => {
229        window.addEventListener(eventName, this.handleActivitySignal);
230        document.addEventListener(eventName, this.handleActivitySignal);
231      });
232    } // Indica se está ativo ou não
233
234
235    handleActivitySignal() {
236      // Throttling
237      if (!!this.handleActivitySignalIsProcessing) return;
238      this.handleActivitySignalIsProcessing = true; // Em casos onde o usuário não estava ativo, emite um evento
239
240      if (!this.isCurrentlyActive) {
241        Events.trigger('useractive');
242      } // Mantém o status em true
243
244
245      this.isCurrentlyActive = true; // Limpa o timeout atual de inatividade
246
247      if (!!this.handleActivitySignalInactiveTimeout) clearTimeout(this.handleActivitySignalInactiveTimeout); // Gera um novo timeout para inatividade
248
249      this.handleActivitySignalInactiveTimeout = setTimeout(() => {
250        this.isCurrentlyActive = false;
251        Events.trigger('userinactive');
252      }, this.inactivityTimeout); // Ativa eventos novamente
253
254      setTimeout(() => {
255        this.handleActivitySignalIsProcessing = false;
256      }, 100);
257    }
258
259  }, _temp3)(); // Classe de Analytics da API
260
261  const TecnoblogAdAnalytics = class TecnoblogAdAnalytics {
262    static send(action, label, value) {
263      if (window.ga) {
264        // Argumentos padrão do GA
265        let args = ['send', 'event', 'Ads']; // Prepara argumentos custom
266
267        if (action) args.push(action);
268        if (label) args.push(label);
269        if (value) args.push(value); // Obrigar a ter mais de 3 args
270
271        if (args.length <= 3) {
272          // Exibe erro
273          Debug.error('AdAnalytics:', 'Argumentos insuficientes', args);
274          return;
275        } // Dispara
276
277
278        window.ga.apply(window.ga, args);
279      }
280    }
281
282  }; // Classe de AdSlot para ser usado pela API
283
284  const AdSlot = (_temp4 = class AdSlot {
285    // Inicializador do AdSlot
286    constructor(adManager, {
287      eventCode,
288      mediaQuery,
289      block,
290      code,
291      container,
292      sizes,
293      mediaTypes,
294      prebid,
295      options,
296      events
297    }) {
298      _defineProperty(this, "isSlotBiddable", false);
299
300      _defineProperty(this, "bidRefreshTimer", null);
301
302      _defineProperty(this, "bidRefreshShowedMessage", false);
303
304      _defineProperty(this, "impressionViewed", false);
305
306      _defineProperty(this, "viewablePercentage", 0.00);
307
308      // Manager do slot, para notificar quando o slot está pronto para bids, etc
309      this.manager = adManager; // Opções
310
311      this.options = Object.assign({
312        unsafeFrame: true,
313        minViewabilityPercent: this.manager.options.viewabilityTracker.minViewabilityPercent,
314        timeoutRefresh: this.manager.options.viewabilityTracker.timeoutRefresh,
315        timeoutRefreshRetry: this.manager.options.viewabilityTracker.timeoutRefreshRetry
316      }, options); // Media Query condicional para exibir o Ad
317
318      this.mediaQuery = mediaQuery || 'screen'; // Bloco do anúncio (GPT)
319
320      this.block = block; // ID/Código do elemento do Ad
321
322      this.code = code; // Tipos de mídia
323
324      this.mediaTypes = mediaTypes; // Código de eventos
325
326      this.eventCode = eventCode; // Eventos
327
328      for (let event in events || {}) {
329        // Pega qual é o callback
330        let callback = events[event]; // Registra o evento
331
332        this.on(event, callback);
333      } // Container do Ad
334
335
336      this.container = container; // Tamanhos do Ad
337
338      this.sizes = sizes; // Definições do Prebid
339
340      this.prebid = prebid; // Definições de slot registradas
341
342      this.registeredWith = {}; // Se o media atual for adequado, já renderizamos o slot
343
344      if (this.isSlotAvailableOnCurrentMedia()) this.renderElement();
345    } // Eventos
346
347
348    on(event, callback) {
349      Events.on(`${this.eventCode}::${event}`, callback);
350    }
351
352    trigger(event) {
353      Events.trigger.apply(this, [`${this.eventCode}::${event}`].concat(Utils.argumentsToArray(arguments)));
354    }
355
356    triggerAndClear(event) {
357      Events.triggerAndClear.apply(this, [`${this.eventCode}::${event}`].concat(Utils.argumentsToArray(arguments)));
358    } // Quando houver resize, testar se devemos ou não exibir o slot
359
360
361    handleWindowResize() {
362      // Nosso slot está disponível no media atual?
363      if (this.isSlotAvailableOnCurrentMedia()) {
364        // Caso esteja, detecta se já foi renderizado. Caso tenha, deixamos visível, caso não, renderizamos.
365        if (this.element) {
366          this.element.style.display = 'block';
367          this.element.style.visibility = 'visible';
368          this.manager.makeSlotBiddable(this);
369        } else {
370          this.renderElement();
371        }
372      } else {
373        // Se o slot estiver renderizado, deixamos ele invisível, caso contrário não fazemos nada
374        if (!!this.element) {
375          this.element.style.display = 'none';
376          this.element.style.visibility = 'hidden';
377          this.manager.makeSlotUnbiddable(this);
378        }
379      }
380    } // Detecta se o media atual é adequado
381
382
383    isSlotAvailableOnCurrentMedia() {
384      return window.matchMedia(this.mediaQuery).matches;
385    } // Renderiza o HTML do slot
386
387
388    renderElement() {
389      // Não renderiza duas vezes
390      if (!!this.element) return; // Pega o container do nosso slot
391
392      Utils.trackElementLoading(this.container, containerElement => {
393        // Cria a <div> do nosso slot
394        let element = document.createElement('div'); // Coloca o ID do slot
395
396        element.setAttribute('id', this.code); // Insere ele no container
397
398        containerElement.appendChild(element); // Define slot como renderizado
399
400        this.element = element; // Emite evento
401
402        this.triggerAndClear('rendered'); // Registra o slot no Prebid
403
404        if (this.prebid) this.registerWithPrebid(); // Registra o slot no GPT
405
406        this.registerWithGpt(); // Define o slot como biddable
407
408        this.manager.makeSlotBiddable(this);
409      });
410    } // Indica se o slot está biddable
411
412
413    // Verifica se o slot pod receber anúncios
414    canReceiveAds() {
415      // Se o elemento não existe, retorna false
416      if (!this.element) return false; // Checa se o slot está biddable mas a impressão atual não foi vista
417
418      if (this.isSlotBiddable && !this.impressionViewed) return false; // Checa se ele está visível
419
420      if ('hidden' == this.element.style.visibility) return false; // Checa se ele está visível
421
422      if ('none' == this.element.style.display) return false; // Deu bom, retorna true
423
424      return true;
425    } // Registra o slot no Prebid
426
427
428    registerWithPrebid() {
429      // Coloca na fila do Prebid
430      this.manager.enqueuePrebid(() => {
431        // Não registra se não pode receber ads
432        if (!this.canReceiveAds()) return Debug.warn('Registro de slot no Prebid nao foi possivel. Elemento esta visivel?', this.code); // Não registra duas vezes!
433
434        if (this.registeredWith.prebid) return; // Debug!
435
436        Debug.info('Registrando slot no Prebid:', this.code); // Filtrar tamanhos para o Prebid
437
438        let prebidSizes = [];
439
440        for (let iSize = 0; iSize < this.sizes.length; iSize++) {
441          // Pega o tamanho
442          let size = this.sizes[iSize]; // Devemos remover ele?
443
444          if (!Array.isArray(size) || ~size.indexOf('fluid')) continue; // Inserir na array de tamanhos adaptada ao prebid
445
446          prebidSizes.push(size);
447        } // Cria a definição de Ad Unit para o Prebid
448
449
450        let adUnitDef = Object.assign({
451          code: this.code,
452          mediaTypes: this.mediaTypes ? this.mediaTypes : {
453            banner: {
454              sizes: prebidSizes
455            }
456          },
457          bids: this.prebid && this.prebid.bids ? this.prebid.bids : []
458        }, this.prebid ? this.prebid : {}); // Registra no Prebid
459
460        Debug.info('Prebid.addAdUnits', this.code);
461        pbjs.addAdUnits(adUnitDef); // Salva no registro
462
463        this.registeredWith.prebid = adUnitDef;
464      });
465    } // Registra o slot no GPT
466
467
468    registerWithGpt() {
469      // Coloca na fila do GPT
470      this.manager.enqueueGpt(() => {
471        // Não registra se não pode receber ads
472        if (!this.canReceiveAds()) return Debug.warn('Registro de slot no GPT nao foi possivel. Elemento esta visivel?', this.code); // Não registra duas vezes!
473
474        if (this.registeredWith.gpt) return; // Debug!
475
476        Debug.info('Registrando slot no GPT:', this.code); // Cria o slot GPT
477
478        let gptSlot = window.googletag.defineSlot(this.block, this.sizes, this.code); // Se o slot estiver null, dá erro
479
480        if (null == gptSlot) return Debug.warn('GPT retornou slot como null:', this.code); // Safe frame
481
482        Debug.info('GPT.setForceSafeFrame:', !this.options.unsafeFrame);
483        gptSlot.setForceSafeFrame(!this.options.unsafeFrame); // Inclui serviço pubads
484
485        Debug.info('GPT.addService:', 'pubads()');
486        gptSlot.addService(googletag.pubads()); // Targeting opcional
487
488        if (this.options.targeting) {
489          for (let target in this.options.targeting) {
490            Debug.info('GPT.setTargeting:', target, this.options.targeting[target]);
491            gptSlot.setTargeting(target, this.options.targeting[target]);
492          }
493        } // Faz o fetch via SRA
494
495
496        Debug.info('GPT.display:', this.code);
497        window.googletag.display(gptSlot); // Salva no registro
498
499        this.registeredWith.gpt = gptSlot;
500      });
501    } // Limpa o slot para receber um novo anúncio
502
503
504    cleanup() {
505      // Limpa no HTML
506      let slotInnerElement = document.querySelector(this.code);
507      if (!!slotInnerElement) document.querySelector(this.code).innerHTML = '';
508    } // Processa o refresh do slot
509
510
511    refresh() {
512      // Executa apenas quando a página terminar de carregar, para não dar render block
513      this.manager.enqueueWhenPageReady(() => {
514        // Debug
515        Debug.info('Preparando exibicao do slot:', this.code); // Marca como não visto
516
517        this.impressionViewed = false; // Faz o refresh no GPT
518
519        if (this.registeredWith.gpt) {
520          Debug.info('Exibindo slot usando GPT:', this.code);
521          this.manager.refreshGpt({
522            code: this.code,
523            slot: this.registeredWith.gpt
524          });
525        }
526      });
527    } // Função que refaz o bid do slot
528
529
530    bidRefresh() {
531      // Checamos se a % visível dele atende nosso mínimo
532      if (!this.isInView()) {
533        // Não estamos, então recriamos o timer um pouco mais pra frente e deixamos um log
534        if (!this.bidRefreshShowedMessage) {
535          Debug.info('Slot solicitou refresh mas nao atende porcentagem minima de visibilidade para refresh:', this.code);
536          this.bidRefreshShowedMessage = true;
537        } // Para e remove o timer de refresh
538
539
540        this.bidRefreshTimer.pause();
541        delete this.bidRefreshTimer; // Cria um novo timer
542
543        if (!this.bidRefreshTimer) this.bidRefreshTimer = new Timer(() => {
544          this.bidRefresh();
545        }, this.options.timeoutRefreshRetry); // Encerra
546
547        return;
548      } // Permite exibir a mensagem novamente
549
550
551      this.bidRefreshShowedMessage = false; // Para e remove o timer de refresh
552
553      this.bidRefreshTimer.pause();
554      delete this.bidRefreshTimer; // Enfileramos o refresh para o próximo momento que o usuário e a janela estiverem ativos
555
556      this.manager.enqueueWhenVisibleAndActive(() => {
557        // Debug
558        Debug.info('Preparando slot para bid:', this.code); // Insere na fila de bids
559
560        this.manager.makeSlotBiddable(this, true);
561      }); // Debug
562
563      Debug.info('Slot inserido na fila de bid:', this.code);
564    } // Determina se a impressão do anúncio já computou viewability
565
566
567    computeViewability() {
568      // Marca o slot com impressão exibida
569      this.impressionViewed = true;
570      Debug.info('Impressao exibida:', this.code, this.impressionViewed); // Cria um timer para disparar o refresh do anúncio
571
572      if (!this.bidRefreshTimer) this.bidRefreshTimer = new Timer(() => {
573        this.bidRefresh();
574      }, this.options.timeoutRefresh); // Emite evento de viewability
575
576      this.trigger('viewability', this);
577    } // Porcentagem do slot que está visível
578
579
580    updateViewablePercentage(percentage) {
581      // Atualiza o valor
582      this.viewablePercentage = percentage; // Emite um evento
583
584      this.trigger('slotVisibilityChanged', this.isInView(), this.viewablePercentage);
585    } // Processa impressões perdidas (quando o anúncio buga e fica em branco)
586
587
588    handleMissedImpression(event) {
589      // Debug
590      Debug.warn(`Impressao perdida no slot '${this.code}':`, event);
591      Debug.warn(`Enfileirando slot '${this.code}' sem Prebid...`); // Enfileira para rodar quando der o tempo de refresh
592
593      if (!this.bidRefreshTimer) {
594        this.bidRefreshTimer = new Timer(() => {
595          // Garantir que a página está visível e ativa
596          this.manager.enqueueWhenVisibleAndActive(() => {
597            //Debug
598            Debug.warn(`Executando bid do slot '${this.code}' sem Prebid...`); // Tenta limpar os targetings do Prebid e exibir diretamente da GPT
599
600            this.registeredWith.gpt.clearTargeting();
601            googletag.pubads().refresh([this.registeredWith.gpt]);
602          });
603        }, this.options.timeoutRefresh);
604      }
605    } // Processa mudanças de status do slot
606
607
608    handleStateChange(eventName, event) {
609      // Debug
610      Debug.info(`Evento '${eventName}' disparado no slot '${this.code}':`, event);
611
612      if (eventName == 'slotVisibilityChanged') {
613        // Loga no Google Analytics o que for de % visível
614        TecnoblogAdAnalytics.send(`Slot Visibility Changed`, this.block || this.code, event.inViewPercentage);
615      } else {
616        // Loga no Google Analytics o que não for de % visível
617        TecnoblogAdAnalytics.send(`GPT Event ${eventName}`, this.block || this.code);
618      }
619    } // Retorna se o slot está ou não visível
620
621
622    isInView() {
623      return this.viewablePercentage >= this.options.minViewabilityPercent;
624    }
625
626  }, _temp4); // Classe principal da API
627
628  const TecnoblogAdBidding = (_temp5 = class TecnoblogAdBidding {
629    // Opções default
630    // Inicializador da API
631    constructor({
632      options,
633      labels,
634      ads,
635      adsPerLabel
636    }) {
637      _defineProperty(this, "options", {
638        // Ajustes do Prebid
639        prebid: {
640          timeout: 1100
641        },
642        // Ajustes do GPT
643        gpt: {
644          centering: true,
645          unsafeFrame: true,
646          lazyLoad: {
647            fetchMarginPercent: 70,
648            renderMarginPercent: 50,
649            mobileScaling: 1.7
650          }
651        }
652      });
653
654      _defineProperty(this, "isPageVisible", true);
655
656      _defineProperty(this, "isUserActive", true);
657
658      _defineProperty(this, "queueOnVisibleAndActive", []);
659
660      _defineProperty(this, "handleQueueVisibleAndActiveIsProcessing", false);
661
662      _defineProperty(this, "biddableSlots", []);
663
664      _defineProperty(this, "makeSlotBiddableAutoBidTimeout", null);
665
666      _defineProperty(this, "queueOnPageReady", []);
667
668      _defineProperty(this, "isProcessingWhenPageReady", false);
669
670      _defineProperty(this, "bidCurrently", []);
671
672      _defineProperty(this, "refreshGptSlots", []);
673
674      _defineProperty(this, "refreshGptIsRefreshing", false);
675
676      // Opções básicas
677      this.options = Object.assign(this.options, options); // Debug das opções
678
679      Debug.info('Inicializando TB Prebid com as opcoes:', this.options); // Inicializa estrutura básica do Prebid
680
681      window.pbjs = window.pbjs || {
682        que: []
683      }; // Inicializa estrutura básica do GPT
684
685      window.googletag = window.googletag || {
686        cmd: []
687      }; // Coloca notificações de inicialização na fila do GPT e Prebid
688
689      this.enqueuePrebid(() => {
690        Debug.info(`Prebid inicializado. Versao: ${pbjs.version}`);
691      });
692      this.enqueueGpt(() => {
693        Debug.info(`GPT inicializado. Versao: ${googletag.getVersion()}`);
694      }); // Inicialização do Prebid
695
696      this.enqueuePrebid(() => {
697        // Seta configuração básica do prebid
698        window.pbjs.setConfig({
699          useBidCache: true,
700          bidderSequence: 'random',
701          priceGranularity: 'high',
702          enableSendAllBids: false,
703          bidderTimeout: this.options.prebid.timeout,
704          userSync: {
705            syncDelay: 5000,
706            iframeEnabled: true
707          },
708          currency: {
709            adServerCurrency: 'USD'
710          }
711        }); // Seta multiplicadores de bidder (corrige CPM)
712
713        if (this.options.prebid.bidderCpmMultipliers) {
714          let bidderSettingsCurrent = window.pbjs.bidderSettings || {};
715
716          for (let bidder in this.options.prebid.bidderCpmMultipliers) {
717            // Pegamos o valor do bidder
718            let bidderValue = this.options.prebid.bidderCpmMultipliers[bidder]; // Pegamos as opções deste bidder
719
720            let bidderSettings = bidderSettingsCurrent[bidder] || {}; // Configuramos o ajuste de CPM
721
722            bidderSettings.bidCpmAdjustment = bidCpm => {
723              // Calculamos novo valor
724              let newBidCpm = bidCpm * bidderValue; // Debug
725
726              Debug.info('Prebid.bicCpmAdjustment:', bidder, `$${bidCpm.toFixed(3)} => $${newBidCpm.toFixed(3)}`); // Retornamos o valor com o bid ajustado
727
728              return newBidCpm;
729            }; // Salvamos as novas opções deste bidder
730
731
732            bidderSettingsCurrent[bidder] = bidderSettings;
733          } // Atualizamos todas opções
734
735
736          window.pbjs.bidderSettings = bidderSettingsCurrent;
737        }
738      }); // Inicialização do GPT
739
740      this.enqueueGpt(() => {
741        // Desativa carregamento automático (conflita com Prebid)
742        window.googletag.pubads().disableInitialLoad(); // Ativa modo single request
743
744        window.googletag.pubads().enableSingleRequest(); // Ativa centralização
745
746        window.googletag.pubads().setCentering(this.options.gpt.centering); // Ativa safe-frame
747
748        window.googletag.pubads().setForceSafeFrame(!this.options.gpt.unsafeFrame); // Ativa lazy-loading
749
750        if (this.options.gpt.lazyLoad) window.googletag.pubads().enableLazyLoad(this.options.gpt.lazyLoad); // Ativa serviços
751
752        window.googletag.enableServices(); // Processa mudança de states de um slot (mais para debug)
753
754        window.googletag.pubads().addEventListener('slotVisibilityChanged', event => {
755          this.handleGptSlotState('slotVisibilityChanged', event);
756        });
757        window.googletag.pubads().addEventListener('impressionViewable', event => {
758          this.handleGptSlotState('impressionViewable', event);
759        });
760        window.googletag.pubads().addEventListener('slotRenderEnded', event => {
761          this.handleGptSlotState('slotRenderEnded', event);
762        });
763        window.googletag.pubads().addEventListener('slotRequested', event => {
764          this.handleGptSlotState('slotRequested', event);
765        });
766        window.googletag.pubads().addEventListener('slotOnload', event => {
767          this.handleGptSlotState('slotOnload', event);
768        }); // Registra eventos
769
770        window.googletag.pubads().addEventListener('impressionViewable', event => {
771          this.handleGptImpressionViewable(event);
772        });
773        window.googletag.pubads().addEventListener('slotVisibilityChanged', event => {
774          this.handleGptSlotViewability(event);
775        });
776        window.googletag.pubads().addEventListener('slotRenderEnded', event => {
777          this.handleGptSlotRendered(event);
778        });
779      }); // Importa as labels
780
781      this.labels = labels; // Prepara onde os slots ficarão armazenados
782
783      this.adSlots = []; // Cria uma lista de ads, caso não tenha sido passada
784
785      ads = ads || []; // Caso os slots estejam organizados por label, convertemos de formato
786
787      if (!!adsPerLabel) {
788        // Loop em cada label
789        for (let adLabelCode in adsPerLabel) {
790          // Pega todos os ads
791          let adLabelAds = adsPerLabel[adLabelCode]; // Processa os ads
792
793          adLabelAds = adLabelAds.map(adSlotDef => {
794            adSlotDef.label = adLabelCode;
795            return adSlotDef;
796          }); // Coloca junto dos outros ads
797
798          ads = ads.concat(adLabelAds);
799        }
800      } // Processa os Ads
801
802
803      for (let iAdSlotDef = 0; iAdSlotDef < ads.length; iAdSlotDef++) {
804        // Importa a definição do slot
805        let adSlotDef = ads[iAdSlotDef]; // Define um tipo caso ele não possua
806
807        adSlotDef.type = adSlotDef.type || 'single'; // Cria o AdSlot de acordo com o tipo
808
809        switch (adSlotDef.type.toLowerCase()) {
810          case 'single':
811            // Apenas insere o slot
812            this.insertAdSlot(adSlotDef);
813            break;
814
815          case 'ab-bidding':
816            // Verifica se o A/B bidding está ativo
817            if (!this.options.abBidding) {
818              Debug.warn('A/B bidding nao esta ativo nas configuracoes.');
819              break;
820            } // Pega os pesos do A/B bidding
821
822
823            let abWeights = this.options.abBidding.weights || {};
824            let abValues = []; // Converte os pesos em valores
825
826            for (let abWeight in abWeights) {
827              // Só insere no sorteio se o valor estiver disponivel nas definições de slot
828              if (!adSlotDef.formats[abWeight]) continue; // Prepara o sorteio
829
830              for (let abWeightValue = 0; abWeightValue < abWeights[abWeight]; abWeightValue++) {
831                abValues.push(abWeight);
832              }
833            } // Caso nenhum peso for encontrado, retorna erro
834
835
836            if (abValues.length == 0) {
837              Debug.warn('Nenhum valor para A/B bidding foi encontrado:', Object.keys(adSlotDef.formats).join(', '), '<->', Object.keys(abWeights).join(', '));
838              break;
839            } // Determina qual das definições de slot(s) vai ser usada
840
841
842            Debug.info('Determinando A/B bidding para os valores:', abValues.join(', '));
843            let abWinner = abValues[Math.round(Math.random() * (abValues.length - 1))];
844            let abWinnerFormat = adSlotDef.formats[abWinner];
845            Debug.info('Utilizando A/B bidding com o vencedor:', abWinner); // Insere os slots
846
847            for (let iAbSlotDef = 0; iAbSlotDef < abWinnerFormat.length; iAbSlotDef++) {
848              // Cria as labels corretas, sem isso os ads desktop podem aparecer no mobile e vice-versa
849              if (adSlotDef.label) abWinnerFormat[iAbSlotDef].label = adSlotDef.label; // Insere o slot
850
851              this.insertAdSlot(abWinnerFormat[iAbSlotDef]);
852            }
853
854            break;
855
856          default:
857            Debug.warn('Tipo de slot invalido:', adSlotDef.type);
858            break;
859        }
860      } // Event handler pra quando o usuário ficar ativo e inativo
861
862
863      Events.on('useractive', () => {
864        this.isUserActive = true;
865        this.handleQueueVisibleAndActive();
866      });
867      Events.on('userinactive', () => {
868        this.isUserActive = false;
869      }); // Event handler para quando a janela perder foco ou ganhar foco
870
871      window.addEventListener('blur', () => {
872        this.isPageVisible = false;
873      });
874      window.addEventListener('focus', () => {
875        this.isPageVisible = true;
876      }); // Event handler para detectar quando a página está pronta
877
878      window.addEventListener('readystatechange', this.handleWhenPageReady); // Event handler pra quando houver resize da janela passar para cada slot
879
880      // window.addEventListener('resize', () => {
881      //   this.adSlots.map(adSlot => adSlot.handleWindowResize());
882      // });
883    } // Indica se a página está ou não visível
884
885
886    // Determina se a página e o usuário estão ativos
887    isVisibleAndActive() {
888      // Retorna se a página está visível e o usuário está ativo
889      return this.isPageVisible && this.isUserActive;
890    } // Fila de ações a serem executadas quando o usuário e a página estão ativos
891
892
893    // Enfilera ações nos slots quando a página e usuário estiverem ativos
894    enqueueWhenVisibleAndActive(fn) {
895      // Insere no final da fila
896      this.queueOnVisibleAndActive.push(fn); // Se já está ativo, causa um trigger no handler, apenas caso já estiver ativo
897
898      this.handleQueueVisibleAndActive();
899    } // Processa ações nos slots quando a página e o usuário estiverem ativos
900
901
902    handleQueueVisibleAndActive() {
903      // Caso não estiver visível e ativo, não faz nada
904      if (!this.isVisibleAndActive()) return; // Throttling
905
906      if (!!this.handleQueueVisibleAndActiveIsProcessing) return;
907      this.handleQueueVisibleAndActiveIsProcessing = true; // Processa a fila
908
909      let fn = null;
910
911      while (fn = this.queueOnVisibleAndActive.shift()) {
912        // Só processa funções
913        if ('function' == typeof fn) {
914          // Dispara função
915          fn();
916        }
917      } // Throttling (fim)
918
919
920      this.handleQueueVisibleAndActiveIsProcessing = false;
921    } // Insere um único AdSlot baseado numa definição de slot, já convertendo a label do mesmo em uma Media Query
922
923
924    insertAdSlot(adSlotDef) {
925      // Checa se o slot depende de uma idade mínima ou máxima do post
926      if (!!adSlotDef.contentMinAge || !!adSlotDef.contentMaxAge) {
927        // Checa se a idade do conteúdo foi informada, se não for paramos aqui e retornamos um warning
928        if (!window.currentContentAge) return Debug.warn(`O slot ${adSlotDef.code} depende da variavel 'window.currentContentAge', que nao esta presente. Pulando slot...`); // Detecta se o slot está fora da faixa de tempo configurada, se estiver fora a
928penas registramos no log e ignoramos
929
930        if (!((adSlotDef.contentMinAge || 0) <= window.currentContentAge && window.currentContentAge <= (adSlotDef.contentMaxAge || Infinity))) return Debug.info(`O slot ${adSlotDef.code} nao sera inserido pois nao atende aos requisitos de idade do conteudo atual.`);
931      } // Cria a Media Query caso ela não tenha sido especificada
932
933
934      adSlotDef.mediaQuery = adSlotDef.mediaQuery || this.labels[adSlotDef.label]; // Cria o objeto do slot
935
936      let adSlot = new AdSlot(this, adSlotDef); // Debug
937
938      Debug.info(`Inserindo slot ${adSlotDef.code} na lista de AdSlots:`, adSlotDef, adSlot); // Insere ele na lista de slots
939
940      this.adSlots.push(adSlot); // Retorna ele
941
942      return adSlot;
943    } // Registra quais slots podem receber bids
944
945
946    makeSlotBiddable(slot, autoBid) {
947      this.makeSlotUnbiddable(slot);
948      slot.isSlotBiddable = true;
949      this.biddableSlots.push(slot); // Detecta se usaremos autobid
950
951      autoBid = autoBid || false; // Depois de um breve intervalo (caso entre mais algum slot nesse tempo) disparar os bids
952
953      if (true == autoBid) {
954        // Reseta o timeout de auto-bid
955        if (this.makeSlotBiddableAutoBidTimeout) clearTimeout(this.makeSlotBiddableAutoBidTimeout); // Seta um novo timeout
956
957        this.makeSlotBiddableAutoBidTimeout = setTimeout(() => {
958          this.bid();
959        }, 50);
960      }
961    } // Indica que um determinado slot não pode receber bids
962
963
964    makeSlotUnbiddable(slot) {
965      slot.isSlotBiddable = false;
966      this.biddableSlots = this.biddableSlots.filter(biddableSlot => biddableSlot.code != slot.code);
967    } // Detecta se a página carregou
968
969
970    isPageReady() {
971      return document.readyState == 'complete' || document.readyState == 'interactive';
972    } // Coloca na fila de processamento para quando a página estiver "ready"
973
974
975    enqueueWhenPageReady(fn) {
976      // Se a página estiver pronta, executamos direto
977      if (this.isPageReady()) fn(); // Senão, colocamos na fila
978
979      this.queueOnPageReady.push(fn);
980    } // Processa a fila
981
982
983    handleWhenPageReady() {
984      // Não executa se não estiver pronto
985      if (!this.isPageReady()) return; // Debounce
986
987      if (this.isProcessingWhenPageReady) return;
988      this.isProcessingWhenPageReady = true; // Debug
989
990      if (this.queueOnPageReady.length > 0) Debug.info(`Carregamento da pagina concluido. Status atual: ${document.readyState}. Processando ${this.queueOnPageReady.length} eventos...`); // Processa fila
991
992      let fn = null;
993
994      while (fn = this.queueOnPageReady.shift()) {
995        if ('function' == typeof fn) fn();
996      } // Debounce (fim)
997
998
999      this.isProcessingWhenPageReady = false;
1000    } // Coloca na fila do Prebid
1001
1002
1003    enqueuePrebid(fn) {
1004      window.pbjs.que.push(fn);
1005    } // Coloca na fila do Prebid
1006
1007
1008    enqueueGpt(fn) {
1009      window.googletag.cmd.push(fn);
1010    } // Função que roda todos os bids
1011
1012
1013    bid() {
1014      // Evita que duas bids ocorram ao mesmo tempo
1015      if (this.bid.isBidding) return; // Marca como bid em andamento
1016
1017      this.bid.isBidding = true; // Salva os biddableSlots
1018
1019      let biddableSlots = this.biddableSlots; // Limpa os biddableSlots
1020
1021      this.biddableSlots.map(slot => {
1022        slot.isSlotBiddable = false;
1023      });
1024      this.biddableSlots = []; // Registro do que vai ser bidado
1025
1026      this.bidCurrently = []; // Bids para slots que usam Prebid
1027
1028      this.enqueuePrebid(() => {
1029        // Filtra slots que recebem bids do Prebid
1030        let biddablePrebid = biddableSlots.filter(slot => !!slot.registeredWith.prebid);
1031        let biddablePrebidCodes = biddablePrebid.map(slot => slot.code); // Marca os slots sendo bidados
1032
1033        this.bidCurrently = this.bidCurrently.concat(biddablePrebid); // Roda a bid
1034
1035        Debug.info('Prebid.requestBids:', biddablePrebidCodes);
1036        window.pbjs.requestBids({
1037          adUnitCodes: biddablePrebidCodes,
1038          bidsBackHandler: () => {
1039            this.handlePrebidBidsBack();
1040          }
1041        });
1042      }); // Bids para slots que não usam Prebid
1043
1044      this.enqueueGpt(() => {
1045        // Filtra slots que não recebem bids do Prebid
1046        let biddableNonPrebid = biddableSlots.filter(slot => !slot.registeredWith.prebid);
1047        let biddableNonPrebidSlots = biddableNonPrebid.map(slot => slot.registeredWith.gpt);
1048        let biddableNonPrebidCodes = biddableNonPrebid.map(slot => slot.code); // Debug
1049
1050        if (biddableNonPrebidSlots.length > 0) Debug.info('Processando slots GPT direto (sem Prebid)'); // Faz o refresh dos slots (exibindo os anúncios)
1051
1052        Debug.info('pubads().refresh:', biddableNonPrebidCodes.join(', '));
1053        window.googletag.pubads().refresh(biddableNonPrebidSlots);
1054      });
1055    } // Obtém o slot a partir de um ID
1056
1057
1058    getSlotFromId(elementId) {
1059      // Processa todos slots procurando nosso slot destino
1060      for (let iSlot = 0; iSlot < this.adSlots.length; iSlot++) {
1061        // Retorna ele diretamente se for encontrado
1062        if (this.adSlots[iSlot].code == elementId) return this.adSlots[iSlot];
1063      } // Retorna null se não encontrar
1064
1065
1066      return null;
1067    } // Processa evento de quando a impressão do slot foi vista
1068
1069
1070    handleGptImpressionViewable(event) {
1071      // Computa impressão no slot
1072      this.getSlotFromId(event.slot.getSlotElementId()).computeViewability();
1073    } // Processa evento de visiblidade do slot do GPT
1074
1075
1076    handleGptSlotViewability(event) {
1077      // Atualiza a visibilidade do slot
1078      this.getSlotFromId(event.slot.getSlotElementId()).updateViewablePercentage(event.inViewPercentage);
1079    } // Processa evento de render do GPT
1080
1081
1082    handleGptSlotRendered(event) {
1083      // Caso o anúncio vier vazio => PREJUÍZO AAAAAAAAAAAAAA
1084      if (event.isEmpty) {
1085        this.getSlotFromId(event.slot.getSlotElementId()).handleMissedImpression(event);
1086      }
1087    } // Processa TODOS eventos de um slot
1088
1089
1090    handleGptSlotState(eventName, event) {
1091      // Passa o evento para o slot
1092      this.getSlotFromId(event.slot.getSlotElementId()).handleStateChange(eventName, event);
1093    } // Processa resposta das bids do Prebid
1094
1095
1096    handlePrebidBidsBack() {
1097      // Agora que temos as bids simplesmente aguardamos a resposta do AdServer da Google
1098      Debug.info('Resposta de bids do Prebid recebida. Aguardando AdServer da Google...'); // Coloca na fila do GPT
1099
1100      this.enqueueGpt(() => {
1101        this.awaitForGoogleAdServer();
1102      });
1103    } // Parte final para exibir os anúncios
1104
1105
1106    awaitForGoogleAdServer() {
1107      // Se já inicializou está tudo ok.
1108      if (!!this.awaitForGoogleAdServer.initialized) return; // Verifica se o pubads já está disponível
1109
1110      if (!(window.googletag && window.googletag.pubadsReady)) {
1111        // Ainda não está disponível, aguardamos um pouco mais
1112        setTimeout(() => {
1113          this.awaitForGoogleAdServer();
1114        }, 50);
1115        return;
1116      } // Neste ponto o pubads está disponível, enfileramos no GPT para poder setar o targeting
1117
1118
1119      Debug.info('AdServer da Google pronto, prosseguindo!');
1120      this.awaitForGoogleAdServer.initialized = true; // Filtra quais slots serão setados
1121
1122      let prebidAdUnitCodes = this.bidCurrently.map(slot => slot.code); // Define o targeting do Prebid
1123
1124      Debug.info('Prebid.setTargetingForGPTAsync:', prebidAdUnitCodes.join(', '));
1125      window.pbjs.setTargetingForGPTAsync(prebidAdUnitCodes); // Força o refresh (exibição) dos slots
1126
1127      this.bidCurrently.map(slot => {
1128        slot.cleanup();
1129        slot.refresh();
1130      }); // Libera processamento das bids novamente
1131
1132      this.awaitForGoogleAdServer.initialized = false;
1133      this.bid.isBidding = false;
1134    } // Refresh GPT
1135
1136
1137    refreshGpt(slotData) {
1138      // Coloca o slot na fila
1139      this.refreshGptSlots.push(slotData); // Enfilera refresh
1140
1141      setTimeout(() => {
1142        // Debounce
1143        if (this.refreshGptIsRefreshing) return;
1144        this.refreshGptIsRefreshing = true; // Obtém os dados da fila e limpa ela
1145
1146        let refreshSlots = this.refreshGptSlots;
1147        this.refreshGptSlots = []; // Converte a fila em uma lista de slots
1148
1149        let refreshSlotsGpt = refreshSlots.map(slotData => slotData.slot);
1150        let refreshSlotsCodes = refreshSlots.map(slotData => slotData.code); // Debug
1151
1152        if (refreshSlotsGpt.length > 0) Debug.info('Processando refresh de slots...'); // Faz o refresh
1153
1154        if (refreshSlotsGpt.length > 0) {
1155          Debug.info('pubads().refresh:', refreshSlotsCodes);
1156          window.googletag.pubads().refresh(refreshSlotsGpt);
1157        } // Desativa debounce
1158
1159
1160        this.refreshGptIsRefreshing = false;
1161      }, 50);
1162    }
1163
1164  }, _temp5); // Registra a API na janela
1165
1166  window.TecnoblogAdBidding = TecnoblogAdBidding;
1167  window.TecnoblogAdBidding.Utils = Utils;
1168  window.TecnoblogAdBidding.AdSlot = AdSlot;
1169  window.TecnoblogAdBidding.Events = Events;
1170  window.TecnoblogAdBidding.ActivityTracker = ActivityTracker;
1171})();
1172

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.