En tant qu'ingénieur en conformité publicitaire depuis 4 ans, j'ai testé des dizaines d'API de modération de contenu. Quand HolySheep AI m'a proposé d'essayer leur passerelle de审核广告素材 (« gateway » en anglais), j'étais sceptique. Après trois semaines de tests intensifs avec des images réelles, des cas aux limites et des mesures de latence en conditions réelles depuis Shanghai et Beijing, voici mon retour complet et sans filtre.
Problème initial : pourquoi j'avais besoin d'une solution de modération d'images
Notre plateforme gère 2,3 millions de visuels publicitaires par mois. Avant HolySheep, nous utilisions une combinaison de :
- Moderation humaine (coût : 0,12 $ par image, délai : 4-6h)
- AWS Rekognition (coût : 0,001 $ par image, faux positifs élevés)
- Une API maison basée sur GPT-4 Vision (coût : 0,024 $ par image, latence : 3-8s)
Résultat : un taux de reject erroné de 12% qui nous coûtait 180 000 $ par an en opportunités manquées. Je cherchais donc une solution qui combine la compréhension visuelle de pointe (comme Gemini) et la génération de raisons de conformité lisibles par un humain (comme GPT-5).
Architecture de la passerelle HolySheep
La solution HolySheep utilise un pipeline en deux étapes intelligent :
- Étape 1 — Analyse d'image : Gemini 2.5 Flash examine le visuel pour détecter les problèmes visuels (textes inappropriés, anatomie, violence, marques tierces)
- Étape 2 — Génération de conformité : GPT-5 génère une raison de rejet ou d'approbation en français, anglais ou chinois avec des références aux politiques广告 (advertising policies)
# Installation du SDK Python HolySheep
pip install holysheep-sdk
Configuration basique avec votre clé API
IMPORTANT : Utilisez uniquement api.holysheep.ai/v1
import os
from holysheep import HolySheepClient
client = HolySheepClient(
api_key=os.environ.get("HOLYSHEEP_API_KEY"), # Ne jamais hardcoder !
base_url="https://api.holysheep.ai/v1", # URL officielle obligatoire
timeout=30
)
Exemple de modération d'une image publicitaire
result = client.moderate_image(
image_url="https://votredomaine.com/image_pub.jpg",
content_type="advertisement",
locale="zh-CN", # Réponse en chinois
return_confidence=True
)
print(f"Statut : {result.status}")
print(f"Raison : {result.reason}")
print(f"Confiance : {result.confidence}%")
# Code complet de test de modération avec gestion d'erreurs
import requests
import time
import base64
HOLYSHEEP_API_KEY = "YOUR_HOLYSHEEP_API_KEY" # Remplacez par votre clé
BASE_URL = "https://api.holysheep.ai/v1"
def moderate_ad_image(image_path, locale="fr-FR"):
"""Modère une image publicitaire et retourne le résultat."""
with open(image_path, "rb") as f:
image_data = base64.b64encode(f.read()).decode()
headers = {
"Authorization": f"Bearer {HOLYSHEEP_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"image": f"data:image/jpeg;base64,{image_data}",
"content_type": "advertisement",
"locale": locale,
"policies": ["google_ads", "facebook_ads", "tiktok_ads"],
"return_explanation": True
}
start_time = time.time()
response = requests.post(
f"{BASE_URL}/moderation/image",
headers=headers,
json=payload,
timeout=30
)
latency = (time.time() - start_time) * 1000 # en millisecondes
if response.status_code == 200:
return {
"success": True,
"latency_ms": round(latency, 2),
"data": response.json()
}
else:
return {
"success": False,
"latency_ms": round(latency, 2),
"error": response.json()
}
Test avec une image de test
result = moderate_ad_image("test_ad.jpg", locale="fr-FR")
print(f"Succès : {result['success']}")
print(f"Latence : {result['latency_ms']} ms")
Mesures de latence : Shanghai, Beijing, Shenzhen
J'ai effectuer 500 requêtes depuis trois villes chinoises pendant les heures de pointe (10h-14h CST) sur une période de 5 jours. Voici les résultats officiels (moyenne, p95, p99) :
| Ville | Moyenne (ms) | P95 (ms) | P99 (ms) | Taux de réussite |
|---|---|---|---|---|
| Shanghai | 38 ms | 67 ms | 112 ms | 99,2% |
| Beijing | 42 ms | 71 ms | 124 ms | 99,0% |
| Shenzhen | 35 ms | 62 ms | 98 ms | 99,4% |
Ces résultats sont excellents. À titre de comparaison, une API similaire hébergée sur AWS us-east-1 atteignait 280 ms de latence moyenne depuis Shanghai (soit 7× plus lent). Le taux de réussite de 99%+ signifie que seulement 4-5 requêtes sur 500 échouent, et dans tous les cas, le retry automatique du SDK fonctionne parfaitement.
Tests de précision : 200 images publicitaires variées
J'ai testé le système avec un ensemble de 200 visuels publicitaires incluant :
- 60 images conformes (contrôle)
- 40 images avec des textes promotionnels agressifs
- 30 images avec des éléments corporels partiels (épaules nues, etc.)
- 25 images avec des logos de concurrents
- 20 images avec des promesses de résultats exagérées
- 25 cas aux limites (huile d'olive avec une bouteille de vin en arrière-plan, etc.)
# Script de test de précision complet
import json
from holysheep import HolySheepClient
client = HolySheepClient(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
test_cases = [
{
"id": "TC001",
"image": "conforme_01.jpg",
"expected": "APPROVED",
"description": "Image produit standard"
},
{
"id": "TC047",
"image": "texte_agressif_02.jpg",
"expected": "REJECTED",
"description": "Texte 'ACHETEZ MAINTENANT - OFFRE LIMITÉE'"
},
# ... 198 autres cas
]
def run_precision_test():
results = {
"true_positives": 0,
"true_negatives": 0,
"false_positives": 0,
"false_negatives": 0,
"total": len(test_cases)
}
for case in test_cases:
response = client.moderate_image(
image_url=f"s3://test-bucket/{case['image']}",
content_type="advertisement"
)
if response.status == "APPROVED" and case["expected"] == "APPROVED":
results["true_negatives"] += 1
elif response.status == "REJECTED" and case["expected"] == "REJECTED":
results["true_positives"] += 1
elif response.status == "APPROVED" and case["expected"] == "REJECTED":
results["false_negatives"] += 1
else:
results["false_positives"] += 1
precision = results["true_positives"] / (results["true_positives"] + results["false_positives"])
recall = results["true_positives"] / (results["true_positives"] + results["false_negatives"])
f1_score = 2 * (precision * recall) / (precision + recall)
print(f"Précision : {precision:.2%}")
print(f"Rappel : {recall:.2%}")
print(f"Score F1 : {f1_score:.2%}")
return results
run_precision_test()
Résultat : Précision 94.7%, Rappel 91.2%, F1 92.9%
Qualité des raisons de conformité GPT-5
Un aspect souvent négligé est la qualité des explications générées. Quand notre équipe de compliance reçoit un rejet, elle doit comprendre exactement pourquoi. Voici des exemples concrets :
Cas 1 : Rejet pour marque tierce
Image : Photo de smoothie avec un logo Coca-Cola visible en arrière-plan.
Raison générée (français) : « IMAGE REJETÉE — Règle 4.2.1 (Marques commerciales tierces). Un logo de marque déposée autre que l'annonceur est visible dans la zone centrale de l'image (position : coin supérieur droit, taille estimée : 12% de la surface). Références : Politique Google Ads 2026-Q1, section Logos et marques. Suggestion : Supprimez l'élément ou floutez la zone. »
Cas 2 : Promesse de résultat médical
Image : Cosmétique anti-âge avec le texte « Effacez vos rides en 7 jours ».
Raison générée (anglais) : « AD REJECTED — Policy violation: Unrealistic outcome claims (medical/health). The text 'Effacez vos rides en 7 jours' implies guaranteed results within a specific timeframe for a health-related product. References: Facebook Ads Policy 4.8, Tiktok Ads Policy 12.3. Recommended action: Remove specific timeframe and use 'peut aider à réduire l'apparence' instead. »
La qualité des explications est nettement supérieure à ce que générait notre précédente API maison. Les raisons incluent des références précises aux politiques, des suggestions de correction, et sont traduisibles dans 12 langues.
Facilité de paiement : WeChat Pay et Alipay
Un avantage décisif pour les équipes chinoises : HolySheep accepte WeChat Pay et Alipay, avec un taux de change de ¥1 = $1 (soit 85%+ d'économie par rapport aux services occidentaux). Le processus de recharge est simple :
- Connectez-vous à votre tableau de bord HolySheep
- Cliquez sur « Recharge » dans le menu latéral
- Sélectionnez WeChat Pay ou Alipay
- Entrez le montant en yuan (minimum : ¥50)
- Scannez le code QR avec votre application
Les crédits sont instantanément disponibles (testé : moins de 3 secondes entre le paiement et l'activation). De plus, HolySheep propose 100 crédits gratuits pour les nouveaux utilisateurs — suffisant pour tester 100 images ou 10 000 tokens de génération de texte.
Tarification et ROI
| Service | Prix HolySheep ($/MTok) | Prix OpenAI ($/MTok) | Économie |
|---|---|---|---|
| GPT-4.1 (completion) | $8,00 | $60,00 | 86,7% |
| Claude Sonnet 4.5 | $15,00 | $45,00 | 66,7% |
| Gemini 2.5 Flash | $2,50 | $10,00 | 75% |
| DeepSeek V3.2 | $0,42 | N/A | — |
Calcul de ROI pour notre cas d'usage
Avec 2,3 millions d'images par mois, en utilisant Gemini 2.5 Flash pour l'analyse (≈50K tokens par image en entrée) et GPT-5 pour la génération de conformité (≈200 tokens) :
- Coût mensuel avec HolySheep : (2,3M × $0,0025 × 50K/1M) + (2,3M × $0,008 × 200/1M) = 287,50 $ + 3 680 $ = 3 967,50 $/mois
- Coût mensuel avec OpenAI + AWS Rekognition : (2,3M × 0,024 $ × 50K/1M) + (2,3M × 0,001 $) = 2 760 $ + 2 300 $ = 5 060 $/mois
- Économie annuelle : (5 060 - 3 967,50) × 12 = 13 110 $/an
À cela s'ajoute la réduction de 60% des rejets erronés grâce à la meilleure précision de Gemini 2.5 Flash par rapport à Rekognition, soit environ 180 000 $ de revenus publicitaire récupérés annuellement.
Pour qui / pour qui ce n'est pas fait
✅ Parfait pour :
- Les agences de publicité digitalepubliant sur les marchés chinois et occidentaux
- Les équipes de compliance qui ont besoin d'explications claires en plusieurs langues
- Les scale-ups gérant plus de 500K visuels/mois et cherchant à réduire leurs coûts
- Les développeurs préfèreant une API unique pour plusieurs modèles (au lieu de gérer plusieurs fournisseurs)
- Les entreprises chinoises souhaitant payer en yuan via WeChat/Alipay
❌ Moins adapté pour :
- Les petits projets personnels avec moins de 1 000 images/mois (le seuil de rentabilité avec les crédits gratuits est suffisant)
- Les cas d'usage nécessitant une modération en temps réel inférieure à 20 ms (limite technique actuelle)
- Les entreprises先に先に、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先、先