HEX
Server: Apache/2
System: Linux host.jethost.pl 4.19.0-26-amd64 #1 SMP Debian 4.19.304-1 (2024-01-09) x86_64
User: frigodor (1049)
PHP: 7.4.33
Disabled: exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname,mail
Upload Files
File: /home/frigodor/public_html/wp-content/plugins/complianz-gdpr-premium/pro/tcf/src/index.js
/**
 * Resources
 * https://github.com/InteractiveAdvertisingBureau/iabtcf-es
 * */
import {CmpApi} from '@iabtcf/cmpapi';
import {TCModel, TCString, GVL, Segment} from '@iabtcf/core';
import UsprivacyString from '../ccpa/src/uspapi.js';
const cmplzCMP = 332;
const cmplzCMPVersion = 1;
const cmplzIsServiceSpecific = cmplz_tcf.isServiceSpecific == 1 ? true : false;
const cmplzExistingLanguages = ['gl','eu','bg', 'ca', 'cs', 'da', 'de', 'el', 'es', 'et', 'fi', 'fr', 'hr', 'hu', 'it', 'ja', 'lt', 'lv', 'mt', 'nl', 'no', 'pl', 'pt', 'ro', 'ru', 'sk', 'sl', 'sr', 'sv', 'tr', 'zh',];
let langCount = cmplzExistingLanguages.length;
let cmplz_html_lang_attr =  document.documentElement.lang.length ? document.documentElement.lang.toLowerCase() : 'en';
let cmplzLanguage = 'en';
for (let i = 0; i < langCount; i++) {
	let cmplzLocale = cmplzExistingLanguages[i];
	//needs to be exact match, as for example "ca" (catalan) occurs in "fr-ca", which should only match on "fr"
	if ( cmplz_html_lang_attr.indexOf(cmplzLocale)===0 ) {
		cmplzLanguage = cmplzLocale;
		break;
	}
}
if (cmplzLanguage==='eu') cmplzLanguage='eus';
let cmplzLanguageJson;
let dataCategories = [];
let ACVendors = [];
let useAcVendors = cmplz_tcf.ac_mode;

let onOptOutPolicyPage = document.getElementById('cmplz-tcf-us-vendor-container') !== null;
let onOptInPolicyPage = document.getElementById('cmplz-tcf-vendor-container') !== null;
/**
 * initialize the __tcfapi function and post message
 * https://github.com/InteractiveAdvertisingBureau/iabtcf-es/tree/master/modules/stub
 */

let ACVendorsUrl = cmplz_tcf.cmp_url + 'cmp/vendorlist/additional-consent-providers.csv';
let purposesUrl = cmplz_tcf.cmp_url+'cmp/vendorlist'+'/purposes-'+cmplzLanguage+'.json';
if (!cmplzExistingLanguages.includes(cmplzLanguage)) {
	cmplzLanguage = 'en';
	purposesUrl = cmplz_tcf.cmp_url + 'cmp/vendorlist' + '/vendor-list.json';
}

/**
 * Get a cookie by name
 * @param name
 * @returns {string}
 */

function cmplz_tcf_get_cookie(name) {
	if ( typeof document === "undefined" ) {
		return "";
	}
	let prefix = typeof complianz !== "undefined" ? complianz.prefix : 'cmplz_';
	const value = "; " + document.cookie;
	const parts = value.split("; " + prefix + name + "=");
	if ( parts.length === 2 ) {
		return parts.pop().split(";").shift();
	}
	return "";
}

/**
 * Add an event
 * @param event
 * @param selector
 * @param callback
 * @param context
 */
function cmplz_tcf_add_event(event, selector, callback, context) {
	document.addEventListener(event, e => {
		if ( e.target.closest(selector) ) {
			callback(e);
		}
	});
}

/**
 * Check if the element is hidden
 * @param el
 * @returns {boolean}
 */
function is_hidden(el) {
	return (el.offsetParent === null)
}

let bannerDataLoadedResolve;
let tcModelLoadedResolve;
let tcfLanguageLoadedResolve;
let bannerLoadedResolve;
let revokeResolve;
let bannerDataLoaded = new Promise(function(resolve, reject){
	bannerDataLoadedResolve = resolve;
});
let tcModelLoaded = new Promise(function(resolve, reject){
	tcModelLoadedResolve = resolve;
});
let tcfLanguageLoaded = new Promise(function(resolve, reject){
	tcfLanguageLoadedResolve = resolve;
});
let bannerLoaded = new Promise(function(resolve, reject){
	bannerLoadedResolve = resolve;
});
let revoke = new Promise(function(resolve, reject){
	revokeResolve = resolve;
});

const acVendorsPromise = useAcVendors ? fetch(ACVendorsUrl)
	.then(response => response.text())
	.then(csvData => {
		// Parse the CSV data
		const rows = csvData.split('\n');
		// Remove first row
		rows.shift();
		// Convert array of arrays to array of objects
		ACVendors = rows.map(row => {
			if (row.length === 0) {
				return null;
			}
			const [id, name, policyUrl, domains] = row.split(',').map(item => item.replace(/^"(.*)"$/, '$1'));
			return {
				id: parseInt(id),
				name,
				policyUrl,
				domains,
				consent: 0, // Default no consent
			};
		});
		// Filter out null values
		ACVendors = ACVendors.filter(el => el != null);
	})
	.catch(error => {
		console.log('Error:', error);
	}) : Promise.resolve();

const purposesPromise = fetch(purposesUrl, {
	method: "GET",
})
	.then(response => response.json())
	.then(data => {
		cmplzLanguageJson = data;
	})
	.catch(error => {
		console.log('Error:', error);
	});

Promise.all([acVendorsPromise, purposesPromise]).then(() => {
	tcfLanguageLoadedResolve();
});

document.addEventListener('wp_consent_type_defined', function (e) {
	bannerDataLoadedResolve();
});
document.addEventListener('cmplz_cookie_warning_loaded', function (e) {
	if ( !complianz.disable_cookiebanner) {
		bannerLoadedResolve();
	}
});
document.addEventListener('cmplz_revoke', function (e) {
	const reload = e.detail;
	revokeResolve(reload);
});

bannerDataLoaded.then(()=>{

});

