SPB Git

spb/sorti-ka

Public

Toutes les sorties et tous les événements du Québec, un seul endroit — 7 connecteurs, fiches SSR, design Groupe KA.

Sorti·Ka v1 — agrégateur de sorties & événements du Québec

8 connecteurs actifs (Le point de vente, SIT Québec, Ville de Montréal,
evenko, La Vitrine, Atuvu, Sherbrooke, Laval), 15 231 événements actifs
dans les 17 régions, fiches SSR /evenement/{uid} avec JSON-LD, dédup
inter-sources, enrichissement d'images og:image, design system Groupe KA
« éditorial sharp », 19 tests sur fixtures réelles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed (Aug 17, 2026) Browse files

39 changed files +11,585 −0

added .gitignore +13 −0
@@ -0,0 +1,13 @@
1+# ==============================================================================
2+# Author: Simon-Pierre Boucher <contact@spboucher.ai>
3+# File: .gitignore
4+# Desc: Exclusions Git — secrets, base de données, caches
5+# ==============================================================================
6+.env
7+data/sortika.db
8+data/*_cache.json
9+__pycache__/
10+*.pyc
11+.pytest_cache/
12+.venv/
13+.DS_Store
added CLAUDE.md +572 −0
@@ -0,0 +1,572 @@
1+<!--
2+================================================================================
3+ Author: Simon-Pierre Boucher <contact@spboucher.ai>
4+ File: CLAUDE.md
5+ Project: Resto·Ka — Agrégateur québécois de tous les restaurants (menus + prix)
6+================================================================================
7+-->
8+
9+# CLAUDE.md — Resto·Ka
10+
11+> **Agrégateur exhaustif de tous les restaurants du Québec, avec leurs menus
12+> complets et leurs prix.**
13+> Chaque resto, chaque plat, chaque prix — dans les 17 régions, au même endroit,
14+> comparable et cherchable.
15+
16+Ce fichier est la source de vérité pour tout agent Claude (ou humain) qui travaille
17+sur ce dépôt. Lis-le **en entier** avant d'écrire une seule ligne de code.
18+
19+---
20+
21+## 0. À LIRE EN PREMIER — Règles non négociables
22+
23+1. **En-tête d'auteur obligatoire.** **Chaque fichier** du dépôt (code, config,
24+ doc, script) doit commencer par un en-tête mentionnant l'auteur :
25+ `Simon-Pierre Boucher <contact@spboucher.ai>`. Voir la **section 17** pour le
26+ format exact selon le type de fichier. Aucun fichier ne doit être commité sans
27+ cet en-tête.
28+
29+2. **Inspire-toi du dépôt Lou·Ka.** Avant de concevoir ou d'écrire **le moindre
30+ connecteur**, va lire le **dépôt de Lou·Ka** (le site jumeau, agrégateur de
31+ logements locatifs). Ses connecteurs sont le patron de référence : structure
32+ des modules, extraction (Firecrawl / Scrapfly), normalisation, déduplication,
33+ gestion des mises à jour, planification des tâches. **Ne réinvente rien** :
34+ reprends les mêmes conventions, la même architecture de connecteur, les mêmes
35+ utilitaires partagés. Resto·Ka doit être cohérent avec l'écosystème `·Ka`
36+ (Lou·Ka, Immo·Ka, Auto·Ka, Food·Ka, Fabri·Ka, Sorti·Ka). Voir **section 3**.
37+
38+3. **Travail de moine.** L'agrégation de menus est un travail minutieux, source par
39+ source, plat par plat, sans rien précipiter. Un menu mal parsé (mauvais prix,
40+ plat manquant, option ignorée) détruit la confiance dans toute la base. Mieux
41+ vaut un connecteur robuste de plus que dix fragiles.
42+
43+4. **Vérifie l'existant avant d'ajouter.** Avant d'intégrer un resto ou une source,
44+ confirme qu'il/elle n'est **pas déjà couvert(e)** (voir le registre des sources
45+ et l'index des restaurants, sections 9 et 12). Ne duplique jamais un connecteur
46+ ni une fiche resto. Un restaurant = une fiche canonique, quelles que soient les
47+ sources qui l'alimentent.
48+
49+5. **Chaque source a son connecteur sur mesure**, mais les sources qui partagent
50+ une **même plateforme** (livraison, commande en ligne, POS, réservation)
51+ doivent être couvertes par un **connecteur générique templatisé** réutilisable.
52+ Voir **section 8**.
53+
54+6. **La provenance du prix est sacrée.** Un prix de livraison (Uber Eats, DoorDash,
55+ Skip) est **majoré de 25-30 %** par rapport à la salle à manger. Ne **jamais**
56+ présenter un prix sans son contexte (`price_context`). Voir **sections 5 et 11**.
57+
58+---
59+
60+## 1. Mission
61+
62+Rendre visible, en un seul endroit, **tous les restaurants du Québec avec leurs
63+menus et leurs prix réels**, dans les 17 régions — pour que quiconque puisse
64+répondre à *« qu'est-ce que je mange, où, et combien ça coûte ? »* sans ouvrir
65+quinze applis.
66+
67+### Ce qui nous distingue
68+
69+Les plateformes existantes sont soit des **apps de livraison** (Uber Eats, Skip,
70+DoorDash — menus complets mais prix majorés, périmètre limité aux restos inscrits
71+et payants), soit des **annuaires** (Google, Yelp, TripAdvisor — avis et coordonnées,
72+mais **pas de menus structurés ni de prix comparables**), soit des **médias food**
73+(Tastet, RestoMontréal — éditorial, pas exhaustif).
74+
75+Personne n'offre **le menu complet + les prix de tous les restos, comparables entre
76+eux, partout au Québec.** C'est le créneau de Resto·Ka.
77+
78+---
79+
80+## 2. Périmètre — TOUS les établissements où l'on mange
81+
82+Périmètre maximaliste. Si on peut y commander à manger, ça doit finir dans Resto·Ka :
83+
84+- **Restaurants** (tous services : gastronomique, décontracté, familial).
85+- **Fast-food & chaînes** (menus standardisés, multi-succursales).
86+- **Cafés & salons de thé** (avec offre alimentaire).
87+- **Bars & pubs** avec cuisine.
88+- **Comptoirs pour emporter, cantines, casse-croûtes, food trucks.**
89+- **Pizzérias, sushis, poulet, burgers, shawarma**, etc.
90+- **Boulangeries-pâtisseries et traiteurs** avec menu et prix.
91+- **Microbrasseries et établissements** avec menu de bouffe.
92+- **Restaurants d'hôtel**, cuisines fantômes (ghost kitchens).
93+
94+> Règle d'or : en cas de doute sur l'inclusion, **on inclut** et on catégorise par
95+> type d'établissement. Le périmètre est large par conception.
96+
97+---
98+
99+## 3. Dépôts de référence — étudier Lou·Ka AVANT de coder
100+
101+Resto·Ka fait partie de la famille `·Ka`. **Le dépôt de Lou·Ka est la référence
102+canonique pour l'architecture des connecteurs.** Avant tout développement, l'agent
103+Claude doit :
104+
105+1. **Ouvrir le dépôt de Lou·Ka** et localiser le dossier des connecteurs
106+ (typiquement `connectors/`, `scrapers/` ou `sources/`).
107+2. **Lire 2 ou 3 connecteurs complets** de bout en bout pour comprendre :
108+ - la structure d'un module connecteur (interface commune, méthodes attendues) ;
109+ - l'**extraction** (Firecrawl / Scrapfly, endpoints JSON, sitemaps) ;
110+ - la **normalisation** vers le schéma commun ;
111+ - la **déduplication** (annonces publiées sur plusieurs plateformes) ;
112+ - la gestion des **mises à jour** (nouveautés, changements, retraits) ;
113+ - la **planification** (cadence, files, retries, backoff), les **erreurs** et le
114+ **logging**.
115+3. **Réutiliser** les utilitaires partagés de Lou·Ka (client Firecrawl/Scrapfly,
116+ helpers de normalisation, déduplication, géocodage) plutôt que d'en réécrire.
117+4. **Calquer** les conventions de nommage, la structure des dossiers et le style
118+ de code de Lou·Ka. Un dev qui connaît Lou·Ka doit se retrouver immédiatement.
119+
120+> Adaptation propre à Resto·Ka : là où Lou·Ka normalise une **annonce**, Resto·Ka
121+> normalise un **restaurant + un menu imbriqué (catégories → plats → prix →
122+> options)**. Le schéma est plus profond ; le reste du patron s'applique tel quel.
123+
124+> Si tu ne trouves pas le dépôt Lou·Ka ou l'accès aux connecteurs, **arrête-toi et
125+> demande** plutôt que d'inventer une architecture divergente.
126+
127+Écosystème complet, pour contexte :
128+
129+| Site | Domaine | Agrège |
130+|-------------|------------------|-------------------------------------------|
131+| Lou·Ka | lou-ka.com | Logements à louer |
132+| Immo·Ka | immo-ka.com | Propriétés à vendre |
133+| Auto·Ka | auto-ka.com | Véhicules usagés |
134+| Food·Ka | food-ka.com | Prix d'épicerie & circulaires |
135+| Fabri·Ka | fabri-ka.com | Produits québécois |
136+| Sorti·Ka | sorti-ka.com | Sorties & événements |
137+| **Resto·Ka**| **resto-ka.com** | **Restaurants, menus & prix (ce dépôt)** |
138+
139+---
140+
141+## 4. Architecture
142+
143+Pipeline standard de la famille `·Ka`, adapté aux restaurants et menus :
144+
145+```
146+ ┌─────────────┐ ┌──────────────┐ ┌────────────────┐ ┌──────────────┐ ┌──────────┐
147+ │ CONNECTEUR │──▶│ EXTRACTION │──▶│ NORMALISATION │──▶│ DÉDUPLICATION │──▶│ STOCKAGE │
148+ │ (par source)│ │ FC / Scrapfly│ │ resto + menu │ │ identité resto│ │ (DB) │
149+ │ │ │ + parse PDF │ │ (schéma commun)│ │ + items │ │ │
150+ └─────────────┘ └──────────────┘ └────────────────┘ └──────────────┘ └────┬─────┘
151+ │
152+ ┌──────────▼──────────┐
153+ │ API / RECHERCHE / │
154+ │ UI (menus & prix) │
155+ └─────────────────────┘
156+```
157+
158+Composants :
159+
160+- **Connecteurs** : un module par source (ou par plateforme), interface commune.
161+- **Orchestrateur** : planifie et exécute (cadence, retries, backoff).
162+- **Extraction** : Firecrawl & Scrapfly + clients d'API + **parsing de menus PDF /
163+ images** (OCR) pour les menus non structurés.
164+- **Normalisation** : mappe le brut vers le **schéma Restaurant + Menu** (section 5).
165+- **Déduplication** : fusionne les restos et les items en double inter-sources.
166+- **Stockage** : base restos + menus + **historique des prix** (suivi des hausses).
167+- **API / UI** : recherche géolocalisée, filtres (cuisine, prix, diète), comparaison.
168+
169+---
170+
171+## 5. Modèle de données — schéma Restaurant + Menu
172+
173+### 5.1 Restaurant
174+
175+```jsonc
176+{
177+ "id": "string", // * id interne canonique (post-déduplication)
178+ "source_ids": ["ubereats:abc"], // * id(s) d'origine par source (préfixés)
179+ "name": "string", // * nom normalisé
180+ "chain": "string|null", // marque/chaîne si applicable
181+ "cuisines": ["italien", "pizza"], // * taxonomie cuisine (section 6)
182+ "establishment_type": "restaurant",// restaurant|fast-food|cafe|bar|food-truck|traiteur...
183+ "price_range": "$$", // $ à $$$$ (estimé à partir des prix)
184+ "address": "string", // *
185+ "city": "string", // *
186+ "region": "string", // * une des 17 régions (section 7)
187+ "postal_code": "string",
188+ "lat": 0.0, // * géolocalisation
189+ "lng": 0.0, // *
190+ "phone": "string",
191+ "website": "string",
192+ "hours": { /* horaires par jour */ },
193+ "services": ["salle", "emporter", "livraison"], // dine-in|takeout|delivery
194+ "dietary_options": ["vegan", "sans-gluten", "halal"],
195+ "languages": ["fr", "en"],
196+ "menu": { /* voir 5.2 */ },
197+ "status": "open", // open|temporarily_closed|closed
198+ "first_seen": "ISO-8601", // *
199+ "last_seen": "ISO-8601", // *
200+ "updated_at": "ISO-8601" // *
201+}
202+```
203+
204+### 5.2 Menu (imbriqué)
205+
206+```jsonc
207+"menu": {
208+ "currency": "CAD",
209+ "price_context": "delivery", // * dine-in | takeout | delivery (voir §6)
210+ "price_source": "ubereats", // * source du prix (traçabilité)
211+ "captured_at": "ISO-8601", // * quand ce menu/prix a été capté
212+ "sections": [
213+ {
214+ "name": "Pizzas",
215+ "items": [
216+ {
217+ "id": "string",
218+ "name": "Margherita", // *
219+ "description": "string",
220+ "price": 16.50, // * prix de l'item (dans price_context)
221+ "currency": "CAD",
222+ "tags": ["vegetarien"],
223+ "options": [ // modificateurs / variantes
224+ {
225+ "group": "Format",
226+ "required": true,
227+ "choices": [
228+ { "name": "10 pouces", "price_delta": 0.00 },
229+ { "name": "14 pouces", "price_delta": 6.00 }
230+ ]
231+ }
232+ ]
233+ }
234+ ]
235+ }
236+ ]
237+}
238+```
239+
240+Règles :
241+- `price_context` et `price_source` sont **obligatoires** : un prix sans contexte
242+ est inutilisable (livraison ≠ salle).
243+- `lat`/`lng` obligatoires → **géocoder** l'adresse si absente.
244+- Capturer les **options/modificateurs** (formats, suppléments, choix) : ils
245+ changent le prix réel.
246+- Conserver la **devise** partout (CAD). Au QC, TPS/TVQ s'ajoutent ; ne pas les
247+ inclure dans `price` sauf si la source le fait, et alors le **documenter**.
248+
249+---
250+
251+## 6. Taxonomies
252+
253+### 6.1 Cuisines (multi-valué)
254+`quebecois` · `francais` · `italien` · `pizza` · `burgers` · `poulet` ·
255+`bbq-grillades` · `fruits-de-mer` · `sushi-japonais` · `chinois` · `thai` ·
256+`vietnamien` · `coreen` · `indien` · `libanais-moyen-orient` · `mexicain` ·
257+`grec` · `mediterraneen` · `dejeuner-brunch` · `cafe-dessert` · `vegetarien-vegan` ·
258+`fast-food` · `autre`
259+
260+### 6.2 Contexte de prix (`price_context`) — CRITIQUE
261+- `dine-in` — prix en salle (référence idéale).
262+- `takeout` — prix pour emporter (souvent = salle).
263+- `delivery` — prix sur plateforme de livraison, **majoré de 25-30 %**.
264+
265+> Toujours privilégier `dine-in`/`takeout` (menu du resto lui-même ou sa plateforme
266+> de commande en ligne) plutôt que `delivery` quand les deux existent. Si on n'a que
267+> `delivery`, on l'affiche **clairement étiqueté**.
268+
269+### 6.3 Diètes / tags
270+`vegan` · `vegetarien` · `sans-gluten` · `halal` · `casher` · `sans-noix` · `epice`
271+
272+---
273+
274+## 7. Régions du Québec (obligatoire pour chaque restaurant)
275+
276+Bas-Saint-Laurent · Saguenay–Lac-Saint-Jean · Capitale-Nationale · Mauricie ·
277+Estrie · Montréal · Outaouais · Abitibi-Témiscamingue · Côte-Nord ·
278+Nord-du-Québec · Gaspésie–Îles-de-la-Madeleine · Chaudière-Appalaches · Laval ·
279+Lanaudière · Laurentides · Montérégie · Centre-du-Québec.
280+
281+Rattacher chaque resto à sa région via la ville/adresse (table de correspondance
282+ville → région, comme dans Lou·Ka).
283+
284+---
285+
286+## 8. Philosophie des connecteurs
287+
288+- **Un connecteur par source**, taillé sur mesure.
289+- **Connecteurs templatisés par plateforme** : c'est le levier d'échelle nº 1. Une
290+ plateforme de commande en ligne ou de livraison couvre des **milliers** de restos
291+ avec la même structure → un seul connecteur paramétré les couvre tous (exactement
292+ comme les connecteurs par plateforme d'Auto·Ka et Fabri·Ka).
293+- **Deux types de sources à combiner** :
294+ 1. **Découverte** (liste des restos + métadonnées) : annuaires, cartes, tourisme.
295+ 2. **Menus + prix** (le cœur) : commande en ligne, livraison, sites de restos, PDF.
296+- Interface commune (à calquer sur Lou·Ka) : `fetch()` → `normalize()` → `emit()`.
297+ Idempotent et incrémental quand c'est possible.
298+- **Robustesse** : timeouts, retries + backoff, tolérance aux changements mineurs,
299+ alerte si le nombre d'items d'un menu chute anormalement (connecteur cassé).
300+
301+---
302+
303+## 9. Catalogue des sources à connecter (priorisé)
304+
305+> ⚠️ Vérifie le registre des sources et l'index des restos **avant** d'ajouter.
306+
307+### Palier 1 — Plateformes de commande en ligne des restos (MEILLEUR prix + volume)
308+
309+Ces plateformes propulsent les **sites/apps des restos eux-mêmes** → menus complets
310+à des **prix réels (dine-in/takeout, non majorés)**. À templatiser par plateforme :
311+
312+- **UEAT** (foodtech de Québec, marque blanche, **très répandue au QC**).
313+- **Square Online Ordering**, **Toast**, **Clover**, **GloriaFood (Oracle)**,
314+ **Flipdish**, **Foodiv**, **ChowNow**, **Bite (DoorDash)**.
315+
316+### Palier 2 — Plateformes de livraison (menus complets, prix MAJORÉS)
317+
318+Menus riches et structurés, mais prix `delivery` (+25-30 %), anti-bot fort et CGU
319+restrictives (voir **section 15** — risque légal réel) :
320+
321+- **Uber Eats**, **SkipTheDishes**, **DoorDash**.
322+- Plateformes québécoises : **RestoLoco** et autres services locaux régionaux.
323+
324+> Politique : utiliser la livraison surtout pour la **découverte** et pour les
325+> restos qu'on ne trouve nulle part ailleurs. Toujours étiqueter `price_context:
326+> delivery`. Préférer une source `dine-in` dès qu'elle existe.
327+
328+### Palier 3 — Sites web des restaurants (menus « maison »)
329+
330+- Menus en **HTML** (parse direct) ou en **PDF / image** (→ parsing PDF + OCR,
331+ voir section 10). Détecter la plateforme de commande embarquée (souvent Palier 1).
332+
333+### Palier 4 — Découverte & métadonnées (liste des restos)
334+
335+- **Google Places / Maps**, **Yelp**, **TripAdvisor** (coordonnées, horaires, type
336+ de cuisine, fourchette de prix — **rarement les menus** ; respecter les CGU/API).
337+- **Associations touristiques régionales (ATR)**, Tourisme Québec.
338+- Médias food : **Tastet**, **RestoMontréal** et annuaires régionaux (découverte).
339+
340+### Palier 5 — Réservation (métadonnées + parfois menus)
341+
342+- **OpenTable**, **LibroReserve** (Québec), **Resy**, **Zenchef** — horaires,
343+ services, parfois menus.
344+
345+### Palier 6 — Chaînes (menus standardisés)
346+
347+- Sites des grandes chaînes : menus et prix souvent uniformes par bannière et
348+ parfois par région → un connecteur par chaîne couvre toutes les succursales.
349+
350+---
351+
352+## 10. Extraction — Firecrawl, Scrapfly & parsing de menus
353+
354+Les connecteurs s'appuient **souvent sur Firecrawl et Scrapfly** (comme tout
355+l'écosystème `·Ka`). Règle de choix :
356+
357+- **API / endpoint JSON de la plateforme** → toujours privilégié (données
358+ structurées, stables). Beaucoup de plateformes de commande chargent leur menu
359+ via un appel JSON interne : **le trouver et le consommer directement.**
360+- **Firecrawl** → crawl et extraction en volume de sites relativement ouverts
361+ (sites de restos, annuaires), extraction structurée (markdown/JSON).
362+- **Scrapfly** → sites protégés, JavaScript lourd, anti-bot, rendu navigateur,
363+ rotation d'IP. **Requis** pour les plateformes de livraison (Uber Eats, Skip,
364+ DoorDash) qui bloquent agressivement.
365+- **Parsing de menus PDF / images** : de nombreux restos publient un menu en PDF ou
366+ en photo. Prévoir extraction de texte PDF + **OCR** + un post-traitement (LLM) qui
367+ transforme le texte brut en structure `sections → items → price → options`.
368+ Valider systématiquement (un prix mal OCR-isé est pire que pas de prix).
369+
370+Chaque connecteur doit **documenter** en tête de fichier son mode d'extraction et
371+pourquoi. Réutiliser les clients partagés de Lou·Ka.
372+
373+---
374+
375+## 11. Normalisation
376+
377+- Nettoyer noms de restos, sections et plats (HTML résiduel, majuscules, doublons).
378+- Mapper vers le **schéma Restaurant + Menu** (section 5) intégralement.
379+- **Cuisines** et **type d'établissement** classés dès la normalisation (section 6).
380+- **Géocoder** (lat/lng obligatoires) et **rattacher la région** (section 7).
381+- **Prix** : renseigner **obligatoirement** `price_context` et `price_source` ;
382+ capturer les **options/modificateurs**. Ne jamais mélanger des prix de contextes
383+ différents dans un même menu.
384+- **Devise** CAD ; documenter le traitement des taxes (TPS/TVQ hors prix au QC).
385+- Conserver les **`source_ids`** préfixés (ex. `ueat:1234`, `ubereats:abcd`).
386+
387+---
388+
389+## 12. Déduplication — restaurants ET items
390+
391+Un même resto apparaît sur Uber Eats + DoorDash + Skip + son propre site + Google.
392+
393+### 12.1 Identité du restaurant
394+1. **Clé** : nom normalisé + adresse (géoloc arrondie) + téléphone → empreinte.
395+2. **Approché** : noms proches + même adresse → fusion candidate (journaliser).
396+3. **Fusion** : un enregistrement canonique, agréger les `source_ids`, choisir la
397+ meilleure source par champ.
398+4. **Multi-succursales / chaînes** : chaque **adresse** est une fiche resto
399+ distincte, reliée par `chain`. Ne pas fusionner deux succursales.
400+
401+### 12.2 Menus & prix
402+- Ne pas écraser un menu `dine-in` par un menu `delivery` : **conserver les deux
403+ contextes** et présenter le meilleur (dine-in prioritaire), en gardant delivery
404+ étiqueté.
405+- Dédupliquer les **items** au sein d'un même contexte (même plat listé deux fois).
406+- **Historiser** les prix : à chaque capture, si le prix d'un item change, garder la
407+ série temporelle (utile pour détecter les hausses et pour la crédibilité).
408+
409+S'inspirer de la déduplication de **Lou·Ka** (multi-plateformes) et d'Auto·Ka
410+(identité forte par clé).
411+
412+---
413+
414+## 13. Fraîcheur des menus & états
415+
416+- **Menus changeants** : prix et plats évoluent (saisonnier, table d'hôte,
417+ spéciaux). Rafraîchir régulièrement et **horodater** chaque capture (`captured_at`).
418+- **Fermetures** : resto fermé temporairement / définitivement → `status` mis à jour
419+ plutôt que suppression brutale (politique de grâce via `last_seen`, comme Lou·Ka).
420+- **Items retirés** : disparition d'un plat → le marquer inactif, conserver
421+ l'historique.
422+- **Spéciaux / table d'hôte** : capturer si structurés, avec leur période de validité.
423+
424+---
425+
426+## 14. Cadence de rafraîchissement
427+
428+- Grandes plateformes (commande en ligne, livraison, chaînes) : **hebdomadaire** au
429+ minimum ; **quotidien** pour les prix sur les gros volumes urbains.
430+- Sites de restos indépendants : **hebdomadaire à mensuel** (menus stables).
431+- Découverte (annuaires) : **mensuel** pour repérer nouveaux restos / fermetures.
432+- Toujours mettre à jour `last_seen` et `captured_at` à chaque passage réussi.
433+
434+---
435+
436+## 15. Conformité & aspects légaux — À PRENDRE AU SÉRIEUX
437+
438+> C'est le point le plus sensible de ce projet. Les plateformes de livraison
439+> **protègent activement** leurs données (menus/prix) et l'interdisent dans leurs
440+> CGU. Ne pas traiter ça à la légère.
441+
442+- Respecter les **CGU** et `robots.txt` de chaque source. Les plateformes de
443+ livraison sont explicitement restrictives : **minimiser**, privilégier d'autres
444+ sources pour les mêmes restos, et **demander** en cas de doute avant d'industrialiser.
445+- Privilégier les **sources de première partie** : le **site du resto** et sa
446+ **plateforme de commande** (UEAT, etc.) sont la voie la plus légitime pour le
447+ menu et le prix réel.
448+- **Rate-limiting** raisonnable, identification honnête, pas de surcharge.
449+- Utiliser les **API officielles** quand elles existent (Google Places, Yelp) et
450+ en respecter les quotas et conditions d'affichage/attribution.
451+- Ne republier que ce qui est nécessaire à la découverte (nom, plats, prix, infos
452+ pratiques, lien vers la source). **Attribuer** les sources requises.
453+- Consigner par source la base légale/mode d'accès retenu (API vs scraping) en tête
454+ de connecteur.
455+
456+---
457+
458+## 16. Conventions de code
459+
460+- Suivre **les mêmes conventions que Lou·Ka** (langage, structure de dossiers,
461+ nommage, linting, formatage). Cohérence > préférences personnelles.
462+- Un connecteur = un module isolé, testable indépendamment.
463+- Secrets (clés Firecrawl/Scrapfly, API Google/Yelp) via variables d'environnement /
464+ gestionnaire de secrets. Jamais en clair.
465+- Logging structuré (source, nb de restos, nb d'items, erreurs, durée).
466+- Commits atomiques, messages clairs.
467+
468+---
469+
470+## 17. En-tête d'auteur — OBLIGATOIRE dans chaque fichier
471+
472+**Tout fichier** du dépôt doit débuter par un en-tête d'auteur. L'auteur est
473+toujours **Simon-Pierre Boucher \<contact@spboucher.ai\>**.
474+
475+**Python / Shell / YAML / TOML / Dockerfile :**
476+```python
477+# ==============================================================================
478+# Author: Simon-Pierre Boucher <contact@spboucher.ai>
479+# File: <nom_du_fichier>
480+# Desc: <brève description>
481+# ==============================================================================
482+```
483+
484+**JavaScript / TypeScript / Go / Rust / Java / C :**
485+```javascript
486+// ==============================================================================
487+// Author: Simon-Pierre Boucher <contact@spboucher.ai>
488+// File: <nom_du_fichier>
489+// Desc: <brève description>
490+// ==============================================================================
491+```
492+
493+**Markdown / HTML / XML :**
494+```html
495+<!--
496+ Author: Simon-Pierre Boucher <contact@spboucher.ai>
497+ File: <nom_du_fichier>
498+ Desc: <brève description>
499+-->
500+```
501+
502+**CSS / SCSS :**
503+```css
504+/*
505+ Author: Simon-Pierre Boucher <contact@spboucher.ai>
506+ File: <nom_du_fichier>
507+*/
508+```
509+
510+Règles :
511+- **Aucun** fichier commité sans cet en-tête.
512+- Pour un connecteur, indiquer dans `Desc:` la **source/plateforme couverte**, le
513+ **mode d'extraction** (API / Firecrawl / Scrapfly / PDF-OCR) et le **contexte de
514+ prix** produit (dine-in / takeout / delivery).
515+- Vérifier la présence de l'en-tête en revue de code (idéalement hook de pré-commit).
516+
517+---
518+
519+## 18. Tests & qualité
520+
521+- Chaque connecteur : **tests unitaires** de normalisation sur des fixtures réelles
522+ (réponses JSON, HTML, PDF de menus figés).
523+- Tests de **parsing de menus** : vérifier prix, options et sections sur des
524+ échantillons connus (les prix sont l'actif le plus critique).
525+- Tests de **déduplication** resto + items multi-sources.
526+- **Validation de schéma** : tout resto/menu émis doit passer la validation avant
527+ stockage ; rejeter un menu sans `price_context`/`price_source`.
528+- **Monitoring** : alerte si le nb d'items d'un resto ou le volume d'une source
529+ chute anormalement (connecteur probablement cassé).
530+
531+---
532+
533+## 19. Checklist — ajouter un nouveau connecteur / restaurant
534+
535+1. [ ] Lire les connecteurs de référence dans le **dépôt Lou·Ka** (section 3).
536+2. [ ] Vérifier que la source/le resto **n'est pas déjà couvert** (registres).
537+3. [ ] Identifier la **plateforme** : peut-on templatiser/réutiliser un connecteur ?
538+4. [ ] Choisir le **mode d'extraction** : API > site du resto > Firecrawl > Scrapfly ;
539+ PDF/OCR si menu non structuré (section 10).
540+5. [ ] Déterminer le **`price_context`** produit et le documenter.
541+6. [ ] Implémenter `fetch()` → `normalize()` → `emit()` (interface commune).
542+7. [ ] Mapper **tout** le schéma resto + menu, géocoder, région, cuisines, options.
543+8. [ ] Brancher la **déduplication** resto + items (section 12).
544+9. [ ] Gérer **fraîcheur, fermetures, items retirés, historique des prix** (§13).
545+10. [ ] Vérifier la **conformité** CGU/robots et consigner la base d'accès (§15).
546+11. [ ] Ajouter l'**en-tête d'auteur** (section 17).
547+12. [ ] Écrire les **tests** + fixtures, dont le parsing de prix (section 18).
548+13. [ ] Enregistrer la source dans le **registre** avec sa cadence.
549+14. [ ] Valider volume et qualité sur un premier run, journaliser.
550+
551+---
552+
553+## 20. Roadmap / MVP
554+
555+**MVP** : templatiser **un** connecteur pour la plateforme de commande en ligne la
556+plus répandue au QC (**UEAT**) → menus complets à prix réels (`dine-in`/`takeout`)
557+pour des milliers de restos d'un coup. Ajouter la découverte via Google Places/Yelp
558+pour la liste et les métadonnées, et le parsing des menus PDF des sites de restos.
559+UI de recherche géolocalisée avec filtres (cuisine, prix, diète, service) et
560+affichage clair du **contexte de prix**.
561+
562+**Ensuite** : plateformes de livraison (avec étiquetage strict), chaînes,
563+réservation, régions moins couvertes. Puis historique des prix, comparaison entre
564+restos, et cross-linking avec les autres sites `·Ka`.
565+
566+**Nord stratégique** : être **le seul** à offrir menus **et** prix **comparables**
567+de **tous** les restos du Québec — là où la livraison est chère et partielle, les
568+annuaires sans menus, et les médias food non exhaustifs.
569+
570+---
571+
572+*Fin de CLAUDE.md — Resto·Ka. Auteur : Simon-Pierre Boucher \<contact@spboucher.ai\>.*
added README.md +141 −0
@@ -0,0 +1,141 @@
1+<!--
2+ Author: Simon-Pierre Boucher <contact@spboucher.ai>
3+ File: README.md
4+ Desc: Documentation du dépôt Sorti-Ka — agrégateur de sorties & événements
5+-->
6+
7+<div align="center">
8+
9+# Sorti·Ka
10+
11+### Toutes les sorties et tous les événements du Québec. Un seul endroit.
12+
13+**[www.sorti-ka.com](https://www.sorti-ka.com)**
14+
15+![Python](https://img.shields.io/badge/Python-3.14-141814?style=for-the-badge&logo=python&logoColor=d9f26b)
16+![FastAPI](https://img.shields.io/badge/FastAPI-API_+_SSR-141814?style=for-the-badge&logo=fastapi&logoColor=d9f26b)
17+![SQLite](https://img.shields.io/badge/SQLite-storage-141814?style=for-the-badge&logo=sqlite&logoColor=d9f26b)
18+![Frontend](https://img.shields.io/badge/Frontend-SPA_sans_build-141814?style=for-the-badge&logo=html5&logoColor=d9f26b)
19+
20+![Événements](https://img.shields.io/badge/%C3%A9v%C3%A9nements_actifs-15_231-1c5c41?style=flat-square)
21+![À venir](https://img.shields.io/badge/%C3%A0_venir-11_559-1c5c41?style=flat-square)
22+![Gratuits](https://img.shields.io/badge/gratuits-3_159-1c5c41?style=flat-square)
23+![Connecteurs](https://img.shields.io/badge/connecteurs_actifs-8-1c5c41?style=flat-square)
24+![Régions](https://img.shields.io/badge/r%C3%A9gions-17%2F17-1c5c41?style=flat-square)
25+![Villes](https://img.shields.io/badge/villes-428-1c5c41?style=flat-square)
26+![Tests](https://img.shields.io/badge/tests-19_pass-1c5c41?style=flat-square)
27+
28+*Agrégateur indépendant de sorties & événements — concerts, festivals, spectacles,
29+expositions, sport, famille — dans les 17 régions administratives du Québec, avec
30+dates, lieux, gratuité, fiche par événement et lien direct vers la billetterie ou
31+la source originale. Mise à jour horaire, automatiquement.*
32+
33+<img src="docs/screenshots/accueil.png" alt="Page d'accueil Sorti-Ka" width="920">
34+
35+</div>
36+
37+---
38+
39+## Pourquoi Sorti·Ka ?
40+
41+Trouver quoi faire au Québec, c'est ouvrir dix sites : les billetteries ne montrent
42+que leurs propres spectacles, les calendriers municipaux que leur ville, les sites
43+touristiques que leurs membres. **Sorti·Ka retourne le problème** : un connecteur
44+dédié par source visite chaque calendrier, normalise chaque événement vers un
45+schéma unique, déduplique les doublons inter-sources et détecte les changements
46+en continu.
47+
48+Sorti·Ka n'est pas une billetterie : c'est un **index fidèle**. Aucun prix inventé,
49+aucune date devinée — chaque fiche est attribuée à sa source et renvoie vers la
50+fiche originale pour les billets. Membre de la famille **·Ka**
51+([Lou·Ka](https://www.lou-ka.com), Immo·Ka, Auto·Ka, Food·Ka, Fabri·Ka, Resto·Ka),
52+architecture calquée sur le patron de référence Lou·Ka.
53+
54+## Visite guidée
55+
56+| | |
57+|:---:|:---:|
58+| **Recherche filtrée** — région, catégorie, période, gratuité, texte libre | **Fiche par événement** — dates, lieu, prix, carte, similaires, SSR + JSON-LD |
59+| <img src="docs/screenshots/accueil.png" alt="Accueil" width="440"> | <img src="docs/screenshots/fiche.png" alt="Fiche événement" width="440"> |
60+
61+## L'architecture en 30 secondes
62+
63+```
64+ connecteurs (1 module / source) normalisation (Event) SQLite (diff + grâce)
65+ sortika/connectors/*.py → schema.py + normalize.py → db.py
66+ ▲ auto-découverts + regions.py (MAMH) │
67+ │ ▼
68+ watcher horaire (PM2) frontend SPA + fiches ← API FastAPI + SSR SEO
69+ ingest.py watch frontend/index.html web.py + seo.py
70+```
71+
72+| Couche | Rôle | Fichiers |
73+|---|---|---|
74+| **Connecteurs** | 1 module Python par source : API JSON internes (Algolia evenko, Tourinsoft, CKAN), listes HTML, Scrapfly (Cloudflare), caches incrémentaux | `sortika/connectors/*.py` |
75+| **Schéma** | `Event` standardisé : titre, catégories canoniques, lieu, ville, **région (17)**, lat/lng, dates ISO, gratuité/prix avec `price_label` source | `sortika/schema.py` |
76+| **Normalisation** | dates FR/ISO, prix, catégories (14), villes, entités HTML | `sortika/normalize.py` |
77+| **Régions** | Répertoire des municipalités MAMH : 1 250 villes + arrondissements + alias, homonymes résolus par population | `sortika/regions.py` + `data/villes_regions.json` |
78+| **Persistance** | upsert par hash de contenu, délai de grâce 2 syncs, alerte de dérive, historique de syncs | `sortika/db.py` |
79+| **Dédup** | empreinte titre + ville + date : un même concert publié par 3 sources = **une carte**, la fiche la plus riche gagne | `schema.dedup_key()` + `web.py` |
80+| **API + SSR** | recherche/filtres JSON, fiches `/evenement/{uid}` servies avec `<head>` unique + **JSON-LD Event**, robots, sitemaps | `sortika/web.py` + `sortika/seo.py` |
81+| **Frontend** | SPA sans build, routeur History API, design system **Groupe KA « éditorial sharp »** | `frontend/index.html` |
82+
83+## Les 8 connecteurs actifs
84+
85+| Source | Type / accès | Extraction | Volume |
86+|---|---|---|---|
87+| **Le point de vente** | billetterie QC — robots `Allow: *` | listes HTML paginées (~65 pages) | ~2 500 concerts, humour, théâtre — toute la province |
88+| **SIT Québec** (Ministère du Tourisme) | données ouvertes CC 4.0 | API JSON Tourinsoft | ~1 600 événements touristiques, toutes les régions |
89+| **Ville de Montréal** | données ouvertes CC BY 4.0 | API CKAN datastore | ~5 600 événements municipaux |
90+| **evenko** | promoteur — robots `Allow: /api/search*` | proxy Algolia percé (`body=base64({params:[q,opts],lang})`) | ~460 grands concerts (Centre Bell, Place Bell, MTELUS…) |
91+| **La Vitrine** | Content-Signal `search=yes, use=reference` | sitemap + fiches HTML (dates de tournée dédupliquées par id de représentation), cache incrémental | ~5 100 représentations |
92+| **Atuvu.ca** | Cloudflare → **Scrapfly**, robots `Allow: /` | sitemaps lastmod + fiches, cache incrémental plafonné | rattrapage progressif |
93+| **Ville de Sherbrooke** | calendrier municipal public | JSON embarqué `TRANSFER_CACHE` — 1 requête | ~270 événements avec images et gratuité |
94+| **Ville de Laval** | données ouvertes CC 4.0 | JSON officiel | ~290 activités |
95+
96+Sources écartées après vérification (jeux périmés) : Longueuil (2017), Saguenay (2022),
97+Repentigny (2021) — consignées au registre `data/sources.json` avec leur statut.
98+
99+## Démarrage rapide
100+
101+```bash
102+python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
103+.venv/bin/python -m pytest tests/ -q # 19 tests (fixtures réelles, zéro réseau)
104+.venv/bin/python run.py sync # ingestion des 8 sources
105+.venv/bin/python run.py web --port 8120 # API + frontend + SSR
106+.venv/bin/python run.py watch --interval 3600 # boucle d'ingestion horaire
107+```
108+
109+Secrets : `SCRAPFLY_API_KEY` dans `.env` (requis seulement pour Atuvu).
110+
111+## API
112+
113+| Route | Description |
114+|---|---|
115+| `GET /api/events` | recherche — `q`, `region`, `city`, `category`, `free`, `from`, `to`, `sort`, pagination ; dédupliquée inter-sources |
116+| `GET /api/events/{uid}` | fiche complète d'un événement |
117+| `GET /api/stats` | volumes par région et par catégorie |
118+| `GET /api/sources` | registre des sources + événements actifs + dernière synchro |
119+| `GET /evenement/{uid}` | fiche HTML SSR (title/og/canonical + **JSON-LD Event**) |
120+| `GET /sitemap.xml` · `/robots.txt` | référencement |
121+| `GET /docs` | Swagger |
122+
123+## Production
124+
125+Nœud **M3U96a** (MacLustr) — PM2 : `sorti-ka-web` (uvicorn :8120),
126+`sorti-ka-sync` (watch **horaire** — mise à jour continue), `sorti-ka-ngrok`
127+(`www.sorti-ka.com`). Registre : `~/Desktop/cluster-skill/cluster-deployments.json`.
128+
129+## Principes
130+
131+1. **Index fidèle** — rien d'inventé : prix et dates viennent de la source, avec
132+ `price_label` original conservé et attribution systématique.
133+2. **Sources légitimes d'abord** — données ouvertes officielles et sites au
134+ robots.txt permissif ; CGU/licences consignées en tête de chaque connecteur.
135+3. **Travail de moine** — un connecteur robuste à la fois, testé sur fixtures
136+ réelles, avec alerte de dérive quand une source casse.
137+4. **Cohérence ·Ka** — architecture Lou·Ka, design system Groupe KA.
138+
139+---
140+
141+© 2026 Sorti·Ka — Simon-Pierre Boucher \<contact@spboucher.ai\>
added data/sources.json +129 −0
@@ -0,0 +1,129 @@
1+{
2+ "_comment": "Sorti-Ka — Registre des sources d'événements (province de Québec). Auteur : Simon-Pierre Boucher — contact@spboucher.ai",
3+ "sources": [
4+ {
5+ "id": "sitq",
6+ "name": "SIT Québec — Ministère du Tourisme",
7+ "url": "https://www.donneesquebec.ca/recherche/dataset/sit-quebec-evenements",
8+ "type": "donnees-ouvertes",
9+ "extraction": "API JSON (Tourinsoft, syndication publique)",
10+ "acces_legal": "Licence Creative Commons 4.0 (Données Québec) — API officielle publiée par le Ministère du Tourisme",
11+ "couverture": "Événements touristiques, toutes les régions du Québec",
12+ "cadence": "horaire (watcher PM2)",
13+ "statut": "actif"
14+ },
15+ {
16+ "id": "montreal",
17+ "name": "Ville de Montréal — Événements publics",
18+ "url": "https://donnees.montreal.ca/dataset/evenements-publics",
19+ "type": "donnees-ouvertes",
20+ "extraction": "API CKAN datastore_search (JSON, paginée)",
21+ "acces_legal": "Licence CC BY 4.0 (donnees.montreal.ca) — attribution : Ville de Montréal",
22+ "couverture": "Événements municipaux, île de Montréal",
23+ "cadence": "horaire (watcher PM2)",
24+ "statut": "actif"
25+ },
26+ {
27+ "id": "lepointdevente",
28+ "name": "Le point de vente — billetterie québécoise",
29+ "url": "https://lepointdevente.com/billets",
30+ "type": "billetterie",
31+ "extraction": "pages de liste HTML rendues serveur (paginées), parse des cartes",
32+ "acces_legal": "robots.txt : « User-Agent: * / Allow: * » — GET throttlés, identification honnête, lien direct vers chaque billetterie",
33+ "couverture": "Concerts, humour, théâtre, festivals — partout au Québec (~2 500 événements à venir)",
34+ "cadence": "horaire (watcher PM2)",
35+ "statut": "actif"
36+ },
37+ {
38+ "id": "laval",
39+ "name": "Ville de Laval — Calendrier des activités",
40+ "url": "https://www.donneesquebec.ca/recherche/dataset/calendrier-des-activites",
41+ "type": "donnees-ouvertes",
42+ "extraction": "fichier JSON officiel (Données Québec)",
43+ "acces_legal": "Licence CC 4.0 (Données Québec) — Ville de Laval",
44+ "couverture": "Activités municipales, Laval",
45+ "cadence": "horaire (watcher PM2)",
46+ "statut": "actif"
47+ },
48+ {
49+ "id": "sherbrooke",
50+ "name": "Ville de Sherbrooke — Calendrier des événements",
51+ "url": "https://www.sherbrooke.ca/fr/culture-sports-et-loisirs/calendrier-des-activites",
52+ "type": "municipal",
53+ "extraction": "JSON embarqué window['TRANSFER_CACHE'] (CMS Maruche) — 1 requête, ~270 événements avec images, gratuité, catégories",
54+ "acces_legal": "page municipale publique (référencée sur Données Québec) — GET direct, identification honnête",
55+ "couverture": "Événements municipaux et culturels, Sherbrooke (Estrie)",
56+ "cadence": "horaire (watcher PM2)",
57+ "statut": "actif"
58+ },
59+ {
60+ "id": "longueuil",
61+ "name": "Ville de Longueuil — Événements",
62+ "url": "https://www.donneesquebec.ca/recherche/dataset/evenements",
63+ "type": "donnees-ouvertes",
64+ "extraction": "CSV (Données Québec)",
65+ "acces_legal": "Licence CC 4.0 (Données Québec)",
66+ "couverture": "Longueuil (Montérégie)",
67+ "cadence": "n/d",
68+ "statut": "abandonnee",
69+ "note": "Jeu de données périmé — dernière date d'événement : 2017-03 (vérifié 2026-08-17)"
70+ },
71+ {
72+ "id": "saguenay",
73+ "name": "Ville de Saguenay — Événements culturels",
74+ "url": "https://www.donneesquebec.ca/recherche/dataset/sag_evenements-culturels",
75+ "type": "donnees-ouvertes",
76+ "extraction": "CSV (Données Québec)",
77+ "acces_legal": "Licence CC 4.0 (Données Québec)",
78+ "couverture": "Saguenay",
79+ "cadence": "n/d",
80+ "statut": "abandonnee",
81+ "note": "Jeu de données périmé — dernière date d'événement : 2022-06 (vérifié 2026-08-17)"
82+ },
83+ {
84+ "id": "repentigny",
85+ "name": "Ville de Repentigny — Événements",
86+ "url": "https://www.donneesquebec.ca/recherche/dataset/evenement-sur-le-territoire-de-la-ville",
87+ "type": "donnees-ouvertes",
88+ "extraction": "CSV (Données Québec)",
89+ "acces_legal": "Licence CC 4.0 (Données Québec)",
90+ "couverture": "Repentigny (Lanaudière)",
91+ "cadence": "n/d",
92+ "statut": "abandonnee",
93+ "note": "Jeu de données périmé — dernière date d'événement : 2021-09 (vérifié 2026-08-17)"
94+ },
95+ {
96+ "id": "evenko",
97+ "name": "evenko — grands concerts et festivals",
98+ "url": "https://evenko.ca/fr/evenements",
99+ "type": "promoteur",
100+ "extraction": "API /api/search (proxy Algolia) — format percé : GET ?body=base64({params:[query,options],lang:'fr-CA'}), filters entity_type:evenko_show, ~5 requêtes/sync",
101+ "acces_legal": "robots.txt : Allow /api/search* (explicite) — lien billets = URL Ticketmaster officielle",
102+ "couverture": "Grands concerts (Centre Bell, Place Bell, MTELUS…), festivals (Osheaga, ÎleSoniq…)",
103+ "cadence": "horaire (watcher PM2)",
104+ "statut": "actif"
105+ },
106+ {
107+ "id": "atuvu",
108+ "name": "Atuvu.ca — calendrier culturel",
109+ "url": "https://atuvu.ca/",
110+ "type": "agregateur",
111+ "extraction": "Scrapfly (Cloudflare) — sitemaps lastmod + fiches .event-play, cache incrémental data/atuvu_cache.json, plafond 120 fiches/sync",
112+ "acces_legal": "robots.txt : Allow / + sitemap public",
113+ "couverture": "Sorties culturelles, Grand Montréal",
114+ "cadence": "horaire (watcher PM2, incrémental)",
115+ "statut": "actif"
116+ },
117+ {
118+ "id": "lavitrine",
119+ "name": "La Vitrine culturelle",
120+ "url": "https://www.lavitrine.com/",
121+ "type": "billetterie",
122+ "extraction": "GET directs — sitemap.xml (2 000 fiches evenement + 185 exposition) + fiches HTML (bloc event_calendar), cache incrémental, 150 fiches/sync, re-visite 7 j",
123+ "acces_legal": "robots.txt : Allow / + Content-Signal search=yes, use=reference — usage index + lien vers la fiche originale",
124+ "couverture": "Spectacles et sorties culturelles, Grand Montréal",
125+ "cadence": "horaire (watcher PM2, incrémental)",
126+ "statut": "actif"
127+ }
128+ ]
129+}
\ No newline at end of file
added data/villes_regions.json +1255 −0
@@ -0,0 +1,1255 @@
1+{
2+"_comment": "Sorti-Ka — table ville → région administrative, générée depuis le Répertoire des municipalités (MAMH, données ouvertes : MUN.csv + ARR.csv arrondissements) + alias fréquents. Auteur : Simon-Pierre Boucher — contact@spboucher.ai. Clés normalisées (minuscules, sans accents, séparateurs → espace).",
3+"villes": {
4+"abercorn": "Estrie",
5+"acton vale": "Montérégie",
6+"adstock": "Chaudière-Appalaches",
7+"aguanish": "Côte-Nord",
8+"ahuntsic cartierville": "Montréal",
9+"akulivik": "Nord-du-Québec",
10+"akwesasne": "Montérégie",
11+"albanel": "Saguenay–Lac-Saint-Jean",
12+"albertville": "Bas-Saint-Laurent",
13+"alleyn et cawood": "Outaouais",
14+"alma": "Saguenay–Lac-Saint-Jean",
15+"amherst": "Laurentides",
16+"amos": "Abitibi-Témiscamingue",
17+"amqui": "Bas-Saint-Laurent",
18+"ange gardien": "Montérégie",
19+"anjou": "Montréal",
20+"armagh": "Chaudière-Appalaches",
21+"arundel": "Laurentides",
22+"ascot corner": "Estrie",
23+"aston jonction": "Centre-du-Québec",
24+"auclair": "Bas-Saint-Laurent",
25+"audet": "Estrie",
26+"aumond": "Outaouais",
27+"aupaluk": "Nord-du-Québec",
28+"austin": "Estrie",
29+"authier": "Abitibi-Témiscamingue",
30+"authier nord": "Abitibi-Témiscamingue",
31+"ayer s cliff": "Estrie",
32+"baie atibenne": "Lanaudière",
33+"baie comeau": "Côte-Nord",
34+"baie d hudson": "Nord-du-Québec",
35+"baie d urfe": "Montréal",
36+"baie de la bouteille": "Lanaudière",
37+"baie des chaloupes": "Laurentides",
38+"baie des sables": "Bas-Saint-Laurent",
39+"baie du febvre": "Centre-du-Québec",
40+"baie johan beetz": "Côte-Nord",
41+"baie obaoca": "Lanaudière",
42+"baie saint paul": "Capitale-Nationale",
43+"baie sainte catherine": "Capitale-Nationale",
44+"baie trinite": "Côte-Nord",
45+"barkmere": "Laurentides",
46+"barnston ouest": "Estrie",
47+"barraute": "Abitibi-Témiscamingue",
48+"batiscan": "Mauricie",
49+"beaconsfield": "Montréal",
50+"bearn": "Abitibi-Témiscamingue",
51+"beauceville": "Chaudière-Appalaches",
52+"beauharnois": "Montérégie",
53+"beaulac garthby": "Chaudière-Appalaches",
54+"beaumont": "Chaudière-Appalaches",
55+"beauport": "Capitale-Nationale",
56+"beaupre": "Capitale-Nationale",
57+"becancour": "Centre-du-Québec",
58+"bedford": "Estrie",
59+"begin": "Saguenay–Lac-Saint-Jean",
60+"belcourt": "Abitibi-Témiscamingue",
61+"belle riviere": "Saguenay–Lac-Saint-Jean",
62+"belleterre": "Abitibi-Témiscamingue",
63+"beloeil": "Montérégie",
64+"berry": "Abitibi-Témiscamingue",
65+"berthier sur mer": "Chaudière-Appalaches",
66+"berthierville": "Lanaudière",
67+"bethanie": "Montérégie",
68+"biencourt": "Bas-Saint-Laurent",
69+"blainville": "Laurentides",
70+"blanc sablon": "Côte-Nord",
71+"blue sea": "Outaouais",
72+"boileau": "Outaouais",
73+"bois des filion": "Laurentides",
74+"bois franc": "Outaouais",
75+"boisbriand": "Laurentides",
76+"boischatel": "Capitale-Nationale",
77+"bolton est": "Estrie",
78+"bolton ouest": "Estrie",
79+"bonaventure": "Gaspésie–Îles-de-la-Madeleine",
80+"bonne esperance": "Côte-Nord",
81+"bonsecours": "Estrie",
82+"boucherville": "Montérégie",
83+"bouchette": "Outaouais",
84+"bowman": "Outaouais",
85+"brebeuf": "Laurentides",
86+"brigham": "Estrie",
87+"bristol": "Outaouais",
88+"brome": "Estrie",
89+"bromont": "Estrie",
90+"brompton rock forest saint elie deauville": "Estrie",
91+"brossard": "Montérégie",
92+"brownsburg chatham": "Laurentides",
93+"bryson": "Outaouais",
94+"bury": "Estrie",
95+"cacouna": "Bas-Saint-Laurent",
96+"calixa lavallee": "Montérégie",
97+"calumet": "Laurentides",
98+"campbell s bay": "Outaouais",
99+"candiac": "Montérégie",
100+"caniapiscau": "Côte-Nord",
101+"cantley": "Outaouais",
102+"cap chat": "Gaspésie–Îles-de-la-Madeleine",
103+"cap saint ignace": "Chaudière-Appalaches",
104+"cap sante": "Capitale-Nationale",
105+"caplan": "Gaspésie–Îles-de-la-Madeleine",
106+"carignan": "Montérégie",
107+"carleton sur mer": "Gaspésie–Îles-de-la-Madeleine",
108+"cascades malignes": "Outaouais",
109+"cascapedia saint jules": "Gaspésie–Îles-de-la-Madeleine",
110+"causapscal": "Bas-Saint-Laurent",
111+"cayamant": "Outaouais",
112+"chambly": "Montérégie",
113+"chambord": "Saguenay–Lac-Saint-Jean",
114+"champlain": "Mauricie",
115+"champneuf": "Abitibi-Témiscamingue",
116+"chandler": "Gaspésie–Îles-de-la-Madeleine",
117+"chapais": "Nord-du-Québec",
118+"charette": "Mauricie",
119+"charlemagne": "Lanaudière",
120+"charlesbourg": "Capitale-Nationale",
121+"chartierville": "Estrie",
122+"chateau richer": "Capitale-Nationale",
123+"chateauguay": "Montérégie",
124+"chazel": "Abitibi-Témiscamingue",
125+"chelsea": "Outaouais",
126+"cheneville": "Outaouais",
127+"chertsey": "Lanaudière",
128+"chesterville": "Centre-du-Québec",
129+"chibougamau": "Nord-du-Québec",
130+"chichester": "Outaouais",
131+"chicoutimi": "Saguenay–Lac-Saint-Jean",
132+"chisasibi": "Nord-du-Québec",
133+"chute aux outardes": "Côte-Nord",
134+"chute saint philippe": "Laurentides",
135+"clarenceville": "Montérégie",
136+"clarendon": "Outaouais",
137+"clerval": "Abitibi-Témiscamingue",
138+"cleveland": "Estrie",
139+"cloridorme": "Gaspésie–Îles-de-la-Madeleine",
140+"coaticook": "Estrie",
141+"collines du basque": "Gaspésie–Îles-de-la-Madeleine",
142+"colombier": "Côte-Nord",
143+"compton": "Estrie",
144+"contrecoeur": "Montérégie",
145+"cookshire eaton": "Estrie",
146+"cote des neiges notre dame de grace": "Montréal",
147+"cote nord du golfe du saint laurent": "Côte-Nord",
148+"cote saint luc": "Montréal",
149+"coteau du lac": "Montérégie",
150+"coucoucache": "Mauricie",
151+"coulee des adolphe": "Gaspésie–Îles-de-la-Madeleine",
152+"courcelles saint evariste": "Chaudière-Appalaches",
153+"cowansville": "Estrie",
154+"crabtree": "Lanaudière",
155+"danville": "Estrie",
156+"daveluyville": "Centre-du-Québec",
157+"degelis": "Bas-Saint-Laurent",
158+"deleage": "Outaouais",
159+"delson": "Montérégie",
160+"denholm": "Outaouais",
161+"depot echouani": "Outaouais",
162+"desbiens": "Saguenay–Lac-Saint-Jean",
163+"deschaillons sur saint laurent": "Centre-du-Québec",
164+"deschambault grondines": "Capitale-Nationale",
165+"desjardins": "Chaudière-Appalaches",
166+"deux montagnes": "Laurentides",
167+"disraeli": "Chaudière-Appalaches",
168+"dixville": "Estrie",
169+"dolbeau mistassini": "Saguenay–Lac-Saint-Jean",
170+"dollard des ormeaux": "Montréal",
171+"doncaster": "Laurentides",
172+"donnacona": "Capitale-Nationale",
173+"dorval": "Montréal",
174+"dosquet": "Chaudière-Appalaches",
175+"drummondville": "Centre-du-Québec",
176+"dudswell": "Estrie",
177+"duhamel": "Outaouais",
178+"duhamel ouest": "Abitibi-Témiscamingue",
179+"dundee": "Montérégie",
180+"dunham": "Estrie",
181+"duparquet": "Abitibi-Témiscamingue",
182+"dupuy": "Abitibi-Témiscamingue",
183+"durham sud": "Centre-du-Québec",
184+"east angus": "Estrie",
185+"east broughton": "Chaudière-Appalaches",
186+"east farnham": "Estrie",
187+"east hereford": "Estrie",
188+"eastmain": "Nord-du-Québec",
189+"eastman": "Estrie",
190+"eeyou istchee baie james": "Nord-du-Québec",
191+"egan sud": "Outaouais",
192+"elgin": "Montérégie",
193+"entrelacs": "Lanaudière",
194+"escuminac": "Gaspésie–Îles-de-la-Madeleine",
195+"esprit saint": "Bas-Saint-Laurent",
196+"essipit": "Côte-Nord",
197+"esterel": "Laurentides",
198+"farnham": "Estrie",
199+"fassett": "Outaouais",
200+"ferland et boilleau": "Saguenay–Lac-Saint-Jean",
201+"ferme neuve": "Laurentides",
202+"fermont": "Côte-Nord",
203+"fleurimont": "Estrie",
204+"forestville": "Côte-Nord",
205+"fort coulonge": "Outaouais",
206+"fortierville": "Centre-du-Québec",
207+"fossambault sur le lac": "Capitale-Nationale",
208+"frampton": "Chaudière-Appalaches",
209+"franklin": "Montérégie",
210+"franquelin": "Côte-Nord",
211+"frelighsburg": "Estrie",
212+"frontenac": "Estrie",
213+"fugereville": "Abitibi-Témiscamingue",
214+"gallichan": "Abitibi-Témiscamingue",
215+"gaspe": "Gaspésie–Îles-de-la-Madeleine",
216+"gatineau": "Outaouais",
217+"gesgapegiag": "Gaspésie–Îles-de-la-Madeleine",
218+"girardville": "Saguenay–Lac-Saint-Jean",
219+"godbout": "Côte-Nord",
220+"godmanchester": "Montérégie",
221+"gore": "Laurentides",
222+"gracefield": "Outaouais",
223+"granby": "Estrie",
224+"grand metis": "Bas-Saint-Laurent",
225+"grand remous": "Outaouais",
226+"grand saint esprit": "Centre-du-Québec",
227+"grande riviere": "Gaspésie–Îles-de-la-Madeleine",
228+"grande vallee": "Gaspésie–Îles-de-la-Madeleine",
229+"grandes piles": "Mauricie",
230+"greenfield park": "Montérégie",
231+"grenville": "Laurentides",
232+"grenville sur la rouge": "Laurentides",
233+"gros mecatina": "Côte-Nord",
234+"grosse ile": "Gaspésie–Îles-de-la-Madeleine",
235+"grosses roches": "Bas-Saint-Laurent",
236+"guerin": "Abitibi-Témiscamingue",
237+"ham nord": "Centre-du-Québec",
238+"ham sud": "Estrie",
239+"hampden": "Estrie",
240+"hampstead": "Montréal",
241+"harrington": "Laurentides",
242+"hatley": "Estrie",
243+"havelock": "Montérégie",
244+"havre saint pierre": "Côte-Nord",
245+"hebertville": "Saguenay–Lac-Saint-Jean",
246+"hemmingford": "Montérégie",
247+"henryville": "Montérégie",
248+"herouxville": "Mauricie",
249+"hinchinbrooke": "Montérégie",
250+"honfleur": "Chaudière-Appalaches",
251+"hope": "Gaspésie–Îles-de-la-Madeleine",
252+"hope town": "Gaspésie–Îles-de-la-Madeleine",
253+"howick": "Montérégie",
254+"huberdeau": "Laurentides",
255+"hudson": "Montérégie",
256+"huntingdon": "Montérégie",
257+"ile bizard": "Montréal",
258+"ile des soeurs": "Montréal",
259+"inukjuak": "Nord-du-Québec",
260+"inverness": "Centre-du-Québec",
261+"irlande": "Chaudière-Appalaches",
262+"ivry sur le lac": "Laurentides",
263+"ivujivik": "Nord-du-Québec",
264+"joliette": "Lanaudière",
265+"jonquiere": "Saguenay–Lac-Saint-Jean",
266+"kahnawake": "Montérégie",
267+"kamouraska": "Bas-Saint-Laurent",
268+"kangiqsualujjuaq": "Nord-du-Québec",
269+"kangiqsujuaq": "Nord-du-Québec",
270+"kangirsuk": "Nord-du-Québec",
271+"kataskomiq": "Bas-Saint-Laurent",
272+"kawawachikamach": "Côte-Nord",
273+"kazabazua": "Outaouais",
274+"kebaowek": "Abitibi-Témiscamingue",
275+"kiamika": "Laurentides",
276+"kingsbury": "Estrie",
277+"kingsey falls": "Centre-du-Québec",
278+"kinnear s mills": "Chaudière-Appalaches",
279+"kipawa": "Abitibi-Témiscamingue",
280+"kirkland": "Montréal",
281+"kitigan zibi": "Outaouais",
282+"knowlton": "Estrie",
283+"kuujjuaq": "Nord-du-Québec",
284+"kuujjuarapik": "Nord-du-Québec",
285+"l ancienne lorette": "Capitale-Nationale",
286+"l anse saint jean": "Saguenay–Lac-Saint-Jean",
287+"l ascension": "Laurentides",
288+"l ascension de notre seigneur": "Saguenay–Lac-Saint-Jean",
289+"l ascension de patapedia": "Gaspésie–Îles-de-la-Madeleine",
290+"l assomption": "Lanaudière",
291+"l avenir": "Centre-du-Québec",
292+"l epiphanie": "Lanaudière",
293+"l ile bizard sainte genevieve": "Montréal",
294+"l ile cadieux": "Montérégie",
295+"l ile d anticosti": "Côte-Nord",
296+"l ile dorval": "Montréal",
297+"l ile du grand calumet": "Outaouais",
298+"l ile perrot": "Montérégie",
299+"l isle aux allumettes": "Outaouais",
300+"l isle aux coudres": "Capitale-Nationale",
301+"l isle verte": "Bas-Saint-Laurent",
302+"l islet": "Chaudière-Appalaches",
303+"la baie": "Saguenay–Lac-Saint-Jean",
304+"la bostonnais": "Mauricie",
305+"la cite limoilou": "Capitale-Nationale",
306+"la conception": "Laurentides",
307+"la corne": "Abitibi-Témiscamingue",
308+"la dore": "Saguenay–Lac-Saint-Jean",
309+"la durantaye": "Chaudière-Appalaches",
310+"la guadeloupe": "Chaudière-Appalaches",
311+"la haute saint charles": "Capitale-Nationale",
312+"la macaza": "Laurentides",
313+"la malbaie": "Capitale-Nationale",
314+"la martre": "Gaspésie–Îles-de-la-Madeleine",
315+"la minerve": "Laurentides",
316+"la morandiere rochebaucourt": "Abitibi-Témiscamingue",
317+"la motte": "Abitibi-Témiscamingue",
318+"la patrie": "Estrie",
319+"la peche": "Outaouais",
320+"la pocatiere": "Bas-Saint-Laurent",
321+"la prairie": "Montérégie",
322+"la presentation": "Montérégie",
323+"la redemption": "Bas-Saint-Laurent",
324+"la reine": "Abitibi-Témiscamingue",
325+"la romaine": "Côte-Nord",
326+"la sarre": "Abitibi-Témiscamingue",
327+"la trinite des monts": "Bas-Saint-Laurent",
328+"la tuque": "Mauricie",
329+"la visitation de l ile dupas": "Lanaudière",
330+"la visitation de yamaska": "Centre-du-Québec",
331+"labelle": "Laurentides",
332+"labrecque": "Saguenay–Lac-Saint-Jean",
333+"lac a la croix": "Bas-Saint-Laurent",
334+"lac achouakan": "Saguenay–Lac-Saint-Jean",
335+"lac akonapwehikan": "Laurentides",
336+"lac alfred": "Bas-Saint-Laurent",
337+"lac ashuapmushuan": "Saguenay–Lac-Saint-Jean",
338+"lac au brochet": "Côte-Nord",
339+"lac au saumon": "Bas-Saint-Laurent",
340+"lac aux sables": "Mauricie",
341+"lac bazinet": "Laurentides",
342+"lac beauport": "Capitale-Nationale",
343+"lac blanc": "Capitale-Nationale",
344+"lac boisbouscache": "Bas-Saint-Laurent",
345+"lac bouchette": "Saguenay–Lac-Saint-Jean",
346+"lac boule": "Mauricie",
347+"lac brome": "Estrie",
348+"lac cabasta": "Lanaudière",
349+"lac casault": "Bas-Saint-Laurent",
350+"lac chicobi": "Abitibi-Témiscamingue",
351+"lac croche": "Capitale-Nationale",
352+"lac de la bidiere": "Laurentides",
353+"lac de la maison de pierre": "Laurentides",
354+"lac de la pomme": "Laurentides",
355+"lac delage": "Capitale-Nationale",
356+"lac des aigles": "Bas-Saint-Laurent",
357+"lac des dix milles": "Lanaudière",
358+"lac des eaux mortes": "Bas-Saint-Laurent",
359+"lac des ecorces": "Laurentides",
360+"lac des plages": "Outaouais",
361+"lac des seize iles": "Laurentides",
362+"lac despinassy": "Abitibi-Témiscamingue",
363+"lac devenyns": "Lanaudière",
364+"lac douaire": "Laurentides",
365+"lac drolet": "Estrie",
366+"lac du cerf": "Laurentides",
367+"lac du taureau": "Lanaudière",
368+"lac duparquet": "Abitibi-Témiscamingue",
369+"lac edouard": "Mauricie",
370+"lac ernest": "Laurentides",
371+"lac etchemin": "Chaudière-Appalaches",
372+"lac frontiere": "Chaudière-Appalaches",
373+"lac granet": "Abitibi-Témiscamingue",
374+"lac huron": "Bas-Saint-Laurent",
375+"lac jacques cartier": "Capitale-Nationale",
376+"lac jerome": "Côte-Nord",
377+"lac john": "Côte-Nord",
378+"lac juillet": "Côte-Nord",
379+"lac lapeyrere": "Capitale-Nationale",
380+"lac legendre": "Lanaudière",
381+"lac lenotre": "Outaouais",
382+"lac marguerite": "Laurentides",
383+"lac masketsi": "Mauricie",
384+"lac matapedia": "Bas-Saint-Laurent",
385+"lac matawin": "Lanaudière",
386+"lac megantic": "Estrie",
387+"lac metei": "Abitibi-Témiscamingue",
388+"lac minaki": "Lanaudière",
389+"lac ministuk": "Saguenay–Lac-Saint-Jean",
390+"lac moncouche": "Saguenay–Lac-Saint-Jean",
391+"lac moselle": "Outaouais",
392+"lac nilgaut": "Outaouais",
393+"lac normand": "Mauricie",
394+"lac oscar": "Laurentides",
395+"lac pikauba": "Capitale-Nationale",
396+"lac poulin": "Chaudière-Appalaches",
397+"lac pythonga": "Outaouais",
398+"lac rapide": "Outaouais",
399+"lac saguay": "Laurentides",
400+"lac saint joseph": "Capitale-Nationale",
401+"lac saint paul": "Laurentides",
402+"lac sainte marie": "Outaouais",
403+"lac sante": "Lanaudière",
404+"lac sergent": "Capitale-Nationale",
405+"lac superieur": "Laurentides",
406+"lac tremblant nord": "Laurentides",
407+"lac vacher": "Côte-Nord",
408+"lac wagwabika": "Laurentides",
409+"lac walker": "Côte-Nord",
410+"lachine": "Montréal",
411+"lachute": "Laurentides",
412+"lacolle": "Montérégie",
413+"laforce": "Abitibi-Témiscamingue",
414+"lalemant": "Saguenay–Lac-Saint-Jean",
415+"lamarche": "Saguenay–Lac-Saint-Jean",
416+"lambton": "Estrie",
417+"landrienne": "Abitibi-Témiscamingue",
418+"laniel": "Abitibi-Témiscamingue",
419+"lanoraie": "Lanaudière",
420+"lantier": "Laurentides",
421+"larouche": "Saguenay–Lac-Saint-Jean",
422+"lasalle": "Montréal",
423+"latulipe et gaboury": "Abitibi-Témiscamingue",
424+"launay": "Abitibi-Témiscamingue",
425+"laurier station": "Chaudière-Appalaches",
426+"laurierville": "Centre-du-Québec",
427+"laval": "Laval",
428+"lavaltrie": "Lanaudière",
429+"laverlochere angliers": "Abitibi-Témiscamingue",
430+"lawrenceville": "Estrie",
431+"le plateau mont royal": "Montréal",
432+"le sud ouest": "Montréal",
433+"le vieux longueuil": "Montérégie",
434+"lebel sur quevillon": "Nord-du-Québec",
435+"leclercville": "Chaudière-Appalaches",
436+"lefebvre": "Centre-du-Québec",
437+"lejeune": "Bas-Saint-Laurent",
438+"lemieux": "Centre-du-Québec",
439+"lennoxville": "Estrie",
440+"lery": "Montérégie",
441+"les bergeronnes": "Côte-Nord",
442+"les cedres": "Montérégie",
443+"les chutes de la chaudiere est": "Chaudière-Appalaches",
444+"les chutes de la chaudiere ouest": "Chaudière-Appalaches",
445+"les coteaux": "Montérégie",
446+"les eboulements": "Capitale-Nationale",
447+"les escoumins": "Côte-Nord",
448+"les hauteurs": "Bas-Saint-Laurent",
449+"les iles de la madeleine": "Gaspésie–Îles-de-la-Madeleine",
450+"les lacs du temiscamingue": "Abitibi-Témiscamingue",
451+"les mechins": "Bas-Saint-Laurent",
452+"les nations": "Estrie",
453+"les rivieres": "Capitale-Nationale",
454+"levis": "Chaudière-Appalaches",
455+"lingwick": "Estrie",
456+"linton": "Capitale-Nationale",
457+"listuguj": "Gaspésie–Îles-de-la-Madeleine",
458+"litchfield": "Outaouais",
459+"lochaber": "Outaouais",
460+"lochaber partie ouest": "Outaouais",
461+"longue pointe de mingan": "Côte-Nord",
462+"longue rive": "Côte-Nord",
463+"longueil": "Montérégie",
464+"longueuil": "Montérégie",
465+"lorraine": "Laurentides",
466+"lorrainville": "Abitibi-Témiscamingue",
467+"lotbiniere": "Chaudière-Appalaches",
468+"louiseville": "Mauricie",
469+"low": "Outaouais",
470+"lyster": "Centre-du-Québec",
471+"macamic": "Abitibi-Témiscamingue",
472+"macnider": "Bas-Saint-Laurent",
473+"maddington falls": "Centre-du-Québec",
474+"magog": "Estrie",
475+"malartic": "Abitibi-Témiscamingue",
476+"maliotenam": "Côte-Nord",
477+"manawan": "Lanaudière",
478+"mandeville": "Lanaudière",
479+"maniwaki": "Outaouais",
480+"manseau": "Centre-du-Québec",
481+"mansfield et pontefract": "Outaouais",
482+"maria": "Gaspésie–Îles-de-la-Madeleine",
483+"maricourt": "Estrie",
484+"marieville": "Montérégie",
485+"marsoui": "Gaspésie–Îles-de-la-Madeleine",
486+"marston": "Estrie",
487+"martinville": "Estrie",
488+"mascouche": "Lanaudière",
489+"mashteuiatsh": "Saguenay–Lac-Saint-Jean",
490+"maskinonge": "Mauricie",
491+"massueville": "Montérégie",
492+"matagami": "Nord-du-Québec",
493+"matane": "Bas-Saint-Laurent",
494+"matapedia": "Gaspésie–Îles-de-la-Madeleine",
495+"matchi manitou": "Abitibi-Témiscamingue",
496+"matimekosh": "Côte-Nord",
497+"mayo": "Outaouais",
498+"mcmasterville": "Montérégie",
499+"melbourne": "Estrie",
500+"mercier": "Montérégie",
501+"mercier hochelaga maisonneuve": "Montréal",
502+"messines": "Outaouais",
503+"metabetchouan lac a la croix": "Saguenay–Lac-Saint-Jean",
504+"metis sur mer": "Bas-Saint-Laurent",
505+"milan": "Estrie",
506+"mille isles": "Laurentides",
507+"mingan": "Côte-Nord",
508+"mirabel": "Laurentides",
509+"mistissini": "Nord-du-Québec",
510+"moffet": "Abitibi-Témiscamingue",
511+"mont albert": "Gaspésie–Îles-de-la-Madeleine",
512+"mont alexandre": "Gaspésie–Îles-de-la-Madeleine",
513+"mont apica": "Saguenay–Lac-Saint-Jean",
514+"mont blanc": "Laurentides",
515+"mont carmel": "Bas-Saint-Laurent",
516+"mont elie": "Capitale-Nationale",
517+"mont joli": "Bas-Saint-Laurent",
518+"mont laurier": "Laurentides",
519+"mont royal": "Montréal",
520+"mont saint gregoire": "Montérégie",
521+"mont saint hilaire": "Montérégie",
522+"mont saint michel": "Laurentides",
523+"mont saint pierre": "Gaspésie–Îles-de-la-Madeleine",
524+"mont tremblant": "Laurentides",
525+"mont valin": "Saguenay–Lac-Saint-Jean",
526+"montcalm": "Laurentides",
527+"montcerf lytton": "Outaouais",
528+"montebello": "Outaouais",
529+"montmagny": "Chaudière-Appalaches",
530+"montpellier": "Outaouais",
531+"montreal": "Montréal",
532+"montreal est": "Montréal",
533+"montreal nord": "Montréal",
534+"montreal ouest": "Montréal",
535+"morin heights": "Laurentides",
536+"mtl": "Montréal",
537+"mulgrave et derry": "Outaouais",
538+"murdochville": "Gaspésie–Îles-de-la-Madeleine",
539+"namur": "Outaouais",
540+"nantes": "Estrie",
541+"napierville": "Montérégie",
542+"natashquan": "Côte-Nord",
543+"nedelec": "Abitibi-Témiscamingue",
544+"nemaska": "Nord-du-Québec",
545+"neuville": "Capitale-Nationale",
546+"new carlisle": "Gaspésie–Îles-de-la-Madeleine",
547+"new richmond": "Gaspésie–Îles-de-la-Madeleine",
548+"newport": "Estrie",
549+"nicolet": "Centre-du-Québec",
550+"nominingue": "Laurentides",
551+"normandin": "Saguenay–Lac-Saint-Jean",
552+"normetal": "Abitibi-Témiscamingue",
553+"north hatley": "Estrie",
554+"notre dame auxiliatrice de buckland": "Chaudière-Appalaches",
555+"notre dame de bonsecours": "Outaouais",
556+"notre dame de ham": "Centre-du-Québec",
557+"notre dame de l ile perrot": "Montérégie",
558+"notre dame de la merci": "Lanaudière",
559+"notre dame de la paix": "Outaouais",
560+"notre dame de la salette": "Outaouais",
561+"notre dame de lorette": "Saguenay–Lac-Saint-Jean",
562+"notre dame de montauban": "Mauricie",
563+"notre dame de pontmain": "Laurentides",
564+"notre dame de stanbridge": "Estrie",
565+"notre dame des anges": "Capitale-Nationale",
566+"notre dame des bois": "Estrie",
567+"notre dame des monts": "Capitale-Nationale",
568+"notre dame des neiges": "Bas-Saint-Laurent",
569+"notre dame des pins": "Chaudière-Appalaches",
570+"notre dame des prairies": "Lanaudière",
571+"notre dame des sept douleurs": "Bas-Saint-Laurent",
572+"notre dame du bon conseil": "Centre-du-Québec",
573+"notre dame du laus": "Laurentides",
574+"notre dame du mont carmel": "Mauricie",
575+"notre dame du nord": "Abitibi-Témiscamingue",
576+"notre dame du portage": "Bas-Saint-Laurent",
577+"notre dame du rosaire": "Chaudière-Appalaches",
578+"notre dame du sacre coeur d issoudun": "Chaudière-Appalaches",
579+"nouvelle": "Gaspésie–Îles-de-la-Madeleine",
580+"noyan": "Montérégie",
581+"obedjiwan": "Mauricie",
582+"odanak": "Centre-du-Québec",
583+"ogden": "Estrie",
584+"oka": "Laurentides",
585+"orford": "Estrie",
586+"ormstown": "Montérégie",
587+"otter lake": "Outaouais",
588+"otterburn park": "Montérégie",
589+"ouje bougoumou": "Nord-du-Québec",
590+"outremont": "Montréal",
591+"p a t": "Montréal",
592+"packington": "Bas-Saint-Laurent",
593+"padoue": "Bas-Saint-Laurent",
594+"palmarolle": "Abitibi-Témiscamingue",
595+"papineauville": "Outaouais",
596+"parisville": "Centre-du-Québec",
597+"paspebiac": "Gaspésie–Îles-de-la-Madeleine",
598+"passes dangereuses": "Saguenay–Lac-Saint-Jean",
599+"perce": "Gaspésie–Îles-de-la-Madeleine",
600+"peribonka": "Saguenay–Lac-Saint-Jean",
601+"pessamit": "Côte-Nord",
602+"petit lac sainte anne": "Bas-Saint-Laurent",
603+"petit mecatina": "Côte-Nord",
604+"petit saguenay": "Saguenay–Lac-Saint-Jean",
605+"petite riviere saint francois": "Capitale-Nationale",
606+"petite vallee": "Gaspésie–Îles-de-la-Madeleine",
607+"picard": "Bas-Saint-Laurent",
608+"piedmont": "Laurentides",
609+"pierrefonds": "Montréal",
610+"pierrefonds roxboro": "Montréal",
611+"pierreville": "Centre-du-Québec",
612+"pike river": "Estrie",
613+"pikogan": "Abitibi-Témiscamingue",
614+"pincourt": "Montérégie",
615+"piopolis": "Estrie",
616+"plaisance": "Outaouais",
617+"plessisville": "Centre-du-Québec",
618+"pohenegamook": "Bas-Saint-Laurent",
619+"pointe a la croix": "Gaspésie–Îles-de-la-Madeleine",
620+"pointe aux outardes": "Côte-Nord",
621+"pointe aux trembles": "Montréal",
622+"pointe calumet": "Laurentides",
623+"pointe claire": "Montréal",
624+"pointe des cascades": "Montérégie",
625+"pointe fortune": "Montérégie",
626+"pointe lebel": "Côte-Nord",
627+"pont rouge": "Capitale-Nationale",
628+"pontiac": "Outaouais",
629+"port cartier": "Côte-Nord",
630+"port daniel gascons": "Gaspésie–Îles-de-la-Madeleine",
631+"portage du fort": "Outaouais",
632+"portneuf": "Capitale-Nationale",
633+"portneuf sur mer": "Côte-Nord",
634+"potton": "Estrie",
635+"poularies": "Abitibi-Témiscamingue",
636+"preissac": "Abitibi-Témiscamingue",
637+"prevost": "Laurentides",
638+"price": "Bas-Saint-Laurent",
639+"princeville": "Centre-du-Québec",
640+"puvirnituq": "Nord-du-Québec",
641+"quaqtaq": "Nord-du-Québec",
642+"quebec": "Capitale-Nationale",
643+"quebec city": "Capitale-Nationale",
644+"racine": "Estrie",
645+"ragueneau": "Côte-Nord",
646+"rapide danseur": "Abitibi-Témiscamingue",
647+"rapides des joachims": "Outaouais",
648+"rawdon": "Lanaudière",
649+"remigny": "Abitibi-Témiscamingue",
650+"repentigny": "Lanaudière",
651+"reservoir dozois": "Abitibi-Témiscamingue",
652+"richelieu": "Montérégie",
653+"richmond": "Estrie",
654+"rigaud": "Montérégie",
655+"rimouski": "Bas-Saint-Laurent",
656+"ripon": "Outaouais",
657+"ristigouche sud est": "Gaspésie–Îles-de-la-Madeleine",
658+"riviere a claude": "Gaspésie–Îles-de-la-Madeleine",
659+"riviere a pierre": "Capitale-Nationale",
660+"riviere au tonnerre": "Côte-Nord",
661+"riviere aux outardes": "Côte-Nord",
662+"riviere beaudette": "Montérégie",
663+"riviere bleue": "Bas-Saint-Laurent",
664+"riviere bonaventure": "Gaspésie–Îles-de-la-Madeleine",
665+"riviere bonjour": "Bas-Saint-Laurent",
666+"riviere de la savane": "Mauricie",
667+"riviere des prairies pointe aux trembles": "Montréal",
668+"riviere du loup": "Bas-Saint-Laurent",
669+"riviere eternite": "Saguenay–Lac-Saint-Jean",
670+"riviere heva": "Abitibi-Témiscamingue",
671+"riviere koksoak": "Nord-du-Québec",
672+"riviere mistassini": "Saguenay–Lac-Saint-Jean",
673+"riviere mouchalagane": "Côte-Nord",
674+"riviere nipissis": "Côte-Nord",
675+"riviere nouvelle": "Gaspésie–Îles-de-la-Madeleine",
676+"riviere ojima": "Abitibi-Témiscamingue",
677+"riviere ouelle": "Bas-Saint-Laurent",
678+"riviere patapedia est": "Bas-Saint-Laurent",
679+"riviere rouge": "Laurentides",
680+"riviere saint jean": "Côte-Nord",
681+"riviere vaseuse": "Bas-Saint-Laurent",
682+"roberval": "Saguenay–Lac-Saint-Jean",
683+"roquemaure": "Abitibi-Témiscamingue",
684+"rosemere": "Laurentides",
685+"rosemont la petite patrie": "Montréal",
686+"rougemont": "Montérégie",
687+"routhierville": "Bas-Saint-Laurent",
688+"rouyn noranda": "Abitibi-Témiscamingue",
689+"roxboro": "Montréal",
690+"roxton": "Montérégie",
691+"roxton falls": "Montérégie",
692+"roxton pond": "Estrie",
693+"ruisseau des mineurs": "Bas-Saint-Laurent",
694+"ruisseau ferguson": "Gaspésie–Îles-de-la-Madeleine",
695+"sacre coeur": "Côte-Nord",
696+"sacre coeur de jesus": "Chaudière-Appalaches",
697+"sagard": "Capitale-Nationale",
698+"saguenay": "Saguenay–Lac-Saint-Jean",
699+"saint adalbert": "Chaudière-Appalaches",
700+"saint adelme": "Bas-Saint-Laurent",
701+"saint adelphe": "Mauricie",
702+"saint adolphe d howard": "Laurentides",
703+"saint adrien": "Estrie",
704+"saint adrien d irlande": "Chaudière-Appalaches",
705+"saint agapit": "Chaudière-Appalaches",
706+"saint aime": "Montérégie",
707+"saint aime des lacs": "Capitale-Nationale",
708+"saint aime du lac des iles": "Laurentides",
709+"saint alban": "Capitale-Nationale",
710+"saint albert": "Centre-du-Québec",
711+"saint alexandre": "Montérégie",
712+"saint alexandre de kamouraska": "Bas-Saint-Laurent",
713+"saint alexandre des lacs": "Bas-Saint-Laurent",
714+"saint alexis": "Lanaudière",
715+"saint alexis de matapedia": "Gaspésie–Îles-de-la-Madeleine",
716+"saint alexis des monts": "Mauricie",
717+"saint alfred": "Chaudière-Appalaches",
718+"saint alphonse": "Gaspésie–Îles-de-la-Madeleine",
719+"saint alphonse de granby": "Estrie",
720+"saint alphonse rodriguez": "Lanaudière",
721+"saint amable": "Montérégie",
722+"saint ambroise": "Saguenay–Lac-Saint-Jean",
723+"saint ambroise de kildare": "Lanaudière",
724+"saint anaclet de lessard": "Bas-Saint-Laurent",
725+"saint andre avellin": "Outaouais",
726+"saint andre d argenteuil": "Laurentides",
727+"saint andre de kamouraska": "Bas-Saint-Laurent",
728+"saint andre de restigouche": "Gaspésie–Îles-de-la-Madeleine",
729+"saint andre du lac saint jean": "Saguenay–Lac-Saint-Jean",
730+"saint anicet": "Montérégie",
731+"saint anselme": "Chaudière-Appalaches",
732+"saint antoine de l isle aux grues": "Chaudière-Appalaches",
733+"saint antoine de tilly": "Chaudière-Appalaches",
734+"saint antoine sur richelieu": "Montérégie",
735+"saint antonin": "Bas-Saint-Laurent",
736+"saint apollinaire": "Chaudière-Appalaches",
737+"saint armand": "Estrie",
738+"saint arsene": "Bas-Saint-Laurent",
739+"saint athanase": "Bas-Saint-Laurent",
740+"saint aubert": "Chaudière-Appalaches",
741+"saint augustin de desmaures": "Capitale-Nationale",
742+"saint augustin de woburn": "Estrie",
743+"saint barnabe": "Mauricie",
744+"saint barnabe sud": "Montérégie",
745+"saint barthelemy": "Lanaudière",
746+"saint basile": "Capitale-Nationale",
747+"saint basile le grand": "Montérégie",
748+"saint benjamin": "Chaudière-Appalaches",
749+"saint benoit du lac": "Estrie",
750+"saint benoit labre": "Chaudière-Appalaches",
751+"saint bernard": "Chaudière-Appalaches",
752+"saint bernard de lacolle": "Montérégie",
753+"saint bernard de michaudville": "Montérégie",
754+"saint blaise sur richelieu": "Montérégie",
755+"saint bonaventure": "Centre-du-Québec",
756+"saint boniface": "Mauricie",
757+"saint bruno de guigues": "Abitibi-Témiscamingue",
758+"saint bruno de kamouraska": "Bas-Saint-Laurent",
759+"saint bruno de montarville": "Montérégie",
760+"saint calixte": "Lanaudière",
761+"saint camille": "Estrie",
762+"saint camille de lellis": "Chaudière-Appalaches",
763+"saint casimir": "Capitale-Nationale",
764+"saint celestin": "Centre-du-Québec",
765+"saint cesaire": "Montérégie",
766+"saint charles borromee": "Lanaudière",
767+"saint charles de bellechasse": "Chaudière-Appalaches",
768+"saint charles de bourget": "Saguenay–Lac-Saint-Jean",
769+"saint charles garnier": "Bas-Saint-Laurent",
770+"saint charles sur richelieu": "Montérégie",
771+"saint christophe d arthabaska": "Centre-du-Québec",
772+"saint chrysostome": "Montérégie",
773+"saint claude": "Estrie",
774+"saint clement": "Bas-Saint-Laurent",
775+"saint cleophas": "Bas-Saint-Laurent",
776+"saint cleophas de brandon": "Lanaudière",
777+"saint clet": "Montérégie",
778+"saint colomban": "Laurentides",
779+"saint come": "Lanaudière",
780+"saint come liniere": "Chaudière-Appalaches",
781+"saint constant": "Montérégie",
782+"saint cuthbert": "Lanaudière",
783+"saint cyprien de napierville": "Montérégie",
784+"saint cyrille de lessard": "Chaudière-Appalaches",
785+"saint cyrille de wendover": "Centre-du-Québec",
786+"saint damase de l islet": "Chaudière-Appalaches",
787+"saint damien": "Lanaudière",
788+"saint damien de buckland": "Chaudière-Appalaches",
789+"saint david": "Montérégie",
790+"saint david de falardeau": "Saguenay–Lac-Saint-Jean",
791+"saint denis de brompton": "Estrie",
792+"saint denis de la bouteillerie": "Bas-Saint-Laurent",
793+"saint denis sur richelieu": "Montérégie",
794+"saint didace": "Lanaudière",
795+"saint dominique": "Montérégie",
796+"saint dominique du rosaire": "Abitibi-Témiscamingue",
797+"saint edmond de grantham": "Centre-du-Québec",
798+"saint edmond les plaines": "Saguenay–Lac-Saint-Jean",
799+"saint edouard": "Montérégie",
800+"saint edouard de fabre": "Abitibi-Témiscamingue",
801+"saint edouard de lotbiniere": "Chaudière-Appalaches",
802+"saint edouard de maskinonge": "Mauricie",
803+"saint elie de caxton": "Mauricie",
804+"saint eloi": "Bas-Saint-Laurent",
805+"saint elphege": "Centre-du-Québec",
806+"saint elzear de temiscouata": "Bas-Saint-Laurent",
807+"saint emile de suffolk": "Outaouais",
808+"saint ephrem de beauce": "Chaudière-Appalaches",
809+"saint epiphane": "Bas-Saint-Laurent",
810+"saint esprit": "Lanaudière",
811+"saint etienne de beauharnois": "Montérégie",
812+"saint etienne de bolton": "Estrie",
813+"saint etienne des gres": "Mauricie",
814+"saint eugene": "Centre-du-Québec",
815+"saint eugene d argentenay": "Saguenay–Lac-Saint-Jean",
816+"saint eugene de guigues": "Abitibi-Témiscamingue",
817+"saint eugene de ladriere": "Bas-Saint-Laurent",
818+"saint eusebe": "Bas-Saint-Laurent",
819+"saint eustache": "Laurentides",
820+"saint fabien": "Bas-Saint-Laurent",
821+"saint fabien de panet": "Chaudière-Appalaches",
822+"saint felicien": "Saguenay–Lac-Saint-Jean",
823+"saint felix d otis": "Saguenay–Lac-Saint-Jean",
824+"saint felix de kingsey": "Centre-du-Québec",
825+"saint felix de valois": "Lanaudière",
826+"saint ferdinand": "Centre-du-Québec",
827+"saint ferreol les neiges": "Capitale-Nationale",
828+"saint flavien": "Chaudière-Appalaches",
829+"saint fortunat": "Chaudière-Appalaches",
830+"saint francois d assise": "Gaspésie–Îles-de-la-Madeleine",
831+"saint francois de l ile d orleans": "Capitale-Nationale",
832+"saint francois de la riviere du sud": "Chaudière-Appalaches",
833+"saint francois de sales": "Saguenay–Lac-Saint-Jean",
834+"saint francois du lac": "Centre-du-Québec",
835+"saint francois xavier de brompton": "Estrie",
836+"saint francois xavier de viger": "Bas-Saint-Laurent",
837+"saint frederic": "Chaudière-Appalaches",
838+"saint fulgence": "Saguenay–Lac-Saint-Jean",
839+"saint gabriel": "Lanaudière",
840+"saint gabriel de brandon": "Lanaudière",
841+"saint gabriel de rimouski": "Bas-Saint-Laurent",
842+"saint gabriel de valcartier": "Capitale-Nationale",
843+"saint gabriel lalemant": "Bas-Saint-Laurent",
844+"saint gedeon": "Saguenay–Lac-Saint-Jean",
845+"saint gedeon de beauce": "Chaudière-Appalaches",
846+"saint georges": "Chaudière-Appalaches",
847+"saint georges de windsor": "Estrie",
848+"saint gerard majella": "Montérégie",
849+"saint germain de grantham": "Centre-du-Québec",
850+"saint germain de kamouraska": "Bas-Saint-Laurent",
851+"saint gervais": "Chaudière-Appalaches",
852+"saint gilbert": "Capitale-Nationale",
853+"saint gilles": "Chaudière-Appalaches",
854+"saint godefroi": "Gaspésie–Îles-de-la-Madeleine",
855+"saint guillaume": "Centre-du-Québec",
856+"saint guillaume nord": "Lanaudière",
857+"saint henri": "Chaudière-Appalaches",
858+"saint henri de taillon": "Saguenay–Lac-Saint-Jean",
859+"saint hermenegilde": "Estrie",
860+"saint hilaire de dorset": "Chaudière-Appalaches",
861+"saint hilarion": "Capitale-Nationale",
862+"saint hippolyte": "Laurentides",
863+"saint honore": "Saguenay–Lac-Saint-Jean",
864+"saint honore de shenley": "Chaudière-Appalaches",
865+"saint honore de temiscouata": "Bas-Saint-Laurent",
866+"saint hubert": "Montérégie",
867+"saint hubert de riviere du loup": "Bas-Saint-Laurent",
868+"saint hugues": "Montérégie",
869+"saint hyacinthe": "Montérégie",
870+"saint ignace de loyola": "Lanaudière",
871+"saint ignace de stanbridge": "Estrie",
872+"saint irenee": "Capitale-Nationale",
873+"saint isidore de clifton": "Estrie",
874+"saint jacques": "Lanaudière",
875+"saint jacques de leeds": "Chaudière-Appalaches",
876+"saint jacques le majeur de wolfestown": "Chaudière-Appalaches",
877+"saint jacques le mineur": "Montérégie",
878+"saint janvier de joly": "Chaudière-Appalaches",
879+"saint jean baptiste": "Montérégie",
880+"saint jean de brebeuf": "Chaudière-Appalaches",
881+"saint jean de cherbourg": "Bas-Saint-Laurent",
882+"saint jean de dieu": "Bas-Saint-Laurent",
883+"saint jean de l ile d orleans": "Capitale-Nationale",
884+"saint jean de la lande": "Bas-Saint-Laurent",
885+"saint jean de matha": "Lanaudière",
886+"saint jean port joli": "Chaudière-Appalaches",
887+"saint jean sur richelieu": "Montérégie",
888+"saint jerome": "Laurentides",
889+"saint joachim": "Capitale-Nationale",
890+"saint joachim de shefford": "Estrie",
891+"saint joseph de beauce": "Chaudière-Appalaches",
892+"saint joseph de coleraine": "Chaudière-Appalaches",
893+"saint joseph de kamouraska": "Bas-Saint-Laurent",
894+"saint joseph de lepage": "Bas-Saint-Laurent",
895+"saint joseph de sorel": "Montérégie",
896+"saint joseph des erables": "Chaudière-Appalaches",
897+"saint joseph du lac": "Laurentides",
898+"saint jude": "Montérégie",
899+"saint jules": "Chaudière-Appalaches",
900+"saint julien": "Chaudière-Appalaches",
901+"saint just de bretenieres": "Chaudière-Appalaches",
902+"saint juste du lac": "Bas-Saint-Laurent",
903+"saint justin": "Mauricie",
904+"saint lambert": "Montérégie",
905+"saint lambert de lauzon": "Chaudière-Appalaches",
906+"saint laurent": "Montréal",
907+"saint laurent de l ile d orleans": "Capitale-Nationale",
908+"saint lazare": "Montérégie",
909+"saint lazare de bellechasse": "Chaudière-Appalaches",
910+"saint leandre": "Bas-Saint-Laurent",
911+"saint leon de standon": "Chaudière-Appalaches",
912+"saint leonard": "Montréal",
913+"saint leonard d aston": "Centre-du-Québec",
914+"saint leonard de portneuf": "Capitale-Nationale",
915+"saint liboire": "Montérégie",
916+"saint liguori": "Lanaudière",
917+"saint lin laurentides": "Lanaudière",
918+"saint louis": "Montérégie",
919+"saint louis de blandford": "Centre-du-Québec",
920+"saint louis de gonzague du cap tourmente": "Capitale-Nationale",
921+"saint louis du ha! ha!": "Bas-Saint-Laurent",
922+"saint luc de bellechasse": "Chaudière-Appalaches",
923+"saint luc de vincennes": "Mauricie",
924+"saint lucien": "Centre-du-Québec",
925+"saint ludger": "Estrie",
926+"saint ludger de milot": "Saguenay–Lac-Saint-Jean",
927+"saint magloire": "Chaudière-Appalaches",
928+"saint majorique de grantham": "Centre-du-Québec",
929+"saint malachie": "Chaudière-Appalaches",
930+"saint malo": "Estrie",
931+"saint marc de figuery": "Abitibi-Témiscamingue",
932+"saint marc des carrieres": "Capitale-Nationale",
933+"saint marc du lac long": "Bas-Saint-Laurent",
934+"saint marc sur richelieu": "Montérégie",
935+"saint marcel": "Chaudière-Appalaches",
936+"saint marcel de richelieu": "Montérégie",
937+"saint marcellin": "Bas-Saint-Laurent",
938+"saint martin": "Chaudière-Appalaches",
939+"saint mathias sur richelieu": "Montérégie",
940+"saint mathieu": "Montérégie",
941+"saint mathieu d harricana": "Abitibi-Témiscamingue",
942+"saint mathieu de beloeil": "Montérégie",
943+"saint mathieu de rioux": "Bas-Saint-Laurent",
944+"saint mathieu du parc": "Mauricie",
945+"saint maurice": "Mauricie",
946+"saint maxime du mont louis": "Gaspésie–Îles-de-la-Madeleine",
947+"saint medard": "Bas-Saint-Laurent",
948+"saint michel": "Montérégie",
949+"saint michel de bellechasse": "Chaudière-Appalaches",
950+"saint michel des saints": "Lanaudière",
951+"saint michel du squatec": "Bas-Saint-Laurent",
952+"saint modeste": "Bas-Saint-Laurent",
953+"saint moise": "Bas-Saint-Laurent",
954+"saint narcisse": "Mauricie",
955+"saint narcisse de beaurivage": "Chaudière-Appalaches",
956+"saint narcisse de rimouski": "Bas-Saint-Laurent",
957+"saint nazaire": "Saguenay–Lac-Saint-Jean",
958+"saint nazaire d acton": "Montérégie",
959+"saint nazaire de dorchester": "Chaudière-Appalaches",
960+"saint neree de bellechasse": "Chaudière-Appalaches",
961+"saint noel": "Bas-Saint-Laurent",
962+"saint norbert": "Lanaudière",
963+"saint norbert d arthabaska": "Centre-du-Québec",
964+"saint octave de metis": "Bas-Saint-Laurent",
965+"saint odilon de cranbourne": "Chaudière-Appalaches",
966+"saint omer": "Chaudière-Appalaches",
967+"saint ours": "Montérégie",
968+"saint pacome": "Bas-Saint-Laurent",
969+"saint pamphile": "Chaudière-Appalaches",
970+"saint pascal": "Bas-Saint-Laurent",
971+"saint patrice de beaurivage": "Chaudière-Appalaches",
972+"saint patrice de sherrington": "Montérégie",
973+"saint paul": "Lanaudière",
974+"saint paul d abbotsford": "Montérégie",
975+"saint paul de l ile aux noix": "Montérégie",
976+"saint paul de la croix": "Bas-Saint-Laurent",
977+"saint paul de montminy": "Chaudière-Appalaches",
978+"saint paulin": "Mauricie",
979+"saint philemon": "Chaudière-Appalaches",
980+"saint philibert": "Chaudière-Appalaches",
981+"saint philippe": "Montérégie",
982+"saint philippe de neri": "Bas-Saint-Laurent",
983+"saint pie": "Montérégie",
984+"saint pie de guire": "Centre-du-Québec",
985+"saint pierre": "Lanaudière",
986+"saint pierre baptiste": "Centre-du-Québec",
987+"saint pierre de broughton": "Chaudière-Appalaches",
988+"saint pierre de l ile d orleans": "Capitale-Nationale",
989+"saint pierre de la riviere du sud": "Chaudière-Appalaches",
990+"saint pierre de lamy": "Bas-Saint-Laurent",
991+"saint pierre les becquets": "Centre-du-Québec",
992+"saint placide": "Laurentides",
993+"saint polycarpe": "Montérégie",
994+"saint prime": "Saguenay–Lac-Saint-Jean",
995+"saint prosper": "Chaudière-Appalaches",
996+"saint prosper de champlain": "Mauricie",
997+"saint raphael": "Chaudière-Appalaches",
998+"saint raymond": "Capitale-Nationale",
999+"saint remi": "Montérégie",
1000+"saint remi de tingwick": "Centre-du-Québec",
1001+"saint rene": "Chaudière-Appalaches",
1002+"saint rene de matane": "Bas-Saint-Laurent",
1003+"saint robert": "Montérégie",
1004+"saint robert bellarmin": "Estrie",
1005+"saint roch de l achigan": "Lanaudière",
1006+"saint roch de mekinac": "Mauricie",
1007+"saint roch de richelieu": "Montérégie",
1008+"saint roch des aulnaies": "Chaudière-Appalaches",
1009+"saint roch ouest": "Lanaudière",
1010+"saint romain": "Estrie",
1011+"saint rosaire": "Centre-du-Québec",
1012+"saint samuel": "Centre-du-Québec",
1013+"saint sauveur": "Laurentides",
1014+"saint severe": "Mauricie",
1015+"saint simon": "Montérégie",
1016+"saint simon de rimouski": "Bas-Saint-Laurent",
1017+"saint simon les mines": "Chaudière-Appalaches",
1018+"saint sixte": "Outaouais",
1019+"saint stanislas de kostka": "Montérégie",
1020+"saint sulpice": "Lanaudière",
1021+"saint sylvere": "Centre-du-Québec",
1022+"saint sylvestre": "Chaudière-Appalaches",
1023+"saint telesphore": "Montérégie",
1024+"saint tharcisius": "Bas-Saint-Laurent",
1025+"saint theodore d acton": "Montérégie",
1026+"saint theophile": "Chaudière-Appalaches",
1027+"saint thomas": "Lanaudière",
1028+"saint thomas didyme": "Saguenay–Lac-Saint-Jean",
1029+"saint thuribe": "Capitale-Nationale",
1030+"saint tite": "Mauricie",
1031+"saint tite des caps": "Capitale-Nationale",
1032+"saint ubalde": "Capitale-Nationale",
1033+"saint ulric": "Bas-Saint-Laurent",
1034+"saint urbain": "Capitale-Nationale",
1035+"saint urbain premier": "Montérégie",
1036+"saint valentin": "Montérégie",
1037+"saint valere": "Centre-du-Québec",
1038+"saint valerien": "Bas-Saint-Laurent",
1039+"saint valerien de milton": "Montérégie",
1040+"saint vallier": "Chaudière-Appalaches",
1041+"saint venant de paquette": "Estrie",
1042+"saint vianney": "Bas-Saint-Laurent",
1043+"saint victor": "Chaudière-Appalaches",
1044+"saint wenceslas": "Centre-du-Québec",
1045+"saint zacharie": "Chaudière-Appalaches",
1046+"saint zenon": "Lanaudière",
1047+"saint zenon du lac humqui": "Bas-Saint-Laurent",
1048+"saint zephirin de courval": "Centre-du-Québec",
1049+"saint zotique": "Montérégie",
1050+"sainte adele": "Laurentides",
1051+"sainte agathe de lotbiniere": "Chaudière-Appalaches",
1052+"sainte agathe des monts": "Laurentides",
1053+"sainte angele de merici": "Bas-Saint-Laurent",
1054+"sainte angele de monnoir": "Montérégie",
1055+"sainte angele de premont": "Mauricie",
1056+"sainte anne de beaupre": "Capitale-Nationale",
1057+"sainte anne de bellevue": "Montréal",
1058+"sainte anne de la perade": "Mauricie",
1059+"sainte anne de la rochelle": "Estrie",
1060+"sainte anne de sabrevois": "Montérégie",
1061+"sainte anne de sorel": "Montérégie",
1062+"sainte anne des lacs": "Laurentides",
1063+"sainte anne des monts": "Gaspésie–Îles-de-la-Madeleine",
1064+"sainte anne des plaines": "Laurentides",
1065+"sainte anne du lac": "Laurentides",
1066+"sainte apolline de patton": "Chaudière-Appalaches",
1067+"sainte aurelie": "Chaudière-Appalaches",
1068+"sainte barbe": "Montérégie",
1069+"sainte beatrix": "Lanaudière",
1070+"sainte brigide d iberville": "Montérégie",
1071+"sainte brigitte de laval": "Capitale-Nationale",
1072+"sainte brigitte des saults": "Centre-du-Québec",
1073+"sainte catherine": "Montérégie",
1074+"sainte catherine de hatley": "Estrie",
1075+"sainte catherine de la jacques cartier": "Capitale-Nationale",
1076+"sainte cecile de levrard": "Centre-du-Québec",
1077+"sainte cecile de milton": "Estrie",
1078+"sainte cecile de whitton": "Estrie",
1079+"sainte christine": "Montérégie",
1080+"sainte christine d auvergne": "Capitale-Nationale",
1081+"sainte claire": "Chaudière-Appalaches",
1082+"sainte clotilde": "Montérégie",
1083+"sainte clotilde de beauce": "Chaudière-Appalaches",
1084+"sainte clotilde de horton": "Centre-du-Québec",
1085+"sainte croix": "Chaudière-Appalaches",
1086+"sainte edwidge de clifton": "Estrie",
1087+"sainte elisabeth": "Lanaudière",
1088+"sainte elisabeth de proulx": "Saguenay–Lac-Saint-Jean",
1089+"sainte elizabeth de warwick": "Centre-du-Québec",
1090+"sainte emelie de l energie": "Lanaudière",
1091+"sainte eulalie": "Centre-du-Québec",
1092+"sainte euphemie sur riviere du sud": "Chaudière-Appalaches",
1093+"sainte famille de l ile d orleans": "Capitale-Nationale",
1094+"sainte flavie": "Bas-Saint-Laurent",
1095+"sainte florence": "Bas-Saint-Laurent",
1096+"sainte foy sillery cap rouge": "Capitale-Nationale",
1097+"sainte genevieve de batiscan": "Mauricie",
1098+"sainte genevieve de berthier": "Lanaudière",
1099+"sainte germaine boule": "Abitibi-Témiscamingue",
1100+"sainte gertrude manneville": "Abitibi-Témiscamingue",
1101+"sainte hedwidge": "Saguenay–Lac-Saint-Jean",
1102+"sainte helene de bagot": "Montérégie",
1103+"sainte helene de chester": "Centre-du-Québec",
1104+"sainte helene de kamouraska": "Bas-Saint-Laurent",
1105+"sainte helene de mancebourg": "Abitibi-Témiscamingue",
1106+"sainte henedine": "Chaudière-Appalaches",
1107+"sainte irene": "Bas-Saint-Laurent",
1108+"sainte jeanne d arc": "Saguenay–Lac-Saint-Jean",
1109+"sainte jeanne d arc de la mitis": "Bas-Saint-Laurent",
1110+"sainte julie": "Montérégie",
1111+"sainte julienne": "Lanaudière",
1112+"sainte justine": "Chaudière-Appalaches",
1113+"sainte justine de newton": "Montérégie",
1114+"sainte louise": "Chaudière-Appalaches",
1115+"sainte luce": "Bas-Saint-Laurent",
1116+"sainte lucie de beauregard": "Chaudière-Appalaches",
1117+"sainte lucie des laurentides": "Laurentides",
1118+"sainte madeleine": "Montérégie",
1119+"sainte madeleine de la riviere madeleine": "Gaspésie–Îles-de-la-Madeleine",
1120+"sainte marcelline de kildare": "Lanaudière",
1121+"sainte marguerite": "Chaudière-Appalaches",
1122+"sainte marguerite du lac masson": "Laurentides",
1123+"sainte marguerite marie": "Bas-Saint-Laurent",
1124+"sainte marie": "Chaudière-Appalaches",
1125+"sainte marie de blandford": "Centre-du-Québec",
1126+"sainte marie madeleine": "Montérégie",
1127+"sainte marie salome": "Lanaudière",
1128+"sainte marthe": "Montérégie",
1129+"sainte marthe sur le lac": "Laurentides",
1130+"sainte martine": "Montérégie",
1131+"sainte melanie": "Lanaudière",
1132+"sainte paule": "Bas-Saint-Laurent",
1133+"sainte petronille": "Capitale-Nationale",
1134+"sainte praxede": "Chaudière-Appalaches",
1135+"sainte rita": "Bas-Saint-Laurent",
1136+"sainte rose de watford": "Chaudière-Appalaches",
1137+"sainte rose du nord": "Saguenay–Lac-Saint-Jean",
1138+"sainte seraphine": "Centre-du-Québec",
1139+"sainte sophie": "Laurentides",
1140+"sainte sophie d halifax": "Centre-du-Québec",
1141+"sainte sophie de levrard": "Centre-du-Québec",
1142+"sainte thecle": "Mauricie",
1143+"sainte therese": "Laurentides",
1144+"sainte therese de gaspe": "Gaspésie–Îles-de-la-Madeleine",
1145+"sainte therese de la gatineau": "Outaouais",
1146+"sainte ursule": "Mauricie",
1147+"sainte victoire de sorel": "Montérégie",
1148+"saints anges": "Chaudière-Appalaches",
1149+"saints martyrs canadiens": "Centre-du-Québec",
1150+"salaberry de valleyfield": "Montérégie",
1151+"salluit": "Nord-du-Québec",
1152+"sault au cochon": "Capitale-Nationale",
1153+"sayabec": "Bas-Saint-Laurent",
1154+"schefferville": "Côte-Nord",
1155+"scotstown": "Estrie",
1156+"scott": "Chaudière-Appalaches",
1157+"senneterre": "Abitibi-Témiscamingue",
1158+"senneville": "Montréal",
1159+"sept iles": "Côte-Nord",
1160+"shannon": "Capitale-Nationale",
1161+"shawinigan": "Mauricie",
1162+"shawville": "Outaouais",
1163+"sheenboro": "Outaouais",
1164+"shefford": "Estrie",
1165+"sherbrooke": "Estrie",
1166+"shigawake": "Gaspésie–Îles-de-la-Madeleine",
1167+"sorel tracy": "Montérégie",
1168+"st sauveur": "Laurentides",
1169+"stanbridge east": "Estrie",
1170+"stanbridge station": "Estrie",
1171+"stanstead": "Estrie",
1172+"stanstead est": "Estrie",
1173+"ste adele": "Laurentides",
1174+"stoke": "Estrie",
1175+"stoneham et tewkesbury": "Capitale-Nationale",
1176+"stornoway": "Estrie",
1177+"stratford": "Estrie",
1178+"stukely sud": "Estrie",
1179+"sutton": "Estrie",
1180+"tadoussac": "Côte-Nord",
1181+"taschereau": "Abitibi-Témiscamingue",
1182+"tasiujaq": "Nord-du-Québec",
1183+"temiscaming": "Abitibi-Témiscamingue",
1184+"temiscouata sur le lac": "Bas-Saint-Laurent",
1185+"terrasse vaudreuil": "Montérégie",
1186+"terrebonne": "Lanaudière",
1187+"thetford mines": "Chaudière-Appalaches",
1188+"thorne": "Outaouais",
1189+"thurso": "Outaouais",
1190+"timiskaming": "Abitibi-Témiscamingue",
1191+"tingwick": "Centre-du-Québec",
1192+"toponyme a venir": "Nord-du-Québec",
1193+"tourville": "Chaudière-Appalaches",
1194+"trecesson": "Abitibi-Témiscamingue",
1195+"tres saint redempteur": "Montérégie",
1196+"tres saint sacrement": "Montérégie",
1197+"tring jonction": "Chaudière-Appalaches",
1198+"trois pistoles": "Bas-Saint-Laurent",
1199+"trois rives": "Mauricie",
1200+"trois rivieres": "Mauricie",
1201+"uashat": "Côte-Nord",
1202+"ulverton": "Estrie",
1203+"umiujaq": "Nord-du-Québec",
1204+"upton": "Montérégie",
1205+"val alain": "Chaudière-Appalaches",
1206+"val brillant": "Bas-Saint-Laurent",
1207+"val d or": "Abitibi-Témiscamingue",
1208+"val david": "Laurentides",
1209+"val des bois": "Outaouais",
1210+"val des lacs": "Laurentides",
1211+"val des monts": "Outaouais",
1212+"val des sources": "Estrie",
1213+"val joli": "Estrie",
1214+"val morin": "Laurentides",
1215+"val racine": "Estrie",
1216+"val saint gilles": "Abitibi-Témiscamingue",
1217+"valcourt": "Estrie",
1218+"vallee jonction": "Chaudière-Appalaches",
1219+"varennes": "Montérégie",
1220+"vaudreuil dorion": "Montérégie",
1221+"vaudreuil sur le lac": "Montérégie",
1222+"venise en quebec": "Montérégie",
1223+"vercheres": "Montérégie",
1224+"verdun": "Montréal",
1225+"victoriaville": "Centre-du-Québec",
1226+"vieux montreal": "Montréal",
1227+"vieux quebec": "Capitale-Nationale",
1228+"ville marie": "Abitibi-Témiscamingue",
1229+"ville st laurent": "Montréal",
1230+"villeray saint michel parc extension": "Montréal",
1231+"villeroy": "Centre-du-Québec",
1232+"waltham": "Outaouais",
1233+"warden": "Estrie",
1234+"warwick": "Centre-du-Québec",
1235+"waskaganish": "Nord-du-Québec",
1236+"waswanipi": "Nord-du-Québec",
1237+"waterloo": "Estrie",
1238+"waterville": "Estrie",
1239+"weedon": "Estrie",
1240+"wemindji": "Nord-du-Québec",
1241+"wemotaci": "Mauricie",
1242+"wendake": "Capitale-Nationale",
1243+"wentworth": "Laurentides",
1244+"wentworth nord": "Laurentides",
1245+"westbury": "Estrie",
1246+"westmount": "Montréal",
1247+"whapmagoostui": "Nord-du-Québec",
1248+"wickham": "Centre-du-Québec",
1249+"windsor": "Estrie",
1250+"wolinak": "Centre-du-Québec",
1251+"wotton": "Estrie",
1252+"yamachiche": "Mauricie",
1253+"yamaska": "Montérégie"
1254+}
1255+}
\ No newline at end of file
added docs/screenshots/accueil.png +0 −0

Binary file not shown.

added docs/screenshots/fiche.png +0 −0

Binary file not shown.

added frontend/index.html +586 −0
Large diff (586 lines) is not loaded by default to keep the page fast.Load diff
added requirements.txt +9 −0
Large diff (9 lines) is not loaded by default to keep the page fast.Load diff
added run.py +51 −0
Large diff (51 lines) is not loaded by default to keep the page fast.Load diff
added sortika/__init__.py +9 −0
Large diff (9 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/__init__.py +30 −0
Large diff (30 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/atuvu.py +127 −0
Large diff (127 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/base.py +142 −0
Large diff (142 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/evenko.py +113 −0
Large diff (113 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/laval.py +59 −0
Large diff (59 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/lavitrine.py +162 −0
Large diff (162 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/lepointdevente.py +96 −0
Large diff (96 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/montreal.py +114 −0
Large diff (114 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/sherbrooke.py +103 −0
Large diff (103 lines) is not loaded by default to keep the page fast.Load diff
added sortika/connectors/sitq.py +152 −0
Large diff (152 lines) is not loaded by default to keep the page fast.Load diff
added sortika/db.py +205 −0
Large diff (205 lines) is not loaded by default to keep the page fast.Load diff
added sortika/ingest.py +67 −0
Large diff (67 lines) is not loaded by default to keep the page fast.Load diff
added sortika/normalize.py +201 −0
Large diff (201 lines) is not loaded by default to keep the page fast.Load diff
added sortika/regions.py +173 −0
Large diff (173 lines) is not loaded by default to keep the page fast.Load diff
added sortika/schema.py +116 −0
Large diff (116 lines) is not loaded by default to keep the page fast.Load diff
added sortika/seo.py +200 −0
Large diff (200 lines) is not loaded by default to keep the page fast.Load diff
added sortika/web.py +207 −0
Large diff (207 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/atuvu_fiche.html +1426 −0
Large diff (1,426 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/evenko_sample.json +1 −0
Large diff (2 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/laval_sample.json +449 −0
Large diff (450 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/lavitrine_fiche.html +736 −0
Large diff (737 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/lepointdevente_page1.html +2284 −0
Large diff (2,284 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/montreal_sample.json +1 −0
Large diff (2 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/sherbrooke_page.html +1 −0
Large diff (2 lines) is not loaded by default to keep the page fast.Load diff
added tests/fixtures/sitq_sample.json +1373 −0
Large diff (1,374 lines) is not loaded by default to keep the page fast.Load diff
added tests/test_connectors.py +148 −0
Large diff (148 lines) is not loaded by default to keep the page fast.Load diff
added tests/test_db.py +61 −0
Large diff (61 lines) is not loaded by default to keep the page fast.Load diff
added tests/test_normalize.py +73 −0
Large diff (74 lines) is not loaded by default to keep the page fast.Load diff
Menu

Theme