valtech-components 2.0.500 → 2.0.501
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/atoms/button/button.component.mjs +87 -48
- package/esm2022/lib/components/molecules/action-header/action-header.component.mjs +1 -1
- package/esm2022/lib/components/molecules/ad-slot/ad-slot.component.mjs +249 -0
- package/esm2022/lib/components/molecules/button-group/button-group.component.mjs +1 -1
- package/esm2022/lib/components/molecules/card/card.component.mjs +2 -2
- package/esm2022/lib/components/molecules/file-input/file-input.component.mjs +1 -1
- package/esm2022/lib/components/molecules/raffle-status-card/raffle-status-card.component.mjs +2 -2
- package/esm2022/lib/components/organisms/article/article.component.mjs +2 -2
- package/esm2022/lib/components/organisms/menu/menu.component.mjs +1 -1
- package/esm2022/lib/components/templates/page-template/page-template.component.mjs +1 -1
- package/esm2022/lib/services/ads/ads-consent.service.mjs +152 -0
- package/esm2022/lib/services/ads/ads-loader.service.mjs +160 -0
- package/esm2022/lib/services/ads/ads.service.mjs +449 -0
- package/esm2022/lib/services/ads/config.mjs +118 -0
- package/esm2022/lib/services/ads/index.mjs +14 -0
- package/esm2022/lib/services/ads/types.mjs +23 -0
- package/esm2022/public-api.mjs +6 -1
- package/fesm2022/valtech-components.mjs +1330 -154
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/atoms/button/button.component.d.ts +30 -6
- package/lib/components/molecules/ad-slot/ad-slot.component.d.ts +78 -0
- package/lib/components/organisms/article/article.component.d.ts +3 -3
- package/lib/services/ads/ads-consent.service.d.ts +59 -0
- package/lib/services/ads/ads-loader.service.d.ts +46 -0
- package/lib/services/ads/ads.service.d.ts +123 -0
- package/lib/services/ads/config.d.ts +69 -0
- package/lib/services/ads/index.d.ts +10 -0
- package/lib/services/ads/types.d.ts +163 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ads Consent Service
|
|
3
|
+
*
|
|
4
|
+
* Integra el servicio de Ads con el Consent Mode v2 existente en AnalyticsService.
|
|
5
|
+
* Proporciona estado de consent especifico para ads (advertising).
|
|
6
|
+
*/
|
|
7
|
+
import { Injectable, Injector, PLATFORM_ID, inject, signal, computed } from '@angular/core';
|
|
8
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
9
|
+
import * as i0 from "@angular/core";
|
|
10
|
+
/**
|
|
11
|
+
* Servicio que maneja el consent para ads.
|
|
12
|
+
*
|
|
13
|
+
* Se integra con AnalyticsService para reutilizar el estado de consent GDPR.
|
|
14
|
+
* Si AnalyticsService no esta disponible, usa valores por defecto conservadores.
|
|
15
|
+
*/
|
|
16
|
+
export class AdsConsentService {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.platformId = inject(PLATFORM_ID);
|
|
19
|
+
this.injector = inject(Injector);
|
|
20
|
+
// Cache del estado de consent
|
|
21
|
+
this._consentState = signal({
|
|
22
|
+
adStorage: false,
|
|
23
|
+
adPersonalization: false,
|
|
24
|
+
adUserData: false,
|
|
25
|
+
});
|
|
26
|
+
/** Estado de consent para ads (readonly) */
|
|
27
|
+
this.adsConsentState = this._consentState.asReadonly();
|
|
28
|
+
/** Indica si se pueden mostrar ads (al menos consent basico) */
|
|
29
|
+
this.canShowAds = computed(() => {
|
|
30
|
+
// Siempre permitimos mostrar ads (pueden ser no personalizados)
|
|
31
|
+
// El control real esta en canPersonalize
|
|
32
|
+
return true;
|
|
33
|
+
});
|
|
34
|
+
/** Indica si se pueden mostrar ads personalizados */
|
|
35
|
+
this.canPersonalize = computed(() => {
|
|
36
|
+
const state = this._consentState();
|
|
37
|
+
return state.adStorage && state.adPersonalization && state.adUserData;
|
|
38
|
+
});
|
|
39
|
+
this.analyticsService = null;
|
|
40
|
+
this.consentSyncInterval = null;
|
|
41
|
+
if (isPlatformBrowser(this.platformId)) {
|
|
42
|
+
this.initializeConsentSync();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Inicializa la sincronizacion con AnalyticsService.
|
|
47
|
+
*/
|
|
48
|
+
initializeConsentSync() {
|
|
49
|
+
// Intentar obtener AnalyticsService de forma lazy
|
|
50
|
+
// Usamos setTimeout para dar tiempo a que se inicialice
|
|
51
|
+
setTimeout(() => {
|
|
52
|
+
this.syncWithAnalyticsConsent();
|
|
53
|
+
}, 100);
|
|
54
|
+
// Re-sincronizar periodicamente por si el usuario cambia consent
|
|
55
|
+
this.consentSyncInterval = setInterval(() => {
|
|
56
|
+
this.syncWithAnalyticsConsent();
|
|
57
|
+
}, 5000);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Sincroniza el estado de consent desde AnalyticsService.
|
|
61
|
+
*/
|
|
62
|
+
async syncWithAnalyticsConsent() {
|
|
63
|
+
try {
|
|
64
|
+
// Importar AnalyticsService dinamicamente
|
|
65
|
+
const { AnalyticsService } = await import('../firebase/analytics.service');
|
|
66
|
+
if (!this.analyticsService) {
|
|
67
|
+
this.analyticsService = this.injector.get(AnalyticsService, null);
|
|
68
|
+
}
|
|
69
|
+
if (this.analyticsService) {
|
|
70
|
+
// AnalyticsService expone consentState como signal
|
|
71
|
+
const consentState = this.analyticsService.consentState();
|
|
72
|
+
this.updateFromAnalyticsConsent(consentState.settings);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// AnalyticsService no disponible - usar defaults
|
|
77
|
+
this.setDefaultConsent();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Actualiza el estado de consent desde AnalyticsService.
|
|
82
|
+
*/
|
|
83
|
+
updateFromAnalyticsConsent(settings) {
|
|
84
|
+
const hasAdvertisingConsent = settings['advertising'] === true;
|
|
85
|
+
this._consentState.set({
|
|
86
|
+
adStorage: hasAdvertisingConsent,
|
|
87
|
+
adPersonalization: hasAdvertisingConsent,
|
|
88
|
+
adUserData: hasAdvertisingConsent,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Establece consent por defecto (sin datos personales).
|
|
93
|
+
*/
|
|
94
|
+
setDefaultConsent() {
|
|
95
|
+
this._consentState.set({
|
|
96
|
+
adStorage: false,
|
|
97
|
+
adPersonalization: false,
|
|
98
|
+
adUserData: false,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Actualiza manualmente el consent para ads.
|
|
103
|
+
* Usar cuando el usuario actualiza sus preferencias directamente.
|
|
104
|
+
*
|
|
105
|
+
* @param consent - Nuevo estado de consent parcial
|
|
106
|
+
*/
|
|
107
|
+
updateConsent(consent) {
|
|
108
|
+
this._consentState.update((current) => ({
|
|
109
|
+
...current,
|
|
110
|
+
...consent,
|
|
111
|
+
}));
|
|
112
|
+
// Notificar a GPT si ya esta cargado
|
|
113
|
+
this.applyConsentToGPT();
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Aplica el estado de consent actual a GPT.
|
|
117
|
+
*/
|
|
118
|
+
applyConsentToGPT() {
|
|
119
|
+
if (!isPlatformBrowser(this.platformId))
|
|
120
|
+
return;
|
|
121
|
+
const googletag = window.googletag;
|
|
122
|
+
if (!googletag)
|
|
123
|
+
return;
|
|
124
|
+
googletag.cmd.push(() => {
|
|
125
|
+
const canPersonalize = this.canPersonalize();
|
|
126
|
+
// 0 = personalized, 1 = non-personalized
|
|
127
|
+
googletag.pubads().setRequestNonPersonalizedAds(canPersonalize ? 0 : 1);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Obtiene el estado actual de consent.
|
|
132
|
+
*/
|
|
133
|
+
getConsentState() {
|
|
134
|
+
return this._consentState();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Destruye el servicio y limpia recursos.
|
|
138
|
+
*/
|
|
139
|
+
destroy() {
|
|
140
|
+
if (this.consentSyncInterval) {
|
|
141
|
+
clearInterval(this.consentSyncInterval);
|
|
142
|
+
this.consentSyncInterval = null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AdsConsentService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
146
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AdsConsentService, providedIn: 'root' }); }
|
|
147
|
+
}
|
|
148
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AdsConsentService, decorators: [{
|
|
149
|
+
type: Injectable,
|
|
150
|
+
args: [{ providedIn: 'root' }]
|
|
151
|
+
}], ctorParameters: () => [] });
|
|
152
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRzLWNvbnNlbnQuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvc2VydmljZXMvYWRzL2Fkcy1jb25zZW50LnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFFSCxPQUFPLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQVUsTUFBTSxlQUFlLENBQUM7QUFDcEcsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7O0FBR3BEOzs7OztHQUtHO0FBRUgsTUFBTSxPQUFPLGlCQUFpQjtJQThCNUI7UUE3QmlCLGVBQVUsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDakMsYUFBUSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUU3Qyw4QkFBOEI7UUFDYixrQkFBYSxHQUFHLE1BQU0sQ0FBa0I7WUFDdkQsU0FBUyxFQUFFLEtBQUs7WUFDaEIsaUJBQWlCLEVBQUUsS0FBSztZQUN4QixVQUFVLEVBQUUsS0FBSztTQUNsQixDQUFDLENBQUM7UUFFSCw0Q0FBNEM7UUFDbkMsb0JBQWUsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBRTNELGdFQUFnRTtRQUN2RCxlQUFVLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtZQUNsQyxnRUFBZ0U7WUFDaEUseUNBQXlDO1lBQ3pDLE9BQU8sSUFBSSxDQUFDO1FBQ2QsQ0FBQyxDQUFDLENBQUM7UUFFSCxxREFBcUQ7UUFDNUMsbUJBQWMsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1lBQ3RDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUNuQyxPQUFPLEtBQUssQ0FBQyxTQUFTLElBQUksS0FBSyxDQUFDLGlCQUFpQixJQUFJLEtBQUssQ0FBQyxVQUFV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LENBQUMsY0FBYyxFQUFFLENBQUM7WUFDN0MseUNBQXlDO1lBQ3pDLFNBQVMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyw0QkFBNEIsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDMUUsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxlQUFlO1FBQ2IsT0FBTyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsT0FBTztRQUNMLElBQUksSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7WUFDN0IsYUFBYSxDQUFDLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ3hDLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLENBQUM7UUFDbEMsQ0FBQztJQUNILENBQUM7K0dBbEpVLGlCQUFpQjttSEFBakIsaUJBQWlCLGNBREosTUFBTTs7NEZBQ25CLGlCQUFpQjtrQkFEN0IsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEFkcyBDb25zZW50IFNlcnZpY2VcbiAqXG4gKiBJbnRlZ3JhIGVsIHNlcnZpY2lvIGRlIEFkcyBjb24gZWwgQ29uc2VudCBNb2RlIHYyIGV4aXN0ZW50ZSBlbiBBbmFseXRpY3NTZXJ2aWNlLlxuICogUHJvcG9yY2lvbmEgZXN0YWRvIGRlIGNvbnNlbnQgZXNwZWNpZmljbyBwYXJhIGFkcyAoYWR2ZXJ0aXNpbmcpLlxuICovXG5cbmltcG9ydCB7IEluamVjdGFibGUsIEluamVjdG9yLCBQTEFURk9STV9JRCwgaW5qZWN0LCBzaWduYWwsIGNvbXB1dGVkLCBlZmZlY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IGlzUGxhdGZvcm1Ccm93c2VyIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IEFkc0NvbnNlbnRTdGF0ZSB9IGZyb20gJy4vdHlwZXMnO1xuXG4vKipcbiAqIFNlcnZpY2lvIHF1ZSBtYW5lamEgZWwgY29uc2VudCBwYXJhIGFkcy5cbiAqXG4gKiBTZSBpbnRlZ3JhIGNvbiBBbmFseXRpY3NTZXJ2aWNlIHBhcmEgcmV1dGlsaXphciBlbCBlc3RhZG8gZGUgY29uc2VudCBHRFBSLlxuICogU2kgQW5hbHl0aWNzU2VydmljZSBubyBlc3RhIGRpc3BvbmlibGUsIHVzYSB2YWxvcmVzIHBvciBkZWZlY3RvIGNvbnNlcnZhZG9yZXMuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgQWRzQ29uc2VudFNlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IHBsYXRmb3JtSWQgPSBpbmplY3QoUExBVEZPUk1fSUQpO1xuICBwcml2YXRlIHJlYWRvbmx5IGluamVjdG9yID0gaW5qZWN0KEluamVjdG9yKTtcblxuICAvLyBDYWNoZSBkZWwgZXN0YWRvIGRlIGNvbnNlbnRcbiAgcHJpdmF0ZSByZWFkb25seSBfY29uc2VudFN0YXRlID0gc2lnbmFsPEFkc0NvbnNlbnRTdGF0ZT4oe1xuICAgIGFkU3RvcmFnZTogZmFsc2UsXG4gICAgYWRQZXJzb25hbGl6YXRpb246IGZhbHNlLFxuICAgIGFkVXNlckRhdGE6IGZhbHNlLFxuICB9KTtcblxuICAvKiogRXN0YWRvIGRlIGNvbnNlbnQgcGFyYSBhZHMgKHJlYWRvbmx5KSAqL1xuICByZWFkb25seSBhZHNDb25zZW50U3RhdGUgPSB0aGlzLl9jb25zZW50U3RhdGUuYXNSZWFkb25seSgpO1xuXG4gIC8qKiBJbmRpY2Egc2kgc2UgcHVlZGVuIG1vc3RyYXIgYWRzIChhbCBtZW5vcyBjb25zZW50IGJhc2ljbykgKi9cbiAgcmVhZG9ubHkgY2FuU2hvd0FkcyA9IGNvbXB1dGVkKCgpID0+IHtcbiAgICAvLyBTaWVtcHJlIHBlcm1pdGltb3MgbW9zdHJhciBhZHMgKHB1ZWRlbiBzZXIgbm8gcGVyc29uYWxpemFkb3MpXG4gICAgLy8gRWwgY29udHJvbCByZWFsIGVzdGEgZW4gY2FuUGVyc29uYWxpemVcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSk7XG5cbiAgLyoqIEluZGljYSBzaSBzZSBwdWVkZW4gbW9zdHJhciBhZHMgcGVyc29uYWxpemFkb3MgKi9cbiAgcmVhZG9ubHkgY2FuUGVyc29uYWxpemUgPSBjb21wdXRlZCgoKSA9PiB7XG4gICAgY29uc3Qgc3RhdGUgPSB0aGlzLl9jb25zZW50U3RhdGUoKTtcbiAgICByZXR1cm4gc3RhdGUuYWRTdG9yYWdlICYmIHN0YXRlLmFkUGVyc29uYWxpemF0aW9uICYmIHN0YXRlLmFkVXNlckRhdGE7XG4gIH0pO1xuXG4gIHByaXZhdGUgYW5hbHl0aWNzU2VydmljZTogdW5rbm93biA9IG51bGw7XG4gIHByaXZhdGUgY29uc2VudFN5bmNJbnRlcnZhbDogUmV0dXJuVHlwZTx0eXBlb2Ygc2V0SW50ZXJ2YWw+IHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgaWYgKGlzUGxhdGZvcm1Ccm93c2VyKHRoaXMucGxhdGZvcm1JZCkpIHtcbiAgICAgIHRoaXMuaW5pdGlhbGl6ZUNvbnNlbnRTeW5jKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEluaWNpYWxpemEgbGEgc2luY3Jvbml6YWNpb24gY29uIEFuYWx5dGljc1NlcnZpY2UuXG4gICAqL1xuICBwcml2YXRlIGluaXRpYWxpemVDb25zZW50U3luYygpOiB2b2lkIHtcbiAgICAvLyBJbnRlbnRhciBvYnRlbmVyIEFuYWx5dGljc1NlcnZpY2UgZGUgZm9ybWEgbGF6eVxuICAgIC8vIFVzYW1vcyBzZXRUaW1lb3V0IHBhcmEgZGFyIHRpZW1wbyBhIHF1ZSBzZSBpbmljaWFsaWNlXG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLnN5bmNXaXRoQW5hbHl0aWNzQ29uc2VudCgpO1xuICAgIH0sIDEwMCk7XG5cbiAgICAvLyBSZS1zaW5jcm9uaXphciBwZXJpb2RpY2FtZW50ZSBwb3Igc2kgZWwgdXN1YXJpbyBjYW1iaWEgY29uc2VudFxuICAgIHRoaXMuY29uc2VudFN5bmNJbnRlcnZhbCA9IHNldEludGVydmFsKCgpID0+IHtcbiAgICAgIHRoaXMuc3luY1dpdGhBbmFseXRpY3NDb25zZW50KCk7XG4gICAgfSwgNTAwMCk7XG4gIH1cblxuICAvKipcbiAgICogU2luY3Jvbml6YSBlbCBlc3RhZG8gZGUgY29uc2VudCBkZXNkZSBBbmFseXRpY3NTZXJ2aWNlLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzeW5jV2l0aEFuYWx5dGljc0NvbnNlbnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIEltcG9ydGFyIEFuYWx5dGljc1NlcnZpY2UgZGluYW1pY2FtZW50ZVxuICAgICAgY29uc3QgeyBBbmFseXRpY3NTZXJ2aWNlIH0gPSBhd2FpdCBpbXBvcnQoJy4uL2ZpcmViYXNlL2FuYWx5dGljcy5zZXJ2aWNlJyk7XG5cbiAgICAgIGlmICghdGhpcy5hbmFseXRpY3NTZXJ2aWNlKSB7XG4gICAgICAgIHRoaXMuYW5hbHl0aWNzU2VydmljZSA9IHRoaXMuaW5qZWN0b3IuZ2V0KEFuYWx5dGljc1NlcnZpY2UsIG51bGwpO1xuICAgICAgfVxuXG4gICAgICBpZiAodGhpcy5hbmFseXRpY3NTZXJ2aWNlKSB7XG4gICAgICAgIC8vIEFuYWx5dGljc1NlcnZpY2UgZXhwb25lIGNvbnNlbnRTdGF0ZSBjb21vIHNpZ25hbFxuICAgICAgICBjb25zdCBjb25zZW50U3RhdGUgPSAodGhpcy5hbmFseXRpY3NTZXJ2aWNlIGFzIHsgY29uc2VudFN0YXRlOiAoKSA9PiB7IHNldHRpbmdzOiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuIHwgdW5kZWZpbmVkPiB9IH0pLmNvbnNlbnRTdGF0ZSgpO1xuICAgICAgICB0aGlzLnVwZGF0ZUZyb21BbmFseXRpY3NDb25zZW50KGNvbnNlbnRTdGF0ZS5zZXR0aW5ncyk7XG4gICAgICB9XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBBbmFseXRpY3NTZXJ2aWNlIG5vIGRpc3BvbmlibGUgLSB1c2FyIGRlZmF1bHRzXG4gICAgICB0aGlzLnNldERlZmF1bHRDb25zZW50KCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFjdHVhbGl6YSBlbCBlc3RhZG8gZGUgY29uc2VudCBkZXNkZSBBbmFseXRpY3NTZXJ2aWNlLlxuICAgKi9cbiAgcHJpdmF0ZSB1cGRhdGVGcm9tQW5hbHl0aWNzQ29uc2VudChzZXR0aW5nczogUmVjb3JkPHN0cmluZywgYm9vbGVhbiB8IHVuZGVmaW5lZD4pOiB2b2lkIHtcbiAgICBjb25zdCBoYXNBZHZlcnRpc2luZ0NvbnNlbnQgPSBzZXR0aW5nc1snYWR2ZXJ0aXNpbmcnXSA9PT0gdHJ1ZTtcblxuICAgIHRoaXMuX2NvbnNlbnRTdGF0ZS5zZXQoe1xuICAgICAgYWRTdG9yYWdlOiBoYXNBZHZlcnRpc2luZ0NvbnNlbnQsXG4gICAgICBhZFBlcnNvbmFsaXphdGlvbjogaGFzQWR2ZXJ0aXNpbmdDb25zZW50LFxuICAgICAgYWRVc2VyRGF0YTogaGFzQWR2ZXJ0aXNpbmdDb25zZW50LFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEVzdGFibGVjZSBjb25zZW50IHBvciBkZWZlY3RvIChzaW4gZGF0b3MgcGVyc29uYWxlcykuXG4gICAqL1xuICBwcml2YXRlIHNldERlZmF1bHRDb25zZW50KCk6IHZvaWQge1xuICAgIHRoaXMuX2NvbnNlbnRTdGF0ZS5zZXQoe1xuICAgICAgYWRTdG9yYWdlOiBmYWxzZSxcbiAgICAgIGFkUGVyc29uYWxpemF0aW9uOiBmYWxzZSxcbiAgICAgIGFkVXNlckRhdGE6IGZhbHNlLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFjdHVhbGl6YSBtYW51YWxtZW50ZSBlbCBjb25zZW50IHBhcmEgYWRzLlxuICAgKiBVc2FyIGN1YW5kbyBlbCB1c3VhcmlvIGFjdHVhbGl6YSBzdXMgcHJlZmVyZW5jaWFzIGRpcmVjdGFtZW50ZS5cbiAgICpcbiAgICogQHBhcmFtIGNvbnNlbnQgLSBOdWV2byBlc3RhZG8gZGUgY29uc2VudCBwYXJjaWFsXG4gICAqL1xuICB1cGRhdGVDb25zZW50KGNvbnNlbnQ6IFBhcnRpYWw8QWRzQ29uc2VudFN0YXRlPik6IHZvaWQge1xuICAgIHRoaXMuX2NvbnNlbnRTdGF0ZS51cGRhdGUoKGN1cnJlbnQpID0+ICh7XG4gICAgICAuLi5jdXJyZW50LFxuICAgICAgLi4uY29uc2VudCxcbiAgICB9KSk7XG5cbiAgICAvLyBOb3RpZmljYXIgYSBHUFQgc2kgeWEgZXN0YSBjYXJnYWRvXG4gICAgdGhpcy5hcHBseUNvbnNlbnRUb0dQVCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFwbGljYSBlbCBlc3RhZG8gZGUgY29uc2VudCBhY3R1YWwgYSBHUFQuXG4gICAqL1xuICBhcHBseUNvbnNlbnRUb0dQVCgpOiB2b2lkIHtcbiAgICBpZiAoIWlzUGxhdGZvcm1Ccm93c2VyKHRoaXMucGxhdGZvcm1JZCkpIHJldHVybjtcblxuICAgIGNvbnN0IGdvb2dsZXRhZyA9IHdpbmRvdy5nb29nbGV0YWc7XG4gICAgaWYgKCFnb29nbGV0YWcpIHJldHVybjtcblxuICAgIGdvb2dsZXRhZy5jbWQucHVzaCgoKSA9PiB7XG4gICAgICBjb25zdCBjYW5QZXJzb25hbGl6ZSA9IHRoaXMuY2FuUGVyc29uYWxpemUoKTtcbiAgICAgIC8vIDAgPSBwZXJzb25hbGl6ZWQsIDEgPSBub24tcGVyc29uYWxpemVkXG4gICAgICBnb29nbGV0YWcucHViYWRzKCkuc2V0UmVxdWVzdE5vblBlcnNvbmFsaXplZEFkcyhjYW5QZXJzb25hbGl6ZSA/IDAgOiAxKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnRpZW5lIGVsIGVzdGFkbyBhY3R1YWwgZGUgY29uc2VudC5cbiAgICovXG4gIGdldENvbnNlbnRTdGF0ZSgpOiBBZHNDb25zZW50U3RhdGUge1xuICAgIHJldHVybiB0aGlzLl9jb25zZW50U3RhdGUoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXN0cnV5ZSBlbCBzZXJ2aWNpbyB5IGxpbXBpYSByZWN1cnNvcy5cbiAgICovXG4gIGRlc3Ryb3koKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuY29uc2VudFN5bmNJbnRlcnZhbCkge1xuICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmNvbnNlbnRTeW5jSW50ZXJ2YWwpO1xuICAgICAgdGhpcy5jb25zZW50U3luY0ludGVydmFsID0gbnVsbDtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ads Loader Service
|
|
3
|
+
*
|
|
4
|
+
* Maneja la carga lazy del script GPT (Google Publisher Tag).
|
|
5
|
+
* Solo carga el script cuando se necesita el primer ad.
|
|
6
|
+
*/
|
|
7
|
+
import { Injectable, Inject, PLATFORM_ID, signal } from '@angular/core';
|
|
8
|
+
import { isPlatformBrowser } from '@angular/common';
|
|
9
|
+
import { VALTECH_ADS_CONFIG } from './config';
|
|
10
|
+
import * as i0 from "@angular/core";
|
|
11
|
+
import * as i1 from "./ads-consent.service";
|
|
12
|
+
/** URL del script GPT */
|
|
13
|
+
const GPT_SCRIPT_URL = 'https://securepubads.g.doubleclick.net/tag/js/gpt.js';
|
|
14
|
+
/**
|
|
15
|
+
* Servicio para cargar el script de Google Publisher Tags.
|
|
16
|
+
*
|
|
17
|
+
* Implementa lazy loading: el script solo se carga cuando
|
|
18
|
+
* se solicita renderizar el primer ad slot.
|
|
19
|
+
*/
|
|
20
|
+
export class AdsLoaderService {
|
|
21
|
+
constructor(config, platformId, consentService) {
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.platformId = platformId;
|
|
24
|
+
this.consentService = consentService;
|
|
25
|
+
this._isLoading = signal(false);
|
|
26
|
+
this._isLoaded = signal(false);
|
|
27
|
+
this._error = signal(null);
|
|
28
|
+
/** Indica si el script esta cargando */
|
|
29
|
+
this.isLoading = this._isLoading.asReadonly();
|
|
30
|
+
/** Indica si el script esta cargado */
|
|
31
|
+
this.isLoaded = this._isLoaded.asReadonly();
|
|
32
|
+
/** Error de carga (si existe) */
|
|
33
|
+
this.error = this._error.asReadonly();
|
|
34
|
+
this.loadPromise = null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Carga el script GPT de forma lazy.
|
|
38
|
+
* Retorna la instancia de googletag o null si falla.
|
|
39
|
+
*
|
|
40
|
+
* @returns Promise con googletag o null
|
|
41
|
+
*/
|
|
42
|
+
loadGPT() {
|
|
43
|
+
// SSR check
|
|
44
|
+
if (!isPlatformBrowser(this.platformId)) {
|
|
45
|
+
return Promise.resolve(null);
|
|
46
|
+
}
|
|
47
|
+
// Ya cargado
|
|
48
|
+
if (this._isLoaded() && window.googletag) {
|
|
49
|
+
return Promise.resolve(window.googletag);
|
|
50
|
+
}
|
|
51
|
+
// Ya hay una carga en progreso
|
|
52
|
+
if (this.loadPromise) {
|
|
53
|
+
return this.loadPromise;
|
|
54
|
+
}
|
|
55
|
+
this._isLoading.set(true);
|
|
56
|
+
this._error.set(null);
|
|
57
|
+
this.loadPromise = new Promise((resolve) => {
|
|
58
|
+
// Inicializar cmd queue
|
|
59
|
+
window.googletag = window.googletag || { cmd: [] };
|
|
60
|
+
const googletag = window.googletag;
|
|
61
|
+
// Crear script
|
|
62
|
+
const script = document.createElement('script');
|
|
63
|
+
script.async = true;
|
|
64
|
+
script.src = GPT_SCRIPT_URL;
|
|
65
|
+
script.onload = () => {
|
|
66
|
+
googletag.cmd.push(() => {
|
|
67
|
+
this.configureGPT(googletag);
|
|
68
|
+
this._isLoaded.set(true);
|
|
69
|
+
this._isLoading.set(false);
|
|
70
|
+
if (this.config.debugMode) {
|
|
71
|
+
console.log('[ValtechAds] Script GPT cargado y configurado');
|
|
72
|
+
}
|
|
73
|
+
resolve(googletag);
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
script.onerror = (error) => {
|
|
77
|
+
console.error('[ValtechAds] Error cargando GPT:', error);
|
|
78
|
+
this._error.set(new Error('Error cargando Google Publisher Tag'));
|
|
79
|
+
this._isLoading.set(false);
|
|
80
|
+
this.loadPromise = null;
|
|
81
|
+
resolve(null);
|
|
82
|
+
};
|
|
83
|
+
// Insertar script
|
|
84
|
+
const firstScript = document.getElementsByTagName('script')[0];
|
|
85
|
+
firstScript.parentNode?.insertBefore(script, firstScript);
|
|
86
|
+
});
|
|
87
|
+
return this.loadPromise;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Configura GPT con las opciones de la aplicacion.
|
|
91
|
+
*/
|
|
92
|
+
configureGPT(googletag) {
|
|
93
|
+
const pubads = googletag.pubads();
|
|
94
|
+
// Single Request Architecture para mejor performance
|
|
95
|
+
pubads.enableSingleRequest();
|
|
96
|
+
// Colapsar divs vacios antes de fetch
|
|
97
|
+
pubads.collapseEmptyDivs(true);
|
|
98
|
+
// Lazy loading nativo de GPT
|
|
99
|
+
if (this.config.lazyLoad && this.config.lazyLoadConfig) {
|
|
100
|
+
pubads.enableLazyLoad({
|
|
101
|
+
fetchMarginPercent: this.config.lazyLoadConfig.fetchMarginPercent,
|
|
102
|
+
renderMarginPercent: this.config.lazyLoadConfig.renderMarginPercent,
|
|
103
|
+
mobileScaling: 2.0,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Targeting global
|
|
107
|
+
if (this.config.globalTargeting) {
|
|
108
|
+
for (const [key, value] of Object.entries(this.config.globalTargeting)) {
|
|
109
|
+
pubads.setTargeting(key, value);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Non-personalized ads segun consent
|
|
113
|
+
if (!this.consentService.canPersonalize()) {
|
|
114
|
+
pubads.setRequestNonPersonalizedAds(1);
|
|
115
|
+
}
|
|
116
|
+
// Event listeners
|
|
117
|
+
pubads.addEventListener('slotRenderEnded', (event) => {
|
|
118
|
+
const slotId = event.slot.getSlotElementId();
|
|
119
|
+
if (this.config.debugMode) {
|
|
120
|
+
console.log(`[ValtechAds] Slot ${slotId} rendered, empty: ${event.isEmpty}`);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
// Debug mode
|
|
124
|
+
if (this.config.debugMode) {
|
|
125
|
+
console.log('[ValtechAds] GPT configurado:', {
|
|
126
|
+
lazyLoad: this.config.lazyLoad,
|
|
127
|
+
personalized: this.consentService.canPersonalize(),
|
|
128
|
+
targeting: this.config.globalTargeting,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Verifica si el script GPT esta disponible.
|
|
134
|
+
*/
|
|
135
|
+
isGPTAvailable() {
|
|
136
|
+
return isPlatformBrowser(this.platformId) && !!window.googletag && this._isLoaded();
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Obtiene la instancia de googletag si esta cargada.
|
|
140
|
+
*/
|
|
141
|
+
getGPT() {
|
|
142
|
+
if (this.isGPTAvailable()) {
|
|
143
|
+
return window.googletag;
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AdsLoaderService, deps: [{ token: VALTECH_ADS_CONFIG }, { token: PLATFORM_ID }, { token: i1.AdsConsentService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
148
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AdsLoaderService, providedIn: 'root' }); }
|
|
149
|
+
}
|
|
150
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AdsLoaderService, decorators: [{
|
|
151
|
+
type: Injectable,
|
|
152
|
+
args: [{ providedIn: 'root' }]
|
|
153
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
154
|
+
type: Inject,
|
|
155
|
+
args: [VALTECH_ADS_CONFIG]
|
|
156
|
+
}] }, { type: Object, decorators: [{
|
|
157
|
+
type: Inject,
|
|
158
|
+
args: [PLATFORM_ID]
|
|
159
|
+
}] }, { type: i1.AdsConsentService }] });
|
|
160
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRzLWxvYWRlci5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9hZHMvYWRzLWxvYWRlci5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN4RSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUVwRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxVQUFVLENBQUM7OztBQUk5Qyx5QkFBeUI7QUFDekIsTUFBTSxjQUFjLEdBQUcsc0RBQXNELENBQUM7QUFFOUU7Ozs7O0dBS0c7QUFFSCxNQUFNLE9BQU8sZ0JBQWdCO0lBZ0IzQixZQUNzQyxNQUF3QixFQUMvQixVQUFrQixFQUN2QyxjQUFpQztRQUZMLFdBQU0sR0FBTixNQUFNLENBQWtCO1FBQy9CLGVBQVUsR0FBVixVQUFVLENBQVE7UUFDdkMsbUJBQWMsR0FBZCxjQUFjLENBQW1CO1FBbEIxQixlQUFVLEdBQUcsTUFBTSxDQUFVLEtBQUssQ0FBQyxDQUFDO1FBQ3BDLGNBQVMsR0FBRyxNQUFNLENBQVUsS0FBSyxDQUFDLENBQUM7UUFDbkMsV0FBTSxHQUFHLE1BQU0sQ0FBZSxJQUFJLENBQUMsQ0FBQztRQUVyRCx3Q0FBd0M7UUFDL0IsY0FBUyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsVUFBVSxFQUFFLENBQUM7UUFFbEQsdUNBQXVDO1FBQzlCLGFBQVEsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBRWhELGlDQUFpQztRQUN4QixVQUFLLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUVsQyxnQkFBVyxHQUF3QyxJQUFJLENBQUM7SUFNN0QsQ0FBQztJQUVKOzs7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QUUsQ0FBQztnQkFDMUIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsTUFBTSxxQkFBcUIsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7WUFDL0UsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsYUFBYTtRQUNiLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUMxQixPQUFPLENBQUMsR0FBRyxDQUFDLCtCQUErQixFQUFFO2dCQUMzQyxRQUFRLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRO2dCQUM5QixZQUFZLEVBQUUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxjQUFjLEVBQUU7Z0JBQ2xELFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWU7YUFDdkMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILGNBQWM7UUFDWixPQUFPLGlCQUFpQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7SUFDdEYsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTTtRQUNKLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUM7WUFDMUIsT0FBTyxNQUFNLENBQUMsU0FBVSxDQUFDO1FBQzNCLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7K0dBekpVLGdCQUFnQixrQkFpQmpCLGtCQUFrQixhQUNsQixXQUFXO21IQWxCVixnQkFBZ0IsY0FESCxNQUFNOzs0RkFDbkIsZ0JBQWdCO2tCQUQ1QixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRTs7MEJBa0I3QixNQUFNOzJCQUFDLGtCQUFrQjs7MEJBQ3pCLE1BQU07MkJBQUMsV0FBVyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQWRzIExvYWRlciBTZXJ2aWNlXG4gKlxuICogTWFuZWphIGxhIGNhcmdhIGxhenkgZGVsIHNjcmlwdCBHUFQgKEdvb2dsZSBQdWJsaXNoZXIgVGFnKS5cbiAqIFNvbG8gY2FyZ2EgZWwgc2NyaXB0IGN1YW5kbyBzZSBuZWNlc2l0YSBlbCBwcmltZXIgYWQuXG4gKi9cblxuaW1wb3J0IHsgSW5qZWN0YWJsZSwgSW5qZWN0LCBQTEFURk9STV9JRCwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBpc1BsYXRmb3JtQnJvd3NlciB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5cbmltcG9ydCB7IFZBTFRFQ0hfQURTX0NPTkZJRyB9IGZyb20gJy4vY29uZmlnJztcbmltcG9ydCB7IFZhbHRlY2hBZHNDb25maWcsIEdQVE5hbWVzcGFjZSB9IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgQWRzQ29uc2VudFNlcnZpY2UgfSBmcm9tICcuL2Fkcy1jb25zZW50LnNlcnZpY2UnO1xuXG4vKiogVVJMIGRlbCBzY3JpcHQgR1BUICovXG5jb25zdCBHUFRfU0NSSVBUX1VSTCA9ICdodHRwczovL3NlY3VyZXB1YmFkcy5nLmRvdWJsZWNsaWNrLm5ldC90YWcvanMvZ3B0LmpzJztcblxuLyoqXG4gKiBTZXJ2aWNpbyBwYXJhIGNhcmdhciBlbCBzY3JpcHQgZGUgR29vZ2xlIFB1Ymxpc2hlciBUYWdzLlxuICpcbiAqIEltcGxlbWVudGEgbGF6eSBsb2FkaW5nOiBlbCBzY3JpcHQgc29sbyBzZSBjYXJnYSBjdWFuZG9cbiAqIHNlIHNvbGljaXRhIHJlbmRlcml6YXIgZWwgcHJpbWVyIGFkIHNsb3QuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgQWRzTG9hZGVyU2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2lzTG9hZGluZyA9IHNpZ25hbDxib29sZWFuPihmYWxzZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgX2lzTG9hZGVkID0gc2lnbmFsPGJvb2xlYW4+KGZhbHNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfZXJyb3IgPSBzaWduYWw8RXJyb3IgfCBudWxsPihudWxsKTtcblxuICAvKiogSW5kaWNhIHNpIGVsIHNjcmlwdCBlc3RhIGNhcmdhbmRvICovXG4gIHJlYWRvbmx5IGlzTG9hZGluZyA9IHRoaXMuX2lzTG9hZGluZy5hc1JlYWRvbmx5KCk7XG5cbiAgLyoqIEluZGljYSBzaSBlbCBzY3JpcHQgZXN0YSBjYXJnYWRvICovXG4gIHJlYWRvbmx5IGlzTG9hZGVkID0gdGhpcy5faXNMb2FkZWQuYXNSZWFkb25seSgpO1xuXG4gIC8qKiBFcnJvciBkZSBjYXJnYSAoc2kgZXhpc3RlKSAqL1xuICByZWFkb25seSBlcnJvciA9IHRoaXMuX2Vycm9yLmFzUmVhZG9ubHkoKTtcblxuICBwcml2YXRlIGxvYWRQcm9taXNlOiBQcm9taXNlPEdQVE5hbWVzcGFjZSB8IG51bGw+IHwgbnVsbCA9IG51bGw7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChWQUxURUNIX0FEU19DT05GSUcpIHByaXZhdGUgY29uZmlnOiBWYWx0ZWNoQWRzQ29uZmlnLFxuICAgIEBJbmplY3QoUExBVEZPUk1fSUQpIHByaXZhdGUgcGxhdGZvcm1JZDogT2JqZWN0LFxuICAgIHByaXZhdGUgY29uc2VudFNlcnZpY2U6IEFkc0NvbnNlbnRTZXJ2aWNlXG4gICkge31cblxuICAvKipcbiAgICogQ2FyZ2EgZWwgc2NyaXB0IEdQVCBkZSBmb3JtYSBsYXp5LlxuICAgKiBSZXRvcm5hIGxhIGluc3RhbmNpYSBkZSBnb29nbGV0YWcgbyBudWxsIHNpIGZhbGxhLlxuICAgKlxuICAgKiBAcmV0dXJucyBQcm9taXNlIGNvbiBnb29nbGV0YWcgbyBudWxsXG4gICAqL1xuICBsb2FkR1BUKCk6IFByb21pc2U8R1BUTmFtZXNwYWNlIHwgbnVsbD4ge1xuICAgIC8vIFNTUiBjaGVja1xuICAgIGlmICghaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5wbGF0Zm9ybUlkKSkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShudWxsKTtcbiAgICB9XG5cbiAgICAvLyBZYSBjYXJnYWRvXG4gICAgaWYgKHRoaXMuX2lzTG9hZGVkKCkgJiYgd2luZG93Lmdvb2dsZXRhZykge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh3aW5kb3cuZ29vZ2xldGFnKTtcbiAgICB9XG5cbiAgICAvLyBZYSBoYXkgdW5hIGNhcmdhIGVuIHByb2dyZXNvXG4gICAgaWYgKHRoaXMubG9hZFByb21pc2UpIHtcbiAgICAgIHJldHVybiB0aGlzLmxvYWRQcm9taXNlO1xuICAgIH1cblxuICAgIHRoaXMuX2lzTG9hZGluZy5zZXQodHJ1ZSk7XG4gICAgdGhpcy5fZXJyb3Iuc2V0KG51bGwpO1xuXG4gICAgdGhpcy5sb2FkUHJvbWlzZSA9IG5ldyBQcm9taXNlPEdQVE5hbWVzcGFjZSB8IG51bGw+KChyZXNvbHZlKSA9PiB7XG4gICAgICAvLyBJbmljaWFsaXphciBjbWQgcXVldWVcbiAgICAgIHdpbmRvdy5nb29nbGV0YWcgPSB3aW5kb3cuZ29vZ2xldGFnIHx8ICh7IGNtZDogW10gfSBhcyBHUFROYW1lc3BhY2UpO1xuICAgICAgY29uc3QgZ29vZ2xldGFnID0gd2luZG93Lmdvb2dsZXRhZztcblxuICAgICAgLy8gQ3JlYXIgc2NyaXB0XG4gICAgICBjb25zdCBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtcbiAgICAgIHNjcmlwdC5hc3luYyA9IHRydWU7XG4gICAgICBzY3JpcHQuc3JjID0gR1BUX1NDUklQVF9VUkw7XG5cbiAgICAgIHNjcmlwdC5vbmxvYWQgPSAoKSA9PiB7XG4gICAgICAgIGdvb2dsZXRhZy5jbWQucHVzaCgoKSA9PiB7XG4gICAgICAgICAgdGhpcy5jb25maWd1cmVHUFQoZ29vZ2xldGFnKTtcbiAgICAgICAgICB0aGlzLl9pc0xvYWRlZC5zZXQodHJ1ZSk7XG4gICAgICAgICAgdGhpcy5faXNMb2FkaW5nLnNldChmYWxzZSk7XG5cbiAgICAgICAgICBpZiAodGhpcy5jb25maWcuZGVidWdNb2RlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnW1ZhbHRlY2hBZHNdIFNjcmlwdCBHUFQgY2FyZ2FkbyB5IGNvbmZpZ3VyYWRvJyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmVzb2x2ZShnb29nbGV0YWcpO1xuICAgICAgICB9KTtcbiAgICAgIH07XG5cbiAgICAgIHNjcmlwdC5vbmVycm9yID0gKGVycm9yKSA9PiB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ1tWYWx0ZWNoQWRzXSBFcnJvciBjYXJnYW5kbyBHUFQ6JywgZXJyb3IpO1xuICAgICAgICB0aGlzLl9lcnJvci5zZXQobmV3IEVycm9yKCdFcnJvciBjYXJnYW5kbyBHb29nbGUgUHVibGlzaGVyIFRhZycpKTtcbiAgICAgICAgdGhpcy5faXNMb2FkaW5nLnNldChmYWxzZSk7XG4gICAgICAgIHRoaXMubG9hZFByb21pc2UgPSBudWxsO1xuICAgICAgICByZXNvbHZlKG51bGwpO1xuICAgICAgfTtcblxuICAgICAgLy8gSW5zZXJ0YXIgc2NyaXB0XG4gICAgICBjb25zdCBmaXJzdFNjcmlwdCA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKVswXTtcbiAgICAgIGZpcnN0U2NyaXB0LnBhcmVudE5vZGU/Lmluc2VydEJlZm9yZShzY3JpcHQsIGZpcnN0U2NyaXB0KTtcbiAgICB9KTtcblxuICAgIHJldHVybiB0aGlzLmxvYWRQcm9taXNlO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbmZpZ3VyYSBHUFQgY29uIGxhcyBvcGNpb25lcyBkZSBsYSBhcGxpY2FjaW9uLlxuICAgKi9cbiAgcHJpdmF0ZSBjb25maWd1cmVHUFQoZ29vZ2xldGFnOiBHUFROYW1lc3BhY2UpOiB2b2lkIHtcbiAgICBjb25zdCBwdWJhZHMgPSBnb29nbGV0YWcucHViYWRzKCk7XG5cbiAgICAvLyBTaW5nbGUgUmVxdWVzdCBBcmNoaXRlY3R1cmUgcGFyYSBtZWpvciBwZXJmb3JtYW5jZVxuICAgIHB1YmFkcy5lbmFibGVTaW5nbGVSZXF1ZXN0KCk7XG5cbiAgICAvLyBDb2xhcHNhciBkaXZzIHZhY2lvcyBhbnRlcyBkZSBmZXRjaFxuICAgIHB1YmFkcy5jb2xsYXBzZUVtcHR5RGl2cyh0cnVlKTtcblxuICAgIC8vIExhenkgbG9hZGluZyBuYXRpdm8gZGUgR1BUXG4gICAgaWYgKHRoaXMuY29uZmlnLmxhenlMb2FkICYmIHRoaXMuY29uZmlnLmxhenlMb2FkQ29uZmlnKSB7XG4gICAgICBwdWJhZHMuZW5hYmxlTGF6eUxvYWQoe1xuICAgICAgICBmZXRjaE1hcmdpblBlcmNlbnQ6IHRoaXMuY29uZmlnLmxhenlMb2FkQ29uZmlnLmZldGNoTWFyZ2luUGVyY2VudCxcbiAgICAgICAgcmVuZGVyTWFyZ2luUGVyY2VudDogdGhpcy5jb25maWcubGF6eUxvYWRDb25maWcucmVuZGVyTWFyZ2luUGVyY2VudCxcbiAgICAgICAgbW9iaWxlU2NhbGluZzogMi4wLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gVGFyZ2V0aW5nIGdsb2JhbFxuICAgIGlmICh0aGlzLmNvbmZpZy5nbG9iYWxUYXJnZXRpbmcpIHtcbiAgICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMuY29uZmlnLmdsb2JhbFRhcmdldGluZykpIHtcbiAgICAgICAgcHViYWRzLnNldFRhcmdldGluZyhrZXksIHZhbHVlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBOb24tcGVyc29uYWxpemVkIGFkcyBzZWd1biBjb25zZW50XG4gICAgaWYgKCF0aGlzLmNvbnNlbnRTZXJ2aWNlLmNhblBlcnNvbmFsaXplKCkpIHtcbiAgICAgIHB1YmFkcy5zZXRSZXF1ZXN0Tm9uUGVyc29uYWxpemVkQWRzKDEpO1xuICAgIH1cblxuICAgIC8vIEV2ZW50IGxpc3RlbmVyc1xuICAgIHB1YmFkcy5hZGRFdmVudExpc3RlbmVyKCdzbG90UmVuZGVyRW5kZWQnLCAoZXZlbnQpID0+IHtcbiAgICAgIGNvbnN0IHNsb3RJZCA9IGV2ZW50LnNsb3QuZ2V0U2xvdEVsZW1lbnRJZCgpO1xuICAgICAgaWYgKHRoaXMuY29uZmlnLmRlYnVnTW9kZSkge1xuICAgICAgICBjb25zb2xlLmxvZyhgW1ZhbHRlY2hBZHNdIFNsb3QgJHtzbG90SWR9IHJlbmRlcmVkLCBlbXB0eTogJHtldmVudC5pc0VtcHR5fWApO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gRGVidWcgbW9kZVxuICAgIGlmICh0aGlzLmNvbmZpZy5kZWJ1Z01vZGUpIHtcbiAgICAgIGNvbnNvbGUubG9nKCdbVmFsdGVjaEFkc10gR1BUIGNvbmZpZ3VyYWRvOicsIHtcbiAgICAgICAgbGF6eUxvYWQ6IHRoaXMuY29uZmlnLmxhenlMb2FkLFxuICAgICAgICBwZXJzb25hbGl6ZWQ6IHRoaXMuY29uc2VudFNlcnZpY2UuY2FuUGVyc29uYWxpemUoKSxcbiAgICAgICAgdGFyZ2V0aW5nOiB0aGlzLmNvbmZpZy5nbG9iYWxUYXJnZXRpbmcsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpY2Egc2kgZWwgc2NyaXB0IEdQVCBlc3RhIGRpc3BvbmlibGUuXG4gICAqL1xuICBpc0dQVEF2YWlsYWJsZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gaXNQbGF0Zm9ybUJyb3dzZXIodGhpcy5wbGF0Zm9ybUlkKSAmJiAhIXdpbmRvdy5nb29nbGV0YWcgJiYgdGhpcy5faXNMb2FkZWQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnRpZW5lIGxhIGluc3RhbmNpYSBkZSBnb29nbGV0YWcgc2kgZXN0YSBjYXJnYWRhLlxuICAgKi9cbiAgZ2V0R1BUKCk6IEdQVE5hbWVzcGFjZSB8IG51bGwge1xuICAgIGlmICh0aGlzLmlzR1BUQXZhaWxhYmxlKCkpIHtcbiAgICAgIHJldHVybiB3aW5kb3cuZ29vZ2xldGFnITtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cbiJdfQ==
|