tcfLanguageLoaded.then(()=>{
	const storedTCString = cmplzGetTCString();
	const ACString = cmplzGetACString();
	GVL.baseUrl = cmplz_tcf.cmp_url + "cmp/vendorlist";
	dataCategories = cmplzLanguageJson.dataCategories;
	let gvl = new GVL(cmplzLanguageJson);
	let sourceGvl = gvl.clone();
	let tcModel = new TCModel(gvl);
	tcModel.publisherCountryCode = cmplz_tcf.publisherCountryCode;
	tcModel.version = 2;
	tcModel.cmpId = cmplzCMP;
	tcModel.cmpVersion = cmplzCMPVersion;
	tcModel.isServiceSpecific = cmplzIsServiceSpecific;
	tcModel.UseNonStandardStacks = 0; //A CMP that services multiple publishers sets this value to 0
	const cmpApi = new CmpApi(cmplzCMP, cmplzCMPVersion, cmplzIsServiceSpecific, {
		//https://github.com/InteractiveAdvertisingBureau/iabtcf-es/tree/master/modules/cmpapi#built-in-and-custom-commands
		'getTCData': (next, tcData, success) => {
			// tcData will be constructed via the TC string and can be added to here
			if ( tcData ) {
				tcData.addtlConsent = ACString;
			}

			// pass data along
			next(tcData, success);
		}
	});


	/**
	 * After banner data is fully loaded
	 */

	tcModel.gvl.readyPromise.then(() => {
		const json = tcModel.gvl.getJson();
		let vendors = json.vendors;
		let vendorIds = cmplzFilterVendors(vendors);
		tcModel.gvl.narrowVendorsTo(vendorIds);

		//update model with given consents
		try {
			tcModel = TCString.decode(storedTCString, tcModel);

			//update tcmodel to ensure gdpr applies is set
			cmplzSetTCString(tcModel, cmplzUIVisible() );
			ACVendors = updateACVendorsWithConsent(ACString, ACVendors);
		} catch (err) {}

		//get the given consents from the Google Extended vendors
		tcModelLoadedResolve();
	});

	Promise.all([bannerDataLoaded, tcModelLoaded]).then(()=> {
		insertVendorsInPolicy(tcModel.gvl.vendors, ACVendors);
		if (complianz.consenttype === 'optin'){
			if (cmplz_tcf.debug) console.log(tcModel);
			let date = new Date();
			/**
			 * If the TC String was created over a year ago, we clear it.
			 */
			if (Date.parse(tcModel.created) < date.getTime() - 365 * 24 * 60 * 60 * 1000) {
				cmplzSetTCString(null, cmplzUIVisible() );
			} else {
				cmplzSetTCString(tcModel, cmplzUIVisible() );
			}
		} else {
			if (cmplz_tcf.debug) console.log("not an optin tcf region");
			cmplzSetTCString(null, false );
		}
	});

	Promise.all([bannerLoaded, tcModelLoaded, tcfLanguageLoaded]).then(()=> {
		configureOptinBanner();
	});

	revoke.then(reload => {
		if (cmplz_is_tcf_region(complianz.region)) {
			revokeAllVendors(reload);
		}
	});

	/**
	 * When the marketing is accepted, make sure all vendors are allowed
	 */

	document.addEventListener("cmplz_fire_categories", function (e) {
		//skip if not gdpr
		if (complianz.consenttype !== 'optin') {
			return;
		}
		if (cmplz_in_array('marketing', e.detail.categories)) {
			acceptAllVendors();
		}
	});

	/**
	 * Accept all vendors
	 */
	function acceptAllVendors() {
		consentAllACVendors();

		cmplzSetAllVendorLegitimateInterests();
		tcModel.setAllPurposeLegitimateInterests();
		for (let key in cmplz_tcf.purposes) {
			tcModel.purposeConsents.set(cmplz_tcf.purposes[key]);
			cmplzSetTypeByVendor('purpose_legitimate_interest', cmplz_tcf.purposes[key]);
		}

		tcModel.setAllSpecialFeatureOptins()
		for (let key in cmplz_tcf.specialFeatures) {
			tcModel.specialFeatureOptins.set(cmplz_tcf.specialFeatures[key]);
			cmplzSetTypeByVendor('specialfeature', cmplz_tcf.specialFeatures[key]);
		}

		tcModel.setAllPurposeConsents();
		for (let key in cmplz_tcf.purposes) {
			tcModel.purposeConsents.set(cmplz_tcf.purposes[key]);
			cmplzSetTypeByVendor('purpose_consent', cmplz_tcf.purposes[key]);
		}

		tcModel.setAllVendorConsents();
		document.querySelectorAll('.cmplz-tcf-input').forEach(checkbox => {
			checkbox.checked = true;
		});
		cmplzSetTCString(tcModel, cmplzUIVisible() );
		cmplz_set_cookie('banner-status', 'dismissed');
	}

	/**
	 * Revoke all vendors
	 * @param reload
	 */
	function revokeAllVendors(reload) {
		denyAllACVendors();

		//legint should be handled by right to object checkbox in vendor overview.
		// tcModel.unsetAllVendorLegitimateInterests();
		tcModel.unsetAllPurposeLegitimateInterests();
		cmplzUnsetAllVendorLegitimateInterests();
		for ( let key in cmplz_tcf.specialFeatures ) {
			tcModel.specialFeatureOptins.set(cmplz_tcf.specialFeatures[key]);
			cmplzUnsetTypeByVendor('specialfeature', cmplz_tcf.specialFeatures[key]);
		}

		for (let key in cmplz_tcf.purposes) {
			tcModel.purposeConsents.set(cmplz_tcf.purposes[key]);
			cmplzUnsetTypeByVendor('purpose_consent', cmplz_tcf.purposes[key]);
		}

		tcModel.unsetAllVendorConsents();
		document.querySelectorAll('.cmplz-tcf-input').forEach(checkbox => {
			if (!checkbox.disabled) checkbox.checked = false;
		});
		cmplzSetTCString(tcModel, cmplzUIVisible() );

		if (reload) {
			location.reload();
		}
	}

	/**
	 * Set all legitimate interests, except when a vendor does not have legints or special purposes.
	 */
	function cmplzSetAllVendorLegitimateInterests() {
		tcModel.setAllVendorLegitimateInterests();
		for (let key in tcModel.gvl.vendors) {
			let vendor = tcModel.gvl.vendors[key];
			/**
			 * no legint, and no special purposes, set legint signal to 0.
			 */
			if ( vendor.legIntPurposes.length === 0 && vendor.specialPurposes.length === 0 ) {
				tcModel.vendorLegitimateInterests.unset(vendor.id);
			}
		}
	}

	/**
	 * UnSet all legitimate interests, except when a vendor does not have legints or special purposes.
	 */
	function cmplzUnsetAllVendorLegitimateInterests() {
		tcModel.unsetAllVendorLegitimateInterests();
		for (let key in tcModel.gvl.vendors) {
			let vendor = tcModel.gvl.vendors[key];
			/**
			 * If a vendor only has special purposes, and no other purposes, there's no right to object.
			 */
			if (vendor.legIntPurposes.length === 0 && vendor.purposes.length === 0 && vendor.flexiblePurposes.length === 0 && vendor.specialFeatures.length === 0 && vendor.specialPurposes.length !== 0) {
				tcModel.vendorLegitimateInterests.set(vendor.id);
			}
		}
	}

	const updateACVendorsWithConsent = (storedConsentString, vendors) => {
		//retrieve array of consented vendors from the stored consent string
		let consentedVendors = decodeACString(storedConsentString);
		//loop through ACVendors, and set each vendor that exists in the consentedVendor array to consented
		vendors.forEach((vendor) => {
			if (consentedVendors.includes(vendor.id)) {
				vendor.consent = 1;
			}
		})
		//strip out vendors that already exist in the tcf vendor list
		const tcfVendorNames = new Set(Object.values(tcModel.gvl.vendors).map( vendor => vendor.name ));
		return vendors.filter(vendor => !tcfVendorNames.has(vendor.name));
	}

	const denyACVendor = (vendorId) => {
		ACVendors.forEach((vendor) => {
			if (parseInt(vendor.id) === vendorId) {
				vendor.consent = 0;
			}
		});
	}
	const denyAllACVendors = () => {
		ACVendors.forEach((vendor) => {
			vendor.consent = 0;
		})
	}
	const consentAllACVendors = () => {
		ACVendors.forEach((vendor) => {
			vendor.consent = 1;
		})
	}
	const consentACVendor = (vendorId) => {
		ACVendors.forEach((vendor) => {
			if (parseInt(vendor.id) === vendorId) {
				vendor.consent = 1;
			}
		});
	}

	const decodeACString = (ACString) => {
		if (!ACString || ACString.length===0) return [];

		//split the string on the ~
		let ACArray = ACString.split('~');
		//get the version number
		let ACversion = ACArray[0];
		//get the array of vendor id's
		let vendors = ACArray[1].split('.');
		// change each vendor id to an integer
		return vendors.map((vendor) => {
			return parseInt(vendor);
		})
	}

	/**
	 * If a purpose has been selected/deselected, we need to re-check for al vendors if this has consenquences for legint
	 */
	function cmplzUpdateAllVendorLegitimateInterests() {
		for (let key in tcModel.gvl.vendors) {
			let vendor = tcModel.gvl.vendors[key];

			/**
			 * no legint, and no special purposes, set legint signal to 0.
			 */
			if (vendor.legIntPurposes.length === 0 && vendor.specialPurposes.length === 0) {
				tcModel.vendorLegitimateInterests.unset(vendor.id);
			}

			if (vendor.legIntPurposes.length === 0 && vendor.purposes.length === 0 && vendor.flexiblePurposes.length === 0 && vendor.specialFeatures.length === 0 && vendor.specialPurposes.length !== 0) {
				tcModel.vendorLegitimateInterests.set(vendor.id);
			}
		}
	}

	/**
	 * We use this method to keep track of consents per vendor. This is not stored in the core tcString
	 *
	 * @param type
	 * @param typeId
	 */
	function cmplzSetTypeByVendor(type, typeId) {
		if (type === 'purpose_consent') {
			tcModel.purposeConsents.set(typeId);
			for (let key in tcModel.gvl.vendors) {
				let vendor = tcModel.gvl.vendors[key];
				if (sourceGvl.vendors[vendor.id].purposes.includes(typeId) && !vendor.purposes.includes(typeId)) {
					tcModel.gvl.vendors[vendor.id].purposes.push(typeId);
				}
			}
		}

		if (type === 'purpose_legitimate_interest') {
			tcModel.purposeLegitimateInterests.set(typeId);
			for (let key in tcModel.gvl.vendors) {
				let vendor = tcModel.gvl.vendors[key];
				if (sourceGvl.vendors[vendor.id].purposes.includes(typeId) && !vendor.purposes.includes(typeId)) {
					tcModel.gvl.vendors[vendor.id].purposes.push(typeId);
				}
			}
		}

		if (type === 'specialfeature') {
			tcModel.specialFeatureOptins.set(typeId);
			for (let key in tcModel.gvl.vendors) {
				let vendor = tcModel.gvl.vendors[key];
				if (sourceGvl.vendors[vendor.id].specialFeatures.includes(typeId) && !vendor.specialFeatures.includes(typeId)) {
					tcModel.gvl.vendors[vendor.id].specialFeatures.push(typeId);
				}
			}
		}

		if (type === 'feature') {
			for (let key in tcModel.gvl.vendors) {
				let vendor = tcModel.gvl.vendors[key];
				if (sourceGvl.vendors[vendor.id].features.includes(typeId) && !vendor.features.includes(typeId)) {
					tcModel.gvl.vendors[vendor.id].features.push(typeId);
				}
			}
		}
	}

	function cmplzUnsetTypeByVendor(type, typeId) {
		if (type === 'purpose_consent') {
			tcModel.purposeConsents.unset(typeId);
			for (let key in tcModel.gvl.vendors) {
				let vendor = tcModel.gvl.vendors[key];
				let index = vendor.purposes.indexOf(typeId);
				if (index > -1) {
					tcModel.gvl.vendors[vendor.id].purposes.splice(index, 1);
				}
			}
		}

		if (type === 'purpose_legitimate_interest') {
			tcModel.purposeLegitimateInterests.unset(typeId);
			for (let key in tcModel.gvl.vendors) {
				let vendor = tcModel.gvl.vendors[key];
				let index = vendor.legIntPurposes.indexOf(typeId);
				if (index > -1) {
					tcModel.gvl.vendors[vendor.id].legIntPurposes.splice(index, 1);
				}
			}
		}

		if (type === 'specialfeature') {
			tcModel.specialFeatureOptins.unset(typeId);
			for (let key in tcModel.gvl.vendors) {
				let vendor = tcModel.gvl.vendors[key];
				const index = vendor.specialFeatures.indexOf(typeId);
				if (index > -1) {
					tcModel.gvl.vendors[vendor.id].specialFeatures.splice(index, 1);
				}
			}
		}

		if (type === 'feature') {
			for (let key in tcModel.gvl.vendors) {
				let vendor = tcModel.gvl.vendors[key];
				const index = vendor.features.indexOf(typeId);
				if (index > -1) {
					tcModel.gvl.vendors[vendor.id].features.splice(index, 1);
				}
			}
		}
	}

	/**
	 * When revoke button is clicked, so banner shows again
	 *
	 */

	cmplz_tcf_add_event('click', '.cmplz-manage-consent', function () {
		const storedTCString = cmplzGetTCString();
		cmpApi.update(storedTCString, true);  //just got the banner to show again, so we have to pass ui visible true
	});

	/**
	 * Create a checkbox, clickable
	 * @param type
	 * @param object
	 * @param container
	 * @param checked
	 * @param disabled
	 */
	function cmplzRenderCheckbox(type, object, container, checked, disabled) {
		const { name, description, id, illustrations } = object;
		let illustration = illustrations && illustrations.hasOwnProperty(0) ? illustrations[0] : '';
		const vendors = tcModel.gvl.vendors;
		let vendorsWithPurpose = cmplzGetVendorsWithPurpose('purposes', vendors, [id]);
		const count = vendorsWithPurpose.length;

		const descArr = description.split('*');
		const descriptionOut = descArr.join(', ');
		const template = document.getElementById('cmplz-tcf-type-template').innerHTML
			.replace(/{type_name}/g, name )
			.replace(/{type_count}/g, count )
			.replace(/{type_description}/g, descriptionOut)
			.replace(/{type_id}/g, id)
			.replace(/{type_example}/g, illustration)
			.replace(/{type}/g, type);

		const wrapper = document.createElement('div');
		wrapper.innerHTML = template;
		const checkbox = wrapper.firstChild;
		const input = checkbox.querySelector(`.cmplz-tcf-${type}-input`);
		input.checked = checked;
		input.disabled = disabled;
		input.setAttribute(`data-${type}_id`, id);

		container.appendChild(checkbox);
	}

	/**
	 * Generate entire block of checkboxes with event listener
	 * @param type
	 * @param objects
	 * @param filterBy
	 */

	function generateTypeBlock(type, objects, filterBy) {
		let containerid = type;
		let srcPurposes;
		if (filterBy !== false) {
			containerid = filterBy + '-' + containerid;
			srcPurposes = getPurposes(filterBy, false);
		}

		const container = document.getElementById('cmplz-tcf-' + containerid + 's-container');
		if (container === null) {
			return;
		}
		container.innerHTML = '';
		for (let key in objects) {
			if (objects.hasOwnProperty(key)) {
				const object = objects[key];
				const addItem = filterBy ? srcPurposes.includes(object.id) : true;

				if (addItem) {
					let checked = false;
					let disabled = false;
					if (type === 'purpose_consent') checked = tcModel.purposeConsents.has(object.id);
					if (type === 'purpose_legitimate_interest') checked = tcModel.purposeLegitimateInterests.has(object.id);
					if (type === 'specialfeature') checked = tcModel.specialFeatureOptins.has(object.id);
					if (type === 'feature' || type === 'specialpurpose') checked = disabled = true;

					cmplzRenderCheckbox(type, object, container, checked, disabled);
				}
			}
		}

		//add event listener
		cmplz_tcf_add_event("click", '.cmplz-tcf-' + type + '-input', function (e) {
			const obj = e.target;
			const typeId = parseInt(obj.getAttribute('data-'+type + '_id'));
			const checked = obj.checked;

			document.querySelectorAll('[data-' + type + '_id="' + typeId + '"]').forEach(obj => {
				obj.checked = checked;
			});

			if (type === 'purpose_consent') tcModel.purposeConsents[checked ? 'set' : 'unset'](typeId);
			if (type === 'purpose_legitimate_interest') tcModel.purposeLegitimateInterests[checked ? 'set' : 'unset'](typeId);
			if (type === 'specialfeature') tcModel.specialFeatureOptins[checked ? 'set' : 'unset'](typeId);

			if (checked) cmplzSetTypeByVendor(type, typeId);
			else cmplzUnsetTypeByVendor(type, typeId);

			cmplzUpdateAllVendorLegitimateInterests();
			cmplzSetTCString(tcModel, true);
		});



		cmplz_tcf_add_event("click", '.cmplz-tcf-toggle', function (e) {
			let obj = e.target;

			e.preventDefault();
			let label = obj.closest('label');
			let description = label.querySelector('.cmplz-tcf-type-description');

			if ( is_hidden(description) ) {
				obj.classList.add('cmplz-tcf-rl');
				obj.classList.remove('cmplz-tcf-rm');
				description.style.display = 'block';
			} else {
				obj.classList.add('cmplz-tcf-rm');
				obj.classList.remove('cmplz-tcf-rl');
				description.style.display = 'none';
			}
		});
	}

	function cmplzUIVisible() {
		let bannerVisible = true;
		const bannerStatus = cmplz_tcf_get_cookie('banner-status');
		if (bannerStatus === 'dismissed') {
			bannerVisible = false;
		}

		const policyVisible = document.getElementById('cmplz-tcf-vendor-container') !== null;
		return bannerVisible || policyVisible;
	}

	/**
	 * Create a list of checkable vendors in the cookie policy
	 * @param vendors
	 */

	function insertVendorsInPolicy(vendors) {
		const vendorContainer = document.getElementById('cmplz-tcf-vendor-container');
		if (vendorContainer === null) {
			return;
		}

		vendorContainer.innerHTML = '';
		const template = document.getElementById('cmplz-tcf-vendor-template').innerHTML;
		const purposes = cmplzFilterArray(cmplzLanguageJson.purposes, cmplz_tcf.purposes);
		const specialPurposes = cmplzFilterArray(cmplzLanguageJson.specialPurposes, cmplz_tcf.specialPurposes);
		const features = cmplzFilterArray(cmplzLanguageJson.features, cmplz_tcf.features);
		const specialFeatures = cmplzFilterArray(cmplzLanguageJson.specialFeatures, cmplz_tcf.specialFeatures);

		generateTypeBlock('purpose_consent', purposes, 'statistics');
		generateTypeBlock('purpose_consent', purposes, 'marketing');
		generateTypeBlock('purpose_legitimate_interest', purposes, 'statistics');
		generateTypeBlock('purpose_legitimate_interest', purposes, 'marketing');
		generateTypeBlock('feature', features, false);
		generateTypeBlock('specialpurpose', specialPurposes, false);
		generateTypeBlock('specialfeature', specialFeatures, false);

		if (specialFeatures.length === 0) {
			document.getElementById('cmplz-tcf-specialfeatures-wrapper').style.display = 'none';
		}
		for (let key in vendors) {
			if (vendors.hasOwnProperty(key)) {
				let customTemplate = template;
				const vendor = vendors[key];
				const vendorPurposes = vendor.purposes.concat(vendor.legIntPurposes);
				let purposeString = '';
				for (const p_key in vendorPurposes) {
					if (vendorPurposes.hasOwnProperty(p_key)) {
						let vendorPurposeId = vendorPurposes[p_key];
						let purposeName = false;
						for (const src_p_key in purposes) {
							if (purposes.hasOwnProperty(src_p_key) && purposes[src_p_key].id === vendorPurposeId) {
								purposeName = purposes[src_p_key].name;
								let defaultRetention = vendor.dataRetention && vendor.dataRetention.hasOwnProperty('stdRetention') ? vendor.dataRetention.stdRetention : null;
								let retention = vendor.dataRetention && vendor.dataRetention.hasOwnProperty(vendorPurposeId) ? vendor.dataRetention[vendorPurposeId] : defaultRetention;
								if ( typeof retention === 'undefined' ) {
									retention = cmplz_tcf.undeclared_string;
								}
								const purposeLink = 'https://cookiedatabase.org/tcf/' + purposeName.replace(/ /g, '-').replace(/\//g, '-').toLowerCase();
								purposeString += '<div class="cmplz-tcf-purpose"><a href="' + purposeLink + '" target="_blank" rel="noopener noreferrer nofollow">' + purposeName + '</a>| '+cmplz_tcf.retention_string+': '+retention+'</div>';
							}
						}
					}
				}

				//get list of categories from dataCategories that exist  in vendor.dataDeclaration
				let categories = [];

				for (const catKey in vendor.dataDeclaration) {
					if (vendor.dataDeclaration.hasOwnProperty(catKey)) {
						let categoryId = vendor.dataDeclaration[catKey];
						let cat = '';
						for (const key in dataCategories) {
							if (dataCategories.hasOwnProperty(key) && dataCategories[key].id === categoryId) {
								cat = dataCategories[key].name;
							}
						}
						categories.push(cat);
					}
				}
				categories = categories.join(', ');

				let retentionInDays = Math.round(vendor.cookieMaxAgeSeconds / (60 * 60 * 24));
				//if result is 0, get day in decimals.
				console.log(vendor);
				customTemplate = customTemplate.replace(/{cookie_retention_seconds}/g, vendor.cookieMaxAgeSeconds);
				customTemplate = customTemplate.replace(/{cookie_retention_days}/g, retentionInDays);
				customTemplate = customTemplate.replace(/{vendor_name}/g, vendor.name);
				customTemplate = customTemplate.replace(/{vendor_categories}/g, categories);
				customTemplate = customTemplate.replace(/{vendor_id}/g, vendor.id);
				customTemplate = customTemplate.replace(/{purposes}/g, purposeString);
				//get first array item
				if ( vendor.urls.hasOwnProperty(0)) {
					const url = vendor.urls[0].privacy;
					customTemplate = customTemplate.replace(/{privacy_policy}/g, url);
				}

				const wrapper = document.createElement('div');
				wrapper.innerHTML = customTemplate;
				const checkbox = wrapper.firstChild;
				checkbox.querySelector('.cmplz-tcf-vendor-input').checked = tcModel.vendorConsents.has(vendor.id) || tcModel.vendorLegitimateInterests.has(vendor.id);
				checkbox.querySelector('.cmplz-tcf-vendor-input').setAttribute('data-vendor_id', vendor.id);

				//set consent
				checkbox.querySelector('.cmplz-tcf-consent-input').checked = tcModel.vendorConsents.has(vendor.id);
				checkbox.querySelector('.cmplz-tcf-consent-input').setAttribute('data-vendor_id', vendor.id);

				//show legint option if vendor has legintpurposes
				if (vendor.legIntPurposes.length !== 0) {
					checkbox.querySelector('.cmplz_tcf_legitimate_interest_checkbox').style.display = 'block';
					checkbox.querySelector('.cmplz-tcf-legitimate-interest-input').setAttribute('data-vendor_id', vendor.id);
					checkbox.querySelector('.cmplz-tcf-legitimate-interest-input').checked = tcModel.vendorLegitimateInterests.has(vendor.id);
				}

				//handle non cookie access
				if (vendor.usesNonCookieAccess) {
					wrapper.querySelector('.non-cookie-storage-active').style.display = 'block';
				} else {
					wrapper.querySelector('.non-cookie-storage-inactive').style.display = 'block';
				}

				if (vendor.cookieRefresh) {
					wrapper.querySelector('.non-cookie-refresh-active').style.display = 'block';
				} else {
					wrapper.querySelector('.non-cookie-refresh-inactive').style.display = 'block';
				}

				if (vendor.cookieMaxAgeSeconds <= 0) {
					wrapper.querySelector('.session-storage').style.display = 'block';
				} else if (vendor.cookieMaxAgeSeconds <= 60 * 60 * 24) {
					wrapper.querySelector('.retention_seconds').style.display = 'block';
				} else {
					wrapper.querySelector('.retention_days').style.display = 'block';
				}

				let fragment = document.createDocumentFragment();
				checkbox.classList.add('cmplz-vendortype-tcf');
				fragment.appendChild(checkbox);

				vendorContainer.appendChild(checkbox);
			}
		}

		for (let key in ACVendors) {
			if (ACVendors.hasOwnProperty(key)) {
				let customTemplate = template;
				const vendor = ACVendors[key];
				customTemplate = customTemplate.replace(/{vendor_name}/g, vendor.name);
				customTemplate = customTemplate.replace(/{vendor_id}/g, vendor.id);
				customTemplate = customTemplate.replace(/{privacy_policy}/g, vendor.policyUrl);

				const wrapper = document.createElement('div');
				wrapper.innerHTML = customTemplate;
				const checkbox = wrapper.firstChild;
				checkbox.querySelector('.cmplz-tcf-vendor-input').checked = vendor.consent === 1;
				checkbox.querySelector('.cmplz-tcf-vendor-input').setAttribute('data-ac_vendor_id', vendor.id);

				//set consent
				checkbox.querySelector('.cmplz-tcf-consent-input').checked = vendor.consent === 1;
				checkbox.querySelector('.cmplz-tcf-consent-input').setAttribute('data-ac_vendor_id', vendor.id);

				let fragment = document.createDocumentFragment();
				checkbox.classList.add('cmplz-vendortype-ac');
				fragment.appendChild(checkbox);
				vendorContainer.appendChild(checkbox);
			}
		}

		cmplz_tcf_add_event("click", '.cmplz-tcf-legitimate-interest-input', function (e) {
			let obj = e.target;
			const vendorId = parseInt(obj.getAttribute('data-vendor_id'));
			if ( obj.checked ) {
				tcModel.vendorLegitimateInterests.set(vendorId);
				let container = obj.closest('.cmplz-tcf-vendor-container');
				container.querySelector('.cmplz-tcf-vendor-input').checked = true;
			} else {
				tcModel.vendorLegitimateInterests.unset(vendorId);
			}

			cmplzSetTCString(tcModel, true);
			cmplz_set_cookie('banner-status', 'dismissed');
		});

		cmplz_tcf_add_event("click", '.cmplz-tcf-consent-input', function (e) {
			let obj = e.target;
			const vendorId = parseInt(obj.getAttribute('data-vendor_id'));
			let container = obj.closest('.cmplz-tcf-vendor-container');
			if (vendorId) {
				if (obj.checked) {
					tcModel.vendorConsents.set(vendorId);
					container.querySelector('.cmplz-tcf-vendor-input').prop('checked', true);
				} else {
					tcModel.vendorConsents.unset(vendorId);
					container.querySelector('.cmplz-tcf-vendor-input').prop('checked', false);
				}
			}

			const ACVendorId = parseInt(obj.getAttribute('data-ac_vendor_id'));
			if (ACVendorId){
				if (obj.checked) {
					consentACVendor(ACVendorId);
					container.querySelector('.cmplz-tcf-vendor-input').prop('checked', true);
				} else {
					denyACVendor(ACVendorId);
					container.querySelector('.cmplz-tcf-vendor-input').prop('checked', false);
				}
			}
			//now we update the tcstring
			cmplzSetTCString(tcModel, true);
			cmplz_set_cookie('banner-status', 'dismissed');
		});

		cmplz_tcf_add_event("click", '.cmplz-tcf-vendor-input', function (e) {
			let obj = e.target;
			const vendorId = parseInt(obj.getAttribute('data-vendor_id'));
			const ACVendorId = parseInt(obj.getAttribute('data-ac_vendor_id'));
			let container = obj.closest('.cmplz-tcf-vendor-container');
			if (vendorId){
				if (obj.checked) {
					tcModel.vendorConsents.set(vendorId);
					//positive leg int should not be set.
					tcModel.vendorLegitimateInterests.set(vendorId);
					container.querySelector('.cmplz-tcf-legitimate-interest-input' ).checked = true;
					container.querySelector('.cmplz-tcf-consent-input' ).checked = true;
				} else {
					tcModel.vendorConsents.unset(vendorId);
					tcModel.vendorLegitimateInterests.unset(vendorId);
					container.querySelector('.cmplz-tcf-legitimate-interest-input').checked = false;
					container.querySelector('.cmplz-tcf-consent-input').checked = false;
				}
			} else if (ACVendorId){
				if (obj.checked) {
					consentACVendor(ACVendorId);
					container.querySelector('.cmplz-tcf-consent-input' ).checked = true;
				} else {
					denyACVendor(ACVendorId);
					container.querySelector('.cmplz-tcf-consent-input').checked = false;
				}
			}
			cmplzSetTCString(tcModel, true);
			cmplz_set_cookie('banner-status', 'dismissed');
		});

		cmplz_tcf_add_event("click", '.cmplz-tcf-toggle-info', function (e) {
			let obj = e.target;
			e.preventDefault();
			if ( is_hidden() ) {
				obj.style.display = 'block';
			} else {
				obj.style.display = 'none';
			}
		});

		cmplz_tcf_add_event("click", '.cmplz-tcf-toggle-vendor', function (e) {
			let obj = e.target;
			e.preventDefault();
			const container = obj.closest('.cmplz-tcf-vendor-container');
			const info = container.querySelector('.cmplz-tcf-info');
			if ( is_hidden(info) ) {
				obj.classList.add('cmplz-tcf-rl');
				obj.classList.remove('cmplz-tcf-rm');
				info.style.display = 'block';
			} else {
				obj.classList.add('cmplz-tcf-rm');
				obj.classList.remove('cmplz-tcf-rl');
				info.style.display = 'none';
			}
		});

		cmplz_tcf_add_event("click", "#cmplz-tcf-selectall", function () {
			for (let key in vendors) {
				if (vendors.hasOwnProperty(key)) {
					const vendor = vendors[key];
					tcModel.vendorConsents.set(vendor.id);
					document.querySelector('#cmplz-tcf-' + vendor.id).checked = true;
				}
			}
			const vendorCheckboxes = document.querySelectorAll('[data-vendor_id]');
			vendorCheckboxes.forEach(vendorCheckbox => {
				vendorCheckbox.checked = true;
			});
			acceptAllVendors();
		});

		cmplz_tcf_add_event("click", "#cmplz-tcf-deselectall", function () {
			for (let key in vendors) {
				if (vendors.hasOwnProperty(key)) {
					const vendor = vendors[key];
					tcModel.vendorConsents.unset(vendor.id);
					document.querySelector('#cmplz-tcf-' + vendor.id).checked = false;
				}
			}
			revokeAllVendors(true);
		});
		let event = new CustomEvent('cmplz_vendor_container_loaded', {detail: complianz.region});
		document.dispatchEvent(event);
	}

	/**
	 * Filter the list of vendors
	 *
	 * @param vendors
	 * @returns {*}
	 */
	function cmplzFilterVendors(vendors) {
		let vendorIds = Object.values(vendors).map(vendor => vendor.id);

		let addVendorIds = cmplzFilterVendorsBy('purposes', vendors, cmplz_tcf.purposes);
		vendorIds = vendorIds.filter(value => addVendorIds.includes(value));
		addVendorIds = cmplzFilterVendorsBy('specialPurposes', vendors, cmplz_tcf.specialPurposes);
		vendorIds = vendorIds.filter(value => addVendorIds.includes(value));

		addVendorIds = cmplzFilterVendorsBy('features', vendors, cmplz_tcf.features);
		vendorIds = vendorIds.filter(value => addVendorIds.includes(value));
		addVendorIds = cmplzFilterVendorsBy('specialFeatures', vendors, cmplz_tcf.specialFeatures);
		vendorIds = vendorIds.filter(value => addVendorIds.includes(value));
		//remove all vendors that are included in cmplz_tcf.excludedVendors
		//convert cmplz_tcf.excludedVendors json to array
		let excludedVendors = Object.keys(cmplz_tcf.excludedVendors).map(function(key) {
			return cmplz_tcf.excludedVendors[key];
		});

		vendorIds = vendorIds.filter(value => !excludedVendors.includes(value));

		return vendorIds;
	}

	/**
	 * Get all vendors who use this purpose
	 * @param type
	 * @param vendors
	 * @param category_purposes
	 * @returns {[]}
	 */
	function cmplzGetVendorsWithPurpose(type, vendors, category_purposes) {
		let output = [];
		for (const vendor in vendors) {
			for (const purpose in category_purposes) {
				if (vendors[vendor][type].includes(category_purposes[''+purpose])) {
					output.push(vendors[vendor].id);
					break;
				}
			}
		}
		return output;
	}


	/**
	 * Get vendors who only have one of these purposes
	 * @param type
	 * @param vendors
	 * @param category_purposes
	 * @returns {[]}
	 */
	// function cmplzFilterVendorsBy(type, vendors, category_purposes) {
	// 	let output = [];
	// 	for (let key in vendors) {
	// 		if (vendors.hasOwnProperty(key)) {
	// 			const vendor = vendors[key];
	// 			//for each vendor purpose, check if it exists in the category purposes list. If not, don't add this vendor
	// 			let allPurposesAreCategoryPurpose = true;
	// 			const vendorProperties = vendor[type];
	// 			for (let p_key in vendorProperties) {
	// 				if (vendorProperties.hasOwnProperty(p_key)) {
	// 					const purpose = vendorProperties[p_key];
	// 					const inPurposeArray = category_purposes.includes(purpose);
	// 					if (!inPurposeArray) {
	// 						allPurposesAreCategoryPurpose = false;
	// 					}
	// 				}
	// 			}
	// 			const inOutPutArray = output.includes(vendor.id);
	// 			if (!inOutPutArray && allPurposesAreCategoryPurpose) {
	// 				output.push(vendor.id);
	// 			}
	// 		}
	// 	}
	// 	return output;
	// }

	function cmplzFilterVendorsBy(type, vendors, category_purposes) {
		const output = [];

		for (const vendor of Object.values(vendors)) {
			const vendorProperties = vendor[type];

			if (Object.values(vendorProperties).every(purpose => category_purposes.includes(purpose))) {
				output.push(vendor.id);
			}
		}

		return output;
	}

	/**
	 * Get thet TC String
	 * @returns {string}
	 */
	function cmplzGetTCString() {
		let user_policy_id = cmplz_tcf_get_cookie('policy_id');
		if ( !user_policy_id || (typeof complianz!=='undefined' && complianz.current_policy_id !== user_policy_id)  ) {
			if (localStorage.cmplz_tcf_consent) localStorage.removeItem('cmplz_tcf_consent');
		}
		return window.localStorage.getItem('cmplz_tcf_consent');
	}

	/**
	 * Get thet TC String
	 * @returns {string}
	 */
	function cmplzGetACString() {
		return window.localStorage.getItem('cmplz_ac_string');
	}

	/**
	 * Set the tc string, and update the api if needed
	 */
	function cmplzSetACString() {
		// skip if the ACVendors array objects do not have a consent attribute
		if (ACVendors.length===0 || typeof ACVendors[0].consent === 'undefined') return;

		let ACversion = 1;
		let ACString = ACversion + '~';
		//filter out all vendors where the 'consent' attribute is 0
		let consentedVendors = ACVendors.filter((vendor) => {
			return vendor.consent === 1;
		})

		//delete if no consent was given
		if (consentedVendors.length===0) {
			if (localStorage.cmplz_ac_string) localStorage.removeItem('cmplz_ac_string');
			return
		}

		//get an array of vendor id's, and join it.
		ACString += consentedVendors.map((vendor) => {
			return vendor.id;
		}).join('.');

		window.localStorage.setItem('cmplz_ac_string', ACString);
	}

	/**
	 * Set the tc string, and update the api if needed
	 * @param tcModel
	 * @param uiVisible
	 */
	function cmplzSetTCString( tcModel, uiVisible ) {
		cmplzSetACString();
		let encodedTCString = null;
		if ( tcModel ) {
			tcModel.created = cmplzRemoveTime(tcModel.lastUpdated);
			tcModel.lastUpdated = cmplzRemoveTime(tcModel.lastUpdated);
			encodedTCString = TCString.encode(tcModel);
		}
		// __tcfapi('getTCData', 2, (tcData, success) => {}, [tcModel.vendors]);

		cmpApi.update(encodedTCString, uiVisible);
		window.localStorage.setItem('cmplz_tcf_consent', encodedTCString);
	}

	/**
	 * Ensure the date does not contain hours or minutes
	 * @param date
	 * @returns {Date}
	 */

	function cmplzRemoveTime(date) {
		return new Date(
			date.getFullYear(),
			date.getMonth(),
			date.getDate()
		);
	}

	/**
	 * Get list of purposes
	 * @param category
	 * @param includeLowerCategories
	 * @returns {*[]|number[]}
	 */
	function getPurposes(category, includeLowerCategories) {
		//these categories aren't used
		if (category === 'functional' || category === 'preferences') {
			return [];
		}

		if (category === 'marketing') {
			if (includeLowerCategories) {
				return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
			} else {
				return [1, 2, 3, 4, 5, 6, 10];
			}
		} else if (category === 'statistics') {
			return [1, 7, 8, 9];
		}
	}

	/**
	 * Check if a region is a TCF region
	 * @param region
	 * @returns {boolean}
	 */
	function cmplz_is_tcf_region(region) {
		return !!cmplz_in_array(region, complianz.tcf_regions);

	}

	function configureOptinBanner() {
		//don't do this for non TCF regions
		if (!cmplz_is_tcf_region(complianz.region)) {
			return;
		}
		/**
		 * Filter purposes based on passed purposes
		 */
		//only optin variant of tcf has these purposes on the banner.
		if ( complianz.consenttype === 'optin' ) {
			const srcMarketingPurposes = getPurposes('marketing', false);
			const srcStatisticsPurposes = getPurposes('statistics', false);
			const marketingPurposes = cmplzFilterArray(cmplzFilterArray(cmplzLanguageJson.purposes, cmplz_tcf.purposes), srcMarketingPurposes);
			const statisticsPurposes = cmplzFilterArray(cmplzFilterArray(cmplzLanguageJson.purposes, cmplz_tcf.purposes), srcStatisticsPurposes);
			const features = cmplzFilterArray(cmplzLanguageJson.features, cmplz_tcf.features);
			const specialPurposes = cmplzFilterArray(cmplzLanguageJson.specialPurposes, cmplz_tcf.specialPurposes);
			const specialFeatures = cmplzFilterArray(cmplzLanguageJson.specialFeatures, cmplz_tcf.specialFeatures);

			if (features.length === 0) document.querySelector('.cmplz-tcf .cmplz-features').style.display = 'none';
			if (specialPurposes.length === 0) document.querySelector('.cmplz-tcf .cmplz-specialpurposes').style.display = 'none';
			if (specialFeatures.length === 0) document.querySelector('.cmplz-tcf .cmplz-specialfeatures').style.display = 'none';
			if (statisticsPurposes.length === 0) document.querySelector('.cmplz-tcf .cmplz-statistics').style.display = 'none';
			document.querySelector('.cmplz-tcf .cmplz-statistics .cmplz-description').innerHTML = cmplzConcatenateString(statisticsPurposes);
			document.querySelector('.cmplz-tcf .cmplz-marketing .cmplz-description').innerHTML = cmplzConcatenateString(marketingPurposes);
			document.querySelector('.cmplz-tcf .cmplz-features .cmplz-description').innerHTML = cmplzConcatenateString(features);
			document.querySelector('.cmplz-tcf .cmplz-specialfeatures .cmplz-title').innerHTML = cmplzConcatenateString(specialFeatures);
			document.querySelector('.cmplz-tcf .cmplz-specialpurposes .cmplz-title').innerHTML = cmplzConcatenateString(specialPurposes);
		}

		let vendorCountContainers = document.querySelectorAll('.cmplz-manage-vendors.tcf');
		if ( vendorCountContainers ) {
			let count = complianz.consenttype === 'optin' ? tcModel.gvl.vendorIds.size : '';
			if ( useAcVendors && complianz.consenttype === 'optin' ){
				count+= ACVendors.length;
			}
			vendorCountContainers.forEach(obj => {
				obj.innerHTML = obj.innerHTML.replace('{vendor_count}', count);
			});
		}

		//on pageload, show vendorlist area
		let wrapper = document.getElementById('cmplz-tcf-wrapper');
		let noscript_wrapper = document.getElementById('cmplz-tcf-wrapper-nojavascript');
		if ( wrapper ){
			wrapper.style.display = 'block';
			noscript_wrapper.style.display = 'none';
		}
	}

	function cmplzFilterArray(arrayToFilter, arrayToFilterBy) {
		let output = [];
		for (let key in arrayToFilter) {
			if (arrayToFilterBy.includes(''+arrayToFilter[key].id) || arrayToFilterBy.includes(arrayToFilter[key].id)) {
				output.push(arrayToFilter[key]);
			}
		}
		return output;
	}

	function cmplzConcatenateString(array) {
		let string = '';
		const max = array.length - 1;
		for (let key in array) {
			if (array.hasOwnProperty(key)) {
				string += array[key].name;
				if (key < max) {
					string += ', ';
				} else {
					string += '.';
				}
			}
		}
		return string;
	}

});

/**
 * TCF for CCPA
 */

const USPSTR_NN = "1NN";
const USPSTR_YN = "1YN";
const USPSTR_YY = "1YY";
const USPSTR_NA = "1---";
let ccpaVendorlistLoadedResolve;
let ccpaVendorlistLoaded = new Promise(function(resolve, reject){
	ccpaVendorlistLoadedResolve = resolve;
});
let USvendorlistUrl = cmplz_tcf.cmp_url + 'cmp/vendorlist' + '/lspa.json';
let ccpaVendorList;
bannerDataLoaded.then(()=> {
	if (complianz.consenttype === 'optout' || onOptOutPolicyPage) {
		fetch(USvendorlistUrl, {
			method: "GET",
		}).then(response => response.json())
			.then(
				function (data) {
					ccpaVendorList = data;
					ccpaVendorlistLoadedResolve();
				}
			);
		cmplz_set_ccpa_tc_string();
		cmplzRenderUSVendorsInPolicy();
	} else {
		if (cmplz_tcf.debug) console.log("not an optout tcf region or page");
	}
});

/**
 * When CCPA applies, we set the TC string in the usprivacy cookie
 */
function cmplz_set_ccpa_tc_string() {
	if ( cmplz_tcf.ccpa_applies ) {
		cmplz_set_cookie('usprivacy', USPSTR_YN + cmplz_tcf.lspact, false);
		document.addEventListener("cmplz_fire_categories", function (e) {
			let val = USPSTR_YY + cmplz_tcf.lspact;
			if (cmplz_in_array('marketing', e.detail.categories)) {
				val = USPSTR_YN + cmplz_tcf.lspact;
			}
			cmplz_set_cookie('usprivacy', val, false);
		});
	} else {
		cmplz_set_cookie('usprivacy', USPSTR_NA + cmplz_tcf.lspact, false );
	}
}

function cmplzRenderUSVendorsInPolicy() {
	ccpaVendorlistLoaded.then(()=> {
		let vendors = ccpaVendorList.signatories;
		const vendorContainer = document.getElementById('cmplz-tcf-us-vendor-container');

		if (vendorContainer === null) {
			return;
		}
		vendorContainer.innerHTML = '';
		const template = document.getElementById('cmplz-tcf-vendor-template').innerHTML;

		for (let key in vendors) {
			if (vendors.hasOwnProperty(key)) {
				let customTemplate = template;
				let vendor = vendors[key];
				customTemplate = customTemplate.replace(/{vendor_name}/g, vendor.signatoryLegalName);
				let hasOptoutUrl = true;
				if (vendor.optoutUrl.indexOf('http') === -1) {
					hasOptoutUrl = false;
					customTemplate = customTemplate.replace(/{optout_string}/g, vendor.optoutUrl);
				} else {
					customTemplate = customTemplate.replace(/{optout_url}/g, vendor.optoutUrl);
				}

				const wrapper = document.createElement('div');
				wrapper.innerHTML = customTemplate;
				const html = wrapper.firstChild;
				if (hasOptoutUrl) {
					html.querySelector('.cmplz-tcf-optout-string').style.display = 'none';
					html.querySelector('.cmplz-tcf-optout-url').style.display = 'block';

				} else {
					html.querySelector('.cmplz-tcf-optout-string').style.display = 'block';
					html.querySelector('.cmplz-tcf-optout-url').style.display = 'none';
				}
				let fragment = document.createDocumentFragment();
				fragment.appendChild(html);
				vendorContainer.appendChild(html);
			}
		}

		document.querySelector('#cmplz-tcf-wrapper').style.display = 'block';
		document.querySelector('#cmplz-tcf-wrapper-nojavascript').style.display = 'none';
	})
}

/**
 * @todo get a list of ddr.js files. Not currently available
 * https://github.com/InteractiveAdvertisingBureau/USPrivacy/issues/17
 */
// Add all Vendor scripts; this is just an array of string sources
//https://github.com/InteractiveAdvertisingBureau/USPrivacy/blob/master/CCPA/Data%20Deletion%20Request%20Handling.md
// vendorDeleteScriptSources.forEach((vendorDeleteScriptSource) => {
//
// 	const scriptElement = document.createElement("script");
// 	scriptElement.src = vendorDeleteScriptSource;
//
// 	document.body.appendChild(scriptElement);
//
// });

/**
 * Fire a data deletion request.
 */
document.addEventListener("cmplz_dnsmpi_submit", function (e) {
	if (cmplz_tcf.debug) console.log("fire data deletion request for TCF");
	__uspapi('performDeletion', 1);
});