|
|
|
|
|
const inputText = document.getElementById('input-text'); |
|
|
const outputText = document.getElementById('output-text'); |
|
|
const optimizeBtn = document.getElementById('optimize-btn'); |
|
|
const clearBtn = document.getElementById('clear-btn'); |
|
|
const exampleBtn = document.getElementById('example-btn'); |
|
|
const copyBtn = document.getElementById('copy-btn'); |
|
|
const charCount = document.getElementById('char-count'); |
|
|
const optimizationScore = document.getElementById('optimization-score'); |
|
|
const toast = document.getElementById('toast'); |
|
|
const toastMessage = document.getElementById('toast-message'); |
|
|
|
|
|
|
|
|
const tabBtns = document.querySelectorAll('.tab-btn'); |
|
|
const tabContents = document.querySelectorAll('.tab-content'); |
|
|
|
|
|
|
|
|
const analysisContent = document.getElementById('analysis-content'); |
|
|
const beforeText = document.getElementById('before-text'); |
|
|
const afterText = document.getElementById('after-text'); |
|
|
|
|
|
|
|
|
const examples = [ |
|
|
"Make me a website for my restaurant", |
|
|
"Write a function to sort numbers", |
|
|
"Create a chatbot for customer service", |
|
|
"Generate a report about sales data", |
|
|
"Build an app to track expenses", |
|
|
"Design a landing page for my startup", |
|
|
"Write code to connect to a database", |
|
|
"Create an API endpoint for user authentication" |
|
|
]; |
|
|
|
|
|
const optimizationRules = { |
|
|
|
|
|
addStructure: (text) => { |
|
|
const hasRole = /^role:/im.test(text.trim()); |
|
|
const hasGoal = /^goal:/im.test(text.trim()); |
|
|
const hasConstraints = /^constraints:/im.test(text.trim()); |
|
|
const hasSteps = /^steps:/im.test(text.trim()); |
|
|
const hasSuccess = /^success criteria:/im.test(text.trim()); |
|
|
|
|
|
let structured = ''; |
|
|
|
|
|
if (!hasRole) { |
|
|
structured += 'ROLE: AI Assistant\n'; |
|
|
} else { |
|
|
const roleMatch = text.match(/^role:(.+?)(?=\n\w+:|$)/im); |
|
|
if (roleMatch) { |
|
|
structured += 'ROLE: ' + roleMatch[1].trim() + '\n'; |
|
|
} |
|
|
} |
|
|
|
|
|
structured += '\n'; |
|
|
|
|
|
if (!hasGoal) { |
|
|
structured += 'GOAL: Execute the specified task with absolute precision, robustness, and full adherence to the intended functionality.\n'; |
|
|
} else { |
|
|
const goalMatch = text.match(/^goal:(.+?)(?=\n\w+:|$)/im); |
|
|
if (goalMatch) { |
|
|
structured += 'GOAL: ' + goalMatch[1].trim() + '\n'; |
|
|
} |
|
|
} |
|
|
|
|
|
structured += '\n'; |
|
|
|
|
|
if (!hasConstraints) { |
|
|
structured += 'CONSTRAINTS:\n- Operate without errors, omissions, or deviations from the defined purpose.\n- Ensure maximum reliability and performance under all expected conditions.\n- Do not introduce assumptions, interpretations, or modifications beyond the defined scope.\n'; |
|
|
} else { |
|
|
const constraintsMatch = text.match(/^constraints:(.+?)(?=\n\w+:|$)/ims); |
|
|
if (constraintsMatch) { |
|
|
const constraints = constraintsMatch[1].trim().split('\n'); |
|
|
structured += 'CONSTRAINTS:\n'; |
|
|
constraints.forEach(line => { |
|
|
if (line.trim()) { |
|
|
if (!line.startsWith('-')) { |
|
|
structured += '- ' + line.trim() + '\n'; |
|
|
} else { |
|
|
structured += line.trim() + '\n'; |
|
|
} |
|
|
} |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
structured += '\n'; |
|
|
|
|
|
if (!hasSteps) { |
|
|
structured += 'STEPS:\n1. Analyze the core objective of the task as explicitly and implicitly defined.\n2. Implement the solution with complete fidelity to the intended behavior.\n3. Reinforce all components to ensure flawless, brute-force reliability.\n4. Validate output against the highest standard of functional correctness.\n5. Deliver the final result in a fully optimized, error-free state.\n'; |
|
|
} else { |
|
|
const stepsMatch = text.match(/^steps:(.+?)(?=\n\w+:|$)/ims); |
|
|
if (stepsMatch) { |
|
|
const steps = stepsMatch[1].trim().split('\n'); |
|
|
structured += 'STEPS:\n'; |
|
|
let stepNum = 1; |
|
|
steps.forEach(line => { |
|
|
if (line.trim()) { |
|
|
const cleanLine = line.replace(/^\d+\.?\s*/, '').trim(); |
|
|
structured += stepNum + '. ' + cleanLine + '\n'; |
|
|
stepNum++; |
|
|
} |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
structured += '\n'; |
|
|
|
|
|
if (!hasSuccess) { |
|
|
structured += 'SUCCESS CRITERIA: The output must perform perfectly, consistently, and robustly according to the original intent, with no failure under expected use.'; |
|
|
} else { |
|
|
const successMatch = text.match(/^success criteria:(.+?)(?=\n\w+:|$)/im); |
|
|
if (successMatch) { |
|
|
structured += 'SUCCESS CRITERIA: ' + successMatch[1].trim(); |
|
|
} |
|
|
} |
|
|
|
|
|
return structured; |
|
|
}, |
|
|
|
|
|
makeImperative: (text) => { |
|
|
return text |
|
|
.replace(/I want you to/gi, 'MANDATE: GENERATE') |
|
|
.replace(/can you/gi, 'DIRECTIVE: EXECUTE') |
|
|
.replace(/please/gi, 'REQUIREMENT:') |
|
|
.replace(/I need/gi, 'SPECIFICATION: PRODUCE') |
|
|
.replace(/we should/gi, 'IMPLEMENTATION: ESTABLISH') |
|
|
.replace(/it would be good if/gi, 'MANDATORY: ENSURE') |
|
|
.replace(/\bmake\b/gi, 'CONSTRUCT') |
|
|
.replace(/\bwrite\b/gi, 'COMPOSE') |
|
|
.replace(/\bbuild\b/gi, 'ENGINEER') |
|
|
.replace(/\bcreate\b/gi, 'GENERATE') |
|
|
.replace(/\bdevelop\b/gi, 'ENGINEER') |
|
|
.replace(/\bdesign\b/gi, 'ARCHITECT') |
|
|
.replace(/\bimplement\b/gi, 'DEPLOY') |
|
|
.replace(/\bcode\b/gi, 'PROGRAM'); |
|
|
}, |
|
|
|
|
|
|
|
|
addPrecision: (text) => { |
|
|
return text |
|
|
.replace(/good/gi, 'OPTIMAL') |
|
|
.replace(/nice/gi, 'AESTHETICALLY SUPERIOR') |
|
|
.replace(/fast/gi, 'HIGH-PERFORMANCE') |
|
|
.replace(/simple/gi, 'MINIMALIST WITH CLEAN ARCHITECTURE') |
|
|
.replace(/modern/gi, 'STATE-OF-THE-ART') |
|
|
.replace(/professional/gi, 'ENTERPRISE-GRADE') |
|
|
.replace(/efficient/gi, 'RESOURCE-OPTIMIZED') |
|
|
.replace(/reliable/gi, 'FAULT-TOLERANT') |
|
|
.replace(/secure/gi, 'CYBERSECURE'); |
|
|
}, |
|
|
|
|
|
addScope: (text) => { |
|
|
if (!/scope|boundary|limit/i.test(text)) { |
|
|
text += '\n\nSCOPE DEFINITION:\n- IN-SCOPE: [Specify all included elements and functionalities]\n- OUT-OF-SCOPE: [Define explicitly excluded items and limitations]\n- BOUNDARIES: [Establish clear operational limits]\n- SUCCESS METRICS: [Define quantifiable performance indicators]'; |
|
|
} |
|
|
return text; |
|
|
}, |
|
|
|
|
|
|
|
|
addQualityAssurance: (text) => { |
|
|
if (!/quality|validation|testing/i.test(text)) { |
|
|
text += '\n\nQUALITY ASSURANCE PROTOCOL:\n- VALIDATION: Verify output against all specified requirements\n- TESTING: Execute comprehensive functionality tests\n- VERIFICATION: Confirm adherence to all constraints\n- OPTIMIZATION: Ensure peak performance under all conditions'; |
|
|
} |
|
|
return text; |
|
|
}, |
|
|
|
|
|
|
|
|
addErrorHandling: (text) => { |
|
|
if (!/error|exception|failure/i.test(text)) { |
|
|
text += '\n\nERROR HANDLING SPECIFICATION:\n- EXCEPTION MANAGEMENT: Implement robust error detection and recovery\n- FAILURE MODES: Define all possible failure scenarios\n- RECOVERY PROCEDURES: Establish automatic recovery protocols\n- LOGGING: Maintain detailed error logs for diagnostics'; |
|
|
} |
|
|
return text; |
|
|
} |
|
|
}; |
|
|
|
|
|
function extractSection(text, sectionType) { |
|
|
const lines = text.split('\n'); |
|
|
let section = ''; |
|
|
let inSection = false; |
|
|
const sectionPatterns = { |
|
|
'ROLE': /^role:/im, |
|
|
'GOAL': /^goal:/im, |
|
|
'CONSTRAINTS': /^constraints?:/im, |
|
|
'STEPS': /^steps?:/im, |
|
|
'SUCCESS CRITERIA': /^success criteria:/im |
|
|
}; |
|
|
|
|
|
for (const line of lines) { |
|
|
const trimmedLine = line.trim(); |
|
|
|
|
|
|
|
|
if (sectionPatterns[sectionType] && sectionPatterns[sectionType].test(trimmedLine)) { |
|
|
inSection = true; |
|
|
section += line + '\n'; |
|
|
continue; |
|
|
} |
|
|
|
|
|
|
|
|
if (inSection) { |
|
|
let foundNewSection = false; |
|
|
for (const [key, pattern] of Object.entries(sectionPatterns)) { |
|
|
if (key !== sectionType && pattern.test(trimmedLine)) { |
|
|
foundNewSection = true; |
|
|
break; |
|
|
} |
|
|
} |
|
|
if (foundNewSection) break; |
|
|
} |
|
|
|
|
|
|
|
|
if (inSection) { |
|
|
section += line + '\n'; |
|
|
} |
|
|
} |
|
|
|
|
|
return section || `${sectionType}:\n${text}`; |
|
|
} |
|
|
|
|
|
function optimizeText() { |
|
|
const input = inputText.value.trim(); |
|
|
|
|
|
if (!input) { |
|
|
showToast('Please enter some text to optimize', 'error'); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
optimizeBtn.classList.add('loading'); |
|
|
optimizeBtn.innerHTML = '<i data-feather="loader" class="w-5 h-5 animate-spin"></i>'; |
|
|
feather.replace(); |
|
|
|
|
|
setTimeout(() => { |
|
|
let optimized = input; |
|
|
|
|
|
optimized = optimizationRules.makeImperative(optimized); |
|
|
optimized = optimizationRules.addPrecision(optimized); |
|
|
optimized = optimizationRules.addScope(optimized); |
|
|
optimized = optimizationRules.addQualityAssurance(optimized); |
|
|
optimized = optimizationRules.addErrorHandling(optimized); |
|
|
|
|
|
|
|
|
const hasStructure = /role|goal|constraint|step|output format/i.test(optimized); |
|
|
if (!hasStructure || optimized.split('\n').length < 3) { |
|
|
optimized = optimizationRules.addStructure(optimized); |
|
|
} |
|
|
|
|
|
|
|
|
optimized = optimized.replace(/\n\s*\n\s*\n/g, '\n\n').trim(); |
|
|
|
|
|
|
|
|
outputText.value = optimized; |
|
|
updateCharCount(); |
|
|
updateOptimizationScore(input, optimized); |
|
|
updateAnalysis(input, optimized); |
|
|
|
|
|
|
|
|
optimizeBtn.classList.remove('loading'); |
|
|
optimizeBtn.innerHTML = '<i data-feather="zap" class="w-5 h-5 mr-2"></i>Optimize Prompt'; |
|
|
feather.replace(); |
|
|
|
|
|
showToast('Prompt optimized successfully!'); |
|
|
}, 800); |
|
|
} |
|
|
|
|
|
|
|
|
function updateCharCount() { |
|
|
const count = outputText.value.length; |
|
|
charCount.textContent = `${count} characters`; |
|
|
} |
|
|
|
|
|
function updateOptimizationScore(original, optimized) { |
|
|
const originalWords = original.split(/\s+/).length; |
|
|
const optimizedWords = optimized.split(/\s+/).length; |
|
|
|
|
|
|
|
|
const hasRole = /^role:/im.test(optimized); |
|
|
const hasGoal = /^goal:/im.test(optimized); |
|
|
const hasConstraints = /^constraints:/im.test(optimized); |
|
|
const hasSteps = /^steps:/im.test(optimized); |
|
|
const hasSuccess = /^success criteria:/im.test(optimized); |
|
|
|
|
|
const structureScore = (hasRole + hasGoal + hasConstraints + hasSteps + hasSuccess) * 20; |
|
|
|
|
|
|
|
|
const precisionKeywords = /precision|robustness|reliability|consistently|flawless|maximum|absolute/gi; |
|
|
const precisionCount = (optimized.match(precisionKeywords) || []).length; |
|
|
const precisionScore = Math.min(20, precisionCount * 4); |
|
|
|
|
|
|
|
|
const actionKeywords = /execute|implement|validate|deliver|analyze|reinforce/gi; |
|
|
const actionCount = (optimized.match(actionKeywords) || []).length; |
|
|
const actionScore = Math.min(20, actionCount * 4); |
|
|
|
|
|
|
|
|
const clarityBonus = optimized.includes('no failure under expected use') ? 10 : 0; |
|
|
const specificityBonus = optimized.includes('highest standard') ? 10 : 0; |
|
|
|
|
|
const score = Math.min(100, structureScore + precisionScore + actionScore + clarityBonus + specificityBonus); |
|
|
|
|
|
let scoreColor = 'text-red-500'; |
|
|
if (score >= 95) scoreColor = 'text-green-500'; |
|
|
else if (score >= 85) scoreColor = 'text-green-600'; |
|
|
else if (score >= 75) scoreColor = 'text-yellow-500'; |
|
|
else if (score >= 65) scoreColor = 'text-orange-500'; |
|
|
else if (score >= 50) scoreColor = 'text-red-600'; |
|
|
|
|
|
optimizationScore.textContent = `Optimization Score: ${score}/100`; |
|
|
optimizationScore.className = `font-semibold ${scoreColor} score-update`; |
|
|
|
|
|
setTimeout(() => { |
|
|
optimizationScore.classList.remove('score-update'); |
|
|
}, 500); |
|
|
} |
|
|
|
|
|
function updateAnalysis(original, optimized) { |
|
|
beforeText.textContent = original; |
|
|
afterText.textContent = optimized; |
|
|
|
|
|
const improvements = []; |
|
|
const structureComponents = ['Role', 'Goal', 'Constraints', 'Steps', 'Success Criteria']; |
|
|
|
|
|
|
|
|
structureComponents.forEach(component => { |
|
|
const pattern = new RegExp(`^${component}:`, 'im'); |
|
|
if (!pattern.test(original) && pattern.test(optimized)) { |
|
|
improvements.push(`✅ Added ${component} section for comprehensive structure`); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
if (!/precision|robustness|reliability|absolute/gi.test(original)) { |
|
|
improvements.push('✅ Enhanced with precision-focused language'); |
|
|
} |
|
|
|
|
|
if (!/maximum|flawless|consistent/gi.test(original)) { |
|
|
improvements.push('✅ Added reliability and consistency requirements'); |
|
|
} |
|
|
|
|
|
|
|
|
if (!/execute|implement|validate|deliver/gi.test(original)) { |
|
|
improvements.push('✅ Transformed to action-oriented directives'); |
|
|
} |
|
|
|
|
|
|
|
|
if (!/without errors|no failure|no deviations/gi.test(original)) { |
|
|
improvements.push('✅ Implemented error prevention measures'); |
|
|
} |
|
|
|
|
|
|
|
|
const hasRole = /^role:/im.test(optimized); |
|
|
const hasGoal = /^goal:/im.test(optimized); |
|
|
const hasConstraints = /^constraints:/im.test(optimized); |
|
|
const hasSteps = /^steps:/im.test(optimized); |
|
|
const hasSuccess = /^success criteria:/im.test(optimized); |
|
|
const structureCount = [hasRole, hasGoal, hasConstraints, hasSteps, hasSuccess].filter(Boolean).length; |
|
|
|
|
|
const precisionCount = (optimized.match(/precision|robustness|reliability|absolute|flawless|maximum/gi) || []).length; |
|
|
const actionCount = (optimized.match(/execute|implement|validate|deliver|analyze|reinforce/gi) || []).length; |
|
|
|
|
|
const analysisHTML = ` |
|
|
<div class="space-y-3"> |
|
|
<div class="bg-blue-50 p-3 rounded-lg"> |
|
|
<h4 class="font-semibold text-blue-800 mb-1">Key Improvements Applied:</h4> |
|
|
<ul class="text-sm space-y-1"> |
|
|
${improvements.map(imp => `<li class="flex items-start"><span class="mr-2">•</span>${imp}</li>`).join('')} |
|
|
</ul> |
|
|
</div> |
|
|
<div class="bg-green-50 p-3 rounded-lg"> |
|
|
<h4 class="font-semibold text-green-800 mb-1">Optimization Metrics:</h4> |
|
|
<div class="grid grid-cols-2 gap-2 text-sm"> |
|
|
<div>Original Words: <span class="font-semibold">${original.split(/\s+/).length}</span></div> |
|
|
<div>Optimized Words: <span class="font-semibold">${optimized.split(/\s+/).length}</span></div> |
|
|
<div>Structure Components: <span class="font-semibold">${structureCount}/5</span></div> |
|
|
<div>Precision Keywords: <span class="font-semibold">${precisionCount}</span></div> |
|
|
<div>Action Directives: <span class="font-semibold">${actionCount}</span></div> |
|
|
<div>Robustness Score: <span class="font-semibold">${Math.min(100, structureCount * 20 + precisionCount * 3 + actionCount * 2)}%</span></div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="bg-purple-50 p-3 rounded-lg"> |
|
|
<h4 class="font-semibold text-purple-800 mb-1">Expected Impact:</h4> |
|
|
<p class="text-sm">This optimized prompt will execute with absolute precision, ensuring maximum reliability and performance under all expected conditions. The structure eliminates ambiguity, enforces error-free operation, and delivers consistent results according to the highest functional standards.</p> |
|
|
</div> |
|
|
<div class="bg-orange-50 p-3 rounded-lg"> |
|
|
<h4 class="font-semibold text-orange-800 mb-1">Compliance Status:</h4> |
|
|
<p class="text-sm">✅ All constraints defined and enforced<br>✅ Success criteria clearly specified<br>✅ No assumptions beyond defined scope<br>✅ Brute-force reliability implemented</p> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
|
|
|
analysisContent.innerHTML = analysisHTML; |
|
|
} |
|
|
|
|
|
function copyToClipboard() { |
|
|
if (!outputText.value) { |
|
|
showToast('No optimized prompt to copy', 'error'); |
|
|
return; |
|
|
} |
|
|
|
|
|
outputText.select(); |
|
|
document.execCommand('copy'); |
|
|
showToast('Optimized prompt copied to clipboard!'); |
|
|
} |
|
|
|
|
|
|
|
|
function clearAll() { |
|
|
inputText.value = ''; |
|
|
outputText.value = ''; |
|
|
charCount.textContent = '0 characters'; |
|
|
optimizationScore.textContent = ''; |
|
|
analysisContent.innerHTML = '<p class="text-gray-500">Analysis will appear after optimization...</p>'; |
|
|
beforeText.textContent = ''; |
|
|
afterText.textContent = ''; |
|
|
|
|
|
showToast('Fields cleared'); |
|
|
} |
|
|
|
|
|
|
|
|
function loadExample() { |
|
|
const randomExample = examples[Math.floor(Math.random() * examples.length)]; |
|
|
inputText.value = randomExample; |
|
|
inputText.focus(); |
|
|
showToast('Example loaded - try optimizing it!'); |
|
|
} |
|
|
|
|
|
|
|
|
function showToast(message, type = 'success') { |
|
|
toastMessage.textContent = message; |
|
|
|
|
|
|
|
|
if (type === 'error') { |
|
|
toast.className = 'fixed bottom-8 right-8 bg-red-500 text-white px-6 py-3 rounded-lg shadow-lg transform transition-all duration-300 flex items-center'; |
|
|
} else { |
|
|
toast.className = 'fixed bottom-8 right-8 bg-gray-800 text-white px-6 py-3 rounded-lg shadow-lg transform transition-all duration-300 flex items-center'; |
|
|
} |
|
|
|
|
|
toast.classList.add('show'); |
|
|
|
|
|
setTimeout(() => { |
|
|
toast.classList.remove('show'); |
|
|
}, 3000); |
|
|
} |
|
|
|
|
|
|
|
|
function switchTabs() { |
|
|
tabBtns.forEach(btn => { |
|
|
btn.addEventListener('click', () => { |
|
|
const targetTab = btn.dataset.tab; |
|
|
|
|
|
|
|
|
tabBtns.forEach(b => b.classList.remove('active')); |
|
|
btn.classList.add('active'); |
|
|
|
|
|
|
|
|
tabContents.forEach(content => { |
|
|
content.classList.add('hidden'); |
|
|
}); |
|
|
document.getElementById(`${targetTab}-tab`).classList.remove('hidden'); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
inputText.addEventListener('input', updateCharCount); |
|
|
outputText.addEventListener('input', updateCharCount); |
|
|
|
|
|
|
|
|
document.addEventListener('keydown', (e) => { |
|
|
|
|
|
if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { |
|
|
e.preventDefault(); |
|
|
optimizeText(); |
|
|
} |
|
|
|
|
|
|
|
|
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === 'C') { |
|
|
e.preventDefault(); |
|
|
copyToClipboard(); |
|
|
} |
|
|
|
|
|
|
|
|
if (e.key === 'Escape') { |
|
|
clearAll(); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
optimizeBtn.addEventListener('click', optimizeText); |
|
|
clearBtn.addEventListener('click', clearAll); |
|
|
exampleBtn.addEventListener('click', loadExample); |
|
|
copyBtn.addEventListener('click', copyToClipboard); |
|
|
|
|
|
|
|
|
switchTabs(); |
|
|
|
|
|
window.addEventListener('load', () => { |
|
|
inputText.focus(); |
|
|
}); |
|
|
|
|
|
|
|
|
class BookmarkletManager { |
|
|
constructor() { |
|
|
this.panel = null; |
|
|
} |
|
|
|
|
|
init() { |
|
|
|
|
|
if (!window.location.href.includes('huggingface.co')) { |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
if (document.readyState === 'loading') { |
|
|
document.addEventListener('DOMContentLoaded', () => this.injectPanel()); |
|
|
} else { |
|
|
this.injectPanel(); |
|
|
} |
|
|
} |
|
|
|
|
|
injectPanel() { |
|
|
|
|
|
if (document.querySelector('hf-panel')) { |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
this.panel = document.createElement('hf-panel'); |
|
|
document.body.appendChild(this.panel); |
|
|
} |
|
|
|
|
|
removePanel() { |
|
|
if (this.panel) { |
|
|
this.panel.remove(); |
|
|
this.panel = null; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
window.bookmarkletManager = new BookmarkletManager(); |
|
|
|
|
|
|
|
|
window.initHFBookmarklet = () => { |
|
|
window.bookmarkletManager.init(); |
|
|
}; |
|
|
|
|
|
|
|
|
if (window.location.href.includes('huggingface.co')) { |
|
|
window.initHFBookmarklet(); |
|
|
} |
|
|
|