UNPKG

@jussimirvfx/meta-pixel-tracking

Version:

Sistema completo de tracking do Meta Pixel (Pixel + CAPI) com proteção anti-adblock para landing pages

1 lines 133 kB
{"version":3,"file":"index.cjs","sources":["../src/lib/config/meta-pixel.ts","../src/lib/utils/logger.ts","../src/lib/utils/cookies.ts","../src/lib/utils/parameter-builder.ts","../src/lib/facebook-pixel-init.ts","../__vite-browser-external","../node_modules/crypto-js/core.js","../node_modules/crypto-js/sha256.js","../src/lib/utils/hash.ts","../src/lib/hooks/use-meta-pixel.ts","../src/components/providers/meta-pixel-provider.tsx","../src/lib/hooks/use-scroll-tracking.ts","../src/components/analytics/meta-pixel.tsx"],"sourcesContent":["// Tipagem da configuração\nexport interface MetaPixelConfig {\n PIXEL_ID: string;\n ACCESS_TOKEN: string;\n TEST_EVENT_CODE?: string;\n DEDUPLICATION?: {\n MAX_AGE_HOURS: number;\n };\n UNIVERSAL_PARAMETERS: string[];\n STANDARD_EVENTS: string[];\n VERBOSE?: boolean;\n}\n\n// Flag para controlar se já foi configurado\nlet isConfigured = false;\n\n/**\n * Detecta se está em ambiente Vercel e ativa debug automaticamente\n */\nfunction detectVercelAndEnableDebug(): boolean {\n if (typeof window === 'undefined') return false;\n \n const url = window.location.href;\n const isVercel = url.includes('vercel.app') || url.includes('vercel.com');\n \n if (isVercel) {\n console.log('[META PIXEL] 🚀 Detectado ambiente Vercel, ativando debug automático');\n return true;\n }\n \n return false;\n}\n\n// Configuração padrão\nexport let META_PIXEL_CONFIG: MetaPixelConfig = {\n PIXEL_ID: '',\n ACCESS_TOKEN: '',\n TEST_EVENT_CODE: '',\n DEDUPLICATION: {\n MAX_AGE_HOURS: 24,\n },\n UNIVERSAL_PARAMETERS: [\n 'event_time',\n 'event_source_url',\n 'page_title',\n 'page_path',\n 'browser_language',\n 'screen_width',\n 'screen_height',\n 'viewport_width',\n 'viewport_height',\n 'timezone',\n 'referrer',\n ],\n STANDARD_EVENTS: [\n 'PageView',\n 'Lead',\n 'LeadQualificado',\n ],\n VERBOSE: false,\n};\n\n// Função para verificar se está configurado\nexport function isMetaPixelConfigured(): boolean {\n return isConfigured && !!META_PIXEL_CONFIG.PIXEL_ID && !!META_PIXEL_CONFIG.ACCESS_TOKEN;\n}\n\n// Função para validar configuração obrigatória\nexport function validateConfiguration(): void {\n if (!META_PIXEL_CONFIG.PIXEL_ID) {\n throw new Error('PIXEL_ID é obrigatório. Configure usando configureMetaPixel()');\n }\n if (!META_PIXEL_CONFIG.ACCESS_TOKEN) {\n throw new Error('ACCESS_TOKEN é obrigatório. Configure usando configureMetaPixel()');\n }\n}\n\n// Função para configurar o Meta Pixel\nexport function configureMetaPixel(config: Partial<MetaPixelConfig>) {\n META_PIXEL_CONFIG = { ...META_PIXEL_CONFIG, ...config };\n isConfigured = true;\n \n // Detectar Vercel e ativar debug automaticamente\n const isVercel = detectVercelAndEnableDebug();\n \n // Ativar debug se estiver em Vercel ou development/preview\n if (isVercel || (typeof window !== 'undefined' && (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'preview'))) {\n META_PIXEL_CONFIG.VERBOSE = true;\n console.log('[META PIXEL] 🔍 Debug ativado automaticamente');\n }\n \n // Validar configuração\n if (!config.PIXEL_ID) {\n console.error('⚠️ PIXEL_ID não fornecido na configuração');\n }\n if (!config.ACCESS_TOKEN) {\n console.error('⚠️ ACCESS_TOKEN não fornecido na configuração');\n }\n \n // Debug simplificado após configuração\n if (META_PIXEL_CONFIG.VERBOSE) {\n console.log('[META PIXEL CONFIGURADO]', {\n PIXEL_ID: META_PIXEL_CONFIG.PIXEL_ID ? 'Configurado' : 'Não configurado',\n ACCESS_TOKEN: META_PIXEL_CONFIG.ACCESS_TOKEN ? 'Configurado' : 'Não configurado',\n TEST_EVENT_CODE: META_PIXEL_CONFIG.TEST_EVENT_CODE || 'Não configurado',\n VERBOSE: META_PIXEL_CONFIG.VERBOSE,\n ENVIRONMENT: isVercel ? 'Vercel' : import.meta.env.MODE\n });\n }\n \n if (typeof window !== 'undefined') {\n (window as any)._metaPixelDebug = {\n getConfig: () => META_PIXEL_CONFIG,\n isConfigured: () => isMetaPixelConfigured(),\n validate: validateConfiguration\n };\n }\n}\n\n // Debug imediato para desenvolvedores (apenas se não configurado)\n if (typeof window !== 'undefined' && (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'preview')) {\n // Aguardar um microtask para dar tempo de configuração\n Promise.resolve().then(() => {\n if (!isMetaPixelConfigured()) {\n console.warn('[META PIXEL NÃO CONFIGURADO] Package não configurado. Use configureMetaPixel() antes de usar o hook.');\n }\n });\n \n (window as any)._metaPixelDebug = {\n getConfig: () => META_PIXEL_CONFIG,\n isConfigured: () => isMetaPixelConfigured(),\n validate: validateConfiguration\n };\n}\n\nexport type StandardEvent = (typeof META_PIXEL_CONFIG.STANDARD_EVENTS)[number]; ","// Sistema de logging para o Meta Pixel\n\nexport enum LogCategory {\n INIT = 'INIT',\n META_PIXEL = 'META_PIXEL',\n CONVERSION_API = 'CONVERSION_API',\n PAGE_VIEW = 'PAGE_VIEW',\n SCROLL = 'SCROLL',\n LEAD = 'LEAD',\n QUALIFIED_LEAD = 'QUALIFIED_LEAD',\n VIDEO = 'VIDEO',\n ERROR = 'ERROR',\n DEBUG = 'DEBUG'\n}\n\nexport enum LogLevel {\n DEBUG = 0,\n INFO = 1,\n WARN = 2,\n ERROR = 3\n}\n\ninterface LogEntry {\n timestamp: number\n level: LogLevel\n category: LogCategory\n message: string\n data?: any\n}\n\nclass Logger {\n private logs: LogEntry[] = []\n private maxLogs = 1000\n\n // Função para detectar se deve mostrar logs\n private shouldShowLogs(): boolean {\n // Verificar se estamos no navegador\n if (typeof window === 'undefined') return false\n \n // Verificar configuração VERBOSE do Meta Pixel\n try {\n // Verificar se há configuração VERBOSE no window\n if ((window as any)._metaPixelDebug?.getConfig?.()?.VERBOSE) {\n return true;\n }\n } catch (error) {\n // Se não conseguir verificar, continuar com outras verificações\n }\n \n // Verificar se estamos em desenvolvimento\n const isDev = \n // Vite development\n (typeof import.meta !== 'undefined' && import.meta.env?.MODE === 'development') ||\n // Vite preview\n (typeof import.meta !== 'undefined' && import.meta.env?.MODE === 'preview') ||\n // Node.js development\n process.env.NODE_ENV === 'development' ||\n // Verificar se há debug ativo\n window.location.hostname === 'localhost' ||\n window.location.hostname === '127.0.0.1' ||\n // Verificar se há parâmetro de debug na URL\n window.location.search.includes('debug=true') ||\n // Verificar se há localStorage com debug ativo\n localStorage.getItem('meta-pixel-debug') === 'true' ||\n // Verificar se há console aberto (método simples)\n window.outerHeight - window.innerHeight > 200\n\n return isDev\n }\n\n private addLog(level: LogLevel, category: LogCategory, message: string, data?: any) {\n const entry: LogEntry = {\n timestamp: Date.now(),\n level,\n category,\n message,\n data\n }\n\n this.logs.push(entry)\n\n // Manter apenas os últimos logs\n if (this.logs.length > this.maxLogs) {\n this.logs = this.logs.slice(-this.maxLogs)\n }\n\n // Expor logs no console em desenvolvimento\n if (this.shouldShowLogs()) {\n const prefix = `[META PIXEL - ${category}]`\n const timestamp = new Date().toLocaleTimeString()\n\n switch (level) {\n case LogLevel.DEBUG:\n console.debug(`${prefix} ${timestamp} - ${message}`, data || '')\n break\n case LogLevel.INFO:\n console.info(`${prefix} ${timestamp} - ${message}`, data || '')\n break\n case LogLevel.WARN:\n console.warn(`${prefix} ${timestamp} - ${message}`, data || '')\n break\n case LogLevel.ERROR:\n console.error(`${prefix} ${timestamp} - ${message}`, data || '')\n break\n }\n }\n\n // Expor logs globalmente para debug (sempre disponível)\n if (typeof window !== 'undefined') {\n if (!window._metaPixelLogs) {\n window._metaPixelLogs = {\n getLogs: () => this.logs,\n getLogsByCategory: (category: string) => this.logs.filter(log => log.category === category),\n clear: () => { this.logs = [] },\n enable: () => { localStorage.setItem('meta-pixel-debug', 'true') },\n disable: () => { localStorage.removeItem('meta-pixel-debug') },\n isEnabled: () => this.shouldShowLogs()\n }\n }\n }\n }\n\n debug(category: LogCategory, message: string, data?: any) {\n this.addLog(LogLevel.DEBUG, category, message, data)\n }\n\n info(category: LogCategory, message: string, data?: any) {\n this.addLog(LogLevel.INFO, category, message, data)\n }\n\n warn(category: LogCategory, message: string, data?: any) {\n this.addLog(LogLevel.WARN, category, message, data)\n }\n\n error(category: LogCategory, message: string, data?: any) {\n this.addLog(LogLevel.ERROR, category, message, data)\n }\n\n // Métodos específicos para eventos principais\n pageView(eventId: string, params: any) {\n this.info(LogCategory.PAGE_VIEW, 'PageView enviado', {\n eventId,\n pageTitle: params.page_title,\n pagePath: params.page_path,\n hasUserData: !!params.user_data,\n userData: {\n hasEmail: !!params.user_data?.em,\n hasPhone: !!params.user_data?.ph,\n hasName: !!(params.user_data?.fn || params.user_data?.ln),\n hasFbc: !!params.user_data?.fbc,\n hasFbp: !!params.user_data?.fbp\n }\n })\n }\n\n scroll(depth: number, eventId: string, params: any) {\n this.info(LogCategory.SCROLL, `Scroll atingiu ${depth}%`, {\n eventId,\n depth,\n scrollPercentage: params.scroll_percentage,\n scrollY: params.scroll_y,\n pageTitle: params.page_title,\n pagePath: params.page_path\n })\n }\n\n lead(eventId: string, params: any, userData: any) {\n this.info(LogCategory.LEAD, 'Lead enviado', {\n eventId,\n value: params.value,\n currency: params.currency,\n contentName: params.content_name,\n hasUserData: true,\n userData: {\n hasEmail: !!userData?.em,\n hasPhone: !!userData?.ph,\n hasName: !!(userData?.fn || userData?.ln),\n hasFbc: !!userData?.fbc,\n hasFbp: !!userData?.fbp\n },\n processedUserData: {\n hasEmailHash: !!userData?.em,\n hasPhoneHash: !!userData?.ph,\n hasNameHash: !!(userData?.fn || userData?.ln)\n }\n })\n }\n\n leadQualificado(eventId: string, params: any, userData: any) {\n this.info(LogCategory.QUALIFIED_LEAD, 'LeadQualificado enviado', {\n eventId,\n value: params.value,\n currency: params.currency,\n contentName: params.content_name,\n leadScore: params.lead_score,\n qualificationStatus: params.qualification_status,\n hasUserData: true,\n userData: {\n hasEmail: !!userData?.em,\n hasPhone: !!userData?.ph,\n hasName: !!(userData?.fn || userData?.ln),\n hasFbc: !!userData?.fbc,\n hasFbp: !!userData?.fbp\n }\n })\n }\n\n pixelEvent(eventName: string, eventId: string, method: 'track' | 'trackCustom', success: boolean) {\n this.info(LogCategory.META_PIXEL, `Evento enviado via Pixel: ${eventName}`, {\n eventId,\n method,\n success\n })\n }\n\n conversionApiEvent(eventName: string, eventId: string, success: boolean, responseTime?: number) {\n this.info(LogCategory.CONVERSION_API, `Evento enviado via API: ${eventName}`, {\n eventId,\n success,\n responseTime: responseTime ? `${Math.round(responseTime)}ms` : undefined\n })\n }\n\n getLogs(): LogEntry[] {\n return [...this.logs]\n }\n\n getLogsByCategory(category: LogCategory): LogEntry[] {\n return this.logs.filter(log => log.category === category)\n }\n\n clear(): void {\n this.logs = []\n }\n}\n\nconst logger = new Logger()\nexport default logger ","/**\n * Obtém valor de um cookie pelo nome\n */\nexport function getCookie(name: string): string | null {\n if (typeof document === 'undefined') return null;\n \n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n \n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || null;\n }\n \n return null;\n}\n\n/**\n * Obtém o FBP (Facebook Browser ID) do cookie\n */\nexport function getFbp(): string | null {\n return getCookie('_fbp');\n}\n\n/**\n * Obtém o FBC (Facebook Click ID) do cookie\n */\nexport function getFbc(): string | null {\n return getCookie('_fbc');\n}\n\n/**\n * Gera um Event ID único para deduplicação\n */\nexport function generateEventId(prefix: string = 'evt'): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2, 15);\n return `${prefix}_${timestamp}_${random}`;\n} ","/**\n * Meta Parameter Builder SDK Integration\n * \n * Integra o SDK oficial do Meta para otimização de parâmetros FBC e FBP\n * seguindo as melhores práticas recomendadas pelo Meta.\n * \n * @see https://developers.facebook.com/docs/marketing-api/conversions-api/parameter-builder-feature-library\n */\n\nimport { getCookie } from './cookies'\n\n/**\n * Interface para parâmetros otimizados\n */\nexport interface OptimizedParams {\n fbc: string | null\n fbp: string | null\n // Indica se os parâmetros foram otimizados pelo SDK\n optimized: boolean\n // Fonte da otimização\n source: 'sdk' | 'fallback' | 'manual'\n}\n\n// TODO: Instalar @facebook/parameter-builder-js quando disponível no NPM\n// Por enquanto, implementamos as funcionalidades do SDK manualmente\n\n/**\n * Processa a URL e coleta parâmetros otimizados\n * Simula o comportamento do SDK oficial até a instalação do pacote real\n */\nexport async function processAndCollectAllParams(url: string): Promise<{\n fbc?: string\n fbp?: string\n}> {\n try {\n // Extrair fbclid da URL\n const urlObj = new URL(url)\n const fbclid = urlObj.searchParams.get('fbclid')\n \n // Se temos fbclid, criar/atualizar fbc\n if (fbclid) {\n // Formato do fbc: fb.1.timestamp.fbclid\n const timestamp = Math.floor(Date.now() / 1000)\n const fbc = `fb.1.${timestamp}.${fbclid}`\n \n // Salvar no cookie (domínio principal)\n if (typeof document !== 'undefined') {\n const domain = window.location.hostname.replace('www.', '')\n document.cookie = `_fbc=${fbc}; max-age=7776000; domain=.${domain}; path=/; secure; samesite=lax`\n }\n \n return {\n fbc,\n fbp: getCookie('_fbp') || generateFbp()\n }\n }\n \n // Fallback para cookies existentes\n return {\n fbc: getCookie('_fbc') || undefined,\n fbp: getCookie('_fbp') || generateFbp()\n }\n } catch (error) {\n console.error('[Parameter Builder] Erro ao processar URL:', error)\n return {\n fbc: getCookie('_fbc') || undefined,\n fbp: getCookie('_fbp') || generateFbp()\n }\n }\n}\n\n/**\n * Gera um novo FBP se não existir\n * Formato: fb.1.timestamp.randomId\n */\nfunction generateFbp(): string {\n const timestamp = Math.floor(Date.now() / 1000)\n const randomId = Math.random().toString(36).substring(2, 15)\n const fbp = `fb.1.${timestamp}.${randomId}`\n \n // Salvar no cookie\n if (typeof document !== 'undefined') {\n const domain = window.location.hostname.replace('www.', '')\n document.cookie = `_fbp=${fbp}; max-age=7776000; domain=.${domain}; path=/; secure; samesite=lax`\n }\n \n return fbp\n}\n\n/**\n * Obtém parâmetros otimizados usando o SDK do Meta\n * \n * Esta função:\n * 1. Tenta usar o SDK oficial (quando disponível)\n * 2. Fallback para implementação manual\n * 3. Garante que sempre temos fbc/fbp válidos\n */\nexport async function getOptimizedParams(): Promise<OptimizedParams> {\n try {\n // Verificar se o SDK oficial está disponível\n // TODO: Usar o SDK real quando instalarmos @facebook/parameter-builder-js\n const useRealSDK = false // Mudar para true quando tivermos o SDK\n \n if (useRealSDK && typeof window !== 'undefined') {\n // Usar SDK oficial\n const params = await processAndCollectAllParams(window.location.href)\n return {\n fbc: params.fbc || null,\n fbp: params.fbp || null,\n optimized: true,\n source: 'sdk'\n }\n } else {\n // Usar nossa implementação otimizada\n const params = await processAndCollectAllParams(window.location.href)\n return {\n fbc: params.fbc || null,\n fbp: params.fbp || null,\n optimized: true,\n source: 'fallback'\n }\n }\n } catch (error) {\n console.error('[Parameter Builder] Erro ao obter parâmetros otimizados:', error)\n \n // Fallback manual para garantir que sempre temos algo\n return {\n fbc: getCookie('_fbc'),\n fbp: getCookie('_fbp') || generateFbp(),\n optimized: false,\n source: 'manual'\n }\n }\n}\n\n/**\n * Processa requisição no servidor (para uso futuro com SDK server-side)\n * TODO: Implementar quando instalarmos @facebook/parameter-builder-nodejs\n */\nexport interface ServerProcessRequest {\n host: string\n query: Record<string, string>\n cookies: Record<string, string>\n referer?: string\n}\n\nexport interface UpdatedCookie {\n name: string\n value: string\n maxAge: number\n domain: string\n}\n\n/**\n * Processa requisição no servidor e retorna cookies atualizados\n * Simula o comportamento do ParamBuilder do SDK oficial\n */\nexport function processServerRequest(request: ServerProcessRequest): {\n updatedCookies: UpdatedCookie[]\n fbc: string | null\n fbp: string | null\n} {\n const updatedCookies: UpdatedCookie[] = []\n let fbc = request.cookies._fbc || null\n let fbp = request.cookies._fbp || null\n \n // Processar fbclid se presente\n if (request.query.fbclid) {\n const timestamp = Math.floor(Date.now() / 1000)\n fbc = `fb.1.${timestamp}.${request.query.fbclid}`\n \n updatedCookies.push({\n name: '_fbc',\n value: fbc,\n maxAge: 7776000, // 90 dias\n domain: `.${request.host.replace('www.', '')}`\n })\n }\n \n // Garantir que temos fbp\n if (!fbp) {\n const timestamp = Math.floor(Date.now() / 1000)\n const randomId = Math.random().toString(36).substring(2, 15)\n fbp = `fb.1.${timestamp}.${randomId}`\n \n updatedCookies.push({\n name: '_fbp',\n value: fbp,\n maxAge: 7776000, // 90 dias\n domain: `.${request.host.replace('www.', '')}`\n })\n }\n \n return {\n updatedCookies,\n fbc,\n fbp\n }\n}\n\n/**\n * Valida e normaliza FBC\n * Seguindo as best practices do Meta:\n * - Não modificar case sensitivity\n * - Validar formato\n */\nexport function validateFbc(fbc: string | null): boolean {\n if (!fbc) return false\n \n // Formato esperado: fb.1.timestamp.fbclid\n const parts = fbc.split('.')\n return parts.length === 4 && parts[0] === 'fb' && parts[1] === '1'\n}\n\n/**\n * Valida e normaliza FBP\n */\nexport function validateFbp(fbp: string | null): boolean {\n if (!fbp) return false\n \n // Formato esperado: fb.1.timestamp.randomId\n const parts = fbp.split('.')\n return parts.length === 4 && parts[0] === 'fb' && parts[1] === '1'\n}","// Inicialização do Facebook Pixel para Vite com proteção anti-adblock\n\nimport { META_PIXEL_CONFIG } from './config/meta-pixel'\nimport logger, { LogCategory } from './utils/logger'\nimport { processAndCollectAllParams } from './utils/parameter-builder'\n\nlet isInitialized = false\n\n// Lista de eventos padrão do Facebook Pixel\nconst STANDARD_EVENTS = [\n \"PageView\",\n \"Lead\",\n \"LeadQualificado\",\n]\n\n// Configuração anti-adblock (para futuras expansões)\n// const ANTI_ADBLOCK_CONFIG = {\n// // Nomes ofuscados para evitar detecção\n// scriptNames: ['analytics.js', 'stats.js', 'metrics.js', 'tracking.js'],\n// functionNames: ['analytics', 'stats', 'metrics', 'track'],\n// // URLs de proxy local para o script do Facebook\n// proxyUrls: [\n// '/assets/fb-pixel.js',\n// '/public/analytics.js',\n// '/static/tracking.js'\n// ]\n// }\n\n/**\n * Cria um proxy local para o script do Facebook\n */\nfunction createFacebookPixelProxy(): void {\n if (typeof window === 'undefined') return\n\n // Criar conteúdo do script ofuscado\n const fbPixelCode = `\n !function(f,b,e,v,n,t,s)\n {if(f.fbq)return;n=f.fbq=function(){n.callMethod?\n n.callMethod.apply(n,arguments):n.queue.push(arguments)};\n if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';\n n.queue=[];}(window,document,'script','');\n \n // Carregar o script real do Facebook de forma assíncrona\n (function() {\n var script = document.createElement('script');\n script.async = true;\n script.src = 'https://connect.facebook.net/en_US/fbevents.js';\n script.onerror = function() {\n // Fallback: tentar outros CDNs\n var fallbackScript = document.createElement('script');\n fallbackScript.async = true;\n fallbackScript.src = 'https://cdn.fbsbx.com/en_US/fbevents.js';\n document.head.appendChild(fallbackScript);\n };\n document.head.appendChild(script);\n })();\n `\n\n // Criar blob e URL para o script\n const blob = new Blob([fbPixelCode], { type: 'application/javascript' })\n const scriptUrl = URL.createObjectURL(blob)\n\n // Carregar o script proxy\n const script = document.createElement('script')\n script.async = true\n script.src = scriptUrl\n script.onload = () => {\n logger.info(LogCategory.INIT, \"Script do Facebook carregado via proxy anti-adblock\")\n window._fbPixelScriptLoaded = true\n // Limpar URL do blob após carregar\n URL.revokeObjectURL(scriptUrl)\n }\n script.onerror = () => {\n logger.warn(LogCategory.INIT, \"Proxy falhou, tentando método direto\")\n loadFacebookPixelScriptDirect()\n }\n \n document.head.appendChild(script)\n}\n\n/**\n * Carrega o script do Facebook diretamente (fallback)\n */\nfunction loadFacebookPixelScriptDirect(): void {\n if (typeof window === 'undefined') return\n \n const script = document.createElement('script')\n script.async = true\n script.src = 'https://connect.facebook.net/en_US/fbevents.js'\n script.onload = () => {\n logger.info(LogCategory.INIT, \"Script do Facebook carregado diretamente\")\n window._fbPixelScriptLoaded = true\n }\n script.onerror = (error) => {\n logger.error(LogCategory.INIT, \"Erro ao carregar script do Facebook\", { error })\n // Último recurso: tentar CDN alternativo\n loadFacebookPixelAlternativeCDN()\n }\n \n document.head.appendChild(script)\n}\n\n/**\n * Tenta CDN alternativo do Facebook (último recurso)\n */\nfunction loadFacebookPixelAlternativeCDN(): void {\n if (typeof window === 'undefined') return\n \n const script = document.createElement('script')\n script.async = true\n script.src = 'https://cdn.fbsbx.com/en_US/fbevents.js'\n script.onload = () => {\n logger.info(LogCategory.INIT, \"Script do Facebook carregado via CDN alternativo\")\n window._fbPixelScriptLoaded = true\n }\n script.onerror = (error) => {\n logger.error(LogCategory.INIT, \"Todos os métodos de carregamento falharam\", { error })\n }\n \n document.head.appendChild(script)\n}\n\n/**\n * Inicializa o fbq mesmo se o script não carregar (modo offline)\n */\nfunction initFacebookPixelOffline(): void {\n if (typeof window === 'undefined') return\n\n // Criar implementação mínima do fbq para casos onde o script é bloqueado\n if (!window.fbq) {\n window.fbq = function(...args: any[]) {\n // Armazenar eventos para envio posterior via API\n if (!window._fbq_calls) window._fbq_calls = []\n window._fbq_calls.push(args)\n \n // Log dos eventos mesmo quando bloqueado\n if (args.length >= 2) {\n const [command, eventName] = args\n logger.info(LogCategory.META_PIXEL, `Evento ${eventName} armazenado (script bloqueado)`, {\n command,\n args: args.slice(2)\n })\n }\n }\n\n if (!window._fbq) window._fbq = window.fbq\n ;(window.fbq as any).push = window.fbq\n ;(window.fbq as any).loaded = true\n ;(window.fbq as any).version = \"2.0-offline\"\n ;(window.fbq as any).queue = []\n\n logger.warn(LogCategory.INIT, \"Facebook Pixel inicializado em modo offline (script bloqueado)\")\n }\n}\n\n// Função para inicializar o Facebook Pixel\nexport function initFacebookPixel(): void {\n // Verificar se estamos no lado do cliente\n if (typeof window === \"undefined\") return\n\n // Debug simplificado para identificar conflitos\n if (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'preview') {\n console.log('[META PIXEL INIT] Status:', {\n isInitialized,\n fbPixelInitialized: window._fbPixelInitialized,\n fbqExists: !!window.fbq,\n pixelId: META_PIXEL_CONFIG.PIXEL_ID ? 'Configurado' : 'Não configurado'\n });\n }\n\n // Verificar se já foi inicializado globalmente\n if (isInitialized || window._fbPixelInitialized) {\n logger.debug(LogCategory.INIT, \"Facebook Pixel já inicializado, pulando...\")\n isInitialized = true\n return\n }\n\n // Marcar como inicializado\n isInitialized = true\n window._fbPixelInitialized = true\n\n logger.info(LogCategory.INIT, \"Iniciando Facebook Pixel com proteção anti-adblock...\")\n\n // ✅ NOVO: Processar parâmetros da URL com SDK do Meta\n processAndCollectAllParams(window.location.href).then(params => {\n logger.info(LogCategory.INIT, 'Parâmetros otimizados obtidos via SDK:', {\n hasFbc: !!params.fbc,\n hasFbp: !!params.fbp,\n fbcFromUrl: params.fbc?.includes('fb.1.') || false,\n source: 'parameter-builder-sdk'\n })\n }).catch(error => {\n logger.error(LogCategory.INIT, 'Erro ao processar parâmetros com SDK:', error)\n })\n\n // Tentar carregar script com proteção anti-adblock primeiro\n if (!window._fbPixelScriptLoaded) {\n createFacebookPixelProxy()\n \n // Timeout para detectar se o script foi bloqueado\n setTimeout(() => {\n if (!window.fbq || typeof window.fbq !== 'function') {\n logger.warn(LogCategory.INIT, \"Script detectado como bloqueado, inicializando modo offline\")\n initFacebookPixelOffline()\n }\n }, 3000)\n }\n\n // Inicializar o objeto fbq se ainda não existe\n if (!window.fbq) {\n window.fbq = function(...args: any[]) {\n // Verificar se há argumentos\n if (args.length === 0) {\n logger.warn(LogCategory.META_PIXEL, \"Tentativa de chamar fbq() sem argumentos\")\n return\n }\n\n if ((window.fbq as any).callMethod) {\n (window.fbq as any).callMethod.apply(window.fbq, args)\n } else {\n (window.fbq as any).queue.push(args)\n }\n }\n\n if (!window._fbq) window._fbq = window.fbq\n ;(window.fbq as any).push = window.fbq\n ;(window.fbq as any).loaded = true\n ;(window.fbq as any).version = \"2.0\"\n ;(window.fbq as any).queue = []\n }\n\n // Obter o ID do Pixel da configuração\n const pixelId = META_PIXEL_CONFIG.PIXEL_ID\n \n // Debug simplificado da inicialização\n if (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'preview') {\n console.log('[META PIXEL INIT] Inicializando com Pixel ID:', pixelId ? 'Configurado' : 'Não configurado');\n }\n \n // Registrar um evento para garantir que o script seja utilizado\n window.fbq(\"init\", pixelId)\n\n // Não rastrear PageView automaticamente, isso será feito pelo componente\n logger.info(LogCategory.INIT, `Facebook Pixel inicializado ${pixelId} com proteção anti-adblock`)\n\n // Definir a função global de rastreamento\n if (!window.trackFBEvent) {\n window.trackFBEvent = (event, params) => {\n if (window.fbq) {\n // Extrair event_id dos parâmetros se presente\n const { event_id, ...otherParams } = params || {}\n \n // Preparar opções com eventID no formato correto\n const options = event_id ? { eventID: event_id } : {}\n \n // Verificar se é um evento padrão ou personalizado\n if (STANDARD_EVENTS.includes(event)) {\n window.fbq(\"track\", event, otherParams, options)\n } else {\n window.fbq(\"trackCustom\", event, otherParams, options)\n }\n return true\n }\n return false\n }\n logger.info(LogCategory.INIT, \"Função global de rastreamento registrada\")\n }\n}\n\n// Função para rastrear eventos\nexport function trackPixelEvent(eventName: string, params?: any, leadData?: any): boolean {\n // Verificar se estamos no lado do cliente\n if (typeof window === \"undefined\") return false\n\n // Inicializar o pixel se ainda não foi feito\n if (!isInitialized) {\n initFacebookPixel()\n }\n\n // Gerar um ID de evento único para deduplicação\n const eventId = `evt_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`\n\n // Obter FBC e FBP para incluir nos parâmetros\n const fbc = document.cookie.match(/_fbc=([^;]+)/)?.pop() || null\n const fbp = document.cookie.match(/_fbp=([^;]+)/)?.pop() || null\n\n // Adicionar FBC, FBP e eventId aos parâmetros\n const enhancedParams = {\n ...params,\n _fbc: fbc || undefined,\n _fbp: fbp || undefined,\n event_id: eventId,\n }\n\n logger.info(LogCategory.META_PIXEL, `Rastreando evento: ${eventName}`, {\n eventId,\n hasParams: !!params,\n hasLeadData: !!leadData,\n fbqAvailable: !!window.fbq\n })\n\n // Usar a função global de rastreamento\n if (window.trackFBEvent) {\n return window.trackFBEvent(eventName, enhancedParams)\n } else if (window.fbq) {\n // Extrair o event_id dos parâmetros para usar no formato correto\n const { event_id, ...otherParams } = enhancedParams\n\n // Preparar opções com eventID no formato correto\n const options = event_id ? { eventID: event_id } : {}\n\n // Verificar se é um evento padrão ou personalizado\n if (STANDARD_EVENTS.includes(eventName)) {\n window.fbq(\"track\", eventName, otherParams, options)\n } else {\n window.fbq(\"trackCustom\", eventName, otherParams, options)\n }\n return true\n }\n\n // Se chegou aqui, o fbq não está disponível (bloqueado)\n logger.warn(LogCategory.META_PIXEL, `Evento ${eventName} não pôde ser enviado via pixel (bloqueado)`, {\n eventId,\n willSendViaAPI: true\n })\n\n return false\n}\n\n// Função para verificar se o pixel está inicializado\nexport function isPixelInitialized(): boolean {\n return isInitialized && !!window.fbq\n}\n\n// Função para carregar o script do Facebook com proteção anti-adblock\nexport function loadFacebookPixelScript(): void {\n if (typeof window === \"undefined\") return\n \n // Verificar se o script já foi carregado\n if (window._fbPixelScriptLoaded) {\n logger.debug(LogCategory.INIT, \"Script do Facebook já carregado\")\n return\n }\n\n logger.info(LogCategory.INIT, \"Carregando script do Facebook com proteção anti-adblock\")\n \n // Tentar método anti-adblock primeiro\n createFacebookPixelProxy()\n}\n\n// Função para verificar se o pixel está sendo bloqueado\nexport function isPixelBlocked(): boolean {\n if (typeof window === 'undefined') return false\n \n // Verificar se o fbq existe e funciona\n if (!window.fbq) return true\n \n // Verificar se é a versão offline (bloqueada)\n return (window.fbq as any).version === \"2.0-offline\"\n}\n\n// Função para obter estatísticas de bloqueio\nexport function getPixelBlockingStats(): {\n isBlocked: boolean;\n method: string;\n fallbackActive: boolean;\n} {\n return {\n isBlocked: isPixelBlocked(),\n method: window._fbPixelScriptLoaded ? 'script_loaded' : 'script_blocked',\n fallbackActive: !window._fbPixelScriptLoaded && !!window.fbq\n }\n} ","export default {}",";(function (root, factory) {\n\tif (typeof exports === \"object\") {\n\t\t// CommonJS\n\t\tmodule.exports = exports = factory();\n\t}\n\telse if (typeof define === \"function\" && define.amd) {\n\t\t// AMD\n\t\tdefine([], factory);\n\t}\n\telse {\n\t\t// Global (browser)\n\t\troot.CryptoJS = factory();\n\t}\n}(this, function () {\n\n\t/*globals window, global, require*/\n\n\t/**\n\t * CryptoJS core components.\n\t */\n\tvar CryptoJS = CryptoJS || (function (Math, undefined) {\n\n\t var crypto;\n\n\t // Native crypto from window (Browser)\n\t if (typeof window !== 'undefined' && window.crypto) {\n\t crypto = window.crypto;\n\t }\n\n\t // Native crypto in web worker (Browser)\n\t if (typeof self !== 'undefined' && self.crypto) {\n\t crypto = self.crypto;\n\t }\n\n\t // Native crypto from worker\n\t if (typeof globalThis !== 'undefined' && globalThis.crypto) {\n\t crypto = globalThis.crypto;\n\t }\n\n\t // Native (experimental IE 11) crypto from window (Browser)\n\t if (!crypto && typeof window !== 'undefined' && window.msCrypto) {\n\t crypto = window.msCrypto;\n\t }\n\n\t // Native crypto from global (NodeJS)\n\t if (!crypto && typeof global !== 'undefined' && global.crypto) {\n\t crypto = global.crypto;\n\t }\n\n\t // Native crypto import via require (NodeJS)\n\t if (!crypto && typeof require === 'function') {\n\t try {\n\t crypto = require('crypto');\n\t } catch (err) {}\n\t }\n\n\t /*\n\t * Cryptographically secure pseudorandom number generator\n\t *\n\t * As Math.random() is cryptographically not safe to use\n\t */\n\t var cryptoSecureRandomInt = function () {\n\t if (crypto) {\n\t // Use getRandomValues method (Browser)\n\t if (typeof crypto.getRandomValues === 'function') {\n\t try {\n\t return crypto.getRandomValues(new Uint32Array(1))[0];\n\t } catch (err) {}\n\t }\n\n\t // Use randomBytes method (NodeJS)\n\t if (typeof crypto.randomBytes === 'function') {\n\t try {\n\t return crypto.randomBytes(4).readInt32LE();\n\t } catch (err) {}\n\t }\n\t }\n\n\t throw new Error('Native crypto module could not be used to get secure random number.');\n\t };\n\n\t /*\n\t * Local polyfill of Object.create\n\n\t */\n\t var create = Object.create || (function () {\n\t function F() {}\n\n\t return function (obj) {\n\t var subtype;\n\n\t F.prototype = obj;\n\n\t subtype = new F();\n\n\t F.prototype = null;\n\n\t return subtype;\n\t };\n\t }());\n\n\t /**\n\t * CryptoJS namespace.\n\t */\n\t var C = {};\n\n\t /**\n\t * Library namespace.\n\t */\n\t var C_lib = C.lib = {};\n\n\t /**\n\t * Base object for prototypal inheritance.\n\t */\n\t var Base = C_lib.Base = (function () {\n\n\n\t return {\n\t /**\n\t * Creates a new object that inherits from this object.\n\t *\n\t * @param {Object} overrides Properties to copy into the new object.\n\t *\n\t * @return {Object} The new object.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var MyType = CryptoJS.lib.Base.extend({\n\t * field: 'value',\n\t *\n\t * method: function () {\n\t * }\n\t * });\n\t */\n\t extend: function (overrides) {\n\t // Spawn\n\t var subtype = create(this);\n\n\t // Augment\n\t if (overrides) {\n\t subtype.mixIn(overrides);\n\t }\n\n\t // Create default initializer\n\t if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {\n\t subtype.init = function () {\n\t subtype.$super.init.apply(this, arguments);\n\t };\n\t }\n\n\t // Initializer's prototype is the subtype object\n\t subtype.init.prototype = subtype;\n\n\t // Reference supertype\n\t subtype.$super = this;\n\n\t return subtype;\n\t },\n\n\t /**\n\t * Extends this object and runs the init method.\n\t * Arguments to create() will be passed to init().\n\t *\n\t * @return {Object} The new object.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var instance = MyType.create();\n\t */\n\t create: function () {\n\t var instance = this.extend();\n\t instance.init.apply(instance, arguments);\n\n\t return instance;\n\t },\n\n\t /**\n\t * Initializes a newly created object.\n\t * Override this method to add some logic when your objects are created.\n\t *\n\t * @example\n\t *\n\t * var MyType = CryptoJS.lib.Base.extend({\n\t * init: function () {\n\t * // ...\n\t * }\n\t * });\n\t */\n\t init: function () {\n\t },\n\n\t /**\n\t * Copies properties into this object.\n\t *\n\t * @param {Object} properties The properties to mix in.\n\t *\n\t * @example\n\t *\n\t * MyType.mixIn({\n\t * field: 'value'\n\t * });\n\t */\n\t mixIn: function (properties) {\n\t for (var propertyName in properties) {\n\t if (properties.hasOwnProperty(propertyName)) {\n\t this[propertyName] = properties[propertyName];\n\t }\n\t }\n\n\t // IE won't copy toString using the loop above\n\t if (properties.hasOwnProperty('toString')) {\n\t this.toString = properties.toString;\n\t }\n\t },\n\n\t /**\n\t * Creates a copy of this object.\n\t *\n\t * @return {Object} The clone.\n\t *\n\t * @example\n\t *\n\t * var clone = instance.clone();\n\t */\n\t clone: function () {\n\t return this.init.prototype.extend(this);\n\t }\n\t };\n\t }());\n\n\t /**\n\t * An array of 32-bit words.\n\t *\n\t * @property {Array} words The array of 32-bit words.\n\t * @property {number} sigBytes The number of significant bytes in this word array.\n\t */\n\t var WordArray = C_lib.WordArray = Base.extend({\n\t /**\n\t * Initializes a newly created word array.\n\t *\n\t * @param {Array} words (Optional) An array of 32-bit words.\n\t * @param {number} sigBytes (Optional) The number of significant bytes in the words.\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.lib.WordArray.create();\n\t * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);\n\t * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);\n\t */\n\t init: function (words, sigBytes) {\n\t words = this.words = words || [];\n\n\t if (sigBytes != undefined) {\n\t this.sigBytes = sigBytes;\n\t } else {\n\t this.sigBytes = words.length * 4;\n\t }\n\t },\n\n\t /**\n\t * Converts this word array to a string.\n\t *\n\t * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex\n\t *\n\t * @return {string} The stringified word array.\n\t *\n\t * @example\n\t *\n\t * var string = wordArray + '';\n\t * var string = wordArray.toString();\n\t * var string = wordArray.toString(CryptoJS.enc.Utf8);\n\t */\n\t toString: function (encoder) {\n\t return (encoder || Hex).stringify(this);\n\t },\n\n\t /**\n\t * Concatenates a word array to this word array.\n\t *\n\t * @param {WordArray} wordArray The word array to append.\n\t *\n\t * @return {WordArray} This word array.\n\t *\n\t * @example\n\t *\n\t * wordArray1.concat(wordArray2);\n\t */\n\t concat: function (wordArray) {\n\t // Shortcuts\n\t var thisWords = this.words;\n\t var thatWords = wordArray.words;\n\t var thisSigBytes = this.sigBytes;\n\t var thatSigBytes = wordArray.sigBytes;\n\n\t // Clamp excess bits\n\t this.clamp();\n\n\t // Concat\n\t if (thisSigBytes % 4) {\n\t // Copy one byte at a time\n\t for (var i = 0; i < thatSigBytes; i++) {\n\t var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n\t thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);\n\t }\n\t } else {\n\t // Copy one word at a time\n\t for (var j = 0; j < thatSigBytes; j += 4) {\n\t thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2];\n\t }\n\t }\n\t this.sigBytes += thatSigBytes;\n\n\t // Chainable\n\t return this;\n\t },\n\n\t /**\n\t * Removes insignificant bits.\n\t *\n\t * @example\n\t *\n\t * wordArray.clamp();\n\t */\n\t clamp: function () {\n\t // Shortcuts\n\t var words = this.words;\n\t var sigBytes = this.sigBytes;\n\n\t // Clamp\n\t words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);\n\t words.length = Math.ceil(sigBytes / 4);\n\t },\n\n\t /**\n\t * Creates a copy of this word array.\n\t *\n\t * @return {WordArray} The clone.\n\t *\n\t * @example\n\t *\n\t * var clone = wordArray.clone();\n\t */\n\t clone: function () {\n\t var clone = Base.clone.call(this);\n\t clone.words = this.words.slice(0);\n\n\t return clone;\n\t },\n\n\t /**\n\t * Creates a word array filled with random bytes.\n\t *\n\t * @param {number} nBytes The number of random bytes to generate.\n\t *\n\t * @return {WordArray} The random word array.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.lib.WordArray.random(16);\n\t */\n\t random: function (nBytes) {\n\t var words = [];\n\n\t for (var i = 0; i < nBytes; i += 4) {\n\t words.push(cryptoSecureRandomInt());\n\t }\n\n\t return new WordArray.init(words, nBytes);\n\t }\n\t });\n\n\t /**\n\t * Encoder namespace.\n\t */\n\t var C_enc = C.enc = {};\n\n\t /**\n\t * Hex encoding strategy.\n\t */\n\t var Hex = C_enc.Hex = {\n\t /**\n\t * Converts a word array to a hex string.\n\t *\n\t * @param {WordArray} wordArray The word array.\n\t *\n\t * @return {string} The hex string.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var hexString = CryptoJS.enc.Hex.stringify(wordArray);\n\t */\n\t stringify: function (wordArray) {\n\t // Shortcuts\n\t var words = wordArray.words;\n\t var sigBytes = wordArray.sigBytes;\n\n\t // Convert\n\t var hexChars = [];\n\t for (var i = 0; i < sigBytes; i++) {\n\t var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n\t hexChars.push((bite >>> 4).toString(16));\n\t hexChars.push((bite & 0x0f).toString(16));\n\t }\n\n\t return hexChars.join('');\n\t },\n\n\t /**\n\t * Converts a hex string to a word array.\n\t *\n\t * @param {string} hexStr The hex string.\n\t *\n\t * @return {WordArray} The word array.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.enc.Hex.parse(hexString);\n\t */\n\t parse: function (hexStr) {\n\t // Shortcut\n\t var hexStrLength = hexStr.length;\n\n\t // Convert\n\t var words = [];\n\t for (var i = 0; i < hexStrLength; i += 2) {\n\t words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);\n\t }\n\n\t return new WordArray.init(words, hexStrLength / 2);\n\t }\n\t };\n\n\t /**\n\t * Latin1 encoding strategy.\n\t */\n\t var Latin1 = C_enc.Latin1 = {\n\t /**\n\t * Converts a word array to a Latin1 string.\n\t *\n\t * @param {WordArray} wordArray The word array.\n\t *\n\t * @return {string} The Latin1 string.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);\n\t */\n\t stringify: function (wordArray) {\n\t // Shortcuts\n\t var words = wordArray.words;\n\t var sigBytes = wordArray.sigBytes;\n\n\t // Convert\n\t var latin1Chars = [];\n\t for (var i = 0; i < sigBytes; i++) {\n\t var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n\t latin1Chars.push(String.fromCharCode(bite));\n\t }\n\n\t return latin1Chars.join('');\n\t },\n\n\t /**\n\t * Converts a Latin1 string to a word array.\n\t *\n\t * @param {string} latin1Str The Latin1 string.\n\t *\n\t * @return {WordArray} The word array.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.enc.Latin1.parse(latin1String);\n\t */\n\t parse: function (latin1Str) {\n\t // Shortcut\n\t var latin1StrLength = latin1Str.length;\n\n\t // Convert\n\t var words = [];\n\t for (var i = 0; i < latin1StrLength; i++) {\n\t words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);\n\t }\n\n\t return new WordArray.init(words, latin1StrLength);\n\t }\n\t };\n\n\t /**\n\t * UTF-8 encoding strategy.\n\t */\n\t var Utf8 = C_enc.Utf8 = {\n\t /**\n\t * Converts a word array to a UTF-8 string.\n\t *\n\t * @param {WordArray} wordArray The word array.\n\t *\n\t * @return {string} The UTF-8 string.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);\n\t */\n\t stringify: function (wordArray) {\n\t try {\n\t return decodeURIComponent(escape(Latin1.stringify(wordArray)));\n\t } catch (e) {\n\t throw new Error('Malformed UTF-8 data');\n\t }\n\t },\n\n\t /**\n\t * Converts a UTF-8 string to a word array.\n\t *\n\t * @param {string} utf8Str The UTF-8 string.\n\t *\n\t * @return {WordArray} The word array.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.enc.Utf8.parse(utf8String);\n\t */\n\t parse: function (utf8Str) {\n\t return Latin1.parse(unescape(encodeURIComponent(utf8Str)));\n\t }\n\t };\n\n\t /**\n\t * Abstract buffered block algorithm template.\n\t *\n\t * The property blockSize must be implemented in a concrete subtype.\n\t *\n\t * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0\n\t */\n\t var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({\n\t /**\n\t * Resets this block algorithm's data buffer to its initial state.\n\t *\n\t * @example\n\t *\n\t * bufferedBlockAlgorithm.reset();\n\t */\n\t reset: function () {\n\t // Initial values\n\t this._data = new WordArray.init();\n\t this._nDataBytes = 0;\n\t },\n\n\t /**\n\t * Adds new data to this block algorithm's buffer.\n\t *\n\t * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.\n\t *\n\t * @example\n\t *\n\t * bufferedBlockAlgorithm._append('data');\n\t * bufferedBlockAlgorithm._append(wordArray);\n\t */\n\t _append: function (data) {\n\t // Convert string to WordArray, else assume WordArray already\n\t if (typeof data == 'string') {\n\t data = Utf8.parse(data);\n\t }\n\n\t