payload-validation #34
.vscode
src
models
routes
types
utils
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -52,6 +52,8 @@
|
|||||||
"Typica",
|
"Typica",
|
||||||
"Verte",
|
"Verte",
|
||||||
"VSOP",
|
"VSOP",
|
||||||
|
"wineyard",
|
||||||
|
"wineyards",
|
||||||
"Yamahai",
|
"Yamahai",
|
||||||
"Yuzu"
|
"Yuzu"
|
||||||
]
|
]
|
||||||
|
@ -4,7 +4,9 @@ import {
|
|||||||
Viticulture,
|
Viticulture,
|
||||||
BottleClosure,
|
BottleClosure,
|
||||||
VintageOptions,
|
VintageOptions,
|
||||||
StandardDrinks100ml
|
StandardDrinks,
|
||||||
|
WineRegion,
|
||||||
|
WineVolume
|
||||||
} from '../types'
|
} from '../types'
|
||||||
import { Alpha2Code } from 'i18n-iso-countries'
|
import { Alpha2Code } from 'i18n-iso-countries'
|
||||||
import { CurrencyCode } from 'currency-codes-ts/dist/types'
|
import { CurrencyCode } from 'currency-codes-ts/dist/types'
|
||||||
@ -18,13 +20,14 @@ export class Wine {
|
|||||||
public style: string, // bubbles+fizz, table, dessert, fortified, vermouth
|
public style: string, // bubbles+fizz, table, dessert, fortified, vermouth
|
||||||
public characteristic: string, // light aromatic, textural, fruit forward, structural & savoury, powerful
|
public characteristic: string, // light aromatic, textural, fruit forward, structural & savoury, powerful
|
||||||
public country: Alpha2Code, // two-letter country codes defined in ISO 3166-1 (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
|
public country: Alpha2Code, // two-letter country codes defined in ISO 3166-1 (https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
|
||||||
public region: string, // appellation, village, sub-region, vineyard
|
public region: WineRegion, // appellation, village, sub-region, vineyard
|
||||||
public name: string, // label
|
public name: string, // label
|
||||||
public producerId: ObjectId, // product producer
|
public producerId: ObjectId, // product producer
|
||||||
public varietal: string, // if more than one, list as 'blend'
|
public varietal: string, // if more than one, list as 'blend'
|
||||||
public vintage: number | VintageOptions, // year, nv (non-vintage) or mv (multi-vintage)
|
public vintage: number | VintageOptions, // year, nv (non-vintage) or mv (multi-vintage)
|
||||||
|
public volume: WineVolume, // bottle volume
|
||||||
public alcohol: number, // alcohol percentage
|
public alcohol: number, // alcohol percentage
|
||||||
public standardDrinks100ml: StandardDrinks100ml, // an amount of standard drinks per 100ml in AU, UK and US
|
public standardDrinks: StandardDrinks, // an amount of standard drinks per 100ml and bottle in AU, UK and US
|
||||||
public viticulture: Viticulture, // viticulture
|
public viticulture: Viticulture, // viticulture
|
||||||
public sulfites: number, // parts per million
|
public sulfites: number, // parts per million
|
||||||
public filtered: boolean, // is wine filtered (fined (egg or fish))
|
public filtered: boolean, // is wine filtered (fined (egg or fish))
|
||||||
|
@ -5,7 +5,8 @@ import {
|
|||||||
wineValidation,
|
wineValidation,
|
||||||
handleReqError,
|
handleReqError,
|
||||||
handleReqSuccess,
|
handleReqSuccess,
|
||||||
alcoholToStandardDrinks
|
alcoholToStandardDrinks,
|
||||||
|
volumeToMl
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
import Joi from 'joi'
|
import Joi from 'joi'
|
||||||
|
|
||||||
@ -76,7 +77,10 @@ winesRouter.post('/', async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wine.standardDrinks100ml = alcoholToStandardDrinks(wine.alcohol)
|
wine.standardDrinks = alcoholToStandardDrinks(
|
||||||
|
wine.alcohol,
|
||||||
|
volumeToMl(wine.volume)
|
||||||
|
)
|
||||||
|
|
||||||
const result = await collections.wines?.insertOne(wine)
|
const result = await collections.wines?.insertOne(wine)
|
||||||
|
|
||||||
|
@ -66,8 +66,7 @@ export enum VintageOptions {
|
|||||||
MV = 'mv'
|
MV = 'mv'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StandardDrinks100ml {
|
export interface StandardDrinks {
|
||||||
AU: number
|
'100ml': { AU: number; UK: number; US: number }
|
||||||
UK: number
|
bottle: { AU: number; UK: number; US: number }
|
||||||
US: number
|
|
||||||
}
|
}
|
||||||
|
@ -16,3 +16,21 @@ export enum BottleClosure {
|
|||||||
CrownSeal = 'crown-seal',
|
CrownSeal = 'crown-seal',
|
||||||
Screwcap = 'screwcap'
|
Screwcap = 'screwcap'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface WineRegion {
|
||||||
|
[key: string]:
|
||||||
|
| string[]
|
||||||
|
| { [key: string]: string[] | { [key: string]: string[] } }
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WineVolume {
|
||||||
|
'0.05L' = '0.05L',
|
||||||
|
'0.187L' = '0.187L',
|
||||||
|
'0.375L' = '0.375L',
|
||||||
|
'0.5L' = '0.5L',
|
||||||
|
'0.75L' = '0.75L',
|
||||||
|
'1.5L' = '1.5L',
|
||||||
|
'3L' = '3L',
|
||||||
|
'6L' = '6L',
|
||||||
|
'12L' = '12L'
|
||||||
|
}
|
||||||
|
@ -1,10 +1,36 @@
|
|||||||
import { StandardDrinks100ml } from '../types'
|
import { StandardDrinks, WineVolume } from '../types'
|
||||||
import { roundToOneDecimal } from './'
|
import { roundToOneDecimal } from './'
|
||||||
|
|
||||||
export const alcoholToStandardDrinks = (
|
export const alcoholToStandardDrinks = (
|
||||||
alcohol: number
|
alcohol: number,
|
||||||
): StandardDrinks100ml => ({
|
bottle: number
|
||||||
UK: roundToOneDecimal(10 * alcohol),
|
): StandardDrinks => {
|
||||||
AU: roundToOneDecimal(7.91 * alcohol),
|
const UK100ml = roundToOneDecimal(10 * alcohol)
|
||||||
US: roundToOneDecimal(5.64 * alcohol)
|
const AU100ml = roundToOneDecimal(7.91 * alcohol)
|
||||||
})
|
const US100ml = roundToOneDecimal(5.64 * alcohol)
|
||||||
|
|
||||||
|
const bottleMultiplier = bottle / 100
|
||||||
|
|
||||||
|
return {
|
||||||
|
'100ml': {
|
||||||
|
UK: UK100ml,
|
||||||
|
AU: AU100ml,
|
||||||
|
US: US100ml
|
||||||
|
},
|
||||||
|
bottle: {
|
||||||
|
UK: UK100ml * bottleMultiplier,
|
||||||
|
AU: AU100ml * bottleMultiplier,
|
||||||
|
US: US100ml * bottleMultiplier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const volumeToMl = (volume: WineVolume): number => {
|
||||||
|
if (volume.endsWith('L')) {
|
||||||
|
const volumeMl = volume.replace('L', '')
|
||||||
|
|
||||||
|
return Number(volumeMl) * 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Not supported volume type')
|
||||||
|
}
|
||||||
|
@ -3,3 +3,4 @@ export * from './nostr'
|
|||||||
export * from './route'
|
export * from './route'
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
export * from './alcohol'
|
export * from './alcohol'
|
||||||
|
export * from './wine'
|
||||||
|
@ -1,2 +1,5 @@
|
|||||||
export const roundToOneDecimal = (number: number) =>
|
export const roundToOneDecimal = (number: number) =>
|
||||||
Math.round(number * 10) / 10
|
Math.round(number * 10) / 10
|
||||||
|
|
||||||
|
export const isObject = (item: unknown) =>
|
||||||
|
typeof item === 'object' && !Array.isArray(item) && item !== null
|
||||||
|
@ -3,8 +3,11 @@ import {
|
|||||||
WineType,
|
WineType,
|
||||||
VintageOptions,
|
VintageOptions,
|
||||||
BottleClosure,
|
BottleClosure,
|
||||||
Viticulture
|
Viticulture,
|
||||||
|
WineRegion,
|
||||||
|
WineVolume
|
||||||
} from '../../types'
|
} from '../../types'
|
||||||
|
import { wineRegionsMap, isObject } from '../'
|
||||||
|
|
||||||
export const wineValidation = (data: unknown): Joi.ValidationResult =>
|
export const wineValidation = (data: unknown): Joi.ValidationResult =>
|
||||||
Joi.object({
|
Joi.object({
|
||||||
@ -17,18 +20,256 @@ export const wineValidation = (data: unknown): Joi.ValidationResult =>
|
|||||||
style: Joi.string().required(),
|
style: Joi.string().required(),
|
||||||
characteristic: Joi.string().required(),
|
characteristic: Joi.string().required(),
|
||||||
country: Joi.string().length(2),
|
country: Joi.string().length(2),
|
||||||
region: Joi.string().required(),
|
region: Joi.alternatives()
|
||||||
|
.try(
|
||||||
|
Joi.string().custom((value, helper) => {
|
||||||
|
if (value) {
|
||||||
|
if (helper.state.ancestors) {
|
||||||
|
const { country } = helper.state.ancestors[0]
|
||||||
|
|
||||||
|
if (country) {
|
||||||
|
const regionMap = wineRegionsMap[country]
|
||||||
|
|
||||||
|
if (regionMap) {
|
||||||
|
const regions = Array.isArray(regionMap)
|
||||||
|
? regionMap
|
||||||
|
: Object.keys(regionMap)
|
||||||
|
|
||||||
|
if (!regions.includes(value)) {
|
||||||
|
return helper.message({
|
||||||
|
custom: Joi.expression(
|
||||||
|
`"region" contains an invalid value. Valid values for ${country} are [${regions.join(', ')}]`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}),
|
||||||
|
Joi.object().custom(
|
||||||
|
(
|
||||||
|
value: {
|
||||||
|
[key: string]:
|
||||||
|
| string
|
||||||
|
| { [key: string]: string | { [key: string]: string } }
|
||||||
|
},
|
||||||
|
helper: Joi.CustomHelpers<unknown>
|
||||||
|
) => {
|
||||||
|
// return if no value
|
||||||
|
if (!value) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
// return if no state ancestors
|
||||||
|
if (!helper.state.ancestors) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
const country: string = helper.state.ancestors[0].country
|
||||||
|
|
||||||
|
// return if no country
|
||||||
|
if (!country) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
const regionMap = wineRegionsMap[country]
|
||||||
|
|
||||||
|
// return if no region map
|
||||||
|
if (!regionMap) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Region
|
||||||
|
*/
|
||||||
|
// list of supported regions
|
||||||
|
const regions = Array.isArray(regionMap)
|
||||||
|
? regionMap
|
||||||
|
: Object.keys(regionMap)
|
||||||
|
|
||||||
|
const providedRegions = Object.keys(value)
|
||||||
|
|
||||||
|
// check if multiple regions provided
|
||||||
|
if (providedRegions.length !== 1) {
|
||||||
|
return helper.message({
|
||||||
|
custom: Joi.expression(
|
||||||
|
`"region" contains an invalid value. Valid values a single string or a region object`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const returnCustomMessage = (
|
||||||
|
map: string[],
|
||||||
|
options: string[]
|
||||||
|
): Joi.ErrorReport =>
|
||||||
|
helper.message({
|
||||||
|
custom: Joi.expression(
|
||||||
|
`"region" contains an invalid value. Valid values for ${map.join(' -> ')} are [${options.join(', ')}]`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const providedRegion = providedRegions[0]
|
||||||
|
|
||||||
|
// check if provided region is in list of supported regions
|
||||||
|
if (!regions.includes(providedRegion)) {
|
||||||
|
return returnCustomMessage([country], regions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subregion
|
||||||
|
*/
|
||||||
|
// list of supported subregions
|
||||||
|
const subRegions: string[] = Object.keys(
|
||||||
|
(regionMap as WineRegion)[providedRegion]
|
||||||
|
)
|
||||||
|
|
||||||
|
const providedSubRegion:
|
||||||
|
| string
|
||||||
|
| { [key: string]: string | { [key: string]: string } } =
|
||||||
|
value[providedRegion]
|
||||||
|
|
||||||
|
// return if provided subregion is not a string or an object
|
||||||
|
if (
|
||||||
|
typeof providedSubRegion !== 'string' &&
|
||||||
|
!isObject(providedSubRegion)
|
||||||
|
) {
|
||||||
|
return returnCustomMessage([country, providedRegion], subRegions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if providedSubRegion is a string, check if it is in the list of supported subregions
|
||||||
|
if (
|
||||||
|
typeof providedSubRegion === 'string' &&
|
||||||
|
!subRegions.includes(providedSubRegion)
|
||||||
|
) {
|
||||||
|
return returnCustomMessage([country, providedRegion], subRegions)
|
||||||
|
}
|
||||||
|
// if providedSubRegion is an object, check if it is in the list of supported subregions
|
||||||
|
else if (isObject(providedSubRegion)) {
|
||||||
|
const providedSubRegions = Object.keys(providedSubRegion)
|
||||||
|
const providedSubRegionName: string = providedSubRegions[0]
|
||||||
|
|
||||||
|
// return if provided multiple subregions or if provided subregion is not in the supported list
|
||||||
|
if (
|
||||||
|
providedSubRegions.length !== 1 ||
|
||||||
|
!subRegions.includes(providedSubRegionName)
|
||||||
|
) {
|
||||||
|
return returnCustomMessage(
|
||||||
|
[country, providedRegion],
|
||||||
|
subRegions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Village
|
||||||
|
*/
|
||||||
|
// list of supported villages
|
||||||
|
const villages: string[] = Object.keys(
|
||||||
|
(
|
||||||
|
(regionMap as WineRegion)[providedRegion] as {
|
||||||
|
[key: string]: string | { [key: string]: string[] }
|
||||||
|
}
|
||||||
|
)[providedSubRegionName]
|
||||||
|
)
|
||||||
|
|
||||||
|
const providedVillage: string | { [key: string]: string } = (
|
||||||
|
value[providedRegion] as {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
||||||
|
)[providedSubRegionName]
|
||||||
|
|
||||||
|
// return if provided village is not a string or an object
|
||||||
|
if (
|
||||||
|
typeof providedVillage !== 'string' &&
|
||||||
|
!isObject(providedVillage)
|
||||||
|
) {
|
||||||
|
return returnCustomMessage(
|
||||||
|
[country, providedRegion, providedSubRegionName],
|
||||||
|
subRegions
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if village is a string, check if it is in the supported list
|
||||||
|
if (
|
||||||
|
typeof providedVillage === 'string' &&
|
||||||
|
!villages.includes(providedVillage)
|
||||||
|
) {
|
||||||
|
return returnCustomMessage(
|
||||||
|
[country, providedRegion, providedSubRegionName],
|
||||||
|
villages
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// if providedVillage is an object, check if it is in the supported list
|
||||||
|
else if (isObject(providedVillage)) {
|
||||||
|
const providedVillages = Object.keys(providedVillage)
|
||||||
|
|
||||||
|
const providedVillageName: string = providedVillages[0]
|
||||||
|
|
||||||
|
// return if provided multiple villages or if provided village is not in the supported list
|
||||||
|
if (
|
||||||
|
providedVillages.length !== 1 ||
|
||||||
|
!villages.includes(providedVillageName)
|
||||||
|
) {
|
||||||
|
return returnCustomMessage(
|
||||||
|
[country, providedRegion, providedSubRegionName],
|
||||||
|
villages
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wineyard
|
||||||
|
*/
|
||||||
|
// list of supported wineyards
|
||||||
|
const wineyards: string[] = (
|
||||||
|
(regionMap as WineRegion)[providedRegion] as {
|
||||||
|
[key: string]: { [key: string]: string[] }
|
||||||
|
}
|
||||||
|
)[providedSubRegionName][providedVillageName]
|
||||||
|
|
||||||
|
const providedWineyard: string = (
|
||||||
|
value[providedRegion] as {
|
||||||
|
[key: string]: {
|
||||||
|
[key: string]: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)[providedSubRegionName][providedVillageName]
|
||||||
|
|
||||||
|
// check if provided wineyard is in the supported list
|
||||||
|
if (!wineyards.includes(providedWineyard)) {
|
||||||
|
return returnCustomMessage(
|
||||||
|
[
|
||||||
|
country,
|
||||||
|
providedRegion,
|
||||||
|
providedSubRegionName,
|
||||||
|
providedVillageName
|
||||||
|
],
|
||||||
|
wineyards
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.allow('')
|
||||||
|
.required(),
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
producerId: Joi.string().length(24).required(),
|
producerId: Joi.string().length(24).required(),
|
||||||
varietal: Joi.string().required(),
|
varietal: Joi.string().required(),
|
||||||
vintage: Joi.alternatives()
|
vintage: Joi.alternatives()
|
||||||
.try(Joi.string().valid(...Object.values(VintageOptions)), Joi.number())
|
.try(Joi.string().valid(...Object.values(VintageOptions)), Joi.number())
|
||||||
.required(),
|
.required(),
|
||||||
|
volume: Joi.string()
|
||||||
|
.valid(...Object.values(WineVolume))
|
||||||
|
.required(),
|
||||||
alcohol: Joi.number().min(0).max(0.99).required(),
|
alcohol: Joi.number().min(0).max(0.99).required(),
|
||||||
viticulture: Joi.string()
|
viticulture: Joi.string()
|
||||||
.valid(...Object.values(Viticulture))
|
.valid(...Object.values(Viticulture))
|
||||||
.required(),
|
.required(),
|
||||||
sulfites: Joi.number().required(),
|
sulfites: Joi.number().min(0).max(400),
|
||||||
filtered: Joi.boolean().required(),
|
filtered: Joi.boolean().required(),
|
||||||
vegan: Joi.boolean().required(),
|
vegan: Joi.boolean().required(),
|
||||||
kosher: Joi.boolean().required(),
|
kosher: Joi.boolean().required(),
|
||||||
|
689
src/utils/wine.ts
Normal file
689
src/utils/wine.ts
Normal file
@ -0,0 +1,689 @@
|
|||||||
|
import { WineRegion } from '../types'
|
||||||
|
|
||||||
|
export const wineRegionsMap: { [key: string]: string[] | WineRegion } = {
|
||||||
|
IT: {
|
||||||
|
Piedmont: {
|
||||||
|
Langhe: {
|
||||||
|
Barolo: ['La Morra', 'Castiglione Falletto', `Serralunga d'Alba`],
|
||||||
|
Barbaresco: ['Neive', 'Alba', 'Treiso']
|
||||||
|
},
|
||||||
|
Monferrato: ['Gavi', 'Asti', 'Canelli']
|
||||||
|
},
|
||||||
|
Tuscany: [
|
||||||
|
'Chianti',
|
||||||
|
'Montalcino',
|
||||||
|
'Montepulciano',
|
||||||
|
'Scansano',
|
||||||
|
'Carmignano'
|
||||||
|
],
|
||||||
|
Veneto: ['Valpolicella', 'Soave'],
|
||||||
|
'Friuli-Venezia Giulia': [
|
||||||
|
'Collio',
|
||||||
|
'Colli Orientali del Friuli',
|
||||||
|
'Friuli Grave del Friuli'
|
||||||
|
],
|
||||||
|
'Trentino-Alto Adige': ['Trentino', 'Alto Adige'],
|
||||||
|
Lombardy: [],
|
||||||
|
Franciacorta: [],
|
||||||
|
Valtellina: [],
|
||||||
|
'Emilia-Romagna': ['Lambrusco'],
|
||||||
|
Umbria: ['Orvieto', 'Torgiano'],
|
||||||
|
Lazio: ['Frascati'],
|
||||||
|
Abruzzo: [],
|
||||||
|
Molise: ['Biferno', 'Pentro'],
|
||||||
|
Campania: ['Taurasi', 'Aglianico del Vulture', 'Fiano di Avellino'],
|
||||||
|
Puglia: ['Primitivo di Manduria', 'Salice Salentino'],
|
||||||
|
Basilicata: [],
|
||||||
|
Calabria: ['Cirò', 'Greco di Bianco'],
|
||||||
|
Sicily: ['Etna', 'Marsala', 'Pantelleria'],
|
||||||
|
Sardinia: ['Vermentino di Gallura', 'Cannonau di Sardegna']
|
||||||
|
},
|
||||||
|
FR: {
|
||||||
|
Alsace: [],
|
||||||
|
Ardeche: [],
|
||||||
|
Aquitaine: [],
|
||||||
|
Bordeaux: {
|
||||||
|
Médoc: ['Pauillac', 'Margaux', 'Saint-Estèphe', 'Saint-Julien'],
|
||||||
|
'Saint-Émilion': [],
|
||||||
|
Pomerol: [],
|
||||||
|
Graves: ['Pessac-Léognan'],
|
||||||
|
Sauternes: ['Barsac']
|
||||||
|
},
|
||||||
|
Burgundy: {
|
||||||
|
Chablis: [],
|
||||||
|
'Côte de Nuits': [
|
||||||
|
'Gevrey-Chambertin',
|
||||||
|
'Vosne-Romanée',
|
||||||
|
'Nuits-Saint-Georges'
|
||||||
|
],
|
||||||
|
'Côte de Beaune': ['Meursault', 'Puligny-Montrachet', 'Beaune'],
|
||||||
|
'Côte Chalonnaise': ['Mercurey'],
|
||||||
|
Mâconnais: ['Pouilly-Fuissé'],
|
||||||
|
Beaujolais: ['Morgon', 'Fleurie', 'Moulin a Vent']
|
||||||
|
},
|
||||||
|
Champagne: ['Montagne de Reims', 'Vallée de la Marne', 'Côte des Blancs'],
|
||||||
|
'Loire Valley': [
|
||||||
|
'Sancerre',
|
||||||
|
'Pouilly-Fumé',
|
||||||
|
'Vouvray',
|
||||||
|
'Muscadet',
|
||||||
|
'Anjou',
|
||||||
|
'Saumur',
|
||||||
|
'Chinon'
|
||||||
|
],
|
||||||
|
'Rhône Valley': [
|
||||||
|
'Côte-Rôtie',
|
||||||
|
'Hermitage',
|
||||||
|
'Condrieu',
|
||||||
|
'Saint-Joseph',
|
||||||
|
'Châteauneuf-du-Pape',
|
||||||
|
'Côtes du Rhône',
|
||||||
|
'Gigondas',
|
||||||
|
'Vacqueyras'
|
||||||
|
],
|
||||||
|
Provence: ['Côtes de Provence', 'Bandol'],
|
||||||
|
'Languedoc-Roussillon': [],
|
||||||
|
'Southwest France': ['Cahors', 'Madiran', 'Jurançon'],
|
||||||
|
Jura: ['Arbois', 'Côtes du Jura'],
|
||||||
|
Savoie: [],
|
||||||
|
Corsica: ['Patrimonio']
|
||||||
|
},
|
||||||
|
DE: {
|
||||||
|
Mosel: ['Saar', 'Ruwer'],
|
||||||
|
Pfalz: [],
|
||||||
|
Rheinhessen: [],
|
||||||
|
Nahe: [],
|
||||||
|
Rheingau: [],
|
||||||
|
'Hessische Bergstraße': [],
|
||||||
|
Franken: [],
|
||||||
|
Baden: [],
|
||||||
|
Württemberg: [],
|
||||||
|
'Saale-Unstrut': [],
|
||||||
|
Sachsen: [],
|
||||||
|
Ahr: []
|
||||||
|
},
|
||||||
|
CH: {
|
||||||
|
Vaud: ['Lavaux', 'Vevey', 'Morges', 'Nyon'],
|
||||||
|
Valais: ['Sierre', 'Sion', 'Martigny'],
|
||||||
|
Geneva: ['Lancy', 'Carouge'],
|
||||||
|
Ticino: ['Locarno', 'Bellinzona', 'Ascona'],
|
||||||
|
Neuchâtel: ['Val-de-Travers', 'Val-de-Ruz'],
|
||||||
|
Fribourg: ['Glâne', 'Sarine'],
|
||||||
|
Bern: ['Thun', 'Biel'],
|
||||||
|
Aargau: ['Baden', 'Brugg'],
|
||||||
|
Thurgau: ['Frauenfeld', 'Arbon'],
|
||||||
|
Zürich: ['Affoltern', 'Dietikon']
|
||||||
|
},
|
||||||
|
ES: {
|
||||||
|
Rioja: ['Rioja Alta', 'Rioja Alavesa', 'Rioja Oriental'],
|
||||||
|
Navarra: [],
|
||||||
|
'Rías Baixas': [],
|
||||||
|
'Ribeira Sacra': [],
|
||||||
|
Valdeorras: [],
|
||||||
|
Txakoli: ['Getariako Txakolina', 'Bizkaiko Txakolina', 'Arabako Txakolina'],
|
||||||
|
'Ribera del Duero': [],
|
||||||
|
Rueda: [],
|
||||||
|
Toro: [],
|
||||||
|
Cigales: [],
|
||||||
|
'La Mancha': [],
|
||||||
|
Valdepeñas: [],
|
||||||
|
Priorat: [],
|
||||||
|
Penedès: [],
|
||||||
|
Cava: [],
|
||||||
|
Montsant: [],
|
||||||
|
'Conca de Barberà': [],
|
||||||
|
'Jerez-Xérès': [],
|
||||||
|
'Montilla-Moriles': [],
|
||||||
|
Málaga: [],
|
||||||
|
'Sierras de Málaga': [],
|
||||||
|
'Condado de Huelva': [],
|
||||||
|
'Utiel-Requena': [],
|
||||||
|
Valencia: [],
|
||||||
|
Jumilla: [],
|
||||||
|
Yecla: [],
|
||||||
|
Bullas: [],
|
||||||
|
'Canary Islands': [],
|
||||||
|
'Balearic Islands': ['Binissalem', 'Pla i Llevant'],
|
||||||
|
Bierzo: [],
|
||||||
|
'Campo de Borja': [],
|
||||||
|
Aragón: ['Calatayud', 'Somontano'],
|
||||||
|
'Ribera del Guadiana': []
|
||||||
|
},
|
||||||
|
PT: {
|
||||||
|
Douro: ['Baixo Corgo', 'Cima Corgo', 'Douro Superior'],
|
||||||
|
Alentejo: ['Central', 'Litoral', 'Interior Norte', 'Interior Sul'],
|
||||||
|
Porto: ['Gaia'],
|
||||||
|
'Vinho Verde': [
|
||||||
|
'Amarante',
|
||||||
|
'Ave',
|
||||||
|
'Baião',
|
||||||
|
'Basto',
|
||||||
|
'Cávado',
|
||||||
|
'Lima',
|
||||||
|
'Lima Interior',
|
||||||
|
'Lima Litoral',
|
||||||
|
'Monção',
|
||||||
|
'Paiva',
|
||||||
|
'Sousa'
|
||||||
|
],
|
||||||
|
Tejo: [
|
||||||
|
'Alcobaça',
|
||||||
|
'Arruda dos Vinhos',
|
||||||
|
'Azeiteira',
|
||||||
|
'Benavente e Santarém',
|
||||||
|
'Bico do Cachorro',
|
||||||
|
'Borba',
|
||||||
|
'Casaínhos',
|
||||||
|
'Chamusca',
|
||||||
|
'Colares',
|
||||||
|
'Coruche',
|
||||||
|
'Fátima',
|
||||||
|
'Figueira da Foz',
|
||||||
|
'Golegã',
|
||||||
|
'Gualtar',
|
||||||
|
'Gândara',
|
||||||
|
'Mação',
|
||||||
|
'Mafra',
|
||||||
|
'Montemor-o-Novo',
|
||||||
|
'Montijo',
|
||||||
|
'Odivelas',
|
||||||
|
'Palmela',
|
||||||
|
'Pataias',
|
||||||
|
'Peniche',
|
||||||
|
'Porto de Mós',
|
||||||
|
'Reguengos de Monsaraz',
|
||||||
|
'Ribatejo',
|
||||||
|
'Sabugal',
|
||||||
|
'Setúbal',
|
||||||
|
'Tomar',
|
||||||
|
'Torres Vedras',
|
||||||
|
'Vila Franca de Xira'
|
||||||
|
],
|
||||||
|
Lisbon: [
|
||||||
|
'Alenquer',
|
||||||
|
'Arruda',
|
||||||
|
'Carcavelos e Cascais',
|
||||||
|
'Colares',
|
||||||
|
'Encoro',
|
||||||
|
'Estremoz',
|
||||||
|
'Oeiras',
|
||||||
|
'Palmela',
|
||||||
|
'Setúbal'
|
||||||
|
],
|
||||||
|
Madeira: [
|
||||||
|
'Machico',
|
||||||
|
'Santa Cruz',
|
||||||
|
'Caniço',
|
||||||
|
'Santo António da Serra',
|
||||||
|
'Ponta do Sol',
|
||||||
|
'Calheta',
|
||||||
|
'Funchal',
|
||||||
|
'Câmara de Lobos',
|
||||||
|
'Ribeira Brava',
|
||||||
|
'Paul do Mar',
|
||||||
|
'Canhas',
|
||||||
|
'Arco da Calheta',
|
||||||
|
'São Vicente',
|
||||||
|
'Porto Moniz',
|
||||||
|
'Paul da Serra'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
AT: {
|
||||||
|
Wagram: ['Marchfeld'],
|
||||||
|
Kremstal: ['Krems', 'Spitz'],
|
||||||
|
Kamptal: ['Langenlois', 'Gumpoldskirchen'],
|
||||||
|
Wachau: [],
|
||||||
|
Thermenregion: ['Baden', 'Mödling'],
|
||||||
|
Wienerwald: [],
|
||||||
|
Südsteiermark: ['Grazer Bergland', 'Leibnitz', 'Deutschlandsberg'],
|
||||||
|
Burgenland: ['Neusiedlersee', 'Eisenberg', 'Rosalia'],
|
||||||
|
Styria: ['Südsteiermark', 'Weststeiermark'],
|
||||||
|
Salzburg: ['Flachgau'],
|
||||||
|
Tyrol: ['Innsbruck', 'Hall'],
|
||||||
|
Carinthia: ['Villach', 'Klagenfurt']
|
||||||
|
},
|
||||||
|
HU: {
|
||||||
|
Tokaj: [],
|
||||||
|
Eger: [],
|
||||||
|
Badacsony: [],
|
||||||
|
Balaton: [
|
||||||
|
'Balatonalmádi',
|
||||||
|
'Balatonboglár',
|
||||||
|
'Balatonfüred-Csopak',
|
||||||
|
'Balatonlelle',
|
||||||
|
'Balatonfüred',
|
||||||
|
'Somló'
|
||||||
|
],
|
||||||
|
Mátra: [],
|
||||||
|
Hegyalja: [],
|
||||||
|
Pannon: ['Szekszárd', 'Pécs', 'Baja', 'Sopron'],
|
||||||
|
Villány: []
|
||||||
|
},
|
||||||
|
CZ: {
|
||||||
|
'South Moravia': ['Znojmo', 'Břeclav', 'Hodonín', 'Kyjov', 'Vranov'],
|
||||||
|
'Zlín Region': ['Valašské Meziříčí', 'Kroměříž', 'Vsetín'],
|
||||||
|
'Olomouc Region': ['Prostějov', 'Olomouc', 'Litomyšl'],
|
||||||
|
'South Bohemia': ['České Budějovice', 'Písek', 'Strakonice'],
|
||||||
|
Plzeň: ['Rokycany', 'Domažlice']
|
||||||
|
},
|
||||||
|
MD: ['Iași', 'Botoșani', 'Vaslui', 'Neamț'],
|
||||||
|
RO: {
|
||||||
|
Transylvania: ['Cluj', 'Sibiu', 'Brașov', 'Mureș'],
|
||||||
|
Muntenia: ['Buzău', 'Dâmbovița', 'Prahova', 'Vrancea'],
|
||||||
|
Oltenia: ['Dolj', 'Gorj', 'Vâlcea', 'Mehedinți'],
|
||||||
|
Banat: ['Arad', 'Timiș', 'Caraș-Severin'],
|
||||||
|
Dobrogea: ['Constanța', 'Tulcea'],
|
||||||
|
Crisana: ['Bihor'],
|
||||||
|
Maramureș: ['Suceava', 'Maramureș']
|
||||||
|
},
|
||||||
|
GR: {
|
||||||
|
Attica: [],
|
||||||
|
'Central Greece': [
|
||||||
|
'Euboea',
|
||||||
|
'Boeotia',
|
||||||
|
'Phocis',
|
||||||
|
'Locris',
|
||||||
|
'Phthiotis',
|
||||||
|
'Phocis',
|
||||||
|
'Locris',
|
||||||
|
'Phthiotis'
|
||||||
|
],
|
||||||
|
Peloponnese: [
|
||||||
|
'Nemea',
|
||||||
|
'Mantineia',
|
||||||
|
'Achaia',
|
||||||
|
'Messenia',
|
||||||
|
'Laconia',
|
||||||
|
'Arcadia',
|
||||||
|
'Argolis',
|
||||||
|
'Corinthia'
|
||||||
|
],
|
||||||
|
Thrace: [],
|
||||||
|
Macedonia: [
|
||||||
|
'Thessaloniki',
|
||||||
|
'Kilkis',
|
||||||
|
'Pella',
|
||||||
|
'Florina',
|
||||||
|
'Kastoria',
|
||||||
|
'Imathia',
|
||||||
|
'Pella',
|
||||||
|
'Florina',
|
||||||
|
'Kastoria'
|
||||||
|
],
|
||||||
|
Thessaly: ['Trikala', 'Larissa', 'Magnesia', 'Karditsa', 'Trikala'],
|
||||||
|
'Ionian Islands': [
|
||||||
|
'Corfu',
|
||||||
|
'Zakynthos',
|
||||||
|
'Kefalonia',
|
||||||
|
'Lefkada',
|
||||||
|
'Ithaca',
|
||||||
|
'Paxos',
|
||||||
|
'Corfu',
|
||||||
|
'Zakynthos',
|
||||||
|
'Kefalonia',
|
||||||
|
'Lefkada',
|
||||||
|
'Ithaca',
|
||||||
|
'Paxos'
|
||||||
|
],
|
||||||
|
Cyclades: [
|
||||||
|
'Santorini',
|
||||||
|
'Paros',
|
||||||
|
'Naxos',
|
||||||
|
'Mykonos',
|
||||||
|
'Sifnos',
|
||||||
|
'Tinos',
|
||||||
|
'Santorini',
|
||||||
|
'Paros',
|
||||||
|
'Naxos',
|
||||||
|
'Mykonos',
|
||||||
|
'Sifnos',
|
||||||
|
'Tinos'
|
||||||
|
],
|
||||||
|
Crete: [],
|
||||||
|
'Aegean Islands': [
|
||||||
|
'Samos',
|
||||||
|
'Lesbos',
|
||||||
|
'Chios',
|
||||||
|
'Limnos',
|
||||||
|
'Ikaria',
|
||||||
|
'Samos',
|
||||||
|
'Lesbos',
|
||||||
|
'Chios',
|
||||||
|
'Limnos',
|
||||||
|
'Ikaria'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
HR: {
|
||||||
|
Dalmatia: ['Hvar', 'Brac', 'Korcula', 'Peljesac', 'Dubrovnik-Riviera'],
|
||||||
|
Istria: [],
|
||||||
|
Slavonia: [],
|
||||||
|
Kvarner: ['Kvarner Bay', 'Labin'],
|
||||||
|
'Continental Croatia': ['Srijem', 'Moslavina', 'Podravina'],
|
||||||
|
'Central Croatia': ['Zagorje', 'Medgurje', 'Bilogora']
|
||||||
|
},
|
||||||
|
GE: {
|
||||||
|
Kakheti: ['Telavi', 'Sighnaghi', 'Akhasheni', 'Kvareli'],
|
||||||
|
Imereti: ['Kutaisi', 'Khoni', 'Tsqaltubo', 'Sachkhere'],
|
||||||
|
'Racha-Lechkhumi': [],
|
||||||
|
'Kvemo Svaneti': [],
|
||||||
|
Kartli: ['Tbilisi', 'Gori', 'Kaspi', 'Rustavi'],
|
||||||
|
Adjara: ['Batumi', 'Kobuleti'],
|
||||||
|
'Samegrelo-Zemo Svaneti': ['Poti', 'Zugdidi'],
|
||||||
|
Abkhazia: ['Gagra', 'Gudauta', 'Ochamchire'],
|
||||||
|
'South Georgia': ['Adigeni', 'Akhalkalaki', 'Bolnisi', 'Ninotsminda']
|
||||||
|
},
|
||||||
|
IL: {
|
||||||
|
Galilee: ['Golan Heights', 'Carmel Mountains'],
|
||||||
|
'Central District': ['Shomron', 'Shfela'],
|
||||||
|
Negev: ['Southern Negev', 'Central Negev'],
|
||||||
|
'Coastal Plain': ['Central Coastal Plain', 'Southern Coastal Plain']
|
||||||
|
},
|
||||||
|
LB: ['Bekaa Valley', 'Mount Lebanon', 'North Lebanon', 'South Lebanon'],
|
||||||
|
TR: {
|
||||||
|
Anatolia: [
|
||||||
|
'Konya',
|
||||||
|
'Aksaray',
|
||||||
|
'Nevşehir',
|
||||||
|
'Erzurum',
|
||||||
|
'Van',
|
||||||
|
'Bitlis',
|
||||||
|
'İzmir',
|
||||||
|
'Manisa',
|
||||||
|
'Ayvalık'
|
||||||
|
],
|
||||||
|
'Aegean Region': ['Urla', 'Foça', 'Bornova'],
|
||||||
|
Ayvalık: [],
|
||||||
|
'Marmara Region': ['İstanbul', 'Edirne'],
|
||||||
|
'Black Sea Region': ['Rize', 'Artvin', 'Trabzon'],
|
||||||
|
'Southeastern Anatolia': ['Gaziantep', 'Şanlıurfa', 'Adana']
|
||||||
|
},
|
||||||
|
AM: ['Vayots Dzor', 'Ararat Valley', 'Gegharkunik', 'Tavush', 'Syunik'],
|
||||||
|
CA: {
|
||||||
|
Ontario: [
|
||||||
|
'Niagara Peninsula',
|
||||||
|
'Lake Erie North Shore',
|
||||||
|
'Pelee Island',
|
||||||
|
'Prince Edward County'
|
||||||
|
],
|
||||||
|
'British Columbia': [
|
||||||
|
'Okanagan Valley',
|
||||||
|
'Similkameen Valley',
|
||||||
|
'Fraser Valley',
|
||||||
|
'Southern Gulf Islands'
|
||||||
|
],
|
||||||
|
Quebec: ['Montreal', 'Eastern Townships', 'Charlevoix'],
|
||||||
|
'Nova Scotia': ['Annapolis Valley', 'Gaspereau Valley', 'North Shore'],
|
||||||
|
'New Brunswick': ['Annapolis Valley', 'Gaspereau Valley'],
|
||||||
|
'Prince Edward Island': ['Eastern PEI', 'Western PEI']
|
||||||
|
},
|
||||||
|
US: {
|
||||||
|
California: [
|
||||||
|
'Napa Valley',
|
||||||
|
'Sonoma Valley',
|
||||||
|
'Paso Robles',
|
||||||
|
'Santa Barbara County',
|
||||||
|
'Central Coast',
|
||||||
|
'Lodi',
|
||||||
|
'Mendocino County',
|
||||||
|
'Santa Cruz Mountains',
|
||||||
|
'Russian River Valley'
|
||||||
|
],
|
||||||
|
Oregon: [
|
||||||
|
'Willamette Valley',
|
||||||
|
'Rogue Valley',
|
||||||
|
'Umpqua Valley',
|
||||||
|
'Southern Oregon',
|
||||||
|
'Oregon Coast'
|
||||||
|
],
|
||||||
|
Washington: [
|
||||||
|
'Columbia Valley',
|
||||||
|
'Walla Walla Valley',
|
||||||
|
'Red Mountain',
|
||||||
|
'Snake River'
|
||||||
|
],
|
||||||
|
'New York': [
|
||||||
|
'Finger Lakes',
|
||||||
|
'Long Island',
|
||||||
|
'Hudson River',
|
||||||
|
'Western New York'
|
||||||
|
],
|
||||||
|
Virginia: [
|
||||||
|
'Monticello',
|
||||||
|
'Shenandoah Valley',
|
||||||
|
'Northern Virginia',
|
||||||
|
'Virginia Piedmont'
|
||||||
|
],
|
||||||
|
'Texas Hill Country': [],
|
||||||
|
'Arizona Sonoita': [],
|
||||||
|
'Colorado Grand Valley': [],
|
||||||
|
'Idaho Snake River Valley': [],
|
||||||
|
Michigan: ['Michigan Lake', 'Michigan Shore']
|
||||||
|
},
|
||||||
|
AR: {
|
||||||
|
Mendoza: ['Luján de Cuyo', 'Uco Valley', 'Maipú', 'San Rafael'],
|
||||||
|
Salta: ['Calchaquí Valleys', 'Quebrada de Humahuaca'],
|
||||||
|
'San Juan': ['Ullum', 'Calingasta', 'Tulum'],
|
||||||
|
'La Rioja': [],
|
||||||
|
Catamarca: ['Andalgalá', 'Belén'],
|
||||||
|
'San Luis': [
|
||||||
|
'Valle del Conlara',
|
||||||
|
'Valle del Potrerillos',
|
||||||
|
'Valle de las Carreras'
|
||||||
|
],
|
||||||
|
'Buenos Aires': [
|
||||||
|
'Partido de General Belgrano',
|
||||||
|
'Partido de Lobos',
|
||||||
|
'Partido de Tandil'
|
||||||
|
],
|
||||||
|
Neuquén: ['Valle de Río Negro', 'Valle de Agrelo']
|
||||||
|
},
|
||||||
|
CL: {
|
||||||
|
'Central Valley': [
|
||||||
|
'Maipo Valley',
|
||||||
|
'Casablanca Valley',
|
||||||
|
'San Antonio Valley',
|
||||||
|
'Maule Valley',
|
||||||
|
'Colchagua Valley'
|
||||||
|
],
|
||||||
|
'Coastal Regions': [
|
||||||
|
'Valle de Aconcagua',
|
||||||
|
'Valle de Limarí',
|
||||||
|
'Valle de Elqui'
|
||||||
|
],
|
||||||
|
'Southern Chile': ['Valle de Itata', 'Valle de Bío-Bío'],
|
||||||
|
'Northern Chile': ['Valle de Elqui']
|
||||||
|
},
|
||||||
|
ZA: {
|
||||||
|
'Western Cape': {
|
||||||
|
Stellenbosch: [
|
||||||
|
'Simonsberg-Stellenbosch',
|
||||||
|
'Jonkershoek-Stellenbosch',
|
||||||
|
'Stellenbosch Mountain'
|
||||||
|
],
|
||||||
|
Paarl: ['Franschhoek', 'Paarl Mountain'],
|
||||||
|
Constantia: ['Constantia Valley'],
|
||||||
|
Durbanville: ['Durbanville Hills'],
|
||||||
|
'Walker Bay': ['Hemel-en-Aarde'],
|
||||||
|
Swartland: ['Paardeberg']
|
||||||
|
},
|
||||||
|
'Eastern Cape': ['Jeffreys Bay'],
|
||||||
|
'Northern Cape': ['Augrabies']
|
||||||
|
},
|
||||||
|
AU: {
|
||||||
|
'South Eastern Australia': [],
|
||||||
|
'New South Wales': [
|
||||||
|
'Hunter Valley',
|
||||||
|
'Riverina',
|
||||||
|
'Mudgee',
|
||||||
|
'Orange',
|
||||||
|
'Cowra',
|
||||||
|
'Hilltops',
|
||||||
|
'Tumbarumba',
|
||||||
|
'Gundagai',
|
||||||
|
'Shoalhaven Coast',
|
||||||
|
'Southern Highlands',
|
||||||
|
'New England'
|
||||||
|
],
|
||||||
|
'South Australia': [
|
||||||
|
'Barossa Valley',
|
||||||
|
'McLaren Vale',
|
||||||
|
'Clare Valley',
|
||||||
|
'Coonawarra',
|
||||||
|
'Adelaide Hills',
|
||||||
|
'Eden Valley',
|
||||||
|
'Langhorne Creek',
|
||||||
|
'Padthaway',
|
||||||
|
'Kangaroo Island',
|
||||||
|
'Mount Gambier',
|
||||||
|
'Robe',
|
||||||
|
'Wrattonbully',
|
||||||
|
'Fleurieu Peninsula',
|
||||||
|
'Currency Creek',
|
||||||
|
'Southern Fleurieu'
|
||||||
|
],
|
||||||
|
Victoria: [
|
||||||
|
'Yarra Valley',
|
||||||
|
'Mornington Peninsula',
|
||||||
|
'Geelong',
|
||||||
|
'Bellarine Peninsula',
|
||||||
|
'Sunbury',
|
||||||
|
'Macedon Ranges',
|
||||||
|
'Heathcote',
|
||||||
|
'Bendigo',
|
||||||
|
'Pyrenees',
|
||||||
|
'Grampians',
|
||||||
|
'Great Western',
|
||||||
|
'Henty',
|
||||||
|
'Otway Ranges',
|
||||||
|
'King Valley',
|
||||||
|
'Alpine Valleys',
|
||||||
|
'Rutherglen',
|
||||||
|
'Glenrowan',
|
||||||
|
'Goulburn Valley',
|
||||||
|
'Strathbogie Ranges'
|
||||||
|
],
|
||||||
|
'Western Australia': [
|
||||||
|
'Margaret River',
|
||||||
|
'Great Southern',
|
||||||
|
'Swan Valley',
|
||||||
|
'Pemberton',
|
||||||
|
'Manjimup',
|
||||||
|
'Blackwood Valley',
|
||||||
|
'Geographe',
|
||||||
|
'Peel',
|
||||||
|
'Perth Hills',
|
||||||
|
'Frankland River',
|
||||||
|
'Mount Barker',
|
||||||
|
'Porongurup',
|
||||||
|
'Denmark',
|
||||||
|
'Albany',
|
||||||
|
'Esperance'
|
||||||
|
],
|
||||||
|
Tasmania: [
|
||||||
|
'Tamar Valley',
|
||||||
|
'Pipers River',
|
||||||
|
'East Coast',
|
||||||
|
'Coal Valley',
|
||||||
|
'Derwent Valley',
|
||||||
|
'Huon Valley'
|
||||||
|
],
|
||||||
|
Queensland: [
|
||||||
|
'Granite Belt',
|
||||||
|
'South Burnett',
|
||||||
|
'Darling Downs',
|
||||||
|
'Scenic Rim'
|
||||||
|
],
|
||||||
|
'Canberra District': [
|
||||||
|
'Canberra',
|
||||||
|
'Murrumbateman',
|
||||||
|
'Yass Valley',
|
||||||
|
'Gundaroo',
|
||||||
|
'Lake George'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
NZ: {
|
||||||
|
'North Island': [
|
||||||
|
'Auckland',
|
||||||
|
'Gisborne',
|
||||||
|
`Hawke's Bay`,
|
||||||
|
'Wairarapa',
|
||||||
|
'Bay of Islands',
|
||||||
|
'Coromandel',
|
||||||
|
'Waikato'
|
||||||
|
],
|
||||||
|
'South Island': [
|
||||||
|
'Marlborough',
|
||||||
|
'Nelson',
|
||||||
|
'Waipara',
|
||||||
|
'Canterbury',
|
||||||
|
'Central Otago',
|
||||||
|
'Waipara Valley',
|
||||||
|
'North Canterbury',
|
||||||
|
'North Otago'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
CN: {
|
||||||
|
Ningxia: {
|
||||||
|
Yinchuan: [],
|
||||||
|
'Helan Mountain': ['Qingtongxia', 'Wucaiwan', 'Qingshuihe', 'Jinfeng']
|
||||||
|
},
|
||||||
|
Shaanxi: ['Lishan', 'Fengxiang'],
|
||||||
|
Shandong: ['Yantai', 'Penglai', 'Weihai'],
|
||||||
|
Xinjiang: ['Turpan', 'Yili', 'Jinghe'],
|
||||||
|
Hebei: ['Changli', 'Qinhuangdao'],
|
||||||
|
Heilongjiang: ['Yichun', 'Qiqihar'],
|
||||||
|
Jilin: ['Baishan', 'Changchun'],
|
||||||
|
Liaoning: ['Dalian', 'Shenyang'],
|
||||||
|
'Inner Mongolia': ['Hohhot', 'Baotou'],
|
||||||
|
Guangxi: ['Nanning', 'Liuzhou'],
|
||||||
|
Hunan: ['Changsha', 'Yongzhou'],
|
||||||
|
Hubei: ['Wuhan'],
|
||||||
|
Sichuan: ['Chengdu', `Ya'an`],
|
||||||
|
Guizhou: ['Guiyang', 'Zunyi'],
|
||||||
|
Yunnan: ['Kunming', 'Dali']
|
||||||
|
},
|
||||||
|
JP: {
|
||||||
|
'Yamanashi Prefecture': ['Kofu Basin', 'Katsunuma', 'Fuefuki'],
|
||||||
|
'Hokkaido Prefecture': ['Biei', 'Tomakomai', 'Nanae'],
|
||||||
|
'Niigata Prefecture': ['Uonuma', 'Sannosawa'],
|
||||||
|
'Nagano Prefecture': ['Kiso Valley', 'Nagano'],
|
||||||
|
'Gifu Prefecture': ['Gujo', 'Mino'],
|
||||||
|
'Aichi Prefecture': ['Nishio', 'Seto'],
|
||||||
|
'Shizuoka Prefecture': ['Suruga', 'Shizuoka'],
|
||||||
|
'Kanagawa Prefecture': ['Yokohama', 'Kawasaki'],
|
||||||
|
'Chiba Prefecture': ['Noda', 'Chiba'],
|
||||||
|
'Ibaraki Prefecture': ['Tsukuba', 'Hitachi'],
|
||||||
|
'Tochigi Prefecture': ['Utsunomiya', 'Tochigi'],
|
||||||
|
'Gunma Prefecture': ['Maebashi', 'Gunma']
|
||||||
|
},
|
||||||
|
UK: {
|
||||||
|
Kent: ['Ashford', 'Canterbury', 'Dover', 'Maidstone', 'Sevenoaks'],
|
||||||
|
Sussex: ['Brighton', 'Eastbourne', 'Hastings', 'Chichester', 'Horsham'],
|
||||||
|
Hampshire: ['Winchester', 'Petersfield', 'Basingstoke', 'Andover'],
|
||||||
|
Wiltshire: ['Swindon', 'Chippenham', 'Salisbury', 'Trowbridge'],
|
||||||
|
Dorset: ['Poole', 'Bournemouth', 'Dorset'],
|
||||||
|
Devon: ['Exeter', 'Newton Abbot', 'Plymouth', 'Torquay'],
|
||||||
|
Somerset: ['Bath', 'Weston-super-Mare', 'Taunton', 'Yeovil'],
|
||||||
|
Gloucestershire: ['Cheltenham', 'Gloucester', 'Cirencester', 'Stroud'],
|
||||||
|
Worcestershire: ['Worcester', 'Malvern', 'Kidderminster', 'Bewdley'],
|
||||||
|
Warwickshire: [
|
||||||
|
'Warwick',
|
||||||
|
'Stratford-upon-Avon',
|
||||||
|
'Leamington Spa',
|
||||||
|
'Kenilworth'
|
||||||
|
],
|
||||||
|
Herefordshire: ['Hereford', 'Leominster', 'Ross-on-Wye', 'Kington'],
|
||||||
|
Shropshire: ['Shrewsbury', 'Telford', 'Ludlow', 'Oswestry']
|
||||||
|
},
|
||||||
|
UY: {
|
||||||
|
'Canelones Department': ['San Carlos', 'Melo', 'Paso de los Toros'],
|
||||||
|
'Montevideo Department': ['Carrasco', 'Punta del Este'],
|
||||||
|
'Colonia Department': ['Colonia del Sacramento', 'Villa Soriano'],
|
||||||
|
'San José Department': ['Progreso', 'Treinta y Tres'],
|
||||||
|
'Rocha Department': ['La Paloma', 'Rocha Sur'],
|
||||||
|
'Florida Department': ['Florida', 'Sarandí del Yí'],
|
||||||
|
'Soriano Department': ['Soriano', 'Río Negro'],
|
||||||
|
'Tacuarembó Department': ['Tacuarembó', 'Paso de los Toros'],
|
||||||
|
'Treinta y Tres Department': ['Treinta y Tres', 'Rivera']
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user