diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..43e8ab1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.dockerignore +.env +.git +.gitignore +.vs +.vscode +docker-compose.yml +docker-compose.*.yml +*/bin +*/obj diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..df9f5ed --- /dev/null +++ b/.env.example @@ -0,0 +1,13 @@ +PG_CONNECTION= +XMLDIR= +IMG_URL= +DOC_URL= +S3_BUCKET_ACCESSPOINT= +S3_IMAGEUPLOADER_ACCESSKEY= +S3_IMAGEUPLOADER_SECRETKEY= +OAUTH_AUTORITY= +ELK_URL= +ELK_TOKEN= +JSONPATH= +DATABROWSER_URL= +API_URL= diff --git a/.github/workflows/main_api.yml b/.github/workflows/main_api.yml new file mode 100644 index 0000000..e055ed4 --- /dev/null +++ b/.github/workflows/main_api.yml @@ -0,0 +1,89 @@ +name: CI/CD API + +on: + push: + pull_request: + +env: + PROJECT_NAME: odh-content-api + DOCKER_IMAGE: ghcr.io/${{ github.repository }}/${{ github.event.repository.name }}-api + DOCKER_TAG: ${{ github.sha }} + +jobs: + test: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: REUSE Compliance Check + uses: fsfe/reuse-action@v1 + - name: Setup .NET + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '8.0.x' + dotnet-quality: 'preview' + - name: Restore dependencies + run: dotnet restore ContentApiCore.sln + - name: Build ContentApiCore Solution + run: dotnet build ContentApiCore.sln --no-restore + - name: Test + run: dotnet test ContentApiCore --filter Category!=Integration + + # deploy-test-api: + # runs-on: ubuntu-20.04 + # if: github.ref == 'refs/heads/main' + # env: + # API_URL: "https://api.tourism.testingmachine.eu/v1/" + # needs: test + # concurrency: deploy-test-api + # steps: + # - name: Checkout source code + # uses: actions/checkout@v2 + # with: + # submodules: true + + # - name: Create .env file + # uses: noi-techpark/github-actions/env-file@v2 + # env: + # X_COMPOSE_PROJECT_NAME: ${{ env.PROJECT_NAME }} + # X_DOCKER_IMAGE: ${{ env.DOCKER_IMAGE }} + # X_DOCKER_TAG: ${{ env.DOCKER_TAG }} + # X_SERVER_PORT: 1011 + + # X_ASPNETCORE_ENVIRONMENT: "Development" + # X_PG_CONNECTION: ${{ secrets.PG_CONNECTION_TEST }} + + # - name: Setup config + # run: | + # echo "${{ secrets.GOOGLE_SERVICE_ACCOUNT_NOICOMMUNITY }}" > google-service-account.noicommunity.json + # chmod +r google-service-account.noicommunity.json + + # - name: Build and push + # uses: noi-techpark/github-actions/docker-build-and-push@v2 + # with: + # docker-username: ${{ github.actor }} + # docker-password: ${{ secrets.GITHUB_TOKEN }} + # working-directory: OdhApiCore + # docker-compose-file: docker-compose.yml + + # - name: Deploy application + # uses: noi-techpark/github-actions/docker-deploy@v2 + # with: + # hosts: 'test' + # ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + # docker-username: 'noi-techpark-bot' + # docker-password: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} + # project-name: ${{ env.PROJECT_NAME }} + + # - name: Generate Json + # run: | + # curl "${{ env.API_URL }}STA/JsonPoi" + # curl "${{ env.API_URL }}STA/JsonAccommodation" + # curl "${{ env.API_URL }}ODH/AccommodationBooklist" + # curl "${{ env.API_URL }}ODH/AccommodationFulllist" + # curl "${{ env.API_URL }}ODH/Taglist" + # curl "${{ env.API_URL }}ODH/OdhTagAutoPublishlist" + # curl "${{ env.API_URL }}ODH/OdhTagCategorieslist" + # curl "${{ env.API_URL }}ODH/WeatherForecast" \ No newline at end of file diff --git a/.github/workflows/reuse.yml b/.github/workflows/reuse.yml new file mode 100644 index 0000000..2018cb2 --- /dev/null +++ b/.github/workflows/reuse.yml @@ -0,0 +1,12 @@ +name: REUSE Compliance Check + +on: push + +jobs: + test: + runs-on: ubuntu-20.04 + steps: + - name: Checkout source code + uses: actions/checkout@v2 + - name: REUSE Compliance Check + uses: fsfe/reuse-action@v1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e78ba9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,182 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +[Bb]in/ +[Oo]bj/ +-vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml + +# NuGet Packages Directory +## TODO: If you have NuGet Package Restore enabled, uncomment the next line +packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + + +#LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store +/.paket +/.vs +/OdhApiCore/docker/postgres/dumps + +# Docker +/.env +/.vscode + +.fake +.ionide + +/OdhApiCore/STAAccommodations_de.json +/OdhApiCore/STAAccommodations_en.json +/OdhApiCore/STAAccommodations_it.json +/OdhApiCore/STAOdhActivitiesPois_de.json +/OdhApiCore/STAOdhActivitiesPois_en.json +/OdhApiCore/STAOdhActivitiesPois_it.json +/OdhApiCore/AccosAll.json +/OdhApiCore/AccosBookable.json +/OdhApiCore/GenericTags.json +/OdhApiCore/wwwroot/json/swagger.json +/OdhApiCore/wwwroot/json +/OdhApiCore/.env +/OdhApiImporter/.env +/OdhApiImporter/json/SMOS_MCPL-WX_EXP_SIAG.JSON +/PushServer/files/noi-community-firebase-adminsdk-qv1b9-5c488d5e06.json +/google-service-account.noicommunity.json diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0b77528 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "sqlkata"] + path = sqlkata + url = https://github.com/toburger/querybuilder diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..78f7167 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,5 @@ +repos: +- repo: https://github.com/fsfe/reuse-tool + rev: v1.0.0 + hooks: + - id: reuse \ No newline at end of file diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 0000000..5fc17a6 --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,28 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: opendatahub-content-api-core +Upstream-Contact: NOI Techpark +Source: https://github.com/noi-techpark/opendatahub-content-api-core + +Files: .github/* infrastructure/* .gitignore .pre-commit-config.yaml .dockerignore .env.example .gitmodules docker-compose.dcproj OdhApiCore.sln */*.csproj */*.fsproj */appsettings.* */Dockerfile */Properties/*.json OdhApiImporter/json/* OdhApiCoreTests/xunit.runner.json OdhApiCore/Pages/Index.cshtml OdhApiCore/wwwroot/images/* OdhApiCore/wwwroot/json/* OdhApiCore/wwwroot/favicon.ico OdhApiCore/docker/* LCS/**/ConnectedService.json CDB/**/ConnectedService.json GeoConverterTests/Files/* +Copyright: (c) NOI Techpark +License: CC0-1.0 + +Files: ContentApiCore/wwwroot/*/*.min.* ContentApiCore/pages/Index.cshtml +Copyright: (c) NOI Techpark +License: AGPL-3.0-or-later + +Files: ContentApiCore/wwwroot/lib/bootstrap/* +Copyright: 2011-2016 Twitter, Inc. +License: MIT + +Files: ContentApiCore/wwwroot/lib/jquery/* +Copyright: JS Foundation and other contributors +License: MIT + +Files: ContentApiCore/wwwroot/lib/jquery-validation/* +Copyright: 2017 Jörn Zaefferer +License: MIT + +Files: ContentApiCore/wwwroot/lib/jquery-validation-unobtrusive/* +Copyright: Microsoft Corporation. All rights reserved. +License: MIT \ No newline at end of file diff --git a/ContentApiCore/Binders/CommaSeparatedArrayBinder.cs b/ContentApiCore/Binders/CommaSeparatedArrayBinder.cs new file mode 100644 index 0000000..b9a2c30 --- /dev/null +++ b/ContentApiCore/Binders/CommaSeparatedArrayBinder.cs @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Mvc.ModelBinding; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers +{ + public class CommaSeparatedArrayBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); + + string[] model = + valueProviderResult + .Values + .SelectMany(value => + value?.Split(",", StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty()) + .ToArray(); + + bindingContext.Result = ModelBindingResult.Success(model); + + return Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/ContentApiCore/Binders/LegacyBool.cs b/ContentApiCore/Binders/LegacyBool.cs new file mode 100644 index 0000000..8c9c663 --- /dev/null +++ b/ContentApiCore/Binders/LegacyBool.cs @@ -0,0 +1,58 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using System; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers +{ + [ModelBinder(typeof(LegacyBoolBinder))] + public class LegacyBool + { + public bool? Value { get; } + + public LegacyBool(bool? value) + { + this.Value = value; + } + + public static implicit operator Boolean?(LegacyBool legacyBool) + { + return legacyBool.Value; + } + + public static implicit operator LegacyBool(bool? boolean) + { + return new LegacyBool(boolean); + } + } + + public class LegacyBoolBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); + var firstValue = valueProviderResult.FirstValue; + if (firstValue == null || firstValue == "null") // "null" exists for compatibility reasons + { + bindingContext.Result = ModelBindingResult.Success(new LegacyBool(null)); + } + else if (bool.TryParse(firstValue, out var value)) + { + bindingContext.Result = ModelBindingResult.Success(new LegacyBool(value)); + } + else + { + bindingContext.ModelState.TryAddModelError( + bindingContext.ModelName, + bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueIsInvalidAccessor(firstValue) + ); + bindingContext.Result = ModelBindingResult.Failed(); + } + return Task.CompletedTask; + } + } +} diff --git a/ContentApiCore/Binders/PageSize.cs b/ContentApiCore/Binders/PageSize.cs new file mode 100644 index 0000000..8810441 --- /dev/null +++ b/ContentApiCore/Binders/PageSize.cs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using System; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers +{ + [ModelBinder(typeof(PageSizeBinder))] + public class PageSize + { + public int? Value { get; } + + public PageSize(int? value) + { + this.Value = value; + } + + public static implicit operator int?(PageSize pagesize) + { + return pagesize.Value; + } + + public static implicit operator PageSize(int value) + { + return new PageSize(value); + } + + public static implicit operator PageSize(int? value) + { + return new PageSize(value); + } + } + + public class PageSizeBinder : IModelBinder + { + public Task BindModelAsync(ModelBindingContext bindingContext) + { + var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); + var firstValue = valueProviderResult.FirstValue; + if (firstValue == null || firstValue == "null") // "null" exists for compatibility reasons + { + bindingContext.Result = ModelBindingResult.Success(new PageSize(10)); + } + else if (firstValue == "-1" || firstValue == "0") + { + bindingContext.Result = ModelBindingResult.Success(new PageSize(int.MaxValue)); + } + else if (int.TryParse(firstValue, out var value)) + { + bindingContext.Result = ModelBindingResult.Success(new PageSize(value)); + } + else + { + bindingContext.ModelState.TryAddModelError( + bindingContext.ModelName, + bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueIsInvalidAccessor(firstValue) + ); + bindingContext.Result = ModelBindingResult.Failed(); + } + return Task.CompletedTask; + } + } +} diff --git a/ContentApiCore/ContentApiCore.csproj b/ContentApiCore/ContentApiCore.csproj new file mode 100644 index 0000000..7bb4c61 --- /dev/null +++ b/ContentApiCore/ContentApiCore.csproj @@ -0,0 +1,65 @@ + + + + net8.0 + enable + aspnet-OdhApiCore-8340F15F-CE93-44F5-ABBD-4E830074B59D + Linux + ..\docker-compose.dcproj + true + 1701;1702;1591;1572;1573 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ContentApiCore/Controllers/api/ExampleApiController.cs b/ContentApiCore/Controllers/api/ExampleApiController.cs new file mode 100644 index 0000000..3aab4dd --- /dev/null +++ b/ContentApiCore/Controllers/api/ExampleApiController.cs @@ -0,0 +1,398 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using AspNetCore.CacheOutput; +using DataModel; +using Helper; +using Helper.Generic; +using Helper.Identity; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using ContentApiCore.Responses; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers.api +{ + /// + /// Examples Api + /// + [EnableCors("CorsPolicy")] + [NullStringParameterActionFilter] + public class ExampleController : OdhController + { + public ExampleController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + } + + #region SWAGGER Exposed API + + //Standard GETTER + + /// + /// GET Example List + /// + /// Pagenumber + /// Elements per Page, (default:10) + /// Seed '1 - 10' for Random Sorting, '0' generates a Random Seed, 'null' disables Random Sorting, (default:null) + /// IDFilter (Separator ',' List of IDs), (default:'null') + /// Example Types Filter (Separator ',' List of ExampleTypes IDs), (default:'null') + /// Active Filter (possible Values: 'true' only Active Data, 'false' only Disabled Data), (default:'null') + /// Filter by Source (Separator ','), (Sources available 'idm','noi'...),(default: 'null') + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Language field selector, displays data and fields in the selected language (default:'null' all languages are displayed) + /// Language filter (returns only data available in the selected Language, Separator ',' possible values: 'de,it,en,nl,sc,pl,fr,ru', 'null': Filter disabled) + /// Published On Filter (Separator ',' List of publisher IDs), (default:'null') + /// Returns data changed after this date Format (yyyy-MM-dd), (default: 'null') + /// String to search for, Title in all languages are searched, (default: null) Wiki searchfilter + /// Wiki rawfilter + /// Wiki rawsort + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Collection of Example Objects + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(JsonResult), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + //[OdhCacheOutput(ClientTimeSpan = 0, ServerTimeSpan = 3600, CacheKeyGenerator = typeof(CustomCacheKeyGenerator), MustRevalidate = true)] + [HttpGet, Route("Example")] + public async Task GetExamples( + string? language = null, + uint pagenumber = 1, + PageSize pagesize = null!, + string? exampletype = null, + string? idlist = null, + string? langfilter = null, + LegacyBool active = null!, + string? updatefrom = null, + string? seed = null, + string? publishedon = null, + string? source = null, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? searchfilter = null, + string? rawfilter = null, + string? rawsort = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + + return await GetExampleList( + fields: fields ?? Array.Empty(), language: language, pagenumber: pagenumber, pagesize: pagesize, + type: exampletype, searchfilter: searchfilter, idfilter: idlist, languagefilter: langfilter, + active: active?.Value, seed: seed, source: source, lastchange: updatefrom, publishedon: publishedon, + rawfilter: rawfilter, rawsort: rawsort, removenullvalues: removenullvalues, cancellationToken); + } + + /// + /// GET Example Single + /// + /// ID of the Example + /// Language field selector, displays data and fields in the selected language (default:'null' all languages are displayed) + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Example Object + /// Object created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(ExampleLinked), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("Example/{id}", Name = "SingleExample")] + public async Task GetExample( + string id, + string? language, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await GetExampleSingle(id, language, fields: fields ?? Array.Empty(), removenullvalues, cancellationToken); + } + + //Special GETTER + + /// + /// GET ExampleTypes List + /// + /// Language field selector, displays data and fields in the selected language (default:'null' all languages are displayed) + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// String to search for, Title in all languages are searched, (default: null) Wiki searchfilter + /// Wiki rawfilter + /// Wiki rawsort + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Collection of ExampleTypes Object + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("ExampleTypes")] + public async Task GetExampleTypes( + string? language, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? searchfilter = null, + string? rawfilter = null, + string? rawsort = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await GetExampleTypesList(language, fields: fields ?? Array.Empty(), searchfilter, rawfilter, rawsort, removenullvalues, cancellationToken); + } + + /// + /// GET ExampleTypes Single + /// + /// ID of the ExampleType + /// Language field selector, displays data and fields in the selected language (default:'null' all languages are displayed) + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// ExampleTypes Object + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(ExampleTypes), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("ExampleTypes/{id}", Name = "SingleExampleTypes")] + public async Task GetExampleType( + string id, + string? language, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await GetExampleTypeSingle(id, language, fields: fields ?? Array.Empty(), removenullvalues, cancellationToken); + } + + #endregion + + #region GETTER + + private Task GetExampleList(string[] fields, string? language, uint pagenumber, int? pagesize, + string? type, string? searchfilter, string? idfilter, string? languagefilter, + bool? active, string? seed, string? source, string? lastchange, + string? publishedon, string? rawfilter, string? rawsort, bool removenullvalues, + CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + ExampleHelper examplehelper = ExampleHelper.Create( + type, idfilter, languagefilter, active, source, lastchange, publishedon); + + var query = + QueryFactory.Query() + .SelectRaw("data") + .From("examples") + .ExampleWhereExpression( + idlist: examplehelper.idlist, typelist: examplehelper.typelist, + languagelist: examplehelper.languagelist, activefilter: examplehelper.active, + sourcelist: examplehelper.sourcelist, + publishedonlist: examplehelper.publishedonlist, + searchfilter: searchfilter, language: language, lastchange: examplehelper.lastchange, + additionalfilter: additionalfilter, + userroles: UserRolesToFilter) + .ApplyRawFilter(rawfilter) + .ApplyOrdering_GeneratedColumns(ref seed, new PGGeoSearchResult() { geosearch = false }, rawsort); + + + // Get paginated data + var data = + await query + .PaginateAsync( + page: (int)pagenumber, + perPage: pagesize ?? 25); + + var dataTransformed = + data.List.Select( + raw => raw.TransformRawData(language, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null) + ); + + uint totalpages = (uint)data.TotalPages; + uint totalcount = (uint)data.Count; + + return ResponseHelpers.GetResult( + pagenumber, + totalpages, + totalcount, + seed, + dataTransformed, + Url); + }); + } + + private Task GetExampleSingle(string id, string? language, string[] fields, bool removenullvalues, CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + var query = + QueryFactory.Query("examples") + .Select("data") + .Where("id", id.ToUpper()) + .When(!String.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + .FilterDataByAccessRoles(UserRolesToFilter); + + var data = await query.FirstOrDefaultAsync(); + + return data?.TransformRawData(language, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null); + }); + } + + #endregion + + #region CATEGORIES + + private Task GetExampleTypesList(string? language, string[] fields, string? searchfilter, string? rawfilter, string? rawsort, bool removenullvalues, CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + var query = + QueryFactory.Query("exampletypes") + .SelectRaw("data") + .SearchFilter(PostgresSQLWhereBuilder.TypeDescFieldsToSearchFor(language), searchfilter) + .ApplyRawFilter(rawfilter) + .OrderOnlyByRawSortIfNotNull(rawsort); + + var data = await query.GetAsync(); + + return + data.Select( + raw => raw?.TransformRawData(language, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null) + ); + }); + } + + private Task GetExampleTypeSingle(string id, string? language, string[] fields, bool removenullvalues, CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + var query = + QueryFactory.Query("exampletypes") + .Select("data") + .Where("id", id.ToLower()); + + var data = await query.FirstOrDefaultAsync(); + + return data?.TransformRawData(language, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null); + }); + } + + #endregion + + #region POST PUT DELETE + + /// + /// POST Insert new Example + /// + /// Example Object + /// Http Response + [AuthorizeODH(PermissionAction.Create)] + [InvalidateCacheOutput(nameof(GetExampleList))] + [ProducesResponseType(typeof(PGCRUDResult), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpPost, Route("Example")] + public Task Post([FromBody] ExampleLinked example) + { + return DoAsyncReturn(async () => + { + //Additional Filters on the Action Create + AdditionalFiltersToAdd.TryGetValue("Create", out var additionalfilter); + + //GENERATE ID + example.Id = Helper.IdGenerator.GenerateIDFromType(example); + + example.CheckMyInsertedLanguages(new List { "de", "en", "it" }); + + if (example.LicenseInfo == null) + example.LicenseInfo = new LicenseInfo() { ClosedData = false }; + + example.TrimStringProperties(); + + return await UpsertData(example, new DataInfo("example", CRUDOperation.Create), new CompareConfig(true, true), new CRUDConstraints(additionalfilter, UserRolesToFilter)); + }); + } + + /// + /// PUT Modify existing Example + /// + /// Example Id + /// Example Object + /// Http Response + //[ApiExplorerSettings(IgnoreApi = true)] + [AuthorizeODH(PermissionAction.Update)] + [InvalidateCacheOutput(nameof(GetExampleList))] + [ProducesResponseType(typeof(PGCRUDResult), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpPut, Route("Example/{id}")] + public Task Put(string id, [FromBody] ExampleLinked example) + { + return DoAsyncReturn(async () => + { + //Additional Filters on the Action Create + AdditionalFiltersToAdd.TryGetValue("Update", out var additionalfilter); + + //Check ID uppercase lowercase + example.Id = Helper.IdGenerator.CheckIdFromType(id); + + if (String.IsNullOrEmpty(example.Source)) + example.Source = "noi"; + + example.CheckMyInsertedLanguages(new List { "de", "en", "it" }); + + example.TrimStringProperties(); + + return await UpsertData(example, new DataInfo("examples", CRUDOperation.Update), new CompareConfig(true, true), new CRUDConstraints(additionalfilter, UserRolesToFilter)); + }); + } + + /// + /// DELETE Example by Id + /// + /// Example Id + /// Http Response + //[ApiExplorerSettings(IgnoreApi = true)] + [AuthorizeODH(PermissionAction.Delete)] + [InvalidateCacheOutput(nameof(GetExampleList))] + [ProducesResponseType(typeof(PGCRUDResult), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpDelete, Route("Example/{id}")] + public Task Delete(string id) + { + return DoAsyncReturn(async () => + { + //Additional Filters on the Action Create + AdditionalFiltersToAdd.TryGetValue("Delete", out var additionalfilter); + + //Check ID uppercase lowercase + id = Helper.IdGenerator.CheckIdFromType(id); + + return await DeleteData(id, new DataInfo("examples", CRUDOperation.Delete), new CRUDConstraints(additionalfilter, UserRolesToFilter)); + }); + } + + #endregion + } +} diff --git a/ContentApiCore/Controllers/base/OdhController.cs b/ContentApiCore/Controllers/base/OdhController.cs new file mode 100644 index 0000000..621eb29 --- /dev/null +++ b/ContentApiCore/Controllers/base/OdhController.cs @@ -0,0 +1,329 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Helper.Generic; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using MongoDB.Driver; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers +{ + [ApiController] + [Route("v1")] + [FormatFilter] + public abstract class OdhController : ControllerBase + { + private readonly IWebHostEnvironment env; + private readonly ISettings settings; + + public OdhController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + { + this.env = env; + this.settings = settings; + this.Logger = logger; + this.QueryFactory = queryFactory; + this.OdhPushnotifier = odhpushnotifier; + + //TO CHECK ControllerContext.RouteData is null in constructor + //UserRolesToFilter = GetEndPointAccessRole(endpoint); + } + + protected ILogger Logger { get; } + + protected QueryFactory QueryFactory { get; } + + protected IOdhPushNotifier OdhPushnotifier; + + //Ensure this is only called 1 time per Controller operation + protected IEnumerable UserRolesToFilter + { + get + { + return GetEndPointAccessRole(); + } + } + + //Hack Method for Search api which passes endpoint + protected IEnumerable UserRolesToFilterEndpoint(string endpoint) + { + return GetEndPointAccessRole(endpoint); + } + + + //Ensure this is only called 1 time per Controller operation + protected IDictionary AdditionalFiltersToAdd + { + get + { + return GetAdditionalFilterDictionary(); + } + } + + //Hack Method for Search api which passes endpoint + protected IDictionary AdditionalFiltersToAddEndpoint(string endpoint) + { + return GetAdditionalFilterDictionary(endpoint); + } + + + private IDictionary GetAdditionalFilterDictionary(string? pathtocheck = null) + { + var additionalfilterdict = new Dictionary(); + + if (pathtocheck == null) + pathtocheck = ControllerContext.RouteData.Values["controller"]?.ToString(); + + if (pathtocheck != null) + { + var rolesforendpoint = User.Claims.Where(c => c.Type == ClaimTypes.Role && c.Value.StartsWith(pathtocheck + "_")); + foreach (var role in rolesforendpoint) + { + var splittedrole = role.Value.Split("_"); + if (splittedrole.Length == 3) + { + //TODO if key is already there add the info on the value with a & + if(additionalfilterdict.ContainsKey(splittedrole[1])) + { + additionalfilterdict.TryAddOrUpdate(splittedrole[1], additionalfilterdict[splittedrole[1]] + "&" + splittedrole[2]); + } + else + { + additionalfilterdict.TryAddOrUpdate(splittedrole[1], splittedrole[2]); + } + } + } + } + return additionalfilterdict; + } + + private List GetEndPointAccessRole(string? path = null) + { + List rolelist = new List(); + + var dict = GetAdditionalFilterDictionary(path); + + if(dict.ContainsKey("Read")) + { + if(dict["Read"].Split("&").Any(x => x.Contains("accessrole"))) + { + foreach(var tocheck in dict["Read"].Split("&").Where(x => x.Contains("accessrole"))) + { + foreach(var role in tocheck.Split("=").LastOrDefault().Split(",")) + { + rolelist.Add(role); + } + } + } + } + + return rolelist.Count == 0 ? new List() { "ANONYMOUS" } : rolelist; + } + + + + //NOT Needed at moment + protected IEnumerable FieldsToHide + { + get + { + List fieldstohide = new(); + + var roleclaims = User.Claims.Where(x => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/role").Select(claim => claim.Value).ToList(); + + //Search all settings with Entity = Controllername + var fields = settings.Field2HideConfig + .Where(x => x.Entity == this.ControllerContext.RouteData.Values["controller"]?.ToString() || + string.IsNullOrEmpty(x.Entity)); + + foreach (var field in fields) + { + if (roleclaims.Intersect(field.DisplayOnRoles ?? new()).Count() == 0) + { + fieldstohide.AddRange(field.Fields ?? new()); + } + } + + return fieldstohide; + } + } + + protected Func UrlGenerator + { + get + { + return self => + { + var chunks = self.Split('/', 2); + if (chunks.Length < 2) + return self; + + //Hack if there is another / in the route to check if it is not generating side effects + if(chunks[1].Split('/').Count() > 1) + { + chunks[1] = chunks[1].Split('/')[1]; + } + + var (controller, id) = (chunks[0], chunks[1]); + return Url.Link($"Single{controller}", new { id })!; + }; + } + } + + protected Func UrlGeneratorStatic + { + get + { + return self => + { + var location = new Uri($"{Request.Scheme}://{Request.Host}/" + self); + return location.AbsoluteUri; + }; + } + } + + protected async Task DoAsync(Func> f) + { + try + { + return await f(); + } + catch (PostGresSQLHelperException ex) + { + return this.StatusCode(StatusCodes.Status500InternalServerError, new { error = ex.Message }); + } + catch (JsonPathException ex) + { + return this.BadRequest(new + { + error = "Invalid JSONPath selection", + path = ex.Path, + details = env.IsDevelopment() ? ex.ToString() : ex.Message + }); + } + catch (Exception ex) + { + if (ex.Message == "Request Error") + return this.BadRequest(new { error = env.IsDevelopment() ? ex.ToString() : ex.Message }); + else if (ex.Message == "No data") + return this.StatusCode(StatusCodes.Status404NotFound, new { error = env.IsDevelopment() ? ex.ToString() : ex.Message }); + else + return this.StatusCode(StatusCodes.Status500InternalServerError, new { error = env.IsDevelopment() ? ex.ToString() : ex.Message }); + } + } + + //GET Data + protected Task DoAsyncReturn(Func> f) + { + return DoAsync(async () => + { + object? result = await f(); + if (result == null) + return this.NotFound(); + else if (result is ActionResult) + return (IActionResult)result; + else + return this.Ok(result); + }); + } + + + //CREATE and UPDATE data + protected async Task UpsertData(T data, DataInfo datainfo, CompareConfig compareconfig, CRUDConstraints crudconstraints, string editsource = "api") where T : IIdentifiable, IImportDateassigneable, IMetaData, new() + { + //TODO Username and provenance of the insert/edit + //Get the Username + string editor = this.User != null && this.User.Identity != null && this.User.Identity.Name != null ? this.User.Identity.Name : "anonymous"; + + if (HttpContext.Request.Headers.ContainsKey("Referer") && !String.IsNullOrEmpty(HttpContext.Request.Headers["Referer"])) + editsource = HttpContext.Request.Headers["Referer"]; + + var result = await QueryFactory.UpsertData(data, datainfo, new EditInfo(editor, editsource), crudconstraints, compareconfig); + + //push modified data to all published Channels + result.pushed = await CheckIfObjectChangedAndPush(result, result.id, result.odhtype); + + return ReturnCRUDResult(result); + } + + //DELETE data + protected async Task DeleteData(string id, DataInfo datainfo, CRUDConstraints crudconstraints) where T : IIdentifiable, IMetaData, IImportDateassigneable, new() + { + //TODO Add logic which checks if user is authorized to delete data + //Return not found if wrong ID + //Return forbitten 403 if + //Return 401 if unauthorized + + var result = await QueryFactory.DeleteData(id, datainfo, crudconstraints); + //push modified data to all published Channels + result.pushed = await PushDeletedObject(result, result.id, result.odhtype); + + return ReturnCRUDResult(result); + } + + //PUSH Modified data + protected async Task?> CheckIfObjectChangedAndPush(PGCRUDResult myupdateresult, string id, string datatype, IDictionary? additionalpushinfo = null, string pushorigin = "odh.api.push") + { + IDictionary? pushresults = default(IDictionary); + + //Check if data has changed and Push To all channels + if (myupdateresult.error == 0 && myupdateresult.objectchanged != null && myupdateresult.objectchanged > 0 && myupdateresult.pushchannels != null && myupdateresult.pushchannels.Count > 0) + { + if (additionalpushinfo == null) + additionalpushinfo = new Dictionary(); + + //Check if image has changed + if (myupdateresult.objectimagechanged != null && myupdateresult.objectimagechanged.Value > 0) + additionalpushinfo.TryAdd("imageschanged", true); + else + additionalpushinfo.TryAdd("imageschanged", false); + + pushresults = await OdhPushnotifier.PushToPublishedOnServices(id, datatype.ToLower(), pushorigin, additionalpushinfo, false, "api", myupdateresult.pushchannels.ToList()); + } + + return pushresults; + } + + //PUSH Deleted data + private async Task?> PushDeletedObject(PGCRUDResult myupdateresult, string id, string datatype, string pushorigin = "odh.api.push") + { + IDictionary? pushresults = default(IDictionary); + + //Check if data has changed and Push To all channels + if (myupdateresult.deleted > 0 && myupdateresult.pushchannels.Count > 0) + { + pushresults = await OdhPushnotifier.PushToPublishedOnServices(id, datatype.ToLower(), pushorigin, null, true, "api", myupdateresult.pushchannels.ToList()); + } + + return pushresults; + } + + + protected IActionResult ReturnCRUDResult(PGCRUDResult result) + { + switch (result.errorreason) + { + case "": return Ok(result); + case "Not Allowed": return StatusCode(403, "Not enough permissions"); + case "Not Found": return NotFound(); + case "Bad Request": return BadRequest(); + case "No Data": return BadRequest(); + case "Internal Error": return StatusCode(500); + default: + return Ok(result); + } + } + } +} \ No newline at end of file diff --git a/ContentApiCore/Controllers/generic/DeprecatedController.cs b/ContentApiCore/Controllers/generic/DeprecatedController.cs new file mode 100644 index 0000000..d0e604f --- /dev/null +++ b/ContentApiCore/Controllers/generic/DeprecatedController.cs @@ -0,0 +1,123 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using ContentApiCore.GenericHelpers; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers +{ + [EnableCors("CorsPolicy")] + [NullStringParameterActionFilter] + public class DeprecatedController : OdhController + { + public DeprecatedController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + } + + #region SWAGGER Exposed API + + /// + /// GET Generic Deprecated search of fields + /// + /// Pagenumber + /// Elements per Page, (default:10) + /// Seed '1 - 10' for Random Sorting, '0' generates a Random Seed, 'null' disables Random Sorting, (default:null) + /// Mandatory search trough Entities (metadata, accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... null = search trough all entities) + /// Mandatory search trough Entities (metadata, accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... null = search trough all entities) + /// Mandatory Select a field for the Distinct Query, example fields=Source, arrays are selected with a [*] example HasLanguage[*] / Features[*].Id (Only one field supported). Wiki fields + /// Wiki rawfilter + /// Wiki rawsort + /// Get only first selected field as simple string Array + /// Exclude empty and null values from output + /// Array of string/object + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + //[OdhCacheOutput(ClientTimeSpan = 0, ServerTimeSpan = 3600, CacheKeyGenerator = typeof(CustomCacheKeyGenerator), MustRevalidate = true)] + [HttpGet, Route("Deprecated")] + //[Authorize(Roles = "DataReader,CommonReader,AccoReader,ActivityReader,PoiReader,ODHPoiReader,PackageReader,GastroReader,EventReader,ArticleReader")] + public async Task GetDeprecatedAsync( + uint? pagenumber = null, + PageSize pagesize = null!, + string? odhtype = null, + string? type = null, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? seed = null, + string? rawfilter = null, + string? rawsort = null, + bool getasarray = false, + bool excludenulloremptyvalues = false, + CancellationToken cancellationToken = default) + { + var fieldstodisplay = fields ?? Array.Empty(); + + return await GetDeprecated(pagenumber, pagesize, odhtype ?? type, fieldstodisplay, seed, rawfilter, rawsort, getasarray, excludenulloremptyvalues, null, cancellationToken); + } + + ////TODO Get openapi file and parse trough an render to output + //[HttpGet, Route("v1/DeprecatedTest")] + //public async Task Deprecated() + //{ + // var requesturl = string.Format("{0}://{1}{2}{3}", HttpContext.Request.Scheme, HttpContext.Request.Host, HttpContext.Request.Path, "swagger/v1/swagger.json"); + + // using (var client = new HttpClient()) + // { + // var response = await client.GetAsync(requesturl); + // var responsecontent = await response.Content.ReadAsStringAsync(); + + // JObject? obj = JsonConvert.DeserializeObject(responsecontent); + + // return Ok(obj); + // } + //} + + #endregion + + #region GETTER + + private Task GetDeprecated(uint? pagenumber, int? pagesize, + string? odhtype, string[] fields, string? seed, string? rawfilter, string? rawsort, bool? getasarray,bool excludenullvalues, + PGGeoSearchResult geosearchresult, CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + List typestocheck = new List(); + Dictionary> resultdict = new Dictionary>(); + + if (odhtype == null) + typestocheck = ODHTypeHelper.GetAllTypeStrings().ToList(); + else + typestocheck = odhtype.Split(",").ToList(); + + foreach(var typetocheck in typestocheck) + { + + resultdict.Add(typetocheck, GetDeprecatedFieldsByAttributes.GetDeprecatedFields(ODHTypeHelper.TranslateTypeString2Type(typetocheck))); + + } + + return resultdict; + }); + } + + #endregion + } +} \ No newline at end of file diff --git a/ContentApiCore/Controllers/generic/DistinctController.cs b/ContentApiCore/Controllers/generic/DistinctController.cs new file mode 100644 index 0000000..34ab5bf --- /dev/null +++ b/ContentApiCore/Controllers/generic/DistinctController.cs @@ -0,0 +1,190 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using ContentApiCore.Responses; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers +{ + [EnableCors("CorsPolicy")] + [NullStringParameterActionFilter] + public class DistinctController : OdhController + { + public DistinctController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + } + + #region SWAGGER Exposed API + + /// + /// GET Generic Distinct search of fields + /// + /// Pagenumber + /// Elements per Page, (default:10) + /// Seed '1 - 10' for Random Sorting, '0' generates a Random Seed, 'null' disables Random Sorting, (default:null) + /// Mandatory search trough Entities (metadata, accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... ) + /// Mandatory search trough Entities (metadata, accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... ) + /// Mandatory Select a field for the Distinct Query, example fields=Source, arrays are selected with a [*] example HasLanguage[*] / Features[*].Id (Only one field supported). Wiki fields + /// Wiki rawfilter + /// Wiki rawsort + /// Get only first selected field as simple string Array + /// Exclude empty and null values from output + /// Array of string/object + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + //[OdhCacheOutput(ClientTimeSpan = 0, ServerTimeSpan = 3600, CacheKeyGenerator = typeof(CustomCacheKeyGenerator), MustRevalidate = true)] + [HttpGet, Route("Distinct")] + //[Authorize(Roles = "DataReader,CommonReader,AccoReader,ActivityReader,PoiReader,ODHPoiReader,PackageReader,GastroReader,EventReader,ArticleReader")] + public async Task GetDistinctAsync( + uint? pagenumber = null, + PageSize pagesize = null!, + string? odhtype = null, + string? type = null, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? seed = null, + string? rawfilter = null, + string? rawsort = null, + bool getasarray = false, + bool excludenulloremptyvalues = false, + CancellationToken cancellationToken = default) + { + var fieldstodisplay = fields ?? Array.Empty(); + + if (fieldstodisplay.Count() == 0) + return BadRequest("please add a field"); + + if (fieldstodisplay.Count() > 1 && getasarray) + return BadRequest("Get As Array only possible with 1 selected field"); + + //let more non array fields pass, if arrays are selected then only one field is allowed + if (fieldstodisplay.Count() > 1 && (fieldstodisplay.Any(x => x.Contains("[*]")) || fieldstodisplay.Any(x => x.Contains("[]")))) + return BadRequest("On Array fields, currently only one field supported"); + + return await GetDistinct(pagenumber, pagesize, odhtype ?? type, fieldstodisplay, seed, rawfilter, rawsort, getasarray, excludenulloremptyvalues, null, cancellationToken); + } + + #endregion + + #region GETTER + + private Task GetDistinct(uint? pagenumber, int? pagesize, + string? odhtype, string[] fields, string? seed, string? rawfilter, string? rawsort, bool? getasarray,bool excludenullvalues, + PGGeoSearchResult geosearchresult, CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + if (odhtype == null) + return BadRequest("odhtype missing"); + + var table = ODHTypeHelper.TranslateTypeString2Table(odhtype); + + string nullexclude = ""; + if (excludenullvalues) + nullexclude = " ? (@ <> null && @ <> \"\")"; + + List selects = new List(); + + var fieldschecked = JsonPathCompatibilitycheck(fields); + + foreach (var field in fieldschecked) + { + string kataField = field.Item1.Replace("[", "\\[").Replace("]", "\\]"); + string asField = field.Item2.Replace("[", "\\[").Replace("]", "\\]"); + + string select = $@"jsonb_path_query(data, '$.{kataField}{nullexclude}')#>>'\{{\}}' as ""{asField}"""; + + selects.Add(select); + } + + string endpoint = ODHTypeHelper.TranslateTypeToEndPoint(odhtype); + + var query = + QueryFactory.Query() + .Distinct() + .SelectRaw(String.Join(",", selects)) + .From(table) + .ApplyRawFilter(rawfilter) + // .Anonymous_Logged_UserRule_GeneratedColumn(FilterClosedData, !ReducedData) + .OrderByRawIfNotNull(rawsort) + //.ApplyOrdering_GeneratedColumns(null, null, rawsort) + .FilterDataByAccessRoles(UserRolesToFilterEndpoint(endpoint)); + + //TODOS Metadata api support + + if (getasarray.HasValue && getasarray.Value) + { + //TODOS GetAsarray returns values simple + var data = await query.GetAsync(); + return data; + } + else + { + if (!pagenumber.HasValue || getasarray.HasValue) + { + return await query.GetAsync(cancellationToken: cancellationToken); + } + else + { + var data = await query.PaginateAsync( + page: (int)pagenumber, + perPage: pagesize ?? 25, + cancellationToken: cancellationToken); + + uint totalpages = (uint)data.TotalPages; + uint totalcount = (uint)data.Count; + + return ResponseHelpers.GetResult( + pagenumber.Value, + totalpages, + totalcount, + seed, + data.List, + Url + ); + } + } + }); + } + + public static List> JsonPathCompatibilitycheck(string[] fields) + { + List> result = new List>(); + + foreach(var field in fields) + { + Tuple tp = default(Tuple); + + //Fix support also .[*] and .[] Notation + if (field.Contains(".[*]") || field.Contains(".[]")) + tp = Tuple.Create(field.Replace(".[*]", "[*]").Replace(".[]", "[*]"), field); + else + tp = Tuple.Create(field, field); + + result.Add(tp); + } + + return result; + } + + #endregion + } +} \ No newline at end of file diff --git a/ContentApiCore/Controllers/generic/PublisherController.cs b/ContentApiCore/Controllers/generic/PublisherController.cs new file mode 100644 index 0000000..41ece91 --- /dev/null +++ b/ContentApiCore/Controllers/generic/PublisherController.cs @@ -0,0 +1,261 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Helper.Generic; +using Helper.Identity; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using ContentApiCore.Responses; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers.generic +{ + + [EnableCors("CorsPolicy")] + [NullStringParameterActionFilter] + public class PublisherController : OdhController + { + public PublisherController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + } + + #region SWAGGER Exposed API + + /// + /// GET Publishers List + /// + /// Language field selector, displays data and fields available in the selected language (default:'null' all languages are displayed) + /// IDFilter (Separator ',' List of IDs, 'null' = No Filter), (default:'null') + /// Source Filter (possible Values: 'lts','idm'), (default:'null') + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// String to search for, Title in all languages are searched, (default: null) Wiki searchfilter + /// Wiki rawfilter + /// Wiki rawsort + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Collection of PublisherLinked Objects + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("Publisher")] + public async Task GetPublishersAsync( + uint? pagenumber = 1, + PageSize pagesize = null!, + string? language = null, + string? idlist = null, + string? source = null, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? searchfilter = null, + string? rawfilter = null, + string? rawsort = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await Get(pagenumber, pagesize, language, idlist, source, + fields: fields ?? Array.Empty(), + searchfilter, rawfilter, rawsort, removenullvalues: removenullvalues, + cancellationToken); + } + + /// + /// GET Publisher Single + /// + /// ID of the Publisher + /// Language field selector, displays data and fields available in the selected language (default:'null' all languages are displayed) + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// PublisherLinked Object + /// Object created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(PublisherLinked), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("Publisher/{id}", Name = "SinglePublisher")] + public async Task GetPublisherSingle(string id, + string? language = null, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? localizationlanguage = null, //TODO ignore this in swagger + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + //Compatibility + if (string.IsNullOrEmpty(language) && !string.IsNullOrEmpty(localizationlanguage)) + language = localizationlanguage; + + return await GetSingle(id, language, fields: fields ?? Array.Empty(), removenullvalues: removenullvalues, cancellationToken); + } + + #endregion + + #region GETTER + + private Task Get( + uint? pagenumber, int? pagesize, string? language, string? idfilter, string? source, string[] fields, + string? searchfilter, string? rawfilter, string? rawsort, bool removenullvalues, + CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + var sourcelist = CommonListCreator.CreateIdList(source); + var idlist = CommonListCreator.CreateIdList(idfilter); + + var query = + QueryFactory.Query() + .SelectRaw("data") + .From("publishers") + .PublishersWhereExpression( + languagelist: new List(), + idlist: idlist, + sourcelist: sourcelist, + searchfilter: searchfilter, + language: language, + additionalfilter: additionalfilter, + userroles: UserRolesToFilter + ) + .ApplyRawFilter(rawfilter) + .ApplyOrdering(new PGGeoSearchResult() { geosearch = false }, rawsort, "data#>>'\\{Shortname\\}'"); + + + // Get paginated data + var data = + await query + .PaginateAsync( + page: (int)pagenumber, + perPage: pagesize ?? 25); + + var dataTransformed = + data.List.Select( + raw => raw.TransformRawData(language, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null) + ); + + uint totalpages = (uint)data.TotalPages; + uint totalcount = (uint)data.Count; + + return ResponseHelpers.GetResult( + (uint)pagenumber, + totalpages, + totalcount, + null, + dataTransformed, + Url); + }); + } + + private Task GetSingle(string id, string? language, string[] fields, bool removenullvalues, CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + var data = await QueryFactory.Query("publishers") + .Select("data") + .Where("id", id.ToLower()) + .When(!string.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + .FilterDataByAccessRoles(UserRolesToFilter) + .FirstOrDefaultAsync(); + + return data?.TransformRawData(language, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null); + }); + } + + #endregion + + #region POST PUT DELETE + + /// + /// POST Insert new Publisher + /// + /// PublisherLinked Object + /// Http Response + //[Authorize(Roles = "DataWriter,DataCreate,PublisherManager,PublisherCreate")] + [AuthorizeODH(PermissionAction.Create)] + [HttpPost, Route("Publisher")] + public Task Post([FromBody] PublisherLinked publisher) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Create", out var additionalfilter); + + publisher.Id = publisher.Key.ToLower().Replace(" ", "") ?? IdGenerator.GenerateIDFromType(publisher); + + if (publisher.LicenseInfo == null) + publisher.LicenseInfo = new LicenseInfo() { ClosedData = false }; + + return await UpsertData(publisher, new DataInfo("publishers", CRUDOperation.Create), new CompareConfig(false, false), new CRUDConstraints(additionalfilter, UserRolesToFilter)); + }); + } + + /// + /// PUT Modify existing Publisher + /// + /// Publisher Id + /// Publisher Object + /// Http Response + //[Authorize(Roles = "DataWriter,DataModify,PublisherManager,PublisherModify,PublisherUpdate")] + [AuthorizeODH(PermissionAction.Update)] + [HttpPut, Route("Publisher/{id}")] + public Task Put(string id, [FromBody] PublisherLinked publisher) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Update", out var additionalfilter); + + publisher.Id = IdGenerator.CheckIdFromType(id); + + return await UpsertData(publisher, new DataInfo("publishers", CRUDOperation.Update), new CompareConfig(false, false), new CRUDConstraints(additionalfilter, UserRolesToFilter)); + }); + } + + /// + /// DELETE Publisher by Id + /// + /// Publisher Id + /// Http Response + //[Authorize(Roles = "DataWriter,DataDelete,PublisherManager,PublisherDelete")] + [AuthorizeODH(PermissionAction.Delete)] + [HttpDelete, Route("Publisher/{id}")] + public Task Delete(string id) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Delete", out var additionalfilter); + + id = IdGenerator.CheckIdFromType(id); + + //return await DeleteData(id, "publishers", additionalfilter); // Does not implement IPublishedOn + + return await DeleteData(id, new DataInfo("publishers", CRUDOperation.Delete), new CRUDConstraints(additionalfilter, UserRolesToFilter)); + }); + } + + + #endregion + } + + +} \ No newline at end of file diff --git a/ContentApiCore/Controllers/generic/PushResponseController.cs b/ContentApiCore/Controllers/generic/PushResponseController.cs new file mode 100644 index 0000000..63f41c5 --- /dev/null +++ b/ContentApiCore/Controllers/generic/PushResponseController.cs @@ -0,0 +1,193 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using ContentApiCore.Responses; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers +{ + + [EnableCors("CorsPolicy")] + [NullStringParameterActionFilter] + public class PushResponseController : OdhController + { + public PushResponseController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + } + + #region SWAGGER Exposed API + + /// + /// GET PushResponse List + /// + /// IDFilter (Separator ',' List of IDs, 'null' = No Filter), (default:'null') + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// publisher Filter (Separator ',' List of IDs, 'null' = No Filter), (default:'null') + /// BeginDate of Events (Format: yyyy-MM-dd), (default: 'null') + /// EndDate of Events (Format: yyyy-MM-dd), (default: 'null') + /// Wiki rawfilter + /// Wiki rawsort + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Collection of PushResponse Objects + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("PushResponse")] + public async Task GetPushResultsAsync( + uint? pagenumber = 1, + PageSize pagesize = null!, + string? idlist = null, + string? publisher = null, + string? begindate = null, + string? enddate = null, + string? objectidlist = null, + string? objecttypelist = null, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? rawfilter = null, + string? rawsort = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await Get(pagenumber, pagesize, idlist, publisher, begindate, enddate, + objectidlist, objecttypelist, + fields: fields ?? Array.Empty(), + rawfilter, rawsort, removenullvalues: removenullvalues, + cancellationToken); + } + + /// + /// GET PushResponse Single + /// + /// ID of the PushResponse + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// PushResponse Object + /// Object created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(PushResponse), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("PushResponse/{id}", Name = "SinglePushResponse")] + public async Task GetPushResultSingle(string id, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await GetSingle(id, fields: fields ?? Array.Empty(), removenullvalues: removenullvalues, cancellationToken); + } + + #endregion + + #region GETTER + + private Task Get( + uint? pagenumber, int? pagesize, string? idfilter, string? publisherfilter, string? begindate, string? enddate, string? objectidfilter, string? objecttypefilter, + string[] fields, string? rawfilter, string? rawsort, bool removenullvalues, + CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + var idlist = Helper.CommonListCreator.CreateIdList(idfilter); + var objectidlist = Helper.CommonListCreator.CreateIdList(objectidfilter); + var objecttypelist = Helper.CommonListCreator.CreateIdList(objecttypefilter); + + var publisherlist = Helper.CommonListCreator.CreateIdList(publisherfilter); + + DateTime begin = DateTime.MinValue; + DateTime end = DateTime.MaxValue; + + if (!String.IsNullOrEmpty(begindate)) + if (begindate != "null") + begin = Convert.ToDateTime(begindate); + + if (!String.IsNullOrEmpty(enddate)) + if (enddate != "null") + end = Convert.ToDateTime(enddate); + + var query = + QueryFactory.Query() + .SelectRaw("data") + .From("pushresults") + .PushResultWhereExpression( + idlist: idlist, + publisherlist: publisherlist, + begin: begin, + end: end, + objectidlist: objectidlist, + objecttypelist: objecttypelist, + additionalfilter: additionalfilter + ) + .ApplyRawFilter(rawfilter) + .ApplyOrdering(new PGGeoSearchResult() { geosearch = false }, rawsort, "gen_lastchange DESC"); + + // Get paginated data + var data = + await query + .PaginateAsync( + page: (int)pagenumber, + perPage: pagesize ?? 25); + + var dataTransformed = + data.List.Select( + raw => raw.TransformRawData(null, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null) + ); + + uint totalpages = (uint)data.TotalPages; + uint totalcount = (uint)data.Count; + + return ResponseHelpers.GetResult( + (uint)pagenumber, + totalpages, + totalcount, + null, + dataTransformed, + Url); + }); + } + + private Task GetSingle(string id, string[] fields, bool removenullvalues, CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + var data = await QueryFactory.Query("pushresults") + .Select("data") + .Where("id", id) + .When(!String.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + .FirstOrDefaultAsync(); + + return data?.TransformRawData(null, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null); + }); + } + + #endregion + } + + +} \ No newline at end of file diff --git a/ContentApiCore/Controllers/generic/SearchController.cs b/ContentApiCore/Controllers/generic/SearchController.cs new file mode 100644 index 0000000..fd4ceb9 --- /dev/null +++ b/ContentApiCore/Controllers/generic/SearchController.cs @@ -0,0 +1,176 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers +{ + [EnableCors("CorsPolicy")] + [NullStringParameterActionFilter] + public class SearchController : OdhController + { + public SearchController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + } + + #region SWAGGER Exposed API + + /// + /// GET Search over all Entities + /// + /// Restrict search to Entities (accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... ) + /// Restrict search to Entities (accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... ) + /// Term to Search for Wiki + /// Language field selector, displays data and fields available in the selected language ('null' all languages are displayed) + /// Limit search to n items per entity + /// Search also trough base text (true/false), caution can slow down the search significantly + /// Search also on this fields, syntax analog to the fields filter + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Wiki rawfilter + /// Wiki rawsort + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Collection of ODHTag Objects + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + //[OdhCacheOutput(ClientTimeSpan = 0, ServerTimeSpan = 3600, CacheKeyGenerator = typeof(CustomCacheKeyGenerator), MustRevalidate = true)] + [HttpGet, Route("Find")] + [HttpGet, Route("Filter")] //Filter + //[Authorize(Roles = "DataReader,CommonReader,AccoReader,ActivityReader,PoiReader,ODHPoiReader,PackageReader,GastroReader,EventReader,ArticleReader")] + public async Task GetSearchAsync( + string term, + string? language = "en", + string? odhtype = null, + string? type = null, + bool searchbasetext = false, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? filteronfields = null, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? rawfilter = null, + string? rawsort = null, + int? limitto = 5, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + var fieldstodisplay = fields ?? Array.Empty(); + var fieldstosearchon = filteronfields ?? Array.Empty(); + + return await Get(language: language ?? "en", validforentity: odhtype ?? type, fields: fieldstodisplay, + searchfilter: term, searchontext: searchbasetext, passedfieldstosearchon: fieldstosearchon, + rawfilter: rawfilter, rawsort: rawsort, limitto: limitto, removenullvalues: removenullvalues, cancellationToken); + } + + //TODO EXTEND THE FILTER with the possibility to add fields for search + + + #endregion + + #region GETTER + + private Task Get(string language, string? validforentity, string[] fields, + string? searchfilter, bool searchontext, string[] passedfieldstosearchon, string? rawfilter, string? rawsort, int? limitto, bool removenullvalues, CancellationToken cancellationToken) + { + var myentitytypelist = (validforentity ?? "").Split(',', StringSplitOptions.RemoveEmptyEntries); + + if (myentitytypelist.Count() == 0) + myentitytypelist = ODHTypeHelper.GetAllSearchableODHTypes(false); + + var searchresult = new List(); + var searchresultpertype = new Dictionary(); + + return DoAsyncReturn(async () => + { + foreach (var entitytype in myentitytypelist) + { + var customfields = new string[] { "Id", ODHTypeHelper.TranslateTypeToTitleField(entitytype, language), "_Meta.Type", "Self" }; + + foreach(var field in fields) + { + customfields = customfields.AddToStringArray(field); + } + + var result = await SearchTroughEntity(entitytype, ODHTypeHelper.TranslateTypeToSearchField(entitytype), ODHTypeHelper.TranslateTypeString2Table(entitytype), language, customfields, searchfilter, searchontext, passedfieldstosearchon, rawfilter, rawsort, limitto, removenullvalues, cancellationToken); + + if (result != null) + { + searchresult.AddRange(result); + searchresultpertype.Add(entitytype, (uint)result.Count()); + } + } + + return new SearchResult + { + Items = searchresult, + searchTerm = searchfilter, + totalResults = (uint)searchresult.Count, + detailedResults = searchresultpertype + }; + }); + } + + private async Task> SearchTroughEntity(string entitytype, Func fieldsearchfunc, string table, string language, string[] fields, + string? searchfilter, bool searchontext, string[] passedfieldstosearchon, string? rawfilter, string? rawsort, int? limitto, bool removenullvalues, CancellationToken cancellationToken) + { + string endpoint = ODHTypeHelper.TranslateTypeToEndPoint(entitytype); + + //check if there are additionalfilters to add + AdditionalFiltersToAddEndpoint(endpoint).TryGetValue("Read", out var additionalfilter); + + var searchonfields = fieldsearchfunc(language); + + //Add Textfields to search on if searchontext = true + if(searchontext) + { + var textsearchfields = ODHTypeHelper.TranslateTypeToBaseTextField(entitytype, language); + searchonfields = searchonfields.AddToStringArray(textsearchfields); + } + + //Add selected Fields to search on + if (passedfieldstosearchon.Length > 0) + { + searchonfields = searchonfields.AddToStringArray(passedfieldstosearchon); + } + + var query = + QueryFactory.Query() + .SelectRaw("data") + .From(table) + .SearchFilter(searchonfields, searchfilter) + .FilterDataByAccessRoles(UserRolesToFilterEndpoint(endpoint)) + .When(!String.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + .ApplyRawFilter(rawfilter) + .ApplyOrdering(new PGGeoSearchResult() { geosearch = false }, rawsort, "data#>>'\\{Shortname\\}'") + .Limit(limitto ?? int.MaxValue); + + + var data = await query.GetAsync(); + + return data.Select(raw => raw.TransformRawData(language, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null)) + .Where(json => json != null) + .Select(json => json!); + } + + #endregion + } + + +} \ No newline at end of file diff --git a/ContentApiCore/Controllers/generic/SourceController.cs b/ContentApiCore/Controllers/generic/SourceController.cs new file mode 100644 index 0000000..d322009 --- /dev/null +++ b/ContentApiCore/Controllers/generic/SourceController.cs @@ -0,0 +1,258 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Helper.Generic; +using Helper.Identity; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using ContentApiCore.Responses; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers.generic +{ + + [EnableCors("CorsPolicy")] + [NullStringParameterActionFilter] + public class SourceController : OdhController + { + public SourceController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + } + + #region SWAGGER Exposed API + + /// + /// GET Sources List + /// + /// Language field selector, displays data and fields available in the selected language (default:'null' all languages are displayed) + /// IDFilter (Separator ',' List of IDs, 'null' = No Filter), (default:'null') + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Type Filter (Separator ',' Filter Sources by Type ('accommodation','event','odhactivitypoi','webcam','region','municipality','district','tourismassocation','weather','measuringpoint','weatherhistory','weatherforecast','accommodationroom','venue','article','eventshort','wineaward','tag','odhtag'), (default:'null') + /// String to search for, Title in all languages are searched, (default: null) Wiki searchfilter + /// Wiki rawfilter + /// Wiki rawsort + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Collection of SourceLinked Objects + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("Source")] + public async Task GetSourcesAsync( + uint? pagenumber = 1, + PageSize pagesize = null!, + string? language = null, + string? idlist = null, + string? typelist = null, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? searchfilter = null, + string? rawfilter = null, + string? rawsort = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await Get(pagenumber, pagesize, idlist, typelist, language, + fields: fields ?? Array.Empty(), + searchfilter, rawfilter, rawsort, removenullvalues: removenullvalues, + cancellationToken); + } + + /// + /// GET Source Single + /// + /// ID of the Source + /// Language field selector, displays data and fields available in the selected language (default:'null' all languages are displayed) + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// SourceLinked Object + /// Object created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(SourceLinked), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("Source/{id}", Name = "SingleSource")] + public async Task GetSourceSingle(string id, + string? language = null, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? localizationlanguage = null, //TODO ignore this in swagger + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + //Compatibility + if (string.IsNullOrEmpty(language) && !string.IsNullOrEmpty(localizationlanguage)) + language = localizationlanguage; + + return await GetSingle(id, language, fields: fields ?? Array.Empty(), removenullvalues: removenullvalues, cancellationToken); + } + + #endregion + + #region GETTER + + private Task Get( + uint? pagenumber, int? pagesize, string? idfilter, string? typefilter, string? language, string[] fields, + string? searchfilter, string? rawfilter, string? rawsort, bool removenullvalues, + CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + var idlist = CommonListCreator.CreateIdList(idfilter); + var typeslist = CommonListCreator.CreateIdList(typefilter); + + var query = + QueryFactory.Query() + .SelectRaw("data") + .From("sources") + .SourcesWhereExpression( + languagelist: new List(), + idlist: idlist, + typeslist: typeslist, + searchfilter: searchfilter, + language: language, + additionalfilter: additionalfilter, + userroles: UserRolesToFilter + ) + .ApplyRawFilter(rawfilter) + .ApplyOrdering(new PGGeoSearchResult() { geosearch = false }, rawsort, "data#>>'\\{Shortname\\}'"); + + // Get paginated data + var data = + await query + .PaginateAsync( + page: (int)pagenumber, + perPage: pagesize ?? 25); + + var dataTransformed = + data.List.Select( + raw => raw.TransformRawData(language, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null) + ); + + uint totalpages = (uint)data.TotalPages; + uint totalcount = (uint)data.Count; + + return ResponseHelpers.GetResult( + (uint)pagenumber, + totalpages, + totalcount, + null, + dataTransformed, + Url); + }); + } + + private Task GetSingle(string id, string? language, string[] fields, bool removenullvalues, CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + var data = await QueryFactory.Query("sources") + .Select("data") + .Where("id", id.ToLower()) + .When(!string.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + .FilterDataByAccessRoles(UserRolesToFilter) + .FirstOrDefaultAsync(); + + return data?.TransformRawData(language, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null); + }); + } + + #endregion + + #region POST PUT DELETE + + /// + /// POST Insert new Source + /// + /// SourceLinked Object + /// Http Response + //[Authorize(Roles = "DataWriter,DataCreate,SourceManager,SourceCreate")] + [AuthorizeODH(PermissionAction.Create)] + [HttpPost, Route("Source")] + public Task Post([FromBody] SourceLinked source) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Create", out var additionalfilter); + + source.Id = source.Key.ToLower().Replace(" ", "") ?? IdGenerator.GenerateIDFromType(source); + + if (source.LicenseInfo == null) + source.LicenseInfo = new LicenseInfo() { ClosedData = false }; + + return await UpsertData(source, new DataInfo("sources", CRUDOperation.Create), new CompareConfig(false, false), new CRUDConstraints(additionalfilter, UserRolesToFilter)); + }); + } + + /// + /// PUT Modify existing Source + /// + /// Source Id + /// Source Object + /// Http Response + //[Authorize(Roles = "DataWriter,DataModify,SourceManager,SourceModify,SourceUpdate")] + [AuthorizeODH(PermissionAction.Update)] + [HttpPut, Route("Source/{id}")] + public Task Put(string id, [FromBody] SourceLinked source) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Update", out var additionalfilter); + + source.Id = IdGenerator.CheckIdFromType(id); + + return await UpsertData(source, new DataInfo("sources", CRUDOperation.Update), new CompareConfig(false, false), new CRUDConstraints(additionalfilter, UserRolesToFilter)); + }); + } + + /// + /// DELETE Source by Id + /// + /// Source Id + /// Http Response + //[Authorize(Roles = "DataWriter,DataDelete,SourceManager,SourceDelete")] + [AuthorizeODH(PermissionAction.Delete)] + [HttpDelete, Route("Source/{id}")] + public Task Delete(string id) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Delete", out var additionalfilter); + + id = IdGenerator.CheckIdFromType(id); + + return await DeleteData(id, new DataInfo("sources", CRUDOperation.Delete), new CRUDConstraints(additionalfilter, UserRolesToFilter)); + }); + } + + + #endregion + } + + +} \ No newline at end of file diff --git a/ContentApiCore/Controllers/geo/GeoConverterController.cs b/ContentApiCore/Controllers/geo/GeoConverterController.cs new file mode 100644 index 0000000..0cbb348 --- /dev/null +++ b/ContentApiCore/Controllers/geo/GeoConverterController.cs @@ -0,0 +1,100 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using GeoConverter; +using Helper; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using OdhNotifier; +using SqlKata.Execution; +using System.Net.Http; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers.api +{ + public class GeoConverterController : OdhController + { + private readonly IHttpClientFactory _clientFactory; + + public GeoConverterController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier, IHttpClientFactory clientFactory) : base(env, settings, logger, queryFactory, odhpushnotifier) + { + _clientFactory = clientFactory; + } + + /// + /// Converts the KML file from the supplied URL to GeoJSON. + /// + /// The URL to the KML file. + /// The generated GeoJSON file. + [HttpGet] + [Route("GeoConverter/KmlToGeoJson")] + [Produces("application/geo+json")] + [ProducesResponseType(200)] + [ProducesResponseType(404)] + public async Task GetKmlToGeoJson([FromQuery] string url) + { + var client = _clientFactory.CreateClient(); + var response = await client.GetAsync(url); + if (response.StatusCode == System.Net.HttpStatusCode.NotFound) + { + return NotFound($"URL {url} not found."); + } + var body = await response.Content.ReadAsStringAsync(); + return PostKmlToGeoJson(body); + } + + /// + /// Converts the KML provided as the body to GeoJSON. + /// + /// The KML file content. + /// application/geo+json + /// The generated GeoJSON file. + [HttpPost] + [Route("GeoConverter/KmlToGeoJson")] + [Produces("application/geo+json")] + [ProducesResponseType(200)] + public ActionResult PostKmlToGeoJson(string body) + { + return Content(GeoJsonConverter.ConvertFromKml(body), "application/geo+json"); + } + + /// + /// Converts the GPX file from the supplied URL to GeoJSON. + /// + /// The URL to the GPX file. + /// The generated GeoJSON file. + [HttpGet] + [Route("GeoConverter/GpxToGeoJson")] + [Produces("application/geo+json")] + [ProducesResponseType(200)] + [ProducesResponseType(404)] + public async Task GetGpxToGeoJson([FromQuery] string url) + { + var client = _clientFactory.CreateClient(); + var response = await client.GetAsync(url); + if (response.StatusCode == System.Net.HttpStatusCode.NotFound) + { + return NotFound($"URL {url} not found."); + } + var body = await response.Content.ReadAsStringAsync(); + return PostGpxToGeoJson(body); + } + + /// + /// Converts the GPX provided as the body to GeoJSON. + /// + /// The GPX file content. + /// application/geo+json + /// The generated GeoJSON file. + [HttpPost] + [Route("GeoConverter/GpxToGeoJson")] + [Produces("application/geo+json")] + [ProducesResponseType(200)] + public ActionResult PostGpxToGeoJson(string body) + { + return Content(GeoJsonConverter.ConvertFromGpx(body), "application/geo+json"); + } + } +} diff --git a/ContentApiCore/Controllers/helper/ExampleHelper.cs b/ContentApiCore/Controllers/helper/ExampleHelper.cs new file mode 100644 index 0000000..dcc68ba --- /dev/null +++ b/ContentApiCore/Controllers/helper/ExampleHelper.cs @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ContentApiCore.Controllers.api +{ + public class ExampleHelper + { + public List typelist; + public List idlist; + public List languagelist; + public bool? active; + public string? lastchange; + public List publishedonlist; + public List sourcelist; + + public static ExampleHelper Create( + string? typefilter, string? idfilter, string? languagefilter, bool? activefilter, string? source, string? lastchange, string? publishedonfilter) + { + return new ExampleHelper(typefilter, idfilter, languagefilter, activefilter, source, lastchange, publishedonfilter); + } + + private ExampleHelper( + string? typefilter, string? idfilter, string? languagefilter, + bool? activefilter, string? source, string? lastchange, string? publishedonfilter) + { + typelist = new List(); + + if (!String.IsNullOrEmpty(typefilter)) + { + if (int.TryParse(typefilter, out int typeinteger)) + { + typelist = Helper.ExampleListCreator.CreateExampleTypefromFlag(typefilter); + } + else + { + typelist.AddRange(Helper.CommonListCreator.CreateIdList(typefilter)); + } + } + + idlist = Helper.CommonListCreator.CreateIdList(idfilter?.ToUpper()); + languagelist = Helper.CommonListCreator.CreateIdList(languagefilter); + sourcelist = Helper.CommonListCreator.CreateSmgPoiSourceList(source); + active = activefilter; + this.lastchange = lastchange; + publishedonlist = Helper.CommonListCreator.CreateIdList(publishedonfilter?.ToLower()); + } + } +} diff --git a/ContentApiCore/Controllers/other/FileUploadController.cs b/ContentApiCore/Controllers/other/FileUploadController.cs new file mode 100644 index 0000000..c95ccf5 --- /dev/null +++ b/ContentApiCore/Controllers/other/FileUploadController.cs @@ -0,0 +1,187 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.IO; +using Amazon.Runtime; +using Amazon.S3; +using Amazon; +using Amazon.S3.Model; +using Helper; + +namespace ContentApiCore.Controllers.api +{ + //[ApiExplorerSettings(IgnoreApi = true)] + //[Route("api/[controller]")] + [ApiController] + public class FileUploadController : ControllerBase + { + private readonly IWebHostEnvironment env; + private readonly ISettings settings; + protected ILogger Logger { get; } + + public FileUploadController(IWebHostEnvironment env, ISettings settings, ILogger logger) + { + this.env = env; + this.settings = settings; + this.Logger = logger; + } + + + //[ApiExplorerSettings(IgnoreApi = true)] + [Authorize] + //[HttpPost, Route("v1/FileUpload/{type}/{directory}")] + [HttpPost, Route("v1/FileUpload")] + [HttpPost, Route("v1/FileUpload/Image")] + public async Task PostFormData(IFormCollection form) + { + var filenames = new List(); + + // read from settings + var keyid = settings.S3ImageresizerConfig.AccessKey; + var key = settings.S3ImageresizerConfig.SecretKey; + var bucketName = settings.S3ImageresizerConfig.BucketAccessPoint; + + var creds = new BasicAWSCredentials(keyid, key); + var config = new AmazonS3Config(); + config.RegionEndpoint = RegionEndpoint.EUWest1; + var client = new AmazonS3Client(creds, config); + + foreach (var file in form.Files) + { + var filename = $"{Guid.NewGuid()}{Path.GetExtension(file.FileName)}"; + var request = new PutObjectRequest //UploadPartRequest + { + BucketName = bucketName, + Key = filename, + InputStream = file.OpenReadStream(), + ContentType = file.ContentType + }; + var response = await client.PutObjectAsync(request); //UploadPartAsync(request); + + if(IsFileImage(file.ContentType)) + filenames.Add(String.Format("{0}{1}", settings.S3ImageresizerConfig.Url, filename)); + else + filenames.Add(String.Format("{0}{1}", settings.S3ImageresizerConfig.DocUrl, filename)); + } + if (filenames.Count == 1) + return Ok(filenames.FirstOrDefault()); + else + return Ok(filenames); + } + + [ApiExplorerSettings(IgnoreApi = true)] + [Authorize] + [HttpPost, Route("v1/FileUpload/Doc")] + public async Task PostFormDataPDF(IFormCollection form) + { + var filenames = new List(); + + // read from settings + var keyid = settings.S3ImageresizerConfig.AccessKey; + var key = settings.S3ImageresizerConfig.SecretKey; + var bucketName = settings.S3ImageresizerConfig.BucketAccessPoint; + + var creds = new BasicAWSCredentials(keyid, key); + var config = new AmazonS3Config(); + config.RegionEndpoint = RegionEndpoint.EUWest1; + var client = new AmazonS3Client(creds, config); + + foreach (var file in form.Files) + { + var filename = $"{Guid.NewGuid()}{Path.GetExtension(file.FileName)}"; + var request = new PutObjectRequest + { + BucketName = bucketName, + Key = filename, + InputStream = file.OpenReadStream(), + ContentType = file.ContentType + }; + var response = await client.PutObjectAsync(request); + + filenames.Add(String.Format("{0}{1}", settings.S3ImageresizerConfig.DocUrl, filename)); + } + if (filenames.Count == 1) + return Ok(filenames.FirstOrDefault()); + else + return Ok(filenames); + } + + //[ApiExplorerSettings(IgnoreApi = true)] + [Authorize] + [HttpDelete, Route("v1/FileDelete/{filepath}")] + public async Task Delete(string filepath) + { + string keyName = filepath.Replace("|", "\\").Replace("$", "."); + + // read from settings + var keyid = settings.S3ImageresizerConfig.AccessKey; + var key = settings.S3ImageresizerConfig.SecretKey; + var bucketName = settings.S3ImageresizerConfig.BucketAccessPoint; + + var creds = new BasicAWSCredentials(keyid, key); + var config = new AmazonS3Config(); + config.RegionEndpoint = RegionEndpoint.EUWest1; + var client = new AmazonS3Client(creds, config); + + try + { + var deleteObjectRequest = new DeleteObjectRequest + { + BucketName = bucketName, + Key = keyName + }; + + Console.WriteLine("Deleting an object"); + var deleteresult = await client.DeleteObjectAsync(deleteObjectRequest); + + //AWS api is always returning nocontent + //if(deleteresult != null ) + //{ + // switch(deleteresult.HttpStatusCode) + // { + // case System.Net.HttpStatusCode.OK: + // return Ok(String.Format("Success: '{0}' deleted", filepath)); + // case System.Net.HttpStatusCode.NotFound: + // case System.Net.HttpStatusCode.NoContent: + // return NotFound(String.Format("Not found: '{0}'", filepath)); + // default: + // return BadRequest(String.Format("An error occured Http Status: '{0}'", deleteresult.HttpStatusCode.ToString())); + + // } + //} + //else + //{ + // return BadRequest("Generic Error"); + //} + + return Ok(String.Format("Success: '{0}' deleted", filepath)); + } + catch (AmazonS3Exception e) + { + return BadRequest(String.Format("Error encountered on server.Message:'{0}' when deleting an object", e.Message)); + } + catch (Exception e) + { + return BadRequest(String.Format("Unknown encountered on server. Message:'{0}' when deleting an object", e.Message)); + } + } + + //Hack check if contenttype begins with image + private static bool IsFileImage(string contenttype) + { + return contenttype.ToLower().StartsWith("image"); + } + } + + +} diff --git a/ContentApiCore/Controllers/other/GeoController.cs b/ContentApiCore/Controllers/other/GeoController.cs new file mode 100644 index 0000000..4b55090 --- /dev/null +++ b/ContentApiCore/Controllers/other/GeoController.cs @@ -0,0 +1,167 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using ContentApiCore.Responses; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers +{ + [EnableCors("CorsPolicy")] + //[ApiExplorerSettings(IgnoreApi = true)] + [NullStringParameterActionFilter] + public class GeoController : OdhController + { + public GeoController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + } + + #region SWAGGER Exposed API + + /// + /// GET GeoShapes List + /// + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// String to search for, Title in all languages are searched, (default: null) Wiki searchfilter + /// Wiki rawfilter + /// Wiki rawsort + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Collection of GeoShapes Objects + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + //[OdhCacheOutput(ClientTimeSpan = 0, ServerTimeSpan = 3600, CacheKeyGenerator = typeof(CustomCacheKeyGenerator))] + [HttpGet, Route("GeoShapes")] + //[Authorize(Roles = "DataReader,CommonReader,AccoReader,ActivityReader,PoiReader,ODHPoiReader,PackageReader,GastroReader,EventReader,ArticleReader")] + public async Task GetGeoShapesAsync( + uint? pagenumber = 1, + PageSize pagesize = null!, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? searchfilter = null, + string? rawfilter = null, + string? rawsort = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await Get(pagenumber, pagesize, fields: fields ?? Array.Empty(), + searchfilter, rawfilter, rawsort, removenullvalues: removenullvalues, + cancellationToken); + } + + /// + /// GET GeoShape Single + /// + /// ID of the Tag + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// GeoShapes Object + /// Object created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(GeoShapes), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [HttpGet, Route("GeoShapes/{id}", Name = "SingleShapes")] + //[Authorize(Roles = "DataReader,CommonReader,AccoReader,ActivityReader,PoiReader,ODHPoiReader,PackageReader,GastroReader,EventReader,ArticleReader")] + public async Task GetGeoShapeSingle(uint? pagenumber, int? pagesize, string id, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await GetSingle(id, fields: fields ?? Array.Empty(), removenullvalues: removenullvalues, cancellationToken); + } + + #endregion + + #region GETTER + + private Task Get( + uint? pagenumber, int? pagesize, + string[] fields, string? searchfilter, string? rawfilter, string? rawsort, bool removenullvalues, + CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + var query = + QueryFactory.Query() + .SelectRaw("data") + .From("shapes") + .ApplyRawFilter(rawfilter) + .ApplyOrdering(new PGGeoSearchResult() { geosearch = false }, rawsort, "data #>>'\\{Type\\}', data#>>'\\{Name\\}'"); + + // Get paginated data + var data = + await query + .PaginateAsync( + page: (int)pagenumber, + perPage: pagesize ?? 10); + + var dataTransformed = + data.List.Select( + raw => raw.TransformRawData(null, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null) + ); + + uint totalpages = (uint)data.TotalPages; + uint totalcount = (uint)data.Count; + + return ResponseHelpers.GetResult( + (uint)pagenumber, + totalpages, + totalcount, + null, + dataTransformed, + Url); + + }); + } + + private Task GetSingle(string id, string[] fields, bool removenullvalues, CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + //Additional Read Filters to Add Check + AdditionalFiltersToAdd.TryGetValue("Read", out var additionalfilter); + + if (int.TryParse(id, out var idint)) + { + var data = await QueryFactory.Query("shapes") + .SelectRaw("data") + .Where("id", idint) + .When(!String.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + //.FilterDataByAccessRoles(UserRolesToFilter) + .FirstOrDefaultAsync(); + + return data?.TransformRawData(null, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null); + } + else + throw new Exception("id has to be numeric"); + }); + } + + #endregion + } + + +} \ No newline at end of file diff --git a/ContentApiCore/Controllers/other/JsonLDController.cs b/ContentApiCore/Controllers/other/JsonLDController.cs new file mode 100644 index 0000000..1c6ffda --- /dev/null +++ b/ContentApiCore/Controllers/other/JsonLDController.cs @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text.Json.Serialization; +using System.Text.Json; +using System.Threading.Tasks; +using OdhNotifier; + +namespace ContentApiCore.Controllers.api +{ + public class JsonLDController : OdhController + { + public JsonLDController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier, IHttpClientFactory httpClientFactory) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + + } + + /// + /// GET Detail Data in JSON LD Format (Schema.org Datatypes as output) + /// + /// Data Type to transform currently available: ('accommodation', 'gastronomy', 'event', 'recipe', 'poi', 'region', 'tv', 'municipality', 'district', 'skiarea') required + /// ID of the data to transform, required + /// Output Language, standard EN + /// ID to show on Json LD @id, not provided Id of ODH api call is taken + /// image url to show on Json LD @image, not provided image url of data is taken + /// url to show on Json LD @id, not provided idtoshow is taken, idtoshow not provided url is filled with url of the data + /// Show the @id property in Json LD default value true + /// + //[Authorize(Roles = "DataReader")] + [HttpGet, Route("JsonLD/DetailInLD")] + public async Task GetDetailInLD(string type, string Id, string? language = "en", string? idtoshow = "", string? urltoshow = "", string? imageurltoshow = "", bool showid = true) + { + try + { + var location = new Uri($"{HttpContext.Request.Scheme}://{HttpContext.Request.Host}/{HttpContext.Request.Path}"); + var currentroute = location.AbsoluteUri; + + var myobject = default(List); + + switch (type.ToLower()) + { + case "example": + myobject = await LoadFromRavenDBSchemaNet(Id, currentroute + "/Example/" + Id, language, idtoshow, urltoshow, imageurltoshow, type.ToLower(), showid, "accommodations"); + break; + default: + myobject = new List(); + myobject.Add(new { message = "JSON LD not available" }); + break; + } + + var myjson = ""; + + if (myobject != null) + { + var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault }; + + if (type.ToLower() == "event") + myjson = System.Text.Json.JsonSerializer.Serialize(myobject, options); + else + myjson = System.Text.Json.JsonSerializer.Serialize(myobject.FirstOrDefault(), options); + + return Ok(myjson); + } + else + return NotFound(); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + + private async Task> LoadFromRavenDBSchemaNet(string Id, string currentroute, string language, string idtoshow, string urltoshow, string imagetoshow, string type, bool showid, string table) + { + //TO CHECK + var query = + QueryFactory.Query(table) + .Select("data") + .Where("id", Id.ToUpper()) + //.Anonymous_Logged_UserRule_GeneratedColumn(FilterClosedData, !ReducedData); + //.When(FilterClosedData, q => q.FilterClosedData()); + .FilterDataByAccessRoles(UserRolesToFilter); + + var myobject = await query.FirstOrDefaultAsync(); + + if (myobject != null) + { + var myparsedobject = JsonConvert.DeserializeObject(myobject.Value); + if (myparsedobject is { }) + return JsonLDTransformer.TransformToSchemaNet.TransformDataToSchemaNet(myparsedobject, currentroute, type, language, null, idtoshow, urltoshow, imagetoshow, showid); + } + + return new(); + } + + } +} diff --git a/ContentApiCore/Controllers/other/ODHProxyController.cs b/ContentApiCore/Controllers/other/ODHProxyController.cs new file mode 100644 index 0000000..0c007b4 --- /dev/null +++ b/ContentApiCore/Controllers/other/ODHProxyController.cs @@ -0,0 +1,143 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using AspNetCore.Proxy; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers.other +{ + [ApiExplorerSettings(IgnoreApi = true)] + public class ODHProxyController : ControllerBase + { + + [ApiExplorerSettings(IgnoreApi = true)] + [HttpGet,HttpHead, Route("v1/ODHProxy/{*url}")] + public Task GetODHProxy(string url) + { + try + { + var parameter = "?"; + + foreach (var paramdict in HttpContext.Request.Query) + { + parameter = parameter + paramdict.Key + "=" + paramdict.Value + "&"; + } + + var fullurl = url + parameter.Remove(parameter.Length - 1, 1); + + //Quick production fix + //fullurl = fullurl.Replace("https:/", "https://"); + + Console.WriteLine("Url to proxy: " + fullurl); + + return this.HttpProxyAsync(fullurl); + } + catch(Exception ex) + { + return Task.FromException(ex); + } + } + + [ApiExplorerSettings(IgnoreApi = true)] + [HttpHead, Route("v1/HeadRequest/{*url}")] + public async Task GetGetHeadRequest(string url) + { + try + { + var parameter = "?"; + + foreach (var paramdict in HttpContext.Request.Query) + { + parameter = parameter + paramdict.Key + "=" + paramdict.Value + "&"; + } + + var fullurl = url + parameter.Remove(parameter.Length - 1, 1); + + var request = HttpContext.CreateProxyHttpRequest(new Uri(fullurl)); + + using (var client = new HttpClient()) + { + var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); + + await HttpContext.CopyProxyHttpResponse(response); + + return new EmptyResult(); + } + + } + catch (Exception ex) + { + return BadRequest(); + } + } + } + + public static class ODHRequestExtensions + { + public static HttpRequestMessage CreateProxyHttpRequest(this HttpContext context, Uri uri) + { + var request = context.Request; + + var requestMessage = new HttpRequestMessage(); + var requestMethod = request.Method; + if (!HttpMethods.IsGet(requestMethod) && + !HttpMethods.IsHead(requestMethod) && + !HttpMethods.IsDelete(requestMethod) && + !HttpMethods.IsTrace(requestMethod)) + { + var streamContent = new StreamContent(request.Body); + requestMessage.Content = streamContent; + } + + // Copy the request headers + foreach (var header in request.Headers) + { + if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) && requestMessage.Content != null) + { + requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()); + } + } + + requestMessage.Headers.Host = uri.Authority; + requestMessage.RequestUri = uri; + requestMessage.Method = new HttpMethod(request.Method); + + return requestMessage; + } + + public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage responseMessage) + { + if (responseMessage == null) + { + throw new ArgumentNullException(nameof(responseMessage)); + } + + var response = context.Response; + + response.StatusCode = (int)responseMessage.StatusCode; + foreach (var header in responseMessage.Headers) + { + response.Headers[header.Key] = header.Value.ToArray(); + } + + foreach (var header in responseMessage.Content.Headers) + { + response.Headers[header.Key] = header.Value.ToArray(); + } + + // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response. + response.Headers.Remove("transfer-encoding"); + + using (var responseStream = await responseMessage.Content.ReadAsStreamAsync()) + { + await responseStream.CopyToAsync(response.Body); + } + } + } +} diff --git a/ContentApiCore/Controllers/other/PushNotificationController.cs b/ContentApiCore/Controllers/other/PushNotificationController.cs new file mode 100644 index 0000000..ae8a6e5 --- /dev/null +++ b/ContentApiCore/Controllers/other/PushNotificationController.cs @@ -0,0 +1,307 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using OdhNotifier; +using PushServer; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers.api +{ + public class PushNotificationController : OdhController + { + private readonly ISettings settings; + private readonly IWebHostEnvironment env; + + public PushNotificationController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + this.settings = settings; + this.env = env; + } + + #region Exposed Generic Endpoint + + /// + /// POST Generic Push Endpoint + /// + /// Http Response + [ApiExplorerSettings(IgnoreApi = true)] + [Authorize(Roles = "DataWriter,DataCreate,PushMessageWriter")] + [HttpPost, Route("PushData/{id}/{type}/{publisher}")] + public async Task PushData(string id, string type, string publisher, bool usemocks = true, string ? language = null) + { + IDictionary resultdict = new Dictionary(); + + //If environment is set on production deactivate usemocks + //if (!env.IsDevelopment()) + usemocks = false; + + foreach (var publish in publisher.Split(",")) + { + var data = new PushResponse(); + data.Publisher = publish; + data.Date = DateTime.Now; + data.Id = Guid.NewGuid().ToString(); + + PushObject pushobject = new PushObject(); + pushobject.Type = type; + pushobject.Id = id; + + data.PushObject = pushobject; + + //Check if data can be pushed + var checkobjectresult = await CheckPublishedOnAttribute(id, type, publish); + + if (checkobjectresult.Item1) + { + switch (publish) + { + //FCM Push + case "noi-communityapp": + data.Result = usemocks ? new PushResult() { Error = "", Success = true, Messages = 1, Response = "This is a mockup response" } : await GetDataAndSendFCMMessage(type, id, publish, language); + break; + + //NOTIFIER + case "idm-marketplace": + if (usemocks) + data.Result = new NotifierResponse() { HttpStatusCode = System.Net.HttpStatusCode.OK, Response = "This is a mockup response", Service = "idm-marketplace", Success = true }; + else + { + var notifierresult = await OdhPushnotifier.PushToPublishedOnServices(id, type, "manual.push", new Dictionary { { "imageschanged", true } }, false, "push.api", new List() { publish }); + data.Result = notifierresult != null && + notifierresult.ContainsKey(publish) ? + notifierresult[publish] : + new { Success = false }; + } + break; + default: + data.Result = new { Response = "Publisher is not registered on this api", Success = false }; + break; + } + } + else + { + data.Result = new { Response = checkobjectresult.Item2, Success = false }; + } + + + //Save the result in a push table + var insertresult = await QueryFactory.Query("pushresults") + .InsertAsync(new JsonBData() { id = data.Id, data = new JsonRaw(data) }); + + resultdict.Add(publish, data); + } + + return Ok(resultdict); + } + + private async Task<(bool, string)> CheckPublishedOnAttribute(string id, string type, string publish) + { + //Check if the object has the publisher in the PublishedOn Array + var mytable = ODHTypeHelper.TranslateTypeString2Table(type); + + var query = + QueryFactory.Query(mytable) + .Select("data") + .Where("id", ODHTypeHelper.ConvertIdbyTypeString(type, id)); + + var data = await query.FirstOrDefaultAsync(); + + if (data is not { }) + return (false, "data not found"); + + var myobject = ODHTypeHelper.ConvertJsonRawToObject(type, data); + + + if (myobject == null) + return (false, "data not found"); + else if(myobject != null && myobject is IPublishedOn) + { + //check if publisher is set + if ((myobject as IPublishedOn).PublishedOn != null && (myobject as IPublishedOn).PublishedOn.Contains(publish)) + return (true,""); + else + return (false,"publisher not activated for this record"); + } + + return (false, "something went wrong"); + } + + #endregion + + + #region Using NOI PushServer + + /// + /// GET Send a PushMessage to NOI Pushserver + /// + /// Http Response + [ApiExplorerSettings(IgnoreApi = true)] + [Authorize(Roles = "DataWriter,DataCreate,PushMessageWriter")] + [HttpGet, Route("PushNotification/{type}/{id}")] + public async Task Get(string type, string id) + { + //Get the object + var mytable = ODHTypeHelper.TranslateTypeString2Table(type); + var mytype = ODHTypeHelper.TranslateTypeString2Type(type); + + var query = + QueryFactory.Query(mytable) + .Select("data") + .Where("id", ODHTypeHelper.ConvertIdbyTypeString(type, id)); + //.When(FilterClosedData, q => q.FilterClosedData()); + + // TODO: Create a logic that constructs a message out of the object + + var pushserverconfig = settings.PushServerConfig; + + // TODO: Construct the message + + var message = new PushServerMessage(); + + var result = await SendToPushServer.SendMessageToPushServer(pushserverconfig.ServiceUrl, message, pushserverconfig.User, pushserverconfig.Password, message.destination.language); + + return Ok(result); + } + + /// + /// POST Send a PushMessage to NOI Pushserver + /// + /// PushServerMessage Object + /// Http Response + [ApiExplorerSettings(IgnoreApi = true)] + [Authorize(Roles = "DataWriter,DataCreate,PushMessageWriter")] + [HttpPost, Route("PushNotification")] + public async Task Post([FromBody] PushServerMessage message) + { + var pushserverconfig = settings.PushServerConfig; + + var result = await SendToPushServer.SendMessageToPushServer(pushserverconfig.ServiceUrl, message, pushserverconfig.User, pushserverconfig.Password, message.destination.language); + + return Ok(result); + } + + #endregion + + #region Using FCM Google Api + + /// + /// GET Send a PushMessage to FCM Google Api + /// + /// Http Response + [ApiExplorerSettings(IgnoreApi = true)] + [Authorize(Roles = "DataWriter,DataCreate,PushMessageWriter")] + [HttpGet, Route("FCMMessage/{type}/{id}/{identifier}/{language}")] + public async Task GetFCM(string type, string id, string identifier, string? language = null) + { + return Ok(GetDataAndSendFCMMessage(type, id, identifier, language)); + } + + private async Task GetDataAndSendFCMMessage(string type, string id, string identifier, string? language = null) + { + try + { + //Get the object + var mytable = ODHTypeHelper.TranslateTypeString2Table(type); + var mytype = ODHTypeHelper.TranslateTypeString2Type(type); + + var query = + QueryFactory.Query(mytable) + .Select("data") + .Where("id", ODHTypeHelper.ConvertIdbyTypeString(type, id)); + //.When(FilterClosedData, q => q.FilterClosedData()); + + + var data = await query.FirstOrDefaultAsync(); + + if (data is not { }) + throw new Exception("no data"); + + var myobject = ODHTypeHelper.ConvertJsonRawToObject(type, data); + + if (myobject == null) + throw new Exception("object conversion failed"); + + List languages = new List(); + + if (language != null) + languages = language.Split(',').ToList(); + else if(myobject is IHasLanguage && (myobject as IHasLanguage).HasLanguage != null) + languages = (myobject as IHasLanguage).HasLanguage.ToList(); + + List messages = new(); + + foreach (var lang in languages) + { + //Construct the message + var message = FCMMessageConstructor.ConstructMyMessageV2(identifier, lang.ToLower(), myobject); + + if (message != null) + messages.Add(message); + else + throw new Exception("Message could not be constructed"); + } + + var pushserverconfig = settings.FCMConfig.Where(x => x.Identifier == identifier).FirstOrDefault(); + + if (pushserverconfig == null) + throw new Exception("PushserverConfig could not be found"); + List resultlist = new(); + + string sendurl = $"https://fcm.googleapis.com/v1/projects/{pushserverconfig.ProjecTName}/messages:send"; + + + foreach (var message in messages) + { + //var result = await FCMPushNotification.SendNotification(message, sendurl, pushserverconfig.SenderId, pushserverconfig.ServerKey); + + var result = await FCMPushNotification.SendNotificationV2(message, sendurl, pushserverconfig.ServiceAccount); + + resultlist.Add(result); + } + + return PushResult.MergeMultipleFCMPushNotificationResponses(resultlist); + } + catch (Exception ex) + { + return new PushResult() { Error = ex.Message, Response = "Error", Success = false }; + } + } + + /// + /// POST Send a PushMessage directly to Google Api + /// + /// FCMModels Object + /// Http Response + [ApiExplorerSettings(IgnoreApi = true)] + [Authorize(Roles = "DataWriter,DataCreate,PushMessageWriter")] + [HttpPost, Route("FCMMessage/{identifier}")] + public async Task PostFCMMessage(string identifier, [FromBody] FCMModels message) + { + //TODO add configurable FCM setting where config can be accessed by identifier + var pushserverconfig = settings.FCMConfig.Where(x => x.Identifier == identifier).FirstOrDefault(); + + if (pushserverconfig != null) + { + var result = await FCMPushNotification.SendNotification(message, " https://fcm.googleapis.com/fcm/send", pushserverconfig.SenderId, pushserverconfig.ServerKey); + + return Ok(result); + } + else + return BadRequest("not found"); + } + + #endregion + } +} diff --git a/ContentApiCore/Controllers/raw/RawApiController.cs b/ContentApiCore/Controllers/raw/RawApiController.cs new file mode 100644 index 0000000..567fbe1 --- /dev/null +++ b/ContentApiCore/Controllers/raw/RawApiController.cs @@ -0,0 +1,232 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using DataModel.Annotations; +using Helper; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using ContentApiCore.Filters; +using ContentApiCore.Responses; +using OdhNotifier; +using SqlKata.Execution; +using System; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore.Controllers.raw +{ + //[ApiExplorerSettings(IgnoreApi = true)] + public class RawdataApiController : OdhController + { + public RawdataApiController(IWebHostEnvironment env, ISettings settings, ILogger logger, QueryFactory queryFactory, IOdhPushNotifier odhpushnotifier) + : base(env, settings, logger, queryFactory, odhpushnotifier) + { + } + + /// + /// GET Raw Data List + /// + /// Pagenumber + /// Elements per Page, (default:10) + /// Type Filter (Separator ',' List of rawdata types, 'null' = No Filter), (default:'null') + /// Source Filter (Separator ',' List of rawdata sources, 'null' = No Filter), (default:'null') + /// SourceInterface Filter (Separator ',' List of Sourceinterfaces, 'null' = No Filter), (default:'null') + /// SourceIDFilter (Separator ',' List of Rawdata SourceIDs, 'null' = No Filter), (default:'null') + /// IDFilter (Separator ',' List of Rawdata IDs, 'null' = No Filter), (default:'null') + /// Get only latest data + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Currently not working on rawdataWiki rawfilter + /// Currently not working on rawdataWiki rawsort + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Collection of Raw Data Objects + /// List created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(JsonResult), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [ApiExplorerSettings(IgnoreApi = true)] + [OdhCacheOutput(ClientTimeSpan = 0, ServerTimeSpan = 3600, CacheKeyGenerator = typeof(CustomCacheKeyGenerator))] + [HttpGet, Route("Rawdata")] + //[Authorize(Roles = "DataReader,CommonReader,AccoReader,ActivityReader,PoiReader,ODHPoiReader,PackageReader,GastroReader,EventReader,ArticleReader")] + public async Task GetRawdataAsync( + uint pagenumber = 1, + PageSize pagesize = null!, + [SwaggerEnum(new[] { "event_euracnoi", "odhactivitypoi-lift", "odhactivitypoi-slope", "odhactivitypoi-museum", "weather", "event_centrotrevi-drin", "ejob" })] + string? type = null, + [SwaggerEnum(new[] { "dss", "eurac", "siag", "centrotrevi-drin", "looptec" })] + string? source = null, + string? sourceinterface = null, + string? sourceid = null, + string? idlist = null, + bool latest = true, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + string? searchfilter = null, + string? rawfilter = null, + string? rawsort = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await Get(pagenumber, pagesize, type, source, idlist, sourceid, latest, fields: fields ?? Array.Empty(), + searchfilter, rawfilter, rawsort, removenullvalues: removenullvalues, cancellationToken); + } + + /// + /// GET Rawdata Single + /// + /// ID of rawdata + /// Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields + /// Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki + /// Rawdata Object + /// Object created + /// Request Error + /// Internal Server Error + [ProducesResponseType(typeof(RawDataStoreWithId), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + [ApiExplorerSettings(IgnoreApi = true)] + [HttpGet, Route("Rawdata/{id}", Name = "SingleRawdata")] + public async Task GetRawdataSingle( + string id, + [ModelBinder(typeof(CommaSeparatedArrayBinder))] + string[]? fields = null, + bool removenullvalues = false, + CancellationToken cancellationToken = default) + { + return await GetSingle(id, fields: fields ?? Array.Empty(), removenullvalues: removenullvalues, cancellationToken); + } + + private Task Get( + uint pagenumber, int? pagesize, + string type, string source, string ids, string sourceids, bool latest, + string[] fields, string? searchfilter, string? rawfilter, string? rawsort, + bool removenullvalues, + CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + var typelist = !string.IsNullOrEmpty(type) ? type.Split(",").ToList() : null; + var sourcelist = !string.IsNullOrEmpty(source) ? source.Split(",").ToList() : null; + var idlist = !string.IsNullOrEmpty(ids) ? ids.Split(",").ToList() : null; + var sourceidlist = !string.IsNullOrEmpty(sourceids) ? sourceids.Split(",").ToList() : null; + + //Example latest records + //select* + //from rawdata + //where id in (SELECT max(id) FROM rawdata where type = 'ejob' group by sourceid) + + //TO CHECK additionalfilter??? + + var query = + QueryFactory.Query() + .When(latest, q => q.SelectRaw("max(id)")) + .From("rawdata") + .RawdataWhereExpression(idlist, + sourceidlist, typelist, sourcelist, + additionalfilter: null, + userroles: UserRolesToFilter) + .ApplyRawFilter(rawfilter) + .OrderOnlyByRawSortIfNotNull(rawsort) + .When(latest, q => q.GroupBy("sourceid")); + + //rawfilter and rawsort could be extended with a generated column "data" which only applies when rawtype is json + + if (latest) + { + var query2 = + QueryFactory.Query() + .From("rawdata") + .WhereIn("id", query); + + // Get paginated data + var data = + await query2 + .PaginateAsync( + page: (int)pagenumber, + perPage: pagesize ?? 25); + + + var jsonrawdata = data.List.Select(raw => new JsonRaw(raw.UseJsonRaw())).ToList(); + + var dataTransformed = + jsonrawdata.Select( + raw => raw.TransformRawData(null, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null) + ); + + uint totalpages = (uint)data.TotalPages; + uint totalcount = (uint)data.Count; + + return ResponseHelpers.GetResult( + pagenumber, + totalpages, + totalcount, + null, + dataTransformed, + Url); + } + else + { + // Get paginated data + var data = + await query + .PaginateAsync( + page: (int)pagenumber, + perPage: pagesize ?? 25); + + + var jsonrawdata = data.List.Select(raw => new JsonRaw(raw.UseJsonRaw())).ToList(); + + var dataTransformed = + jsonrawdata.Select( + raw => raw.TransformRawData(null, fields, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null) + ); + + uint totalpages = (uint)data.TotalPages; + uint totalcount = (uint)data.Count; + + return ResponseHelpers.GetResult( + pagenumber, + totalpages, + totalcount, + null, + dataTransformed, + Url); + } + + + }); + } + + private Task GetSingle(string id, + string[] fields, + bool removenullvalues, + CancellationToken cancellationToken) + { + return DoAsyncReturn(async () => + { + if (int.TryParse(id, out var numericid)) + { + var query = + QueryFactory.Query("rawdata") + .Where("id", numericid); + //.When(FilterClosedData, q => q.FilterClosedData_Raw()); + + var data = await query.FirstOrDefaultAsync(); + + //return data?.TransformRawData(language, fields, checkCC0: FilterCC0License, filterClosedData: FilterClosedData, filteroutNullValues: removenullvalues, urlGenerator: UrlGenerator, fieldstohide: null); + return data != null ? data.UseJsonRaw() : new RawDataStoreWithId(); + } + else + return BadRequest("Id could not be found"); + + }); + } + + } +} diff --git a/ContentApiCore/Dockerfile b/ContentApiCore/Dockerfile new file mode 100644 index 0000000..4d9d756 --- /dev/null +++ b/ContentApiCore/Dockerfile @@ -0,0 +1,43 @@ +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +WORKDIR /app +EXPOSE 80 +EXPOSE 443 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src +COPY DataModel/DataModel.csproj DataModel/ +COPY Helper/Helper.csproj Helper/ +COPY OdhNotifier/OdhNotifier.csproj OdhNotifier/ +COPY PushServer/PushServer.csproj EBMS/ +COPY JsonLDTransformer/JsonLDTransformer.csproj JsonLDTransformer/ +COPY ContentApiCore/ContentApiCore.csproj ContentApiCore/ +RUN dotnet restore ContentApiCore/ContentApiCore.csproj +COPY . . +WORKDIR /src/ContentApiCore +RUN dotnet build ContentApiCore.csproj -c Release -o /app + +FROM build AS test +WORKDIR /src +RUN dotnet test --filter Category!=Integration ContentApiCore.sln + +FROM build AS publish +RUN dotnet publish ContentApiCore.csproj -c Release -o /app/publish +# Install dotnet debug tools +RUN dotnet tool install --tool-path /tools dotnet-counters +RUN dotnet tool install --tool-path /tools dotnet-trace +RUN dotnet tool install --tool-path /tools dotnet-dump +RUN dotnet tool install --tool-path /tools dotnet-gcdump + +FROM base AS final +# Copy dotnet-tools +WORKDIR /tools +COPY --from=publish /tools . +WORKDIR /app +COPY --from=publish /app/publish . +COPY ContentApiCore/xml/RequestInterceptor.xml xml/ +COPY ContentApiCore/appsettings.Production.json appsettings.json + +# Expose the API port +EXPOSE 80 + +ENTRYPOINT ["dotnet", "ContentApiCore.dll"] diff --git a/ContentApiCore/Extensions/DistributedCachingExtensions.cs b/ContentApiCore/Extensions/DistributedCachingExtensions.cs new file mode 100644 index 0000000..58e5426 --- /dev/null +++ b/ContentApiCore/Extensions/DistributedCachingExtensions.cs @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.Extensions.Caching.Distributed; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore +{ + public static class DistributedCachingExtensions + { + public async static Task SetCacheValueAsync(this IDistributedCache distributedCache, string key, T value, CancellationToken token = default) where T : notnull + { + await distributedCache.SetAsync(key, value.ToByteArray(), token); + } + + public async static Task SetCacheValueAsync(this IDistributedCache distributedCache, string key, TimeSpan timewindow, T value, CancellationToken token = default) where T : notnull + { + //var options = new DistributedCacheEntryOptions { AbsoluteExpiration = DateTimeOffset.Now.Add(timewindow) }; + var options = new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = timewindow }; + await distributedCache.SetAsync(key, value.ToByteArray(), options, token); + } + + public async static Task GetCacheValueAsync(this IDistributedCache distributedCache, string key, CancellationToken token = default(CancellationToken)) where T : class + { + var result = await distributedCache.GetAsync(key, token); + return result.FromByteArray(); + } + } +} diff --git a/ContentApiCore/Extensions/HttpContextExtensions.cs b/ContentApiCore/Extensions/HttpContextExtensions.cs new file mode 100644 index 0000000..658c778 --- /dev/null +++ b/ContentApiCore/Extensions/HttpContextExtensions.cs @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace ContentApiCore +{ + public static class HttpContextExtensions + { + public static void AddRateLimitHeaders(this HttpContext context, int maxrequests, int requestsdone, int timewindow, string policy, CancellationToken token = default) + { + var remainingrequests = maxrequests - requestsdone; + + context.Response.Headers.Add("X-Rate-Limit-Policy", policy); + context.Response.Headers.Add("X-Rate-Limit-Limit", maxrequests.ToString()); + context.Response.Headers.Add("X-Rate-Limit-Remaining", remainingrequests.ToString()); + context.Response.Headers.Add("X-Rate-Limit-Reset", timewindow.ToString()); + } + } +} diff --git a/ContentApiCore/Extensions/MiddlewareExtensions.cs b/ContentApiCore/Extensions/MiddlewareExtensions.cs new file mode 100644 index 0000000..bf80957 --- /dev/null +++ b/ContentApiCore/Extensions/MiddlewareExtensions.cs @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper.Identity; +using Microsoft.AspNetCore.Builder; + +namespace ContentApiCore +{ + public static class MiddlewareExtensions + { + public static IApplicationBuilder UseRateLimiting(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + + public static IApplicationBuilder UseKeycloakAuthorizationService(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} diff --git a/ContentApiCore/Extensions/Serialization.cs b/ContentApiCore/Extensions/Serialization.cs new file mode 100644 index 0000000..f935c40 --- /dev/null +++ b/ContentApiCore/Extensions/Serialization.cs @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Newtonsoft.Json; +using System.Text; + +namespace ContentApiCore +{ + public static class Serialization + { + public static byte[] ToByteArray(this T objectToSerialize) where T : notnull + { + return Encoding.Default.GetBytes(JsonConvert.SerializeObject(objectToSerialize)); + } + + public static T? FromByteArray(this byte[] arrayToDeserialize) where T : class + { + if (arrayToDeserialize == null) + { + return default; + } + + return JsonConvert.DeserializeObject(Encoding.Default.GetString(arrayToDeserialize)); + } + } +} diff --git a/ContentApiCore/Filters/NullStringParameterActionFilterAttribute.cs b/ContentApiCore/Filters/NullStringParameterActionFilterAttribute.cs new file mode 100644 index 0000000..05bb388 --- /dev/null +++ b/ContentApiCore/Filters/NullStringParameterActionFilterAttribute.cs @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Mvc.Filters; +using System.Linq; + +namespace ContentApiCore.Controllers +{ + public class NullStringParameterActionFilterAttribute : ActionFilterAttribute + { + public NullStringParameterActionFilterAttribute() + { + } + + public override void OnActionExecuting(ActionExecutingContext context) + { + foreach (var key in context.ActionArguments.Keys.ToArray()) + { + var value = context.ActionArguments[key]; + if (value as string == "null") + { + context.ActionArguments[key] = null!; + } + } + base.OnActionExecuting(context); + } + } +} \ No newline at end of file diff --git a/ContentApiCore/Filters/OdhCacheOutputAttribute.cs b/ContentApiCore/Filters/OdhCacheOutputAttribute.cs new file mode 100644 index 0000000..2e7b7ac --- /dev/null +++ b/ContentApiCore/Filters/OdhCacheOutputAttribute.cs @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using AspNetCore.CacheOutput; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace ContentApiCore.Filters +{ + public class OdhCacheOutputAttribute : CacheOutputAttribute + { + protected override bool IsCachingAllowed(FilterContext actionContext, bool anonymousOnly) + { + var environment = actionContext.HttpContext.RequestServices.GetService(); + if (environment?.IsDevelopment() ?? false) + { + return false; + } + return base.IsCachingAllowed(actionContext, anonymousOnly); + } + } +} diff --git a/ContentApiCore/Filters/RequestInterceptorAttribute.cs b/ContentApiCore/Filters/RequestInterceptorAttribute.cs new file mode 100644 index 0000000..1c8e8f9 --- /dev/null +++ b/ContentApiCore/Filters/RequestInterceptorAttribute.cs @@ -0,0 +1,173 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Routing; +using ContentApiCore.Controllers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ContentApiCore.Filters +{ + public class RequestInterceptorAttribute : ActionFilterAttribute + { + private readonly ISettings settings; + + public RequestInterceptorAttribute(ISettings settings) + { + this.settings = settings; + } + + public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + context.ActionDescriptor.RouteValues.TryGetValue("action", out string? actionid); + context.ActionDescriptor.RouteValues.TryGetValue("controller", out string? controllerid); + + var matchedactiontointercept = GetActionsToIntercept(actionid, controllerid, context.ActionArguments); + + if (matchedactiontointercept != null) + { + RouteValueDictionary redirectTargetDictionary = new(); + + redirectTargetDictionary.Add("action", matchedactiontointercept.RedirectAction); + redirectTargetDictionary.Add("controller", matchedactiontointercept.RedirectController); + + if (matchedactiontointercept.RedirectQueryStrings != null) + { + foreach (var redirectqs in matchedactiontointercept.RedirectQueryStrings) + { + if (context.ActionArguments.ContainsKey(redirectqs)) + redirectTargetDictionary.Add(redirectqs, context.ActionArguments[redirectqs]); + } + } + + context.Result = new RedirectToRouteResult(redirectTargetDictionary); + await context.Result.ExecuteResultAsync(context); + } + + await base.OnActionExecutionAsync(context, next); + } + + public RequestInterceptorConfig? GetActionsToIntercept(string? actionid, string? controller, IDictionary actionarguments) + { + if (settings.RequestInterceptorConfig != null && settings.RequestInterceptorConfig.Where(x => x.Action == actionid && x.Controller == controller).Count() > 0) + { + foreach(var validconfig in settings.RequestInterceptorConfig.Where(x => x.Action == actionid && x.Controller == controller)) + { + var match = GetQueryStringsToInterceptAndMatch(validconfig, actionarguments); + + if (match) + return validconfig; + } + } + + return null; + } + + public bool GetQueryStringsToInterceptAndMatch(RequestInterceptorConfig config, IDictionary querystrings) + { + // Forget about cancellationtoken and other generated + Dictionary configdict = new(); + + if (config.QueryStrings != null) + { + foreach (var item in config.QueryStrings) + { + var configqssplitted = item.Split("="); + + if (configqssplitted.Count() >= 2) + { + configdict.TryAdd(configqssplitted[0], configqssplitted[1].ToLower()); + } + } + } + + var actualdict = new Dictionary(); + + List toexclude = new() { "cancellationToken" }; + + foreach(var item in querystrings) + { + if (!toexclude.Contains(item.Key)) + { + if (item.Key == "pagesize") + { + actualdict.TryAdd(item.Key, ((PageSize?)item.Value)?.Value.ToString()); + } + else if (item.Key == "highlight" || item.Key == "active" || item.Key == "odhactive" || item.Key == "hascc0image" || item.Key == "hasimage") + { + if (((LegacyBool?)item.Value)?.Value != null) + actualdict.TryAdd(item.Key, ((LegacyBool)item.Value).Value.ToString()); + } + else if (item.Key == "fields") + { + if (((string[]?)item.Value)?.Count() > 0) + actualdict.TryAdd(item.Key, (String.Join(",", (string[])item.Value))); + } + else if (item.Key == "pagenumber") + { + actualdict.TryAdd(item.Key, ((uint?)item.Value).ToString()); + } + else if (item.Key == "removenullvalues") + { + actualdict.TryAdd(item.Key, ((bool?)item.Value).ToString()); + } + else + { + actualdict.TryAdd(item.Key, ((string?)item.Value)); + } + } + } + + // Matching the two Dictionaries + return MatchDictionaries(configdict, actualdict); + } + + private static bool MatchDictionaries(IDictionary dict1, IDictionary dict2) + { + List validlanguages = new() { "de", "it", "en", "nl", "cs", "pl", "fr", "ru" }; + + // Return only if there is a 1:1 match + foreach(var item in dict1) + { + // If the Request does not contain the configured QS Key exit immediately + if (!dict2.ContainsKey(item.Key)) + return false; + + + // If the config does not contains a * go on + if (!item.Value.Contains("*")) + { + // If the values are different exit immediately + if (dict2?[item.Key]?.ToLower() != item.Value.ToLower()) + return false; + } + else + { + // Specialcase Language + fields with * + // check if one of the validlanguages matches + int matchcount = 0; + + foreach(var lang in validlanguages) + { + var newconfigvalue = item.Value.ToLower().Replace("*", lang); + + if(dict2?[item.Key]?.ToLower() == newconfigvalue.ToLower()) + matchcount++; + } + + // If no matches exit immediately + if (matchcount == 0) + return false; + } + } + + return true; + } + } +} diff --git a/ContentApiCore/Formatters/CsvOutputFormatter.cs b/ContentApiCore/Formatters/CsvOutputFormatter.cs new file mode 100644 index 0000000..4c7e76f --- /dev/null +++ b/ContentApiCore/Formatters/CsvOutputFormatter.cs @@ -0,0 +1,110 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using CsvHelper; +using DataModel; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Net.Http.Headers; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Dynamic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ContentApiCore.Formatters +{ + public class CsvOutputFormatter : TextOutputFormatter + { + public CsvOutputFormatter() + { + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/csv")); + + SupportedEncodings.Add(Encoding.UTF8); + SupportedEncodings.Add(Encoding.Unicode); + } + + //protected override bool CanWriteType(Type type) + //{ + // return base.CanWriteType(type); + //} + + private static dynamic ConvertToExpandoObject(Dictionary dict) + { + var eo = new ExpandoObject(); + var eoColl = (ICollection>)eo!; + foreach (var kvp in dict) + { + // Filter out IEnumerables, because they cannot be serialized to CSV + if (kvp.Value is IEnumerable) + { + //Try to cast to string + //var stringlist = kvp.Value as Newtonsoft.Json.Linq.JArray; + var stringlist = kvp.Value as IEnumerable; + if (stringlist != null) + eoColl.Add(new KeyValuePair(kvp.Key, String.Join("|", stringlist))); + else + continue; + } + else + { + eoColl.Add(kvp); + } + } + return eo; + } + + public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) + { + //Works only with List Method add an understandable Exception if it is used on single methods + //Add support if an object list is returned instead of JsonRAW issue 4762 + + var result = context.Object as IResponse; + if (result != null) + { + var data = + (from item in result.Items + let dict = JsonConvert.DeserializeObject>(item.Value) + select ConvertToExpandoObject(dict)).ToList(); + + await WriteCSVStream(context, data); + } + else if (context.Object != null) + { + var listresult = context.Object as IEnumerable; + + if (listresult != null) + { + var data = + (from item in listresult + let dict = JsonConvert.DeserializeObject>(item.Value) + select ConvertToExpandoObject(dict)).ToList(); + + await WriteCSVStream(context, data); + } + else + { + await OutputFormatterHelper.NotImplemented(context); + } + } + else + { + await OutputFormatterHelper.BadRequest(context); + } + } + + private async Task WriteCSVStream(OutputFormatterWriteContext context, List? data) + { + var stream = context.HttpContext.Response.Body; + + await using var writer = new StreamWriter(stream, leaveOpen: true, encoding: Encoding.UTF8); + await using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture); + await csv.WriteRecordsAsync(data); + await writer.FlushAsync(); + } + } +} diff --git a/ContentApiCore/Formatters/JsonLdOutputFormatter.cs b/ContentApiCore/Formatters/JsonLdOutputFormatter.cs new file mode 100644 index 0000000..47cd191 --- /dev/null +++ b/ContentApiCore/Formatters/JsonLdOutputFormatter.cs @@ -0,0 +1,95 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper.JsonHelpers; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Net.Http.Headers; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace ContentApiCore.Formatters +{ + public class JsonLdOutputFormatter : TextOutputFormatter + { + public JsonLdOutputFormatter() + { + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/ld+json")); + // Hack because Output formatter Mapping does not work with + inside + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/ldjson")); + + SupportedEncodings.Add(Encoding.UTF8); + SupportedEncodings.Add(Encoding.Unicode); + } + + private List? Transform(PathString path, JsonRaw jsonRaw, string language, string currentroute) + { + //TODO: extract language + var settings = new JsonSerializerSettings { ContractResolver = new GetOnlyContractResolver() }; + + + if (path.StartsWithSegments("/v1/Example")) + { + var acco = JsonConvert.DeserializeObject(jsonRaw.Value, settings); + return JsonLDTransformer.TransformToSchemaNet.TransformDataToSchemaNet(acco, currentroute, "example", language); + } + else + { + return null; + } + } + + public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) + { + if (context.Object is JsonRaw jsonRaw) + { + //Get the requested language + var query = context.HttpContext.Request.Query; + string language = (string?)query["language"] ?? "en"; + + //Get the route + var location = new Uri($"{context.HttpContext.Request.Scheme}://{context.HttpContext.Request.Host}/{context.HttpContext.Request.Path}"); + var currentroute = location.AbsoluteUri; + + + var transformed = Transform(context.HttpContext.Request.Path, jsonRaw, language, currentroute); + if (transformed != null) + { + var jsonLD = ""; + var options = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault }; + + if (transformed.Count == 1) + { + jsonLD = System.Text.Json.JsonSerializer.Serialize(transformed.FirstOrDefault(), options); //TODO REMOVE NULL VALUES + //JsonConvert.SerializeObject(transformed.FirstOrDefault(), Newtonsoft.Json.Formatting.None, jsonsettings); + + } + else if (transformed.Count > 1) + { + jsonLD = System.Text.Json.JsonSerializer.Serialize(transformed, options); + } + + + await context.HttpContext.Response.WriteAsync(jsonLD); + //await context.HttpContext.Response.WriteAsync(transformed); + } + else + { + await OutputFormatterHelper.NotImplemented(context); + } + } + else + { + await OutputFormatterHelper.BadRequest(context); + } + } + } +} diff --git a/ContentApiCore/Formatters/OutputFormatterHelper.cs b/ContentApiCore/Formatters/OutputFormatterHelper.cs new file mode 100644 index 0000000..01efa0c --- /dev/null +++ b/ContentApiCore/Formatters/OutputFormatterHelper.cs @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Formatters; +using System.Threading.Tasks; + +namespace ContentApiCore.Formatters +{ + public class OutputFormatterHelper + { + public static Task BadRequest(OutputFormatterWriteContext context) + { + context.HttpContext.Response.StatusCode = 400; + return context.HttpContext.Response.WriteAsync("Bad Request"); + } + + public static Task NotImplemented(OutputFormatterWriteContext context) + { + context.HttpContext.Response.StatusCode = 501; + return context.HttpContext.Response.WriteAsync("Not implemented"); + } + + public static Task InternalServerError(OutputFormatterWriteContext context) + { + context.HttpContext.Response.StatusCode = 501; + return context.HttpContext.Response.WriteAsync("Internal Server Error"); + } + } +} diff --git a/ContentApiCore/Formatters/RawdataOutputFormatter.cs b/ContentApiCore/Formatters/RawdataOutputFormatter.cs new file mode 100644 index 0000000..e76d8cb --- /dev/null +++ b/ContentApiCore/Formatters/RawdataOutputFormatter.cs @@ -0,0 +1,92 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.Net.Http.Headers; +using Newtonsoft.Json; +using SqlKata.Execution; +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ContentApiCore.Formatters +{ + public class RawdataOutputFormatter : TextOutputFormatter + { + public RawdataOutputFormatter() + { + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/rawdata")); + + SupportedEncodings.Add(Encoding.UTF8); + SupportedEncodings.Add(Encoding.Unicode); + } + + private string? ConvertToRawdataObject(JsonRaw jsonRaw, QueryFactory QueryFactory) + { + try + { + if (jsonRaw != null) + { + //Get Id of jsonRaw + dynamic? jsonvalue = JsonConvert.DeserializeObject(jsonRaw.Value); + string id = Convert.ToString(jsonvalue?.Id); + string odhtype = Convert.ToString(jsonvalue?._Meta.Type); + + string table = ODHTypeHelper.TranslateTypeString2Table(odhtype); + + //Load rawid + var rawid = QueryFactory.Query() + .Select("rawdataid") + .From(table) + .Where("id", id) + .Get() + .FirstOrDefault(); + + var rawdata = QueryFactory.Query() + .Select("raw") + .From("rawdata") + .Where("id", rawid) + .Get() + .FirstOrDefault(); + + return rawdata; + } + else + return null; + + } + catch(Exception) + { + return null; + } + } + + public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) + { + var queryFactory = (QueryFactory?)context.HttpContext.RequestServices.GetService(typeof(QueryFactory)); + + if (context.Object is JsonRaw jsonRaw && queryFactory is { }) + { + var transformed = ConvertToRawdataObject(jsonRaw, queryFactory); + if (transformed != null) + { + await context.HttpContext.Response.WriteAsync(transformed); + } + else + { + await OutputFormatterHelper.NotImplemented(context); + } + } + else + { + await OutputFormatterHelper.BadRequest(context); + } + } + } +} diff --git a/ContentApiCore/GenericHelpers/CustomCacheKeyGenerator.cs b/ContentApiCore/GenericHelpers/CustomCacheKeyGenerator.cs new file mode 100644 index 0000000..101d61a --- /dev/null +++ b/ContentApiCore/GenericHelpers/CustomCacheKeyGenerator.cs @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using AspNetCore.CacheOutput; +using Microsoft.AspNetCore.Mvc.Filters; +using System; + +namespace ContentApiCore +{ + public class CustomCacheKeyGenerator : DefaultCacheKeyGenerator //ICacheKeyGenerator + { + //public string MakeBaseCacheKey(string controller, string action) + //{ + // throw new NotImplementedException(); + //} + + //public string MakeCacheKey(ActionExecutingContext context, string mediaType, bool excludeQueryString = false) + //{ + // throw new NotImplementedException(); + //} + + public override string MakeCacheKey(ActionExecutingContext context, string mediaType, bool excludeQueryString = false) + { + var key = base.MakeCacheKey(context, mediaType, excludeQueryString); + + var userIdentity = FormatUserIdentity(context); + + return $"{key}:{userIdentity}"; + + //var baseKey = MakeBaseCacheKey(context.Controller., context.ActionDescriptor); + //var parameters = FormatParameters(context, excludeQueryString); + //var userIdentity = FormatUserIdentity(context); + + //return string.Format("{0}{1}:{2}:{3}", baseKey, parameters, userIdentity, mediaType); + } + + protected virtual string FormatUserIdentity(ActionExecutingContext context) + { + var username = "anonymous"; + + if (context.HttpContext.User.Identity != null) + { + if (context.HttpContext.User.Identity.IsAuthenticated) + { + if(!String.IsNullOrEmpty(context.HttpContext.User.Identity.Name)) + username = context.HttpContext.User.Identity.Name.ToLower(); + } + } + + return username; + } + + } +} diff --git a/ContentApiCore/GenericHelpers/GetDeprecatedFieldsByAttributes.cs b/ContentApiCore/GenericHelpers/GetDeprecatedFieldsByAttributes.cs new file mode 100644 index 0000000..358b65c --- /dev/null +++ b/ContentApiCore/GenericHelpers/GetDeprecatedFieldsByAttributes.cs @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System.Reflection; +using System; +using System.Linq; +using System.Collections.Generic; +using DataModel.Annotations; + +namespace ContentApiCore.GenericHelpers +{ + public class GetDeprecatedFieldsByAttributes + { + public static IEnumerable GetDeprecatedFields(Type type) + { + var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance); + var deprecatedprops = props.Where(p => p.GetCustomAttribute(typeof(SwaggerDeprecatedAttribute), true) != null); + + //foreach(var deprecatedprop in deprecatedprops) + //{ + + //} + + return deprecatedprops.Select(x => new DeprecationInfo() { + Name = x.Name, + Description = x.GetCustomAttribute().Description, + Type = FriendlyName(x.PropertyType), + DeprecationDate = x.GetCustomAttribute().DeprecationDate, + RemovedAfter = x.GetCustomAttribute().RemovedAfter, + }) + .ToList(); + + } + + public static string FriendlyName(Type type) + { + if (type.IsGenericType) + { + var namePrefix = type.Name.Split(new[] { '`' }, StringSplitOptions.RemoveEmptyEntries)[0]; + var genericParameters = String.Join(", ", type.GetGenericArguments().Select(FriendlyName)); + return namePrefix + "<" + genericParameters + ">"; + } + + return type.Name; + } + } + + public class DeprecationInfo + { + public string? Name { get; set; } + public string? Type { get; set; } + public string? Description { get; set; } + public DateTime? DeprecationDate { get; set; } + public DateTime? RemovedAfter { get; set; } + } +} diff --git a/ContentApiCore/Middleware/HttpRequestMiddleware.cs b/ContentApiCore/Middleware/HttpRequestMiddleware.cs new file mode 100644 index 0000000..0bdf491 --- /dev/null +++ b/ContentApiCore/Middleware/HttpRequestMiddleware.cs @@ -0,0 +1,135 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Newtonsoft.Json; +using System; +using System.Diagnostics; + +namespace ContentApiCore +{ + public static class HttpRequestExtensions + { + public static IApplicationBuilder UseODHCustomHttpRequestConfig(this IApplicationBuilder builder, IConfiguration configuration) + { + return builder.Use(async (context, next) => + { + //If Root is requested forward to Databrowser (Compatibility reason) + if (String.IsNullOrEmpty(context.Request.Path.Value) || context.Request.Path.Value == "/") + { + if (context.Request.Host.ToString().Equals("tourism.opendatahub.com") || context.Request.Host.ToString().Equals("tourism.opendatahub.bz.it")) + { + context.Response.Redirect(configuration.GetSection("DataBrowserConfig").GetValue("Url")); + return; + } + else + { + context.Response.Redirect("/swagger"); + return; + } + } + + else if (context.Request.Path.Value == "/api") + { + context.Response.Redirect("/v1"); + return; + } + + else if (context.Request.Path.Value.StartsWith("/swagger/ui/index")) + { + context.Response.Redirect("/swagger"); + return; + } + Stopwatch requesttime = new Stopwatch(); + requesttime.Start(); + + await next(); + + //Log only if api is requested! including HTTP Statuscode therefore after await next(); + //if(context.Request.Path.StartsWithSegments("/v1/", StringComparison.OrdinalIgnoreCase)) + if (!String.IsNullOrEmpty(context.Request.Path.Value) && context.Request.Path.Value.StartsWith("/v1", StringComparison.OrdinalIgnoreCase)) + { + requesttime.Stop(); + + GenerateLogResponse(context, requesttime.ElapsedMilliseconds, "", ""); + } + }); + } + + public static void GenerateLogResponse(Microsoft.AspNetCore.Http.HttpContext context, long? elapsedtime = 0, string? quotaapplied = "", string? cachekey = "") + { + //TODO Make a Referer Class/Method for the logic + var referer = "not provided"; + + //TO CHECK make parameter referer if it is provided as source of truth + if (context.Request.Headers.ContainsKey("Referer")) + referer = context.Request.Headers["Referer"].ToString(); + else + { + //Search the QS for Referer + if (context.Request.Query.ContainsKey("Referer")) + referer = context.Request.Query["Referer"].ToString(); + } + + //Quick Fix, Android is passing http://localhost/ as referer + if (referer == "http://localhost/" && context.Request.Query.ContainsKey("Referer")) + referer = context.Request.Query["Referer"].ToString(); + + //Origin + var origin = "not provided"; + if (context.Request.Query.ContainsKey("Origin")) + origin = context.Request.Query["Origin"].ToString(); + + //User Agent + var useragent = "not provided"; + if (context.Request.Headers.ContainsKey("User-Agent")) + useragent = context.Request.Headers["User-Agent"].ToString(); + + var urlparameters = context.Request.QueryString.Value != null ? context.Request.QueryString.HasValue ? context.Request.QueryString.Value.Replace("?", "") : "" : ""; + + //To check + var remoteip = RemoteIpHelper.GetRequestIP(context, true); + + //Rate Limit Policy + var ratelimitpolicy = quotaapplied; + if (context.Response.Headers.ContainsKey("X-Rate-Limit-Policy")) + ratelimitpolicy = context.Response.Headers["X-Rate-Limit-Policy"].ToString(); + + //TODO Add Response Size + //var responsesize = context.Response.ContentLength; always null + + //TODO Add Roles + //var roles = ((ClaimsIdentity)context.User.Identity).Claims + // .Where(c => c.Type == ClaimTypes.Role) + // .Select(c => c.Value); + + HttpRequestLog httplog = new HttpRequestLog() + { + host = context.Request.Host.ToString(), + path = context.Request.Path.ToString(), + method = context.Request.Method.ToString(), + urlparams = urlparameters, //.Replace("&", "-"), //Helper.StringHelpers.GenerateDictionaryFromQuerystring(context.Request.QueryString.ToString()), + referer = referer, + schema = context.Request.Scheme, + useragent = useragent, + username = context.User.Identity != null ? context.User.Identity.Name != null ? context.User.Identity.Name.ToString() : "anonymous" : "anonymous", + ipaddress = remoteip, + statuscode = context.Response.StatusCode, + origin = origin, + elapsedtime = elapsedtime, + appliedquota = ratelimitpolicy, + ratelimitkey = cachekey + }; + LogOutput logoutput = new LogOutput() { id = "", type = "HttpRequest", log = "apiaccess", output = httplog }; + + Console.WriteLine(JsonConvert.SerializeObject(logoutput)); + } + + } + + + +} diff --git a/ContentApiCore/Middleware/MyHttpContext.cs b/ContentApiCore/Middleware/MyHttpContext.cs new file mode 100644 index 0000000..3c94f46 --- /dev/null +++ b/ContentApiCore/Middleware/MyHttpContext.cs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +//using Microsoft.AspNetCore.Builder; +//using Microsoft.AspNetCore.Http; +//using Microsoft.Extensions.DependencyInjection; +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Threading.Tasks; + +//namespace ContentApiCore +//{ +// public class MyHttpContext +// { +// private static IHttpContextAccessor m_httpContextAccessor; + +// public static HttpContext Current => m_httpContextAccessor.HttpContext; + +// public static string AppBaseUrl => $"{Current.Request.Scheme}://{Current.Request.Host}{Current.Request.PathBase}"; + +// internal static void Configure(IHttpContextAccessor contextAccessor) +// { +// m_httpContextAccessor = contextAccessor; +// } +// } + +// public static class HttpContextExtensions +// { +// public static void AddHttpContextAccessor(this IServiceCollection services) +// { +// services.AddSingleton(); +// } + +// public static IApplicationBuilder UseHttpContext(this IApplicationBuilder app) +// { +// MyHttpContext.Configure(app.ApplicationServices.GetRequiredService()); +// return app; +// } +// } +//} diff --git a/ContentApiCore/Middleware/OdhRateLimitMiddleware.cs b/ContentApiCore/Middleware/OdhRateLimitMiddleware.cs new file mode 100644 index 0000000..4ab6cd9 --- /dev/null +++ b/ContentApiCore/Middleware/OdhRateLimitMiddleware.cs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +//using AspNetCoreRateLimit; +//using Microsoft.AspNetCore.Http; +//using Microsoft.Extensions.Options; +//using System.IdentityModel.Tokens.Jwt; +//using System.Linq; +//using System.Net.Http.Headers; +//using System.Threading.Tasks; + +//namespace OdhApiCore.Middleware +//{ +// class OdhRateLimitConfiguration : RateLimitConfiguration +// { +// private readonly IHttpContextAccessor _httpContextAccessor; + +// public OdhRateLimitConfiguration( +// IHttpContextAccessor httpContextAccessor, +// IOptions ipOptions, +// IOptions clientOptions) +// : base(ipOptions, clientOptions) +// { +// _httpContextAccessor = httpContextAccessor; +// } + +// public override void RegisterResolvers() +// { +// base.RegisterResolvers(); +// //ClientResolvers.Add(new OdhResolveContributor(_httpContextAccessor)); +// } +// } + +// class OdhResolveContributor : IClientResolveContributor +// { +// private IHttpContextAccessor httpContextAccessor; + +// public OdhResolveContributor(IHttpContextAccessor httpContextAccessor) +// { +// this.httpContextAccessor = httpContextAccessor; +// } + +// public Task ResolveClientAsync(HttpContext httpContext) +// { +// var request = httpContextAccessor.HttpContext?.Request; +// var authorization = request!.Headers.Authorization.ToString(); +// if (authorization != "") +// { +// //if (AuthenticationHeaderValue.TryParse(authorization, out var auth)) +// //{ +// // var handler = new JwtSecurityTokenHandler(); +// // var token = handler.ReadJwtToken(auth.Parameter); +// //} +// return Task.FromResult("Authenticated"); +// } + +// var referer = request!.Headers.Referer.ToString(); + +// if (referer != "") +// { +// return Task.FromResult(referer); +// } + +// return Task.FromResult("Anonymous"); +// } +// } +//} diff --git a/ContentApiCore/Middleware/RateLimitMiddleware.cs b/ContentApiCore/Middleware/RateLimitMiddleware.cs new file mode 100644 index 0000000..881068c --- /dev/null +++ b/ContentApiCore/Middleware/RateLimitMiddleware.cs @@ -0,0 +1,316 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Caching.Distributed; +using System; +using System.IdentityModel.Tokens.Jwt; +using System.IO; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Linq; +using System.Collections.Generic; +using System.Security.Claims; +using Helper; + +namespace ContentApiCore +{ + public class RateLimitingMiddleware + { + private readonly RequestDelegate _next; + private readonly IDistributedCache _cache; + + public RateLimitingMiddleware(RequestDelegate next, IDistributedCache cache) + { + _next = next; + _cache = cache; + } + + public async Task InvokeAsync(HttpContext context, ISettings settings) + { + var ratelimitconfig = settings.RateLimitConfig; + var endpoint = context.GetEndpoint(); + + //If already a 401 Response is waiting do nothing + if(context.Response.HasStarted) + { + return; + } + + // If no config present do nothing + if (ratelimitconfig is null) + { + await _next(context); + return; + } + + // If route is listed in NoRateLimitRoutesConfig do nothing + if (CheckNoRestrictionRoutes(context.Request.Path, settings)) + { + await _next(context); + return; + } + + // If Referer is listed in NoRateLimitRefererConfig do nothing + if (CheckNoRestricionReferer(context, settings)) + { + await _next(context); + return; + } + + var (rlConfig, key) = GenerateClientKeyExtended(context, settings.RateLimitConfig); + + if (rlConfig is not null && rlConfig.Type != "Admin") + { + var clientStatistics = await GetClientStatisticsByKey(key); + + context.AddRateLimitHeaders(rlConfig.MaxRequests, clientStatistics == null ? 0 : clientStatistics.LastSuccessfulResponseTimeList.Count, rlConfig.TimeWindow, rlConfig.Type); + + if (clientStatistics != null && clientStatistics.LastSuccessfulResponseTimeList.Count >= rlConfig.MaxRequests) + { + // Done by WriteasJson + context.Response.StatusCode = (int)HttpStatusCode.TooManyRequests; + + await context.Response.WriteAsJsonAsync(new QuotaExceededMessage { Message = "You have exhausted your API Request Quota", Policy = rlConfig.Type, RetryAfter = rlConfig.TimeWindow, RequestsDone = clientStatistics.LastSuccessfulResponseTimeList.Count }); + + HttpRequestExtensions.GenerateLogResponse(context, clientStatistics.LastSuccessfulResponseTimeList.Count, rlConfig.Type, key); + + return; + } + + await UpdateClientStatisticsStorage(key, rlConfig.MaxRequests, TimeSpan.FromSeconds(rlConfig.TimeWindow)); + } + + await _next(context); + } + + private static string GenerateClientKey(HttpContext context) => $"{context.Request.Path}_{context.Connection.RemoteIpAddress}"; + + private static (RateLimitConfig? rlConfig, string key) GenerateClientKeyExtended(HttpContext context, List rlsettings) + { + RateLimitConfig? ratelimitconfig = default; + string ratelimitcachekey = ""; + + var referer = ""; + + // Check Referer + if (context.Request.Headers.ContainsKey("Referer")) + referer = context.Request.Headers["Referer"].ToString(); + else + { + // Search the QS for Referer + if (context.Request.Query.ContainsKey("Referer")) + referer = context.Request.Query["Referer"].ToString(); + } + + var bearertoken = ""; + var loggeduser = ""; + List userrole = new List(); + + // Check Referer + if (context.Request.Headers.ContainsKey("Authorization")) + bearertoken = context.Request.Headers["Authorization"].ToString(); + + if (!string.IsNullOrEmpty(bearertoken) && bearertoken.StartsWith("Bearer")) + { + var handler = new JwtSecurityTokenHandler(); + var token = bearertoken.Replace("Bearer", "").Trim(); + + var jwttoken = ReadMyJWTSecurityToken(token, handler); + + + if (jwttoken != null) + { + // Gets name from claims. Generally it's an email address. + var usernameClaim = jwttoken.Claims + .Where(x => x.Type == ClaimTypes.Name || x.Type == "name") + .FirstOrDefault(); + + //HACK if no username (Serviceaccount) lets get the preferred_username + if(usernameClaim == null) + { + usernameClaim = jwttoken.Claims + .Where(x => x.Type == ClaimTypes.Name || x.Type == "preferred_username") + .FirstOrDefault(); + } + + if (usernameClaim != null) + loggeduser = usernameClaim.Value; + + var roleClaim = jwttoken.Claims + .Where(x => x.Type == ClaimTypes.Name || x.Type == "role"); + + if(roleClaim != null) + { + foreach(var role in roleClaim) + { + userrole.Add(role.Value); + } + } + } + } + + // Check Loggeduser + + // TODO: Check if User has Referer, isLogged isAnonymous + + // Case 1 Anonymous, Go to IP Restriction (Maybe on Path?) + if (String.IsNullOrEmpty(referer) && String.IsNullOrEmpty(loggeduser)) + { + ratelimitcachekey = $"{context.Request.Path}_{context.Connection.RemoteIpAddress}"; + ratelimitconfig = rlsettings.FirstOrDefault(x => x.Type == "Anonymous"); + } + // Case 2 Referer passed generate key with Referer + else if (!String.IsNullOrEmpty(referer) && String.IsNullOrEmpty(loggeduser)) + { + ratelimitcachekey = $"{context.Request.Path}_{context.Connection.RemoteIpAddress}_{referer}"; + ratelimitconfig = rlsettings.Where(x => x.Type == "Referer").FirstOrDefault(); + } + + // Case 3 Logged user, decode token and use username as key + else if (!String.IsNullOrEmpty(loggeduser)) + { + ratelimitcachekey = $"{context.Request.Path}_{context.Connection.RemoteIpAddress}_{loggeduser}"; + ratelimitconfig = rlsettings.Where(x => x.Type == "Basic").FirstOrDefault(); + + // If user is in Role + if(userrole.Count > 0) + { + if(userrole.Contains("ODH_ROLE_ADVANCED")) + ratelimitconfig = rlsettings.Where(x => x.Type == "Advanced").FirstOrDefault(); + if (userrole.Contains("ODH_ROLE_PREMIUM")) + ratelimitconfig = rlsettings.Where(x => x.Type == "Premium").FirstOrDefault(); + if (userrole.Contains("ODH_ROLE_ADMIN")) + ratelimitconfig = rlsettings.Where(x => x.Type == "Admin").FirstOrDefault(); + } + + // Fallback if ratelimitconfig by Role is null + if(ratelimitconfig == null) + ratelimitconfig = rlsettings.Where(x => x.Type == "Basic").FirstOrDefault(); + } + // No rate limit + else + { + return (null, ""); + } + + return (ratelimitconfig, ratelimitcachekey); + } + + private static JwtSecurityToken? ReadMyJWTSecurityToken(string token, JwtSecurityTokenHandler handler) + { + try + { + var jwttoken = handler.ReadJwtToken(token); + + return jwttoken; + } + catch + { + return null; + } + } + + private async Task GetClientStatisticsByKey(string key) => await _cache.GetCacheValueAsync(key); + + private async Task UpdateClientStatisticsStorage(string key, int maxRequests, TimeSpan timeWindow) + { + var clientStat = await _cache.GetCacheValueAsync(key); + + if (clientStat != null) + { + var now = DateTime.UtcNow; + + clientStat.LastSuccessfulResponseTimeList.Add(now); + clientStat.LastSuccessfulResponseTimeList = RemoveAllExpiredResponseDateTimes(clientStat.LastSuccessfulResponseTimeList, timeWindow, now); + + await _cache.SetCacheValueAsync(key, timeWindow, clientStat); + } + else + { + var clientStatistics = new ClientStatistics + { + LastSuccessfulResponseTimeList = new List() { DateTime.UtcNow } + }; + + await _cache.SetCacheValueAsync(key, timeWindow, clientStatistics); + } + + } + + private static List RemoveAllExpiredResponseDateTimes(List list, TimeSpan timeWindow, DateTime dateto) + { + var validfrom = dateto.Subtract(timeWindow); + + // Remove all no more valid Requests + return list.Where(x => x >= validfrom).ToList(); + } + + public static MemoryStream GenerateStreamFromString(string value) + { + return new MemoryStream(Encoding.UTF8.GetBytes(value ?? "")); + } + + private static bool CheckNoRestrictionRoutes(PathString currentpath, ISettings settings) + { + bool toreturn = false; + + if (settings.NoRateLimitConfig.NoRateLimitRoutes != null && currentpath.Value != null && settings.NoRateLimitConfig.NoRateLimitRoutes.Contains(currentpath.Value)) + return true; + + + return toreturn; + } + + private static bool CheckNoRestricionReferer(HttpContext context, ISettings settings) + { + bool toreturn = false; + + string currentreferer = ""; + // Check Referer + if (context.Request.Headers.ContainsKey("Referer")) + currentreferer = context.Request.Headers["Referer"].ToString(); + else + { + // Search the QS for Referer + if (context.Request.Query.ContainsKey("Referer")) + currentreferer = context.Request.Query["Referer"].ToString(); + } + + if (settings.NoRateLimitConfig.NoRateLimitReferer != null && settings.NoRateLimitConfig.NoRateLimitReferer.Contains(currentreferer)) + return true; + + + return toreturn; + } + } + + public class ClientStatistics + { + public ClientStatistics() + { + LastSuccessfulResponseTimeList = new List(); + } + + public List LastSuccessfulResponseTimeList { get; set; } + } + + public class QuotaExceededMessage + { + public string? Message { get; set; } + public string? Hint + { + get + { + return "https://github.com/noi-techpark/odh-docs/wiki/Api-Quota"; + } + } + public string? Policy { get; set; } + + public int RetryAfter { get; set; } + + public int RequestsDone { get; set; } + } +} diff --git a/ContentApiCore/Program.cs b/ContentApiCore/Program.cs new file mode 100644 index 0000000..c20f39b --- /dev/null +++ b/ContentApiCore/Program.cs @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using System.Threading.Tasks; + +namespace ContentApiCore +{ + public class Program + { + public static async Task Main(string[] args) + { + var host = CreateHostBuilder(args).Build(); + + await host.RunAsync(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + webBuilder.UseStartup()); + } + } +} \ No newline at end of file diff --git a/ContentApiCore/Properties/launchSettings.json b/ContentApiCore/Properties/launchSettings.json new file mode 100644 index 0000000..a1597b8 --- /dev/null +++ b/ContentApiCore/Properties/launchSettings.json @@ -0,0 +1,46 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:58799/", + "sslPort": 44373 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchUrl": "api/status", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "OdhApiCore": { + "commandName": "Project", + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:8001;http://localhost:8000" + }, + "Docker": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "ASPNETCORE_URLS": "http://+:80", + "ASPNETCORE_ConnectionStrings__PgConnection": "PG_CONNECTION", + "ASPNETCORE_JsonConfig__Jsondir": "wwwroot/json/", + "ASPNETCORE_Xmldir__Xmldir": "XMLDIR" + }, + "httpPort": 8001, + "useSSL": false + }, + "dotnet": { + "commandName": "Project", + "hotReloadProfile": "aspnetcore" + } + } +} \ No newline at end of file diff --git a/ContentApiCore/Properties/serviceDependencies.json b/ContentApiCore/Properties/serviceDependencies.json new file mode 100644 index 0000000..a4e7aa3 --- /dev/null +++ b/ContentApiCore/Properties/serviceDependencies.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "secrets1": { + "type": "secrets" + } + } +} \ No newline at end of file diff --git a/ContentApiCore/Properties/serviceDependencies.local.json b/ContentApiCore/Properties/serviceDependencies.local.json new file mode 100644 index 0000000..09b109b --- /dev/null +++ b/ContentApiCore/Properties/serviceDependencies.local.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "secrets1": { + "type": "secrets.user" + } + } +} \ No newline at end of file diff --git a/ContentApiCore/Responses/ResponseHelpers.cs b/ContentApiCore/Responses/ResponseHelpers.cs new file mode 100644 index 0000000..b5f2602 --- /dev/null +++ b/ContentApiCore/Responses/ResponseHelpers.cs @@ -0,0 +1,137 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Mvc; +using System.Collections.Generic; +using System.Linq; +using DataModel; + +namespace ContentApiCore.Responses +{ + public static class ResponseHelpers + { + private static (string? previouspage, string? nextpage) GetPreviousAndNextPage(uint pagenumber, uint totalpages, IUrlHelper? url, string? seed) + { + string? previouspage = null; + string? nextpage = null; + if (url != null) + { + var query = url.ActionContext.HttpContext.Request.Query; + var queryDict = query.ToDictionary(x => x.Key, x => x.Value.ToString()); + if (seed != null) + { + queryDict["seed"] = seed; + } + if (pagenumber > 1 && pagenumber <= totalpages) + { + queryDict["pagenumber"] = (pagenumber - 1).ToString(); + previouspage = url.Link(null, queryDict); + } + if (pagenumber < totalpages) + { + queryDict["pagenumber"] = (pagenumber + 1).ToString(); + nextpage = url.Link(null, queryDict); + } + } + return (previouspage, nextpage); + } + + public static JsonResult GetResult( + uint pagenumber, uint totalpages, uint totalcount, string? seed, IEnumerable data, IUrlHelper? url) + { + var (previouspage, nextpage) = GetPreviousAndNextPage(pagenumber, totalpages, url, seed); + return new JsonResult + { + TotalResults = totalcount, + TotalPages = totalpages, + CurrentPage = pagenumber, + PreviousPage = previouspage, + NextPage = nextpage, + Seed = seed, + Items = data + }; + } + + public static JsonResultWithOnlineResults GetResult( + uint pagenumber, uint totalpages, uint totalcount, int onlineresults, string? seed, + IEnumerable data, IUrlHelper url) + where T : notnull + { + var (previouspage, nextpage) = GetPreviousAndNextPage(pagenumber, totalpages, url, seed); + return new JsonResultWithOnlineResults + { + TotalResults = totalcount, + TotalPages = totalpages, + CurrentPage = pagenumber, + PreviousPage = previouspage, + NextPage = nextpage, + OnlineResults = onlineresults, + Seed = seed, + Items = data + }; + } + + public static JsonResultWithOnlineResultsAndResultId GetResult( + uint pagenumber, uint totalpages, uint totalcount, int onlineresults, + string resultid, string? seed, IEnumerable data, IUrlHelper url) + where T : notnull + { + var (previouspage, nextpage) = GetPreviousAndNextPage(pagenumber, totalpages, url, seed); + return new JsonResultWithOnlineResultsAndResultId + { + TotalResults = totalcount, + TotalPages = totalpages, + CurrentPage = pagenumber, + PreviousPage = previouspage, + NextPage = nextpage, + OnlineResults = onlineresults, + ResultId = resultid, + Seed = seed, + Items = data + }; + } + + public static JsonResultWithOnlineResultsAndResultIdLowercase GetResultLowercase( + uint pagenumber, uint totalpages, uint totalcount, int onlineresults, + string resultid, string seed, IEnumerable data, IUrlHelper url) + where T : notnull + { + var (previouspage, nextpage) = GetPreviousAndNextPage(pagenumber, totalpages, url, seed); + return new JsonResultWithOnlineResultsAndResultIdLowercase + { + totalResults = totalcount, + totalPages = totalpages, + currentPage = pagenumber, + previousPage = previouspage, + nextPage = nextpage, + onlineResults = onlineresults, + resultId = resultid, + seed = seed, + items = data + }; + } + + public static JsonResultWithBookingInfo GetResult( + uint pagenumber, uint totalpages, uint totalcount, int accosrequested, int availableonline, int availableonrequest, + string resultid, string? seed, IEnumerable data, IUrlHelper url) + { + var (previouspage, nextpage) = GetPreviousAndNextPage(pagenumber, totalpages, url, seed); + return new JsonResultWithBookingInfo + { + TotalResults = totalcount, + TotalPages = totalpages, + CurrentPage = pagenumber, + PreviousPage = previouspage, + NextPage = nextpage, + OnlineResults = availableonline, + AccommodationsRequested = accosrequested, + AvailableOnline = availableonline, + AvailableOnRequest = availableonrequest, + ResultId = resultid, + Seed = seed, + Items = data + }; + } + } +} diff --git a/ContentApiCore/Settings.cs b/ContentApiCore/Settings.cs new file mode 100644 index 0000000..a09d196 --- /dev/null +++ b/ContentApiCore/Settings.cs @@ -0,0 +1,114 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.Extensions.Configuration; +using System; +using System.Collections.Generic; +using Helper; + +namespace ContentApiCore +{ + public class Settings : ISettings + { + private readonly IConfiguration configuration; + private readonly Lazy connectionString; + private readonly XmlConfig xmlConfig; + private readonly JsonConfig jsonConfig; + private readonly S3ImageresizerConfig s3imageresizerConfig; + private readonly PushServerConfig pushserverConfig; + private readonly List field2hideConfig; + private readonly List requestInterceptorConfig; + private readonly List rateLimitConfig; + private readonly NoRateLimitConfig noRateLimitConfig; + private readonly List fcmConfig; + + private readonly List notifierConfig; + + + public Settings(IConfiguration configuration) + { + this.configuration = configuration; + this.connectionString = new Lazy(() => + this.configuration.GetConnectionString("PGConnection")); + var xml = this.configuration.GetSection("XmlConfig"); + this.xmlConfig = new XmlConfig(xml.GetValue("Xmldir", ""), xml.GetValue("XmldirWeather", "")); + var json = this.configuration.GetSection("JsonConfig"); + this.jsonConfig = new JsonConfig(json.GetValue("Jsondir", "")); + var s3img = this.configuration.GetSection("S3ImageresizerConfig"); + this.s3imageresizerConfig = new S3ImageresizerConfig(s3img.GetValue("Url", ""), s3img.GetValue("DocUrl", ""), s3img.GetValue("BucketAccessPoint", ""), s3img.GetValue("AccessKey", ""), s3img.GetValue("SecretKey", "")); + var pushserver = this.configuration.GetSection("PushServerConfig"); + this.pushserverConfig = new PushServerConfig(pushserver.GetValue("Username", ""), pushserver.GetValue("Password", ""), pushserver.GetValue("ServiceUrl", "")); + var field2hidelist = this.configuration.GetSection("Field2HideConfig").GetChildren(); + this.field2hideConfig = new List(); + foreach (var field2hide in field2hidelist) + { + this.field2hideConfig.Add(new Field2HideConfig(field2hide.GetValue("Entity", ""), field2hide.GetValue("Fields", ""), field2hide.GetValue("DisplayOnRoles", ""))); + } + + var requestinterceptorlist = this.configuration.GetSection("RequestInterceptorConfig").GetChildren(); + this.requestInterceptorConfig = new List(); + + foreach (var requestinterceptor in requestinterceptorlist) + { + this.requestInterceptorConfig.Add(new RequestInterceptorConfig(requestinterceptor.GetValue("Action", ""), requestinterceptor.GetValue("Controller", ""), requestinterceptor.GetValue("QueryStrings", ""), + requestinterceptor.GetValue("RedirectAction", ""), requestinterceptor.GetValue("RedirectController", ""), requestinterceptor.GetValue("RedirectQueryStrings", ""))); + } + + var ratelimitlist = this.configuration.GetSection("RateLimitConfig").GetChildren(); + this.rateLimitConfig = new List(); + foreach (var ratelimitconfig in ratelimitlist) + { + this.rateLimitConfig.Add(new RateLimitConfig(ratelimitconfig.GetValue("Type", ""), ratelimitconfig.GetValue("TimeWindow", 0), ratelimitconfig.GetValue("MaxRequests", 0))); + } + + var noratelimitroutes = this.configuration.GetSection("NoRateLimitConfig").GetSection("NoRateLimitRoutesConfig").GetChildren(); + var noratelimitreferers = this.configuration.GetSection("NoRateLimitConfig").GetSection("NoRateLimitRefererConfig").GetChildren(); + this.noRateLimitConfig = new NoRateLimitConfig(new List(), new List()); + foreach (var routepath in noratelimitroutes) + { + this.noRateLimitConfig.NoRateLimitRoutes.Add(routepath.GetValue("Path","")); + } + foreach (var referer in noratelimitreferers) + { + this.noRateLimitConfig.NoRateLimitReferer.Add(referer.GetValue("Referer", "")); + } + + this.fcmConfig = new List(); + + var fcmdict = this.configuration.GetSection("FCMConfig").GetChildren(); + if(fcmdict != null) + { + foreach (var fcmkey in fcmdict) + { + var fcmconfigobj = new FCMConfig(fcmkey.Key, fcmkey.GetValue("ServerKey", ""), fcmkey.GetValue("SenderId", ""), fcmkey.GetValue("ProjectName", ""), fcmkey.GetValue("FCMServiceAccount", ""), fcmkey.GetValue("FCMServiceAccountJson", "")); + this.fcmConfig.Add(fcmconfigobj); + } + } + + this.notifierConfig = new List(); + + var notifierconfigdict = this.configuration.GetSection("NotifierConfig").GetChildren(); + if (notifierconfigdict != null) + { + foreach (var notifiercfg in notifierconfigdict) + { + this.notifierConfig.Add(new NotifierConfig(notifiercfg.Key, notifiercfg.GetValue("Url", ""), notifiercfg.GetValue("User", ""), notifiercfg.GetValue("Password", ""))); + } + } + } + + public string PostgresConnectionString => this.connectionString.Value; + public XmlConfig XmlConfig => this.xmlConfig; + public JsonConfig JsonConfig => this.jsonConfig; + public S3ImageresizerConfig S3ImageresizerConfig => this.s3imageresizerConfig; + public PushServerConfig PushServerConfig => this.pushserverConfig; + public List FCMConfig => this.fcmConfig; + public List Field2HideConfig => this.field2hideConfig; + public List RequestInterceptorConfig => this.requestInterceptorConfig; + public List RateLimitConfig => this.rateLimitConfig; + public NoRateLimitConfig NoRateLimitConfig => this.noRateLimitConfig; + + public List NotifierConfig => this.notifierConfig; + } +} diff --git a/ContentApiCore/Startup.cs b/ContentApiCore/Startup.cs new file mode 100644 index 0000000..b449303 --- /dev/null +++ b/ContentApiCore/Startup.cs @@ -0,0 +1,319 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using AspNetCore.CacheOutput.InMemory.Extensions; +using Helper; +using Helper.Factories; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.AspNetCore.Rewrite; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.IdentityModel.Tokens; +using Microsoft.OpenApi.Models; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using ContentApiCore.Controllers; +using ContentApiCore.Swagger; +using OdhNotifier; +using Serilog; +using Serilog.Core; +using Serilog.Events; +using SqlKata.Execution; +using Swashbuckle.AspNetCore.Filters; +using Swashbuckle.AspNetCore.Swagger; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Reflection; + +namespace ContentApiCore +{ + public class Startup + { + public Startup(IWebHostEnvironment env, IConfiguration configuration) + { + Configuration = configuration; + CurrentEnvironment = env; + } + public IConfiguration Configuration { get; } + public IWebHostEnvironment CurrentEnvironment { get; } + + // This method gets called by the runtime. Use this method to add services to the container. + public void ConfigureServices(IServiceCollection services) + { + //Adding Cache Service in Memory + services.AddInMemoryCacheOutput(); + services.AddSingleton(); + + services.AddDistributedMemoryCache(); + + services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy()) + .AddNpgSql(Configuration.GetConnectionString("PgConnection"), tags: new[] { "services" }); + + services.AddLogging(options => + { + options.ClearProviders(); + + var levelSwitch = new LoggingLevelSwitch + { + MinimumLevel = + CurrentEnvironment.IsDevelopment() ? + LogEventLevel.Debug : + LogEventLevel.Warning + }; + var loggerConfiguration = new LoggerConfiguration() + .MinimumLevel.ControlledBy(levelSwitch) + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .Enrich.FromLogContext() + .WriteTo.Console(outputTemplate: "{Message}{NewLine}") + .WriteTo.Debug() + .CreateLogger(); + options.AddSerilog(loggerConfiguration, dispose: true); + + // Configure Serilogs own configuration to use + // the configured logger configuration. + // This allows to Log via Serilog's Log and ILogger. + Log.Logger = loggerConfiguration; + }); + + services.Configure(options => options.Level = System.IO.Compression.CompressionLevel.Optimal); + services.AddResponseCompression(options => + { + options.EnableForHttps = true; + options.Providers.Add(); + }); + + services.AddCors(o => + { + o.AddPolicy("CorsPolicy", builder => + { + builder.AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials() + .SetIsOriginAllowed(hostName => true); + }); + }); + + services.AddControllers().AddNewtonsoftJson(options => + { + options.SerializerSettings.ContractResolver = new DefaultContractResolver(); + options.SerializerSettings.Converters.Add(new StringEnumConverter()); + }); + + services.AddRazorPages(); + + services.AddSingleton(); + services.AddScoped(); + services.AddScoped(); + + //Initialize JWT Authentication + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddJwtBearer(jwtBearerOptions => + { + jwtBearerOptions.Authority = Configuration.GetSection("OauthServerConfig").GetValue("Authority"); + //jwtBearerOptions.Audience = "account"; + jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters + { + NameClaimType = "preferred_username", + ValidateAudience = false, + ValidateLifetime = true, + ValidIssuer = Configuration.GetSection("OauthServerConfig").GetValue("Authority"), + ValidateIssuer = true, + }; + jwtBearerOptions.Events = new JwtBearerEvents() + { + OnAuthenticationFailed = c => + { + c.NoResult(); + c.Response.StatusCode = 401; + c.Response.ContentType = "text/plain"; + + //Generate Log + HttpRequestExtensions.GenerateLogResponse(c.HttpContext); + + return c.Response.WriteAsync(""); + }, + }; + }); + + services.AddMvc(options => + { + options.OutputFormatters.Add(new Formatters.CsvOutputFormatter()); + options.FormatterMappings.SetMediaTypeMappingForFormat("csv", "text/csv"); + + options.OutputFormatters.Add(new Formatters.JsonLdOutputFormatter()); + //Hack only ldjson accepted + options.FormatterMappings.SetMediaTypeMappingForFormat("json-ld", "application/ldjson"); + + options.OutputFormatters.Add(new Formatters.RawdataOutputFormatter()); + options.FormatterMappings.SetMediaTypeMappingForFormat("rawdata", "application/rawdata"); + }); + + services.AddSwaggerGen(c => + { + c.SwaggerDoc("v1", new OpenApiInfo + { + Title = "Open Data Hub Content Api", + Version = "v1", + Description = "Open Data Hub Content Api based on .Net Core with PostgreSQL", + TermsOfService = new System.Uri("https://opendatahub.readthedocs.io/en/latest/"), + Contact = new OpenApiContact + { + Name = "Open Data Hub Team", + Email = "help@opendatahub.com", + Url = new System.Uri("https://opendatahub.com/"), + }, + }); + c.MapType(() => new OpenApiSchema + { + Type = "boolean" + }); + c.MapType(() => new OpenApiSchema + { + Type = "integer" + }); + // Set the comments path for the Swagger JSON and UI. + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + //var xmlPathdatamodel = Path.Combine(AppContext.BaseDirectory, $"DataModel.xml"); + c.IncludeXmlComments(xmlPath, includeControllerXmlComments: true); + //c.IncludeXmlComments(xmlPathdatamodel, includeControllerXmlComments: true); + c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme + { + In = ParameterLocation.Header, + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows + { + Password = new OpenApiOAuthFlow + { + TokenUrl = new Uri(Configuration.GetSection("OauthServerConfig").GetValue("Authority") + "protocol/openid-connect/token") + }, + ClientCredentials = new OpenApiOAuthFlow + { + TokenUrl = new Uri(Configuration.GetSection("OauthServerConfig").GetValue("Authority") + "protocol/openid-connect/token") + } + }, + BearerFormat = "JWT", + Scheme = "Bearer" + }); + c.OperationFilter(); + c.OperationFilter(); + c.SchemaFilter(); + c.SchemaFilter(); + c.EnableAnnotations(); + }); + services.AddSwaggerGenNewtonsoftSupport(); + + //Use server side caching of the swagger doc + services.Replace(ServiceDescriptor.Transient()); + + services.Configure(options => + { + options.ForwardedHeaders = ForwardedHeaders.XForwardedProto; + }); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseForwardedHeaders(); + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + app.UseHsts(); + } + + app.UseResponseCompression(); + + app.UseStaticFiles(new StaticFileOptions() + { + OnPrepareResponse = ctx => + { + //Activate Browser Cache of the swagger file for 1 day + if (ctx.File.Name.ToLower() == "swagger.json") + { + ctx.Context.Response.Headers.Append("Cache-Control", "public,max-age=86400"); + } + ctx.Context.Response.Headers.Append("Access-Control-Allow-Origin", "*"); + ctx.Context.Response.Headers.Append("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + }, + }); + + app.UseRouting(); + + //Important! Register Cors Policy before Using Authentication and Authorization + app.UseCors("CorsPolicy"); + app.UseAuthentication(); + app.UseAuthorization(); + + // Enable middleware to serve generated Swagger as a JSON endpoint. + app.UseSwagger(c => + { + c.PreSerializeFilters.Add((swagger, httpReq) => + { + swagger.Servers = new List { new OpenApiServer { Url = $"{httpReq.Scheme}://{httpReq.Host.Value}" } }; + }); + }); + + app.ApplicationServices.SaveSwaggerJson(Configuration.GetSection("ApiConfig").GetValue("Url"), Configuration.GetSection("JsonConfig").GetValue("Jsondir")); + + // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint. + app.UseSwaggerUI(c => + { + c.SwaggerEndpoint("/swagger/v1/swagger.json", "Open Data Hub Content API V1"); + c.RoutePrefix = "swagger"; + c.OAuthClientSecret(""); + c.OAuthRealm("noi"); + c.EnableDeepLinking(); + }); + + app.UseRateLimiting(); + + app.UseKeycloakAuthorizationService(); + + ////LOG EVERY REQUEST WITH HEADERs + app.UseODHCustomHttpRequestConfig(Configuration); + + app.UseEndpoints(endpoints => + { + endpoints.MapRazorPages(); + endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}"); + }); + + app.UseHealthChecks("/self", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + + app.UseHealthChecks("/ready", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("services") + }); + } + } + + +} diff --git a/ContentApiCore/Swagger/AuthenticationRequirementsOperationFilter.cs b/ContentApiCore/Swagger/AuthenticationRequirementsOperationFilter.cs new file mode 100644 index 0000000..c41b34d --- /dev/null +++ b/ContentApiCore/Swagger/AuthenticationRequirementsOperationFilter.cs @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; + +namespace ContentApiCore.Swagger +{ + public class AuthenticationRequirementsOperationFilter : IOperationFilter + { + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + if (operation.Security == null) + operation.Security = new List(); + + + var scheme = new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } }; + operation.Security.Add(new OpenApiSecurityRequirement + { + [scheme] = new List() + }); + } + } +} diff --git a/ContentApiCore/Swagger/CachingSwaggerProvider.cs b/ContentApiCore/Swagger/CachingSwaggerProvider.cs new file mode 100644 index 0000000..b42a5c9 --- /dev/null +++ b/ContentApiCore/Swagger/CachingSwaggerProvider.cs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.Swagger; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Concurrent; + +namespace ContentApiCore.Swagger +{ + public class CachingSwaggerProvider : ISwaggerProvider + { + private static readonly ConcurrentDictionary _cache = new ConcurrentDictionary(); + + private readonly SwaggerGenerator _swaggerGenerator; + + public CachingSwaggerProvider( + IOptions optionsAccessor, + IApiDescriptionGroupCollectionProvider apiDescriptionsProvider, + ISchemaGenerator schemaGenerator) + { + _swaggerGenerator = new SwaggerGenerator(optionsAccessor.Value, apiDescriptionsProvider, schemaGenerator); + } + + public OpenApiDocument GetSwagger(string documentName, string host = null, string basePath = null) + { + //bool isincache = false; + //if (_cache.ContainsKey("v1")) + // isincache = true; + + var doc = _cache.GetOrAdd(documentName, (_) => _swaggerGenerator.GetSwagger(documentName, host, basePath)); + + //if (!isincache) + // this.SaveSwaggerJson("haslo"); + + return doc; + } + } +} diff --git a/ContentApiCore/Swagger/DeprecatedAttributeSchemaFilter.cs b/ContentApiCore/Swagger/DeprecatedAttributeSchemaFilter.cs new file mode 100644 index 0000000..195a12e --- /dev/null +++ b/ContentApiCore/Swagger/DeprecatedAttributeSchemaFilter.cs @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel.Annotations; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Linq; +using System.Reflection; + +namespace ContentApiCore.Swagger +{ + public class DeprecatedAttributeSchemaFilter : ISchemaFilter + { + public void Apply(OpenApiSchema schema, SchemaFilterContext context) + { + if ((context.ParameterInfo as ICustomAttributeProvider ?? context.MemberInfo) is { } info) + { + var deprecatedAttribute = info + .GetCustomAttributes(false) + .FirstOrDefault(attribute => attribute.GetType() == typeof(SwaggerDeprecatedAttribute)); + if (deprecatedAttribute is SwaggerDeprecatedAttribute deprecated) + { + schema.Deprecated = true; + if (!string.IsNullOrEmpty(deprecated.Description)) + { + if (string.IsNullOrEmpty(schema.Description)) + schema.Description = deprecated.Description; + else + schema.Description += $"\n{deprecated.Description}"; + } + } + } + } + } +} diff --git a/ContentApiCore/Swagger/EnumAttributeSchemaFilter.cs b/ContentApiCore/Swagger/EnumAttributeSchemaFilter.cs new file mode 100644 index 0000000..4e8654b --- /dev/null +++ b/ContentApiCore/Swagger/EnumAttributeSchemaFilter.cs @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel.Annotations; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace ContentApiCore.Swagger +{ + public class EnumAttributeSchemaFilter : ISchemaFilter + { + public void Apply(OpenApiSchema schema, SchemaFilterContext context) + { + if ((context.MemberInfo as ICustomAttributeProvider ?? context.ParameterInfo) is { } info) + { + var obsoleteMemberAttribute = info + .GetCustomAttributes(false) + .FirstOrDefault(attribute => attribute.GetType() == typeof(SwaggerEnumAttribute)); + if (obsoleteMemberAttribute is SwaggerEnumAttribute obsoleteMember) + { + var enumValues = new List(); + foreach (var enumValue in obsoleteMember.EnumValues) + enumValues.Add(new OpenApiString(enumValue)); + schema.Enum = enumValues; + } + } + } + } +} diff --git a/ContentApiCore/Swagger/SwaggerExtensions.cs b/ContentApiCore/Swagger/SwaggerExtensions.cs new file mode 100644 index 0000000..6d5488a --- /dev/null +++ b/ContentApiCore/Swagger/SwaggerExtensions.cs @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi.Extensions; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.Swagger; +using System; +using System.IO; + +namespace ContentApiCore.Swagger +{ + public static class SwaggerExtensions + { + //public static IApplicationBuilder UseSaveSwaggerJson(this IApplicationBuilder builder, IConfiguration configuration) + //{ + // return builder.Use(async (context, next) => + // { + // builder.ApplicationServices.SaveSwaggerJson() + // }); + //} + + + public static void SaveSwaggerJson(this IServiceProvider provider, string servername, string swaggerdir) + { + ISwaggerProvider sw = provider.GetRequiredService(); + + OpenApiDocument doc = sw.GetSwagger("v1", null, servername); + string swaggerFile = doc.SerializeAsJson(Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0); + + string fileName = Path.Combine(swaggerdir, "swagger.json"); + File.WriteAllText(fileName, swaggerFile); + } + } +} diff --git a/ContentApiCore/appsettings.Development.json b/ContentApiCore/appsettings.Development.json new file mode 100644 index 0000000..6ae78e1 --- /dev/null +++ b/ContentApiCore/appsettings.Development.json @@ -0,0 +1,65 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "RateLimitConfig": [ + { + "Type": "Anonymous", + "TimeWindow": 1, + "MaxRequests": 10 + }, + { + "Type": "Referer", + "TimeWindow": 1, + "MaxRequests": 20 + }, + { + "Type": "Basic", + "TimeWindow": 1, + "MaxRequests": 30 + }, + { + "Type": "Advanced", + "TimeWindow": 1, + "MaxRequests": 50 + }, + { + "Type": "Premium", + "TimeWindow": 1, + "MaxRequests": 100 + }, + { + "Type": "Admin", + "TimeWindow": 1, + "MaxRequests": 0 + } + ], + "NoRateLimitConfig": { + "NoRateLimitRoutesConfig": [ + { + "Path": "/v1/Activity/Gpx" + }, + { + "Path": "/v1/Activity/GpxByUrl" + }, + { + "Path": "/v1/Poi/Gpx" + }, + { + "Path": "/v1/SmgPoiGpx" + } + ], + "NoRateLimitRefererConfig": [ + { + "Referer": "testreferer" + } + ] + }, + "ApiConfig": { + "Url": "https://api.tourism.testingmachine.eu" + } +} diff --git a/ContentApiCore/appsettings.Production.json b/ContentApiCore/appsettings.Production.json new file mode 100644 index 0000000..25faa02 --- /dev/null +++ b/ContentApiCore/appsettings.Production.json @@ -0,0 +1,81 @@ +{ + "Field2HideConfig": [ + { + "Entity": "Accommodation", + "DisplayOnRoles": "IDM,DataReader", + "Fields": "TVMember,Beds,Units,TrustYouID,TrustYouScore,TrustYouState,TrustYouResults,TrustYouActive,Representation" + }, + { + "Entity": "", + "DisplayOnRoles": "DataReader,IDM", + "Fields": "RepresentationRestriction" + } + ], + + "RequestInterceptorConfig": [ + { + "Action": "GetODHActivityPoiList", + "Controller": "ODHActivityPoi", + "QueryStrings": "language=*&poitype=447&active=true&fields=Id,Detail.*.Title,ContactInfos.*.City&pagesize=20000", + "RedirectAction": "GetODHActivityPoiListSTA", + "RedirectController": "STA", + "RedirectQueryStrings": "language" + } + ], + "RateLimitConfig": [ + { + "Type": "Anonymous", + "TimeWindow": 1, + "MaxRequests": 10 + }, + { + "Type": "Referer", + "TimeWindow": 1, + "MaxRequests": 20 + }, + { + "Type": "Basic", + "TimeWindow": 1, + "MaxRequests": 50 + }, + { + "Type": "Advanced", + "TimeWindow": 1, + "MaxRequests": 100 + }, + { + "Type": "Premium", + "TimeWindow": 1, + "MaxRequests": 200 + }, + { + "Type": "Admin", + "TimeWindow": 1, + "MaxRequests": 0 + } + ], + "NoRateLimitConfig": { + "NoRateLimitRoutesConfig": [ + { + "Path": "/v1/Activity/Gpx" + }, + { + "Path": "/v1/Activity/GpxByUrl" + }, + { + "Path": "/v1/Poi/Gpx" + }, + { + "Path": "/v1/SmgPoiGpx" + } + ], + "NoRateLimitRefererConfig": [ + { + "Referer": "testreferer" + } + ] + }, + "ApiConfig": { + "Url": "https://tourism.api.opendatahub.com" + } +} diff --git a/ContentApiCore/appsettings.json b/ContentApiCore/appsettings.json new file mode 100644 index 0000000..6f322f3 --- /dev/null +++ b/ContentApiCore/appsettings.json @@ -0,0 +1,89 @@ +{ + "ConnectionStrings": { + "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-OdhApiCore-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true" + }, + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "AllowedHosts": "*", + "Field2HideConfig": [ + { + "Entity": "Accommodation", + "DisplayOnRoles": "IDM,DataReader", + "Fields": "TVMember,Beds,Units,TrustYouID,TrustYouScore,TrustYouState,TrustYouResults,TrustYouActive,Representation" + }, + { + "Entity": "", + "DisplayOnRoles": "DataReader,IDM", + "Fields": "RepresentationRestriction" + } + ], + "RequestInterceptorConfig": [ + { + "Action": "GetODHActivityPoiList", + "Controller": "ODHActivityPoi", + "QueryStrings": "language=*&poitype=447&active=true&fields=Id,Detail.*.Title,ContactInfos.*.City&pagesize=20000", + "RedirectAction": "GetODHActivityPoiListSTA", + "RedirectController": "STA", + "RedirectQueryStrings": "language" + } + ], + "RateLimitConfig": [ + { + "Type": "Anonymous", + "TimeWindow": 1, + "MaxRequests": 5 + }, + { + "Type": "Referer", + "TimeWindow": 1, + "MaxRequests": 10 + }, + { + "Type": "Basic", + "TimeWindow": 1, + "MaxRequests": 50 + }, + { + "Type": "Advanced", + "TimeWindow": 1, + "MaxRequests": 100 + }, + { + "Type": "Premium", + "TimeWindow": 1, + "MaxRequests": 200 + }, + { + "Type": "Admin", + "TimeWindow": 1, + "MaxRequests": 0 + } + ], + "NoRateLimitConfig": { + "NoRateLimitRoutesConfig": [ + { + "Path": "/v1/Activity/Gpx" + }, + { + "Path": "/v1/Activity/GpxByUrl" + }, + { + "Path": "/v1/Poi/Gpx" + }, + { + "Path": "/v1/SmgPoiGpx" + } + ], + "NoRateLimitRefererConfig": [ + { + "Referer": "testreferer" + } + ] + }, + "ApiConfig": { + "Url": "https://localhost:8001" + } +} diff --git a/ContentApiCore/docker-compose.yml b/ContentApiCore/docker-compose.yml new file mode 100644 index 0000000..cd12a2e --- /dev/null +++ b/ContentApiCore/docker-compose.yml @@ -0,0 +1,34 @@ +# SPDX-FileCopyrightText: NOI Techpark +# +# SPDX-License-Identifier: CC0-1.0 + +services: + api: + image: ${DOCKER_IMAGE:-odh-content-api}:${DOCKER_TAG:-latest} + build: + context: ../ + dockerfile: ContentApiCore/Dockerfile + environment: + ASPNETCORE_ENVIRONMENT: Development + ASPNETCORE_URLS: http://+:80 + ASPNETCORE_ConnectionStrings__PgConnection: ${PG_CONNECTION} + ASPNETCORE_XmlConfig__XmldirWeather: ${XMLDIR} + ASPNETCORE_Xmldir__Xmldir: ${XMLDIR} + ASPNETCORE_S3ImageresizerConfig__Url: ${IMG_URL} + ASPNETCORE_S3ImageresizerConfig__BucketAccessPoint: ${S3_BUCKET_ACCESSPOINT} + ASPNETCORE_S3ImageresizerConfig__AccessKey: ${S3_IMAGEUPLOADER_ACCESSKEY} + ASPNETCORE_S3ImageresizerConfig__SecretKey: ${S3_IMAGEUPLOADER_SECRETKEY} + ASPNETCORE_OauthServerConfig__Authority: ${OAUTH_AUTORITY} + ASPNETCORE_ElasticSearchConfig__ElasticUrl: ${ELK_URL} + ASPNETCORE_ElasticSearchConfig__ElasticAuthtoken: ${ELK_TOKEN} + ASPNETCORE_JsonConfig__Jsondir: ${JSONPATH} + ASPNETCORE_DataBrowserConfig__Url: ${DATABROWSER_URL} + ASPNETCORE_FCMConfig__noi-communityapp__ServerKey: ${NOICOMMUNITY_SERVERKEY} + ASPNETCORE_FCMConfig__noi-communityapp__SenderId: ${NOICOMMUNITY_SENDERID} + ASPNETCORE_FCMConfig__noi-communityapp__ProjectName: ${NOICOMMUNITY_PROJECTNAME} + ASPNETCORE_FCMConfig__noi-communityapp__FCMServiceAccount: ${NOICOMMUNITY_FCMSERVICEACCOUNT} + ASPNETCORE_NotifierConfig__idm-marketplace__Url: ${MARKETPLACE_PUSH_URL} + ASPNETCORE_NotifierConfig__idm-marketplace__User: ${MARKETPLACE_PUSH_USER} + ASPNETCORE_NotifierConfig__idm-marketplace__Password: ${MARKETPLACE_PUSH_PSWD} + ports: + - "8001:80" diff --git a/ContentApiCore/wwwroot/json/.gitkeep b/ContentApiCore/wwwroot/json/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ContentApiCore/wwwroot/json/swagger.json b/ContentApiCore/wwwroot/json/swagger.json new file mode 100644 index 0000000..b7fb8bd --- /dev/null +++ b/ContentApiCore/wwwroot/json/swagger.json @@ -0,0 +1,4913 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Open Data Hub Content Api", + "description": "Open Data Hub Content Api based on .Net Core with PostgreSQL", + "termsOfService": "https://opendatahub.readthedocs.io/en/latest/", + "contact": { + "name": "Open Data Hub Team", + "url": "https://opendatahub.com/", + "email": "help@opendatahub.com" + }, + "version": "v1" + }, + "servers": [ + { + "url": "https://api.tourism.testingmachine.eu" + } + ], + "paths": { + "/v1/Deprecated": { + "get": { + "tags": [ + "Deprecated" + ], + "summary": "GET Generic Deprecated search of fields", + "parameters": [ + { + "name": "pagenumber", + "in": "query", + "description": "Pagenumber", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pagesize", + "in": "query", + "description": "Elements per Page, (default:10)", + "schema": { + "type": "integer" + } + }, + { + "name": "odhtype", + "in": "query", + "description": "Mandatory search trough Entities (metadata, accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... null = search trough all entities)", + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "description": "Mandatory search trough Entities (metadata, accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... null = search trough all entities)", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Mandatory Select a field for the Distinct Query, example fields=Source, arrays are selected with a [*] example HasLanguage[*] / Features[*].Id (Only one field supported). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "seed", + "in": "query", + "description": "Seed '1 - 10' for Random Sorting, '0' generates a Random Seed, 'null' disables Random Sorting, (default:null)", + "schema": { + "type": "string" + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "getasarray", + "in": "query", + "description": "Get only first selected field as simple string Array", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "excludenulloremptyvalues", + "in": "query", + "description": "Exclude empty and null values from output", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/ld+json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/ldjson": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/rawdata": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/Distinct": { + "get": { + "tags": [ + "Distinct" + ], + "summary": "GET Generic Distinct search of fields", + "parameters": [ + { + "name": "pagenumber", + "in": "query", + "description": "Pagenumber", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pagesize", + "in": "query", + "description": "Elements per Page, (default:10)", + "schema": { + "type": "integer" + } + }, + { + "name": "odhtype", + "in": "query", + "description": "Mandatory search trough Entities (metadata, accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... )", + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "description": "Mandatory search trough Entities (metadata, accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... )", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Mandatory Select a field for the Distinct Query, example fields=Source, arrays are selected with a [*] example HasLanguage[*] / Features[*].Id (Only one field supported). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "seed", + "in": "query", + "description": "Seed '1 - 10' for Random Sorting, '0' generates a Random Seed, 'null' disables Random Sorting, (default:null)", + "schema": { + "type": "string" + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "getasarray", + "in": "query", + "description": "Get only first selected field as simple string Array", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "excludenulloremptyvalues", + "in": "query", + "description": "Exclude empty and null values from output", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/ld+json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/ldjson": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "application/rawdata": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/Example": { + "get": { + "tags": [ + "Example" + ], + "summary": "GET Example List", + "parameters": [ + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields in the selected language (default:'null' all languages are displayed)", + "schema": { + "type": "string" + } + }, + { + "name": "pagenumber", + "in": "query", + "description": "Pagenumber", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pagesize", + "in": "query", + "description": "Elements per Page, (default:10)", + "schema": { + "type": "integer" + } + }, + { + "name": "exampletype", + "in": "query", + "description": "Example Types Filter (Separator ',' List of ExampleTypes IDs), (default:'null')", + "schema": { + "type": "string" + } + }, + { + "name": "idlist", + "in": "query", + "description": "IDFilter (Separator ',' List of IDs), (default:'null')", + "schema": { + "type": "string" + } + }, + { + "name": "langfilter", + "in": "query", + "description": "Language filter (returns only data available in the selected Language, Separator ',' possible values: 'de,it,en,nl,sc,pl,fr,ru', 'null': Filter disabled)", + "schema": { + "type": "string" + } + }, + { + "name": "active", + "in": "query", + "description": "Active Filter (possible Values: 'true' only Active Data, 'false' only Disabled Data), (default:'null')", + "schema": { + "type": "boolean" + } + }, + { + "name": "updatefrom", + "in": "query", + "description": "Returns data changed after this date Format (yyyy-MM-dd), (default: 'null')", + "schema": { + "type": "string" + } + }, + { + "name": "seed", + "in": "query", + "description": "Seed '1 - 10' for Random Sorting, '0' generates a Random Seed, 'null' disables Random Sorting, (default:null)", + "schema": { + "type": "string" + } + }, + { + "name": "publishedon", + "in": "query", + "description": "Published On Filter (Separator ',' List of publisher IDs), (default:'null')", + "schema": { + "type": "string" + } + }, + { + "name": "source", + "in": "query", + "description": "Filter by Source (Separator ','), (Sources available 'idm','noi'...),(default: 'null')", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "searchfilter", + "in": "query", + "description": "String to search for, Title in all languages are searched, (default: null) Wiki searchfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ExampleLinkedJsonResult" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinkedJsonResult" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinkedJsonResult" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ExampleLinkedJsonResult" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinkedJsonResult" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ExampleLinkedJsonResult" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ExampleLinkedJsonResult" + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "post": { + "tags": [ + "Example" + ], + "summary": "POST Insert new Example", + "requestBody": { + "description": "Example Object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/Example/{id}": { + "get": { + "tags": [ + "Example" + ], + "summary": "GET Example Single", + "operationId": "SingleExample", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of the Example", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields in the selected language (default:'null' all languages are displayed)", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Object created", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "put": { + "tags": [ + "Example" + ], + "summary": "PUT Modify existing Example", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Example Id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Example Object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/ExampleLinked" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "delete": { + "tags": [ + "Example" + ], + "summary": "DELETE Example by Id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Example Id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/PGCRUDResult" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/ExampleTypes": { + "get": { + "tags": [ + "Example" + ], + "summary": "GET ExampleTypes List", + "parameters": [ + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields in the selected language (default:'null' all languages are displayed)", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "searchfilter", + "in": "query", + "description": "String to search for, Title in all languages are searched, (default: null) Wiki searchfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExampleTypes" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExampleTypes" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExampleTypes" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExampleTypes" + } + } + }, + "application/ld+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExampleTypes" + } + } + }, + "application/ldjson": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExampleTypes" + } + } + }, + "application/rawdata": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExampleTypes" + } + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/ExampleTypes/{id}": { + "get": { + "tags": [ + "Example" + ], + "summary": "GET ExampleTypes Single", + "operationId": "SingleExampleTypes", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of the ExampleType", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields in the selected language (default:'null' all languages are displayed)", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ExampleTypes" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExampleTypes" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ExampleTypes" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ExampleTypes" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ExampleTypes" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ExampleTypes" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ExampleTypes" + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/FileUpload": { + "post": { + "tags": [ + "FileUpload" + ], + "summary": " (Auth)", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "form": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StringStringValuesKeyValuePair" + } + } + } + }, + "encoding": { + "form": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/FileUpload/Image": { + "post": { + "tags": [ + "FileUpload" + ], + "summary": " (Auth)", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "form": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StringStringValuesKeyValuePair" + } + } + } + }, + "encoding": { + "form": { + "style": "form" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/FileDelete/{filepath}": { + "delete": { + "tags": [ + "FileUpload" + ], + "summary": " (Auth)", + "parameters": [ + { + "name": "filepath", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/GeoShapes": { + "get": { + "tags": [ + "Geo" + ], + "summary": "GET GeoShapes List", + "parameters": [ + { + "name": "pagenumber", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pagesize", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "searchfilter", + "in": "query", + "description": "String to search for, Title in all languages are searched, (default: null) Wiki searchfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeoShapes" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeoShapes" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeoShapes" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeoShapes" + } + } + }, + "application/ld+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeoShapes" + } + } + }, + "application/ldjson": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeoShapes" + } + } + }, + "application/rawdata": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GeoShapes" + } + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/GeoShapes/{id}": { + "get": { + "tags": [ + "Geo" + ], + "summary": "GET GeoShape Single", + "operationId": "SingleShapes", + "parameters": [ + { + "name": "pagenumber", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pagesize", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "id", + "in": "path", + "description": "ID of the Tag", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Object created", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/GeoShapes" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/GeoShapes" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/GeoShapes" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/GeoShapes" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/GeoShapes" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/GeoShapes" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/GeoShapes" + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/GeoConverter/KmlToGeoJson": { + "get": { + "tags": [ + "GeoConverter" + ], + "summary": "Converts the KML file from the supplied URL to GeoJSON.", + "parameters": [ + { + "name": "url", + "in": "query", + "description": "The URL to the KML file.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "404": { + "description": "Not Found", + "content": { + "application/geo+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "post": { + "tags": [ + "GeoConverter" + ], + "summary": "Converts the KML provided as the body to GeoJSON.", + "parameters": [ + { + "name": "body", + "in": "query", + "description": "The KML file content.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/GeoConverter/GpxToGeoJson": { + "get": { + "tags": [ + "GeoConverter" + ], + "summary": "Converts the GPX file from the supplied URL to GeoJSON.", + "parameters": [ + { + "name": "url", + "in": "query", + "description": "The URL to the GPX file.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + }, + "404": { + "description": "Not Found", + "content": { + "application/geo+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "post": { + "tags": [ + "GeoConverter" + ], + "summary": "Converts the GPX provided as the body to GeoJSON.", + "parameters": [ + { + "name": "body", + "in": "query", + "description": "The GPX file content.", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/JsonLD/DetailInLD": { + "get": { + "tags": [ + "JsonLD" + ], + "summary": "GET Detail Data in JSON LD Format (Schema.org Datatypes as output)", + "parameters": [ + { + "name": "type", + "in": "query", + "description": "Data Type to transform currently available: ('accommodation', 'gastronomy', 'event', 'recipe', 'poi', 'region', 'tv', 'municipality', 'district', 'skiarea') required", + "schema": { + "type": "string" + } + }, + { + "name": "Id", + "in": "query", + "description": "ID of the data to transform, required", + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Output Language, standard EN", + "schema": { + "type": "string", + "default": "en" + } + }, + { + "name": "idtoshow", + "in": "query", + "description": "ID to show on Json LD @id, not provided Id of ODH api call is taken", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "urltoshow", + "in": "query", + "description": "url to show on Json LD @id, not provided idtoshow is taken, idtoshow not provided url is filled with url of the data", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "imageurltoshow", + "in": "query", + "description": "image url to show on Json LD @image, not provided image url of data is taken", + "schema": { + "type": "string", + "default": "" + } + }, + { + "name": "showid", + "in": "query", + "description": "Show the @id property in Json LD default value true", + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/Publisher": { + "get": { + "tags": [ + "Publisher" + ], + "summary": "GET Publishers List", + "parameters": [ + { + "name": "pagenumber", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pagesize", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields available in the selected language (default:'null' all languages are displayed)", + "schema": { + "type": "string" + } + }, + { + "name": "idlist", + "in": "query", + "description": "IDFilter (Separator ',' List of IDs, 'null' = No Filter), (default:'null')", + "schema": { + "type": "string" + } + }, + { + "name": "source", + "in": "query", + "description": "Source Filter (possible Values: 'lts','idm'), (default:'null')", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "searchfilter", + "in": "query", + "description": "String to search for, Title in all languages are searched, (default: null) Wiki searchfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + }, + "application/ld+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + }, + "application/ldjson": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + }, + "application/rawdata": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "post": { + "tags": [ + "Publisher" + ], + "summary": "POST Insert new Publisher", + "requestBody": { + "description": "PublisherLinked Object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/Publisher/{id}": { + "get": { + "tags": [ + "Publisher" + ], + "summary": "GET Publisher Single", + "operationId": "SinglePublisher", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of the Publisher", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields available in the selected language (default:'null' all languages are displayed)", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "localizationlanguage", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Object created", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "put": { + "tags": [ + "Publisher" + ], + "summary": "PUT Modify existing Publisher", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Publisher Id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Publisher Object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/PublisherLinked" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "delete": { + "tags": [ + "Publisher" + ], + "summary": "DELETE Publisher by Id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Publisher Id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/PushResponse": { + "get": { + "tags": [ + "PushResponse" + ], + "summary": "GET PushResponse List", + "parameters": [ + { + "name": "pagenumber", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pagesize", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "idlist", + "in": "query", + "description": "IDFilter (Separator ',' List of IDs, 'null' = No Filter), (default:'null')", + "schema": { + "type": "string" + } + }, + { + "name": "publisher", + "in": "query", + "description": "publisher Filter (Separator ',' List of IDs, 'null' = No Filter), (default:'null')", + "schema": { + "type": "string" + } + }, + { + "name": "begindate", + "in": "query", + "description": "BeginDate of Events (Format: yyyy-MM-dd), (default: 'null')", + "schema": { + "type": "string" + } + }, + { + "name": "enddate", + "in": "query", + "description": "EndDate of Events (Format: yyyy-MM-dd), (default: 'null')", + "schema": { + "type": "string" + } + }, + { + "name": "objectidlist", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "objecttypelist", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushResponse" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushResponse" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushResponse" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushResponse" + } + } + }, + "application/ld+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushResponse" + } + } + }, + "application/ldjson": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushResponse" + } + } + }, + "application/rawdata": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushResponse" + } + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/PushResponse/{id}": { + "get": { + "tags": [ + "PushResponse" + ], + "summary": "GET PushResponse Single", + "operationId": "SinglePushResponse", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of the PushResponse", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Object created", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/PushResponse" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/PushResponse" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/PushResponse" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/PushResponse" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/PushResponse" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/PushResponse" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/PushResponse" + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/Find": { + "get": { + "tags": [ + "Search" + ], + "summary": "GET Search over all Entities", + "parameters": [ + { + "name": "term", + "in": "query", + "description": "Term to Search for Wiki", + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields available in the selected language ('null' all languages are displayed)", + "schema": { + "type": "string", + "default": "en" + } + }, + { + "name": "odhtype", + "in": "query", + "description": "Restrict search to Entities (accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... )", + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "description": "Restrict search to Entities (accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... )", + "schema": { + "type": "string" + } + }, + { + "name": "searchbasetext", + "in": "query", + "description": "Search also trough base text (true/false), caution can slow down the search significantly", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "filteronfields", + "in": "query", + "description": "Search also on this fields, syntax analog to the fields filter", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "limitto", + "in": "query", + "description": "Limit search to n items per entity", + "schema": { + "type": "integer", + "format": "int32", + "default": 5 + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "application/ld+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "application/ldjson": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "application/rawdata": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/Filter": { + "get": { + "tags": [ + "Search" + ], + "summary": "GET Search over all Entities", + "parameters": [ + { + "name": "term", + "in": "query", + "description": "Term to Search for Wiki", + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields available in the selected language ('null' all languages are displayed)", + "schema": { + "type": "string", + "default": "en" + } + }, + { + "name": "odhtype", + "in": "query", + "description": "Restrict search to Entities (accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... )", + "schema": { + "type": "string" + } + }, + { + "name": "type", + "in": "query", + "description": "Restrict search to Entities (accommodation, odhactivitypoi, event, webcam, measuringpoint, ltsactivity, ltspoi, ltsgastronomy, article ..... )", + "schema": { + "type": "string" + } + }, + { + "name": "searchbasetext", + "in": "query", + "description": "Search also trough base text (true/false), caution can slow down the search significantly", + "schema": { + "type": "boolean", + "default": false + } + }, + { + "name": "filteronfields", + "in": "query", + "description": "Search also on this fields, syntax analog to the fields filter", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "limitto", + "in": "query", + "description": "Limit search to n items per entity", + "schema": { + "type": "integer", + "format": "int32", + "default": 5 + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "application/ld+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "application/ldjson": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + }, + "application/rawdata": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonRaw" + } + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/Source": { + "get": { + "tags": [ + "Source" + ], + "summary": "GET Sources List", + "parameters": [ + { + "name": "pagenumber", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "pagesize", + "in": "query", + "schema": { + "type": "integer" + } + }, + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields available in the selected language (default:'null' all languages are displayed)", + "schema": { + "type": "string" + } + }, + { + "name": "idlist", + "in": "query", + "description": "IDFilter (Separator ',' List of IDs, 'null' = No Filter), (default:'null')", + "schema": { + "type": "string" + } + }, + { + "name": "typelist", + "in": "query", + "description": "Type Filter (Separator ',' Filter Sources by Type ('accommodation','event','odhactivitypoi','webcam','region','municipality','district','tourismassocation','weather','measuringpoint','weatherhistory','weatherforecast','accommodationroom','venue','article','eventshort','wineaward','tag','odhtag'), (default:'null')", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "searchfilter", + "in": "query", + "description": "String to search for, Title in all languages are searched, (default: null) Wiki searchfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawfilter", + "in": "query", + "description": "Wiki rawfilter", + "schema": { + "type": "string" + } + }, + { + "name": "rawsort", + "in": "query", + "description": "Wiki rawsort", + "schema": { + "type": "string" + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "List created", + "content": { + "text/plain": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceLinked" + } + } + }, + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceLinked" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceLinked" + } + } + }, + "text/csv": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceLinked" + } + } + }, + "application/ld+json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceLinked" + } + } + }, + "application/ldjson": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceLinked" + } + } + }, + "application/rawdata": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SourceLinked" + } + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "post": { + "tags": [ + "Source" + ], + "summary": "POST Insert new Source", + "requestBody": { + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + }, + "/v1/Source/{id}": { + "get": { + "tags": [ + "Source" + ], + "summary": "GET Source Single", + "operationId": "SingleSource", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "ID of the Source", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "language", + "in": "query", + "description": "Language field selector, displays data and fields available in the selected language (default:'null' all languages are displayed)", + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "Select fields to display, More fields are indicated by separator ',' example fields=Id,Active,Shortname (default:'null' all fields are displayed). Wiki fields", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + { + "name": "localizationlanguage", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "removenullvalues", + "in": "query", + "description": "Remove all Null values from json output. Useful for reducing json size. By default set to false. Documentation on Opendatahub Wiki", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Object created", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + } + } + }, + "400": { + "description": "Request Error", + "content": { + "text/plain": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ld+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/ldjson": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + }, + "application/rawdata": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "put": { + "tags": [ + "Source" + ], + "summary": "PUT Modify existing Source", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Source Id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "Source Object", + "content": { + "application/json-patch+json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "application/json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "text/json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + }, + "application/*+json": { + "schema": { + "$ref": "#/components/schemas/SourceLinked" + } + } + } + }, + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + }, + "delete": { + "tags": [ + "Source" + ], + "summary": "DELETE Source by Id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Source Id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + }, + "security": [ + { + "oauth2": [ ] + } + ] + } + } + }, + "components": { + "schemas": { + "ContactInfos": { + "type": "object", + "properties": { + "Address": { + "type": "string", + "description": "Street Address", + "nullable": true + }, + "Region": { + "type": "string", + "description": "Region (Province / State / Departement / Canton etc...", + "nullable": true + }, + "RegionCode": { + "type": "string", + "description": "Regioncode", + "nullable": true + }, + "Area": { + "type": "string", + "description": "Area (Additional Area Name)", + "nullable": true + }, + "City": { + "type": "string", + "nullable": true + }, + "ZipCode": { + "type": "string", + "nullable": true + }, + "CountryCode": { + "type": "string", + "nullable": true + }, + "CountryName": { + "type": "string", + "nullable": true + }, + "Surname": { + "type": "string", + "nullable": true + }, + "Givenname": { + "type": "string", + "nullable": true + }, + "NamePrefix": { + "type": "string", + "nullable": true + }, + "Email": { + "type": "string", + "nullable": true + }, + "Phonenumber": { + "type": "string", + "nullable": true + }, + "Faxnumber": { + "type": "string", + "nullable": true + }, + "Url": { + "type": "string", + "nullable": true + }, + "Language": { + "type": "string", + "nullable": true + }, + "CompanyName": { + "type": "string", + "nullable": true + }, + "Vat": { + "type": "string", + "nullable": true + }, + "Tax": { + "type": "string", + "nullable": true + }, + "LogoUrl": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Detail": { + "type": "object", + "properties": { + "Header": { + "type": "string", + "nullable": true + }, + "SubHeader": { + "type": "string", + "nullable": true + }, + "IntroText": { + "type": "string", + "nullable": true + }, + "BaseText": { + "type": "string", + "nullable": true + }, + "Title": { + "type": "string", + "nullable": true + }, + "AdditionalText": { + "type": "string", + "nullable": true + }, + "MetaTitle": { + "type": "string", + "nullable": true + }, + "MetaDesc": { + "type": "string", + "nullable": true + }, + "GetThereText": { + "type": "string", + "nullable": true + }, + "Language": { + "type": "string", + "nullable": true + }, + "Keywords": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "ParkingInfo": { + "type": "string", + "nullable": true + }, + "PublicTransportationInfo": { + "type": "string", + "nullable": true + }, + "AuthorTip": { + "type": "string", + "nullable": true + }, + "SafetyInfo": { + "type": "string", + "nullable": true + }, + "EquipmentInfo": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ExampleLinked": { + "type": "object", + "properties": { + "Self": { + "type": "string", + "description": "generated field", + "nullable": true, + "readOnly": true + }, + "ODHTags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExampleTypes" + }, + "description": "generated field", + "nullable": true, + "readOnly": true + }, + "_Meta": { + "$ref": "#/components/schemas/Metadata" + }, + "Id": { + "type": "string", + "nullable": true + }, + "FirstImport": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "LastChange": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "Source": { + "type": "string", + "nullable": true + }, + "Active": { + "type": "boolean" + }, + "Shortname": { + "type": "string", + "nullable": true + }, + "Mapping": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "nullable": true + }, + "HasLanguage": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "PublishedOn": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "Detail": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Detail" + }, + "nullable": true + }, + "GpsInfo": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GpsInfo" + }, + "nullable": true + }, + "GpsPoints": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/GpsInfo" + }, + "description": "generated field", + "nullable": true, + "readOnly": true, + "deprecated": true + }, + "ImageGallery": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ImageGallery" + }, + "nullable": true + }, + "ContactInfos": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ContactInfos" + }, + "nullable": true + }, + "ExampleTypeIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "LicenseInfo": { + "$ref": "#/components/schemas/LicenseInfo" + }, + "AdditionalProperties": { + "type": "object", + "additionalProperties": { }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ExampleLinkedJsonResult": { + "type": "object", + "properties": { + "TotalResults": { + "type": "integer", + "format": "int32" + }, + "TotalPages": { + "type": "integer", + "format": "int32" + }, + "CurrentPage": { + "type": "integer", + "format": "int32" + }, + "PreviousPage": { + "type": "string", + "nullable": true + }, + "NextPage": { + "type": "string", + "nullable": true + }, + "Seed": { + "type": "string", + "nullable": true + }, + "Items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExampleLinked" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ExampleTypes": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "nullable": true + }, + "Self": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "GeoShapes": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "country": { + "type": "string", + "nullable": true + }, + "code_rip": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "code_reg": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "code_prov": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "code_cm": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "code_uts": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "istatnumber": { + "type": "string", + "nullable": true + }, + "abbrev": { + "type": "string", + "nullable": true + }, + "type_uts": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "name_alternative": { + "type": "string", + "nullable": true + }, + "shape_leng": { + "type": "number", + "format": "float" + }, + "shape_area": { + "type": "number", + "format": "float" + }, + "geom": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "GpsInfo": { + "type": "object", + "properties": { + "Gpstype": { + "enum": [ + "position", + "viewpoint", + "startingandarrivalpoint", + "startingpoint", + "arrivalpoint", + "carparking", + "halfwaypoint", + "valleystationpoint", + "middlestationpoint", + "mountainstationpoint" + ], + "type": "string", + "nullable": true + }, + "Latitude": { + "type": "number", + "format": "double" + }, + "Longitude": { + "type": "number", + "format": "double" + }, + "Altitude": { + "type": "number", + "format": "double", + "nullable": true + }, + "AltitudeUnitofMeasure": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "HttpStatusCode": { + "enum": [ + "Continue", + "SwitchingProtocols", + "Processing", + "EarlyHints", + "OK", + "Created", + "Accepted", + "NonAuthoritativeInformation", + "NoContent", + "ResetContent", + "PartialContent", + "MultiStatus", + "AlreadyReported", + "IMUsed", + "MultipleChoices", + "MovedPermanently", + "Found", + "SeeOther", + "NotModified", + "UseProxy", + "Unused", + "RedirectKeepVerb", + "PermanentRedirect", + "BadRequest", + "Unauthorized", + "PaymentRequired", + "Forbidden", + "NotFound", + "MethodNotAllowed", + "NotAcceptable", + "ProxyAuthenticationRequired", + "RequestTimeout", + "Conflict", + "Gone", + "LengthRequired", + "PreconditionFailed", + "RequestEntityTooLarge", + "RequestUriTooLong", + "UnsupportedMediaType", + "RequestedRangeNotSatisfiable", + "ExpectationFailed", + "MisdirectedRequest", + "UnprocessableEntity", + "Locked", + "FailedDependency", + "UpgradeRequired", + "PreconditionRequired", + "TooManyRequests", + "RequestHeaderFieldsTooLarge", + "UnavailableForLegalReasons", + "InternalServerError", + "NotImplemented", + "BadGateway", + "ServiceUnavailable", + "GatewayTimeout", + "HttpVersionNotSupported", + "VariantAlsoNegotiates", + "InsufficientStorage", + "LoopDetected", + "NotExtended", + "NetworkAuthenticationRequired" + ], + "type": "string" + }, + "ImageGallery": { + "type": "object", + "properties": { + "ImageName": { + "type": "string", + "nullable": true + }, + "ImageUrl": { + "type": "string", + "nullable": true + }, + "Width": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "Height": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ImageSource": { + "type": "string", + "nullable": true + }, + "ImageTitle": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + }, + "ImageDesc": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + }, + "ImageAltText": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + }, + "IsInGallery": { + "type": "boolean", + "nullable": true + }, + "ListPosition": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "ValidFrom": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "ValidTo": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "CopyRight": { + "type": "string", + "nullable": true + }, + "License": { + "type": "string", + "nullable": true + }, + "LicenseHolder": { + "type": "string", + "nullable": true + }, + "ImageTags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "JsonRaw": { + "type": "object", + "properties": { + "Value": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "LicenseInfo": { + "type": "object", + "properties": { + "License": { + "enum": [ + "CC0", + "CC-BY", + "Closed" + ], + "type": "string", + "nullable": true + }, + "LicenseHolder": { + "type": "string", + "nullable": true + }, + "Author": { + "type": "string", + "nullable": true + }, + "ClosedData": { + "type": "boolean", + "description": "readonly field", + "readOnly": true + } + }, + "additionalProperties": false + }, + "Metadata": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "nullable": true + }, + "Type": { + "enum": [ + "accommodation", + "accommodationroom", + "event", + "odhactivitypoi", + "measuringpoint", + "webcam", + "article", + "venue", + "eventshort", + "experiencearea", + "region", + "metaregion", + "tourismassociation", + "municipality", + "district", + "area", + "wineaward", + "skiarea", + "skiregion", + "odhtag", + "publisher", + "tag", + "weatherhistory", + "weather", + "weatherdistrict", + "weatherforecast", + "weatherrealtime", + "snowreport", + "odhmetadata", + "package", + "ltsactivity", + "ltspoi", + "ltsgastronomy" + ], + "type": "string", + "nullable": true + }, + "LastUpdate": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "Source": { + "type": "string", + "nullable": true + }, + "Reduced": { + "type": "boolean" + }, + "UpdateInfo": { + "$ref": "#/components/schemas/UpdateInfo" + } + }, + "additionalProperties": false + }, + "NotifierResponse": { + "type": "object", + "properties": { + "Response": { + "nullable": true + }, + "HttpStatusCode": { + "$ref": "#/components/schemas/HttpStatusCode" + }, + "Service": { + "type": "string", + "nullable": true + }, + "Success": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "PGCRUDResult": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true + }, + "odhtype": { + "type": "string", + "nullable": true + }, + "operation": { + "type": "string", + "nullable": true + }, + "updated": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "created": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "deleted": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "error": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "errorreason": { + "type": "string", + "nullable": true + }, + "compareobject": { + "type": "boolean", + "nullable": true + }, + "objectchanged": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "objectimagechanged": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "pushchannels": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "changes": { + "nullable": true + }, + "pushed": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/NotifierResponse" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ProblemDetails": { + "type": "object", + "properties": { + "Type": { + "type": "string", + "nullable": true + }, + "Title": { + "type": "string", + "nullable": true + }, + "Status": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "Detail": { + "type": "string", + "nullable": true + }, + "Instance": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": { } + }, + "PublisherLinked": { + "type": "object", + "properties": { + "_Meta": { + "$ref": "#/components/schemas/Metadata" + }, + "Self": { + "type": "string", + "description": "generated field", + "nullable": true, + "readOnly": true + }, + "LicenseInfo": { + "$ref": "#/components/schemas/LicenseInfo" + }, + "Id": { + "type": "string", + "nullable": true + }, + "Key": { + "type": "string", + "nullable": true + }, + "Name": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + }, + "FirstImport": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "LastChange": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "Url": { + "type": "string", + "nullable": true + }, + "PushConfig": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PushConfig" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PushConfig": { + "type": "object", + "properties": { + "PathParam": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "BaseUrl": { + "type": "string", + "nullable": true + }, + "PushApiUrl": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "PushObject": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "nullable": true + }, + "Type": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "PushResponse": { + "type": "object", + "properties": { + "Id": { + "type": "string", + "nullable": true + }, + "Publisher": { + "type": "string", + "nullable": true + }, + "Date": { + "type": "string", + "format": "date-time" + }, + "Result": { + "nullable": true + }, + "PushObject": { + "$ref": "#/components/schemas/PushObject" + } + }, + "additionalProperties": false + }, + "SourceLinked": { + "type": "object", + "properties": { + "_Meta": { + "$ref": "#/components/schemas/Metadata" + }, + "Self": { + "type": "string", + "description": "generated field", + "nullable": true, + "readOnly": true + }, + "LicenseInfo": { + "$ref": "#/components/schemas/LicenseInfo" + }, + "Id": { + "type": "string", + "nullable": true + }, + "Key": { + "type": "string", + "nullable": true + }, + "Name": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + }, + "Description": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "nullable": true + }, + "FirstImport": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "LastChange": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "Url": { + "type": "string", + "nullable": true + }, + "Interfaces": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Interfaces that are offered by the source", + "nullable": true + }, + "Types": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "StringStringValuesKeyValuePair": { + "type": "object", + "properties": { + "Key": { + "type": "string", + "nullable": true + }, + "Value": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "UpdateInfo": { + "type": "object", + "properties": { + "UpdatedBy": { + "type": "string", + "nullable": true + }, + "UpdateSource": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + } + }, + "securitySchemes": { + "oauth2": { + "type": "oauth2", + "flows": { + "password": { + "tokenUrl": "https://auth.opendatahub.testingmachine.eu/auth/realms/noi/protocol/openid-connect/token", + "scopes": { } + }, + "clientCredentials": { + "tokenUrl": "https://auth.opendatahub.testingmachine.eu/auth/realms/noi/protocol/openid-connect/token", + "scopes": { } + } + } + } + } + }, + "tags": [ + { + "name": "Example", + "description": "Examples Api" + } + ] +} \ No newline at end of file diff --git a/ContentApiCoreTests/ContentApiCoreTests.csproj b/ContentApiCoreTests/ContentApiCoreTests.csproj new file mode 100644 index 0000000..a69e985 --- /dev/null +++ b/ContentApiCoreTests/ContentApiCoreTests.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + Always + + + + diff --git a/ContentApiCoreTests/Helper/FlagsHelperTests.cs b/ContentApiCoreTests/Helper/FlagsHelperTests.cs new file mode 100644 index 0000000..6155376 --- /dev/null +++ b/ContentApiCoreTests/Helper/FlagsHelperTests.cs @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper; +using System; +using System.Linq; +using Xunit; + +namespace ContentApiCoreTests.Helper +{ + public class FlagsHelperTests + { + [Fact] + public void GetFlags_ValidEnum() + { + var @enum = ExampleTypeFlag.examplecategory1 | ExampleTypeFlag.examplecategory2; + var flags = @enum.GetFlags(); + Assert.Equal(2, flags.Count()); + Assert.Contains(ExampleTypeFlag.examplecategory1, flags); + Assert.Contains(ExampleTypeFlag.examplecategory2, flags); + } + + [Fact] + public void GetFlags_InvalidEnumType() + { + var @enum = 12333; + Assert.Throws("withFlags", () => + { + var flags = @enum.GetFlags().ToList(); + }); + } + + [Fact] + public void GetFlags_InvalidNonFlaggedEnum() + { + var @enum = DayOfWeek.Monday; + Assert.Throws("withFlags", () => + { + var flags = @enum.GetFlags().ToList(); + }); + } + + [Fact] + public void SetFlags_Test() + { + var @enum = ExampleTypeFlag.examplecategory1 | ExampleTypeFlag.examplecategory2; + var newenum = @enum.SetFlags(ExampleTypeFlag.examplecategory3); + var flags = newenum.GetFlags(); + Assert.Equal(3, flags.Count()); + Assert.True(newenum.HasFlag(ExampleTypeFlag.examplecategory3)); + + // Functionally equivalent + Assert.Equal(@enum | ExampleTypeFlag.examplecategory3, @enum.SetFlags(ExampleTypeFlag.examplecategory3)); + } + + [Fact] + public void SetFlags_TestWithOnFalse() + { + var @enum = ExampleTypeFlag.examplecategory1 | ExampleTypeFlag.examplecategory2 | ExampleTypeFlag.examplecategory3; + + // Attention, not functionally equivalent! + //Assert.Equal(@enum & ActivityTypeBerg.Bergtouren, @enum.SetFlags(ActivityTypeBerg.Bergtouren, false)); + + var newenum2 = @enum.SetFlags(ExampleTypeFlag.examplecategory1, false); + Assert.False(newenum2.HasFlag(ExampleTypeFlag.examplecategory1)); + Assert.True(newenum2.HasFlag(ExampleTypeFlag.examplecategory2)); + Assert.True(newenum2.HasFlag(ExampleTypeFlag.examplecategory3)); + Assert.Equal(2, newenum2.GetFlags().Count()); + } + + [Fact] + public void IsFlagSet_Test() + { + var @enum = ExampleTypeFlag.examplecategory1 | ExampleTypeFlag.examplecategory2; + // Functionally equivalent + Assert.Equal(@enum.HasFlag(ExampleTypeFlag.examplecategory3), @enum.IsFlagSet(ExampleTypeFlag.examplecategory3)); + } + } +} diff --git a/ContentApiCoreTests/Helper/JsonTransformerTests.cs b/ContentApiCoreTests/Helper/JsonTransformerTests.cs new file mode 100644 index 0000000..35d9f22 --- /dev/null +++ b/ContentApiCoreTests/Helper/JsonTransformerTests.cs @@ -0,0 +1,116 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace ContentApiCoreTests.Helper +{ + public class JsonTransformerTests + { + [Fact] + public void FilterByLanguageTest() + { + var actual = @"{ + ""languages"": { + ""de"": ""hallo"", + ""it"": ""ciao"", + ""en"": ""hello"" + } + }"; + var expected = @"{ + ""languages"": { + ""de"": ""hallo"" + } + }"; + var token = JToken.Parse(actual); + var transformedToken = token.FilterByLanguage("de"); + var expectedToken = JToken.Parse(expected); + Assert.Equal(expectedToken, transformedToken); + } + + [Fact] + public void FilterImagesByCC0LicenseTest() + { + var actual = @"[{ + ""License"": ""CC0"", + ""Name"": ""Image1"" + }, + { + ""License"": ""LTS"", + ""Name"": ""Image2"" + }]"; + var expected = @"[{ + ""License"": ""CC0"", + ""Name"": ""Image1"" + }]"; + var token = JToken.Parse(actual); + var transformedToken = token.FilterImagesByCC0License(); + var expectedToken = JToken.Parse(expected); + Assert.Equal(expectedToken, transformedToken); + } + + //[Theory] + //[InlineData("de", "Hallo")] + //[InlineData("en", "Hello")] + //[InlineData(null, "Hello")] + //[InlineData("it", null)] + //public void FilterByFieldsTests(string? language, string? expectedName) + //{ + // var actual = @"{ + // ""Id"": 1, + // ""IsOpen"": true, + // ""Detail"": { + // ""de"": { + // ""Title"": ""Hallo"", + // ""Body"": ""Welt"" + // }, + // ""en"": { + // ""Title"": ""Hello"", + // ""Body"": ""World"" + // } + // }, + // ""Values"": [""A"", ""B"", ""C""] + // }"; + // var expected = $@"{{ + // ""Id"": 1, + // ""Name"": {(expectedName == null ? "null" : $@"""{expectedName}""")}, + // ""IsOpen"": true, + // ""Detail.de.Title"": ""Hallo"", + // ""Detail['en']['Body']"": ""World"", + // ""Values[1]"": ""B"", + // ""FooBar"": null + // }}"; + // // Documentation for JSONPath: https://goessner.net/articles/JsonPath/ + // var fields = new string[] { + // "IsOpen", + // "Detail.de.Title", + // "Detail['en']['Body']", + // "Values[1]", + // "FooBar" + // }; + // var token = JToken.Parse(actual); + // var transformedToken = token.FilterByFields(fields, language); + // var expectedToken = JToken.Parse(expected); + // Assert.Equal(expectedToken, transformedToken); + //} + + [Fact] + public void FilterNullPropertiesTest() + { + var actual = @"{ field1: null, field2: 42, field3: { field4: null } }"; + var expected = @"{ field2: 42, field3: {} }"; + var token = JToken.Parse(actual); + var transformedToken = token.FilterOutNullProperties(); + var expectedToken = JToken.Parse(expected); + Assert.Equal(expectedToken.ToString(), transformedToken?.ToString()); + } + } +} diff --git a/ContentApiCoreTests/Helper/PostgresSQLOrderByBuilderTests.cs b/ContentApiCoreTests/Helper/PostgresSQLOrderByBuilderTests.cs new file mode 100644 index 0000000..f70d887 --- /dev/null +++ b/ContentApiCoreTests/Helper/PostgresSQLOrderByBuilderTests.cs @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Xunit; +using Helper; + +namespace ContentApiCoreTests.Helper +{ + public class PostgresSQLOrderByBuilderTests + { + [Theory] + [InlineData("100", "10")] + [InlineData("42", "42")] + [InlineData("83", "8")] + public void BuildSeedOrderBy_WithSeed(string? seed, string resultSeed) + { + string orderby = ""; + PostgresSQLOrderByBuilder.BuildSeedOrderBy(ref orderby, ref seed, ""); + Assert.Equal($"md5(id || '{resultSeed}')", orderby); + } + + [Fact] + public void BuildSeedOrderBy_WithoutSeed() + { + string orderby = ""; + string? nullseed = null; + + PostgresSQLOrderByBuilder.BuildSeedOrderBy(ref orderby, ref nullseed, "orderbyclause"); + Assert.Equal("orderbyclause", orderby); + } + + [Fact] + public void BuildSeedOrderBy_WithInvalidSeed() + { + string orderby = ""; + string? invalidseed = "invalidnumber"; + + PostgresSQLOrderByBuilder.BuildSeedOrderBy(ref orderby, ref invalidseed, "orderbyclause"); + // CHECK: Is this the correct behavior? + Assert.Equal("md5(id || '')", orderby); + } + } +} diff --git a/ContentApiCoreTests/Helper/PostgresSQLWhereBuilderTests.cs b/ContentApiCoreTests/Helper/PostgresSQLWhereBuilderTests.cs new file mode 100644 index 0000000..9bae69c --- /dev/null +++ b/ContentApiCoreTests/Helper/PostgresSQLWhereBuilderTests.cs @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper; +using SqlKata; +using SqlKata.Compilers; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace ContentApiCoreTests.Helper +{ + public class PostgresSQLWhereBuilderTests + { + private readonly static PostgresCompiler compiler = new(); + + [Fact] + public void CreateExampleWhereExpression_LoggedUser() + { + var query = + new Query() + .From("examples") + .ExampleWhereExpression( + languagelist: System.Array.Empty(), + idlist: System.Array.Empty(), + typelist: System.Array.Empty(), + activefilter: null, + sourcelist: System.Array.Empty(), + publishedonlist: System.Array.Empty(), + searchfilter: null, + language: null, + lastchange: null, + additionalfilter: null, + userroles: new List() { "STA" } + ); + + var result = compiler.Compile(query); + + Assert.Equal("SELECT * FROM \"examples\" WHERE gen_access_role @> array\\[$$\\]", result.RawSql); + } + + [Fact] + public void CreateExampleWhereExpression_Anonymous() + { + var query = + new Query() + .From("examples") + .ExampleWhereExpression( + languagelist: System.Array.Empty(), + idlist: System.Array.Empty(), + typelist: System.Array.Empty(), + activefilter: null, + sourcelist: System.Array.Empty(), + publishedonlist: System.Array.Empty(), + searchfilter: null, + language: null, + lastchange: null, + additionalfilter: null, + new List() { "ANONYMOUS" } + ); + + var result = compiler.Compile(query); + + Assert.Equal("SELECT * FROM \"examples\" WHERE gen_access_role @> array\\[$$\\]", result.RawSql); + } + + [Fact] + public void CreateExampleWhereExpression_IDMUser() + { + var query = + new Query() + .From("examples") + .ExampleWhereExpression( + languagelist: System.Array.Empty(), + idlist: System.Array.Empty(), + typelist: System.Array.Empty(), + activefilter: null, + sourcelist: System.Array.Empty(), + publishedonlist: System.Array.Empty(), + searchfilter: null, + language: null, + lastchange: null, + additionalfilter: null, + userroles: new List() { "IDM" } + ); + + var result = compiler.Compile(query); + + Assert.Equal("SELECT * FROM \"examples\" WHERE gen_access_role @> array\\[$$\\]", result.RawSql); + } + } +} diff --git a/ContentApiCoreTests/IntegrationTests/CustomWebApplicationFactory.cs b/ContentApiCoreTests/IntegrationTests/CustomWebApplicationFactory.cs new file mode 100644 index 0000000..9d34d29 --- /dev/null +++ b/ContentApiCoreTests/IntegrationTests/CustomWebApplicationFactory.cs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Linq; +using Xunit; + +namespace ContentApiCoreTests.IntegrationTests +{ + public static class Helpers + { + public static T JsonIsType(JToken token) => + token switch + { + JValue value when (value.Value == null) => default!, + JValue value => Assert.IsType(value.Value), + _ => Assert.IsType(token), + }; + } + + public class CustomWebApplicationFactory : WebApplicationFactory where TStartup : class + { + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + builder.ConfigureServices(services => + { + var sp = services + .AddRouting() + .BuildServiceProvider(); + + //using (var scope = sp.CreateScope()) + //{ + // var scopedServices = scope.ServiceProvider; + // var logger = scopedServices.GetRequiredService>>(); + //} + }); + } + } +} diff --git a/ContentApiCoreTests/IntegrationTests/ExampleApiControllerTests.cs b/ContentApiCoreTests/IntegrationTests/ExampleApiControllerTests.cs new file mode 100644 index 0000000..ad75ad6 --- /dev/null +++ b/ContentApiCoreTests/IntegrationTests/ExampleApiControllerTests.cs @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Microsoft.AspNetCore.Mvc.Testing; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; +using static ContentApiCoreTests.IntegrationTests.Helpers; + +namespace ContentApiCoreTests.IntegrationTests +{ + [Trait("Category", "Integration")] + public class ExampleApiControllerTests : IClassFixture> + { + private readonly HttpClient _client; + private readonly CustomWebApplicationFactory _factory; + + public ExampleApiControllerTests(CustomWebApplicationFactory factory) + { + _factory = factory; + _client = factory.CreateClient(new WebApplicationFactoryClientOptions + { + AllowAutoRedirect = false + }); + } + + [Theory] + [InlineData("/v1/Example")] + [InlineData("/v1/Example?pagesize=1")] + [InlineData("/v1/Example?language=de")] + [InlineData("/v1/Example?pagenumber=1&pagesize=10&seed=null")] + [InlineData("/v1/Example?pagenumber=1&pagesize=20&active=true&seed=null")] + public async Task Get_Examples(string url) + { + var response = await _client.GetAsync(url); + response.EnsureSuccessStatusCode(); + Assert.Equal("application/json; charset=utf-8", + response.Content.Headers.ContentType?.ToString()); + string json = await response.Content.ReadAsStringAsync(); + dynamic? data = JsonConvert.DeserializeObject(json); + Assert.NotNull(data); + if (data != null) + { + Assert.IsType(data); + JsonIsType(data.TotalResults); + Assert.NotEqual(0, (long)data.TotalResults); + JsonIsType(data.TotalPages); + Assert.NotEqual(0, (long)data.TotalPages); + JsonIsType(data.CurrentPage); + Assert.Equal(1, (long)data.CurrentPage); + JsonIsType(data.Seed); + Assert.Empty(data.Seed); + Assert.IsType(data.Items); + Assert.NotEmpty(data.Items); + } + } + + [Theory] + [InlineData("/v1/Example/123456789")] + [InlineData("/v1/Example/12345678910")] + public async Task Get_SinglePoi(string url) + { + var response = await _client.GetAsync(url); + response.EnsureSuccessStatusCode(); + Assert.Equal("application/json; charset=utf-8", + response.Content.Headers.ContentType?.ToString()); + string json = await response.Content.ReadAsStringAsync(); + dynamic? data = JsonConvert.DeserializeObject(json); + Assert.NotNull(data); + if (data != null) + { + Assert.IsType(data); + JsonIsType(data.Id); + JsonIsType(data.Type); + JsonIsType(data.SmgId); + JsonIsType(data.Active); + //Assert.IsType(data.AreaId); + //Assert.NotEmpty(data.AreaId); + Assert.IsType(data.Detail); + Assert.IsType(data.Detail.de); + JsonIsType(data.Detail.de.Title); + //JsonIsType(data.IsOpen); + Assert.IsType(data.GpsInfo); + //JsonIsType(data.Highlight); + Assert.IsType(data.HasLanguage); + Assert.IsType(data.ContactInfos); + Assert.IsType(data.ContactInfos.de); + JsonIsType(data.TourismorganizationId); + } + } + + [Theory] + [InlineData("/v1/Poi/0000000")] + [InlineData("/v1/Poi/0000001")] + public async Task Get_SingleNonExistentPoi(string url) + { + var response = await _client.GetAsync(url); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task Get_ExampleTypes() + { + var response = await _client.GetAsync("/v1/ExampleTypes"); + response.EnsureSuccessStatusCode(); + Assert.Equal("application/json; charset=utf-8", + response.Content.Headers.ContentType?.ToString()); + string json = await response.Content.ReadAsStringAsync(); + dynamic? data = JsonConvert.DeserializeObject(json); + Assert.NotEmpty(data); + } + } +} diff --git a/ContentApiCoreTests/IntegrationTests/FilterTests.cs b/ContentApiCoreTests/IntegrationTests/FilterTests.cs new file mode 100644 index 0000000..64d2d80 --- /dev/null +++ b/ContentApiCoreTests/IntegrationTests/FilterTests.cs @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Mvc.Testing; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using ContentApiCoreTests.IntegrationTests; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +namespace ContentApiCoreTests.IntegrationTests +{ + [Trait("Category", "Integration")] + public class FilterTests : IClassFixture> + + { + private readonly HttpClient _client; + private readonly CustomWebApplicationFactory _factory; + + public FilterTests(CustomWebApplicationFactory factory) + { + _factory = factory; + _client = factory.CreateClient(new WebApplicationFactoryClientOptions + { + AllowAutoRedirect = false + }); + } + + [Fact] + public async Task TestFields() + { + var url = "/v1/Example?pagesize=20&pagenumber=1&fields=Detail.de.Title,Features[*].Name,HgvId,Test"; + var response = await _client.GetAsync(url); + response.EnsureSuccessStatusCode(); + Assert.Equal("application/json; charset=utf-8", + response.Content.Headers.ContentType?.ToString()); + string json = await response.Content.ReadAsStringAsync(); + dynamic? data = JsonConvert.DeserializeObject(json); + Assert.NotNull(data); + if (data != null) + { + Assert.IsType(data); + Helpers.JsonIsType(data.TotalResults); + Assert.NotEqual(0, (long)data.TotalResults); + Helpers.JsonIsType(data.TotalPages); + Assert.NotEqual(0, (long)data.TotalPages); + Helpers.JsonIsType(data.CurrentPage); + Assert.Equal(1, (long)data.CurrentPage); + Helpers.JsonIsType(data.Seed); + Assert.Empty(data.Seed); + Assert.IsType(data.Items); + Assert.NotEmpty(data.Items); + + Assert.Equal(20, data.Items.Count); + + var firstItem = data.Items[0]; + Helpers.JsonIsType(firstItem.Id); + Assert.Equal("118939DAC0CD11D2AE71004095429799_REDUCED", (string)firstItem.Id); + Helpers.JsonIsType(firstItem["AccoDetail.de.Name"]); + Assert.Equal("\"Bamguat\"", (string)firstItem["AccoDetail.de.Name"]); + Helpers.JsonIsType(firstItem["Features[*].Name"]); + //Assert.Equal(ToJArray(new[] { + // "Families", + // "Seniors", + // "Hiking", + // "Bread delivery service", + // "Pick-up service", + // "Washing machine", + // "Barbeque area", + // "Garden ", + // "Playground", + // "Open car park", + // "Fruit growing farm", + // "WLAN", + // "Free Wi-Fi", + // "No pets or domestic animals", + // "Outdoor pool", + // "Partner Therme Meran", + // "Quiet location", + // "MeranCard (15.10.-30.06.)" + // }), (JArray)firstItem["Features[*].Name"]); + Helpers.JsonIsType(firstItem.HgvId); + Assert.Null((string?)firstItem.HgvId); + Helpers.JsonIsType(firstItem.Test); + Assert.Equal((object?)firstItem.Test, new JValue((object?)null)); + } + } + + private IEnumerable ToJArray(object[] objects) + { + return new JArray(objects.Select(@object => new JValue(@object))); + } + } +} diff --git a/ContentApiCoreTests/Properties/launchSettings.json b/ContentApiCoreTests/Properties/launchSettings.json new file mode 100644 index 0000000..6f2bdcc --- /dev/null +++ b/ContentApiCoreTests/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:64550/", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "OdhApiCoreTests": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:64553/" + } + } +} \ No newline at end of file diff --git a/ContentApiCoreTests/xunit.runner.json b/ContentApiCoreTests/xunit.runner.json new file mode 100644 index 0000000..1c72a42 --- /dev/null +++ b/ContentApiCoreTests/xunit.runner.json @@ -0,0 +1,3 @@ +{ + "shadowCopy": false +} diff --git a/DataModel/DataModel.csproj b/DataModel/DataModel.csproj new file mode 100644 index 0000000..cd0de85 --- /dev/null +++ b/DataModel/DataModel.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + annotations + True + CS1591 + + + + + + + + + + + diff --git a/DataModel/entities/Common.cs b/DataModel/entities/Common.cs new file mode 100644 index 0000000..5609757 --- /dev/null +++ b/DataModel/entities/Common.cs @@ -0,0 +1,573 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using Swashbuckle.AspNetCore.Annotations; +using System.Linq; +using System.ComponentModel.DataAnnotations; +using Newtonsoft.Json.Converters; +using DataModel.Annotations; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Diagnostics; +using System.ComponentModel; +using System.Net; + +namespace DataModel +{ + #region Interfaces + + //Common Interfaces (shared between all Entities) + + public interface IIdentifiable + { + string Id { get; set; } + } + + public interface IShortName + { + string? Shortname { get; set; } + } + + public interface IMetaData + { + Metadata _Meta { get; set; } + } + + public interface ILicenseInfo + { + LicenseInfo LicenseInfo { get; set; } + } + + public interface ISource + { + [SwaggerSchema("Source of the Data")] + string Source { get; set; } + } + + public interface IImportDateassigneable + { + DateTime? FirstImport { get; set; } + DateTime? LastChange { get; set; } + } + + public interface IMappingAware + { + IDictionary> Mapping { get; set; } + } + + public interface IActivateable + { + bool Active { get; set; } + } + + public interface ILanguage + { + string? Language { get; set; } + } + + public interface IHasLanguage + { + ICollection? HasLanguage { get; set; } + } + + public interface IDetailInfosAware + { + IDictionary Detail { get; set; } + } + + public interface IDetailInfos + { + string? Header { get; set; } + string? IntroText { get; set; } + string? BaseText { get; set; } + string? Title { get; set; } + + string? MetaTitle { get; set; } + string? MetaDesc { get; set; } + + string? AdditionalText { get; set; } + string? GetThereText { get; set; } + } + + public interface IContactInfos + { + string? Address { get; set; } + string? City { get; set; } + string? ZipCode { get; set; } + string? CountryCode { get; set; } + string? CountryName { get; set; } + string? Surname { get; set; } + string? Givenname { get; set; } + string? NamePrefix { get; set; } + string? Email { get; set; } + string? Phonenumber { get; set; } + string? Faxnumber { get; set; } + string? Url { get; set; } + string? Vat { get; set; } + string? Tax { get; set; } + } + + public interface IContactInfosAware + { + IDictionary ContactInfos { get; set; } + } + + public interface IImageGallery + { + string? ImageName { get; set; } + string? ImageUrl { get; set; } + int? Width { get; set; } + int? Height { get; set; } + string? ImageSource { get; set; } + + IDictionary ImageTitle { get; set; } + IDictionary ImageDesc { get; set; } + + bool? IsInGallery { get; set; } + int? ListPosition { get; set; } + DateTime? ValidFrom { get; set; } + DateTime? ValidTo { get; set; } + } + + public interface IImageGalleryAware + { + ICollection? ImageGallery { get; set; } + } + + public interface IVideoItems + { + string? Name { get; set; } + string? Url { get; set; } + string? VideoSource { get; set; } + string? VideoType { get; set; } + + string? StreamingSource { get; set; } + + string VideoTitle { get; set; } + string VideoDesc { get; set; } + + bool? Active { get; set; } + string? CopyRight { get; set; } + string? License { get; set; } + string? LicenseHolder { get; set; } + } + + public interface IVideoItemsAware + { + IDictionary>? VideoItems { get; set; } + } + + public interface IGpsInfo + { + string? Gpstype { get; set; } + double Latitude { get; set; } + double Longitude { get; set; } + double? Altitude { get; set; } + string? AltitudeUnitofMeasure { get; set; } + } + + public interface IGPSInfoAware + { + ICollection GpsInfo { get; set; } + } + + public interface IGPSPointsAware + { + IDictionary GpsPoints { get; } + } + + public interface IGpsTrack + { + string? Id { get; set; } + IDictionary GpxTrackDesc { get; set; } + string? GpxTrackUrl { get; set; } + string? Type { get; set; } + + string? Format { get; set; } + } + + public interface IGpsPolygon + { + double Latitude { get; set; } + double Longitude { get; set; } + } + + public interface IGpsPolygonAware + { + ICollection? GpsPolygon { get; set; } + } + + public interface IOperationSchedules + { + IDictionary OperationscheduleName { get; set; } + //string OperationscheduleName { get; set; } + DateTime Start { get; set; } + DateTime Stop { get; set; } + //bool? ClosedonPublicHolidays { get; set; } + + ICollection? OperationScheduleTime { get; set; } + } + + public interface IOperationScheduleTime + { + TimeSpan Start { get; set; } + TimeSpan End { get; set; } + bool Monday { get; set; } + bool Tuesday { get; set; } + bool Wednesday { get; set; } + bool Thursday { get; set; } + bool Friday { get; set; } + bool Saturday { get; set; } + bool Sunday { get; set; } + int State { get; set; } + int Timecode { get; set; } + } + + public interface ITags + { + IDictionary> Tags { get; set; } + } + + public interface IPublishedOn + { + ICollection? PublishedOn { get; set; } + } + + #endregion + + #region CommonInfos + + public class Metadata + { + public string Id { get; set; } + [SwaggerEnum(new[] { "accommodation", "accommodationroom", "event", "odhactivitypoi", "measuringpoint", "webcam", "article", "venue", "eventshort", "experiencearea", "region", "metaregion", "tourismassociation", "municipality", "district", "area", "wineaward", "skiarea", "skiregion", "odhtag", "publisher", "tag", "weatherhistory", "weather", "weatherdistrict", "weatherforecast", "weatherrealtime", "snowreport", "odhmetadata", "package", "ltsactivity", "ltspoi", "ltsgastronomy" })] + public string Type { get; set; } + public DateTime? LastUpdate { get; set; } + public string Source { get; set; } + public bool Reduced { get; set; } + + public UpdateInfo? UpdateInfo { get; set; } + } + + public class UpdateInfo + { + public string? UpdatedBy { get; set; } + + public string? UpdateSource { get; set; } + } + + public class LicenseInfo + { + [SwaggerEnum(new[] { "CC0", "CC-BY", "Closed" })] + public string? License { get; set; } + public string? LicenseHolder { get; set; } + public string? Author { get; set; } + [SwaggerSchema(Description = "readonly field", ReadOnly = true)] + public bool ClosedData { get; set; } + } + + public class Publisher : IIdentifiable, IImportDateassigneable, ILicenseInfo + { + public LicenseInfo? LicenseInfo { get; set; } + + public Publisher() + { + Name = new Dictionary(); + + //Mapping = new Dictionary>(); + } + + public string? Id { get; set; } + + public string Key { get; set; } + + public IDictionary Name { get; set; } + + public DateTime? FirstImport { get; set; } + public DateTime? LastChange { get; set; } + + public string? Url { get; set; } + + //New fields to store Information on Push + public ICollection? PushConfig { get; set; } + } + + public class PushConfig + { + public ICollection? PathParam { get; set; } + + public string? BaseUrl { get; set; } + + public string? PushApiUrl + { + get + { + return String.Format("{0}/{1}", this.BaseUrl != null ? this.BaseUrl : "", String.Join("/", this.PathParam)); + } + } + } + + public class Source : IIdentifiable, IImportDateassigneable, ILicenseInfo + { + public LicenseInfo? LicenseInfo { get; set; } + + public Source() + { + Name = new Dictionary(); + Description = new Dictionary(); + } + + public string? Id { get; set; } + + public string Key { get; set; } + + public IDictionary Name { get; set; } + public IDictionary Description { get; set; } + + public DateTime? FirstImport { get; set; } + public DateTime? LastChange { get; set; } + + public string? Url { get; set; } + + [SwaggerSchema("Interfaces that are offered by the source")] + public ICollection? Interfaces { get; set; } + + public ICollection Types { get; set; } + } + + public class Detail : IDetailInfos, ILanguage + { + public string? Header { get; set; } + //public string SiteHeader { get; set; } + public string? SubHeader { get; set; } + public string? IntroText { get; set; } + public string? BaseText { get; set; } + public string? Title { get; set; } + //OLT + //public string Alttext { get; set; } + public string? AdditionalText { get; set; } + //NEW + public string? MetaTitle { get; set; } + public string? MetaDesc { get; set; } + + public string? GetThereText { get; set; } + public string? Language { get; set; } + + public ICollection? Keywords { get; set; } + + //New LTS Fields + public string? ParkingInfo { get; set; } + public string? PublicTransportationInfo { get; set; } + public string? AuthorTip { get; set; } + public string? SafetyInfo { get; set; } + public string? EquipmentInfo { get; set; } + } + + public class GpsInfo : IGpsInfo + { + //[DefaultValue("position")] + //[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] + [SwaggerEnum(new[] { "position", "viewpoint", "startingandarrivalpoint", "startingpoint", "arrivalpoint", "carparking", "halfwaypoint", "valleystationpoint", "middlestationpoint", "mountainstationpoint" })] + public string? Gpstype { get; set; } + public double Latitude { get; set; } + public double Longitude { get; set; } + public double? Altitude { get; set; } + public string? AltitudeUnitofMeasure { get; set; } + } + + public class GpsTrack : IGpsTrack + { + public GpsTrack() + { + GpxTrackDesc = new Dictionary(); + } + + public string? Id { get; set; } + public IDictionary GpxTrackDesc { get; set; } + public string? GpxTrackUrl { get; set; } + public string? Type { get; set; } + public string? Format { get; set; } + } + + public class GpsPolygon : IGpsPolygon + { + public double Latitude { get; set; } + public double Longitude { get; set; } + } + + public class ImageGallery : IImageGallery + { + public ImageGallery() + { + ImageTitle = new Dictionary(); + ImageDesc = new Dictionary(); + ImageAltText = new Dictionary(); + } + + public string? ImageName { get; set; } + public string? ImageUrl { get; set; } + public int? Width { get; set; } + public int? Height { get; set; } + public string? ImageSource { get; set; } + + public IDictionary ImageTitle { get; set; } + public IDictionary ImageDesc { get; set; } + public IDictionary ImageAltText { get; set; } + + public bool? IsInGallery { get; set; } + public int? ListPosition { get; set; } + public DateTime? ValidFrom { get; set; } + public DateTime? ValidTo { get; set; } + + //NEU + public string? CopyRight { get; set; } + public string? License { get; set; } + public string? LicenseHolder { get; set; } + public ICollection? ImageTags { get; set; } + } + + public class VideoItems : IVideoItems + { + public string? Name { get; set; } + public string? Url { get; set; } + public string? VideoSource { get; set; } + public string? VideoType { get; set; } + public string? StreamingSource { get; set; } + public string VideoTitle { get; set; } + public string VideoDesc { get; set; } + public bool? Active { get; set; } + public string? CopyRight { get; set; } + public string? License { get; set; } + public string? LicenseHolder { get; set; } + public string? Language { get; set; } + public int? Width { get; set; } + public int? Height { get; set; } + + //NEW + public string? Definition { get; set; } + public double? Duration { get; set; } + public int? Resolution { get; set; } + public int? Bitrate { get; set; } + } + + public class ContactInfos : IContactInfos, ILanguage + { + [SwaggerSchema(Description = "Street Address")] + public string? Address { get; set; } + + [SwaggerSchema(Description = "Region (Province / State / Departement / Canton etc...")] + public string? Region { get; set; } + + [SwaggerSchema(Description = "Regioncode")] + public string? RegionCode { get; set; } + + [SwaggerSchema(Description = "Area (Additional Area Name)")] + public string? Area { get; set; } + public string? City { get; set; } + public string? ZipCode { get; set; } + public string? CountryCode { get; set; } + public string? CountryName { get; set; } + public string? Surname { get; set; } + public string? Givenname { get; set; } + public string? NamePrefix { get; set; } + public string? Email { get; set; } + public string? Phonenumber { get; set; } + public string? Faxnumber { get; set; } + public string? Url { get; set; } + public string? Language { get; set; } + public string? CompanyName { get; set; } + public string? Vat { get; set; } + public string? Tax { get; set; } + public string? LogoUrl { get; set; } + } + + [SwaggerSchema("Wiki Article on Wiki Article")] + public class OperationSchedule : IOperationSchedules + { + public OperationSchedule() + { + OperationscheduleName = new Dictionary(); + } + public IDictionary OperationscheduleName { get; set; } + public DateTime Start { get; set; } + public DateTime Stop { get; set; } + /// + /// Type: 1 - Standard, 2 - Only day + month recurring (year not to consider) 3 - only month recurring (season: year and day not to consider) + /// + [SwaggerSchema("1 - Standard, 2 - Only day + month recurring (year not to consider) 3 - only month recurring (season: year and day not to consider), Wiki Article on Wiki Article")] + public string? Type { get; set; } + + public ICollection? OperationScheduleTime { get; set; } + } + + public class OperationScheduleTime : IOperationScheduleTime + { + public TimeSpan Start { get; set; } + public TimeSpan End { get; set; } + public bool Monday { get; set; } + public bool Tuesday { get; set; } + public bool Wednesday { get; set; } + // Here for compatibility reasons + [SwaggerDeprecated("Will be removed within 2023-12-31")] + public bool Thuresday { get { return Thursday; } } + public bool Thursday { get; set; } + public bool Friday { get; set; } + public bool Saturday { get; set; } + public bool Sunday { get; set; } + /// + /// //1 = closed, 2 = open, 0 = undefined + /// + [SwaggerSchema("1 = closed, 2 = open, 0 = undefined, Wiki Article on Wiki Article")] + public int State { get; set; } + + /// + /// 1 = General Opening Time, 2 = time range for warm meals, 3 = time range for pizza, 4 = time range for snack’s + /// + [SwaggerSchema("1 = General Opening Time, 2 = time range for warm meals, 3 = time range for pizza, 4 = time range for snack’s, Wiki Article on Wiki Article")] + public int Timecode { get; set; } + } + + #endregion + + + public class PushResponse + { + public string Id { get; set; } + public string Publisher { get; set; } + public DateTime Date { get; set; } + public dynamic Result { get; set; } + + public PushObject? PushObject { get; set; } + } + + public class PushObject + { + public string Id { get; set; } + + //Add the info for the pushed object + public string Type { get; set; } + } + + public class PushResult + { + public int? Messages { get; set; } + public bool Success { get; set; } + public string? Response { get; set; } + public string? Error { get; set; } + + public static PushResult MergeMultipleFCMPushNotificationResponses(IEnumerable responses) + { + return new PushResult() + { + Messages = responses.Sum(x => x.Messages), + Error = String.Join("|", responses.Select(x => x.Error)), + Success = responses.Any(x => x.Success == true), + Response = String.Join("|", responses.Select(x => x.Response)) + }; + } + } + +} diff --git a/DataModel/entities/CommonLinked.cs b/DataModel/entities/CommonLinked.cs new file mode 100644 index 0000000..0587c75 --- /dev/null +++ b/DataModel/entities/CommonLinked.cs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel.Annotations; +using Swashbuckle.AspNetCore.Annotations; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; + +namespace DataModel +{ + /// + /// This class contains the classes used by Open Data Hub PG Instance with linked data + /// + #region Linked Sub Classes + + public class Tags + { + public string Id { get; set; } + + public string Source { get; set; } + public string? Self + { + get + { + return "Tag/" + this.Id; + } + } + } + + #endregion + + #region Linked Main Classes + + public class PublisherLinked : Publisher, IMetaData + { + public Metadata? _Meta { get; set; } + + [SwaggerSchema(Description = "generated field", ReadOnly = true)] + public string? Self + { + get + { + return this.Id != null ? "Publisher/" + Uri.EscapeDataString(this.Id) : null; + } + } + } + + public class SourceLinked : Source, IMetaData + { + public Metadata? _Meta { get; set; } + + [SwaggerSchema(Description = "generated field", ReadOnly = true)] + public string? Self + { + get + { + return this.Id != null ? "Source/" + Uri.EscapeDataString(this.Id) : null; + } + } + } + + #endregion +} diff --git a/DataModel/entities/Example.cs b/DataModel/entities/Example.cs new file mode 100644 index 0000000..3633793 --- /dev/null +++ b/DataModel/entities/Example.cs @@ -0,0 +1,97 @@ +using DataModel.Annotations; +using Swashbuckle.AspNetCore.Annotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DataModel +{ + public class Example : IIdentifiable, IImportDateassigneable, IMappingAware, IHasLanguage, ISource, IActivateable, IMetaData, IPublishedOn, IDetailInfosAware, IGPSInfoAware, IImageGalleryAware, IShortName, IContactInfosAware, ILicenseInfo, IGPSPointsAware + { + public Example() + { + //Initialize Dictionaries + Detail = new Dictionary(); + ContactInfos = new Dictionary(); + Mapping = new Dictionary>(); + AdditionalProperties = new Dictionary(); + } + + public Metadata _Meta { get; set; } + public string Id { get; set; } + public DateTime? FirstImport { get; set; } + public DateTime? LastChange { get; set; } + public string Source { get; set; } + public bool Active { get; set; } + public string? Shortname { get; set; } + public IDictionary> Mapping { get; set; } + public ICollection? HasLanguage { get; set; } + public ICollection? PublishedOn { get; set; } + public IDictionary Detail { get; set; } + public ICollection GpsInfo { get; set; } + + [SwaggerDeprecated("Deprecated, use GpsInfo")] + [SwaggerSchema(Description = "generated field", ReadOnly = true)] + public IDictionary GpsPoints + { + get + { + return this.GpsInfo.ToGpsPointsDictionary(); + } + } + + public ICollection? ImageGallery { get; set; } + public IDictionary ContactInfos { get; set; } + + public ICollection? ExampleTypeIds { get; set; } + public LicenseInfo LicenseInfo { get; set; } + + public IDictionary? AdditionalProperties { get; set; } + } + + public class ExampleType : IIdentifiable + { + public ExampleType() + { + TypeDesc = new Dictionary(); + } + + public string? Id { get; set; } + public long Bitmask { get; set; } + public string? Type { get; set; } + public string? Parent { get; set; } + public string Key { get; set; } + + public IDictionary? TypeDesc { get; set; } + } + + public class ExampleLinked : Example + { + [SwaggerSchema(Description = "generated field", ReadOnly = true)] + public string? Self + { + get + { + return this.Id != null ? "Example/" + Uri.EscapeDataString(this.Id) : null; + } + } + + [SwaggerSchema(Description = "generated field", ReadOnly = true)] + public ICollection ODHTags + { + get + { + return this.ExampleTypeIds != null ? this.ExampleTypeIds.Select(x => new ExampleTypes() { Id = x, Self = "ExampleType/" + x }).ToList() : new List(); + } + } + } + + public class ExampleTypes + { + public string Id { get; set; } + public string? Self { get; set; } + } + +} diff --git a/DataModel/generic/Annotations.cs b/DataModel/generic/Annotations.cs new file mode 100644 index 0000000..84613d8 --- /dev/null +++ b/DataModel/generic/Annotations.cs @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DataModel.Annotations +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)] + public class SwaggerDeprecatedAttribute : Attribute + { + public SwaggerDeprecatedAttribute(string? description = null, string? deprecationdate = null, string? removedafter = null) + { + Description = description; + + if(DateTime.TryParse(deprecationdate, out DateTime deprecationdatetemp)) + DeprecationDate = deprecationdatetemp; + else + DeprecationDate = null; + + if (DateTime.TryParse(removedafter, out DateTime removedaftertemp)) + RemovedAfter = removedaftertemp; + else + RemovedAfter = null; + } + + public string Description { get; } + public DateTime? DeprecationDate { get; } + public DateTime? RemovedAfter { get; } + } + + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter)] + public class SwaggerEnumAttribute : Attribute + { + public SwaggerEnumAttribute(string[] enumValues) + { + EnumValues = enumValues; + } + + public IEnumerable EnumValues { get; } + } + + [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] + public class GetOnlyJsonPropertyAttribute : Attribute + { + } +} diff --git a/DataModel/generic/ApiResult.cs b/DataModel/generic/ApiResult.cs new file mode 100644 index 0000000..5ab6b29 --- /dev/null +++ b/DataModel/generic/ApiResult.cs @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Text; + +namespace DataModel +{ + public class GenericResult + { + public string Message { get; set; } + } + + public class GenericResultExtended : GenericResult + { + public string? Id { get; set; } + } + + public class UnauthorizedResult + { + public string Message { get; set; } + } +} diff --git a/DataModel/generic/FCMModels.cs b/DataModel/generic/FCMModels.cs new file mode 100644 index 0000000..e74154f --- /dev/null +++ b/DataModel/generic/FCMModels.cs @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DataModel +{ + public class FCMModels + { + public string to { get; set; } + public FCMNotification notification { get; set; } + public dynamic data { get; set; } + } + + public class FCMNotification + { + public string? title { get; set; } + public string? body { get; set; } + //public string? sound { get; set; } + //public string? link { get; set; } + //public string? icon { get; set; } + } + + public class FCMessageV2 + { + public FCMessageBodyV2 message { get; set; } + } + + public class FCMessageBodyV2 + { + public string topic { get; set; } + public FCMNotification notification { get; set; } + public dynamic data { get; set; } + } +} diff --git a/DataModel/generic/GenericResults.cs b/DataModel/generic/GenericResults.cs new file mode 100644 index 0000000..2b6a330 --- /dev/null +++ b/DataModel/generic/GenericResults.cs @@ -0,0 +1,422 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace DataModel +{ + public struct UpdateResult + { + public string operation { get; init; } + public string updatetype { get; init; } + public string otherinfo { get; init; } + public string message { get; init; } + public bool success { get; init; } + public int? recordsmodified { get; init; } + + public int? updated { get; init; } + public int? created { get; init; } + public int? deleted { get; init; } + + public int? objectcompared { get; init; } + public int? objectchanged { get; init; } + public int? objectimagechanged { get; init; } + + public dynamic? objectchanges { get; init; } + public string? objectchangestring { get; init; } + + //Push Infos + public ICollection? pushchannels { get; init; } + + public IDictionary? pushed { get; init; } + + public int? error { get; init; } + + public string id { get; init; } + + public string exception { get; init; } + + public string stacktrace { get; init; } + + public string source { get; init; } + } + + public struct UpdateDetail + { + //Crud + public int? updated { get; init; } + public int? created { get; init; } + public int? deleted { get; init; } + + //Error + public int? error { get; init; } + + //Comparision + public int? comparedobjects { get; init; } + public int? objectchanged { get; init; } + public int? objectimagechanged { get; init; } + + public JToken? changes { get; init; } + + //Push Infos + public ICollection? pushchannels { get; init; } + + public IDictionary? pushed { get; set; } + } + + + //TO CHECK if this could be unified + + public struct UpdateResultFailureQueue + { + public string operation { get; init; } + public string updatetype { get; init; } + public string otherinfo { get; init; } + public string message { get; init; } + public bool success { get; init; } + public int? recordsmodified { get; init; } + + //Push Infos + public ICollection? pushchannels { get; init; } + + public IDictionary>? pushed { get; init; } + + public int? error { get; init; } + + public string id { get; init; } + + public string exception { get; init; } + + public string stacktrace { get; init; } + + public string source { get; init; } + } + + + public struct UpdateDetailFailureQueue + { + //Error + public int? error { get; init; } + + //Push Infos + public ICollection? pushchannels { get; init; } + + public IDictionary>? pushed { get; set; } + } + + + public struct PGCRUDResult + { + public string id { get; init; } + + public string? odhtype { get; init; } + public string operation { get; init; } + public int? updated { get; init; } + public int? created { get; init; } + public int? deleted { get; init; } + + public int? error { get; init; } + + public string? errorreason { get; init; } + + public bool? compareobject { get; init; } + public int? objectchanged { get; init; } + public int? objectimagechanged { get; init; } + + public ICollection? pushchannels { get; init; } + + public JToken? changes { get; init; } + + public IDictionary? pushed { get; set; } + } + + public struct JsonGenerationResult + { + public string operation { get; init; } + public string type { get; init; } + public string message { get; init; } + public bool success { get; init; } + public string exception { get; init; } + } + + public class GenericResultsHelper + { + public static UpdateDetail MergeUpdateDetail(IEnumerable updatedetails) + { + int? updated = 0; + int? created = 0; + int? deleted = 0; + int? error = 0; + int? objectscompared = 0; + int? objectchanged = 0; + int? objectimagechanged = 0; + List? channelstopush = new List(); + + JToken? changes = null; + + IDictionary pushed = new Dictionary(); + + foreach (var updatedetail in updatedetails) + { + objectscompared = updatedetail.comparedobjects + objectscompared; + + created = updatedetail.created + created; + updated = updatedetail.updated + updated; + deleted = updatedetail.deleted + deleted; + error = updatedetail.error + error; + if(updatedetail.objectchanged != null) + objectchanged = updatedetail.objectchanged + objectchanged; + if (updatedetail.objectimagechanged != null) + objectimagechanged = updatedetail.objectimagechanged + objectimagechanged; + + if (updatedetail.changes != null) + { + if (changes == null) + changes = updatedetail.changes; + else + changes.Append(updatedetail.changes); + } + + + if (updatedetail.pushchannels != null) + { + foreach (var pushchannel in updatedetail.pushchannels) + { + if (!channelstopush.Contains(pushchannel)) + channelstopush.Add(pushchannel); + } + } + + if (updatedetail.pushed != null) + { + foreach (var updatedetailpushed in updatedetail.pushed) + pushed.TryAdd(updatedetailpushed.Key, updatedetailpushed.Value); + } + } + + return new UpdateDetail() { created = created, updated = updated, deleted = deleted, error = error, comparedobjects = objectscompared, objectchanged = objectchanged, objectimagechanged = objectimagechanged, pushchannels = channelstopush, pushed = pushed, changes = changes }; + } + + public static UpdateResult GetSuccessUpdateResult(string id, string source, string operation, string updatetype, string message, string otherinfo, UpdateDetail detail, bool createlog) + { + var result = new UpdateResult() + { + id = id, + source = source, + operation = operation, + updatetype = updatetype, + otherinfo = otherinfo, + message = message, + recordsmodified = (detail.created + detail.updated + detail.deleted), + created = detail.created, + updated = detail.updated, + deleted = detail.deleted, + objectcompared = detail.comparedobjects, + objectchanged = detail.objectchanged, + objectimagechanged = detail.objectimagechanged, + //objectchanges = detail.changes != null ? JsonConvert.DeserializeObject(detail.changes.ToString(Formatting.None)) : null, + objectchanges = null, + objectchangestring = detail.changes != null ? detail.changes.ToString(Formatting.None) : null, + pushchannels = detail.pushchannels, + pushed = detail.pushed, + error = detail.error, + success = true, + exception = null, + stacktrace = null + }; + + if (createlog) + Console.WriteLine(JsonConvert.SerializeObject(result)); + + return result; + } + + public static UpdateResult GetErrorUpdateResult(string id, string source, string operation, string updatetype, string message, string otherinfo, UpdateDetail detail, Exception ex, bool createlog) + { + var result = new UpdateResult() + { + id = id, + source = source, + operation = operation, + updatetype = updatetype, + otherinfo = otherinfo, + message = message, + recordsmodified = (detail.created + detail.updated + detail.deleted), + created = detail.created, + updated = detail.updated, + deleted = detail.deleted, + objectcompared = detail.comparedobjects, + objectchanged = detail.objectchanged, + objectimagechanged = detail.objectimagechanged, + objectchanges = null, + objectchangestring = null, + pushchannels = detail.pushchannels, + pushed = detail.pushed, + error = detail.error, + success = false, + exception = ex.Message, + stacktrace = ex.StackTrace + }; + + if (createlog) + Console.WriteLine(JsonConvert.SerializeObject(result)); + + return result; + } + + + public static UpdateResultFailureQueue GetSuccessUpdateResult(string id, string source, string operation, string updatetype, string message, string otherinfo, UpdateDetailFailureQueue detail, bool createlog) + { + var result = new UpdateResultFailureQueue() + { + id = id, + source = source, + operation = operation, + updatetype = updatetype, + otherinfo = otherinfo, + message = message, + recordsmodified = 0, + pushchannels = detail.pushchannels, + pushed = detail.pushed, + error = detail.error, + success = true, + exception = null, + stacktrace = null + }; + + if (createlog) + Console.WriteLine(JsonConvert.SerializeObject(result)); + + return result; + } + + public static UpdateResultFailureQueue GetErrorUpdateResult(string id, string source, string operation, string updatetype, string message, string otherinfo, UpdateDetailFailureQueue detail, Exception ex, bool createlog) + { + var result = new UpdateResultFailureQueue() + { + id = id, + source = source, + operation = operation, + updatetype = updatetype, + otherinfo = otherinfo, + message = message, + recordsmodified = 0, + pushchannels = detail.pushchannels, + pushed = detail.pushed, + error = detail.error, + success = false, + exception = ex.Message, + stacktrace = ex.StackTrace + }; + + if (createlog) + Console.WriteLine(JsonConvert.SerializeObject(result)); + + return result; + } + + + public static JsonGenerationResult GetSuccessJsonGenerateResult(string operation, string type, string message, bool createlog) + { + var result = new JsonGenerationResult() + { + operation = operation, + type = type, + message = message, + success = true, + exception = null + }; + + if (createlog) + Console.WriteLine(JsonConvert.SerializeObject(result)); + + return result; + } + + public static JsonGenerationResult GetErrorJsonGenerateResult(string operation, string type, string message, Exception ex, bool createlog) + { + var result = new JsonGenerationResult() + { + operation = operation, + type = type, + message = message, + success = true, + exception = ex.Message + }; + + if (createlog) + Console.WriteLine(JsonConvert.SerializeObject(result)); + + return result; + } + + } + + #region Pushnotifications + + public class NotifyLog + { + public string message { get; set; } + public string id { get; set; } + public string origin { get; set; } + public string destination { get; set; } + public bool? imageupdate { get; set; } + public bool? roomsupdate { get; set; } + public string updatemode { get; set; } + + public string? response { get; set; } + + public string? exception { get; set; } + + public bool? success { get; set; } + } + + public class NotifierFailureQueue + { + public string Id { get; set; } + public bool? HasImageChanged { get; set; } + public bool? Roomschanged { get; set; } + public bool? IsDeleteOperation { get; set; } + public string ItemId { get; set; } + public string Type { get; set; } + public string NotifyType { get; set; } + public string Exception { get; set; } + public string Status { get; set; } + public string PushUrl { get; set; } + public string Service { get; set; } + public DateTime LastChange { get; set; } + public Nullable RetryCount { get; set; } + } + + public class NotifierResponse + { + public object? Response { get; set; } + public HttpStatusCode HttpStatusCode { get; set; } + public string Service { get; set; } + public bool Success { get; set; } + } + + public class IdmMarketPlacePushResponse + { + public string notificationId { get; set; } + } + + public class EqualityResult + { + public bool isequal { get; set; } + //public IList? operations {get;set;} + public JToken? patch { get; set; } + } + + #endregion +} diff --git a/DataModel/generic/GeoModels.cs b/DataModel/generic/GeoModels.cs new file mode 100644 index 0000000..4ab722b --- /dev/null +++ b/DataModel/generic/GeoModels.cs @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DataModel +{ + public class GeoShapes + { + public int id { get; set; } + public string country { get; set; } + public int? code_rip { get; set; } + public int? code_reg { get; set; } + public int? code_prov { get; set; } + public int? code_cm { get; set; } + public int? code_uts { get; set; } + public string? istatnumber { get; set; } + public string? abbrev { get; set; } + public string? type_uts { get; set; } + public string? name { get; set; } + public string? name_alternative { get; set; } + + public float shape_leng { get; set; } + public float shape_area { get; set; } + + public string geom { get; set; } + } +} diff --git a/DataModel/generic/JsonBData.cs b/DataModel/generic/JsonBData.cs new file mode 100644 index 0000000..82a382c --- /dev/null +++ b/DataModel/generic/JsonBData.cs @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Text; + +namespace DataModel +{ + public class JsonBData + { + public string? id { get; set; } + public JsonRaw? data { get; set; } + } + + public class JsonBDataDestinationData + { + public string? id { get; set; } + public JsonRaw? data { get; set; } + public JsonRaw? destinationdata { get; set; } + } + + public class JsonBDataRaw + { + public string id { get; set; } + public JsonRaw data { get; set; } + public Int32 rawdataid { get; set; } + } + + public interface IRawDataStore + { + string type { get; set; } + string datasource { get; set; } + string sourceinterface { get; set; } + string sourceid { get; set; } + string sourceurl { get; set; } + DateTime importdate { get; set; } + string license { get; set; } + string rawformat { get; set; } + } + + public class RawDataStore : IRawDataStore + { + public string type { get; set; } + public string datasource { get; set; } + public string sourceinterface { get; set; } + public string sourceid { get; set; } + public string sourceurl { get; set; } + public DateTime importdate { get; set; } + + public string license { get; set; } + public string rawformat { get; set; } + + public string raw { get; set; } + } + + public class RawDataStoreWithId : RawDataStore + { + public int? id { get; set; } + } + + public class RawDataStoreJson : RawDataStoreWithId + { + public RawDataStoreJson(RawDataStoreWithId rawdatastore) + { + this.id = rawdatastore.id; + this.importdate = rawdatastore.importdate; + this.datasource = rawdatastore.datasource; + this.rawformat = rawdatastore.rawformat; + this.sourceid = rawdatastore.sourceid; + this.sourceinterface = rawdatastore.sourceinterface; + this.sourceurl = rawdatastore.sourceurl; + this.type = rawdatastore.type; + this.license = rawdatastore.license; + + this.raw = new JsonRaw(rawdatastore.raw); + } + + public new JsonRaw raw { get; set; } + } + + public static class RawDataStoreExtensions + { + public static IRawDataStore UseJsonRaw(this RawDataStoreWithId rawdatastore) + { + if(rawdatastore.rawformat == "json") + { + return new RawDataStoreJson(rawdatastore); + } + else + return rawdatastore; + } + } +} + diff --git a/DataModel/generic/JsonRaw.cs b/DataModel/generic/JsonRaw.cs new file mode 100644 index 0000000..fe0ee06 --- /dev/null +++ b/DataModel/generic/JsonRaw.cs @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Newtonsoft.Json; +using Npgsql; +using NpgsqlTypes; +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Linq; +using System.Text; +using static Dapper.SqlMapper; + +namespace DataModel +{ + public class JsonRawConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, JsonRaw? value, JsonSerializer serializer) + { + if (value != null) + writer.WriteRawValue(value.Value); + } + + public override JsonRaw ReadJson(JsonReader reader, Type objectType, JsonRaw? existingValue, bool hasExistingValue, JsonSerializer serializer) + { + string json = reader.ReadAsString(); + return new JsonRaw(json); + } + } + + [JsonConverter(typeof(JsonRawConverter))] + public class JsonRaw : ICustomQueryParameter + { + public JsonRaw(string data) + { + Value = data; + } + + public JsonRaw(object data) + { + Value = JsonConvert.SerializeObject(data); + } + + public string Value { get; } + + public void AddParameter(IDbCommand command, string name) + { + var parameter = new NpgsqlParameter(name, NpgsqlDbType.Json); + parameter.Value = Value; + command.Parameters.Add(parameter); + } + + public override string? ToString() + { + throw new InvalidOperationException("ToString on JsonRaw shouldn't be called, there is somewhere an implicit ToString() happening (maybe from a manual JSON serialization)."); + } + + public static explicit operator JsonRaw(string x) => new JsonRaw(x); + } + + public class JsonRawUtils + { + public static IEnumerable ConvertObjectToJsonRaw(IEnumerable obj) + { + return obj.Select(x => new JsonRaw(x)).ToList(); + } + } +} diff --git a/DataModel/generic/JsonResult.cs b/DataModel/generic/JsonResult.cs new file mode 100644 index 0000000..1cdbe0c --- /dev/null +++ b/DataModel/generic/JsonResult.cs @@ -0,0 +1,101 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Text.Json.Serialization; + +namespace DataModel +{ + /// + /// Marker interface + /// + public interface IResponse + { + public IEnumerable Items { get; } + } + + public class JsonResult : IResponse + { + public uint TotalResults { get; set; } + public uint TotalPages { get; set; } + public uint CurrentPage { get; set; } + public string? PreviousPage { get; set; } + public string? NextPage { get; set; } + public string? Seed { get; set; } + public IEnumerable Items { get; set; } = Enumerable.Empty(); + } + + public class JsonResultWithOnlineResults : JsonResult + { + public int OnlineResults { get; set; } + } + + public class JsonResultWithOnlineResultsAndResultId : JsonResultWithOnlineResults + { + public string? ResultId { get; set; } + } + + public class JsonResultWithBookingInfo : JsonResultWithOnlineResultsAndResultId + { + public int AvailableOnline { get; set; } + public int AvailableOnRequest { get; set; } + public int AccommodationsRequested { get; set; } + } + + public class JsonResultWithOnlineResultsAndResultIdLowercase : IResponse + { + public uint totalResults { get; set; } + public uint totalPages { get; set; } + public uint currentPage { get; set; } + public string? previousPage { get; set; } + public string? nextPage { get; set; } + public string? seed { get; set; } + public int onlineResults { get; set; } + public string? resultId { get; set; } + public IEnumerable items { get; set; } = Enumerable.Empty(); + [JsonIgnore] + public IEnumerable Items => items; + } + + public class SearchResult : IResponse + { + public uint totalResults { get; set; } + public string? searchTerm { get; set; } + public Dictionary detailedResults { get; set; } = new Dictionary(); + public IEnumerable Items { get; set; } = Enumerable.Empty(); + } + + #region Resultset + + //Generic Result für Paging + public class Result + { + public int TotalResults { get; set; } + public int TotalPages { get; set; } + public int CurrentPage { get; set; } + public Nullable OnlineResults { get; set; } + public string? ResultId { get; set; } + public string? Seed { get; set; } + + public ICollection? Items { get; set; } + } + + public class ResultAsync + { + public int TotalResults { get; set; } + public int TotalPages { get; set; } + public int CurrentPage { get; set; } + public Nullable OnlineResults { get; set; } + + public string? Seed { get; set; } + + public IList? Items { get; set; } + } + + #endregion +} diff --git a/DataModel/generic/PushServerModels.cs b/DataModel/generic/PushServerModels.cs new file mode 100644 index 0000000..f1804c5 --- /dev/null +++ b/DataModel/generic/PushServerModels.cs @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System.Collections.Generic; + +namespace DataModel +{ + public class PushServerMessage + { + public PushServerMessage() + { + + } + + public string? title { get; set; } + public string? text { get; set; } + public string? image { get; set; } + public string video { get; set; } + public PushServerDestination destination { get; set; } + } + + public class PushServerDestination + { + public string group { get; set; } + public string language { get; set; } + } + + public class PushServerCustomMessage + { + public PushServerCustomMessage() + { + destination = new Dictionary>(); + } + + public string title { get; set; } + public string text { get; set; } + + public PushServerCustom custom { get; set; } + //public Dictionary image { get; set; } + //public Dictionary video { get; set; } + public Dictionary> destination { get; set; } + } + + public class PushServerCustom + { + public string group { get; set; } + public string listId { get; set; } + public string listName { get; set; } + public string listOwner { get; set; } + } +} \ No newline at end of file diff --git a/DataModel/helper/GpsConverter.cs b/DataModel/helper/GpsConverter.cs new file mode 100644 index 0000000..7dd1ab9 --- /dev/null +++ b/DataModel/helper/GpsConverter.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DataModel +{ + public static class GpsConverter + { + public static IDictionary ToGpsPointsDictionary(this ICollection? gpsinfos, bool ltsactivitypoi = false) + { + //ODHActivityPoi should already pass + if (!ltsactivitypoi) + { + if (gpsinfos != null && gpsinfos.Count > 0) + { + //If GPSInfo has GpsType = null or Empty ---> + if (gpsinfos.Any(x => String.IsNullOrEmpty(x.Gpstype))) + { + foreach (var gpsinfo in gpsinfos.Where(x => String.IsNullOrEmpty(x.Gpstype))) + { + gpsinfo.Gpstype = "position"; + } + } + + //If GPSInfo has more GpsType = position ---> Grouped count is inferior to totalcount GpsPoints returns only first element..... + if (gpsinfos.GroupBy(x => x.Gpstype).Count() < gpsinfos.Count) + { + + return gpsinfos + .DistinctBy(x => x.Gpstype) + .Where(x => x.Gpstype != null) + .ToDictionary(x => x.Gpstype!, x => x); + } + else + { + return gpsinfos + .DistinctBy(x => x.Gpstype) + .Where(x => x.Gpstype != null) + .ToDictionary(x => x.Gpstype!, x => x); + } + } + else + return new Dictionary(); + } + //For LTS POI & LTS Activity + else + { + var gpspoints = new Dictionary(); + var positioncount = 0; + + if (gpsinfos != null) + { + foreach (var gpsinfo in gpsinfos) + { + string postionstr = "position"; + + if (positioncount > 0) + postionstr = postionstr + positioncount; + + if (gpsinfo.Gpstype == "Endpunkt" || gpsinfo.Gpstype == "Bergstation") + gpspoints.Add("endposition", gpsinfo); + + if (gpsinfo.Gpstype == "position" || gpsinfo.Gpstype == "Standpunkt" || gpsinfo.Gpstype == "Startpunkt" || gpsinfo.Gpstype == "Start und Ziel" || gpsinfo.Gpstype == "Talstation") + gpspoints.Add(postionstr, gpsinfo); + + positioncount = gpspoints.Where(x => x.Key.StartsWith("position")).Count(); + } + } + + return gpspoints; + } + } + + public static ICollection ConvertGpsInfoOnRootToGpsInfoArray(this IGpsInfo gpsinfo) + { + if (gpsinfo.Latitude != 0 && gpsinfo.Longitude != 0) + { + return new List + { + new GpsInfo(){ Gpstype = "position", Altitude = gpsinfo.Altitude, AltitudeUnitofMeasure = gpsinfo.AltitudeUnitofMeasure, Latitude = gpsinfo.Latitude, Longitude = gpsinfo.Longitude } + }; + } + else + { + return null; + } + } + } +} diff --git a/GeoConverter/GeoConverter.csproj b/GeoConverter/GeoConverter.csproj new file mode 100644 index 0000000..8e6f49f --- /dev/null +++ b/GeoConverter/GeoConverter.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/GeoConverter/GeoJsonConverter.cs b/GeoConverter/GeoJsonConverter.cs new file mode 100644 index 0000000..fc2a4ac --- /dev/null +++ b/GeoConverter/GeoJsonConverter.cs @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace GeoConverter; + +using System.Globalization; +using System.Text.RegularExpressions; +using System.Xml.Linq; +using Geo; +using Geo.Abstractions.Interfaces; +using Geo.Geometries; +using Geo.Gps.Serialization; +using Geo.IO.GeoJson; + +public static class GeoJsonConverter +{ + private static readonly CultureInfo _culture = CultureInfo.InvariantCulture; + + private static string? ExtractCoordinates(string xml) + { + var doc = XDocument.Parse(xml); + var multiGeo = doc + ?.Element("kml") + ?.Element("Document") + ?.Element("Folder") + ?.Element("Placemark") + ?.Element("MultiGeometry"); + return multiGeo + ?.Element("LineString") + ?.Element("coordinates") + ?.Value; + } + + private static IGeometry ParseGeo(string geo) + { + var res = Regex.Matches(geo, @"(?\d+\.\d+),(?\d+\.\d+)") + .Select(m => (m.Groups["lat"].Value, m.Groups["long"].Value)) + .Select(x => (double.Parse(x.Item2, _culture), double.Parse(x.Item1, _culture))) + .Select(x => new Coordinate(x.Item1, x.Item2)); + return new LineString(res); + } + + private static string ConvertToGeoJson(IGeometry geometry) + { + var writer = new GeoJsonWriter(); + return writer.Write(geometry); + } + + public static string ConvertFromKml(string kml) + { + var coordinates = ExtractCoordinates(kml); + if (coordinates == null) + { + throw new Exception("Could not parse KML file."); + } + var geo = ParseGeo(coordinates); + return ConvertToGeoJson(geo); + } + + public static string ConvertFromGpx(string gpx) + { + var bytes = System.Text.Encoding.UTF8.GetBytes(gpx); + var stream = new MemoryStream(bytes); + var serializer = new Gpx11Serializer(); + var serialized = serializer.DeSerialize(new StreamWrapper(stream)); + var geometry = + serialized.Waypoints.Any() ? + serialized.Waypoints : + serialized.Tracks.SelectMany(x => x.Segments).SelectMany(x => x.Waypoints); + var coordinates = geometry.Select(x => x.Coordinate); + var writer = new GeoJsonWriter(); + return ConvertToGeoJson(new LineString(coordinates)); + } +} diff --git a/GeoConverterTests/Files/216051.json b/GeoConverterTests/Files/216051.json new file mode 100644 index 0000000..7dd7afa --- /dev/null +++ b/GeoConverterTests/Files/216051.json @@ -0,0 +1 @@ +{"type":"LineString","coordinates":[[11.7774357026,46.49160455494],[11.77744237341,46.49159808646],[11.77750760584,46.49154247356],[11.77757962637,46.4914910103],[11.77765788436,46.49144409166],[11.77774177913,46.49140207693],[11.77783067032,46.49136528767],[11.7779238764,46.49133400503],[11.77802068507,46.49130846862],[11.77812035437,46.49128887286],[11.77822212323,46.49127536946],[11.77832520983,46.4912680611],[11.77842882738,46.49126700382],[11.77849288372,46.49126839863],[11.77853218272,46.4912722052],[11.77856795978,46.49128051913],[11.77864724541,46.49130627681],[11.77870624025,46.49132073131],[11.77876523513,46.49133518577],[11.77885138157,46.4913522975],[11.77894685105,46.49136793686],[11.77904316652,46.49138089603],[11.77913185297,46.49138985469],[11.77919422714,46.49139349863],[11.77925660001,46.49139714257],[11.77931918486,46.49139801739],[11.77938176846,46.49139889311],[11.77946279722,46.49139932652],[11.77950684063,46.49139509998],[11.77953688724,46.49138721687],[11.77960556386,46.49136252708],[11.7796566961,46.49134909827],[11.77970782827,46.49133566853],[11.77976038517,46.49132518676],[11.77981294209,46.49131470587],[11.77986656895,46.49130724276],[11.77992019584,46.49129978052],[11.77997452912,46.49129538722],[11.78002886238,46.49129099389],[11.78008353348,46.49128969916],[11.78013820587,46.49128840437],[11.78019284782,46.49129021803],[11.78024748848,46.49129203169],[11.78030172924,46.4912969403],[11.78035597005,46.49130184977],[11.78040944311,46.49130982084],[11.78046291618,46.49131779188],[11.78051525913,46.49132877123],[11.78056760345,46.49133975142],[11.78061846329,46.49135366483],[11.78066932316,46.49136757823],[11.78073140476,46.49138666454],[11.78076738689,46.49140108566],[11.78079756579,46.49141805191],[11.78083952269,46.49144685562],[11.7809048292,46.49149727915],[11.78096268231,46.49155187285],[11.78101252499,46.49161011388],[11.78105388039,46.49167144235],[11.78108635101,46.49173527032],[11.7811096255,46.49180098707],[11.78112348129,46.49186795993],[11.78112778536,46.49193554862],[11.78112249671,46.49200310342],[11.78110766436,46.49206997695],[11.78108343278,46.49213552757],[11.78104751478,46.49235567232]]} \ No newline at end of file diff --git a/GeoConverterTests/Files/216051.kml b/GeoConverterTests/Files/216051.kml new file mode 100644 index 0000000..7795139 --- /dev/null +++ b/GeoConverterTests/Files/216051.kml @@ -0,0 +1,16 @@ + + + + + + +216051 + + + 3-Tre Var. Turistica + 216051 + + 11.7774357026,46.49160455494 11.77744237341,46.49159808646 11.77750760584,46.49154247356 11.77757962637,46.4914910103 11.77765788436,46.49144409166 11.77774177913,46.49140207693 11.77783067032,46.49136528767 11.7779238764,46.49133400503 11.77802068507,46.49130846862 11.77812035437,46.49128887286 11.77822212323,46.49127536946 11.77832520983,46.4912680611 11.77842882738,46.49126700382 11.77849288372,46.49126839863 11.77853218272,46.4912722052 11.77856795978,46.49128051913 11.77864724541,46.49130627681 11.77870624025,46.49132073131 11.77876523513,46.49133518577 11.77885138157,46.4913522975 11.77894685105,46.49136793686 11.77904316652,46.49138089603 11.77913185297,46.49138985469 11.77919422714,46.49139349863 11.77925660001,46.49139714257 11.77931918486,46.49139801739 11.77938176846,46.49139889311 11.77946279722,46.49139932652 11.77950684063,46.49139509998 11.77953688724,46.49138721687 11.77960556386,46.49136252708 11.7796566961,46.49134909827 11.77970782827,46.49133566853 11.77976038517,46.49132518676 11.77981294209,46.49131470587 11.77986656895,46.49130724276 11.77992019584,46.49129978052 11.77997452912,46.49129538722 11.78002886238,46.49129099389 11.78008353348,46.49128969916 11.78013820587,46.49128840437 11.78019284782,46.49129021803 11.78024748848,46.49129203169 11.78030172924,46.4912969403 11.78035597005,46.49130184977 11.78040944311,46.49130982084 11.78046291618,46.49131779188 11.78051525913,46.49132877123 11.78056760345,46.49133975142 11.78061846329,46.49135366483 11.78066932316,46.49136757823 11.78073140476,46.49138666454 11.78076738689,46.49140108566 11.78079756579,46.49141805191 11.78083952269,46.49144685562 11.7809048292,46.49149727915 11.78096268231,46.49155187285 11.78101252499,46.49161011388 11.78105388039,46.49167144235 11.78108635101,46.49173527032 11.7811096255,46.49180098707 11.78112348129,46.49186795993 11.78112778536,46.49193554862 11.78112249671,46.49200310342 11.78110766436,46.49206997695 11.78108343278,46.49213552757 11.78104751478,46.49235567232 + + + diff --git a/GeoConverterTests/Files/216052.json b/GeoConverterTests/Files/216052.json new file mode 100644 index 0000000..f9d6c4d --- /dev/null +++ b/GeoConverterTests/Files/216052.json @@ -0,0 +1 @@ +{"type":"LineString","coordinates":[[11.75153885558,46.49703635675],[11.75174451841,46.49698132919],[11.75119391865,46.49709995753],[11.7511695832,46.49710130233],[11.75114524775,46.49710264711],[11.75112091229,46.4971039919],[11.75109657684,46.49710533667],[11.75107254979,46.4971083236],[11.75104852273,46.49711131053],[11.75102449568,46.49711429744],[11.75100046862,46.49711728436],[11.75097698174,46.49712188461],[11.75095349486,46.49712648485],[11.75093000798,46.49713108509],[11.75090652109,46.49713568533],[11.75088380096,46.49714185452],[11.75086108082,46.49714802371],[11.75083836067,46.4971541929],[11.75081564052,46.49716036208],[11.7507939063,46.49716804071],[11.75077217206,46.49717571934],[11.75075043783,46.49718339796],[11.75072870358,46.49719107658],[11.75070816493,46.49720019058],[11.75068762627,46.49720930457],[11.7506670876,46.49721841856],[11.75064654892,46.49722753254],[11.75062740397,46.49723799398],[11.750608259,46.49724845542],[11.75058911403,46.49725891685],[11.75056996905,46.49726937828],[11.75055240247,46.49728108625],[11.75053483589,46.49729279422],[11.7505172693,46.49730450219],[11.75049970271,46.49731621015],[11.75048388398,46.49732905171],[11.75046806524,46.49734189327],[11.75045224649,46.49735473482],[11.75043642774,46.49736757638],[11.75042250945,46.49738142765],[11.75040859116,46.49739527892],[11.75039467285,46.49740913019],[11.75038075455,46.49742298146],[11.75036887097,46.49743770882],[11.75035698739,46.49745243619],[11.75034510381,46.49746716355],[11.75033322021,46.49748189092],[11.750323486,46.49749735231],[11.75031375177,46.4975128137],[11.75030401755,46.49752827509],[11.75029428331,46.49754373649],[11.75028679236,46.49755978276],[11.75027930141,46.49757582902],[11.75027181045,46.49759187529],[11.75026431948,46.49760792156],[11.75026571198,46.4976203452],[11.75026710447,46.49763276884],[11.75026849697,46.49764519248],[11.75026988946,46.49765761612],[11.75027128196,46.49767003976],[11.75027267446,46.4976824634],[11.75027239232,46.49769492267],[11.75027211018,46.49770738195],[11.75027182805,46.49771984123],[11.75027154591,46.4977323005],[11.75027126378,46.49774475978],[11.75027098164,46.49775721906],[11.7502690273,46.49776960655],[11.75026707296,46.49778199405],[11.75026511862,46.49779438155],[11.75026316428,46.49780676904],[11.75026120994,46.49781915654],[11.7502592556,46.49783154403],[11.7502556459,46.49784375294],[11.7502520362,46.49785596186],[11.75024842649,46.49786817077],[11.75024481679,46.49788037968],[11.75024120708,46.4978925886],[11.75023759738,46.49790479751],[11.75023236343,46.49791672258],[11.75022712948,46.49792864764],[11.75022189553,46.49794057271],[11.75021666158,46.49795249778],[11.75021142763,46.49796442285],[11.75020619367,46.49797634792],[11.7501993806,46.49798788633],[11.75019256753,46.49799942473],[11.75018575445,46.49801096314],[11.75017894137,46.49802250155],[11.75017212829,46.49803403996],[11.75016531521,46.49804557837],[11.75015698174,46.49805663063],[11.75014864828,46.4980676829],[11.75014031481,46.49807873517],[11.75013198134,46.49808978744],[11.75012364786,46.4981008397],[11.75011531438,46.49811189197],[11.75010553237,46.49812236281],[11.75009575036,46.49813283364],[11.75008596834,46.49814330448],[11.75007618632,46.49815377531],[11.75006640429,46.49816424614],[11.75005662226,46.49817471698],[11.75004547604,46.49818451611],[11.75003432981,46.49819431523],[11.75002318358,46.49820411436],[11.75001203735,46.49821391348],[11.75000089111,46.4982237126],[11.74998974486,46.49823351173],[11.74997733052,46.49824255466],[11.74996491618,46.49825159759],[11.74995250183,46.49826064052],[11.74994008748,46.49826968344],[11.74992767312,46.49827872637],[11.74991525876,46.49828776929],[11.74990168333,46.49829597806],[11.7498881079,46.49830418683],[11.74987453247,46.49831239559],[11.74986095703,46.49832060435],[11.74984738159,46.49832881312],[11.74983380614,46.49833702188],[11.74981918667,46.4983443257],[11.7498045672,46.49835162953],[11.74978994772,46.49835893335],[11.74977532824,46.49836623718],[11.74976070876,46.498373541],[11.74974608927,46.49838084482],[11.74972879578,46.49838767898],[11.74971150228,46.49839451315],[11.74969420878,46.49840134731],[11.74967691527,46.49840818147],[11.74965962176,46.49841501562],[11.74964232824,46.49842184977],[11.74962587723,46.49842961274],[11.74960942622,46.49843737571],[11.7495929752,46.49844513868],[11.74957652418,46.49845290164],[11.74956007315,46.4984606646],[11.74954362212,46.49846842756],[11.74952811797,46.49847707008],[11.74951261381,46.49848571261],[11.74949710965,46.49849435512],[11.74948160549,46.49850299764],[11.74946610132,46.49851164016],[11.74945059714,46.49852028267],[11.74943613822,46.49852974992],[11.74942167929,46.49853921716],[11.74940722035,46.4985486844],[11.74939276141,46.49855815164],[11.74937830247,46.49856761888],[11.74936384352,46.49857708612],[11.74935052156,46.49858731802],[11.74933719959,46.49859754993],[11.74932387761,46.49860778183],[11.74931055564,46.49861801373],[11.74929723365,46.49862824562],[11.74928391167,46.49863847752],[11.74927181119,46.49864940917],[11.74925971071,46.49866034081],[11.74924761022,46.49867127246],[11.74923550973,46.4986822041],[11.74922340923,46.49869313574],[11.74921130873,46.49870406738],[11.74920050651,46.49871562942],[11.74918970429,46.49872719145],[11.74917890207,46.49873875348],[11.74916809984,46.49875031552],[11.7491572976,46.49876187755],[11.74914649536,46.49877343958],[11.74913705995,46.49878555864],[11.74912762453,46.49879767771],[11.7491181891,46.49880979678],[11.74910875367,46.49882191584],[11.74909931824,46.49883403491],[11.7490898828,46.49884615397],[11.74908187406,46.49885875319],[11.7490738653,46.4988713524],[11.74906585655,46.49888395161],[11.74905784779,46.49889655082],[11.74904983903,46.49890915003],[11.74904183026,46.49892174924],[11.749035299,46.49893474866],[11.74902876773,46.49894774808],[11.74902223647,46.4989607475],[11.74901570519,46.49897374691],[11.74900917392,46.49898674633],[11.74900264264,46.49899974575],[11.74899763031,46.4990130629],[11.74899261798,46.49902638006],[11.74898760564,46.49903969721],[11.7489825933,46.49905301436],[11.74897758096,46.49906633151],[11.74897256861,46.49907964867],[11.74896910702,46.49909319906],[11.74896564542,46.49910674946],[11.74896218383,46.49912029985],[11.74895872223,46.49913385024],[11.74895526063,46.49914740064],[11.74895179903,46.49916095103],[11.74894991014,46.4991746487],[11.74894802125,46.49918834636],[11.74894613236,46.49920204403],[11.74894424347,46.49921574169],[11.74894235458,46.49922943935],[11.74894046569,46.49924313702],[11.74893682751,46.49925787097],[11.74893318933,46.49927260493],[11.74892955115,46.49928733888],[11.74892591296,46.49930207283],[11.74892227477,46.49931680679],[11.74891863659,46.49933154074],[11.7489166449,46.49934642395],[11.74891465322,46.49936130715],[11.74891266153,46.49937619036],[11.74891066984,46.49939107357],[11.74890867815,46.49940595677],[11.74890668646,46.49942083998],[11.74890635301,46.49943578482],[11.74890601955,46.49945072967],[11.74890568609,46.49946567452],[11.74890535263,46.49948061937],[11.74890501918,46.49949556421],[11.74890468572,46.49951050906],[11.74890601246,46.49952542758],[11.7489073392,46.49954034609],[11.74890866595,46.49955526461],[11.74890999269,46.49957018312],[11.74891131943,46.49958510163],[11.74891264618,46.49960002015],[11.74891562532,46.49961482451],[11.74891860446,46.49962962887],[11.7489215836,46.49964443323],[11.74892456274,46.49965923759],[11.74892754188,46.49967404196],[11.74893052103,46.49968884632],[11.74893513504,46.49970344938],[11.74893974904,46.49971805244],[11.74894436305,46.4997326555],[11.74894897707,46.49974725856],[11.74895359108,46.49976186162],[11.7489582051,46.49977646468],[11.74896442682,46.49979078048],[11.74897064854,46.49980509627],[11.74897687027,46.49981941207],[11.74898309199,46.49983372787],[11.74898931373,46.49984804366],[11.74899553546,46.49986235946],[11.74900332828,46.49987630372],[11.7490111211,46.49989024797],[11.74901891392,46.49990419223],[11.74902670675,46.49991813649],[11.74903449958,46.49993208075],[11.74903744726,46.49993735524],[11.74904229241,46.499946025],[11.74905161046,46.49995951564],[11.74906092851,46.49997300628],[11.74907024656,46.49998649691],[11.74907956462,46.49999998754],[11.74908888268,46.50001347818],[11.74909820075,46.50002696881],[11.74910898918,46.50003992641],[11.74911977761,46.500052884],[11.74913056605,46.5000658416],[11.74914135449,46.50007879919],[11.74915214294,46.50009175678],[11.74916293139,46.50010471437],[11.74917512669,46.50011706265],[11.74918732201,46.50012941093],[11.74919951732,46.5001417592],[11.74921171265,46.50015410748],[11.74922390798,46.50016645575],[11.74923610331,46.50017880402],[11.74924963371,46.50019047029],[11.74926316411,46.50020213656],[11.74927669453,46.50021380282],[11.74929022494,46.50022546909],[11.74930375537,46.50023713535],[11.7493172858,46.50024880161],[11.74933207164,46.50025971719],[11.7493468575,46.50027063277],[11.74936164336,46.50028154835],[11.74937642922,46.50029246392],[11.74939121509,46.50030337949],[11.74940600097,46.50031429506],[11.74942195523,46.5003243957],[11.74943790949,46.50033449633],[11.74945386376,46.50034459696],[11.74946981804,46.50035469759],[11.74948577232,46.50036479822],[11.7495017266,46.50037489884],[11.74952560764,46.50037940726],[11.74954948868,46.50038391567],[11.74964257821,46.50040695398],[11.74973566782,46.50042999221],[11.74982875751,46.50045303037],[11.74992184727,46.50047606844],[11.75000748073,46.50048729086],[11.75009311422,46.50049851321],[11.75017874775,46.50050973549],[11.7502643813,46.50052095771],[11.75035001489,46.50053217986],[11.75043564852,46.50054340195],[11.75052442223,46.50055235479],[11.75061319597,46.50056130756],[11.75070196973,46.50057026026],[11.75079074353,46.50057921289],[11.75088249636,46.50057397529],[11.75097424917,46.50056873763],[11.75106600196,46.50056349988],[11.75115775473,46.50055826207],[11.75124950747,46.50055302418],[11.7513412602,46.50054778622],[11.7513630156,46.50054600839],[11.751384771,46.50054423056],[11.751408378,46.50054095212],[11.75143198499,46.50053767368],[11.75145559198,46.50053439524],[11.75147620195,46.50053064441],[11.75149681191,46.50052689359],[11.75151742186,46.50052314276],[11.75154057565,46.50051820985],[11.75156372944,46.50051327693],[11.75158688322,46.50050834401],[11.75160632785,46.50050373108],[11.75162577248,46.50049911815],[11.75164521711,46.50049450522],[11.75166466173,46.50048989228],[11.75168410635,46.50048527933],[11.75170355096,46.50048066639],[11.75172299557,46.50047605344],[11.75174244018,46.50047144049],[11.75176188479,46.50046682753],[11.75178132939,46.50046221457],[11.75180077399,46.50045760161],[11.75182021858,46.50045298865],[11.75183966317,46.50044837568],[11.75185910776,46.50044376271],[11.75187855234,46.50043914973],[11.75189799692,46.50043453675],[11.75191773618,46.50043068006],[11.75193747544,46.50042682336],[11.7519572147,46.50042296666],[11.75197695395,46.50041910996],[11.7520006427,46.50041548131],[11.75202433144,46.50041185265],[11.75204802018,46.50040822399],[11.75207114227,46.50040491643],[11.75209426435,46.50040160886],[11.75211738642,46.50039830129],[11.75214050849,46.50039499371],[11.75216363056,46.50039168613],[11.75218675263,46.50038837855],[11.75220987469,46.50038507096],[11.75223299675,46.50038176336],[11.75225611881,46.50037845576],[11.75227553451,46.50037665302],[11.7522759908,46.50037661078],[11.75229586279,46.5003747658],[11.75231573478,46.50037292082],[11.75233339261,46.50037228711],[11.75235105044,46.5003716534],[11.75236870796,46.50037101973],[11.75239029824,46.50037175553],[11.7524118882,46.50037249136],[11.75243347816,46.50037322718],[11.75245598322,46.50037554803],[11.75247848828,46.50037786888],[11.75250099334,46.50038018972],[11.75252453242,46.500384107],[11.75254807151,46.50038802427],[11.75257161059,46.50039194154],[11.75259020757,46.5003961043],[11.75260880454,46.50040026705],[11.75262740152,46.5004044298],[11.7526459985,46.50040859255],[11.75266504421,46.50041381446],[11.75268408993,46.50041903637],[11.75270313564,46.50042425827],[11.75272218136,46.50042948017],[11.75274282903,46.50043602743],[11.75276347671,46.50044257469],[11.75278412439,46.50044912195],[11.75280477207,46.5004556692],[11.75282721871,46.50046356172],[11.75284966535,46.50047145423],[11.75287211199,46.50047934675],[11.75289455865,46.50048723925],[11.7529151567,46.50049495803],[11.75293575477,46.50050267681],[11.75295635284,46.50051039558],[11.75297695091,46.50051811435],[11.75299754899,46.50052583311],[11.75301814708,46.50053355187],[11.75303322415,46.50053967857],[11.75304830122,46.50054580526],[11.7530633783,46.50055193195],[11.7530785506,46.50055892723],[11.75309372291,46.50056592251],[11.75310889523,46.50057291779],[11.75312430212,46.50058084512],[11.75313970902,46.50058877244],[11.75315511592,46.50059669976],[11.75317100754,46.5006056874],[11.75318689917,46.50061467505],[11.7532027908,46.50062366269],[11.75321833207,46.50063344351],[11.75323387334,46.50064322432],[11.75324941462,46.50065300514],[11.7532649559,46.50066278595],[11.75328049719,46.50067256677],[11.75329603848,46.50068234757],[11.75331096571,46.50069256758],[11.75332589294,46.50070278759],[11.75334082018,46.5007130076],[11.75335574742,46.5007232276],[11.75337067467,46.5007334476],[11.75338560193,46.5007436676],[11.75340052919,46.5007538876],[11.75341545645,46.50076410759],[11.75343038373,46.50077432759],[11.753445311,46.50078454758],[11.75346023829,46.50079476756],[11.75347516557,46.50080498755],[11.75348791626,46.5008133153],[11.75350066695,46.50082164305],[11.75351341765,46.5008299708],[11.75352616835,46.50083829855],[11.75353891905,46.50084662629],[11.75355166976,46.50085495404],[11.75356552533,46.50086311187],[11.75357938091,46.50087126971],[11.75359323649,46.50087942754],[11.75360709207,46.50088758538],[11.75362094766,46.50089574321],[11.75363480326,46.50090390104],[11.75365444637,46.50091380253],[11.75367408949,46.50092370402],[11.75369373261,46.50093360551],[11.75371337575,46.50094350699],[11.75373027282,46.50095075056],[11.7537471699,46.50095799414],[11.75376406698,46.5009652377],[11.75378096406,46.50097248127],[11.75379786115,46.50097972483],[11.75381475825,46.5009869684],[11.75383165535,46.50099421195],[11.75384855245,46.50100145551],[11.75386787037,46.50100876295],[11.75388718829,46.50101607039],[11.75390650622,46.50102337783],[11.75392582415,46.50103068527],[11.75394514208,46.5010379927],[11.75396446002,46.50104530012],[11.75398377797,46.50105260755],[11.75400309592,46.50105991497],[11.754024746,46.50106732307],[11.75404639609,46.50107473118],[11.75406804618,46.50108213928],[11.75408969628,46.50108954738],[11.75411134638,46.50109695547],[11.75413299649,46.50110436356],[11.75415464661,46.50111177164],[11.75417629673,46.50111917972],[11.75419889559,46.50112644357],[11.75422149445,46.50113370741],[11.75424409333,46.50114097124],[11.7542666922,46.50114823507],[11.75428929109,46.5011554989],[11.75431188998,46.50116276272],[11.75433448887,46.50117002654],[11.75435708777,46.50117729035],[11.75437968668,46.50118455416],[11.75440228559,46.50119181796],[11.75442488451,46.50119908176],[11.75444748343,46.50120634556],[11.75447102844,46.50121379443],[11.75449457346,46.50122124331],[11.75451811848,46.50122869217],[11.7545416635,46.50123614104],[11.75456520854,46.50124358989],[11.75458875358,46.50125103875],[11.75461229862,46.50125848759],[11.75463584367,46.50126593644],[11.75465938873,46.50127338527],[11.75468293379,46.50128083411],[11.75470647886,46.50128828293],[11.75473002394,46.50129573175],[11.75475356902,46.50130318057],[11.75477711411,46.50131062938],[11.75480065921,46.50131807819],[11.75482420431,46.50132552699],[11.75484699301,46.50133229785],[11.75486978172,46.5013390687],[11.75489257043,46.50134583954],[11.75491535915,46.50135261038],[11.75493814787,46.50135938121],[11.7549609366,46.50136615204],[11.75498176605,46.50137196086],[11.75500259551,46.50137776968],[11.75502279496,46.5013834028],[11.75502342497,46.50138357849],[11.75504425444,46.5013893873],[11.75506508391,46.5013951961],[11.75508591338,46.5014010049],[11.75510650407,46.50140629861],[11.75512709477,46.50141159231],[11.75514768547,46.50141688601],[11.75516827617,46.50142217971],[11.75518886688,46.5014274734],[11.75520945759,46.50143276709],[11.75522905707,46.50143731582],[11.75524865655,46.50144186455],[11.75526825604,46.50144641328],[11.75528785553,46.501450962],[11.75530745502,46.50145551072],[11.75532705452,46.50146005944],[11.75534592432,46.50146392368],[11.75536479412,46.50146778792],[11.75538366393,46.50147165216],[11.75540253374,46.50147551639],[11.75542140355,46.50147938062],[11.75544027337,46.50148324485],[11.75545855938,46.50148645408],[11.7554768454,46.5014896633],[11.75549513142,46.50149287252],[11.75551341744,46.50149608174],[11.75553170346,46.50149929095],[11.75554998949,46.50150250016],[11.75557262214,46.5015059093],[11.7555952548,46.50150931844],[11.75561788746,46.50151272757],[11.75564052012,46.50151613669],[11.75566315278,46.50151954581],[11.75568578545,46.50152295493],[11.75570779417,46.50152583066],[11.75572980288,46.50152870639],[11.7557518116,46.50153158211],[11.75577382033,46.50153445783],[11.75579582905,46.50153733355],[11.75581783778,46.50154020926],[11.75583922573,46.50154255199],[11.75586061368,46.50154489473],[11.75588200163,46.50154723746],[11.75590338959,46.50154958018],[11.75592477755,46.5015519229],[11.75594616551,46.50155426562],[11.75596693124,46.50155607519],[11.75598769698,46.50155788476],[11.75600314186,46.5015725132],[11.75602922846,46.50159080416],[11.75610458435,46.50165868391],[11.75627055345,46.50169512944],[11.75641067943,46.50168562706],[11.75645679852,46.50165157562],[11.7564842946,46.50162484924],[11.7565031776,46.5016049141],[11.75657342899,46.50157427838],[11.7565943991,46.50157314829],[11.7566153692,46.50157201819],[11.7566363393,46.50157088809],[11.7566573094,46.50156975798],[11.7566782795,46.50156862787],[11.7566992496,46.50156749776],[11.75672071284,46.50156548048],[11.75674217607,46.5015634632],[11.7567636393,46.50156144592],[11.75678510253,46.50155942863],[11.75680656576,46.50155741134],[11.75682802899,46.50155539404],[11.75684949221,46.50155337674],[11.75687095544,46.50155135944],[11.75689267612,46.50154847703],[11.7569143968,46.50154559461],[11.75693611748,46.50154271219],[11.75695783816,46.50153982977],[11.75697955883,46.50153694734],[11.7570012795,46.50153406491],[11.75702300017,46.50153118247],[11.75704472084,46.50152830003],[11.75706643508,46.50152458739],[11.75708814931,46.50152087474],[11.75710986355,46.50151716209],[11.75713157778,46.50151344943],[11.757153292,46.50150973677],[11.75717500623,46.5015060241],[11.75719672045,46.50150231144],[11.75721843466,46.50149859876],[11.7572398821,46.50149409967],[11.75733582164,46.50159215163],[11.75747166766,46.50160962774],[11.7576008626,46.50163900707],[11.75772084242,46.5016203639],[11.75778487391,46.50158491],[11.75779853423,46.50155314475],[11.75780745027,46.50150671625],[11.7577839659,46.50140160566],[11.75779342126,46.50134788964],[11.75781238739,46.50134142502],[11.75783135352,46.5013349604],[11.75785031964,46.50132849577],[11.75786928576,46.50132203114],[11.75789008469,46.50131387838],[11.75791088362,46.50130572561],[11.75793168255,46.50129757284],[11.75795248146,46.50128942006],[11.75797305862,46.50128030412],[11.75799363576,46.50127118817],[11.7580142129,46.50126207222],[11.75803479003,46.50125295626],[11.75805518094,46.50124286145],[11.75807557184,46.50123276664],[11.75809596273,46.50122267183],[11.75811635361,46.50121257701],[11.75813660341,46.50120148104],[11.75815685319,46.50119038506],[11.75817710297,46.50117928909],[11.75819735274,46.50116819311],[11.75821077805,46.50116011885],[11.75822420336,46.5011520446],[11.75823762866,46.50114397034],[11.75825105395,46.50113589608],[11.75826447924,46.50112782182],[11.75827790453,46.50111974755],[11.75829131399,46.50111096223],[11.75830472345,46.5011021769],[11.7583181329,46.50109339156],[11.75833154234,46.50108460623],[11.75834495178,46.5010758209],[11.75835836122,46.50106703556],[11.75837180586,46.50105750588],[11.7583852505,46.50104797619],[11.75838604135,46.50104741563],[11.75839869514,46.50103844651],[11.75841213977,46.50102891682],[11.75842558439,46.50101938714],[11.75843902901,46.50100985745],[11.75845258309,46.50099953088],[11.75846613717,46.50098920432],[11.75847969124,46.50097887775],[11.75849324531,46.50096855119],[11.75850679937,46.50095822462],[11.75852035342,46.50094789805],[11.75853253433,46.50093802123],[11.75854471524,46.50092814441],[11.75855689615,46.50091826758],[11.75856907705,46.50090839076],[11.75858125794,46.50089851393],[11.75859343883,46.50088863711],[11.75860587638,46.50087799938],[11.75861831392,46.50086736165],[11.75863075146,46.50085672391],[11.75864318899,46.50084608618],[11.75865562652,46.50083544844],[11.75866806404,46.50082481071],[11.75868088174,46.50081330711],[11.75869369943,46.50080180351],[11.75870651711,46.50079029991],[11.75871933478,46.50077879631],[11.75873215246,46.5007672927],[11.75874497012,46.5007557891],[11.75875841055,46.50074320224],[11.75877185098,46.50073061537],[11.75878529139,46.50071802851],[11.75879873181,46.50070544164],[11.75881217221,46.50069285477],[11.75882561261,46.5006802679],[11.75884047729,46.50066571873],[11.75885534197,46.50065116955],[11.75887020663,46.50063662037],[11.75888507129,46.50062207119],[11.75889993594,46.50060752201],[11.75891480059,46.50059297283],[11.75892966522,46.50057842364],[11.75894452985,46.50056387445],[11.75895939447,46.50054932526],[11.75897321636,46.50053531992],[11.75898703824,46.50052131458],[11.75900086012,46.50050730924],[11.75901468199,46.50049330389],[11.75902850386,46.50047929854],[11.75904232571,46.50046529319],[11.75905614756,46.50045128784],[11.7590699694,46.50043728249],[11.75908379124,46.50042327714],[11.75909761307,46.50040927178],[11.75911143489,46.50039526643],[11.7591252567,46.50038126107],[11.75913907851,46.50036725571],[11.75915290031,46.50035325035],[11.7591667221,46.50033924498],[11.75918054389,46.50032523962],[11.75919436567,46.50031123425],[11.75920818744,46.50029722889],[11.75922200921,46.50028322352],[11.75923583096,46.50026921815],[11.75925072461,46.50025447609],[11.75926561824,46.50023973403],[11.75928051187,46.50022499198],[11.75929540549,46.50021024992],[11.7593102991,46.50019550785],[11.75932519271,46.50018076579],[11.7593400863,46.50016602372],[11.75935497989,46.50015128166],[11.75936724473,46.50013872253],[11.75937950957,46.5001261634],[11.7593917744,46.50011360428],[11.75940403923,46.50010104515],[11.75941630405,46.50008848602],[11.75942856886,46.50007592688],[11.75944134629,46.50006150157],[11.75945412372,46.50004707626],[11.75946690115,46.50003265094],[11.75947967856,46.50001822562],[11.75949245597,46.5000038003],[11.75950523337,46.49998937498],[11.75951709676,46.49997499764],[11.75952896014,46.4999606203],[11.75954082351,46.49994624296],[11.75955268688,46.49993186562],[11.75956455025,46.49991748828],[11.7595764136,46.49990311093],[11.7595873591,46.49988939266],[11.75959830459,46.49987567439],[11.75960925008,46.49986195611],[11.75962019557,46.49984823784],[11.75963114104,46.49983451956],[11.75964208651,46.49982080128],[11.75965303198,46.49980708301],[11.75966397744,46.49979336473],[11.7596749229,46.49977964645],[11.75968586835,46.49976592817],[11.75968778133,46.49976353056],[11.75969681379,46.49975220988],[11.75970775923,46.4997384916],[11.75971870467,46.49972477332],[11.75972965009,46.49971105503],[11.75974059552,46.49969733675],[11.75975154093,46.49968361846],[11.75976398237,46.49966910388],[11.75977642379,46.49965458931],[11.75978886521,46.49964007473],[11.75980130662,46.49962556016],[11.75981374802,46.49961104558],[11.75982618942,46.499596531],[11.75983863081,46.49958201642],[11.7598510722,46.49956750183],[11.75986492168,46.49955274092],[11.75987877117,46.49953798],[11.75989262064,46.49952321908],[11.75990647011,46.49950845816],[11.75992013022,46.49949500647],[11.75993379032,46.49948155477],[11.75994745042,46.49946810307],[11.75996111051,46.49945465137],[11.75997483097,46.49944226366],[11.75998855142,46.49942987595],[11.76000227186,46.49941748823],[11.7600159923,46.49940510052],[11.76002991044,46.49939365407],[11.76004382858,46.49938220762],[11.76005774672,46.49937076117],[11.76007166485,46.49935931472],[11.76008810643,46.49934790043],[11.760104548,46.49933648613],[11.76012098956,46.49932507183],[11.76013743112,46.49931365753],[11.76015492661,46.49930099123],[11.76017242209,46.49928832491],[11.76018991757,46.4992756586],[11.76020741303,46.49926299228],[11.76022490849,46.49925032596],[11.76024240394,46.49923765964],[11.76025989938,46.49922499331],[11.76027739482,46.49921232699],[11.76029489024,46.49919966066],[11.76031238566,46.49918699433],[11.76032988107,46.49917432799],[11.76034737647,46.49916166165],[11.76036540425,46.49915002599],[11.76038343201,46.49913839033],[11.76040145977,46.49912675467],[11.76041948752,46.499115119],[11.76043652205,46.49910545246],[11.76045355657,46.49909578591],[11.76047059108,46.49908611937],[11.76048762559,46.49907645282],[11.76050786182,46.4990662526],[11.76050811386,46.49906612559],[11.76052809809,46.49905605242],[11.76052860215,46.4990557984],[11.76054834095,46.49904585847],[11.76056857938,46.49903566034],[11.76058911015,46.49902620335],[11.76060964092,46.49901674636],[11.76063017168,46.49900728936],[11.76065070243,46.49899783236],[11.76067139896,46.49898917469],[11.76069209548,46.49898051701],[11.760712792,46.49897185933],[11.76073348852,46.49896320165],[11.76075424703,46.49895538659],[11.76077500553,46.49894757154],[11.76079576403,46.49893975647],[11.76081652252,46.49893194141],[11.76084032311,46.49892486211],[11.76086412369,46.4989177828],[11.76088792427,46.4989107035],[11.76091172484,46.49890362418],[11.7609355254,46.49889654486],[11.76095932596,46.49888946554],[11.76098312651,46.49888238621],[11.76100692706,46.49887530688],[11.7610307276,46.49886822754],[11.76105120493,46.49886093169],[11.76107168226,46.49885363583],[11.76109215958,46.49884633997],[11.76110965405,46.49883887436],[11.7611271485,46.49883140875],[11.76114464295,46.49882394314],[11.76116142626,46.49881506772],[11.76117820956,46.4988061923],[11.76119499286,46.49879731688],[11.76121037571,46.49878789874],[11.76122575855,46.49877848059],[11.76124114138,46.49876906244],[11.76125652421,46.49875964429],[11.76127190703,46.49875022613],[11.76128728985,46.49874080798],[11.76130685776,46.49872970843],[11.76132642567,46.49871860888],[11.76134212406,46.49871029375],[11.76135782245,46.49870197862],[11.76137352084,46.49869366349],[11.76138921922,46.49868534836],[11.76140567459,46.49867776325],[11.76141960073,46.49867134399],[11.76142212996,46.49867017814],[11.76143858533,46.49866259303],[11.76145504069,46.49865500791],[11.76147149604,46.49864742279],[11.76148795139,46.49863983767],[11.76150440674,46.49863225255],[11.76152086208,46.49862466743],[11.76153800335,46.49861784508],[11.76155514461,46.49861102274],[11.76157228586,46.49860420039],[11.76158942712,46.49859737804],[11.76160656836,46.49859055569],[11.76162370961,46.49858373333],[11.76164085085,46.49857691098],[11.76165799208,46.49857008862],[11.76167905171,46.49856293948],[11.76170011133,46.49855579034],[11.76172117095,46.49854864119],[11.76174223056,46.49854149205],[11.76176609551,46.49853433104],[11.76178996046,46.49852717003],[11.7618138254,46.49852000902],[11.76183769033,46.498512848],[11.76186155526,46.49850568697],[11.76188542018,46.49849852594],[11.76189907873,46.49849442749],[11.76190770208,46.49849204055],[11.76191278747,46.49849031397],[11.76193315,46.49848420387],[11.76195281577,46.49847732614],[11.76197248154,46.4984704484],[11.7619921473,46.49846357065],[11.76201181305,46.49845669291],[11.76202846975,46.49844991198],[11.76204512644,46.49844313106],[11.76206178312,46.49843635013],[11.7620784398,46.4984295692],[11.76209509648,46.49842278826],[11.76211175315,46.49841600733],[11.76212761922,46.49840837561],[11.7621434853,46.4984007439],[11.76215935136,46.49839311218],[11.76217521742,46.49838548046],[11.76219108348,46.49837784874],[11.76220694953,46.49837021701],[11.76222193405,46.49836177826],[11.76223691857,46.49835333949],[11.76225190308,46.49834490073],[11.76226688758,46.49833646197],[11.76228187208,46.4983280232],[11.76229685657,46.49831958443],[11.76231087365,46.49831038699],[11.76232489072,46.49830118956],[11.76233890779,46.49829199212],[11.76235292485,46.49828279468],[11.7623669419,46.49827359724],[11.76238095895,46.49826439979],[11.76239392825,46.4982544964],[11.76240689753,46.498244593],[11.76241986682,46.49823468961],[11.76243283609,46.49822478621],[11.76244580537,46.49821488281],[11.76245877463,46.49820497941],[11.76247062181,46.49819442682],[11.76248246898,46.49818387423],[11.76249431614,46.49817332164],[11.7625061633,46.49816276905],[11.76251801046,46.49815221646],[11.76252985761,46.49814166387],[11.76254051477,46.49813052257],[11.76255117192,46.49811938127],[11.76256182907,46.49810823998],[11.76257248621,46.49809709868],[11.76258314335,46.49808595738],[11.76259380048,46.49807481608],[11.76260320654,46.49806314993],[11.7626126126,46.49805148378],[11.76262201865,46.49803981763],[11.76263142469,46.49802815149],[11.76264083073,46.49801648534],[11.76265023677,46.49800481919],[11.76265859486,46.49799161859],[11.76266695294,46.497978418],[11.76267531102,46.4979652174],[11.76268366909,46.4979520168],[11.76269125606,46.49794204561],[11.76269884303,46.49793207441],[11.76270753616,46.49792333701],[11.76271622928,46.49791459962],[11.7627272694,46.49790545176],[11.76273830952,46.49789630391],[11.76275225552,46.49788650793],[11.76276620151,46.49787671195],[11.7627801475,46.49786691597],[11.76279409348,46.49785711998],[11.76280803945,46.497847324],[11.76282198543,46.49783752801],[11.76283819696,46.49782624387],[11.76289493729,46.49778674935],[11.76295167753,46.49774725481],[11.7629678621,46.49773698955],[11.76298404665,46.49772672429],[11.7630002312,46.49771645902],[11.76301641575,46.49770619376],[11.76303260029,46.49769592849],[11.76304878482,46.49768566321],[11.76305628155,46.49768124108],[11.76306707591,46.49767487376],[11.763085367,46.4976640843],[11.76310365809,46.49765329484],[11.76312194916,46.49764250538],[11.76314024023,46.49763171592],[11.76315853129,46.49762092645],[11.7631762619,46.49761079031],[11.7631939925,46.49760065417],[11.76321172309,46.49759051803],[11.76322945368,46.49758038188],[11.76324788107,46.49757085687],[11.76326342848,46.49756282049],[11.76326630845,46.49756133185],[11.76328473582,46.49755180683],[11.76330316318,46.49754228181],[11.76332159054,46.49753275678],[11.76334001789,46.49752323176],[11.76335844524,46.49751370673],[11.76337687258,46.49750418169],[11.76339595259,46.4974952906],[11.76341503259,46.4974863995],[11.76343411259,46.4974775084],[11.76345319258,46.4974686173],[11.76347227256,46.49745972619],[11.76349135254,46.49745083508],[11.76351043251,46.49744194397],[11.76352951248,46.49743305286],[11.76354919943,46.49742481697],[11.76356888637,46.49741658108],[11.7635885733,46.49740834519],[11.76360826023,46.49740010929],[11.76362794716,46.49739187339],[11.76364763407,46.49738363749],[11.76366732098,46.49737540158],[11.76368700789,46.49736716567],[11.76370725464,46.49735960472],[11.76372750138,46.49735204375],[11.76374774811,46.49734448279],[11.76376799484,46.49733692182],[11.76378824156,46.49732936084],[11.76380848828,46.49732179987],[11.76382873499,46.49731423889],[11.7638489817,46.4973066779],[11.76386973977,46.49729980997],[11.76389049783,46.49729294204],[11.76391125589,46.4972860741],[11.76393201394,46.49727920616],[11.76395277198,46.49727233822],[11.76397353002,46.49726547027],[11.76399428806,46.49725860232],[11.76401504608,46.49725173437],[11.76403626577,46.49724557591],[11.76405748545,46.49723941745],[11.76407870512,46.49723325899],[11.76409992479,46.49722710052],[11.76412114446,46.49722094205],[11.76414236412,46.49721478358],[11.76416358377,46.4972086251],[11.76418480342,46.49720246662],[11.76420887471,46.49719620506],[11.76423294599,46.4971899435],[11.76425701726,46.49718368193],[11.76428108853,46.49717742036],[11.76430496748,46.49717163012],[11.76432884642,46.49716583987],[11.76435272536,46.49716004962],[11.7643766043,46.49715425936],[11.76440048323,46.49714846909],[11.76442436215,46.49714267883],[11.76444824107,46.49713688855],[11.76447211998,46.49713109828],[11.76449599889,46.49712530799],[11.76451987779,46.49711951771],[11.76454375669,46.49711372741],[11.76456763558,46.49710793712],[11.76459061894,46.49710166111],[11.76461360229,46.49709538509],[11.76463658563,46.49708910907],[11.76465956897,46.49708283305],[11.7646825523,46.49707655702],[11.76470553563,46.49707028099],[11.76472851895,46.49706400495],[11.76475150226,46.49705772891],[11.76477448557,46.49705145287],[11.76479710973,46.4970445826],[11.76481973388,46.49703771232],[11.76484235802,46.49703084204],[11.76486498216,46.49702397176],[11.76488760629,46.49701710147],[11.76491023042,46.49701023118],[11.7649182711,46.49700778946],[11.76493285454,46.49700336088],[11.76494236203,46.49700047373],[11.76495547866,46.49699649058],[11.76497810276,46.49698962027],[11.76500033552,46.49698216552],[11.76502256826,46.49697471077],[11.765044801,46.49696725601],[11.76506703373,46.49695980124],[11.76508926646,46.49695234648],[11.76511149918,46.4969448917],[11.7651337319,46.49693743693],[11.7651559646,46.49692998215],[11.76517819731,46.49692252736],[11.76520000701,46.49691449874],[11.7652218167,46.49690647012],[11.76522849687,46.496904011],[11.76524362638,46.49689844149],[11.76526543606,46.49689041286],[11.76528724574,46.49688238422],[11.76530905541,46.49687435558],[11.76533086507,46.49686632694],[11.76535267472,46.49685829829],[11.76537448437,46.49685026964],[11.76539583997,46.49684167858],[11.76541719556,46.49683308752],[11.76543855115,46.49682449645],[11.76545990673,46.49681590538],[11.76548126231,46.4968073143],[11.76550261788,46.49679872323],[11.76552397344,46.49679013214],[11.76554532899,46.49678154106],[11.76556668454,46.49677294997],[11.76558755565,46.4967638087],[11.76560842675,46.49675466743],[11.76562929784,46.49674552615],[11.76565016892,46.49673638487],[11.76567104,46.49672724359],[11.76569191107,46.49671810231],[11.76571278213,46.49670896102],[11.76573365319,46.49669981972],[11.76575452424,46.49669067842],[11.76577488114,46.49668099996],[11.76579523804,46.49667132149],[11.76581559492,46.49666164302],[11.7658359518,46.49665196455],[11.76585630868,46.49664228607],[11.76587666554,46.49663260759],[11.7658970224,46.4966229291],[11.76591737925,46.49661325061],[11.76593773609,46.49660357212],[11.76595754981,46.49659337024],[11.76597736353,46.49658316835],[11.76599717723,46.49657296646],[11.76601699093,46.49656276457],[11.76603680462,46.49655256267],[11.76605661831,46.49654236077],[11.76607643198,46.49653215887],[11.76609624565,46.49652195696],[11.76611605931,46.49651175505],[11.76613223803,46.49650416252],[11.76614841674,46.49649656999],[11.76616459544,46.49648897745],[11.76618077414,46.49648138492],[11.76619695284,46.49647379238],[11.76621313153,46.49646619983],[11.76623059383,46.49645844537],[11.76624805613,46.49645069091],[11.76626551843,46.49644293644],[11.76628298072,46.49643518197],[11.76630044301,46.49642742749],[11.76631790529,46.49641967302],[11.76633536757,46.49641191854],[11.76635282984,46.49640416406],[11.76637293826,46.49639560756],[11.76639304668,46.49638705106],[11.76641315509,46.49637849456],[11.7664332635,46.49636993805],[11.7664533719,46.49636138154],[11.7664734803,46.49635282502],[11.76649358868,46.49634426851],[11.76651369706,46.49633571199],[11.76653380544,46.49632715546],[11.76655391381,46.49631859893],[11.76657402217,46.4963100424],[11.76659413052,46.49630148587],[11.76661459866,46.49629334635],[11.76663506678,46.49628520682],[11.7666555349,46.4962770673],[11.76667600302,46.49626892777],[11.76669647112,46.49626078823],[11.76671693922,46.49625264869],[11.76673740732,46.49624450915],[11.76675787541,46.49623636961],[11.76677834349,46.49622823006],[11.76679881157,46.49622009051],[11.76681927964,46.49621195095],[11.7668397477,46.49620381139],[11.76686055741,46.49619609606],[11.76688136712,46.49618838072],[11.76690217682,46.49618066537],[11.76692298652,46.49617295002],[11.76694379621,46.49616523467],[11.76696460589,46.49615751932],[11.76698541557,46.49614980396],[11.76700622524,46.4961420886],[11.76702703491,46.49613437323],[11.76704784457,46.49612665786],[11.76706865422,46.49611894249],[11.76708946387,46.49611122711],[11.76711059674,46.49610394279],[11.76713172961,46.49609665846],[11.76715286246,46.49608937413],[11.76717399532,46.4960820898],[11.76719512816,46.49607480546],[11.767216261,46.49606752112],[11.76723739384,46.49606023678],[11.76725852667,46.49605295243],[11.76727965949,46.49604566807],[11.76730079231,46.49603838372],[11.76732192512,46.49603109936],[11.76734305792,46.49602381499],[11.76736449524,46.49601696814],[11.76738593254,46.49601012127],[11.76740736984,46.49600327441],[11.76742880714,46.49599642754],[11.76745024443,46.49598958066],[11.76747168172,46.49598273378],[11.76749311899,46.4959758869],[11.76751455627,46.49596904002],[11.76753599354,46.49596219313],[11.7675574308,46.49595534623],[11.76757886806,46.49594849934],[11.76760030531,46.49594165243],[11.7676237479,46.49593489405],[11.76764719048,46.49592813566],[11.76767063306,46.49592137726],[11.76769407564,46.49591461886],[11.7677175182,46.49590786045],[11.76774096077,46.49590110204],[11.76776440332,46.49589434363],[11.76778784587,46.49588758521],[11.76780612897,46.49588189195],[11.76782441206,46.4958761987],[11.76784269515,46.49587050544],[11.76786097824,46.49586481218],[11.76788280996,46.49585718073],[11.76790464167,46.49584954927],[11.76792647338,46.49584191781],[11.76794441238,46.49583509913],[11.76796235138,46.49582828044],[11.76798029037,46.49582146175],[11.76799822936,46.49581464306],[11.76801797782,46.49580656723],[11.76803772627,46.49579849139],[11.76805747472,46.49579041555],[11.76807722316,46.49578233971],[11.7680969716,46.49577426386],[11.76811672003,46.49576618801],[11.76813646845,46.49575811216],[11.76815621687,46.49575003631],[11.76817596528,46.49574196045],[11.76819571368,46.49573388459],[11.76821546208,46.49572580872],[11.76823521047,46.49571773285],[11.76825758897,46.49570861134],[11.76827996746,46.49569948983],[11.76830234593,46.49569036832],[11.76832472441,46.4956812468],[11.76834710287,46.49567212528],[11.76836948132,46.49566300375],[11.76839185977,46.49565388222],[11.76841423821,46.49564476068],[11.76843661665,46.49563563914],[11.76845762272,46.49562680958],[11.76847862879,46.49561798002],[11.76849963485,46.49560915046],[11.76852064091,46.49560032089],[11.76854164696,46.49559149131],[11.768562653,46.49558266173],[11.76858365903,46.49557383215],[11.76860466506,46.49556500257],[11.76862289001,46.49555708723],[11.76864111496,46.49554917189],[11.7686593399,46.49554125655],[11.76867756484,46.4955333412],[11.76869578977,46.49552542586],[11.7687140147,46.4955175105],[11.76873223962,46.49550959515],[11.76875046454,46.49550167979],[11.76876868945,46.49549376443],[11.76878691436,46.49548584907],[11.76880513926,46.49547793371],[11.76882336415,46.49547001834],[11.76884158904,46.49546210297],[11.76885981392,46.49545418759],[11.7688780388,46.49544627222],[11.76889626368,46.49543835684],[11.76891448854,46.49543044146],[11.76893271341,46.49542252607],[11.76895093826,46.49541461069],[11.76896916311,46.4954066953],[11.76898659721,46.49539889874],[11.76898713446,46.4953986587],[11.76900510018,46.49539061597],[11.76902306871,46.4953825763],[11.76904103723,46.49537453663],[11.76905900574,46.49536649696],[11.76907697425,46.49535845729],[11.76909494276,46.49535041761],[11.76911291126,46.49534237793],[11.76913087975,46.49533433824],[11.76914884824,46.49532629856],[11.76916681672,46.49531825887],[11.76918478937,46.49531022342],[11.76919719492,46.49530441269],[11.76920275676,46.49530180629],[11.76921595616,46.49529562272],[11.76922072406,46.49529338918],[11.76923471818,46.49528683356],[11.76923869143,46.49528497227],[11.76925348019,46.49527804439],[11.76925665879,46.49527655536],[11.76927224219,46.49526925523],[11.76927462614,46.49526813845],[11.76929100419,46.49526046605],[11.76929259349,46.49525972154],[11.76930976618,46.49525167688],[11.76931056087,46.49525130465],[11.76932852817,46.4952428877],[11.76934720743,46.49523349507],[11.76936588669,46.49522410244],[11.76938456594,46.49521470981],[11.76940324519,46.49520531717],[11.76942192443,46.49519592453],[11.76944060366,46.49518653189],[11.76945928288,46.49517713924],[11.7694779621,46.49516774659],[11.76949664132,46.49515835394],[11.76951532052,46.49514896128],[11.76953399972,46.49513956863],[11.76955267892,46.49513017597],[11.76957092436,46.49512038511],[11.7695891698,46.49511059425],[11.76960741523,46.49510080339],[11.76962566065,46.49509101253],[11.76964390607,46.49508122167],[11.76966215148,46.4950714308],[11.76968039689,46.49506163993],[11.76969864229,46.49505184905],[11.76971688768,46.49504205818],[11.76973513306,46.4950322673],[11.76975337844,46.49502247641],[11.76977162381,46.49501268553],[11.76978941765,46.495002506],[11.76980721147,46.49499232646],[11.76982500529,46.49498214693],[11.7698427991,46.49497196739],[11.76986059291,46.49496178785],[11.76987838671,46.4949516083],[11.7698961805,46.49494142875],[11.76991397429,46.4949312492],[11.76993176806,46.49492106965],[11.76994956184,46.4949108901],[11.7699673556,46.49490071054],[11.76998514936,46.49489053098],[11.77000346785,46.49487914355],[11.77002178634,46.49486775611],[11.77004010482,46.49485636867],[11.77005842329,46.49484498123],[11.77007674175,46.49483359378],[11.77009506021,46.49482220633],[11.77011337865,46.49481081888],[11.77013169709,46.49479943143],[11.77014703466,46.49479053144],[11.77016237223,46.49478163145],[11.77017770979,46.49477273145],[11.77019304734,46.49476383146],[11.77021038964,46.49475469612],[11.77022773193,46.49474556078],[11.77024507422,46.49473642544],[11.7702624165,46.4947272901],[11.77027828818,46.49471695806],[11.77029415986,46.49470662601],[11.77031003153,46.49469629396],[11.77032590319,46.49468596191],[11.77034013193,46.49467454535],[11.77035436066,46.49466312878],[11.77036858938,46.4946517122],[11.7703828181,46.49464029563],[11.7703952494,46.49462791849],[11.7704076807,46.49461554135],[11.77042011199,46.49460316422],[11.77043254328,46.49459078707],[11.77044304218,46.49457758376],[11.77045354107,46.49456438044],[11.77046403996,46.49455117712],[11.77047453885,46.4945379738],[11.77048299136,46.49452408766],[11.77049144386,46.49451020151],[11.77049989636,46.49449631537],[11.77050834886,46.49448242923],[11.77051466321,46.49446801103],[11.77052097756,46.49445359284],[11.77052729191,46.49443917464],[11.77053360625,46.49442475645],[11.77053720027,46.49441061683],[11.77054079429,46.49439647722],[11.77054301573,46.49438048217],[11.77054523717,46.49436448711],[11.7705474586,46.49434849205],[11.77054968004,46.49433249699],[11.7705535711,46.49431902214],[11.77055746216,46.49430554729],[11.77056343635,46.4942934785],[11.77056349422,46.4942933616],[11.77056941054,46.49428140972],[11.77056952628,46.49428117591],[11.77057538472,46.49426934094],[11.77058414908,46.49425534664],[11.77059291149,46.49424135189],[11.77060166856,46.49422735554],[11.77060172167,46.49422727082],[11.77061043631,46.49421336238],[11.77062070487,46.49419843106],[11.77063097344,46.49418349974],[11.77064124199,46.49416856841],[11.77065151055,46.49415363709],[11.77065782871,46.49414444995],[11.77066177909,46.49413870576],[11.77067204763,46.49412377443],[11.77068371154,46.49410934019],[11.77069537544,46.49409490594],[11.77070703934,46.49408047169],[11.77071660344,46.49406918339],[11.77072616753,46.49405789509],[11.77073573162,46.49404660679],[11.7707452957,46.49403531849],[11.77075485978,46.49402403019],[11.7707596443,46.49401838311],[11.77076442385,46.49401274189],[11.7707783392,46.49399803606],[11.77079225455,46.49398333022],[11.77080616988,46.49396862439],[11.77082008521,46.49395391855],[11.77083438342,46.49394066238],[11.77084868163,46.4939274062],[11.77086297983,46.49391415003],[11.77087727802,46.49390089385],[11.77088651569,46.4938923294],[11.7708915762,46.49388763768],[11.77090587438,46.4938743815],[11.77092140023,46.49386180125],[11.77093692606,46.49384922101],[11.77095245189,46.49383664077],[11.77096502766,46.49382686214],[11.77097760343,46.4938170835],[11.7709901792,46.49380730487],[11.77100275496,46.49379752623],[11.77101533071,46.4937877476],[11.77102162185,46.49378285574],[11.77102790647,46.49377796896],[11.77103575307,46.49377244329],[11.77104571716,46.49376542645],[11.77106352785,46.49375288394],[11.77108133852,46.49374034143],[11.77109914919,46.49372779891],[11.77111692487,46.49371672978],[11.77113470054,46.49370566065],[11.7711524762,46.49369459152],[11.77117025185,46.49368352238],[11.77118173622,46.49367637091],[11.7711880275,46.49367245325],[11.77120580313,46.49366138411],[11.77122459133,46.49365114366],[11.77124337952,46.49364090321],[11.7712621677,46.49363066276],[11.7712771308,46.49362284903],[11.77129209388,46.49361503531],[11.77130705697,46.49360722158],[11.77132202005,46.49359940785],[11.77133698312,46.49359159412],[11.77134583846,46.49358696985],[11.77135194619,46.49358378039],[11.77137317249,46.49357376907],[11.77139439878,46.49356375776],[11.77141562507,46.49355374644],[11.77143685135,46.49354373511],[11.77145741804,46.49353528046],[11.77147798473,46.49352682581],[11.77149855141,46.49351837115],[11.77151911808,46.49350991648],[11.77153968475,46.49350146182],[11.77156025141,46.49349300715],[11.77158157643,46.49348550193],[11.77160290144,46.4934779967],[11.77162422645,46.49347049147],[11.77164555145,46.49346298624],[11.77166687644,46.493455481],[11.77168820143,46.49344797576],[11.77171019301,46.49344145227],[11.77173218459,46.49343492877],[11.77175417616,46.49342840526],[11.77177616772,46.49342188175],[11.77179815928,46.49341535824],[11.77182015084,46.49340883472],[11.77184271436,46.49340332101],[11.77186527787,46.4933978073],[11.77188784138,46.49339229359],[11.77191040488,46.49338677987],[11.77193296838,46.49338126615],[11.77195553188,46.49337575242],[11.77197857024,46.49337127224],[11.77200160861,46.49336679204],[11.77202464697,46.49336231185],[11.77204768532,46.49335783165],[11.77207072368,46.49335335144],[11.77209376202,46.49334887123],[11.77211717611,46.49334544384],[11.77214059019,46.49334201644],[11.77216400428,46.49333858904],[11.77218741835,46.49333516163],[11.77221083243,46.49333173422],[11.7722342465,46.4933283068],[11.77225778923,46.49332567538],[11.77228133197,46.49332304396],[11.7723048747,46.49332041253],[11.77232841743,46.49331778109],[11.77235090211,46.49331576201],[11.7723733868,46.49331374292],[11.77239587149,46.49331172383],[11.77241835617,46.49330970473],[11.77244084085,46.49330768563],[11.77246332553,46.49330566652],[11.77248581021,46.49330364741],[11.77250829488,46.4933016283],[11.77253077956,46.49329960918],[11.77255326423,46.49329759006],[11.7725757489,46.49329557093],[11.77259823357,46.4932935518],[11.77262270391,46.49329047721],[11.77264717426,46.49328740263],[11.7726716446,46.49328432804],[11.77269611494,46.49328125344],[11.77272058528,46.49327817884],[11.77274505561,46.49327510423],[11.77276952594,46.49327202962],[11.77279399627,46.493268955],[11.77281846659,46.49326588038],[11.77284270443,46.49326202622],[11.77286694227,46.49325817206],[11.77289118011,46.49325431789],[11.77291541794,46.49325046372],[11.77293965576,46.49324660954],[11.77296389358,46.49324275536],[11.7729881314,46.49323890117],[11.77301236922,46.49323504698],[11.77303660703,46.49323119279],[11.77306056032,46.49322656733],[11.77308451361,46.49322194187],[11.77310846689,46.4932173164],[11.77313242017,46.49321269093],[11.77315637345,46.49320806545],[11.77318032672,46.49320343997],[11.77320427998,46.49319881448],[11.77322823325,46.49319418899],[11.7732521865,46.49318956349],[11.77327155132,46.49318534002],[11.77329091613,46.49318111655],[11.77331028094,46.49317689307],[11.77332964575,46.4931726696],[11.77334901055,46.49316844611],[11.77336837536,46.49316422263],[11.77339246706,46.49315843745],[11.77341655876,46.49315265227],[11.77344065045,46.49314686708],[11.77346474214,46.49314108189],[11.77348751813,46.49313490236],[11.77351029412,46.49312872283],[11.7735330701,46.4931225433],[11.77355584608,46.49311636376],[11.77357862205,46.49311018422],[11.77360139802,46.49310400467],[11.77362355142,46.49309682632],[11.77364570482,46.49308964797],[11.77366785822,46.49308246962],[11.7736900116,46.49307529126],[11.77371216498,46.4930681129],[11.77373431836,46.49306093453],[11.77375575745,46.49305278708],[11.77377719654,46.49304463964],[11.77379863563,46.49303649218],[11.7738200747,46.49302834473],[11.77384151377,46.49302019726],[11.77386295283,46.4930120498],[11.77388358886,46.49300296699],[11.77390422488,46.49299388417],[11.77392486089,46.49298480135],[11.77394549689,46.49297571853],[11.77396613289,46.4929666357],[11.77398676888,46.49295755287],[11.7740065164,46.4929475723],[11.77402626391,46.49293759172],[11.77404601142,46.49292761114],[11.77406575891,46.49291763056],[11.7740855064,46.49290764997],[11.77410525388,46.49289766938],[11.77412403114,46.49288683237],[11.77414280839,46.49287599535],[11.77416158563,46.49286515833],[11.77418036286,46.49285432131],[11.77419914009,46.49284348429],[11.7742179173,46.49283264726],[11.77423564656,46.49282099868],[11.7742533758,46.49280935009],[11.77427110504,46.4927977015],[11.77428883427,46.49278605291],[11.7743065635,46.49277440431],[11.77432429271,46.49276275571],[11.77434090057,46.49275034379],[11.77435750841,46.49273793185],[11.77437411625,46.49272551992],[11.77439072408,46.49271310799],[11.7744073319,46.49270069605],[11.77442393972,46.49268828411],[11.77443935741,46.49267516023],[11.7744547751,46.49266203634],[11.77447019279,46.49264891245],[11.77448561046,46.49263578856],[11.77450102813,46.49262266467],[11.77451644579,46.49260954078],[11.77452947796,46.49259637513],[11.77454251013,46.49258320949],[11.7745555423,46.49257004385],[11.77456857445,46.4925568782],[11.7745816066,46.49254371255],[11.77459463874,46.4925305469],[11.77460749412,46.49252001199],[11.77462034948,46.49250947707],[11.77463320485,46.49249894215],[11.77465215343,46.49248694692],[11.77467110199,46.4924749517],[11.77469261126,46.49246523221],[11.77471412052,46.49245551271],[11.77473762353,46.49244832514],[11.77476112654,46.49244113756],[11.77478600381,46.49243667135],[11.77481088107,46.49243220514],[11.77483647689,46.49243057801],[11.7748620727,46.49242895089],[11.77488771242,46.49243020573],[11.77491335214,46.49243146058],[11.77493835995,46.49243556432],[11.77496336776,46.49243966806],[11.77498138364,46.49244486731],[11.77498708451,46.49244651254],[11.77501080127,46.49245335701],[11.77503260184,46.49246276181],[11.77505440242,46.49247216661],[11.77506971283,46.49247695856],[11.77507637405,46.49247904343],[11.77508502324,46.4924817505],[11.77510643089,46.49248694164],[11.77512783853,46.49249213278],[11.77514690759,46.49249563126],[11.77516597665,46.49249912973],[11.77518504572,46.4925026282],[11.77520411478,46.49250612667],[11.77522364025,46.49250808554],[11.77524316572,46.49251004442],[11.77526269119,46.49251200329],[11.77528221666,46.49251396215],[11.77530193884,46.49251435537],[11.77532166102,46.49251474859],[11.7753413832,46.49251514181],[11.77536110537,46.49251553502],[11.77538076195,46.49251435735],[11.77540041852,46.49251317969],[11.77542007509,46.49251200202],[11.77543973166,46.49251082434],[11.77545906119,46.49250809146],[11.77547839072,46.49250535857],[11.77549772024,46.49250262568],[11.77551704976,46.49249989278],[11.77553787705,46.49249468655],[11.77555870433,46.49248948031],[11.77558076751,46.49248156788],[11.77560283069,46.49247365546],[11.77562287116,46.49246483342],[11.77564291162,46.49245601139],[11.77565750846,46.49244899934],[11.77567210531,46.4924419873],[11.77568670215,46.49243497525],[11.77570129899,46.49242796319],[11.77571589582,46.49242095114],[11.77573049265,46.49241393908],[11.77574982212,46.49240564325],[11.77576915158,46.49239734742],[11.77579048292,46.49238919244],[11.77581181426,46.49238103746],[11.77583314559,46.49237288247],[11.77585447692,46.49236472747],[11.77587580824,46.49235657247],[11.77589713955,46.49234841747],[11.77591847085,46.49234026247],[11.77593980215,46.49233210746],[11.77596113344,46.49232395244],[11.77598246473,46.49231579743],[11.77600379601,46.49230764241],[11.77602512728,46.49229948738],[11.77604604174,46.49229091947],[11.7760669562,46.49228235155],[11.77608787064,46.49227378362],[11.77610878509,46.49226521569],[11.77612969952,46.49225664776],[11.77615061395,46.49224807983],[11.77617152837,46.49223951189],[11.77619244278,46.49223094395],[11.77620836755,46.4922259337],[11.77622429232,46.49222092345],[11.77624021708,46.4922159132],[11.77626250572,46.49221114781],[11.77628479436,46.49220638242],[11.77630287728,46.49220470958],[11.77632096021,46.49220303674],[11.77633904313,46.49220136389],[11.77635712606,46.49219969105],[11.77637520898,46.4921980182],[11.7763932919,46.49219634534],[11.77641246611,46.4921937598],[11.77643164032,46.49219117426],[11.77645081453,46.49218858871],[11.7764755231,46.49218439203],[11.77650023168,46.49218019535],[11.77652474171,46.49217548257],[11.77654925173,46.4921707698],[11.77656779879,46.49216652696],[11.77658634584,46.49216228413],[11.77660489289,46.49215804129],[11.7766231965,46.49215332543],[11.7766415001,46.49214860956],[11.77665618572,46.49214482585],[11.7766598037,46.49214389369],[11.77668318691,46.4921369631],[11.77670657011,46.4921300325],[11.77672290478,46.49212442005],[11.77673923943,46.49211880759],[11.77675557409,46.49211319514],[11.77677190874,46.49210758268],[11.77678824339,46.49210197021],[11.77680457803,46.49209635775],[11.77682668312,46.49208765924],[11.7768487882,46.49207896073],[11.77686527749,46.49207172183],[11.77688176678,46.49206448293],[11.77689825607,46.49205724402],[11.77691304221,46.49204986251],[11.77692782834,46.492042481],[11.77694261447,46.49203509949],[11.7769574006,46.49202771797],[11.77697218672,46.49202033645],[11.77698697284,46.49201295494],[11.77700083244,46.49200476062],[11.77701469203,46.4919965663],[11.77702855163,46.49198837198],[11.77704241122,46.49198017766],[11.7770562708,46.49197198334],[11.77707013038,46.49196378902],[11.77708297003,46.49195483712],[11.77709580968,46.49194588523],[11.77710864933,46.49193693334],[11.77712148897,46.49192798144],[11.7771343286,46.49191902954],[11.77714716823,46.49191007764],[11.7771589014,46.49190042851],[11.77717063456,46.49189077938],[11.77718236772,46.49188113024],[11.77719410088,46.49187148111],[11.77720583403,46.49186183197],[11.77721756717,46.49185218283],[11.77722811478,46.4918419015],[11.77723866238,46.49183162016],[11.77724920997,46.49182133882],[11.77725975756,46.49181105748],[11.77726622152,46.49180475669],[11.77727453357,46.49179560559],[11.77728593091,46.49178305775],[11.77729732825,46.49177050991],[11.77730872558,46.49175796207],[11.77731801652,46.49174711782],[11.77732730745,46.49173627357],[11.77733659839,46.49172542932],[11.77738622684,46.49166509559],[11.77743585518,46.49160476184],[11.77744237341,46.49159808646],[11.77745868153,46.49158418324],[11.77747498964,46.49157028001],[11.77749129775,46.49155637678],[11.77750760584,46.49154247356],[11.77752561099,46.49152960775],[11.77754361612,46.49151674193],[11.77756162125,46.49150387612],[11.77757962637,46.4914910103],[11.77759919088,46.49147928064],[11.77761875538,46.49146755099],[11.77763831988,46.49145582132],[11.77765788436,46.49144409166],[11.77767885807,46.49143358798],[11.77769983176,46.4914230843],[11.77772080545,46.49141258062],[11.77774177913,46.49140207693],[11.77776400194,46.49139287962],[11.77778622474,46.49138368231],[11.77780844753,46.49137448499],[11.77783067032,46.49136528767],[11.77785397185,46.49135746702],[11.77787727337,46.49134964636],[11.77790057489,46.4913418257],[11.7779238764,46.49133400503],[11.77794807858,46.49132762094],[11.77797228075,46.49132123684],[11.77799648291,46.49131485273],[11.77802068507,46.49130846862],[11.7780456024,46.49130356969],[11.77807051973,46.49129867075],[11.77809543705,46.49129377181],[11.77812035437,46.49128887286],[11.77814579659,46.49128549702],[11.77817123881,46.49128212117],[11.77819668102,46.49127874532],[11.77822212323,46.49127536946],[11.77824789488,46.49127354238],[11.77827366653,46.49127171529],[11.77829943818,46.4912698882],[11.77832520983,46.4912680611],[11.77835111422,46.49126779679],[11.77837701861,46.49126753247],[11.778402923,46.49126726815],[11.77842882738,46.49126700382],[11.77845017992,46.49126746845],[11.77847153245,46.49126793308],[11.77849288498,46.4912683977],[11.77851253385,46.49127030145],[11.77853218272,46.4912722052],[11.77855006865,46.49127636223],[11.77856795458,46.49128051926],[11.77858777728,46.49128695865],[11.77860759998,46.49129339804],[11.77862742269,46.49129983742],[11.77864724541,46.49130627681],[11.77866691035,46.49131109498],[11.7786865753,46.49131591314],[11.77870624025,46.49132073131],[11.77872590521,46.49132554946],[11.77874557016,46.49133036762],[11.77876523513,46.49133518577],[11.77878530654,46.49133912373],[11.77880537795,46.49134306168],[11.77882544937,46.49134699963],[11.77884552079,46.49135093758],[11.77886559222,46.49135487552],[11.77888566364,46.49135881346],[11.7789075516,46.49136212904],[11.77892943955,46.49136544462],[11.77895132751,46.4913687602],[11.77897321547,46.49137207577],[11.77899739771,46.49137492133],[11.77902157995,46.49137776687],[11.7790457622,46.49138061242],[11.77906994444,46.49138345795],[11.7790942739,46.49138562512],[11.77911860335,46.49138779229],[11.77914293281,46.49138995945],[11.77916726227,46.4913921266],[11.7791895967,46.4913933806],[11.77921193114,46.4913946346],[11.77923426557,46.49139588859],[11.77925660001,46.49139714257],[11.77927746163,46.49139743418],[11.77929832324,46.49139772579],[11.77931918486,46.49139801739],[11.77934004606,46.4913983093],[11.77936090726,46.49139860121],[11.77938176846,46.49139889311],[11.77940202503,46.49139900216],[11.7794222816,46.4913991112],[11.77944253818,46.49139922025],[11.77946279475,46.49139932928],[11.77948481769,46.49139721463],[11.77950684063,46.49139509998],[11.77952175269,46.49139118723],[11.77953666474,46.49138727449],[11.77955963112,46.49137902535],[11.77958259749,46.49137077622],[11.77960556386,46.49136252708],[11.77962383624,46.49135766768],[11.77964210863,46.49135280828],[11.77966038101,46.49134794888],[11.77967865339,46.49134308948],[11.77969908634,46.49133861381],[11.77971951928,46.49133413813],[11.77973995223,46.49132966245],[11.77976038517,46.49132518676],[11.7797811272,46.49132145101],[11.77980186924,46.49131771526],[11.77982261127,46.49131397951],[11.77984335329,46.49131024375],[11.77986256393,46.49130762795],[11.77988177457,46.49130501214],[11.77990098521,46.49130239634],[11.77992019584,46.49129978052],[11.77993830693,46.49129831609],[11.77995641803,46.49129685166],[11.77997452912,46.49129538722],[11.77999264021,46.49129392278],[11.7800107513,46.49129245834],[11.78002886238,46.49129099389],[11.78004842813,46.4912904741],[11.78006799388,46.4912899543],[11.78008755962,46.4912894345],[11.78010712537,46.49128891469],[11.78012855598,46.49128924053],[11.78014998659,46.49128956637],[11.78017141721,46.4912898922],[11.78019284782,46.49129021803],[11.78021422482,46.49129131309],[11.78023560181,46.49129240815],[11.78025697881,46.4912935032],[11.78027835581,46.49129459825],[11.78029775937,46.49129641114],[11.78031716293,46.49129822402],[11.78033656649,46.4913000369],[11.78035597005,46.49130184977],[11.7803737944,46.4913045068],[11.78039161876,46.49130716382],[11.78040944311,46.49130982084],[11.78042726747,46.49131247786],[11.78044509182,46.49131513487],[11.78046291618,46.49131779188],[11.78048036383,46.49132145167],[11.78049781148,46.49132511145],[11.78051525913,46.49132877123],[11.78053270724,46.49133243129],[11.78055015534,46.49133609136],[11.78056760345,46.49133975142],[11.78058455673,46.49134438922],[11.78060151001,46.49134902703],[11.78061846329,46.49135366483],[11.78063541658,46.49135830263],[11.78065236987,46.49136294043],[11.78066932316,46.49136757823],[11.78069001787,46.49137394001],[11.7807107126,46.49138030179],[11.78073140732,46.49138666357],[11.7807493971,46.49139387462],[11.78076738689,46.49140108566],[11.78078247773,46.49140957055],[11.78079756857,46.49141805544],[11.78081155328,46.4914276555],[11.78082553798,46.49143725556],[11.78083952269,46.49144685562],[11.78085584931,46.49145946151],[11.78087217593,46.49147206739],[11.78088850256,46.49148467327],[11.7809048292,46.49149727915],[11.78091929246,46.49151092758],[11.78093375574,46.49152457601],[11.78094821902,46.49153822443],[11.78096268231,46.49155187285],[11.78097514297,46.49156643311],[11.78098760364,46.49158099337],[11.78100006431,46.49159555363],[11.78101252499,46.49161011388],[11.78102286383,46.491625446],[11.78103320268,46.49164077812],[11.78104354153,46.49165611023],[11.78105388039,46.49167144235],[11.78106199803,46.49168739934],[11.78107011569,46.49170335633],[11.78107823334,46.49171931333],[11.78108635101,46.49173527032],[11.78109216962,46.49175169951],[11.78109798824,46.4917681287],[11.78110380687,46.49178455789],[11.7811096255,46.49180098707],[11.78111308944,46.49181773029],[11.78111655339,46.4918344735],[11.78112001734,46.49185121672],[11.78112348129,46.49186795993],[11.78112455731,46.4918848571],[11.78112563333,46.49190175427],[11.78112670934,46.49191865145],[11.78112778536,46.49193554862],[11.7811264632,46.49195243732],[11.78112514104,46.49196932602],[11.78112381887,46.49198621472],[11.78112249671,46.49200310342],[11.78111878862,46.49201982181],[11.78111508054,46.49203654019],[11.78111137245,46.49205325857],[11.78110766436,46.49206997695],[11.78110160647,46.49208636461],[11.78109554858,46.49210275226],[11.78108949068,46.49211913992],[11.78108343278,46.49213552757],[11.78104751478,46.49235567232]]} \ No newline at end of file diff --git a/GeoConverterTests/Files/216052.kml b/GeoConverterTests/Files/216052.kml new file mode 100644 index 0000000..0a2bdce --- /dev/null +++ b/GeoConverterTests/Files/216052.kml @@ -0,0 +1,24 @@ + + + + + + + + 216052 + + + + 3-Tre + 216052 + + + + + 11.75153885558,46.49703635675 11.75174451841,46.49698132919 11.75119391865,46.49709995753 11.7511695832,46.49710130233 11.75114524775,46.49710264711 11.75112091229,46.4971039919 11.75109657684,46.49710533667 11.75107254979,46.4971083236 11.75104852273,46.49711131053 11.75102449568,46.49711429744 11.75100046862,46.49711728436 11.75097698174,46.49712188461 11.75095349486,46.49712648485 11.75093000798,46.49713108509 11.75090652109,46.49713568533 11.75088380096,46.49714185452 11.75086108082,46.49714802371 11.75083836067,46.4971541929 11.75081564052,46.49716036208 11.7507939063,46.49716804071 11.75077217206,46.49717571934 11.75075043783,46.49718339796 11.75072870358,46.49719107658 11.75070816493,46.49720019058 11.75068762627,46.49720930457 11.7506670876,46.49721841856 11.75064654892,46.49722753254 11.75062740397,46.49723799398 11.750608259,46.49724845542 11.75058911403,46.49725891685 11.75056996905,46.49726937828 11.75055240247,46.49728108625 11.75053483589,46.49729279422 11.7505172693,46.49730450219 11.75049970271,46.49731621015 11.75048388398,46.49732905171 11.75046806524,46.49734189327 11.75045224649,46.49735473482 11.75043642774,46.49736757638 11.75042250945,46.49738142765 11.75040859116,46.49739527892 11.75039467285,46.49740913019 11.75038075455,46.49742298146 11.75036887097,46.49743770882 11.75035698739,46.49745243619 11.75034510381,46.49746716355 11.75033322021,46.49748189092 11.750323486,46.49749735231 11.75031375177,46.4975128137 11.75030401755,46.49752827509 11.75029428331,46.49754373649 11.75028679236,46.49755978276 11.75027930141,46.49757582902 11.75027181045,46.49759187529 11.75026431948,46.49760792156 11.75026571198,46.4976203452 11.75026710447,46.49763276884 11.75026849697,46.49764519248 11.75026988946,46.49765761612 11.75027128196,46.49767003976 11.75027267446,46.4976824634 11.75027239232,46.49769492267 11.75027211018,46.49770738195 11.75027182805,46.49771984123 11.75027154591,46.4977323005 11.75027126378,46.49774475978 11.75027098164,46.49775721906 11.7502690273,46.49776960655 11.75026707296,46.49778199405 11.75026511862,46.49779438155 11.75026316428,46.49780676904 11.75026120994,46.49781915654 11.7502592556,46.49783154403 11.7502556459,46.49784375294 11.7502520362,46.49785596186 11.75024842649,46.49786817077 11.75024481679,46.49788037968 11.75024120708,46.4978925886 11.75023759738,46.49790479751 11.75023236343,46.49791672258 11.75022712948,46.49792864764 11.75022189553,46.49794057271 11.75021666158,46.49795249778 11.75021142763,46.49796442285 11.75020619367,46.49797634792 11.7501993806,46.49798788633 11.75019256753,46.49799942473 11.75018575445,46.49801096314 11.75017894137,46.49802250155 11.75017212829,46.49803403996 11.75016531521,46.49804557837 11.75015698174,46.49805663063 11.75014864828,46.4980676829 11.75014031481,46.49807873517 11.75013198134,46.49808978744 11.75012364786,46.4981008397 11.75011531438,46.49811189197 11.75010553237,46.49812236281 11.75009575036,46.49813283364 11.75008596834,46.49814330448 11.75007618632,46.49815377531 11.75006640429,46.49816424614 11.75005662226,46.49817471698 11.75004547604,46.49818451611 11.75003432981,46.49819431523 11.75002318358,46.49820411436 11.75001203735,46.49821391348 11.75000089111,46.4982237126 11.74998974486,46.49823351173 11.74997733052,46.49824255466 11.74996491618,46.49825159759 11.74995250183,46.49826064052 11.74994008748,46.49826968344 11.74992767312,46.49827872637 11.74991525876,46.49828776929 11.74990168333,46.49829597806 11.7498881079,46.49830418683 11.74987453247,46.49831239559 11.74986095703,46.49832060435 11.74984738159,46.49832881312 11.74983380614,46.49833702188 11.74981918667,46.4983443257 11.7498045672,46.49835162953 11.74978994772,46.49835893335 11.74977532824,46.49836623718 11.74976070876,46.498373541 11.74974608927,46.49838084482 11.74972879578,46.49838767898 11.74971150228,46.49839451315 11.74969420878,46.49840134731 11.74967691527,46.49840818147 11.74965962176,46.49841501562 11.74964232824,46.49842184977 11.74962587723,46.49842961274 11.74960942622,46.49843737571 11.7495929752,46.49844513868 11.74957652418,46.49845290164 11.74956007315,46.4984606646 11.74954362212,46.49846842756 11.74952811797,46.49847707008 11.74951261381,46.49848571261 11.74949710965,46.49849435512 11.74948160549,46.49850299764 11.74946610132,46.49851164016 11.74945059714,46.49852028267 11.74943613822,46.49852974992 11.74942167929,46.49853921716 11.74940722035,46.4985486844 11.74939276141,46.49855815164 11.74937830247,46.49856761888 11.74936384352,46.49857708612 11.74935052156,46.49858731802 11.74933719959,46.49859754993 11.74932387761,46.49860778183 11.74931055564,46.49861801373 11.74929723365,46.49862824562 11.74928391167,46.49863847752 11.74927181119,46.49864940917 11.74925971071,46.49866034081 11.74924761022,46.49867127246 11.74923550973,46.4986822041 11.74922340923,46.49869313574 11.74921130873,46.49870406738 11.74920050651,46.49871562942 11.74918970429,46.49872719145 11.74917890207,46.49873875348 11.74916809984,46.49875031552 11.7491572976,46.49876187755 11.74914649536,46.49877343958 11.74913705995,46.49878555864 11.74912762453,46.49879767771 11.7491181891,46.49880979678 11.74910875367,46.49882191584 11.74909931824,46.49883403491 11.7490898828,46.49884615397 11.74908187406,46.49885875319 11.7490738653,46.4988713524 11.74906585655,46.49888395161 11.74905784779,46.49889655082 11.74904983903,46.49890915003 11.74904183026,46.49892174924 11.749035299,46.49893474866 11.74902876773,46.49894774808 11.74902223647,46.4989607475 11.74901570519,46.49897374691 11.74900917392,46.49898674633 11.74900264264,46.49899974575 11.74899763031,46.4990130629 11.74899261798,46.49902638006 11.74898760564,46.49903969721 11.7489825933,46.49905301436 11.74897758096,46.49906633151 11.74897256861,46.49907964867 11.74896910702,46.49909319906 11.74896564542,46.49910674946 11.74896218383,46.49912029985 11.74895872223,46.49913385024 11.74895526063,46.49914740064 11.74895179903,46.49916095103 11.74894991014,46.4991746487 11.74894802125,46.49918834636 11.74894613236,46.49920204403 11.74894424347,46.49921574169 11.74894235458,46.49922943935 11.74894046569,46.49924313702 11.74893682751,46.49925787097 11.74893318933,46.49927260493 11.74892955115,46.49928733888 11.74892591296,46.49930207283 11.74892227477,46.49931680679 11.74891863659,46.49933154074 11.7489166449,46.49934642395 11.74891465322,46.49936130715 11.74891266153,46.49937619036 11.74891066984,46.49939107357 11.74890867815,46.49940595677 11.74890668646,46.49942083998 11.74890635301,46.49943578482 11.74890601955,46.49945072967 11.74890568609,46.49946567452 11.74890535263,46.49948061937 11.74890501918,46.49949556421 11.74890468572,46.49951050906 11.74890601246,46.49952542758 11.7489073392,46.49954034609 11.74890866595,46.49955526461 11.74890999269,46.49957018312 11.74891131943,46.49958510163 11.74891264618,46.49960002015 11.74891562532,46.49961482451 11.74891860446,46.49962962887 11.7489215836,46.49964443323 11.74892456274,46.49965923759 11.74892754188,46.49967404196 11.74893052103,46.49968884632 11.74893513504,46.49970344938 11.74893974904,46.49971805244 11.74894436305,46.4997326555 11.74894897707,46.49974725856 11.74895359108,46.49976186162 11.7489582051,46.49977646468 11.74896442682,46.49979078048 11.74897064854,46.49980509627 11.74897687027,46.49981941207 11.74898309199,46.49983372787 11.74898931373,46.49984804366 11.74899553546,46.49986235946 11.74900332828,46.49987630372 11.7490111211,46.49989024797 11.74901891392,46.49990419223 11.74902670675,46.49991813649 11.74903449958,46.49993208075 11.74903744726,46.49993735524 11.74904229241,46.499946025 11.74905161046,46.49995951564 11.74906092851,46.49997300628 11.74907024656,46.49998649691 11.74907956462,46.49999998754 11.74908888268,46.50001347818 11.74909820075,46.50002696881 11.74910898918,46.50003992641 11.74911977761,46.500052884 11.74913056605,46.5000658416 11.74914135449,46.50007879919 11.74915214294,46.50009175678 11.74916293139,46.50010471437 11.74917512669,46.50011706265 11.74918732201,46.50012941093 11.74919951732,46.5001417592 11.74921171265,46.50015410748 11.74922390798,46.50016645575 11.74923610331,46.50017880402 11.74924963371,46.50019047029 11.74926316411,46.50020213656 11.74927669453,46.50021380282 11.74929022494,46.50022546909 11.74930375537,46.50023713535 11.7493172858,46.50024880161 11.74933207164,46.50025971719 11.7493468575,46.50027063277 11.74936164336,46.50028154835 11.74937642922,46.50029246392 11.74939121509,46.50030337949 11.74940600097,46.50031429506 11.74942195523,46.5003243957 11.74943790949,46.50033449633 11.74945386376,46.50034459696 11.74946981804,46.50035469759 11.74948577232,46.50036479822 11.7495017266,46.50037489884 11.74952560764,46.50037940726 11.74954948868,46.50038391567 11.74964257821,46.50040695398 11.74973566782,46.50042999221 11.74982875751,46.50045303037 11.74992184727,46.50047606844 11.75000748073,46.50048729086 11.75009311422,46.50049851321 11.75017874775,46.50050973549 11.7502643813,46.50052095771 11.75035001489,46.50053217986 11.75043564852,46.50054340195 11.75052442223,46.50055235479 11.75061319597,46.50056130756 11.75070196973,46.50057026026 11.75079074353,46.50057921289 11.75088249636,46.50057397529 11.75097424917,46.50056873763 11.75106600196,46.50056349988 11.75115775473,46.50055826207 11.75124950747,46.50055302418 11.7513412602,46.50054778622 11.7513630156,46.50054600839 11.751384771,46.50054423056 11.751408378,46.50054095212 11.75143198499,46.50053767368 11.75145559198,46.50053439524 11.75147620195,46.50053064441 11.75149681191,46.50052689359 11.75151742186,46.50052314276 11.75154057565,46.50051820985 11.75156372944,46.50051327693 11.75158688322,46.50050834401 11.75160632785,46.50050373108 11.75162577248,46.50049911815 11.75164521711,46.50049450522 11.75166466173,46.50048989228 11.75168410635,46.50048527933 11.75170355096,46.50048066639 11.75172299557,46.50047605344 11.75174244018,46.50047144049 11.75176188479,46.50046682753 11.75178132939,46.50046221457 11.75180077399,46.50045760161 11.75182021858,46.50045298865 11.75183966317,46.50044837568 11.75185910776,46.50044376271 11.75187855234,46.50043914973 11.75189799692,46.50043453675 11.75191773618,46.50043068006 11.75193747544,46.50042682336 11.7519572147,46.50042296666 11.75197695395,46.50041910996 11.7520006427,46.50041548131 11.75202433144,46.50041185265 11.75204802018,46.50040822399 11.75207114227,46.50040491643 11.75209426435,46.50040160886 11.75211738642,46.50039830129 11.75214050849,46.50039499371 11.75216363056,46.50039168613 11.75218675263,46.50038837855 11.75220987469,46.50038507096 11.75223299675,46.50038176336 11.75225611881,46.50037845576 11.75227553451,46.50037665302 11.7522759908,46.50037661078 11.75229586279,46.5003747658 11.75231573478,46.50037292082 11.75233339261,46.50037228711 11.75235105044,46.5003716534 11.75236870796,46.50037101973 11.75239029824,46.50037175553 11.7524118882,46.50037249136 11.75243347816,46.50037322718 11.75245598322,46.50037554803 11.75247848828,46.50037786888 11.75250099334,46.50038018972 11.75252453242,46.500384107 11.75254807151,46.50038802427 11.75257161059,46.50039194154 11.75259020757,46.5003961043 11.75260880454,46.50040026705 11.75262740152,46.5004044298 11.7526459985,46.50040859255 11.75266504421,46.50041381446 11.75268408993,46.50041903637 11.75270313564,46.50042425827 11.75272218136,46.50042948017 11.75274282903,46.50043602743 11.75276347671,46.50044257469 11.75278412439,46.50044912195 11.75280477207,46.5004556692 11.75282721871,46.50046356172 11.75284966535,46.50047145423 11.75287211199,46.50047934675 11.75289455865,46.50048723925 11.7529151567,46.50049495803 11.75293575477,46.50050267681 11.75295635284,46.50051039558 11.75297695091,46.50051811435 11.75299754899,46.50052583311 11.75301814708,46.50053355187 11.75303322415,46.50053967857 11.75304830122,46.50054580526 11.7530633783,46.50055193195 11.7530785506,46.50055892723 11.75309372291,46.50056592251 11.75310889523,46.50057291779 11.75312430212,46.50058084512 11.75313970902,46.50058877244 11.75315511592,46.50059669976 11.75317100754,46.5006056874 11.75318689917,46.50061467505 11.7532027908,46.50062366269 11.75321833207,46.50063344351 11.75323387334,46.50064322432 11.75324941462,46.50065300514 11.7532649559,46.50066278595 11.75328049719,46.50067256677 11.75329603848,46.50068234757 11.75331096571,46.50069256758 11.75332589294,46.50070278759 11.75334082018,46.5007130076 11.75335574742,46.5007232276 11.75337067467,46.5007334476 11.75338560193,46.5007436676 11.75340052919,46.5007538876 11.75341545645,46.50076410759 11.75343038373,46.50077432759 11.753445311,46.50078454758 11.75346023829,46.50079476756 11.75347516557,46.50080498755 11.75348791626,46.5008133153 11.75350066695,46.50082164305 11.75351341765,46.5008299708 11.75352616835,46.50083829855 11.75353891905,46.50084662629 11.75355166976,46.50085495404 11.75356552533,46.50086311187 11.75357938091,46.50087126971 11.75359323649,46.50087942754 11.75360709207,46.50088758538 11.75362094766,46.50089574321 11.75363480326,46.50090390104 11.75365444637,46.50091380253 11.75367408949,46.50092370402 11.75369373261,46.50093360551 11.75371337575,46.50094350699 11.75373027282,46.50095075056 11.7537471699,46.50095799414 11.75376406698,46.5009652377 11.75378096406,46.50097248127 11.75379786115,46.50097972483 11.75381475825,46.5009869684 11.75383165535,46.50099421195 11.75384855245,46.50100145551 11.75386787037,46.50100876295 11.75388718829,46.50101607039 11.75390650622,46.50102337783 11.75392582415,46.50103068527 11.75394514208,46.5010379927 11.75396446002,46.50104530012 11.75398377797,46.50105260755 11.75400309592,46.50105991497 11.754024746,46.50106732307 11.75404639609,46.50107473118 11.75406804618,46.50108213928 11.75408969628,46.50108954738 11.75411134638,46.50109695547 11.75413299649,46.50110436356 11.75415464661,46.50111177164 11.75417629673,46.50111917972 11.75419889559,46.50112644357 11.75422149445,46.50113370741 11.75424409333,46.50114097124 11.7542666922,46.50114823507 11.75428929109,46.5011554989 11.75431188998,46.50116276272 11.75433448887,46.50117002654 11.75435708777,46.50117729035 11.75437968668,46.50118455416 11.75440228559,46.50119181796 11.75442488451,46.50119908176 11.75444748343,46.50120634556 11.75447102844,46.50121379443 11.75449457346,46.50122124331 11.75451811848,46.50122869217 11.7545416635,46.50123614104 11.75456520854,46.50124358989 11.75458875358,46.50125103875 11.75461229862,46.50125848759 11.75463584367,46.50126593644 11.75465938873,46.50127338527 11.75468293379,46.50128083411 11.75470647886,46.50128828293 11.75473002394,46.50129573175 11.75475356902,46.50130318057 11.75477711411,46.50131062938 11.75480065921,46.50131807819 11.75482420431,46.50132552699 11.75484699301,46.50133229785 11.75486978172,46.5013390687 11.75489257043,46.50134583954 11.75491535915,46.50135261038 11.75493814787,46.50135938121 11.7549609366,46.50136615204 11.75498176605,46.50137196086 11.75500259551,46.50137776968 11.75502279496,46.5013834028 11.75502342497,46.50138357849 11.75504425444,46.5013893873 11.75506508391,46.5013951961 11.75508591338,46.5014010049 11.75510650407,46.50140629861 11.75512709477,46.50141159231 11.75514768547,46.50141688601 11.75516827617,46.50142217971 11.75518886688,46.5014274734 11.75520945759,46.50143276709 11.75522905707,46.50143731582 11.75524865655,46.50144186455 11.75526825604,46.50144641328 11.75528785553,46.501450962 11.75530745502,46.50145551072 11.75532705452,46.50146005944 11.75534592432,46.50146392368 11.75536479412,46.50146778792 11.75538366393,46.50147165216 11.75540253374,46.50147551639 11.75542140355,46.50147938062 11.75544027337,46.50148324485 11.75545855938,46.50148645408 11.7554768454,46.5014896633 11.75549513142,46.50149287252 11.75551341744,46.50149608174 11.75553170346,46.50149929095 11.75554998949,46.50150250016 11.75557262214,46.5015059093 11.7555952548,46.50150931844 11.75561788746,46.50151272757 11.75564052012,46.50151613669 11.75566315278,46.50151954581 11.75568578545,46.50152295493 11.75570779417,46.50152583066 11.75572980288,46.50152870639 11.7557518116,46.50153158211 11.75577382033,46.50153445783 11.75579582905,46.50153733355 11.75581783778,46.50154020926 11.75583922573,46.50154255199 11.75586061368,46.50154489473 11.75588200163,46.50154723746 11.75590338959,46.50154958018 11.75592477755,46.5015519229 11.75594616551,46.50155426562 11.75596693124,46.50155607519 11.75598769698,46.50155788476 11.75600314186,46.5015725132 11.75602922846,46.50159080416 11.75610458435,46.50165868391 11.75627055345,46.50169512944 11.75641067943,46.50168562706 11.75645679852,46.50165157562 11.7564842946,46.50162484924 11.7565031776,46.5016049141 11.75657342899,46.50157427838 11.7565943991,46.50157314829 11.7566153692,46.50157201819 11.7566363393,46.50157088809 11.7566573094,46.50156975798 11.7566782795,46.50156862787 11.7566992496,46.50156749776 11.75672071284,46.50156548048 11.75674217607,46.5015634632 11.7567636393,46.50156144592 11.75678510253,46.50155942863 11.75680656576,46.50155741134 11.75682802899,46.50155539404 11.75684949221,46.50155337674 11.75687095544,46.50155135944 11.75689267612,46.50154847703 11.7569143968,46.50154559461 11.75693611748,46.50154271219 11.75695783816,46.50153982977 11.75697955883,46.50153694734 11.7570012795,46.50153406491 11.75702300017,46.50153118247 11.75704472084,46.50152830003 11.75706643508,46.50152458739 11.75708814931,46.50152087474 11.75710986355,46.50151716209 11.75713157778,46.50151344943 11.757153292,46.50150973677 11.75717500623,46.5015060241 11.75719672045,46.50150231144 11.75721843466,46.50149859876 11.7572398821,46.50149409967 11.75733582164,46.50159215163 11.75747166766,46.50160962774 11.7576008626,46.50163900707 11.75772084242,46.5016203639 11.75778487391,46.50158491 11.75779853423,46.50155314475 11.75780745027,46.50150671625 11.7577839659,46.50140160566 11.75779342126,46.50134788964 11.75781238739,46.50134142502 11.75783135352,46.5013349604 11.75785031964,46.50132849577 11.75786928576,46.50132203114 11.75789008469,46.50131387838 11.75791088362,46.50130572561 11.75793168255,46.50129757284 11.75795248146,46.50128942006 11.75797305862,46.50128030412 11.75799363576,46.50127118817 11.7580142129,46.50126207222 11.75803479003,46.50125295626 11.75805518094,46.50124286145 11.75807557184,46.50123276664 11.75809596273,46.50122267183 11.75811635361,46.50121257701 11.75813660341,46.50120148104 11.75815685319,46.50119038506 11.75817710297,46.50117928909 11.75819735274,46.50116819311 11.75821077805,46.50116011885 11.75822420336,46.5011520446 11.75823762866,46.50114397034 11.75825105395,46.50113589608 11.75826447924,46.50112782182 11.75827790453,46.50111974755 11.75829131399,46.50111096223 11.75830472345,46.5011021769 11.7583181329,46.50109339156 11.75833154234,46.50108460623 11.75834495178,46.5010758209 11.75835836122,46.50106703556 11.75837180586,46.50105750588 11.7583852505,46.50104797619 11.75838604135,46.50104741563 11.75839869514,46.50103844651 11.75841213977,46.50102891682 11.75842558439,46.50101938714 11.75843902901,46.50100985745 11.75845258309,46.50099953088 11.75846613717,46.50098920432 11.75847969124,46.50097887775 11.75849324531,46.50096855119 11.75850679937,46.50095822462 11.75852035342,46.50094789805 11.75853253433,46.50093802123 11.75854471524,46.50092814441 11.75855689615,46.50091826758 11.75856907705,46.50090839076 11.75858125794,46.50089851393 11.75859343883,46.50088863711 11.75860587638,46.50087799938 11.75861831392,46.50086736165 11.75863075146,46.50085672391 11.75864318899,46.50084608618 11.75865562652,46.50083544844 11.75866806404,46.50082481071 11.75868088174,46.50081330711 11.75869369943,46.50080180351 11.75870651711,46.50079029991 11.75871933478,46.50077879631 11.75873215246,46.5007672927 11.75874497012,46.5007557891 11.75875841055,46.50074320224 11.75877185098,46.50073061537 11.75878529139,46.50071802851 11.75879873181,46.50070544164 11.75881217221,46.50069285477 11.75882561261,46.5006802679 11.75884047729,46.50066571873 11.75885534197,46.50065116955 11.75887020663,46.50063662037 11.75888507129,46.50062207119 11.75889993594,46.50060752201 11.75891480059,46.50059297283 11.75892966522,46.50057842364 11.75894452985,46.50056387445 11.75895939447,46.50054932526 11.75897321636,46.50053531992 11.75898703824,46.50052131458 11.75900086012,46.50050730924 11.75901468199,46.50049330389 11.75902850386,46.50047929854 11.75904232571,46.50046529319 11.75905614756,46.50045128784 11.7590699694,46.50043728249 11.75908379124,46.50042327714 11.75909761307,46.50040927178 11.75911143489,46.50039526643 11.7591252567,46.50038126107 11.75913907851,46.50036725571 11.75915290031,46.50035325035 11.7591667221,46.50033924498 11.75918054389,46.50032523962 11.75919436567,46.50031123425 11.75920818744,46.50029722889 11.75922200921,46.50028322352 11.75923583096,46.50026921815 11.75925072461,46.50025447609 11.75926561824,46.50023973403 11.75928051187,46.50022499198 11.75929540549,46.50021024992 11.7593102991,46.50019550785 11.75932519271,46.50018076579 11.7593400863,46.50016602372 11.75935497989,46.50015128166 11.75936724473,46.50013872253 11.75937950957,46.5001261634 11.7593917744,46.50011360428 11.75940403923,46.50010104515 11.75941630405,46.50008848602 11.75942856886,46.50007592688 11.75944134629,46.50006150157 11.75945412372,46.50004707626 11.75946690115,46.50003265094 11.75947967856,46.50001822562 11.75949245597,46.5000038003 11.75950523337,46.49998937498 11.75951709676,46.49997499764 11.75952896014,46.4999606203 11.75954082351,46.49994624296 11.75955268688,46.49993186562 11.75956455025,46.49991748828 11.7595764136,46.49990311093 11.7595873591,46.49988939266 11.75959830459,46.49987567439 11.75960925008,46.49986195611 11.75962019557,46.49984823784 11.75963114104,46.49983451956 11.75964208651,46.49982080128 11.75965303198,46.49980708301 11.75966397744,46.49979336473 11.7596749229,46.49977964645 11.75968586835,46.49976592817 11.75968778133,46.49976353056 11.75969681379,46.49975220988 11.75970775923,46.4997384916 11.75971870467,46.49972477332 11.75972965009,46.49971105503 11.75974059552,46.49969733675 11.75975154093,46.49968361846 11.75976398237,46.49966910388 11.75977642379,46.49965458931 11.75978886521,46.49964007473 11.75980130662,46.49962556016 11.75981374802,46.49961104558 11.75982618942,46.499596531 11.75983863081,46.49958201642 11.7598510722,46.49956750183 11.75986492168,46.49955274092 11.75987877117,46.49953798 11.75989262064,46.49952321908 11.75990647011,46.49950845816 11.75992013022,46.49949500647 11.75993379032,46.49948155477 11.75994745042,46.49946810307 11.75996111051,46.49945465137 11.75997483097,46.49944226366 11.75998855142,46.49942987595 11.76000227186,46.49941748823 11.7600159923,46.49940510052 11.76002991044,46.49939365407 11.76004382858,46.49938220762 11.76005774672,46.49937076117 11.76007166485,46.49935931472 11.76008810643,46.49934790043 11.760104548,46.49933648613 11.76012098956,46.49932507183 11.76013743112,46.49931365753 11.76015492661,46.49930099123 11.76017242209,46.49928832491 11.76018991757,46.4992756586 11.76020741303,46.49926299228 11.76022490849,46.49925032596 11.76024240394,46.49923765964 11.76025989938,46.49922499331 11.76027739482,46.49921232699 11.76029489024,46.49919966066 11.76031238566,46.49918699433 11.76032988107,46.49917432799 11.76034737647,46.49916166165 11.76036540425,46.49915002599 11.76038343201,46.49913839033 11.76040145977,46.49912675467 11.76041948752,46.499115119 11.76043652205,46.49910545246 11.76045355657,46.49909578591 11.76047059108,46.49908611937 11.76048762559,46.49907645282 11.76050786182,46.4990662526 11.76050811386,46.49906612559 11.76052809809,46.49905605242 11.76052860215,46.4990557984 11.76054834095,46.49904585847 11.76056857938,46.49903566034 11.76058911015,46.49902620335 11.76060964092,46.49901674636 11.76063017168,46.49900728936 11.76065070243,46.49899783236 11.76067139896,46.49898917469 11.76069209548,46.49898051701 11.760712792,46.49897185933 11.76073348852,46.49896320165 11.76075424703,46.49895538659 11.76077500553,46.49894757154 11.76079576403,46.49893975647 11.76081652252,46.49893194141 11.76084032311,46.49892486211 11.76086412369,46.4989177828 11.76088792427,46.4989107035 11.76091172484,46.49890362418 11.7609355254,46.49889654486 11.76095932596,46.49888946554 11.76098312651,46.49888238621 11.76100692706,46.49887530688 11.7610307276,46.49886822754 11.76105120493,46.49886093169 11.76107168226,46.49885363583 11.76109215958,46.49884633997 11.76110965405,46.49883887436 11.7611271485,46.49883140875 11.76114464295,46.49882394314 11.76116142626,46.49881506772 11.76117820956,46.4988061923 11.76119499286,46.49879731688 11.76121037571,46.49878789874 11.76122575855,46.49877848059 11.76124114138,46.49876906244 11.76125652421,46.49875964429 11.76127190703,46.49875022613 11.76128728985,46.49874080798 11.76130685776,46.49872970843 11.76132642567,46.49871860888 11.76134212406,46.49871029375 11.76135782245,46.49870197862 11.76137352084,46.49869366349 11.76138921922,46.49868534836 11.76140567459,46.49867776325 11.76141960073,46.49867134399 11.76142212996,46.49867017814 11.76143858533,46.49866259303 11.76145504069,46.49865500791 11.76147149604,46.49864742279 11.76148795139,46.49863983767 11.76150440674,46.49863225255 11.76152086208,46.49862466743 11.76153800335,46.49861784508 11.76155514461,46.49861102274 11.76157228586,46.49860420039 11.76158942712,46.49859737804 11.76160656836,46.49859055569 11.76162370961,46.49858373333 11.76164085085,46.49857691098 11.76165799208,46.49857008862 11.76167905171,46.49856293948 11.76170011133,46.49855579034 11.76172117095,46.49854864119 11.76174223056,46.49854149205 11.76176609551,46.49853433104 11.76178996046,46.49852717003 11.7618138254,46.49852000902 11.76183769033,46.498512848 11.76186155526,46.49850568697 11.76188542018,46.49849852594 11.76189907873,46.49849442749 11.76190770208,46.49849204055 11.76191278747,46.49849031397 11.76193315,46.49848420387 11.76195281577,46.49847732614 11.76197248154,46.4984704484 11.7619921473,46.49846357065 11.76201181305,46.49845669291 11.76202846975,46.49844991198 11.76204512644,46.49844313106 11.76206178312,46.49843635013 11.7620784398,46.4984295692 11.76209509648,46.49842278826 11.76211175315,46.49841600733 11.76212761922,46.49840837561 11.7621434853,46.4984007439 11.76215935136,46.49839311218 11.76217521742,46.49838548046 11.76219108348,46.49837784874 11.76220694953,46.49837021701 11.76222193405,46.49836177826 11.76223691857,46.49835333949 11.76225190308,46.49834490073 11.76226688758,46.49833646197 11.76228187208,46.4983280232 11.76229685657,46.49831958443 11.76231087365,46.49831038699 11.76232489072,46.49830118956 11.76233890779,46.49829199212 11.76235292485,46.49828279468 11.7623669419,46.49827359724 11.76238095895,46.49826439979 11.76239392825,46.4982544964 11.76240689753,46.498244593 11.76241986682,46.49823468961 11.76243283609,46.49822478621 11.76244580537,46.49821488281 11.76245877463,46.49820497941 11.76247062181,46.49819442682 11.76248246898,46.49818387423 11.76249431614,46.49817332164 11.7625061633,46.49816276905 11.76251801046,46.49815221646 11.76252985761,46.49814166387 11.76254051477,46.49813052257 11.76255117192,46.49811938127 11.76256182907,46.49810823998 11.76257248621,46.49809709868 11.76258314335,46.49808595738 11.76259380048,46.49807481608 11.76260320654,46.49806314993 11.7626126126,46.49805148378 11.76262201865,46.49803981763 11.76263142469,46.49802815149 11.76264083073,46.49801648534 11.76265023677,46.49800481919 11.76265859486,46.49799161859 11.76266695294,46.497978418 11.76267531102,46.4979652174 11.76268366909,46.4979520168 11.76269125606,46.49794204561 11.76269884303,46.49793207441 11.76270753616,46.49792333701 11.76271622928,46.49791459962 11.7627272694,46.49790545176 11.76273830952,46.49789630391 11.76275225552,46.49788650793 11.76276620151,46.49787671195 11.7627801475,46.49786691597 11.76279409348,46.49785711998 11.76280803945,46.497847324 11.76282198543,46.49783752801 11.76283819696,46.49782624387 11.76289493729,46.49778674935 11.76295167753,46.49774725481 11.7629678621,46.49773698955 11.76298404665,46.49772672429 11.7630002312,46.49771645902 11.76301641575,46.49770619376 11.76303260029,46.49769592849 11.76304878482,46.49768566321 11.76305628155,46.49768124108 11.76306707591,46.49767487376 11.763085367,46.4976640843 11.76310365809,46.49765329484 11.76312194916,46.49764250538 11.76314024023,46.49763171592 11.76315853129,46.49762092645 11.7631762619,46.49761079031 11.7631939925,46.49760065417 11.76321172309,46.49759051803 11.76322945368,46.49758038188 11.76324788107,46.49757085687 11.76326342848,46.49756282049 11.76326630845,46.49756133185 11.76328473582,46.49755180683 11.76330316318,46.49754228181 11.76332159054,46.49753275678 11.76334001789,46.49752323176 11.76335844524,46.49751370673 11.76337687258,46.49750418169 11.76339595259,46.4974952906 11.76341503259,46.4974863995 11.76343411259,46.4974775084 11.76345319258,46.4974686173 11.76347227256,46.49745972619 11.76349135254,46.49745083508 11.76351043251,46.49744194397 11.76352951248,46.49743305286 11.76354919943,46.49742481697 11.76356888637,46.49741658108 11.7635885733,46.49740834519 11.76360826023,46.49740010929 11.76362794716,46.49739187339 11.76364763407,46.49738363749 11.76366732098,46.49737540158 11.76368700789,46.49736716567 11.76370725464,46.49735960472 11.76372750138,46.49735204375 11.76374774811,46.49734448279 11.76376799484,46.49733692182 11.76378824156,46.49732936084 11.76380848828,46.49732179987 11.76382873499,46.49731423889 11.7638489817,46.4973066779 11.76386973977,46.49729980997 11.76389049783,46.49729294204 11.76391125589,46.4972860741 11.76393201394,46.49727920616 11.76395277198,46.49727233822 11.76397353002,46.49726547027 11.76399428806,46.49725860232 11.76401504608,46.49725173437 11.76403626577,46.49724557591 11.76405748545,46.49723941745 11.76407870512,46.49723325899 11.76409992479,46.49722710052 11.76412114446,46.49722094205 11.76414236412,46.49721478358 11.76416358377,46.4972086251 11.76418480342,46.49720246662 11.76420887471,46.49719620506 11.76423294599,46.4971899435 11.76425701726,46.49718368193 11.76428108853,46.49717742036 11.76430496748,46.49717163012 11.76432884642,46.49716583987 11.76435272536,46.49716004962 11.7643766043,46.49715425936 11.76440048323,46.49714846909 11.76442436215,46.49714267883 11.76444824107,46.49713688855 11.76447211998,46.49713109828 11.76449599889,46.49712530799 11.76451987779,46.49711951771 11.76454375669,46.49711372741 11.76456763558,46.49710793712 11.76459061894,46.49710166111 11.76461360229,46.49709538509 11.76463658563,46.49708910907 11.76465956897,46.49708283305 11.7646825523,46.49707655702 11.76470553563,46.49707028099 11.76472851895,46.49706400495 11.76475150226,46.49705772891 11.76477448557,46.49705145287 11.76479710973,46.4970445826 11.76481973388,46.49703771232 11.76484235802,46.49703084204 11.76486498216,46.49702397176 11.76488760629,46.49701710147 11.76491023042,46.49701023118 11.7649182711,46.49700778946 11.76493285454,46.49700336088 11.76494236203,46.49700047373 11.76495547866,46.49699649058 11.76497810276,46.49698962027 11.76500033552,46.49698216552 11.76502256826,46.49697471077 11.765044801,46.49696725601 11.76506703373,46.49695980124 11.76508926646,46.49695234648 11.76511149918,46.4969448917 11.7651337319,46.49693743693 11.7651559646,46.49692998215 11.76517819731,46.49692252736 11.76520000701,46.49691449874 11.7652218167,46.49690647012 11.76522849687,46.496904011 11.76524362638,46.49689844149 11.76526543606,46.49689041286 11.76528724574,46.49688238422 11.76530905541,46.49687435558 11.76533086507,46.49686632694 11.76535267472,46.49685829829 11.76537448437,46.49685026964 11.76539583997,46.49684167858 11.76541719556,46.49683308752 11.76543855115,46.49682449645 11.76545990673,46.49681590538 11.76548126231,46.4968073143 11.76550261788,46.49679872323 11.76552397344,46.49679013214 11.76554532899,46.49678154106 11.76556668454,46.49677294997 11.76558755565,46.4967638087 11.76560842675,46.49675466743 11.76562929784,46.49674552615 11.76565016892,46.49673638487 11.76567104,46.49672724359 11.76569191107,46.49671810231 11.76571278213,46.49670896102 11.76573365319,46.49669981972 11.76575452424,46.49669067842 11.76577488114,46.49668099996 11.76579523804,46.49667132149 11.76581559492,46.49666164302 11.7658359518,46.49665196455 11.76585630868,46.49664228607 11.76587666554,46.49663260759 11.7658970224,46.4966229291 11.76591737925,46.49661325061 11.76593773609,46.49660357212 11.76595754981,46.49659337024 11.76597736353,46.49658316835 11.76599717723,46.49657296646 11.76601699093,46.49656276457 11.76603680462,46.49655256267 11.76605661831,46.49654236077 11.76607643198,46.49653215887 11.76609624565,46.49652195696 11.76611605931,46.49651175505 11.76613223803,46.49650416252 11.76614841674,46.49649656999 11.76616459544,46.49648897745 11.76618077414,46.49648138492 11.76619695284,46.49647379238 11.76621313153,46.49646619983 11.76623059383,46.49645844537 11.76624805613,46.49645069091 11.76626551843,46.49644293644 11.76628298072,46.49643518197 11.76630044301,46.49642742749 11.76631790529,46.49641967302 11.76633536757,46.49641191854 11.76635282984,46.49640416406 11.76637293826,46.49639560756 11.76639304668,46.49638705106 11.76641315509,46.49637849456 11.7664332635,46.49636993805 11.7664533719,46.49636138154 11.7664734803,46.49635282502 11.76649358868,46.49634426851 11.76651369706,46.49633571199 11.76653380544,46.49632715546 11.76655391381,46.49631859893 11.76657402217,46.4963100424 11.76659413052,46.49630148587 11.76661459866,46.49629334635 11.76663506678,46.49628520682 11.7666555349,46.4962770673 11.76667600302,46.49626892777 11.76669647112,46.49626078823 11.76671693922,46.49625264869 11.76673740732,46.49624450915 11.76675787541,46.49623636961 11.76677834349,46.49622823006 11.76679881157,46.49622009051 11.76681927964,46.49621195095 11.7668397477,46.49620381139 11.76686055741,46.49619609606 11.76688136712,46.49618838072 11.76690217682,46.49618066537 11.76692298652,46.49617295002 11.76694379621,46.49616523467 11.76696460589,46.49615751932 11.76698541557,46.49614980396 11.76700622524,46.4961420886 11.76702703491,46.49613437323 11.76704784457,46.49612665786 11.76706865422,46.49611894249 11.76708946387,46.49611122711 11.76711059674,46.49610394279 11.76713172961,46.49609665846 11.76715286246,46.49608937413 11.76717399532,46.4960820898 11.76719512816,46.49607480546 11.767216261,46.49606752112 11.76723739384,46.49606023678 11.76725852667,46.49605295243 11.76727965949,46.49604566807 11.76730079231,46.49603838372 11.76732192512,46.49603109936 11.76734305792,46.49602381499 11.76736449524,46.49601696814 11.76738593254,46.49601012127 11.76740736984,46.49600327441 11.76742880714,46.49599642754 11.76745024443,46.49598958066 11.76747168172,46.49598273378 11.76749311899,46.4959758869 11.76751455627,46.49596904002 11.76753599354,46.49596219313 11.7675574308,46.49595534623 11.76757886806,46.49594849934 11.76760030531,46.49594165243 11.7676237479,46.49593489405 11.76764719048,46.49592813566 11.76767063306,46.49592137726 11.76769407564,46.49591461886 11.7677175182,46.49590786045 11.76774096077,46.49590110204 11.76776440332,46.49589434363 11.76778784587,46.49588758521 11.76780612897,46.49588189195 11.76782441206,46.4958761987 11.76784269515,46.49587050544 11.76786097824,46.49586481218 11.76788280996,46.49585718073 11.76790464167,46.49584954927 11.76792647338,46.49584191781 11.76794441238,46.49583509913 11.76796235138,46.49582828044 11.76798029037,46.49582146175 11.76799822936,46.49581464306 11.76801797782,46.49580656723 11.76803772627,46.49579849139 11.76805747472,46.49579041555 11.76807722316,46.49578233971 11.7680969716,46.49577426386 11.76811672003,46.49576618801 11.76813646845,46.49575811216 11.76815621687,46.49575003631 11.76817596528,46.49574196045 11.76819571368,46.49573388459 11.76821546208,46.49572580872 11.76823521047,46.49571773285 11.76825758897,46.49570861134 11.76827996746,46.49569948983 11.76830234593,46.49569036832 11.76832472441,46.4956812468 11.76834710287,46.49567212528 11.76836948132,46.49566300375 11.76839185977,46.49565388222 11.76841423821,46.49564476068 11.76843661665,46.49563563914 11.76845762272,46.49562680958 11.76847862879,46.49561798002 11.76849963485,46.49560915046 11.76852064091,46.49560032089 11.76854164696,46.49559149131 11.768562653,46.49558266173 11.76858365903,46.49557383215 11.76860466506,46.49556500257 11.76862289001,46.49555708723 11.76864111496,46.49554917189 11.7686593399,46.49554125655 11.76867756484,46.4955333412 11.76869578977,46.49552542586 11.7687140147,46.4955175105 11.76873223962,46.49550959515 11.76875046454,46.49550167979 11.76876868945,46.49549376443 11.76878691436,46.49548584907 11.76880513926,46.49547793371 11.76882336415,46.49547001834 11.76884158904,46.49546210297 11.76885981392,46.49545418759 11.7688780388,46.49544627222 11.76889626368,46.49543835684 11.76891448854,46.49543044146 11.76893271341,46.49542252607 11.76895093826,46.49541461069 11.76896916311,46.4954066953 11.76898659721,46.49539889874 11.76898713446,46.4953986587 11.76900510018,46.49539061597 11.76902306871,46.4953825763 11.76904103723,46.49537453663 11.76905900574,46.49536649696 11.76907697425,46.49535845729 11.76909494276,46.49535041761 11.76911291126,46.49534237793 11.76913087975,46.49533433824 11.76914884824,46.49532629856 11.76916681672,46.49531825887 11.76918478937,46.49531022342 11.76919719492,46.49530441269 11.76920275676,46.49530180629 11.76921595616,46.49529562272 11.76922072406,46.49529338918 11.76923471818,46.49528683356 11.76923869143,46.49528497227 11.76925348019,46.49527804439 11.76925665879,46.49527655536 11.76927224219,46.49526925523 11.76927462614,46.49526813845 11.76929100419,46.49526046605 11.76929259349,46.49525972154 11.76930976618,46.49525167688 11.76931056087,46.49525130465 11.76932852817,46.4952428877 11.76934720743,46.49523349507 11.76936588669,46.49522410244 11.76938456594,46.49521470981 11.76940324519,46.49520531717 11.76942192443,46.49519592453 11.76944060366,46.49518653189 11.76945928288,46.49517713924 11.7694779621,46.49516774659 11.76949664132,46.49515835394 11.76951532052,46.49514896128 11.76953399972,46.49513956863 11.76955267892,46.49513017597 11.76957092436,46.49512038511 11.7695891698,46.49511059425 11.76960741523,46.49510080339 11.76962566065,46.49509101253 11.76964390607,46.49508122167 11.76966215148,46.4950714308 11.76968039689,46.49506163993 11.76969864229,46.49505184905 11.76971688768,46.49504205818 11.76973513306,46.4950322673 11.76975337844,46.49502247641 11.76977162381,46.49501268553 11.76978941765,46.495002506 11.76980721147,46.49499232646 11.76982500529,46.49498214693 11.7698427991,46.49497196739 11.76986059291,46.49496178785 11.76987838671,46.4949516083 11.7698961805,46.49494142875 11.76991397429,46.4949312492 11.76993176806,46.49492106965 11.76994956184,46.4949108901 11.7699673556,46.49490071054 11.76998514936,46.49489053098 11.77000346785,46.49487914355 11.77002178634,46.49486775611 11.77004010482,46.49485636867 11.77005842329,46.49484498123 11.77007674175,46.49483359378 11.77009506021,46.49482220633 11.77011337865,46.49481081888 11.77013169709,46.49479943143 11.77014703466,46.49479053144 11.77016237223,46.49478163145 11.77017770979,46.49477273145 11.77019304734,46.49476383146 11.77021038964,46.49475469612 11.77022773193,46.49474556078 11.77024507422,46.49473642544 11.7702624165,46.4947272901 11.77027828818,46.49471695806 11.77029415986,46.49470662601 11.77031003153,46.49469629396 11.77032590319,46.49468596191 11.77034013193,46.49467454535 11.77035436066,46.49466312878 11.77036858938,46.4946517122 11.7703828181,46.49464029563 11.7703952494,46.49462791849 11.7704076807,46.49461554135 11.77042011199,46.49460316422 11.77043254328,46.49459078707 11.77044304218,46.49457758376 11.77045354107,46.49456438044 11.77046403996,46.49455117712 11.77047453885,46.4945379738 11.77048299136,46.49452408766 11.77049144386,46.49451020151 11.77049989636,46.49449631537 11.77050834886,46.49448242923 11.77051466321,46.49446801103 11.77052097756,46.49445359284 11.77052729191,46.49443917464 11.77053360625,46.49442475645 11.77053720027,46.49441061683 11.77054079429,46.49439647722 11.77054301573,46.49438048217 11.77054523717,46.49436448711 11.7705474586,46.49434849205 11.77054968004,46.49433249699 11.7705535711,46.49431902214 11.77055746216,46.49430554729 11.77056343635,46.4942934785 11.77056349422,46.4942933616 11.77056941054,46.49428140972 11.77056952628,46.49428117591 11.77057538472,46.49426934094 11.77058414908,46.49425534664 11.77059291149,46.49424135189 11.77060166856,46.49422735554 11.77060172167,46.49422727082 11.77061043631,46.49421336238 11.77062070487,46.49419843106 11.77063097344,46.49418349974 11.77064124199,46.49416856841 11.77065151055,46.49415363709 11.77065782871,46.49414444995 11.77066177909,46.49413870576 11.77067204763,46.49412377443 11.77068371154,46.49410934019 11.77069537544,46.49409490594 11.77070703934,46.49408047169 11.77071660344,46.49406918339 11.77072616753,46.49405789509 11.77073573162,46.49404660679 11.7707452957,46.49403531849 11.77075485978,46.49402403019 11.7707596443,46.49401838311 11.77076442385,46.49401274189 11.7707783392,46.49399803606 11.77079225455,46.49398333022 11.77080616988,46.49396862439 11.77082008521,46.49395391855 11.77083438342,46.49394066238 11.77084868163,46.4939274062 11.77086297983,46.49391415003 11.77087727802,46.49390089385 11.77088651569,46.4938923294 11.7708915762,46.49388763768 11.77090587438,46.4938743815 11.77092140023,46.49386180125 11.77093692606,46.49384922101 11.77095245189,46.49383664077 11.77096502766,46.49382686214 11.77097760343,46.4938170835 11.7709901792,46.49380730487 11.77100275496,46.49379752623 11.77101533071,46.4937877476 11.77102162185,46.49378285574 11.77102790647,46.49377796896 11.77103575307,46.49377244329 11.77104571716,46.49376542645 11.77106352785,46.49375288394 11.77108133852,46.49374034143 11.77109914919,46.49372779891 11.77111692487,46.49371672978 11.77113470054,46.49370566065 11.7711524762,46.49369459152 11.77117025185,46.49368352238 11.77118173622,46.49367637091 11.7711880275,46.49367245325 11.77120580313,46.49366138411 11.77122459133,46.49365114366 11.77124337952,46.49364090321 11.7712621677,46.49363066276 11.7712771308,46.49362284903 11.77129209388,46.49361503531 11.77130705697,46.49360722158 11.77132202005,46.49359940785 11.77133698312,46.49359159412 11.77134583846,46.49358696985 11.77135194619,46.49358378039 11.77137317249,46.49357376907 11.77139439878,46.49356375776 11.77141562507,46.49355374644 11.77143685135,46.49354373511 11.77145741804,46.49353528046 11.77147798473,46.49352682581 11.77149855141,46.49351837115 11.77151911808,46.49350991648 11.77153968475,46.49350146182 11.77156025141,46.49349300715 11.77158157643,46.49348550193 11.77160290144,46.4934779967 11.77162422645,46.49347049147 11.77164555145,46.49346298624 11.77166687644,46.493455481 11.77168820143,46.49344797576 11.77171019301,46.49344145227 11.77173218459,46.49343492877 11.77175417616,46.49342840526 11.77177616772,46.49342188175 11.77179815928,46.49341535824 11.77182015084,46.49340883472 11.77184271436,46.49340332101 11.77186527787,46.4933978073 11.77188784138,46.49339229359 11.77191040488,46.49338677987 11.77193296838,46.49338126615 11.77195553188,46.49337575242 11.77197857024,46.49337127224 11.77200160861,46.49336679204 11.77202464697,46.49336231185 11.77204768532,46.49335783165 11.77207072368,46.49335335144 11.77209376202,46.49334887123 11.77211717611,46.49334544384 11.77214059019,46.49334201644 11.77216400428,46.49333858904 11.77218741835,46.49333516163 11.77221083243,46.49333173422 11.7722342465,46.4933283068 11.77225778923,46.49332567538 11.77228133197,46.49332304396 11.7723048747,46.49332041253 11.77232841743,46.49331778109 11.77235090211,46.49331576201 11.7723733868,46.49331374292 11.77239587149,46.49331172383 11.77241835617,46.49330970473 11.77244084085,46.49330768563 11.77246332553,46.49330566652 11.77248581021,46.49330364741 11.77250829488,46.4933016283 11.77253077956,46.49329960918 11.77255326423,46.49329759006 11.7725757489,46.49329557093 11.77259823357,46.4932935518 11.77262270391,46.49329047721 11.77264717426,46.49328740263 11.7726716446,46.49328432804 11.77269611494,46.49328125344 11.77272058528,46.49327817884 11.77274505561,46.49327510423 11.77276952594,46.49327202962 11.77279399627,46.493268955 11.77281846659,46.49326588038 11.77284270443,46.49326202622 11.77286694227,46.49325817206 11.77289118011,46.49325431789 11.77291541794,46.49325046372 11.77293965576,46.49324660954 11.77296389358,46.49324275536 11.7729881314,46.49323890117 11.77301236922,46.49323504698 11.77303660703,46.49323119279 11.77306056032,46.49322656733 11.77308451361,46.49322194187 11.77310846689,46.4932173164 11.77313242017,46.49321269093 11.77315637345,46.49320806545 11.77318032672,46.49320343997 11.77320427998,46.49319881448 11.77322823325,46.49319418899 11.7732521865,46.49318956349 11.77327155132,46.49318534002 11.77329091613,46.49318111655 11.77331028094,46.49317689307 11.77332964575,46.4931726696 11.77334901055,46.49316844611 11.77336837536,46.49316422263 11.77339246706,46.49315843745 11.77341655876,46.49315265227 11.77344065045,46.49314686708 11.77346474214,46.49314108189 11.77348751813,46.49313490236 11.77351029412,46.49312872283 11.7735330701,46.4931225433 11.77355584608,46.49311636376 11.77357862205,46.49311018422 11.77360139802,46.49310400467 11.77362355142,46.49309682632 11.77364570482,46.49308964797 11.77366785822,46.49308246962 11.7736900116,46.49307529126 11.77371216498,46.4930681129 11.77373431836,46.49306093453 11.77375575745,46.49305278708 11.77377719654,46.49304463964 11.77379863563,46.49303649218 11.7738200747,46.49302834473 11.77384151377,46.49302019726 11.77386295283,46.4930120498 11.77388358886,46.49300296699 11.77390422488,46.49299388417 11.77392486089,46.49298480135 11.77394549689,46.49297571853 11.77396613289,46.4929666357 11.77398676888,46.49295755287 11.7740065164,46.4929475723 11.77402626391,46.49293759172 11.77404601142,46.49292761114 11.77406575891,46.49291763056 11.7740855064,46.49290764997 11.77410525388,46.49289766938 11.77412403114,46.49288683237 11.77414280839,46.49287599535 11.77416158563,46.49286515833 11.77418036286,46.49285432131 11.77419914009,46.49284348429 11.7742179173,46.49283264726 11.77423564656,46.49282099868 11.7742533758,46.49280935009 11.77427110504,46.4927977015 11.77428883427,46.49278605291 11.7743065635,46.49277440431 11.77432429271,46.49276275571 11.77434090057,46.49275034379 11.77435750841,46.49273793185 11.77437411625,46.49272551992 11.77439072408,46.49271310799 11.7744073319,46.49270069605 11.77442393972,46.49268828411 11.77443935741,46.49267516023 11.7744547751,46.49266203634 11.77447019279,46.49264891245 11.77448561046,46.49263578856 11.77450102813,46.49262266467 11.77451644579,46.49260954078 11.77452947796,46.49259637513 11.77454251013,46.49258320949 11.7745555423,46.49257004385 11.77456857445,46.4925568782 11.7745816066,46.49254371255 11.77459463874,46.4925305469 11.77460749412,46.49252001199 11.77462034948,46.49250947707 11.77463320485,46.49249894215 11.77465215343,46.49248694692 11.77467110199,46.4924749517 11.77469261126,46.49246523221 11.77471412052,46.49245551271 11.77473762353,46.49244832514 11.77476112654,46.49244113756 11.77478600381,46.49243667135 11.77481088107,46.49243220514 11.77483647689,46.49243057801 11.7748620727,46.49242895089 11.77488771242,46.49243020573 11.77491335214,46.49243146058 11.77493835995,46.49243556432 11.77496336776,46.49243966806 11.77498138364,46.49244486731 11.77498708451,46.49244651254 11.77501080127,46.49245335701 11.77503260184,46.49246276181 11.77505440242,46.49247216661 11.77506971283,46.49247695856 11.77507637405,46.49247904343 11.77508502324,46.4924817505 11.77510643089,46.49248694164 11.77512783853,46.49249213278 11.77514690759,46.49249563126 11.77516597665,46.49249912973 11.77518504572,46.4925026282 11.77520411478,46.49250612667 11.77522364025,46.49250808554 11.77524316572,46.49251004442 11.77526269119,46.49251200329 11.77528221666,46.49251396215 11.77530193884,46.49251435537 11.77532166102,46.49251474859 11.7753413832,46.49251514181 11.77536110537,46.49251553502 11.77538076195,46.49251435735 11.77540041852,46.49251317969 11.77542007509,46.49251200202 11.77543973166,46.49251082434 11.77545906119,46.49250809146 11.77547839072,46.49250535857 11.77549772024,46.49250262568 11.77551704976,46.49249989278 11.77553787705,46.49249468655 11.77555870433,46.49248948031 11.77558076751,46.49248156788 11.77560283069,46.49247365546 11.77562287116,46.49246483342 11.77564291162,46.49245601139 11.77565750846,46.49244899934 11.77567210531,46.4924419873 11.77568670215,46.49243497525 11.77570129899,46.49242796319 11.77571589582,46.49242095114 11.77573049265,46.49241393908 11.77574982212,46.49240564325 11.77576915158,46.49239734742 11.77579048292,46.49238919244 11.77581181426,46.49238103746 11.77583314559,46.49237288247 11.77585447692,46.49236472747 11.77587580824,46.49235657247 11.77589713955,46.49234841747 11.77591847085,46.49234026247 11.77593980215,46.49233210746 11.77596113344,46.49232395244 11.77598246473,46.49231579743 11.77600379601,46.49230764241 11.77602512728,46.49229948738 11.77604604174,46.49229091947 11.7760669562,46.49228235155 11.77608787064,46.49227378362 11.77610878509,46.49226521569 11.77612969952,46.49225664776 11.77615061395,46.49224807983 11.77617152837,46.49223951189 11.77619244278,46.49223094395 11.77620836755,46.4922259337 11.77622429232,46.49222092345 11.77624021708,46.4922159132 11.77626250572,46.49221114781 11.77628479436,46.49220638242 11.77630287728,46.49220470958 11.77632096021,46.49220303674 11.77633904313,46.49220136389 11.77635712606,46.49219969105 11.77637520898,46.4921980182 11.7763932919,46.49219634534 11.77641246611,46.4921937598 11.77643164032,46.49219117426 11.77645081453,46.49218858871 11.7764755231,46.49218439203 11.77650023168,46.49218019535 11.77652474171,46.49217548257 11.77654925173,46.4921707698 11.77656779879,46.49216652696 11.77658634584,46.49216228413 11.77660489289,46.49215804129 11.7766231965,46.49215332543 11.7766415001,46.49214860956 11.77665618572,46.49214482585 11.7766598037,46.49214389369 11.77668318691,46.4921369631 11.77670657011,46.4921300325 11.77672290478,46.49212442005 11.77673923943,46.49211880759 11.77675557409,46.49211319514 11.77677190874,46.49210758268 11.77678824339,46.49210197021 11.77680457803,46.49209635775 11.77682668312,46.49208765924 11.7768487882,46.49207896073 11.77686527749,46.49207172183 11.77688176678,46.49206448293 11.77689825607,46.49205724402 11.77691304221,46.49204986251 11.77692782834,46.492042481 11.77694261447,46.49203509949 11.7769574006,46.49202771797 11.77697218672,46.49202033645 11.77698697284,46.49201295494 11.77700083244,46.49200476062 11.77701469203,46.4919965663 11.77702855163,46.49198837198 11.77704241122,46.49198017766 11.7770562708,46.49197198334 11.77707013038,46.49196378902 11.77708297003,46.49195483712 11.77709580968,46.49194588523 11.77710864933,46.49193693334 11.77712148897,46.49192798144 11.7771343286,46.49191902954 11.77714716823,46.49191007764 11.7771589014,46.49190042851 11.77717063456,46.49189077938 11.77718236772,46.49188113024 11.77719410088,46.49187148111 11.77720583403,46.49186183197 11.77721756717,46.49185218283 11.77722811478,46.4918419015 11.77723866238,46.49183162016 11.77724920997,46.49182133882 11.77725975756,46.49181105748 11.77726622152,46.49180475669 11.77727453357,46.49179560559 11.77728593091,46.49178305775 11.77729732825,46.49177050991 11.77730872558,46.49175796207 11.77731801652,46.49174711782 11.77732730745,46.49173627357 11.77733659839,46.49172542932 11.77738622684,46.49166509559 11.77743585518,46.49160476184 11.77744237341,46.49159808646 11.77745868153,46.49158418324 11.77747498964,46.49157028001 11.77749129775,46.49155637678 11.77750760584,46.49154247356 11.77752561099,46.49152960775 11.77754361612,46.49151674193 11.77756162125,46.49150387612 11.77757962637,46.4914910103 11.77759919088,46.49147928064 11.77761875538,46.49146755099 11.77763831988,46.49145582132 11.77765788436,46.49144409166 11.77767885807,46.49143358798 11.77769983176,46.4914230843 11.77772080545,46.49141258062 11.77774177913,46.49140207693 11.77776400194,46.49139287962 11.77778622474,46.49138368231 11.77780844753,46.49137448499 11.77783067032,46.49136528767 11.77785397185,46.49135746702 11.77787727337,46.49134964636 11.77790057489,46.4913418257 11.7779238764,46.49133400503 11.77794807858,46.49132762094 11.77797228075,46.49132123684 11.77799648291,46.49131485273 11.77802068507,46.49130846862 11.7780456024,46.49130356969 11.77807051973,46.49129867075 11.77809543705,46.49129377181 11.77812035437,46.49128887286 11.77814579659,46.49128549702 11.77817123881,46.49128212117 11.77819668102,46.49127874532 11.77822212323,46.49127536946 11.77824789488,46.49127354238 11.77827366653,46.49127171529 11.77829943818,46.4912698882 11.77832520983,46.4912680611 11.77835111422,46.49126779679 11.77837701861,46.49126753247 11.778402923,46.49126726815 11.77842882738,46.49126700382 11.77845017992,46.49126746845 11.77847153245,46.49126793308 11.77849288498,46.4912683977 11.77851253385,46.49127030145 11.77853218272,46.4912722052 11.77855006865,46.49127636223 11.77856795458,46.49128051926 11.77858777728,46.49128695865 11.77860759998,46.49129339804 11.77862742269,46.49129983742 11.77864724541,46.49130627681 11.77866691035,46.49131109498 11.7786865753,46.49131591314 11.77870624025,46.49132073131 11.77872590521,46.49132554946 11.77874557016,46.49133036762 11.77876523513,46.49133518577 11.77878530654,46.49133912373 11.77880537795,46.49134306168 11.77882544937,46.49134699963 11.77884552079,46.49135093758 11.77886559222,46.49135487552 11.77888566364,46.49135881346 11.7789075516,46.49136212904 11.77892943955,46.49136544462 11.77895132751,46.4913687602 11.77897321547,46.49137207577 11.77899739771,46.49137492133 11.77902157995,46.49137776687 11.7790457622,46.49138061242 11.77906994444,46.49138345795 11.7790942739,46.49138562512 11.77911860335,46.49138779229 11.77914293281,46.49138995945 11.77916726227,46.4913921266 11.7791895967,46.4913933806 11.77921193114,46.4913946346 11.77923426557,46.49139588859 11.77925660001,46.49139714257 11.77927746163,46.49139743418 11.77929832324,46.49139772579 11.77931918486,46.49139801739 11.77934004606,46.4913983093 11.77936090726,46.49139860121 11.77938176846,46.49139889311 11.77940202503,46.49139900216 11.7794222816,46.4913991112 11.77944253818,46.49139922025 11.77946279475,46.49139932928 11.77948481769,46.49139721463 11.77950684063,46.49139509998 11.77952175269,46.49139118723 11.77953666474,46.49138727449 11.77955963112,46.49137902535 11.77958259749,46.49137077622 11.77960556386,46.49136252708 11.77962383624,46.49135766768 11.77964210863,46.49135280828 11.77966038101,46.49134794888 11.77967865339,46.49134308948 11.77969908634,46.49133861381 11.77971951928,46.49133413813 11.77973995223,46.49132966245 11.77976038517,46.49132518676 11.7797811272,46.49132145101 11.77980186924,46.49131771526 11.77982261127,46.49131397951 11.77984335329,46.49131024375 11.77986256393,46.49130762795 11.77988177457,46.49130501214 11.77990098521,46.49130239634 11.77992019584,46.49129978052 11.77993830693,46.49129831609 11.77995641803,46.49129685166 11.77997452912,46.49129538722 11.77999264021,46.49129392278 11.7800107513,46.49129245834 11.78002886238,46.49129099389 11.78004842813,46.4912904741 11.78006799388,46.4912899543 11.78008755962,46.4912894345 11.78010712537,46.49128891469 11.78012855598,46.49128924053 11.78014998659,46.49128956637 11.78017141721,46.4912898922 11.78019284782,46.49129021803 11.78021422482,46.49129131309 11.78023560181,46.49129240815 11.78025697881,46.4912935032 11.78027835581,46.49129459825 11.78029775937,46.49129641114 11.78031716293,46.49129822402 11.78033656649,46.4913000369 11.78035597005,46.49130184977 11.7803737944,46.4913045068 11.78039161876,46.49130716382 11.78040944311,46.49130982084 11.78042726747,46.49131247786 11.78044509182,46.49131513487 11.78046291618,46.49131779188 11.78048036383,46.49132145167 11.78049781148,46.49132511145 11.78051525913,46.49132877123 11.78053270724,46.49133243129 11.78055015534,46.49133609136 11.78056760345,46.49133975142 11.78058455673,46.49134438922 11.78060151001,46.49134902703 11.78061846329,46.49135366483 11.78063541658,46.49135830263 11.78065236987,46.49136294043 11.78066932316,46.49136757823 11.78069001787,46.49137394001 11.7807107126,46.49138030179 11.78073140732,46.49138666357 11.7807493971,46.49139387462 11.78076738689,46.49140108566 11.78078247773,46.49140957055 11.78079756857,46.49141805544 11.78081155328,46.4914276555 11.78082553798,46.49143725556 11.78083952269,46.49144685562 11.78085584931,46.49145946151 11.78087217593,46.49147206739 11.78088850256,46.49148467327 11.7809048292,46.49149727915 11.78091929246,46.49151092758 11.78093375574,46.49152457601 11.78094821902,46.49153822443 11.78096268231,46.49155187285 11.78097514297,46.49156643311 11.78098760364,46.49158099337 11.78100006431,46.49159555363 11.78101252499,46.49161011388 11.78102286383,46.491625446 11.78103320268,46.49164077812 11.78104354153,46.49165611023 11.78105388039,46.49167144235 11.78106199803,46.49168739934 11.78107011569,46.49170335633 11.78107823334,46.49171931333 11.78108635101,46.49173527032 11.78109216962,46.49175169951 11.78109798824,46.4917681287 11.78110380687,46.49178455789 11.7811096255,46.49180098707 11.78111308944,46.49181773029 11.78111655339,46.4918344735 11.78112001734,46.49185121672 11.78112348129,46.49186795993 11.78112455731,46.4918848571 11.78112563333,46.49190175427 11.78112670934,46.49191865145 11.78112778536,46.49193554862 11.7811264632,46.49195243732 11.78112514104,46.49196932602 11.78112381887,46.49198621472 11.78112249671,46.49200310342 11.78111878862,46.49201982181 11.78111508054,46.49203654019 11.78111137245,46.49205325857 11.78110766436,46.49206997695 11.78110160647,46.49208636461 11.78109554858,46.49210275226 11.78108949068,46.49211913992 11.78108343278,46.49213552757 11.78104751478,46.49235567232 + + + + + + diff --git a/GeoConverterTests/Files/216053.json b/GeoConverterTests/Files/216053.json new file mode 100644 index 0000000..fec1a6a --- /dev/null +++ b/GeoConverterTests/Files/216053.json @@ -0,0 +1 @@ +{"type":"LineString","coordinates":[[11.7774357026,46.49160455494],[11.77744237341,46.49159808646],[11.77750760584,46.49154247356],[11.77757962637,46.4914910103],[11.77765788436,46.49144409166],[11.77774177913,46.49140207693],[11.77783067032,46.49136528767],[11.7779238764,46.49133400503],[11.77802068507,46.49130846862],[11.77808062278,46.49128680559],[11.77813956331,46.4912598441],[11.77819713983,46.49122775057],[11.77825285683,46.49119079986],[11.7783064107,46.49114914605],[11.77835678387,46.49110353388],[11.77840316399,46.49105469502],[11.77844451556,46.49100371216],[11.7784609889,46.49097838859],[11.77847537088,46.49094930881],[11.77848858782,46.49091457738],[11.77850630768,46.49086027375],[11.77852402749,46.49080597011],[11.77853937544,46.49077234788],[11.77855702274,46.49074344431],[11.77858712602,46.49070354038],[11.77861215487,46.49066544914],[11.77863798797,46.49062068995],[11.77865858791,46.49057800381],[11.77867918647,46.49053531681],[11.77869482437,46.49049163708],[11.77871046098,46.49044795829],[11.77872103881,46.49040356008],[11.77873161661,46.49035916186],[11.77873706916,46.49031432485],[11.77874252035,46.49026948697],[11.77874281117,46.49022449285],[11.77874310195,46.49017949783],[11.778739189,46.49014066479],[11.77873527605,46.49010183175],[11.77872751621,46.49006327583],[11.77871975764,46.49002471899],[11.77870819012,46.48998662106],[11.77869662257,46.48994852222],[11.77867347338,46.48989127462],[11.7786582806,46.48983276977],[11.77865117785,46.48977353362],[11.77865245427,46.48971162053],[11.77866256708,46.48965009651],[11.77868142045,46.4895895615],[11.77870882952,46.48953060771],[11.77874452503,46.48947380776],[11.77878816141,46.48941971907],[11.77883931063,46.48936886684],[11.77889747554,46.48932174916],[11.7789620866,46.48927882446],[11.77903251371,46.48924051307],[11.77910807089,46.48920718715],[11.77918801902,46.48917917338],[11.77925909148,46.48914936115],[11.77931373155,46.48912336853],[11.77936837158,46.48909737588],[11.77942657864,46.48906820042],[11.7794847856,46.48903902404],[11.7795429925,46.48900984762],[11.77959916237,46.48897882529],[11.77965533218,46.48894780294],[11.77971150188,46.48891677966],[11.77976551162,46.48888397826],[11.77981952129,46.48885117684],[11.7798735309,46.4888183754],[11.77991344937,46.48879237425],[11.7799533678,46.48876637309],[11.77999104676,46.48874061179],[11.78002872694,46.48871484955],[11.78007399082,46.48868195744],[11.78011925466,46.48864906531],[11.78017142251,46.48860890053],[11.78022359024,46.48856873483],[11.78027043207,46.48853104229],[11.78031727379,46.48849334884],[11.78038172517,46.48843785315],[11.78041586083,46.48840685524],[11.78044999644,46.48837585732],[11.78049154007,46.48833530825],[11.78053308238,46.4882947601],[11.78057462589,46.488254211],[11.78061191535,46.48821594431],[11.78064920606,46.48817767757],[11.78069088905,46.48812867573],[11.780717505,46.48809104399],[11.78074907607,46.48804086164],[11.78077418043,46.48799579477],[11.78079928349,46.48795072883],[11.78082030195,46.48790467505],[11.78084131913,46.48785862221],[11.78085817086,46.48781175899],[11.78087502256,46.48776489578],[11.78088764244,46.48771740202],[11.78090026229,46.48766990825],[11.78090860358,46.48762196599],[11.78091694486,46.48757402373],[11.78092097394,46.48752581648],[11.78092500307,46.48747761013],[11.780924706,46.48742932365],[11.78092440893,46.48738103716],[11.78091980581,46.48733298865],[11.78091520144,46.48728494107],[11.78090631313,46.48723718133],[11.78089742479,46.48718942069],[11.78088428659,46.48714213066],[11.78087114842,46.48709484063],[11.78085381126,46.48704820087],[11.78083647284,46.48700156113],[11.78081500053,46.48695574919],[11.78079352825,46.48690993724],[11.78076800397,46.48686512749],[11.78074247973,46.48682031773],[11.78071300083,46.48677668149],[11.78068352202,46.48673304615],[11.78065020121,46.48669074899],[11.78061688049,46.48664845272],[11.78057984333,46.48660765717],[11.78054280757,46.48656686247],[11.78050219618,46.48652772348],[11.78046158615,46.48648858443],[11.78041755535,46.48645125032],[11.78037352595,46.48641391705],[11.78031746636,46.48637147815],[11.7802514974,46.48632627515],[11.78019072856,46.4862881466],[11.78012996106,46.48625001709],[11.78006919238,46.48621188847],[11.78000842509,46.48617375979],[11.77993409439,46.48612669716],[11.77985976381,46.48607963449],[11.77978543337,46.48603257176],[11.77971110305,46.48598550898],[11.77963677285,46.48593844615],[11.7795774465,46.48590359964],[11.77950562327,46.48586463616],[11.7794338015,46.48582567349],[11.77937101835,46.48578941602],[11.77930878902,46.48574832638],[11.77925870393,46.4857080628],[11.77922414425,46.48567506727],[11.77918456154,46.48563368426],[11.77915116728,46.48559486879],[11.77911777306,46.48555605331],[11.77908820459,46.48551578398],[11.7790586362,46.48547551553],[11.77903302393,46.48543397367],[11.77900741296,46.48539243087],[11.77898587312,46.48534980086],[11.77896433326,46.48530716994],[11.77894696153,46.48526364207],[11.77892958977,46.48522011329],[11.77891646373,46.48517588097],[11.77890333641,46.48513164868],[11.77889451432,46.4850869094],[11.77888569094,46.48504217015],[11.77888121167,46.48499712458],[11.77887673106,46.48495207814],[11.77887657199,46.48490786803],[11.77887641418,46.484863657],[11.77888043813,46.48481953419],[11.77888446339,46.48477541135],[11.7788926539,46.48473156433],[11.7789008457,46.48468771729],[11.77891316803,46.48464433412],[11.77892549029,46.48460095004],[11.7789418913,46.48455821561],[11.77895829358,46.48451548114],[11.77898914098,46.48445578301],[11.77899911263,46.48443167674],[11.77900798995,46.48438821892],[11.77901030309,46.48434890416],[11.77901261623,46.48430958941],[11.77901542367,46.48424839864],[11.77901823112,46.48418720788],[11.77901582048,46.48413453481],[11.7790134112,46.4840818626],[11.7790145444,46.48404038501],[11.77902181755,46.48399533807],[11.77903468457,46.4839418615],[11.77904755282,46.48388838401],[11.77905554605,46.48383744878],[11.77906354057,46.48378651352],[11.77907153377,46.48373557829],[11.77907650527,46.48368446004],[11.77908147671,46.48363334088],[11.77908644819,46.48358222262],[11.77908838927,46.48353100615],[11.77909033039,46.48347979058],[11.77909227147,46.4834285741],[11.77909117875,46.4833773459],[11.77909008603,46.4833261177],[11.77908899332,46.48327488949],[11.77908474591,46.48322263188],[11.77908049855,46.48317037517],[11.77907625246,46.48311811753],[11.7790688476,46.48306602849],[11.77906144405,46.48301393943],[11.77905404052,46.48296185036],[11.77904585459,46.48291266305],[11.77903766743,46.48286347668],[11.77902239751,46.48280636061],[11.77900537027,46.4827659204],[11.77898106094,46.4827217692],[11.77894667933,46.4826704414],[11.77891229779,46.48261911359],[11.77887791635,46.48256778666],[11.77883955209,46.48250881556],[11.77880118791,46.48244984445],[11.77876282381,46.48239087332],[11.77872445854,46.48233190311],[11.77868387693,46.48227364467],[11.7786432941,46.48221538625],[11.7786027114,46.48215712872],[11.77856212875,46.48209887027],[11.77852759474,46.48205080049],[11.77849306209,46.48200273066],[11.77845852815,46.48195465996],[11.77842478247,46.48191175416],[11.77839103685,46.48186884834],[11.77835298643,46.48182563315],[11.77831493477,46.48178241798],[11.77828112973,46.48173754975],[11.77824732475,46.48169268151],[11.77821791467,46.48164636],[11.7781885046,46.48160003759],[11.77816052421,46.48154945126],[11.77813873491,46.48150489661],[11.77811848629,46.48145628775],[11.7780982377,46.48140767889],[11.77808241284,46.48136194333],[11.77806718992,46.48130881575],[11.7780564592,46.48125878031],[11.77804572984,46.48120874573],[11.77803807717,46.48115524423],[11.77803395414,46.48110791021],[11.77803285123,46.48105080695],[11.77802806725,46.48100425761],[11.77802328332,46.48095770916],[11.77801370333,46.480911514],[11.77800412339,46.48086531973],[11.77798979589,46.48081971427],[11.77797546975,46.48077410967],[11.77795646792,46.48072932792],[11.77793746736,46.48068454525],[11.77791388872,46.48064081345],[11.77789031143,46.48059708162],[11.77786227554,46.48055462367],[11.77783424101,46.48051216568],[11.77779660216,46.48045861086],[11.77776954269,46.48043023055],[11.77770686749,46.48038878276],[11.77765068926,46.48034310537],[11.77760160194,46.48029368168],[11.77756012727,46.48024103542],[11.77752670398,46.48018572294],[11.77750168375,46.48012833151],[11.7774853346,46.48006946843],[11.77747782626,46.48000975509],[11.77747807091,46.47996459463],[11.77748336253,46.47991958332],[11.77748632754,46.47988918535],[11.77749369268,46.47987499047],[11.77750206012,46.47986888845],[11.77752805926,46.47985550343],[11.77755725653,46.47983233945],[11.77758047319,46.47980614556],[11.77759706363,46.47977764938],[11.77760656535,46.47974764425],[11.77760871349,46.47971696643],[11.77760411676,46.47968879346],[11.77759331348,46.47966144184],[11.77757655951,46.47963556056],[11.7775542509,46.47961176369],[11.77752691794,46.47959061436],[11.77749520897,46.47957261522],[11.77743971986,46.47954766446],[11.7773842308,46.47952271368],[11.77731419965,46.47948210504],[11.77725050683,46.47943678827],[11.77719381593,46.47938723236],[11.77714471201,46.47933395142],[11.77710370395,46.4792774983],[11.77708005738,46.47924097798],[11.77707121753,46.47921845667],[11.77707054286,46.47920287765],[11.77707571575,46.47916340972],[11.77707107502,46.47910836883],[11.77705735812,46.47905405518],[11.7770347446,46.47900117993],[11.77700353038,46.47895043697],[11.7769641246,46.47890249228],[11.77691704511,46.47885797227],[11.77686290669,46.47881746231],[11.77680242164,46.47878149318],[11.77673638125,46.47875053525],[11.77666565044,46.47872499502],[11.77659115819,46.4787052072],[11.77651388049,46.47869143158],[11.77641362488,46.47868246127],[11.77631515428,46.47866665962],[11.7762194396,46.47864418575],[11.77612742612,46.47861525881],[11.77604002355,46.47858016632],[11.775958095,46.47853925362],[11.77588244929,46.47849292589],[11.77581383272,46.47844163932],[11.77575292253,46.47838590219],[11.7757003225,46.47832626325],[11.77565654984,46.47826331206],[11.77478271507,46.47436758526],[11.77472412861,46.47396384616]]} \ No newline at end of file diff --git a/GeoConverterTests/Files/216053.kml b/GeoConverterTests/Files/216053.kml new file mode 100644 index 0000000..f70d917 --- /dev/null +++ b/GeoConverterTests/Files/216053.kml @@ -0,0 +1,16 @@ + + + + + + +216053 + + + 3-tre - Mortic - Canazei + 216053 + + 11.7774357026,46.49160455494 11.77744237341,46.49159808646 11.77750760584,46.49154247356 11.77757962637,46.4914910103 11.77765788436,46.49144409166 11.77774177913,46.49140207693 11.77783067032,46.49136528767 11.7779238764,46.49133400503 11.77802068507,46.49130846862 11.77808062278,46.49128680559 11.77813956331,46.4912598441 11.77819713983,46.49122775057 11.77825285683,46.49119079986 11.7783064107,46.49114914605 11.77835678387,46.49110353388 11.77840316399,46.49105469502 11.77844451556,46.49100371216 11.7784609889,46.49097838859 11.77847537088,46.49094930881 11.77848858782,46.49091457738 11.77850630768,46.49086027375 11.77852402749,46.49080597011 11.77853937544,46.49077234788 11.77855702274,46.49074344431 11.77858712602,46.49070354038 11.77861215487,46.49066544914 11.77863798797,46.49062068995 11.77865858791,46.49057800381 11.77867918647,46.49053531681 11.77869482437,46.49049163708 11.77871046098,46.49044795829 11.77872103881,46.49040356008 11.77873161661,46.49035916186 11.77873706916,46.49031432485 11.77874252035,46.49026948697 11.77874281117,46.49022449285 11.77874310195,46.49017949783 11.778739189,46.49014066479 11.77873527605,46.49010183175 11.77872751621,46.49006327583 11.77871975764,46.49002471899 11.77870819012,46.48998662106 11.77869662257,46.48994852222 11.77867347338,46.48989127462 11.7786582806,46.48983276977 11.77865117785,46.48977353362 11.77865245427,46.48971162053 11.77866256708,46.48965009651 11.77868142045,46.4895895615 11.77870882952,46.48953060771 11.77874452503,46.48947380776 11.77878816141,46.48941971907 11.77883931063,46.48936886684 11.77889747554,46.48932174916 11.7789620866,46.48927882446 11.77903251371,46.48924051307 11.77910807089,46.48920718715 11.77918801902,46.48917917338 11.77925909148,46.48914936115 11.77931373155,46.48912336853 11.77936837158,46.48909737588 11.77942657864,46.48906820042 11.7794847856,46.48903902404 11.7795429925,46.48900984762 11.77959916237,46.48897882529 11.77965533218,46.48894780294 11.77971150188,46.48891677966 11.77976551162,46.48888397826 11.77981952129,46.48885117684 11.7798735309,46.4888183754 11.77991344937,46.48879237425 11.7799533678,46.48876637309 11.77999104676,46.48874061179 11.78002872694,46.48871484955 11.78007399082,46.48868195744 11.78011925466,46.48864906531 11.78017142251,46.48860890053 11.78022359024,46.48856873483 11.78027043207,46.48853104229 11.78031727379,46.48849334884 11.78038172517,46.48843785315 11.78041586083,46.48840685524 11.78044999644,46.48837585732 11.78049154007,46.48833530825 11.78053308238,46.4882947601 11.78057462589,46.488254211 11.78061191535,46.48821594431 11.78064920606,46.48817767757 11.78069088905,46.48812867573 11.780717505,46.48809104399 11.78074907607,46.48804086164 11.78077418043,46.48799579477 11.78079928349,46.48795072883 11.78082030195,46.48790467505 11.78084131913,46.48785862221 11.78085817086,46.48781175899 11.78087502256,46.48776489578 11.78088764244,46.48771740202 11.78090026229,46.48766990825 11.78090860358,46.48762196599 11.78091694486,46.48757402373 11.78092097394,46.48752581648 11.78092500307,46.48747761013 11.780924706,46.48742932365 11.78092440893,46.48738103716 11.78091980581,46.48733298865 11.78091520144,46.48728494107 11.78090631313,46.48723718133 11.78089742479,46.48718942069 11.78088428659,46.48714213066 11.78087114842,46.48709484063 11.78085381126,46.48704820087 11.78083647284,46.48700156113 11.78081500053,46.48695574919 11.78079352825,46.48690993724 11.78076800397,46.48686512749 11.78074247973,46.48682031773 11.78071300083,46.48677668149 11.78068352202,46.48673304615 11.78065020121,46.48669074899 11.78061688049,46.48664845272 11.78057984333,46.48660765717 11.78054280757,46.48656686247 11.78050219618,46.48652772348 11.78046158615,46.48648858443 11.78041755535,46.48645125032 11.78037352595,46.48641391705 11.78031746636,46.48637147815 11.7802514974,46.48632627515 11.78019072856,46.4862881466 11.78012996106,46.48625001709 11.78006919238,46.48621188847 11.78000842509,46.48617375979 11.77993409439,46.48612669716 11.77985976381,46.48607963449 11.77978543337,46.48603257176 11.77971110305,46.48598550898 11.77963677285,46.48593844615 11.7795774465,46.48590359964 11.77950562327,46.48586463616 11.7794338015,46.48582567349 11.77937101835,46.48578941602 11.77930878902,46.48574832638 11.77925870393,46.4857080628 11.77922414425,46.48567506727 11.77918456154,46.48563368426 11.77915116728,46.48559486879 11.77911777306,46.48555605331 11.77908820459,46.48551578398 11.7790586362,46.48547551553 11.77903302393,46.48543397367 11.77900741296,46.48539243087 11.77898587312,46.48534980086 11.77896433326,46.48530716994 11.77894696153,46.48526364207 11.77892958977,46.48522011329 11.77891646373,46.48517588097 11.77890333641,46.48513164868 11.77889451432,46.4850869094 11.77888569094,46.48504217015 11.77888121167,46.48499712458 11.77887673106,46.48495207814 11.77887657199,46.48490786803 11.77887641418,46.484863657 11.77888043813,46.48481953419 11.77888446339,46.48477541135 11.7788926539,46.48473156433 11.7789008457,46.48468771729 11.77891316803,46.48464433412 11.77892549029,46.48460095004 11.7789418913,46.48455821561 11.77895829358,46.48451548114 11.77898914098,46.48445578301 11.77899911263,46.48443167674 11.77900798995,46.48438821892 11.77901030309,46.48434890416 11.77901261623,46.48430958941 11.77901542367,46.48424839864 11.77901823112,46.48418720788 11.77901582048,46.48413453481 11.7790134112,46.4840818626 11.7790145444,46.48404038501 11.77902181755,46.48399533807 11.77903468457,46.4839418615 11.77904755282,46.48388838401 11.77905554605,46.48383744878 11.77906354057,46.48378651352 11.77907153377,46.48373557829 11.77907650527,46.48368446004 11.77908147671,46.48363334088 11.77908644819,46.48358222262 11.77908838927,46.48353100615 11.77909033039,46.48347979058 11.77909227147,46.4834285741 11.77909117875,46.4833773459 11.77909008603,46.4833261177 11.77908899332,46.48327488949 11.77908474591,46.48322263188 11.77908049855,46.48317037517 11.77907625246,46.48311811753 11.7790688476,46.48306602849 11.77906144405,46.48301393943 11.77905404052,46.48296185036 11.77904585459,46.48291266305 11.77903766743,46.48286347668 11.77902239751,46.48280636061 11.77900537027,46.4827659204 11.77898106094,46.4827217692 11.77894667933,46.4826704414 11.77891229779,46.48261911359 11.77887791635,46.48256778666 11.77883955209,46.48250881556 11.77880118791,46.48244984445 11.77876282381,46.48239087332 11.77872445854,46.48233190311 11.77868387693,46.48227364467 11.7786432941,46.48221538625 11.7786027114,46.48215712872 11.77856212875,46.48209887027 11.77852759474,46.48205080049 11.77849306209,46.48200273066 11.77845852815,46.48195465996 11.77842478247,46.48191175416 11.77839103685,46.48186884834 11.77835298643,46.48182563315 11.77831493477,46.48178241798 11.77828112973,46.48173754975 11.77824732475,46.48169268151 11.77821791467,46.48164636 11.7781885046,46.48160003759 11.77816052421,46.48154945126 11.77813873491,46.48150489661 11.77811848629,46.48145628775 11.7780982377,46.48140767889 11.77808241284,46.48136194333 11.77806718992,46.48130881575 11.7780564592,46.48125878031 11.77804572984,46.48120874573 11.77803807717,46.48115524423 11.77803395414,46.48110791021 11.77803285123,46.48105080695 11.77802806725,46.48100425761 11.77802328332,46.48095770916 11.77801370333,46.480911514 11.77800412339,46.48086531973 11.77798979589,46.48081971427 11.77797546975,46.48077410967 11.77795646792,46.48072932792 11.77793746736,46.48068454525 11.77791388872,46.48064081345 11.77789031143,46.48059708162 11.77786227554,46.48055462367 11.77783424101,46.48051216568 11.77779660216,46.48045861086 11.77776954269,46.48043023055 11.77770686749,46.48038878276 11.77765068926,46.48034310537 11.77760160194,46.48029368168 11.77756012727,46.48024103542 11.77752670398,46.48018572294 11.77750168375,46.48012833151 11.7774853346,46.48006946843 11.77747782626,46.48000975509 11.77747807091,46.47996459463 11.77748336253,46.47991958332 11.77748632754,46.47988918535 11.77749369268,46.47987499047 11.77750206012,46.47986888845 11.77752805926,46.47985550343 11.77755725653,46.47983233945 11.77758047319,46.47980614556 11.77759706363,46.47977764938 11.77760656535,46.47974764425 11.77760871349,46.47971696643 11.77760411676,46.47968879346 11.77759331348,46.47966144184 11.77757655951,46.47963556056 11.7775542509,46.47961176369 11.77752691794,46.47959061436 11.77749520897,46.47957261522 11.77743971986,46.47954766446 11.7773842308,46.47952271368 11.77731419965,46.47948210504 11.77725050683,46.47943678827 11.77719381593,46.47938723236 11.77714471201,46.47933395142 11.77710370395,46.4792774983 11.77708005738,46.47924097798 11.77707121753,46.47921845667 11.77707054286,46.47920287765 11.77707571575,46.47916340972 11.77707107502,46.47910836883 11.77705735812,46.47905405518 11.7770347446,46.47900117993 11.77700353038,46.47895043697 11.7769641246,46.47890249228 11.77691704511,46.47885797227 11.77686290669,46.47881746231 11.77680242164,46.47878149318 11.77673638125,46.47875053525 11.77666565044,46.47872499502 11.77659115819,46.4787052072 11.77651388049,46.47869143158 11.77641362488,46.47868246127 11.77631515428,46.47866665962 11.7762194396,46.47864418575 11.77612742612,46.47861525881 11.77604002355,46.47858016632 11.775958095,46.47853925362 11.77588244929,46.47849292589 11.77581383272,46.47844163932 11.77575292253,46.47838590219 11.7757003225,46.47832626325 11.77565654984,46.47826331206 11.77478271507,46.47436758526 11.77472412861,46.47396384616 + + + diff --git a/GeoConverterTests/Files/Sample1.gpx b/GeoConverterTests/Files/Sample1.gpx new file mode 100644 index 0000000..f37ea1e --- /dev/null +++ b/GeoConverterTests/Files/Sample1.gpx @@ -0,0 +1,15 @@ + + +3.4171 +3.4171 +3.4171 +3.4171 +3.4171 +3.4171 + \ No newline at end of file diff --git a/GeoConverterTests/Files/Sample1.json b/GeoConverterTests/Files/Sample1.json new file mode 100644 index 0000000..32b7dc6 --- /dev/null +++ b/GeoConverterTests/Files/Sample1.json @@ -0,0 +1 @@ +{"type":"LineString","coordinates":[[-122.391386,37.778259,3.4],[-122.391226,37.778194,3.4],[-122.391174,37.778297,3.4],[-122.391117,37.778378,3.4],[-122.391039,37.778449,3.4],[-122.390942,37.778525,3.4]]} \ No newline at end of file diff --git a/GeoConverterTests/Files/Sample2.gpx b/GeoConverterTests/Files/Sample2.gpx new file mode 100644 index 0000000..54379ea --- /dev/null +++ b/GeoConverterTests/Files/Sample2.gpx @@ -0,0 +1,2 @@ + +Des Iles - Bonifacio (20) >+33495731189 (35m)Araguina - Bonifacio (20) >+33495730273 (24m)Pian Del Fosse - Bonifacio (20) (15/04-15/10) >+33495731634 -CCA(67m)Morto - Bonifacio (20) >+33495730466 (69m)La Trinite - Bonifacio (20) >+33495731091 (120m)U'Farniente de Pertamina -�Bonifacio (20) (01/04-31/10) >+33495730547 -CCpg250(95m)Campo di Liccia - Bonifacio (20) >+33495730309 (89m)Kevano Plage - Pianottoli Caldarello (20) >+33495718322 (11m)Rondinara - Bonifacio (20) >+33495704315 (36m)Le Damier - Pianottoli Caldarello (20) >+33495718295 (17m)Municipal - Sartene (20) >+33495259864 (21m)A la ferme de Poli Bernard - Monacia d'Aullene (20) [<51] >+33495718628 (23m)U Moru - Sotta (20) >+33495712340 (106m)Pero Longo - Sartene (20) >+33495771074 (38m)L'Avena - Sartene (20) (06/06-19/09) >+33495770218 -CCpg251(12m)Asciaghju - Porto Vecchio (20) >+33495703787 (26m)U Stabiacciu - Porto Vecchio (20) >+33495703717 (3m)Les Jardins Du Golfe - Porto Vecchio (20) >+33495704692 (2m)Ferme d'Alzetta - Porto Vecchio (20) [<51] >+33495700232 (58m)Bella Vista - Porto Vecchio (20) >+33495705801 (39m)U Pirellu - Porto Vecchio (20) >+33495702344 (40m)Naturist - La Chiappa - Porto Vecchio (20) >+33495700031 (7m)La Matonara - Porto Vecchio (20) >+33495703705 (9m)Arutoli - Porto Vecchio (20) >+33495701273 (13m)Naturist - U'Furu - Porto Vecchio (20) >+33495701083 (102m)U Farrandu - Sartene (20) [<51] >+33495734169 (177m)Pezza Cardo - Porto Vecchio (20) >+33495722759 (20m)Les Chenes - Porto Vecchio (20) >+33495700985 (18m)Les Ilots D'Or - Porto Vecchio (20) >+33495700130 (18m)La Baie des Voiles - Porto Vecchio (20) >+33495700123 (16m)Peretto Les Roseaux - Belvedere Campomoro (20) >+33495742052 (21m)La Vallee - Propriano (20) >+33495721249 (15m)Golfo Di Sogno - Porto Vecchio (20) >+33495700898 (0m)L'Oso - Porto Vecchio (20) >+33495716099 (3m)La Vetta - Porto Vecchio (20) >+33495700986 (60m)Pitrera - Porto Vecchio (20) >+33495702010 (61m)Olva Les Eucalyptus - Sartene (20) >+33495771158 (75m)Les Amis De La Nature - San Gavino Di Carbini (20) [<51] >+33495702157 (57m)Lecci e Murta - Propriano (20) >+33495760267 (19m)Mora Dell'Onda - Lecci (20) [<51] >+33495251667 (19m)Cupulatta - Porto Vecchio (20) >+33612815089 (39m)Naturist - Villata - Sainte Lucie De Porto Vecchio (20) >+33495716290 (22m)California - Sainte Lucie de Porto Vecchio (20) >+33495714924 (5m)Mulinacciu - Lecci (20) (20/05-30/09) >+33495714748 -CCA(80m)Le Tikiti - Propriano (20) >+33495760832 (18m)La Corsica - Propriano (20) >+33495760832 (7m)Colomba - Propriano (20) >+33495762752 (7m)U Pinarellu - Sainte Lucie de Porto Vecchio (20) >+33495714398 (19m)Aire naturelle de Leonetti Marie - Olmeto (20) [<51] >+33495760024 (48m)U Puntonu - Sainte Lucie de Porto Vecchio (20) >+33495714275 (60m)Chez Antoine** - Olmeto (20) [<51] >+33495760606 (11m)l'Esplanade - Olmeto (20) >+33495760503 (65m)Aglio - Olmeto (20) >+33495760715 (9m)Santa Lucia - Sainte Lucie De Porto Vecchio (20) >+33495714528 (52m)Abartello - Olmeto (20) >+33495740512 (6m)Vigna Maggiore - Olmeto (20) >+33495746202 -CCA(139m)U Libecciu - Olmeto (20) >+33495740128 (33m)Le Ras L'Bol - Olmeto (20) >+33495740425 (4m)Acqua e Sole - Sainte Lucie de Porto Vecchio (20) >+33820201207 (40m)Funtanella - Serra di Ferro (20) (10m)Alfonsi-U Caseddu - Serra di Ferro (20) >+33495740180 (6m)Valinco - Serra di Ferro (20) [<51] >+33495740278 (8m)Fautea - Sainte Lucie de Porto Vecchio (20) [<51] (01/05-30/09) >+33495714151 (8m)Cyrnos - Serra di Ferro (20) >+33495740055 (1m)d'Ora - San Gavino Di Carbini (20) [<51] >+33495784817 (673m)U Turracconu - Serra di Ferro (20) >+33495740057 (151m)Municipal Zonza - Zonza (20) [<51] >+33495786274 (784m)Municipal Serra Di Scopamene - Serra Di Scopamene (20) >+33495787220 (945m)Mozziconaccio - Sainte Lucie de Porto Vecchio (20) >+33495732082 (14m)Aire naturelle La Riviere - Zonza (20) [<51] >+33495700367 (676m)Comte Abbatucci - Casalabriva (20) [<51] (01/02-10/12) >+33495740455 (34m)Le Grand Bleu** - Canella (20) [<51] (20m)La Vallee - Coti Chiavari (20) >+33495254466 (4m)Le Sud - Pietrosella (20) >+33495254051 (16m)U Rosumarinu - Solenzara (20) >+33495574766 (76m)l'Europe - Pietrosella (20) >+33495254294 (9m)Cote Des Nacres - Solenzara (20) >+33495574009 (9m)Les Eucalyptus - Solaro >+33495396552 (5m)Mare e Macchia - Porticcio (20) >+33495251058 (58m)Sole Oro - Solaro (20) >+33495578428 (0m)Benista - Porticcio (20) (01/04-15/10) >+33495251930 -CCA(7m)Chateau De Barbicaggia - Ajaccio (20) >+33495520117 (16m)U Prunelli - Porticcio (20) >+33495251923 (10m)Les Mimosas - Ajaccio (20) >+33495209985 (38m)Via Romana - Casamozza di Fium'Orbu (20) >+33495570702 (10m)Arinella Bianca -�Ghisonaccia (12/04-30/09) >+33495560478 -CCA(0m)U Casone - Ghisonaccia (20) >+33495562071 (0m)Marina d'Erba Rossa - Ghisonaccia (20) (05/04-20/10) >+33495562514 -CCA(0m)Du Soleil - Appietto (20) >+33495228727 (53m)l'Adumbratu - Carbuccia (20) >+33495528839 (319m)San Petru (seulement tentes) - Col de Verde (20) [<51] >+33495244682 (1292m)Les Eaux Vives - Ucciani (20) >+33495528109 (216m)Le Calcatoggio - Calcatoggio (20) >+33495522831 (55m)La Liscia - Calcatoggio (20) >+33495522065 (11m)A Marina - Calcatoggio (20) [<51] >+33495522184 (0m)U Sommalu - Tiuccia (20) >+33495522421 (24m)Liamone - Casaglione (20) >+33495522963 (72m)Les Couchants - Casaglione (20) >+33495522660 (95m)Marina d'Aleria - Aleria (20) (01/05-08/10) >+33495570142 -CCA-BD_FR-S.096(0m)Truggia - Lopigna (20) [<51] >+33495529021 (67m)Sagone -�Sagone (13/04-15/09) >+33495280415 -CCpg252-CCA(13m)Aire naturelle Le Soleil - Vivario (20) [<51] >+33495472116 (797m)Torraccia - Cargese (20) >+33495264239 (101m)La Sposata - Vico (20) >+33495266155 (504m)Naturist - Riva Bella -�Aleria (20) (20/01-20/12) >+33495388110 -CCA-BD_FR-S.097(0m)La Ferme Capicorsine- Aleria (20) [<51] >+33689243031 (25m)Le Bord de Mer - Bravone (20) >+33495388408 (1m)Aire naturelle Ernella - Giuncaggio (20) [<51] >+33495488206 (146m)De La Plage d'Arone - Piana (20) >+33495206454 (26m)U Sortipiani - Piedicorte di Gaggio (20) [<51] >+33495488167 (156m)Naturist - Bagheera - Bravonne (20) (15/03-31/10) >+33495388030 -CCpg254-CCA(5m)Naturist - Les Eucalyptus - Linguizzetta (20) >+33495388717 (9m)Aire naturelle Perindundellu - Venaco (20) [<51] >+33495470989 (354m)Naturist - Corsica Natura - San Nicolao (20b) >+33495389130 (9m)l'Acciola - Evisa (20) [<51] >+33495262301 (925m)Funtana Alora - Porto (20) [<51] >+33495261548 (108m)Les Oliviers - Porto (20) >+33495261449 (30m)Sole E Vista - Ota (20) >+33495261571 (38m)Municipal Ota - Ota (20) >+33495261776 (18m)Tuani - Corte (20) [<51] >+33495461165 (663m)Santa Barbara - Corte (20) [<51] >+33495462022 (332m)l'Alivetu - Corte (20) [<51] >+33495461109 (414m)Aire naturelle de U Sognu - Corte (20) [<51] >+33495460907 (419m)Le Restonica - Corte (20) >+33495461159 (407m)Chez Barto - Corte (20) [<51] >+33495460230 (420m)E Gradelle - Osani (20) (01/05-15/10) >+33495273201 (17m)Le Campoloro - Cervione (20) >+33495380020 (16m)Calamar - Cervione (20) >+33495380354 (7m)Olmello Plage - Valle Di Campoloro (20) >+33495380099 (8m)Acquaviva - Calacuccia >+33495480008 (862m)Aire naturelle L'Arimone - Lozzi (20) [<51] >+33495480551 (1071m)U Monte Cintu- Lozzi (20) [<51] >+33495480445 (1070m)Kalypso - Santa Maria Poggio (20) >+33495385674 (7m)Merendella - San Nicolao (20) >+33495385347 (4m)Naturist - Village Club - Serralongue (66) >+33468396292 (1008m)Municipal Verte Rive - Saint Laurent de Cerdans (66) [<51] >+33468395464 (638m)Aire naturelle Campita - Francardo (20) [<51] (15/03-15/10) >+33495474415 (295m)U Punticchiu - Santa Lucia Di Moriani (20) >+33495385779 (5m)Saint Martin - Prats de Mollo la Preste (66) >+33468397740 (699m)A la ferme Plana Nera - Prats de Mollo la Preste (66) [<51] >+33468397361 (1135m)Can Nadal - Prats de Mollo la Preste (66) >+33468397089 (775m)A la Ferme La Pomarede - Serralongue (66) [<51] >+33468396971 (503m)Miami Plage - Poggio Mezzana (20) >+33495369585 -BD_FR-S.104(6m)Ideal - Galeria (20) >+33495620146 (9m)Aire naturelle La Caravelle - Poggio Mezzana (20) [<51] >+33495368382 (3m)Las Asperas - Palau de Cerdagne (66) >+33468046208 (1180m)Les Deux Torrents - Galeria (20) >+33495620067 (13m)Naturist - Le Clols - Saint Laurent de Cerdans (66) >+33468395168 (721m)Monte Cinto - Asco (20) >+33495478608 (1051m)Valle Longhe - Talasani (20) [<51] >+33495368335 (30m)De Griggione - Ponte Leccia (20) >+33495476361 (229m)Le Segre - Bourg Madame (66) [<51] >+33468046587 (1140m)Les Cascades - Pruno (20) [<51] >+33495369191 (111m)Le Puigmal - Err (66) >+33468047183 (1360m)Mas Piques - Bourg Madame (66) >+33468046211 (1146m)Naturist - Le Ventous-El Ventos - Arles sur Tech (66) >+33621466522 (650m)Aire naturelle Ficajola - Taglio Isolaccio (20) [<51] >+33495369616 (7m)Las Closas - Err (66) >+33468047142 -CCA(1353m)La Riberette - Err (66) >+33468047560 (1327m)La Gare - Ur (66) >+33468048095 (1182m)Municipal Cap Peyrefite - Cerbere (66) >+33468884117 (31m)Le Riuferrer - Arles sur Tech (66) >+33468391106 (311m)Le Robinson - Enveitg (66) >+33468048038 (1265m)Le Cerdan - Saillagouse (66) >+33468047046 (1303m)Ilisa - Saillagouse (66) >+33468047508 (1358m)La Morsetta - Galeria (20) >+33495652524 (18m)Marina Di Casinca - Penta di Casinca (20) >+33495365387 (0m)Rural de Palau Marie-Therese - Estavar (66) [<51] >+33468047275 (1239m)Vallespir - Arles sur Tech (66) >+33971288255 (253m)l'Enclave - Estavar (66) >+33468047227 -CCA(1220m)Le Cortsavi - Corsavy (66) >+33468878924 (810m)Tizzarella - Moltifao (20) >+33495478392 (302m)Municipal l'Oratoire - Latour de Carol (66) >+33468048370 (1264m)Aire naturelle Cabanella - Moltifao (20) [<51] >+33495650336 (294m)Aire naturelle E Canicce - Moltifao (20) [<51] >+33495351675 (280m)Anghione - Castellare di Casinca (20) >+33495365022 (4m)Municipal La Pinede - Banyuls sur Mer (66) [<51] >+33468883213 (15m)Naturist - La Clapere - Maureillas Las Illas (66) [<51] >+33468833604 (154m)Municipal Sol Y Neu - Angoustrine Villeneuve des Escaldes (66) >+33468046683 (1306m)Municipal Amelie les Bains Palalda** - Amelie les Bains Palalda (01/02-30/11) >+33468392237 (207m)Aloha - Amelie les Bains Palalda (66) (15/03-15/11) >+33468390861 -CCA(225m)U Fiumara - Castello di Rostino (20) [<51] >+33495386006 (150m)Europa Beach - Sorbo Cocagnano (2B) >+33495364428 (4m)Municipal Le Bosquet de Nogarede** - Ceret [<51] (01/04-31/10) >+33468872672 (171m)Municipal Le Tourou* - Maureillas Las Illas [<51] (01/01-31/12) >+33468832319 (137m)Marina Di Sorbo - Sorbo Ocagnano (20) >+33495389304 (2m)Les Pommiers* - Reynes [<51] (01/04-30/09) >+33468390472 (180m)Les Cerisiers* - Ceret (01/02-31/12) >+33468870008 (151m)Les Pins Le Congo** - Maureillas Las Illas (01/01-31/12) >+33468832321 (134m)Le Saint Martin - Ceret (66) >+33621504796 (137m)Le Saint Georges*** - Ceret (01/01-31/12) >+33468870373 (137m)Les Bruyeres*** - Maureillas Las Illas (66) (15/03-15/11) >+33468832664 -CCA(137m)La Griole - Targassonne (66) >+33468300384 (1558m)Paradella - Calenzana (20) >+33495650097 (106m)Mas d'en Bacou - Reynes (66) [<51] >+33468870047 (250m)Las Clotes - Egat (66) >+33468302690 (1687m)Huttopia Font-Romeu - Font-Romeu Odeillo Via (66) >+33468300932 (1773m)Val Roma Park** - Maureillas Las Illas (05/05-30/09) >+33468398813 (89m)La Vallee*** - Saint Jean Pla de Corts (66) (01/04-31/10) >+33468832320 -CCA(88m)Mas d'En Mas* - Ceret (01/01-31/12) >+33468834601 (129m)l'Olivette** - Le Boulou (15/03-31/10) >+33468834808 (90m)Les Casteillets*** - Saint Jean Pla de Corts (01/01-31/12) >+33468832683 (103m)Municipal Francois Rouquet - Fontpedrouse (66) >+33468970515 (1007m)Naturist - Mas de la Balma - Amelie les Bains Palalda (66) >+33468390888 (410m)Municipal La Llagonne - La Llagonne (66) >+33468042604 (1657m)Les Oliviers** - Le Boulou (16/01-14/12) >+33468831286 (81m)A la ferme l'Aghja - Vallica (20) [<51] >+33495613613 (818m)Club Mas Manyeres - Laroque des Alberes (66) >+33468893311 (95m)Les Alberes - Laroque des Alberes (66) >+33468892364 (92m)Municipal Le Vivier - Laroque des Alberes (66) >+33468954997 (87m)Las Planes** - Laroque des Alberes (15/06-31/08) >+33468892136 (94m)Le Soleil d'Or** - Villelongue Dels Monts [<51] (15/04-30/09) >+33468555662 (93m)Le Rancho - Argeles sur Mer (66) >+33468810488 (72m)Les Amandiers - Collioure (66) (29/03-12/10) >+33468811469 -CCpg184-CCA(15m)Domaine les Mimosas - Argeles sur Mer (66) >+33468810693 (56m)Sant-Cristau** - Montesquieu des Alberes (15/05-15/10) >+33468897101 (76m)La Girelle - Collioure (66) >+33468812556 (28m)La Coste Rouge - Argeles sur Mer (66) >+33468810870 (24m)Naturist - Le P'tit Bonheur - Escaro (66) [<51] >+33468970853 (906m)Saint Martin - Casteil (66) [<51] (29/03-31/10) >+33468055209 -CCA(838m)Les Criques de Porteils - Argeles sur Mer (66) (29/03-25/10) >+33468811273 -CCA(10m)Les Micocouliers - Sorede (66) >+33468892027 -CCA(71m)La Coscolleda - Sorede (66) (01/04-01/10) >+33468891665 -CCA(64m)Fontanelle - Sahorre (66) >+33468055506 (672m)Bois de Valmarie - Argeles sur Mer (66) >+33468810461 (3m)Le Romarin - Argeles sur Mer (66) (01/04-30/09) >+33468810263 -CCA(48m)La Pinede** - Saint Genis des Fontaines (01/06-31/08) >+33468897529 (57m)Mas Llinas*** - Le Boulou (01/03-30/12) >+33468821564 -BD_FR-Q.064a(102m)Les Cerisiers - Vernet les Bains (66) >+33468056038 (681m)l'Esperanza - Lucciana (20) >+33495361509 (1m)La Sardane - Argeles sur Mer (66) >+33468811082 (3m)Municipal La Riviere - Porte Puymorens (66) >+33468048220 (1616m)Front De Mer - Argeles sur Mer (66) >+33468810870 (3m)Municipal La Bastide - La Bastide (66) [<51] >+33468394281 (795m)Le Stade - Argeles sur Mer (66) >+33468810440 (6m)Municipal Al Comu - Llauro (66) [<51] (01/04-24/10) >+33468394208 -CCA(288m)Le Carrefour - Argeles sur Mer (66) >+33468959034 (2m)Europe - Argeles sur Mer (66) >+33468810810 (2m)Catalan - Argeles sur Mer (66) >+33468811226 (4m)La Plage - Argeles sur Mer (66) >+33468811217 (4m)Les Acacias - Argeles sur Mer (66) >+33468812788 (2m)La Massane - Argeles sur Mer (66) >+33468810685 -BD_FR-Q.076a(7m)Bouix - Argeles sur Mer (66) >+33468811175 (4m)Les Peupliers - Argeles sur Mer (66) >+33468811791 (3m)Comanges - Argeles sur Mer (66) (14/04-01/10) >+33468811562 -CCA(3m)Les Ombrages - Argeles sur Mer (66) >+33468812983 (3m)Paduella - Calvi (20) >+33495650616 (7m)Bella Vista - Calvi (20) >+33495651176 (10m)La Chapelle - Argeles sur Mer (66) (19/04-21/09) >+33468812814 -CCA(3m)La Pinede - Calvi (20) (16/05-10/11) >+33495651780 -CCpg253-CCA(5m)Dolce-Vita - Calvi (20) (01/04-10/11) >+33495650599 (2m)L'Eau Vive -�Vernet les Bains (66) (12/04-28/09) >+33468055414 (580m)Le Libeccio - Calvi (20) (05/04 >+33495651012 (6m)International - Calvi (20) (19/04 >+33495650175 (3m)Les Pins - Argeles sur Mer (66) (12/04-28/09) >+33468811046 -CCA(3m)Del Bosc - Vernet les Bains (66) (07/05-28/09) >+33468055454 (617m)Campo Di Fiori - Calvi (20) (01/04 >+33495483460 (5m)La Cle Des Champs - Calvi (20) [<51] (07/05-04/11) >+33495650086 (5m)Beausejour - Argeles sur Mer (66) (01/01 >+33468811063 (3m)Le Pujol - Argeles sur Mer (66) (15/04 >+33468810025 (4m)Les Castors - Calvi (20) (26/04 >+33495651330 (4m)Paris-Roussillon - Argeles sur Mer (66) (01/03 >+33468811971 (5m)Soleil Sud - Argeles sur Mer (66) (12/04 >+33468952727 (4m)Le Rotja - Fuilla (66) (05/04-11/10) >+33468965275 -CCA(545m)Les Marsouins - Argeles sur Mer (66) (05/04 >+33468811481 -CCA(2m)Les Closes - Corneilla de Conflent (66) (12/04 >+33468965229 (615m)Les Sauterelles - Fillols (66) [<51] (07/12 >+33468056372 (845m)Al Sol - Argeles sur Mer (66) (01/03 >+33468810413 (9m)Le Roussillonnais - Argeles sur Mer (66) (10/05 >+33468811042 (2m)Au Flamenco - Argeles sur Mer (66) >+33468813316 (5m)Le Texas - Argeles sur Mer (66) >+33468810017 (11m)Sol y Mar - Argeles sur Mer (66) >+33468812421 (1m)l'Etoile d'Or - Argeles sur Mer (66) >+33468810434 (5m)Taxo Les Pins - Argeles sur Mer (66) >+33468810605 (9m)La Sirene - Argeles sur Mer (66) >+33468810461 (3m)La Roseraie - Argeles sur Mer (66) (19/04-27/09) >+33468811703 -CCA(8m)l'Hippocampe - Argeles sur Mer (66) (19/04 >+33468810461 (2m)La Marende - Argeles sur Mer (66) (16/05 >+33468811209 -CCA(2m)Le Dauphin - Argeles sur Mer (66) (16/05-21/09) >+33468811754 -CCA(5m)Les Galets - Argeles sur Mer (66) (01/04 >+33468810812 (3m)Le Pearl - Argeles sur Mer (66) (07/05 >+33468812649 (5m)Les Cedres - Argeles sur Mer (66) (01/01 >+33468810382 (6m)Saint Andre - Argeles sur Mer (66) (15/04 >+33468810802 (10m)Le Soleil - Argeles sur Mer (66) (07/05-20/09) >+33468811448 -CCA(1m)Le Haras -�Palau del Vidre (66) (01/04-30/09) >+33468221450 -CCpg185-CCA(19m)Mas de Lastourg - Villefranche de Conflent (66) (12/04 >+33468053525 (487m)l'Equinoxe - Argeles sur Mer (66) (12/04 >+33468810021 (2m)Le Littoral - Argeles sur Mer (66) (05/04 >+33468811774 (3m)Le Lac - Matemale (66) (12/04 >+33468309449 (1549m)Monte Orto - Lumio (20) (07/12 >+33495607393 (173m)Le Panoramic - Lumio (20) (01/03 >+33495607313 -CCA(222m)Municipal La Porte des Cimes - L'Hospitalet Pres l'Andorre (9) (10/05 >+33561052110 (1433m)Municipal Les Padraguets - Elne (66) [<51] >+33468222159 (12m)Cala Gogo - Saint Cyprien (66) (07/05-20/09) >+33468210712 -CCA(0m)Bellevue - Ria Sirach (66) >+33682118567 (466m)Cantarettu City - Aregno (20) >+33495607089 (26m)Cala Di Sole - Algajola (20) >+33495607398 (6m)Aire naturelle La Mignane - Elne (66) [<51] >+33468210097 (19m)Le Florida - Elne (66) (01/01-31/12) >+33468378088 -CCA(9m)Aire naturelle Balanea - Corbara (20) [<51] >+33495600684 (22m)De La Plage - Algajola (20) >+33495607176 (4m)La Deveze - Formigueres (66) >+33468046673 (1584m)A Marina - Aregno (20) >+33495607541 (5m)Al Mouly - Elne (66) >+33468220846 (7m)Municipal Trouillas** - Trouillas (01/07-31/08) >+33468530617 (81m)Le Canigou - Espira de Conflent (66) (15/04-26/10) >+33468058540 -CCA(307m)Le Roussillon - Saint Cyprien (66) >+33468210645 (1m)Municipal Plaine St Martin - Prades (66) [<51] >+33468962983 (332m)l'Orniccio - Monticello (20) >+33495601732 (101m)Le Soleil de la Mediterranee - Saint Cyprien (66) (01/01-31/12) >+33468210797 -CCpg186(0m)Municipal Bosc d'en Roug - Saint Cyprien (66) >+33468212350 (4m)Bodri - Corbara (20) >+33495601086 (29m)Clos Des Chenes - Belgodere (20) >+33495604127 (25m)San Damiano - Biguglia (20) >+33495336802 (1m)Les Oliviers - Monticello (20) >+33495601992 (34m)Les Rives du Lac** - Villeneuve de la Raho (01/04-31/10) >+33468558351 (24m)Le Belgodere - Belgodere (20) >+33495602020 (20m)Cap Sud - Alenya (66) [<51] >+33468221726 -CCA(6m)Municipal Les Escoumes - Vinca (66) >+33468058478 (259m)Municipal Ville De Bau - Merens Les Vals (9) >+33561028540 (1097m)Ferme Mas Las Planes - Alenya (66) [<51] >+33683515113 (13m)Municipal Molitg les Bains - Molitg les Bains (66) [<51] >+33468050212 (603m)De L'Ostriconi - Palasca (20) >+33495601005 (19m)La Pinede - Saint Florent (20) [<51] >+33495370726 (5m)Le Pont d'Espagne - Camelas (66) >+33468571057 (119m)Municipal Ille sur Tet - Ille sur Tet (66) >+33468847240 (143m)Les Flamants Roses - Saint Nazaire (66) >+33468802103 (3m)Les Sables Rouges - Bastia (20) >+33495333608 (7m)Kalliste - Saint Florent (20) >+33495370308 (1m)U Pezzo - Saint Florent (20) >+33495370165 (5m)Acqua Dolce - Saint Florent (20) >+33495370863 (3m)Mar Estang - Canet en Roussillon (66) (26/04-14/09) >+33468803553 -CCA(1m)Les Fontaines - Canet en Roussillon (66) >+33971572301 (2m)La Garenne - Nefiach (66) (01/03-31/10) >+33468571576 -CCA(119m)d'Olzo - Saint Florent (20) >+33495370334 (9m)La Garrigole* - Perpignan [<51] (01/01-31/12) >+33468546610 (42m)Le Bosquet - Querigut (9) >+33607539378 (1217m)Le Miami - Canet en Roussillon (66) [<51] >+33468803771 (2m)Ma Prairie -�Canet en Roussillon (66) (12/04-20/09) >+33468732617 -CCpg187-CCA-BD_FR-Q.084(6m)Municipal D'Orlu - Orlu (9) >+33561643009 (846m)Les Peupliers - Canet en Roussillon (66) >+33468803587 (3m)Le Brasilia - Canet en Roussillon (66) >+33468802382 (3m)Le Bosquet - Canet en Roussillon (66) (12/04-05/10) >+33468802380 -CCA(6m)Municipal La Pradaille - Le Pla (9) >+33561204914 (1174m)Sainte Marie - Sainte Marie (66) (05/04-01/11) >+33468804810 -CCA(5m)Aire naturelle U Sole Marinu - Patrimonio (20) [<51] >+33495371220 (14m)La Ferme de Catarelli (tents only) - Patrimonio (20) [<51] (15/04-15/09) >+33495370284 (17m)U Paradisu - Santo Pietro Di Tenda (20) [<51] >+33495378251 (7m)Ascou la Forge - Ascou (9) [<51] (01/01-31/12) >+33561646003 (1115m)La Pergola - Sainte Marie (66) (12/04-21/09) >+33468730307 -CCpg188-CCA(1m)Aire naturelle La Bergerie - Gavarnie (65) [<51] >+33562924841 (1408m)Le Lamparo - Sainte Marie (66) >+33468738387 (2m)Le Malazeou - Ax les Thermes (9) (07/12-11/11) >+33561646914 -CCA(705m)La Source - Sournia (66) >+33468960813 (545m)A Stella - Farinole (20) >+33495371437 (21m)Du Fournil - Savignac les Ormeaux (9) >+33561642440 (680m)Catalan** - Perpignan (15/03-31/10) >+33468631692 (16m)Le Florida - Sainte Marie (66) >+33561684523 (2m)Municipal La Prade - Sorgeat (9) [<51] >+33561643634 (1145m)Municipal La Bade - Caramany (66) [<51] >+33468845185 (261m)Madres Pyrenees - Roquefort De Sault (11) [<51] >+33468206314 (975m)La Plage - Sainte Marie (66) (01/03-31/10) >+33468806859 -CCA(1m)Le Palais de la Mer - Sainte Marie (66) (10/05-27/09) >+33468730794 -CCA(2m)M. Casanova - Santa Maria Di Lota (20) >+33495339142 (5m)Auberge de la Munia - Gedre (65) [<51] >+33562924839 (1505m)Municipal Le Castella - Luzenac (9) >+33561644753 (607m)Le Pain de Sucre - Gavarnie (65) [<51] >+33562924755 (1240m)Municipal La Verniere - Auzat (9) [<51] >+33561648446 (733m)Les Dunes*** - Torreilles (20/03-15/10) >+33468283829 (1m)La Palmeraie*** - Torreilles (05/04-30/09) >+33442204725 (2m)Le Trivoly**** - Torreilles (66) (05/04-20/09) >+33251330505 -CCA(2m)La Tour de France - Latour de France (66) [<51] >+33468291610 -CCA(91m)Le Soleil 2000*** - Rivesaltes [<51] (01/04-31/10) >+33468385354 (20m)Mar I Sol *** - Torreilles Plage (15/04-20/09) >+33468280407 (1m)Le Calypso*** - Torreilles (01/04-30/09) >+33468280947 (2m)Les Tropiques*** - Torreilles (66) (15/04-30/09) >+33468280509 -CCA-BD_FR-Q.089(2m)La Bexanelle - Vicdessos (9) >+33561648222 (717m)Le Pas De L'Ours - Aston (9) [<51] (01/06-15/09) >+33561649033 (575m)Tam Tam Lodge - Salvezines (11) [<51] >+33468691146 (1037m)Municipal La Coume - Albies (9) >+33561649899 (560m)Club l'Europe*** - Le Barcares (01/01-31/12) >+33468861536 (2m)Les Tamaris - Le Barcares (66) (15/04-30/09) >+33468860818 (2m)California*** - Le Barcares (66) (01/05-28/09) >+33468861608 -CCA(3m)Club Le Soleil Bleu*** - Le Barcares (01/04-30/09) >+33468861550 (3m)l'Oasis*** - Le Barcares (01/05-15/09) >+33468861243 -CCpg189(3m)Chantecler - Bagneres de Luchon [<51] >+33561881533 (654m)La Croix du Sud*** - Le Barcares (01/04-30/09) >+33468861661 (3m)La Ferme de Berbescou- Lordat (9) [<51] (01/05-15/10) >+33561644577 (936m)Au Fil de l'Oo - Bagneres de Luchon (31) >+33561793074 (652m)Le Floride et l'Embouchure*** - Le Barcares (66) (01/04-30/09) >+33468861175 -CCA(4m)Les Thermes - Bagneres de Luchon (31) [<51] >+33561790385 (657m)Le Pre Catalan**** - Le Barcares (01/05-20/09) >+33468861260 -CCA(1m)Aire naturelle Les Tilleuls - Gedre (65) [<51] (15/04-01/10) >+33562924892 (1090m)Le Bellevue - Gedre (65) [<51] >+33562924840 (1098m)Bahia Club** - Le Barcares (01/06-15/09) >+33468809016 (0m)Municipal Du Pont de Moudang - Aragnouet (65) [<51] >+33562396284 (1073m)Las Bousigues *** - Le Barcares (15/04-15/09) >+33468861619 (2m)Municipal Le Bois de Boulogne - Les Cabannes (9) >+33561647745 (539m)Fouga - Aragnouet (65) >+33562396337 (1155m)Des Randonneurs - Fenouillet [<51] (15/04-15/10) >+33468590550 (472m)Ferme des Bouries - Seix (9) [<51] >+33561048584 (855m)Les Sapins - Camurac (11) [<51] >+33468203811 (1276m)La Ferme d'Emprau - Verdun (9) [<51] >+33561647035 (562m)Le Mouscat - Gedre (65) [<51] >+33562924753 (999m)Le Couledous - Aulus les Bains (9) [<51] >+33561664356 (740m)Arome Vanille - Montauban De Luchon (31) >+33561790038 (631m)Pene Blanche - Loudenvielle (65) (21/12-03/11) >+33562996885 -CCA(944m)Municipal Ustou - Ustou (9) >+33561669221 (748m)La Prairie - Capoulet Junac (9) >+33561058181 (571m)Le Relais d'Espagne - Gedre (65) [<51] >+33562924770 (982m)La Presqu'ile - Le Barcares (66) >+33468861280 (0m)l'Agly - Saint Paul de Fenouillet (66) >+33468590909 (251m)Maurynate - Maury (66) [<51] >+33468591524 (142m)La Cremade - Axat (11) >+33468205064 (498m)Pradelongue - Moustajon (31) (01/04-30/09) >+33561798644 -CCA(618m)Les Frenes - Garin (31) [<51] >+33561798844 (1111m)Le Silence Du Midi - Comus (11) [<51] >+33468203626 (1171m)Le Montagnou - Ustou (9) [<51] >+33561669497 (681m)La Casaiola - Sisco (20) [<51] >+33495352010 (14m)Municipal Caudies de Fenouilledes - Caudies de Fenouilledes (66) [<51] (15/06-31/08) >+33468599225 (349m)Le Moulin Du Pont D 'Alies - Axat (11) >+33468205327 (394m)Des Grottes - Alliat (9) (01/03-25/10) >+33561058821 -CCpg161-CCA(551m)Le Priourat - Tautavel (66) [<51] >+33468294145 (100m)Municipal De Saint-Lary Soulan - Saint Lary Soulan (65) >+33562394158 (800m)Les Chalets du Lac - Belcaire (11) >+33468203123 (1025m)Les Myrtilles - Moustajon (31) >+33561798989 (613m)Ariege Evasion - Ornolac Ussat Les Bains (9) >+33561051111 (494m)Le Lustou - Adervielle Pouchergues (65) >+33562996827 (938m)De La Mare Aux Fees - Roquefeuil (11) [<51] >+33468205545 (939m)Le Pyreneen - Salles et Pratviel (31) >+33561795919 (616m)d'Autun - Saint Lary Soulan (65) >+33562394031 (805m)Municipal Le Calcat - Espezel (11) [<51] (01/05-31/10) >+33468203034 (895m)Artiguette - Vignec (65) >+33562395224 (800m)La Mousquere - Bourisp (65) [<51] >+33562394499 (798m)Saint Bazerque - Luz Saint Sauveur (65) [<51] >+33562924993 (859m)Le Bois de Pins* - Salses le Chateau (01/04-31/10) >+33468386844 (50m)Municipal Le Hourgade - Avajan (65) >+33562996986 (921m)Le Rioumajou - Saint Lary Soulan (65) (01/01-31/12) >+33562394832 -CCA(778m)La Pietra - Pietracorbara (20) (20/03-04/11) >+33495352749 -CCA(6m)Le Pre Lombard -�Tarascon sur Ariege (9) (12/04-30/09) >+33561056194 -CCA-BD_FR-P.085b(478m)International Le Roussillon** - Salses le Chateau (01/01-31/12) >+33468386072 -CCA(9m)Le Lustou - Vielle Aure (65) >+33562394064 (777m)U Licetu - Pietracorbara (20) [<51] >+33495352598 (83m)La Neste - Guchan (65) [<51] >+33562399160 (760m)Rives des Corbieres - Leucate (11) (01/04-15/10) >+33468409031 -CCA(3m)A la Ferme Au Vieux Moulin - Cubieres sur Cinoble (11) >+33468698149 (419m)Le Castera - Cier De Luchon (31) [<51] >+33561793083 (595m)Le Sedour - Surba (9) (01/01-31/12) >+33561058728 -CCA-BD_FR-P.085(492m)Aire naturelle de Da Costa - Arignac (9) [<51] >+33561057801 (472m)Le Lavedan - Guchen (65) (15/06-15/09) >+33562399021 (767m)Le Ruisseau - Gouaux (65) >+33562399549 (930m)Les Cascades - Luz Saint Sauveur (65) >+33562928585 (747m)Municipal La Cote - Oust (9) >+33676516754 (504m)Municipal Fos - Fos (31) >+33561793594 (542m)Le Haut Salat - Seix (9) >+33561668178 (508m)Du Lac - Mercus (9) [<51] (30/03-29/09) >+33561059061 (464m)Les 4 Saisons - Oust (9) >+33561965555 (512m)Le Hounta - Sassis (65) >+33562929590 (679m)Toy - Luz Saint Sauveur (65) >+33562928685 (709m)Le Bergons - Esterre (65) >+33562929077 (741m)Municipal La Sapinette - Quillan (11) (01/04-31/10) >+33468201352 (316m)Le Bastan - Esterre (65) >+33562929427 (760m)Municipal La Grange - Sentein (9) [<51] >+33561048023 (725m)Municipal Le Gave d'Aspe - Urdos (64) >+33559348826 (754m)Montorgueil - Saurat (9) [<51] >+33561051290 (628m)Aire Naturelle La Grange Bigourdane - Esquieze Sere (65) [<51] >+33562928743 (689m)Les Pyrenees - Esquieze Sere (65) (05/05-28/09) >+33562928918 -CCA(677m)Les Buis - Fougax et Barrineuf (9) [<51] >+33534146069 (540m)Pyrenevasion - Sazos (65) (20/11-20/10) >+33562929154 -CCA(820m)International - Luz St Sauveur (65) (18/05-30/09) >+33562928202 -CCA(670m)La Peiriere - Tuchan (11) >+33468454650 (152m)Aire naturelle de Bernard - Cadeac (65) [<51] >+33608723553 (740m)Santa Marina - Luri (20) [<51] >+33495350286 (1m)Municipal du Pouech - Massat (9) [<51] >+33561049522 (672m)La Bernadole - Aleu (9) [<51] >+33561968991 (750m)Le Relais D'Aguilar - Tuchan (11) >+33468454784 (157m)Le Vieux Moulin - Massat (9) [<51] >+33561969666 (627m)L'Azaigouat - Biert (9) [<51] >+33561969503 (613m)La Claire - Soueix Rogalle (9) >+33561666276 (475m)Du Fontaulie Sud - Nebias (11) >+33468201762 (582m)Fount de Sicre - Montferrier (9) [<51] >+33561012097 (690m)Les Gleres - Cauterets (65) >+33562925534 (902m)La Ribere - Bareges (65) [<51] >+33680012951 (1188m)La Prairie - Cauterets (65) [<51] >+33562920704 (898m)Le Nere - Saligos (65) >+33562928130 (636m)La Vignemale - Cauterets (65) >+33562925208 (942m)So De Prous - Saligos (65) >+33562928241 (629m)Municipal Biert - Biert (9) [<51] >+33561969892 (588m)Les Bergeronnettes - Cauterets (65) [<51] >+33562925069 (884m)Municipal Arreau - Arreau (65) >+33562986556 (720m)Mer-Sable-Soleil** - Leucate (25/03-10/11) >+33468400090 (3m)Le Saillet - Cauterets (65) [<51] >+33607615112 (862m)Le Peguere - Cauterets (65) >+33562925291 (861m)Municipal Du Cap Leucate** - Leucate (01/02-30/11) >+33468489688 (4m)Le Cabaliros - Cauterets (65) (24/05-30/09) >+33562925536 -CCA(854m)Lac d'Estaing - Estaing (65) >+33562972446 (1180m)Le Mathibot - Benaix (9) [<51] (01/01-31/12) >+33561018636 (630m)Municipal Du Val D'Amour - Belesta (9) [<51] >+33561016002 (499m)Aire naturelle - Pailhac (65) [<51] >+33562986438 (774m)Municipal Clef De France - Saint Beat (31) >+33561943539 (500m)Le GR10 - Cauterets (65) >+33620302585 (848m)Tei La Garonnette - Saint Beat (31) >+33561794136 (499m)La Bernede - Rennes Les Bains (11) >+33468698649 -CCA(318m)Municipal Cierp Gaud - Cierp Gaud (31) [<51] >+33561795073 (489m)Le Fun** - Fitou (11) (01/04-10/11) >+33468457197 -CCA(10m)Municipal De Fontclaire - Puivert (11) >+33468200058 (480m)La Pose - Les Colonies (65) >+33562974310 (1102m)Municipal Les Vignes - Castillon en Couserans (9) >+33561967272 (520m)Le Petit Paradis - Campagne sur Aude (11) >+33468743202 (259m)Pre Cathare - Lavelanet (9) >+33689108213 (544m)International le Refuge - Arreau (65) >+33671787890 (688m)Municipal Le Lauzart - Lescun (64) >+33559345177 (859m)Municipal De Bagneres - Campan (65) >+33562918317 (1201m)La Roucateille - Montgaillard (9) >+33561652250 (450m)La Vie en Vert - Augirein (9) [<51] >+33561968266 (642m)Municipal De La Salle - Esperaza (11) >+33468740860 (237m)La Sirene** - Leucate (15/05-15/09) >+33468810461 (6m)Le Vieux Moulin - Estaing (65) >+33562974323 (997m)Pyrenees Natura - Estaing (65) (01/04-15/10) >+33562974544 -CCA(980m)Les 4 Veziaux - Campan (65) [<51] >+33562915622 (1078m)La Franqui - Leucate (11) (01/04-30/09) >+33468457493 (2m)Aire naturelle Les Asphodeles - Portet d'Aspet (31) [<51] >+33561961316 (1066m)Du Lac - Arques (11) [<51] (01/05-30/09) >+33468698830 (362m)Du S.I.V.O.M. Du Chalabrais - Sainte Colombe sur L'Hers (11) [<51] >+33468692220 (415m)La Fermette - Moulis (9) [<51] >+33561664351 (456m)Aire naturelle Batbere - Arrens Marsous (65) [<51] (01/01-31/12) >+33562971050 (879m)Le Pont Du Nert - Encourtiech (9) [<51] >+33561665848 (419m)Naturist - Le Clapotis - La Palme (11) (11/04-10/10) >+33468481540 -CCpg190-CCA(16m)La Station - Arrens Marsous (65) [<51] >+33561970056 (871m)La Heche - Arrens Marsous (65) >+33562970264 (860m)l'Isulottu - Centuri Morsiglia (20) >+33495356281 (28m)Aire Naturelle Mialanne - Arrens-Marsous (65) [<51] (20/06-10/09) >+33562926714 (869m)Le Larbey - Pierrefitte Nestalas (65) >+33562927461 (535m)Le Moulian - Arrens Marsous (65) >+33562974118 (860m)Le Plateau De Ley - Eaux Bonnes (64) [<51] >+33559051147 (1186m)Municipal La Barguillere - Serres sur Arget (9) [<51] >+33561652380 (507m)U Stazzo de la Plage - Rogliano (20) >+33495354376 (4m)Le Gerrit - Arrens Marsous (65) >+33562972585 (858m)l'Oree des Monts - Campan (65) >+33562918398 (941m)d'Iscoo - Eaux Bonnes (64) [<51] >+33698235493 (805m)Municipal du Rieutort - Cos (9) >+33561653979 (459m)d'Esplantats - Sarrancolin (65) >+33562987920 (629m)Aire du Temps - Siradan [<51] >+33562402785 (496m)Municipal Le Stade* - La Palme (15/06-15/09) >+33468481523 (4m)Azun Nature - Aucun (65) (01/05-30/09) >+33562974505 (844m)Lascrouts - Aucun (65) >+33562974262 (842m)Parc de Paletes - Saint Girons (9) [<51] >+33561660679 (442m)A la ferme de Marie-Therese Campet - Adast (65) [<51] >+33611171367 (440m)Les Rives de l'Adour - Campan (65) >+33562918308 (932m)Le Cazal - Chalabre (11) [<51] >+33468693473 (375m)Le Bosquet - Bun (65) >+33562970781 (800m)Les Frenes - Campan (65) >+33562918246 (921m)Les Bulanettes - Campan (65) >+33562918201 (905m)Despourrins - Accous (64) >+33559347116 (454m)Aire Naturelle La Clairiere- l'Herm (9) [<51] (01/07-30/09) >+33561016512 (548m)Rural de Pages - Saint Martin De Caralp (9) [<51] >+33561651543 (530m)A la ferme la Caoussariou - Arcizans Dessus (65) [<51] >+33562970911 (827m)Le Valentin - Laruns (64) >+33559053933 (529m)Edelweiss - Arcizans Dessus (65) >+33562970945 (813m)Aire naturelle de Terpant Pierre - Montbel (9) [<51] >+33468692018 (415m)Pont de Lauguere - Laruns (64) >+33559053599 (496m)Le Viscos - Beaucens (65) [<51] >+33562970545 (473m)Aire naturelle la Prade - Arcizans Dessus (65) [<51] >+33562972085 (778m)Les Gaves - Laruns (64) >+33559053237 (491m)Le Gourzy - Laruns (64) [<51] >+33559053112 (510m)La Regate - Leran (9) [<51] (30/03-26/10) >+33561030917 -CCA(400m)Les Chataigniers - Arcizans Avant (65) [<51] >+33562979477 (639m)Le Lac - Arcizans Avant (65) >+33562970188 (637m)Rural l'Emeraude - Chalabre (11) [<51] >+33468692854 (421m)Les Frenes - Lau Balagnas (65) >+33562972512 (439m)Bartheque - Laruns (64) >+33559053888 (541m)Le Lavedan -�Argeles Gazost (65) (01/01-31/12) >+33562971884 -CCpg159(439m)Du Lac -�Foix (9) (15/01-15/12) >+33561651158 -CCpg162(367m)Aygueberre - Laruns (64) >+33559053855 (499m)Raulet - Saint Benoit (11) [<51] (01/06-30/09) >+33468693331 (592m)Pyrenees Emotions - Malvezie (31) [<51] (15/04-31/10) >+33561881467 (798m)Le Picourlet - Arras en Lavedan (65) >+33562972542 (721m)Relais De l'Aubisque - Arras en Lavedan (65) [<51] >+33689700848 (697m)Hautacam - Prechac (65) [<51] >+33562971033 (443m)Aire naturelle La Chapelle - Lau Balagnas (65) [<51] >+33631346494 (461m)Naturist - Millefleurs - Varilhes (9) [<51] >+33561607756 (475m)Municipal Beost - Beost (64) >+33559053193 (483m)Val d'Aleth - Alet les Bains (11) [<51] >+33468699040 (205m)l'Ideal - Arras en Lavedan (65) >+33562970313 (650m)La Ferme de Lac de Peyrau - Rimont (9) [<51] >+33561963585 (460m)La Serre - Aigues Vives (9) [<51] >+33561030616 (432m)La Prairie - Lau Balagnas (65) [<51] >+33562971187 (434m)Cap du Roc*** - Port La Nouvelle (01/04-30/09) >+33468480098 (4m)Cote Vermeille* - Port La Nouvelle (15/04-15/09) >+33468480580 (2m)Municipal De Carolle - Bedous (64) [<51] >+33559347045 (402m)La Bourie** - Heches (65) (01/01-31/12) >+33562987319 (594m)Municipal L'Espazo - Durban Corbieres (11) >+33468450681 (92m)L'Arize - La Bastide De Serou (9) (01/04-12/11) >+33561658151 -CCA(428m)Le Geteu - Louvie Soubiron (64) [<51] >+33559053715 (481m)Aire naturelle de Comelongue - Ventenac (9) [<51] (01/03-31/10) >+33561607243 (454m)La Ferme de Marseillas - Saint Jean De Verges (9) [<51] >+33685471747 (397m)Audinac Les Bains - Montjoie en Couserans (9) (01/04-15/10) >+33561664450 (440m)Le Saint Roch - Campan (65) [<51] >+33559303807 (692m)Municipal Le Cagire - Aspet (31) >+33561885155 (443m)Le Deth Potz - Boo Silhen (65) >+33562903723 -CCA(489m)Le Roc Del Rey - Belloc (9) [<51] (28/04-15/10) >+33561688793 (439m)Les Trois Vallees - Argeles Gazost (65) (29/03-15/10) >+33562903547 -CCA(427m)Aire naturelle de Noguez Celestin - Gez (65) [<51] >+33562970818 (623m)Municipal Du Golfe** - Port La Nouvelle (01/04-30/09) >+33468480842 (3m)Ferme du Vignaut - Malvezie (31) [<51] >+33561796646 (624m)Ferme La Besse - Camon (9) [<51] (01/01-31/12) >+33561688463 -CCA(423m)Ibarra - Sainte Engrace (64) [<51] >+33559287359 (398m)La Bergerie - Ayzac Ost (65) (01/05-30/09) >+33562975999 -CCA(425m)Ixtila - Larrau (64) [<51] >+33559286309 (613m)Aire naturelle de Balesta Jacques - Aste-Beon (64) [<51] >+33559349101 (468m)Le Layris - Campan (65) [<51] >+33562917534 (656m)Aire naturelle Bellevue - Ayzac Ost (65) [<51] >+33562975881 (419m)Municipal De Monplaisir - Gere Belesten (64) >+33559826118 (461m)Naturist - La Pinede-Heliopolis - Ile du Levant >+33494059352 (84m)Ensoya - Sigean (01/07-31/08) >+33468484368 -CCpg191(10m)l'Arriou - Beaudean (65) >+33562917404 (637m)Municipal Bords de Garonne* - Loures Barousse (15/02-15/11) >+33562992929 (440m)Es Pibous*** - Saint Bertrand de Comminges (01/03-31/10) >+33561883142 (461m)La Ferme du Plantier - Ouzous (65) [<51] >+33562975801 (544m)La Tour Fondue - Hyeres (83) (05/04-31/10) >+33494582286 -CCA(19m)L'Estelas** - Mauvezin De Prat [<51] (01/04-15/10) >+33561966580 (357m)La Pibola - Mirepoix (9) [<51] (01/01-31/12) >+33561681214 (374m)La Chataigneraie - Agos Vidalos (65) (01/12-15/10) >+33562970740 -CCA(414m)Le Rural - Agos Vidalos (65) [<51] >+33562903153 (406m)Le Soleil du Pibeste - Agos Vidalos (65) (01/05-01/10) >+33562975323 (405m)Le Randonneur - Esparros (65) [<51] >+33562391934 (519m)Le Mediterranee - Hyeres (83) >+33494582106 (7m)l' Ile d'Or - Hyeres (83) >+33494582055 (9m)Olbia - Hyeres (83) (15/04-30/09) >+33494582286 -CCA(14m)La Presqu'Ile de Giens -�Hyeres (83) (28/03-11/10) >+33494582286 -CCpg229(7m)International de Giens - Hyeres (83) >+33494589016 (3m)La Bergerie - Hyeres (83) >+33494589175 (1m)Municipal Du Parc Du Chateau - Varilhes (9) >+33561674284 (331m)Aire naturelle de Jean-Marie Ispa - Couret (31) [<51] (409m)Municipal Du Breil - Limoux (11) [<51] >+33468311363 (171m)l'Adour - Gerde (65) >+33562952761 (573m)La Ferme Vergers de Sesame - Le Mas d'Azil [<51] >+33561699956 (345m)La Pommeraie - Gerde (65) [<51] >+33562951642 (577m)Eurosurf - Hyeres (83) >+33494580020 (1m)Aire Naturelle Arrayade - Ger (65) [<51] (15/05-30/09) >+33562941773 (398m)Les Mijeannes - Rieux De Pelleport (9) (01/01-31/12) >+33561608223 -CCA(316m)l'Ayguelade - Bielle (64) >+33559826650 (430m)La Grange Neuve*** - Sigean (01/01-31/12) >+33468485870 (9m)Aire Naturelle Cazenave Doux - Castet (64) [<51] >+33559058826 (429m)Aire naturelle de Bouchet Sauveur - Licq Atherey (64) [<51] >+33559286101 (261m)Le Rural - Tibiran Jaunac (65) [<51] >+33561883450 (453m)Les Pins**** - La Seyne sur Mer (25/06-05/09) >+33494639145 (18m)Les Fruitiers - Bagneres de Bigorre (65) >+33562952597 (543m)Buffalo Hacienda*** - La Seyne sur Mer (01/01-31/12) >+33494747208 (85m)La Neste** - Saint Laurent de Neste [<51] (01/05-30/09) >+33562397338 (464m)La Pinede*** - Six Fours les Plages (01/06-30/09) >+33494340639 (76m)La Ferme Vergers de Sesame- Le Mas d'Azil (9) [<51] >+33561699956 (372m)Bellevue des Palomieres - Bagneres de Bigorre (65) >+33562910397 (676m)Le Moulin de Barescou - Escot (64) [<51] >+33559344397 (641m)Au Jardin de la Ferme - Six Fours les Plages (83) [<51] (01/01-31/12) >+33494340107 (18m)Aire naturelle de Dedieu Gaston - Montegut Plantaurel (9) [<51] >+33561673494 (318m)Municipal La Justale** - Mane (01/04-31/10) >+33561906818 (305m)Le Petit Pyreneen - Le Mas d'Azil (9) (04/04-05/10) >+33561697137 -CCA(288m)Les Palomieres - Bagneres de Bigorre (65) >+33562955979 (656m)Municipal* - Labarthe Riviere [<51] (01/05-30/09) >+33561890322 (398m)Le Bigourdan - Pouzac (65) >+33562951357 (517m)Le Monloo - Bagneres de Bigorre (65) (01/01-31/12) >+33562951965 -CCA(525m)Municipal De la Vallee d'Ossau - Izeste (64) >+33559056867 (420m)Le Mesnil - Bagneres de Bigorre (65) [<51] (01/06-30/09) >+33562910009 (607m)Saint Pierre des Horts - Hyeres (83) >+33494576531 (19m)Les Deux Pics du Jer - Lourdes (65) [<51] >+33562942094 (408m)Aire naturelle Moulin des Baronnies - Sarlabous [<51] (01/05-31/10) >+33562390514 (351m)Les Hortensias* - Montrejeau [<51] (01/04-31/10) >+33561957443 (476m)Mauvallon 2 - Le Pradet (83) >+33494082404 (35m)Mauvallon I - Le Pradet (83) >+33494213173 (36m)Le Bedat - Pouzac (65) >+33562955817 (503m)Les Nysades - Mirepoix (9) >+33561602863 (303m)Le Rey - Louvie Juzon (64) (15/03-15/11) >+33559057852 -CCA(495m)Les Colonnes - Hyeres (83) >+33494577041 (11m)Rural de Laduree Suzanne - Montrejeau (31) [<51] >+33561958265 (512m)Midi Pyrenees** - Montrejeau (01/01-31/12) >+33561958679 -CCA(509m)Les Arbousiers - Carqueiranne (83) >+33494585656 (101m)Le Rocher Blanc - Louvie Juzon (64) [<51] >+33688633252 (381m)Les Peupliers - Hyeres (83) >+33494389594 (5m)Le Ruisseau Blanc - Lourdes (65) >+33562429483 (415m)Le Mare e Sole - Hyeres (83) >+33494575521 (7m)Les Pins Maritimes - Hyeres (83) >+33494663407 (1m)Parc des Oiseaux - Trebons (65) (01/04-30/10) >+33562953026 (504m)Municipal de Boucocers - Lagrasse (11) >+33468431005 (160m)La Foret - Lourdes (65) (29/03-31/10) >+33562940438 -CCA(428m)La Poste - Lourdes (65) [<51] >+33562944035 (404m)Le Loup - Lourdes (65) >+33562942360 (381m)Municipal Pont de l'Arroue - Arette (64) >+33559399802 (315m)A la ferme de Labau - Ladern sur Lauquet (11) [<51] >+33468694463 (216m)l'Artaudois - Le Pradet (83) (01/04-15/10) >+33494217261 -CCA(57m)Bernard - Hyeres (83) >+33494663054 (1m)Les Rives du Gave - Saint Pe de Bigorre (65) [<51] >+33562418029 (353m)Du Ceinturon III - Hyeres (83) >+33494663265 (1m)Le Prat Dou Rey - Peyrouse (65) (07/03-12/10) >+33562418154 (369m)Le Sarsan - Lourdes (65) (01/04-15/10) >+33562944309 -CCA-BD_FR-P.033(411m)Le Prat - Lourdes (65) [<51] >+33562418154 (411m)Municipal** - Gruissan (01/05-15/09) >+33468490722 (3m)International Saint Jean*** - Six Fours les Plages (01/01-31/12) >+33494875151 (44m)l'Hermitage - Le Pradet (83) >+33494217819 (55m)La Grotte aux Fees - Saint Pe de Bigorre (65) >+33562418163 (350m)Le Vieux Berger - Lourdes (65) [<51] >+33562946057 (419m)l'Arrouach - Lourdes (65) [<51] >+33562421143 (409m)Le Pin de Galle - Le Pradet (83) >+33494084579 (34m)Le Domec - Lourdes (65) >+33562940879 (426m)Les Craoues*** - Capvern (01/04-31/10) >+33562390254 (599m)Municipal - Arudy (64) [<51] >+33559058044 (403m)Rural de Blandinieres Marcel - Madiere (9) [<51] >+33561672103 (315m)Lou Pantai - Le Pradet (83) >+33494751077 (44m)Les Palmiers - Carqueiranne (83) >+33494586401 (34m)La Ferme Sobieta - Alcay Alcabehety Sunharette (64) [<51] >+33559285226 (300m)Rural Olbius Riquier - Hyeres (83) [<51] >+33494572500 (9m)Theil - Lourdes (65) [<51] >+33562942459 (412m)A la Ferme Carrique - Alos Sibas Abense (64) [<51] (01/06-30/09) >+33559285025 (223m)Les Mimosas*** - La Seyne sur Mer (01/01-31/12) >+33494947315 (36m)Municipal Belvedere Des Pyrenees*** - Saint Gaudens (01/06-30/09) >+33562001603 (407m)Les Fontanettes*** - La Seyne sur Mer (83) (01/01-31/12) >+33494947507 -CCA(40m)Aire naturelle Les Joseph - Hyeres (83) >+33611477499 (1m)Le Pont d'Abense - Tardets Sorholus (64) [<51] (15/03-11/11) >+33559285876 -CCA(225m)Le Cerf Volant - Orincles (65) [<51] (15/05-15/10) >+33562429932 (391m)Les Fontetes - Hyeres (83) >+33494664325 (1m)Les Playes** - Six Fours les Plages (83) (01/01-31/12) >+33494255757 -CCA(65m)Plein Soleil - Lourdes (65) [<51] (06/04-10/10) >+33562944093 (426m)Relais Ocean Pyrenees - Poueyferre (65) >+33562945722 (429m)Le Beau Veze - Carqueiranne (83) (01/05-15/09) >+33494576530 -CCpg228-CCA(58m)Aire naturelle Belle De Mai - Hyeres (83) >+33494384665 (42m)Rural Les Loubes - Hyeres (83) >+33494574774 (42m)Le Moulin du Monge - Lourdes (65) (01/04-10/10) >+33562942815 -CCA(420m)Orly d'Azur*** - Six Fours les Plages (01/01-31/12) >+33494255941 (28m)Le Pansard - La Londe les Maures (83) (30/03-30/09) >+33494668322 (1m)Le Pinada** - Villerouge La Cremade (01/04-30/09) >+33468433229 (154m)Du Domaine - Bormes les Mimosas (83) >+33494710312 (19m)La Plenitude** - Capvern les Bains [<51] (01/04-31/10) >+33562391456 (520m)Aire naturelle La Ramiere - Sainte Colome (64) [<51] >+33559056369 (468m)Aire naturelle Les Bergeronnettes - Bartres (65) [<51] >+33562944204 (516m)Les 4 saisons - Asasp Arros (64) [<51] >+33559344310 (268m)Clos Rose Marie - Hyeres (83) >+33494664121 (1m)Miramar - La Londe les Maures (83) >+33494668058 (1m)Domaine de la Capoulade - Gruissan (11) [<51] >+33468322759 (32m)Bel Repayre - Manses (9) [<51] >+33561681199 (407m)La Condamine - Hyeres (83) >+33494383774 (7m)Port Pothuau - Hyeres (83) (06/04-13/10) >+33494664117 (2m)Baretous-Pyrenees - Aramits (64) [<51] (18/02-26/10) >+33559341221 -CCpg157(280m)Les Moulieres - La Londe les Maures (83) >+33494015321 (5m)Municipal De Plasence - Lanne en Baretous (64) [<51] >+33559346206 (364m)Holiday Giavis - La Crau (83) >+33494389438 (40m)Le Capricorne - Hyeres (83) >+33494664094 (3m)La Celinette - Bormes les Mimosas (83) >+33494710798 (21m)Mogador*** -�Sanary sur Mer (83) (28/03-03/11) >+33494745316 -CCA(34m)La Griotte - Bormes les Mimosas (83) >+33494152072 (45m)Les Cypres - Bormes les Mimosas (83) >+33494648650 (19m)Au Pin d'Arnauteille -�Montclar (11) (17/04-15/09) >+33468268453 (240m)Le Landistou - Bruges Capbis Mifaget (64) [<51] >+33559710698 (315m)Municipal Les Chenes - Buzy (64) [<51] >+33559210556 (418m)l'Apamee - Pamiers (9) [<51] (01/05-30/10) >+33561600689 -CCpg163(274m)Rural de Chretienne - La Londe les Maures (83) >+33494668190 (6m)La Lezardiere - La Valette du Var (83) >+33494750662 (90m)La Brulade - La Londe les Maures (83) >+33494668628 (9m)Le Bon Choix - Escosse (9) [<51] (01/04-31/10) >+33561670255 (342m)Le Saillet - Lestelle Betharram (64) >+33559719865 (299m)La Pascalinette - La Londe les Maures (83) >+33494668272 (15m)Le Grand Batailler - Bormes les Mimosas (83) [<51] >+33494710841 (14m)Mas de Pierredon**** - Sanary sur Mer (83) (20/04-30/09) >+33494742502 -CCA(35m)Les Ayguades - Gruissan (11) >+33468498159 (2m)A la Ferme La Chevrerie - Bormes les Mimosas (83) [<51] (01/05-15/09) >+33494648624 (35m)Les Citronniers - Le Lavandou (83) [<51] >+33494649615 (8m)Municipal** - Saint Martory [<51] (15/06-15/09) >+33561974048 (292m)Beau Sejour - Le Lavandou (83) >+33494712530 (9m)Saint-Pons - Le Lavandou (83) >+33494710393 -BD_FR-R.124(9m)Les Mimosas*** -�Narbonne (11( (12/04-31/10) >+33468439455 -CCA(4m)La Chataigneraie* - Ade [<51] (15/06-15/09) >+33562942963 (424m)Municipal Des Eychecadous - Artigat (9) [<51] >+33561689824 (261m)Aire naturelle Municipale Fabrezan - Fabrezan (11) [<51] (08/07-25/08) >+33468278144 (68m)Ferme Equestre Equiloisirs - Sainte Croix Volvestre (9) [<51] >+33561964132 (387m)Le Ravel - Bormes les Mimosas (83) [<51] >+33494710690 (24m)Elizamburu - Ossas Suhare (64) [<51] >+33559284277 (261m)La Cote Des Roses - Narbonne (11) (01/05-07/09) >+33468498365 -CCpg193-CCA(2m)Albide - Ossas Suhare (64) [<51] >+33559285881 (193m)Saint Clair - Le Lavandou (83) >+33494013020 (18m)Soleil D'Oc*** - Narbonne (01/04-15/10) >+33468498621 -CCpg192(1m)La Nautique*** - Narbonne (11) (01/03-31/10) >+33468904819 -CCA-BD_FR-Q.102b(15m)La Pabourette - La Londe les Maures (83) (15/06-15/09) >+33494668092 (40m)Municipal** - Ferrals Les Corbieres [<51] (15/06-31/08) >+33468277575 (59m)Aire Naturelle Les Jardins d'Ossau - Buzy (64) [<51] >+33559210571 (369m)Le Port d'Alon** - Saint Cyr sur Mer (10/04-30/09) >+33494265646 (28m)Vert Gapeau - Hyeres (83) >+33494656855 (14m)Vallongue** - Bandol (01/04-30/09) >+33494294955 (131m)Le Vieux Moulin - Feas (64) >+33559398118 (240m)Le Val du Gave d'Aspe - Gurmencon (64) [<51] >+33559360507 (264m)Rural Les Arbousiers - La Crau (83) [<51] >+33624402038 (59m)Le Pramousquier - Le Lavandou (83) (19/04-29/09) >+33494058395 -CCA(27m)La Ferme des Janets - Bormes les Mimosas (83) [<51] >+33494714511 (60m)Grand Sud*** - Preixan (11) (01/04-30/09) >+33468268818 -CCA(126m)Clos Sainte Therese*** -�St Cyr-Mer (83) (05/04-30/09) >+33494321221 -CCA(131m)La Falaise*** - Narbonne (01/04-30/09) >+33468498077 (3m)Eyharche - Barcus [<51] (01/07-01/11) >+33559289452 (391m)Lei Suves - Le Lavandou (83) >+33494454395 -CCA(53m)Les Bois de Mont-Redon - La Crau (83) >+33494667334 (57m)Colline - Feas [<51] (15/05-30/09) >+33559361402 (241m)Municipal De Plaza-Berri - Saint Jean Pied de Port (64) >+33559371119 (171m)l'Hubac du Bleu - Le Lavandou (83) (01/04-30/09) >+33494058388 (76m)Manjastre - Bormes les Mimosas (83) (01/01-31/12) >+33494710328 -CCpg230(79m)Aire naturelle Municipale Fontcouverte - Fontcouverte (11) [<51] >+33468439066 (87m)Figurotta* - Bizanet [<51] (01/01-31/12) >+33468451626 (105m)A la Ferme Polfages - Villautou (11) [<51] >+33468606526 (348m)Mendy - Saint Jean le Vieux (64) [<51] >+33559371181 (204m)A la ferme Les Brugues - Fanjeaux (11) [<51] (01/06-30/09) >+33468247737 (336m)De la Truite - Uhart Cize (64) [<51] >+33559373122 (155m)Les Floralys** - Narbonne [<51] (01/03-30/11) >+33468326565 (5m)Aire naturelle La Magdeleine - Saint Jean le Vieux (64) [<51] >+33559370263 (176m)Bonporteau - Cavalaire sur Mer (83) (15/03-15/10) >+33494640324 -CCA(22m)l'Arradoy - Saint Jean Pied de Port (64) >+33559370039 (159m)A la ferme Du Lac de la Laure - Unzent (9) [<51] >+33561603316 (305m)La Baie - Cavalaire sur Mer (83) (15/03-15/11) >+33494640815 -CCA(17m)La Treille - Cavalaire sur Mer (83) (11/04-11/10) >+33494643181 -CCpg231(24m)La Bergerie** - Lanne (01/07-05/09) >+33562454005 (366m)Aire naturelle Le Moulin - Momeres (65) [<51] >+33562459434 (374m)La Pinede - Cavalaire sur Mer (83) >+33494641114 (17m)Les Baumelles*** - Saint Cyr sur Mer (01/04-31/10) >+33494262127 (8m)Europ'Camping - Ascarat (64) [<51] >+33559371278 (158m)Municipal Lailleres - Le Fossat (9) [<51] >+33561685012 (242m)La Paix des Champs - Saint Jean le Vieux (64) [<51] >+33559370416 (177m)Narbaitz -�St Jean Pied de Port (64) (26/04-12/09) >+33559371013 -CCA(150m)A la Ferme La Chevaline- Fanjeaux (11) [<51] (01/06-16/09) >+33468247533 (333m)Municipal Du Lac** - Boussens [<51] (01/01-31/12) >+33561900360 (265m)G�teS du Stade - Oloron Sainte Marie (64) >+33559391126 (241m)A L'Ombre Des Oliviers*** - Cazilhac (01/01-31/12) >+33468796508 (147m)Cros de Mouton -�Cavalaire (83) (15/03-01/11) >+33494641087 -CCA(57m)Municipal l'Irouleguy - Saint Etienne de Baigorry (64) >+33559374396 (147m)La ferme Le Petit Real - Sollies Pont [<51] >+33494289480 (62m)La Sauge** - La Ciotat (01/04-30/09) >+33442834765 (20m)Les Amandiers - Sollies Pont (83) >+33494289081 (65m)Municipal Pissevaches - Fleury (11) >+33468498079 (2m)La Baie des Anges**** - La Ciotat (01/04-30/09) >+338000234729 (30m)Municipal Du Rensou** - Tournay [<51] (01/01-31/12) >+33562352262 (259m)Santa Gusta - La Ciotat >+33442831417 (14m)Belle Plage** - La Ciotat [<51] (01/01-31/12) >+33442831472 (7m)La Truite - Ascarat (64) >+33559373122 (144m)Le Canteraines - Le Vernet (09) [<51] >+33673956251 (252m)Le Moulin*** - Martres Tolosane (31) (01/04-05/10) >+33561988640 -CCA(255m)Le Bourdieu - Durfort (9) [<51] (30/05-10/10) >+33561673017 -CCpg164(285m)La Promesse - Bonrepos (65) [<51] >+33562395810 (434m)La Cigale - Ramatuelle (83) >+33494792253 (66m)Le Domaine de Montaut - Montaut (9) [<51] >+33561683416 (295m)Selection -�La Croix Valmer (83) (15/03-15/10) >+33494551030 -CCA(23m)La Ferme de La Reoule - Le Fossat (9) [<51] >+33561685828 (305m)Le Plantaurel*** - Palaminy (01/01-31/12) >+33561970371 (239m)Municipal* - Montreal [<51] (15/06-31/08) >+33468762005 (229m)La Cite*** - Carcassonne (25/03-05/10) >+33468251177 (109m)La Malissonne**** - La Cadiere d'Azur (05/03-20/11) >+33494901060 (99m)La Ferme Landran - Mauleon (64) [<51] >+33559281955 (219m)Les O Kiri - Baudreix (64) (01/04-30/09) >+33559929773 -CCpg158(240m)La Pinede *** - Lezignan Corbieres (01/03-31/10) >+33468270508 -BD_FR-Q.060a(66m)A la ferme La Communion - Latour (31) [<51] >+33561903934 (315m)Les Tournels - Ramatuelle (83) >+33494559090 (30m)Naturist - La Grande Cosse - Fleury (11) (05/04-05/10) >+33468336187 -CCpg194-CCA(2m)La Ferme Chez Marcel - Ramatuelle (83) [<51] >+33494798607 (20m)l'Ombre des Micocouliers ** - Trebes (11) (01/04-30/09) >+33468786175 -CCA(83m)Uhaitza le Saison - Mauleon Licharre (64) [<51] >+33559281879 (149m)Inxauseta - Bunus (64) [<51] >+33559378149 (186m)A la ferme la Graousse - Villeneuve du Latou (9) [<51] >+33673876778 (335m)Lac Saint Georges - Sarrecave (31) [<51] >+33561882336 (362m)Rural de Giraud Gustave - Ramatuelle (83) [<51] >+33494799397 (18m)La Croix du Sud - Ramatuelle (83) >+33494555123 (20m)Les Petites Pyrenees - Aurignac (31) [<51] >+33561987008 (401m)Commanderie - Rustiques (11) [<51] >+33468786763 (129m)Municipal Rive-D'Aude - Fleury (11) >+33468336732 (3m)Belair - Lasseube (64) [<51] >+33559042255 (179m)Le Castillon ** - Le Castellet (15/05-15/10) >+33494326033 (147m)Le Moulin de Verdagne - Gassin (83) (01/04-30/09) >+33494797821 (60m)Le Ceyreste*** - Ceyreste (01/04-31/10) >+33442830768 -CCA(156m)Aire naturelle Municipale - Montmaurin (31) [<51] >+33561797147 (383m)Les Cigales** - Cassis (15/03-15/11) >+33442010734 (96m)Les Foulegues**** - Valras Plage (10/04-30/09) >+33467373365 (4m)Pre Fixe - Cassagnabere Tournas (31) [<51] (01/04-31/10) >+33561987100 -CCA(390m)Blue Bayou**** - Valras Plage (10/04-30/09) >+33467374197 -CCpg195-CCA(2m)Saint-Meen - Valras Plage (34) >+33499410351 (3m)Palmira Beach - Valras Plage (34) (02/04-30/10) >+33467942900 -CCA(2m)Le Chenelierre - Lasseube (64) [<51] >+33559042249 (266m)Les Sablines*** - Valras Plage (01/04-15/09) >+33467374036 (2m)Les Vagues**** -�Valras Plage (34) (15/04-30/09) >+33467373312 -CCA(4m)Naturist - De l'Escride - Belgentier (83) >+33494489724 (146m)Les Tomasses - Belgentier (83) >+33494489270 (169m)Kon Tiki - Ramatuelle (83) >+33494559696 (15m)Aire naturelle Mendikoa - Osses (64) [<51] >+33559377367 (143m)Marina ** - Valras Plage (01/05-20/09) >+33467373380 (5m)Le Defends - Pierrefeu du Var (83) >+33494282062 (82m)Lou Village**** - Valras Plage (34) (26/04-14/09) >+33467373379 -CCA(4m)La Rouillere - Ramatuelle (83) >+33671645909 (56m)La Plage et du Bord de Mer*** - Valras Plage (34) (01/05-20/09) >+33467373438 -CCA(3m)Naturist - La Leze - Gaillac Toulza (31) (01/04-01/11) >+33561084537 (302m)Le Mediterranee** - Valras Plage (01/05-05/09) >+33467373429 (3m)Municipal De Saint Roch - Collobrieres (83) (01/05-31/08) >+33494480800 (166m)La Yole**** - Valras Plage (01/05-21/09) >+33467373387 (5m)Municipal Les Sablous ** - Salles d'Aude [<51] (15/06-15/09) >+33468336173 (18m)Ferme Bahoc - Suhescun (64) [<51] >+33559376083 (229m)Parc Saint James - Gassin (83) >+33494552020 (20m)l'Oasis - Coursan (11) [<51] (01/05-30/09) >+33468335462 (9m)A la ferme Les Eucalyptus - Ramatuelle (83) [<51] (08/05-15/09) >+33689724994 (8m)Municipal Les Berges du Joos - Saint Goin (64) [<51] >+33559880003 (172m)A la Ferme Le Pergouille - Calmont (31) [<51] >+33603437272 (238m)La Bastide - Mazeres (9) (01/05-15/09) >+33561693882 -CCA(232m)Central *** - Valras (15/04-15/09) >+33467321078 (4m)Riviere - Saverdun (9) (01/06-30/09) >+33561603012 (225m)Municipal - Monleon Magnoac (65) [<51] >+33562994008 (356m)La Jasse ** - Valras (01/05-30/09) >+33467321336 (4m)Les Grands Pins ** - Le Castellet (01/01-31/12) >+33494907144 (400m)Le Levant *** - Valras (15/04-15/09) >+33467320445 (1m)Le Gavaudan Blue Garden - Meounes les Montrieux (83) [<51] >+33494489534 (191m)l'Argentiere - Cogolin (83) >+33494546363 (20m)Mas des Lavandes *** - Valras (22/06-01/09) >+33467397588 (13m)A la ferme La Pujade - Alzonne (11) [<51] >+33613118020 (129m)Das Pinhiers - Villemoustaussou (11) [<51] >+33468478190 (121m)Municipal Salleles D'Aude - Salleles D'Aude (11) [<51] >+33468466846 (15m)Naturist - Le Clos De Ferrand - Serignan (34) >+33467321430 (0m)Le Clos de la Grangette - Serignan (34) (14/03-14/10) >+33467352311 -CCpg197(2m)Naturist - L'Eglantiere -�Castenau-Magnoac (65) (13/04-30/09) >+33562398800 -CCpg160-CCA(321m)Naturist - Le Serignan Plage Nature -�Serignan (34) >+33467323533 (1m)Le Serignan Plage*** - Serignan (34) (25/04-30/09) >+33467323533 -CCA(2m)Rural de Cannova Sauveur - Grimaud (83) [<51] >+33494433627 (15m)Aire naturelle Querelles - Serignan (34) >+33467320301 (12m)Yotel de Cogolin - Cogolin (83) >+33494562044 (3m)Le Golfe de Saint-Tropez - Grimaud (83) >+33494432695 (15m)Aire Naturelle Amestoya - Bidarray (64) [<51] >+33559377237 (82m)Beausejour*** - Serignan-Valras (01/04-30/09) >+33467395093 -CCA(3m)Pyrenees Passion - Aren (64) [<51] >+33559880188 (156m)Aloha**** - Serignan (34) (20/04-15/09) >+33467397130 -CCA(2m)La Ferme Contresty - Raissac sur Lampy (11) [<51] >+33468760429 (150m)Municipal Les Cardonilles** - Vendres (15/05-30/09) >+33467395714 (33m)Etoile de Mer - Serignan (11/04-26/09) >+33467774082 -CCpg198(4m)Bleu Marine*** - Serignan Plage (10/04-20/09) >+33467323533 (2m)Le Paradis *** - Serignan (01/04-30/09) >+33467322403 (5m)Le Clos Virgile**** - Serignan Plage (34) (10/05-15/09) >+33467322064 -CCA-BD_FR-Q.111(4m)Holiday Marina - Grimaud (83) >+33494560843 (2m)Municipal du Plan d'Eau** - Rieux [<51] (01/04-31/10) >+33561879883 (226m)La Donadive - Nissan lez Enserune (34) >+33467370020 (51m)La Maire*** - Serignan Plage (01/04-15/09) >+33467397200 (2m)Charlemagne - Grimaud (83) >+33494432290 (17m)La Pinede - Grimaud (83) (28/03-07/11) >+33494560436 -CCpg232(19m)Aux Tonneaux - Meounes les Montrieux (83) >+33494339834 (239m)La Mer** - Agde (34) (12/04-30/09) >+33467947221 -CCA(4m)Le Rochelongue*** - Cap d'Agde (34) (12/04-12/10) >+33467212551 -CCA-BD_FR-Q.134d(4m)Iholdy - Iholdy (64) [<51] >+33559375309 (148m)Aire naturelle Lyons Var Hpa - Grimaud (83) [<51] >+33494563451 (22m)Familial de Venissieux** - Portiragnes (15/04-15/09) >+33467909244 (4m)Les Sablons**** - Portiragnes (34) (11/04-30/09) >+33467909055 -CCA-BD_FR-Q.115(4m)l'Eden Roc** - Agde (01/05-15/09) >+33467947702 (4m)Prairies de la Mer - Grimaud (83) (05/04-12/10) >+33494790909 -CCA(7m)La Plage - Grimaud (83) >+33494563115 (5m)Le Mediterranee Plage - Portiragnes (34) (05/04-30/09) >+33467909907 -CCA(3m)A la ferme de Poubian Georges - Artigueloutan (64) [<51] >+33559818686 (267m)Le Moulin de Sainte Anne - Villegly (11) (01/04-31/10) >+33468722080 -CCA(144m)Le Lac - Boulogne sur Gesse (31) >+33561882054 (306m)Les Auberges - Pouzols Minervois (11) >+33468462650 (54m)Des Mures - Grimaud (83) (05/04-01/10) >+33494561697 -CCA(2m)La Clape - Agde (34) >+33467264132 (6m)Des Naiades - Grimaud (83) >+33494556780 (19m)Cayola - Vias (34) >+33467900185 (5m)Mer et Soleil*** - Agde (34) (15/04-30/09) >+33467942114 -CCA(8m)La Tama** - Agde (15/04-15/09) >+33467947946 (4m)Le Val de Cesse - Mirepeisset (11) >+33468461494 (40m)Le Roucan West - Vias (34) (15/05-15/09) >+33467216464 -CCA(4m)Le Roucan Plage** - Vias (15/06-15/09) >+33467216464 (5m)l'Emeraude*** - Portiragnes (20/05-31/08) >+33467909376 (0m)Le Pedro** - Agde (01/04-30/09) >+33467214939 (9m)Les Mimosas** - Agde (34) (20/03-20/10) >+33467016736 -CCA(7m)Les Sablettes*** - Agde (34) (01/04-30/09) >+33467943665 -CCA-BD_FR-Q.128(6m)Le Brouet - Agde (34) >+33467215792 (9m)Les Sapins*** - Ousse [<51] (01/01-31/12) >+33559817903 (256m)Le Baluffe - Agde (34) [<51] >+33467210015 (7m)Aire Naturelle Goyenetche - Sare (64) [<51] >+33559542834 (66m)La Canotte - Agde (34) (20/05-10/09) >+33467941574 (1m)California Plage**** - Vias (34) (01/04-30/09) >+33467216469 -CCA(6m)Les Flots Bleus*** - Vias (01/05-20/09) >+33467216480 (6m)Les Mimosas*** - Portiragnes (15/05-31/08) >+33467909292 (0m)La Bergerie** - Gemenos (01/01-31/12) >+33442322238 (125m)Farret**** - Vias (15/04-30/09) >+33467216445 (3m)Le Mas de la Plage*** - Vias (34) (01/04-30/09) >+33467216427 -CCA(7m)Xokoan - Ainhoa (64) [<51] (01/02-30/11) >+33559299026 (77m)Napoleon**** - Vias (34) (15/04-28/09) >+33467010780 -CCA(5m)Le Berard - La Garde Freinet (83) >+33494432123 (166m)Helios*** - Vias (34) (04/05-30/09) >+33467216366 -CCA(4m)Cap Soleil*** - Vias (15/04-20/09) >+33467216477 (6m)Les Cigales - Vias (10/04-20/09) >+33467010707 (6m)La Gabinelle*** - Sauvian (10/04-20/09) >+33467395087 (7m)Municipal De Carolle - Castelnau Magnoac (65) [<51] >+33562398062 (318m)Ferme De Preville - Boulogne sur Gesse (31) [<51] >+33561882312 (320m)Les Romarins** - Agde (34) (01/04-30/09) >+33467941859 -CCpg200-CCA(0m)La Pepiniere** - Agde (34) (10/04-30/09) >+33467941094 -CCA(0m)A la ferme Ospitalia - Helette (64) [<51] >+33559379879 (266m)l'Escale*** - Agde (34) (01/04-30/09) >+33467212109 -CCA(0m)Champs Blancs**** -�Agde (01/04-30/09) >+33467942342 -CCpg201(13m)Aire naturelle Ferme Anica - Monein (64) [<51] >+33559212949 (165m)Les Ondines*** - Vias (15/04-15/09) >+33467216359 (3m)Naturist - Rene Oltra - Agde (34) >+33467010636 (1m)Goxoki - Charritte De Bas (64) [<51] (01/07-31/08) >+33559288140 (125m)Montolieu - Montolieu (11) [<51] (15/03-31/10) >+33468248808 -CCA(140m)Le Navarre*** - Vias (15/04-20/09) >+33467216405 (4m)Neptune*** -�Agde (34) (01/04-30/09) >+33467942394 -CCA(1m)Les Salisses**** -�Vias-Plage (15/04-15/09) >+33467216407 -CCpg199(2m)Au Palmier de Barran - Montbernard (31) [<51] >+33561941904 (282m)Claire Fontaine** - Aubagne (01/01-31/12) >+33442030228 (152m)Municipal Pepieux - Pepieux (11) [<51] >+33468918488 (90m)Municipal Les Noisetiers** - Eslourenties Daban [<51] (01/06-30/09) >+33559041584 (388m)La Petite Rhune - Sare (64) [<51] >+33559542397 (92m)L'Air Marin*** - Vias (34) (01/05-27/09) >+33467216490 -CCA(3m)Municipal de Regambert - Salles sur l'Hers (11) [<51] >+33468603022 (241m)International de l'Herault*** - Agde (04/04-26/09) >+33467940101 (2m)Les Mediterranees-Beach Garden - Marseillan (34) (11/04-27/09) >+33467219283 -CCA(4m)Europ 2000 - Marseillan (34) >+33467219285 (3m)Beausejour - Marseillan (34) >+33467219300 (2m)De Baldy - Agde (34) >+33467944450 (17m)Le Grillon Des Mers - Marseillan (34) >+33467219289 (2m)Aire naturelle Harazpy - Ainhoa (64) [<51] >+33559298938 (117m)Les Mediterranees-Nouvelle Floride - Marseillan (34) >+33467219449 (3m)La Plage - Marseillan (34) >+33467219254 (3m)Le Cap Agathois - Agde (34) >+33467940221 -CCA(3m)Le Rieu - Marseillan (34) >+33467219258 (2m)Les Mediterranees-Charlemagne - Marseillan (34) (11/04-27/09) >+33467219249 -CCA(1m)7 Fonts - Agde (34) >+33825002030 (8m)La Jasse Sur Mer - Marseillan (34) >+33467219247 (1m)Le Galet - Marseillan (34) (01/04-30/09) >+33467219561 -CCA(4m)Aire Naturelle La Palmeraie - Agde [<51] (01/04-30/09) >+33467949467 (3m)La Dragonniere**** -�Vias (34) (01/04-30/09) >+33467010310 -CCA(8m)La Creole - Marseillan (34) (29/03-19/10) >+33467219269 -CCA(3m)Beauregard Sud-Dunes et Soleil - Marseillan (34) (29/03-19/10) >+33467771868 -CCA(2m)Municipal Lubret Saint Luc - Lubret Saint Luc (65) [<51] >+33562355294 (310m)Les Amandiers - Vias (10/04-30/09) >+33467216747 (21m)La Mouette - Marseillan (34) [<51] >+33467218892 (1m)Beauregard Plage - Marseillan Plage (34) (29/03-15/10) >+33467771545 -CCA(3m)Le Cathare - Belflou (11) [<51] >+33468603249 (249m)La Cesse - Bize Minervois (11) [<51] >+33468461440 (55m)Municipal Trie sur Baise - Trie sur Baise (65) [<51] >+33562355021 (246m)Municipal Le Gourg Du Maffre - Marseillan (34) >+33467219052 (2m)Les Berges du Canal*** - Villeneuve les Bezier (34) (15/03-18/10) >+33467393609 -CCpg196-CCA(9m)Domaine de la Capelle- Saint Martin Lalande (11) [<51] >+33468949190 (166m)Les Peupliers** - Colombiers (34) [<51] (01/01-31/12) >+33467370526 -CCA(28m)Lou Garagai - Rocbaron (83) [<51] >+33682859791 (359m)Robinson - Marseillan (34) (19/04-21/09) >+33467219007 -CCA(2m)Municipal du Stade - Monein (64) [<51] >+33559214609 (134m)Municipal Le Pisse Saumes - Marseillan (34) (01/06-31/08) >+33467219058 (1m)Municipal Beau Rivage - Navarrenx (64) [<51] >+33559661000 (122m)Les Virgiles - Sainte Maxime (83) [<51] >+33494961979 (26m)La Giraille* - Castelnaudary [<51] (23/06-31/08) >+33468941128 (188m)Le Terrier*** - Lescar (01/01-31/12) >+33559810182 (152m)Granet - Marseillan (34) >+33467219381 (1m)Le Paradou - Marseillan (34) >+33467219010 (3m)Municipal Les Courtals - Caunes Minervois (11) [<51] >+33468780028 (185m)Le Casties - Casties Labrande (31) >+33561908111 (258m)A la ferme Erreka - Espelette (64) [<51] >+33559938029 (108m)La Beaumette - Sainte Maxime (83) (31/03-29/09) >+33494961092 -CCpg233(20m)Sud Loisirs - Agde (34) >+33467210910 (7m)Du Vernis - Azillanet (34) >+33468911322 (210m)Municipal Tounel - Capestang (34) >+33467933423 (16m)Le Nautic - Marseillan (34) >+33467219340 (1m)Municipal Ur-Alde - Saint Palais (64) >+33559657201 (43m)Lou Soulei - Carry le Rouet (13) >+33442447575 (8m)Lou Cigalon - Martigues (La Couronne) (13) >+33442496171 (6m)Les Mouettes - Martigues (La Couronne) (13) >+33442807001 (15m)Les Cigalons - Sainte Maxime (83) (23/03-12/10) >+33494960551 -CCA(8m)L'Arquet - Martigues (La Couronne) (13) >+33442428100 (20m)Le Mas - Martigues (La Couronne) (13) >+33442807034 (19m)Le Canard Fou - Lunax (31) [<51] >+33561882606 (293m)Municipal Le Belvedere - Lastours (11) [<51] (15/06-15/09) >+33618944127 (308m)Le Col d'Ibardin*** - Urrugne (01/04-30/09) >+33559543121 -CCA(86m)Pascalounet - Martigues (La Couronne) (13) (01/04-30/09) >+33442437087 -CCpg225-CCA(7m)Marius - Martigues (La Couronne) (13) >+33442807029 (8m)La Laune - Plan de la Tour (83) [<51] (01/05-01/09) >+33660427551 (41m)Mendi-Azpian - Urrugne (64) >+33559543346 (67m)A la ferme Le Pre de Baume - Besse sur Issole (83) [<51] (01/04-02/11) >+33494596496 (252m)La Royale - Villardonnel (11) [<51] >+33468775113 (381m)Hiriberria - Itxassou (64) (01/01-31/12) >+33559299809 -CCA(79m)La Vidaresse - Sainte Anastasie sur Issole (83) >+33494722175 (280m)Le Martinet Rouge - Brousses et Villaret (11) >+33468265198 (383m)A Cassagnau - Chelan (32) [<51] >+33562660958 (259m)Alegra - Souraide (64) >+33559939180 (60m)Le Castellas - Sete (34) (11/04-20/09) >+33467516300 -CCpg202(1m)Rural Cap de Port - Saissac (11) [<51] >+33468244255 (326m)Naturist - Le Mas de Lignieres - Cesseras (34) [<51] >+33468912486 (248m)Municipal Du Ramier - Auterive (31) [<51] >+33561506573 (188m)Aire-Ona - Urrugne (64) >+33610437660 (76m)Aire naturelle Donamartia - Saint Pee sur Nivelle (64) [<51] >+33559545059 (25m)Fontrailles - Fontrailles (65) [<51] (01/07-30/09) >+33562356252 (258m)Chourio - Ascain (64) [<51] >+33559540631 (17m)Municipal - Montaner (64) [<51] >+33559819355 (326m)Municipal De la Piscine** - Morlaas [<51] (15/05-30/09) >+33559120087 (283m)Guinguette du Lac - Besse sur Issole (83) >+33494697414 (258m)Biper Gorri - Espelette (64) (29/03-08/11) >+33559939688 -CCA(42m)Ascain - Ascain (64) [<51] >+33559544061 (6m)Le Lac de Thesauque*** - Nailloux [<51] (01/01-31/12) >+33561813467 (214m)Bixta Eder - Cambo les Bains (64) (13/04-13/10) >+33559299423 (80m)Naturist - La Vitarelle - Villaniere (11) [<51] >+33616048385 (498m)Les Truites*** - Ascain (15/06-30/09) >+33559540119 (3m)l'Ibarron - Saint Pee sur Nivelle (64) >+33559541043 -CCA(13m)Les Bruyeres** - Le Luc (01/01-31/12) >+33494734707 (128m)Aire naturelle Epherra - Souraide (64) [<51] >+33559541342 (148m)Manex - Saint Pee sur Nivelle (64) [<51] >+33559541342 (120m)Aire naturelle Municipale - Avignonet Lauragais (31) [<51] >+33561816367 (193m)Municipal La Petite Colle - Nans les Pins (83) [<51] >+33494786598 (400m)Le Moulin de Saint Jean - Saissac (11) >+33468763608 (504m)De Clairac - Beziers [<51] (01/04-30/09) >+33467767897 (40m)Goyetchea - Saint Pee sur Nivelle (64) >+33559541959 (39m)Au Paradis des Campeurs - Saint Aygulf (83) (01/04-30/09) >+33494969355 -CCA(8m)Rural de Loiseau - Minerve (34) [<51] >+33467971495 (475m)Le Moulin - Hendaye (64) >+33559207635 (39m)Dorrondeguy - Hendaye (64) >+33559202616 (36m)d'Hortes - Bessan (34) >+33467775110 (12m)Rural de Lafitte Veronique - Nailloux (31) [<51] >+33561813498 (246m)Larrouleta*** - Urrugne (01/01-31/12) >+33559473784 -CCA(7m)Les Acacias*** - Hendaye (01/04-30/09) >+33559207876 (36m)Ur-Hegia - Cambo les Bains (64) >+33559297203 (31m)Bernadou - Fontiers Cabardes (11) [<51] >+33468265230 (638m)Ametza*** - Hendaye (01/05-31/10) >+33559200705 -CCA(46m)Les Deux Jumeaux - Hendaye (64) [<51] >+33559200165 (22m)Alturan*** - Hendaye (01/06-30/09) >+33559200455 (27m)Elsuya* - Hasparren (01/07-31/08) >+33559296757 (200m)Municipal Les Oliviers - Creissan (34) [<51] >+33467938185 (110m)La Corniche*** - Urrugne (01/04-30/09) >+33559200687 -CCpg156(30m)Eskualduna*** - Hendaye (01/05-30/09) >+33559200464 (34m)Le Bout du Monde - Verdun en Lauragais (11) [<51] >+33468949596 (474m)La Sainte Baume - Nans les Pins (83) (01/04-30/09) >+33494789268 -CCpg227(408m)Aire naturelle Municipale Caudebronde - Caudebronde (11) [<51] >+33468265443 (548m)Suhiberry*** - Urrugne (01/05-30/09) >+33559470623 -CCA(9m)Saint-Jacques - Laas (64) [<51] >+33559661945 (95m)Chapital*** - Hasparren (01/05-30/09) >+33559296294 (71m)Unxin Socoa - Urrugne (64) >+33559472709 (9m)Aire naturelle de Anglade-Salvaire - Marseillan (34) >+33467625748 (32m)Domaine au Piet - Montpezat (32) [<51] >+33562624452 (280m)Le Pin Parasol** - Saint Thibery (34) (01/04-31/10) >+33467778429 (39m)Municipal La Galotte - Rabastens de Bigorre (65) >+33609863133 (216m)Naturist - Saint-Laurent - Montferrand (11) [<51] >+33468601580 (275m)St. Aygulf Plage** - St. Aygulf (10/04-25/10) >+33494176249 (9m)A la ferme Mamia Baita - Ustaritz (64) [<51] >+33559930398 (22m)Juantcho*** - Urrugne (01/05-30/09) >+33559471197 -CCA(21m)Le Gave - Sauveterre de Bearn (64) [<51] >+33671606957 (52m)Aire Naturelle Villemarin - Pinet (34) [<51] (01/04-12/11) >+33467770462 (5m)Le Rebau*** - Montblanc (34) (10/03-15/10) >+33467985078 -CCA(20m)La Bergerie**** - Roquebrune s/Argens (83) (01/05-30/09) >+33498114545 -CCA(17m)La Gantesse - Saint Zacharie (83) [<51] >+33442729138 (339m)Elgar - Saint Jean de Luz (64) >+33559268585 (20m)Municipal Plan d'Eau Birotos - Pradelles Cabardes (11) >+33468261447 (787m)Aire naturelle Municipale Barinque - Barinque (64) [<51] >+33559689116 (218m)Naturist - Terre De Soleil - Pinet (34) >+33467779909 -CCA(16m)Ferme d'Erromardie*** - St. Jean de Luz (15/03-30/09) >+33559512685 -CCA(9m)Municipal** - Brignoles (01/04-05/10) >+33494692010 (217m)Erromardie**** - St. Jean de Luz (64) (15/03-10/11) >+33559260774 -CCA(8m)Bord de Mer*** - St. Jean de Luz (64) (11/04-02/11) >+33559262461 -CCA(4m)A la ferme Le Poul'Art - Rieumes (31) [<51] (15/03-15/01) >+33534472712 (292m)Les Lauriers Roses**** - St. Aygulf (20/04-30/09) >+33494812446 (10m)La Verdiere - Septemes les Vallons (13) >+33491655998 (230m)La Foret - Rieumes (31) [<51] >+44534472712 (291m)La Rigole - Les Cammazes (81) >+33563732899 (622m)Municipal Chibaou-Berria - Saint Jean de Luz (64) >+33559261194 (12m)Residence du Campeur*** - St. Aygulf (83) (15/04-15/10) >+33494810159 -CCA(12m)La Plage d'Argens** - St. Aygulf (83) (05/04-13/10) >+33494511497 -CCA(1m)Rural l'Orme - Roquebrune sur Argens (83) >+33494829078 (14m)Les Jardins du Mai Tai - Saint Aygulf (83) (15/04-30/09) >+33494813053 -CCA(13m)Le Vaudois*** - Roquebrune s/Argens (83) (01/05-30/09) >+33494813770 -CCA(9m)Le Maya - Saint Jean de Luz (64) >+33559265491 (40m)La Grand' Piece - Saint Aygulf >+33494810990 (3m)A La Ferme Les Armengauds - Labecede Lauragais (11) [<51] (01/06-15/09) >+33534661227 (266m)Itsas Mendi*** - St. Jean de Luz (25/03-05/11) >+33559265650 -CCpg155-CCA(49m)Playa *** - St. Jean de Luz (01/04-11/11) >+33559265585 (36m)Inter-Plages*** - St. Jean de Luz (64) (01/04-30/09) >+33559265694 (37m)Atlantica*** - St. Jean de Luz (64) (01/04-30/09) >+33559477244 -CCA(38m)Etoile d'Argens**** - St. Aygulf (01/04-30/09) >+33494810141 (13m)Arena - Saint Jean de Luz (64) >+33559265190 (23m)Plage Soubelet - Saint Jean de Luz (64) >+33559265160 (30m)Municipal De Bottai - Port de Bouc (13) >+33442062664 (2m)La Barque*** - St. Aygulf (83) (01/04-31/10) >+33494813186 -CCA(10m)Le Dramont - Saint Raphael (83) >+33494820768 (13m)Tamaris - Saint Jean de Luz (64) (11/04-02/11) >+33559265590 -CCA(17m)Duna Munguy*** - St. Jean de Luz (01/03-30/09) >+33559477070 (14m)Merko Lacarra*** - St. Jean de Luz (01/04-05/10) >+33559265676 (19m)Royal - Agay (83) >+33494820020 (9m)Municipal les Terrasses - Saint Chinian (34) [<51] >+33467382828 (150m)De la Cigaliere*** - Le Cannet des Maures (01/04-30/09) >+33494738106 (174m)Peyrebazal - Les Brunels (11) [<51] >+33468604223 (582m)La Merindole - Port de Bouc (13) >+33442062689 (23m)Aire naturelle Saint Esprit - Meze (34) [<51] >+33467439500 (35m)Municipal La Pascale - Servian (34) >+33467308489 (58m)Municipal Les Pres - Cabasse (83) [<51] >+33494802214 (190m)Le Jai - Marignane (13) >+33608993761 (0m)Aux Memes - Bellegarde (32) [<51] (01/04-15/09) >+33562669145 (298m)Les Terrasses d'Harrobia*** - Bidart (01/04-30/09) >+33559265471 (16m)La Tamarissade** - Frontignan (01/07-31/08) >+33467430540 (1m)Le Provencal*** - St. Maximin la Sainte Baume (01/04-30/09) >+33494781697 (332m)Les Cledelles - Masseube (32) >+33562660175 (198m)Mediterranee** - Frontignan (01/04-30/09) >+33499049232 (0m)A la ferme La Vernede - Roquebrune sur Argens (83) [<51] >+33494457626 (20m)l'Horizon* - Frontignan (01/01-31/12) >+33467187950 (0m)Riqu'et Zette** - Frontignan (06/04-25/09) >+33499040430 (0m)Beau Rivage*** -�Meze (15/04-20/09) >+33467438148 -CCpg203(2m)Las Prades - Vaudreuille (31) >+33561834320 (344m)Municipal Arfons - Arfons (81) [<51] >+33563741137 (664m)Municipal du Ramier** - Vernet (01/01-31/12) >+33561083398 (169m)La Plage - Bidart (64) (25/06-10/09) >+33559549269 (4m)De Montrose*** - Pezenas (01/05-30/09) >+33467985210 (79m)Domaine du Plan - Puget sur Argens (83) >+33494455186 (7m)A la ferme Solongo - Pardailhan (34) [<51] >+33467971808 (585m)Agay Soleil - Agay (83) >+33494820079 (9m)Les Amandiers** - Castelnau de Guers [<51] (15/02-14/01) >+33467989251 (31m)Ur-Onea*** - Bidart (15/04-20/09) >+33559265361 -CCA(5m)Les Rives de l'Agay - Agay (83) >+33494820274 (3m)En Salvan - Vaudreuille (31) >+33561835595 (328m)Oyam*** - Bidart (15/04-30/09) >+33559549161 -CCA(28m)Le Ruisseau**** - Bidart (15/05-15/09) >+33559419450 (13m)Azur Rivage -�Antheor (83) >+33494448312 (14m)Du Tipi - Saint Chinian (34) [<51] >+33467972356 (542m)Le Viaduc - Agay (83) >+33494448231 (20m)Berrua*** -�Bidart (01/04-20/09) >+33559549666 -CCpg154-CCA(37m)Dolamatcheria - Bidart (64) (01/05-15/09) >+33559547532 (39m)Le Vadim - Roquebrune s/Argens (01/04-30/11) >+33494457470 (17m)Nono - Frontignan (34) >+33499040753 (0m)l'Aigue Marine - Frontignan (34) [<51] >+33499040427 (0m)Du Pech d'Ay** - Balaruc (20/04-14/12) >+33467485034 (3m)La Vallee de Taradeau*** - Taradeau (01/01-31/12) >+33494730914 (57m)Le Mas du Rastel - Agay (83) >+33494448584 (17m)Rural de Sigaut Rita - Frejus (83) >+33494513221 (13m)Les Cigales* - Pezenas (01/04-30/09) >+33467989799 (24m)Municipal Le Hougaa - Lembeye (64) [<51] >+33559682525 (314m)Le Devancon** - Peynier (13) [<51] (15/01-15/11) >+33442531006 -CCA(332m)Saint Paul le Marseillais - Meze (34) [<51] >+33467742996 (51m)Les Acacias** - Frejus (01/04-31/10) >+33494532122 (25m)Le Cator - Simorre (32) [<51] >+33562653344 (230m)Municipal Chemin des Bains** - Balaruc (01/04-15/10) >+33467485034 (6m)Municipal ** - Loupian (34) (05/04-13/10) >+33467435767 -CCA(15m)Moulin des Iscles*** -�Roquebrune sur Argens (83) (01/04-30/09) >+33494457074 -CCpg234-CCA(8m)Le Soleil - Frontignan (34) >+33467430202 (0m)Du Colombier**** -�Frejus (25/03-31/10) >+33494515601 (18m)Erreka*** - Bidart (15/06-15/09) >+33559549364 (67m)Douce Quietude**** -�St Raphael (01/04-10/10) >+33494443000 -CCpg236(52m)l'Eau Vive *** - Les Arcs (01/03-31/10) >+33494474066 (45m)La Ferme Les Therondels - Saint Pons de Thomieres (34) [<51] >+33467953663 (497m)Les Reflets du Lac - Mielan (32) [<51] >+33562675176 (226m)Le Dattier**** - Frejus (01/04-30/09) >+33494408901 (34m)Les Tamaris -�Frontignan Plage (34) (05/04-10/10) >+33467434477 -CCA(0m)Le Clos Du Rhone - Les Saintes Maries De La Mer (13) (05/04-07/11) >+33490978599 -CCA(1m)Lou Labech*** - Bouzigues [<51] (11/05-20/09) >+33467783038 (6m)Les Peupliers - Ayguesvives (31) >+33688238296 (160m)Site de Gorge Vent** - Frejus (01/01-31/12) >+33494408943 (42m)Les Pecheurs**** -�Roquebrune sur Argens (83) (01/04-30/09) >+33494457125 -CCA(11m)Aire naturelle Le Bravet - Frejus (83) >+33494408592 (23m)Saint Martin du Pin - Montagnac [<51] (01/03-05/10) >+33467240037 (56m)Municipal Du Stade - Simorre (32) >+33562653413 (198m)Municipal de l'Orb - Cessenon sur Orb (34) >+33467895329 (56m)Le Mas du Padre*** - Balaruc (01/04-20/10) >+33467485341 (23m)Esperbasque** - Salies de Bearn (64) (01/03-31/10) >+33559382104 -CCA(108m)Ilbarritz-Des Pins**** -�Bidart (05/04-05/10) >+33559230029 -CCA(47m)Les Vignes*** - Balaruc (01/04-31/10) >+33467480493 (7m)Municipal Castel Sec** - Pezenas (01/04-31/10) >+33467980402 (31m)Esterel**** - St. Raphael-Agay (25/03-30/09) >+33494820328 -BD_FR-R.200(61m)l'Estap - Albine (81) [<51] (30/03-02/11) >+33563983474 (394m)Saint Martin - Soreze (81) [<51] (01/04-30/09) >+33563732899 -CCA(278m)Municipal Le Moulin Du Roy - Revel (31) >+33561833247 (225m)Pavillon Royal**** - Bidart (15/05-30/09) >+33559230054 (39m)La Brise - Saintes Maries De La Mer (13) (16/12-11/11) >+33490978467 -CCpg217(2m)Le Malbousquet*** - Frejus (01/04-30/09) >+33494408730 (21m)Montourey*** - Frejus (25/05-15/09) >+33556079017 (15m)Les Aubredes*** - Puget s/Argens (01/06-31/08) >+33494455146 (24m)Municipal l'Oree du Bois** - Arthez de Bearn (01/06-30/09) >+33559677656 (139m)La Roquette - Roquebrune s/Argens (15/05-15/09) >+33494457861 (19m)Le Castor - Vitrolles (13) (01/01-31/12) >+33442893074 (13m)Biarritz*** - Biarritz (01/04-05/10) >+33559230012 (37m)Les Cigales**** - Le Muy (83) (15/03-15/10) >+33494451208 -CCA(41m)J.J. Bousquet - Roquebrune sur Argens (83) >+33494454251 (19m)Les Pins Parasols**** - Frejus (83) (10/04-30/09) >+33494408843 -CCA(45m)Le Frejus*** - Frejus (83) (15/01-15/12) >+33494199460 -CCA(41m)Le Parme*** - Anglet (20/04-15/09) >+33559230300 (67m)Les Hautes Vernedes** - Puget s/Argens (01/04-30/09) >+33494445858 (22m)La Baume-La Palmeraire**** - Frejus (83) (01/04-30/09) >+33494198888 -CCA(43m)Clair Sejour - Saint Mitre les Remparts (13) >+33442809882 (51m)Saint Christol** - Pezenas (15/04-15/09) >+33467980900 (21m)Municipal De l'Echez - Maubourguet (65) (15/05-15/09) >+33562963744 (179m)Le Sellig** - Le Muy (10/04-30/09) >+33494451171 (41m)Neptune - Saint Mitre les Remparts (13) >+33442440660 -CCA(7m)RCN De la Noguiere *** - Le Muy (83) (22/03-25/10) >+33494451378 -CCpg235-CCA(23m)La Prairie** - Le Muy (15/03-15/10) >+33494451004 (43m)A la ferme les Aresquiers - Vic la Gardiole (34) [<51] >+33467780375 (4m)Felix de la Bastide - Saint Mitre les Remparts (13) >+33442809935 (4m)Marina Plage - Vitrolles (13) >+33442893146 (6m)A la Ferme du Moulin - Lespielle (64) [<51] >+33684934788 (166m)La Bastiane**** - Puget s/Argens (83) (15/04-20/10) >+33494555594 -CCA(28m)Rural de Michel Claude - Roquebrune sur Argens (83) >+33494454159 (20m)Aire naturelle des Marnieres - Sainte Suzanne (64) [<51] >+33685890057 (81m)Municipal Les Fouguieres - Carces (83) >+33674296902 (129m)Municipal** - Alignan du Vent [<51] (01/07-31/08) >+33467249244 (101m)Municipal De Mosqueros*** - Salies de Bearn [<51] (15/03-15/10) >+33559381294 (68m)Municipal De Cabanes - Labastide Rouairoux (81) [<51] >+33563980126 (440m)Lei Suves**** - Roquebrune s/Argens (83) (01/04-15/10) >+33494454395 -CCA-BD_FR-R.196(20m)Geni - Fuveau (13) >+33442586071 (188m)Municipal Travers de Saint Stapin - Dourgne (81) [<51] >+33563503120 (291m)Vallee du Thore - Saint Amans Soult (81) [<51] >+33563970543 (266m)A la ferme des Enclauses - Courniou (34) [<51] >+33467970358 (405m)Municipal La Piboule** - Montagnac (01/05-31/10) >+33467240131 (54m)New Day* - Vic la Gardiole (01/03-31/10) >+33467361252 (4m)Municipal Du Grand Jardin - Correns (83) [<51] >+33494372195 (179m)Aire naturelle La Hourguette - Berdoues (32) [<51] (01/01-31/12) >+33562665847 (230m)La Pierre Verte**** - Frejus (83) (15/04-30/09) >+33494408830 -CCA(40m)Holiday Green**** - Frejus (01/04-30/09) >+33494198830 (63m)Le Clos Fleuri** - Vic la Gardiole (01/01-31/12) >+33467781568 (10m)Les Viollettes** - Deyme (01/01-31/12) >+33561817207 (161m)La Source** - Orthez [<51] (01/04-31/10) >+33559670481 (69m)Le Garel** - Poussan (01/05-30/09) >+33467782221 (22m)Municipal de la Chaussee - Samatan (32) [<51] (01/07-31/08) >+33562620298 (166m)Rural de Denans Andree - La Motte (83) [<51] >+33494702438 (58m)Municipal les Cerisiers du Jaur - Saint Pons de Thomieres (34) (01/04-31/10) >+33467953033 -CCA(287m)l'Europe**** - Vic la Gardiole (01/06-07/09) >+33467781150 (1m)Etche Zahar*** - Urt [<51] (01/03-15/11) >+33559562736 (43m)La Ferme Mimizan** - Urt (01/01-31/12) >+33559562151 (37m)Lacs de Gascogne - Seissan (32) (01/05-30/09) >+33562662794 -CCA(216m)La Lauze - Mazamet (81) >+33623697082 (235m)Borepo - Villeveyrac (34) >+33820200144 (89m)Municipal le Nice - Roquebrun (34) [<51] >+33467896199 (95m)Altea*** - Vic la Gardiole (01/01-31/12) >+33467781409 (6m)Naturist - Du Moulin de Faget - Faget Abbatial (32) [<51] >+33562654909 (256m)Les Petits Camarguais - Le Grau du Roi (30) >+33466511616 (0m)Secrets De Camargue - Le Grau du Roi (30) >+33466800800 (2m)L'Espiguette - Le Grau du Roi (30) >+33466514392 (2m)Municipal** - Roques [<51] (01/05-31/10) >+33561725607 (154m)Le Soleil - Le Grau du Roi (30) >+33466515007 (2m)Bruno - Saint Lys (31) >+33561916316 (209m)Bon Sejour - Le Grau du Roi (30) >+33466514711 (2m)La Borio de Roque - Saint Pons de Thomieres (34) [<51] >+33467971097 (464m)Arc en Ciel**** - Aix en Provence (01/04-30/09) >+33442261428 (149m)l'Ile Du Pont - Mirande (32) >+33562666411 (155m)Chantecler**** - Aix en Provence (01/01-31/12) >+33442261298 (174m)Sainte Victoire** - Beaurecueil (13) (01/02-15/11) >+33442669131 -CCA(230m)La Foux** - Draguignan (01/01-31/12) >+33494681827 (160m)Aire naturelle Municipale - Cadillon (64) [<51] >+33559040234 (211m)A la ferme du Clos Peyron - Les Saintes Maries De La Mer (13) [<51] >+33490975631 (2m)Municipal les Terrasses du Jaur - Premian (34) >+33467972785 (258m)Les Jardins De Tivoli - Le Grau du Roi (30) >+33466539700 (1m)Cote Mer - Mandelieu La Napoule (6 (01/04-30/09) >+33493499419 -CCA(14m)Abri de Camargue - Le Grau du Roi (30) >+33466515483 (0m)l'Eden - Le Grau du Roi (30) >+33466514981 (0m)Le Vallon des Cigales - Istres (13) (01/01-31/12) >+33442565157 -CCA(19m)Lou P'tit Poun*** - St. Martin de Seignanx (01/06-15/09) >+33559565371 (30m)Municipal L'Orme Blanc - Caraman (31) [<51] >+33561831012 (233m)l'Argentiere*** - Madelieu La Napoule (01/01-31/12) >+33493499504 (5m)Le Canet Plage - Saint Chamas en Provence (13) >+33490509689 (9m)Le Cezanne - Puyloubier (13) [<51] (01/04-01/11) >+33680321110 (375m)Les Philippons** - Les Adrets de l'Esterel (83) (10/04-05/10) >+33494409067 -CCA(222m)Le Minelle* - Madelieu La Napoule [<51] (01/05-31/10) >+33493497990 (15m)Municipal La Galupe** - Sorde l'Abbaye [<51] (01/07-31/08) >+33558731813 (11m)Naturist - La Ferme Au Paple - Traverseres (32) [<51] >+33965173210 (273m)Le Lac - Marciac (32) (22/03-18/10) >+33562082119 -CCA(156m)Montpellier Plage*** - Palavas les Flots (15/04-30/09) >+33467680701 (2m)Naturist - Les Aillos - Caraman (31) (28/03-01/11) >+33561832257 -CCpg165(213m)Les Pruniers** - Madelieu La Napoule (01/04-25/10) >+33493499923 (1m)Saint Maurice*** - Palavas les Flots (15/04-15/09) >+33467680701 (3m)L'Oliveraie - Laurens (34) (01/03-31/10) >+33467902436 -CCA(181m)Les Clos - Bagnols en Foret (83) >+33494406069 (307m)Municipal Les Pouverels - Cotignac (83) [<51] >+33494047191 -CCA(331m)l'Arnel*** - Villeneuve l.Maguelone (01/04-30/09) >+33467693365 (3m)Les Roquilles*** - Palavas les Flots (15/04-15/09) >+33467680347 (2m)Les Cigales**** - Mandelieu La Napoule (6) (15/12-15/11) >+33493492353 -CCA(2m)Le Botanic** - Fabregues (01/04-10/10) >+33467855318 -CCpg205-CCA(48m)Rural de Lafond Jacques - Hastingues (40) [<51] >+33558730369 (4m)Plateau des Chasses*** - Madelieu La Napoule (01/04-30/09) >+33493492593 (44m)A la ferme de Villeneuve - Lartigue (32) [<51] >+33562659495 (249m)Les Gaves* - Peyrehorade [<51] (01/07-31/08) >+33613295052 (6m)Les Clairettes*** - Adissan (05/02-15/10) >+33467253864 (79m)Le Chateau Rouge - Draguignan (83) >+33609026707 (189m)l'Evasion* - Fontes (01/04-31/10) >+33467253200 -CCpg204-CCA(81m)Le Camarguais* - Lattes (01/05-05/09) >+33467151007 (1m)Jobel** - Tarnos (01/01-31/12) >+33979040600 (29m)Aire naturelle L'Arrayade - Saint Martin de Seignanx (40) [<51] >+33559561060 (45m)Municipal Le Madiran - Madiran (65) [<51] >+33562361769 (160m)Eden**** - Lattes (01/05-15/09) >+33467151105 (1m)Les Saladelles** - Mauguio (01/04-15/09) >+33467682371 (2m)Pouylebon - Montesquiou (32) [<51] (15/04-15/10) >+33562667210 -CCA(192m)Naturist - Le Haute Garduer - Callas (83) >+33494679520 (276m)Le Ruou -�Villecroze-les Grottes (83) (19/04-15/10) >+33494706770 (280m)l'Oasis Palavasienne**** - Lattes (01/05-05/09) >+33467151161 (1m)Le Boucanet -�Le Grau du Roi (30) >+33466514148 (2m)Aire naturelle de Ducasse Jean-Luc - Saint Martin De Seignanx (40) [<51] >+33559561167 (50m)Le Ruisseau - Saint Andre de Seignanx (40) [<51] >+33559567192 (35m)Les Cadenieres - Villecroze (83) >+33494675966 (267m)Parc Bellevue*** -�Cannes (01/04-30/09) >+33493472897 -CCpg238(18m)Libarrey ** - Orthevielle (01/01-15/12) >+33558736340 (22m)Municipal Le Baous - Olargues (34) >+33467977150 (184m)Rural de Bats Alain - Armous et Cau (32) [<51] >+33462709034 (192m)Municipal De Tarassac - Mons (34) >+33467977264 (131m)La Petite Camargue - Aigues Mortes (30) >+33466539898 (1m)Le Garden - La Grande Motte (34) >+33965121088 (5m)Le Grand Saule - Le Cannet (6) >+33493905510 (20m)Lous Pibols - La Grande Motte (34) >+33467565008 (5m)La Petite Motte - La Grande Motte (34) (28/03-27/09) >+33467565475 -CCpg206(5m)Le Ranch*** - Le Cannet-Cannes (6) (25/04-15/10) >+33493460011 -CCA(83m)Du Lac** - Ondres (40) (01/04-31/10) >+33559452845 -CCA(25m)Municipal - Lou Gardian - La Grande Motte (34) >+33467561414 (4m)Aire naturelle la Cibade - Saint Andre De Seignanx (40) [<51] >+33559567103 (45m)Les Arnauds - Salernes (83) >+33494675195 (236m)De l'Or - La Grande Motte (34) >+33467565210 (4m)Intercommunal Des Cigales - La Grande Motte (34) >+33467565085 (3m)Le Haget - Montesquiou (32) >+33562709580 (172m)Les Melias - Fos (34) >+33467329196 (307m)La Pinede - Cornillon Confoux (13) >+33626817247 (86m)Lou Pignada*** - Ondres (01/05-30/09) >+33559453065 (8m)La ferme Mas de Plaisance - Aigues-Mortes [<51] (01/04-30/09) >+33466539284 (0m)Le Relais de la Bresque - Sillans la Cascade (83) >+33494046489 (389m)Blue Ocean** - Ondres Plage (01/04-30/09) >+33559453140 (10m)Les Blimouses - Callas (83) (01/03-31/12) >+33494478341 -CCA(286m)Le Parc*** - Lattes (01/01-31/12) >+33467658567 (8m)De Gatinie - Les Aires (34) >+33467957195 (173m)l'Anjou - Montesquiou (32) [<51] (15/04-15/10) >+33562709524 (224m)Lac de Sain Fris - Bassoues (32) [<51] >+33562665148 (178m)Aire naturelle Les Tilleuls - Habas (40) [<51] (01/07-31/08) >+33558980421 (89m)l'Eau Vive** - Mougins (01/01-31/12) >+33493753635 (72m)Panoramic*** - La Roquette sur Siagne (01/01-31/12) >+33492190777 (16m)Le Parc - Saint Paul en Foret (83) (06/04-29/09) >+33494761535 -CCpg237(287m)Naturist - La Tuquette - Fayence (83) >+33682877717 (284m)Municipal au Chateau - l'Isle De Noe (32) [<51] >+33562641721 (138m)Aire naturelle Domaine de Trestaure - Fayence (83) [<51] >+33494765368 (292m)Rural de Cabrol Thierry - La Salvetat sur Agout (34) [<51] >+33467976320 (870m)Lou Cantaire - Fayence (83) >+33494762377 (281m)A la ferme de Grigioni Marthe - Tourrettes (83) [<51] >+33494761106 (334m)Saint Louis**** - La Roquette sur Siagne (01/04-30/09) >+33492192313 (18m)Municipal La Digue - Amou (40) [<51] >+33558890022 (46m)Le Floreal** - Lattes (01/01-31/12) >+33467929305 (9m)Les Mimosas** - Pegomas (01/04-30/09) >+33493423611 (15m)Chez Bruna - Tanneron (83) [<51] >+33688373830 (295m)l'Affenage** - Le Pouget [<51] (01/06-15/09) >+33467886604 (70m)Aire naturelle de Morere Christian - Saubrigues (40) [<51] >+33558779054 (20m)A la ferme du menhir de Cascavel - La Salvetat sur Agout (34) [<51] >+33467976945 (720m)Cote d'Argent**** - Labenne Ocean (25/03-31/10) >+33559454202 -CCpg153(7m)Sylvamar**** - Labenne (40) (05/04-05/10) >+33559457516 -CCA(8m)Oceanic** - Labenne (01/04-30/09) >+33559454622 (7m)La Mer*** - Labenne (25/03-30/09) >+33559454209 (8m)Le Boudigau**** - Labenne (01/04-30/09) >+33559454207 (7m)Le Rouquie - Lamontelarie (81) >+33563709806 (686m)A la ferme de l'Adour - Saint Jean de Marsacq (40) [<51] >+33634131191 (6m)Municipal Le Verdale - Lamalou les Bains (34) >+33467958689 (187m)Les Cepes - La Salvetat sur Agout (34) >+33467976345 (718m)Les Moulieres - La Salvetat sur Agout (34) [<51] (01/05-31/10) >+33675844910 (686m)Les Bouldouires - La Salvetat sur Agout (34) >+33467973691 (702m)Municipal Les Pins Blues** - Labenne (01/04-31/10) >+33559454113 (6m)Le Lac *** - Montauroux (01/01-31/12) >+33494764626 (178m)La Comtesse*** - Belus (10/04-25/10) >+33558576907 (61m)Le Rouquier - Seillans (83) [<51] (01/04-31/10) >+33494768671 (326m)La Blaquiere - La Salvetat sur Agout (34) >+33467976129 (683m)Municipal De la Garde - Rians (83) [<51] >+33494805267 (386m)Municipal Lou Redoundel - La Salvetat sur Agout (34) [<51] >+33467973691 (675m)Le Rossignol*** - Antibes (6) (13/04-25/09) >+33493335698 -CCA(20m)La Bouriette** - Toulouse (01/01-31/12) >+33561496446 (148m)Du Pioch - Fraisse sur Agout (34) [<51] (01/05-01/10) >+33467976172 (845m)Parc des Monges*** - Auribeau sur Siagne [<51] (20/04-30/09) >+33493609171 (30m)Les Prairies** - Callian (01/04-31/10) >+33494764836 (190m)Les Chaumettes - Montauroux (83) [<51] >+33494764327 (187m)Les Floralies*** - Montauroux (01/04-30/09) >+33622497923 (197m)La Riviere** - Auribeau sur Siagne (01/01-31/12) >+33493428226 (27m)De L'Arros - Plaisance du Gers (32) >+33562693028 (129m)Le Plo - Le Bez (81) [<51] >+33563740082 (637m)Ideal** - Antibes [<51] (15/03-10/10) >+33493742707 (3m)Rural de Brune Jeannette - Saubrigues (40) [<51] >+33558779069 (37m)A la ferme de Rene Graciet - Saint Jean de Marsacq (40) [<51] >+33558777107 (33m)Le Grillon - Tourrettes (83) >+33687613475 (211m)Municipal Pouillon - Pouillon (40) [<51] >+33558982162 (37m)Logis de la Brague*** - Antibes (01/05-30/09) >+33493335472 (2m)Antipolis**** - Antibes (01/04-20/09) >+33493339399 -CCpg239(1m)Le Sequoia** - Antibes (05/04-20/09) >+33493744475 (1m)Fleur de Camargue -�St Laurent d'Aigouse (30) >+33466881542 (0m)Du Pylone*** - Antibes (01/01-31/12) >+33493749470 (4m)Douce France - Antibes (6) >+33493617136 (5m)Les Frenes** - Antibes (6) (20/05-25/09) >+33493333652 -CCA(3m)Les Embruns*** - Antibes (01/04-31/10) >+33493333335 (4m)Les Lentisques - Mougins (6) >+33493900045 (218m)Les Rivieres*** - Canet (05/04-15/09) >+33467967553 (37m)Le Belaman - Fraisse sur Agout (34) [<51] >+33467975954 (848m)Municipal Pont Tourne - l'Isle Jourdain (32) >+33562071439 (142m)Les Treilles** - Antibes [<51] (01/07-31/08) >+33493741431 (14m)Le Mistral* - Biot (01/04-30/09) >+33493656148 (10m)La Vieille Ferme**** - Villeneuve Loubet (01/01-31/12) >+33493334144 (11m)L'Eden - Biot (6) >+33493655690 (19m)Le Pessac - Vielmur sur Agout (81) >+33563743024 (155m)Municipal Gourjade - Castres (81) >+33563593351 (178m)L'Oree De Vaugrenier - Villeneuve Loubet (6) (Easter-15/10) >+33493335730 (17m)A la ferme Mas St Claude - Saint Martin De Crau (13) [<51] >+33490506328 (41m)La Vallee du Salagou - Salasc (34) [<51] >+33467881339 (179m)Rural de Delage Lionel - Salasc (34) [<51] >+33467961562 (198m)La Pointe*** - Capbreton (01/06-30/09) >+33558721498 (7m)Aire naturelle Le Peyral - La Salvetat sur Agout (34) [<51] (01/06-14/09) >+33467975185 (723m)Les Pres - Aups (83) (01/03-31/10) >+33687395393 -CCA(482m)De Pelican - Gignac (34) [<51] >+33467576892 (105m)International - Aups (83) >+33494700680 (504m)La Chapelette - Saint Martin De Crau (13) (01/02-31/12) >+33490984481 -CCpg218(12m)Du Pere Francois - Villeneuve Loubet (6) [<51] >+33493200644 (6m)Goudal - La Salvetat sur Agout (34) >+33467976044 (768m)Riviera Vaugrenier - Villeneuve Loubet (6) >+33493209250 (14m)Orion** - Villeneuve Loubet (01/01-31/12) >+33493739373 (18m)Municipal La Civelle*** - Capbreton (01/03-30/09) >+33558721511 (8m)Municipal La Lande - Brassac (81) [<51] >+33563740082 (486m)Parc des Maurettes*** - Villeneuve Loubet (10/01-15/11) >+33493209191 (17m)Vialavert-En-Sidobr - Le Bez (81) [<51] >+33493209191 (659m)Rural de Cauquil Gilbert - Nages (81) [<51] >+33563372855 (783m)Le Pinet - Callian (83) [<51] >+33494764013 (396m)La Paoute - Grasse (6) >+33493091142 (119m)Le Panorama** - Villeneuve Loubet (01/01-31/12) >+33493209153 (25m)Municipal Geaune - Geaune (40) [<51] >+33558445027 (101m)Municipal De L'Ile St Martin - Auch (32) >+33562050022 (132m)Saint Lazare - Aups (83) >+33494701286 (516m)Neptune** - Villeneuve Loubet (15/04-30/09) >+33493739381 (19m)De la Crau - Saint Martin De Crau (13) (01/04-10/10) >+33490471709 -CCA(22m)Le Gardian - Arles (13) [<51] >+33490984651 (8m)Chateau de l'Eouviere - Montmeyan (83) (01/05-30/09) >+33494807554 -CCA(513m)Provence - Lambesc (13) (01/04-30/09) >+33442929802 -CCA(208m)Le Septimanien*** - St. Andre de Sangonis (25/04-15/09) >+33467578423 (57m)Municipal Fontvieille - La Verdiere (83) >+33494041210 (415m)l'Hippodrome*** - Villeneuve Loubet (01/01-31/12) >+33493200200 (11m)Naturist - Messidor - Le Puy Sainte Reparade (13) (01/04-16/09) >+33614837656 -CCpg226(240m)Municipal Le Salagou** - Clermont-l'Herault (01/01-31/12) >+33467961313 (146m)A la ferme de Alain Cazaux - Josse (40) [<51] >+33558777127 (14m)Benito - Capbreton (40) [<51] >+33558435341 (9m)Rieu Montagne - Nages (81) (02/05-20/09) >+33563372471 -CCpg183(805m)Aire naturelle Les Arcades de Fromenty - Octon (34) [<51] >+33467969913 (149m)La Bienheureuse - Arles (13) >+33490984806 (13m)Le Castagne - Auch (32) >+33607974037 (190m)Lou Troumpetoun - Montmeyan (83) >+33494807898 (465m)Municipal La Cite Verte - Hagetmau (40) >+33558797979 (91m)Le Mas des Carles** - Octon (Easter-30/09) >+33467963233 (176m)Le Plein Air des Chenes**** -�Clapiers (34) (15/04-10/10) >+33467020253 -CCA(59m)Le Fou du Roi** - Lansargues (34) (01/04-15/10) >+33467867808 -CCA(9m)El Perdido - Saint Cezaire sur Siagne (6) [<51] >+33493602076 (450m)Le Pont** - Gignac (01/04-30/09) >+33467575240 (51m)Aire naturelle de Vajra Yogini - Marzens (81) [<51] >+33563581722 (202m)Rural La Cote de Boue - Peyrusse Grande (32) [<51] >+33562092735 (198m)Mas de Mourgues - Vauvert (30) (15/03-15/10) >+33466733088 -CCA(28m)Lacanal - Nages (81) [<51] >+33563372510 (861m)Le Rupe** - Toulouse (01/01-31/12) >+33561700735 -CCpg166-CCA(130m)Bon Port*** - Lunel (34) (01/04-30/09) >+33467711565 -CCpg207-CCA(4m)Du Pont Du Bosquet - Villeneuve Loubet (6) [<51] >+33493208813 (8m)l'Oree d'Azur - Opio (6) >+33493773200 (250m)Aramis - Marsan (32) >+33562656011 (198m)l'Arlesienne - Arles (13) (01/04-31/10) >+33490960212 -CCA(19m)Naturist - Village du Bosc - Octon (34) >+33467960737 (191m)Le Sourire-Saint James**** - Villeneuve Loubet (15/04-30/09) >+33493209611 (29m)Le Mas de Riri - Celles (01/04-30/09) >+33467446395 (156m)Municipal Le Siloe - Roquecourbe (81) [<51] >+33563730544 (221m)Les Lacs du Verdon - Regusse (83) >+33494701795 (560m)Crin Blanc - Albaron (13) (01/04-30/09) >+33466874878 -CCA(2m)Municipal La Meuse*** - Gignac (15/04-30/09) >+33467579297 (60m)Le Clocher de Neyran - Saint Gervais sur Mare (34) >+33467236416 (336m)Le Plan d'Eau Saint Charles - Damiatte (81) (01/04-31/10) >+33563706607 (146m)Saint Pierre de Rousieux - Servies (81) [<51] (15/06-15/09) >+33563500443 (202m)La Garenne - Dio et Valquieres (34) [<51] >+33467954524 (413m)City Arles - Arles (13) >+33490930886 (5m)Municipal Les Vailhes** - Celles (01/04-30/09) >+33467442598 (145m)Le Colombier*** - Cagnes sur Mer (6) [<51] (01/04-30/09) >+33493731277 (49m)Mas de l'Isle*** - Lunel (01/04-30/09) >+33467832652 (7m)Aire naturelle Municipale Therondel les Pins - Vabre (81) [<51] >+33563744060 (447m)La Sieste - La Tour sur Orb (34) >+33467237296 (238m)Municipal Ginasservis - Ginasservis (83) >+33494804511 (411m)Naturist - La source St Pierre - Aniane (34) >+33467577695 (49m)Aire naturelle Sausset - Tercis les Bains (40) [<51] >+33558578201 (45m)La Chicanette - Saint Gilles (30) >+33466872832 (7m)Tout Repos - Cagnes sur Mer (6) >+33493310261 (63m)La Pomme de Pin** - Saubion (25/03-30/09) >+33558770071 -CCpg152(18m)Municipal Les Cedres de Grand Champ - Graissessac (34) [<51] >+33467951004 (326m)Nostradamus*** -�Salon de Provence (13) (01/03-30/10) >+33490560836 -CCA(98m)Saint Paul**** - Saint Paul de Vence (01/04-31/10) >+33493329371 (59m)La Vallee de Roussy - Vabre (81) [<51] >+33563730544 (281m)Gascon le Luy - Seyresse (40) >+33558743542 (9m)A la ferme Les Amandaies - Mouries (13) [<51] >+33490475059 (69m)Bellevue*** - Aimargues (01/01-31/12) >+33466886375 (6m)Les Pinedes*** - La Colle sur Loup (6) (15/03-30/09) >+33493329894 -CCA(41m)Lou Bascou** - Riviere Saas et Gourby [<51] (15/04-15/10) >+33558975729 (25m)Montmeuille* - La Colle sur Loup (01/05-15/09) >+33493328429 (107m)Le Vallon Rouge*** -�La Colle sur Loup (6) (01/04-30/09) >+33493328612 -CCA(54m)Municipal Les Adrets - Murat sur Vebre (81) (01/05-30/10) >+33563374116 (848m)Rural de Alonso Paul - Menville (31) [<51] >+33561854459 (214m)Lac De Thoux St-Cricq - Thoux (32) >+33562657129 (172m)Le Pont de Lunel** - Lunel (15/03-30/09) >+33467711022 (9m)Bertranborde - Riviere Saas et Gourby (40) [<51] (01/01-31/12) >+33558975839 (43m)Le Val Fleuri** - Cagnes sur Mer (6) (01/04-27/09) >+33493312174 -CCA(74m)l'Oree du Bois - Dax (40) >+33558908108 (26m)Le Castellas*** - Roquefort les Pins (01/01-31/12) >+33493329705 (46m)Green Park**** - Cagnes sur Mer (01/04-30/09) >+33493070996 (81m)Les Pinedes*** - Pertuis (15/03-20/10) >+33490791098 (275m)Les Platanes** - St. Geours de Maremne (01/04-31/10) >+33558574535 (37m)Le Todos*** - Cagnes sur Mer (15/05-15/09) >+33493312005 (84m)l'Avelanede - Artignosc sur Verdon (83) >+33615316393 -CCA(504m)Parc Des Arboins - Saint Vallier De Thiey (6) >+33493426389 (747m)Les Peupliers** - Le Bosc (01/01-31/12) >+33467443808 (126m)Des Sources - Eugenie les Bains >+33689751387 (103m)Le Clot - Lacaune (81) [<51] (15/03-15/11) >+33563370359 (955m)Castex - Aignan (32) [<51] (25/03-20/10) >+33562092513 -CCA-BD_FR-P.011(156m)Municipal La Riviere - Le Bousquet d'Orb (34) >+33467238089 (248m)Les Tourrades*** - Vauvert (01/01-31/12) >+33466888020 (7m)Fondespierre*** - Castries (34) (01/01-31/12) >+33467912003 -CCA(60m)Oceliances*** - Seignosse (01/04-31/10) >+33558433030 (13m)La Chenaie - Saint Julien (83) >+33494800255 (452m)Municipal Saint Julien - Saint Julien (83) >+33494800478 (437m)La Riviere** - Cagnes sur Mer (15/03-15/10) >+33493206227 (43m)Le Lahount - Lelin Lapujolle (32) >+33562696409 (116m)Les Pres du Verdon - Quinson (4) >+33825002030 (375m)Le Val de Cagnes ** - Cagnes sur Mer (01/01-31/12) >+33493733653 (84m)Les Rives du Loup - Vence (6) >+33493241565 (141m)Barthon - Buanes (40) >+33558511295 (133m)Le Devenson - Mouries (13) [<51] >+33490475201 (41m)Aire naturelle Le Vieux Platane - Narrosse (40) >+33558742075 (20m)Les Gorges du Loup - Bar sur Loup (6) (12/04-27/09) >+33493424506 -CCA(223m)Percabot - Narrosse (40) >+33558748043 (20m)Le Clown Ocean - Tosse (40) >+33558430303 (26m)Les Ombrages de l'Adour - Aire sur l'Adour (40) >+33558717510 (80m)La Camassade - Tourrettes sur Loup (6) [<51] (01/01-31/12) >+33493593154 (321m)Le Bascat - Dax (40) >+33558561668 (9m)A la ferme de Cola Anne - Pertuis (84) [<51] >+33490096681 (229m)Aire naturelle Lanotte - Yzosse (40) >+33558740999 (9m)Les Restanques - Bauduen (83) >+33494700858 (576m)Naturist - d'Enriou - Saint Laurent du Verdon (4) >+33492740120 (457m)Le Jouanon - Yzosse (40) >+33558901114 (11m)Les Chenes - Dax (40) >+33558900553 (12m)De la Bergerie*** -�Vence (25/03-15/10) >+33493580936 -CCpg240(327m)Les Vals - Lod�ve (34) (25/04-30/10) >+33430401780 -CCA(145m)Le Talouch -�Roquelaure (32) (18/04-21/09) >+33562655243 -CCA(145m)Aire naturelle Saint Barthelemy - Bauduen (83) [<51] >+33682803698 (540m)Luberon Parc - Charleval (13) >+33442966060 (173m)Magali*** - Saint Laurent du Var (01/02-31/10) >+33493315700 (43m)Le Clos de Barbey - Bauduen (83) >+33494700856 (561m)Municipal Du Pontet - Comps sur Artuby (83) >+33494769140 (926m)Rural de De Bathurt - Soustons (40) [<51] >+33558412159 (18m)Aire naturelle de Dailhat - Yzosse (40) [<51] >+33558742439 (9m)Les Amandiers*** - Gallargues le Montueux (30) (01/04-30/09) >+33466352802 -CCA(15m)Municipal l'Ourtal - Montredon Labessonnie (81) >+33563751418 (537m)Val de Durance - Cadenet (84) >+33490683775 (154m)La ferme de Fourniller - Mallemort (13) [<51] >+33490591210 (127m)Les Pins du Soleil**** -�St Paul les Dax (01/04-31/10) >+33558913791 -CCpg151(20m)Fontenelle** - Mallemort (01/04-30/09) >+33490591154 (126m)Le Silvacane en Provence - La Roque d'Antheron (13) >+33442504054 (166m)Durance Luberon**** - Mallemort (13) (01/04-30/09) >+33490591336 -CCA(126m)Municipal Les Romarins - Maussane Les Alpilles (13) >+33490543360 (38m)l'Air du Temps - Villelaure (84) >+33490098495 (199m)Aux Vallons - Bauduen (83) >+33682599968 (485m)Municipal Notre Dame - Bauduen (83) >+33494700867 (519m)Les Romarins - Eze (6) >+33493018164 (486m)Le Vieux Chene - Bauduen (83) >+33494700908 (515m)Municipal l'Eouviere Verte - Artignosc sur Verdon (83) >+33494807106 (419m)Municipal Les Pins - Fontvieille (13) >+33490547869 (53m)Municipal Notre Dame - La Roque Esclapon (83) >+33494504050 (958m)Le Club Hippique - Bauduen (83) >+33494700889 (505m)Les Chevreuils**** - Seignosse (01/05-30/09) >+33558433280 (19m)Lou Prada - Preneron (32) >+33562065799 (182m)Les Oyats - Seignosse (40) >+33558433794 (11m)l'Etang d'Ardy*** - St. Paul les Dax (01/04-20/10) >+33558975774 (22m)La Partence - Nousse (40) [<51] >+33558985250 (37m)Municipal - La Tour d'Aigues (84) [<51] (15/06-31/08) >+33490074108 (249m)Des Iscles - La Roque d'Antheron (13) >+33442504425 (146m)Municipal Du Verdon** - Vinon s/Verdon (01/07-31/08) >+33492788151 (275m)La Theulere - Margouet-Meymes (32) [<51] (01/06-01/11) >+33562085588 (168m)Aire naturelle Le Cavalet - Bauduen (83) [<51] >+33494700845 (517m)Municipal De la Rabaudie - Viane (81) [<51] >+33563375034 (518m)La Farigoulette - Saint Laurent du Verdon (4) >+33492744162 (431m)Le Soleil - Esparron de Verdon (4) >+33492771378 (391m)Les Amphons - Escragnolles (6) [<51] >+33493092675 (892m)Le Lavandin- Esparron de Verdon (4) >+33492774609 (485m)Naturist - De Lambeyran - Les Plans (34) >+33467441399 (444m)Le Jardin - Lacaze (81) [<51] >+33563371708 (466m)Aire naturelle de Arniaud - Beaumont de Pertuis (84) [<51] >+33490080485 (338m)La Grangeonne - Esparron de Verdon (4) >+33492771687 (426m)Aire naturelle Le Breut - Soustons (40) [<51] (01/06-31/08) >+33558415728 (30m)Le Grand Pre - Albiosc (48) [<51] (10/05-15/09) >+33492771592 (431m)Aire naturelle Le Sable - Soustons (40) [<51] >+33558415669 (31m)Abesses** - St. Paul les Dax (15/03-10/11) >+33558916534 (47m)La Beaume - Esparron de Verdon >+33492771528 (418m)Les Cent Chenes - Saint Jeannet (6) >+33493244426 (294m)Les Jardins de l'Adour - Saint Vincent de Paul (40) >+33558899960 (18m)Coteau de la Marine - Montagnac Montpezat (4) (11/04-20/09) >+33492775333 -CCpg242(428m)Aire naturelle Le Plan - Cucuron (84) [<51] (01/05-31/10) >+33490772099 (253m)Regain*** - Greoux les Bains (01/04-20/10) >+33492780923 (299m)La Pinede** - Greoux les Bains (01/03-30/11) >+33492780547 -CCpg243(320m)Le Lac - Esparron de Verdon (4) >+33492771612 (392m)Namaste - Puyssegur (31) [<51] (01/05-30/09) >+33561857784 (252m)Aire naturelle La Bouyssiere De Blanc - Peux et Couffouleux (12) [<51] >+33565495517 (736m)Les Lacs - Merville (31) [<51] >+33561825446 (115m)Le Verseau*** - Greoux les Bains (01/03-31/10) >+33492776710 (303m)Verdon Parc*** - Greoux les Bains (4) (01/04-26/10) >+33492780808 -CCA(306m)La Vignoble des Sausses - St. Jeannet (6) [<51] (15/04-15/10) >+33493247307 (377m)Municipal l'Airial**** - Soustons (25/03-05/10) >+33558411248 (7m)Aire naturelle La Rigaudie - Giroussens (81) [<51] >+33563416720 (156m)Naturist - Verdon Provence - Esparron de Verdon (4) >+33492771225 (461m)Les Trois Granges - Joncelets (34) [<51] (01/06-30/09) >+33607884915 (385m)Le Val de Ceras- Brusque (12) >+33565495066 (469m)Le Moulin a Vent - Cucuron (84) >+33490772577 (290m)Les Argiles - Merindol [<51] (01/04-30/09) >+33490728102 (118m)Le Lac de Nabeillou - Graulhet (81) >+33563346004 (190m)Les Chenes Verts - Sannes (84) >+33622346096 (336m)La Bonde - Cabrieres d'Aigues (84) >+33490776364 (329m)Rural de Lacommere Daniel - Saint Paul les Dax (40) [<51] >+33558919760 (38m)Municipal La Saucille - Mugron (40) [<51] >+33558979850 (17m)Les Oliviers - Eygalieres (13) >+33490959186 (109m)Municipal Les Roches - Sainte Croix De Verdon (4) >+33492777899 (478m)Du Dourdou - Brusque (12) [<51] (01/04-30/09) >+33565975167 (471m)La Foret - Saint Pierre de Trivisy (81) >+33563504869 (619m)Les Chenes** - Junas (30) (10/04-10/10) >+33466809907 -CCA(53m)Bireben - Soustons [<51] >+33558415076 (26m)Les Sources*** - Soubes [<51] (01/04-30/09) >+33467443202 (251m)Rural Entre Les Thermes - Louer (40) [<51] >+33558572126 (33m)De Chanteraine - Aiguines (83) >+33608911686 (523m)Municipal l'Etang de Laubanere - Louer (40) >+33558579608 (31m)Les Bastides du Lac - Aiguines (83) [<51] >+33494842250 (598m)De Massereau**** - Sommieres (01/04-30/10) >+33466531120 -BD_FR-Q.163(44m)Municipal Les Rives de l'Adour - Saint Sever (40) >+33558760460 (38m)Du Gajan *** - Boisseron (34) (01/04-30/09) >+33466809430 -CCA(37m)Saint Gabriel - Tarascon (13) (01/03-30/11) >+33561857784 -CCpg219-CCA-BD_FR-Q.201(7m)Chateau Laval*** - Greoux les Bains (15/04-15/10) >+33492702300 (342m)Lou Badareu - Cucuron (84) [<51] >+33490772146 (322m)Les Hautes Prairies - Lourmarin (84) (15/03-01/11) >+33490680289 -CCA(248m)Poney Club - Sainte Croix De Verdon (4) >+33492777970 (641m)l'Olivier*** - Junas [<51] (01/04-15/10) >+33466803952 (74m)Le Bleu Lavande - Saint Martin De Bromes (4) >+33492776489 (420m)Les Truffieres - Sainte Croix De Verdon (4) >+33492778791 (641m)Municipal De la Batisse - Realmont (81) [<51] >+33563555041 (197m)Aire naturelle de Burle - Saint Martin De Bromes (4) [<51] >+33492776019 (372m)La Laune** - Peillon (01/04-31/10) >+33493799161 (168m)Municipal de Fontvieille - La Martre (83) [<51] >+33494604790 (982m)Municipal Grenade sur l'Adour - Grenade sur l'Adour (40) [<51] >+33558459114 (55m)Aire naturelle Les Roux - Sainte Croix De Verdon (4) [<51] >+33492777583 (643m)A la ferme de Boulogne - La Palud sur Verdon (4) [<51] >+33492773027 (918m)Les Rials*** - Soubes (01/07-31/08) >+33467441553 (236m)A la Ferme La- Graou - La Palud sur Verdon [<51] (01/04-30/10) >+33492773822 (941m)La Source - Les Salles sur Verdon (83) >+33494702040 (481m)l'Aigle - Aiguines (83) (01/05-14/09) >+33494842375 -CCA(851m)Le Pesquie - Eygalieres [<51] (15/03-01/11) >+33490959950 (71m)Les Pins - Les Salles sur Verdon (83) >+33498102380 (484m)A la Ferme Marsan - Saint-Sever [<51] (01/01-31/12) >+33558761870 (37m)Rural de Gary - Vacquiers (31) [<51] >+33561849772 (204m)Municipal Saint Michel - Menton (6) >+33493358123 (111m)Aire naturelle Le Cou de la Girafe - Herm (40) [<51] >+33699444884 (49m)Gre du Vent - Taybosc (32) >+33562651759 (188m)Municipal Le Grand Canyon - La Palud sur Verdon (4) >+33492773813 (893m)A la ferme Les Clos du Lac - Aiguines (83) [<51] >+33494702141 (610m)A la ferme la Lieure - Saint Lieux Lafenasse [<51] >+33563556962 (327m)Municipal Les Ruisses - Les Salles sur Verdon (83) >+33498102815 (478m)La Ferme du Vieux Chemin d'Arles- Saint Remy de Provence (13) [<51] >+33490922722 (68m)A la ferme de Bourras- La Palud sur Verdon (4) [<51] >+33688451992 (929m)Les Chenes - Vieux Boucau les Bains (40) >+33558482121 (6m)La Vallee Heureuse - Orgon (13) (01/04-30/09) >+33490441713 -CCpg224-CCA(101m)Azu Rivage*** - Azur (15/05-30/09) >+33558483072 (9m)Rural Le Mas de Baudran - Aujargues (30) [<51] (60m)Aire naturelle Haoud'Ici - Magescq (40) [<51] >+33558477072 (30m)Municipal Saint Etienne Du Gres - Saint Etienne Du Gres (13) >+33490490003 (9m)La Paillotte**** - Azur (25/03-20/09) >+33558481212 (7m)Municipal Le Garanel** - Sommieres [<51] (01/04-30/09) >+33466803349 (29m)Aire Naturelle La Giandola - Gorbio (6) [<51] >+33493283523 (363m)De la Bastide*** - Nimes (01/01-31/12) >+33466620582 (26m)Pegomas - Saint Remy de Provence (13) >+33490920121 (61m)Aqua Relle - Souprosse (40) [<51] >+33558442616 (45m)Parc de la Bastide - Saint Remy de Provence (13) (03/03-03/11) >+33432619486 -CCA(54m)A la ferme Le Maunard - Aiguines (83) [<51] (15/06-15/09) >+33494702003 (485m)Le Pic Saint Loup - Saint Martin de Londres (34) >+33467550053 (200m)Rural de Clave - Souprosse (40) [<51] >+33558442073 (39m)Le Tuc*** - Azur (01/05-15/09) >+33558482252 (15m)Rural en Saubis - Montestruc sur Gers (32) [<51] >+33562622612 (109m)Aire naturelle Le St Antoine - Coursegoules (6) [<51] >+33493591236 (977m)Municipal les Sableres - Vieux Boucau les Bains (40) >+33558481229 (3m)Les Angeles - Cezan (32) [<51] (01/06-01/09) >+33562652980 (156m)Municipal de Carajuan - Rougon (4) >+33492837094 (639m)La Ferme de Martine - Montestruc sur Gers (32) [<51] >+33562622318 (151m)Mas de Nicolas - Saint Remy de Provence (13) >+33490922705 (46m)Municipal Monfort - Monfort (32) >+33562068326 (151m)Municipal Le Galetas - Aiguines (83) >+33494702048 (517m)Albret - Messanges (40) >+33558480367 (7m)Albret Plage - Messanges (40) (01/04-30/09) >+33558480367 -CCA(3m)De la Marina - Messanges (40) (01/04-30/08) >+33558490040 (7m)Monplaisir - Saint Remy de Provence (13) >+33490922270 (30m)Lou Pignada - Messanges (40) >+33172039160 (6m)Aire naturelle Pesson - Azur (01/04-30/09) >+33558483049 (18m)Le Vieux Port -�Messanges (40) (28/03-27/09) >+33490911983 -CCpg150-CCA(5m)Les Acacias - Messanges (40) (25/03-25/10) >+33558480178 -CCA(6m)De la Cote - Messanges (40) (01/04-30/09) >+33558489494 -CCA(4m)Municipal Le Bouloc - Ceilhes et Rocozels (34) >+33467234089 (442m)Tartarin - Tarascon (13) >+33490910146 (12m)La Plage de Verduzan - Castera Verduzan (32) >+33562681223 (111m)Le Moussaillon - Messanges (40) >+33558489289 (8m)Caravaning Rose de Provence - Riez la Romaine (4) >+33492777545 (545m)Le Moulin - Moustiers Sainte Marie (4) >+33492746666 (487m)Le Pre Saint Andre - Souvignargues (30) >+33466809585 (95m)Ferme Riola - Contes (6) [<51] (01/04-30/10) >+33493790302 (398m)A la Ferme Ser'ane - Saint Jean de Bueges (34) [<51] >+33467731326 (169m)Le Moisan - Messanges (40) >+33558489206 (10m)Le Val Fleuri - Belmont sur Rance (12) [<51] >+33565990476 (432m)La Ferme La Cazelle - Teillet (81) [<51] >+33563557050 (395m)Municipal Du Vallon - Bonnieux (84) >+33490758614 (358m)Le Petit Lac - Moustiers Sainte Marie (4) >+33492746711 (510m)La Ferme La Peyrade - Courrensan (32) [<51] >+33562580185 (144m)La Durance*** - Cavaillon (84) (01/04-30/09) >+33490711178 -CCA(72m)Ararat - Contes (6) [<51] >+33493790115 (327m)A la ferme Mas d'Arbousse - Ceilhes et Rocozels (34) [<51] (01/04-01/11) >+33467234123 (494m)Des Gorges Du Verdon - Castellane-Chasteuil (4) (08/05-15/09) >+33492836364 -CCA(655m)Aire Naturelle Le Toy - Herm (40) [<51] (01/03-31/10) >+33558915516 (67m)Oxygene*** - Villedieu (01/05-15/09) >+33492724177 (313m)RCN Les Collines de Castellane - Castellane (4) (19/04-20/09) >+33492836896 -CCA(989m)La Ferme Les Granges - Montfuron (4) [<51] >+33492743060 (482m)Residence Du Rougier - Camares (12) [<51] (01/04-31/10) >+33565995936 (388m)Aire naturelle Municipale Septvals - Paulinet (81) [<51] >+33563558265 (481m)Saint Clair - Moustiers Sainte Marie (4) (01/05-30/09) >+33492746715 -CCA(521m)Air Naturelle Peyrengues- Moustiers Sainte Marie (4) [<51] (01/04-30/09) >+33492746740 (522m)Chasteuil-Provence - Castellane (4) >+33492836121 (660m)Provence Vallee - Manosque (07/03-15/11) >+33492722808 -CCA(390m)Municipal Des Auzerals - Rabastens (81) [<51] >+33563337036 (176m)l'Entre Deux Lacs - Teillet (81) >+33563557445 (483m)Municipal*** - St. Andiol [<51] (01/01-31/12) >+33490950113 (57m)Naturist - Du Pas de Ceilhes - Fondamente (12) >+33565993512 (522m)d'Andabre - Camares (12) [<51] >+33565994616 (416m)Mas de Messier - Le Caylar (34) [<51] (15/04-15/10) >+33467445263 (679m)Aire Naturelle Escoffier- La Roquette sur Var (6) [<51] >+33493089157 (120m)La Colle - Castellane (4) >+33492836157 (768m)La Ferme de Castellane - Castellane (4) (07/04-23/09) >+33492836777 -CCA(762m)Naturist - Petit Arlane - Valensole (4) >+33492748270 (577m)Le Castel de Brames a la Ferme - Peyrole (81) [<51] >+33563570756 (182m)La Ferme Al Boucle d'Or- La Roquette sur Var (6) [<51] >+33493739135 (120m)Municipal Les Lavandes - Valensole (4) >+33672484844 (591m)Le Camp du Verdon -�Castellane (4) >+33492836129 (735m)Aquitaine*** - Grisolles (02/01-22/12) >+33563673322 (140m)Le Vieux Colombier - Moustiers Sainte Marie (4) >+33492746189 (600m)Municipal Royeres du Prieure** - Maubec (01/04-15/10) >+33490765034 (145m)Les Bardons - Castellet (84) >+33490752087 (491m)La Ferme Framboiseilles - Castellane (4) [<51] >+33686854422 (744m)Marie Rose*** - Noves (01/02-31/12) >+33490954164 (46m)Saint Jean - Moustiers Sainte Marie (4) (05/04-12/10) >+33492746685 -CCA(576m)Les Micocouliers -�Graveson en Provence (13) (15/03-15/10) >+33490958149 -CCA(15m)Municipal La Pinatelle - Saint Auban (6) [<51] >+33493604046 (1036m)Manaysse - Moustiers Sainte Marie (4) >+33492746666 (578m)Notre Dame - Castellane (4) [<51] (01/04-10/10) >+33492836302 (736m)La Ferme Le Bois de Sibourg - Cereste (4) [<51] (21/04-21/09) >+33492790222 (351m)Les Lavandes - Castellane (4) [<51] >+33492836878 (732m)Le Frederic Mistral - Castellane (4) >+33492836227 (733m)A la ferme les Carolins - Meilhan (40) [<51] >+33558441733 (79m)Le Val d'Herault - Brissac (34) (15/03-15/10) >+33467737229 -CCA(121m)Municipal Fleurance - Fleurance (32) [<51] >+33562061001 (92m)Le Pilon d'Agel*** - Noves (01/05-15/09) >+33490951623 (48m)Les Cigales - Moliets et Maa (40) >+33558485118 (14m)Saint Martin - Moliets et Maa (40) (11/04-02/11) >+33558485230 -CCA(10m)Le Pesquier - Castellane (4) >+33492836681 (748m)Lou Vincen - Vallabregues (30) (01/04-31/10) >+33466592129 -CCA-BD_FR-Q.207(12m)Les Boudougnes - Oppede (84) [<51] >+33490769610 (129m)Aire naturelle de Franc - Moliets et Maa (40) [<51] >+33609441459 (12m)Aire Naturelle Les Joncquiers - Saint Martin de Castillon (84) [<51] (15/04-15/10) >+33490752011 (376m)Le Provencal - Castellane (4) [<51] (01/05-14/09) >+33492836550 -CCA(765m)La ferme de Biscarat - Robion (84) [<51] >+33490202425 (82m)Le Grand Gravier - Verdun sur Garonne (82) [<51] >+33563643244 (94m)Montdenier - Moustiers Sainte Marie (4) [<51] (15/04-15/10) >+33492746739 (969m)Aire naturelle de le Plan de la Palud - Castellane (4) [<51] >+33609967516 (760m)International -�Castellane (4) (31/03-01/10) >+33492836667 -CCpg241(765m)Les Fines Roches - Roquesteron (6) >+33493059185 (321m)Aire naturelle Petit Jean - Leon (40) [<51] >+33558492598 (29m)Naturist - Le Haut Chandelalar - Brianconnet (6) >+33493604009 (1032m)Land'Island - Moliets et Maa (40) >+33558491149 (26m)Les Lacs de Courtes - Estang (32) (28/03-29/10) >+33562096198 -CCpg167(94m)Des Sirenes - Castellane (4) [<51] (10/04-20/09) >+33492837056 (1145m)La Mouline - Fondamente (12) [<51] (01/03-30/09) >+33565993196 (441m)Aire naturelle les Cerisiers - Robion (84) [<51] >+33490202425 (87m)Le Luberon - Apt (84) (01/04-30/09) >+33490048540 -CCA(329m)Municipal Les Lavandes - Puimoisson (4) [<51] >+33492745401 (700m)Municipal De la Vandelle** - Volx [<51] (15/06-15/09) >+33492795466 (416m)Ferme La Brouquere - Gondrin (32) [<51] (27/04-30/09) >+33562291944 (140m)Le Domaine des Templiers - Le Caylar (34) (01/04-30/11) >+33467449090 (730m)Municipal Le Moulin Du Pouy - Eauze (32) >+33562098600 (130m)Rural des Ferrays - Blieux (4) [<51] >+33492342251 (929m)Naturist - Le Vallon Des Oiseaux - Reillanne (4) >+33492764733 (471m)Municipal Fondamente - Fondamente (12) [<51] >+33565993705 (474m)D'Anglas - Brissac (34) >+33467737018 (130m)La Ferme d'Embarthe - Avezan (32) [<51] >+33562664158 (157m)Les Cedres - Apt (84) >+33490741461 (229m)Le St. Antoine** - St. Michel Escalus [<51] (15/04-30/09) >+33558487850 (35m)Municipal Au Stade E.Donato - Sospel (6) [<51] >+33493043317 (361m)Le Mas de Reilhe -�Crespian (30) (25/04-13/09) >+33466778212 -CCpg208(83m)Aire naturelle de Inda Pierre - Saint Michel Escalus (40) [<51] >+33558487713 (23m)Municipal Le Galan*** - Castets (01/02-30/11) >+33558894352 (58m)Belle Rive*** - Montfrin [<51] (01/04-30/09) >+33466572079 (15m)Aire Naturelle La Folie - Lagnes (84) [<51] >+33490202002 (94m)Les Cypres** - Bezouce (01/01-31/12) >+33466752430 (74m)Le Pardaillan - Gondrin (32) >+33562291669 (166m)Le Relais Landais - Villeneuve De Marsan (40) [<51] >+33558453623 (92m)A la ferme Mas de Campagnani - Liouc (30) [<51] >+33633817746 (110m)La Roquette*** - Chateaurenard (13) (01/04-31/10) >+33490944681 -CCA(40m)Le Mas Fleuri - Sospel (6) >+33603269607 (428m)Le Lomagnol - Beaumont de Lomagne (82) >+33563261200 (102m)Punta Lago - Leon (40) >+33558492440 (15m)Lou Puntaou - Leon (40) >+33558487430 (14m)Naturist - Castillon De Provence - Castellane (4) >+33492836424 (1011m)Le Revel - Rogues (30) [<51] >+33617025491 (565m)Espace Loisirs Boade - Senez (4) >+33492342294 (863m)Des Muriers - Saint Bauzille de Putois (34) [<51] >+33467737363 (126m)l'Arc En Ciel - Roussillon (84) >+33490057396 (262m)Naturist - Deveze - Gaudonville (32) >+33562664386 (185m)Municipal La Franqueze - Alban (81) >+33563559187 (593m)La Cle des Champs - Apt (84) [<51] (01/04-30/09) >+33490744141 (409m)La Tisarne* - Campsas (01/01-31/12) >+33563640275 (133m)Des Sources - Gaillac (81) >+33607820440 (142m)Sainte Madeleine - Sospel (6) [<51] >+33493041048 (445m)A la Ferme de Vauvenieres - Saint Jurs (4) [<51] (01/04-01/10) >+33492744418 (813m)La Riviere** - St. Maime (4) (15/04-30/09) >+33558492440 -CCA(370m)Le Neri - Mauroux (32) [<51] >+33562663018 (160m)Aire naturelle Le Cayre - Saint Michel Escalus (40) [<51] >+33558492385 (27m)Le Col Vert - Vielle Saint Girons (40) (12/04-21/09) >+33558429406 -CCpg149-CCA(10m)Le Gaoucher - Vielle Saint Girons (40) >+33558429300 (18m)Les Lacs d'Armagnac - Bretagne d'Armagnac (32) >+33562097092 (143m)Le Yody - Chateaurenard (13) >+33490942523 (26m)Naturist - Arnaoutchot -�Vielle St Girons (40) (12/04-28/09) >+33558491111 -CCpg148-CCA(14m)Les Pommiers d'Aigueleze - Rivieres (81) (01/04-30/09) >+33563330249 -CCA(148m)Epona De Fontaret - Blandas (30) [<51] >+33467734937 (637m)La Couteliere - Lagnes (84) (01/04-15/10) >+33490203397 -CCA(72m)Rouncaou - Taller (40) [<51] >+33558894318 (75m)l'Eau Vive - Dauphin (4) (01/04-31/10) >+33492795191 -CCA(392m)Le Lac des 3 Vallees - Lectoure (32) >+33562688233 (101m)Le Mas St Pierre - Saint Julien D'Asse (4) >+33492344111 (443m)Le Colorado - Rustrel (84) >+33490049037 (315m)La Sorguette - l'Isle sur la Sorgue (84) (15/03-15/10) >+33490380571 -CCA(62m)Le Bel Air - Vielle Saint Girons (40) [<51] >+33558429928 (17m)Aire naturelle Municipale Les Tasconi - Salvagnac (81) [<51] >+33563335789 (158m)Du Lac - Saint Julien Du Verdon (4) >+33492890793 (918m)Le Hameau - Mouchan (tentes seulement) (32) [<51] (01/04-31/10) >+33562682377 (118m)Lous Pignats - Linxe [<51] (15/06-30/09) >+33558429361 (41m)Aire naturelle de Desbieys Jean - Linxe (40) [<51] >+33558429236 (61m)Les Pres - Fontaine de Vaucluse (84) >+33609715349 (84m)Les Chenes Blancs -�St Saturnin Les Apt (84) (01/04-31/10) >+33612724787 -CCpg223-CCA(263m)Aire naturelle Berdoulet - Linxe (40) [<51] >+33558429024 (41m)L'Oceane - Vielle Saint Girons (40) >+33558429437 (22m)A la ferme de la Salvetat - La Couvertoirade (12) [<51] >+33565581922 (769m)Les Oliviers*** - Oraison (4) [<51] (01/01-31/12) >+33492782000 -CCA(391m)De Groene Uitleg - Saint Andre (81) [<51] >+33563559884 (290m)Municipal Le Moulin De L'Horte - Plaisance (12) [<51] >+33565997507 (248m)La Soubeyranne*** - Remoulins (10/04-25/09) >+33466370321 (25m)Municipal Le Grillon - Montoulieu (34) [<51] >+33467733075 -CCA(193m)Municipal Le Tivoli - Laroque (34) >+33467739728 (146m)Le Verger de Varennes - Varennes (82) [<51] >+33563304129 (124m)A la Ferme De Labeyrie - Laree (32) [<51] >+33562095183 (148m)Les Sources - Gordes (84) (12/04-27/09) >+33490721248 -CCA(472m)Fontisson** - Chateauneuf de Gadagne (84) (01/04-15/10) >+33490225977 -CCA(101m)Ferme De La Deveze - Montoulieu (34) [<51] >+33467737021 (226m)Municipal La Couronne - Montdardier (30) [<51] >+33467815246 (607m)Le Jantou*** - Le Thor (10/04-20/09) >+33490339007 (50m)A la ferme La Marniere - Cazaubon (32) [<51] >+33562095146 (120m)A la ferme de Dumas Max - Vielle Saint Girons (40) [<51] >+33558479485 (26m)Municipal Le Grandjean*** - Linxe (20/06-05/09) >+33558429000 (40m)Le Moulin de Ventre**** -�Niozelles (4) (10/04-30/09) >+33492786331 -CCA(379m)Albirondack Park - Albi (81) >+33684042313 (177m)Ferme Saint Sebastien - Moulinet (6) [<51] (15/05-31/10) >+33493048147 (744m)A la ferme Danto Dominique - Condom (32) [<51] >+33562281971 (107m)A la ferme Causse et Lamas - Montdardier (30) [<51] >+33613157209 (621m)A la ferme le Bosquet - Montoulieu (34) [<51] >+33467733211 (207m)Le Lac de L'Uby - Cazaubon (32) >+33562095391 (115m)La Ferme les Coccinelles - Lurs (4) [<51] >+33492798053 (403m)Municipal Les Chalottes - Murs (84) [<51] >+33490726084 (511m)La Mise a l'eau - Ambialet (81) >+33563795829 (205m)l'Amitie - Trebas (81) [<51] >+33563558407 (216m)Azur Et Merveilles - Breil sur Roya (6) [<51] >+33493624704 (286m)Les Merveilles - Lantosque (6) >+33493031573 (350m)Aux Rives du Tarn - Courris (81) >+33677935774 (221m)Rural Ferme de Couloume - Montreal (32) [<51] >+33685355126 (92m)Municipal De Villeneuve sur Tarn - Curvalle (81) [<51] >+33563559163 (222m)Municipal du Coucut - Castelnau d'Auzan (32) [<51] >+33562292021 (131m)L'Amitie - Touet sur Var (6) >+33493057432 (317m)Les Ramiers - Bourret (82) [<51] >+33563263371 (95m)Le Pont d'Ambialet - Saint Cirgue (81) >+33563564353 (209m)La Sousta*** - Remoulins (01/03-31/10) >+33466371280 (36m)Rural de Bastide - Martrin (12) [<51] >+33565997120 (508m)Municipal De L'Argente - Condom (32) [<51] >+33562281732 (76m)Le Poteau - Castelnau d'Auzan (32) [<51] >+33632775415 (152m)Municipal Saint Affrique - Saint Affrique (12) >+33565990554 (326m)Eurosol - Vielle Saint Girons (40) (13/05-14/09) >+33558479014 -CCA-BD_FR-L.194(18m)Le Bois des Ecureuils** - Domazan (10/01-20/12) >+33466571003 (153m)La Ferme de Lapaloup - Coupiac (12) [<51] >+33565491056 (587m)Bagatelle*** - Avignon (84) (01/01-31/12) >+33490863039 -CCA(21m)Napoleon - Barreme (4) [<51] >+33672904274 (726m)Ferme du Bas Chalus - Forcalquier (4) [<51] >+33492750567 (460m)Isis en Cevennes - Saint Julien de la Nef (30) >+33467738028 (171m)Aire Naturelle Les Olivettes - Les Mees (4) [<51] (15/04-15/10) >+33492341897 (399m)Les Tourterelles - Vielle Saint Girons (40) (18/04-28/09) >+33558479312 -CCpg147-CCA(19m)Aire naturelle De Sebens - Sauve (30) [<51] >+33466775551 (134m)Les Gorges du Gardon** - Vers Pont du Gard (15/03-31/10) >+33466228181 (33m)La Libaudie - La Bastide Solages (12) [<51] (01/04-01/10) >+33565997033 (340m)Le Pont d'Avignon**** -�Avignon (01/03-30/11) >+33490806350 -CCpg220-CCA(19m)Mas Naut - Coupiac (12) [<51] (01/04-30/09) >+33676034039 (406m)Naturist - l'Origan -�Puget-Theniers (6) (01/05-30/09) >+33493050600 -CCA(472m)La Ferme Barrachin - Lectoure (32) [<51] >+33562688457 (132m)La Ferme Bernadon - Vielle-St-Girons (40) [<51] >+33558479098 (39m)Le Barralet*** - Collias (01/04-30/09) >+33466228452 (48m)Rural de Barrieu Claudine - Lagarde (32) [<51] >+33562688552 (160m)Aire naturelle L'Albugue - Brasc (12) [<51] >+33565997322 (459m)Aire Naturelle Le Pastaire - Moriez (4) [<51] >+33492891648 (933m)Les Matherons - Puimichel (4) [<51] (01/05-30/09) >+33492796010 (564m)Municipal Des Iscles - Saint Andre Les Alpes (4) >+33492890229 (896m)Municipal Le Bertranon - Lavit (82) [<51] >+33563940554 (213m)Du Brec - Entrevaux (4) (15/03-15/10) >+33493054245 -CCA(495m)Indigo Forcalquier*** - Forcalquier (4) (15/04-30/09) >+33492752794 -CCA(530m)De Valsaintes - Simiane la Rotonde (4) [<51] (31/03-22/10) >+33671110627 (513m)La Ferme l'Enclos - Lagarde (32) [<51] >+33562687738 (178m)Rose d'Armagnac - Montreal (32) [<51] >+33562294770 (129m)Aire naturelle de L'Albatros - Saint Andre Les Alpes (4) [<51] >+33492890875 (894m)Le Paradis - Montech (01/05-15/09) >+33563311429 (105m)Parc de Couchoy*** - Lesperon (01/06-15/09) >+33558896015 (72m)Les Deux Rhones** - Avignon (01/01-31/12) >+33490854970 (20m)Halte et Repos* - l'Hospitalet du Larzac (01/05-30/09) >+33565627053 (729m)Lou Payou** - Lesperon (10/04-25/10) >+33558896324 (87m)Municipal Monclar de Quercy - Monclar de Quercy (82) >+33563304285 (180m)La Celestine - Beynes (4) (01/05-30/09) >+33786183508 -CCA(540m)Municipal La Laune*** - Villeneuve-les Avignon (01/04-15/10) >+33490257606 -CCA(18m)Naturist - La Couliche - Cestayrols (81) [<51] >+33617352240 (211m)Laparot - Molieres Cavaillac (30) [<51] >+33467811382 (250m)La Ribiere - Annot (4) (08/03-01/11) >+33492832144 -CCA(722m)Naturist - Des Lauzons - Forcalquier (4) (01/04-30/09) >+33492730060 -CCA(510m)Municipal La Planque - Saint Izaire (12) >+33565994031 (265m)La Tessonne - Molieres Cavaillac (30) >+33467811735 (251m)A la ferme de Guinland - Condom (32) [<51] >+33607067386 (166m)Le Grand Bois** - Le Pontet (15/05-15/09) >+33490313744 (31m)Le Figaret - Saint Hippolyte du Fort (30) [<51] >+33466772634 (180m)Aire naturelle De L'Issole - Saint Andre Les Alpes (4) [<51] >+33492890222 (931m)Le Chene Vert - Castelnau De Montmiral (81) >+33563331610 (186m)Le Mercou - Saint Julien de la Nef (30) >+33467824265 (181m)A la ferme Bonnefont - Garganvillar (82) [<51] >+33563946908 (148m)Les Terrasses - Puycelci (81) >+33563331748 (166m)Le Graniers - Monoblet (30) >+33619413670 (274m)Le Camp de Florence -�La Romieu (32) (01/04-10/10) >+33562281558 -CCA(191m)Municipal La Cheneraie - Gabarret [<51] (01/03-31/10) >+33558449262 (153m)Municipal Cahuzac sur Vere - Cahuzac sur Vere (81) >+33563339194 (200m)A la ferme La Bouysse - Saint Izaire (12) [<51] >+33565994336 (334m)Rural de Sourbes Rene - Fources (32) [<51] >+33562294062 (80m)Parc des Libertes - Avignon (84) >+33490851773 (26m)Le Batut - Saint Izaire (12) [<51] >+33624288283 (256m)Ferme des Etangs - Garganvillar (82) [<51] >+33563948860 (133m)Flory*** - Vedene (84) (01/04-30/09) >+33490310051 -CCpg221-CCA(35m)Le Val De L'Arre - Le Vigan (30) (01/04-15/09) >+33467810277 -CCA(220m)La Glory - Lit et Mixe (40) [<51] (01/05-30/09) >+33607099545 (39m)Les Gorges de l'Herault - Sumene-Pont d'Herault (30) (01/04-30/09) >+33467824223 -CCA(187m)Fargogne - Puygaillard de Quercy (82) [<51] (28/04-14/10) >+33563309561 (245m)Naturist - Le Fiscalou - Puycelsi (81) >+33563304595 (250m)L'ile des Papes**** - Villeneuve-les Avignon (30) (01/04-10/11) >+33490151590 -CCpg216-CCA(22m)Les Chalets du Tarn - Requista (12) [<51] >+33673944391 (240m)Municipal Le Claus - Mezel (4) >+33492355387 (574m)Mas de Rey - Arpaillargues et Aureillac (30) >+33466221827 (94m)Ferme Lacoussade - Lit et Mixe [<51] (01/06-30/09) >+33612985332 (34m)Municipal Le Coucourelle - Pernes les Fontaines (84) [<51] (01/04-30/09) >+33490664555 (90m)La Cazette - Broquies (12) >+33565994733 (299m)Rural La Cigale - Tornac (30) [<51] >+33466618095 (177m)Les Magnanarelles - Saint Andre de Majencoules (30) >+33467824013 (201m)Le Pin - Saint Justin (40) [<51] >+33558448891 (117m)La Bastide d'Albignac - Le Dourn (81) [<51] >+33563534844 (348m)Naturist - La Sesquiere - Vieux (81) >+33563339602 (222m)A la ferme de Lasseube - Gazaupouy (32) [<51] >+33562280525 (176m)Les Fontaines - Pernes les Fontaines (84) (28/03-19/10) >+33490468255 -CCpg222-CCA(66m)l'Adrech - La Mure Argens (4) >+33492891781 (971m)Municipal Fontan - Fontan (6) [<51] >+33493045202 (451m)Le Clave*** - Morcenx Bourg [<51] (01/04-31/10) >+33558078311 (65m)Aire naturelle Mas Carriere - Saint Andre de Majencoules (30) [<51] >+33467824578 (204m)Aire naturelle Caravaland - Lit et Mixe (40) [<51] >+33558428480 (25m)Aire naturelle De Castelnau - Nant (12) [<51] >+33565588470 (493m)Font Neuve - Malemort du Comtat (84) >+33490699000 (247m)La Corconne - Valleraugue (30) [<51] (01/04-31/10) >+33467824682 (215m)Les Templiers - Roquebilliere (6) >+33493034028 (583m)Les Deux Vallees - Nant (12) (15/04-06/10) >+33565622689 -CCA(494m)Aire naturelle Ferme Lessale - Lit et Mixe (40) [<51] >+33558427071 (21m)La Dourbie - St. Jean-du-Bruel (11/04-28/09) >+33565460640 -CCA(513m)Municipal Sarbazan - Sarbazan (40) [<51] >+33558456493 (96m)Les Vernedes - Nant (12) >+33565621519 (499m)La Montagne** - Sorgues (01/01-31/12) >+33490833666 -CCA(54m)Le Mas Des Chenes - Lezan (30) >+33613752057 (114m)L'Olivier - Massillargues Attuech (30) >+33671216268 (121m)Aire naturelle Municipale Valence d'Albigeois - Valence d'Albigeois (81) [<51] >+33563534100 (452m)La Claparede - Saint Jean du Bruel (12) >+33565622341 (526m)Les Vignes - Lit et Mixe (40) >+33558428560 (21m)L'Epi Bleu - Banon (4) (19/04-30/09) >+33492733030 -CCpg244-CCA(717m)A la ferme de Descamps Marie - Lit et Mixe (40) [<51] >+33558428436 (26m)Le Fief d'Anduze - Massillargues Attuech (30) (01/04-30/09) >+33466618171 -CCA(117m)Municipal Le Seuil - Saint Christol (84) [<51] >+33490750105 (849m)Le Vialaret - Nant (12) >+33688628175 (480m)Beau Rivage - Cardet (30) (01/04-01/10) >+33466830248 -CCA(112m)Municipal La Pinede** - Les Mees (01/06-20/09) >+33492343389 (466m)La Ferme La Tuiliere - Le Chaffaut Saint Jurson (4) [<51] >+33492346514 (498m)Municipal Aeria - Blauvac (84) >+33490618141 (400m)Soleil des Landes - Lit et Mixe (40) (11/04-21/09) >+33558428337 (16m)Du Chercheur D'Or - Cardet (30) >+33681729197 (107m)Municipal de Trescasses - Castelsarrasin (82) >+33563323037 (71m)Municipal aire naturelle Les Gravieres - Banon (4) [<51] >+33492732008 (744m)La Bouriasse - Vaissac (82) [<51] >+33567211472 (161m)Le Moulin Neuf - Uzes (30) >+33466221721 (95m)Rural de Bonnafous Robert - Saint Antoine (32) [<51] >+33562286616 (70m)Le Mouliat - Moncrabeau (47) [<51] >+33608263040 (63m)La ferme du Pouget - Saint Jean Delnous (12) [<51] >+33565740068 (503m)Aire Naturelle la Reserve - Garrosse [<51] (01/04-30/09) >+33558043812 (84m)De Gaujac -�Anduze-Boisset et Gaujac (30) (01/04-19/09) >+33466616757 -CCpg209-CCA(120m)Le Roc qui Parle - Nant (12) >+33565622205 (509m)Municipal du Cap de l'Homy - Lit et Mixe (40) >+33558428347 (14m)Le Bel Ete - Anduze (30) >+33684564713 (136m)La Salendrinque - Lasalle (30) (01/05-15/09) >+33466852457 -CCA(267m)Municipal De Bellerive** - Monteux (01/04-15/10) >+33490668188 (45m)La Brise Des Pins - Anduze (30) >+33466616339 (287m)L'Art de Vivre** - Chateauneuf du Pape (84) (01/04-30/09) >+33490026543 -CCA(32m)Ferme d' Accueil - Anduze (30) [<51] (07/04-30/09) >+33466605329 (150m)Camp Redon - Cordes sur Ciel-Livers Cazelles (81) [<51] (05/04-19/10) >+33563561464 -CCA(317m)Aire naturelle Municipale Brocas - Brocas (40) [<51] >+33558514023 (68m)La Pommeraie - Thoiras (30) (12/04-30/09) >+33466852052 (217m)La Ferme Chez Didier et Muriel - Thorame Haute (4) [<51] >+33492832520 (1452m)Les Chalets d'Uza - Uza (40) [<51] >+33558428035 (35m)Lou Comtadou - Carpentras (84) (01/04-30/09) >+33490670316 -CCA(88m)RCN Val de Cantobre -�Nant (12) (05/04-27/09) >+33565584300 -CCpg182-CCA(471m)Le Payssel - Bruniquel (82) [<51] >+33563672595 (114m)Les Vistes - Saint Jean de Ceyrargues (30) >+33466832956 (198m)De la Base Nautique - Saint Rome de Tarn (12) [<51] >+33565581469 (325m)Municipal De Nauton - Roquefort (40) [<51] >+33558455999 (81m)La Prade - Le Truel (12) [<51] >+33565464146 (283m)Aici Sem Pla - Vaissac (82) >+33563309801 (151m)La Tioule - Saint Victor et Melvieu (12) [<51] (15/06-15/09) >+33565625193 (630m)La Cascade - Saint Rome de Tarn (12) (01/01-31/12) >+33565625659 -CCA(356m)Le Moulin de Julien - Cordes sur Ciel (81) >+33563561110 -CCA-BD_FR-P.101(204m)Aire naturelle Des Lavandes - Lambruisse (4) [<51] (01/06-01/10) >+33492891246 (1150m)Grandchamp - Cruis (4) [<51] >+33492770110 (686m)Municipal Villes sur Auzon - Villes sur Auzon (84) >+33490618205 (303m)A la ferme Bellevue Cadabuech - Boisset et Gaujac (30) [<51] >+33466619708 (193m)Les Verguettes -�Villes sur Auzon (84) (05/04-05/10) >+33490618818 -CCA(281m)l'Auzon - Mormoiron (84) >+33490618042 (201m)Les Fauvettes - Anduze (30) (26/04-30/09) >+33466617223 -CCA(143m)Municipal La Pensiere - Dourbies (30) [<51] >+33467827246 (849m)La Ferme La Renardiere - Vindrac-Alayrac (81) [<51] >+33563563169 (177m)Des Champouns - Saint Martin Vesubie (6) [<51] >+33680137702 (1009m)Le Pradal - Anduze (30) (01/04-30/09) >+33466617981 -CCA(136m)La Ferme Lou Pebre d'Ail - Mallefougasse Auges (4) [<51] >+33492770415 (681m)Municipal Bienvenue*** - Onesse et Laharie [<51] (15/06-15/09) >+33558073049 (40m)Castel Rose - Anduze (30) (01/04-28/09) >+33466618015 -CCA(136m)La Casse - Chateau Arnoux Saint Auban (4) >+33492642971 (451m)A la ferme Saint Joseph - Saint Martin Vesubie (6) [<51] >+33493032014 (913m)A la ferme de Saint-Dalmas - Valdeblore (6) [<51] (26/05-04/10) >+33684158455 (1244m)Municipal Le Pont Du Gers - Astaffort (47) [<51] (15/06-15/09) >+33553640251 (59m)Aire naturelle Le Garissou - Les Cabannes (81) (15/03-09/11) >+33563562714 -CCpg169(168m)Aire naturelle de Pont De La Mariee - Guillaumes (6) [<51] >+33493055350 (762m)Municipal La Passerelle - Saint Julien en Born (40) (01/05-30/09) >+33558427618 (10m)De L'Arche - Anduze (30) >+33466617408 (144m)Les Hauts de Labahou - Anduze (30) [<51] >+33603933888 (167m)Municipal Valdeblore - Valdeblore (6) >+33493232586 (1312m)A la ferme le Mas Bresson - Dourbies (30) [<51] >+33616201319 (1038m)Aire naturelle Eco Le Cun Du Larzac - Millau (12) [<51] (27/04-13/10) >+33565611438 (798m)Aire Naturelle Piou de Pelle - Saint Julien en Born (40) [<51] >+33558428887 (10m)Municipal Les Prunettes - Monesties (81) >+33563761917 (207m)La ferme Le Pont Noir - Saint Julien en Born (40) [<51] >+33558428442 (10m)Municipal Le Colombier** - Negrepelisse (10/06-15/09) >+33563642034 (108m)Sen Yan**** - Mezos (31/05-06/09) >+33558426005 -CCA(26m)Le Vieux Moulin - Saint Julien en Born (40) >+33558428012 (11m)Aire naturelle La Teouleyre - Saint Julien en Born (40) [<51] (01/06-01/10) >+33558427780 (11m)Lac de Lislebonne - Reaup (47) (01/05-13/09) >+33553656528 (98m)Saint Martin - Creissels (12) (01/04-31/10) >+33565603183 (384m)La ferme de La Plaine - Viala Du Tarn (12) [<51] >+33565625450 (656m)Aire naturelle de Soulan - Saint Julien en Born (40) [<51] >+33558428710 (14m)Le Clos Lalande - Montricoux (82) (29/03-28/09) >+33563241889 -CCA(100m)Le Tuc - Lit et Mixe (40) >+33558428174 (15m)Saint Louis Lac - Lamontjoie (19/04-11/10) >+33553995938 -CCA(115m)Cevennes-Provence - Anduze (30) >+33466617310 (162m)A la Ferme Le Mas de l'Eglise - Corbes [<51] (01/01-31/12) >+33466618080 (195m)Municipal Treves - Treves (30) >+33467827290 (571m)Aire naturelle Le Tress - Saint Julien en Born (40) [<51] >+33558428024 (15m)Aire naturelle Les Farguettes - Sainte Gemme (81) [<51] >+33563766690 (363m)La Ferme Du Villard - Thorame Basse (4) [<51] >+33670974484 (1116m)La Sainte Croix - Sarrians (84) (01/05-30/11) >+33490654372 (35m)Au Mas Cauvy - Saint Christol les Ales (30) [<51] (01/04-30/09) >+33466607824 (122m)Aire naturelle de Daret Jean - Saint Julien en Born (40) [<51] >+33558427235 (17m)Le Ventoux - Mazan (84) [<51] (15/03-31/10) >+33490697094 -CCA(158m)Les Sources**** - Courthezon (01/01-31/12) >+33490706773 (33m)Municipal La Lette Fleurie - Saint Julien en Born (40) >+33558427409 (19m)Aire naturelle Le Katalpa - Compregnac (12) [<51] (01/04-31/10) >+33565623005 (345m)Le Faucon d'Or - Montricoux (80) [<51] >+33563241479 (162m)Municipal - Revest du Bion (4) [<51] >+33492772226 (910m)Le Vieux Verger - Connaux (30) (01/01-31/12) >+33466829162 -CCpg215(104m)La Merio - Saint Martin Vesubie (6) >+33493033038 (1078m)Le Plan d'Eau - Saint Nicolas de la Grave (82) >+33563955002 (64m)Le Pied De L'Aigoual - Valleraugue (30) [<51] >+33467822440 (406m)Rural Aurifeuille - Penne (81) [<51] >+33563563276 (247m)Les Eaux Chaudes - Digne les Bains (4) >+33492363562 (633m)Le Mouretou - Valleraugue (30) [<51] (13/04-03/11) >+33467822230 (425m)Aire naturelle Lou Triadou - Revens (30) [<51] >+33467827358 (790m)Aire naturelle de Hypolite - Luglon (40) [<51] >+33558075610 (91m)Lous Seurrots - Saint Julien en Born (40) >+33558428582 (14m)Municipal L'Esperou - L'Esperou (30) [<51] (15/06-30/09) >+33467817960 (1255m)La Forge*** - Albias [<51] (01/04-30/09) >+33563310044 (92m)Municipal Saint Jacques - Tende (6) >+33493047608 (807m)Le Rivet - Tonnac (81) [<51] >+33563563151 (423m)Municipal La Rouquette - Mialet (30) >+33466850095 (157m)A la ferme Hameau de Berthezene - Valleraugue (30) [<51] >+33467822057 (398m)Rural de Blanc Francis - Salles (81) [<51] >+33563761546 (347m)l'Ile du Bidounet - Moissac (82) (01/04-30/09) >+33563325252 -CCA(69m)Municipal Val de Garonne - Valence (82) >+33563396167 (61m)Cesar*** - Laudun l'Ardoise (01/04-31/10) >+33466902034 (49m)Le Bregoux - Aubignan (84) >+33490626250 (67m)Municipal Aqui Sian Ben - Flassan (84) >+33490618122 (458m)Le Saint Etienne - Villefranche De Panat (12) >+33565464518 (736m)Saint Lambert** - Millau (12) (01/05-30/09) >+33565600048 -CCA(369m)Le Cians - Beuil (6) >+33493025729 (1425m)Notre Dame du Bourg - Digne les Bains (4) >+33492366262 (626m)Les Rivages**** - Millau (12) (15/04-30/09) >+33565610107 -CCA(361m)Les Contes d'Albret - Nerac (47) [<51] >+33553651873 (73m)Indigo Cote Sud*** - Millau (12) (01/04-30/09) >+33565611883 -CCA(360m)Les Deux Rivieres*** - Millau (12) (01/04-31/10) >+33565600027 -CCA(357m)Municipal Le Defends - Sault (84) >+33490640718 (801m)Belle-Vue - Crillon Le Brave (84) (01/03-31/10) >+33490624229 (241m)L'Hippocampe**** -�Volonne (4) (01/05-30/09) >+33492335000 -CCpg245-CCA(437m)Du Viaduc**** - Millau (12) (01/05-15/09) >+33565601575 -CCA(359m)Les Erables*** - Millau (12) (10/04-30/09) >+33565591513 -CCA(359m)Les Cantarelles - Alrance (12) [<51] >+33565464035 (734m)Municipal Fontchaude - Thorame Haute (4) [<51] >+33642196381 (1098m)Le Terondel - Saint Sauveur Camprieu (30) >+33467826189 (1114m)Aire naturelle Municipale Moulin de Roupeyrac - Durenque (12) [<51] (01//06-30/09) >+33565465803 (689m)Chateau de l'Hom - Saumane (30) >+33466839089 (306m)Larribal** - Millau (12) (01/04-30/09) >+33565590804 -CCA(360m)Mas De La Cam - Saint Jean du Gard (30) (27/04-20/09) >+33466851202 -CCA(210m)Le Petit Baigneur - Saint Jean du Gard (30) >+33466853205 (212m)Le Verdier - Saumane (30) >+33684588352 (324m)Les Sources - Saint Jean du Gard (30) >+33466853803 (234m)Municipal Les Peupliers** - Jonquieres [<51] (01/05-30/09) >+33490706709 (53m)Meneque - Bedoin (84) >+33490659350 (294m)Aire naturelle de Gourgues Michel - Saint Julien en Born (40) [<51] >+33558427810 (39m)Aire naturelle La Vernede - Saint Jean du Gard (30) [<51] (16/04-17/09) >+33466853304 (215m)Millau Plage**** - Millau (12) (18/04-21/09) >+33565601097 -CCA(361m)A la ferme La Muse - Mialet (30) [<51] >+33670566943 (170m)Municipal Peone - Peone (6) [<51] >+33493025989 (1199m)La Garenne - Bedoin (84) [<51] >+33490656305 (314m)le Chateau Bergonce - Bourriot Bergonce (40) [<51] >+33558933622 (123m)La Presqu'�le du Caylou - Les Plantiers (30) >+33466839285 (398m)Municipal Roquefiguier - Beaumes de Venise (84) >+33631902028 (100m)La Berge Fleurie - Mialet (30) >+33466557972 (178m)Le Bouquier - Caromb (84) >+33490623013 (235m)Les Plans - Mialet (30) >+33466850246 (188m)Municipal De la Pinede - Bedoin (84) >+33490656103 (311m)Municipal Du Lac - Lafrancaise (82) [<51] >+33563658969 (181m)Le Thuries - Pampelonne (81) [<51] >+33563764401 (274m)Naturist - De Belezy -�Bedoin (84) >+33490656018 (344m)Le Pastory - Bedoin (84) >+33490128583 -BD_FR-R.006(342m)La Foret - Saint Jean du Gard (30) >+33466853700 (237m)De Pradines - Lanuejols (30) [<51] >+33467827385 (879m)A la Ferme Maia - Bias (40) [<51] >+33620336665 (38m)A la Ferme de Ferrieres - Realville (82) [<51] >+33563310670 (123m)Les Gorges de Capou - Saint Andre de Valborgne (30) >+33466839613 (354m)Rural Le Sahut - Castelnau Pegayrols (12) [<51] >+33672771114 (895m)Rural de Astoul Serge - Milhars (81) [<51] >+33563563314 (143m)Les Relarguiers - Beauvezer (4) >+33492834773 (1141m)Aire naturelle les Oliviers - Bedoin (84) [<51] >+33490656889 (342m)Municipal Les Queyrades - Vacqueyras (84) [<51] >+33490658424 (119m)Du Peyricat - Sabres (40) >+33558075188 (83m)Cap de Pin** - Solferino [<51] (01/04-30/09) >+33558072052 (78m)Le Tatiou - Bias (40) >+33558090476 (37m)Manon - Orange (01/04-31/10) >+33617264201 (41m)Municipal Les Tilleuls - Laguepie (82) >+33563302081 (173m)Le Prieure - Saint Martin d'Entraunes (6) [<51] >+33493055499 (1056m)Municipal Du Pont de l'Elze - Saint Andre de Valborgne (30) [<51] >+33466603008 (433m)Des Gorges de l'Aveyron - Saint Antonin Noble Val (82) (18/04-28/09) >+33563306976 -CCA(130m)La Croix Clementine - Cendras (30) >+33466865269 (157m)La Belle Etoile - Aguessac (12) (01/05-30/09) >+33565598467 -CCA-BD_FR-Q.008b(369m)Municipal le Clos De L'Abbaye - Cendras (30) [<51] >+33466865205 (146m)Pech Contal - Varen (82) [<51] >+33563654834 (267m)Chateau Lamothe d'Allot - Boe (47) >+33553683311 (49m)Les Bergassous - Chusclan (30) >+33466901731 (49m)Le Jas du Moine** - Salignac (01/03-31/10) >+33492614043 (521m)Escapade La Barque - Aguessac (12) [<51] >+33565597203 (374m)Nature Le Moulin - Thoard (4) [<51] >+33492346575 (760m)Ferme de Marjoab - Meyrueis (48) [<51] >+33466455359 (1010m)Domaine de Cadenne - Saint Antonin Noble Val (82) [<51] >+33563276943 (298m)Le Martinet - Saint Etienne Vallee Francaise (48) >+33466457488 (273m)Municipal Le Ponget - Saint Antonin Noble Val (82) [<51] >+33563682113 (131m)Le Haut Verdon - Villars Colmars (4) >+33492834009 (1185m)Municipal Le Glandou - Cassagnes Begonhes (12) [<51] >+33565467009 (547m)Rural de Thaon Marguerite - Saint Martin d'Entraunes (6) [<51] >+33632375974 (1133m)Des Favards - Violes (84) >+33490709093 (88m)La Ferme de Montalrat - Centres (12) [<51] >+33565722686 (524m)Domaine du Chasselas - Castelsagrat (82) [<51] >+33601878886 (151m)La Pelucarie - Moissac-Vallee-Francaise [<51] (28/04-16/09) >+33466457557 (285m)A la ferme Espeye - Saint Urcisse (47) [<51] (18/04-18/10) >+33553875622 (106m)A la Ferme Maubert - Saint Pierre de Clairac (47) [<51] >+33553873728 (147m)A la ferme Audubert - Saint Antonin Noble Val (82) [<51] >+33563302641 (306m)Municipal La Muse* - St. Beauzely (01/04-31/10) >+33664114591 (605m)Municipal De la Piboulette** - Caussade (01/05-30/09) >+33563930907 (109m)A la ferme la Rigolle - Camaret sur Aigues (84) [<51] >+33490372026 (73m)Aire naturelle Municipale Malaucene - Malaucene (84) [<51] >+33490461638 (410m)Les Cerisiers - Pailhas (12) >+33678516356 (374m)La Prade - Montirat (81) [<51] >+33563769568 (180m)Municipal La Javie - La Javie (4) [<51] >+33492349176 (823m)Le Clapas - Castelmary (12) [<51] (15/05-15/09) >+33665744047 (414m)Les Genets D'Or - Bagnols sur Ceze (30) (20/04-20/09) >+33466895867 -CCA-BD_FR-Q.230(47m)Le Bois Joly - Colmars (4) [<51] >+33492834040 (1220m)Les Busserolles - Peyreleau (12) [<51] >+33565626723 (723m)La Coquille-Froumain - Bagnols sur Ceze (30) [<51] (02/04-15/09) >+33466890305 -CCA(52m)Municipal du Pre des Arbres - Montbrun les Bains (26) >+33475288541 (619m)Les Clots - Mirandol Bourgnougnac (81) [<51] >+33563769278 (299m)Les Pommiers - Colmars (4) [<51] >+33492834156 (1235m)Aire naturelle Pre de Malon - Saint Andre d'Olerargues (30) [<51] (01/04-30/09) >+33466790368 (104m)Aire naturelle La Tacherie - Saint Beauzely (12) [<51] >+33565620038 (766m)Aire naturelle Lou Treillat - Sainte Croix Vallee Francais (48) [<51] >+33466447056 (339m)Le Bosquet - Malaucene (84) >+33490652909 (338m)l'Estival - Mimizan (40) [<51] >+33558090988 (26m)CynoCamp Terre Neuve - Verfeuil (30) [<51] >+33466728259 (93m)Les Ecureuils - Mimizan (40) >+33558090051 (31m)La Deveze - Salles Curan (12) >+33656463458 (817m)d'Ayres - Meyrueis (48) >+33466456051 (705m)Le Gourpassou - Bor et Bar (12) >+33565657698 (185m)La Vallee Verte - La Roque sur Ceze (30) (19/04-27/09) >+33466790889 -CCA(80m)La Lande - Mimizan (40) >+33558824662 (36m)Aire naturelle Municipale - Salmiech (12) [<51] >+33565467239 (632m)Le Bois Redon*** - Septfonds (82) [<51] (01/01-31/12) >+33563649249 -CCA(176m)A la ferme de Rameyron - Serignan du Comtat (84) [<51] >+33490700648 (70m)Municipal Puymirol - Puymirol (47) [<51] >+33553953210 (75m)De Merlanes - Molieres (82) (19/04-27/09) >+33611524247 -CCA(154m)Le Mont Serein - Beaumont du Ventoux (84) >+33490604916 (1409m)Des Fumades - Allegre Les Fumades (30) >+33466248078 (134m)Les Peupliers**** -�Riviere sur Tarn (01/04-30/09) >+33565598517 -CCpg181(376m)Au Pre de Charlet - Meyrueis (48) >+33466456365 (719m)Le Capelan -�Meyrueis (48) (05/05-13/09) >+33466456050 -CCpg210(713m)Le Papillon*** - La Cresse (12) [<51] (20/04-30/09) >+33565590842 -CCA(396m)Municipal Le Malivert - Molieres (82) [<51] >+33563677637 (127m)Lac de Bonnefon -�Naucelle (12) (01/04-15/10) >+33565693320 -CCA(479m)Ferme La Charagne* - Entrepierres [<51] (01/04-30/09) >+33492613368 (560m)Les Cascades - La Roque sur Ceze (30) (11/04-12/10) >+33466827297 -CCpg214-CCA(82m)Les Genets - Salles Curan (12) (11/05-12/09) >+33565463534 -CCpg180(812m)Le Tellier - Entraunes (6) [<51] >+33493055183 (1277m)Le Lac Des Neiges - Isola (6) >+33493021816 (903m)Latapie - Vazerac (82) [<51] >+33563677092 (143m)Le Doumergal - Arvieu (12) >+33565742492 (713m)Les Peupliers - Le Rozier (48) [<51] (01/04-13/10) >+33565626085 (395m)De Peyrelade**** - Riviere sur Tarn (12) (10/05-15/09) >+33565626254 -CCA(392m)Municipal de Brouillet - Le Rozier (48) (01/04-30/09) >+33565626398 -CCA(394m)Le Touring - Salles Curan (12) >+33565463674 (814m)Brudy Plage - Le Rozier (48) >+33565626633 (394m)Les Libellules - Cornillon (30) >+33466822004 (77m)Les 3 Cantons -�Saint Antonin Noble Val (82) (15/04-15/09) >+33563319857 -CCA-BD_FR-P.001a(314m)A la ferme Le Lavoir d'Arlinde - La Begude [<51] (15/04-15/10) >+33621354734 (129m)A la ferme La Boucoule - Montbrun les Bains (26) [<51] >+33604024984 (769m)La Muse - Mostuejouls (12) [<51] >+33672035869 (398m)Municipal Bel Air - Le Pompidou (48) [<51] >+33466603200 (776m)La Cascade - Meyrueis (48) [<51] (07/04-30/09) >+33685840715 (757m)Saint-Pal - Mostuejouls (12) >+33565626446 (395m)La Resclauze - Mostuejouls (12) [<51] >+33565626556 (386m)Longue Legue - Mostuejouls (12) [<51] >+33565626262 (396m)Parc du Charrouzech - Salles Curan (12) >+33565460111 (820m)A la ferme La Mouline - Durfort Lacapelette (82) [<51] >+33682249012 (136m)De l'Aubigue - Mostuejouls (12) [<51] >+33565626367 (393m)Le Randonneur - Mostuejouls (12) [<51] >+33565626062 (396m)Ferme La Borie Basse - Naucelle (12) [<51] >+33565470349 (431m)Les Bords du Tarn - Mostuejouls (12) >+33565626294 (395m)Le Pre des Amarines - Gatuzieres (48) [<51] (12/07-25/08) >+33466456165 (797m)La Presqu'�le - Salles Curan (12) [<51] >+33565460526 (824m)Les Prades - Le Rozier-Peyreleau (12) (01/05-15/09) >+33565626209 -CCA(405m)Municipal Les Vernhes - Salles Curan (12) [<51] >+33565463362 (813m)Le Bon Soleil - Saint Nazaire (30) >+33466799865 (100m)Le Mas De Rome - Goudargues (30) [<51] >+33466822524 (84m)La Saousse - Malaucene (84) [<51] >+33490652352 (280m)Le Moulin De La Galiniere - Riviere sur Tarn (12) (01/05-14/09) >+33608284907 -CCA(383m)Beau Rivage - Salles Curan (12) (26/04-21/09) >+33565463332 -CCA(825m)Aire naturelle L'Azur - Salles Curan (12) [<51] >+33565463913 (828m)Municipal Les Biaux - Sederon (26) [<51] >+33475285095 (823m)Le Pont - Riviere sur Tarn (12) [<51] (01/03-31/10) >+33633601348 (391m)Club Marina-Landes - Mimizan (40) (12/04-21/09) >+33558091266 -CCA(7m)Aire naturelle la Quillette - Rousses (48) [<51] >+33466440029 (740m)Centre Equestre de la Blaquiere - Saint Julien de Cassagnas (30) [<51] >+33466248980 (144m)Municipal Parc de Peyre- Labouheyre [<51] (01/06-30/09) >+33558044500 (79m)La Ferme de la Fabrie - Camboulazet (12) [<51] >+33565722603 (575m)A la ferme des Tronques - La Salvetat Peyrales (12) [<51] >+33565818134 (489m)Aire naturelle La Sarrade - Salles Curan (12) [<51] >+33565463364 (842m)Chateau De Boisson - Allegre Les Fumades (30) >+33466248561 (128m)Municipal La Gambionne - Goudargues (30) >+33466823101 (79m)Les Dolmens - Mejannes le Clap (30) >+33631641465 (314m)A la ferme la Prade - Najac (12) [<51] >+33565297151 (398m)Retenue de Pareloup - Canet De Salars (12) >+33565463326 (812m)Beauregard*** - Mornas (01/04-20/09) >+33490370208 (106m)La Grenouille - Goudargues (30) [<51] >+33466822136 (78m)Municipal Les Pres-Hauts**** - Sisteron (01/04-30/09) >+33492611969 (464m)Soleil Levant - Canet De Salars (12) (01/05-30/09) >+33565460365 -CCA(804m)Le Caussanel -�Canet de Salars (12) (11/05-05/09) >+33565468519 -CCpg179(821m)Moulin de Liort - La Salvetat Peyrales (12) [<51] (01/05-30/09) >+33565818967 (393m)A la ferme des Damias - Eourres (5) [<51] >+33492652050 (975m)Municipal La Croix de Mouly - La Salvetat Peyrales (12) >+33565814246 (503m)La Garde - Saint Germain de Calberte (48) [<51] >+33661717744 (405m)Aire naturelle Municipale - Sauveterre De Rouergue (12) [<51] >+33565720252 (458m)La Plage - Mimizan (40) >+33558090032 (9m)Le Clos de la Lere - Cayriech (82) >+33563312041 -CCA(152m)Landes Bleues - Aureilhan (40) >+33558090142 (14m)La Roque - Canet De Salars (12) >+33565460203 (815m)Municipal Du Lac - Mimizan (40) >+33558090121 (13m)Les Amarines II - Goudargues (30) >+33466822492 (78m)A la ferme l'Abeille - Saint Caprais de Lerm (47) [<51] (109m)Mas De Lafont - Mostuejouls (12) [<51] >+33565626040 (412m)Le Paisserou - Najac (12) >+33565297396 (211m)Mandala - Prads Haute Bleone (4) >+33688184868 (1045m)La Fontaine** - Ribiers (01/05-30/09) >+33492632095 (510m)Le Saint Michelet - Goudargues (30) >+33466822499 (82m)Eurolac Les Landes - Aureilhan (40) >+33558090287 (10m)Aurilandes - Aureilhan (40) (23/05-20/09) >+33499572121 -CCpg146(10m)Le Voconce - Saint Marcellin les Vaison (84) (01/04-15/10) >+33490362810 -CCA(225m)Municipal Le Bosquet - La Fouillade (12) >+33565657113 (392m)Le Bon Crouzet - Entrechaux (84) >+33490460162 (236m)La Ferme - Auron (6) [<51] >+33493230168 (1603m)A la ferme Merle a Lavaurette - Septfonds(82) [<51] >+33563319762 (223m)Le Cubersel - Auron (6) >+33493230040 (1609m)A la ferme Combe de Sarda - La Sauvetat de Saveres (47) [<51] >+33553953912 (158m)le Riou - Auron (6) [<51] >+33493230175 (1639m)Font de Merle - Branoux les Taillades (30) >+33634393689 (214m)Blaziou Bas - Saint-Martin-de Beauville (47) [<51] >+33553954932 (170m)La Ferme de Blaquiere - Verrieres [<51] (01/05-10/11) >+33675093173 (838m)Buzenac-Bas - Castelnau Montratier (46) >+33565218786 (126m)Naturist - La Combe de Ferriere - Saint Michel de Deze (48) [<51] (15/05-15/09) >+33466455243 (590m)Aire naturelle La Dondelle - Lachau (26) [<51] >+33475284004 (715m)Le Moulin Saint Laurent - Saint Laurent (47) [<51] >+33632916708 (35m)Municipal le Guilleman - Pontenx Les Forges (40) >+33558074048 (25m)La Bonnette - Caylus (82) [<51] (29/03-04/10) >+33563657020 -CCA(191m)Carpe Diem -�Vaison la Romaine (84) >+33490360202 (216m)La Clairiere - Saint Paul en Born (40) >+33558048307 (16m)Parc en Ciel - Les Mages (30) >+33466256113 (242m)l'Oree des Cevennes - Saint Jean de Valeriscle (30) >+33466568036 (212m)Les 3 Rivieres - Entrechaux (84) >+33490460172 (254m)Beau Rivage - Saint Ambroix (30) >+33466241017 (152m)Universal - Rochegude (30) >+33466244126 (116m)La Moliere - Vebron (48) >+33466440240 (651m)La Saraillere - Goudargues (30) [<51] (09/06-31/08) >+33631948529 (83m)Les Lavandes Bleues - Ballons (26) >+33475284049 (716m)Aire naturelle de Combes - Barre des Cevennes (48) [<51] >+33668262838 (947m)De Labeiller - Saint Victor de Malcap (30) >+33466241527 (133m)Les Castors - Pierrelongue (26) >+33475287467 (301m)Le Faillal - Montpezat de Quercy (82) (11/04-27/09) >+33563020708 -CCpg168(283m)La Pinede** - Mondragon (84) (01/03-15/11) >+33490408298 -CCA(70m)Le Moulin de Mellet - Saint Hilaire de Lusignan (47) [<51] (01/04-15/10) >+33553875089 -CCA(48m)Le Theatre Romain - Vaison la Romaine (84) >+33490287866 (221m)Aire naturelle de Camping la Combe - Saint Pierre des Tripiers (48) [<51] >+33466456132 (930m)La Plage - Saint Andre de Roquepertuis (30) >+33466509729 (93m)Municipal du Collet-de-Deze - Le Collet de Deze (48) >+33466455014 (301m)Le Moulin De Cost - Buis les Baronnies (26) >+33475280982 (375m)Les Cauvines - Sainte Cecile d'Andorge (30) >+33466342134 (288m)Aire naturelle La Gravouse - Poet en Percip (26) [<51] >+33475282312 (800m)Naturist - Centre Pardigue - Valernes (4) >+33492621369 (520m)La Gautiere - Buis les Baronnies (26) (01/04-31/10) >+33475280268 -CCA(362m)De Cabaresse - Salazac (30) >+33466821639 (260m)De Labadan - Sainte Eulalie en Born (40) >+33558097198 (22m)Aire naturelle de Couder Bruno - Montclus (30) [<51] >+33466822761 (88m)Aire naturelle Municipale - Luxey (40) [<51] >+33558047070 (94m)Mas le Jeune - Saint Ambroix (30) >+33466240498 (133m)Municipal Aime Giraud - Le Martinet (30) [<51] >+33466249500 (261m)Les Trinitaires - Saint Etienne De Tinee (6) [<51] >+33493024157 (1159m)De La Tour - Saint Ambroix (30) >+33607970723 (156m)Moulin De Caveirac - Saint Jean de Maruejols et Avejan (30) [<51] >+33466244105 (120m)La ferme Les Cerisiers - Montclus (30) >+33466822366 (98m)Gorges de la Meouge*** - Barret sur Meouge (01/05-30/09) >+33492650847 (639m)l'Ayguette - Faucon (84) (19/04-27/09) >+33490464035 -CCA(307m)A la ferme Mas du Moulin - Montclus (30) [<51] >+33466822252 (97m)Le Clos - Saint Ambroix (30) >+33607545766 (144m)Le Gite Du Lievre - La Roche sur le Buis (26) [<51] >+33475281149 (937m)Aire naturelle Le Ranquet sur Ceze - Saint Ambroix (30) [<51] >+33466241972 (141m)Les Acacias - Montclus (30) [<51] >+33466822761 (105m)la Cambuse - Vaison la Romaine (84) [<51] >+33490361453 (232m)Les Rives De L'Aygues - Tulette (26) (01/05-25/09) >+33475983750 -CCA(134m)Aire naturelle de Mantou - Bajamont (47) [<51] >+33553670993 (116m)Le Grenier des Coeurs - Lauzerte (82) [<51] >+33563947560 (110m)Naturist - La Genese - Mejannes le Clap (30) (30/03-14/09) >+33466245182 -CCpg213-CCA(153m)Le Muret - Saint Salvadou (12) [<51] (01/04-30/09) >+33565818069 (548m)Naturist - De la Sabliere -�Barjac (30) (29/03-30/09) >+33466245116 -CCpg212-CCA(237m)Le Soleil de Provence - Saint Romain en Viennois (84) >+33490464600 (280m)Les Ephelides - Buis les Baronnies (26) >+33475281015 (378m)Naturist - Chateau De Fereyrolles - Saint Privat de Champclos (30) >+33466245164 (120m)Les 2 Lacs - Beauville (47) [<51] (01/04-31/10) >+33553954541 -CCA(199m)Le Lac de Parisot - Parisot (82) >+33563657065 (338m)Naturist - Ran du Chabrier - Saint Privat de Champclos (30) >+33466245155 (122m)l'Espace Stevenson - Cassagnas (48) >+33466452034 (706m)Moulin de Campech - Villefranche du Queyran (47) [<51] (01/04-07/10) >+33553887243 -CCA(93m)Municipal La Capelle - Monteils (12) [<51] >+33565296397 (235m)Municipal - St Rome de Dolan - Saint Rome de Dolan (48) [<51] >+33466488746 (860m)Municipal Des 3 Moulins - Castelnau Montratier (46) [<51] >+33565219421 (252m)Les Oliviers - Saint Paulet de Caisson (30) [<51] >+33466821413 (79m)Le Pont Du Martinet - Barles (4) [<51] >+33492351467 (1094m)Lou Cadenoux - Saint Rome de Dolan (48) >+33466328446 (896m)Municipal - Touffailles (82) [<51] >+33563944891 (165m)Le Clos des Capitelles - Saint Privat de Champclos (30) >+33466892483 (210m)Les Acacias* - St. Paulet de Caisson (01/01-31/12) >+33466390233 (54m)Municipal Buis les Baronnies - Buis les Baronnies (26) >+33475280496 (379m)Aire naturelle Au Clocheton - Montauban sur l'Ouveze (26) [<51] >+33475286003 (709m)Aire naturelle La Savoillane - Buis les Baronnies (26) [<51] >+33672019087 (380m)Terrados - Les Vignes (48) [<51] >+33675189460 (423m)Rural de Vignat Paul - Saint Julien de Peyrolas (30) [<51] (01/01-31/12) >+33466821842 (149m)Mas de Linde - Goudargues (30) >+33466245096 (243m)Du Lac - Saint Pierre de Buzet (47) >+33553843263 (51m)La Valette - Robiac Rochessadoule (30) >+33466252177 (200m)Les Cessenades - Saint Frezal de Ventalon (48) [<51] (01/04-31/10) >+33466454831 (503m)Le Mas Sud Ardeche - Saint Just (7) >+33475046731 (48m)La Plage*** - Saint Just (01/04-30/09) >+33475046946 (47m)Lou Passavous - Le Vernet (4) (01/05-15/09) >+33492351467 -CCA(1211m)Le Plan* - Vaumeilh (01/01-31/12) >+33492621745 (532m)Des Ponts - Saint-Just (7) (20/06-08/09) >+33475046731 (49m)Rural de Bardonnenche Roger - Le Poet (5) [<51] >+33492657185 (538m)La Fontaine d'Annibal - Buis les Baronnies (26) (11/04-26/10) >+33475280312 -CCA(380m)Aire naturelle de Perroy - Sainte Eulalie en Born (40) >+33558097092 (38m)Le Beldoire - Les Vignes (48) >+33466488279 (429m)Municipal Tulette - Tulette (26) >+33475983202 (157m)Parc Le Peyrolais - Saint Julien de Peyrolas (30) >+33466821494 (48m)Aire naturelle La Roquette- Aigueze (30) [<51] >+33466821513 (92m)De L'Ecluse - Benivay (26) (19/04-30/09) >+33475280732 -CCA(387m)Les Drouilhedes - Peyremale (30) (01/05-15/09) >+33466250480 -CCA(182m)Du Lez** - Suze la Rousse (26) [<51] (19/04-30/09) >+33475907308 (85m)Parc Du Lac - Pont De Salars (12) >+33565468486 (729m)Lac de Neguenou - Prayssas (47) [<51] >+33553950067 (94m)Fontpetite** - Le Poet [<51] (01/01-31/12) >+33492657011 (582m)Les Bruyeres - Sainte Eulalie en Born (40) >+33558097336 (28m)La ferme La Riviere - La Bastide L'Eveque (12) [<51] (01/04-30/09) >+33565818522 (550m)Naturist - Le Merou - Saint Projet (82) >+33567052040 (360m)La Simioune** - Bollene (01/01-31/12) >+33490631791 -CCA(132m)Les Cigales - Aigueze (30) >+33466821852 (55m)Les Catoyes* - Orpierre (15/03-15/11) >+33492466490 (746m)Aire naturelle La Canarde - Vercoiran (26) [<51] >+33475281641 (489m)Municipal - Saint Maurice sur Eygues (26) [<51] >+33475276061 (196m)Aire naturelle La Borie - Courry (30) [<51] >+33466240567 (291m)La Claysse - Saint Sauveur De Cruzieres (7) (01/04-30/09) >+33475354065 -CCpg255-CCA(152m)Municipal La Plaine - Besseges (30) >+33466251306 (175m)Le Moulin - Saint Martin d'Ardeche (7) (17/04-29/09) >+33475046620 -CCA(54m)Municipal de Pradet - La Malene (48) >+33466485855 (458m)La ferme Le Galinier - Aigueze (30) [<51] (014/04-15/09) >+33466821551 (97m)Le Bois Des Roches - Bouchet (26) >+33475048394 (96m)La ferme Chez Richard - Belfort du Quercy (46) [<51] >+33565247248 (275m)Municipal Du Vieux Moulin - Peyremale (30) >+33466253235 (209m)Naturist - Le Romegas - Buis les Baronnies (26) >+33475281078 (585m)Municipal Village - Saint Martin d'Ardeche (7) >+33475046525 (59m)La Revire - Saint Martin d'Ardeche (7) >+33475987114 (53m)Municipal Le Luech - Chambon (30) >+33475281078 (265m)Le Pontet - Saint Martin d'Ardeche (7) >+33475046307 (64m)La Blaquiere - Les Vignes (48) [<51] (28/04-20/09) >+33466485493 -CCA(451m)Les Terrasses Du Lac - Pont De Salars (12) (01/04-30/09) >+33565468818 -CCA(750m)Municipal du Vieux Moulin - Aiguillon (47) >+33553796258 (33m)Municipal l'Arriu*** - Pissos (01/07-15/09) >+33558044140 (59m)Lou Pelous - Chambon (30) >+33466612907 (235m)Le Castelas - Saint Martin d'Ardeche (7) >+33475046655 (54m)La Chataigneraie - Genolhac (30) >+33664443598 (306m)Du Lac - Sainte Eulalie en Born (40) (12/04-30/11) >+33558097010 -CCA(28m)Le Village - Lapalud (84) >+33490403103 (46m)Les Moulinoches - Le Vibal (12) [<51] >+33565468580 (725m)Municipal La Tiere - Florac (48) [<51] >+33466450402 (562m)Source De Vie - Gagnieres (30) >+33466250267 (181m)Le Martinet - Genolhac (30) (01/05-30/09) >+33682965014 (302m)La Cerisaie - Saint Martin d'Ardeche (7) >+33475046109 (66m)Les Princes d'Orange**** - Orpierre (5) (01/04-31/10) >+33492662253 -CCpg246-CCA(679m)A la ferme Pierre Fain - Mirabel Aux Baronnies (26) [<51] >+33475271216 (217m)Des Gorges - Saint Martin d'Ardeche (7) (01/04-15/09) >+33475046109 -CCA(65m)l'Herein - Visan (84) (01/04-15/10) >+33490419599 -CCA(143m)Municipal - Orgnac l'Aven (7) >+33475386368 (308m)De Monteglin** - Laragne Monteglin (01/04-15/10) >+33684114213 (569m)La Buissiere - Barjac (30) >+33466245452 (275m)La Reserve - Gastes (40) >+33558097479 (33m)Cassaduc - Saint Georges de Levejac (48) [<51] (01/07-31/08) >+33466488580 (844m)Municipal De La Piscine - Casteljaloux (47) [<51] >+33553935468 (65m)La Combe - Barjac (30) >+33610623212 (145m)Le Pont Neuf - Florac (48) [<51] >+33633447261 (553m)Les Esparnettes - Genolhac (30) >+33466614450 (320m)Les Echasses - Gastes (40) >+33558097536 (34m)Les Calquieres** - Severac le Chateau (12) (01/04-15/10) >+33565476482 -CCA(683m)Aire naturelle Municipale - Sore (40) [<51] >+33558076006 (73m)Le Clot Du Jay - Clamensane (4) [<51] >+33684436360 (714m)Clairval - Gagnieres (30) >+33466251529 (201m)A la ferme Le Mas Neuf - Barjac (30) [<51] >+33466245079 (158m)Aire naturelle Le Pavillon - Saint Marcel D'Ardeche (7) [<51] >+33475987190 (109m)Des Grottes - Bidon (7) [<51] (01/04-15/09) >+33670366667 (75m)Le Sagittaire - Nyons (26) >+33475270000 (230m)Les Pres Verts - Gastes (40) >+33558097411 (23m)Municipal - Vinsobres (26) >+33475276165 (267m)Municipal Lac des Forges** - Ychoux (01/04-15/10) >+33558782007 (52m)Rural Saint Georges - Lazer (5) [<51] >+33492650931 (617m)Les Osiers - La Chadenede (48) >+33466485179 (498m)Municipal du Pont du Mas - Genolhac (30) [<51] >+33466611790 (415m)Les Baronnies ** - Eyguians (01/01-31/12) >+33492662064 (592m)Aire naturelle Chadenede - Montbrun (48) [<51] >+33466485088 (488m)Aire naturelle de Charbonnieres - Montbrun (48) [<51] >+33466485178 (493m)Municipal Le Pont du Tarn - Florac (48) (29/03-03/11) >+33475270000 -CCA(546m)Municipal Les Chenes - Montaigu De Quercy (82) >+33563943221 (200m)Le Prat de Milou - Montbrun (48) [<51] >+33466485098 (489m)Del Ron - Blajoux (48) >+33466485471 (515m)De La Massas - Hautefage-la-Tour (47) >+33951653565 (188m)Municipal** - Lalbenque [<51] (15/06-15/09) >+33565316117 (275m)Les Chenes - Vaylats (46) [<51] (321m)Aire naturelle du Mazet - Bidon (7) [<51] >+33475043619 (278m)Municipal Prat Del Serre - Vialas (48) >+33466410005 (613m)Municipal l'Hospital - Monheurt (47) [<51] >+33553794614 (30m)Val des Cevennes - Florac (48) >+33466313420 (540m)Municipal Le Plo*** - Recoules Previnquieres [<51] (01/05-30/09) >+33621284242 -CCpg178(636m)La Chapelle - Montbrun (48) >+33466485249 (494m)Le Site de Castelbouc - Sainte Enimie (48) >+33466485189 (488m)La Fontinelle - Bessas (7) >+33475386569 (235m)Municipal Saint Jean - Montcuq (46) >+33565229373 (152m)Municipal Le Mousserrein - La Motte Du Caire (4) >+33492683330 (705m)Naturist - La Plage Des Templiers - Saint Remeze (7) >+33475042858 (188m)La Rouviere les Pins - Vagnas (7) >+33475386141 (242m)Le Rouergue - Villefranche De Rouergue (12) (12/04-30/09) >+33565451624 -CCA(250m)Les Prairies - Seyne (4) (01/05-15/09) >+33492351021 -CCA(1160m)Municipal Les Cigales - Sainte Jalle (26) >+33475273278 (402m)Les Truffieres - Saint Marcel d'Ardeche (7) >+33622821333 (161m)Chon du Tarn - Bedoues (48) >+33466450914 (567m)Chantemerle - Bedoues (48) (01/04-12/11) >+33466451966 -CCA(568m)Municipal Pipiou - Parentis en Born (40) >+33558785725 (22m)Les Fayards - Sainte Enimie (48) >+33466485736 (481m)l'Arbre d'Or - Parentis en Born (40) (01/04-31/10) >+33558784156 -CCpg145-CCA(28m)La Blanche - Seyne (4) >+33492350255 (1122m)A la ferme Prunets - Sainte Enimie (48) [<51] >+33466485598 (983m)Parc de Saint Sauvayre - Vagnas (7) >+33475386151 (206m)De M. Arnal - Sainte Enimie (tentes seulement) (48) [<51] >+33466485445 (498m)Foret Lahitte - Parentis en Born (40) >+33558784717 (29m)Le Mas de Serret - Labastide de Virac (7) [<51] >+33475386093 (256m)Calede - Parentis en Born (40) >+33558784463 (28m)Aire naturelle de Ducom Rene - Parentis en Born (40) [<51] >+33558785382 (50m)Couderc - Sainte Enimie (48) >+33466485053 (482m)Les Crozes - Le Recoux (48) >+33565716900 (880m)Municipal De Layoule - Rodez (12) >+33565670952 (534m)Naturist - Les Manoques - Valeilles (82) >+33563952406 (221m)Le Papagayo - Clairac (47) >+33553843448 (34m)Aire naturelle Les Restanques Rochette - Quezac (48) [<51] >+33466317982 (538m)La Goule - Vagnas (7) [<51] (27/03-28/10) >+33475386124 (208m)Les Cerisiers du Chambonnet - Quezac (48) [<51] >+33466442016 (518m)Ferme l'Indien - Savignac (12) [<51] >+33662623462 (412m)Les Cigales** - St. Genis (01/04-30/09) >+33492662063 (612m)Le Bouquet - Saint Georges de Levejac (48) [<51] >+33466488182 (817m)Le Moulin de Pistou - Aujac (30) >+33466837125 (348m)Municipal de Gilliaou - Le Pont de Montvert (48) >+33466458288 (895m)Le Buisson - Quezac (48) [<51] (505m)A la Ferme Cote de Fumel - Valeilles (82) [<51] >+33563943433 (182m)Les Clos - Nyons (26) >+33475262990 (268m)Domeizel - Sainte Enimie (48) [<51] >+33466485938 (488m)La Grange de Monteillac - Severac L'Eglise (12) (07/05-15/09) >+33687469083 -CCA(645m)Centre De Plein Air - Sainte Enimie (48) >+33466485355 (491m)Moulin de Gournier - Malbosc (7) [<51] >+33475373550 (287m)Municipal Selonnet - Selonnet (4) >+33492350612 (1101m)A la ferme de Gosse Joseph - Quezac (48) [<51] >+33466442303 (504m)Des Arcades - Saint Pantaleon (46) (26/04-30/09) >+33565229227 -CCA(217m)Les Cerisiers - Ispagnac (48) >+33675137587 (511m)Municipal du Pre Morjal - Ispagnac (48) >+33645701407 (509m)l'Or vert - Nyons (26) >+33475262485 (285m)Clos des Oiseaux - Penne d'Agenais (47) >+33553414612 (101m)A la ferme Ferme Bres - La Blachette - Nyons (26) [<51] >+33475260541 (421m)Aire naturelle Municipale Compolibat - Compolibat (12) [<51] >+33565819550 (365m)Aire naturelle Ubertrop - Arpavon [<51] >+33475273285 (400m)Le Vieux Moulin - Ispagnac (48) [<51] >+33466442067 (507m)A la ferme La Roulotte du Forgeron - Brandonnet (12) [<51] >+33633263077 (506m)De La Rouviere - Vallon Pont d'Arc (7) >+33475371007 (105m)Les Terrasses Du Rouret - Grospierres (7) >+33475393148 (173m)Du Midi - Vallon Pont d'Arc (7) >+33475880678 (109m)Camp Des Gorges - Vallon Pont d'Arc (7) >+33475880005 (103m)Aire naturelle de Charron Jean-Luc - Vagnas (7) [<51] >+33475377080 (163m)La Source - Berrias et Casteljau (7) >+33475393913 (126m)l'Aiguebelle - Ispagnac (48) >+33466442026 (522m)De la Chamarade - Chamaret (26) >+33475902166 (167m)Le Pouchou - Tournon d'Agenais (47) [<51] (01/03-30/11) >+33553407268 (151m)Les Cigales - Berrias et Casteljau (7) >+33680258202 (128m)Municipal Robinson - Tonneins (47) [<51] (01/06-20/09) >+33553790228 (26m)Le Bosc - Le Temple sur Lot (47) [<51] >+33553010613 (45m)Courbiac - Courbiac [<51] >+33553716392 (206m)Le Lion - Bourg Saint Andeol (7) (01/04-30/09) >+33475545320 -CCA(56m)De La Chaup - Enchastrayes (4) [<51] >+33492810282 (1189m)De Fans - Rignac (12) [<51] (01/05-30/09) >+33565644956 (425m)Des Rosieres - Rosans (5) >+33492666206 (590m)Garrigon - Grillon (84) (15/03-15/11) >+33490287294 -CCA(176m)Tampico - Barcelonnette (4) >+33492810255 (1125m)Le Plan De Barcelonette - Barcelonnette (4) >+33492810811 (1129m)Du Pont D'Arc - Vallon Pont d'Arc (7) >+33475880064 (106m)Municipal Du Lac de Ferie - Penne d'Agenais (47) >+33553413097 (66m)Moulin De Bannac - Martiel (12) >+33678047112 (350m)Aire naturelle Le Gessy - Verclause (26) [<51] >+33475278039 (598m)Le Peyra - Barcelonnette (4) >+33492812406 (1140m)Le Chateau - Monetier Allemont (5) >+33492664310 (550m)Municipal Du Bourg - Laparade (47) >+33553840519 (179m)A la ferme Les Volets Bleus - Brandonnet (12) [<51] >+33565293543 (485m)Municipal Le Bourg - Belcastel (12) [<51] >+33565645608 (417m)Les Blachas - Salavas (7) (04/04-30/09) >+33475880207 -CCpg256(105m)Latecoere - Biscarrosse (40) >+33558781301 (25m)Municipal Sainte Catherine - Rosans (5) [<51] >+33492666666 (639m)Du pont de Maisonneuve - Beaulieu (7) >+33475393925 (116m)La Ferme les Lebres- Beaulieu (7) [<51] >+33475390351 (116m)Des Tunnels - Vallon Pont d'Arc (7) >+33475880022 (101m)Carrefour De L'Ardeche - Saint Remeze (7) >+33475041575 (382m)Le Pequelet - Salavas (7) >+33475880449 (95m)La Residence - Saint Remeze (7) >+33475042687 (368m)Bout de la Cote - Lagruere (47) [<51] (01/04-31/10) >+33553209547 (30m)Aire naturelle de Boulle Mireille - Saint Remeze (7) [<51] >+33665066130 (359m)L'Ile Sur Mezelet - Vallon Pont d'Arc (7) >+33475370544 (96m)La Coronne - Valreas (84) (01/04-31/10) >+33490350378 -CCA(233m)Le Fontarache - Barcelonnette (4) >+33684050381 (1103m)Le Clapas - Salavas (7) >+33475371476 (92m)Lot et Bastides - Pujols (47) (01/04-30/09) >+33614137893 -CCA(70m)Municipal Rochebouteille - Colonzelle (26) >+33475465032 (165m)Municipal Plage De Gazaille - Castelmoron sur Lot (47) [<51] >+33553849036 (41m)Les Hauts de Rosans - Rosans (5) (26/04-15/10) >+33492666155 -CCpg247-CCA(662m)Aire naturelle de Bilas Gilbert - Le Temple sur Lot (47) [<51] >+33553011291 (44m)La Rouveyrolle - Berrias et Casteljau (7) >+33475390067 (116m)Bel Air - Limogne en Quercy (46) [<51] >+33565243275 (323m)Le Casque Roi - Salavas (7) >+33673855599 (94m)Les Berges Du Lot - Saint Sylvestre sur Lot (47) [<51] >+33553412223 (58m)Le Sablon - Saint Sylvestre sur Lot (47) >+33553413774 (60m)Mazet Plage - Berrias et Casteljau (7) >+33475393256 (142m)River - Meolans-Revel (4) [<51] (01/05-30/09) >+33492855713 -CCA(986m)Dom-De l'Ubaye - Meolans Revel (4) (01/05-15/10) >+33492810196 -CCA(1071m)Les Chadenedes - Grospierres (7) [<51] >+33475390919 (158m)Mondial - Vallon Pont d'Arc (7) (01/04-28/09) >+33475880044 -CCA(87m)Le Chauvieux - Salavas (7) >+33475880537 (90m)A la ferme les Cypres - Saint Pantaleon les Vignes (26) [<51] (01/04-31/10) >+33681537803 (359m)Municipal De Zamenhof - Salavas (7) >+33475880473 (90m)International - Vallon Pont d'Arc(7) (02/05-28/09) >+33475880099 -CCA(89m)Le Provencal - Vallon Pont d'Arc (7) >+33475880048 (88m)L'Ardechois - Vallon Pont d'Arc (7) >+33475880663 (90m)Les Escaliers de la Combe - Saint Matre (46) [<51] >+33565314680 (251m)Naturist - Les Ramieres - Sahune (26) (11/04-12/09) >+33475274045 -CCA(369m)Les Actinidias - Berrias et Casteljau (7) >+33475390279 (131m)Le Rio Clar - Barcelonnette (4) >+33492811032 (1066m)Le Vieux Vallon - Vallon Pont d'Arc (7) (14/03-17/11) >+33475880147 (121m)Le Micocoulier - Salavas (7) >+33475881257 (94m)Le Manoir - Berrias et Casteljau (7) (01/06-15/09) >+33475356850 (188m)Les Tournayres - Berrias et Casteljau (7) >+33475393639 (134m)la Barette - Finiels (48) [<51] (01/05-15/09) >+33466458182 (1226m)Le Vieux Moulin - Berrias et Casteljau (7) >+33475392570 (130m)La Vignasse - Berrias et Casteljau (7) >+33475393044 (133m)De Chaulet-Plage - Berrias et Casteljau (7) >+33475393027 (131m)Les Petits Ecureuils - Biscarrosse (40) >+33558780197 (31m)Rural Les Amandiers - Berrias et Casteljau (7 ) [<51] >+33475390096 (123m)Du Torrent - Vallon Pont d'Arc (7) >+33680082825 (94m)La Roubine - Vallon Pont d'Arc (7) >+33475880456 -BD_FR-N.109(89m)Chaulet Village - Berrias et Casteljau (7) >+33475393139 (130m)Municipal La Peyrade - Rignac (12) [<51] (01/06-15/09) >+33565644464 (501m)La Ferme La Garissonnie - Rignac (12) [<51] >+33673864540 (609m)Beau Rivage - Vallon Pont d'Arc (7) (26/04-13/09) >+33475880354 -CCA-BD_FR-N.110(92m)De Briange - Saint Remeze (7) >+33475041443 (384m)De RamonJavel - Fongrave (47) [<51] >+33629324669 (44m)Les Terrasses Provencales - Nyons (26) >+33475279236 -CCA(460m)Municipal Du Golf - La Canourgue (01/06-15/09) >+33466328400 (627m)Oasis - Grospierres (7) >+33475390919 (118m)Le Pradal - Les Vans (7) (01/04-30/10) >+33475372516 (242m)A la ferme du Soulie-Bias - Villeneuve (12) [<51] >+33614892772 (406m)La Plage Fleurie - Vallon Pont d'Arc (7) >+33475880115 (95m)Le Razal - Vallon Pont d'Arc (7) >+33475880430 (104m)Etoile des Neiges -�Montclar (4) >+33492350129 (1290m)Le Muretois** - Saugnacq et Muret (01/04-30/09) >+33558096214 (47m)Municipal Les Malenies- Privezac (12) >+33565819280 (453m)Des Chenes - Les Vans (7) >+33475373435 (164m)Aire naturelle Municipale Les Allees - Le Mas d'Agenais (47) [<51] >+33553895037 (51m)Municipal - Remuzat (26) >+33475278143 (461m)Lou Rouchetou - Les Vans (7) >+33475373313 -CCA(138m)Les Truffieres - Grignan (26) >+33475469362 (195m)Bonhomme - Vallon Pont d'Arc (7) >+33475880462 (104m)Arc en Ciel - Vallon Pont d'Arc (7) >+33475880465 (105m)La Vallee Bleue - Sahune (26) >+33681199422 (358m)Aire naturelle Les Malenies - Privezac [<51] >+33565819280 (454m)Les Chataigniers - Chambonas (7) >+33475372518 (152m)Aire naturelle La Chataigneraie - Gravieres (7) [<51] (01/04-30/09) >+33608483365 (198m)Le Ranc Davaine -�St. Alban Auriolles (7) (12/04-14/09) >+33475396055 -CCA(116m)Aire naturelle l'Abeille - Vallon Pont d'Arc (7) [<51] >+33681712985 (128m)De L'Esquiras - Vallon Pont d'Arc (7) (12/04-21/09) >+33475880416 -CCA(105m)Le Chambron - Condorcet(26) >+33475277054 (382m)Le Mas Du Serre - Gravieres (7) >+33475373384 (174m)Municipal Les Oliviers - Sahune (26) [<51] >+33475274284 (361m)Chateau De Peyreguilhot - Laparade (47) >+33553668898 (158m)La Hure - Saint Symphorien (33) >+33686770927 (67m)La Vernede - Gravieres (7) >+33475373239 (166m)La Palhere - Pourcharesses (48) [<51] >+33466468063 (754m)Les Barillons*** - Serres (10/05-15/09) >+33492671735 (673m)Municipal La Sagne* - Campagnac [<51] (15/06-15/09) >+33565704127 (707m)L'Amandier - Gigors (4) >+33492551310 (822m)Le Planet - Jausiers (4) [<51] >+33492810657 (1220m)Les Deux Soleils**** - Serres (01/05-31/10) >+33492670133 (763m)Le Rocheyrol - Gravieres (7) >+33622490492 (175m)A la ferme du Serre Rouge - Valaurie (26) [<51] >+33475985011 (123m)Naturist - De Lalbrade - Limogne en Quercy (46) >+33620059857 (250m)A la ferme Le Boilasier - Chandolas (7) [<51] >+33475390119 (176m)Municipal Les Thermes - St. Saturnin de Lenne [<51] (01/07-30/09) >+33565704169 (631m)Rural Le Forestier - Savournon (5) [<51] >+33492670324 (740m)Le Mas De La Source - Sampzon (7) >+33475396798 (110m)Le Chassezac - Sampzon (7) (03/04-19/09) >+33681966876 -CCpg257(104m)Les Trouilleres - Sampzon (7) [<51] >+33475930459 (106m)La Bastide en Ardeche - Ruoms (7) (05/04-27/09) >+33475396472 -CCA(110m)Aire Naturelle Le Bois Des Hoches - Le Lauzet Ubaye (4) [<51] >+33686169146 (886m)Aire naturelle de Noailles - Biscarrosse (40) [<51] >+33677642195 (30m)La Grand'Terre - Ruoms (7) >+33475396494 (102m)Le Trente Pas - Saint Ferreol Trente Pas (26) [<51] >+33475277069 (407m)Le Noyer Du Baron - Le Lauzet Ubaye (4) >+33686169146 (903m)Paradis de Bazas - Bazas (33) >+33556651317 (94m)Du Lac - Curbans (5) >+33492542310 (580m)Rural de Lortal Robert - Lanuejouls (12) [<51] >+33670225404 (503m)Aire naturelle du Bosque - Biscarrosse (40) [<51] >+33558780291 (31m)Bimbo - Biscarrosse (40) (01/04-30/09) >+33558098233 -CCA(29m)Le Carpenty - Ruoms (7) >+33475397429 (106m)Aloha Plage - Sampzon (7) >+33608988503 (101m)La Plaine - Ruoms (7) >+33475396583 (101m)A la ferme La Surre - Chambonas (7) [<51] >+33475372791 (157m)Le Riviera - Sampzon (7) (18/04-21/09) >+33475396757 -CCA(98m)Sun - Sampzon (7) >+33475397612 (103m)La Condamine - La Saulce (5) >+33492542182 (580m)Le Coucouzac - Lagorce (7) >+33475371661 (124m)Le Soleil Vivarais - Sampzon (7) >+33475396756 (98m)Les Ecureuils - Biscarrosse (40) >+33558098000 (24m)Le Confluent - Saint Alban Auriolles (7) >+33475397678 (107m)En Chon les Pins - Biscarrosse (40) >+33558781600 (26m)Aire naturelle de Chenivesse Maryse - Gras (7) [<51] >+33475043990 (344m)Lou Galip - Biscarrosse (40) (31/03-22/09) >+33558098181 (24m)La Chapouliere - Ruoms (7) >+33475396498 (113m)Les Lavandes - Gras (7) >+33630214276 (344m)Naturist - Le Clos Barrat - Serignac (46) >+33565319793 (247m)Navarrosse - Biscarrosse (40) (26/04-14/09) >+33558098432 -CCA(21m)Le Mas des Sedaries - Villefort (48) >+33466462520 (646m)Ferme de Cassagne - Saint Alban Auriolles (7) [<51] >+33681104910 (113m)Municipal - Trentels (47) [<51] >+33553707722 (64m)Aire naturelle Les Bruyeres - Biscarrosse (40) [<51] >+33558787923 (31m)Le Mas du Sartre - Saint Alban Auriolles (7) >+33475397174 (115m)Le Source et Moulin- Le Lauzet Ubaye (4) [<51] >+33492855255 (875m)Aire naturelle de Lafargue - Biscarrosse (40) [<51] >+33558781064 (25m)Mayotte - Biscarrosse (40) (05/04-28/09) >+33558780000 -CCA(24m)Ibie - Vallon Pont d'Arc (7) >+33475880126 (120m)Le Pilat - Saint Ferreol Trente Pas (26) >+33475277209 (460m)Municipal De la Vallee** - Canilhac [<51] (25/06-05/09) >+33466329114 (510m)Le Moulin* - Banassac [<51] (01/05-30/09) >+33466328328 (542m)Les Gorges Du Chassezac - Malarce sur La Thines (7) >+33475394512 (207m)Le Mas de Barry - Ruoms (7) >+33442164782 (119m)D'Imbours - Larnas (7) >+33475543950 (338m)Aire naturelle de Loriot Bruno - Biscarrosse (40) [<51] >+33558787796 (29m)Aire naturelle Le Frezat - Biscarrosse (40) [<51] >+33622655737 (27m)Ferme Pierre Vieille - Cornillac (26) [<51] >+33475274194 (713m)Municipal La Galiniere** - St. Laurent d'Olt [<51] (01/07-31/08) >+33565474110 (497m)Aire naturelle Les Chenes - Saint Montan (7) [<51] >+33475526392 (138m)Aire naturelle Municipale La Coustoune - Villeneuve (12) [<51] >+33565817928 (391m)Plage Sud - Biscarrosse (40) (18/04-14/09) >+33558782124 -CCA(17m)Le Pompit - Esclauzels (46) [<51] >+33565315340 (356m)La Pierre De L'Aigle - La Breole (4) [<51] >+33611144430 (1023m)La Mothe** - Banassac (01/04-30/10) >+33466328811 (526m)La Savane - Labeaume (7) >+33475396354 (109m)La Tuque - Belaye (46) >+33565213434 (255m)Aire naturelle La Graviere - Villefort (48) [<51] >+33466468035 (578m)Aluna - Ruoms (7) (12/04-14/09) >+33475939315 -CCA(190m)A la ferme Le Chaudron Magique - Brugnac (47) [<51] >+33553888077 (99m)Aire naturelle de Morin Joel - Pommerol (26) [<51] (01/04-31/10) >+33475272563 (792m)Des Marmottes - Larche (4) >+33492843364 (1680m)Aire naturelle Le Vieux Pont - Saint Alban Auriolles (7) [<51] >+33475397598 (113m)De Chaussy - Lagorce (7) >+33475939966 (182m)De Chavetourte - Saint Alban Auriolles (7) >+33676035514 (175m)La Truffiere -�St Cirq-Lapopie (46) (12/04-28/09) >+33565302022 -CCpg170-CCA(336m)De Peyroche - Labeaume (7) (12/04-07/09) >+33475397939 -CCA(109m)Lou Cigalou - Payzac (7) [<51] >+33475394868 (350m)La Plage De Peyroche - Labeaume (7) >+33677190917 (109m)L'Ombrage - Lagorce (7) [<51] >+33475397414 (187m)La Cyprea - Lugos (33) >+33557719330 (48m)Municipal - Ruoms (7) >+33475939916 (108m)Lou Carretou - Lagorce (7) >+33475880077 (233m)Les Gonies - Mauroux (46) [<51] (01/04-01/10) >+33565216074 (218m)La Garenne** - La Batie Montsaleon (5) [<51] >+33492671080 (702m)Municipal Le Chene - Tallard (5) [<51] >+33492541014 (614m)La Ferme de la Borde - Bournazel (12) [<51] >+33565644109 (504m)Le Lac - Saint Vincent Les Forts (4) (16/05-28/09) >+33492855157 -CCpg248-CCA(788m)Barneaud - La Breole (4) [<51] >+33492855137 (925m)Les Platanes - Rosieres (7) >+33475395231 (142m)Lou Pibou - Saint Vincent Les Forts (4) [<51] >+33492855158 (817m)Le Vivier - Biscarrosse (40) (26/04-14/09) >+33558782576 -CCA(20m)Des Paillotes - Ruoms (7) >+33673187250 (122m)Municipal du Ciron - Villandraut (33) >+33648073395 (37m)Les 3 Lacs - Rochebrune (5) >+33492544152 (640m)Les Gorges de la Blanches - Espinasses (5) >+33492544026 (662m)De la Rive -�Biscarosse (40) (04/04-30/08) >+33558781233 -CCpg137(23m)Le Petit Bois - Ruoms (7) (01/04-23/09) >+33475396072 -CCA(138m)Le Maguide - Biscarrosse (40) >+33558098190 (32m)Le Lac - Villefort (48) >+33466468127 (638m)Marmotel -�St Geniez d'Olt (12) >+33565704651 (427m)Aire naturelle Municipale le Sol - Drulhe (12) [<51] >+33565806303 (494m)Feleze - La Condamine Chatelard (4) >+33492352579 (1297m)Riviere de Cabessut - Cahors (46) >+33565300630 (119m)Arleblanc - Rosieres (7) (01/04-01/11) >+33475395311 -CCA-BD_FR-N.085(150m)Municipal La Grave - Sainte Eulalie d'Olt (12) >+33565474459 (419m)Municipal La Vignogue - Chanac (48) >+33466482409 (657m)Municipal - Lamagdelaine (46) [<51] (15/06-15/09) >+33565350597 (123m)Ferme de Monredon - Saint Aubin (47) [<51] >+33667532158 (132m)Le Grand Pre - Cenevieres (46) [<51] (01/06-30/09) >+33565302265 (141m)Aire naturelle de Boudigues Alban - Sanguinet (40) [<51] >+33558786336 (34m)Chadeyron - Lagorce (7) [<51] (30/03-13/10) >+33475880481 -CCA(220m)La Boissiere - Saint Geniez d'Olt (12) (05/04-28/09) >+33565704043 -CCpg177(441m)De la Plage - Saint Cirq Lapopie (46) (19/04-30/09) >+33565302951 -CCA(142m)Municipal - Saint Gery (46) >+33565314008 (128m)Carmant - Laborde-Verteuil d'Agenais (47) [<51] (01/05-15/10) >+33553200908 (72m)La Cheneraie - Vers (46) >+33565314029 (172m)Municipal - Altier (48) >+33466468161 (719m)Brise Du Lac - Sainte Eulalie d'Olt (12) >+33565475555 (440m)Le Ruisseau du Treil - Larnagol (46) (10/05-14/09) >+33565312339 -CCA(154m)Les Oliviers - Rosieres (7) >+33678264219 (146m)Du Pont - Pradons (7) (01/04-21/09) >+33475939398 -CCA(127m)La Pinede - Sanguinet (40) >+33558821140 (31m)Ma Kim Lan - Le Nizan (33) [<51] >+33671194244 (87m)Les Gorges du Chassezac - Pied de Borne (48) [<51] >+33466462553 (330m)Les Silhols - Lagorce (7) >+33475875064 (245m)Le Sous Perret - Joyeuse (7) >+33670182842 (147m)La Piboure - La Motte Chalancon (26) >+33475272284 (540m)Laouguey - Sanguinet (40) >+33671324872 (30m)Le Levant*** - St. Germain du Teil (48) >+33466326023 (787m)Base Nautique Floiras - Anglars Juillac (46) [<51] (01/04-15/10) >+33565362739 (90m)L'International - Pradons (7) >+33475396607 (129m)Les Coudoulets - Pradons (7) (19/04-20/09) >+33475939495 -CCA-BD_FR-N.123(130m)Municipal - Saint Bauzile (48) >+33466470597 (714m)La Viste - Espinasses (5) (15/05-15/09) >+33492544339 -CCA(879m)A la ferme Les Glaudes - Saint Pastour (47) [<51] >+33553017177 (148m)Municipal - Marcillac Vallon (12) >+33565717496 (273m)Les Vignes - Puy l'Eveque (46) [<51] >+33670272391 (84m)Municipal de l'Ecluse - Douelle (46) [<51] >+33565200202 (106m)Aire naturelle Les Vernades - Rosieres (7) [<51] >+33475394009 (148m)La Ferme de Clareau - La Motte Chalancon (26) [<51] (11/04-12/10) >+33475272603 -CCA(615m)Le Chti' Franoi - Lablachere (7) >+33475366409 (439m)De Laborie - Pradons (7) >+33475397226 (131m)La Ferme les Ecureuils- Lablachere (7) [<51] >+33475366683 (297m)Aire naturelle de Roche Michel - Lablachere (7) [<51] >+33475366272 (296m)Le Clos Bouyssac - Touzac (46) >+33565365221 -CCA(80m)Le Lac - Sanguinet (40) (27/04-15/09) >+33558827080 -CCpg136-CCA(25m)Municipal - La Motte Chalancon (26) >+33475272295 (540m)Le Moulin - Rosieres (7) >+33475394313 (162m)Du Vignal - Lablachere (7) >+33475366666 (312m)Le Plan D'Eau - Salvagnac Cajarc (12) [<51] >+33565406445 (152m)Le Grillou - Rosieres (7) >+33683058636 (165m)La Nouzarede - Joyeuse (7) (11/04-19/09) >+33475399201 -CCpg258-CCA(162m)Municipal du Terriol - Cajarc (46) [<51] >+33565406520 (149m)Les Grands Pins - Sanguinet (40) (01/04-28/09) >+33558786174 -CCA(25m)La Plaine - Rosieres (7) >+33475395135 (159m)Municipal l'Arquette - Vers (46) >+33565314560 (124m)Le Sablas - Rosieres (7) >+33475395037 (157m)La ferme Le Pre des Roses- Sigoyer (5) [<51] >+33492578166 (1192m)La Digue - Chauzon (7) (01/04-30/09) >+33475396357 -CCA(128m)Le Moulin - La Motte Chalancon (26) [<51] >+33475272603 (546m)Le Coin Charmant- Chauzon (7) [<51] >+33475397873 (130m)La ferme Du Boudenas - Chauzon (7) [<51] >+33675727618 (140m)Les Acacias - Rosieres (7) >+33475399585 (162m)Les Bastides - Chauzon (7) >+33475939279 (130m)Municipal La Graveline** - Chateauneuf du Rhone [<51] (05/06-31/08) >+33475908096 (89m)Les Hortensias - Rosieres (7) (28/04-30/09) >+33475399138 (162m)Le Sous Bois - Saint Maurice D'Ibie (7) >+33475948695 (205m)Les Catalpas - Fumel (47) >+33553711199 (73m)Aire naturelle Le Valenty - Soturac (46) [<51] (01/01-31/12) >+33672576980 (109m)Rochecondrie**** - Viviers (01/04-15/10) >+33475527466 -BD_FR-N.133a(75m)Le Beaussement - Chauzon (7) >+33475397206 (134m)Municipal La Gazelle - Le Bleymard (48) >+33466486048 (1083m)Les Cruses - Ribes (7) [<51] >+33475395469 (265m)Aire naturelle Du Causse - Ambeyrac (12) [<51] >+33565817448 (329m)La Croix De Vinchannes - Joyeuse (7) >+33475395050 (290m)Municipal Les Airials - Hostens (33) >+33556887029 (82m)Aire naturelle Les Galets - Rosieres (7) [<51] >+33664381654 (167m)A la ferme Le Bosc - Rosieres (7) [<51] >+33475394922 (207m)Aire naturelle Le Moulinas - Malataverne [<51] (01/04-30/09) >+33475907235 (94m)Bois Simonet - Joyeuse (7) [<51] (13/04-27/10) >+33475395860 (217m)Duravel - Duravel (46) >+33565246506 (79m)Les Chataigniers - Ribes (7) [<51] >+33689185031 (300m)Base Nautic Alauzet - Mandailles (12) >+33565487464 (435m)Le Ch'timi - Touzac (46) (01/04-30/09) >+33565365236 -CCA(119m)Municipal Les Gravieres - Neffes (5) >+33492578109 (660m)Les Bonnets - Neffes (5) >+33688731359 -CCA(671m)Le Saut du Loup - Rosieres (7) >+33682370117 (207m)Municipal Le Colombier - Valvigneres (7) [<51] >+33475526221 (174m)La Palatriere - Le Sauze Du Lac (5) >+33492442098 (1026m)A la ferme du Moulin de Chamandre - Vernon (7) [<51] >+33475394453 (174m)Saint-Amand - Laurac en Vivarais (7) >+33475368445 (164m)Le Clos des Peupliers - Barjac (48) >+33466470116 (657m)Lou Broustaricq - Sanguinet (40) >+33558827482 (32m)Les Cadichons - Sauliac sur Cele (46) [<51] (01/05-15/09) >+33565309156 (266m)Rural de Ranchin Jules - Balazuc (7) [<51] >+33475377016 (194m)Langeot - Sanguinet (40) >+33558786614 (34m)Le Rocher de Moise - Balsieges (48) >+33466470023 (708m)Les Chataigniers - Laurac en Vivarais (7) (01/04-30/09) >+33475368626 -CCA(185m)La Source - Prayssac (46) >+33565224392 (87m)Le Chateau - Pontis (4) >+33492442499 (1119m)L' Escourby - Vernon (7) [<51] (01/04-30/09) >+33475394356 (326m)Municipal Du Moulin - Valdrome (26) [<51] >+33475214006 (789m)Cournoulises - Montbrun (46) [<51] (25/05-01/10) >+33615530058 (170m)La Croix du Bois - Balazuc (7) [<51] >+33475377020 (186m)Le Medieval*** - Saint Thome (7) (01/04-31/10) >+33475526876 -CCA(113m)Le Retourtier - Balazuc (7) >+33475377767 (194m)Cantal - Cabrerets (46) >+33565312661 (146m)Le Chamadou - Balazuc (7) >+33686915447 (186m)Le Mas D'Aubezon - Vernon (7) [<51] >+33475395120 (301m)Le Tivoli - Bagnols les Bains (48) (05/04-02/11) >+33466476593 -CCA(908m)La Turelure - Uzer (7) >+33475368747 (148m)Les Reflets du Quercy - Catus (46) (05/04-28/09) >+33565300027 -CCpg171-CCA(288m)A la ferme le Verger - Les Orres (5) [<51] >+33492440751 (1372m)Les Rivieres* - Le Monastier (01/06-31/08) >+33466327995 (606m)La Falaise - Balazuc (7) [<51] (01/04-30/09) >+33475377427 (144m)Belle Rive - Saint Come d'Olt (12) >+33565440585 (356m)Les Granges - Pontis (5) >+33492442047 (890m)Tivoli - Mende (48) >+33466650038 (706m)Les Chappas - Pontis (5) >+33662514752 (873m)Le Grand Morgon - Savines Le Lac (5) >+33492442667 (835m)l'Adrech** - Aspres s/Buech (01/04-31/10) >+33492586045 (755m)Municipal - Bouvieres (26) [<51] >+33475533004 (634m)Municipal Bel Iscle - Saint Paul sur Ubaye (4) >+33492843831 (1446m)A la ferme Les Marronniers - Montreal (7) [<51] >+33475368254 (174m)Les Rives du Lac*** - Veynes (5) (01/05-20/09) >+33492572090 -CCA(800m)Municipal les Eygoires - Savines Le Lac (5) >+33492442048 (805m)La Ferme des Crouzets - Sebrazac (12) [<51] >+33565447369 (410m)La ferme Rochepierre - Sanilhac (7) [<51] >+33475391740 (383m)Le Bilos** - Salles (01/01-31/12) >+33556883653 (31m)Solaire** - Veynes (5) (01/01-31/12) >+33492581234 -CCA(800m)La Prade - Largentiere (7) >+33475368354 (171m)Le Chevalet*** - Aspres s/Buech (01/04-31/10) >+33492587309 (830m)Les Grands Pres - Dieulefit (26) >+33630570843 -CCA(378m)Baume Giraud - Balazuc (7) >+33687856903 (226m)Du Roc De L'Arche - Espalion (12) (02/05-20/09) >+33565440679 -CCpg176(337m)Le Matin Calme - Vesc (26) [<51] (01/05-30/09) >+33475463793 (595m)Le Roustou - Prunieres (5) (15/05-25/09) >+33492506263 -CCA(798m)La Motte Flottante - La Freissinouse (5) >+33492578585 (976m)Municipal les Faysses - Cransac (12) >+33565630595 (288m)De Jossoin - Largentiere (7) >+33475892286 (174m)Les Chaumettes - Savines Le Lac (5) >+33492442016 (821m)Municipal Du Lac - Cancon (47) >+33553365430 (132m)Les Sources - Savines Le Lac (5) >+33492442052 (799m)Municipal Au Jardin - Meilhan sur Garonne (47) [<51] >+33553943004 (17m)Municipal Les Pervenches - Prevencheres (48) >+33466460155 (850m)Au Soleil Levant - Chirac (48) (15/04-15/10) >+33466327192 (626m)Aire naturelle Les Acacias - Uzer (7) [<51] >+33607093722 (174m)La Cle des Champs - Chorges (5) >+33661802552 (843m)Naturist - Mas de Nadal - Sauliac sur Cele (46) [<51] (20/04-01/10) >+33565312051 (252m)Les Graves*** - St.Pierre-Lafeuille [<51] (01/03-31/10) >+33565368312 (333m)Le Nautic -�Prunieres (5) (15/05-15/09) >+33492506249 -CCA(793m)La Diege - Sonnac (12) [<51] >+33565646125 (222m)Municipal La Baie Saint Michel - Chorges (5) >+33492506772 (807m)L'Evasion - Martignac-Puy l'Eveque (46) (01/04-30/09) >+33565308009 -CCA(251m)Le Serre Du Lac - Chorges (5) >+33492506757 (861m)Municipal Lorette - Le Poet Laval (26) >+33475910062 (307m)Les Cotes - Vinezac (7) [<51] >+33475368010 (187m)Sirvens - Mende (48) >+33466651693 (736m)Les Airelles - Baratier (5) (15/05-22/09) >+33492431157 -CCA(895m)Rural La Source - Saint Pierre D'Argencon (5) [<51] (16/04-15/10) >+33492586781 (794m)Quercy Vacances**** - St.Pierre-Lafeuille (46) (01/04-30/09) >+33565368715 -CCA(309m)La Pinede - Crots (5) >+33492431355 (823m)Municipal Du Lac De Cazaux - La Teste de Buch (33) >+33556222233 (25m)Aire naturelle Municipale Du Moulin - Badaroux (48) [<51] >+33466477132 (753m)La Montagne - Manteyer (5) >+33492579514 (1349m)Le Cros D'Auzon - Saint Maurice D'Ardeche (7) >+33475377586 (150m)Municipal Le Vert Dourdou - Villecomtal (12) [<51] >+33565446021 (306m)Rural de Combe Yves - Chorges (5) [<51] >+33492506544 (899m)Le Rio Claret - Chorges (5) [<51] >+33492506677 (871m)Le Verger - Baratier (5) >+33681930615 (852m)De L'Arche - Lanas (7) >+33475377915 (157m)Les Peupliers - Vogue (7) >+33475377147 (156m)Manu - Crots (5) >+33492431763 (789m)L'Oasis Des Garrigues - Vogue (7) >+33681046637 (157m)Relais Des Brison - Beaumont (7) >+33671388935 (266m)La ferme Les Fredeyres - Sanilhac (7) [<51] (01/05-31/08) >+33475391449 (455m)Les Deux Bois - Baratier (5) >+33492435414 (843m)Municipal La Garenne - Crots (5) >+33492431193 (789m)Domaine Salinie- Montcabrier (46) >+33565246445 (249m)l'Oasis - Nuzejouls (46) [<51] >+33565200327 (204m)Huttopia - Dieulefit (26) (10/04-03/11) >+33475546394 -CCA(467m)Aire Naturelle La Treille - Savines Le Lac (5) [<51] >+33492442145 (822m)La Prevaliere - Chorges (5) [<51] (08/06-15/09) >+33662639957 (842m)Rural de Belle Vue - Chorges (5) [<51] >+33492506205 (966m)A la ferme de Derbez Noel - Montgardin (5) [<51] >+33492503278 (873m)Aire naturelle Le Grand Pre - Chorges (5) [<51] (01/05-15/10) >+33681464306 (978m)La Drobie - Sablieres (7) >+33475369522 (548m)Municipal Emile Loubet - La Begude de Mazenc (26) >+33475462122 (210m)Les Chenes Verts - Vogue (7) >+33475377154 (176m)Les Esparons - Embrun (5) >+33492430273 (829m)Aire naturelle Les Pommiers - Baratier (5) [<51] >+33687925603 (804m)Cap Du Mount - La Teste de Buch (33) >+33556229479 (27m)Val de l'Eyre*** - Salles (01/04-30/09) >+33556884703 (20m)Le Petit Liou - Embrun-Baratier (5) (01/05-30/09) >+33492431910 -CCA(803m)Moulin de Laborde - Montcabrier (46) (01/05-07/09) >+33565246206 -CCA(132m)Les Grillons - Embrun (5) >+33492433275 (811m)De Chadenas-Club Nautique Alpin - Puy Sanieres (5) >+33492430002 (791m)Municipal - Saint Cyprien sur Dourdou (12) [<51] >+33565728052 (243m)Municipal - Chasserades (48) [<51] >+33466460116 (1158m)Ferme Les Roures - Montelimar (26) [<51] >+33475539144 (206m)Au Blanc Manteau - Manteyer (5) >+33492578256 (937m)Le Coulagnet - Marvejols (48) (15/05-15/09) >+33466320369 (653m)Municipal La Clapiere - Embrun (5) >+33492430183 (785m)Domaine Troteligotte - Pomarede (46) [<51] >+33565200189 (275m)A la ferme les Blanchons - Prunieres (5) [<51] (15/05-15/09) >+33612444148 (1201m)La Source Du Jabron - Dieulefit (26) >+33475906130 (484m)Les Bastides - Salles-Monflanquin (47) (11/04-30/09) >+33553408309 -CCA(114m)A la ferme Le Bardou - Saint Germain (7) [<51] >+33640250571 (198m)La Vieille Ferme - Embrun (5) [<51] (01/05-30/09) >+33492430408 -CCA(800m)La Pineda - La Teste de Buch (33) >+33556222324 (20m)La Tour - Embrun (5) >+33679412907 (803m)Municipal du Pre de Monsieur - Marcilhac sur Cele (46) [<51] >+33565407788 (156m)Aire naturelle Prat Claux - Chasserades (48) [<51] >+33673041408 (1182m)Val en Theze - Montcabrier (46) [<51] (01/04-15/10) >+33565360357 (150m)La Madeleine - Embrun (5) >+33492430116 (805m)Du Theatre - Alba la Romaine (7) >+33475524115 (186m)Les Tourelles - Embrun (5) >+33492431531 (851m)Rural Les Boissets - Avancon (5) [<51] >+33492503280 (932m)L'Etang du Camp - Senergues (20) (01/04-30/09) >+33565460195 -CCA(598m)Le Roubreau - Joannas (7) >+33475883207 (376m)Les Ranchisses -�Largentiere (7) (12/04-21/09) >+33475883197 -CCpg259-CCA(279m)Le Clos Du Lac - Saint Apollinaire (5) [<51] (16/05-21/09) >+33492442743 -CCpg266-CCA(1455m)Municipal La Chantellerie - Estaing (12) [<51] >+33565447032 (343m)La ferme La Terrasse - Chorges (5) [<51] >+33492506616 (1047m)Le Carbet - Cassagnes (46) >+33565366179 (164m)Les Rives d'Auzon - Lavilledieu (7) [<51] >+33475947064 (204m)A la Ferme des Roures - La Begude de Mazenc (26) [<51] >+33475539144 (184m)Le Parc Des Serigons - La Roche Des Arnauds (5) >+33492578177 (900m)La Cavalerie - Estaing (12) [<51] >+33565447194 (320m)La Guarrigue*** - La Faurie (01/04-15/10) >+33492465542 (828m)Municipal Saint Martin - Beaumont en Diois (26) [<51] (01/05-29/09) >+33475212983 (671m)De La Marette - Joannas (7) >+33475883888 (413m)Municipal Chanteduc - Beaurieres (26) >+33475214659 (779m)A la Ferme La Joie - La Batie Rolland (26) [<51] >+33475538151 (177m)La Combe - Joannas (7) >+33475883250 (458m)Aire naturelle De Chaudebry - Vinezac (7) [<51] >+33676282413 (256m)Aire naturelle Grimolles - Rochemaure (7) [<51] >+33475491272 (73m)Municipal Le Cele - Saint Sulpice (46) >+33565406464 (161m)Municipal - Saint Nazaire le Desert (26) [<51] >+33610140602 (560m)Mon Repos - Montmaur (5) >+33492580314 (939m)Le Petit Nice -�Pyla sur Mer (33) >+33556227403 (51m)Le Panorama - Pyla sur Mer (33) (11/04-29/09) >+33556221044 -CCA(47m)Le Pommier - Villeneuve De Berg (7) (25/04-05/09) >+33475948281 -CCA-BD_FR-N.130(344m)Rural Le Mont Orel - Saint Andre D'Embrun (5) [<51] >+33492431592 (1146m)Municipal Les Rives d'Olt - Capdenac Gare (12) [<51] >+33565808887 (169m)Municipal - Brengues (46) [<51] >+33565400682 (160m)l'Allier - La Bastide Puylaurent (48) [<51] >+33466460406 (1047m)La Pinede - Goujounac (46) [<51] >+33565366858 (247m)Municipal De Saint Chavit - Lougratte (47) >+33553016595 (124m)Municipal - La Reole (33) >+33556611355 (16m)Pyla - Pyla sur Mer (33) >+33556221044 (61m)Les Bois Du Chatelas - Bourdeaux (26) (11/04-14/09) >+33475006080 -CCA(493m)Aire naturelle Municipale La Muzette - Valgorge (7) [<51] >+33475889531 (441m)Aire naturelle Aux Paons - Gap (5) [<51] >+33492512995 (891m)Alpes Dauphine -�Gap (5) (15/04-20/10) >+33492512995 -CCA(903m)Le Grand Bois - Le Poet Celard (26) [<51] (29/04-30/09) >+33648381249 (644m)La Dune (Les Flots Bleus) - Pyla sur Mer (33) (12/04-29/09) >+33556227217 (59m)Napoleon - Gap (5) >+33492521241 (943m)Municipal La Pontiere - Laubert (48) >+33466477137 (1204m)Municipal le Gap des Tortelles - Bourdeaux (26) >+33475533045 (414m)Beau Rivage - Livinhac Le Haut (12) >+33565633759 (183m)Le Moulin Bas - Frayssinet Le Gelat (46) [<51] >+33565366632 (190m)La Foret - Pyla sur Mer (33) (11/04-20/09) >+33499572121 -CCpg135(39m)Le Moulin Vieux - Brengues (46) >+33565400041 (170m)Les Arches - Saint Jean le Centenier (7) (25/04-14/09) >+33475367519 -CCA-BD_FR-N.131(288m)Aire naturelle Lou Landier - Veynes (5) [<51] >+33492580494 (963m)Le Roquelongue - Boisse Penchot (12) >+33565633967 (194m)Les Pres - Veynes (5) [<51] >+33492572622 (962m)La Chareyrasse - Saint Pierre Aubenas (7) >+33475351459 (172m)Moulin du Perie -�Sauveterre la Lemance (47) (17/05-20/09) >+33553406726 -CCpg144-CCA(170m)L'Ile Blanc *** - Ancone (15/03-15/11) >+33475512005 (73m)Aire naturelle Municipale Au Bord de la Baralde - Saint Chely d'Aubrac (12) [<51] >+33565442115 (817m)A la ferme Boudonne - Le Poet Celard (26) [<51] >+33475533281 (481m)A la ferme du Villard - Brette (26) [<51] >+33475272292 (741m)Bouriac - Laborde (47) [<51] >+33553366834 (142m)Le Fraysse - Devillac (47) [<51] (01/06-30/09) >+33553360329 (105m)Du Rocher de Jastres - Aubenas (7) >+33475350439 (184m)Aire naturelle du Moulin - Bezaudun sur Bine (26) [<51] >+33475533721 (483m)Le Couspeau -�Le Poet Celard (26) >+33475533014 (584m)Les Acacias - Saint Etienne de Fontbellon (7) >+33475936787 (213m)Roudayres - Saint-Sauveur-la-Vallee (46) [<51] (01/05-01/10) >+33565313599 (238m)La Place - Saint Andre D'Embrun (5) >+33492431513 (909m)Municipal Le Ceytrou - Saint Laurent Les Bains (7) >+33466460203 (727m)Beau Rivage - Conques (12) >+33661174773 (239m)Le Moulinal -�Biron (24) >+33553408460 (161m)A la ferme du Claps - Luc en Diois (26) [<51] >+33475213650 (625m)Les Eygas - Chateauroux les Alpes (5) >+33492436380 (912m)Municipal Bellevue - Golinhac (12) >+33565445073 (661m)Les Cariamas - Chateauroux les Alpes (5) (01/04-31/10) >+33492432263 (932m)Le Moulin - Pradelle (26) [<51] (01/05-01/09) >+33475216996 (507m)La Planque - Le Nayrac (12) [<51] >+33681307922 (665m)Municipal Le Parc - Pont de Barret (26) >+33475904764 (247m)l'Eyre - Mios (33) >+33556264204 (10m)Ludo - Lussas (7) (26/04-05/10) >+33475942122 -CCA(279m)Le Chantalou - Saint Didier sous Aubenas (7) >+33475352580 (184m)Municipal De L'Iscle - Reallon (5) >+33492442708 (1433m)Aire naturelle de la Grange Neuve - Mornans (26) [<51] >+33475533218 (513m)Las Patrasses - Vergt de Biron (24) [<51] >+33553630587 (159m)Municipal Les Cigales - Cleon d'Andran (26) [<51] >+33475901273 (187m)Le Port Lacombe - Flagnac (12) (01/04-30/09) >+33565641008 -CCA(188m)Les Ormes - Saint Etienne de Villereal (47) (25/04-15/09) >+33553366026 -CCA(158m)Rural De Chichoye - Loupiac (33) [<51] >+33556620179 (84m)Domaine du Surgie - Figeac (46) >+33561648854 (204m)A la Ferme Les Pommiers - Chateauroux-les-Alpes (5) [<51] (15/06-15/09) >+33643854538 (1039m)Naturist - Laborde - Monflanquin (47) (01/04-01/10) >+33553631488 -CCA-BD_FR-M.113(139m)Fontaine du Roc - Devillac (47) (01/04-01/10) >+33553360816 -CCA-BD_FR-M.110(153m)Ferme La Civadille - Chateauroux-les-Alpes (5) [<51] (01/05-15/09) >+33492432212 (950m)Municipal Les Foulons - Luc en Diois (26) (10/04-20/10) >+33475213614 -CCA(538m)La ferme du Fraysse - Senergues (12) [<51] >+33565728779 (588m)La Vallee de Gardeleau - Serignac Peboudou (47) [<51] (01/02-30/11) >+33553369696 (89m)Les Pins - Chateauroux les Alpes (5) >+33492432264 (1040m)La Ferme du Battedou - Golinhac (12) [<51] >+33565486162 (414m)Municipal Point Du Jour - Montauriol (47) >+33553369280 (80m)Les Taillas - Ancelle (5) >+33492508090 (1354m)Le Plan d'Eau - Saint Privat (7) (15/04-30/09) >+33475354498 -CCA(195m)La Velle - Montclera (46) [<51] >+33565239463 (172m)Municipal du Rabioux - Chateauroux les Alpes (5) >+33492434378 (852m)A la Ferme L' Oasienne - Clavies [<51] >+33684697903 (309m)Le Moulin - Grand Vabre (12) [<51] >+33565728728 (216m)Les Auches - Ancelle (5) >+33492508028 (1353m)La Ferme les Trois Rieux - Saint Cirgues de Prades (7) [<51] >+33475932244 (402m)Chasselouve - Jaujac (7) >+33475932262 (438m)Le Tourasse - Lauzun (47) [<51] >+33553941021 (93m)Municipal Les Thibauds - Miscon (26) >+33475213047 (821m)La Bastide - Villefranche du Perigord (24) (01/04-30/09) >+33553289457 -CCA(231m)La Plaine - Saint Parthem (12) (01/04-31/10) >+33565640524 (205m)St Vincent - Levignac de Guyenne (47) >+33553837517 (58m)Aire Naturelle Les Lavandes - Soyans (26) [<51] (15/05-15/09) >+33475760409 (314m)Moulin Brule - Agnac (47) [<51] (15/04-15/09) >+33553830756 (118m)Ringaud - Moustier (47) [<51] >+33553646249 (40m)A la Ferme du Bois de Mercier - Douzains (47) [<51] >+33553368197 (92m)Les Charmilles - Darbres (7) (26/04-30/09) >+33475885627 -CCA-BD_FR-N.137(513m)Aire naturelle Les Pommiers - Forest Saint Julien (5) [<51] >+33492507471 (1157m)Municipal - Chateauneuf de Randon (48) >+33466479143 (1175m)Municipal - Cadillac (33) >+33556627298 (7m)Floral - La Coucourde (26) (01/01-31/12) >+33683033404 (102m)Auberge Le Domanial - Pennes le Sec (26) >+33683033404 (776m)Les Aygues Douces - Saint Etienne De Lugdares (7) >+33466466565 (1047m)Ker Helen - Le Teich (33) >+33556660379 (4m)Les Bonnes Vacances - La Teste de Buch (33) >+33556661340 (4m)Aire naturelle de Taylor-Block - Bournel (47) [<51] >+33553366715 (80m)Du Chateau - Chabottes (5) >+33492504995 (1060m)Municipal Du Plan d'Eau - Cazals (46) >+33565228445 (172m)Municipal - Rieutort de Randon (48) [<51] >+33466473331 (1113m)De Coursavy - Cassaniouze (15) [<51] >+33471499770 (211m)De Gil - Ucel (7) (18/04-21/09) >+33475946363 -CCA(228m)Les Auberts - Chabottes (5) [<51] >+33492507348 (1053m)Le Val de Saures - Entraygues sur Truyere (12) (01/05-30/09) >+33565445692 -CCA(228m)A. Dejoie - Gujan Mestras (33) >+33556661224 (2m)Verdalle - Gujan Mestras (33) >+33556661262 (2m)Municipal l'Estombe** - Labastide Murat [<51] (Easter-31/10) >+33565311150 (433m)Le Pastural - Ucel (7) >+33475376028 (235m)Aire naturelle le Gout de Li - Degagnac (46) [<51] (18/05-06/09) >+33565416416 (281m)La Pause - Saint Leger Les Melezes (5) >+33492504492 (1266m)Les Mille Vents - Saint Clement sur Durance (5) >+33492451090 (881m)l'Etoile Du Drot - Monsegur (33) [<51] >+33556616754 (29m)Aire naturelle de La Briance - Saou (26) [<51] (01/04-05/11) >+33627387055 (333m)Les Lavandes - Darbres (7) >+33475942065 (449m)Municipal La Graville - Saou (26) [<51] >+33475760043 (421m)Samba** - Lacanau de Mios (01/01-31/12) >+33557711881 (41m)A la ferme Le Peyret Bas - Villefranche du Perigord (24) [<51] >+33553285978 (219m)Bonneval - Jaujac (7) >+33475932709 (394m)Les Pins - Ucel (7) [<51] (01/06-16/09) >+33475374920 (307m)Le Moulin Vieux - Saint Germain du Bel Air (46) >+33565310071 (201m)l'Estival - Fabras (7) [<51] >+33610464523 (456m)Le Marache - Biganos (33) >+33557706119 (14m)Les Sitelles - Chabottes (5) >+33492504772 (1061m)Municipal Du Pont Des Issoux - Lalevade d'Ardeche (7) >+33475941409 (264m)Club D'Arcachon - Arcachon (33) (01/01-14/11) >+33556832415 -CCpg134(31m)Municipal - Le Fel (12) [<51] >+33565486112 (487m)Le Bergougne - Rives (47) >+33553360130 (109m)Municipal Les Ecureuils - Recoubeau Jansac (26) [<51] >+33475213597 (511m)Municipal Aire Naturelle Les Galets - Luc (48) [<51] >+33466466007 (980m)Le Moulin de Mandassagne - Villereal (47) [<51] >+33553360402 (107m)Papillon - Reyrevignes (46) [<51] (01/06-15/09) >+33565401240 (350m)Les Melezes - Ceillac (5) [<51] >+33492452193 (1672m)Aire naturelle Clos du Celine - Castillonnes (47) [<51] >+33681037891 (103m)La Romiguiere - Montpeyroux (12) [<51] >+33565444464 (595m)Municipal - Castillonnes (47) [<51] >+33553369468 (92m)La Ribiere - Guillestre (5) [<51] (01/06-30/09) >+33492537757 (986m)Le Serre Altitude 1000 - Guillestre (5) [<51] >+33492450040 (1054m)Le Rieutord - Saint Vincent De Barres (7) >+33475650773 (193m)Aire naturelle Le Bon Accueil - Guillestre (5) [<51] >+33492450913 (1039m)Saint James Les Pins - Guillestre (5) (15/12-15/11) >+33492450824 -CCA(937m)Chateau de Fonrives - Rives (47) >+33553366338 (103m)Les Ilons - Cruas (7) >+33475495543 (81m)Les Bastets -�Marsanne (26) (26/04-30/09) >+33475903503 -CCpg263-CCA-BD_FR-O.116(237m)Municipal La Rochette - Guillestre (5) (15/05-30/09) >+33662170215 -CCA(953m)Le Vivier - Guillestre (5) >+33492450147 (948m)Les Sycomores- Lalevade d'Ardeche (7) >+33466466007 (279m)Le Villard - Guillestre (5) >+33492450654 (916m)Le Couriou - Recoubeau Jansac (26) (01/04-15/09) >+33475213323 -CCpg264-CCA(499m)La Chevre** - Lus la Croix Haute (39) (20/04-14/09) >+33492585014 -CCpg265-CCA(500m)Le Moulin Des Donnes - Concores (46) >+33565310390 (179m)Moulin De David - Gaugeac (24) >+33553226525 (149m)La Ferme de Caffoulens - Bagnac sur Cele (46) [<51] >+33565349581 (310m)Municipal - Chaudeyrac (48) [<51] >+33466479107 (1140m)A la ferme de Naulet - Mourens (33) [<51] >+33556619626 (99m)Retour a la Source - Marminiac (46) [<51] >+33565307242 (235m)Le Catinat Fleuri- Guillestre (5) >+33492450762 (1028m)La Hontanille - Laroque (33) >+33556626011 (57m)Municipal Les Moutets - Ceillac (5) >+33492451789 (1640m)A la ferme l'Eperviere - Guillestre (5) [<51] >+33492451376 (1068m)Les Berges du Cele - Bagnac sur Cele (46) [<51] (01/06-15/09) >+33565349431 (230m)Le Diamant - Saint Jean Saint Nicolas (5) >+33492559125 (1111m)La Charderie - Pont de Labeaume (7) >+33475380052 (313m)Les Tours -�Saint Amans des Cots (12) (05/06-06/09) >+33565448810 -CCpg175(617m)La Chataigneraie - Mayres (7) [<51] (01/05-30/09) >+33475872040 (687m)Municipal Le Grand Pre - Barnas (7) >+33475364012 (461m)Le Ventadour - Meyras (7) (19/04-05/10) >+33475941815 -CCA(318m)Les Rives Du Drac - Saint Bonnet En Champsaur (5) [<51] >+33687846148 (998m)Au fil de la Volane - Vals Les Bains (7) >+33475374685 (261m)Municipal Du Chateau - Eymet (24) >+33553238028 (50m)Le Belos - Thueyts (7) >+33475364435 (423m)Les Rives de l'Ardeche - Mayres (7) >+33475872139 (656m)Municipal - Nasbinals (48) [<51] >+33466325187 (1172m)Des 6 Stations - Saint Jean Saint Nicolas (5) [<51] >+33492559195 (1137m)Le Barutel - Meyras (7) >+33475380378 (338m)Municipal du Stade - Linac (46) [<51] >+33565349387 (396m)La Motte - Saillans (26) [<51] >+33475215240 (428m)La Condamine** - Lus la Croix Haute (01/02-31/10) >+33492585086 (1006m)La Plage du Relais*** - Frayssinet (01/04-31/10) >+33565302142 (232m)De la Plage - Meyras (7) >+33475364059 (344m)Le Pont De Mercier - Thueyts (7) >+33687856903 (380m)Municipal Les Iscles - Eygliers (5) >+33492451418 (900m)Les Chenes- Vesseaux (7) [<51] >+33761897000 (444m)Rural de Rioux Joseph - Berzeme (7) [<51] >+33475642152 (773m)Municipal Les Pradels - Assier (46) >+33565405797 (350m)Municipal Du Lauradiol - Campouriez (12) [<51] >+33565445395 (265m)Municipal - Duras (47) [<51] >+33553837018 (80m)Le Veronne - Saulce sur Rhone (26) [<51] >+33475630170 (90m)Municipal La Fontaine - Reotier (5) >+33681296200 (902m)Aire naturelle La Magerie - La Roche sur Grane (26) [<51] (01/03-01/11) >+33475627177 (301m)La ferme Crestilie - Soulages Bonneval (12) [<51] >+33565443163 (865m)Base De Loisirs - Orcieres (5) >+33492557667 (1298m)La Jarjatte* - Lus la Croix Haute (20/05-30/09) >+33492585058 (1181m)A la ferme Du Passe Temps- Degagnac (46) [<51] >+33565321042 (194m)L'Hirondelle -�Menglon (26) (19/04-14/09) >+33475218208 (510m)Moulin de Chaules - Saint Constant (15) (12/04-26/10) >+33471491102 -CCA(293m)Municipal Les Monts D'Aubrac - Laguiole (12) >+33565443972 (1040m)Le Lac Bleu - Chatillon en Diois (26) (19/04-28/09) >+33475218530 -CCA(513m)A la ferme Le Cabri - Duras (47) [<51] (01/01-31/12) >+33553838103 -CCA(65m)Municipal De La Vernhe - Saint Amans Des Cots (12) >+33565448619 (712m)Les Auches - Saint Etienne en Devoluy (5) >+33492588303 (1303m)A la ferme la Frairie - Eygliers (5) [<51] >+33492451902 (1011m)Municipal - Salviac (46) >+33565415598 (157m)Le Braou - Audenge (33) (01/04-30/09) >+33556269003 -CCA(10m)La Poche** - Mirmande (01/04-30/09) >+33475630288 (249m)Municipal - Saint Urcize (15) [<51] >+33471232139 (1147m)Rural de Bosredon - Doissat (24) [<51] >+33684902103 (306m)Municipal Le Solicou - Saint Constant (15) >+33471491030 (255m)Le Pont d'Espenel - Espenel (26) >+33475217295 (305m)La Clairette - Espenel (26) >+33475217448 (279m)Rural de Emmen Antoinius - Saint Aubin de Nabirat (24) [<51] >+33553284271 (112m)La Faurie*** -�Seniergues (46) (05/04-30/09) >+33565211436 -CCpg172-CCA(331m)Les Civelles d'Ozon** - Saint Lager Bressac (01/04-30/09) >+33475650186 (159m)La ferme La Casse - Orcieres (5) [<51] (01/05-30/09) >+33661722348 (1544m)Municipal Les Chaussieres - Chatillon en Diois (26) >+33475211030 (558m)Aire naturelle Ma Colline - Piegros La Clastre (26) [<51] >+33475400160 (238m)La ferme Le Massiol - Saint Michel De Boulogne (7) [<51] >+33475871004 (495m)Municipal Les Chapelains - Saillans (26) [<51] (19/04-15/09) >+33475215547 -CCA(258m)Municipal La Colombe - Aurel (26) >+33475217629 (421m)Les Acacias - Vercheny (26) (01/04-30/09) >+33475217251 -CCA(313m)Les Chamberts - Piegros La Clastre (26) [<51] (01/05-30/09) >+33475750864 (232m)Municipal Du Pont De Drome - Vercheny (26) >+33475217639 (291m)Lac de Veronne - Monpazier (24) >+33553226222 (181m)Aire naturelle de Saint Pierre - Vercheny (26) [<51] >+33475217493 (299m)Municipal La Grangeotte - Montsalvy (15) >+33477390827 (772m)Aire naturelle Le Petit Nid - Mirabel et Blacons (26) [<51] >+33475400070 (231m)Municipal - Serverette (48) [<51] >+33466483036 (992m)La Chataigneraie - Montpezat Sous Bauzon (7) [<51] >+33614869931 (519m)La Ferme Lou Tuquet - Fonroque (24) [<51] (01/04-01/10) >+33553743832 (136m)Les Trois Becs - Piegros La Clastre (26) >+33475400377 (223m)Municipal Pres Des Etangs - Cassaniouze (15) >+33471499003 (520m)La Ferme Chez Bebert - Lolme (24) >+33678315226 (208m)Municipal Du Vert - Maurs (15) [<51] >+33471490415 (252m)De Minjou - Faurilles (24) [<51] >+33553587124 (114m)Le Merle Roux** - Baix (01/04-31/10) >+33475858414 -CCA(189m)Municipal De L'Ile - Saint Crepin (5) >+33678107523 (910m)Municipal** - Aumont Aubrac (01/07-31/08) >+33466428002 (1051m)Du Roumingue - Lanton (33) >+33556829748 (6m)La Garrigeat - Saint Amans les Cots (12) [<51] >+33565448810 (496m)Aire naturelle Famille Du Cheminot - Montpezat Sous Bauzon (7) [<51] >+33475944210 (518m)Naturist - Val Drome Soleil - Mirabel et Blacons (26) >+33475400157 (290m)Municipal Pre Bonnefoy - Montpezat Sous Bauzon (7) (01/05-30/10) >+33475944255 (526m)La Cabane - Saint Crepin (5) >+33492450733 (916m)Aire Naturelle Municipale - Calvinet (15) [<51] >+33471499432 (569m)Gervanne - Mirabel et Blacons (26) (01/04-30/09) >+33475400020 -CCA(212m)Municipal La Riviere - Saint Hippolyte (12) >+33565661816 (270m)Aire naturelle De La Gazelle - Langogne (48) [<51] >+33466691203 (998m)Coq Hardi - Lanton (33) >+33556820180 (6m)A la ferme le Barrail - Saint Sernin (47) [<51] >+33553947772 (86m)Le Truc Vert - Lege Cap Ferret (33) >+33556608955 (9m)Les Tuilleres - Vercheny (26) >+33475211886 (321m)La Bezorgues - Aizac (7) [<51] >+33475882425 (534m)Municipal - Antraigues sur Volane (7) >+33668304660 (438m)Le Paradis - Gourdon (46) [<51] (15/04-10/09) >+33565416501 (244m)Aire naturelle Chanterane - Molines en Queyras (5) [<51] (10/06-15/09) >+33661412826 (1902m)Les Clorinthes - Crest (26) (28/04-14/09) >+33475250528 -CCA(184m)Le Trel - Saint Pompont (24) >+33553284378 (129m)Le Soleil - Saint Aubin de Nabirat (24) [<51] >+33553284271 (226m)Naturist - Chateau Guiton - Frontenac (33) [<51] >+33556235279 (56m)Pont De Braye - Chastanier (48) [<51] (01/05-20/09) >+33466695304 -CCA(1060m)Municipal - Lanarce (7) >+33466694787 (1165m)Fontaine Vieille - Andernos-les-Bains (33) (01/04-30/09) >+33556820167 -CCA(4m)Ardeche -�Privas (7) (11/04-26/09) >+33475640580 -CCpg260(250m)La Pierre a Feu - Aouste sur Sye (26) >+33475767623 (241m)Les 4 Saisons**** - Grane (26) (01/04-30/09) >+33475626417 -CCpg262-CCA(195m)Le Serre - La Motte en Champsaur (5) >+33492501121 (1093m)Municipal De l'Allier - Langogne (48) >+33466692898 (915m)Chateau Lacomte**** - Carlucet (46) (01/05-15/09) >+33565387546 -CCA(323m)Le Douzou - Bouzic (24) [<51] (29/03-30/09) >+33553284160 (116m)Municipal Le Bourg - Issigeac (24) [<51] >+33553587962 (108m)A la ferme de l'Olivier - Crest (26) [<51] >+33475626370 (172m)Naturist - Rural de Eymery Rene - Saint Martial de Nabirat (24) [<51] >+33553283164 (137m)Municipal Bois de Sophie - Lacapelle Marival (46) [<51] >+33565408259 (392m)Les Terrasses du Lac -�Langogne (48) (15/04-30/09) >+33466692962 -CCA(953m)Les Viviers - Lege Cap Ferret (33) >+33556607004 (7m)Naturist - Le Marcassin - Saint Aubin de Nabirat (24) >+33553285730 (207m)Rural Bois de la Dame - Monsaguel (24) [<51] >+33553582618 (168m)Moto - Montclar sur Gervanne (26) (motorbikes only) [<51] >+33475400483 (260m)Moulin d'Onclaire - Coux (7) [<51] >+33699743592 (194m)Municipal - Burzet (7) [<51] >+33475944391 (529m)Municipal Saint Gervais - Saint Symphorien De Thenieres (12) [<51] (01/05-30/09) >+33565448243 (714m)Aire naturelle Le Moulin De Charrier - Labastide sur Besorgues (7) [<51] >+33677916247 (708m)Moto La Vieille Eglise - Saint Aubin de Nabirat (24) [<51] >+33553312406 (184m)Les Sous Bois du Lac - Chastanier (48) (02/05-27/09) >+33681289089 -CCpg211(1028m)Rondin des Bois - Rocles (48) (01/05-30/09) >+33466695046 (1015m)Le Moulin Du Rayol - Lavillatte (7) >+33466694756 (1103m)Rural de Monteil Alain - Flaviac (7) [<51] >+33475657411 (162m)Aire naturelle Municipale - Montet et Bouxal (46) [<51] >+33565402260 (603m)Municipal Des Allouviers - Freissinieres (5) >+33492209324 (1130m)Les Hauts de Ratebout - Sainte Foy de Belves (24) >+33553290210 (235m)La Ferme de la Croze - Saint Joseph des Bancs (7) [<51] >+33475933623 (661m)Le Carbonnier - Saint Martial de Nabirat (24) >+33553284253 (197m)Le Glandasse - Die (26) (10/04-30/09) >+33475220250 -CCA(401m)Aire naturelle La Truite - Montclar sur Gervanne (26) [<51] >+33475764200 (278m)Les Pins - Lesperon (7) >+33466693844 (1033m)Municipal Le Lac - La Roche De Rame (5) >+33492209031 -CCA(944m)Le Teuliere - Issendolus (46) >+33565408671 (329m)Rural de Pistolozzi Christian - Saint Amand de Belves (24) [<51] >+33633887562 (236m)Le Quercy - Gourdon (46) (26/04-19/09) >+33565410619 -CCA(186m)Le Daguet - Saint Laurent la Vallee (24) [<51] (01/06-15/09) >+33553282955 (280m)Municipal La Graviere - Auroux (48) >+33466695234 (992m)Municipal de Justin - Die (26) >+33475221477 (396m)Municipal Les Pastourelles - Lege Cap Ferret (33) >+33556607061 (7m)Municipal Les Embruns - Lege Cap Ferret (33) >+33556607076 (7m)Municipal La Bourliette*** - Lorion s/Drome (01/05-20/09) >+33475855194 (104m)La Peyrugue - Daglan (24) (01/04-01/10) >+33553284026 -CCA(101m)Le Riou Merle - Die (26) (01/04-15/10) >+33475222131 -CCA(422m)Les Nauves - Belves (24) (05/04-27/09) >+33553291264 -CCA(175m)Calmesympa - Saint Martial de Nabirat (24) [<51] (15/06-15/09) >+33553284315 (165m)Belle Roche*** -�Lalley (38) (25/03-10/10) >+33476347533 -CCA(832m)Le Lac - Blasimon (33) >+33556618273 (51m)Beau Soleil ** - Gradignan [<51] (01/01-31/12) >+33556890048 (40m)Naturist - Le Couderc - Naussannes (24) >+33553224040 (123m)Les Airelles - Saint Cirgues En Montagne (7) >+33475389249 (1059m)Du Murier Le Glandasse - Die (26) [<51] (28/04-23/09) >+33475210551 (384m)Le Pot De Resine - Ares (33) >+33556602531 (5m)L'Albanou*** - St.Julien en St.Alban (7) (20/04-30/09) >+33475660097 -CCA(112m)La Pinede - Die (26) (25/04-14/09) >+33475221777 (397m)Les Goelands - Ares (33) >+33556825564 (7m)Pleine Foret - Andernos Les Bains (33) >+33556821718 (18m)Les Arbousiers - Andernos Les Bains (33) >+33556821246 (17m)Municipal L'Iscle - Chateau Ville Vieille (5) >+33492467621 (1360m)Le Verger - La Roche De Rame (5) >+33492209223 (988m)Naturist - Terme D'Astor - Bouillac (24) (19/04-28/09) >+33553632452 (166m)Les Pierres Blanches - Beaumont du Perigord (24) >+33668934500 (139m)Les Mouettes - Ares (33) (2m)Pasteur Vacances - Ares (33) (01/03-15/11) >+33556603333 (4m)RCN Le Moulin de La Pique - Belves (24) (19/04-27/09) >+33553290115 -CCpg143-CCA(103m)Municipal Rocher De Grelet - Pradelles (43) >+33471008007 (1100m)De Chamarges - Die (26) (29/03-05/10) >+33475221413 -CCA(379m)Aire Naturelle La Condamine - Pontaix (26) [<51] >+33670491292 (339m)Moulin De Paulhiac - Daglan (24) (10/05-14/09) >+33553282088 -CCA(89m)Municipal De Rieutord - Usclades et Rieutord (7) >+33475380048 (1131m)La ferme de Valette - Ladinhac (15) [<51] >+33471478033 (617m)Municipal la Monta - Ristolas (5) >+33492468779 (1639m)La Ferme le Folastere - Saint Julien du Gua (7) [<51] >+33475668504 (725m)La Gardonnette - Pomport (24) >+33553588194 (60m)Les Abberts - Ares (33) >+33556602680 (4m)Municipal le Moulin - Lacalm (12) [<51] >+33565443012 (1070m)La Cigale - Ares (33) >+33556602259 (5m)Le Reve - Le Vigan (46) (15/05-21/09) >+33565412520 (306m)Rastaillou - Cadouin (24) [<51] >+33553574402 (178m)Rural Les Garennes - Faux (24) [<51] >+33553243116 (120m)Le Galier** - St. Alban s/Limagnole (48) (01/03-30/09) >+33466315880 -CCA(932m)Municipal Fontmaure - Pradelles (43) >+33471008037 (1196m)Municipal Les Ecrins - L'Argentiere la Bessee (5) >+33620970973 (963m)Les Cascades - Saint Cybranet (24) [<51] >+33553283226 (86m)La Canadienne - Ares (33) (01/02-30/11) >+33556602491 -CCA(8m)Municipal - Boisset (15) >+33471622290 (406m)Le Ceou - Saint Cybranet (24) >+33553283212 -CCA(91m)Municipal Le Valadio - Grandrieu (48) (15/06-15/09) >+33466463026 (1159m)Municipal - Marcoles (15) [<51] >+33471469898 (682m)Les Pialades - Nabirat (24) >+33553285228 (126m)Le Chambourlas -�Les Ollieres (7) (15/04-30/09) >+33475662431 -CCA(423m)La Villette - Saint Firmin (5) [<51] >+33687308983 (944m)La Pra - Saint Firmin (5) [<51] >+33492554876 (925m)La ferme Moulinage du Sablas - Saint Etienne de Serre (7) [<51] >+33671809806 (391m)Le Vieux Chateau - Rauzan (33) [<51] (30/03-31/10) >+33557841538 -CCA(44m)Bel-Air - Creon (33) >+33556230190 (104m)Municipal Leyme - Leyme (46) >+33565389873 (463m)Pech de Caumont - Cenac et Saint Julien (24) (01/04-30/09) >+33553282163 -CCA(140m)Municipal Le Gouret - Aiguilles (5) [<51] >+33492467461 (1504m)De la Belonne - Beaufort sur Gervanne (26) [<51] >+33475764615 (397m)La ferme La Combette - Rouffilhac (46) [<51] >+33678585999 (205m)Les Pins - Payrac (46) (19/04-07/09) >+33565379632 -CCA(330m)Le Queyras - Abries (5) >+33603152044 (1555m)Aire Naturelle Chez Gaby - Rocamadour (46) [<51] >+33565336517 (255m)Municipal - Cros De Georand (7) [<51] >+33475389383 (1047m)Bel Ombrage - Saint Cybranet (24) >+33553283414 (84m)Rural de Aguesse Philippe Et Babette - Faux (24) [<51] >+33553243257 (153m)La Grande Veyiere - Molieres (24) [<51] (15/06-15/09) >+33684044608 (163m)La Lenotte - Montplaisant (24) >+33553302580 -CCA(72m)A la ferme des Boutins - Saint Baudille et Pipet (38) [<51] >+33476346364 (907m)Lou Castel - Castelnaud La Chapelle (24) >+33553298924 (231m)Bremontier - Lege Cap Ferret (33) >+33556600399 (10m)Les Landes - Latronquiere (46) [<51] >+33565402662 (649m)Municipal Du Planet - Arvieux (5) [<51] >+33492467915 (1845m)Rural de Bonthoux Elie - Aspres Les Corps (5) [<51] >+33492552069 (939m)Municipal - Saint Paul de Tartas (43) [<51] >+33471008144 (1205m)Rural de English Nelson - Cenac et Saint Julien (24) [<51] (195m)Municipal - Sainte Genevieve sur Argence (12) [<51] >+33565661975 (808m)Municipal - Coucouron (7) [<51] >+33466461308 (1154m)Municipal Le Picouty - Payrac (46) [<51] (31/03-01/11) >+33687279952 (288m)Lac de Grolejac - Grolejac (24) >+33553594870 (91m)Le Vieux Moulin - Grandrieu (48) >+33466464037 (1005m)La Prairie - Lege Cap Ferret (33) >+33556600975 (12m)Mer Et Foret - Lege Cap Ferret (33) >+33556601836 (12m)La ferme La Ressegue - Molieres (46) [<51] (01/04-31/10) >+33621417151 (361m)Aire naturelle de Estay Bertrand - Rocamadour (46) [<51] (01/05-30/09) >+33565337182 (279m)Le Relais Du Campeur - Rocamadour (46) >+33565336328 (257m)Municipal de Cenac - Cenac et Saint Julien (24) >+33553283191 (72m)Maisonneuve - Castelnaud La Chapelle (24) (01/04-31/10) >+33553295129 -CCA(73m)Les Cigales - Rocamadour (46) (10/04-20/09) >+33565336444 (259m)Rural de Sardan Jean-Louis - Cenac et Saint Julien (24) [<51] >+33553282334 (188m)Le Panoramic - Payrac (46) [<51] (01/01-31/12) >+33565379845 (296m)A la ferme de Monteil Eugene - Rignac (46) [<51] >+33565336025 (295m)Mas De Champel - Les Ollieres sur Eyrieux (7) (26/04-21/09) >+33475662323 -CCA(191m)Eyrieux - Les Ollieres sur Eyrieux (7) >+33607221743 (187m)Le Tournesol - Sainte Genevieve sur Argence (12) [<51] (01/01-31/12) >+33565664965 (909m)Mini Chateau La Tour - Saint Pierreville (7) [<51] >+33475666400 (704m)La Pinede - Lege Cap Ferret (33) >+33556600639 (16m)Verte Rive - La Roque Gageac (24) [<51] >+33553283004 (73m)Des Plantas -�Les Ollieres sur Eyrieux (7) >+33475662153 (200m)Municipal La Grave - Sainte Eulalie(7) [<51] >+33565474459 (1218m)Ferme des Campagnes - Rocamadour (46) [<51] (01/04-01/11) >+33565336337 (258m)Naturist - Les Grands Chenes - Lamothe Fenelon (46) >+33565416879 (213m)Les Jardins De L'Abbaye - Le Buisson De Cadouin (24) [<51] >+33553618930 (144m)Municipal Valpreveyre - Abries (5) [<51] >+33492457226 (1857m)Le Bocage - Saint Maurice en Valgodemard (5) [<51] >+33492218648 -CCA(962m)Municipal De Gourjatoux - Marcols Les Eaux (7) [<51] >+33475656336 (742m)Municipal De Puausson - Saint Pierreville (7) [<51] >+33475666568 (563m)Les Tilleuls - Rocamadour (46) [<51] >+33565336466 (302m)Les Pastourels - Veyrines de Domme (24) (12/04-27/09) >+33553295249 -CCA(168m)Le Pre Rolland*** - Mens (21/04-15/09) >+33476346580 (770m)Municipal Les Chataigniers - Saint Sauveur De Montagut (7) [<51] >+33475653622 (237m)La Riviere De Domme - Domme (24) [<51] >+33553283346 (81m)Le Perpetuum - Domme (24) (01/05-10/10) >+33553283518 -CCA(75m)Les Granges - Grolejac (24) (26/04-13/09) >+33553281115 -CCA(98m)Aire naturelle de Vial Aime - Prebois (38) [<51] >+33476346003 (598m)A la ferme de Bonneau - Le Lac d'Issarles (7) [<51] >+33466462389 (1004m)Beau Rivage - La Roque Gageac (24) (26/04-13/09) >+33553283205 -CCA(76m)Municipal La Croix des Anglais** - St. Chely d'Apcher [<51] (01/04-31/10) >+33466310324 (1042m)Lac Du Sautet - Corps (38) [<51] >+33467863087 (777m)Chez Prosper - Fournels (48) [<51] >+33466316596 (958m)Aire naturelle Municipale Les Melezes - La Chapelle en Valgaudemar (5) [<51] >+33492552366 (1087m)Rural de la Chenaie - Ourches (26) [<51] (01/01-31/12) >+33475603169 (246m)Padimadour - Rocamadour (46) [<51] (30/04-12/10) >+33553590361 -CCA(320m)Aire naturelle Les Pres Ronds - La Chapelle En Valgaudemar (5) [<51] >+33492552888 (1085m)La Plaine de la Loire - Le Lac d'Issarles (7) >+33624492279 (908m)Les Marines - La Chapelle en Valgaudemar (5) [<51] >+33615097896 (1090m)Municipal Les Voiliers - Beauchastel (7) >+33614848202 (96m)Municipal les Aires - Corps (38) [<51] >+33476300385 (932m)A la ferme la Noyeraie - Grolejac (24) [<51] >+33672513454 (137m)Le Roc - Rocamadour (46) [<51] >+33565336850 (282m)Municipal Les Vaudois - Les Vigneaux (5) [<51] >+33492230209 (1042m)La Rouillere - Corps (38) [<51] >+33476300334 (928m)Les Pierres Chaudes - Veyrignac (24) [<51] (01/04-01/11) >+33670852293 (143m)La Butte - La Roque Gageac (24) >+33680007869 (87m)Moulin De Caudon - Domme (24) [<51] >+33553310369 (87m)Rural Treil - Loupiac (46) [<51] >+33565376487 (260m)Le Bosquet - Domme (24) [<51] (11/04-27/09) >+33553283739 -CCA(80m)Les Charmes - Sainte Mondane (24) [<51] >+33688607684 (145m)Municipal Bois Chabrier - Albon d'Ardeche (7) [<51] >+33475656581 (625m)La Plage - Saint Seurin De Prats (24) >+33553586107 (11m)La Ferme Gabert - Clelles (38) [<51] >+33476344251 (765m)De Fromengal - Le Buisson De Cadouin (24) >+33553631155 (193m)Site Neolithique de Sigoniac - Molieres (24) [<51] >+33553272511 (141m)La Bouysse - Carsac-Vitrac (24) (12/04-21/09) >+33553283305 -CCA(75m)Municipal Bord Dordogne - Sainte Terre (33) [<51] >+33557471623 (6m)Municipal La Croix - Eynesse (33) [<51] >+33557410038 (25m)Le Bras - Domme (24) [<51] >+33553283420 (82m)Les Gravieres - Villar Loubiere (5) [<51] >+33492553535 (1024m)Municipal Les Bords du Lac - Le Lac d'Issarles (7) >+33640607934 (1007m)La Plage - Vezac (24) (01/04-30/09) >+33553295083 -CCA-BD_FR-M.073(73m)Pralong - Saint Pierreville (7) [<51] >+33475666372 (550m)Le Courounba - Les Vigneaux (5) (01/05-14/09) >+33492230209 -CCA(1091m)Rural de la Riviere de Prats - Juillac (33) [<51] >+33557402736 (9m)De l'Amiral - Saint Laurent du Pape (7) [<51] (01/01-31/12) >+33475624212 (126m)Soleil Plage - Sarlat la Caneda (24) (11/04-30/09) >+33553283333 -CCpg142(75m)Aire naturelle le Marconnes - Saint Arcons de Barges (43) [<51] >+33471010116 (1110m)La Sagne - Vitrac (24) [<51] >+33553281836 (80m)Du Port - Siorac en Perigord (24) [<51] >+33618126475 (55m)Croque Loisirs - Puy Saint Vincent (5) [<51] >+33492202447 (1477m)Le Ventoulou - Thegra (46) (01/04-02/11) >+33565336701 -CCA(349m)La Cabane - Vezac (24) >+33553295228 (70m)La Garenne*** - St. Laurent du Pape (7) (15/03-31/10) >+33475622462 -CCA(129m)La Gare des Amis - Saint Fortunat sur Eyrieux (7) [<51] >+33475652280 (149m)Des Moulins - Couze et Saint Front (24) [<51] >+33689857624 (45m)Le Tolerme - Senaillac Latronquiere (46) >+33565402123 (545m)Chez Nanie - Coux et Bigaroque (24) [<51] >+33553316511 (56m)Aire naturelle La Mare - Etoile sur Rhone (26) [<51] >+33475593379 (160m)Aire naturelle Municipale Lo Qualh - Flaujagues (33) [<51] >+33557400833 (10m)L'Ardechois -�St Sauveur de Montagut (7) (09/05-19/09) >+33475666187 -CCpg261-CCA(423m)La Riviere Fleurie - Saint Antoine de Breuilh (24) (10/04-20/09) >+33553248280 -CCpg138(16m)Les Magnanas - Vezac (24) >+33553295179 (71m)Le Rocher De La Cave - Carsac Aillac (24) >+33553281426 (78m)La ferme l'Ouysse - Lacave (46) [<51] >+33565326301 (107m)Municipal - Brommat (12) [<51] >+33565660096 (648m)La Ferme La Vallee des Chateaux - Domme (24) [<51] >+33553295186 (92m)Le Pont de Fayrac - Vezac (24) >+33553295473 (67m)Le Moulin de Rivet - Saint Julien en Quint (26) [<51] (06/04-02/11) >+33475212043 (540m)Le Plein Air Des Bories - Carsac Aillac (24) (01/05-20/09) >+33553281567 -CCA(76m)Municipal Cantoin - Cantoin (12) [<51] >+33565664315 (923m)La Cascade - Mayrinhac Lentour (46) [<51] >+33565382091 (350m)Les Teuilleres - Sousceyrac (46) [<51] (01/06-15/09) >+33565119055 (568m)Domaine De Barbe - Badefols sur Dordogne (24) [<51] >+33553734220 (130m)Les Hirondelles*** - Loupiac (15/04-20/09) >+33565376625 (261m)Les Deux Vallees - Vezac (24) (17/02-12/11) >+33553295355 -CCA(72m)Clos Bernard - Vitrac (24) [<51] >+33553283344 (97m)Le Cro Magnon - Allas Les Mines (24) >+33553291370 (164m)La ferme Cle des Champs - Sainte Mondane (24) [<51] >+33553296234 (145m)Le Tiradou - Saint Vincent de Cosse (24) [<51] >+33553303073 (71m)Le Capeyrou - Beynac et Cazenac (24) >+33553295495 (65m)Municipal - Mur De Barrez (12) [<51] >+33565660047 (776m)Municipal Les Eaux Vives - Saint Bonnet de Montauroux (48) >+33466463618 (739m)Parc Servois - Gardonne (24) [<51] >+33553572746 (25m)Rural des 4 Routes de Senilhes - Arpajon sur Cere (15) [<51] >+33471626001 (774m)Municipal La Guillou - Lalinde (24) >+33553610291 (44m)Aire naturelle - Vallouise (5) >+33492233026 (1159m)Les Bo-Bains - Badefols sur Dordogne (24) (01/04-30/09) >+33553735252 (54m)Municipal - Saint Michel de Chabrillanoux (7) [<51] >+33475662513 (532m)La Bastide - Pineuilh-Sainte Foy La Grande (24) [<51] (01/04-28/10) >+33557461384 -CCA(19m)Caravaneige Les Chambonnettes - Vallouise (5) >+33492233026 (1155m)Municipal Le Chateau Du Couffour - Chaudes Aigues (15) >+33471235708 (919m)A la ferme du Mont Inaccessible - Saint Martin De Clelles (38) [<51] >+33476344666 (1024m)Municipal Chadeyre - Issarles (7) [<51] >+33466462147 (940m)Roca d'Amour - Padirac (46) (25/04-21/09) >+33565336554 (353m)Aire naturelle Les Noisetiers - Le Porge (33) [<51] (01/06-30/09) >+33556265491 (21m)Municipal - Gluiras (7) [<51] >+33475667430 (774m)Plein Sud - Gilhac et Bruzac (7) >+33475404661 (426m)Le Parc - Lalinde (24) >+33553610230 (53m)Municipal La Pelouse - Bergerac (24) (01/04-31/10) >+33553570667 -CCA(27m)Le Relais Moto Des Sources - Vezac (24) >+33553594593 (107m)Municipal La Roche Aux Myrtilles - Rouveyret (48) [<51] >+33466310679 (1068m)Les Bouleaux - Le Rouget (15) >+33471469272 (579m)Municipal La Gandole - Dornas (7) >+33475292345 (652m)Municipal La Graviere - Mouleydier (24) [<51] >+33553222200 (36m)Aire naturelle de Constant Jacqueline - Prinsac [<51] >+33565370019 (108m)La Chabannerie*** - St. Martin de Clelles (01/05-30/09) >+33476340038 (738m)Rural du Maine - Lalinde (24) [<51] >+33553611299 (89m)La Piscine*** - Le Malzieu Ville [<51] (01/05-30/09) >+33466314763 (864m)Les Chenes-Roca d'Amour1 - Padirac (46) >+33565336554 (359m)Rural de Chazelas Jeanne - Coux et Bigaroque (24) [<51] >+33553316252 (193m)Le Pigeonnier - Miers (46) [<51] >+33565337195 (363m)Municipal La Pelouse - Castillon La Bataille (33) [<51] >+33577400422 (8m)A la ferme Borie de Bar - Vitrac (24) [<51] >+33553591757 (140m)Municipal Les Parrines - Saint Mamet La Salvetat (15) [<51] (01/04-31/10) >+33471647521 (740m)Le Pont de Vicq - Le Buisson De Cadouin (24) (01/04-31/10) >+33553220173 -CCA(54m)A la ferme de Mialon Prosper - Vielprat (43) [<51] >+33471571599 (963m)La Source Aveyron -�Therondels (12) (05/06-06/09) >+33565660562 -CCpg174(657m)Municipal Du Pre du Pont** - Le Malzieu Ville [<51] (15/06-15/09) >+33466317665 (860m)Municipal Beauregard** - Pinsac [<51] (15/06-15/09) >+33565370602 (101m)Municipal** - Charmes sur Rhone [<51] (01/04-30/09) >+33475609662 (104m)Du Garrit - Saint Cyprien (24) >+33683264766 (61m)Le Champ Long - La Salle en Beaumont (38) >+33476304181 (676m)L'Iscle de Prelles - Saint Martin de Queyrieres (5) (01/01-31/12) >+33688786279 -CCpg249(1148m)Les Acacias - Sarlat la Caneda (24) (12/04-30/09) >+33553310850 -CCA(144m)Le Soulhol - Saint Cere (46) (01/05-20/09) >+33565381237 (154m)Aire naturelle Municipale - Le Beage (7) [<51] >+33475388073 (1110m)Les Valades - Coux et Bigaroque (24) (01/04-15/10) >+33553291427 (181m)Municipal Les Faures - Valjouffrey (38) [<51] >+33476302228 (1062m)La Prairie - Landos (43) >+33471082258 (1146m)La Riviere - Lacave (46) >+33685084549 (100m)Le Clou - Coux et Bigaroque (24) (19/04-28/09) >+33553316332 -CCA(200m)A la ferme de Calvel Jean-Philippe - Lacave (46) [<51] >+33565378720 (111m)Le Coulet - Gluiras (7) [<51] >+33475654387 (358m)Rural de Mazelaygue Jean - Proissans (24) [<51] >+33553594114 (119m)Des Chenes Verts - Calviac en Perigord (24) (10/05-27/09) >+33614295516 (105m)Le Mondou - Saint Julien de Lampon (24) (01/04-15/10) >+33553297037 -CCA(115m)Municipal La Mauzacoise - Mauzac et Grand Castang (24) [<51] >+33553225057 (49m)Municipal Le Bourniou - Saint Julien de Lampon (24) >+33553298339 (81m)Le Moulin de Jo - Saint-Venerand (43) [<51] >+33466696107 (968m)Le Montant - Sarlat la Caneda (24) >+33553591850 (203m)Verte Rive**** - Pinsac (01/04-15/10) >+33565378596 (95m)Heron - Le Roc (46) (01/05-30/09) >+33565376738 (98m)Les Ombrages - Carlux (24) >+33553286217 (86m)Lo Gorissado - Saint Andre d'Allas (24) [<51] (01/04-30/09) >+33553593406 (192m)Aqua Viva - Sarlat la Caneda (24) >+33553314600 (99m)De Trionac - Mur De Barrez (12) >+33565660691 (656m)La Garrigue - Loubressac (46) [<51] >+33565383488 (338m)La ferme Le Paluel - Saint Vincent Le Paluel (24) [<51] >+33553592940 (96m)Municipal Le Freyssinet - Pelvoux (5) [<51] >+33492233783 (1245m)Municipal Du Rouvier - Saint Martial (7) [<51] >+33475292032 (847m)La Haute Yerle - Alles sur Dordogne (24) [<51] >+33553633585 (56m)Municipal La Borgne** - Cazoules [<51] (15/06-15/09) >+33553298164 (85m)La Penetie - Tremolat (24) [<51] >+33553275232 (136m)A la ferme Chez Felicia - Briancon (5) [<51] >+33492211642 (1493m)Aire naturelle Les Pins - Vassieux en Vercors (26) [<51] >+33475482882 (1102m)Le Belvedere de l'Obiou -�St Laurent-en-Beaumont (38) (15/05-15/10) >+33476304080 -CCpg267(852m)La Plage - Meyronne (46) (01/06-15/09) >+33565322326 (107m)Les Borgnes** - St. Sozy (15/04-20/09) >+33565322148 (103m)Municipal - Sousceyrac (46) >+33565330220 (547m)Des 5 Vallees - Briancon (5) >+33492210627 (1182m)Aire naturelle de Riou Marcel - Vernoux en Vivarais (7) [<51] >+33475581437 (434m)A la ferme de Campagnac - Castels (24) [<51] >+33553292603 (156m)Naturist - Les Clapieres - Briancon (5) >+33492211583 (1257m)Tremolat - Tremolat (24) >+33553056565 (47m)La Ferme du Cambord - Sarlat la Caneda (24) [<51] >+33553310095 (275m)Le Port de Limeuil - Limeuil-Alles sur Dordogne (24) (01/05-30/09) >+33553632976 -CCA(51m)A la ferme Chapelle - Saint-Sozy (46) [<51] (01/06-01/11) >+33565271906 (258m)Municipal - Silhac (7) [<51] >+33475581136 (591m)Municipal du Pont ** - Lanzac (01/07-31/08) >+33565370258 (92m)De Savel - Mayres Savel (38) (01/04-31/10) >+33476811479 -CCA(497m)A la ferme Le Petit Durbec - La Force (24) [<51] >+33610943299 (56m)Aire naturelle de Lescaran - Le Porge (33) [<51] >+33556265185 (21m)La Source - Chabeuil (26) >+33620678419 (234m)Municipal D'Aile Froide - Pelvoux (5) >+33492233200 (1482m)Naturist - De La Taillade - Neuveglise (15) >+33471238013 (800m)Le Port - Creysse (46) (20/04-27/09) >+33565322082 -CCA(106m)A la ferme La Perigourdine - Peyrillac et Millac (24) [<51] (01/01-31/12) >+33607221507 (86m)Club L'Escapade - Lamonzie Montastruc (24) (05/04-06/09) >+33553572379 (105m)Le Campagnard - Lembras (24) [<51] >+33553270655 (59m)Municipal Le Pre aux Moines - Goudet (43) [<51] >+33471571580 (772m)Le Colombier - Castels (24) [<51] >+33553292625 (182m)La Ferme Accueil de Viescamp - Pers (15) [<51] (01/05-15/10) >+33471622514 (544m)Municipal les Ondines*** - Souillac (46) (01/05-30/09) >+33565378644 -CCA(89m)Aire naturelle Maisonneuve - Le Porge (33) [<51] >+33556265409 (26m)Municipal*** - St. Just (Easter-30/09) >+33471737048 (915m)Rural de Soulie Yvon - Audrix (24) [<51] >+33553072568 (164m)Au Bord De L'Eau - Goudet (43) (18/04-18/09) >+33471571682 -CCpg340(766m)D'Uzanoux - Silhac (7) [<51] >+33475581539 (649m)Municipal du Plan d'Eau - Valbonnais (38) >+33476302128 (708m)La Ferme de Perdigat - Limeuil (24) (23/03-10/10) >+33608420237 -CCA(52m)La Ferme Des Poutiroux - Limeuil (24) (30/03-30/09) >+33553633162 (158m)Municipal La Grigne - Le Porge (33) >+33556265488 (12m)Indigo Les Perieres - Sarlat la Caneda (24) (17/04-29/09) >+33553590584 -CCA(207m)Les Charmes - Saint Andre d'Allas (24) >+33553310289 (224m)Des Granges - Liorac sur Louyre (24) [<51] >+33553630759 (133m)Aire naturelle les Pres dus Pas du Mas - Le Porge (33) [<51] >+33556265429 (21m)Le Belvedere - Neuveglise (15) (12/04-28/09) >+33471235050 -CCA(731m)Les 4 Saisons - Gresse en Vercors (38) (01/01-31/12) >+33476343027 -CCA(1226m)Bordeaux Lac - Bordeaux (33) (01/01-31/12) >+33557877060 -CCA(5m)La Cere - Arpajon sur Cere (15) >+33471645507 (597m)Herbelon*** - Treffort (38) (01/05-30/09) >+33476340547 -CCA(496m)Au P'tit Bonheur**** - Peyrillac et Millac (01/04-30/09) >+33553297793 (268m)Les Blaches - Vernoux en Vivarais (7) [<51] >+33475617213 (532m)Municipal - Arcens(7) [<51] >+33475304072 (621m)La Chataigneraie - Prats de Carlux (24) >+33553590361 (139m)Le Pic*** - Mayrac [<51] (01/04-30/09) >+33565322504 (158m)Municipal Les Vigneaux - Entraigues (38) [<51] >+33643762266 (797m)La ferme Les Deux Vallees - Fridefont (15) [<51] (15/06-15/09) >+33607881904 (914m)Merle - Chabeuil (26) [<51] (01/01-31/12) >+33475590008 (208m)A la Ferme Chassany- Fridefont (15) [<51] >+33471235610 (911m)Rural Le Pouget - Simeyrols (24) [<51] >+33553298578 (188m)Municipal Le Bois De Pras - Vernoux en Vivarais (7) >+33475581844 (581m)Naturist - Ferme du Feyt - La Segalassiere (15) [<51] >+33471622556 (584m)Les Grottes De Roffy - Sarlat la Caneda (24) >+33553591561 (139m)Municipal Les Pres Verts - Fridefont (15) [<51] >+33471235901 (904m)La Ferme de Villeneuve - Saint Andre d'Allas (24) >+33680080963 (194m)Le Mas de la Croux - Tauriac (46) >+33565108904 (124m)Le Viaduc - Pers (15) (26/04-11/10) >+33471647008 -CCA(530m)Les Terrasses du Perigord - Sarlat la Caneda (24) >+33553590225 -CCA(278m)Le Val De La Marquise - Campagne (24) >+33553547410 (84m)La Palombiere - Sarlat la Caneda (24) >+33553594234 -CCA(140m)La Cheze - Le Cheylard (7) >+33689382132 (509m)Le Moulin du Roch -�Sarlat (24) (17/05-20/09) >+33553592027 -CCpg141-CCA(127m)Le Vintojol - Saint Andre d'Allas (24) [<51] >+33553591462 (217m)Les Trois Caupain - Le Bugue (24) (01/04-31/10) >+33553072460 -CCA(56m)Caravaning Le Rivaux - Sarlat la Caneda (24) [<51] >+33553590441 (263m)Municipal La Plage** - Treffort (38) (01/04-15/10) >+33476340631 -CCA(497m)Les Falaises - Martel (46) >+33565373778 (111m)l'Eau Vive - Carennac (46) (19/04-05/10) >+33565109739 -CCA(128m)A la ferme Lasfargues - Bretenoux (46) [<51] >+33565385231 (132m)Croix d'Esteil - Sainte Nathalene (24) [<51] >+33553591581 (158m)Le Rocher De La Granelle - Le Bugue (24) (01/04-01/10) >+33553072432 -CCA(56m)La Presqu'ile du Puech des Ouilhes - Lacapelle Viescamp (15) >+33680371561 (516m)De Maillac - Sainte Nathalene (24) >+33553592212 (166m)A la ferme La Combe - Les Eyzies de Tayac Sireuil (24) [<51] >+33553069152 (115m)Rural de Fustier Henri - Boffres (7) [<51] >+33475583378 (629m)La Ferme de Magnaudes - Boree (7) [<51] >+33475293274 (940m)La Sole - Puybrun (46) >+33673163112 (129m)De Blanc - Briancon (5) [<51] >+33492205556 (1347m)Ferme Auberge Coustaty Marie-Rose - Meyrals (24) [<51] >+33553292907 (170m)Municipal Les Portes du Trieves*** - Monestier de Clermont (01/05-30/09) >+33476340124 (854m)La Foret - Pezuls (24) >+33553227169 (176m)Le Grand Lierne**** - Chabeuil (01/05-15/09) >+33475598314 (284m)Municipal De Chambaud - Le Cheylard (7) [<51] >+33684496572 (444m)A la ferme Les Costes - Nonieres (7) [<51] >+33971211217 (612m)Municipal Le Pont - Alleyras (43) >+33471575686 (668m)A la ferme de M. Gadiffert Daniel - Saint Jean Chambre (7) [<51] >+33475580878 (644m)A la ferme Chez Sylvie et Serge - Orliaguet (24) [<51] >+33624608221 (171m)Municipal Les Fauvettes - Saint Prejet d'Allier (43) >+33633187463 (838m)La Bourgnatelle - Bretenoux (46) >+33565384407 (135m)Saint Emilion -�Saint Emilion (33) (25/04-12/10) >+33557247580 -CCA(24m)A la ferme Les Rosiers - Chabeuil (26) [<51] >+33475590671 (221m)De L'Etang De Bazange - Monfaucon (24) >+33553246479 (73m)A la ferme La Roussie - Proissans (24) [<51] >+33553310884 (188m)Les Gentianes - Val Des Pres (5) >+33492212141 (1357m)Municipal Eperviere*** - Valence (15/01-10/12) >+33475423200 (107m)Des Mathevies - Sainte Nathalene (24) [<51] (27/04-21/09) >+33614109586 (166m)Le Caminel - Sarlat la Caneda (24) >+33553593716 (220m)Les Chalets sur la Dordogne - Girac (46) [<51] >+33565109333 (132m)Municipal - Pierrefort (15) [<51] >+33471233116 (978m)La ferme La Chazalet - Saint Julien Labrousse (7) [<51] >+31180424956 (727m)A la ferme Bastier - Saint Julien Labrousse (7) [<51] >+33475294245 (777m)Municipal - Lacapelle Viescamp (15) >+33471463173 (553m)Municipal - Saint Martin sous Vigouroux (15) [<51] >+33471233316 (756m)A la ferme Le Queylou - Les Eyzies de Tayac-Sireuil (24) [<51] >+33553069471 (120m)Le Pech Charmant - Les Eyzies de Tayac-Sireuil (24) (19/04-20/09) >+33553359708 -CCA(188m)Municipal De Fontbielle - Neuveglise (15) [<51] >+33471238408 (961m)Del Moules - Saint Gerons (15) >+33471460465 (523m)A la Ferme de Lascour - Proissans (24) [<51] >+33553594114 (181m)Rural de Audit Louis - Les Eyzies de Tayac Sireuil (24) [<51] >+33553069574 (206m)Aire naturelle Magali Plage - Liourdres (19) [<51] >+33555912529 (134m)Municipal Du Bois Des Alberts - Montgenevre (5) >+33492211611 (1370m)Rural Elevage du Plec - Salaunes (33) [<51] >+33689898446 (47m)La Linotte - Le Bugue (24) >+33820150040 (153m)Rural de Ampoulange Jean-Claude - Marquay (24) [<51] >+33553296745 (217m)Les Granges - Vayrac (46) (01/05-20/09) >+33565324658 -CCA(115m)Le Bourg - Campsegret (24) [<51] >+33553618790 (82m)Municipal La Coueyre - Lavastrie (15) [<51] >+33471238282 (962m)Municipal La Berarde - Saint Christophe en Oisans (38) (01/06-30/09) >+33608705970 (1687m)Le Moulin - Cayres (43) [<51] (15/06-15/09) >+33471573350 (1029m)Municipal De L'Ombrade - Aurillac (15) >+33471482887 (627m)La Draille**** - Souillac (46) (19/04-05/10) >+33565326501 -CCA(131m)Le Val d'Ussel - Sarlat la Caneda (24) >+33553592873 (181m)Le Moulin de Savin - Le Monastier sur Gazeille (43) [<51] >+33471616147 (820m)La Riviere - Les Eyzies de Tayac Sireuil (24) (05/04-31/10) >+33553069714 -CCA(79m)La Ferme de Lente - Lente (26) [<51] >+33475482799 (1147m)Le Mas - Les Eyzies de Tayac Sireuil (24) >+33553316087 (211m)Lac de Gurson - Carsac de Gurson (24) >+33553804613 (60m)Chateau du Besset - Saint Prix (7) >+33475293306 (701m)Les Escures - Billac (19) [<51] >+33555910092 (164m)Municipal La Callopie** - Martel [<51] (15/06-15/09) >+33565373003 (240m)Municipal Faverolles*** - Faverolles (15/06-15/09) >+33471234991 (942m)L'Iscle Du Rosier - Val Des Pres (5) >+33492210601 (1379m)Municipal La Duzonne - Alboussiere (7) >+33475582091 (523m)Les Trois Sources - Calviac (46) >+33565330301 (542m)Naturist - De Chaudeau - Montpon Menesterol (24) >+33553824964 (84m)Municipal du Lac des Vergnes - Comiac (46) [<51] >+33565338793 (460m)Municipal - Saint Agnan en Vercors (26) [<51] >+33475482067 (824m)Municipal - Saint Martin de Valamas (7) >+33475304716 (532m)Aire naturelle De Camping - Billac (19) [<51] >+33555915314 (199m)El Cortijo - Lorcieres (15) [<51] >+33471234241 (1021m)Le Gallo Romain - Barbieres (26) (19/04-30/09) >+33475474407 -CCA(474m)Le Diamant Noir - Sainte Alvere (24) >+33553227727 (192m)Municipal La Palenquiere - Vayrac (46) [<51] >+33565324367 (119m)Brin d'Amour - Le Bugue (24) >+33553072373 (214m)Les Reveilles - La Chapelle en Vercors (26) [<51] >+33475482181 (940m)Les Trois Chateaux - Polminhac (15) >+33471400768 (641m)La Paille Basse**** -�Souillac (15/05-15/09) >+33565378548 -CCpg173-CCA(247m)La ferme La Brugere - Saint Felix de Villadeix (24) [<51] (01/04-15/09) >+33553611302 (156m)Rural de Neyrat Jean-Pierre - Borreze (24) [<51] >+33553288306 (148m)Naturist - Le Courtialet - Avignonet (38) >+33689276948 (642m)Saint Avit Loisirs - Saint Avit de Vialard (24) (01/04-14/09) >+33553026400 -CCA(228m)Rural de Veyret Claude - Marquay (24) [<51] >+33553296844 (177m)Rural de Laflaquiere Mariette - Marcillac Saint Quentin (24) [<51] >+33553291934 (243m)Rural de Valayer Roger - Saint Basile (7) [<51] >+33475065061 (552m)La Veyssiere - Marcillac Saint Quentin (24) [<51] >+33553591084 (250m)La Ferme Du Pelou - Tursac (24) >+33553069817 (224m)La Ferme la Source - Faverolles (15) [<51] >+33471234906 (843m)Municipal - Siran (15) [<51] >+33471460164 (641m)Les Peneyrals - Saint Crepin Carlucet (24) (08/05-12/09) >+33553288571 -CCA(261m)Municipal Sporting de la Seuge - Saugues (43) [<51] >+33471778062 (930m)La Ferme de la Brauge - Tursac (24) [<51] (01/01-31/12) >+33553296826 (223m)A la ferme Camelot - Villegouge (33) [<51] >+33557844308 (57m)La Tuilliere - Montpon Menesterol (24) >+33553824729 (78m)Les Fetoules - Saint Christophe en Oisans (38) [<51] >+33476802399 (1206m)Le Temps de Vivre - Salignac Eyvigues (24) [<51] (07/04-01/10) >+33553289321 (286m)Le Pigeonnier - Salignac Eyvigues (24) >+33553289262 (276m)Municipal Les Bains - Laroquebrou (15) >+33471460284 (449m)Municipal de l'Iris - Solignac sur Loire (43) [<51] >+33471031146 (875m)Le Pont de Mazerat - Tamnies (24) >+33553291495 (137m)La ferme Les Combelles - Borreze (24) [<51] >+33553288325 (206m)Sevincamp - Minzac (24) >+33553816170 (63m)Municipal Agree Les Cordeliers - Pierre Chatel (38) >+33476307753 (936m)Des Myrtilles - La Chapelle en Vercors (26) [<51] >+33475482089 (873m)Le Pigeonnier - Tursac (24) [<51] (01/06-15/09) >+33553069690 (101m)Municipal Le Vivier - Monistrol d'Allier (43) [<51] >+33471572121 (598m)Municipal Les Bruyeres - La Chapelle en Vercors (26) >+33475482146 (892m)La Pommeraie - Vic sur Cere (15) >+33471475418 (771m)A La Ferme De La Catie - Tamnies (24) [<51] >+33553296878 (213m)Municipal Panama - Altillac (19) [<51] >+33555910816 (141m)Les Tailladis - Sarlat la Caneda (24) (15/03-31/10) >+33553591095 -CCA(150m)Rural de Cremoux Pierre - Cazillac (46) [<51] >+33565321113 (153m)Le Vezere Perigord - Tursac (24) (15/04-31/10) >+33553069631 -CCA(103m)Municipal Du Pont - Beaulieu sur Dordogne (19) [<51] >+33555910057 (142m)Petits Pellegrins - Lacanau (33) >+33556030510 (21m)Rural de Pebeyre Paul - Saint Genies (24) [<51] >+33553289741 (216m)Rural Lespinasse - Tursac (24) [<51] >+33553069681 (73m)Combe d'Oyans - Rochefort Samson (26) >+33475473323 (377m)Des �les - Beaulieu sur Dordogne (19) (26/04-27/09) >+33555910265 -CCA(143m)A la ferme Jardin Biologique de la Contie - Saint Gery (24) [<51] >+33553586431 (132m)Municipal les 2 Glaciers - Le Monetier les Bains (5) >+33492461008 (1499m)Bouyssou - Tursac (24) >+33553069808 (94m)Municipal Vic' Nature - Vic sur Cere (15) >+33471475104 (665m)La Praise - Lacanau (33) [<51] >+33556035875 (17m)La Ferme De Mathias - Fay sur Lignon (43) [<51] >+33471595489 (1126m)La Cascade - Venosc (38) [<51] >+33476110975 (946m)La ferme de Fournet Dominique - Tursac (24) [<51] >+33553069823 (118m)Les Mouettes - Saint Theoffrey (38) [<51] >+33476830249 (945m)Municipal - Ayrens (15) [<51] >+33471463070 (617m)La Coste Jaubert - Fleurac (24) [<51] >+33476800738 (114m)Municipal Du Sabot - Notre Dame de Vaux (38) [<51] >+33476307090 (982m)Du Moulin - Venosc (38) >+33476800738 (935m)Aire naturelle de Bouffard Andre - Altillac (19) [<51] >+33555911124 (147m)Le Tedey - Lacanau (33) (26/04-20/09) >+33556030015 -CCA(25m)Les Chenes Clairs - Condat (46) [<51] >+33565321632 (161m)A la Ferme des Terres Hautes - Cazillac (46) [<51] >+33565320048 (284m)Municipal La Chataigneraie - Camps Saint Mathurin Leobazel (19) [<51] >+33555285315 (564m)Le Riou La Selle - Saint Agreve (7) [<51] (01/05-30/09) >+33475302928 (1018m)Municipal Le Vignon - Les Quatre Routes du Lot (46) [<51] >+33565321283 (122m)Municipal Le Marchat - Saint Privat d'Allier (43) [<51] >+33471572213 (892m)De Retourtour - Lamastre (7) (19/04-26/09) >+33475064071 -CCA(392m)Du Moulin - Jussac (15) [<51] >+33471466985 (624m)Lestaubiere - Douville (24) (12/04-04/10) >+33553829815 -CCA(188m)Comme au Soleil - Coubon (43) [<51] >+33616514871 (641m)l'Oasis - Lussac (33) [<51] >+33557491718 (37m)Le Pressoir -�Saint Emilion-Petit Palais (33) >+33557697325 (30m)Le Soleil Rouge - Desaignes (7) [<51] >+33475066381 (471m)Le Soleil Fruite**** - Chateuneuf s/ Isere (26) (01/05-15/09) >+33475841970 -CCA(116m)La Bouquerie - Saint Genies (24) >+33553289822 (229m)Les Loges - Menesplet (24) >+33553818439 (41m)Le Petit Bois*** - Ruynes-en-Margeride (01/05-15/09) >+33471234226 -CCpg339(898m)Aire naturelle La Malinie - Fleurac (24) [<51] >+33553054284 (233m)Ser Sirant - Petichet-Saint Theoffrey (38) (01/05-30/09) >+33476839197 -CCA(915m)Domaine P & B - Goulles (19) [<51] >+33674752580 (581m)Het Franse Leven - Gignac (46) [<51] >+31651719461 (281m)Le Paradis -�Saint Leon sur Vezere (24) >+33553507264 -CCA(73m)Rural de Rampon - Clavieres (15) [<51] >+33471234330 (1071m)Aire naturelle Les Fougeres - Lacanau (33) >+33556035676 (17m)Au Pre du Lac - Saint Theoffrey (38) (01/03-25/10) >+33476839134 -CCA(919m)Municipal - Velzic (15) [<51] >+33471479304 (707m)L'Ermitage - Lacanau (33) >+33556030024 (31m)Relais Les Moreaux - Saint Martin en Vercors (26) [<51] (01/01-31/12) >+33475455034 (707m)Ferme de Simondon - Plats (7) [<51] (01/04-30/09) >+33475076575 (482m)Rural de Delorme Etienne - Clavieres (15) [<51] >+33471234395 (1075m)Port Neuf** - St. Andre de Cubzac (01/05-30/09) >+33557431644 (3m)Roc De Lavandre - Saint Felix De Reillac et Mortema (24) >+33553032347 (144m)Talaris - Lacanau (33) >+33556030415 (16m)Les Jardin du Littoral - Lacanau (33) >+33663455839 (18m)Intercommunal Lac de Neufond - Vergt (24) >+33553549390 (148m)De L'Ocean - Lacanau (33) >+33556032445 (13m)Municipal Les Vernes**** - La Roche de Glun (01/05-30/09) >+33475845411 (114m)La Berge Ombragee - Le Peyriget (19) [<51] (30/04-30/09) >+33555910117 (158m)Chateau Lacour-La Licorne - Saint Agreve (7) [<51] >+33475302709 (1040m)Les Grands Pins - Lacanau (33) (25/04-29/09) >+33556032077 -CCA(22m)Municipal - Saint Leon sur Vezere (24) [<51] >+33553507316 (71m)Municipal** Les Bords de Lyonne - St. Jean en Royans [<51] (01/05-30/09) >+33475477460 (240m)A la ferme Chanson Albert - Clavieres (15) [<51] >+33471234128 (1112m)Les Roches - Le Crestet (7) (01/04-30/09) >+33475062020 -CCA(398m)A la ferme Bourrier Brioude - Clavieres (15) [<51] >+33471234180 (1127m)Le Port Vieux - Montpon Menesterol (24) >+33553802216 (32m)Le Paradis - Abzac (33) >+33557490510 (13m)De Landrevie - Le Bugue (24) [<51] >+33553032094 (236m)Hortiver Lombriculture - Marmanhac (15) >+33471473154 (670m)Municipal Bedisse - Thiezac (15) [<51] >+33471470041 -CCA(764m)De Feneyrolles - Chauffour sur Vell (19) [<51] >+33555840958 (173m)Sabatoux - Montusclat (43) [<51] >+33471087615 (1162m)Municipal La Lame - Nevache (5) [<51] >+33492205191 (1584m)La Fage -�Montignac-La Chapelle Aubareil (24) (11/04-11/10) >+33553507650 -CCpg140-CCA(243m)Rural de Pau Julienne - Saint Genies (24) [<51] >+33553289794 (223m)l'Ecluse - Saint Antoine sur l'Isle (33) [<51] >+33557497001 (19m)Municipal Le Pontillou - Villamblard (24) [<51] >+33625170956 (126m)Le Gua - Saint Medard de Guizieres (33) [<51] >+33557698237 (14m)Napoleon - Laffrey (38) >+33476133674 (919m)Le Coucoulou - Laffrey (38) [<51] >+33476731231 (918m)Aire naturelle La Champagne - Brivezac (19) [<51] >+33555912776 (163m)La Prairie - Mars (7) [<51] >+33475302447 (1067m)Le Viaduc - Arlebosc (7) >+33475067449 (298m)La Nouvelle Croze - Rouffignac Saint Cernin de Reilhac (24) [<51] >+33553053890 (285m)La Belle Etoile - Reygade (19) [<51] (15/05-30/09) >+33555285008 (458m)La Porte Saint Martin - Saint Martin en Vercors (26) >+33475455110 (776m)La ferme Les Vieilles Granges - Saint Genies (24) [<51] >+33553289883 (250m)Les Escargots Bleus - Prades (43) [<51] >+33670291863 (551m)A la ferme L'Offrerie - Rouffignac Saint Cernin de Reilhac (24) (07/04-29/09) >+33553353326 (276m)Orpheo Negro - Douville (24) (01/04-31/10) >+33607383240 -CCA(219m)Le Vieux Moulin - Brivezac (19) [<51] >+33555911472 (172m)Pont de Fournil - Saint Laurent des Hommes (24) [<51] >+33553819752 (37m)Le Meygal - Champclause (43) [<51] >+33471087103 (1207m)Le Clou - Thiezac (15) [<51] (01/05-15/10) >+33471470145 (1102m)La Lande - Bourgnac (24) [<51] >+33553811410 (141m)La Vallee Du Doux - Boucieu Le Roi (7) >+33475087183 (275m)Le Lac - Plazac (24) (08/05-30/09) >+33553507586 -CCA(109m)Ferme Auberge de Puech Verny - Saint Cirgues de Jordanne (15) [<51] >+33471479072 (863m)Municipal Des Orgues** - St. Flour (01/06-31/08) >+33471604401 (881m)Municipal De Fontcouverte - Nevache (5) [<51] >+33492213821 (1865m)Municipal D'Arsine - Villar D'Arene (5) [<51] >+33476799307 (1656m)Municipal La Citadelle** - Bourg [<51] (01/04-30/09) >+33556684006 (10m)L'Auberge Du Doux - Colombier Le Vieux (7) [<51] >+33475067910 (265m)Municipal La Croix Blanche - Saint Julien Chapteuil (43) [<51] >+33471087001 (817m)A la ferme de Girard Odette - Saint Julien Chapteuil (43) [<51] >+33471087127 (802m)A la ferme Le Petit Paradis - Vergt (24) [<51] >+33553051016 (202m)Aire naturelle Le Bois Du Geai - Brach (33) [<51] >+33556587054 (31m)La Castillonderie - Thonac (24) (29/03-28/09) >+33553507679 -CCA(128m)Le Traversant - Le Freney d'Oisans (38) >+33612404457 (968m)Municipal Frais Rivage - Coutras (33) [<51] >+33557491200 (10m)A la ferme le Sorbier - Montignac (24) [<51] >+33553518730 (85m)Le Farganaud - Saint Laurent des Hommes (24) [<51] >+33553817403 (48m)Le Gravelotte - La Grave (5) [<51] >+33476799314 (1406m)Municipal Audinet - Brives Charensac (43) >+33471091018 (604m)De la Meije - La Grave (5) [<51] >+33608543084 (1453m)La Prade - La Douze (24) >+33553067359 (217m)Le Vaurette - Argentat-Monceaux sur Dordogne (19) (01/05-21/09) >+33555280967 -CCA(174m)Le Vernis - Le Bourg d'Oisans (38) >+33476800268 (717m)A la ferme le Ruisselet - Roffiac (15) [<51] >+33471601133 (848m)Municipal Bouthezard - Le Puy en Velay (43) >+33471095509 (615m)Roche Murat** - St. Flour (01/04-30/10) >+33471604363 (847m)La Ferme les Ecuries de Longchamp - Colombier le Vieux (7) [<51] >+33475067918 (379m)Municipal - Sourzac (24) [<51] >+33553810106 (54m)Rural de Chinnery - Rouffignac Saint Cernin de Reilhac (24) [<51] (185m)Municipal Les Blats - Saint Jacques Des Blats (15) >+33471470600 (969m)Le Marchand - Colombier le Vieux (7) >+33475067306 (252m)Le Colporteur - Le Bourg d'Oisans (38) >+33476791144 -BD_FR-O.029a(718m)Du Lac Devesset - Devesset (7) >+33475300037 (1096m)Municipal - Saint Cernin (15) [<51] >+33471476503 (758m)Les Malenies - Saint Amand de Coly (24) >+33553508157 (235m)Les Hirondelles - Le Chambon sur Lignon (43) >+33471597384 (994m)Municipal Surnette - Mazet Saint Voy (43) >+33471650569 (1022m)Bleu Soleil - Rouffignac Saint Cernin de Reilhac (24) (12/04-30/09) >+33553054830 -CCA(248m)Rural de Morambert Jacques - Saint Pierre Eynac (43) [<51] >+33471087202 (909m)Du Saulou - Monceaux sur Dordogne (19) >+33555281233 (177m)De Clarat - Lafarre (7) >+33475066590 (570m)Les Eaux Claires* - St. Nazaire en Royans (01/01-31/12) >+33475484110 (177m)Aire naturelle La Chikane - Le Chambon sur Lignon (43) [<51] >+33471597978 (1057m)Municipal*** - St. Nazaire en Royans (01/05-30/09) >+33475484118 (170m)Du Lignon - Le Chambon sur Lignon (43) >+33471597286 -CCA(929m)Le Pont de Manne** - St. Thomas en Royans (01/03-15/11) >+33475484247 (177m)Le Moulin de Bleufond - Montignac (24) (31/03-06/10) >+33553518395 -CCA(76m)Le Moulin de Barette - Blavozy (43) >+33471030088 (656m)Moulin De Valane - Collonges La Rouge (19) >+33555254159 (206m)Municipal Les Seraines** - Pont en Royans (15/04-30/09) >+33476360630 (200m)Chez la Mere Michon - Choranche (38) >+33476360727 (297m)La Piscine - Le Bourg d'Oisans (38) >+33476800241 (718m)La Cascade - Le Bourg d'Oisans (38) (01/01-30/09) >+33476800242 -CCA(720m)Naturist - Laulurie En Perigord - La Douze (24) >+33553067400 (207m)Le Gouffre de la Croix - Choranche (38) >+33476360713 (276m)Les Sables** - Tournon s/Rhone (10/04-30/09) >+33475082005 (150m)Les Foulons** - Tournon s/Rhone (25/03-30/09) >+33475082272 (146m)Le Manoir*** - Tournon s/Rhone (10/04-20/09) >+33475080250 (148m)A la Rencontre du Soleil -�Bourg d'Oisans (38) (01/05-30/09) >+33476791222 -CCA(725m)A la ferme la Foret - Carcans (33) [<51] >+33556033276 (23m)Rural de Dubois Guy - La Dornac (24) [<51] >+33553510424 (242m)Municipal Les Millieres - Choranche (38) [<51] >+33476360165 (257m)Les Acacias*** - Tournon s/Rhone (7) (01/04-30/09) >+33475088390 -CCA(133m)Les Terrasses du Lac - Carcans (33) >+33556033712 (24m)De Maubuisson - Carcans (33) >+33556033012 (19m)Municipal les Lucs*** - Tain-l'Hermitage [<51] (15/03-15/10) >+33475083282 (120m)La Grande Prade - La Cassagne (24) >+33553516613 (127m)Le Preoula - La Garde (38) [<51] >+33476801119 (949m)Le Castelet** - St. Jean de Muzols (7) (10/04-05/09) >+33475080948 -CCA(148m)La Celliere* - St. Jean de Muzols (01/03-31/10) >+33475081048 (144m)La Magaudie* - Chartrier-Ferriere [<51] (01/01-31/12) >+33555852606 (275m)Le Paradis - Carcans (33) >+33556033357 (21m)Perigord Vacances - Saint Amand de Coly (24) >+33553516064 (154m)Naturist - Le Coteau de l'Herm - Rouffignac Saint Cernin de Reilhac (24) [<51] >+33553466777 (268m)Tournon*** - Tournon s/Rhone (7) (01/01-31/12) >+33475080528 -CCA(122m)Rural de Maleysson Bernard - Saint Etienne Lardeyrol (43) [<51] >+33471576613 (814m)Municipal Pont Du Rouffet - Saint Martin Cantales (15) [<51] (27/04-08/09) >+33471694276 (456m)A la ferme La Tournerie - Aubas (24) [<51] >+33553510416 (215m)Rural de Lasserre Denise Et Laborde - Montignac (24) [<51] >+33553519424 (222m)Le Lierre - Carcans (33) >+33672295367 (22m)Aire naturelle de Gubert David - Monceaux sur Dordogne (19) [<51] >+33555287227 (176m)Cap de Ville - Carcans (33) >+33556033374 (18m)Puy Mary - Mandailles Saint Julien (15) (01/07-31/08) >+33471479039 (940m)Cap Ocean - Carcans (33) >+33683510018 (18m)Naturist - Le Puy Bousquet - Collonges La Rouge (19) >+33555254843 (435m)La Foret - Saint Christophe de Double (33) >+33557495002 (64m)Au Soleil d'Oc -�Argentat (19) (15/04-16/11) >+33555288484 -CCpg329-CCA(176m)Le Vieux Port - Argentat (19) [<51] (01/07-15/09) >+33555287227 (174m)A la Ferme La Bouriote - Hautefage (19) [<51] >+33555280677 (490m)Les Arbousiers - Carcans (33) >+33683960388 (18m)La Chrysalide - Carcans (33) >+33680089503 (18m)Municipal De Pierrageais - Saint Felicien (7) [<51] >+33475060305 (416m)Europe - Monceaux sur Dordogne (19) >+33555280770 (174m)l'Oursiere - Villard de Lans (38) >+33476951477 (988m)Aire naturelle Municipale - Albepierre Bredons (15) [<51] >+33471202049 (1054m)Aire naturelle Municipale - Besse (38) [<51] >+33476802580 (1567m)Longayroux - Pleaux (15) >+33471404830 (438m)Le Chene du Lac - Bayas (33) (29/03-14/11) >+33557691378 -CCA(64m)Ferme d'Accueuil - Saint Cirgues la Loutre (19) (01/05-30/09) >+33555282741 (465m)Les Alizes - Pleaux (15) >+33471409256 (440m)Echo du Malpas - Monceaux sur Dordogne (19) (05/04-28/09) >+33565108904 (185m)Aire naturelle Les Lauriers - Carcans (33) [<51] >+33556033284 (22m)l'Ocean - Carcans (33) >+33556034144 (15m)Le Moulin de Tulette - Varces [<51] (01/05-30/09) >+33476725598 (268m)Les Pins - Carcans (33) >+33556033872 (20m)Les Mimosas - Carcans (33) >+33556033905 (19m)Le Bois de Cornage*** - Vizille (38) (01/04-31/10) >+33476681239 -CCA(288m)Rural Les Geymonds - Villard de Lans (38) [<51] >+33476951277 (980m)Aire naturelle La Pignada - Carcans (33) [<51] >+33556033954 (23m)A la Ferme Noemie - Bourg d'Oisans [<51] >+33687450875 (714m)Rural de Camp Municipal - Teuillac (33) [<51] >+33557643455 (37m)Aire naturelle Le Lac Vert - Laruscade (33) [<51] >+33557686443 (31m)Municipal - Siaugues Sainte Marie (43) [<51] >+33471742368 (886m)La ferme Micoulaux - Rochepaule (7) [<51] >+33475300686 (893m)Ferme de la Bourgearie - Sainte Marie De Chignac (24) [<51] >+33553041674 (223m)l'Eau Vive - Les Eglisottes et Chalaures (33) [<51] >+33680584506 (15m)Rural de Salvetat Jean-Marie - Chavagnac (24) [<51] >+33553510059 (321m)La Prairie*** - Lissac s/Couze (01/01-31/12) >+33555853797 (151m)A la Ferme Delmas - Noailles (19) [<51] >+33555858133 (264m)l'Imprevu - Vaulnaveys le Bas (38) >+33681410991 (311m)La Dune Bleue - Carcans (33) >+33557701212 (26m)Aire naturelle Lissart de Miege - Le Fau (15) [<51] (15/05-15/10) >+33678343855 (952m)Le Pradeau - Gorges de l'Allier - Langeac (43) >+33471770501 (492m)Municipal du Langour - Argentat (19) >+33555281384 (187m)Municipal De Stalapos - Murat (15) >+33471200183 (886m)Le Marandan** - St. Romans (38) (01/05-15/09) >+33476644177 -CCA(210m)Les Sorias - Fossemagne-Thenon (24) [<51] >+33553044306 (241m)Aire naturelle Les Resineux - Carcans (33) >+33556033202 (25m)La Chataigneraie - Leyge-Saint Privat (19) [<51] >+33555910018 (537m)Le Chante Merle*** - Chantemerle les Bles [<51] (01/02-31/12) >+33475074973 (186m)Neuvicois - Neuvic sur l'Isle (24) >+33553815077 (59m)Le Sabotier - Montrem (24) [<51] (01/05-15/09) >+33553542778 (201m)Municipal De Chantelermuze - Saint Victor (7) >+33475060855 (570m)Aire naturelle - Talizat (15) [<51] >+33471237317 (945m)Municipal La Levee des Freres - Tence (43) >+33471598310 (845m)Du Gibanel - Argentat (19) >+33555281011 (201m)A la ferme Milhac-Oie - Milhac d'Auberoche (24) [<51] >+33553075628 (229m)Aire naturelle la Prairie - Carcans (33) [<51] >+33556033760 (18m)A la ferme Etang de Malesse - Saint Privat (19) [<51] >+33671406345 (543m)Municipal La Pierre Plate - Fontanges (15) [<51] >+33471407149 (681m)RCN Belledonne -�Bourg d'Oisans (38) (19/04-20/09) >+33476800718 -CCpg268-CCA(713m)Municipal Le Moulin du Teinturier - Saint Martin Valmeroux (15) >+33471694312 (633m)Le Chateau - Le Bourg d'Oisans (38) (15/05-15/09) >+33476110440 (709m)La ferme Les Carrets - Saint-Hilaire du Rosier (26) [<51] >+33476384115 (260m)Municipal Le Vallagnon - Laveissiere (15) [<51] >+33471201134 (928m)Bois Sigu - Lans en Vercors (38) >+33476954702 (1023m)La Libellule - Le Bourg d'Oisans (38) >+33476791557 (708m)Le Verdoyant - Thenon (24) >+33553052078 (163m)Les Ulezes - Saint Donat sur l'Herbasse (26) >+33475478320 (204m)La Rochelambert - Saint Paulien (43) (01/04-30/09) >+33471005402 -CCA(771m)La Salvinie - Terrasson Lavilledieu (24) >+33603615572 (84m)Les Bouleaux - Allemont (38) >+33476807123 (711m)A la ferme La Bruyere - Saint Romans (38) [<51] >+33476384884 (206m)Iserand** - Vion (20/04-15/09) >+33475080173 -CCpg270(132m)Le Chateau De Beauvoir**** - Beauvoir en Royans [<51] (15/04-31/10) >+33476640179 (257m)Aire naturelle - Saint Privat (19) [<51] >+33555826532 (580m)Municipal Les Chaumes - Echourgnac (24) [<51] >+33553803656 (102m)Municipal Le Pre Du Moulin - Lalouvesc (7) >+33475678486 (1099m)La ferme la Cle de Sol - Marsaz (26) [<51] >+33475450082 (210m)Le Replat*** - Parnans [<51] (01/05-30/09) >+33475453193 (325m)Les Longes - Lavoute sur Loire (43) >+33471081879 (553m)Municipal Le Manoire - Fossemagne (24) >+33553044346 (198m)Le Grand Calme - Allemont (38) >+33476807003 (727m)Les Sources - Vissac Auteyrac (43) >+33471742026 (931m)A la Ferme Des Sources - Beynat (19) [<51] >+33555859791 (499m)A la ferme de Breuilh - Atur (24) [<51] >+33553082837 (219m)Municipal Le Plan - Allemont (38) >+33476807688 (730m)Municipal La Prade - Neussargues Moissac (15) >+33471205021 (819m)Municipal La Citadelle - Blaye (33) >+33557420020 (26m)Les Buissonnets - Meaudre (38) (01/01-31/12) >+33476952104 -CCA(978m)De La Pelonie - Saint Antoine d'Auberoche (24) (20/04-10/10) >+33553075578 -CCA(174m)Lac de Miel - Beynat (19) >+33555855066 (521m)Municipal De Choumouroux - Yssingeaux (43) >+33471655344 (908m)La ferme Rancon - Chenereilles (43) [<51] >+33471654003 (873m)Aire naturelle Apcher - Saint Paul De Salers (15) [<51] >+33471407226 (923m)A la ferme Les Genets d'Or - Chenereilles (43) [<51] >+33471654003 (860m)Lac De Champos - Saint Donat sur l'Herbasse (26) >+33475451781 (239m)Aire naturelle L'Acacia - Hourtin (33) [<51] (01/06-30/09) >+33556738080 (16m)Municipal d'Entassit - Pleaux (15) >+33471404005 (628m)A la ferme La Garnasette - Rosieres (43) [<51] >+33471574096 (728m)Le Maine Blanc - Saint Christoly de Blaye (33) >+33557425281 (33m)A la ferme de la Maurinie - Eyliac (24) [<51] >+33553075718 (231m)Municipal Le Grangeon - Satillieu (7) >+33681547696 (515m)Ferme Les Baies Sauvages - Saint Georges d'Aurac (43) [<51] >+33471775105 (755m)Les Eymes - Meaudre (38) (01/05-30/09) >+33476952485 -CCpg269(1035m)Municipal des Chanaux - Saint Privat (19) [<51] >+33555282877 (583m)Municipal du Lac de Feyt - Servieres le Chateau (19) >+33555282542 (493m)Rural de Vergne Louis - Beynat (19) [<51] >+33555855031 (541m)Municipal Les Falquets - Charmes sur l'Herbasse (26) >+33475457557 (240m)Municipal Le Mouriol - Saint Paul De Salers (15) >+33471407309 (981m)Le Pontet - Saint Astier (24) (05/04-28/09) >+33553541422 -CCA(65m)Municipal - Malleval (38) >+33476385459 (930m)Le Grand Dague - Atur (24) >+33553042101 -CCA(216m)Municipal Les Gerbes - La Roche Chalais (24) >+33553914065 (31m)Les Myosotis - La Chazotte (43) [<51] >+33471590529 (848m)La Chapelle en Correze*** - Parnans (01/05-30/09) >+33555244874 (189m)Municipal la Ribeyre - Lavoute Chilhac (43) >+33471774803 (461m)Aire naturelle Du Chambon - Le Falgoux (15) [<51] >+33471695339 (900m)A la Ferme Le Marain - Montregard (43) [<51] >+33471599527 (899m)Municipal La Souvigne - Forges (19) [<51] >+33555286164 (222m)Municipal Au Fil de l'Eau - Chilhac (43) [<51] (01/05-30/09) >+33471774171 (475m)Le Luiset - Saint Martin d'Uriage (38) >+33476897798 (587m)Municipal du Couderc - Chalinargues (15) [<51] >+33171200352 (1056m)Municipal Auvergn-Yack - Chavaniac-Lafayette (43) [<51] >+33668284703 (697m)La Ferme Pierrefiche - Albignac (19) [<51] >+33555257395 (377m)Le Buisson - Saint Martin d'Uriage (38) >+33630681793 (814m)Municipal d'Enchaniers - Le Claux (15) >+33471789388 (1041m)Au Grand Etang - La Jemaye (24) >+33553900961 (95m)La Ferme Le Biquet - Charmes sur l'Herbasse (26) [<51] (01/04-31/10) >+33475456040 (265m)La Garenne - Peyrignac (24) (01/01-31/12) >+33553505773 (214m)Municipal Les Cuves - Razac sur l'Isle (24) [<51] >+33553546020 (75m)Aire naturelle La Farandole - Cublac (19) [<51] >+33555851979 (285m)Le Relais du Chavan - Laruscade (33) [<51] >+33557686305 (59m)Municipal La Croix du Brunal - Saint Martin La Meanne (19) >+33555291191 (542m)Les Trois Pucelles** - Seyssins (01/01-31/12) >+33476964573 (223m)Aire naturelle Les Tilleuls - Mazion (33) [<51] >+33557421813 (28m)Municipal Le Sainte-Thecle - Valloire (73) >+33479833011 (1392m)Le Vercors - Autrans (38) [<51] >+33671078150 (1034m)Masloup - Mansac (19) >+33555852714 (190m)Ferme de la Chatonniere - Cognin les Gorges (38) [<51] >+33476381876 (276m)l'Oree Du Bois - Hourtin (33) >+33609654896 (19m)Le Littoral - Hourtin (33) >+33556091373 (18m)Le Paradis - Saint Laurent Medoc (33) >+33556594215 (32m)Au Joyeux Reveil -�Autrans (38) (01/05-30/09) >+33476953344 -CCA(1051m)Aire naturelle Municipale - Ally (15) [<51] >+33471690069 (714m)La Ferme Du Suc - La Chapelle Laurent (15) [<51] >+33471731277 (1055m)Municipal Les Vigeaires - Ferrieres Saint Mary (15) >+33471206147 (670m)L'Oasis - Eclassan (7) [<51] (25/04-05/09) >+33475345623 -CCA(332m)La Rotonde - Hourtin (33) >+33556091060 (16m)Le Rouzeau - La Roche Chalais (24) [<51] >+33553914648 (34m)Les Ourmes - Hourtin (33) (26/04-21/09) >+33556091276 -CCA(21m)Le Bon Coin - Hourtin (33) >+33556091082 (19m)Le Barry - Grazac (43) [<51] >+33471593847 (792m)Municipal Les Gabarreys - Pauillac (33) >+33556591003 (4m)La Mariflaude - Hourtin (33) >+33556091197 (21m)Le Coiroux - Aubazine (19) (05/04-28/09) >+33555272196 -CCpg328-CCA(454m)Les Moulettes - Vorey (43) (01/05-15/09) >+33471037048 -CCA(549m)Barnabe Plage - Boulazac (24) >+33553534145 (88m)La Vie Moderne - Ceaux d'Allegre (43) [<51] >+33471007966 (881m)Etang Des Garennes - Saint Aquilin (24) >+33553047995 (124m)Municipal Les Isles De Silon - Saint Vallier (26) >+33475232217 (132m)Municipal La Mechaussie - Lagarde Enval (19) [<51] >+33555271368 (513m)Le Paradou - Parcoul (24) >+33553914278 (63m)Le Moulin Du Cours - Ardoix (7) >+33475349510 (267m)Les Combes** - Modane [<51] (01/05-30/09) >+33479050023 (1086m)Municipal - Retournac (43) [<51] >+33471594016 (501m)A la ferme Les Pins - Montchenu (26) [<51] >+33475456385 (423m)La Fridiere - Paulhaguet (43) [<51] >+33471766554 (529m)Municipal aire naturelle - Saint Vincent De Salers (15) [<51] >+33471695239 (641m)Aire naturelle Municipale - Anglards De Salers (15) [<51] >+33471400002 (817m)la Garenne - Saint Avit (26) >+33475686226 -CCA(258m)Municipal les Bouyges - La Roche Canillac (19) [<51] >+33555291375 (487m)Municipal - Auriac (19) >+33555282597 (611m)Rural de l'Hote Bernard- La Vergne - Le Change (24) [<51] >+33553060452 (100m)Du Pra De Mars - Vorey (43) >+33471034086 (547m)A la ferme Le Chazal - Saint Hilaire Peyroux (19) [<51] (01/04-01/11) >+33555255248 (340m)Municipal La Vialette - Villeneuve d'Allier (43) >+33471747211 (444m)Le Naysord* - St. Jean le Vieux [<51] (01/04-31/10) >+33476771237 (728m)Municipal La Plage - Saint Aulaye (24) >+33553906220 (38m)Municipal* - Orelle [<51] (01/01-31/12) >+33479568722 (903m)Cosy Camp - Chamalieres sur Loire (43) (24/05-04/10) >+33471759156 -CCpg341-CCA(515m)Municipal La Pinede - Allegre (43) >+33471007679 (1031m)Municipal De La Biaugue - Cheylade (15) [<51] >+33471789067 (992m)La Chapelle D'Auberoche - Le Change (24) [<51] >+33553060419 (110m)Aire naturelle de Communal Isabelle - Retournac (43) [<51] >+33471592195 (500m)Municipal La Roussilhe - Mauriac (15) [<51] >+33471680699 (708m)Municipal - Bassignac Le Haut (19) [<51] >+33555282472 (545m)La Motte - Le Fouilloux (17) (01/01-31/12) >+33546040839 -CCA(82m)A la ferme les Liattes - La Motte de Galaure (26) [<51] >+33475684172 (351m)Le Maritan*** - St. Michel de Maurienne (01/01-31/12) >+33479591736 (723m)Au Fil de l'eau - Antonne et Trigonant (24) [<51] >+33553061788 (96m)Le Meyrat - Trelissac (24) [<51] >+33553046707 (200m)A la ferme La Petite Grange - Bonnes (16) [<51] (01/04-30/09) >+33545985428 (40m)De Vaubarlet -�Sainte-Sigolene (43) (29/04-30/09) >+33471666495 -CCpg342-CCA(595m)Les Ecureuils - Hourtin (33) >+33556091047 (17m)Val Saint-Jean - Mauriac (15) (30/04-14/09) >+33471673113 -CCpg331(652m)Municipal La Riviere*** - Donzenac (01/05-30/09) >+33555857233 (125m)Municipal Vallat - Allanche (15) >+33471204587 (960m)Le Bois du Coderc - Antonne et Trigonant [<51] (01/01-31/12) >+33553059983 (104m)La Griveliere - Montrigaud (26) (01/04-30/09) >+33475717071 -CCA(461m)l'�lot - Cubjac (24) >+33553053979 (114m)Municipal De Sabot - Saint Maurice de Lignon (43) >+33471653268 (706m)La Cote d'Argent Hourtin Plage -�Hourtin (33) (13/05-13/09) >+33556091025 -CCpg133(16m)Municipal Des Lacs - Soursac (19) >+33555275261 (265m)Col de la Croix de Fer - Saint Sorlin d'Arves (73) [<51] >+33479595436 (1684m)Chateau De Galaure - Chateauneuf de Galaure (26) (24/04-26/09) >+33475686522 -CCpg271-CCA(243m)La Buidonniere*** - Aussois (01/01-31/12) >+33479203558 (1462m)Municipal Val d'Ambin - Bramans (73) (01/05-31/10) >+33479050305 -CCA(1232m)La ferme De Bresillas - Vinay (38) [<51] >+33476366377 (479m)La Barge - Cubjac (24) [<51] (01/05-29/10) >+33553541250 (129m)Municipal** - Molompize [<51] (15/06-15/09) >+33471736290 (579m)Municipal - Moussages (15) [<51] >+33471400768 (848m)Huttopia Lanmary - Antonne-et-Trigonant (24) (02/04-19/10) >+33553458863 -CCA(129m)Municipal La Tigny - Villarembert (73) [<51] >+33479830251 (1286m)Municipal** - Braud et St. Louis (02/01-31/12) >+33557426087 (6m)Municipal Apchon - Apchon (15) [<51] >+33471780398 (1041m)Le Roybon - Aigue Noire - Roybon (38) (15/04-15/10) >+33476362367 -CCA(538m)Du Coucou - Nailhac (24) >+33553508697 (167m)Municipal Le Pioulat - Trizac (15) >+33471786420 (952m)Municipal De L'Allagnon*** - Massiac (01/05-31/10) >+33471230393 (539m)Municipal Des Lilas - Montlieu La Garde (17) [<51] >+33546044412 (125m)Aire naturelle Les Ajoncs-Grands Chenes - Naujac sur Mer (33) [<51] >+33556730005 (15m)Le Pre Du Moulin - Laguenne (19) [<51] (01/04-30/09) >+33555262196 (239m)Le Petit Bois - Saint Merd de Lapleau (19) [<51] >+33555278944 (581m)La Barrerie - Chalais (16) [<51] >+33545986237 (117m)Municipal Du Chateau - Hauterives (26) (05/04-28/09) >+33475688019 -CCA(300m)Les Moulins - Beauzac (43) >+33471614702 (472m)Municipal de Lavaurs - Jaleyrac (15) >+33471697365 (698m)La Chataigneraie - Anneyron (26) (05/04-28/09) >+33475314333 -CCA(350m)Municipal Le Pre Sec - Tocane Saint Apre (24) >+33553904060 (75m)Municipal La Dronne - Riberac (24) >+33553905008 (61m)Le Chatelet*** - Andance (01/04-30/09) >+33475341447 (132m)Le Col - Fontcouverte la Toussuire (73) >+33479830080 (1625m)Municipal De Vaure - Annonay (7) >+33475337373 (405m)Etang De Taysse - Espagnac (19) >+33555207900 (549m)La Plaine-Lac du Moulin - Saint Saturnin (15) [<51] >+33565640524 (926m)La Virette - Le Sappey en Chartreuse (38) [<51] >+33476888528 (994m)Le Chenantier - Sollieres Sardieres (73) [<51] >+33686857698 (1280m)La Rochade - Naujac sur Mer (33) >+33618917383 (15m)Aire naturelle Le Laisser Aller - Sollieres-Sardieres (73) [<51] (01/06-30/09) >+33479205099 (1353m)Hermitage Rochas Couchaud - Saint Robert (19) [<51] >+33555841664 (304m)Municipal des Regnieres - Saint Sauveur en Rue (42) [<51] >+33477372471 (793m)La Prophetie - Saint-Robert (19) [<51] >+33555252998 (228m)Mouney Bas - Hautefort (24) [<51] >+33677218718 (155m)Municipal* - Auriac l'Eglise [<51] (15/06-15/09) >+33471739128 (610m)Rural de Cabirol - Villetoureix (24) [<51] >+33553900353 (88m)La Foret - Montendre (17) >+33546864639 (69m)Le Pin Sec - Naujac sur Mer (33) >+33556730066 (14m)Aire naturelle de Arnaud Rose-Marie - Naujac sur Mer (33) [<51] >+33556730220 (12m)A la ferme Les Rochers - Tourtoirac (24) [<51] >+33553511217 (161m)Municipal Du Lac - Marcillac La Croisille (19) (03/04-25/10) >+33555278138 -CCpg330-CCA(498m)Municipal Aubeterre- Aubeterre sur Dronne (16) >+33545986017 (45m)Rural de Ballandraud Jean - Burdignes (42) [<51] >+33477391146 (891m)Du Grand Cerf - Le Grand Serre (26) [<51] >+33475688614 -CCA(434m)Aire naturelle de Chateau Rocher - Roybon (38) [<51] >+33476362098 (628m)Les Grands Cols*** - St. Jean de Maurienne (73) (17/05-20/09) >+33479642802 -CCA(551m)La ferme La Belle Vue - Boisseuilh (24) [<51] >+33553516271 (194m)De Lascaux** - St. Germain les Vergnes [<51] (15/06-30/09) >+33555293090 (309m)Municipal Les Casses - Sembadel (43) [<51] >+33471009062 (1081m)Les 7 Laux*** - Theys (01/06-15/09) >+33476710269 (939m)Municipal La Prade - Laurie (15) [<51] >+33471739124 (814m)La Petite Riviere - Clergoux (19) [<51] (15/04-15/09) >+33555276850 (538m)Les Melezes - Termignon (73) >+33479205141 (1298m)Les Tourterelles - Tourtoirac (24) >+33553511117 (156m)Aire Naturelle La Bontat - Voutezac (19) [<51] >+33555847394 (126m)Municipal De La Plage - Soursac (19) >+33555275543 (516m)La Santoire - Saint Bonnet De Condat (15) [<51] >+33471784033 (898m)La ferme La Grenouille - Hautefort (24) [<51] >+33553501171 (207m)Municipal Du Pont - Lisle (24) (01/04-15/10) >+33562071439 -CCA(82m)La Bageasse - Brioude (43) (03/04-25/10) >+33471500770 -CCpg338(435m)Les Hirondelles - Naujac sur Mer (33) >+33682333654 (10m)Municipal Le Sedour - Riom Es Montagnes (15) >+33471780571 (846m)Chateau de La Peyrouse - Saint Sorlin en Valloire (26) >+33475317021 (278m)La Fennaz - Termignon (73) [<51] (06/07-24/08) >+33479205141 (1324m)Municipal Les Balmasses - Lanslebourg Mont Cenis (73) >+33479205277 (1390m)Le Ranch - Naujac sur Mer (33) >+33556730063 (8m)Le Laguneaussan - Lesparre Medoc (33) [<51] (01/01-31/12) >+33668087774 (21m)Municipal La Perriere** - St. Colomban des Villards [<51] (01/07-31/08) >+33479565026 (1118m)La ferme La Guinguette de Renamont - Grand Brassac (24) [<51] >+33553048244 (81m)Le Val Cenis - Lanslevillard (73) >+33479059052 -CCA(1459m)Lestage - Saint Seurin de Cadourne (33) [<51] >+33556423112 (19m)Municipal les Escures** - St. Pardoux l'Ortigier [<51] (15/06-15/09) >+33555845106 (330m)La Camarque - Bas en Basset (43) >+33471667110 (449m)Rural de Laoue Yvan - Naujac sur Mer (33) [<51] >+33686233880 (8m)Municipal Couly - Lapleau (19) [<51] >+33555275317 (534m)Les Collieres - Epinouze (26) [<51] >+33475317485 (198m)Municipal Les Catalpas** - Tullins [<51] (01/06-30/09) >+33476079799 (193m)L'Astree - Bourg-Argental (42) >+33670553656 (507m)Aire naturelle Les 3 Rivieres - Bassignac (15) [<51] >+33471408233 (366m)Municipal Theys* - Theys [<51] (01/06-30/09) >+33476710547 (645m)Twinlakes** - Soumeras (01/01-31/12) >+33546497712 (47m)Municipal Le Clupeau - Cherveix Cubas (24) >+33553504321 (147m)Les Claires*** - St.Rambert d'Albon (01/04-31/10) >+33475310187 (140m)A la ferme M. Barallon - Saint Regis du Coin (42) [<51] >+33477518437 (1140m)Municipal La Fressange - Saint Didier en Velay (43) >+33471662528 -CCA(798m)Municipal Belle Vue - Chevanceaux (17) [<51] >+33546046009 (127m)Municipal Les Mandieres* - St. Hilaire (01/05-30/09) >+33476083148 (1013m)Aire naturelle Municipale Le Lac - Menet (15) >+33471783180 (704m)Ferme Bio La Baraque - Servieres (43) [<51] >+33466611277 (659m)Les Avenieres - Manthes (26) [<51] >+33475319727 (227m)L'Etang Du Ruffaud*** - St.Priest de Gimel (20/05-30/09) >+33555212665 (511m)Lalle - Champagnac la Noaille [<51] (15/04-15/10) >+33555278418 (577m)Municipal De La Garenne - Bas en Basset (43) >+33471667001 (441m)Municipal Jullianges - Jullianges (43) [<51] >+33471033900 (934m)Le Bas Larin*** - Felines (01/04-30/09) >+33475348793 (327m)l'Illaz - Bessans (73) [<51] >+33684206460 (1680m)Aire naturelle Le Bonheur est dans le Pre - Vendays Montalivet (33) [<51] (30/04-16/09) >+33668800807 (7m)Municipal La Bessiere** - Blesle (15/04-30/09) >+33471762582 (514m)Municipal Saint Severin - Saint Severin (16) [<51] >+33545985241 (54m)Aire naturelle de Cruchon - Vendays Montalivet (33) [<51] >+33556417181 (7m)Beausejour*** - Chanas [<51] (15/04-30/09) >+33474843101 (151m)Chez Gendron** - St. Palais (33) (01/03-31/10) >+33557329647 -CCA(63m)Aire naturelle La Cordeliere - Marlhes (42) [<51] >+33477390827 (1013m)Planete Equi - Boisredon (17) [<51] >+33546048134 (61m)Municipal Juillac - Juillac (19) [<51] >+33555256046 (297m)A la ferme la Gueriniere - Chantillac (16) [<51] >+32479695756 (113m)Neige et Nature de la Ferriere D'Allevard - La Ferriere (38) >+33476451984 (901m)Municipal Lac de la Terrasse** - La Terrasse (01/05-30/09) >+33555581214 (236m)Aire naturelle de Granjon Jean-Michel - Thelis La Combe (42) [<51] >+33477396525 (918m)La Ferme Le Miron - Saint Jacques d'Atticieux (7) [<51] >+33475671110 (627m)A la Ferme Les Bellesvues - Merignac (17) [<51] >+33604039282 (95m)Le Temps Libre**** -�Bouge-Chambalud (01/04-30/09) >+33474840409 (196m)Aire naturelle de Heyraud - La Versanne (42) [<51] >+33477396715 (999m)Rural de Batard Gilles - Valeuil (24) [<51] >+33553058651 (111m)Municipal Les Combes - Saint Pantaleon De Lapleau (19) [<51] >+33619404585 (602m)Les Guyots*** - Chanas (01/03-30/10) >+33474842536 (172m)Mini Chene Vert - Saint Bonnet sur Gironde (17) [<51] (30/04-30/09) >+33546499441 (39m)De Martiniere -�Saint Pierre de Chartreuse (38) (01/05-14/09) >+33476886036 -CCA(886m)Le Val Ternay - Saint Julien Molin Molette (42) [<51] >+33477515076 (621m)A la ferme les Ecuries de l'Abbaye - La Chaise Dieu (43) [<51] >+33471000676 (1014m)Municipal - Craponne sur Arzon (43) [<51] >+33471032309 (908m)A la ferme Chez Sarrazin - Brossac (16) [<51] >+33545782157 (116m)Municipal De Vialle - Saignes (15) [<51] >+33471406280 (499m)Municipal - Saint Simeon de Bressieux (38) [<51] >+33474200022 (385m)Municipal - Naves (19) [<51] >+33555266016 (489m)Du Bas-Meygnaud - Valeuil (24) (01/04-15/10) >+33553055844 (139m)A la ferme de Sudul Bernard - Pommiers La Placette (38) [<51] >+33476563405 (675m)Miserieux - Saint Jacques d'Atticieux (7) [<51] >+33475671110 (533m)La Vigne - Saignes (15) [<51] >+33683123932 (524m)Municipal De La Borie Basse - Condat (15) [<51] >+33471785285 (711m)Municipal Les Prades - La Chaise Dieu (43) >+33471000848 (1028m)La Maison des Peres - Lascaux (19) [<51] >+33643813682 (348m)A la ferme la Grange du Traverole - Bessans (73) [<51] >+33682110310 (1740m)Municipal La Croix de Garry - Saint Genest Malifaux (42) >+33685409538 (928m)Municipal - Excideuil (24) [<51] >+33553624372 (150m)Municipal De Bellevue - Saignes (15) >+33471406840 (489m)Intercommunal - Beaurepaire (38) >+33474846489 (260m)Municipal aire naturelle Du Vilon - Vebret (15) [<51] >+33471402086 (491m)Naturist - Chez Martin - Bors de Montmoreau (16) >+33545240824 (81m)Aire naturelle Municipale - Ydes (15) [<51] >+33471408251 (468m)Aire naturelle Le Cottet - Saint Appolinard (42) [<51] >+33474873878 (442m)Aire naturelle Laouba - Vendays Montalivet (33) [<51] >+33556417152 (5m)Municipal - Saint Amandin (15) [<51] >+33471781828 (783m)Du Bois Coutal - Vigeois [<51] (15/04-15/10) >+33555737193 (370m)Puynadal - Brantome (24) >+33553061966 (157m)Le Pagnon- Saint Mesmin (24) [<51] (01/04-31/10) >+33657573121 (311m)Municipal de Pilard** - Lagrauliere [<51] (15/06-15/09) >+33555737104 (401m)Municipal Le Pontis Sud-Est - Verteillac (24) [<51] >+33553903774 (103m)Bruyere - D' Essendieras - Saint Medard d'Excideuil (24) [<51] >+33553553434 (277m)Les Peupliers - Vendays Montalivet (33) >+33556417044 (7m)Municipal Les Ormeaux* - St. Bonnet sur Gironde [<51] (01/06-30/09) >+33546860159 (4m)La Rose Blanche*** - Mirambeau (01/05-30/09) >+33546040994 (34m)Municipal Sainte Reine - Saint Pal de Chalencon (43) [<51] >+33471613019 (904m)Port Buisson - Aurec sur Loire (43) >+33477352465 (441m)Peyrelevade - Brantome (24) (01/05-30/09) >+33553057524 -CCA(104m)Le Bois Joli** - St. Martin s/l Chambre (01/01-31/12) >+33479562128 (532m)A la ferme Chez Baron - Oriolles (16) [<51] >+33545987922 (111m)Naturist - Centre Helio Marin Montalivet - Vendays Montalivet (33) (29/03-28/09) >+33556737373 -CCpg132-CCA(12m)A la ferme Verchalles - Vebret (15) [<51] >+33471402158 (489m)La Bois de Calais - Correze (19) >+33555262627 (425m)Aire naturelle L'Alouette - Vendays Montalivet (33) [<51] >+33556417334 (3m)Municipal De La Champ - Champagnac (15) >+33471696155 (635m)La Chanterelle - Champagnac le Vieux (43) >+33471763400 (861m)La ferme l'Ecureuil - Champs sur Tarentaine Marchal (15) [<51] >+33471787185 (515m)Municipal De Leignecq - Merle Leignec (42) >+33477502199 (902m)Le Chinfert - Pinsot (38) [<51] >+33476975375 (684m)Le Merin - Vendays Montalivet (33) >+33556417864 (3m)Municipal - Montboudif (15) [<51] >+33471785388 (928m)Municipal Du Lac De Pontcharal*** - Vigeois (01/06-15/09) >+33555989086 (329m)Le Petit Nice** - St. Martin s/l Chambre (01/01-31/12) >+33479563772 (544m)Atlantic Club - Vendays-Montalivet (33) (02/05-20/09) >+33825002030 -CCpg131(13m)Medoc Plage - Vendays Montalivet (33) (19/04-14/09) >+33556093345 -CCpg130-CCA(13m)La Ferme Domaine la Valade - Vigeois (19) [<51] >+33587450061 (348m)A la Ferme Equestre Les Chevaliers - Penol (38) [<51] >+33474204372 (340m)Aire naturelle des Cerisiers - Maclas (42) [<51] >+33474874968 (420m)Municipal La Chapelle*** - Correze [<51] (15/06-15/09) >+33555212521 (456m)De Mayan - Vendays Montalivet (33) [<51] >+33556417651 (4m)La Colline - Linard (24) [<51] >+33553522339 (323m)Le Champanay*** - St. Maurice l'Exil (01/04-30/09) >+33474296585 (138m)Municipal Du Pont de la Riviere** - Vitrac sur Montane [<51] (15/06-15/09) >+33555213968 (561m)La Chesnays - Vendays Montalivet (33) [<51] >+33556417274 (6m)Le Parc Isertan - Pralognan la Vanoise (73) (28/05-30/09) >+33479087524 (1429m)Le Chamois - Pralognan la Vanoise (73) >+33479087154 (1429m)Municipal - Saint Sornin Lavolps (19) [<51] >+33555733895 (380m)La Ferme du Paysan - La Murette (38) [<51] >+33476656783 (433m)Le Carrelet** - Mirambeau (01/04-30/10) >+33554702699 (62m)Lac de Bournazel**** - Seilhac (01/04-31/10) >+33555270565 (478m)Municipal De la Grande Foret - Saint Etienne de Crossey (38) [<51] >+33476060567 (445m)Soleil d'Or - Vendays Montalivet (33) >+33556093137 (8m)De Mialaret -�Neuvic (19) (26/04-05/10) >+33555460250 (633m)Municipal Le Plein - Baignes Sainte Radegonde (16) >+33661738312 (74m)l'Estuaire - Saint Thomas de Conac (17) (01/01-31/12) >+33546860820 -CCpg128(1m)Municipal La Combe* - St. Vincent de Mercuze (01/04-30/09) >+33476134223 (362m)Aire naturelle Chene et Roseau - Moissieu sur Dolon (38) [<51] >+33474845762 (351m)Municipal Du Lac - Neuvic (19) >+33555958548 (610m)La Lone*** - St. Pierre de Bouef (01/04-30/09) >+33474871424 (142m)Municipal Pont d'Allagnon*** - Lempdes s/Allagnon (43) (01/04-30/09) >+33471765369 -CCA(430m)Municipal Le Bandier - Sauvessanges (63) >+33473959429 (804m)Municipal Les Tilleuls - Usson en Forez (42) [<51] >+33477506373 (913m)Clair Matin*** - Allevard les Bains (38) (01/05-10/10) >+33476975519 -CCA-BD_FR-O.010(514m)Aire naturelle de Baleydier Louis - Usson en Forez (42) [<51] (901m)Municipal Le Maury - Liginiac (19) [<51] >+33555958561 (617m)Municipal Les Berges du Guiers - Saint Laurent du Pont (38) [<51] >+33476552063 (409m)Municipal La Tarentaine - Champs sur Tarentaine Marchal (15) >+33471787125 (495m)Le Moulin Du Chatain - Payzac (24) >+33553527969 (266m)Municipal les Pagues Nord - Saint Pierre (15) >+33471696214 (588m)Municipal Le Pre Chaton - Saint Salvadour (19) >+33555216394 (429m)Les Terrasses du Collet - Allevard (38) >+33678115689 (1390m)Le Lac Bleu** - St. Remy de Maurienne (01/05-30/09) >+33479831659 (414m)Municipal les Eydoches - Faramans (38) >+33625503802 (356m)Municipal La Riviere Haute*** - Auzon [<51] (01/07-31/08) >+33471761861 (442m)La ferme de L'Etang - Champs sur Tarentaine Marchal (15) [<51] >+33471787136 (793m)Rural de Hutchinson Tracey - Nanteuil Auriac De Bourza (24) [<51] >+33553903946 (140m)Aire naturelle Les Chenes - Vendays Montalivet (33) [<51] >+33556094057 (5m)l'Etang** - Meyrignac l'Eglise [<51] (01/07-31/08) >+33555212436 (586m)La Colombiere** - St. Maurice l'Exil (38) (01/04-31/10) >+33474862567 (197m)Le Port de Neuvic - Neuvic (19) >+33678683479 (605m)Tastesoule - Vensac (33) >+33670277305 (6m)Vieux Moulin - Vensac (33) >+33664641312 (9m)Municipal* - Saint Jal [<51] (15/06-15/09) >+33555731609 (407m)Ideal*** - Allevard les Bains (01/05-10/10) >+33476975023 (439m)Municipal du Champ Pigeonnier - Neuvic (19) >+33555958548 (607m)Municipal Les Bruyeres - Tremouille (15) >+33471785076 (882m)A la ferme Maucite - Champagnac de Belair (24) [<51] >+33553542174 (176m)La Bonne Source - Saint Martin Sepert (19) [<51] >+31342476175 (345m)Pellachal - Neuvic (19) [<51] >+33555950371 (606m)Le Domaine Vert - Troche [<51] (01/04-30/09) >+33555735989 (388m)Le Petit Lion - Vendoire (24) [<51] (01/01-31/12) >+33553910074 (80m)Les Acacias - Vensac (33) >+33556095881 (9m)Le Martagon - Les Allues (73) [<51] >+33479005629 (1322m)Le Soustran - Neuvic (19) [<51] >+33555950371 (609m)l'Insolite - Brassac les Mines [<51] (01/04-30/09) >+33473543088 (399m)Les Nations*** - Auberives sur Vareze (38) (01/03-15/11) >+33474849513 -CCA(246m)Le Repaire - Thiviers (24) (01/04-31/10) >+33553526975 -CCA(186m)Municipal Le Metz - Arlanc (63) [<51] >+33473951562 (578m)Aire naturelle Municipale - Saint Julien Pres Bort (19) [<51] >+33555967160 (595m)Les Etangs Du Plessac - Saint Felix De Bourdeilles (24) [<51] >+33553463912 (159m)Bel'Epoque du Pilat - Pelussin (42) (05/04-28/09) >+33474876660 -CCA(407m)Base de loisirs de Rouffiac - Angoisse (24) >+33553056565 (284m)Naturist - Euronat -�Grayan l'Hopital (33) (04/04-01/11) >+33556093333 -CCpg129(15m)Les Aubazines - Bort Les Orgues (19) >+33555960838 (591m)A la ferme Sarrazin - Jau Dignac et Loirac (33) [<51] >+33556094263 (1m)Naturist - Le Dorier - Saint Victor sur Loire (42) >+33477903232 (681m)Municipal - Saint Genes Champespe (63) [<51] >+33473223488 (1010m)Le Lac*** - Egletons (01/01-31/12) >+33555931475 (555m)Municipal Le Colombier - Estivareilles (42) [<51] >+33477502172 (927m)Municipal La Minoterie*** - Uzerche [<51] (01/05-30/09) >+33555731275 (307m)Aire naturelle Chantegril - Liginiac (19) >+33555959162 (572m)Municipal Le Cozon - Saint Pierre d'Entremont (73) [<51] >+33479658133 (640m)Municipal - Saint Augustin (19) [<51] >+33555213277 (543m)Aire naturelle De Mont-Chardon - Oyeu [<51] (01/05-30/09) >+33476557052 (559m)Aire naturelle de Bertholat Pierre - Chavanay (42) [<51] >+33474870044 (350m)Municipal Du Stade - Saint Bonnet le Chateau (42) >+33477500316 (809m)Chante L'Oiseau - Chamboulive (19) >+33555216909 (410m)Le Daxia** - St. Clair du Rhone (38) (01/04-30/09) >+33474563920 -CCA(172m)Les Etangs* - Cheyssieu (01/01-31/12) >+33474849133 (220m)La Charrue - Vieux Mareuil (24) [<51] >+33553566559 (145m)Le Bontemps - Vernioz-St Alban de Vareze (38) (04/04-27/09) >+33474578352 -CCpg272(268m)Les Castors - Jonzac (17) >+33546482565 (41m)Le Domaine Bleu** - St. Pardoux Corbier [<51] (01/07-31/08) >+33555735989 (382m)Le Balcon de Chartreuse - Miribel les Echelles (38) >+33476552853 (704m)Les Petits Chevaliers** - St. Maximin [<51] (01/01-31/12) >+33476976018 (377m)La Siauve - Lanobre (15) >+33471403185 (591m)Les Platanes** - Charavines (01/04-30/09) >+33476066470 (500m)Municipal - Viverols (63) [<51] >+33473959690 (851m)Le Bois des Sources*** - St. Prim (01/04-31/10) >+33474849511 (182m)Le Port Maubert - Saint Fort sur Gironde (17) [<51] (01/01-31/12) >+33546047886 (3m)Municipal Le Gurp - Grayan et l'Hopital (33) >+33556094453 (18m)Aire naturelle Ferme de Biesse - Chambles (42) [<51] >+33477523233 (725m)Chez Philipaud - Lamerac (16) [<51] >+31297775375 (91m)Municipal - Saint Vivien de Medoc (33) >+33556094377 (3m)L'Arc en Ciel - Entre Deux Guiers (38) (01/03-15/10) >+33476660697 -CCA(385m)Milliat - Charavines (38) [<51] >+33476557096 (500m)A la ferme Au Moulin de Feuyas - Thiviers (24) [<51] >+33553550399 (169m)Les Familles - Grayan et l'Hopital (33) >+33556094320 (7m)Rural de Parouque Andre - Villars (24) [<51] >+33553548362 (174m)A la ferme de Sabouraux Andre - Saint Germain de Lusignan (17) [<51] >+33546493705 (53m)La Borde - Uzerche (19) [<51] >+33555984207 (381m)Robert** - Charavines (15/04-15/09) >+33476556677 (497m)Municipal - Bozel (73) >+33555735014 (858m)Municipal de la Vezenie** - Lubersac (01/04-15/10) >+33555735014 (364m)Municipal - Jonzac (17) >+33546484929 (37m)Le Bois D'Enval - Sarroux (19) [<51] >+33555960662 (653m)La Grenouille - Esteil (63) [<51] (29/06-01/09) >+33553501171 (675m)Les Franquettes - Grayan et l'Hopital (33) >+33556094361 (5m)l'Etang Bleu - Vieux Mareuil (24) (01/04-20/10) >+33553609270 -CCA(182m)Municipal Du Bord Du Lac - Bilieu (38) >+33476066700 (498m)Les Richardes - Val d'Isere (73) [<51] >+33479062660 (1869m)Municipal Vieux Moulin - Mareuil (24) [<51] >+33553609120 (119m)Moulin de l'Engrais - Champagnat le Jeune (65) [<51] (15/06-15/09) >+33473713167 (622m)Le Verdier - Saint Victour (19) [<51] >+33555948377 (614m)Outre Val - Bort Les Orgues (19) >+33555960582 (548m)Les Noisetiers - Bilieu (38) >+33476323674 (556m)Municipal De la Rochette** - Saint Clair (01/06-30/09) >+33479257355 (347m)De Longat - Saint Germain Lembron (63) [<51] >+33473964211 (436m)Naturist - Aimee Porcher - Pingrieux (19) >+33601115190 (366m)Municipal Des Monedieres** - St. Yrieix le Dejalat [<51] (15/05-15/10) >+33555930994 (776m)Les Plagnes - Presle (73) [<51] >+33479255229 (794m)l'Air Du Temps - Beaulieu (15) [<51] >+33471403158 (624m)l'Ourson - Entremont le Vieux (73) [<51] >+33479262137 (825m)La Piat - Brides les Bains (73) >+33479552274 (618m)Rural Les Acacias - Clion (17) [<51] >+33546481152 (37m)Municipal La Combe - Saint Geoire en Valdaine (38) [<51] >+33476075990 (439m)Le Sans Souci - Montferrat (38) >+33476324040 (519m)La Bruyere - Saint Jean de Couz (73) [<51] >+33479657911 (604m)Le St-Eloy - Saint Germain l'Herm (63) >+33473720513 (1025m)Rural de Maniquet Joseph - Chuyer (42) [<51] >+33474878452 (373m)Rural de Dezormeaux Jean Claude - Verin (42) [<51] >+33474595559 (315m)Bellevue - Montferrat (38) >+33662432305 (550m)Combe Leat - Presle (73) [<51] >+33479255402 (656m)Municipal Le Canada - Champagny en Vanoise (73) [<51] >+33479550341 (1460m)l'Ile des Pecheurs*** - Condrieu (69) >+33474566730 (146m)Saint Seurin - Barbezieux Saint Hilaire (16) >+33545783503 (72m)Municipal - Picherande (63) [<51] >+33473223084 (1169m)La Save - Picherande (63) [<51] >+33473223119 (1130m)Du Lac - Montferrat (38) >+33476323167 (496m)Municipal Pre de la Gane - Le Lonzac (19) [<51] >+33555982717 (442m)Moulin De La Geneste** - Condat sur Ganaveix [<51] (01/04-30/09) >+33555989008 (351m)Municipal Des Perce-Neige - Saint Donat (63) [<51] >+33473223013 (1046m)Le Granier** - Chapareillan (Easter-30/09) >+33476452136 (273m)La ferme La Rainette - Mortagne sur Gironde (17) [<51] (01/06-10/09) >+33546905034 (7m)La ferme Maumont - Milhac de Nontron (24) [<51] >+33553605372 (262m)Le Calatrin - Paladru (38) >+33630460339 (501m)A la ferme le Mas Laborie - Jumilhac le Grand (24) [<51] (01/04-30/09) >+33553525447 (347m)Naturist - La Robertanne - Saint Genest Lerpt (42) >+33477901524 (507m)Les Loges*** - Nonette (63) (01/04-15/09) >+33473716582 -CCA(389m)La Petite Lande - Saint-Jory-de-Chalais [<51] (01/01-31/12) >+33961360057 (278m)Corneuil - Saint Sulpice de Mareuil (24) [<51] >+33553607948 (142m)Moulin de Pacros - Chadernolles (63) [<51] >+33633418228 (563m)Le Sauzet - Pegoire (63) [<51] >+33473720175 (1063m)Municipal De Bellevue - Vernet la Varenne (63) [<51] >+33473713121 (789m)Escale** - Ste. Helene du Lac (73) (01/04-30/09) >+33479840411 (262m)Aire naturelle de Chovin Pierre - Saint Just Saint Rambert (42) [<51] >+33477902158 (569m)Aire naturelle La Riviere - Talais (33) [<51] >+33556097514 (1m)Municipal Bel Air - Mortagne sur Gironde (17) [<51] >+33546914884 (36m)Municipal La Graviere - Marsac en Livradois (63) [<51] >+33473956008 (540m)L'Ocean - Soulac sur Mer (33) >+33556097610 (14m)A la ferme La Rhue - Jumilhac le Grand (24) [<51] (15/04-30/10) >+33665852843 (335m)Soulac Plage - Soulac sur Mer (33) (11/04-27/09) >+33556098727 -CCA(16m)Les Pins - Soulac sur Mer (33) (01/05-30/09) >+33556098252 -CCA(15m)Du Bois de la Teppe - Saint Franc (73) [<51] >+33476311057 (546m)Municipal Les Oyats - Soulac sur Mer (33) >+33556097854 (16m)Les Lacs - Soulac sur Mer (33) (12/04-12/11) >+33556097663 -CCA-BD_FR-L.045(9m)Municipal La Chomette - Labessette (63) [<51] >+33473222298 (762m)Le Lilhan - Soulac sur Mer (33) >+33556097763 (10m)Les Genets - Soulac sur Mer (33) >+33556098579 (14m)Le Tuquet Vert - Jumilhac le Grand (24) [<51] (15/04-15/10) >+33553625285 (373m)Rural la Barde Fagnouse - Arthenac (17) [<51] >+33546491285 (57m)A la ferme du Grand Goulet - Chatonnay (38) [<51] >+33474583372 (496m)Les Graulges - Les Graugles (24) [<51] >+33553607473 (121m)Aire naturelle Chez Buord - Brie Sous Mortagne (17) [<51] >+33546941236 (46m)La Ferme du Lac*** - Les Marches (15/04-15/09) >+33479281348 (299m)Municipal La Font Pissotte - Saint Pardoux La Riviere (24) [<51] >+33553569181 (146m)Municipal De la Thialle - Bagnols (63) [<51] >+33473222800 (855m)Les Sables d'Argent - Soulac-sur-Mer (33) >+33556098287 (12m)Maisonneuve - Saint Jory De Chalais (24) (01/04-31/10) >+33553551063 -CCA(277m)La Chatonniere - Jumilhac le Grand (24) >+33553525736 (234m)Aire naturelle de Cros Jacques - Saint Just Saint Rambert (42) [<51] >+33477523451 (385m)Municipal Les Brevieres - Tignes (73) [<51] >+33479064586 (1660m)Nature et Vezere - Peyrissac (19) [<51] >+33555981704 (344m)Le Palace - Soulac sur Mer (33) >+33556098022 (13m)Rural de Bonnard Lucien - Les Haies (69) [<51] >+33474878521 (415m)Naturist - Le Fayard - Veix (19) [<51] >+33555940020 (780m)La ferme Le Touroulet - Chalais (24) [<51] (01/03-18/12) >+33553552359 (264m)Le Manoir *** - Montmelian [<51] (15/05-30/09) >+33479652238 (270m)Les Narcisses - Saint Clement de Valorgue (63) [<51] >+33473954576 (903m)Municipal Les bords de la Seugne** - Mosnac [<51] (15/04-15/10) >+33546704845 (23m)La Bastide - Coussac Bonneval (87) [<51] >+33555755568 (325m)Rural Puymezier - Sceau Saint Angel (24) [<51] >+33553560165 (234m)Eliana - Aigueblanche (73) [<51] >+33479242387 (468m)Marie France - Aigueblanche (73) [<51] >+33479242221 (471m)Aire naturelle de Bebieux - Saint Just Saint Rambert [<51] (15/04-15/10) >+33477523357 (382m)La Londagne - Saint Beron (73) [<51] >+33476311370 (335m)Chateau de Grange Fort*** - Les Pradeaux (63) (01/04-31/10) >+33473710243 -CCA-BD_FR-N.013(424m)Base De Loisirs du Moulin - Meyrieu les Etangs (38) >+33474593034 (434m)Le Morel - Aigueblanche (73) >+33479240525 (453m)Les Neiges - Aigueblanche (73) >+33479242390 (449m)Chez Couraud - Chenac Saint Seurin d'Uzet (17) [<51] >+33546904620 (54m)Municipal Du Rocher De Glaisy - Notre Dame Du Pre (73) >+33479240996 (1549m)Naturist - Du Grand Bois - Tupin et Semons (69) >+33474878848 (431m)Mussonville - Soulac sur Mer (33) >+33556097340 (5m)Le Bois de Graviere - Besse et Saint Anastaise (63) >+33473795205 (978m)Les Allees - Coussac Bonneval (87) [<51] >+33555755568 (373m)De Nontron - Nontron (24) [<51] >+33553560204 (151m)Rural de Balmain Raymond - Attignat Oncin (73) [<51] >+33479360729 (565m)Municipal Les Rambauds - Saint Antheme (63) >+33473954879 (922m)Municipal - Archiac (17) [<51] >+33546491046 (85m)A la ferme Le Signal - Attignat Oncin (73) [<51] >+33479360729 (539m)Bellevue - Barzan (17) >+33546904591 (27m)Municipal La Chauderie - La Tour d'Auvergne (63) (26/04-21/09) >+33473215501 (928m)Municipal d' Arfeuille - Saint Yrieix la Perche (87) >+33555750875 (360m)A la ferme Au Rendez-Vous de la Nature - Attignat Oncin (73) [<51] >+33479441225 (481m)La Baie de Chant Dorat - Barzan (17) >+33546904395 (5m)La Vallee - La Tour d'Auvergne (63) >+33473215443 (893m)Les Lanchettes -�Peisey-Nancroix (73) [<51] >+33479079307 (1458m)l'Ombrage - Saint Pierre Colamine (63) [<51] >+33473967787 (774m)Le Ferrand** - Lepin le Lac (01/05-15/09) >+33479360150 (379m)Les Peupliers** - Lepin le Lac (73) (01/04-31/10) >+33479360048 -CCA(378m)Les Trois Chenes - Ambert (63) >+33473823468 (527m)Municipal La Garenne** - Meymac (15/05-15/09) >+33555952280 (676m)Le Curtelet** - Lepin le Lac (73) (15/05-30/09) >+33479441122 -CCA(379m)Le Mont Grele - Lepin le Lac (73) >+33666737243 (379m)Le Royannais - Le Verdon sur Mer (33) >+33556096112 (6m)Le Coin Tranquille**** -�Les Abrets (01/04-31/10) >+33476321348 -CCpg281(323m)Bourliataud - Meilhards (19) >+33555982798 (460m)Le Moulin de Serre - Singles (63) (12/04-14/09) >+33473211606 -CCA(558m)Maison Neuve - Saint Saud Lacoussiere (24) [<51] >+33553569746 (286m)Lamongerie** - Masseret (01/04-30/09) >+33555734457 (421m)Rural Jaubertins - Hautefaye (24) [<51] >+33553560450 (163m)La ferme Vaures- Saint Saud Lacoussiere (24) [<51] >+33553551559 (301m)La Pointe Du Medoc - Le Verdon sur Mer (33) >+33556733999 (5m)Fleurs des Champs - Arces sur Gironde (17) >+33546904011 (3m)Les Prairies - Sauxillanges (01/04-31/10) >+33473968626 (433m)Les Grottes** - Perrier (01/06-31/08) >+33473890317 (426m)Le Perigord Vert - La Coquille (24) [<51] (15/04-30/09) >+33553528577 (342m)Municipal de Ponty*** - Ussel (01/05-30/09) >+33555721669 (650m)La Cle des Champs - Arces (17) [<51] >+33621558770 (10m)Les Chants d'Oiseaux** - Domessin [<51] (15/04-30/09) >+33473890359 (270m)Aire naturelle de Malpelas Sebastien - Ussel [<51] (01/01-31/12) >+33555721568 (667m)Municipal le Mas*** - Issoire (01/04-10/11) >+33609805263 (366m)Chateau Le Verdoyer -�Champs Romain (24) (25/04-30/09) >+33553569464 -CCpg139(309m)La Monnerie - La Coquille (24) >+33553528303 (314m)Municipal Le Savoy*** - Challes les Eaux (73) (10/04-30/09) >+33479729731 -CCA(297m)Municipal Du Lac** - Meuzac (15/06-15/09) >+33555099712 (387m)Le Bellevue - Saint Victor la Riviere (63) [<51] >+33473885277 (1022m)Les Vigeres - Le Chalard (87) [<51] >+33555093722 (342m)Bellevue** - St. Alban de Montbel (01/04-30/09) >+33479360148 (385m)Le Sougey**** - St. Alban de Montbel (73) (01/05-15/09) >+33479360144 -CCA(386m)Municipal Parc Barabeau - Jarnac Champagne (17) [<51] >+33546495071 (54m)Le Soleil Levant-Ribes - Meschers sur Gironde (17) (01/04-30/09) >+33546027662 -CCA(4m)Le Voissieres - Chambon sur Lac (63) >+33473886413 (934m)Le Lac de Carouge*** - St. Pierre d'Albigny (73) (01/05-05/09) >+33479285816 -CCA(290m)Les Trois Lacs**** - Belmont Tramonet (73) (01/05-15/09) >+33476370403 -CCA(232m)Rural Des Gilleberts - Birac (16) [<51] >+33545970296 (69m)La Plage - Treignac (19) (05/04-28/09) >+33555980854 -CCA(527m)La Ripole - Abjat sur Bandiat (24) [<51] >+33553568685 (257m)Les Nonnes - Meschers sur Gironde (17) >+33546027281 (26m)Les Sables - Meschers sur Gironde (17) >+33664814910 (30m)Montchavin - Bellentre (73) >+33479078323 (1185m)La Plage - Meschers sur Gironde (17) >+33546027654 (31m)La Gazelle - Clemensat (63) [<51] >+33473711479 (569m)Municipal Les Aurandeix - Tauves (63) (11/04-19/09) >+33473211406 -CCpg332(855m)Aire naturelle Les Pourettes - Chateau Chervix (87) [<51] >+33555486803 (398m)Le Ribes - Meschers sur Gironde (17) >+33546027026 (2m)Manzac Ferme - Augignac (24) [<51] >+33553560262 (204m)l'Arbaz* - St. Alban de Montbel (73) >+33479360410 (391m)Aire Naturelle La Grange - Meschers sur Gironde (17) [<51] >+33546027508 (4m)La Ribeyre -�Murol (63) >+33473886429 (854m)Rural de Bellemin Noel-Yves - Ayn (73) [<51] >+33479289982 (561m)L'Arclusaz - Saint Pierre d'Albigny (73) [<51] >+33479285339 (350m)Les Chenes Verts - Meschers sur Gironde (17) >+33546741445 (20m)Wakan Tanka - La Bucherie-Saint Saud Lacoussiere (24) [<51] (01/04-31/10) >+33553605998 -CCA(325m)Robert* - Novalaise (01/04-31/10) >+33479360211 (379m)L'Escale - Meschers sur Gironde (17) >+33546027153 (4m)l'Europe - Murol (63) >+33473886046 (857m)Municipal** - Gemozac [<51] (01/04-30/09) >+33546945016 (32m)Le Grand Verney*** - Novalaise (01/04-31/10) >+33479360254 (466m)Pierra-Menta - La Cote d'Aime (73) [<51] >+33608841837 (979m)A la ferme Le Fil d'Or - Ladignac le Long (87) [<51] >+33555093310 (309m)Les Chavannes*** - Novalaise (01/04-31/10) >+33612639678 (447m)Les Bombes - Chambon sur Lac (63) (01/05-15/09) >+33473886403 -CCA(883m)Entre Mer et Foret - Meschers sur Gironde (17) >+33546027679 (12m)Les Guilles - Landry (73) >+33479070889 (793m)Aire naturelle de Chardon - Pons [<51] (01/01-31/12) >+33546950125 (36m)Aire naturelle La Plenitude - Meschers sur Gironde (17) [<51] >+33546027967 (12m)Le Serrette - Chambon sur Lac (63) (01/05-15/09) >+33473886767 -CCA(1032m)l'Ambroisiere** - Novalaise (01/04-31/10) >+33479360476 (381m)La Grande Cascade - Mont Dore (63) >+33473650623 (1281m)La Plage - Murol (63) >+33473886004 (886m)Ferme De Chez Filleux - Arces sur Gironde (17) >+33685930060 (8m)La Hutte des Domes - Saint Nectaire (63) [<51] >+33473885022 (639m)Le Birat - Meschers sur Gironde (17) >+33546027026 (23m)Le Repos Du Baladin - Murol (63) (26/04-06/09) >+33473886193 -CCA(810m)Saviloisirs - Saint Amant Roche Savine (63) >+33473957360 (916m)Le Pre Bas - Murol (63) (26/04-20/09) >+33473886304 -CCA(882m)La Vallee Verte - Saint Nectaire (63) >+33473885268 (661m)La Cle des Champs - Saint Nectaire (63) (01/04-30/09) >+33473885233 -CCA(652m)Les Fougeres - Murol (63) >+33473886708 (868m)Le Pin Franc - Meschers sur Gironde (17) >+33546053196 (16m)l'Eden - Landry (73) (01/01-27/09) >+33479076181 -CCA(733m)Du Marais - Murol (63) >+33473888585 (874m)Municipal Des Crouzets - Mont Dore (63) >+33473652160 (1021m)A la ferme Le Soleillant - Verrieres en Forez (42) [<51] >+33477762273 (840m)Municipal Le Paradis*** - Pons [<51] (01/05-30/09) >+33546913672 (17m)Municipal Le Merle - Chamberet (19) >+33555983012 (441m)Les Bruyeres - Diemoz (38) [<51] >+33478962777 (364m)La Plage Verte - Mont Dore (63) >+33473650985 (1151m)Le Viginet - Saint Nectaire (63) (05/04-30/09) >+33473885380 -CCA(706m)Le Bioley - La Cote d'Aime (73) [<51] >+33614502506 (1295m)Le Dauphin - Saint Georges de Didonne (17) >+33546053331 (23m)Bois Soleil -�St Georges de Didonne (17) (03/04-04/10) >+33546050594 -CCpg127(13m)La F�ret de Suzac - St. Georges-de-Didonne (17) (01/04-20/10) >+33546068000 -CCA(24m)Aire naturelle de Grand Pierre - Saint Andre De Lidon (17) [<51] >+33546942003 (29m)La ferme Royeres - La Roche l'Abeille (87) [<51] >+33555004409 (398m)A la ferme les Moulins - Nances (73) [<51] >+33610717484 (399m)Municipal Le Pre Vert - Montaigut le Blanc (63) >+33473967507 (490m)Domaine des Landais - Tauves (63) [<51] >+33473211244 (956m)Aire naturelle Chez Menard - Saint Andre De Lidon (17) [<51] >+33546900940 (26m)Ideal - Saint Georges de Didonne (17) (01/05-07/09) >+33546052904 -CCA(15m)l'Oasis - Saint Genix sur Guiers (73) [<51] >+33476318019 (235m)Municipal Le Sorlut - Cozes (17) >+33546907599 (43m)Municipal l'Esquiladou - Mont Dore (63) >+33473652374 (1010m)Aire naturelle Chalameyroux - Messeix (63) [<51] >+33473214025 (586m)Municipal Le Chatelard*** - Ste Catherine (01/03-30/11) >+33478818060 (795m)Municipal Les Vernieres ** - La Bourboule (Easter-10/10) >+33473811020 (867m)Moulin des Vallandreaux - Roullet Saint Estephe (16) [<51] >+33670774313 (47m)Maison Neuve - Grandval (63) >+33473957289 (825m)Municipal Le Surizet*** - Moingt-Montbrison (15/04-15/10) >+33477580830 (392m)Municipal Bel'air - Ladignac le Long (87) >+33555093982 (347m)Val de Coise*** - Saint Galmier (42) (11/04-12/10) >+33477541482 -CCA(403m)Les Coux - Murat le Quaire (63) (10/05-10/10) >+33473810710 (894m)Intercommunal Le Grand Etang - Saint Estephe (24) >+33553568093 (236m)Le Poutie - La Bourboule (63) >+33473810454 (899m)Les Moulins de la Vergne*** - Pons (01/01-31/12) >+33546905084 -CCA(11m)Les Clarines*** - La Bourboule (22/12-10/10) >+33473810230 (923m)Aire naturelle Chenegron - Grezac (17) [<51] >+33546909139 (29m)Les Bords du Guiers** - St. Genix s/Guiers (73) (20/04-20/09) >+33476317140 -CCA(218m)Le Panoramique*** - Murat le Quaire (63) (15/05-30/09) >+33473811879 -CCA(990m)Bois De La Chasse - Semussac (17) [<51] >+33546051801 (40m)Le Bigi*** - Bard [<51] (15/06-31/08) >+33477580639 (511m)Du Pas des Biches - Celles (17) [<51] (01/03-31/10) >+33546495203 (17m)Rural de Faure Michel - Augignac (24) [<51] >+33553568087 (281m)Le Moulin des Sources - Abjat sur Bandiat (24) >+33553568270 (230m)Municipal Les Couderts** - Murat le Quaire [<51] (01/04-15/10) >+33473655481 (1049m)Le Blayais Alicat - Saint Georges de Didonne (17) >+33546053192 (10m)A la ferme Le Chiron - Salles d'Angles (16) [<51] >+33545837279 (18m)Azpitarte-Besson - Saint Georges de Didonne (17) [<51] >+33677363865 (6m)Le Pont de la Dordogne - Saint Sauves d'Auvergne (63) (13/06-13/09) >+33612039156 -CCpg333(788m)Le Plan d'Eau** - Murat le Quaire (01/06-31/08) >+33473811005 (1090m)Les Bardonneries-2B - Semussac (17) >+33546059516 (3m)Aire naturelle Le Lys Blanc - Semussac (17) [<51] >+33546056590 (6m)Les Trois Ponts - Bugeat (19) [<51] >+33671090809 (680m)Le Chocot* - St. Sauves d'Auvergne [<51] (01/04-31/10) >+33473811199 (802m)Les Brandes - Saint Georges de Didonne (17) >+33977737110 (24m)Aire naturelle La Riviere - Semussac (17) [<51] >+33546053968 (12m)Du Moulin Brule - Chazelles sur Lyon (42) >+33477942010 (441m)Municipal Puy De Veix - Viam (19) [<51] >+33555955205 (677m)Le Nizour - Sireuil (16) >+33687546405 (27m)La Touyere - Marval (87) [<51] >+33555781208 (295m)A la ferme La Jaurie - Ladignac le Long (87) [<51] >+33555005223 (379m)A la ferme de chien La Soupeze - Dournazac (87) [<51] >+33555784462 (340m)Les Aillons - Aillon le Jeune (73) [<51] >+33479546032 (940m)A la ferme de Patricia et Loic Viguiaud - Semussac (17) [<51] >+33546069114 (28m)Plein Air - Saint Georges de Didonne (17) >+33546053160 (20m)Domaine Le Grand Cailleau - Bougneau (17) [<51] >+33606420555 (22m)Municipal Montreal** - St. Germain les Belles (87) (01/01-31/12) >+33555710083 -CCpg327-CCA(407m)Municipal Les Ribieres - Bussiere Galant (87) >+33555788612 (389m)Les Catalpas - Saint Georges de Didonne (17) (06/04-29/10) >+33825005311 (5m)Le Montet - Ladignac le Long (87) [<51] >+33555081065 (370m)Municipal De la Trillonniere** - Mornant [<51] (01/05-30/09) >+33478441647 (335m)La Ferme La Noyeraie - St Hilaire (87) [<51] >+33555082780 (379m)La Ferme De Lavaux** - St. Sauves d'Auvergne [<51] (15/04-15/09) >+33473811168 (891m)La Ferme de la Gargue* - St.Quentin Fallavier [<51] (01/01-31/12) >+33474942054 (292m)La Triloterie - Royan (17) [<51] >+33473811168 (7m)A la Ferme du Champon - Dolomieu (38) [<51] >+33474336268 (280m)Municipal Les Ecureuils** - Magnac Bourg [<51] (01/04-30/09) >+33555008028 (444m)Aire naturelle Municipale La Croisille sur Briance - La Croisille sur Briance (87) [<51] >+33555008028 (451m)Le Versoyen - Bourg Saint Maurice (73) >+33479070345 (815m)La Foret - Montvalezan (73) [<51] >+33479068621 (1733m)La Barge - Cunlhat (63) [<51] >+33473825710 (690m)Municipal Les Garennes - Piegut Pluviers (24) [<51] >+33553564022 (281m)Le Reclus - Seez (73) >+33479410105 (862m)Aire naturelle de Vernay Aime - Chaponnay (69) [<51] >+33478960035 (258m)Aire naturelle Municipale La Belle Etoile- Chavanac (19) [<51] >+33555954959 (864m)Le Joli Mont - La Bathie (73) >+33479896113 (368m)Le Tarin - La Bathie (73) >+33479896054 (363m)Le Clos Fleuri - Medis (17) >+33546056217 (25m)Clairefontaine - Royan (17) (05/04-28/09) >+33546390811 -CCA(4m)Les Epinettes - Les Avenieres (38) >+33676838913 (240m)Intercommunal Hurongues - Pomeys (69) (18/04-18/10) >+33478484429 -CCpg273(553m)Municipal Du Lac - Saint Hilaire les Places (87) >+33555581214 (386m)Ile de la Comtesse*** - Murs et Gelignieux (1) (01/05-05/09) >+33479872333 -CCA(220m)Municipal La Bruyere - Bregnier Cordon (1) [<51] >+33479872115 (241m)Municipal - Lacelle (19) [<51] >+33555460384 (652m)Naturist - De Bos Redon - Bussiere Galant (87) >+33555788202 (461m)Bernezac - Saint Palais sur Mer (17) >+33546390071 (16m)Municipal de Nauzan Plage - Vaux sur Mer (17) (01/05-30/09) >+33546382913 -CCA(6m)Val Vert - Vaux sur Mer (17) (11/04-26/09) >+33546382551 -CCpg125(8m)Le Royan - Royan (17) (01/04-10/10) >+33546390906 -CCA(20m)Aire naturelle le Moulin de Pousseau - Medis (17) [<51] >+33546067140 (15m)Aire naturelle Du Grand Pre - Medis (17) [<51] >+33546067443 (3m)Le Croix du Vent - Vic le Comte (63) [<51] (01/07-31/08) >+33473692263 (472m)Les Coquelicots - Royan (17) >+33546382321 (26m)Les Ormeaux - Saint Palais sur Mer (17) >+33546390207 (11m)Deux Plages - Saint Palais sur Mer (17) (01/04-30/09) >+33546231142 -CCA(16m)L'Oree Des Bois - Royan (17) >+33546390792 (27m)Chant Des Oiseaux - Royan (17) (04/04-27/09) >+33687830712 -CCpg126(29m)Aire naturelle Municipale Combrady - Bourg Lastic (63) [<51] >+33473218028 (762m)Le Bois Roland - Medis (17) >+33546054758 (13m)A la ferme de Fresney - La Chapelle sur Coise (69) [<51] >+33478484588 (707m)Mas De la Foret* - Heyrieux (01/01-31/12) >+33478400124 (270m)Les Chenes - Medis (17) >+33546067138 (10m)Ferme De Chauchamp - Vaux sur Mer (17) >+33546382762 (23m)Rural de Grange Henri - Saint Martin en Haut (69) [<51] >+33478486390 (789m)Puits de l'Auture - Saint Palais sur Mer (17) (01/05-30/09) >+33546232031 -CCA(10m)La Cote De Beaute - Saint Palais sur Mer (17) >+33546232059 (10m)La Grande Cote - Saint Palais sur Mer (17) >+33546232018 (14m)Naturist - Les Saules - Sussac (87) >+33555696436 (424m)Le Logis - Saint Palais sur Mer (17) >+33546232023 (18m)Le Tahiti - Saint Palais sur Mer (17) >+33546231841 (15m)Municipal Les Verpillieres - Saint Martin en Haut (69) [<51] >+33478486216 (778m)Le Repos - Saint Palais sur Mer (17) >+33627784687 (17m)l'Ile aux Cygnes*** - Bourget du Lac (01/05-30/09) >+33479250176 (231m)A la ferme de Besson Antoine - La Chapelle sur Coise (69) [<51] >+33478484597 (701m)L'Abeille*** - Eygurande (01/05-05/09) >+33473430000 (719m)A la ferme La Nozilliere - Marval (87) [<51] >+33555782560 (345m)La Borderie - Saint Palais sur Mer (17) >+33546233058 (23m)Parc De La Roche - Vaux sur Mer (17) >+33546083009 (21m)Elim - Saint Palais sur Mer (17) >+33546050392 (23m)Les Pins - Saint Palais sur Mer (17) >+33546233083 (22m)Les Suquets - Aydat (63) [<51] >+33473793100 (1004m)Walmone - Saint Sulpice de Royan (17) >+33546391581 (34m)Les Amis - Areches (73) >+33479381465 (1454m)Gorges du Chambon -�Eymouthiers (16) (20/04-14/09) >+33545707170 -CCA-BD_FR-I.094(150m)Municipal Le Bourg - Aydat (63) [<51] >+33473793926 (845m)Municipal Beausejour - Sussac (87) >+33555696241 (424m)Les Volcans - Aydat (63) [<51] >+33473793390 (1023m)La Maladiere - Albertville (73) [<51] >+33479378044 (349m)Municipal Les Moulins De Tardoire - Montbron (16) [<51] >+33545707467 (152m)Longues - Vic le Comte (63) [<51] >+33473625247 (343m)Le Grand Lac - Marval (87) >+33555787385 (348m)Le Lac d'Aydat - Aydat (63) >+33473793809 (848m)La Clairiere - Aydat (63) [<51] >+33473793115 (830m)Municipal l'Etang de la Lande - Nexon (87) >+33555583544 (402m)Municipal Des Chaux - Sornac (19) >+33555946349 (709m)Le Relax - Breuillet (17) >+33615987144 (26m)Municipal - Bourg Charente (16) >+33603986019 (16m)Le Logis Du Breuil - Saint Augustin (17) (10/05-30/09) >+33546232345 (26m)Le Clemencon - Grezieu Le Marche (69) [<51] (466m)Ile Madame - Jarnac (16) >+33545811854 (13m)Municipal Saint-Martial - Busserolles (24) [<51] >+33553605304 (155m)Transhumance - Breuillet (17) >+33546227215 (27m)Municipal Des Adoubes - Albertville (73) >+33479320662 (343m)Municipal de l'Enclose - Tarnac (19) [<51] >+33555955301 (690m)La Font de Bleix** - Martres de Veyre [<51] (01/01-31/12) >+33473392649 (338m)Municipal La Rivoirette - Morestel (38) >+33672979098 (220m)Aire naturelle Le Bol d'Air - Saint Paul (73) [<51] >+33619362496 (436m)Aire naturelle Le Bois - Saint Martin en Haut (69) [<51] >+33478486083 (777m)Les Cotes de Saintonge - Saint Augustin (17) >+33625650750 (27m)Du Lac - Saujon (17) (01/04-15/10) >+33546068299 -CCA(3m)Chateau Bellegarde les Fleurs - Chateauneuf la Foret (87) >+33555697767 (513m)Municipal Le Lamartine* - Bourdeau [<51] (15/06-15/09) >+33479250341 (340m)Naturist - La Serre de Portelas - Saint Saturnin (63) >+33473393525 (768m)l'Etang de Flechat - Orcival (63) [<51] >+33473658296 (931m)Le Logis de la Lande - Saujon (17) [<51] (15/03-15/11) >+33667386298 (2m)Les Barolles - Saint Genis Laval (69) >+33478560556 (216m)Rural de Delorme Francois - Thurins (69) [<51] >+33478489061 (424m)Eldapi - Saint Augustin (17) >+33546391446 (11m)Jollere - Perpezat (63) [<51] >+33473658448 (907m)Les Cyclamens - Le Chatelard (73) [<51] >+33479548019 (721m)Les Vignes - Saint Augustin (17) >+33546231934 (9m)Les 3 Lacs du Soleil -�Trept (38) (26/04-07/09) >+33474929206 -CCA-BD_FR-K.104a(238m)Intercommunal Chabanas*** - Pierre Buffiere (15/05-30/09) >+33555009643 (321m)Les Chelles - Olliergues (63) [<51] (01/04-31/10) >+33473955434 -CCA(566m)Le Plan d'Eau - Saint Yrieix sur Charente (16) >+33545921464 (33m)Beausoleil - Les Mathes (La Palmyre) (17) >+33546223003 -CCA(9m)Zephir - Les Mathes (La Palmyre) (17) >+33608536394 (9m)Aire Naturelle Les Metairies - Saint Sulpice de Royan (17) [<51] >+33546391412 (5m)A la ferme le G�te du Sabotier - Saint Sornin (16) [<51] >+33545622861 (139m)Les Lacs** - St. Jean de Chevelu (01/05-30/09) >+33662483738 (313m)Le Pecheur** - Aix les Bains (01/02-31/12) >+33681167975 (234m)Rural de l'Etang - Mornac sur Seudre (17) [<51] >+33546227225 (3m)Alp'Aix*** - Aix les Bains [<51] (01/07-30/09) >+33479350426 (231m)La Cote Sauvage - Les Mathes (La Palmyre) (17) >+33546224018 (7m)A La Belle Etoile - Breuillet (17) >+33546021407 (24m)Le Clos Auroy*** - Orcet (63) (01/01-31/12) >+33473842697 -CCA(366m)Municipal Saint Fortunat - Flavignac (87) [<51] >+33555391114 (362m)Municipal La Fontaine Du Pre St Jean - Dompierre sur Charente (17) [<51] >+33546910105 (6m)International du Sierroz*** - Aix les Bains (73) (15/03-15/11) >+33479612143 -CCA(231m)Atlantique Parc - Les Mathes (La Palmyre) (17) >+33546224035 (5m)Municipal - Peyrelevade (19) [<51] >+33555947156 (760m)Palmyre Loisirs - Les Mathes (17) >+33546236766 (11m)Municipal Les Iles du Cheran - Lescheraines (73) >+33479638000 (604m)La Cube - Le Brugeron (63) [<51] >+33473726784 (846m)Les Soudans - Yenne (73) [<51] >+33479367319 (335m)Le Flon - Yenne (73) [<51] >+33479368270 (223m)La Malichaude - Yzeron (69) [<51] >+33478810286 (719m)Rural de Boyer Jean - Marcilly Le Chatel (42) [<51] >+33477975141 (387m)La Haute Sioule - Saint Bonnet pres Orcival (63) (01/01-31/12) >+33473658332 (811m)Cognac - Cognac (16) >+33545321332 (10m)Marlice** - Trevignin [<51] (01/05-30/09) >+33479614474 (606m)Ferme Les Trois Coups - Les Mathes (17) >+33546224897 (3m)Le Grand Logis - Les Mathes (17) >+33546224722 (13m)Aire naturelle Municipale Val de Tamie - Seythenex (74) [<51] >+33450324997 (849m)Le Lac - Saint Mathieu (87) >+33555003026 (322m)Belle Riviere** - Chaniers (15/06-15/09) >+33546910220 (2m)Monplaisir - Les Mathes (17) >+33546225031 (6m)Parc du Verger - Champagnac la Riviere (87) >+33555012283 (350m)A la ferme de Clert Simone - Arith (73) [<51] >+33479633160 (740m)Le Cheyenne - Chateauneuf la Foret (87) [<51] >+33555693929 (372m)A la ferme Pragrand - Saint Laurent de Chamousset (69) [<51] >+33672938016 (555m)Municipal Des Glieres - Queige (73) [<51] (01/07-31/08) >+33479380297 (523m)l'Ile Aux Perdrix - Siccieu Saint Julien et Carisieu (38) >+33667810136 (310m)A la ferme Le Coterat - Montverdun (42) [<51] >+33477975662 (360m)Aire Naturelle du P'tit Bois - St Georges en Couzan (42) [<51] (15/04-15/10) >+33477248814 (809m)Municipal - Nedde (87) [<51] >+33555699809 (486m)Rural de Legouet - Colombier Saugnieu (69) [<51] >+33478328172 (230m)La Cle Des Champs - Les Mathes (17) (01/04-15/11) >+33546224053 -CCA(8m)Aire naturelle la Recorbaz - Seythenex (74) [<51] >+33450324509 (745m)La Flachardiere - Les Halles (69) >+33674110079 (633m)Municipal Domelin - Beaufort (73) >+33479383388 (715m)A la ferme les Charmilles - Montcel (73) [<51] >+33479635128 (550m)La Palombiere - Les Mathes (17) (01/04-20/10) >+33546226925 -CCA(10m)Naturist - Le Petit Dauphin - Les Mathes (17) >+33676375765 (6m)La Chenaie - Les Mathes (17) >+33546224225 (16m)Au Vert - Creys Mepieu (38) [<51] >+33474977151 (264m)Les Domes - Nebouzat (63) (27/04-15/09) >+33473871406 -CCA(811m)Ami-Ami - Les Mathes (17) >+33546224238 (7m)La Pinede - Les Mathes (17) (12/04-28/09) >+33546224513 -CCA(7m)Municipal Le Colombier - Billom (63) >+33473733767 (365m)L'Oree du Bois -�Les Mathes (17) (25/05-13/09) >+33546224243 -CCpg124(8m)Les Sables de Cordouan - Les Mathes (La Palmyre) (17) >+33546224513 (10m)Municipal - Eymoutiers (87) [<51] >+33555691398 (491m)L'Estanquet - Les Mathes (17) >+33546224732 (8m)Du Parc - Etaules (17) [<51] >+33546369651 (22m)l'Enclos Fleuri - Saint Pierre Roche (63) [<51] >+33473658427 (776m)Chez Rambaud - Les Salles-Lavauguyon (87) [<51] >+33555000890 (272m)Atlantique-Foret - Les Mathes (17) >+33546224046 (9m)Municipal - Sail sous Couzan (42) [<51] >+33477245208 (424m)De Giraud** - Boen (01/04-31/10) >+33477240891 (391m)Intercommunal De L'Etang De Meouze - Saint Oradoux De Chirouze (23) >+33555667781 (771m)Municipal le Chanset*** - Ceyrat [<51] (01/01-31/12) >+33473613073 (596m)Municipal Le Pre des Laveuses*** - Cournon d'Auvergne (01/04-31/10) >+33473848130 (319m)l'Etang - Le Lindois (16) [<51] >+33545650267 (269m)Aire naturelle La Grande Ile - Marsac (16) [<51] >+33545214246 (41m)A la ferme de Decultieux Bernard - Saint Clement les Places (69) [<51] >+33474263735 (590m)Au Vert - Pusignieu (38) [<51] >+33474977151 (312m)Parc de Bellevue - Arvert (17) >+33546476238 (14m)Les Flots - La Rochefoucauld (16) [<51] >+33681282845 (78m)Le Presqu'Ile - Arvert (17) >+33546368176 (21m)Le Grand Tetras - Hauteluce (73) >+33479389517 (1675m)A La Ferme Des Epinettes - Saint Romain de Jalionas (38) [<51] >+33619310350 (200m)Naturist - Des Monts de Bussy - Eymoutiers (87) [<51] >+33555696820 (486m)Le Puy De Faux - Faux La Montagne (23) [<51] >+33555679304 (729m)A la ferme de la Barge - Sainte Agathe la Bouteresse (42) [<51] >+33477975021 (370m)Les Rivieres - Civens (42) [<51] (01/04-31/10) >+33477261193 (341m)Le Col de la Luere - Vaugneray (69) >+33478458111 (602m)Ferme de Rotozan - Brussieu (69) [<51] >+33679631858 (413m)Municipal Les Taillades - Courpiere (63) [<51] >+33473530121 (317m)Les Framboisiers - Bellecombe en Bauges (73) [<51] >+33630475199 (919m)Municipal Le Palais*** - Feurs (01/04-31/10) >+33477264341 (338m)Au Fil De L'Eau*** - Saintes (01/05-30/09) >+33546930800 (9m)Les Jorets - Hauteluce (73) [<51] >+33642977723 (1669m)Les 4 Vents - Aubusson d'Auvergne (63) >+33473531694 (457m)Aire naturelle Le Goutilier - Aubusson d'Auvergne (63) [<51] >+33473512176 (406m)Le Clos des Fourches** - La Biolle [<51] (01/01-31/12) >+33681167975 (397m)Le Petit Pont - Arvert (17) >+33546360720 (8m)Le Pacha - La Tremblade (17) >+33546361444 (10m)Indigo Royat - Royat (63) (29/04-31/10) >+33473359705 -CCpg334-CCA(608m)Lac De Cadeuil - Sainte Gemme (17) >+33546228142 (10m)Les Etangs Mina - Saint Sornin (17) (05/04-28/09) >+33546228261 -CCA(9m)Aire naturelle Le Clos Francois - La Biolle (73) [<51] >+33681167975 (415m)Tillet - Marlens (74) (01/04-30/09) >+33450443374 -CCA(472m)Aire naturelle La Colombiere - La Biolle (73) [<51] >+33479547701 (416m)La Coulumiere - La Tremblade (17) >+33546360224 (9m)Le Verger*** - Cusy (01/06-31/08) >+33450525201 (531m)Municipal Les Bujoliers- Saint Cesaire (17) [<51] >+33546915545 (47m)Municipal - Gelles (63) [<51] >+33473878020 (851m)Municipal Les Pins - Saint Ferreol (74) [<51] >+33450445636 (507m)Saint Cry La Brevenne - Bessenay (69) [<51] >+33474708320 (285m)Aire naturelle Le Meyrieux - La Biolle (73) [<51] >+33479547201 (423m)Rural Sous la Colline - La Biolle (73) >+33479547679 (467m)Le lac du lit du Roi -�Massignieu de Rives (1) (01/05-21/09) >+33479421203 -CCA(233m)La Grand Maison - Longessaigne (69) >+33630341732 (693m)Aire naturelle de Poyet Joanny - Saint Sixte (42) [<51] >+33477246161 (577m)La Clairiere - La Tremblade (17) >+33546363663 (7m)Le Valerick - Saint Sornin (17) >+33546851595 (16m)La Serraz - Doussard (74) (19/04-14/09) >+33450443068 -CCA(476m)Municipal Les Chataigniers - Montemboeuf (16) [<51] >+33545650117 (279m)Les Ombrages*** - Dallet (63) (15/05-15/09) >+33473831097 -CCA-BD_FR-J.063b(316m)Goute la Vie - Cerin (16) [<51] >+3343786420 (576m)Municipal Bel Air - Saint Pierre de Curtille (73) [<51] >+33479542548 (384m)Le Verger Fleuri - Lathuile (74) >+33450443182 (493m)Municipal Les Platanes - Montignac Charente (16) [<51] >+33545398916 (43m)La Ramade - Flayat (23) [<51] >+33473217680 (741m)Aire naturelle Municipale - Cisternes La Foret (63) [<51] >+33473878105 (842m)Beausejour* - Albens [<51] (15/06-15/09) >+33479541520 (363m)Les Cerisiers de Bessenay - Bessenay (69) [<51] >+33678516356 (364m)Simon De Verthier - Doussard (74) >+33450443657 (450m)Le Ripan - Bessenay (69) >+33474709746 (404m)Rural la Chevre Verte - Bouvesse Quirieu (38) [<51] >+33474884992 (299m)De Pierrefitte - Beaumont du Lac (87) >+33555691588 (665m)Les Ombrages - La Tremblade (Ronce Les Bains) (17) >+33546360841 (12m)Municipal - Panissieres (42) [<51] >+33477286770 (601m)Les Pins - La Tremblade (Ronce les Bains) (17) >+33546360775 (7m)Municipal - Orcines (63) [<51] >+33473621876 (842m)Les Terrasses Du Lac - Royere de Vassiviere (23) >+33555647677 (662m)La Nubliere - Doussard (74) (01/05-21/09) >+33450443344 -CCA(452m)Le Pole - Lathuile (74) >+33688046870 (451m)Le Grand Large*** - Meyzieu (01/01-31/12) >+33478314216 (186m)Mon Desir - La Tremblade (Ronce les Bains) (17) >+33546360645 (10m)International Du Lac Bleu - Doussard (74) >+33450443018 (450m)Grun de Chignore** - Vollore Ville (01/01-31/12) >+33473537337 (543m)La Presqu'ile - Royere de Vassiviere (23) >+33555647898 (658m)Broussas - Faux la Montagne >+33555679801 (657m)Municipal Des Babelles - Conjux (73) >+33479542540 (240m)l'Ideal - Lathuile (74) (01/05-21/09) >+33450443297 -CCA(468m)Rural de Bargel Jean - Montagnieu (1) [<51] >+33478407116 (224m)Le Mus De Loup - La Tremblade (Ronce les Bains) (17) >+33619387046 (12m)Aire naturelle le Verger - Saint Eustache (74) [<51] >+33450320010 (728m)Marco De Bignac - Bignac (16) (01/03-31/10) >+33545217841 -CCA(46m)Municipal Les Greves - Aixe sur Vienne (87) [<51] >+33555701298 (203m)Municipal - Giat (63) [<51] >+33473217167 (772m)La Ferme - Lathuile (74) [<51] >+33673357057 (479m)Mont Bartoux** - Vollore Ville (63) [<51] (01/01-31/12) >+33473537005 -CCA(642m)Les Fontaines - Lathuile (74) >+33681401162 (484m)Rural de Simon Marguerite - Ailleux (42) [<51] >+33477246347 (680m)Aire naturelle le Combarut - Saint Eustache (74) [<51] >+33450320020 (702m)Le Taillefer - Doussard (74) [<51] >+33450443030 (476m)la Ravoire - Doussard (74) (14/05-13/09) >+33450443780 -CCpg284-BD_FR-K.103(464m)Le Pontet - Les Contamines Montjoie (74) >+33450470404 (1181m)Lac St Helene - Bujaleuf (87) >+33555695454 (334m)Municipal Les Sagnes - Peyrat le Chateau (87) >+33555694133 (678m)Les Sablons** - Pont du Chateau (01/06-30/09) >+33473835761 (311m)Des Lacs - Pressignac (16) >+33556701500 (228m)Municipal Du Val d'Amby - Hieres sur Amby (38) >+33474906747 (213m)A la Belle Etoile - Chindrieux (73) >+33479542031 (239m)Les 2 Iles - Peyrat le Chateau (87) >+33555694132 (661m)Municipal de La Roche** - Noiretable (01/04-31/10) >+33477247268 (692m)Municipal Les Plages de l'Ain - St.Maurice Gourdans (01/04-15/10) >+33474358293 -CCpg000-CCA(190m)Sous Le Moulin** - St.Maurice Gourdans (01/01-31/12) >+33474618835 (194m)De la Regniere* - Villette d'Anthon (01/01-31/12) >+33478312526 (184m)La ferme La Roulerie - Le Douhet (17) [<51] >+33675249196 (74m)Sequoia Parc - Saint Just Luzac (17) >+33546855555 (10m)Aire naturelle Le Buchit - Saint Sulpice d'Arnoult (17) [<51] >+33546956466 (37m)Les Iles - Chanaz (73) >+33479545851 (231m)Municipal - Fernoel (63) [<51] >+33473217022 (800m)Les Peupliers - Chindrieux (73) >+33479545236 (241m)Aire naturelle La Bottiere - Serraval (74) [<51] >+33450275056 (810m)La Meteorite - Rochechouart (87) (30/03-30/09) >+33555036596 -CCpg326(209m)Aire naturelle de Mercier Adrien - Alby sur Cheran (74) [<51] >+33450681575 (452m)Du Point Vert - Serrieres de Briord (1) >+33474361345 (202m)Air naturelle de Carret Andre - Sourcieux les Mines (69) >+33474704438 (405m)Tigouleix - Saint Agnant pres Crocq (23) [<51] >+33555678487 (732m)Le Cretoux - Saint Jorioz (74) (01/04-15/11) >+33450686194 -CCA(551m)Essi - Saint Thurin (42) >+33477979047 (481m)Naturist - Lous Suais - Cheissoux (87) >+33555695694 (386m)Au Bon Air - Marennes (17) (01/04-30/09) >+33546850240 -CCA(4m)Indigo Lyon**** - Dardilly (69) (01/01-31/12) >+33478356455 -CCpg277-CCA(325m)Le Vieux Moulin - Flumet (73) [<51] >+33479317006 (959m)Municipal de Beaufort - Saint Leonard de Noblat (87) >+33555560279 (267m)Municipal* - Pommiers (01/04-31/10) >+33477654354 (337m)Le Familial - Duingt (74) [<51] >+33450686991 (469m)Des Alouettes - Cognac la Foret (87) (01/04-30/09) >+33555032693 -CCA(354m)La Route Bleue*** - Balbigny (42) (15/03-31/10) >+33477272497 -CCA(321m)Municipal - Chasseneuil sur Bonnieure (16) [<51] >+33545396071 (110m)Le Repos - Marennes (17) >+33663236679 (4m)Municipal Moulin de l'Eau - Peyrat le Chateau (87) [<51] >+33555694101 (407m)La Chapelle Saint Claude - Talloires (74) >+33450603697 (447m)Le Lanfonnet - Talloires (74) >+33450607212 -BD_FR-K.089(448m)Municipal Les Champs Fleuris - Duingt (74) (19/04-20/09) >+33450685731 -CCA(457m)Ferme De la Pree - Marennes (17) >+33546850361 (2m)Parc De La Garenne - Pont l'Abbe d'Arnoult (17) >+33546970146 (21m)Vallee Bleue - Montalieu Vercieu (38) >+33474886367 (208m)A la ferme de Cotton Jacques - Bourcefranc Le Chapus (17) [<51] >+33546850180 (2m)La Combinette - Saint Trojan Les Bain (17) (01/04-31/10) >+33546760047 -CCA(7m)De la Pras** - St. Germain Laval (15/03-31/10) >+33477654435 (357m)Du Lac - Virieu Le Grand (1) (01/05-07/09) >+33479878202 (263m)Municipal La Palle*** - Pontgibaud (15/04-30/09) >+33473889699 (678m)Le Lac - Talloires (74) >+33450607316 (459m)Europa*** - St. Jorioz (74) (01/05-20/09) >+33450685101 -CCA(456m)International du Lac*** - St. Jorioz (74) (01/05-20/09) >+33450686793 -CCA(459m)Indigo Oleron Les Pins - Saint Trojan Les Bains (17) >+33546760239 (10m)Municipal La Giroflee - Bourcefranc Le Chapus (17) >+33546850643 (2m)Beausejour - La Balme Les Grottes (38) >+33474906747 (199m)Le Paradis - Mazieres (16) [<51] >+33643638477 (189m)Municipal du Chateau - Taillebourg (17) [<51] >+33546917120 (9m)Les Pres de l'Arly - Praz sur Arly (74) >+33610440233 (1016m)A la ferme Chermet - Ancy (69) [<51] >+33474058448 (504m)Chantalouette - Praz sur Arly (74) [<51] >+33450219025 (1013m)l'Univers du Lac* - St. Jorioz (01/06-30/09) >+33450689825 (447m)Le Relais De L'Etang - Thors (17) >+33546582681 (32m)Aire naturelle de Allard - Megeve (74) [<51] >+33450211688 (1038m)Aire naturelle de Pateau Liliane - Megeve (74) [<51] >+33609885469 (1036m)Municipal Le Preguda** - Bromont Lamothe [<51] (01/04-30/09) >+33473889860 (767m)Aire naturelle de Mathieu - Saint Georges De Baroille (42) [<51] (351m)Gai Sejour - Megeve (74) [<51] >+33450212258 (1028m)Le Solitaire du Lac*** - St. Jorioz (74) (05/04-20/09) >+33450685930 -CCA-BD_FR-K.096(451m)Le Madrid*** - Rumilly (74) (01/04-25/10) >+33450011257 -CCpg282-CCA(354m)Municipal** - La Goutelle [<51] (01/01-31/12) >+33473877266 (766m)Devezeau - Saint Angeau (16) [<51] >+33545392129 (84m)La ferme La Garenne - Bromont Lamothe (63) [<51] >+33473889862 (778m)Le Panoramic*** - Sevrier (74) (01/05-30/09) >+33450524309 -CCA-BD_FR-K.094(528m)Les Cerisiers - Saint Romain de Popey (69) >+33474058048 (403m)l'Aloua** - Sevrier (74) (01/05-20/09) >+33450526006 -CCA(453m)Bel Air*** - Saint Ours [<51] (01/05-30/09) >+33473887214 (776m)l'Horizon - Talloires (74) >+33450607871 (555m)Le Douvet - Suris (16) [<51] >+33545718939 (235m)Les Rives du Lac*** - Sevrier (01/04-30/09) >+33450524014 -CCpg283(449m)Saumont - Ruffieux (73) [<51] >+33479542626 (239m)La Bistandille - Siecq (17) [<51] >+33642238203 (81m)l'Isle de la Serre - Porcieu Amblagnieu (38) >+33474366761 (199m)Du Petit Bonheur - Crazannes (17) [<51] >+33664747110 (8m)Aire naturelle - Saint Marc a Loubaud [<51] >+33555660932 (679m)Le Colombier - Culoz (1) >+33479871900 -CCA(235m)Au Coeur du Lac*** - Sevrier (74) (01/04-30/09) >+33450524645 -CCA(452m)Municipal La Giraudiere - Le Grand Village Plage (17) >+33546475225 (7m)Les Trappes* - Menthon St. Bernard [<51] (01/07-31/08) >+33450602204 (510m)La Blanchie - Suris (16) [<51] >+33612156603 (229m)Rural La Vidome - Montagny les Lanches (74) [<51] >+33450466131 (565m)A la ferme le Pre Ombrage - Montagny les Lanches (74) [<51] >+33450467131 (626m)Municipal Des Pins - Le Grand Village Plage (17) (01/04-30/09) >+33546475013 -CCpg123-CCA(8m)Le Clos Don Juan** - Menthon St. Bernard (01/06-31/08) >+33450601866 (493m)Municipal Le Grand Pre - Pontaumur (63) >+33473799007 (536m)Pont Astier*** - Orleat (15/03-31/10) >+33473536440 (286m)Les Chenauds - Saint Junien La Bregere (23) [<51] >+33555549187 (543m)Municipal d'Uzurat*** - Limoges (15/03-31/10) >+33555384943 (303m)Iloa** - Thiers (10/05-05/09) >+33473809235 (287m)Municipal Pierre et Sources** - Volvic (01/05-30/09) >+33473335016 (483m)Municipal - Saillat sur Vienne (87) >+33555034182 (177m)Les Domes de Miage*** -�Saint Gervais les Bains (74) (10/05-15/09) >+33450934596 -CCA(872m)Le Verger* - Sevrier (01/04-31/10) >+33450524133 (455m)Le Vaugrais - Artemare (1) [<51] (01/03-15/12) >+33479873734 -CCA(246m)Municipal - Chabanais (16) [<51] >+33545890399 (153m)l'Ile aux Loisirs - Saint Savinien (17) >+33546903511 (6m)Municipal Le Champion - Mansle (16) >+33545203141 (58m)Municipal Bujaras - Chaillac sur Vienne (87) >+33555021316 (220m)Aire naturelle La Demi Lune - Demi Quartier (74) [<51] >+33450589491 (1083m)Le Megevan - La Giettaz (74) [<51] >+33479329364 (1543m)Bornand** - Demi Quartier [<51] (05/06-31/08) >+33450930086 (1063m)La Plage** - Veyrier du Lac (05/05-10/09) >+33450601099 (453m)Le Clairet - Serrieres en Chautagne (73) [<51] >+33479637515 (246m)Municipal Chambery - Saint Brice sur Vienne (87) [<51] >+33555021813 (223m)Le Maine - Le Grand Village Plage (17) (01/02-15/11) >+33546754276 -CCA(4m)A la ferme des Soleils - Merinchal (23) [<51] >+33555672788 (728m)Oleron - Le Chateau d'Oleron (17) (01/04-30/09) >+33546476182 -CCA(4m)Municipal Du Lavoir - Jure (42) [<51] >+33477625524 (539m)Les Intages - Combloux (74) [<51] >+33450586132 (1172m)Municipal Du Genevray - Thezillieu (1) >+33474375648 (840m)Les Chenes Verts - Dolus d'Oleron (17) [<51] >+33546753288 (12m)Aire naturelle Municipale - Luxe (16) [<51] (54m)Au Pigeonnier - Le Chateau d'Oleron (17) >+33546476220 (7m)Le Trejeux - Thones (74) >+33450020690 (618m)Contereix - Le Chatenet en Dognon (87) [<51] >+33555571112 (378m)La Riviere - Exideuil (16) [<51] (01/01-31/12) >+33661484767 (150m)Les Remparts - Le Chateau d'Oleron (17) >+33546476193 (5m)La Ferme des Ferrieres - Alex (74) >+33450028709 (572m)Municipal Le Belvedere*** - Annecy (01/04-10/10) >+33450454830 (540m)Rochemaux - Miremont (63) [<51] >+33473696430 (626m)Bellevue* - Les Houches (15/06-15/09) >+33450544230 (973m)Le Lachat - Thones (74) >+33450029665 (649m)Le Fief Melin - Le Chateau d'Oleron (17) (01/05-30/09) >+33546476085 -CCA(6m)Municipal du Martinet - Saint Claud (16) [<51] >+33384450040 (157m)La Ferme du Mont-Blanc - Combloux (74) [<51] >+33450581416 (943m)Les Graviers** - Enval (63) >+33473644700 (417m)Municipal De la Glane- Saint Junien (87) >+33555023486 (228m)Moulin de l'Angle - Trizay (17) [<51] >+33546833356 (2m)Le Grand Champ* - Chamonix Mont Blanc (01/05-15/10) >+33450530483 (1026m)Municipal - Miremont (63) [<51] >+33473799252 (518m)La ferme La Bouesse - Saint Jacques d'Ambur (63) [<51] >+33473799264 (635m)L'Ocean - Dolus d'Oleron (17) >+33546753170 (2m)Les Verneys** - Chamonix Mont Blanc (01/06-30/09) >+33450531584 (1030m)Municipal - Cremeaux (42) [<51] >+33477625067 (642m)La Perroche Plage - Saint Pierre d'Oleron (17) >+33546753733 -CCA(4m)Les Deux Glaciers*** - Chamonix Mont Blanc (01/01-31/12) >+33450531584 (1024m)Les Cimes** - Chamonix Mont Blanc (01/06-30/09) >+33965281198 (1020m)Les Charmilles - Vallieres (74) (01/04-31/10) >+33450621060 (336m)Mun. Les Chanterelles*** - St. Remy s/Durolle (01/05-15/09) >+33473943171 -CCpg337-CCA(695m)Les Flots - Saint Pierre d'Oleron (17) >+33546852631 (2m)l'Atlantique - Saint Pierre d'Oleron (17) >+33546753644 (3m)La Brande -�Le Chateau d'Oleron (17) (05/04-11/11) >+33546476237 -CCA(3m)Les Marmottes*** - Chamonix Mont Blanc (01/06-30/09) >+33450536124 (1002m)Le Montet - Dolus d'Oleron (17) >+33546756154 (5m)Les Ecureuils** - Chamonix Mont Blanc (15/04-30/09) >+33450538311 (1003m)Municipal De la Croze** - Chatelguyon (01/04-31/10) >+33473860827 (448m)Municipal De Champagne - Champagne en Valromey (1) [<51] >+33479876170 (539m)Le Savoy** - Annecy le Vieux (74) [<51] (01/05-30/09) >+33610612755 (447m)Le Colovry** - Annecy le Vieux [<51] (01/06-15/09) >+33450231329 (447m)Le Plan du Fernuy - La Clusaz (74) >+33450024475 (1179m)Municipal le Magnerit- Aunac (16) [<51] (15/06-15/09) >+33545222438 (66m)Rural de Christiane David - Vaulx (74) [<51] >+33450605529 (452m)Le Pre d'Avril - Annecy le Vieux (74) [<51] >+33450236446 (453m)l'Ecluse** - Parcieux (01/04-30/09) >+33478980632 (168m)Arpheuilles*** - St. Paul de Vezelin [<51] (15/04-30/09) >+33477634343 -CCA(334m)Clair Riviere** - Villieu Loyes Mollon (01/04-15/10) >+33474619300 (218m)Le Betoux - Domancy (74) [<51] >+33450584458 (550m)Les Molliasses** - Chamonix Mont Blanc [<51] (15/06-30/09) >+33450531681 (1053m)L'Ostrea - Dolus d'Oleron (17) (01/04-30/09) >+33546476236 -CCA(4m)Aire Naturelle du Masvodier - Valliere (23) [<51] >+33555660033 (590m)Le Heron - Dolus d'Oleron (17) >+33546754961 (3m)Les Floralies - Dolus d'Oleron (17) >+33546753075 (2m)Municipal Le Verdille** - St. Just en Chevalet [<51] (15/04-15/10) >+33477650297 (607m)Ile des Barrats*** - Chamonix Mont Blanc (15/05-25/09) >+33450535144 (1030m)Ranch des Volcans - Chatelguyon (63) (15/04-30/09) >+33473860247 -CCA(400m)Municipal La Mothe - Merinchal (23) [<51] >+33555672556 (697m)Aire naturelle le Perron - Cordon (74) [<51] >+33450580788 (953m)La Plage - Miremont (63) >+33473799806 (524m)De Mars - Cordelle (42) [<51] (01/04-15/10) >+33477649442 -CCpg274(366m)Aire Naturelle du Chesnay - Domancy (74) [<51] (01/07-31/08) >+33450583476 (559m)La Cailletiere - Dolus d'Oleron (17) (01/04-30/09) >+33546753633 -CCA(6m)Aire naturelle Lepigny - Domancy (74) [<51] >+33450584458 (553m)Le Treuil Foucaud - Saint Pierre d'Oleron (17) >+33546470892 (5m)Les 3 Masses - Saint Pierre d'Oleron (17) >+33546472396 (3m)Municipal Du Soleil Levant - Saint Martin Terressus (87) [<51] >+33555398378 (284m)L'Oree Des Bois - Saint Pierre d'Oleron (17) >+33546754288 (3m)Les Cercelles - Saint Pierre d'Oleron (17) >+33546471924 (4m)Les Combes - Felletin (23) [<51] (01/03-30/11) >+33555667729 (523m)Le Colombier* - Loubeyrat [<51] (01/04-15/10) >+33473866694 (685m)Les Grissotieres - Dolus d'Oleron (17) [<51] >+33546756713 (3m)Aire naturelle Lou Terriolets - Cordon (74) [<51] >+33450580735 (844m)Les Pins - Saint Pierre d'Oleron (17) >+33546471132 (6m)Le Sous Bois - Saint Pierre d'Oleron (17) (01/04-31/10) >+33546472246 -CCA(6m)Municipal La Fauche Prere - Saint Pierre d'Oleron (17) >+33546471053 (9m)Mont-Blanc Plage** - Sallanches (01/06-15/09) >+33450581428 (549m)Les Iles - Passy (74) (01/05-05/09) >+33499572121 -CCpg285(546m)Le Cret - Saint Jean de Sixt (74) [<51] >+33450023889 (1003m)A la ferme Le Chapi - Saint Laurent d'Oingt (69) [<51] >+33675312972 (291m)l'Ecureuil *** - Sallanches (01/04-31/10) >+33450470924 (544m)La ferme Au Lac Boise - Vendranges (42) [<51] >+33477649212 (483m)La Plaine St-Jean** - Les Houches [<51] (15/05-10/09) >+33450472187 (813m)Municipal Le Rayonnement - Rochefort (17) >+33546826770 (3m)La ferme Le Petit Cheval - Vendranges (42) [<51] >+33477649096 (494m)l'Aubier - Saint Pierre d'Oleron (17) [<51] >+33546751631 (8m)Chateau de Leychoisier**** - Bonnac la Cote (87) (15/04-20/09) >+33555399343 -CCA(384m)La Forge - Le Gicq (17) [<51] (25/05-15/09) >+33546324842 (65m)l'Abri Cotier - Saint Nazaire sur Charente (17) >+33546848165 (5m)Relais de la Vallee Blanche** - Sallanches (01/01-31/12) >+33450585959 (538m)La Mer de Glace*** - Chamonix Mont Blanc (25/04-30/09) >+33450534403 (1066m)Municipal - Fourneaux (42) [<51] >+33477647059 (501m)Municipal De Comps les Fades - Les Ancizes Comps (63) >+33473868164 (698m)Kanopee - Trevoux (1) (01/04-30/09) >+33474001416 -CCA(171m)Municipal - Saint Georges de Mons (63) [<51] >+33473867622 (739m)L'Escale -�Grand Bornand (74) (27/05-28/09-19/12-06/04) >+33450022069 -CCA(910m)Le Clos Du Pin - Le Grand Bornand (74) >+33450022761 (955m)Les Portes du Beaujolais**** -�Anse (69) (01/03-31/10) >+33474671287 -CCpg276-CCA(172m)Municipal Pont du Dognon - Saint Laurent les Eglises (87) >+33555565725 (307m)Lamaziere - Saint Priest des Champs (63) [<51] >+33661714199 (646m)Rural de Rousselot Claude - Saint Pierre d'Oleron (17) [<51] >+33546470958 (4m)Municipal La Croix Blanche - Aubusson (23) >+33555661800 (443m)A la ferme Les Quatre Saisons - Soubrebost (23) [<51] >+33555642335 (582m)Le Suroit - Saint Georges d'Oleron (17) (01/04-30/09) >+33546470725 -CCA(4m)Municipal De La Garenne - Port Des Barques (17) >+33608570875 -CCA(2m)Municipal Val de Boutonne*** - St.Jean d'Angely (17) (01/04-30/09) >+33546322616 -CCA(9m)Le Bateau - Rochefort (17) >+33546994100 (1m)Le Pre Long - Saint Pierre d'Oleron (17) >+33546750530 (2m)International - Seyssel (1) [<51] >+33450592847 (318m)Aire naturelle de Plaine Joux - Passy (74) [<51] >+33450938051 (1349m)L'Ermitage - Saint Rambert En Bugey (1) [<51] >+33474363297 (298m)Les Gros Joncs - Saint Georges d'Oleron (17) (01/01-31/12) >+33546765229 -CCA(5m)Municipal Du Pre Commun - Chaley (1) [<51] >+33687455245 (440m)Les Coquettes - Saint Georges d'Oleron (17) >+33546765285 (5m)Ile Madame - Port Des Barques (17) >+33546845620 (5m)Les Sables Vignier Plage - Saint Georges d'Oleron (17) >+33546765231 (9m)St Hubert - Saint Georges d'Oleron (17) >+33546767965 (4m)La Ferme Le Fournet - Saint Laurent de Ceris (16) [<51] >+33545317828 (164m)Les Grosses Pierres - Saint Georges d'Oleron (17) >+33546765219 (4m)Municipal De la Dore - Puy Guillaume (63) [<51] >+33473947851 (273m)Le Paradou - Saint Priest la Prugne (42) [<51] >+33477629405 -CCA(692m)Le Nant Matraz - Seyssel (74) [<51] >+33450590368 (259m)Moulin du Pommier- Saulgond (16) [<51] >+33545313302 (190m)Municipal La Chassagne - Bourganeuf (23) [<51] >+33555640761 (393m)Municipal Moulin De La Cour - Saint Maurice Des Lions (16) >+33545855599 (164m)La Maurie - Saint Georges d'Oleron (17) >+33671684801 (7m)Domaine D'Oleron - Saint Georges d'Oleron (17) (05/04-20/09) >+33546765497 -CCA(8m)Signol - Saint Georges d'Oleron (17) (03/04-20/09) >+33546470122 -CCpg122(6m)Les 4 Vents - Saint Georges d'Oleron (17) >+33546766547 (8m)Aire naturelle Vieille Ferme - La Balme de Sillingy (74) [<51] >+33450688405 (575m)Oleron Loisirs- Saint Georges d'Oleron (17) >+33546765020 (6m)l'Anse des Pins - Saint Georges d'Oleron (17) >+33546765597 (14m)Les Sablons - Vergeroux (17) >+33546997258 (7m)Les 12 Cols - Hauteville Lompnes (1) (21/12-15/10) >+33437865587 -CCA(778m)Verebleu - Saint Georges d'Oleron (17) >+33546765770 (8m)Municipal de Jonas* - Ambazac (01/06-15/09) >+33555566025 (382m)Municipal - Songieu (1) [<51] >+33479877138 (720m)Beaujolais*** - Villefranche s/Saone (69) (15/05-15/09) >+33474653348 -CCA(172m)Municipal Les Aberreaux - Hauteville Lompnes (1) [<51] >+33474353673 (779m)Le Glacier d'Argentieres** - Chamonix Mont Blanc [<51] (15/05-30/09) >+33450541736 (1229m)La Caille** - La Balme de Sillingy [<51] (01/05-30/09) >+33450688521 (523m)Municipal Les Saumonards - Saint Georges d'Oleron (17) (01/04-31/10) >+33546472320 -CCA(10m)Municipal L'Esperance - Fouras (17) >+33546842418 (3m)Aire naturelle La Bergerie - La Balme de Sillingy (74) [<51] (01/07-31/08) >+33450687305 (520m)Municipal - La Guillermie (3) [<51] >+33470411062 (737m)Municipal Les Tilleuls - Saint Hilaire Le Chateau (23) [<51] >+33555645605 (453m)A la ferme Les Combes d'Usillon - Thorens Glieres (74) [<51] >+33450222896 (662m)Aire naturelle l'Oree du Bois - Charensat (63) [<51] >+33473522112 (702m)Domaine La Bourbonnaise - Laprugne (3) [<51] >+33470593880 (695m)Le Large - Villars Les Dombes (1) >+33474981566 (280m)La Gautrelle - Saint Georges d'Oleron (17) (30/03-01/10) >+33546472157 (8m)l'Oree Du Lac - Villerest (42) [<51] >+33477696088 (321m)Des Charmilles - Fouras (17) >+33546840005 (14m)Les Payolles - Saint Georges d'Oleron (17) >+33546766333 (4m)Le Pre Vert - Saint Laurent de la Pree (17) (01/06-30/09) >+33546848940 (9m)Municipal du Bois de la Dame*** - Ars sur Formans (01/04-30/09) >+33474007723 (238m)Le Cerisier** - Amberieux en Dombes (01/04-30/09) >+33474008340 (299m)A la ferme de Bellaton - Chalamont (1) [<51] >+33474617085 (284m)Aire naturelle Municipale - Cieux (87) [<51] >+33555038876 (303m)La Campiere - Saint Georges d'Oleron (17) (13/04-29/09) >+33546767225 -CCA(3m)Municipal Le Cadoret - Fouras (17) >+33546821919 (6m)Pierre Semard* - Chamonix Mont Blanc [<51] (01/06-15/09) >+33450540029 (1353m)Municipal Du Val De L'Argentor - Nanteuil en Vallee (16) [<51] >+33545318267 (98m)Le Nid du Parc - Villars Les Dombes (1) (17/04-31/10) >+33474980021 -CCpg278-CCA(273m)Municipal - Chatelus Le Marcheix (23) [<51] >+33555643009 (407m)La Fumee - Fouras (17) >+33546842677 (3m)Moulin Dollay**** - Groisy [<51] (01/05-30/09) >+33450680031 (550m)Les Oliviers - Saint Denis d'Oleron (17) >+33546479342 (4m)l'Escapade** - Priay (10/03-30/09) >+33474354408 (232m)l'Etang de la Valette - Puy Malsignat (23) [<51] >+33555661729 (592m)Chez Langin*** - Choisy [<51] (15/04-30/09) >+33450774165 (706m)Municipal Les Marronniers** - Petit Bornand-les-Glieres [<51] (15/06-15/09) >+33450035474 (668m)Municipal Les Haches - Nantiat (87) [<51] >+33555534243 (279m)Les Seulieres - Saint Denis d'Oleron (17) (01/04-31/10) >+33546479051 -CCA(3m)Les Roussilles** - St. Sylvestre [<51] (01/04-31/10) >+33555713254 -BD_FR-I.083(457m)A la ferme Chassagne - Villefagnan (16) [<51] >+33545316147 (120m)Le Fort De La Rade (pas de voitures) - �le d`Aix (17) [<51] >+33546842828 (4m)Le Chamaloup** - Contamine Sarzin [<51] (01/05-15/09) >+33450778828 (359m)A la ferme Moulin des Jarasses - Auzances (23) [<51] >+33648445275 (562m)Le Breuil - La Bree les Bains (17) >+33629791465 (5m)Le Lac des Sapins - Cublize (69) (01/05-28/09) >+33474895283 -CCpg275-CCA(450m)Municipal De Montimbert** - Compreignac [<51] (01/06-15/09) >+33555710449 (406m)Le Rejallant - Condac (16) (01/01-31/12) >+33545290844 -CCA(98m)En Campagne - Saint Christophe (16) [<51] >+33545316757 (251m)Les Huttes - Saint Denis d'Oleron (17) >+33546752169 (4m)Nantizel - Thorens Glieres (74) [<51] >+33450224342 (862m)Municipal l'Etang Des Rosees - Genouille (17) [<51] >+33546277213 (11m)Celestin* - Musieges [<51] (01/01-31/12) >+33450447789 (331m)Municipal Les Favres - Cublize (69) >+33474895354 (451m)Municipal Le Planginot - La Bree les Bains (17) >+33546478218 (3m)Municipal Les Ribieres - Confolens (16) (01/05-15/09) >+33545853527 (136m)Pertuis D'Antioche - La Bree les Bains (17) >+33546479200 (3m)Aire naturelle Du Four - Chaleins [<51] (15/04-15/10) >+33474678256 (235m)La Perle - Fourneaux-Saint Medard La Rochette (23) [<51] (01/04-30/09) >+33555830125 -CCA(417m)MunicipalLe Galizan - Ferrieres sur Sichon (3) [<51] >+33470411010 (556m)Municipal Des Roches - Saint Dizier Leyrenne (23) [<51] >+33555644928 (409m)Municipal Le vieux Moulin -Champdor (1) [<51] >+33474360179 (821m)Municipal Sabatin - Thizy (69) [<51] >+33474640529 (589m)Les Montets - Vallorcine (74) [<51] >+33450546045 (1304m)Cap Soleil - Saint Denis d'Oleron (17) (12/04-28/09) >+33546478303 (3m)Les Filloux - Saint Dizier Leyrenne (23) [<51] >+33555648118 (412m)Municipal Les Pres du Dimanche - Chateauneuf les Bains (63) [<51] >+33473864150 (394m)Le Moulin - Saint Denis d'Oleron (17) >+33546479052 (8m)Municipal Le Got - Chateauneuf les Bains (63) [<51] >+33473866785 (387m)Rural de Jacquemet Mireille - Corlier (1) [<51] >+33474385712 (779m)La Coccinelle - Blot l'Eglise (63) [<51] (01/03-31/10) >+33628580575 -CCA(655m)Santrop*** - Razes [<51] (01/05-30/09) >+33555710808 (376m)La Cabane des Frenes - Yves (17) [<51] (01/04-30/09) >+33546564131 (1m)Les Lauriers - Saint Denis d'Oleron (17) >+33546479153 (5m)La Naute - Champagnat (23) [<51] >+33555676454 (521m)Municipal l'Etang Philippe - Saint Gervais d'Auvergne (63) [<51] >+33473857484 (684m)Les Beaupins - Saint Denis d'Oleron (17) >+33546478574 (9m)Municipal Saint Denis d'Oleron - Saint Denis d'Oleron (17) >+33546478562 (7m)Le Phare Ouest - Saint Denis d'Oleron (17) >+33546479000 (8m)Air naturelle Du Burdel - Saint Vincent de Reins (69) [<51] >+33474640778 (678m)La Chassiron - Saint Denis d'Oleron (17) >+33546768056 (9m)A la ferme Le Petit Mas d'ile - Saint Germain de Confolens (16) [<51] >+33545891433 (166m)Les Vergnes - Auzances (23) [<51] >+33555671746 (527m)Le Lizot - Saint Mande sur Bredoire (17) [<51] >+33546586995 (105m)l'Oiselon*** - Pont d'Ain (15/03-10/10) >+33474390523 (239m)La ferme Bossan - Blace (69) [<51] >+33474675636 (259m)Combe et Replat - Meaux La Montagne (69) [<51] >+33474896095 (593m)Freaudour**** - Saint Pardoux (01/04-31/10) >+33555765722 -CCpg325-CCA(372m)La ferme l'Amitie - Saint Gervais d'Auvergne (63) [<51] >+33473857224 (697m)Municipal* - Messimy s/Saone [<51] (01/04-31/10) >+33474678077 (184m)Le Lyzeron - Lamure sur Azergues (69) >+33683691345 (381m)Auberge Les Myrtilles - Saint Nicolas Des Biefs (3) [<51] >+33470564003 (1007m)Municipal La Niziere - Saint Nizier Le Desert (1) [<51] >+33474303516 (286m)Port Punay - Chatelaillon Plage (17) (19/04-27/09) >+33546560153 -CCA(5m)Ambiance de Vacances - Saint Nicolas Des Biefs (3) [<51] >+33470586966 (1006m)Aire naturelle de Les Garennes - Ballon (17) [<51] >+33683175486 (6m)Aire naturelle de Thete Simone - Sapeins [<51] (01/04-30/09) >+33474678285 (246m)Fonclaire - Blond (87) [<51] >+33555608826 (282m)La Chaize - Gouttieres (63) [<51] >+33473525614 (659m)Aire naturelle Municipale la Bregirole - Saint Maurice Pres Pionsat (63) [<51] >+33473521056 (583m)La Graviere - Saint Yorre (3) >+33627351426 (260m)A la ferme Maillofargueix - Bersac sur Rivalier (87) [<51] >+33555710314 (538m)Municipal - Le Mayet De Montagne (3) [<51] >+33470597052 (553m)Municipal Etang Cocagne - Sandrans (1) [<51] >+33474245268 (282m)La Corbaz** - Cluses [<51] (01/01-31/12) >+33450984403 (479m)Aire Naturelle Municipale Le Pre Marechat - Landrais (17) [<51] >+33546278729 (8m)Les Fayes - Gouttieres (63) [<51] >+33473858119 (657m)Les Plans - Saint Clement (3) >+33664695002 (479m)Aire naturelle Le Pontreau - Thaire (17) [<51] >+33546561064 (6m)Municipal Le Pelly - Sixt Fer a Cheval (74) [<51] >+33450341217 (922m)Municipal les Muriers*** - Montmerle s/Saone (01/04-15/10) >+33474693440 (172m)Rural La Renardiere - Taize Aizie (16) [<51] >+33545301581 (136m)Le Giffre - Samoens (74) (01/01-31/12) >+33450344192 -CCA(692m)Aux 7 Epis de Ble - Gouttieres (63) [<51] >+33473857797 (714m)La Roseraie - Brugheas (3) >+33470324333 (360m)Municipal - Ahun (23) [<51] >+33555624024 (474m)La Balade - Marsac (23) [<51] (01/05-31/10) >+31655100630 (419m)Municipal Du Bois des Tours** - Bonneville (01/07-05/09) >+33450970431 (463m)Central* - Bonneville (15/06-31/08) >+33450257701 (462m)La Chabanne - Chatel-Montagne (3) [<51] >+33650010880 (748m)Maison du Silence - Bonnefond (63) [<51] >+33473521220 (552m)Corsaire des 2 Plages - Chatelaillon Plage (17) (01/05-28/09) >+33546562753 -CCA(4m)La Dombes - St. Paul-de-Varax (1) (01/03-31/12) >+33474303232 -CCA(268m)L'Ocean - Chatelaillon Plage (17) (17/05-20/09) >+33546568797 -CCA(3m)L'Abbaye - Chatelaillon Plage (17) >+33611719267 (3m)Municipal Lac et Montagne - Verchaix (74) >+33450901012 (668m)Vallee de l'Ain*** - Poncin (01/04-30/09) >+33474372078 (256m)Les Genets La Croix du Sud - Saint Rirand (42) >+33477657615 (771m)Rural de Camp Municipal - Pleuville (16) [<51] >+33545896116 (165m)Municipal Le Mont Libre*** - Gannat (01/04-30/10) >+33470901216 (379m)Municipal - Le Vert (79) [<51] >+33549767445 (39m)Lac du Pont a l'Age - Lauriere (07/04-13/10) >+33555714262 (344m)Municipal Des Tarteaux - Menat (63) [<51] >+33473855247 (359m)Rural des Maronniers - Pleuville (16) [<51] >+33545310345 (157m)Le Terroir** - Presilly [<51] (01/05-30/09) >+33450044207 (640m)Municipal De L'Ardour - Marsac (23) [<51] >+33555626132 (390m)Municipal Les Thezieres** - Taninges (01/01-31/12) >+33450342559 (627m)Etang de Sagnat*** - Bessines s/Gartempe (15/06-15/09) >+33555761769 (341m)Municipal De La Geres - Surgeres (17) (01/03-16/11) >+33546077997 -CCA(24m)Municipal Le Gue Lavaud - La Chapelle Taillefert (23) [<51] >+33555521429 (486m)Aire de Chanterelle - Chatillon sur Chalaronne (1) [<51] >+33474552544 (257m)Municipal De La Foret - Chenerailles (23) >+33555623826 (535m)Les Chirats la Platere - Angoulins (17) >+33546569416 (5m)Municipal** - Chouvigny [<51] (Easter-15/09) >+33470909048 (330m)La Croix Saint Martin - Abrest (3) (10/04-10/10) >+33470326774 -CCA(255m)Le Moulin - Chef Boutonne (79) (01/01-31/12) >+33689600049 -CCA(77m)Municipal Le Moulin - Salles sur Mer (17) >+33623393787 (11m)Naturist - Les Pins - Ebreuil (3) [<51] >+33470907242 (399m)La Filature**** - Ebreuil (3) (15/04-30/09) >+33470907201 -CCA(309m)Aire naturelle Municipale - Chef Boutonne (79) [<51] >+33549298004 (84m)Municipal Les Nieres** - Ebreuil (01/06-30/09) >+33470907060 (307m)Le Pont de Saint Gal** - Saint Gal sur Sioule [<51] (01/05-15/09) >+33473974471 (337m)Les Isles - Bellerive sur Allier (3) >+33470322685 (255m)La Taillee - Aigrefeuille d'Aunis (17) >+33632954244 (18m)Beau Rivage - Bellerive sur Allier (3) (01/04-09/10) >+33470323622 -CCpg336-CCA(253m)La Croix Cognat - Chatel Montagne (3) [<51] >+33470593138 (487m)Le Puyberaud - Moutier d'Ahun (23) [<51] >+33555624620 (407m)Municipal Le Vieux Moulin - Chatillon sur Chalaronne (1) >+33474550479 (227m)Les Acacias - Bellerive sur Allier (3) (01/09-15/10) >+33470323622 (252m)Les Sables - Aytre (17) (01/04-15/10) >+33546454030 -CCA(3m)Aire les Biefs - Lapalisse (3) >+33477657894 (774m)La Colombiere**** -�Neydens (74) (01/04-10/11) >+33450351314 -CCA(562m)A la ferme Le Chebra - Charroux (86) [<51] >+33549876318 (165m)Municipal Le Parc - Availles Limouzine (86) [<51] >+33549485122 (124m)Moulin des Valignards - Ebreuil [<51] (01/04-31/10) >+33470564595 (305m)Municipal Puy d'Anche- Sauze Vaussais (79) >+33607643355 (145m)Municipal Les Rochettes - Bellac (87) >+33555681327 (237m)De l'�le Chambod - Hautecourt (1) >+33474372541 (283m)Municipal La Gartempe*** - Chateauponsac (01/01-31/12) >+33555765533 (252m)La Rache - Mieussy (74) [<51] >+33450430182 (618m)Municipal l'Oasis** - La Tour [<51] (01/06-30/09) >+33450356778 (600m)Le Blaise - Neuville Les Dames (1) [<51] >+33474556179 (246m)Aire Naturelle des Closets - Le Poizat (1) [<51] >+33474753119 (938m)Municipal La Prade - Servant (63) [<51] >+33473524248 (565m)Chounaz - Saint Jeoire (74) [<51] (31/03-10/11) >+33450358054 (609m)Municipal - Brioux sur Boutonne (79) [<51] >+33549075046 (56m)A la ferme Domaine de la Couture - Evaux Les Bains (23) [<51] (01/01-31/12) >+33555822918 (482m)Municipal La Cote Sauvage - Sainte Marie De Re (17) >+33546302174 (2m)Municipal La Garenne - Saint Christophe (17) [<51] >+33546355179 (18m)Municipal** - Monterolles sur Semme [<51] (01/01-31/12) >+33555760509 (309m)Municipal** - Journans [<51] (01/05-15/09) >+33474516445 (308m)A la ferme Hallmark - Tillou (79) [<51] (01/01-31/12) >+33549072028 (113m)Rural Les Renauds - Noailly (42) [<51] >+33477666294 (309m)Municipal Les Ilots - Pouilly sous Charlieu (42) [<51] >+33477608067 (257m)Municipal Les Echarmeaux - Poule les Echarmeaux (69) [<51] >+33474037058 (560m)Municipal Du Soleil - La Rochelle (17) >+33546444253 (4m)La Grange au Frene - Les Gets (74) [<51] >+33450758060 (1309m)Municipal La Poule d'Eau - Saint Eloy les Mines (63) >+33473854547 (488m)Le Signal** - Nantua (15/04-15/10) >+33474750209 (478m)De Chantegrele - Saint Pierre De Fursac (23) [<51] >+33555636569 (348m)Le Clos de Montamer - Sainte Marie La Noue (17) >+33660938124 (2m)Les Colettes - Lalizolle (3) [<51] >+33470904447 (556m)La Ferme de Montenon - Le Grand Bourg (23) [<51] >+33555813000 (400m)Aire Naturelle de la Motte Aubert - Saint Saturnin du Bois (17) [<51] >+33546518822 (23m)Les Acacias - Rivedoux Plage (17) >+33546098022 (4m)Municipal Des Aulnes - Civray (86) >+33549871724 (119m)Municipal de la Douze - Charlieu (42) >+33477690170 (271m)Le Platin - Rivedoux Plage (17) (05/04-21/09) >+33546098410 -CCA(4m)La Chassagne** - Sussat (3) [<51] (01/05-30/09) >+33470585466 (424m)Municipal La Boulere - Arfeuilles (3) [<51] >+33470555011 (436m)Les Tamaris - Rivedoux Plage (17) >+33546355731 (3m)Municipal De Port Neuf - La Rochelle (17) >+33546438120 (3m)Les Grenettes - Sainte Marie De Re (17) >+33546302247 (10m)Aire naturelle Municipale - Droux (87) [<51] >+33555685181 (239m)Municipal Le Courtille - Gueret (23) (01/04-31/10) >+33555819224 -CCA(472m)Villa Emmanuel - Monnetier Mornex (74) (01/06-30/09) >+33450365054 (560m)Terreneuve** - Marigny [<51] (15/06-10/09) >+33549260522 (76m)Municipal - Neuville Les Dames (1) [<51] >+33474556097 (244m)Les Ecureuils - Belmont de La Loirel (42) [<51] (01/06-01/10) >+33477637225 (483m)Hortus*** - Thoissey (15/04-15/09) >+33474040297 (170m)Les Chardons Bleus - Sainte Marie de Re (17) >+33546302375 (10m)Champ de la Sioule** - Jenzat (01/05-25/09) >+33470568635 (280m)Le Lac** - Port [<51] (01/05-31/10) >+33474760163 (478m)Antioche - Le Bois Plage en Re (17) >+33546092386 (7m)Interlude - Le Bois Plage en Re (17) >+33546091822 (4m)Municipal** Saint Amand Magnazeix (87) [<51] >+33555760087 (332m)Municipal Beausoleil - La Pacaudiere (42) [<51] >+33477641150 (332m)Municipal La Chalaronne*** - St. Didier s/Chalaronne (01/04-15/10) >+33474697337 (174m)Municipal Les Amis De La Plage - Le Bois Plage en Re (17) (04/04-28/09) >+33546092401 -CCA(4m)Le Beaulieu - Puilboreau (17) >+33546680438 -CCA(18m)Aire Naturelle Le Verger - Belle Croix (17) [<51] (20/06-31/08) >+33546349100 (21m)Les Varennes - Le Bois Plage en Re (17) (12/04-20/09) >+33546091543 -CCA(6m)Municipal Ouches de Budelle - Evaux Les Bains (23) >+33555655582 (449m)Trouve- La Crouzille (63) [<51] >+33952591370 (595m)Les Trois Lys - Lagord (17) >+33546676057 (17m)Les Barjottes - Le Bois Plage en Re (17) >+33546092257 (2m)Le Bel Air - La Flotte (17) >+33546096310 (9m)Du Suro�t - Le Bois Plage en Re (17) >+33546092360 (5m)La Bonne Etoile - Le Bois Plage en Re (17) >+33546091016 (10m)Les Peupliers Ile de Re -�La Flotte en Re (17) >+33546096235 (14m)Municipal - Propieres (69) [<51] >+33684792067 (562m)Municipal Beaujolais** - Saint Romain des Iles [<51] (01/05-30/09) >+33385355252 (171m)Les Pins - Le Bois Plage en Re (17) [<51] >+33546093545 (5m)Bellevue Bon Accueil - La Flotte (17) >+33546095087 (7m)Municipal La Pouge - Chambon sur Voueize (23) [<51] >+33555821321 (327m)Les Dunes - Le Bois Plage en Re (17) >+33546350028 (5m)La Grainetiere - La Flotte (17) (01/04-30/09) >+33546096886 -CCA(15m)La Grappe Fleurie**** - Fleurie (69) (15/04-15/10) >+33474698007 -CCA(272m)La Croix des Bois - Lalizolle (3) [<51] >+33470904155 (623m)Municipal Les Georennes - Champfromier (1) [<51] >+33450569240 (674m)Les Genets - Le Bois Plage en Re (17) >+33546092431 (4m)La Voueize - Gouzon (23) [<51] (01/04-30/09) >+33555817322 (374m)Les Maraises - Saint Martin de Re (17) >+33546096713 (15m)Les Salieres - Saint Martin de Re (17) >+33546092071 (0m)Municipal Le Parc - Lagord (17) >+33546676154 (0m)Les Gandins - Saint Germain de Salles (3) [<51] >+33470568075 (0m)Les Sucheres - Buxieres sous Montaigut (63) [<51] (12/04-30/09) >+33473859266 -CCA(0m)Municipal Le Remondeau - La Couarde sur Mer (17) >+33546298427 (0m)La Ferme du Logis - Magnac Laval (87) [<51] >+33555685723 (0m)Les Marmottes - Essert Romand (74) [<51] >+33612950048 (0m)Sans Parure (pas de caravanes) - Montaigut (63) [<51] >+33473520902 (0m)Au Petit Port de l'Houmeau - l'Houmeau (17) (01/04-30/09) >+33546509082 -CCA(5m)l'Alpage - Bogeve (74) [<51] >+33450361560 (1256m)Le Pre - Montriond (74) [<51] >+33450792476 (901m)Municipal Les Remparts - Saint Martin de Re (17) >+33546092196 (13m)Municipal Le Gue de La Riviere - Mauze sur le Mignon (79) >+33549263035 (9m)Municipal Les Feuilles - Chauffailles (71) >+33385264812 (395m)A la ferme Vilvert - Mouterre sur Blourde (86) [<51] >+33549488948 (193m)Le Puma - La Couarde sur Mer (17) >+33546298568 (6m)Essi - Ars en Re (17) >+33546294473 (4m)Le Bois Henri IV - La Couarde sur Mer (17) >+33546298701 (6m)Municipal du Chateau - Benon (17) [<51] >+33546016148 (21m)Du Soleil - Ars en Re (17) >+33546294062 (2m)La Chassagne - Ronnet (3) [<51] >+33470510807 (479m)L'Ocean -�La Couarde sur Mer (17) (11/04-27/09) >+33546298770 -CCpg117(4m)La Tour Des Prises - Couarde sur Mer (17) (05/04-28/09) >+33546298482 -CCA(3m)Le Paradis - Saint Pierre Laval (42) [<51] >+33477640080 (442m)Municipal Le Pontillard - Bellenaves (3) [<51] >+33470583975 (338m)Chateau la Perche - Montaigut (63) [<51] >+33473520835 (616m)Rural de Marchand Henri - Vonnas (1) [<51] >+33474501508 (196m)Municipal De Challes**** - Bourg en Bresse (01/04-15/10) >+33474453721 (226m)Naturist - La Barriere - Durmignat (63) [<51] >+31650978045 (489m)Municipal La Combe a l'Eau - Ars en Re (17) >+33546294642 (5m)Le Cormoran - Ars en Re (17) >+33546294604 (4m)Municipal - Le Dorat (87) [<51] >+33555607220 (204m)Municipal Le Valserine - Chezery Forens (1) >+33677940456 (576m)Les Dunes - Ars en Re (17) >+33546294141 (1m)Municipal La Valette - Saint Vaury (23) [<51] >+33555802982 (484m)A la ferme Les Marchands - Chezelle (3) [<51] >+33470563271 (305m)Municipal Les Marins - Lapeyrouse (63) (11/04-27/09) >+33473520273 -CCpg335(495m)Municipal Le Renom*** - Vonnas (01/04-30/09) >+33474500275 -CCpg279-CCA(187m)Municipal - Mazirat (3) [<51] >+33470517153 (408m)Municipal La Brande Gasille - Budeliere (23) [<51] >+33555828198 (419m)Municipal - Simandre sur Suran (1) [<51] >+33474306336 (307m)Municipal La Cote Sauvage - Saint Clement Des Baleines (17) (02/05-20/09) >+33546302174 -CCpg116(1m)Aire naturelle Municipale - Dompierre les Eglises (87) [<51] >+33555685378 (303m)Atelier Rich- Lapeyrouse (63) [<51] >+33473520825 (530m)Les Ilates - Loix (17) (05/04-28/09) >+33546290543 -CCA(4m)Le Solerey - Saint Jean d'Aulps (74) [<51] >+33450796469 (806m)Municipal - Louroux De Bouble (3) [<51] >+33470909016 (503m)A la ferme Les Chanoriers - Jullie (71) [<51] >+33675375673 (276m)Municipal La Fontaine De Villiers - Melle (79) [<51] >+33549291804 (108m)Municipal La Croix de l'Hozanne - Bussiere Poitevine (87) [<51] >+33555600817 (226m)Municipal Le Paradis - Chantelle (3) [<51] (01/05-15/10) >+33470566105 (323m)La Semnadisse - Rimondeix (23) [<51] >+33555808609 (396m)Les Baleines - Saint Clement Des Baleines (17) (22/04-20/09) >+33546294076 -CCA(0m)Les Tournesols de Beaulieu - Beaulieu (3) [<51] >+33470991056 (368m)Les Boueix - Fleurat (23) [<51] >+33555418681 (410m)Municipal Port d'Arciat*** - Creches s/Saone (15/05-15/09) >+33385371183 (172m)Municipal Du Lac de Chardes - l'Isle Jourdain (86) [<51] >+33549487246 (131m)La Plage - Saint Clement Des Baleines (17) >+33546294262 (0m)Municipal La Garenne - Courcon (17) [<51] >+33546016019 -CCA(22m)Municipal - Lapalisse (3) [<51] >+33470992631 (279m)Suisse Ocean*** - La Souterraine [<51] (01/01-31/12) >+33555633332 (398m)La Cazine - Noth (23) [<51] >+33555631312 (364m)La Providence - Les Portes en Re (17) >+33546295682 (2m)Les Echaloux - Bayet (3) [<51] >+33470453587 (287m)Municipal La Pree - Les Portes en Re (17) >+33546295104 (2m)Municipal De La Vergne - Bussiere Dunoise (23) [<51] >+33555816890 (396m)Du Lac**** - Cormoranche s/Saone (1) (01/05-30/09) >+33385239710 -CCA(171m)Rural de Gaborit - Nuaille d'Aunis (17) [<51] >+33546018298 (3m)Lazy Duck - Usson du Poitou (86) [<51] >+33549518377 (133m)Ferme Bon Repos - Viriat (01) [<51] >+33474258755 (242m)Municipal Les Misottes - Esnandes (17) [<51] >+33677551913 (4m)Aire naturelle municipale Le Bassin - Artaix (71) [<51] >+33385250131 (262m)Municipal Du Mignon - La Greve sur Mignon (17) >+33546671477 (5m)Aire naturelle Municipale - Monestier (3) [<51] >+33470566191 (318m)Gorges de l'Oignin - Matafelon (1) (14/04-21/09) >+33474768097 -CCA(399m)Municipal Les Crots - Saint Jacques des Arrets (69) [<51] >+33699914488 (478m)Cornaton - Confrancon (1) [<51] (01/03-31/10) >+33474302563 (215m)The Orchard - Messe (79) [<51] >+33549293993 (143m)Municipal La Raza* - Meillonnas [<51] (01/01-31/12) >+33474423242 (252m)l'Oustalet - Chatel (74) (20/12-18/04-20/06-06/09) >+33450732197 (1115m)Municipal - Celles sur Belle (79) [<51] >+33676312276 (112m)Beauvais - Saint Hilaire la Treille (87) [<51] >+33555763814 (275m)La Plage de Pechadoire - Anzeme (23) [<51] >+33555512118 (314m)Municipal - Chavannes sur Suran (1) [<51] >+33474517223 (316m)La Motte aux Merles - Artaix (71) [<51] >+33385253767 (319m)Aire naturelle Municipale - Chateau Garnier (86) [<51] >+33549878011 (141m)Municipal Le Parc - Lezay (79) [<51] >+33549278000 (130m)Municipal Les Vernes - Thoirette (39) >+33474768071 (287m)La ferme Brenazet - Vernusse (3) [<51] >+33470076319 (398m)Municipal Du Moulin - Trades (69) [<51] (01/04-30/10) >+33666517078 (376m)Municipal Des Aulnes - Sommieres du Clain (86) [<51] (01/06-15/09) >+33549877014 (113m)Municipal - Moussac (86) [<51] >+33549487558 (89m)Le Pre - Abondance (74) [<51] >+33450730093 (929m)Garaloisirs Santa Anita - Servilly (3) [<51] >+33609991256 (304m)Municipal du Sevron*** - St. Etienne du Bois [<51] (01/03-25/10) >+33474305065 (223m)Le Lidon - Saint Hilaire la Palud (79) (12/04-20/09) >+33549353364 -CCpg118-CCA(4m)Rural De la Grosse Talle - Sepvret (79) [<51] >+33549073197 (167m)Aire Naturelle Le Grenouillat - Neris Les Bains (3) [<51] (01/05-31/11) >+33470031744 (391m)Aire naturelle de Robin - Neris Les Bains (3) [<51] (01/04-31/10) >+33614604033 (384m)Municipal Du Lac - Neris Les Bains (3) >+33470032470 (345m)Les Voisins - Montaigu le Blin (3) >+33470437399 (309m)Les Bruyeres - La Clayette (71) (18/04-30/09) >+33385280915 -CCA(382m)Chez le Pre - Trezelles (3) [<51] >+33671487743 (317m)Municipal Les Louilles - La Baume (74) (01/07-31/08) >+33648402817 (667m)l'Age - Le Bourg d'Hem (23) [<51] >+33555512118 (272m)Municipal de la Taillee - Arcais (79) >+33549353712 (5m)A la ferme la Dalue - Bellecombe (39) [<51] >+33384416903 (1248m)Naturist - Le Port - La Ronde (17) >+33626067237 (6m)Municipal Le Lambon - Celles sur Belle (79) >+33549328511 (132m)Municipal La Roussille - Chatelus Malvaleix (23) >+33555807031 (399m)Municipal Le Paluet - Matour (71) (26/04-30/09) >+33385597092 -CCA(418m)l'Ilot du Chail - Sansais (79) >+33549350033 (5m)Municipal La Grange du Pin *** - Treffort Cuisiat (01/04-01/10) >+33474513414 (248m)Municipal De L'Ile De La Ronde - Saint Pourcain sur Sioule (3) >+33470459194 (234m)A la Ferme du Noux - Vareilles (71) [<51] >+33385280978 (423m)Municipal De La Baignade - La Celle Dunoise (23) [<51] >+33555512118 (238m)Municipal Les Sillons - La Celle Dunoise (23) [<51] >+33555891077 (231m)Municipal - Taugon (17) [<51] >+33546097615 (4m)Les Peupliers - Couhe (86) (02/05-30/09) >+33549592116 -CCA(112m)Les Conches - Damvix (85) >+33251871706 -CCA(6m)Le Martin Pecheur - Magne (79) (01/05-27/09) >+33549357181 -CCpg119-CCA(6m)Municipal du Mondelet * - St.Sulpice les Feuilles [<51] (01/05-30/09) >+33555767332 (282m)La Venise Verte - Coulon (79) (01/04-31/10) >+33549359036 -CCA(3m)Municipal du Bois Dinot - Marans (17) >+33546011051 (4m)Municipal La Foret - Dun Le Palestel (23) [<51] >+33555890130 (361m)Municipal Du Renard - Queaux (86) >+33549484832 (81m)Chez Nous - Cheniers (23) [<51] >+33555627512 (338m)La Grande Ouche - Bert (3) [<51] >+33470996090 (321m)Municipal** - Voussac [<51] (01/06-30/09) >+33470423047 (458m)Municipal Plan d'eau - Trezelles (3) [<51] >+33648722834 (257m)Les Flots Blues - La Faute sur Mer (85) >+33251271111 (5m)Aire naturelle l'Oree des Bois - Sciez (74) [<51] >+33450727831 (463m)Le Mas - Premilhat (3) [<51] >+33470290397 (250m)La Riviere - Vix (85) [<51] >+33251006596 (4m)Municipal La Niquiere - Coulon (79) [<51] >+33549358119 (8m)Municipal de la Baie - l'Aiguillon sur Mer (85) >+33251564070 (3m)La Terrasse - Trezelles (3) [<51] >+33470557367 (254m)Le Relais du Pecheur - Le Mazeau (85) [<51] >+33251529114 (3m)Le Nant des Mules - Massongy (74) [<51] >+33450942124 (406m)Municipal*** - Macon (15/03-31/10) >+33385381622 (173m)Ferme Equestre - Malafretaz (1) [<51] >+33474308119 (194m)Lac de Mondon*** - Cromac (05/05-20/09) >+33555769334 (241m)Municipal La Cote de Lumiere - La Faute sur Mer (85) >+33251970616 (2m)Le Leman - Sciez (74) [<51] >+33450727251 (402m)Municipal Les Genets - Gex (1) >+33450428457 (581m)Le Petit Booth - l'Ile d'Elle (85) [<51] >+33251520067 (3m)Chateau de Montrouant -�Gibles (71) (31/05-12/09) >+33385845113 -CCpg343(398m)Municipal Sous le Moulin - Condes (39) >+33474758228 (306m)Intercommunal du Lac de St.Point Lamartine - Saint Point Lamartine (71) >+33385505231 (339m)Le Pre des Sables - l'Aiguillon sur Mer (85) >+33251271388 (2m)La Plaine Tonique**** - Montrevel-en-Bresse (1) (15/04-20/09) >+33474308052 -CCA(192m)A la ferme Petit Chaumeix - Le Poteau (23) [<51] >+33555650646 (340m)Brise du Leman - Sciez (74) >+33450725910 (375m)Municipal La Petite Cabane - Maille (85) [<51] >+33251870752 (3m)Le Grand R - La Faute sur Mer (85) >+33251564287 (0m)La Renouillere - Sciez (74) >+33450727339 (384m)Le Chatelet - Sciez (74) >+33450725260 (384m)Les Cyclamens - Chancia (1) >+33474758214 (311m)Le Grand Foc - Sciez (74) >+33450726270 (384m)Le Lac De Coiselet - Dortan (1) >+33474758634 (308m)Le Bel Air - l'Aiguillon sur Mer (85) (03/04-20/09) >+33251564405 -CCpg114(4m)Les Forges - Lussac les Eglises (87) >+33555600497 (194m)Relais du Leman - Douvaine (74) >+33450947111 (409m)Les Preveils Atlantique - La Tranche sur Mer (85) >+33251303052 (7m)Municipal Le Vieux Moulin - La Tranche sur Mer (85) >+33251274847 (12m)La Pinede - Excenevex (74) (15/04-15/09) >+33450728505 -CCpg287-CCA(378m)La Siesta - La Faute sur Mer (85) >+33251271675 (6m)Baie d'Aunis - La Tranche sur Mer (85) >+33251274736 (2m)Municipal de l'Essert - Vinzier (74) [<51] >+33450766119 (913m)Moulin de Piot - Cheniers (23) [<51] (01/04-31/10) >+33555628090 (271m)Sainte Anne - La Tranche sur Mer (85) >+33251304682 (3m)La Grande Vallee - La Tranche sur Mer (85) (01/04-30/09) >+33251301282 -CCA(4m)Naturist - Creuse Nature - Boussac (23) (05/04-31/10) >+33555651801 -CCA(359m)Le Jard - La Tranche sur Mer (85) (11/05-13/09) >+33251274379 -CCA(2m)Bel - La Tranche sur Mer (85) >+33251304739 (2m)La Dive - Saint Michel en l'Herm (85) >+33674682320 -CCA(3m)Le Cottage Fleuri - La Tranche sur Mer (85) >+33251303457 (5m)Les Mizottes - Saint Michel en l'Herm (85) >+33251302363 (4m)La Belle Henriette - La Tranche sur Mer (85) >+33251303351 (3m)La Cleroca - Grues (85) >+33251271992 (1m)La Corba - La Tranche sur Mer (85) >+33251303455 (3m)Aire naturelle Persac - Persac (86) [<51] >+33549484715 (105m)Le Lac - Anthy sur Leman (74) >+33450723658 (403m)Sainte Marie - Treteau (3) [<51] >+33470348271 (259m)Aire naturelle le Merval - Puyravault (85) [<51] >+33251286084 (1m)Municipal - Le Donjon (3) [<51] >+33470995025 (304m)Municipal - Treignat (3) [<51] >+33470070014 (406m)Le Morcy - Thonon les Bains (74) >+33682275150 (430m)l'Ecurie du Marais - Benet (85) [<51] >+33251529838 (4m)La ferme Basse Brenee - Saint Michel en l'Herm (85) [<51] >+33251302409 (1m)Le Grand Pre - La Tranche sur Mer (85) >+33251303575 (1m)Le Lac Noir - Thonon les Bains (74) >+33450260728 (462m)Aire naturelle Municipale - Genouillac (23) [<51] >+33555807425 (273m)Le Chant d'Oiseau - Excenevex (74) [<51] >+33549050141 (391m)Municipal - Saint Sauvant (86) [<51] >+33549597022 (141m)Municipal Du Fouilloux** - La Mothe St. Heray (15/06-15/09) >+33549050141 (79m)La Petite Valette - Sazeret (3) (01/05-30/09) >+33470076457 -BD_FR-J.045(485m)Bellevue - Excenevex (74) >+33450728367 (391m)Le Sable d'Or - La Tranche sur Mer (85) >+33611530884 (2m)Le Village des Meuniers - Dompierre les Ormes (71) (15/03-01/11) >+33385503660 -CCA(448m)Municipal Bouresse - Bouresse (86) [<51] >+33549427310 (121m)Le Villaja - La Tranche sur Mer (85) [<51] >+33251303760 (4m)Pacific - La Tranche sur Mer (85) >+33251300738 (6m)La Ferme La Charviere* - St. Priest en Murat [<51] (01/01-31/12) >+33470073824 (420m)Mathieu Le Leman II - Yvoire (74) >+33450728496 (400m)Mathieu Le Leman I - Yvoire (74) >+33450728431 (398m)Municipal Du Moulin Beau - Gouex (86) [<51] >+33549484614 (77m)Municipal De l'Autize - Maillezais (85) [<51] >+33251007079 (14m)La Prairie - Champanges (74) >+33450810623 (704m)Municipal Du Martinet - Saint Claude (39) (01/04-30/09) >+33384450040 -CCA(430m)Les Almadies - La Tranche sur Mer (85) (11/04-20/09) >+33251303694 -CCpg113(2m)Le Chateau de Poinsouze -�Boussac (23) (15/05-16/09) >+33555650221 -CCA(431m)Le Moulin Ecurades - Moutier-Malcard [<51] (01/01-31/12) >+31647097350 (295m)Indigo Le Fleutron - Divonne les Bains (1) (01/05-12/10) >+33450200195 -CCA(563m)Le Pre Bandaz - Saint Paul en Chablais (74) [<51] >+33450753942 (834m)Le Petit Chaumont - Saint Priest en Murat (3) [<51] >+33470074744 (310m)Municipal Le Moulin De Lyon - Huriel (3) >+33470286008 (294m)Municipal** - Deux Chaises [<51] (25/03-15/10) >+33470471233 (456m)La ferme Pont Grenouille - Vouille les Marais (85) [<51] >+33251525396 (2m)Municipal - Jaligny sur Besbre (3) >+33470347150 (244m)Municipal Du Palot - Fresselines (23) [<51] >+33555897046 (263m)Municipal - Champagne les Marais (85) >+33251567298 (3m)Le Tournesol - Chappes (3) [<51] >+33470029703 (374m)Les Ramiers - Longeville sur Mer (85) (01/04-30/09) >+33251333221 (10m)La Tublerie - Vouille les Marais (85) >+33251525208 (5m)Municipal aire naturelle La Garenne - Saint Sebastien (23) [<51] >+33555635039 (291m)Les Dunes - Longeville sur Mer (85) >+33251333293 (10m)Le Clos des Pins - Longeville sur Mer (85) >+33251903169 (13m)Municipal Fontbonne - Crozant (23) [<51] >+33555898012 (257m)Les Cypres - Lect (39) [<51] >+33384484018 (367m)Le Clos Cottet - Angles (85) >+33251289072 (3m)Municipal l'Ile Cariot - Chaille les Marais (85) [<51] (01/04-30/09) >+33251567527 -CCpg115-CCA(6m)Le Grand Pre - Publier (74) >+33450700045 (381m)Les Huttins - Publier (74) >+33450700309 (381m)Le Sous Bois - Longeville sur Mer (85) >+33251333690 (8m)Municipal - Triaize (85) >+33251561276 (1m)Le Port de Moricq - Angles (85) >+33251289521 (3m)Municipal - Lussac les Chateaux (86) [<51] >+33549480332 (75m)Municipal Saint Julien - Saint Julien (39) [<51] >+33384854237 (352m)Naturist - Du Soleil de Macon Laize - Laize (71) >+33385369950 (228m)Les Myosotis - Lugrin (74) >+33450760759 (464m)Saint Disdille - Thonon les Bains (74) (01/04-30/09) >+33450711411 -CCA(383m)l'Eglantier - La Cellette (23) [<51] >+33555807293 (369m)La Vieille Eglise - Lugrin (74) (12/04-11/10) >+33450760195 -CCpg286-CCA(440m)Municipal - Grues (85) (2m)La Courtine - Chatel De Neuvre (3) [<51] >+33624930135 (223m)Le Rys - Lugrin (74) >+33450760575 (440m)Le Petit Rocher - Longeville sur Mer (85) (12/04-21/09) >+33251204194 -CCA(9m)Aire naturelle Municipale - Saint Leon (3) [<51] >+33470421557 (419m)Zagarella - Longeville sur Mer (85) >+33251333060 (5m)l'Atlantique - Angles (85) (22/03-31/10) >+33251270319 (4m)Moncalm - Angles (85) >+33251975550 (4m)Le Troussepoil - Longeville sur Mer (85) >+33251975150 (4m)Municipal Le Panier Fleuri*** - St. Maixent l'Ecole (01/01-31/12) >+33549055321 (104m)La Forestiere - Longeville sur Mer (85) [<51] >+33251333090 (13m)La Pomme de Pin - Jard sur Mer (85) (01/04-27/09) >+33251334385 (10m)Le Bosquet - Jard sur Mer (85) (12/04-27/09) >+33251335657 (11m)Les Ecureuils - Jard sur Mer (85) >+33251334274 (11m)La Fraignaye - Saint Denis du Payre (85) (01/04-30/09) >+33612052470 (11m)La Ventouse - Jard sur Mer (85) (12/04-27/09) >+33251330672 (18m)Deneuvre - Chatel De Neuvre (3) (01/04-30/09) >+33470420451 -CCA(218m)Les Brunelles -�Longeville sur Mer (85) (11/04-20/09) >+33251335075 -CCpg112(13m)Jarny-Ocean - Longeville sur Mer (85) >+33251334221 (13m)Munucipal Le Pied Girard - Saint Vincent sur Jard (85) >+33251336511 (11m)Intercommunal* - Le Montet [<51] (15/05-15/09) >+33470471202 (448m)La Michenotiere - Longeville sur Mer (85) >+33251333885 (3m)La Bolee d'Air - Saint Vincent sur Jard (85) (05/04-20/09) >+33251330505 -CCA(11m)La Petite Montagne - Moirans en Montagne (39) (12/04-16/09) >+33384423498 (637m)Municipal De l'Allochon - Montmorillon (86) >+33549910233 (93m)l'Oceano d'Or - Jard sur Mer (85) (05/04-20/09) >+33251336508 -CCA(11m)Municipal Le Marais - Saint Benoist sur Mer (85) [<51] >+33251308456 (3m)Municipal du Coq - Mantenay Montlin (1) [<51] >+33474526691 (181m)Municipal De Fougeres - Saint Plantaire (36) >+33254472001 (205m)Municipal - Vivonne (86) [<51] >+33549432595 (90m)La Mouette Cendree - Saint Vincent sur Jard (85) >+33251335904 (13m)Naturist - Le Bois de la Pardiere - Chateau Larcher (86) >+33549435602 (116m)Municipal - Celle Levescault (86) [<51] >+33549435256 (96m)Les Baritaudieres - Le Langon (85) >+33251528184 (2m)Champ d' Ete - Pont de Vaux (01) >+33385239610 -CCA(173m)Municipal Saint Vital - Cluny (71) >+33385590834 (238m)Municipal Les Vieux Chenes - Chaillac (36) >+33254256139 (184m)Municipal Les Nugiras*** - Eguzon-Chantome (01/01-31/12) >+33254474522 (256m)Municipal Champ De Foire - Preveranges (18) [<51] >+33248564677 (421m)L'R Pur - Saint-Hilaire la Foret (85) [<51] >+33615215517 (15m)A la Ferme Le Bois de l'Espau - Tronget (3) [<51] >+33470473804 (426m)Le Raisin D'Or - Clesse (71) >+33385331399 (311m)Municipal De Vauchiron - Lusignan (86) >+33549433008 (118m)Les Dunes - Talmont Saint Hilaire (85) >+33680445800 (3m)Les Grottes** - Aze (01/04-30/09) >+33385333648 (251m)Municipal - Charolles (71) >+33385240490 (283m)Saint Hubert - Talmont Saint Hilaire (85) >+33251222230 (12m)Municipal Le Calme - Le Bernard (85) [<51] >+33251333069 (24m)l'Esperance - Talmont Saint Hilaire (85) >+33251222232 (13m)Municipal aire naturelle de L'Etang - Aigurande (36) [<51] >+33254063056 (396m)Veillon Plage - Talmont Saint Hilaire (85) >+33251222038 (13m)A la Ferme La Grisse - Le Givre (85) [<51] (01/01-31/12) >+33251308303 -CCA(9m)Les Ripettes - Chavannes sur Reyssouze (1) (01/04-30/09) >+33385306658 -CCA(212m)Le Domaine - Dienne (86) >+33549458763 (110m)La Garenne*** - Eguzon-Chantome (36) (11/03-18/10) >+33254474485 -CCA(261m)Aux Rives du Soleil*** - Pont de Vaux (1) (19/04-15/10) >+33385303365 -CCA-BD_FR-J.036(171m)Les Batardieres - Saint Hilaire la Foret (85) (01/07-31/08) >+33251333385 (21m)La Grand' Metairie - Saint Hilaire la Foret (85) (12/04-27/09) >+33251333238 -CCA(20m)Municipal - Civaux (86) >+33549484508 (72m)Les 3 Oiseaux - Premanon (39) >+33384607874 (1137m)Le Littoral - Talmont Saint Hilaire (85) (12/04-14/09) >+33251220464 -CCA(17m)Municipal Mepillat* - St. Nizier le Bouchoux (01/04-30/09) >+33474529724 -CCpg280(211m)A la ferme Les Busserolles - Buxieres les Mines (3) [<51] >+33634960903 (295m)Le Boucher - Buxieres les Mines (3) [<51] >+33646226743 (360m)La Cle des Champs - Lucon (85) [<51] >+33674879759 (1m)Naturist - Soleil du Bourbonnais - Buxiereres-Les-Mines (3) >+33470660304 (305m)Les Mancellieres - Avrille (85) >+33251903597 (17m)Le Chant-Hibou - Audes (3) [<51] >+33470067407 (269m)Le Mambre - Paray le Monial (71) (03/05-04/10) >+33385888920 -CCpg344-CCA-BD_FR-J.042(238m)La ferme Vallee de Lignac - Lignac (36) [<51] >+30254257530 (151m)Aire Naturelle Terre Ferme - Condal (71) [<51] >+33385766257 (215m)Municipal l'Ardiller - Saint Cyr en Talmondais (85) [<51] >+33251308282 (17m)Le Paradis - Talmont Saint Hilaire (85) >+33251222236 (33m)Loyada - Talmont Saint Hilaire (85) (01/04-15/10) >+33251212810 -CCA(33m)Municipal Le Pre aux Loups - La Trimouille (86) [<51] >+33549916014 (104m)Municipal Le Vieux Chene - Nalliers (85) [<51] >+33251309198 (4m)Trelachaume - Maisod (39) >+33384420326 (525m)Le Petit Moulin - Saint-Hilaire (3) [<51] (01/01-31/12) >+33963640943 (378m)Le Beauchene - Avrille (85) (01/04-10/10) >+33251223049 -CCA(33m)Sun Ocean - Talmont Saint Hilaire (85) (29/03-05/10) >+33251906124 -CCA(30m)Moulin de Chateaubrun - Cuzion (36) [<51] >+33254474640 (163m)A la Ferme Raguin - Saint Michel Le Cloucq (85) [<51] >+33251690700 (27m)Le Bel Air - Chateau d'Olonne (85) >+33251220967 (21m)Le Montcocu** - Baraize [<51] (01/06-30/09) >+33254253428 (162m)Municipal - Volesvres (71) [<51] >+33385814233 (271m)Le Petit Paris - Chateau d'Olonne (85) >+33251220444 -CCA(27m)La Dame Blanche - Valdivienne (86) [<51] >+33549563738 (86m)Les Pirons - Chateau d'Olonne (85) >+33251952675 (14m)Des Forges - Avrille (85) >+33251223885 (41m)Municipal Saint Pierre - Lugny (71) [<51] >+33385332196 (272m)Municipal Le Parc - Coulonges sur l'Autize (79) [<51] >+33672606323 (79m)Les Fosses Rouges - Chateau d'Olonne (85) (04/04-24/09) >+33251951795 -CCA(18m)Municipal La Chevrette - Digoin (71) (01/04-10/10) >+33385531149 -CCA(225m)La Tulipe Fioolet - Saint Bonnet de Joux (71) [<51] >+33385247863 (398m)Le Puits Rochais - Chateau d'Olonne (85) (19/04-30/09) >+33251210969 -CCA(25m)Pilorge - Fontenay le Comte (85) [<51] >+33608256912 (13m)Municipal - Loisia (39) [<51] >+33384445418 (377m)Le Baptaillard - Longchaumois (39) >+33384606234 (891m)Municipal de Clairval** - Cosne d'Allier [<51] (01/05-15/09) >+33470075169 (227m)Municipal Du Bois du Bouquet - Moutiers les Mauxfaits (85) (28/06-31/08) >+33251989641 (44m)National 6*** - Uchizy (71) (01/04-30/09) >+33385405390 -CCA(172m)Les Muriats - Vieure (3) [<51] >+33470072847 (261m)Municipal - Sainte Severe sur Indre (36) [<51] >+33254305028 (303m)Municipal Saint Hilaire - Saint Hilaire (3) [<51] >+33470665078 (313m)Les Roses - Les Sables d'Olonne (85) >+33251330505 (14m)Aire naturelle de Bois Pouvreau - Menigoute (79) [<51] >+33549691318 (161m)Pont des Bergers - Sanxay (86) >+33549530649 (121m)Louvarel*** -�Champagnat (71) (15/04-30/09) >+33385766271 -CCA(201m)Les Fruits du Passau - Chazemais (3) [<51] >+33470071285 (269m)Base De Loisirs De La Borde - Vieure (3) >+33470020446 (255m)Municipal Saint Pere - Le Champ Saint Pere (85) [<51] >+33251409178 (10m)Aire naturelle de Fort Michel - Saint Avaugourd des Landes (85) [<51] >+33251989496 (55m)La Chaumerette** - Gargilesse Dampierre (01/05-30/09) >+33254477344 (131m)La Ferme des Maziers - Le Bouchat (71) [<51] >+33385746714 (204m)Municipal Sidiailles - Sidiailles (18) [<51] >+33248566327 (326m)Municipal Le Vernay - Pierrefitte sur Loire (3) >+33470470249 (229m)Le Val d'Ete - Etival (39) [<51] >+33384448731 (814m)La Faz - Ecrille (39) (01/05-30/09) >+33384254027 -CCA(396m)A la ferme les Coqs en Pate - Poiroux (85) [<51] >+33251902030 (52m)Municipal l'Aumance* - Herisson (01/04-31/10) >+33470068045 (195m)l'Etang - Saint Avaugourd des Landes (85) [<51] >+33251989566 (52m)La Dune des Sables - Les Sables d'Olonne (85) >+33251330505 (15m)Aire naturelle La Grande Perrure - Mervent (85) [<51] >+33251002507 (91m)Municipal Les Bords de Besbre - Dompierre sur Besbre (3) >+33470345557 (217m)Municipal De la Clochette - Salornay sur Guye (71) [<51] >+33385599011 (208m)Municipal La Fontaine - Saint Vincent sur Graon (85) [<51] >+33251989089 (35m)l'Etang de la Fragnee - Verruyes (79) (15/04-15/10) >+33549632137 (182m)La Joletiere - Mervent (85) >+33251002687 (73m)De la Fraite - Clairvaux les Lacs (39) (01/05-31/10) >+33384258021 (441m)Surchauffant - La Tour du Meix (39) (01/05-15/09) >+33384254108 -CCA(458m)La Tuilerie de Chazelle - Cormatin (71) [<51] >+33385501955 (225m)Le Chene Tord - Mervent (85) >+33643177370 (84m)Le Moulin de la Salle - Olonne sur Mer (85) >+33251959910 (14m)Benoit - Saint Bonnet de Vieille Vigne (71) [<51] >+33385702773 (336m)Municipal Des Soupirs** - Vallon en Sully [<51] (15/06-15/09) >+33470065096 (172m)Les Vernelles - Saint Aubain le Monial [<51] (01/01-31/12) >+33470660903 (272m)Le Trianon - Olonne sur Mer (85) (11/04-20/09) >+33251236161 -CCpg110(30m)A la ferme Bon Merle - Vesdun (18) [<51] >+33661375018 (320m)Le Nid d'Ete - Olonne sur Mer (85) (01/04-30/09) >+33251953438 -CCA(2m)Municipal La Pree Mareuil - Mareuil sur Lay Dissais (85) >+33251972726 (6m)Les Ormeaux - Olonne sur Mer (85) (15/06-15/09) >+33251956598 (3m)Municipal Du Gue De Loire - Diou (3) [<51] (15/06-31/08) >+33604033292 (214m)La Jamoniere - Mervent (85) [<51] >+33251002629 (85m)La Vertonne - Grosbreuil (85) >+33251226574 (48m)A la ferme les Rousselieres - Olonne sur Mer (85) [<51] >+33686934379 (17m)Municipal Les Bergerolles - Vesdun (18) [<51] >+33248630307 (325m)La Bucle - Morbier (39) [<51] >+33384334855 (858m)Naturist - La Petite Brenne - Luzeret (36) >+33254250578 (162m)Le Bambou - Fenioux (79) [<51] >+33549054098 (113m)Logis de l'Aubonniere - Chaille sous les Ormeaux (85) [<51] (15/04-15/10) >+33251349990 (40m)La Loubine - Olonne sur Mer (85) >+33251331292 (4m)Saint Benoit** - Saint Benoit (15/06-15/09) >+33549884855 (81m)Le Sauveterre - Olonne sur Mer (85) >+33251331058 (5m)Le Hameau des Champs - Cormatin (71) >+33385507671 (209m)Municipal La Smagne - Sainte Hermine (85) >+33251273554 (26m)l'Oree - Olonne sur Mer (85) >+33251331059 (5m)Municipal La Quintaine - Belabre (36) [<51] >+33254372221 (97m)Mathoniere - Louroux Bourbonais (3) [<51] >+33470072306 (348m)Montlobier - Chauviniere (3) [<51] >+33470670444 (264m)Aire naturelle Municipale - Moutiers sur le Lay (85) [<51] >+33251275070 (12m)Le Puy Babin - Saint Mathurin (85) [<51] >+33251227411 (19m)Bois Soleil - Olonne sur Mer (85) >+33251331197 (5m)Municipal La Guinguette - Culan (18) [<51] >+33248566441 (284m)l'Etournerie - Mareuil sur Lay Dissais (85) [<51] >+33251287768 (28m)La Montgarnie - Gilly sur Loire (71) [<51] >+33652567670 (285m)Municipal - Cluis (36) [<51] >+33254312106 (266m)La Ferme Forestiere - Vouhe (79) [<51] >+33549706689 (206m)A la ferme Plessiere - Theneuille (3) [<51] >+33470674097 (310m)Le Lac - Palinges (71) [<51] >+33606881449 (260m)L'Eugenie - Grosbreuil (85) [<51] >+33251056620 (37m)Municipal Le Lay - Sainte Pexine (85) [<51] >+33251275000 (12m)Halte Nautique** - Cuisery (15/04-15/10) >+33385400872 (174m)A la Ferme Les Plattieres - Sainte Croix (71) [<51] >+33385748142 (184m)Le Fayolan - Clairvaux les Lacs (39) (01/05-07/09) >+33384252619 -CCA(536m)La ferme Le Bon Coeur - Ygrande (3) [<51] >+33470663324 (292m)l'Ile aux Oiseaux - l'Ile d'Olonne (85) >+33251908996 (6m)La Grisiere - Clairvaux les Lacs (39) >+33384258048 (538m)A la ferme Les Sorinieres - Nieul le Dolent (85) [<51] >+33251079158 (67m)La Ferme la Caille - Autry-Issards (3) [<51] >+33470439898 (243m)De l'Etang Merlin - Chateaumeillant (18) >+33248613138 (225m)Intercommunal Le Val Vert - La Chatre (36) >+33254483242 (220m)Grand Lac - Clairvaux les Lacs (39) (01/06-30/09) >+33384252214 -CCA(543m)Municipal Du Moulin - Saint-Savin (86) [<51] >+33549481802 (81m)Les Crotenots* - Le Miroir [<51] (01/04-15/10) >+33385767178 (201m)Charcotiere - Ygrande (03) [<51] >+33470663390 (290m)Municipal De Chazey - Gueugnon (71) [<51] >+33385852311 (237m)Municipal De la Fontaine - Chauvigny (86) >+33549463194 (75m)Le Gue - Savigny sur Grosne (71) >+33385926188 (197m)Municipal Tournus - Tournus (71) (01/05-30/09) >+33385511658 -CCpg354-CCA(175m)Aire naturelle La Bergerie - La Chapelle Achard (85) [<51] >+33251056705 (32m)Municipal Le Champs de Mars - Saint Laurent en Grandvaux (39) >+33384601930 (916m)Les Tilleuls - Clairvaux les Lacs (39) >+33671221775 (552m)Municipal Les Garnes - Nieul le Dolent (85) >+33251079092 (62m)Eco A Labigo - Aubigny (85) [<51] (01/01-31/12) >+33683574767 (74m)l'Etang du Rousset - Le Rousset (71) >+33385246874 (391m)Municipal De Bignon - Bourbon l'Archambault (3) >+33682826250 (265m)La Ferme d'Helice - Sarzay (36) [<51] >+33254313230 (254m)Aire naturelle Municipale - Le Beugnon (79) [<51] >+33549637431 (204m)Les Favieres - Lac Des Rouges Truites (39) [<51] >+33384608670 (906m)Les Pecheurs - Pont De Poitte (39) >+33384483133 (439m)Le Moulin - Patornay (39) (26/04-14/09) >+33384483121 -CCA(444m)Le Bonhomme - Neret (36) [<51] (01/04-01/10) >+33254314611 -CCA(250m)La Gachere - Olonne sur Mer (85) >+33251226582 (7m)Ferme-Auberge de Malo - Etrigny (71) [<51] >+33385922340 (197m)La Prairie - Boissia (39) >+33384483439 (482m)Municipal Les Frenes - Neuvy Saint Sepulchre (36) >+33254308027 (190m)La Venise du Bocage - Nesmy (85) >+33630744240 (59m)Chez Baron - Vernoux en Gatine (79) >+33549634204 (216m)l'Abbaye - Bonlieu (39) (01/05-30/09) >+33384255704 -CCA(801m)Municipal Les Chambons*** - Argenton s/Creuse (36) (01/05-30/09) >+33254241526 -CCA(104m)Le Cheval Blanc - Meaulne (3) (01/05-30/09) >+33470069113 (168m)Naturist - Le Colombier - Saint Martin Lars en Sainte Hermine (85) (01/04-01/10) >+33251278384 -CCA(71m)Du Marais - Bonlieu (39) [<51] >+33384255670 (786m)Beauregard - Mesnois (39) (01/04-30/09) >+33384483251 -CCA(460m)La Ripe Blanche- Rancy (71) [<51] >+33385742066 (195m)Municipal Chateau Solange Sand - Montgivray (36) [<51] >+33254061034 (195m)l'Ocean - Brem sur Mer (85) (12/04-01/11) >+33251905916 (9m)Municipal - Bonnes (86) [<51] >+33549564434 (62m)Chalet Du Bugnon - Lac Des Rouges Truites (39) [<51] >+33384602021 (936m)Les Logeries - Vaire (85) >+33251337569 (58m)Le Chaponnet - Brem sur Mer (85) (05/04-30/09) >+33251905556 -CCpg000-CCA(16m)Municipal du Moulin des Effres - Secondigny (79) >+33670348520 (178m)Le Brandais - Brem sur Mer (85) >+33251905587 (10m)Le Moulin de Rambourg - Nesmy (85) [<51] >+33251076383 (37m)Amitie et Nature - Bretignolles sur Mer (85) >+33251905004 (7m)Le Pavillon - La Mothe Achard (85) >+33251056346 (47m)Les Dunes - Bretignolles sur Mer (85) >+33251905532 (9m)Le Roc - Vaire (85) >+33661990159 (51m)A la ferme Plessis-Tesselin - Saint Florent des Bois (85) [<51] >+33251319112 (69m)Le Relais de L'Eventail - Doucier (39) [<51] >+33384257159 (525m)Les Claies - Blye (39) [<51] >+33384483055 (469m)Municipal La Chapelle - Cerilly (3) [<51] >+33470675200 (297m)Du Breuil - Bourbon Lancy (71) (31/03-30/10) >+33385892098 -CCpg345(227m)Le Saint Prix - Bourbon Lancy (71) >+33385892098 (233m)Municipal Peupliers - Azay sur Thouet (79) [<51] >+33549953713 (159m)Municipal*** - Louhans (71) (01/04-30/09) >+33385751902 -CCA(180m)Campilo - Aubigny (85) (01/01-31/12) >+33251316845 -CCpg111-CCA(58m)Les Gatinelles - Bretignolles sur Mer (85) >+33479597441 (13m)Municipal De La Plage Du Cher - Urcay (3) [<51] >+33470069691 (164m)Municipal l'Ile de Creuse - Ruffec (36) [<51] (01/07-31/08) >+33254377011 (80m)La Motine - Bretignolles sur Mer (85) >+33251900442 (10m)Aire naturelle l'Absie - l'Absie (79) [<51] >+33621079914 (241m)Municipal Champ de la Cure - Merigny (36) [<51] (01/04-30/09) >+33254374271 (81m)Municipal Les Rives de la Bouzanne** - Pont Chretien Chabenet [<51] (01/06-31/08) >+33254258140 (101m)Les Vagues - Bretignolles sur Mer (85) >+33251901948 (12m)La Bazelle - Chalmoux (71) [<51] >+33385842352 (334m)Municipal l'Ile d'Avant - Le Blanc (36) [<51] >+33254378822 (78m)Municipal l'Illon** - St. Gaultier [<51] (01/05-15/09) >+33254471122 (97m)Les Marsouins - Bretignolles sur Mer (85) >+33251901457 (12m)Naturist - Ferme l'Oliverie - Saurais (79) [<51] (24/04-27/09) >+33687916453 -CCpg120(171m)l'Oasis du Berry**** - St. Gaultier (01/03-31/10) >+33254471704 (102m)A la Ferme Le Petit Crotet - Franchesse (3) [<51] >+33470667291 (255m)l'Evasion - Landevieille (85) >+33251229014 (31m)Le Marina - Bretignolles sur Mer (85) >+33251338317 (15m)Au Bon Accueil - Bretignolles sur Mer (85) >+33251901592 (15m)La Trevilliere - Bretignolles sur Mer (85) (05/04-20/09) >+33251330505 -CCA(19m)Municipal - Vouille (86) [<51] >+33549519010 (111m)l'Oree de l'Ocean - Landevieille (85) >+33251229636 (30m)Municipal Les Humeaux - Bournezeau (85) [<51] (15/06-15/09) >+33251400131 (85m)Municipal Sur Narlay - Le Frasnois (39) [<51] >+33384255874 (782m)La Chagnee - Saint-Aubin le Cloud (79) [<51] >+33671100966 (219m)Du Bois Vert -�Parthenay (79) (04/04-31/10) >+33549959668 -CCA(141m)Pong - Landevieille (85) >+33251229263 (35m)Champ de La Chapelle - Braize (3) [<51] >+33470061545 (242m)Cateau de la Foret - Saint Julien des Landes (85) >+33251466211 -CCA-BD_FR-H.051(56m)La Bretonniere - Saint Julien des Landes (85) (29/03-30/09) >+33251466244 -CCA(55m)Moulin de Collonge -�St Boil (71) [<51] (01/04-30/09) >+33385440032 -CCA(211m)Motovacances-en-France - Uxeau [<51] (01/01-31/12) >+33385855401 (252m)Les Alouettes - La Chaize Giraud (85) >+33251229621 (20m)La ferme De Soulisse - Cerilly (3) [<51] >+33470666881 (257m)Les Merilles - Doucier (39) (01/04-30/09) >+33384257306 -CCA(511m)l'Epinette -�Chatillon sur Ain (39) (13/06-06/09) >+33384257144 -CCpg288-BD_FR-K.029c(470m)La Guyonniere - Saint Julien des Landes (85) (26/04-26/09) >+33251466259 -CCpg109-CCA(49m)Du Chateau de l'Eperviere**** -�Gigny sur Saone (71) (01/04-30/09) >+33385941690 -CCA(178m)Municipal Villeneuve - Saint Chartier (36) (01/07-31/08) >+33254311004 (204m)Municipal Parc des Ecluzelles** - Chasseneuil du Poitou [<51] (01/04-25/09) >+33549625885 (72m)Municipal Val de Saine - Foncine le Haut (39) >+33384519276 (865m)Le Futur*** - Avanton (86) (01/04-31/10) >+33549540967 -CCA(121m)Montifaut - La Tardiere (85) [<51] >+33251874063 (133m)VIP Peche - Ayron (86) [<51] >+33549508523 (138m)Champ Fosse - Saint Bonnet Troncais (3) >+33470468160 (233m)Municipal de l'Arpent - Mers sur Indre (36) [<51] >+33254310652 (182m)Aire naturelle Municipale Montplaisir - Saint Aubin le Cloud (79) [<51] >+33549953508 (182m)Le Lac - Landevieille (85) >+33251229161 (41m)Le Lac des Arrouettes - Toulon sur Arroux (71) [<51] >+33385795030 (246m)Les Asphodeles - Chantonnay (85) [<51] >+33251943027 (47m)Naturist - Les Fourneaux - Couzon (3) >+33470662318 (250m)Municipal du Bois Joli - Chaux des Crotenay (39) [<51] >+33384515000 (794m)La Garangeoire -�St Julien des Landes (85) (19/04-20/09) >+33251466539 -CCA(42m)Chalain - Doucier (39) (01/05-15/09) >+33384257878 -CCA(494m)Le Futuriste*** -�St Georges Les Baillargeaux (01/01-31/12) >+33549524752 -CCpg121(104m)Le Pin Parasol - La Chapelle Hermier (85) (18/04-25/09) >+33251346472 -CCA(49m)Le Parc de la Greve - l'Aiguillon sur Vie (85) >+33251228623 (27m)Le Jaunay - Givrand (85) >+33251551477 (5m)Le Bois de Saint Hilaire - Chalandray (86) [<51] (01/05-30/09) >+33549602084 -CCA(164m)Aire naturelle Municipale - Saint Vincent en Bresse (71) [<51] >+33385765124 (206m)Aire naturelle Le Castel Blanc - Chatelblanc (25) [<51] >+33607421067 (942m)Les Cypres - Saint Gilles Croix de Vie (85) >+33251553898 (6m)Beaulieu - Givrand -Saint Gilles Croix de Vie (85) (05/04-20/09) >+33251330505 -CCA(6m)Municipal La Pree du Pave - Mouilleron en Pareds (85) >+33251003034 (95m)Municipal La Font Saint Julien - Couleuvre (3) [<51] >+33470661354 (241m)La Heronniere*** -�Laives (71) (21/03-31/10) >+33385449885 -CCA(180m)Les Dauphins Bleus - Saint Gilles Croix de Vie (85) >+33251555934 (13m)La Rousselotiere - Givrand (85) [<51] >+33606456880 (14m)Le Cremault - Bonneuil Matours (86) [<51] >+33549852047 (57m)Le Petit Pavillon - Saint Gilles Croix de Vie (85) (01/04-30/09) >+33251551463 (5m)RCN La Ferme du Latois - Coex (85) [<51] (19/04-20/09) >+33251546730 -CCA(52m)La Pergola -�Marigny (39) (08/05-06/09) >+33384257003 -CCpg289(491m)Le Bahamas Beach - Saint Gilles Croix de Vie (85) >+33251330505 (5m)A la ferme Le Moulin de Fumailles - La Peyratte (79) [<51] >+33549943420 (115m)Les Amandiers*** - Jaunay Clan (01/01-31/12) >+33549628040 (113m)De la Micheliere - Givrand (85) >+33251268973 (17m)Les Ecossais - Isle et Bardais (3) >+33470666257 (245m)Croix du Sud*** - Jaunay Clan (01/04-15/09) >+33549625814 (109m)Le Village de Florine - Coex (85) >+33251601951 (49m)La Marjorie**** - Lons le Saunier (39) (01/04-15/10) >+33384242694 -CCA-BD_FR-K.029(273m)Municipal - Saint Pierre de Maille (86) [<51] >+33549486411 (75m)Familial - Ids Saint Roch (18) [<51] (01/04-01/10) >+33248600849 (193m)Mini Maison Voila - Montipouret (36) [<51] >+33254311791 (236m)Aire naturelle De Rochereau - Bazoges en Pareds (85) [<51] >+33251404097 (69m)Europa - Saint Gilles Croix de Vie (85) >+33251553268 (25m)Municipal Le Val d'Arroux - Toulon sur Arroux (71) >+33385795122 (250m)La Cour Neuve - Saint Leopardin d'Augy (3) [<51] >+33470662287 (221m)l'Ambois - Mouilleron le Captif (85) >+33251372915 (66m)Le Pont Rouge - Saint Reverend (85) >+33251546850 (8m)Municipal du Parc** - Dissay [<51] (15/06-15/09) >+33549628429 (64m)La Padrelle - Saint Hilaire de Riez (85) >+33251553203 (12m)Aire naturelle de Charrier Robert - Saint Reverend (85) [<51] >+33251546330 (25m)Aire naturelle municipale Le Moulin - Lurais (36) [<51] >+33254375117 (71m)Municipal Les Millots - Rosnay (36) [<51] >+33254378017 (106m)Municipal de la Source du Doubs - Mouthe (25) [<51] >+33671454765 (956m)Municipal des Baillys - Dornes (58) [<51] (01/04-30/09) >+33386506881 (233m)Les Portes du Morvan -�Issy l'Eveque (71) >+33385249605 (310m)Les Royautes - Saint Leopardin d'Augy (3) [<51] >+33470662479 (230m)Le Petit Beauregard - Le Fenouiller (85) >+33251550798 (18m)Le Git - Montigny sur l'Ain (39) [<51] >+33384512117 (523m)La P'tite Cuiller - Moutiers sous Chantemerle (79) [<51] (01/01-31/12) >+33549742806 (163m)Municipal De La Toupe - Baume Les Messieurs (39) >+33384446316 (291m)A la ferme La Berthenoux - La Berthenoux (36) [<51] >+33254300798 (229m)Bellevue - Le Fenouiller (85) >+33251551135 (11m)La ferme La Maison Neuve - La Ferriere (85) [<51] >+33251984794 (98m)Municipal de Sion - Saint Hilaire de Riez (85) >+33251984794 (11m)Municipal - Migne (36) [<51] >+33254378610 (107m)A la fermette de la Haye - Saint Aout (36) [<51] >+33254367905 (201m)Municipal La Roche*** - St.Amand-Montrond (18) (01/04-30/09) >+33248960936 -CCA(158m)Municipal Marais de la Guerche - l'Ile d'Yeu (85) >+33251583420 (4m)Lac de Saint Cyr**** - Saint Cyr (86) (01/04-30/09) >+33549625722 -CCA(60m)Les Chalets de Moulieres - Vouneuil sur Vienne (86) (15/06-15/09) >+33549858440 (55m)Sous Doriat - Monnet la Ville (39) >+33384512143 (515m)Municipal Plage de Riez - Saint Hilaire de Riez (85) >+33251543659 -CCA(8m)Le Bivouac - Pont du Navoy (39) >+33384512695 (466m)Le Marronnier - Lurcy Levis (3) [<51] >+33470673100 (253m)La Prevote - Saint Hilaire de Riez (85) >+33251543119 (8m)Naturist - Des Chenes - St Christophe en Bresse (71) >+33608998766 (193m)Le Navoy - Pont du Navoy (39) [<51] >+33384512106 (467m)Le Chateau - Saint Hilaire de Riez (85) >+33251543588 (2m)A la ferme Du Bourg - Gannay sur Loire (3) [<51] >+33470434901 (199m)Municipal Les Grandes Iles - Tournon Saint Martin (36) [<51] (15/06-15/09) >+33254378886 (66m)Les Chouans - Saint Hilaire de Riez (85) (15/04-15/09) >+33251543490 (6m)Aire naturelle La Petite Martiniere - Saint Hilaire de Riez (85) [<51] >+33251544208 (9m)La Sapiniere - Saint Hilaire de Riez (85) (01/06-30/09) >+33251544574 (9m)La Foret - Aizenay (85) >+33251347812 (68m)Domaine Des Pins - Saint Hilaire de Riez (85) (01/06-30/09) >+33251582333 (7m)Municipal - Bessais Le Fromental (18) >+33248608266 (217m)Riez A la Vie - Saint Hilaire de Riez (85) (05/04-28/09) >+33251543049 (3m)Les Biches - Saint Hilaire de Riez (85) >+33251543882 (11m)La Marzelle - Saint Hilaire de Riez (85) (01/05-30/09) >+33251543259 (7m)La Paree Preneau - Saint Hilaire de Riez (85) >+33251543384 (2m)Sol a Gogo - Saint Hilaire de Riez (85) >+33251542900 (3m)La Paree du Both - Saint Hilaire de Riez (85) >+33251547827 (3m)Le Bosquet - Saint Hilaire de Riez (85) >+33251543461 (3m)La Pege - Saint Hilaire de Riez (85) >+33251543452 (2m)Les Grands Pins*** - Velles (36) (20/03-25/10) >+33254366193 -CCA(179m)La Conge - Saint Hilaire de Riez (85) >+33251543247 (4m)Le Romarin - Saint Hilaire de Riez (85) >+33251544382 (4m)Aire naturelle Le Pre de la Fontaine - Aizenay (85) [<51] >+33689907684 (67m)La Prairie - Saint Hilaire de Riez (85) >+33251540856 (2m)Rural de Gourmaud Remy - Saint Germain de Princay (85) [<51] >+33251404781 (94m)La Ningle - Saint Hilaire de Riez (85) >+33680227007 (1m)Les Ecureuils - Saint Hilaire de Riez (85) >+33251543371 (2m)Municipal La Riviere - Sainte Cecile (85) >+33686673951 (48m)La Plage - Saint Hilaire de Riez (85) (05/04-20/09) >+33251543393 -CCA(3m)Le Pissot - Saint Hilaire de Riez (85) >+33251555576 (2m)Municipal De l'Etang Titard - Saint Germain du Bois (71) [<51] >+33385720615 (202m)De Boyse - Champagnole (39) >+33384520032 -CCA(535m)La ferme Le Puy Charrier - Menomblet (85) [<51] >+33680156054 (179m)Le Clos des Pins - Saint Hilaire de Riez (85) >+33251543262 (3m)Le Sableau - Notre Dame de Riez (85) >+33251600120 (3m)Fonteclose - Notre Dame de Riez (85) >+33251552222 (8m)La Baudonniere - Monsireigne (85) [<51] >+33251664379 (95m)La Pomme de Pin - Saint Hilaire de Riez (85) >+33251582126 (3m)Le Clarys Plage - Saint Jean de Monts (85) >+33251581024 (1m)Val de Vie - Mache (85) >+33251602102 (36m)Aire naturelle de Pare Marie-Noelle - La Roche Posay (86) [<51] >+33549862718 (88m)Acapulco - Saint Jean de Monts (85) >+33251592064 (2m)Des Renardieres - Notre Dame de Riez (85) (01/04-04/11) >+33620983746 -CCA(4m)La Ferme Du Petit Cheval Blanc - Fay en Montagne (39) [<51] >+33384853207 (527m)Municipal De L'Ange Blanc - Lignieres (18) [<51] >+33248600018 (160m)Le Tropicana - Saint Jean de Monts (85) >+33251586298 (3m)La Yole -�St Jean de Monts (85) (10/04-24/09) >+33251586717 -CCpg108-CCA(4m)Les Genets - Saint Jean de Monts (85) >+33251589394 (3m)Les Prairies du Lac - Apremont (85) >+33251557058 (56m)Le California - Saint Jean de Monts (85) >+33251581751 (6m)Municipal de Saint Mayeul - Le Veurdre (3) [<51] (15/06-15/09) >+33470664067 (187m)Le Chenal - Saint Jean de Monts (85) >+33251586539 (5m)Chateau de Chigy - Tazilly (58) (26/04-30/09) >+33386301080 -CCA(329m)Aire naturelle Le Trefle a 4 Feuilles - Commequiers (85) >+33251548754 (35m)La Vie - Commequiers (85) >+33251549004 (7m)Aire naturelle de la Gabriere - Linge (36) [<51] >+33254378097 (88m)Les Alizes - Saint Hilaire de Riez (85) >+33228114290 (1m)Mulot - Tazilly (58) [<51] >+33386301195 (294m)Des Salins - Saint Hilaire de Riez (85) >+33251593628 (5m)La Puerta del Sol - Saint Hilaire de Riez (85) >+33251491010 (4m)Le Both d'Orouet - Saint Jean de Monts (85) >+33251586037 (1m)Les Salines - Saint Hilaire de Riez (85) >+33251581195 (7m)Les Ombrages - Saint Hilaire de Riez (85) >+33251581195 (6m)Municipal Du Lac Marnant - La Nocle Maulaix (58) [<51] >+33386308411 (226m)Municipal des Demoiselles - Saint Hilaire de Riez (85) >+33251581071 (4m)Les Pinedes de la Caillauderie - Saint Jean de Monts (85) (01/04-30/10) >+33251582376 (3m)Municipal Les Platanes* - Bruere Allichamps (01/04-30/09) >+33248610669 (147m)Les Jardins de l'Atlantique - Saint Jean de Monts (85) >+33251580574 (3m)Du Lac - Labergement Sainte Marie (25) >+33381693124 (856m)Municipal Le Patis - Les Essarts (85) >+33251629583 (96m)Municipal Le Miroir - Les Hopitaux Neufs (25) (01/11-31/03-01/05-30/09) >+33381491064 -CCpg290(974m)Municipal Le Hameau du Petit Lay - Mouchamps (85) [<51] >+33251662572 (59m)Le Paroy - La Tagniere (71) [<51] (01/04-30/09) >+33603566482 -CCA(400m)La Haute Bottiere - Saint Andre sur Sevre (79) [<51] >+33549808795 (162m)Les Charmes - Apremont (85) [<51] >+33686039693 (52m)Le Logis - Saint Jean de Monts (85) >+33251586067 (4m)Les Sirenes - Saint Jean de Monts (85) (05/04-14/09) >+33251580131 -CCA(6m)Le Zagarella - Saint Jean de Monts (85) >+33251581982 (4m)Municipal Le Lac - Pouzauges (85) [<51] >+33673932708 (146m)Aire naturelle Renoir - La Roche Posay (86) >+33549861919 (99m)Municipal Les Bords de Creuse - Yzeures sur Creuse (37) [<51] >+33247945501 (60m)Pont de Bourgogne** - St. Marcel (71) (01/04-30/09) >+33385482686 -CCpg353-CCA(173m)Les Pins - Saint Jean de Monts (85) >+33251581742 (6m)Municipal De Beaudrillon - Saint Pierre Le Moutier (58) [<51] >+33386374209 (220m)Les Arbois - Montjay (71) [<51] >+33385720905 (200m)La Roussiere - Saint Jean de Monts (85) (01/05-30/09) >+33251586573 (2m)Les Fuvettes - Malbuisson (25) (01/04-30/09) >+33381693150 -CCA(858m)Vue du Lac-Le Champ Donjon - Fours (58) [<51] >+33386502067 (227m)Municipal La Bedure - Luzy (58) >+33675225507 (285m)Rural de Tavet Gerard - Saint Christophe du Ligneron (85) [<51] >+33251352867 (41m)Municipal Le Chillou d'Ozon** - Chatellerault (01/05-31/10) >+33549219402 (52m)Bellebouche - Mezieres en Brenne (36) >+33254382828 (108m)Municipal Le Moulin Neuf - Soullans (85) >+33251680024 (18m)La Roche-Posay - La Roche Posay (86) (12/04-20/09) >+33549862123 -CCA(66m)Le Bois Joly - Saint Jean de Monts (85) (12/04-28/09) >+33251591163 -CCA(1m)Boussal- Thil sur Arroux (71) [<51] >+33979707689 (304m)l'Ocean - Saint Jean de Monts (85) (01/04-21/09) >+33251580388 -CCA(3m)Le Bois Verdon - Saint Jean de Monts (85) >+33251581061 (8m)La Buzeliere - Saint Jean de Monts (85) >+33251586480 (2m)Le Jardin du Marais - Le Perrier (85) >+33251680917 (0m)A la Ferme la Tranquillite - Soullans (85) [<51] >+33251681249 (0m)Municipal du Plan d'Eau - Mervans (71) [<51] >+33385761170 (185m)Aire naturelle Municipale - Thil sur Arroux (71) [<51] >+33385542621 (286m)La Prairie - Saint Jean de Monts (85) >+33251581604 -CCA(6m)Les Championnieres - Saint Jean de Monts (85) >+33251586154 (2m)Le Fief - Saint Jean de Monts (85) >+33251586377 (4m)Municipal De la Plage - Saint Nizier sur Arroux (71) >+33385542955 (263m)La Paree du Jonc - Saint Jean de Monts (85) >+33251588119 (5m)La Daviere - Saint Jean de Monts (85) (01/05-30/09) >+33251582799 -CCA(4m)Le Vieux Ranch - Saint Jean de Monts (85) >+33251588658 (4m)l'Oree des Bois - Saint Jean de Monts (85) >+33251584582 (4m)Aire naturelle Les Chagnelles - Le Perrier (85) [<51] >+33251683513 (1m)Les Amiaux - Saint Jean de Monts (85) >+33251582222 (2m)Aire naturelle la Grimaudiere - La Grimaudiere (86) [<51] >+33549600318 (83m)l'Abri des Pins - Saint Jean de Monts (85) >+33251588386 (1m)La Ferme Le Pont Sargy - Bannegon (18) [<51] >+33248618317 (176m)Aux Coeurs Vendeens - Saint Jean de Monts (85) (20/04-20/09) >+33251588491 -CCA(1m)Plein Sud - Saint Jean de Monts (85) >+33251591040 (1m)Les Places Dorees - Saint Jean de Monts (85) >+33251590293 (1m)Le Dornier - Saint Jean de Monts (85) (18/04-14/09) >+33251588116 -CCA(4m)Municipal La Vallee des Vaux** - Saint Jean de Vaux (01/05-30/09) >+33385451198 (237m)Les Chaumes - Saint Jean de Monts (85) >+33687905049 (4m)Municipal - Saint Point Lac (25) (01/05-15/10) >+33381696164 (849m)Les Aventuriers de la Calypso - Saint Jean de Monts (85) (12/04-27/09) >+33251597966 (1m)Municipal Saint Symphorien - Saint Symphorien (18) [<51] >+33248606079 (150m)Aire naturelle le Bellevue - Saint Christophe du Ligneron (85) >+33251933066 (29m)Municipal - Airvault (79) >+33549647013 (81m)Naturist - De la Gagere - Luzy (58) (01/04-30/09) >+33386304811 -CCA(418m)Municipal La Bruyere - Mornay sur Allier (18) [<51] >+33248745701 (208m)La Foret - Saint Jean de Monts (85) (01/05-20/09) >+33251588463 -CCA(3m)Le Petit Bois - Saint Jean de Monts (85) >+33251588084 (4m)Municipal La Caillauderie - Mezieres en Brenne (36) [<51] >+33254381224 (89m)Le Ragis - Challans (85) >+33251680849 (6m)Municipal De La Maison Blanche - Le Perrier (85) >+33251493923 (1m)Le Pont d'Yeu - Notre Dame de Monts (85) >+33251588376 (7m)La Menardiere - Saint Jean de Monts (85) >+33251588692 (2m)Les Bles d'Or - Grand Landes (85) >+33296419993 (51m)Naturist - Le Bois des Battees - St. Leger-sur-Dheune (71) >+33385453284 (421m)Aire naturelle de Billon Gerard - Le Perrier (85) [<51] >+33251683252 (1m)Petites Minaudieres*** - Saint Sauveur (20/04-30/09) >+33549230421 (139m)Municipal Rochat Belle-Isle**** - Chateauroux (01/04-31/10) >+33254089629 -CCpg324(141m)A la ferme Les Grands Champs - La Chapelle sous Uchon (71) [<51] >+33617980253 (386m)La Motte - Vendrennes (85) (01/01-31/12) >+33251635967 -CCA(87m)La Ferme Ahimsa - Serrigny en Bresse (71) [<51] >+33385477872 (190m)Puy Rond - Bressuire (79) [<51] >+33685603726 (154m)Aire naturelle Vert-Les Grandes Noues - Challans (85) [<51] >+33608895462 (3m)A la ferme de Barranger Guy - Saint Jean de Monts (85) [<51] >+33643716874 (1m)La Petite Boulogne - Saint-Etienne du Bois (85)_ [<51] >+33251345211 (30m)Le Clos du Bourg - Notre Dame de Monts (85) >+33251590747 (1m)Le Courte Vallee - Airvault (79) (01/04-16/10) >+33549647065 -CCA(96m)La Loire Fleurie - Le Perrier (85) >+33272823087 (1m)Municipal de la Croix du Dan - Poligny (39) (01/06-15/09) >+33384737758 (311m)Les Halles - Decize (58) >+33386251405 -CCA(190m)l'Etoile - Notre Dame de Monts (85) (01/04-31/10) >+33228110006 (2m)Le Grand Jardin - Notre Dame de Monts (85) >+33228112175 (1m)Municipal De l'Orgatte - Notre Dame de Monts (85) >+33251588431 (7m)La Mare de Roy* - Gergy [<51] (01/05-30/09) >+33385917545 (181m)Les Pins - Notre Dame de Monts (85) >+33251588375 (7m)La Paree Chalons - Notre Dame de Monts (85) >+33251588330 (6m)Le Bois Collin - Notre Dame de Monts (85) >+33251584697 (3m)Les Tranches - Notre Dame de Monts (85) [<51] >+33251588537 (4m)Val de Boulogne - Les Lucs sur Boulogne (85) [<51] >+33251465900 (59m)Beausejour - Notre Dame de Monts (85) (01/04-30/09) >+33251588388 (3m)La Daviere - Notre Dame de Monts (85) >+33251588596 (6m)l'Albizia - Notre Dame de Monts (85) (01/04-30/09) >+33228112850 (7m)Municipal Du Chateau - Azay Le Ferron (36) [<51] >+33254392191 (101m)Le Lagon Bleu - Notre Dame de Monts (85) (01/04-31/10) >+33251588529 (2m)Municipal Preuilly sur Claise - Preuilly sur Claise (37) (01/06-30/09) >+33247945004 (71m)Aire naturelle La Solitude - Boussay (37) [<51] >+33247945291 (98m)Le Bout du Pont - Barrou (37) [<51] >+33247910414 (54m)Le Lac de la Tricherie - Mesnard la Barotiere (85) >+33251660431 (97m)L'Ile - Chateauneuf sur Cher (18) >+33248604681 (137m)La Rive - Notre Dame les Monts (01/04-31/10) >+33251593250 (1m)Camp Libre - La Chapelle Saint Sauveur (71) [<51] >+33385745927 (200m)Les 2 Rives - Etang sur Arroux (71) (01/01-31/12) >+33385823973 -CCA-BD_FR-J.022a(271m)Municipal Les Rioms - Barrou (37) [<51] >+33247945307 (51m)Le Marais Neuf - La Barre de Monts (85) >+33251490502 (3m)Municipal Le Port - Cercy la Tour (58) >+33386505527 (198m)La Bonne Vie - Saint Maurice les Couches (71) [<51] >+33385455595 (245m)Municipal Les Iris - Savigny sous Faye (86) [<51] >+33549907059 (105m)A la ferme Equilibre les 4 Moulins - Sallertaine (85) [<51] >+33251355203 (12m)Municipal Les Rouches - Saint Urbain (85) [<51] >+33251687334 (1m)Municipal La Gabrelle - Couches (71) [<51] >+33385455949 (360m)Municipal - La Machine (58) [<51] >+33386508423 (223m)Municipal au Fil de l'Eau - Gergy (71) [<51] >+33762923263 (173m)La Corsive - La Barre de Monts (85) >+33251685006 (5m)Municipal - Mareuil sur Arnon (18) [<51] >+33248699106 (142m)Le Marais - La Barre de Monts (85) >+33685070047 (1m)Le Grand Corseau - La Barre de Monts (85) >+33251685287 (7m)Municipal l'Auron - Dun sur Auron (18) [<51] >+33698400635 (156m)La Grande Cote - La Barre de Monts (85) (05/04-21/09) >+33251685189 -CCA(5m)Active Park - Moncontour (86) (01/04-01/10) >+33549223850 (62m)La Darotte - La Barre de Monts (85) >+33673710294 (3m)Petit Trianon de St.Ustre**** - Ingrandes (86) (15/04-21/09) >+33549026147 -CCA(65m)La Breteche - Les Epesses (85) (01/04-30/09) >+33251573334 -CCA(184m)Fontaine la Mere - Laizy (71) [<51] (01/04-01/10) >+33385822801 (311m)Aire naturelle de Veronneau Felicien - La Barre de Monts (85) [<51] >+33251685602 (1m)Municipal - Blet (18) [<51] >+33248747104 (178m)Municipal La Tete Noire - Buzancais (36) (11/04-02/11) >+33254841727 -CCpg323(108m)Municipal La Grande Versenne - Saint Varent (79) >+33549676211 (103m)Municipal - Saint Gervais (85) [<51] >+33251687314 (9m)La Ferme des Couts - Chambretaud (85) [<51] >+33251915144 (214m)Le Larmont - Pontarlier (25) >+33381462333 (882m)Municipal La Plage - Verdun sur le Doubs (71) >+33385915550 (173m)La Foret du Morvan - Larochemillay (58) [<51] >+33386304793 (453m)Municipal Guesnes - Guesnes (86) [<51] >+33549228491 (77m)A la ferme de Nouvelles - Arbois (39) [<51] >+33384662153 (322m)Municipal Les Vignes - Arbois (39) >+33384661412 (309m)Municipal Plateau du Guet - Saint Honore les Bains (58) (01/04-31/10) >+33386307600 (266m)Municipal Les Trois Rivieres - Bragny sur Saone (71) >+33385915026 (176m)Les Bains - St Honore les Bains (58) (01/04-31/10) >+33386307344 -CCA(236m)Les Sources -�Santenay (21) (15/04-31/10) >+33380206655 -CCpg352-CCA(230m)Le Paquier Fane - Chagny (71) (01/04-31/10) >+33385872142 -CCA(206m)Municipal - Chevenon (58) >+33386687171 (208m)Municipal - Vandenesse (58) [<51] >+33386307406 (220m)La Fresnerie - Saint Gervais (85) >+33251687810 (31m)Au Bois du Ce - Chambretaud (85) (01/04-28/09) >+33251915432 (175m)La ferme Les Vieilles Ventes - Chateauneuf (85) >+33251493094 (13m)Le Bois Vieux- Thianges (58) [<51] >+33386509659 (219m)Municipal La Croix Marron - Le Grand Pressigny (37) [<51] >+33247940655 (60m)Aire Naturelle Fief Angibaud - Saint Gervais (85) [<51] >+33251684308 (12m)Les Bords du Doubs - Petit Noir (39) >+33384816356 (182m)La Vallee de Poupet - Saint Malo du Bois (85) >+33251923145 (132m)Municipal aire naturelle La Jeannette - Charette Varennes (71) [<51] >+33385762358 (177m)Les Oncheres - Barbatre (85) >+33251398131 (8m)Les Pecheurs - Lays sur le Doubs (71) (12/04-28/09) >+33385728232 (179m)La Boutiere - Saint Leger sous Beuvray (71) [<51] (15/04-15/10) >+33385824886 -CCA(385m)Le Bois Joli - Bois de Cene (85) (01/04-11/10) >+33251682005 -CCpg107(11m)Intercommunal - Lunery (18) [<51] >+33248680738 (128m)l'Eden - La Boissiere de Montaigu (85) (01/01-31/12) >+33251416232 (74m)Les Rosieres - Palluau sur Indre (36) [<51] >+33254384407 (98m)Municipal Ile de la Claise - Abilly (37) [<51] (01/05-15/09) >+33247930835 (52m)Municipal Robinson - La Guerche sur l'Aubois (18) [<51] >+33248741886 -CCA(195m)A la ferme equestre du Grand Saule - La Coudre (79) [<51] >+33686705630 (129m)Espace Vital - La Grande Verriere (71) [<51] >+33385824941 (428m)Le Midi - Barbatre (85) (12/04-28/09) >+33251396374 -CCA(7m)Rural le Petit Bois Chabot - Saint Laurent sur Sevre (85) [<51] >+33251678282 (165m)Municipal - Salins Les Bains (39) [<51] >+33384731079 (333m)Municipal Les Chaumes Du Mont - Nolay (21) >+33380217961 (316m)Aux sources de l�Yonne - Anverse (58) [<51] >+33386761570 (659m)La Chauvotte - La Grande Verriere (71) [<51] >+33385824971 (365m)Municipal - Villapourcon (58) [<51] (01/06-30/09) >+33386786260 (411m)La Bruyere - Nolay (21) [<51] >+33380218759 (319m)Le Canoe - Chaussin (39) >+33384817655 (184m)Municipal Lac de la Chausseliere - La Guyonniere (85) >+33251415032 (69m)Municipal Pannecot Plaisance - Limanton (58) [<51] (15/06-15/09) >+33386843270 (206m)Le Rouge Gorge -�St Laurent sur Sevre (85) (24/03-10/10) >+33251678639 -CCA(150m)De La Foret - Levier (25) (01/01-31/12) >+33381895346 -CCA(722m)Municipal Les Taupeaux - Issoudun (36) (16/05-14/09) >+33254031346 (125m)Municipal de la Porte d'Arroux - Autun (71) (07/04-26/10) >+33385521082 -CCpg351-CCA(287m)Le Caravan'Ile - La Gueriniere (85) (15/03-15/11) >+33251395029 (2m)Les Moulins - La Gueriniere (85) (01/04-30/09) >+33251395138 (2m)Ferme Auberge L'ile Suavage - Bouin (85) [<51] >+33251491211 (1m)Municipal Des Ormes - Les Ormes (86) [<51] >+33553366026 (44m)La Grosse Motte - Descartes (37) [<51] (01/05-30/09) >+33247598590 (47m)Municipal Le Clos Imbert - Thouars (79) >+33549661799 (60m)La Halte Jurassienne - Mouchard (39) [<51] >+33384378392 (275m)Nevers -�Nevers (58) (12/04-13/10) >+33684986979 -CCA(174m)Municipal Le Bois Maussant** - Levroux (15/06-15/09) >+33254357054 (134m)Municipal la Bosse - l'Epine (85) (01/04-30/09) >+33251390107 -CCA(9m)La Grappe d'Or*** -�Meursault (21) (01/04-15/10) >+33380212248 -CCA(257m)Le Pont Vert - Epinac (71) >+33385820026 (322m)Municipal Du Lac d'Hautibus - Argenton les Vallee (79) (01/04-30/09) >+33549659508 (110m)La Rabine - Machecoul (44) (01/04-30/09) >+33240023048 (5m)Municipal La Menetrie - Chatillon sur Indre (36) [<51] (16/05-30/09) >+33678271639 (88m)Le Val d'Amour - Ounans (39) >+33384376189 (221m)Indigo - Noirmoutier-en-l'�le (85) (10/04-29/09) >+33251390624 -CCA(4m)Municipal Clair Matin - Noirmoutier en l'Ile (85) >+33251390556 (6m)Les Logis de l'Oumois - Maulevrier (49) [<51] >+33626939345 (131m)La Plage - Seurre (21) >+33380204922 (177m)Municipal De l'Escame - Moulins Engilbert (58) [<51] (25/06-15/09) >+33386842612 (238m)Les Radeliers - Port Lesney (39) (01/05-30/09) >+33381883535 (245m)La Plage Blanche -�Ounans (39) (01/05-30/09) >+33384376963 -CCA(214m)Municipal Beausoleil - Loudun (86) [<51] >+33549981422 (76m)l'Etang de la Fougeraie - Saint Leger de Fougeret (58) >+33386851185 -CCA(436m)Naturist - Club Du Soleil - Belmont (39) >+33384815491 (209m)Municipal - Richelieu (37) [<51] >+33247581502 (56m)La ferme Le Bois Noir - Saint Hilaire de Loulay (85) [<51] >+33621023085 (66m)Municipal Les Deux Rivieres - La Celle en Morvan (71) [<51] (26/04-21/09) >+33385541539 -CCA(326m)La Loire - Fourchambault (58) (29/03-04/11) >+33386608159 -CCA(169m)Les 3 Ours - Montbarrey (39) (15/04-30/09) >+33384815045 -CCA(213m)A la ferme Chez Claudine - Rennes sur Loue (25) [<51] (15/05-15/10) >+33680962180 (259m)Les Paquiers* - Corberon [<51] (01/01-31/12) >+33380266544 (183m)Municipal - Pouilly sur Saone (21) >+33380211583 (178m)Les Sables - Pouilly sur Saone (21) [<51] >+33380204350 (176m)Les Roussieres - Noirmoutier en l'Ile (85) >+33251391301 (0m)La Clere - Noirmoutier en l'Ile (85) [<51] (01/05-30/09) >+33251392144 (6m)Les Bords de Loue*** - Parcey (39) (01/05-05/09) >+33384710382 -CCA(196m)La Pointe - Noirmoutier en l'Ile (85) >+33251391670 (3m)Aire naturelle Municipale Launay - Bridore (37) [<51] >+33247947265 (106m)Les Bouleaux** - Vignoles [<51] (01/01-31/12) >+33380222688 (200m)Intercommunal La Noue de l'Anse* - Villeneuve sur Cher [<51] (01/06-25/09) >+33248556660 (119m)Municipal Bords De Loue - Arc et Senans (25) [<51] (27/04-28/09) >+33381574320 (234m)Municipal Les Cent Vignes**** - Beaune (15/03-31/10) >+33380220391 (223m)Rural de Mme Gautier - Saint Hilaire de Loulay (85) [<51] >+33251941007 (37m)Lac de Ribou - Cholet (49) (25/04-15/09) >+33241497430 (105m)Du Collet - Les Moutiers en Retz (44) >+33240214092 (4m)Le Lava - Gilley (25) [<51] (01/01-31/12) >+33381433088 (865m)Municipal La Louve - Champagne sur Loue (39) [<51] (01/04-30/09) >+33384376912 (238m)Les Oyes - Mouthier Haute Pierre (25) [<51] (01/04-31/10) >+33381609139 (388m)La Boulogne - Saint Philbert de Grand Lieu (44) (01/04-30/09) >+33240788879 -CCA(3m)Municipal - Ligueil (37) [<51] (01/06-31/08) >+33247596172 (76m)Municipal - Arleuf (58) [<51] >+33386788037 (644m)Municipal le Champaloux - Lods (25) [<51] >+33381609011 (363m)Aire Naturelle Chateau de Valogne - Sommant (71) [<51] (15/04-15/10) >+33385826297 (342m)La Crepiniere - Verneuil sur Indre (37) [<51] >+33247947125 (113m)Rural Relais Garennes - Montbert (44) [<51] (01/06-30/09) >+33240047873 (15m)Les Chenes verts - Bourgneuf en Retz (44) (01/04-14/09) >+33240214816 (6m)La Croix de la Motte** - Nouatre (15/06-15/09) >+33247652038 (37m)Cul de la Lune - Morteau (25) [<51] (01/06-21/09) >+33381671752 (754m)Municipal - Chatillon en Bazois (58) [<51] >+33386841476 (229m)Municipal Le Perthuy d'oiseau - Chateau Chinon Ville (58) (01/05-30/09) >+33386850817 (559m)Aire naturelle de Le Moulin De La Touche - Ligueil (37) [<51] >+33247919461 (81m)La Baie Doree - Bourgneuf en Retz (44) >+33240214114 (20m)Le Manoir de Bezolle - Saint Pereuse (58) (01/01-31/12) >+33386844255 -CCpg346-CCA(359m)A la ferme de la Rasse - Arc sous Cicon (25) [<51] (15/05-30/09) >+33643464457 (816m)Coin de Ciel - Saint Lumine de Clisson [<51] (01/01-31/12) >+33240547111 (31m)Le Village De La Mer - Les Moutiers en Retz (44) >+33240646590 (5m)Le Prigny - Les Moutiers en Retz (44) (01/01-31/12) >+33240647381 (9m)Municipal Le Pre Bailly - Vuillafans (25) [<51] (15/03-30/09) >+33608110144 (350m)Naturist - Moulin de la Ronde - Vatan (36) [<51] >+33254498328 (131m)Rural de Rousseau Michel - Boussay (44) [<51] >+33240068561 (86m)Municipal Les Premiers Pres** - Savigny les Beaune (15/03-30/09) >+33380261506 (277m)Pont De Charrey - Pagny La Ville (21) >+33380665277 (177m)La Goelette - La Bernerie en Retz (44) >+33240646152 (5m)Municipal De La Ruelle Au Loup** - Vatan (01/05-15/09) >+33254499137 (127m)Les Brillas - Les Moutiers en Retz (44) (11/04-12/10) >+33240827978 -CCA(18m)Municipal Robinson*** - Bourges (15/03-15/11) >+33248201685 (128m)Le Serpolin - Clere sur Layon (49) [<51] (01/01-31/12) >+33241524308 (96m)La Raudiere - Saint Maurice la Fougereuse (79) >+33549802974 (116m)Aire naturelle Municipale Le Ternin - Lucenay l'Eveque (71) [<51] >+33385826186 (336m)Aire naturelle Municipale - Saint Paul du Bois (49) [<51] >+33241758208 (133m)Municipal du Pont de Bussy - Anost (71) (01/04-30/09) >+33385827907 (453m)Aire naturelle Municipale - Montgesoye (25) [<51] >+33381622314 (350m)Municipal La Chenaie - Montapas (58) [<51] (01/04-31/10) >+33386583432 (248m)Municipal La Potiniere - Ecueille (36) [<51] (01/06-30/09) >+33254402110 (143m)Aire Naturelle du Bois Municipal - Sepmes (37) [<51] >+33247654487 (92m)Les Ecureuils - La Bernerie en Retz (44) (12/04-14/09) >+33240827695 -CCA(22m)Municipal Les Chanternes - Pougues les Eaux (58) (01/06-30/09) >+33386688618 (183m)Municipal - Reuilly (36) [<51] (15/05-15/09) >+33254034900 (112m)Le Poteau - La Bernerie en Retz (44) >+33240827371 (32m)Le Pasquier*** - Dole (39) (15/03-25/10) >+33384720261 -CCA(201m)A la ferme La Metairie d'Ardennes - Sainte Pazanne (44) [<51] >+33240026067 (4m)Municipal Le Moulin - Clisson (44) (12/04-15/10) >+33240544448 (37m)Les Epiceas - Preuilly (18) (01/06-31/08) >+33248571204 (115m)Municipal - Chatin (58) [<51] >+33386852362 (434m)Boutinardiere - Pornic (44) (01/04-30/09) >+33240820568 -CCA-BD_FR-H.003b(28m)Parc des Allais**** - Trogues (10/04-30/09) >+33499572121 -CCpg318(38m)Le Papillon - Cussy en Morvan (71) [<51] (25/04-01/09) >+33385546090 (462m)Le Chanet - Ornans (25) (01/04-30/09) >+33381622344 -CCA(346m)La Roche d'Ully - Ornans (02/04-15/10) >+33381571779 -CCpg291(335m)Les Herlequins - Saint Jean de Losne (21) (01/05-30/09) >+33380392226 (178m)Moulin de Prissey** - Premeaux Prissey (01/04-15/10) >+33380623115 -CCA(212m)La ferme Les Noues - Maisdon sur Sevre (44) [<51] >+33240066222 (49m)Municipal l'Etoile- Saint Hilaire de Chaleons (44) [<51] (01/04-31/08) >+33240317040 (17m)Municipal Les Promenades - Quingey (25) (02/05-30/09) >+33381637401 (264m)Municipal de Marans** - Ste. Maure de Touraine (01/04-30/09) >+33247654493 (73m)Chateau la Rolandiere*** - Trogues (37) [<51] (20/04-20/09) >+33247585371 -CCA(58m)Municipal Des Isles - Bligny sur Ouche (21) (01/05-30/09) >+33380201121 (350m)Municipal La Foulquetiere - Lucay Le Male (36) [<51] (01/04-15/10) >+33254405060 (156m)La Madrague - Pornic (44) (01/01-31/12) >+33240820673 (23m)Municipal des Soulins - Corancy (58) [<51] (11/04-26/10) >+33386844752 (328m)La Chenaie - Pornic (44) (28/04-14/09) >+33240820731 (22m)Du Golf - Pornic (44) (15/04-27/09) >+33240824617 (37m)Le Patisseau - Pornic (44) (12/04-28/09) >+33240821039 -CCA(25m)Le Port Cheri - Pornic (44) (01/01-31/12) >+33240823457 (27m)Bon Accueil - Pornic (44) (01/04-30/09) >+33609568428 (29m)Municipal Les Bords de Vienne - l'Ile Bouchard (58) (01/03-25/10) >+33247952359 (36m)Les Coeures - Pornic (44) >+33687293362 (36m)La Citadelle -�Loches (37) (31/03-12/10) >+33247590591 -CCA(71m)Les Amis de la Nature - Prefailles (44) (15/06-31/08) >+33240312022 (17m)Port Meleu - Prefailles (44) [<51] (15/04-15/09) >+33240216291 (13m)Les Marronniers - Rochefort sur Nenon (39) (01/04-31/10) >+33384705037 (204m)A la Ferme Equestre du Garotin - Trementines (49) [<51] >+33698049299 (132m)Agreable - Montigny en Morvan [<51] >+313652640168 (439m)A la ferme Moulin de Saussaye - l'Ile Bouchard (37) [<51] >+33247585044 (36m)Les Nobis - Montreuil Bellay (49) (29/03-05/10) >+33241523366 -CCA(38m)Eleovic - Prefailles (44) (05/04-28/09) >+33240216160 (21m)l'Etang de Fouche - Arnay Le Duc (21) (12/04-12/10) >+33380900223 -CCA(360m)Municipal De la Moriniere - Port Saint Pere (44) [<51] (01/06-30/09) >+33240315013 (2m)Municipal** - Gracay [<51] (01/04-15/09) >+33248512414 (106m)La ferme de l'Arche - Ligre (37) [<51] >+33247931333 (35m)Municipal - Planchez (58) >+33386784203 (621m)l'Etang du Merle - Crux la Ville (58) (07/04-26/10) >+33386583842 -CCpg347-CCA(360m)La Pointe - Prefailles (44) (01/03-15/11) >+33240215205 (20m)Aire naturelle - Arthon en Retz (44) [<51] (01/04-30/09) >+33240648229 (8m)Albatros - La Plaine sur Mer (44) (05/04-25/10) >+33661164245 (18m)La Plage - Osselle (25) [<51] (15/04-30/09) >+33381638388 (219m)Aire naturelle de Caille Francois - Panzoult (37) [<51] >+33247952637 (35m)Les Bleuets - Pornic (44) (01/04-30/09) >+33681647617 (32m)La Renaudiere - La Plaine sur Mer (44) (26/04-15/09) >+33240215003 (22m)La Tabardiere - La Plaine sur Mer (44) (12/04-20/09) >+33240215883 -CCpg97-CCA(17m)La Pree - Prefailles (44) >+33240210264 (4m)Municipal Les Iles - Chaumard (58) [<51] >+33386780300 (329m)Municipal De la Vallee du Lys - Vihiers (49) [<51] (16/06-07/09) >+33241750014 (76m)Municipal - Orchamps (39) [<51] (01/06-15/09) >+33384713035 (212m)Parc de Fierbois**** - Ste.Catherine de Fierbois (15/04-05/09) >+33247654335 -CCA(109m)l'Ile** - Ranchot [<51] (01/01-31/12) >+33384711356 (214m)Municipal - Mehun sur Yevre (18) [<51] (08/05-30/09) >+33248574451 (123m)Naturist - Club Naturiste de Besancon - Osselle (25) [<51] (01/05-30/09) >+33652858892 (254m)Bernier - La Plaine sur Mer (44) [<51] (27/04-28/09) >+33240210431 (11m)Municipal Les Peupliers- Fraisans (39) [<51] >+33384813662 (215m)La Guichardiere - La Plaine sur Mer (44) (12/04-30/09) >+33240215509 (7m)Le Thouet - Montreuil Bellay (49) [<51] (01/01-31/12) >+33241387417 -CCA(39m)La Raudiere - Sainte-Maure de Touraine (37) [<51] >+33247656502 (120m)Le Ranch - La Plaine sur Mer (44) (01/04-30/09) >+33240215262 -CCA(13m)Municipal Du Lac - Montigny en Morvan (58) (15/04-15/10) >+33386847576 (328m)A la ferme de la Salle - Avon les Roches (37) [<51] (Easter-01/11) >+33247952430 (62m)Municipal Les Chenes - Valencay (36) [<51] (01/05-19/09) >+33254000392 (127m)Aire naturelle Les Coteaux du Lac - Chemille sur Indrois (37) [<51] (29/03-05/10) >+33247927783 -CCA(91m)Rose de Provins - Gien sur Cure (58) [<51] (18/04-31/10) >+33386784136 (648m)Le Vieux Chateau - Saint Michel Chef Chef (44) (01/04-31/10) >+33623460660 (11m)Le Thar Cor - Saint Michel Chef Chef (44) (11/04-28/09) >+33240278281 (5m)A la Ferme de la Chaumine - Le Louroux (37) [<51] (01/04-15/10) >+33247928209 (98m)Intercommunal De l'Ile Auger - Chinon (37) (01/04-30/10) >+33247930835 (33m)Municipal De Baye - Bazolles (58) [<51] >+33386389033 (265m)La Riviera - Saint Michel Chef Chef (44) (01/03-30/11) >+33228535488 (14m)A la ferme de Princay - Anjouin (36) [<51] (01/01-31/12) >+33254406730 (135m)Le Bois Fleuri - Saint Epain [<51] (01/05-30/09) >+33247656773 (105m)Municipal le Bourg - Moux en Morvan (58) [<51] >+33386761150 (491m)Le Haut Village - Saint Michel Chef Chef (44) (21/03-02/11) >+33240399345 (24m)l'Hermitage de Chevigny - Moux en Morvan (58) (15/04-30/09) >+33386845097 (592m)Clos Mer et Nature - Saint Michel Chef Chef (44) (01/04-16/10) >+33240278571 (11m)Municipal La Cabane Verte - Moux en Morvan (58) (15/04-15/10) >+33386760225 (592m)La Vallee des Vignes - Concourson sur Layon (49) (01/05-30/09) >+33241598635 -CCA(48m)Bel Essor - Saint Michel Chef Chef (44) (26/04-23/09) >+33240278540 (12m)Municipal La Saulaie - La Charite sur Loire (58) (01/05-30/09) >+33386700083 (155m)La Croix du Gue - Bouguenais (44) >+33240653638 (10m)De la Base de Plein Air et de Loisirs - Bazolles (58) (01/04-30/09) >+33386389739 (263m)Municipal les Pres de la Ville - Premery (58) [<51] (12/04-28/09) >+33386681240 (236m)La Fosse De Tigne - La Fosse De Tigne (49) [<51] >+33241679210 (67m)Les Mesanges - Montsauche les Settons (58) (14/05-15/09) >+33386845577 -CCA(590m)Le Bord de Mer - Saint Michel Chef Chef (44) (01/03-29/11) >+33240279316 -CCA(6m)Sur Yonne - Epiry (58) [<51] (06/04-31/10) >+33386224667 (231m)Ambiance Morvan - Ouroux en Morvan (58) [<51] >+33386782221 (563m)Plage du Midi -�Montsauche les Settons (58) (19/04-11/10) >+33386845197 (592m)Les Genets - Ouroux en Morvan (58) (11/04-27/09) >+33386782288 -CCA(562m)Rural de Goguelat Bernard - La Collancelle (58) [<51] >+33386224189 (258m)Plage des Settons - Montsauche les Settons (58) (01/05-28/09) >+33386845199 (597m)Municipal Les Gresillons - Saint Georges sur Layon (49) [<51] (01/04-30/09) >+33241500232 (64m)Municipal La Baie de la Faye - Montsauche les Settons (58) [<51] (01/06-01/09) >+33386845583 (594m)Municipal - Saint Martin d'Auxigny (18) [<51] (01/05-01/10) >+33248645058 (168m)l'Arquebuse - Auxonne (21) (20/01-19/12) >+33380310689 -CCA(182m)La Fritillaire - Savigny en Veron (37) >+33247580379 (32m)A la ferme du Bridier - Montsauche les Settons (58) [<51] (01/03-15/11) >+33386845370 (633m)Coulvee - Chemille (49) [<51] (01/05-15/09) >+33241303997 -CCpg106-CCA(82m)Aire naturelle Amitie et Nature - Auxonne (21) [<51] >+33380373644 (181m)Le Grand Fay - Saint Pere en Retz (44) (01/04-31/10) >+33240217289 (28m)Municipal Les Rives de Douet - Doue la Fontaine (49) (01/04-30/09) >+33622712553 (61m)Naturist - Le Bois de la Herpinere - Turquant (49) [<51] (012/04-31/10) >+33241517481 (98m)Les Pierres Couchees - Saint Brevin les Pins (44) (24/05-13/09) >+33240278564 (15m)Intercommunal Belle Rive - Candes Saint Martin (37) [<51] >+33662324738 (35m)Municipal de Bellon*** - Vierzon (01/05-30/09) >+33248754910 (107m)Les Rochelets - Saint Brevin les Pins (44) (01/01-31/12) >+33240274025 (8m)Municipal Le Fouzon - Varennes sur Fouzon (36) [<51] >+33254411326 (81m)La Roche Marguerite - Saint Brevin les Pins (44) [<51] >+33240315013 (12m)L'Isle Verte -�Montsoreau (49) (30/03-12/10) >+33241517660 -CCpg105(36m)Aire naturelle de Pruneau Roger - Saint Pere en Retz (44) [<51] >+33240273659 (8m)Le Pas du Gu - Saint Brevin les Pins (44) [<51] (15/06-15/09) >+33240272555 (6m)Les Mouettes - Saint Pere en Retz (44) >+33240272731 (11m)Municipal l'Eglise- Villaines les Rochers (37) [<51] (01/06-15/09) >+33247454308 (71m)A la ferme de Le Cret - Pierrefontaine Les Varans (25) [<51] (01/05-30/09) >+33381560476 (703m)Les Peupliers - Saint Pere en Retz (44) [<51] (01/01-31/12) >+33240273291 (7m)Sunnywingsplace - Guipy (58) [<51] >+31650919135 (246m)Municipal Des Bords de Loire - Chouze sur Loire (37) [<51] (30/06-31/08) >+33247951010 (33m)Relais Des Hautes Cotes - Chamboeuf (21) [<51] (26/04-12/09) >+33380585013 (517m)A la ferme de la Pequiniere - La Boissiere du Dore (44) [<51] (01/04-31/10) >+33240337049 (92m)D'Ainay - Guipy (58) [<51] >+33386290711 (241m)Le Fief - Saint Brevin les Pins (44) (12/04-28/09) >+33240272386 -CCA(6m)Lac de Panthier**** -�Vandenesse en Auxois (21) (15/04-30/09) >+33380492194 -CCA(373m)La Courance - Saint Brevin les Pins (44) (01/01-31/12) >+33240272291 (7m)Village de l'Eve - Saint Nazaire (44) (01/05-07/09) >+33546223822 (29m)Le Petit Port**** - Nantes (44) (23/02-31/12) >+33240744794 -CCpg98-CCA(14m)A la ferme Le Vieux Moulin - Charmoille (25) [<51] >+33381443029 (685m)Le Saint Michel - Maiche (25) >+33381641256 (827m)l'Etang de la Breche - Varennes sur Loire (49) (19/04-14/09) >+33241512292 (28m)Municipal - La Chapelle sur Loire (37) [<51] (01/05-15/09) >+33247973391 (33m)Le Chene** - Saint Julien de Concelles (01/04-30/09) >+33240541200 -CCA(5m)Bel Air - Pornichet (44) (18/04-14/09) >+33240611078 (21m)Les Loriettes - Pornichet (44) (01/04-30/09) >+33240611645 (27m)Les Belles Rives** - Thenioux [<51] (01/07-31/08) >+33248530614 (90m)Belle Riviere*** - Ste Luce sur Loire (01/01-31/12) >+33240258581 (5m)Du Bugeau - Pornichet (44) (12/04-28/09) >+33240610202 -CCA(19m)Municipal Le Port Roux - Villebernier (49) (07/07-25/08) >+33241672304 (27m)Municipal de la Blardiere - Rigny Usse (37) (01/06-30/09) >+33247955585 (36m)Saint Sebastien - Pornichet (44) (15/06-15/09) >+33240615307 (12m)Municipal du Migron - Frossay (44) [<51] (12/06-15/09) >+33678035704 (2m)De l'Ardan - Chaumot (58) [<51] (01/04-01/10) >+33386200770 -CCA(188m)Municipal Le Sabot - Azay le Rideau (37) (01/04-31/10) >+33247454272 (43m)Municipal Le Chambon - Chabris (36) (01/06-30/09) >+33254400759 (78m)Ile d'Offard -�Saumur (49) (15/03-16/11) >+33241403000 -CCA(30m)Municipal - Brassy (58) [<51] (15/05-15/10) >+33386222031 (405m)Municipal Les Saules** - Chatres sur Cher (08/05-06/09) >+33254980455 (93m)Naturist - Chataigneraie - Coueron (44) >+33611752187 (67m)Le Mindin - Saint Brevin les Pins (44) (01/01-31/12) >+33240274641 (7m)Municipal De l'Ecluse - Thouarce (49) [<51] (15/04-15/09) >+33241541436 (29m)Les Cochards**** -�Seigy-Saint Aignan (01/04-15/10) >+33254751559 -CCpg319(69m)Vert Auxois - Pouilly en Auxois (21) [<51] (01/05-15/10) >+33380907189 -CCA(383m)La Plage*** - Chalezeule-Besancon (25) (01/04-30/09) >+33381505462 -CCA(244m)l'Oasis - Pornichet (44) >+33240610880 (3m)Municipal** - Cormery [<51] (15/06-05/09) >+33247430888 (60m)Municipal Val Rose** - Mennetou sur Cher [<51] (07/05-07/09) >+33254980119 (90m)La Govelle - Batz sur Mer (44) [<51] (01/01-31/12) >+33240239163 (8m)Municipal Capitaine - Bourgueil (37) (15/05-15/09) >+33247978562 (29m)Les Forges - Pornichet (44) (05/07-31/08) >+33240611884 (32m)Municipal La Forge - Goumois (25) [<51] (01/04-31/10) >+33381442824 (502m)Le Moulin de Guigot - Glamondans (25) [<51] (01/05-30/10) >+33381630015 (391m)Municipal Le Clein - Le Pouliguen (44) (21/03-28/09) >+33240424399 (2m)Parici*** - Chatillon sur Cher (01/04-30/09) >+33254710221 (76m)Municipal Les Mouettes - Le Pouliguen (44) (21/03-19/10) >+33240150808 (3m)Municipal Les Saults - Saint Brisson (58) [<51] >+33386787080 (608m)Municipal Du Port** - Noyers sur Cher [<51] (01/05-30/09) >+33254750276 (71m)Municipal* - Monts [<51] (01/06-31/08) >+33247341180 (53m)Municipal Les Chataigniers** - Selles sur Cher (10/04-20/09) >+33254976726 (75m)La Colombiere - Pesmes (70) (01/05-31/10) >+33384312015 (191m)Les Trois Chenes - Pornichet (44) (15/03-15/10) >+33240611336 (25m)Les Paludiers - Batz sur Mer (44) (05/04-28/09) >+33240238584 -CCA(6m)Municipal la Coletterie - Saint Etienne de Montluc (44) (01/11-30/09) >+33240869744 (38m)Municipal De l'Etang du Goulot - Lormes (58) (01/05-30/09) >+33386228237 -CCA(421m)Municipal - Sainte Marie sur Ouche (21) [<51] (21/04-30/09) >+33380236088 (286m)Municipal** - Villefranche sur Cher [<51] (15/05-15/09) >+33254964227 (84m)Le Malaga - Pouilly sur Loire (58) (01/05-15/09) >+33386391454 (148m)Les Salorges - Cordemais (44) >+33228017453 (6m)Bois d'Amour - La Baule Escoublac (44) (05/04-28/09) >+33240601740 -CCpg96(11m)De l'Estuaire - Paimboeuf (44) (01/01-31/12) >+33646416093 (8m)La Plage*** - Veigne (25/04-30/09) >+33247262300 (55m)Saulieu - Saulieu (21) (10/03-09/11) >+33380641619 -CCpg350-CCA(533m)Municipal Vert Lagon*** - Marnay (01/05-30/09) >+33384317141 -CCpg292(201m)La Grange Rouge*** - Montbazon (37) (01/04-15/10) >+33247260643 -CCA(54m)Loire et Chateaux - Brehemont (01/01-31/12) >+33661910142 -CCA(34m)Municipal Du Petit Bois - Henrichemont (18) [<51] (02/05-31/10) >+33248269471 (281m)Municipal La Croix du Chateau - Dun les Places (58) [<51] >+33386846205 (564m)La Pierre Longue - Le Croisic (44) (15/03-15/11) >+33240231344 (10m)Municipal Le Port*** - Mareuil sur Cher (15/04-15/09) >+33254327951 (67m)Les Ajonc d'Or - La Baule Escoublac (44) (01/03-30/11) >+33240603329 (9m)Le Chantepie - Saint-Hilaire-Saint-Florent (49) (26/04-13/09) >+33241679534 -CCpg104-CCA(67m)La ferme Le Mirebeau - Rablay sur Layon (49) [<51] (01/05-30/09) >+33241783292 (54m)Le Paradis - Le Croisic (44) (15/03-15/11) >+33240230789 (8m)Municipal De Lannivrec - Locmaria (56) (12/04-28/09) >+33297317375 (60m)Chalet du Montal - Dun les Places (58) [<51] (05/04-28/09) >+33386846277 (440m)l'Ocean - Le Croisic (44) (12/04-28/09) >+33240230769 -CCA-BD_FR-A.178(5m)Tremondec - Guerande (44) (01/04-30/09) >+33240600007 (16m)La Roseraie -�La Baule (44) (05/04-28/09) >+33240604666 -CCpg95-CCA(35m)Le Po Dore - Allonnes (49) (15/03-15/11) >+33241387880 -CCA(23m)De la Coudraye - Saint Lambert du Lattay (49) [<51] (01/04-31/10) >+33241784426 (47m)La Ferme de Montaigu- Valoreille (25) [<51] (01/05-01/10) >+33381933360 (713m)l'Eden - La Baule Escoublac (44) (28/03-15/11) >+33240600323 (48m)Municipal - Saint Martin du Puy (58) [<51] (01/04-31/10) >+33386226135 (414m)Municipal Paulin Roulin - Crezancy en Sancerre (18) [<51] (01/04-15/10) >+33248790394 (278m)La Chanoie - Pontailler sur Saone (21) (15/04-15/10) >+33380361058 (185m)Municipal De Port Andro - Locmaria (56) (24/05-14/09) >+33297317325 (8m)La Terre d'Entente - Saint Martin de la Place (49) (01/04-30/09) >+33972303172 (27m)Kernest - Bangor (56) >+33297315626 (49m)Municipal Des Grenettes - La Varenne (49) [<51] (01/06-15/09) >+33240985892 (12m)La Valboisiere - Perrigny sur l'Ognon (21) [<51] (01/01-31/12) >+33380478078 (186m)Municipal - Neuvy sur Barangeon (18) [<51] (01/04-30/09) >+33248516892 (148m)Municipal du Bourg - Bangor (56) [<51] >+33297318975 (46m)Bellilois des Grands Sables - Locmaria (56) >+33297318446 (34m)Municipal Beau Rivage - Emagny (25) >+33351956758 (206m)Le Chateau et Du Lac - Saint Agnan (58) (01/04-30/10) >+33386787370 (535m)Municipal Du Chene - Pruniers en Sologne (41) [<51] (15/06-15/09) >+33254965231 (89m)Les Chalands Fleuris - Saint Andre des Eaux (44) (05/04-27/09) >+33240012040 (12m)Municipal Le Lac Kir *** - Dijon (01/04-15/10) >+33380305401 (240m)Les Grands Champs - Saint Hippolyte (25) (01/01-31/12) >+33381965453 (393m)Du Bien Vivre - St. Romain sur Cher [<51] (01/01-31/12) >+33254717374 (99m)Le Village - La Motte Ternant (21) [<51] (01/04-01/10) >+33380843011 (384m)Municipal Les Palisseaux - Chaudefonds sur Layon (49) [<51] >+33241780410 (16m)De l'Ile - Pont les Moulins [<51] (01/05-31/08) >+33381841523 -CCA(287m)Aire naturelle Municipale - Heuilley sur Saone (21) [<51] (15/05-30/09) >+33380474218 (189m)La ferme Le Bois Madame - Grezille (49) [<51] (01/03-30/11) >+33241455037 (82m)Le Moulin Fort*** - Francueil (12/04-25/09) >+33247238622 -CCA(58m)River Camp - Civray de Tourraine [<51] (01/06-31/08) >+33247302905 (58m)Municipal Les Tainieres - Donges (44) >+33240910647 (10m)Municipal De La Gatine*** - Blere (01/04-10/10) >+33247579260 (55m)Municipal Du Layon - Saint Aubin de Luigne (49) [<51] (01/05-30/09) >+33241783328 (18m)Municipal Les Chardons Bleus - La Turballe (44) (12/04-28/09) >+33240628060 (4m)De L'Ecluse** - Chisseaux (01/04-30/09) >+33247238710 (58m)Les Peupliers** - Geneuille (25) [<51] (01/05-31/10) >+33672147253 (220m)Municipal du Lac - Langeais (37) (01/06-15/09) >+33247968580 (40m)La Fontaine des Pres - Chenonceaux (37) (01/06-15/09) >+33247239013 (60m)Trion Guen - Le Palais (56) (01/01-31/12) >+33297318576 (51m)A la ferme la Belle Etoile - Brissac Quince (49) [<51] (01/05-15/09) >+33241548118 (62m)De Leveno - Guerande (44) (12/04-28/09) >+33240247930 -CCA-BD_FR-A.176(44m)Couleurs du Monde - Faverolles sur Cher (41) (29/03-27/09) >+33254320608 -CCA(61m)Les Loges - La Breille les Pins (49) [<51] (01/04-31/10) >+33241528166 (73m)Municipal - Baume les Dames (01/01-31/12) >+3381843889 (266m)Municipal de l'Etourneau - Montrichard (41) (01/04-30/09) >+33254321016 (61m)Le Panorama - Guerande (44) (01/04-30/10) >+33240247941 (36m)Le Brehadour - Guerande (44) (02/04-24/09) >+33240176515 (28m)Au Bord de Loire - Gennes (49) (19/04-30/09) >+33241380467 (27m)Les Portes de Sancerre - Saint Satur (18) (05/04-19/10) >+33248721088 -CCA(147m)Municipal - Hoedic (56) [<51] (01/07-31/08) >+33297524888 (5m)Parc Sainte Brigitte - La Turballe (44) (01/04-30/09) >+33240248891 (40m)La Tour** - Oudon (44) [<51] (01/06-15/09) >+33240838022 (6m)Municipal Le Parc - Cinq Mars la Pile (37) [<51] (01/01-31/12) >+33627866391 (40m)l'Ocean - Le Palais (56) (01/04-30/09) >+33297318386 (30m)Municipal Le Clos de Doubs - Glere (25) (01/03-31/10) >+33473191111 (480m)Municipal Beauregret** - Drain (49) [<51] (01/05-30/09) >+33240982016 (10m)Municipal** - Chemery [<51] (01/06-30/09) >+33254713108 (87m)l'Etang - Guerande (44) (01/01-31/12) >+33240619351 (14m)Municipal le Paquier - Vaufrey (25) >+33637515690 (399m)La Fontaine - Guerande (44) (11/04-26/10) >+33240249619 -CCA(32m)Municipal** - Monthou sur Cher [<51] (01/05-30/09) >+33254715385 (75m)De la Confluence - Savonnieres (37) (25/04-28/09) >+33247501571 (44m)Le Candais - Chalonnes sur Loire (49) (01/05-30/09) >+33241780227 (16m)Le Segreen - La Turballe (44) [<51] >+33241923271 (7m)Municipal Des Pins - Nancay (18) (01/04-30/10) >+33248518180 (137m)La Falaise - La Turballe (44) (01/04-02/11) >+33240233253 -CCA(6m)Municipal De Lonot* - Baume les Dames [<51] (01/05-30/09) >+33381843889 (278m)Bordeneo - Le Palais (56) (12/04-28/09) >+33297318896 (36m)Le Tournefeuille **** - Romorantin (41) (01/05-30/09) >+33254953708 (86m)La Mignardiere**** -�Ballan-Mire (01/04-20/09) >+33247733100 -CCA(89m)Municipal Du Lac - Savenay (44) (01/03-30/10) >+33240583176 (51m)Verte Rive** - Cromary [<51] (01/04-30/09) >+33477617812 (218m)Municipal Les Isles*** - Veretz (16/05-09/09) >+33247505048 (54m)Val de Loire - Les Rosiers sur Loire (49) (04/04-30/09) >+33241519433 -CCA(20m)l'Esplanade** - Cromary (70) [<51] (01/04-30/09) >+33384918200 -CCA(218m)l'Etang - Brissac Quince (49) (26/04-13/09) >+33241917061 -CCA(36m)Paradis Nature - La Chapelle d'Angillon (18) [<51] (01/04-26/10) >+33248734012 (196m)Le Refuge - La Turballe (44) (01/06-30/09) >+33240233717 (15m)Les Plages de Loire - Rochefort sur Loire (49) (15/04-05/11) >+33241788211 -CCpg100-CCA(16m)l'Ile Mouchet** - Ancenis (44) (01/01-31/12) >+33240830843 (10m)La Vallee** - Moncey [<51] (01/01-31/12) >+33381578901 (219m)La Gyonniere** - La Pommeraye [<51] (15/03-25/10) >+33241778956 (81m)La Loge en Valee* - Bouzille [<51] (01/05-30/09) >+33240981294 (8m)Les Babins* - Bouzille [<51] (01/05-30/09) >+33240981299 (11m)La Source - Sauzon (56) (01/05-30/09) >+33297316095 (23m)l'Ile Batailleuse - Varades (44) (30/05-14/09) >+33240834501 (13m)Municipal De Penprad - Sauzon (56) (30/03-30/09) >+33297316482 (16m)Municipal - Donzy (58) [<51] (01/06-31/08) >+33386393028 (179m)Val de Loire - St. Avertin (37) (01/02-15/12) >+33247272760 -CCA(49m)Le Veridet - Piriac sur Mer (44) >+33240235850 (8m)Municipal Du Moulin Naudin - Varzy (58) [<51] (15/05-30/09) >+33386294312 (214m)Municipal Du Port - La Possonniere (49) [<51] (15/05-15/09) >+33241722208 (18m)Mon Calme - Piriac sur Mer (44) (05/04-30/09) >+33240236077 (12m)Parc de Montsabert - Coutures (49) (11/04-07/09) >+33241579163 -CCA(46m)Naturist - Le Clos Marot - Piriac-sur-Mer (44) (15/06-31/08) >+33240235920 (31m)Armor Heol - Piriac sur Mer (44) (05/04-21/09) >+33240235780 (15m)Les Flots Bleus - Piriac sur Mer (44) (01/01-31/12) >+33240235171 (8m)Les Granges - Luynes (37) (01/04-30/09) >+33247557905 -CCA(43m)A la Ferrme La Charmoise - Sassay (41) [<51] (01/03-31/10) >+33254795515 (112m)La ferme La Presle Verte - Oisly (41) [<51] (01/01-31/12) >+33615707402 (109m)Parc Du Guibel - Piriac sur Mer (44) (01/04-30/09) >+33240235267 -CCA(17m)Ile De Kernodet - Saint Molf (44) (01/01-31/12) >+33240625562 (19m)Municipal - Precy-sous-Thil [<51] (09/04-05/11) >+33380645718 (328m)La Tuilerie - Boult (70) [<51] (01/05-30/09) >+33384917200 (255m)Les Amis De la Nature - Piriac sur Mer (44) (15/06-15/09) >+33240236179 (8m)Intercommunal La Balance - Jars (18) [<51] (01/04-20/10) >+33248587450 (223m)l'Islette - Fondettes (37) [<51] (01/04-30/10) >+33247422642 (51m)La Grande Pature - Vernantes (49) [<51] (31/03-31/10) >+33241671890 (59m)La Promenade*** - Montjean s/Loire (49) (01/04-30/09) >+33241390268 -CCA(11m)Port St Maur - La Menitre (49) (15/05-15/09) >+33241456080 (21m)Municipal Les Peupliers*** - Montlouis s/Loire (01/04-25/10) >+33247508190 -CCpg317-CCA(51m)Municipal Les Isles * - Clerval [<51] (01/04-31/10) >+33381938619 (281m)Municipal La Vaivre* - Cirey [<51] (01/04-30/09) >+33384918143 (222m)l'Oree du Bois - Darois (21) >+33380356088 (505m)Municipal Le Paquillot * - Cirey [<51] (01/04-30/09) >+33384918143 (223m)A la ferme le Bonheur est dans le Pre - Couffe (44) [<51] >+33240980755 (22m)Fleur de Briere - Saint Lyphard (44) (01/04-30/09) >+33240420953 (5m)Le Chateau du Petit Bois - Mesquer (44) (01/04-12/10) >+33240426877 (20m)Le Chateau de Treambert - Mesquer (44) (12/04-20/09) >+33240425118 (7m)Municipal La Bastille * - Le Fresne s/Loire [<51] (01/05-30/09) >+33241392901 (16m)Le Port** - Ingrandes [<51] (01/06-15/09) >+33241392021 (12m)Municipal le Petit Arcachon * - La Ferte Imbault (01/05-15/09) >+33684996637 (103m)Municipal La Gare - Vitteaux (21) [<51] (15/04-01/11) >+33380496125 (336m)Prad-Heol - Mesquer (44) (01/04-31/10) >+33240426083 (13m)La Ferme le Verger - Marcilly les Vitteaux (21) [<51] >+33380496208 (353m)Les Acacias** - La Ville aux Dames (37) (01/01-31/12) >+33247440816 -CCA(51m)Les Varennes - Murs Erigne (49) (01/04-31/10) >+33241578215 (18m)Le Praderoi - Mesquer (44) [<51] (01/04-30/09) >+33240426672 (9m)Municipal Le Petit Mont en Jonc - Soings en Sologne (41) [<51] (01/06-31/08) >+33254987328 (105m)Soir d'Ete - Mesquer (44) (05/04-28/09) >+33240425726 (5m)l'Ile - Cosne Cours sur Loire (58) (01/04-31/10) >+33386282792 (142m)Municipal Le Bec de Cisse ** - Vouvray [<51] (01/05-30/09) >+33247526881 (53m)Le Beaupre - Mesquer (44) [<51] (01/04-30/09) >+33240426416 (8m)Port la Vallee - Saint Mathurin sur Loire (49) [<51] (01/01-31/12) >+33241573011 (23m)La Pindiere*** - Heric (01/01-31/12) >+33240576541 -CCA(31m)Aire naturelle Municipale - Champtoce sur Loire (49) [<51] (15/04-15/10) >+33241399180 (15m)Naturist - Bois des Forges - Clere Les Pins (37) (15/06-01/09) >+33247246231 (103m)Municipal des Fontaines - Breves (58) [<51] >+33386242078 (159m)Municipal De l'Ile d'Or - Amboise (37) (01/04-30/09) >+33247572337 (57m)Municipal Le Grand Jard** - Sainte Gemmes sur Loire [<51] (15/06-15/09) >+33241680095 (18m)La Baie - Asserac (44) (01/04-30/09) >+33240017116 (14m)l'Ile du Chateau*** - Les Ponts de Ce (01/04-31/10) >+33241446205 (23m)Municipal Le Lac - Rioz (70) (01/04-30/09) >+33384919159 (269m)Aire Naturelle La Ferme d'Isson - Asserac (44) [<51] (01/01-31/12) >+33240017463 (16m)Municipal De L'Arrachis - Ennordres (18) [<51] (01/05-30/09) >+33248580682 (164m)Port Mulon** - Nort sur Erdre (05/04-15/10) >+33240722357 -CCpg99-CCA(10m)Aire Naturelle La Bradiere - Savennieres [<51] (01/01-31/12) >+33241395188 (53m)Les Prairies de l'Etang - Asserac (44) (01/03-15/11) >+33240017335 (14m)A la Ferme Redunel - Asserac (44) [<51] (01/05-30/09) >+33240017198 (14m)Le Sologne*** - Salbris (41) (01/04-30/09) >+33254970638 -CCA(103m)Le Chant d'Oiseau - Mouliherne (49) [<51] (01/03-31/10) >+33241670976 (44m)l'Etoile De Mer - Asserac (44) (01/04-15/10) >+33240611336 (10m)Municipal Des Patis - Nazelles Negron (37) (01/05-14/09) >+33247577107 (55m)A la ferme de la Rente Neuve - Noiron sur Beze (21) [<51] >+33380367167 (210m)Les Bouleaux - Lucelle (68) >+33389408533 (697m)Municipal du Verdeau - Charge (37) (01/07-03/09) >+33247570422 (58m)Bois de Reveuge**** - Huanne Montmartin (25) (25/04-05/09) >+33381843860 -CCA(310m)Aire naturelle Le Clos des Bruyeres - Herbignac (44) [<51] (01/04-31/10) >+33240889623 (16m)Municipal - Saint Seine L'Abbaye (21) [<51] (01/05-01/09) >+33380350009 (460m)Chateau du Deffay -�Pontchateau (44) (01/05-30/09) >+33240880057 -CCpg94(19m)Du Port Caroline - Brain sur l'Authion (49) (01/04-31/10) >+33241804218 -CCpg102-BD_FR-A.216(18m)Le Moulin de l'Eclis - Asserac (44) (01/04-11/11) >+33240017669 -CCA(9m)Des Iles - Penestin (56) (12/04-30/09) >+33299903024 -CCpg91(6m)Municipal Le Bout Du Pont - Menetreol sur Sauldre (18) [<51] (Easter-30/09) >+33248580430 (152m)Le Jardin Botanique - Limeray (37) (01/01-31/12) >+33247301350 (58m)De Pont Mahe - Asserac (44) (01/04-14/11) >+33240017498 (8m)Le Ranrouet - Herbignac (44) (01/04-30/09) >+33240889623 (10m)Ker Lay - Penestin (56) (25/05-20/09) >+33299903128 (16m)Municipal Du Pont Picot - Clamecy (58) (01/04-30/09) >+33386270597 (153m)Les Lumes*** - l'Isle sur Le Doubs (01/04-30/09) >+33689144157 (288m)Municipal Longue Rive - Gray (70) (15/04-30/09) >+33384649044 (189m)Loscolo - Penestin (56) (15/06-15/09) >+33608219530 (12m)Lac de Maine**** -�Angers (49) (25/03-10/10) >+33241730503 -CCpg101-CCA(22m)Le Bois Beaumard - Pontchateau (44) [<51] (01/01-31/12) >+33240880336 (21m)Les Grands Ansanges** - Mandeure [<51] (01/04-31/10) >+33381352379 (331m)l'Ermitage - Vezelay (89) [<51] (01/04-31/10) >+33386332418 (255m)Municipal - Saint Pere (89) [<51] (14/04-30/09) >+33386332662 (146m)Huttopia Rille - Rille (37) (17/04-13/10) >+33247246297 -CCA(81m)A la ferme du Plessis - Rilly sur Loire (41) [<51] (01/04-30/09) >+33254209055 (92m)Municipal - Villemoisan (49) [<51] >+33241394775 (55m)Le Kerfalher - Penestin (56) (14/03-14/10) >+33299903345 (13m)Municipal Entre les Deux Ponts - Montbozon (70) [<51] >+33384205226 (241m)Salixcamp - Entrains sur Nohain (58) [<51] (01/04-30/09) >+33661375050 (215m)Municipal Le Chateau** - Blain [<51] (08/05-28/09) >+33240791100 (15m)Municipal du Lac de Pont*** - Pont et Massene (01/04-31/10) >+33380970126 (303m)Intercommunal Du Plan d'Eau de Courtavon - Courtavon (68) (01/05-30/09) >+33683415092 (436m)A la ferme Raviere - Bouhy (58) [<51] >+33386264084 (306m)D'Inly - Penestin (56) (12/04-15/09) >+33299903509 -CCA-BD_FR-A.167(19m)Municipal Le Goviro - Quiberon (56) (01/04-12/10) >+33297501354 (8m)Le Bois d'Amour - Quiberon (56) (05/04-28/09) >+33442204725 -CCA(12m)Le Conguel - Quiberon (56) (12/04-25/10) >+33297501911 (8m)Les Pins - Penestin (56) (01/04-19/10) >+33299903313 -CCA(25m)Municipal Les Platanes - Missillac (44) (01/07-31/08) >+33240883888 (30m)Les Saules - Cheverny (41) (01/04-20/09) >+33254799001 -CCA(92m)Le Cenic - Penestin (56) (11/04-14/09) >+33299903314 -CCA(18m)Les Joncs du Roch - Quiberon (56) (12/04-27/09) >+33297502437 -CCA(10m)Municipal Sous Roche*** - Avallon (01/04-15/10) >+33386341039 (193m)Les Parcs - Penestin (56) (01/04-05/10) >+33299903059 (7m)La Forge - Montagney Servigney (25) (01/05-30/09) >+33381543591 (245m)Municipal Le Patis - Asquins (89) [<51] (01/05-30/09) >+33386332014 (140m)Des Etangs - Aubigny sur Nere (18) (01/04-30/09) >+33248580237 -CCA(192m)Municipal - Chaumont sur Loire (41) (01/05-30/09) >+33254209522 (62m)Les Hetres - Bendorf (68) (01/05-15/10) >+33389403472 (597m)Les Embruns - Camoel (56) [<51] (01/04-31/10) >+33299900765 (6m)Municipal - Onzain (41) (26/04-15/09) >+33254208515 (64m)La Grande Tortue -�Cande sur Beuvron (41) (12/04-20/09) >+33254441520 -CCpg320-CCA(71m)Saint Jacques - Sarzeau (56) (01/04-30/09) >+33297417929 (5m)Aire naturelle les Rives de Vilaine - Ferel (56) (01/04-30/09) >+33683384704 (33m)Le Grand Guitton - Saint Gildas de Rhuys (56) (01/06-30/09) >+33297417945 (5m)Municipal Kerne - Quiberon (56) (27/06-31/08) >+33297500507 (18m)Les Genets - Sarzeau (56) (01/04-31/10) >+33297418722 (27m)Municipal Les Germains - Belleville sur Loire (18) (01/01-31/12) >+33621272440 (143m)La Gree Penvins - Sarzeau (56) (01/04-30/09) >+33297673396 (3m)La Ferme Maison Salvard - Bitry (58) [<51] (21/03-21/03) >+33960148347 (238m)Do Mi Si La Mi - Quiberon (56) (01/04-02/11) >+33297502252 -CCA(8m)Beausejour - Quiberon (56) (12/04-27/09) >+33297304493 (8m)Municipal Le Serein* - Toutry [<51] (15/04-15/10) >+33380964393 (218m)Aire naturelle Municipale - Vernou en Sologne (41) [<51] >+33254982022 (88m)Municipal Du Rohu - Saint Pierre Quiberon (56) (29/03-20/10) >+33297502785 (6m)Manoir de Ker an Poul - Sarzeau (56) (12/04-27/09) >+33297673330 (15m)An Trest - Sarzeau (56) (01/01-31/12) >+33297417960 (16m)La Plage - Sarzeau (56) (30/03-03/11) >+33297417356 (5m)Park er Lann - Saint Pierre Quiberon (56) (01/06-31/08) >+33297502493 (12m)La ferme Le Langatre - Saint Gildas des Bois (44) [<51] (01/01-31/12) >+33240886719 (15m)La Ferme de Lann Hoedic -�Sarzeau (56) [<51] (01/04-31/10) >+33297480173 -CCpg90-CCA(22m)Le Val de Bonnal - Rougemont (25) (07/05-07/09) >+33381869087 (255m)Les Mouettes - Sarzeau (56) (01/04-04/10) >+33297419050 (11m)A la ferme du Menguen - Sarzeau (56) [<51] >+33618393507 (40m)l'Abri Cotier - Saint Gildas de Rhuys (56) (01/04-30/09) >+33297452742 (40m)Parc du Val de Loire **** - Mesland (41) (15/04-20/09) >+33254702718 -CCA(95m)Le Goh'velin - Saint Gildas de Rhuys (56) >+33297452167 (23m)Kernejeune - Arzal (56) >+33297450160 (11m)Au Bois Joli - Andryes (89) (01/04-31/10) >+33386817048 -CCA(197m)Les Granges - Billiers (56) >+33297416498 (7m)Ty Breiz - Damgan (56) >+33297411347 (8m)Les Cedres - Chouzy sur Cisse (41) [<51] (01/06-30/09) >+33254204696 (69m)La Plage - Damgan (56) >+33297481041 (4m)Municipal La Foret** - Le Gavre (01/04-15/10) >+33240512062 (26m)l'Oasis - Damgan (56) >+33297411052 (10m)Celimene - Damgan (56) (05/04-30/09) >+33297411107 (7m)Municipal Roch Vetur - Le Tour du Parc (56) >+33297673001 (2m)Municipal Le Patis - La Roche Bernard (56) (01/04-30/09) >+33299906013 (6m)Aire naturelle Landrezac - Damgan (56) [<51] >+33297411550 (8m)l'Ile - Damgan (56) [<51] (01/06-15/09) >+33243025025 (6m)l'Ocean - Damgan (56) >+33624790862 (8m)Le Cadran Solaire - Le Tour du Parc (56) (01/04-30/09) >+33297673040 (7m)Clos Nenn - Damgan (56) (01/04-31/10) >+33670001650 (5m)Aire naturelle le Cosquer - Damgan (56) [<51] >+33297412529 (7m)Grand Air Cadu - Damgan (56) (05/04-05/10) >+33297411730 -CCA(6m)Municipal des Capucins** - Is sur Tille [<51] (01/06-30/09) >+33380950208 (279m)Saint Clair - Guenrouet (44) (01/04-30/09) >+33240876152 (12m)Presqu'ile de Rhuys - Sarzeau (56) (29/03-30/09) >+33297417868 -CCA(34m)Municipal Des Berges de l'Yonne - Coulanges sur Yonne (89) (01/05-15/09) >+33386817687 (137m)Municipal De Kerver - Saint Gildas de Rhuys (56) (01/05-30/09) >+33297452121 (11m)A la ferme du Forsdoff - Missillac (44) [<51] (01/04-30/09) >+33675652178 (50m)Port Blanc - Saint Pierre Quiberon (56) >+33297309130 (15m)Municipal** - Cellettes [<51] (01/06-30/09) >+33254704841 (71m)Les Ajoncs d'Or - Damgan (56) (20/03-11/11) >+33297412499 (5m)Cromenac'h 1 - Ambon (56) >+33297416747 (11m)Dugny -�Onzain (41) >+33254207066 (96m)Les Goelands - Ambon (56) >+33680132493 (12m)Les Oiseaux - Ambon (56) >+33297410692 (11m)L'Arada Parc -�Sonzay (37) (01/04-15/10) >+33247247269 -CCA(97m)Le Bouchot - Pierrefitte sur Sauldre (41) [<51] >+33671576126 (127m)La Croix Neuve - Nivillac (56) [<51] (01/01-31/12) >+33624974331 (41m)Aire naturelle Municipale - Autet (70) [<51] (01/07-31/08) >+33384671067 (193m)Le Menhir - Saint Gildas de Rhuys (56) >+33297452288 (6m)La Guerandiere - Billiers (56) >+33297416006 (11m)Les Sapins - Til Chatel (21) [<51] (01/04-30/09) >+33380951668 (284m)Tremelgon Clos Pen Par - Ambon (56) >+33297416747 (14m)Nature Ocean - Billiers (56) >+33297415607 (12m)l'Escale - Ambon (56) >+33297411625 (17m)Municipal du Passeloup - Joncherey (90) (01/04-31/10) >+33384563263 (392m)La Tour - Ambon (56) >+33297411438 (18m)Municipal - Saint Amand en Puisaye (58) [<51] (01/06-30/09) >+33386397221 (177m)La Grande Sologne*** - Nouan le Fuzelier (41) (01/04-15/10) >+33254887022 -CCpg321-CCA(113m)A la ferme de Quelescouet - Ambon (56) [<51] >+33297416006 (22m)Le Relais De l'Ocean - Saint Pierre Quiberon (56) >+33297309129 (8m)Municipal Le Petit Port - Chatel Censoir (89) [<51] (15/04-30/09) >+33386810198 (130m)Ker Eugene - Ambon (56) (01/04-01/11) >+33297411474 (21m)Municipal d'Autrey le Vay - Villersexel (70) [<51] (15/04-15/10) >+33632655005 (259m)Le Kermadec - Ambon (56) >+33297411590 (15m)Municipal de La Varenne - Neung sur Beuvron (41) (Easter-30/09) >+33254836852 (103m)A la ferme de Kermadec - Ambon (56) [<51] >+33297411458 (16m)Municipal Leon Delanoue - Montreuil Juigne (49) (24/05-27/09) >+33241424018 (22m)Aire naturelle du Listy - Ambon (56) [<51] (01/04-01/10) >+33297410433 (19m)Les Lupins - Seppois le Bas (68) (26/05-06/09) >+33389256537 -CCpg295(384m)Municipal Pont des Fees - Bauge (49) [<51] (01/04-01/11) >+33241891479 (52m)Municipal De Kerhostin - Saint Pierre Quiberon (56) >+33297309525 (11m)Municipal R Coeffier - Cernoy en Berry (45) [<51] >+33238310078 (189m)La ferme l'Etang Fourchu - Florimont (90) [<51] >+33384296159 (395m)Le Cosson** - Chailles [<51] (01/05-31/08) >+33254794649 (67m)Municipal Du Canal - Beaulieu sur Loire (45) [<51] (Easter-01/11) >+33238353216 (133m)Municipal De Port Sable - Arzon (56) (07/04-06/10) >+33297537198 (21m)Le Parc Des Alicourts - Pierrefitte sur Sauldre (41) (02/05-06/09) >+33254886334 (128m)Municipal Alesia - Venarey Les Laumes (21) (01/04-15/10) >+33380960776 (232m)Municipal Le Val Joyeux - Chateau la Valliere (37) (15/05-30/09) >+33247240493 (74m)Municipal De Malague** - Chaumont d'Anjou [<51] (01/06-30/09) >+33241275780 (56m)Indigo les Chateaux - Bracieux (41) (10/04-03/11) >+33254464184 -CCA(78m)Municipal Le Tindio - Arzon (56) >+33297537559 (13m)Municipal De Penthievre - Saint Pierre Quiberon (56) >+33297523386 (5m)La Ferme de Prunay - Seillac (41) [<51] (30/03-16/10) >+33254700201 -CCA(109m)Les Bertrands / Argent sur Sauldre )18' [<51] (01/01-31/12) >+33248733479 (183m)Les Peupliers - Ambon (56) >+33297411251 (11m)Municipal De la Falaise - Locmariaquer (56) >+33297573159 (4m)Le Grearn - Ambon (56) >+33297411100 (7m)l'Arvor - Ambon (56) >+33297411669 (7m)Le Chapeau Chinois - Villersexel (70) (01/04-10/10) >+33384634060 (262m)Le Relais De l'Ocean - Ambon (56) >+33297416648 (23m)Rural de Gernier Madeleine - Beaumont la Ronce (37) [<51] >+33247244283 (125m)Le Brouel - Ambon (56) >+33297411022 (14m)Le Kerpenhir - Locmariaquer (56) >+33673932648 (3m)Du Val - Bonny sur Loire (45) >+33238515771 (133m)Le Bilouris - Arzon (56) >+33297537055 (14m)La Blanche Hermine - Muzillac (56) >+33676819579 (44m)La Ferme De Saint Pierre - Locmariaquer (56) (25/06-01/09) >+33297573048 (2m)Municipal Le Trou D'Argot - Montigny Mornay Villeneuve Sur (21) [<51] (15/04-15/10) >+33380758955 (229m)Rural La Huchette - Argent sur Sauldre (18) [<51] (01/04-15/10) >+33682452833 (155m)Municipal Des Sables Blancs - Plouharnel (56) >+33297523715 (7m)La Ferme Fleurie - Locmariaquer (56) [<51] (02/04-15/10) >+33297573406 (12m)Les Oeillets - Heimersdorf (68) >+33389405130 (361m)La Baie - La Trinite sur Mer (56) >+33297557342 (8m)Rural de Lanier Daniel - Poiseul La Grange (21) [<51] (01/04-15/10) >+33380351113 (425m)Les Menhirs - Carnac (56) >+33297529467 (6m)La Plage - La Trinite sur Mer (56) >+33297557328 (9m)Au Manoir - Surzur (56) [<51] >+33297421988 (32m)l'Ocean - Carnac (56) >+33631650075 (12m)Municipal - Saint More (89) [<51] (01/06-30/09) >+33386334503 (129m)Lann Brick - Locmariaquer (56) (01/04-31/10) >+33607584710 -CCA(4m)Men-Du - Carnac (56) >+33297520423 (11m)Municipal - Pruille (49) [<51] (01/06-30/09) >+33241326729 (27m)La Tour - Locmariaquer (56) (01/04-31/10) >+33297574062 (5m)Les Druides - Carnac (56) (12/04-06/09) >+33297520818 -CCA(13m)Municipal Le Parc du Chateau - l'Isle sur Serein (89) [<51] (01/04-30/09) >+33386339350 (195m)Le Dolmen - Carnac (56) >+33297521235 (13m)Municipal La Louviere - Soing Cubry Charentenay (70) [<51] >+33384784517 (201m)Municipal Le Guerno - Le Guerno (56) (01/04-31/10) >+33297429938 (65m)Municipal Les Courvelles* - Selongey [<51] (01/05-30/09) >+33380755238 (300m)Ty-Coet - Surzur (56) (01/03-15/11) >+33297420905 -CCA(36m)Park Plijadur - La Trinite sur Mer (56) >+33297557205 (3m)Les Palmiers - La Trinite sur Mer (56) (01/04-15/10) >+33297550117 (8m)Aire Naturelle La Chenaie - Sacquenay [<51] (01/04-30/09) >+33380758943 (281m)Municipal Le Pre du Roi - Mailly le Chateau (89) (01/05-01/09) >+33386814485 (121m)Aire naturelle Le Chatillon - Huisseau sur Cosson (41) [<51] (01/05-20/09) >+33254203526 (80m)Ker Eden - Larmor Baden (56) >+33297570523 (8m)Municipal De Vauchevrier** - Chateau Renault (01/05-15/09) >+33247295443 (90m)Le Diben - Larmor Baden (56) >+33297572912 (8m)Municipal Le Vieux Moulin - Ile aux Moines (56) >+33297263068 (8m)Petit Port ** - Huningue [<51] (12/04-12/10) >+33389700171 (244m)Les Goelands - Plouharnel (56) >+33297523192 (19m)l'Evasion - Saint Philibert (56) >+33297550490 (14m)Moulin de Kermaux - Carnac (56) >+33297521590 (19m)Le Kerabus - Carnac (56) >+33297522490 (20m)Kermarquer - La Trinite sur Mer (56) >+33297557447 (16m)La Grande Metairie - Carnac (56) >+33297522401 (14m)Municipal Du Chateau - Rieux (56) [<51] (01/04-31/10) >+33299919785 (8m)Municipal Du Bellion - Fegreac (44) [<51] >+33240912021 (5m)Municipal Des Tamaris - Ile d'Arz (56) (01/04-30/09) >+33297443397 (0m)Municipal L'Ecluse des Combles - Chatillon sur Loire (45) (26/04-30/09) >+33238363594 (129m)l'Etang - Carnac (56) >+33297521406 (19m)La Lande - Plouharnel (56) >+33297523148 (17m)Kervilor - La Trinite sur Mer (56) (12/04-21/09) >+33297557675 -CCA(17m)Municipal - Vern d'Anjou (49) [<51] (01/01-31/12) >+33241610408 (49m)Les Ombrages - Carnac (56) >+33297521652 (19m)Le Rosnual - Carnac (56) >+33251273780 (19m)Le Moulin - Tincey et Pontrebeau (70) [<51] (01/01-31/12) >+33384784649 (202m)Aire naturelle Birhit - Noyalo (56) [<51] >+33297430212 (5m)Aire Naturelle Municipale - Treffieux [<51] (01/05-31/10) >+33240514842 (27m)Municipal De l'Isle St Jean - Arcy sur Cure (89) [<51] (12/04-30/09) >+33386819808 (120m)Penn Mar - Baden (56) >+33297574990 -CCA(21m)Val de Blois - Vineuil (41) (01/05-30/09) >+33254788205 -CCA(70m)Les Bruyeres - Carnac-Plouharnel (56) (05/04-30/09) >+33297523057 -CCA(18m)Le Moustoir -�Carnac (56) (12/04-19/09) >+33297521618 -CCpg88(21m)Municipal La Calanque - Saint Fargeau (89) (11/04-28/09) >+33386740455 (219m)Le Kersily - Plouharnel (56) >+33297523965 (17m)Le Lac - La Trinite sur Mer (56) >+33297557878 (9m)A la ferme de l'Aunay Lubin (tentes seulement) - Savigne sous le Lude (72) [<51] (01/07-31/08) >+33243458915 (56m)Aire naturelle La Prairie - Traves (70) [<51] (01/07-31/08) >+33381250800 (201m)Les Acacias - Altkirch (68) [<51] (01/05-15/10) >+33389406940 (346m)Municipal Kerhillio Plage - Erdeven (56) (15/06-15/09) >+33237556923 (8m)l'Etang de Loperhet - Plouharnel (56) (01/04-12/10) >+33297523468 (13m)Moulin de Cadillac - Noyal Muzillac (56) (12/04-14/09) >+33297670347 -CCA(30m)Mane Guernehue -�Baden (56) (12/04-02/11) >+33297570206 -CCpg89(33m)Keravel - Erdeven (56) (01/01-31/12) >+33297523466 (11m)Fort Espagnol - Crac'h (56) (05/04-30/09) >+33297551488 (13m)Lodka - Crac'h (56) [<51] (01/01-31/12) >+33297550397 (14m)Les Ormeaux - Erdeven (56) >+33297556757 (12m)l'Ideal - Erdeven (56) >+33297556766 (10m)l'Allee - Arradon (56) (01/04-30/09) >+33297440198 -CCA(20m)Municipal Le Patis - Les Aynans (70) [<51] (01/01-31/12) >+33384639375 (273m)A la ferme La Petite Ecurie - Lauzach (56) [<51] >+33626037085 (44m)Le Penboch - Arradon (56) (12/04-27/09) >+33297447129 -CCA(14m)Les Quatre Saisons- Lomont (70) [<51] (01/05-15/09) >+33384273439 (378m)Municipal De l'Ecluse - Cheffes (49) (01/07-31/08) >+33241428552 (16m)Municipal La Courtillerie - Saints (89) [<51] (01/04-30/10) >+33386455572 (271m)Municipal Plancherotte - Coullons (45) (01/04-31/10) >+33238292042 (157m)Municipal Parc Priol - Arradon (56) [<51] >+33297447049 (12m)Municipal - Champlitte (70) [<51] (01/06-30/09) >+33384676410 (259m)l'Hermitage*** - Guemene Penfao (01/04-31/10) >+33240792348 -CCA(50m)Les Sables Rouges - Groix (56) >+33297868132 (21m)Le Moulin de Cantizac - Sene (56) >+33298925352 (1m)Les Megalithes - Erdeven (56) (01/05-21/09) >+33297556876 -CCA(15m)International du Lac - Vesoul (70) (01/01-31/12) >+33384762286 (214m)Les Joumiers - Saint Sauveur en Puisaye (89) (23/03-13/10) >+33386456628 (240m)Municipal Les Frenes - Le Lion d'Angers (49) (26/04-30/10) >+33241953156 (19m)Municipal Les Treilles - Montbard (21) (01/03-03/11) >+33380926950 -CCA(208m)La Croez Villieu - Erdeven (56) (19/04-30/09) >+33297559043 (14m)Kerzerho - Erdeven (56) >+33297556317 (13m)Municipal De Conleau - Vannes (56) (05/04-28/09) >+33297631388 -CCA(6m)Municipal La Goule D'Eau - Redon (35) [<51] (01/07-31/08) >+33299724792 (5m)Municipal La Fontaine Aux Fees - Renaucourt (70) [<51] (15/05-15/09) >+33384920914 (224m)l'Etang De Challain - Challain la Potherie (49) [<51] (01/05-30/09) >+33241941514 (57m)Les Bois du Bardelet -�Gien (45) (12/04-30/09) >+33238674739 -CCpg322-BD_FR-F.066(170m)Le Rhuys - Theix (56) >+33297541477 (17m)Le Martinet - Briare-Bedoise (45) (04/04-28/09) >+33238312450 -CCA(127m)Aire naturelle Le Relax Vert - Saints (89) [<51] >+33386455383 (256m)Municipal Fort du Mene - Groix (56) >+33297868015 (30m)La Fontaine du Hallate - Plougoumelen (56) >+33616300833 (34m)Le Parc-Lann - Bono (56) >+33297579393 (21m)Kergo - Ploemel (56) >+33297568066 (25m)Municipal Du Cosson - Crouy sur Cosson (41) (01/04-15/10) >+33254870881 (84m)Municipal de la Barre d'Etel - Etel (56) (01/04-30/09) >+33297553379 (7m)Municipal Au Bord du Loir - Le Lude (72) (17/04-05/10) >+33243946770 (38m)L'Etang des Forges*** -�Belfort (10/04-30/09) >+33384225492 -CCpg293(365m)Domaine de la Pierre Percee- Fouvent (70) [<51] >+33384313046 (274m)Naturist - La Pinede - Belz (56) (14/06-14/09) >+33297556155 (19m)Les 7 Saints - Erdeven (56) >+33297555265 (11m)Municipal Les Coullemieres - Vermenton (89) (01/04-30/09) >+33386815302 (112m)La Saone Jolie - Scey sur Saone et Saint Albin (70) [<51] (15/06-01/09) >+33384688507 (209m)Municipal Le Moulin Jacquot - Accolay (89) [<51] (01/04-30/09) >+33645101879 (112m)Municipal l'Etang de Celac - Questembert (56) (01/07-31/08) >+33297261138 (86m)St Laurent - Ploemel (56) (12/04-26/10) >+33297568590 -CCA(20m)Le Moteno - Plouhinec (56) (05/04-28/09) >+33297367663 (14m)Chateau Des Marais**** - Muides s/Loire (10/05-15/09) >+33254870542 (85m)Les Pommiers - Auray (56) >+33297240148 (21m)Municipal Le Port Liberge** - Vaas [<51] (01/05-30/09) >+33243467029 (44m)Municipal Les Etangs de Bodean - Saint Jacut les Pins (56) [<51] (15/06-15/09) >+33299912865 (55m)Municipal La Trezee - Ouzouer sur Trezee (45) (01/04-31/10) >+33238319460 (144m)Les Portes de l'Anjou*** - Durtal (49) (04/04-31/10) >+33241763180 -CCpg103-CCA(30m)Municipal Belle Vue** - Muides s/Loire (01/05-15/09) >+33254870156 (78m)Aire naturelle Municipale - Grancey Le Chateau Neuvelle (21) [<51] (15/06-15/09) >+33380756030 (417m)Municipal Les Pres Bas - Isdes (45) [<51] (01/04-31/10) >+33238291082 (143m)Municipal Du Port - Chateauneuf sur Sarthe (49) (01/05-15/09) >+33241698202 (17m)Aire naturelle La Morinais - Bains sur Oust (35) [<51] (01/03-31/10) >+33299721217 (15m)Moulin Des Oies - Belz (56) >+33681881776 (2m)Municipal La Maladiere - Port sur Saone (70) (15/05-15/09) >+33384915132 (209m)Touristique De Gien - Gien (45) (02/03-10/11) >+33238671250 -CCA-BD_FR-F.065(126m)Le Saint-Cado - Belz (56) >+33297553198 (4m)Municipal - Sennely (45) [<51] (15/03-15/10) >+33238496012 (125m)Aire naturelle Lesvenant - Locoal Mendon (56) [<51] (01/04-30/09) >+33297245691 (11m)Municipal Aire naturelle Les Farnaults - Villemurlin (45) [<51] (01/04-30/09) >+33238362512 (135m)La Grenouillere**** - Suevres (41) (20/04-15/09) >+33254878037 -CCA(90m)Rural Municipal De la Pelletiere - Dommarien (52) [<51] (01/06-15/09) >+33325875881 (275m)l'Amitie - Saint Laurent Nouan (41) (02/01-24/12) >+33254870152 (77m)La ferme Le Chateau Gaillard - Genevreuille (70) [<51] (01/04-30/09) >+33384743529 (368m)Municipal La Lande - Gavres (56) >+33297824861 (7m)La Louviere - Champagney (70) (15/04-15/09) >+33384232024 (418m)Municipal - Noyers sur Serein (89) [<51] >+33386828372 (171m)Municipal - Thoree les Pins (72) [<51] (15/05-15/09) >+33243456485 (34m)Municipal La Route d'Or - La Fleche (72) (01/03-31/10) >+33243945590 (29m)Au Gre des Vents - Rochefort en Terre (56) (01/04-28/09) >+33297433752 -CCA(62m)Municipal Les Joncs - Gavres (56) >+33297824688 (3m)Les Rochelles - Prunay Cassereau (41) [<51] (15/04-15/10) >+33676932061 (131m)l'Ongline - Marigne (49) [<51] (01/05-30/09) >+33241763099 (60m)Municipal Le Motten - Sainte Anne d'Auray (56) (14/06-14/09) >+33297576027 (51m)Fort du Talud - Ploemeur (56) >+33297829150 (13m)La Pointe du Talud - Ploemeur (56) >+33297829190 (14m)Municipal Des Fontenelles - Luche Pringe (72) (01/05-15/09) >+33243454450 (34m)Municipal La Chabotiere - Luche Pringe (72) (01/04-31/10) >+33243451000 (37m)Isle de Besle - Guemene Penfao (44) [<51] (01/05-30/09) >+33240872318 (6m)Bois Girault - Arrabloy (45) (15/03-10/10) >+33238673690 (183m)Municipal Les Briotais - Chateaubriant (44) [<51] (02/05-30/09) >+33240811438 (89m)Municipal Des Algues - Larmor Plage (56) >+33297655547 (5m)Municipal La Pepiniere - Bleneau (89) [<51] (01/04-30/09) >+33386749373 (175m)Les Ballastieres - Champagney (70) (01/04-31/10) >+33384231122 -CCpg294(361m)Belle Plage - Ploemeur (56) >+33297829455 (7m)Municipal La Prairie et les Remparts - Port Louis (56) [<51] (01/06-15/09) >+33297825959 (8m)Les Ceriselles - Vincelles (89) (01/04-30/09) >+33386425047 -CCpg348-CCA(104m)Municipal Pen Palud - Ploemeur (56) >+33297829456 (6m)La Fontaine - Larmor Plage (56) >+33297337128 (12m)Le Heron Bleu - Noyant La Gravoyere (49) [<51] (01/06-31/12) >+33241619309 (79m)Municipal L'Ile Aux Pies - Bains sur Oust (35) (15/06-15/09) >+33299917141 (12m)Le Painfaut - Saint Vincent sur Oust (56) [<51] (01/01-31/12) >+33688646987 (52m)Le Lac des Varennes*** - Marcon (18/04-28/09) >+33243441372 -CCA(51m)A la ferme A-Rigaud - Bourguignon Les Morey (70) [<51] (15/04-20/09) >+33384910858 (294m)La Riviere - Nyoiseau (49) [<51] (15/06-15/09) >+33241922677 (28m)Ferme de Rochefort - Lion en Sullias (45) [<51] >+33238369731 (132m)Municipal Kerdurand - Riantec (56) >+33297339810 (12m)Municipal Le Port Ribouet - La Jaille Yvon (49) [<51] (01/04-30/09) >+33241951258 (37m)La Chaumiere** - Heimsbrunn (01/01-31/12) >+33389819343 (274m)Municipal du Cosson - La Ferte Saint Aubin (45) (25/04-28/09) >+33238765590 (102m)La ferme Le Ciran - Menestreau en Villette (45) [<51] (01/05-30/09) >+33238769093 (136m)Municipal Du Pont d'Oust - Peillac (56) (01/05-30/09) >+33299913933 (6m)Nerhouit - Brech (56) >+33297577062 (49m)l'Atlantys - Ploemeur (56) >+33297059981 (4m)Le Haras - Monterblanc (56) (15/03-12/11) >+33297446606 -CCA(138m)Des 4 Marlettes - Toucy (89) [<51] (01/04-15/10) >+33386441384 (188m)Le Vieux Moulin - La Chartre sur le Loir (72) (25/04-10/11) >+33243444118 (53m)Municipal l'Ill*** - Mulhouse (68) (01/04-15/10) >+33389062066 -CCA(242m)Lac de la Seigneurie*** - Lachapelle s/Rougemont (90) (01/04-31/10) >+33384230013 -CCA(418m)Les Ajoncs - Ploemeur (56) (01/04-30/09) >+33297863011 (45m)Du Lac de la Vingeanne - Villegusien le Lac (52) (15/03-15/10) >+33325884524 -CCA(301m)Plage du Fort Bloque - Guidel (56) >+33297059546 (3m)La Tranquilite - Le Cours (56) >+33297672325 (66m)Municipal Les Lancieres - Rogny les Sept Ecluses (89) [<51] (01/05-30/09) >+33674434304 (142m)Le Pied a Terre - Landaul (56) [<51] >+33297245270 (41m)Les Chaintres - Ruille sur Loir (72) [<51] (01/05-30/09) >+33243444425 (55m)Municipal La Digue - Saint Martin sur Oust (56) (01/05-30/09) >+33299914945 (9m)Municipal Le Moredena - Morannes (49) (15/04-15/10) >+33241427695 (21m)Pen Er Malo - Guidel (56) >+33297059986 (10m)Les Castors*** - Burnhaupt le Haut (01/04-31/10) >+33389487858 -CCpg296(315m)Municipal Les Reclusages - Montoire sur le Loir (41) (26/04-30/09) >+33254850253 (72m)Les Rivieres - Daon (53) [<51] (01/04-30/09) >+33243069478 (25m)Le Lac - Preigney (70) [<51] (01/04-30/09) >+33384685537 (281m)Le Cle des Pres - Pluvigner (56) [<51] >+33297247232 (65m)La Plage - Mansigne (72) (01/04-31/10) >+33243461417 -CCA(53m)Rural de Collardey Claude - Le Val Saint Eloi (70) [<51] (01/05-31/10) >+33384689155 (348m)Aire naturelle Municipale - Pontvallain (72) [<51] >+33243463047 (49m)La Bergereine - Melisey (70) [<51] (01/04-31/10) >+33623368716 (329m)La Broche - Fresse (70) [<51] (01/04-15/10) >+33384633140 (472m)La Doller*** - Guewenheim (01/04-31/10) >+33389825690 (330m)Municipal du Fort des Salles** - Mayet (19/04-14/09) >+33243466872 (91m)Le Creux - Fresse (70) [<51] >+33384633159 (460m)Le Bois Guillaume - Villeneuve les Genets (89) (01/01-31/12) >+33386454541 (198m)La ferme Les Armes de Kaer - Landevant (56) [<51] (15/06-15/09) >+33673986095 (38m)Le Petit Villars - Champignelles (89) [<51] >+33386451040 (177m)Aire naturelle Municipale - Mire (49) [<51] (01/04-31/10) >+33241328214 (40m)Municipal - Saint Just (35) [<51] (01/05-15/09) >+33631470515 (61m)Art Nature - Sixt sur Aff (35) [<51] (05/04-15/10) >+33299081059 (12m)Les Grands Sables - Clohars Carnoet (29) >+33298399443 (16m)Les Embruns - Le Pouldu-Clohars Carnoet (29) (11/04-20/09) >+33298399107 -CCA(22m)A la ferme La Viotterie - La Boissiere (53) [<51] >+33243068010 (88m)Municipal Des Lices** - Precigne [<51] (01/06-31/08) >+33243954613 (37m)Du Kerou - Clohars Carnoet (29) >+33681483726 (22m)Municipal De Kervido - Lanester (56) [<51] >+33297767196 (5m)Jardin de Sully - Saint Pere sur Loire (45) (01/01-31/12) >+33238363594 -CCA(115m)Municipal Du Halage - Saint Congard (56) [<51] >+33297435013 (15m)Le Vieux Four - Clohars Carnoet (29) [<51] (01/06-31/08) >+33298399434 (31m)Keranquernat - Clohars Carnoet (29) >+33298399232 (39m)De la Foret - Ouzouer sur Loire (45) (01/01-31/12) >+33238356267 (146m)Les Jardins de Kergal - Guidel (56) (01/04-30/09) >+33297059818 -CCA(39m)De Kervoen - Clohars Carnoet (29) >+33298399534 (39m)Municipal Du Bac - Menil (53) [<51] (15/04-30/09) >+33243702454 (27m)La Pierre - Melisey (70) (01/05-30/09) >+33384632308 (376m)Municipal du Val de Flux** - Beaugency (15/04-31/08) >+33238445039 (84m)Municipal - Recey sur Ource (21) [<51] >+33380810206 (292m)Municipal - Masevaux (68) (15/03-31/10) >+33389824229 (409m)Moulin Begeot - Ecromagny (70) [<51] (01/04-30/09) >+33384632576 (361m)A la ferme Auberge de l'Entzenbach (tentes seulement) - Niederbruck (68) [<51] >+33389824549 (626m)Le Safary** - Sausheim [<51] (01/01-31/12) >+33389619929 (231m)Le Kergariou - Clohars Carnoet (29) (01/04-07/09) >+33298715465 -CCA(45m)Municipal De l'Etang aux Biches - Tredion (56) [<51] >+33297671406 (93m)De Groas Anter - Clohars Carnoet (29) >+33624886820 (40m)Municipal Les Charbonnieres - Auberive (52) [<51] (15/04-01/10) >+33325842113 (352m)De Locouarn - Clohars Carnoet (29) >+33663549179 (36m)A la ferme Au Vieux Moulin - Clohars Canoet (29) [<51] >+33625046014 (51m)Municipal** - Auxerre (15/04-15/09) >+33386521115 (98m)La Tuilerie - Baulay (70) [<51] (15/03-01/11) >+33384687103 (228m)Le Quinquis - Clohars Carnoet (29) >+33298399240 (27m)l'Ile Percee - Moelan sur Mer (29) >+33298711625 (12m)Au Coeur de Vendome - Vendome (41) (18/04-01/11) >+33254770027 -CCpg316-CCA(80m)Domaine de Beauvoir - Beauvoir (89) [<51] >+33386410048 (179m)Le Raguenes Plage - Nevez (29) (11/04-28/09) >+33298068069 -CCA(26m)A la ferme Des Maisons Blanches - Champignelles (89) [<51] (0105-30/09) >+33386451796 (190m)L'Ocean - Nevez (29) >+33298068713 (28m)Ferme de la Croisee - Flagey (52) [<51] (01/04-15/10) >+33687249619 -CCA(443m)Du Vieux Verger Ty Noul - Nevez (29) (12/04-30/09) >+33298068608 (32m)Les Chaumieres - Nevez (29) >+33298067306 (37m)Les Ormes - Treffiagat (29) >+33298582127 (4m)Des Dunes - Plobannalec Lesconil (29) (05/04-30/09) >+33298878178 -CCA(6m)Le Suroit - Tregunc (29) >+33298500176 (7m)Karreg Skividen - Treffiagat (29) [<51] >+33682447159 (11m)La Grande Plage - Plobannalec Lesconil (29) (12/04-30/09) >+33298878827 -CCA-BD_FR-A.106b(5m)Les Vergers De Squividan - Treffiagat (29) [<51] (15/06-05/09) >+33298580912 (14m)Le Grand Bleu - Penmarc'h (29) >+33668908998 (5m)Municipal La Graviere du Moulin - Lezinnes (89) [<51] (29/03-06/10) >+33386756867 (160m)Les Deux Fontaines - Nevez (29) (25/05-05/09) >+33298068191 -CCpg85(31m)Municipal Toul Ar Ster - Penmarc'h (29) >+33298588688 (3m)La Palue Du Cosquer - Loctudy (29) >+33298875292 (0m)Municipal La Bonne Aventure - Thore la Rochette (41) (014/05-30/09) >+33254720059 (74m)La Ferme La Carterie - Bierne (53) [<51] >+33243079927 (84m)Tal Ar Moor - Moelan sur Mer (29) >+33298711198 (18m)La Plage - Guilvinec (29) >+33298586190 (3m)Le Keralouet - Plobannalec Lesconil (29) [<51] >+33298822305 (3m)Les Cigognes**** - Cernay (01/04-15/10) >+33389755697 -CCA(298m)Le Saint Nicolas - Nevez (29) (30/04-21/09) >+33298068975 -CCA(32m)Les Sables Blancs - Plobannalec Lesconil (29) >+33610144622 (4m)Keraeren - Nevez (29) >+33298068038 (32m)Municipal St-Caradec - Hennebont (56) (15/06-15/09) >+33297362173 (6m)Le Port - Saint Benoit sur Loire (45) [<51] (30/05-28/09) >+33238351234 (109m)Municipal De la Daufresne - Malestroit (56) (15/05-15/09) >+33297751333 (14m)La Pommeraie - Tregunc (29) (01/05-30/09) >+33298500273 (19m)La Grande Lande - Moelan sur Mer (29) >+33298710039 (36m)Les Mouettes - Loctudy (29) >+33298874351 (6m)Les Veneys - Miellin (70) [<51] (15/04-15/09) >+33384204536 (578m)Naturist - Les Bogues - Saint Cyr en Val (45) (15/06-15/09) >+33238632982 (117m)La Joie - Penmarc'h (29) >+33298586324 (4m)Les Etangs de Trevignon - Kerlin >+33298500041 (18m)Municipal l'Etang Sort - Courdemanche (72) [<51] (01/05-15/10) >+33243448019 (72m)Ocean Breton-Le Manoir De Kerlut - Plobannalec Lesconil (29) >+33298822389 (11m)Les Hortensias - Loctudy (29) (01/04-26/09) >+33609919439 -CCpg81(6m)Municipal La Croix d'Arles** - Langres (52) (15/03-31/10) >+33325882402 -CCA(459m)Municipal Le Serein - Chablis (89) [<51] (01/06-15/09) >+33386424439 (130m)Municipal Le Bois Vert** - Carentoir (56) [<51] (01/04-30/09) >+33299937899 (36m)La Forge - Ampilly Le Sec (21) [<51] (01/04-30/09) >+33623778243 (233m)Rural de Lebreton Gilbert - Colpo (56) [<51] >+33297668793 (100m)Municipal Le Chesnaie** - Marigne Laille [<51] (01/05-30/09) >+33243421212 (99m)Le Petit Forcelle - Tigy (45) [<51] (01/04-31/10) >+33238572964 (102m)Le Chateau De Belon - Riec sur Belon (29) (01/04-15/11) >+33298064143 (36m)Municipal De la Lanciere - Chatillon Coligny (45) (01/04-30/09) >+33238925473 (122m)Municipal Port Sainte Marie*** - Malicorne s/Sarthe (01/04-30/09) >+33243948014 (32m)Les Genets - Nevez (29) (01/05-15/09) >+33298068613 (37m)Les Genets - Penmarc'h (29) (12/04-30/09) >+33298586693 -CCpg80-CCA(21m)La Foret - Les Bordes (45) >+33238355836 (138m)Municipal Du Port** - Guipry (01/04-15/10) >+33299347290 (6m)Rural de Hagenbach - Rimbach Pres Masevaux (68) [<51] (01/01-31/12) >+33389820013 (554m)Ty Nenez - Pont Scorff (56) (01/01-31/12) >+33297325116 (26m)Behe* - Bantzenheim (68) [<51] (01/01-31/12) >+33389260455 (217m)Chatigny - Luxeuil les Bains (70) (01/03-31/10) >+33384939797 (327m)Le Pre Gallo - Carentoir (56) >+33299088485 (40m)Aire naturelle de Berce - Pruille l'Eguille (72) [<51] (01/01-31/12) >+33243409151 (160m)Municipal Du Pont Salmon - Serent (56) [<51] (01/06-31/08) >+33297759198 (68m)Kergall - Loctudy (29) >+33298874593 (3m)Le Fleuri - Tregunc (29) >+33298067476 (41m)Municipal Hippodrome La Prairie du Chateau - Sable sur Sarthe (72) (29/03-11/10) >+33243954261 (25m)A la Ferme Les Cloutils - Bray-en-Val (45) [<51] (01/04-30/09) >+33238290358 (130m)Municipal Le Val de Braye - Besse sur Braye (72) (29/03-31/10) >+33243353113 -CCA(70m)La Torche - Plomeur (29) >+33298586282 (19m)Municipal Le Bois Feuillet - Martigne Ferchaud (35) [<51] (01/06-30/09) >+33299478438 (73m)Municipal** - Ecommoy [<51] (01/05-30/09) >+33243421414 (103m)Les Sources - Wattwiller (68) (12/04-30/09) >+33389754494 (480m)La Plage Loc'h-Ven - Tregunc (29) >+33298502620 (8m)Municipal du Lac** - Bain de Bretagne (15/03-15/10) >+33299438567 (72m)Le Parc - Chateau Gontier (53) (01/01-31/12) >+33243073560 (40m)De Pendruc - Tregunc (29) >+33298976628 (19m)Municipal Espace De La Madeleine - Plumelec (56) [<51] >+33297422427 (154m)Le Clolois - Jussey (70) [<51] (15/06-15/09) >+33384681149 (212m)Municipal Du Verduron* - Parce s/Sarthe [<51] (15/05-30/09) >+33243953921 (30m)A la ferme de la Renaudine - Dampierre les Conflans (70) [<51] (01/04-01/11) >+33384498234 (296m)Le Village Insolite - Camors (56) (12/04-27/09) >+33297391836 (83m)Municipal du Murier - Craon (53) [<51] (01/05-15/11) >+33243069633 (51m)Le Grand Large - Fouesnant (29) >+33298560406 (3m)Entre Terre et Mer - Pont Scorff (56) (01/01-31/12) >+33624974331 (53m)La Mine d'Argent - Moosch (68) (15/04-15/10) >+33389823066 (458m)Municipal Du Sillon - Ile Tudy (29) >+33298564257 (8m)Kost Ar Moor - Fouesnant (29) >+33298560416 (5m)PenHoat - Fouesnant (29) >+33298565189 (4m)Le Bois D'Amour - Ile Tudy (29) >+33298564354 (2m)Le Lanven - Plomeur (29) >+33661864516 (32m)La Plage de Cleut Rouz - Fouesnant (29) >+33298565319 (5m)Les Deux Ballons - Saint Maurice sur Moselle (88) (19/04-25/09) >+33329251714 -CCA(537m)Municipal** - Olivet [<51] (10/04-10/10) >+33238635394 (93m)Le Cabellou Plage - Concarneau (29) >+33298973741 (10m)Municipal La Vallee - Rouvres sur Aube (52) [<51] (01/01-31/12) >+33325842439 (299m)La Maltournee - Chateauneuf sur Loire (45) (07/04-28/10) >+33238584246 (101m)L'Atlantique -�Fouesnant (29) (19/04-14/09) >+33298561444 -CCpg83-CCA(6m)Le Cosquer - Fouesnant (29) >+33298560898 (7m)Kerolland - Fouesnant (29) >+33298949100 (15m)Municipal Louis Rigoly - Chatillon sur Seine (21) [<51] (01/04-30/09) >+33380910305 -CCA(245m)Municipal De la Cascade - Tonnerre (89) (12/04-28/09) >+33386551544 -CCpg349(134m)Le Kervastard - Fouesnant (29) (01/04-02/11) >+33298949152 -CCpg84(17m)Municipal Navarre* - Langres (06/03-31/10) >+33325873792 (463m)Aire naturelle de Keraluic - Plomeur (29) [<51] (01/05-31/10) >+33298821022 (23m)Aire naturelle Le Moulin Rose - Montereau (45) [<51] (01/05-30/10) >+33238877167 (118m)l'Escale St Gilles - Benodet (29) (26/04-21/09) >+33298570537 (11m)Du Roc - Le Roc Saint Andre (56) (01/04-02/11) >+33297749107 -CCA(27m)La Rincerie - La Selle Craonnaise (53) [<51] (01/03-21/10) >+33243061752 (57m)A la ferme de Le Gall Guez - Fouesnant (29) [<51] >+33298949744 (16m)Le Letty - Benodet (29) >+33298570469 (9m)Municipal Le Val Joint - Lizio (56) [<51] (15/05-15/10) >+33297747049 (126m)l'Abri de l'Ocean - Baye (29) >+33298968035 (66m)Aire naturelle de Leanou - Fouesnant (29) [<51] (15/05-15/09) >+33298561532 (12m)Municipal des deux Rivieres - Avoise (01/06-31/08) >+33243927612 (30m)La Piscine - Fouesnant (29) (19/04-13/09) >+33298565606 -CCA(16m)Le Moulin d'Aurore - Concarneau (29) >+33298505308 (21m)La Plage - Benodet (29) >+33298570055 (12m)Le Poulquer - Benodet (29) (01/05-30/09) >+33298570419 -CCA(7m)Le Helles - Combrit (29) (01/04-30/09) >+33298563146 -CCA(10m)Menez Lanveur - Combrit (29) (01/06-30/09) >+33298564762 (9m)l'Isle aux Moulins - Jargeau (45) (01/04-31/10) >+33238597004 -CCA(102m)Les Grebes du Lac de Marcenay - Marcenay (21) (01/05-30/09) >+33380816172 -CCA(209m)Municipal l'Oree du Bois - Baud (56) (15/06-15/09) >+33297391246 (78m)Lac de la Liez**** -�Langres (52) (01/04-30/09) >+33325902779 -CCpg309-CCA(379m)Le Trez - Benodet (29) >+33298571594 (13m)Municipal De Kerbertrand - Quimperle (29) [<51] (15/06-15/09) >+33298960432 (55m)La Sapiniere - Wuenheim (68) (01/04-30/09) >+33389767940 (422m)l'Etang Des Bois - Lorris (45) (01/04-30/09) >+33238923200 (135m)Naturist - Les Bruyeres d'Arvor - Cleguer (56) >+33297325791 (107m)Municipal La Noe - Monteneuf (56) [<51] (15/06-15/09) >+33297932482 (104m)La Mer blanche - Benodet (29) >+33298570075 (18m)Ferme de Trocherou - Riec sur Belon (29) [<51] >+33298064582 (66m)Municipal Bon Accueil - Fresse sur Moselle (88) [<51] (01/04-11/11) >+33329250898 (497m)La Goupilliere - Auvers Le Hamon (72) [<51] (01/01-31/12) >+33243958076 (56m)Les Bouleaux - Ranspach (68) (01/12-31/10) >+33389826470 -CCA(422m)Municipal De La Palue De Kerguellec - Treguennec (29) [<51] (15/06-15/09) >+33298877818 (10m)Naturist - Club Du Soleil Mulhouse - Reguisheim (68) (01/05-30/09) >+33389817735 (212m)Kerscolper - Fouesnant (29) (01/04-15/10) >+33298560948 -CCA(28m)Du Pre Aux Moines - Savigny sur Braye (41) (01/01-31/10) >+33254237120 (78m)Au Relais du Grand Ballon - Geishouse (68) [<51] (01/01-31/12) >+33389823047 (666m)Municipal Benelux-Bale - Urbes (68) (01/04-31/10) >+33389827876 (455m)Camp'Eco - Voisey (52) [<51] (15/04-30/09) >+33325849791 (260m)Les Sables Blancs - Concarneau (29) (01/04-31/10) >+33298971644 -CCA(25m)Pont Augan - Baud (56) >+33297510937 (33m)Kersentic - Fouesnant (29) >+33699537421 (41m)Municipal les Patures - Checy (45) [<51] (16/05-29/09) >+33238911327 (96m)Les Chataigniers - Pont l'Abbe (29) [<51] >+33672744675 (15m)Aux 2 Chenes - Benodet (29) (19/04-13/09) >+33298566201 (42m)La Maladrerie - Freteval (41) (15/03-31/10) >+33254826275 (87m)Municipal** - La Suze s/Sarthe (15/06-15/09) >+33243773274 (37m)De Champe - Bussang (88) (01/01-31/12) >+33329616151 -CCpg302-CCA(600m)Municipal Clos des Chaumes - Le Thillot (88) (01/01-31/12) >+33329251030 (482m)Kervallon - Caro (56) [<51] (15/03-10/11) >+33676688367 (105m)Les Pres Verts - Concarneau (29) >+33298970974 -CCA(37m)Les Platanes*** - Charny (89) (01/04-31/10) >+33386918360 (133m)Le Pen An Cap - Fouesnant (29) >+33298560923 (10m)Les Mimosas - Fouesnant (29) >+33298561431 (6m)Municipal - Guehenno (56) [<51] (01/01-31/12) >+33297422989 (109m)Le Clos Martin - Ramonchamp (88) [<51] (01/04-15/09) >+33329250538 (463m)Kerlaz - Treguennec (29) (01/04-30/09) >+33298877679 (38m)Municipal Gaston Marchand** - Saint Jean de la Ruelle [<51] (01/07-31/08) >+33238883939 (96m)Hautoreille** - Bannes (52) (03/01-30/11) >+33325848340 -CCA(395m)Montloue - Mellac (29) [<51] >+33298719312 (74m)Municipal De la Noue Marrou - Ligny le Chatel (89) [<51] (01/05-30/09) >+33386475699 (111m)Le Saint Laurent - La Foret Fouesnant (29) >+33298569765 (20m)La Plage - La Foret Fouesnant (29) >+33298569625 (7m)Kerleven - La Foret Fouesnant (29) >+33298569883 (6m)La Viennerie - Oussoy en Gatinais (45) [<51] >+33238963147 (103m)De Keranterec - La Foret Fouesnant (29) (12/04-21/09) >+33298569811 -CCA(28m)Kersioual - La Foret Fouesnant (29) >+33298569639 (10m)Les Falaises - La Foret Fouesnant (29) >+33298569126 (18m)Les Saules - La Foret Fouesnant (29) >+33298569857 (10m)La Jonquille - Hurecourt (70) [<51] (01/04-01/10) >+33689698231 (288m)Le Wagga - Oderen (68) [<51] >+33389282432 (442m)Le Florival*** - Issenheim (15/04-15/10) >+33389742047 (265m)Municipal Le Budou - Melgven (29) [<51] >+33298979011 (94m)Kerjean - Bannalec (29) [<51] (26/04-13/09) >+33298394458 (83m)Municipal* - Humes Jorquenay [<51] (01/04-30/09) >+33325875065 (319m)Municipal La Varenne - Moree (41) [<51] (01/04-31/10) >+33254891515 (88m)Odet Village - Gouesnach (29) >+33298821159 (32m)Le Lochrist - Concarneau (29) >+33298972595 (77m)De Ponterec - La Foret Fouesnant (29) >+33685081460 (17m)Le Ty Nadan -�Arzano-Locunole (29) (01/05-01/09) >+33298717547 -CCpg86-CCA(29m)Val de Vie - Chatenoy (45) (01/04-01/11) >+33238558271 (131m)Municipal de Mariano - Ploneour Lanvern (29) (15/06-15/09) >+33298877480 (71m)Aire naturelle de la Vallee de l'Oyon - Porcaro (56) [<51] (01/04-30/09) >+33297220638 (52m)l'Oree du Bois - Le Menil (88) [<51] (01/01-31/12) >+33672385276 (536m)Pors-Keraign - Gouesnach (29) >+33298546137 (20m)Manoir De Penn Ar Ster - La Foret Fouesnant (29) [<51] >+33298569775 (9m)Le Pont Nivino - Plouay (56) >+33297332791 (58m)Celtic Village - Tremeoc (29) >+33298823826 (38m)Le Bonheur Cote Pre-Lestregueoc- Ploneour Lanvern (29) [<51] >+33298876246 (46m)Municipal - Chantenay Villedieu (72) [<51] (01/05-30/09) >+33243957425 (45m)La Creche - Le Val d'Ajol (88) [<51] >+33610481085 (451m)Vacances et Peche - Villiers Charlemagne (53) [<51] (01/01-31/12) >+33243077168 (76m)Municipal Le Houssay** - Spay (15/04-30/09) >+33243211658 (41m)Municipal les Oeuvres- Le Val d'Ajol (88) >+33329665517 (348m)Les Genets D'Or - Bannalec (29) [<51] (22/05-28/09) >+33298395435 -CCA(90m)Municipal - Sarge sur Braye (41) >+33254727265 (88m)Le Lac - Saint Calais (72) (01/04-15/10) >+33243350481 (100m)Municipal La Courbe** - Bourg des Comptes (Easter-31/10) >+33297410149 (15m)Municipal Le Patis** - Bonnard [<51] (15/05-30/09) >+33386732625 (80m)A la Ferme La Charpenterie- Beauchamps sur Huillard (45) [<51] >+33678969967 (116m)La Grande Curtille -Fontenois la Ville (70) [<51] >+33384929413 (296m)Municipal Les Patures - Trigueres (45) [<51] (01/03-01/10) >+33238940023 (116m)Vert de Creach Lann - Saint Evarzec (29) [<51] >+33298562988 (75m)Les Cerisiers - Guillac (56) [<51] >+33699885980 (61m)Le Littoral - Pouldreuzic (29) >+33671213285 (7m)Keromen - Saint Evarzec (29) >+33623055825 (37m)Le Schlossberg - Kruth (68) >+33389822676 (518m)Municipal - La Selle Guerchaise (35) >+33299960614 (75m)A la ferme de Penguilly - Peumerit (29) [<51] >+33298829135 (71m)La Ferme Guellec - Kerguivit-Pouldreuzic (29) [<51] >+33298544155 (29m)Municipal De L'Etang - Marcille Robert (35) [<51] >+33661826957 (55m)Le Pont de Maxonchamp - Rupt sur Moselle (88) >+33329243065 (409m)Le Lac - Taupont (56) >+33297740122 (41m)Landrezec - Pouldreuzic (29) [<51] >+33298543481 (40m)Les Myrtilles - Saint Yvi (29) (15/06-15/09) >+33298947125 (109m)Le Bois De Pleuven - Saint Yvi (29) (11/04-20/09) >+33499572121 -CCpg82(105m)Municipal Le Vieux Moulin* - Arc en Barrois [<51] (01/04-30/09) >+33325025133 (266m)Domaine de Kerelly - Josselin (56) (01/04-05/10) >+33624594826 (37m)Lac de la Moselotte - Saulxures sur Moselotte (88) >+33329245656 (452m)Municipal** - Rouffach (01/05-30/09) >+33389497813 (204m)A la ferme Le Mottais - Meral (53) [<51] >+33682249393 (96m)Fontenoy - Fontenoy le Chateau (88) (15/04-30/09) >+33684485148 (330m)Les Confluents*** - Migennes (89) (01/04-31/10) >+33386809455 -CCA(78m)Municipal - Campeneac (56) [<51] >+33297934039 (73m)Montmorency - Bourbonne les Bains (52) >+33620425323 (276m)La ferme Salzbach - Sondernach (68) [<51] >+33389776366 (1147m)Etag de la Vallee - Vitry aux Loges (45) (01/01-31/12) >+33238593577 (130m)l'Etang d'Aleth - Saint Malo de Beignon (56) [<51] >+33678961062 (78m)Municipal De Kerscaven - Bubry (56) [<51] >+33297517007 (96m)Le Septentrion*** - Brulon (72) (01/05-30/09) >+33243956896 -CCA(56m)Municipal La Chesnaie** - Meslay du Maine (53) (Easter-30/09) >+33243984808 (67m)Bois des Ecureuils - Guilligomarc'h (29) [<51] >+33298717098 (145m)Les Tetes - Cornimont (88) [<51] >+33329240563 (541m)Le Fraiteux - Plombieres les Bains-Ruaux (88) [<51] (15/03-31/10) >+33329660071 -CCA(530m)Les Peupliers - Pouldreuzic (29) [<51] >+33298544998 (51m)Le Manoir de Logan - Pouldreuzic (29) [<51] (15/04-01/10) >+33298544114 (51m)Municipal De Roz An Duc - Rosporden (29) [<51] >+33298599027 (119m)l'Hermitage - Plombieres les Bains (88) [<51] (15/04-15/10) >+33329300187 -CCA(525m)A la ferme de Reherrey - Vecoux (88) [<51] >+33329610625 (494m)Municipal De l'Etang - Reguiny (56) (15/06-17/09) >+33297386611 (79m)La Vallee de Ninian - Taupont (56) (01/04-30/09) >+33297935301 -CCA(38m)Municipal du Marais - Riel les Eaux (21) [<51] >+33380937276 (206m)Aire naturelle les Fouquets - Saint Jean Froidmentel (41) [<51] (01/04-30/09) >+33254826697 (124m)A la ferme les Moineaux - Dommartin les Remiremont (88) [<51] >+33329610030 (624m)Le Clos du Blavet - Bieuzy Les Eaux (56) >+33297518307 (69m)Orangerie de Lanniron -�Quimper (29) (29/03-15/11) >+33298906202 -CCA(17m)l'Oree du Bois - Geiswasser (68) [<51] (01/04-30/09) >+33389725495 (193m)La Corniche - Plozevet (29) (28/03-30/09) >+33298913394 -CCpg79-CCA(59m)La Vallee Noble - Osenbach (68) (01/03-31/10) >+33389470522 (408m)Municipal** - Joigny [<51] (01/04-28/09) >+33386620755 (75m)Municipal du Langenwasen - Mittlach (68) (01/05-30/09) >+33389776377 (657m)Aire naturelle La Source - Plozevet (29) [<51] (01/04-30/09) >+33298913701 (61m)Municipal Du Donjon - Bellegarde (45) [<51] (29/05-05/09) >+33238902537 (121m)Municipal l'Ile Saint-Martin - Brienon sur Armancon (89) [<51] (01/05-30/09) >+33386430067 (87m)Municipal des Pres Barrees - Mondoubleau (41) (01/05-15/09) >+33254809073 (114m)Merlin l'Enchanteur - Loyat (56) (01/01-31/12) >+33297930552 -CCpg87-CCA(38m)Municipal Saint Cenere** - Saulges [<51] (01/04-31/10) >+33243904981 (66m)Les Granges de Franould - Dommartin les Remieremont (88) [<51] >+33329232938 (591m)l'Auberge - Obersaasheim (68) [<51] >+33389726020 (192m)Bel Air - Landudec (29) >+33298915027 (84m)Municipal Bois Du Seminaire - Quimper (29) (01/01-31/12) >+33298556109 (24m)Municipal De Keryanic - Elliant (29) [<51] (01/07-31/08) >+33298941984 (113m)Municipal - Naizin (56) [<51] (01/05-31/10) >+33297274327 (89m)l'Armancon - Saint Florentin (89) (02/04-11/10) >+33386350813 (99m)L'Ile de l'Entonnoir - Cezy (01/05-31/10) >+33386631787 (72m)Im Berg - Sondernach (tentes seulement) (68) [<51] >+33608541924 (855m)Municipal de Jean Cloutier - Chuelles (45) >+33238942119 (155m)Municipal la Marette - Plelan Le Grand (35) >+33299075722 (139m)Du Haut des Bluches - La Bresse (88) (13/12-11/11) >+33329256480 -CCA(723m)Municipal - Choue (41) [<51] (15/09-15/09) >+33254809228 (144m)Municipal du Chateau*** - Montigny le Roi (52) (15/04-30/09) >+33325873893 -CCA(423m)La Rocaille - Plogastel Saint Germain (29) [<51] (02/07-15/09) >+33298545813 (144m)Le Val Fleuri - Cloyes sur le Loir (28) (15/03-15/11) >+33237985053 -CCA(97m)l'Ocean - Plouhinec (29) (01/06-30/09) >+33298707021 (60m)Le Broceliande - Trehorenteuc (56) [<51] (01/06-30/09) >+33603797420 (97m)De Kersiny-Plage - Plouhinec (29) (10/05-13/09) >+33298708244 (32m)Les Pins - Bains les Bains (88) [<51] (01/04-30/10) >+33329362049 (332m)Municipal De la Foret - Montargis (45) (01/02-30/11) >+33238980020 (105m)Natur du Mettey - Vagney (88) (01/05-30/09) >+33329621686 -CCpg303-CCA(439m)La Ferme Place - Bazougers (53) [<51] (01/04-30/09) >+33243023021 (95m)Parc de Nibelle - Nibelle (45) (01/03-30/11) >+33238322355 (147m)Vauban - Neuf Brisach (68) (01/04-15/10) >+33389725425 -CCA(195m)Clairvacances**** - Ste.Croix en Plaine (68) (15/04-30/09) >+33389492728 -CCA(192m)A la Ferme Bannwarth - Obermorschwihr (68) [<51] (10/05-30/09) >+33389493087 (245m)A la Ferme Le Vignoble - Obermorschwihr (68) [<51] (01/04-30/10) >+33389493202 (243m)Larenvoie - Plouhinec (29) [<51] >+33298708938 (41m)Municipal Beg Er Roch - Le Faouet (56) (07/03-30/09) >+33297231511 (72m)Le Pont Romain**** - Yvre l'Eveque (15/03-15/11) >+33243822539 -CCA(52m)Municipal Broceliande - Paimpont (35) (05/04-29/09) >+33299078916 (161m)Pied a Terre de Loqueran - Audierne (29) [<51] (10/10-20/09) >+33298749506 (42m)Municipal De Kermalero - Primelin (29) >+33298748475 (29m)Les Iles - Saint Julien du Sault (89) [<51] (15/04-30/10) >+33386632258 (73m)Vallon de Kerlenn - Guern (56) [<51] (15/04-15/10) >+33256620254 (131m)l'Ile du Rhin - Biesheim (68) (26/04-27/09) >+33389725795 -CCpg297(187m)Municipal De Kerisole - Scaer (29) [<51] >+33686001174 (162m)Kerivoas - Audierne (29) [<51] (01/04-15/11) >+33298702686 (61m)Rural de Turbaux Maria - Credin (56) [<51] >+33297389749 (103m)La Garenne De Pan* - Bruz [<51] (01/01-31/12) >+33299412207 (31m)Les Amis de la Nature de Munster - Luttenbach pres Munster (68) (01/02-30/11) >+33389773860 (407m)A la ferme de Tourneux Yves - Saint Agil (41) [<51] (01/01-31/12) >+33254809448 (171m)Municipal Le Chardonneret** - Le Pertre (35) [<51] (01/04-30/09) >+33299969892 (173m)Municipal - Souday (41) [<51] (01/04-30/10) >+33254809318 (166m)Belle Hutte - La Bresse (88) (16/12-15/11) >+33329254975 (880m)Municipal De L'Etang - Saint Agil (41) [<51] (01/04-31/010) >+33254807438 (171m)La ferme Pre vert Kerguidy Izella- Plogoff (29) [<51] >+33298703560 (59m)Municipal - Dollon (72) [<51] (15/05-15/09) >+33243934223 (107m)La ferme Du Goyen - Mahalon (29) [<51] >+33298704020 (18m)Municipal Les Mottes - Ervy Le Chatel (10) (15/05-15/09) >+33325700796 (125m)Rives du Loing - Cepoy (45) [<51] (01/04-31/10) >+33238852933 (78m)Municipal Les Trois Chateaux*** - Eguisheim (68) (01/04-23/12) >+33389231939 -CCA(222m)L'Oiseau Libre - Claudon (88) [<51] (01/06-30/09) >+33329070066 (270m)Municipal La Chesnaye - Pouldergat (29) [<51] >+33298746126 (57m)Le Parc de la Fecht - Munster (68) (27/04-30/09) >+33499572121 -CCpg298(367m)Naturist - Koad Ar Roc'h - Neant sur Yvel (56) (25/05-10/09) >+33297744211 (69m)La Clariere du Verbamont - Claudon (88) [<51] (15/04-15/10) >+33950186452 (344m)A la ferme Perrot - Rangecourt [<51] >+33325903682 (370m)Aire naturelle de Keringard - Cleden Cap Sizun (29) [<51] (01/04-31/10) >+33649228737 (39m)Beau Rivage - Gunsbach (68) (01/04-20/10) >+33389774462 (333m)Les Myrtilles - Gerardmer (88) [<51] (01/05-30/09) >+33329632138 (770m)Centre Lothlorien - Foulain (52) [<51] >+33325034086 (303m)Aire naturelle Du Moulin - Wihr au Val (68) [<51] (15/06-15/09) >+33389710626 (307m)Municipal Les Grands Bosquets** - Chateaugiron [<51] (01/04-30/09) >+33299378902 (46m)Aire naturelle de l'Ecolonie - Hennezel (88) [<51] (01/03-31/10) >+33329070027 (369m)Municipal - Le Cambout (22) [<51] >+33296255054 (75m)La Route Verte - Wihr au Val (68) (25/04-30/09) >+33389711010 (320m)Municipal Le Lac** - Lavare [<51] (15/06-15/09) >+33243719644 (118m)l'Oree Du Bois** - St. Hilaire les Andresis (15/06-15/09) >+33238973657 (133m)La Ferme Saint Nicolas - Choiseul [<51] >+33325013157 (345m)Municipal De Poullen - Coray (29) [<51] >+33298591010 (190m)Municipal Du Val aux Fees - Concoret (56) (28/03-30/09) >+33297226482 (92m)Entre les Sources - Grandrupt de Bains (88) [<51] (01/05-31/08) >+33329309738 (417m)Municipal Lac de Bel Air - Priziac (56) >+33297346355 (162m)La Vologne - Xonrupt Longemer (88) (01/05-15/09) >+33329608723 (756m)Verte Vallee - Xonrupt Longemer (88) (15/12-01/11) >+33329632177 -CCA(741m)Municipal du Lac - Xonrupt Longemer (88) (15/04-15/10) >+33673641576 (747m)Les Sapins - Gerardmer (88) (01/04-10/10) >+33329631501 -CCA(666m)Municipal De Kerros - Goulien (29) [<51] (25/06-31/08) >+33298700604 (85m)Municipal La Plage aux Champs - Connerre (72) (01/07-31/07) >+33243891364 (67m)l'Oree du Bois - Xonrupt Longemer (88) [<51] >+33329632982 (738m)De la Rive du Bois - Chambon la Foret (45) [<51] (01/01-31/12) >+33238322973 (123m)La Grange Mausalaine - Xonrupt Longemer (88) (01/05-30/09) >+33329630715 (746m)Municipal Le Moulin de Coupeau** - St. Berthevin [<51] (01/05-30/09) >+33243683070 (95m)Le Ramberchamp - Gerardmer (88) (03/04-30/09) >+33329630382 (660m)Municipal Le Palevart - Guemene sur Scorff (56) [<51] (15/06-15/09) >+33297512023 (123m)Municipal** - Vibraye [<51] (01/04-31/10) >+33243937862 (130m)Les Jonquilles - Xonrupt Longemer (88) (17/04-30/09) >+33329633401 -CCA(749m)Belle Rive - Xonrupt Longemer (88) >+33329633112 (746m)Aire naturelle de Dagorn Simon - Goulien (29) [<51] (01/05-01/10) >+33298700679 (70m)Les Granges Bas - Gerardmer (88) (20/12-19/10) >+33329631203 (628m)La Chaumiere-Bellevue - Xonrupt Longemer (88) [<51] (01/01-31/12) >+33329631330 (757m)Municipal Du Val d'Oust - Rohan (56) [<51] (01/05-15/09) >+33297515078 (73m)Naturist - Mayenne Nature - Soulge sur Ouette (53) (01/05-30/09) >+33647248065 (108m)Le Vieux Moulin** - Neuville sur Sarthe (01/07-31/08) >+33243253182 (49m)Les Sorbiers - Xonrupt Longemer (88) [<51] >+33329633604 (762m)Municipal du Douric - Pontivy (56) [<51] >+33297250033 (59m)Municipal Domaine de Longemer- Xonrupt Longemer (88) (01/01-14/11-12/12-31/12) >+33329632710 (736m)Rural Chez Chantal et Dany - Soultzeren (68) [<51] (Easter-30/10) >+33389770209 (741m)l'Ill*** - Colmar (68) (28/03-21/12) >+33389411594 -CCA(185m)Municipal du Moulin a Tan - Chateaudun (28) (01/04-30/09) >+33237450534 (106m)Le Saucil - Villeneuve sur Yonne (89) (01/04-30/11) >+33386870069 (69m)La Baie de Douarnenez - Douarnenez (29) (26/04-14/09) >+33298742639 -CCA(74m)A l'Eau Vive - Xonrupt Longemer (88) (01/01-31/12) >+33603740077 (755m)Le Gue Vaslin - Chateaudun (28) [<51] (01/04-31/10) >+33237450816 (108m)Pors Peron - Beuzec Cap Sizun (29) (01/04-30/09) >+33298704024 -CCA(40m)Le Medieval - Turckheim (68) (04/04-26/10) >+33389270200 -CCA(237m)La Presse - Auxy (45) [<51] (01/01-31/12) >+33238964494 (95m)Aire Naturelle Benzen - Logelbach (68) [<51] >+33389274038 (218m)Le Noirrupt - Le Tholy (88) (01/05-30/09) >+33329618127 -CCA(616m)Municipal - Saint Lery (56) [<51] (01/01-31/12) >+33297226876 (62m)Du Perray - Ferrieres en Gatinais (45) >+33671432595 (80m)Beaulieu - Le Plessis Dorin (41) [<51] >+33254808535 (195m)Trezulien - Douarnenez (29) (09/04-24/09) >+33680011798 (24m)Municipal Les Deux Hohnack - Labaroche (68) (01/04-30/09) >+33962386882 (785m)Municipal La Croix Couverte - Sainte Suzanne (53) [<51] (01/05-30/09) >+33243014161 (120m)Val des Rochottes - Darney (88) [<51] (01/06-15/09) >+33329093345 (286m)Croas-Men - Douarnenez (29) >+33298740018 (27m)Municipal - Locronan (29) (18/04-28/09) >+33628804474 -CCpg78-CCA(180m)Municipal du Mont Clair - Clefmont (52) [<51] (30/04-15/10) >+33325313163 (467m)Ar Voden - Plogonnec (29) (01/07-31/08) >+33298917206 (278m)Rural La Houbette - Liezey (88) [<51] (15/04-30/09) >+33329245639 (708m)De Kerleyou - Douarnenez (29) >+33298741303 (69m)Municipal Saint Yves - La Trinite Porhoet (56) [<51] (15/06-15/09) >+33297939200 (86m)De Tremelin - Iffendic (35) (01/04-30/10) >+33299097379 (103m)Municipal du Pont de Pierre - Arrou (28) (01/05-15/09) >+33237970213 (147m)Indigo - Douarnenez (29) >+33298740567 (52m)Le Clos des Tourterelles - Bouzonville aux Bois (45) (01/01-31/12) >+33238330100 (111m)Municipal Sceleen - Sceaux du Gatinais (45) [<51] (12/04-12/10) >+33238874027 (79m)Municipal - Tregourez (29) [<51] (15/06-15/09) >+33298591028 (119m)Le Chateau de Chanteloup - Sille le Philippe (72) (31/05-31/08) >+33243275107 (78m)Aire naturelle Municipale - Bar sur Seine (10) [<51] >+33325298638 (151m)Municipal La Vegre - Tennie (72) (01/04-01/10) >+33683953351 (88m)Les Platanes* - La Guierche (15/04-30/09) >+33243273629 (50m)Municipal St Etienne** - Vitre [<51] (01/03-15/12) >+33299752528 (115m)Trezmalaouen - Plonevez Porzay (29) (04/04-26/09) >+33298925424 -CCpg77-CCA(34m)Les Moraines - Pairis (68) [<51] (01/01-31/12) >+33389712519 (694m)Kervel - Plonevez Porzay (29) >+33298925154 (64m)d'Ys - Plonevez Porzay (29) [<51] >+33298925052 (56m)A la ferme de Secouray - Nottonville (28) [<51] (01/01-31/12) >+33609574486 (121m)La Ferme des Hauts Frenes - Eaux Puiseaux (10) [<51] (01/01-31/12) >+33325421504 (181m)A la Ferme Les Bouleaux - Orbey (68) [<51] (01/04-31/10) >+33389712273 (691m)La ferme Les Noues de Crochet - Arrou (28) [<51] (01/04-30/09) >+33237970403 (166m)Municipal Parc Sainte Marie** - Chaumont (02/05-30/09) >+33325321198 (278m)Le Lac - Tuffe (72) (01/04-30/09) >+33243938834 -CCA-BD_FR-E.001b(89m)Ferme auberge du Chevremont - Orbey (68) [<51] (15/04-15/10) >+33389712351 (615m)Le Barba - Rehaupal (88) [<51] (01/05-30/09) >+33329663557 (505m)La Steniole - Granges sur Vologne (88) (01/05-31/10) >+33329514375 -CCA(727m)Municipal Kermanu - Langoelan (56) [<51] (01/05-31/10) >+33297512554 (194m)Municipal De la Gironde - Conlie (72) [<51] (01/06-15/09) >+33243208107 (111m)Gademont Plage - Granges sur Vologne (88) (01/01-31/12) >+33329514460 (658m)Municipal Du Stade - Cleguerec (56) [<51] (15/06-15/09) >+33297380015 (158m)Municipal La Riviere - La Bazoche Gouet (28) [<51] (03/04-04/10) >+33237492649 (181m)Municipal Lefebure - Orbey (68) [<51] (20/04-30/09) >+33389713742 (544m)Champ de Roches - Barbey Seroux (88) [<51] (01/06-31/08) >+33329514495 (612m)Gina-Park - Granges sur Vologne (88) >+33329514195 (516m)Les Trexons - Gerbepal (88) [<51] (01/06-15/09) >+33329507492 (681m)Municipal des Gayeulles*** - Rennes (01/01-31/12) >+33299369122 -CCpg61(61m)Municipal La Riviere - La Cheze (22) [<51] (01/06-15/09) >+33296266186 (75m)Municipal Pre du Thabor** - Montfort s/Meu [<51] (01/05-30/09) >+33299090017 (37m)Municipal De la Jouanne** - Montsurs [<51] (01/01-31/12) >+33243010031 (75m)Municipal Pont Min - Gourin (56) [<51] >+33297234037 (126m)Ferme les Collieures - Corcieux (88) [<51] (01/05-30/09) >+33329506938 (694m)Les Peupliers - Granges sur Vologne (88) [<51] (01/05-30/09) >+33329575104 (499m)Pont d'Orne** - Montbizot [<51] (15/05-30/09) >+33243276044 (53m)Treguer Plage - Plovenez (29) (05/04-28/09) >+33298925352 -CCpg74-CCA(6m)La Mer - Ploeven (29) (01/06-30/09) >+33298812919 (4m)Municipal**** - Kaysersberg (01/04-30/09) >+33389471447 (266m)Au Chalet du Rhin - Marckolsheim (67) [<51] >+33388925235 (177m)Municipal - Evron (53) >+33243016536 (97m)Aire Naturelle du Champ Miguet - Renauvoid (88) [<51] (01/01-31/12) >+33329822282 (374m)Le Chateau - Granges sur Vologne (88) [<51] (17/04-07/09) >+33329575083 (543m)Aire naturelle Ascpa - Renauvoid (88) [<51] (01/02-30/11) >+33329824467 (375m)Les Braudieres** - Mezieres sous Lavardin [<51] (01/01-31/12) >+33243208148 (112m)Rural de Thirouard Renee - Chapelle Royale (28) [<51] (01/04-30/10) >+33237492175 (190m)A la ferme Belle Vue - Mellionnec (22) [<51] (01/03-30/10) >+33296242423 (254m)Municipal - Lescouet Gouarec (22) [<51] (01/06-30/09) >+33296242185 (225m)Casa Boslimpre - Ban sur Meurthe Clefcy (tentes seulement) (88) [<51] (01/05-30/09) >+33329508704 (753m)Les Amis de la Nature - Chaumousey (88) (01/06-30/09) >+33675781624 (377m)Intercommunal**** - Riquewihr (01/04-05/01) >+33389479008 (246m)Les Lilas - Pithiviers (45) [<51] (01/01-31/12) >+33238392011 (104m)Plage de Pors Ar Vag - Plomodiern (29) (01/04-31/10) >+33298815142 (25m)Au Mica - Corcieux (88) (01/06-30/08) >+33329507007 (562m)Le Goulit Ar Guer - Plomodiern (29) (01/04-31/10) >+33298815271 (38m)Club Lac de Bouzey -�Sanchey (88) (01/02-31/12) >+33329824941 -CCpg305-CCA(373m)Ferme Auberge de Blavon - Bedee (35) [<51] (01/01-31/12) >+33299070403 (67m)Le Clos de la Chaume - Corcieux (88) (01/05-20/09) >+33329507676 -CCA(548m)Municipal Du Goaker - Saint Goazec (29) [<51] (15/06-15/09) >+33298268423 (57m)Des Bans - Corcieux (88) (01/01-31/12) >+33329516467 (545m)Le l'Iroise - Plomodiern (29) >+33298815272 (16m)Stervinou - Saint Thois (29) [<51] >+33298732076 (41m)La Tour - Corcieux (88) [<51] (01/01-31/12) >+33329507519 (541m)Rural Les Myrtilles - Le Bonhomme (tentes seulement) (68) [<51] (12/04-26/10) >+33389475750 (732m)Municipal Le Bois Chievre - Bonneval (28) (01/04-20/10) >+33237475401 -CCA(144m)A la ferme Ty Rouz - Plomodiern (29) [<51] >+33298815848 (45m)A la ferme Le Bois du Barde - Mellionec [<51] >+33296293003 (202m)Les Hirondelles - Bourg Sainte Marie (52) [<51] (01/01-31/12) >+33310206164 -CCA(347m)Municipal Du Pont** - Andouille [<51] (15/04-15/10) >+33243697272 (69m)Municipal Le Pre De La Mare - Plemet (22) [<51] (15/06-15/09) >+33296256110 (132m)Municipal Le Valmer - La Ferte-Bernard (72) (01/05-15/09) >+33243717003 (85m)Les Acacias Nature - Anould (88) [<51] (15/06-15/09) >+33329571106 (567m)Rural de Quenecan - Mur De Bretagne (22) [<51] >+33296260081 (82m)Municipal La Prairie - Bonnetable (72) [<51] (15/05-15/09) >+33620100132 (104m)Aquarev - Loudeac (22) (12/04-01/11) >+33296668500 -CCA(129m)Des Messires - Herpelmont (88) (18/04-28/09) >+33329585629 -CCA(443m)Municipal le Prieure - Saint Marceau (72) [<51] (01/07-31/08) >+33243342622 (58m)Municipal Les Bords du Loing*** - Souppes sur Loing (01/04-31/10) >+33164297263 (64m)Parc du Chateau - Epinal (88) [<51] (01/04-31/10) >+33329344365 -CCA(373m)Municipal Le Tir aux Pigeons*** - Contrexeville (68) (01/04-31/10) >+33329081506 (364m)Municipal Les Noes - La Prenessaye (22) [<51] (01/04-30/09) >+33296256481 (129m)Le Kergorz - Plomodiern (29) (30/06-08/09) >+33298265041 (5m)Municipal Les Verts Bois - Freland (68) [<51] (01/04-31/10) >+33389719194 (524m)Municipal Entre Deux Vannes - Sens (89) [<51] (15/05-15/09) >+33386656471 (69m)Municipal - Saint Meen le Grand (35) [<51] (01/06-30/09) >+33299095804 (96m)Penn Ar Pont - Saint Goazec (29) >+33298818125 (54m)Les Acacias - Anould (88) (05/12-28/09) >+33329571106 (460m)Clairegoutte - Fraize (88) [<51] (01/04-30/10) >+33329503527 (488m)Ker Vella - Plomodiern (29) >+33298265014 (26m)La Pointe - Chateaulin-Saint Coulitz (29) (15/03-15/10) >+33298865153 -CCpg75-CCA(12m)Les Tournesols - Le Grez (72) (01/05-30/09) >+33243201269 -CCpg93(245m)Les Pinasses - La Chapelle devant Bruyeres (88) (01/04-30/09) >+33329585110 -CCpg304(453m)Municipal Rodaven - Chateaulin (29) (01/04-30/09) >+33298863293 -CCpg76-CCA(14m)Menez Bichen - Saint Nic (29) >+33298265082 (3m)Ker-Ys - Saint Nic (29) >+33298265395 (2m)Rural de Jarry Alexandre - La Croixille (53) [<51] (15/05-15/09) >+33243685700 (153m)Rural de Lefevre Therese - Sille le Guillaume (72) [<51] (01/04-31/10) >+33243201191 (249m)Municipal Pont Coblant - Pleyben (29) [<51] >+33298733122 (27m)Municipal** - Toury (28) [<51] (01/04-15/10) >+33237905060 (134m)Municipal Pierre De Coubertin**** - Ribeauville (15/03-15/11) >+33389736671 (219m)Municipal Des Trois Chateaux - Ribeauville (68) (28/06-08/09) >+33389732000 (301m)Val de Landrouet - Merdrignac (22) (01/05-30/09) >+33296284798 (136m)Rural de Brunet Michel - Charbonnieres (28) [<51] (01/01-31/12) >+33237490241 (222m)Municipal Le Point de Vue de Guerledan - Mur De Bretagne (22) (15/02-11/11) >+33296260190 (137m)Porte des Vosges*** - Bulgneville (01/04-31/10) >+33329091200 (394m)Restaurant Merlin - Saint Aignan (56) [<51] (01/05-15/10) >+33297275236 (141m)Le Vignoble - Bergheim (68) [<51] (01/01-31/12) >+33389738281 (198m)Plan D'Eau Des Terres Rouges** - Clerey [<51] (15/04-25/09) >+33325460445 (120m)Municipal - Authon Du Perche (28) [<51] (01/04-31/10) >+33237490341 (233m)Pre Vert La Sauleraie - Meurville (10) [<51] >+33325274056 (198m)Indigo Les Molieres - Sille le Guillaume (72) (17/04-28/09) >+33243201612 -CCA(237m)Municipal De La Vallee St Eloi** - Montauban de Bretagne [<51] (01/07-31/08) >+33299064255 (68m)Les Noyers - Bergheim (68) [<51] (01/04-25/10-05/11-24/12) >+33608346010 (194m)Ty Provost - Chateaulin (29) [<51] (01/06-15/09) >+33298862923 (164m)Municipal** - Vittel (01/04-15/10) >+33329080271 -CCpg306-CCA(347m)Naturist - Soleil de Rennes - Geveze (71) >+33299690592 (88m)Parc de Loisirs*** - Brou (16/02-14/12) >+33237470217 (153m)Nautic de Guerledan - Caurel (22) (15/05-25/09) >+33296285794 (152m)Aire naturelle Du Tempelhof - Bergheim (68) [<51] (01/04-25/10-05/11-24/12) >+33389736559 (236m)La Foret - Sille le Guillaume (72) (01/04-27/10) >+33243201104 -CCA(238m)Pen Bellec - Telgruc sur Mer (29) [<51] (01/05-20/09) >+33666613672 (8m)La Croix Sapin - Bruyeres (88) [<51] (15/02-30/09) >+33329505508 (455m)A la ferme de Chailloy - Bethonvilliers (28) [<51] (01/01-31/12) >+33237490260 (223m)Municipal - Glomel (22) (15/06-15/09) >+33296298420 (216m)Les Bruyeres - Morgat-Crozon (29) (01/05-15/09) >+33603651923 -CCA(26m)La Maillardiere - Alexain (53) [<51] (01/06-31/08) >+33243028275 (125m)Le Moulin Vert - Cleden Poher (29) [<51] (01/06-01/09) >+33298968205 (70m)Le Panoramic - Telgruc sur Mer (29) (01/05-15/09) >+33298277841 -CCA-BD_FR-A.095(64m)Aire naturelle de Toul Rodez - Laniscat (22) [<51] (01/06-30/09) >+33296369484 (173m)Armorique - Telgruc sur Mer (29) (01/04-30/09) >+33298277733 -CCpg73-CCA(77m)Municipal Du Val de Sarthe*** - Beaumont sur Sarthe (01/05-30/09) >+33243970193 (68m)Tost Aven - Gouarec (22) (01/05-01/09) >+33632001694 (132m)Aire naturelle De St Launeuc - Saint Launeuc (22) [<51] (15/06-15/09) >+33296284111 (139m)Schoenau Plage - Schoenau (67) (01/04-30/09) >+33388852285 (165m)Municipal Du Centre D'Acceuil De Kermarc'H - Plouguernevel (22) [<51] (01/04-31/10) >+33673556031 (211m)Les Mimosas - Telgruc sur Mer (29) (01/06-15/09) >+33298277606 (74m)Les Hierottes - They sous Montfort (88) [<51] (01/04-30/09) >+33329084242 (359m)Municipal Du Lac - Chatillon en Vendelais (35) (01/05-30/09) >+33299760632 (111m)Naturist - Le Champ du Moulin - Verrieres (10) (01/05-30/09) >+33661039491 (113m)Fleur De Bretagne - Rostrenen (22) (01/01-31/12) >+33296291645 (218m)Ar Menez - Argol (29) (15/06-15/09) >+33298273302 (151m)Aire naturelle Les Mirabelles - They sous Montfort (88) [<51] (01/07-31/08) >+33329082956 (372m)Les Reflets du Val d'Argent - Sainte Marie aux Mines (68) (01/01-31/12) >+33389586483 -CCA(411m)Les Pins - Crozon (29) (15/04-15/11) >+33660544009 (66m)Aire naturelle Municipale - Landeleau (29) [<51] >+33298938216 (64m)La Plage de Goulien - Crozon (29) (10/06-15/09) >+33608434932 (19m)Municipal De Pierre le Sault** - Bagneaux s/Loing (01/04-31/10) >+33164292444 (61m)L'Aber - Crozon (29) (09/04-01/11) >+33675623907 -CCA(54m)Le Fenarupt - Sainte Marie aux Mines (68) [<51] (01/01-31/12) >+33389585480 (440m)Municipal Claires Vacances - Bais (53) [<51] >+33243370241 (181m)Municipal Du Moulin - Andelot Blancheville (52) (15/04-15/10) >+33325326128 -CCA(239m)Aire naturelle - Mesnil Saint Pere (10) [<51] (01/06-31/10) >+33325412812 (133m)Municipal Le Violu - Gemaingoutte (88) [<51] (01/04-31/10) >+33329577070 (433m)Municipal Les Cigognes** - Selestat (68) (01/04-15/10) >+33388920398 (170m)Le Boterff - Saint Mayeux (22) >+33296240280 (277m)Ile de Boulancourt - Boulancourt (77) (01/01-31/12) >+33164241338 (78m)Municipal L'Etang** - St. Aubin du Cormier [<51] (23/04-23/09) >+33299391042 (107m)De la Joulliere - Andonville (45) (15/02-15/12) >+33238395846 (123m)Lac d'Orient - Mesnil Saint Pere (04/04-26/09) >+33325406185 -CCpg310(147m)Municipal De La Rhone - Souance au Perche (28) [<51] (01/04-31/10) >+33237291562 (136m)La ferme Garmorin - Plouguenast (22) [<51] (15/06-30/09) >+33628197153 (173m)La Baraude** - Darvault (01/01-31/12) >+33164281526 (101m)Aire naturelle Municipale - Saint Goueno (22) [<51] (01/06-15/09) >+33296344344 (190m)Municipal Rives de Marne - Vouecourt (52) [<51] >+33325024446 (221m)Rural de Camping Municipal - Medreac (35) [<51] (01/06-30/09) >+33299072320 (71m)Aire naturelle Municipale - Saint Medard sur Ille (35) [<51] (01/07-30/09) >+33299552353 (57m)Le Haut-Koenigsbourg*** - Liepvre (15/03-15/10) >+33389584320 (275m)Municipal de la Chesnaie - Plessala (22) [<51] (01/04-30/09) >+33296261108 (181m)Municipal Du Lannic - Camaret sur Mer (29) (01/01-31/12) >+33298279131 (39m)Municipal De La Vallee De L'Hyeres - Carhaix Plouguer (29) (01/05-15/09) >+33298991058 (79m)l'Etang des Sources - Mael Carhaix (22) [<51] >+33296246412 (193m)Rural de Lesieur Bernard - Vicheres (28) [<51] (01/04-01/11) >+33237294281 (262m)Le Grand Large Lambezen -�Camaret sur Mer (29) (01/04-30/09) >+33298279141 -CCpg72-CCA-BD_FR-A.094(35m)Gwel Kaer - Crozon (29) >+33298276106 (10m)Municipal Le Sans Souci*** - Fresnay sur Sarthe (01/04-30/09) >+33243973287 (78m)Les Pieds dans l'Eau - Crozon (29) (15/03-15/10) >+33298276243 (18m)Pinebre - Plouguenast [<51] (01/04-30/09) >+33296268004 (151m)Le Seillou - Rosnoen (29) >+33298819214 (5m)Le Bois Fleuri - Illiers Combray (28) (05/04-31/10) >+33237240304 -CCpg315-CCA(161m)Municipal - Courgenay (89) (01/05-30/09) >+33386868207 (124m)Municipal Les Bouleaux - Rombach le Franc (68) [<51] (15/04-15/10) >+33389584156 (347m)Plage de Trez Rouz - Crozon (29) (15/05-15/10) >+33298279396 -CCA(12m)Municipal Les vertes Prairies - Cherance (72) (01/06-31/08) >+33243331290 (89m)Aire naturelle Palmer - Scherwillerr (67) [<51] (15/05-15/09) >+33388929457 (186m)Municipal - Saint Georges le Gaultier (72) >+33243973136 (103m)La Fromentelle** - Dosches (10) [<51] (01/05-30/09) >+33325415267 (120m)Municipal l'Ile de Amour - Pont sur Yonne (89) (01/04-30/09) >+33386670362 (61m)A la ferme Saint Paul - Ebersheim (67) [<51] (Easter-01/11) >+33388857180 (163m)La Cale - Lanveoc (29) (01/01-31/12) >+33661080353 (28m)Municipal Du Pal - Landevennec (29) [<51] (01/05-30/09) >+33298277265 (2m)l'Arc en Ciel** - Neuveville s/Chatenois [<51] (20/04-30/09) >+33369618140 (320m)Municipal - Jessains (10) [<51] (01/05-30/10) >+33325927206 (157m)Municipal - Le Faou (29) (2m)La Base de Buthiers - Buthiers (77) >+33164241287 (91m)Les Grouettes* - Villemer (01/04-31/10) >+33164249216 (81m)Tuchennou - Brasparts (29) [<51] (15/06-15/09) >+33298814302 (123m)Municipal Les Deux Ponts - Froncles (52) [<51] (15/03-15/10) >+33325023835 (213m)Lac de Bosmeleac - Allineuc (22) >+33296288788 (176m)Les Rives du Lac-L'Epine Aux Moines - Geraudot (10) (01/01-31/12) >+33325412436 -CCA(145m)Rural Foyer St. Martin - Ebersheim (67) [<51] (15/06-15/09) >+33685109554 (163m)A la ferme l' Orchidee Home - Roches Bettaincourt (52) [<51] (01/01-31/12) >+33325323393 (251m)Municipal Kervian - Roscanvel (29) [<51] (15/06-15/09) >+33298274851 (45m)Les Peupliers - Tinteniac (35) (01/04-30/09) >+33299454975 -CCA(51m)Municipal Cussulio - Saint Nicolas Du Pelem (22) >+33296295127 (152m)Rural Bretane - Hanvec (29) [<51] (15/05-31/10) >+33298219104 (52m)Moulin des Moines - Chatenois (01/04-31/10) >+33329945859 (305m)La Planchette** - Broons [<51] (01/03-31/10) >+33296846003 (76m)Municipal de Troyes*** - Pont Sainte Marie (01/04-15/10) >+33325810264 (105m)Aire naturelle L'Europeen - Geraudot (10) [<51] (15/06-15/09) >+33325412682 (143m)Municipal Du Gue St Leonard - Mayenne (53) (15/03-30/09) >+33243045714 (89m)Municipal - Saint Hilaire sur Erre (61) [<51] (15/03-30/09) >+33237521242 (105m)Les Pres** - Grez s/Loing (22/03-11/11) >+33164457275 (57m)Municipal Dessous De L'Etang - Corlay (22) [<51] (15/06-15/09) >+33296294041 (182m)Municipal - Saint Paul le Gaultier (72) [<51] (01/04-30/09) >+33243335855 (102m)La Ferme des Tuileries - Rhinau (67) (01/04-30/09) >+33685749897 (157m)Municipal Le Roz - Logonna Daoulas (29) (01/04-31/10) >+33298206786 (9m)De l'Ours - Dambach La Ville (01/03-23/12) >+33677111648 (178m)Gouelet Ker - Logonna Daoulas (29) (01/04-25/10) >+33298206452 (22m)Le Bois Jahan - Brunelles (28) (01/01-30/11) >+33237521473 (241m)Municipal Des Viennes - Nogent Le Rotrou (28) [<51] (15/05-15/09) >+33237528051 (107m)Rural de la Tuilerie - Chatel sur Moselle (88) [<51] (01/05-01/10) >+33329679456 (367m)Aire naturelle Saint Gilles - Saint Pierre Bois [<51] (01/04-31/10) >+33388856726 (248m)Le Ried - Boofzheim (67) (11/04-20/09) >+33388746827 -CCpg299(155m)Municipal Du Pont L'Abbesse - Tinteniac (35) [<51] (01/03-31/10) >+33299680991 (40m)Bois la Justice - Monnerville (91) (07/02-24/11) >+33164950534 -CCA(139m)Le Parc du Gue** - La Genevraye (15/03-30/11) >+33164458779 (56m)Le Giessen - Bassemberg (67) (04/04-14/09) >+33388589814 -CCpg300-CCA(281m)Municipal - Rambervillers (88) [<51] (15/05-15/09) >+33329651184 (286m)Municipal La Bijouterie - Feins (35) [<51] (11/04-30/09) >+33299696323 (72m)Du Beausejour - Sergines (89) (01/01-31/12) >+33386663080 (104m)Les Terrasses de Bertheaume - Plougonvelin (29) (01/01-31/12) >+33298483237 (15m)Municipal - Ploeuc sur Lie (22) [<51] (01/07-05/09) >+33296642200 (201m)A la ferme de Saliou - Plougonvelin (29) [<51] (01/05-01/10) >+33662063335 (46m)Municipal des Dolmens - Marcilly Le Hayer (10) [<51] (01/04-31/10) >+33325217434 (119m)Municipal - Saales (67) [<51] (01/06-15/09) >+33388977026 (579m)Le Colombier - Dienville (10) [<51] (01/01-31/12) >+33325622347 (127m)Le Tertre - Dienville (10) (27/03-15/10) >+33325922650 -CCA(135m)Les 7 Hameaux - Ban de Sapt (88) [<51] (01/04-31/10) >+33329589575 (541m)La Tourelle - Moncontour (22) [<51] (07/05-15/11) >+33296735065 (180m)Municipal des Alpes Mancelles - Saint Leonard des Bois (72) (01/05-30/09) >+33243338179 (104m)Municipal Paron** - Fougeres (02/05-30/09) >+33299994081 (97m)Municipal Le Portez - Locmaria Plouzane (29) (01/05-30/09) >+33298484985 (28m)Intercxommunal - Neufchateau (88) [<51] (15/05-30/09) >+33329941903 (277m)Municipal du Saosnois - Mamers (72) [<51] (02/03-02/11) >+33243976830 (122m)l'Amicale du Port - La Brosse Montceaux (77) >+33164325404 (52m)Municipal Le Garillon - Radonvilliers (10) (01/04-31/10) >+33325922146 (124m)A la ferme de Jegou - Plouzane (29) [<51] >+33684167488 (88m)Municipal Le Drosera - Brennilis (29) [<51] (15/06-15/09) >+33298996657 (229m)Municipal Le Lac - Huelgoat (29) (15/06-15/09) >+33298997250 (171m)La Riviere d'Argent - Huelgoat (29) (02/04-15/10) >+33298997250 -CCA(98m)Beaulieu sur l'Eau - Etival Clairefontaine (88) (01/01-31/12) >+33329415351 (318m)Le Goulet - Brest (29) (01/01-20/12) >+33298458684 -CCA(53m)Les Blancs Sablons - Le Conquet (29) (29/03-30/09) >+33298360791 (30m)Naturist - Roz Pella - Saint-Urbain (29) [<51] >+33298840996 (19m)A la ferme Niedermatten - Breitenbach (67) [<51] >+33388571822 (446m)Du Perche Bellemois - Belleme (61) [<51] (27/04-08/10) >+33233853100 (172m)Grande Paroisse - La Grande Paroisse (77) (16/03-31/10) >+33160570202 (45m)Croix Badeau - Soulaines Dhuys (10) [<51] (01/04-30/09) >+33325270543 (147m)Municipal Les Iles - Charmes (88) (01/04-30/09) >+33329388771 (267m)Le Marcassin - Montereau Fault Yonne (77) >+33160963605 (50m)La Maison Neuve - Romazy (35) [<51] >+33299950564 (80m)Le Haut Saintois - Pleuvezain (88) [<51] (01/06-15/09) >+33329064037 (365m)Les Reflets - St. Pierre (67) [<51] (15/05-01/10) >+33389586431 (176m)Du Logis -�La Chapelle aux Filtzmeens (35) (01/04-06/11) >+33299452545 -CCpg62(28m)Les Courtilles du Lido - Veneux les Sablons (77) (29/03-20/09) >+33160704605 -CCA(49m)Municipal - Botmeur (29) [<51] (01/05-30/09) >+33298996306 (272m)Municipal Tal-Ar-C'Hoat - La Feuillee (29) [<51] (01/07-31/08) >+33298996152 (258m)Au Clair Ruisseau - Gerstheim (67) (01/03-31/10) >+33388983004 (149m)Le Parc de Vaux - Ambrieres les Vallees (53) (18/04-28/09) >+33243049025 -CCpg92-CCA(110m)Municipal Le Drennec - Commana (29) [<51] (15/06-15/09) >+33298780013 (165m)La Musardiere*** - Milly la Foret (15/02-20/11) >+33164989191 (83m)Vosgina - Moyenmoutier (88) [<51] (01/01-31/12) >+33329414763 (337m)Etang de l'Hermitage - La Tombe (77) >+33160968532 (51m)Municipal Jean Jaures - Senones (88) [<51] (15/06-15/09) >+33329579447 (383m)Municipal De Camfrout** - Le Relecq Kerhuon (24/06-03/09) >+33298283784 (12m)Municipal Du Gollen - Sizun (29) [<51] (20/04-30/09) >+33298688013 (89m)Municipal** - Morancez [<51] (30/05-29/08) >+33237300280 (130m)Municipal du Velodrome - Quintin (22) (01/04-15/10) >+33296748401 (170m)Saint Jean - Plougastel Daoulas (29) (12/04-27/09) >+33298403290 -CCpg71-CCA(14m)Municipal Le Bocage *** - Jugon les Lacs (15/04-15/09) >+33296316016 -CCpg63-CCA(45m)Municipal La Verte Vallee - Callac (22) (15/06-15/09) >+33296455850 (150m)Municipal Le Vieux Chatel - Combourg (35) (03/04-03/11) >+33299730703 (46m)Municipal du Herrenhaus - Le Hohwald (67) (15/06-15/09) >+33388083090 (620m)La Forge Sainte Marie -�Thonnance-les-Moulins (52) (19/04-12/09) >+33325944200 -CCpg308-CCA(259m)Saint Martin** - Barr [<51] (15/05-10/10) >+33388080045 (214m)Le Champ Du Feu - Belmont (67) [<51] (01/01-31/12) >+33388973052 (1003m)Kerebel - Ploumoguer (29) [<51] (01/07-30/09) >+33298896759 (50m)Le Calvaire - Montireau (28) [<51] (30/06-10/09) >+33237498597 (276m)La Ferme de la Rondaie - Tremblay (35) [<51] >+33299982089 (83m)Le Vauvert - Ormoy la Riviere (91) (15/05-15/09) >+33164942139 (73m)Les Reflets du Mont Sainte Odile** - Barr (01/03-31/10) >+33388080238 (383m)A la Ferme Entre Pierres et Collines - Saint Germain en Cogles (35) [<51] >+33299956909 (169m)La Trouche - Raon l'Etape (88) [<51] >+33329414240 (331m)Municipal Saint Barthelemy - Trainel (10) (01/04-30/09) >+33325391336 (70m)Wagelrott** - Erstein (01/04-30/09) >+33388980988 -CCA(150m)Rural de Bachert Jean-Louis - Barr (67) [<51] (01/04-31/10) >+33388089589 (224m)La Peupleraie - Bray sur Seine (77) (01/04-31/10) >+33160671224 (54m)Rural La Croix - Mathons (52) [<51] >+33325940174 (299m)Municipal Ruscumunoc - Plouarzel (29) [<51] (15/05-15/09) >+33298896007 (26m)Municipal - Samoreau (77) (01/04-31/10) >+33164237225 (48m)Municipal Le Guerame** - Alencon (01/04-30/09) >+33233263495 (134m)Municipal - Remalard (61) [<51] (15/03-30/09) >+33233737123 (122m)Les Gravieres - Lesmont (10) [<51] (01/04-30/09) >+33325924779 (109m)l'Etang de Belesbat - Courdimanche sur Essonne (91) (01/03-30/12) >+33614258852 (60m)Municipal De Porstevigne - Plouarzel (29) (15/05-15/09) >+33298840702 (20m)Aire naturelle La Petite Suisse - Poissons (52) [<51] (01/05-15/09) >+33325945075 (248m)Municipal Les Bords De L'Eure*** - Chartres (28) (01/03-15/11) >+33237287943 -CCA(130m)Municipal Porscuidic - Plouarzel (29) [<51] (15/05-15/09) >+33298840702 (14m)Aire naturelle Municipale - Xirocourt (54) [<51] (15/06-15/09) >+33383525007 (243m)Forest View - Dorceau (61) [<51] (01/04-31/10) >+33233254527 (164m)La Ferme de Bergue Roger - Le Ribay (53) [<51] >+33243039084 (179m)Municipal - Pontmain (53) [<51] (01/04-30/11) >+33243050702 (153m)Municipal Lokournan - Saint Renan (29) (01/06-15/09) >+33298843767 (31m)Aire naturelle Municipale - Bainville aux Miroirs(54) [<51] >+33383725413 (252m)Municipal - Domremy la Pucelle (88) [<51] (01/06-31/08) >+33329069070 (268m)Naturist - Les Bois de Valence - d'Huison Longueville (91) (01/05-30/09) >+33685315592 (81m)Municipal Pre De Hon - Baccarat (54) [<51] (01/05-15/09) >+33383751337 (267m)Etang du Pre Fleury - Magnieres (54) [<51] (01/05-15/10) >+33383738221 (245m)Municipal Bords de l'Eure - Courville sur Eure (28) (01/05-21/09) >+33237237638 (163m)Municipal Chateaubriand - Dinan (22) [<51] (01/06-30/09) >+33296391196 (39m)A la ferme Le Lanniouarn - Plouarzel (29) [<51] (01/01-31/12) >+33298896044 (22m)Au Bord de Bruche - Rothau (67) [<51] (01/01-31/12) >+33369062802 (351m)Le Bois Coudrais - Cuguen (35) [<51] (01/05-30/09) >+33299732745 (102m)Les Lacs - Celles sur Plaine (88) (01/04-30/09) >+33329412800 -CCA(313m)Aire naturelle Bonteville - Montours (35) [<51] (01/05-30/09) >+33299951660 (160m)Municipal Pen Ar Bed - Ouessant (29) (01/04-30/09) >+33298488465 (14m)Municipal Alain Gerbault - Pre en Pail (53) [<51] (01/04-30/09) >+33243030428 (213m)Aire naturelle le Chene au Loup - Pledeliac (22) [<51] (01/06-30/09) >+33623014289 (106m)Le Petit Barbeau - Samois sur Seine (77) (15/03-30/11) >+33164248779 (47m)Le Vallon de l'Ehn*** - Obernai (67) (14/03-11/01) >+33388953848 -CCA(205m)La Barbuise* - St. Remy sous Barbuise [<51] (01/01-31/12) >+33325375095 (127m)Municipal de la Hallerais - Taden (22) (14/03-12/11) >+33296391593 (49m)Municipal du Grand Jardin - Laneuville a Remy (52) [<51] (01/01-31/12) >+33325553033 (159m)La Bouliniere - Boissy le Cutte (91) (01/02-30/11) >+33164576523 (72m)Municipal Saint Saveur ** - Lamballe [<51] (01/07-20/09) >+33296347433 (77m)Municipal Les Bruyeres - La Chapelle Montligeon (61) [<51] (12/06-12/09) >+33233839043 (191m)La Recre - Milizac (29) (01/01-31/12) >+33298079217 -CCA(71m)A la ferme La Harilais - Le Ferre (35) [<51] (15/05-30/09) >+33299951314 (129m)Municipal Du Bourg - Plorec sur Arguenon (22) [<51] >+33296830104 (79m)Municipal le Tromeur - Lanildut (29) (01/05-30/09) >+33298043113 (31m)Du Passetemps - Bayon (54) (15/04-03/10) >+33383724560 (243m)Aire naturelle de Le Moulin Blanc - Plougonver (22) [<51] (01/01-31/12) >+33296216081 (221m)Municipal de La Sabliere - La Ferte Alais (91) (01/01-31/12) >+33169908844 (125m)Municipal - Louvigne du Desert (35) [<51] >+33299980150 (159m)Lyvet - Saint Samson sur Rance (22) (15/03-30/10) >+33296395979 (47m)Les Bruyeres - Le Clo�tre-Saint-Thegonnec (29) [<51] (01/07-15/09) >+33298797176 (186m)Le Fackenthal - Rosheim (67) (01/04-31/10) >+33388974520 (347m)Municipal De Digue des Lescheres - Wassy (52) [<51] (15/05-15/09) >+33684069420 (182m)Municipal Des Chauvieres - Saint Fraimbault (61) [<51] (21/03-31/10) >+33233383222 (136m)Beausejour - Saint Samson sur Rance (22) (01/06-30/09) >+33296395327 (53m)Les Amis de la Nature - Grendelbruch (67) [<51] >+33388974184 (653m)Municipal - Pleven (22) [<51] (01/04-15/11) >+33296844671 (86m)Municipal - Saint Adrien [<51] (01/07-31/08) >+33296434281 (199m)Des Ormes - Saint-Leonard-Dol de Bretagne (35) (12/04-21/09) >+33299735300 -CCA(76m)Le Nid Vert - Mondeville (91) (15/03-15/11) >+33164983144 (138m)Aire naturelle Pre Vert - Rosheim [<51] (15/03-15/10) >+33388502110 (194m)Ecouves - Radon (61) [<51] (01/04-30/10) >+33233287502 (205m)Municipal La Veillotiere - Ceauce (61) [<51] (01/05-30/09) >+33233383119 (133m)Les Vallees*** - St. Brieuc (16/03-18/12) >+33296940505 -CCA(78m)Naturist - Les Hesperides - Etrechy (91) [<51] >+33160803249 (114m)Naturist - Pallieter - Plancoet (22) (28/04-23/09) >+33296830515 (24m)A la ferme de Klein Remy - Rosheim (67) [<51] >+33388502500 (187m)Les Granges - Montier en Der (52) [<51] (01/01-31/12) >+33325042068 (122m)Municipal - Nogent sur Seine (10) (30/03-06/10) >+33325397667 (62m)Aire naturelle Municipale - Saint Georges de Reintembault (35) [<51] (15/06-15/09) >+33299970113 (136m)Municipal Le Val d'Essonne - Itteville (91) (01/04-31/10) >+33164930663 (54m)Intercommumal de la Prairie - Le Mele sur Sarthe (61) [<51] (15/06-15/09) >+33233271874 (147m)Municipal du Bout de la Ville - Mery sur Seine (10) (01/04-30/09) >+33325212372 (75m)Municipal Etangs Saint-Blaise - Ballancourt sur Essonne (91) >+33164577824 (55m)Le Perche - Fontaine Simon (28) (01/01-31/12) >+33237818811 (199m)A la ferme l'Aire du Verger - Pleslin Trigavou (22) [<51] (01/05-01/09) >+33612134404 (69m)La Ferme La Dierge - Saint James (50) [<51] (01/07-31/08) >+33687400387 (121m)Monaco Parc - Longny au Perche (61) (01/01-31/12) >+33233735959 (175m)Aire naturelle de Robert Pierre - Landebia (22) [<51] (01/04-01/11) >+33296844752 (53m)Municipal Le Verger - Plancoet (22) (01/06-30/09) >+33296840342 (10m)Aire naturelle municipale - Pont sur Seine (10) [<51] (01/01-31/12) >+33325214022 (64m)Alsace - Gresswiller (67) [<51] (01/05-30/09) >+33388501513 (230m)BonAbry ** - Hillion [<51] (Easter-15/10) >+33296322958 (8m)La Ville Ger - Pleudihen sur Rance (22) [<51] (01/04-15/10) >+33296833388 (5m)La Belle Etoile -�Melun La Rochette (77) (01/04-11/10) >+33164394812 -CCpg313(40m)La Noue des Rois - Saint Hilaire sous Romilly (10) (01/01-31/12) >+33325244160 -CCA(67m)Les Petits Pres*** - Dourdan (91) (01/04-30/10) >+33164596483 -CCA(94m)Municipal Saint Gonvel - Landunvez (29) (09/06-01/09) >+33298899100 (8m)A la ferme Montmirel - Les Ventes de Bourse (61) [<51] >+33233280273 (154m)Aire naturelle des Deux Etangs - Heiligenberg (67) [<51] (15/04-15/10) >+33388500051 (214m)Municipal - Velle sur Moselle (54) [<51] (15/04-30/09) >+33383266062 (235m)Bellevue** - Hillion (01/04-30/09) >+33296322039 (39m)Le Clos Normand - Couterne (61) (15/03-31/10) >+33615321932 (170m)Les Charmilles - Essay (61) [<51] (01/04-30/09) >+33233284052 (152m)Aire naturelle Municipale - Montiers sur Saulx (55) [<51] (01/05-15/10) >+33329759063 (272m)Municipal L'Etang d'Or** - Chatelaudren [<51] (01/05-30/09) >+33296741038 (111m)L'Ile Cherlieu** - Arcis s/Aube (15/04-30/09) >+33325379879 (87m)Municipal Molsheim - Molsheim (67) (04/04-19/10) >+33388498245 -CCA(172m)Le Buisson - Louvemont (52) [<51] >+33684979331 (169m)Le Parc des Roches - Saint Cheron (91) (01/03-15/12) >+33164566550 -CCpg314(150m)Les Etangs - Feings (61) [<51] >+33233257479 (180m)Naturist - Heliomonde -�Saint-Cheron (91) (01/01-31/12) >+33164566137 -CCA(151m)Municipal Le Vigneux - La Ville es Nonais (35) (01/05-30/09) >+33299584284 (30m)La Ferme La Binolais - Saint James (50) [<51] >+33233483009 (116m)Municipal - Saint Lormel (22) [<51] (09/04-04/09) >+33296841480 (36m)Aire naturelle de Saint Vreguet - Saint Alban (22) [<51] (01/06-30/09) >+33296329759 (90m)Municipal Les Tendieres - Dol de Bretagne (35) (01/07-31/08) >+33299481468 (6m)La Bassiere - Bessy (10) [<51] >+33325377406 (83m)La Vee - Bagnoles de l'Orne (61) (08/03-16/11) >+33233378745 (161m)Ville Hervy* - Plerin (22) [<51] (01/07-31/08) >+33296730240 (73m)Municipal** - Planguenoual (22) (15/06-15/09) >+33296327193 (67m)Le Vieux Chene - Dol de Bretagne (35) (01/05-28/09) >+33299480955 -CCA(40m)Aire naturelle Le Bois Bouan - Pluduno (22) [<51] (01/06-30/09) >+33296840095 (52m)Municipal Le Grand Vanne - Tonnoy (54) >+33383266236 (231m)La Vallee de la Seine - Conflans sur Seine (51) (01/04-30/10) >+33326809828 (68m)Aire naturelle de la Ferme d'Orgeval - Badonvilliers Gerauvilliers (55) [<51] (01/05-30/10) >+33329897788 (377m)La Plage - Giffaumont Champaubert (51) (01/05-10/09) >+33608513824 (150m)Les Tommelles - Saint Just Sauvage (51) [<51] >+33326800110 (69m)Municipal Le Clos Ruault** - La Croix Avranchin (01/05-10/09) >+33233482440 (84m)Municipal - Juvigny sous Andaine (61) [<51] >+33233381025 (192m)Huttopia Senonches - Senonches (28) (29/04-05/10) >+33237378140 -CCA(221m)A la ferme Le Moulin des Sablons - Maletable (61) [<51] (01/05-31/10) >+33233251336 (177m)Municipal Presqu'�le de Champaubert - Eclaron Braucourt Sainte Liviere (52) (18/04-24/11) >+33325041320 -BD_FR-C.080(140m)Municipal Du Lac- Senonches (28) [<51] (01/05-01/10) >+33237379463 (216m)Les Mouettes** - Plerin [<51] (18/04-26/09) >+33296745148 (81m)Haliotis*** - Pontorson (15/03-10/11) >+33233681159 -CCpg59-CCA(9m)Le Clos du Vieux Moulin - Chatillon sur Broue (51) (01/04-30/11) >+33326413043 (135m)La Lande - Saint Laurent de Terregatte (50) [<51] (131m)Municipal Mon Repos - Still (67) (03/04-18/10) >+33388500430 (231m)A la ferme La Boneliere - Saint Mars d'Egrenne (61) [<51] >+33233386029 (122m)Des Jonquilles - Saint Alban (22) (30/03-29/09) >+33675443969 (88m)La Ferme des Tourelles* - Boissy sous St. Yon [<51] (01/01-31/12) >+33160820747 (93m)Kervernard - Plounevez Moedec (22) [<51] (139m)Le Luttenbach - Oberhaslach (67) (01/04-30/09) >+33388509062 (329m)Pre de l'Etang - Blandy (77) (15/03-15/09) >+33160669634 (89m)Les Dunes de Treompan - Ploudalmezeau (29) (12/04-30/09) >+33298480985 (6m)La Plage aux Champs** - St.Arnoult-en-Yvelines (15/04-30/09) >+33130412141 (119m)Municipal les Dunes - Lampaul Ploudalmezeau (29) (15/06-15/09) >+33298481429 (8m)Aire naturelle La Ferme du Pourpray - Saint Alban (22) [<51] (01/04-30/09) >+33296630862 (45m)La Boucauderie - Saint Arnoult en Yvelines (78) >+33555282101 (115m)Municipal - Carrouges (61) [<51] (01/04-30/10) >+33233280207 (307m)Fontaine Riante - Provins (77) [<51] (01/01-31/12) >+33164005362 (142m)Les Sources du Lac - Eclaron Braucourt Sainte Liviere (52) (17/04-28/09) >+33325063424 (144m)La Mazure - Les Biards (50) >+33233891950 (81m)Municipal Le Rivage - Le Minihic sur Rance (35) [<51] (15/06-15/09) >+33299885910 (28m)Municipal Des Cours - Saint Suliac (35) (01/06-30/09) >+33607804851 (29m)Le Verger - Ruca (22) >+33608524227 (42m)La Roche - Mont Dol (35) [<51] (15/04-30/09) >+33299480165 (5m)Les Canardieres** - Morsang sur Seine (01/01-31/12) >+33160756716 (37m)Bel Event - Saint Pere (35) (15/03-30/10) >+33299588379 (27m)Municipal l'Aber Beno�t - Saint Pabu (29) (25/04-26/09) >+33298897625 (8m)Municipal Le Bulot - Saint Guinoux (35) >+33299588856 (3m)La Geraumiere - Domfront (61) [<51] (194m)Municipal Lanorgant** - Plouvorn (01/07-31/08) >+33298613240 (66m)Les Pres Marteaux - Grandpuits Bailly Carrois (77) [<51] (01/01-15/12) >+33164080088 (119m)Le Roc de l'Hervieu** - Pordic (01/05-30/09) >+33296793012 (85m)La Petite Ville** - Pordic (01/03-30/11) >+33296790239 (83m)Les Grands Hotieux - Saint Jacut De La Mer (22) (01/05-30/09) >+33296277320 (34m)l'Estuaire - Pleurtuit (35) >+33299884406 (61m)Municipal De la Selune - Saint Hilaire du Harcouet (50) (01/04-30/09) >+33233494374 (63m)Le Minihy**** - Plelo (01/04-30/09) >+33296741292 (117m)Le Minihy- Pleneuf Val Andre (22) (01/06-15/09) >+33296722295 (24m)Les Chenes* - Plelo [<51] (01/05-30/09) >+33296797262 (96m)Les Madieres*** - Pordic (01/04-31/10) >+33296790248 -CCA(71m)Le Brewery - Joue du Bois ((61) [<51] >+33233377726 (221m)Le Chateau de Galinee -�Saint Cast le Guildo (22) (05/05-06/09) >+33296411056 -CCpg64-CCA(58m)Municipal - Marchainville (61) [<51] (01/04-30/10) >+33233836814 (239m)Les Sablons* - Saintry sur Seine (91) [<51] (01/01-31/12) >+33160751530 (39m)Les Bruyeres - Le Val Saint Germain (91) [<51] (01/01-30/11) >+33164589272 (102m)Municipal Champ Passais - Domfront (61) [<51] (01/04-30/09) >+33233373766 (158m)A la ferme La Croix Galliot - Cherrueix (35) [<51] (01/06-01/10) >+33299489044 (4m)Le Balcon de la Baie - Dol de Bretagne (35) [<51] (01/04-31/10) >+33299802295 -CCpg60(67m)Municipal De la Vezouze - Blamont (54) (01/05-15/09) >+33607702739 (258m)Des Monts Colleux - Pleneuf Val Andre (22) (05/04-28/09) >+33296729510 -CCpg65-CCA(42m)Le Clos Tranquille - Saint Cast Le Guildo (22) (01/07-31/08) >+33296412972 (48m)Vallon aux Merlettes - Matignon (22) (01/05-30/09) >+33296411161 -CCA(51m)Le Panoramic*** - Binic (01/04-30/09) >+33296736043 -CCA(48m)Des Abers - Landeda (29) (01/05-30/09) >+33298049335 -CCA(13m)Municipal La Manchette - Saint Jacut De La Mer (22) (01/04-30/09) >+33296277033 (7m)Les Quatre Vaulx - Saint Cast Le Guildo (22) (01/07-31/08) >+33296412975 (21m)Milin Kerhe** - Pabu (01/04-31/10) >+33296135959 (65m)Bellevue - Erquy (22) (05/04-20/09) >+33296723304 -CCA(101m)Le Manoir Du Cleuziou**** - Louargat (01/04-30/09) >+33296435932 (137m)Les Couesnons - Roz sur Couesnon (35) (01/04-03/11) >+33299802686 -CCA(11m)Aux Pommiers - Beauvoir (50) (28/03-11/11) >+33233601136 -CCA(8m)Les Bosquets - Luneville (54) [<51] (25/04-30/09) >+33383733758 (226m)Ti Tulipe - Plouvorn (29) [<51] (01/04-01/10) >+33298610812 (47m)Saint Gregoire** - Servon (50) (05/04-21/09) >+33233602603 -CCpg58-CCA(40m)Le Gue De Beauvoir - Beauvoir (50) (seulement tentes) [<51] (15/07-25/08) >+33233600923 (7m)Le Villeu - Lancieux (22) (01/0-15/09) >+33296862167 (5m)Municipal Le Clos Normand** - Sees [<51] (14/04-30/09) >+33233287479 (186m)Municipal La Saulaie - La Ferte Mace (61) [<51] (01/05-01/10) >+33676866720 (241m)La Cornee du Der - Sainte Marie du Lac Nuisement (51) >+33326726623 (142m)l'Aumone - Cherrueix (35) (19/04-31/10) >+33299488482 (4m)Fort Cezon - Landeda (29) [<51] (01/07-30/09) >+33298049346 (10m)Municipal Pen Enez - Landeda (29) >+33298049982 (13m)De Pen-Guen - Saint Cast Le Guildo (22) (31/05-07/09) >+33296419218 (57m)La Foret - Arrigny (51) (01/04-30/09) >+33611122321 -CCA(140m)Aire naturelle Le Pusset - Erquy (22) [<51] (01/06-30/09) >+33296723843 (73m)Municipal Des Mielles - Lancieux (22) (01/04-30/09) >+33296862298 (8m)La ferme Croas Men* - Plouigneau [<51] (01/04-31/10) >+33298791150 (72m)La Vallee - Erquy (22) [<51] (26/04-15/09) >+33296720622 -CCA(56m)A la ferme de la Briantais - Saint Jouan des Guerets (35) [<51] (01/01-31/12) >+33663048288 (33m)Tenzor de la Baie - Cherrueix (35) (06/04-30/09) >+33299489813 (6m)Des Palmiers-Du Menic** - Binic [<51] (15/06-30/09) >+33296737259 (48m)Municipal Bellevue - La Richardais (35) (01/04-15/09) >+33299885080 (29m)Municipal Les Fauvettes** - Binic (28/03-26/09) >+33296736083 (45m)Les Etangs** - Lantic (22) (09/04-26/09) >+33296719547 -CCA(29m)La Plage De La Ville Berneuf et Saint-Pabu - Pleneuf Val Andre (22) (01/04-12/10) >+33296722820 (12m)Les Abrias Perche - La Ferte Vidame (28) [<51] (01/04-31/10) >+33237376400 -CCA(252m)La ferme Le Champ de la Vallee - La Ferte Mace (61) [<51] (01/01-31/12) >+33628816059 (269m)La Freche a L'Ane - Pleboulle (22) (01/04-31/10) >+33296410872 -CCA(36m)La Ferme La Mercy - Chenoise (77) [<51] (01/04-15/10) >+33164009310 (141m)Le P'tit Bois - Saint Jouan des Guerets (35) (11/04-21/09) >+33299211430 -CCA(36m)Aire naturelle L'Auberge de Keralloret - Guisseny (29) [<51] (01/04-31/10) >+33298256037 (50m)Les Roches - Erquy (22) (01/04-30/09) >+33296723290 -CCA(55m)Rugadello** - Plufur [<51] (15/06-31/08) >+33296351676 (123m)Les Ilots de St Val - Villiers le Morhier (28) (01/02-21/12) >+33237827130 -CCA(132m)Municipal - Saint Quirin (57) [<51] (01/06-15/09) >+33387086360 (321m)Les Bles D'Or - Saint Cast Le Guildo (22) (01/06-15/09) >+33296419993 (66m)Le Mont Saint-Michel - Le Mont Saint Michel (50) (03/04-11/11) >+33233602210 (9m)La ferme Kerogel - Goudelin (22) [<51] (01/04-30/09) >+33296700315 (76m)Le Pont Laurin - Saint Briac sur Mer (35) (05/03-05/11) >+33299883464 (10m)A la ferme la Nocherie - Saint Bomer les Forges (61) [<51] (15/03-15/12) >+33233376036 (166m)Le Moulin de Bechereau - Bris sous Forges (91) [<51] >+33164907027 (89m)La Ville Huchet - Saint Malo (35) (11/04-21/09) >+33299811183 -CCA(33m)Vert de Morlaix - Garlan [<51] (Easter-31/10) >+33298791254 (56m)Les Huttes - Wangenbourg Engenthal (67) (10/04-15/10) >+33388873414 (430m)l'Ile Verte - Saint Benoit des Ondes (35) (01/04-02/11) >+33299586255 -CCA(6m)La Ville Mauny - Dinard (35) (Easter-30/09) >+33299469473 (43m)Municipal La Selune** - Ducey [<51] (01/04-30/09) >+33233602153 (16m)Du Donant*** - Begard (Easter-30/09) >+33296454646 (98m)Municipal Des Ondes - Saint Benoit des Ondes (35) (14/06-15/09) >+33299586521 (6m)Rural de Avallonn - Ceaux (50) [<51] (15/04-30/09) >+33233683947 (43m)Le Swin Golf - Arrigny (51) [<51] (01/01-31/12) >+33619378622 (112m)Huttopia - Rambouillet (78) (01/04-31/10) >+33130410734 -CCA(163m)Emeraude - Saint Briac sur Mer (35) (01/04-30/09) >+33299883455 (26m)Saint Michel*** - Courtils (50) (15/03-10/11) >+33233709690 -CCpg57-CCA(16m)La Vallee de la Selune** - Pontaubault (01/04-20/10) >+33233603900 (13m)La Greve Blanche - Plouguerneau (29) (28/03-05/10) >+33298047035 (12m)La Touesse - Dinard (35) (01/04-30/09) >+33299466113 -CCA(27m)Aire naturelle Municipale (seulement tentes) - Goulven (29) [<51] (15/06-30/09) >+33298835048 (9m)Le Vougot - Plouguerneau (29) [<51] (29/03-25/10) >+33298256151 -CCpg70-CCA(5m)Municipal de Salines Sables d'Or Les Pins - Plurien (22) (01/04-01/11) >+33296721740 (8m)La Fontaine - Saint Cast Le Guildo (22) (25/03-25/10) >+33296419564 (45m)Du Val - Erquy (22) (01/04-30/09) >+33296721040 (31m)Snowland Loisirs - Plouguerneau (29) (01/01-31/12) >+33298371019 (9m)De la Baie - Saint Cast Le Guildo (22) (01/04-15/10) >+33296418267 (41m)Longchamp - Saint Lunaire (35) (15/04-30/09) >+33299463398 -CCA(8m)Naturist - Val des Acacias - Wasselonne (67) [<51] (01/06-30/09) >+33388871764 (219m)Municipal De Kerilis - Henvic (29) [<51] (01/07-31/08) >+33298628210 (64m)Municipal Le Port Blanc - Dinard (35) (01/04-30/09) >+33299461074 (17m)L'Abri Cotier - Etables sur mer (22) (01/05-15/09) >+33296706157 (39m)Municipal du Moulin - Abreschviller (57) [<51] (15/04-30/09) >+33387037032 (289m)Municipal Aleth - Saint Malo (35) (01/07-14/09) >+33299816091 (23m)Municipal Du Curnic - Guisseny (29) (25/06-05/09) >+33298256200 (4m)Le Chatelet - Saint Cast Le Guildo (22) (14/04-12/09) >+33296419633 -CCA(55m)Municipal - Wasselonne (67) (15/04-15/10) >+33388870008 (224m)Les Pins - Erquy (22) (27/04-16/09) >+33296723112 (65m)Le Vieux Moulin - Erquy (22) (12/04-07/09) >+33642222036 (62m)Aire naturelle de La Mare Sucree - Saulnieres (28) [<51] >+33237436787 (147m)Le Parc - Ranes (61) (15/06-15/09) >+33233397393 (254m)Municipal Ker Emma - Treflez (29) (30/06-31/08) >+33298616279 (2m)A la ferme du Point du Jour - Saint Meloir des Ondes (35) [<51] >+33299891029 (7m)Municipal Le Guen - Erquy (22) >+33296720705 (55m)La Crique - Saint Cast Le Guildo (22) (15/03-15/11) >+33296418919 (30m)Les Hautes Grees - Erquy (22) (12/04-28/09) >+33296723478 (45m)Aire naturelle Ker Roland - Plestin Les Greves (22) [<51] >+33296350837 (48m)Municipal - Romanswiller (67) [<51] (01/05-30/09) >+33388874554 (223m)Tal Ar Mor - Plouenan (29) [<51] (01/05-30/09) >+33298158935 (16m)La Vallee des Tamaris - Courpalay (77) (15/02-15/12) >+33164420726 (90m)Municipal Saint Michel - Erquy (22) (01/04-30/09) >+33296723767 (19m)Municipal d'Ode-Vras - Plounevez Lochrist (29) (30/05-26/09) >+33298616517 (4m)Municipal De la Poste - Saint Maurice les Charencey (61) [<51] (01/04-31/10) >+33233257298 (208m)Du Rocher - Dabo (57) [<51] >+33387074751 (551m)Municipal Les Cascades - Mortain (50) [<51] (20/04-30/09) >+33233793030 (189m)Les Hortensias - Carantec (29) [<51] (01/05-30/09) >+33298670863 (44m)Armor - Frehel (22) (30/05-06/09) >+33680546438 (32m)Municipal Pont de L'Etang - Frehel (22) (01/04-30/09) >+33296414045 (35m)Vallee de Ludon - Vieux Pont (61) [<51] (01/04-30/09) >+33233352423 (184m)Villey le Sec** - Villey le Sec (54) (01/04-30/09) >+33383636428 -CCA(219m)Municipal De Kerurus - Plouneour Trez (29) (01/04-30/09) >+33298834187 (7m)Beau Village de Paris*** - Villiers s/Orge (01/01-31/12) >+33160161786 -BD_FR-B1.015(40m)Le Brabois*** - Villers-les-Nancy (54) (01/04-15/10) >+33383271828 -CCpg307-CCA(364m)Les Nympheas - Plouneour Trez (29) >+33298835257 (11m)Les Mouettes - Carantec (29) (17/04-06/09) >+33298670246 (11m)La Baie du Kernic - Plouescat (29) >+33298698660 (8m)La Baie de Terenez - Plouezoc'h (29) (05/04-28/09) >+33298672680 -CCA(8m)Municipal - La Ferriere aux Etangs (61) >+33233669218 (259m)Municipal De Rudoloc - Kerlouan (29) (15/06-31/08) >+33298839448 (3m)Bellevue - Saint Quay Portrieux (22) (26/04-14/09) >+33296704184 (30m)Municipal Cap Frehel - Frehel (22) >+33296414334 (41m)Des Etangs Mesqueau - Plougasnou (29) (15/02-31/10) >+33298673745 -CCA(70m)Municipal Les Nielles - Saint Malo (35) [<51] (05/07-26/08) >+33299402635 (22m)Municipal Saint-Efflam*** - Plestin les Greves (01/04-03/10) >+33296356215 (11m)Le Cheval Rouge - Prat (22) [<51] (01/01-31/12) >+33296470774 (87m)Municipal Bendin - Kerlouan (29) (26/04-30/09) >+33298839835 (4m)Municipal Du Bois De La Palud - Plougoulm (29) [<51] (15/06-31/08) >+33298298182 (35m)La Cote des Legendes - Brignogan Plages (29) (29/03-12/11) >+33298834165 (5m)Le Phare - Brignogan Plages (29) (01/04-15/09) >+33298834506 (5m)A la Ferme Cernay la Ville - Cernay la Ville (78) [<51] >+33134852123 (171m)Le Rugunay** - Locquirec (01/04-15/10) >+33298674106 (43m)l'Orme des Mazieres - Draveil (91) [<51] (01/04-01/11) >+33687267938 (38m)Municipal Grand Breuil - Parroy (54) [<51] (01/05-30/09) >+33383713221 (225m)Municipal Du Fond de la Baie** - Locquirec (01/01-31/12) >+33298674085 -CCpg68(9m)Kerdrehoret Les Hortensias** - Plestin les Greves [<51] (01/06-01/09) >+33296356158 (40m)Le Nicet - Saint Malo (35) >+33299402632 (18m)Municipal - Gambsheim (67) (01/05-30/09) >+33296541191 (125m)Les Genets - Cancale (35) (03/04-30/09) >+33299897617 (44m)La Corniche** - Plestin les Greves [<51] (15/06-15/09) >+33296541191 (46m)Vert d'Avranches - Avranches (50) [<51] >+33678181132 (62m)Du Tregor - Plougasnou (29) [<51] (01/04-30/11) >+33298673764 (79m)Municipal Le Chartel - Ligny en Barrois (55) [<51] (01/06-30/09) >+33329770936 (234m)La Ferme de Malassise - Fontenay Tresigny (77) [<51] (01/01-31/12) >+33164252709 (106m)Ar Roch - Sibiril (29) [<51] (15/06-15/09) >+33298299714 (9m)Duguesclin - Saint Coulomb (35) (29/03-03/11) >+33299890324 (33m)Le Tannee - Saint Coulomb (35) (04/04-30/09) >+33683269050 (29m)Les Coques d'Or - Genets (50) (01/04-13/10) >+33233708257 (9m)Municipal Le Poulfoen - Plouescat (29) (15/06-15/09) >+33298698180 (6m)La Ville Es Poulain - Cancale (35) [<51] (15/03-15/11) >+33299899768 (48m)Aire naturelle Base de Loisirs de Bures - Bures (54) [<51] (01/03-31/10) >+33383713304 (232m)La Touesse - Saint Coulomb (35) (01/07-31/08) >+33299890182 (38m)Au Paradis Perdu - Thal Marmoutier (67) [<51] (01/04-15/10) >+33388706059 (299m)Le Bois Pastel - Cancale (35) (01/04-30/09) >+33299896610 (34m)De Keravel - Plouha (22) (01/06-30/09) >+33296224913 (97m)La Ferme Mont Moret - Frignicourt (51) [<51] >+33326720997 (101m)Le Theven - Sibiril (29) (01/01-31/12) >+33298299686 (15m)Les Chevrets - Saint Coulomb (35) (07/04-15/10) >+33299890190 -CCA(25m)Le Roguennic - Cleder (29) (01/05-15/09) >+33298696388 (5m)Ar Kleguer - Saint Pol De Leon (29) (01/04-28/09) >+33298691881 -CCA(5m)Notre Dame Du Verger - Cancale (35) (01/04-30/09) >+33299897284 (28m)La Rafale - Saint Coulomb (35) [<51] (01/05-31/10) >+33299890142 (33m)Les Mouettes - Gondrexange (57) (01/04-15/10) >+33387250601 (267m)Les Capucines - Tredrez Locquemeau (22) (01/04-21/09) >+33296357228 -CCA(85m)Le Kerjean - Plouha (22) (15/06-15/09) >+33296202475 (92m)De Trologot -�Saint Pol de Leon (29) (01/05-30/09) >+33298690626 -CCpg69-CCA(3m)Municipal de Poulennou - Cleder (29) (01/07-31/08) >+33298694837 (4m)Municipal des Dunes - Santec (29) >+33298297534 (6m)Municipal Pont A Gler - Saint Jean Du Doigt (29) [<51] (28/06-30/08) >+33298673215 (16m)Traou-Meledern - Pontrieux (22) (01/01-31/12) >+33648238287 (7m)La Perame - Genets (50) [<51] (01/04-31/10) >+33233708249 (21m)Nature - Luxemont et Villotte (51) [<51] (01/05-15/10) >+33683428353 (114m)Kerven - Plougasnou (29) [<51] (01/05-30/09) >+33298724122 (39m)La Traconne -�Le Meix Saint Epoing (51) >+33326807076 (157m)Municipal Le Grouin - Cancale (35) (01/03-27/10) >+33299896379 (30m)Le Billou - Santec (29) [<51] >+33298294353 (6m)Les Acacias - Beton Bazoches (77) >+33164010193 (142m)Le Kerestat - Roscoff (29) [<51] >+33298697192 (40m)Les Cognets - Dragey Ronthon (50) (01/04-31/10) >+33233488698 (47m)Municipal - Cherence le Roussel (50) [<51] (01/06-15/09) >+33233598416 (83m)Municipal Bois d'Amour - Quemper Guezennec (22) [<51] (15/06-15/09) >+33296956262 (8m)Le Neptune -�Lanloup (22) (04/04-12/10) >+33296223335 -CCpg66-CCA(63m)Aux Quatre Saisons - Roscoff (29) (01/04-11/10) >+33607412853 (4m)Municipal De La Mer - Plougasnou (29) (15/04-26/10) >+33298723706 (14m)Le Plan Incline** - Henridorff (57) (01/04-15/10) >+33387253013 -CCA(225m)Le Varquez - Plouha (22) (29/03-28/09) >+33296223443 (77m)Le Chateau de Chambonnieres - Le Plessis Feu Aussoux (77) (01/01-31/12) >+33164041585 (115m)La ferme Les Hortensias - Pommerit Jaudy (22) [<51] (01/01-31/12) >+33671302782 (84m)Municipal Le Pont Roulland - Brecey (50) [<51] (01/05-01/09) >+33233486060 (36m)Les Tamaris - Plouha (22) (15/06-15/09) >+33296226001 (44m)Municipal - Sezanne (51) (01/04-01/10) >+33326805700 (164m)Aire naturelle Bel Air - Lannion (22) [<51] (15/06-31/08) >+33296376643 (98m)Municipal Natur Le Potager - Sourdeval (50) [<51] >+33233793555 (220m)Intercommunal des 2 Rives - Lannion (22) [<51] >+33296463140 (9m)Municipal - Saint Jean le Thomas (50) (01/03-15/11) >+33233488402 (9m)Municipal Keravilin - Tredrez Locquemeau (22) (01/06-30/09) >+33296352644 (5m)Le Moulin de Pisseloup - Amillis (77) [<51] >+33164046480 (129m)Municipal La Peupleraie - Vitry le Francois (51) (01/06-18/09) >+33326742047 (97m)Les Etangs Fleuris - Touquin (77) (05/04-15/09) >+33164041636 (108m)Les Portes d'Alsace*** - Saverne (67) (05/04-19/10) >+33388913565 -CCpg301-CCA(232m)Municipal Du Chateau - Connantre (51) (01/04-31/10) >+33326810876 (102m)Fredland - Tournan en Brie (77) (01/03-31/10) >+33164079644 (89m)Du Launay - Plouezec (22) (30/03-30/09) >+33296206315 (80m)Aire naturelle de Kerbigniou - Kerfot (22) [<51] >+33296205062 (81m)Les plages de Beg Leguer - Lannion (22) (12/04-02/11) >+33296472500 -CCA(66m)Parc de la Mare aux Biches - Conde sur Vesgre (78) (10/01-10/12) >+33134870542 (142m)Le Vert Bocage - Verneuil sur Avre (27) (01/02-31/12) >+33232322679 (178m)Le Mont Viron - Montviron (50) [<51] (01/03-15/11) >+33233604326 (96m)Municipal de la Noe - Argentan (61) [<51] (01/04-06/10) >+33233360569 (156m)Municipal Des Prajou - La Roche Derrien (22) [<51] (15/06-15/09) >+33296913631 (10m)La ferme Le Coq Hardi - Hengoat (22) [<51] (01/05-01/10) >+33296915569 (59m)Les Boucles de la Moselle - Liverdun (01/05-30/09) >+33383244378 -CCA(190m)Municipal La Gueriniere - Carolles (50) (15/04-15/10) >+33233619375 (58m)Les 4 Vents - Crevecoeur en Brie (77) (15/03-01/11) >+33164074111 (112m)Les Alizes - Lannion (06/04-28/09) >+33296472858 -CCpg67(104m)Aire naturelle de la Damany-Kroas Min - Lannion (22) [<51] (15/06-31/08) >+33296472221 (100m)Municipal Pays de Flers - Flers (61) [<51] (01/04-31/10) >+33233653500 (236m)Municipal De La Pepiniere - Plouezec (22) (20/06-10/09) >+33296206490 (91m)A la ferme Le Cuvet - Exmes (61) [<51] (01/01-31/12) >+33233399367 (249m)l'Etang du Stock - Langatte (57) (01/05-01/10) >+33387036990 (268m)Municipal - Rhodes (57) [<51] (01/04-30/10) >+33670934092 (256m)La Chaumiere - Jullouville (50) >+33233488293 (101m)Cap de Brehat - Plouezec (22) (01/04-28/09) >+33296206428 -CCA(53m)Aire naturelle Des Marnieres - La Houssaye en Brie (77) [<51] >+33164074003 (113m)De Kerdual - Trebeurden (22) [<51] (20/04-30/09) >+33296235486 (32m)Municipal Le Val d'Orne - Putanges Pont Ecrepin (61) [<51] (01/04-30/09) >+33233350025 (125m)Les Etangs de Marsalin - Vert en Drouais (28) (01/01-31/12) >+33237829223 (91m)Roz Ar Mor - Trebeurden (22) [<51] (01/04-30/09) >+33296235812 (42m)Le Grand Chemin - Le Luot (50) [<51] >+33233513096 (131m)Municipal Du Pre De L'Eglise - Saint Remy sur Avre (28) [<51] (01/04-30/09) >+33237489387 (99m)Armor Loisirs - Trebeurden (22) (01/04-30/09) >+33296235231 (73m)Les Granges - La Ferte Gaucher (77) [<51] >+33164040091 (143m)Du Hamel - Jullouville (50) (01/04-15/10) >+33625642957 (72m)Municipal Cruckin - Paimpol (22) (01/04-30/09) >+33296207847 (11m)Le Soleil Levant - Jullouville (50) [<51] (01/07-31/08) >+33233605911 (74m)Le Val Ombre - Jullouville (50) [<51] (01/05-10/10) >+33632583731 (64m)Municipal du Ch�teau - Bar le Duc (55) [<51] (01/05-15/10) >+33329791733 (189m)Le Guillard - Saint Martin des Champs (77) [<51] (01/04-15/10) >+33164205822 (113m)Municipal - Kermaria Sulard (22) [<51] >+33296384390 (80m)Municipal Lemonnier - Jullouville (50) (01/04-30/09) >+33233514260 (7m)La Tuilerie - Vic sur Seille (57) (01/04-31/10) >+33387011900 (205m)Municipal de Kermarquer - Lezardrieux (22) (15/06-15/09) >+33296201722 (24m)La Chaussee - Jullouville (50) (07/04-23/09) >+33233618018 (8m)Le Bois d'Emeraude - La Ferte-Gaucher (77) (11/04-20/09) >+33164202040 (113m)Les Bouleaux** - Vilsberg (57) (01/04-18/10) >+33387241872 -CCA(281m)Ferme du Syet - Minihy Treguier (22) [<51] >+33296923179 (28m)Pont Bleu - Saint Pair sur Mer (50) [<51] (01/04-30/09) >+33233503325 (9m)A la ferme de Pihan Daniel - Bourguenolles (50) [<51] (01/01-31/12) >+33233512315 (179m)Municipal - Saint Evroult Notre Dame du Bois (61) [<51] (01/04-30/09) >+33632720855 (250m)Le Parc Etang - Montigny le Bretonneux (78) >+33130585620 (166m)l'Etoile de Mer - Saint Pair sur Mer (50) (01/04-30/09) >+33670942079 (9m)Angomesnil - Saint Pair sur Mer (50) [<51] (20/06-10/09) >+33233516433 (28m)l'Esperance - Trebeurden (22) (02/04-29/10) >+33296919505 (4m)La Pommeraye - Francheville (27) [<51] (01/04-30/11) >+33232601497 (183m)Ferme De Kerangloff - Perros Guirec (22) [<51] >+33296232867 (90m)Huttopia - Versailles (78) (27/03-03/11) >+33139512361 -CCA(123m)La Chanterie - Saint Pair sur Mer (50) (01/07-30/09) >+33233695419 (26m)Municipal Le Pressoir** - Gace [<51] (15/05-30/09) >+33233355024 (211m)A la Ferme de la Ribardiere - Athis de l'Orne (61) [<51] (15/04-15/10) >+33233664193 (210m)Le Drakkar - Saint Pair sur Mer (50) (02/04-30/09) >+33233507507 (7m)Municipal Ernest Renan - Louannec (22) (01/05-30/09) >+33296231178 (8m)Chateau Lez-Eaux - Saint Pair sur Mer (50) (01/04-21/09) >+33233516609 -CCA(36m)Municipal Le Dourlin - Pleumeur Bodou (22) (20/04-30/09) >+33296919241 (4m)Les Belles Rives - Saint Pair sur Mer (50) (01/03-01/11) >+33233907336 (7m)La Mariennee - Saint Pair sur Mer (50) (01/04-30/09) >+33233906005 (43m)Abri Cotier - Pleumeur Bodou (22) (01/04-30/09) >+33296919203 (10m)Plage Loisirs** - Dossenheim sur Zinsel (01/04-30/09) >+33388700164 (183m)Municipal Les Pins* - Haguenau (01/05-30/09) >+33388937000 (161m)Le Dolmen - Pleumeur Bodou (22) [<51] >+33297521235 (24m)Ferme Michel - Issenhausen (67) [<51] (15/04-15/10) >+33388707296 (180m)Le Chene Gris*** - Pommeuse (77) (31/03-03/11) >+33164042180 -CCA(93m)Les Petits Champs* - St.Evroult De Montfort [<51] (01/01-31/12) >+33233356739 (212m)Le Port - Pleumeur Bodou (22) (15/03-30/11) >+33296238779 -CCA(3m)La Pommeraie - Le Gault Soigny (51) [<51] >+33326815882 (187m)Municipal Landrellec - Pleumeur Bodou (22) (25/04-15/09) >+33296238779 (7m)Port L'Epine -�Trelevern (22) (19/04-20/09) >+33296237194 -CCA(11m)La Fleur de Sel - Chateau Salins (57) [<51] >+33387052880 (207m)Trestraou - Perros Guirec (22) (30/04-30/09) >+33608990393 (11m)Municipal Le Palud - Trelevern (22) (07/06-07/09) >+33296917311 (4m)Naturist - Le Cardinal - Domevre en Haye (54) >+33647726661 (286m)Le Paou - Ploubazlanec (22) [<51] (01/01-31/12) >+33296558722 (42m)Les Macareux - Trevou Treguignec (22) [<51] (01/05-15/09) >+33296237145 (46m)les Hauts de Port Blanc - Penvenan (22) (05/04-30/09) >+33296928672 -CCA(68m)Panorama Du Rohou - Ploubazlanec (22) (01/01-31/2) >+33296558722 (49m)Le Mat - Trevou Treguignec (22) (01/04-30/09) >+33296237152 (3m)La Boderie - Sainte Honorine la Chardonne (61) [<51] >+33233659046 (187m)La Vague - Granville (50) (01/04-15/10) >+33233502997 (15m)West - Perros Guirec (22) (29/03-31/10) >+33296914382 (20m)Tourony - Tregastel (22) (25/04-21/09) >+33296238661 (3m)Municipal du Moulin des Gravieres - Revigny sur Ornain (55) [<51] >+33329787334 (141m)Municipal Oree de la Foret - Mandres aux Quatre Tours (54) [<51] >+33383231731 (243m)Municipal La Piscine - Vire (14) [<51] (01/05-30/09) >+33231672034 (175m)Le Ranolien - Perros Guirec (22) (03/04-20/09) >+33296916565 (22m)Paris Est - Champigny sur Marne (94) (01/01-20/12) >+33143974397 -CCA(39m)De Marcilly - Marcilly-sur-Eure (27) (01/04-30/12) >+33237484542 -CCA(135m)Les Berges De l'Iton - Breteuil (27) (01/04-30/09) >+33232627035 -CCA(169m)Le Staedly - Roeschwoog (67) (01/04-30/10) >+33388864218 (118m)Municipal - Conde sur Iton (27) [<51] (15/03-31/10) >+33232298298 (158m)Municipal Des Dunes - Penvenan (22) (08/05-15/09) >+33296926342 (3m)La Porte - Courson (14) [<51] (01/03-30/09) >+33231680443 (164m)Les Chevaliers*** - Villedieu les Poeles (01/04-30/09) >+33233610244 -CCA(119m)Municipal La Pointe De Goareva - Ile De Brehat (22) (01/06-12/09) >+33296200246 (25m)Municipal Bugueles - Penvenan (22) [<51] (01/07-31/08) >+33296928783 (7m)A la ferme de la Gilberdiere - Berjou (61) [<51] >+33682183739 (201m)Le Rouvrou - Menil Hubert sur Orne (61) (01/04-15/10) >+33233648240 (71m)Imsterfeld** - La Petite Pierre (01/05-30/09) >+33388704212 (227m)Municipal - Plougrescant (22) (15/06-15/09) >+33296925615 (0m)Municipal Du Stade - Conde sur Noireau (14) [<51] (02/05-30/09) >+33231694524 (81m)l'Ermitage - Donville les Bains (50) (15/04-15/10) >+33233500901 (18m)Le Soleil de Crecy*** - Crecy la Chapelle (01/04-31/10) >+33160435700 (58m)Municipal La Haute �le - Neuilly sur Marne (93) (01/04-30/09) >+33143082121 (37m)Le Lac Vert - Mittersheim (57) (01/05-30/09) >+33387076713 (234m)Port La Chaine - Pleubian (22) (12/04-20/09) >+33296229238 -CCA(24m)Municipal Kermagen - Pleubian (22) [<51] (30/06-01/09) >+33296229945 (8m)Aire naturelle Vieuville - Saint Germain Du Crioult (14) [<51] >+33231690825 (143m)Le Varlen - Plougrescant (22) (01/03-15/11) >+33296925215 (22m)Du Gouffre - Plougrescant (22) (01/04-30/09) >+33296920295 (18m)l'Oasis de la Plage - Donville les Bains (50) (01/04-31/10) >+33233505201 (9m)Municipal les Eaux Vives - Anet (28) (01/03-31/10) >+33237414267 (61m)Municipal Les Trillots - Ezy sur Eure (27) (01/03-15/11) >+33237647321 (63m)De Laneros - Pleubian (22) [<51] (30/06-01/09) >+33296229911 (5m)Les Lilas de Morieux - Saint Denis de Mere (14) [<51] (01/03-30/10) >+33235411597 (161m)Indigo-Le Bois de Boulogne - Paris (75) (01/01-31/12) >+33145243000 (30m)La Route Blanche -�Breville sur Mer (50) (03/04-27/09) >+33233502331 -CCpg56-BD_FR-A.021(7m)Municipal Des Chataigniers - Montmirail (51) [<51] (01/04-31/10) >+33326812561 (195m)Municipal Region De Pont D'Ouilly - Pont D'Ouilly (14) >+33231694612 (49m)De la Fee - Verdelot (77) (15/03-14/11) >+33164048019 (98m)A la ferme a Gege - Coudeville sur Mer (50) [<51] >+33608345451 (47m)Le Petit Pont - Ivry la Bataille (27) (01/03-31/01) >+33232364090 (59m)Quincangrogne* - Montevrain (15/03-30/11) >+33164302503 (45m)Die Grune Les Peupliers - Seltz (67) (01/04-30/09) >+33388865237 (112m)A la Ferme de Saint IsIdore - Rupt devant Saint Mihiel (55) [<51] >+33329750169 (278m)Municipal Les Dunes - Coudeville sur Mer (50) (01/04-31/10) >+33233517607 (11m)Municipal du Salmengrund - Seltz (67) (01/04-30/09) >+33388865263 (112m)A la ferme Chateau de Chaalis - Pomponne (77) [<51] >+33160360316 (88m)Municipal du Chateau - Falaise (14) (01/05-30/09) >+33231901655 (121m)Les Salvatres - Thorigny sur Marne (77) (01/04-30/10) >+33164308110 (108m)Municipal - Saint Mihiel (55) >+33675101894 (214m)Municipal La Salle - La Neuve Lyre (27) (15/03-15/10) >+33232601498 (155m)Le Choisel - Saint Cyr sur Morin (77) (01/03-30/11) >+33160238493 (62m)Municipal De la Vanlee - Brehal (50) (01/05-30/09) >+33233616380 (7m)Municipal Aire naturelle Le Steinberg - Hinsbourg (67) [<51] (01/04-31/10) >+33388015651 (338m)Le Parc*** - Villevaude-Montjay la Tour (01/01-31/12) >+33160262079 -BD_FR-B1.050(128m)International de Jablines*** - Jablines (01/04-31/10) >+33160260937 -CCpg312-CCA(45m)Les Rochers Des Parcs - Clecy (14) (01/04-30/09) >+33231697036 -CCpg50(39m)Municipal Wingen - Wingen sur Moder (67) [<51] (01/05-30/09) >+33388897254 (228m)Aire naturelle de Delalande Anne-Marie - Bricqueville sur Mer (50) [<51] (15/04-30/09) >+33233517592 (8m)Municipal Au Rhin et a la Sauer - Munchhausen (67) >+33388861180 (110m)Aire naturelle Ferme de Hauts Vents - Bricqueville sur Mer (50) [<51] (15/03-31/10) >+33672487903 (56m)l'Ile Demoiselle* - Annet sur Marne (01/04-15/10) >+33160260307 (41m)Le Cos des Sablons - Guainville (28) (01/01-31/12) >+33232365865 (130m)Canada - Epone (78) (01/01-31/12) >+33130426176 (126m)Le Nonsard - Nonsard Lamarche (55) >+33329895676 (226m)Clos Gouget - Boinvilliers (78) (01/01-31/12) >+33134763175 (135m)Municipal l'Oasis - Oberbronn (67) (15/03-15/11) >+33388097196 -CCA(238m)Le Tahiti - Precy sur Marne (77) [<51] >+33662650181 (42m)Municipal La Campiere - Vimoutiers (61) [<51] (01/05-25/10) >+33233391886 (98m)Municipal**** - Chalons en Champagne (15/03-15/11) >+33326683800 -CCpg311-CCA(81m)La Ferme d'Escures - Saint Jean le Blanc (14) [<51] >+33231696295 (209m)Claire Foret - Morhange (57) [<51] >+33387862211 (264m)Municipal Des Bords de Vire** - Pont Farcy (01/05-30/09) >+33231683206 (55m)International - Maisons Laffitte (78) (04/04-02/11) >+33139122191 -CCA(22m)l'Etang** - Harskirchen (01/01-31/12) >+33388009365 (216m)Les Passons Madine 2 - Heudicourt sous les Cotes (55) (01/04-31/10) >+33329893608 (229m)Naturist - Paris-Est - Saint-Jean-les-Deux-Jumeaux (77) >+33164357267 (149m)Aire naturelle La Planchette - Saint Pierre de Cernieres (27) [<51] (01/06-30/09) >+33232435067 (167m)Port Trianon - Charmentray (77) [<51] (15/03-30/10) >+33160019357 (49m)Les Renardieres - Villennes sur Seine (78) >+33139758897 (114m)Le Val d'Ante - Givry en Argonne (51) [<51] (01/05-31/08) >+33326600415 (165m)Chateau Les Bondons - La Ferte s/Jouarre (77) (01/01-31/12) >+33160220098 (156m)Municipal* - Ussy s/Marne [<51] (01/03-30/09) >+33160221317 (52m)Les Usages** - Saacy sur Marne (01/01-31/12) >+33160237581 (109m)Les Troenes*** - Meaux (01/04-23/10) >+33160234897 (48m)La Mutche - Morhange (57) >+33387862158 (250m)Municipal Les Peupliers - Annoville (50) (01/06-21/09) >+33233476773 (7m)Le Pont* - Trilport [<51] (01/04-31/10) >+33614361460 (48m)Etangs de la Tensch - Francaltroff (01/04-30/09) >+33387017904 (235m)Aux Champs - Hambye (50) [<51] (01/04-01/11) >+33233900698 (104m)l'Ile du Roi - Triel sur Seine (78) (01/01-31/12) >+33139758788 (20m)Heidenkopf - Niederbronn Les Bains (67) >+33388090846 (248m)Municipal Les Monts - Nogent l' Artaud (2) (30/03-06/10) >+33323701021 (103m)Les Quatre Arpents - Triel sur Seine (78) (01/01-31/12) >+33139752563 (19m)La Pelouse - Jaulny (54) (01/04-10/10) >+33383819167 -CCA(212m)La Pinede - Baerenthal (57) (01/04-31/10) >+33387065504 (234m)Aire naturelle Barthelemy - Quettreville sur Sienne (50) [<51] >+33233075171 (11m)Les Chesnets - Verneuil sur Seine (78) [<51] (01/01-31/12) >+33139719960 (64m)Municipal Du Sud - Hauteville sur Mer (50) (01/04-30/09) >+33233475228 (9m)Municipal Les Mouettes - Lauterbourg (67) (01/04-15/10) >+33388546860 (111m)Aire naturelle Municipale - Tessy sur Vire (50) [<51] (010/06-30/09) >+33233563042 (41m)Municipal Les Illettes - Charly (2) [<51] (01/04-30/09) >+33323821211 -CCA(57m)Les Sapins*** - Keskastel (01/01-31/12) >+33388001925 (223m)Les Garennes - Hauteville sur Mer (50) (01/04-30/09) >+33233462893 (7m)Municipal de Ramstein Plage - Baerenthal (57) (01/04-30/09) >+33387065073 -CCA(212m)La Lande - Quettreville sur Sienne (50) [<51] (30/04-31/10) >+33233074829 (10m)Les Sapins des Vignobles - Villiers St. Denis (01/04-31/10) >+33323821779 (122m)Rural Domjean - Domjean (50) [<51] (15/03-30/10) >+33233563271 (88m)Le Traspy - Thury Harcourt (14) (01/04-30/09) >+33231796180 (50m)Municipal les Gravelets - Montmartin sur Mer (50) (01/04-30/10) >+33233477020 (38m)Ferme du Marais - Montmartin sur Mer (50) [<51] (01/04-31/10) >+33233476187 (6m)Le Val de Seine - Verneuil sur Seine (78) (15/04-30/09) >+33139718834 (29m)Les Peupliers* - Tancrou [<51] (01/04-31/10) >+33160017961 (52m)Le Bac* - Isles les Meldeuses (77) [<51] >+33164355549 (47m)Les Sapins - La Bonneville sur Iton (27) [<51] (01/01-31/12) >+33232371103 (137m)Village Parisien**** - Varreddes (77) (01/04-31/10) >+33164348080 -CCA(58m)Municipal - Livarot (14) [<51] (01/05-31/05) >+33231320118 (68m)Les Pieces Monet* - Isles les Meldeuses [<51] (01/01-31/12) >+33164355134 (50m)Robin Marion* - Isles les Meldeuses (01/03-31/12) >+33164355549 (50m)Dourson - Holving (57) [<51] (01/05-01/09) >+33387026155 (227m)Municipal Hanau Plage - Philippsbourg (57) (01/04-30/09) >+33387065155 (250m)Le Puits** - St. Martin d. Besaces [<51] (01/03-30/10) >+33231678002 (189m)Le Ruet - Regneville sur Mer (50) (01/05-30/09) >+33233458871 (8m)Municipal aire naturelle Du Hohenfels - Dambach (67) [<51] (01/05-30/09) >+33388092571 (233m)l'Ile** - Mary s/Marne [<51] (01/01-31/12) >+33160016707 (50m)Au Bon Repos* - Holving [<51] (01/04-30/09) >+33387979220 (222m)Le Refuge des Pecheurs* - Holving (01/04-30/09) >+33387095146 (226m)Aire naturelle Le Bois Joli - Saint Maurice sous les Cotes (55) [<51] (01/04-30/09) >+33329893332 (296m)La ferme de l'Esperance - Villers sur Meuse (55) [<51] (01/04-15/10) >+33329852485 (205m)Les Etangs du Longeau - Hannonville sous les Cotes (55) [<51] >+33329873054 (332m)Municipal La Closerie** - Aunay s/Odon (01/07-31/08) >+33231773246 (137m)Le Lac des Charmilles - Torigni sur Vire (50) [<51] (01/04-30/09) >+33233569174 -CCpg51-CCA(81m)Municipal Etang des Marais *** - Remering l. Puttelange (01/06-15/09) >+33387096235 (234m)Les Capucins** - Orbec [<51] (24/05-05/09) >+33231327622 (174m)Du Fleckenstein - Lembach (67) (28/03-05/10) >+33388944038 (204m)Les Mouettes - Agon Coutainville (50) (01/04-01/10) >+33681047642 (10m)Le Ronquet - Agon Coutainville (50) (01/04-30/10) >+33233470529 (14m)A la ferme du Pressoir Dajon - Dampierre (14) [<51] (01/04-31/08) >+33231687230 (134m)Le Paquis** - Corny s/Moselle (01/05-30/09) >+33387520359 (172m)Municipal* - Puttelange aux Lacs (15/04-30/09) >+33387094892 (234m)Loisirs des Groux - Mousseaux sur Seine (78) (15/03-30/11) >+33134793386 (18m)Naturist - Nature et Soleil de Normandie - Saint-Laurent de Condel (14) >+33231974850 (54m)Municipal Le Martinet - Agon Coutainville (50) (01/04-30/10) >+33233470520 (9m)Municipal Les Vignettes - Coutances (50) (01/01-31/12) >+33233454313 (66m)Municipal Le Marais - Agon Coutainville (50) (01/04-30/10) >+33233470520 (9m)Aire Naturelle Le Casrouge - Aigon Coutainville (50) [<51] (01/07-15/09) >+33233468470 (41m)La Ferme des Becs Plats - Agon Coutainville (50) [<51] (01/07-15/09) >+33632745909 (43m)Le Prieure - Limetz Villez (78) [<51] (01/01-31/12) >+33134785785 (18m)Le Criquet - Freneuse (78) (01/014-31/12) >+33130930795 (18m)Municipal - Epernay (51) (01/05-01/10) >+33326553214 (69m)Le Bremmendel - Sturzelbronn (57) (01/04-15/10) >+33387062046 (268m)Le Muhlenbach - Sturzelbronn (57) (01/04-30/09) >+33387062015 -CCA(262m)A la ferme de Gournay - Banneville sur Ajon (14) [<51] >+33231771061 (117m)Municipal La Melette - Blainville sur Mer (50) (01/04-31/10) >+33233471484 (6m)Vallee de Craham ** - Cahagnes (01/04-30/10) >+33231778818 (130m)l'Etang d'Oberwiese* - Guebenhouse [<51] (01/05-31/10) >+33387095082 (245m)Municipal* - Futeau (55) [<51] (01/05-15/10) >+33329882706 (180m)Sous Le Clocher** - Trelou sur Marne (02) (20/04-29/09) >+33326582179 (61m)Le Senequet - Gouville sur Mer (50) >+33233478437 (7m)Municipal*** - Bernay [<51] (01/05-30/09) >+33232433047 (154m)A la ferme Du Bout de la Ville - Clinchamps sur Orne (14) [<51] (Easter-01/11) >+33663056666 (66m)Municipal l'Etang - Haspelschiedt (57) (01/04-30/09) >+33387965391 (277m)Rural de Hubert Eugene - Haspelschiedt (57) [<51] >+33387965397 (280m)Municipal de la Grelette** - Ste. Menehould [<51] (15/04-31/10) >+33326608021 (143m)Les Marguerites** - Bonzee (01/04-26/09) >+33329873198 (230m)Les Fosses Rouges - Saint Marcel (27) (01/03-31/10) >+33232515986 (109m)Les Epichees** - Sommedieue (01/01-31/12) >+33329876045 (249m)Naturist - Regain - Rosoy en Multien (60) (15/03-31/10) >+33344873590 (86m)l'Ancien Moulin - Acy en Multien (60) (01/01-31/12) >+33344872128 (82m)International Belle Etoile - Gouville sur Mer (50) (01/07-31/08) >+33233478687 (6m)Le Senequet - Gouville sur Mer (50) >+33233478437 (6m)Ferme de Mr et Mme Nowack - Vandieres (51) [<51] (01/04-31/10) >+33326580269 (84m)Manoir de la Foulerie - Ancteville (50) >+33233452764 (56m)Qui Vivra Verra - Le Mesnil Amey (50) [<51] >+33233565405 (51m)Le Felsberg*** - St. Avold [<51] (01/01-31/12) >+33387927505 (286m)Naturist - Le Vauselet - Landrecourt-Lempire (55) >+33632511886 (318m)Le Grand Large - Anneville sur Mer (50) (15/06-15/09) >+33233478714 (7m)Municipal Metz-Plage**** - Metz (05/05-25/09) >+33387682648 (164m)Les 3 Sources - l'Isle Adam (95) (15/03-31/10) >+33134690880 (26m)Municipal La Vallee - Geffosses (50) [<51] (01/07-31/08) >+33233477150 (22m)Le Maurois - Grisy les Platres (95) (01/01-31/12) >+33134664211 (151m)Les Princes - Asnieres sur Oise (95) (01/05-30/10) >+33130354092 (32m)Val de Nesles - Nesles la Vallee (95) (01/01-31/12) >+33134706324 (96m)A la ferme de la Moriniere - Pirou (50) [<51] (15/04-5/09) >+33684414292 (7m)La ferme Les Etangs de Mandre - Chatillon sous les Cotes (55) [<51] (01/01-31/12) >+33685103563 (232m)Les Breuils*** - Verdun (55) (15/03-15/10) >+33329861531 -CCA(202m)L'Escapade - Cahagnolles (14) (01/04-15/10) >+33231216359 -CCpg49-CCA(102m)Municipal Le Clos Marin - Pirou (50) (01/04-31/10) >+33233463036 (10m)Aire naturelle Le Groseillier - Neuvilly en Argonne (55) [<51] (01/04-31/10) >+33329874284 (187m)La Vallee - Lisieux (14) (15/04-30/09) >+33231620040 (36m)Le Clos Vert - Saint Martin d'Aubigny (50) [<51] (15/04-15/10) >+33233077392 (30m)Municipal - Val de Vesle (51) [<51] (01/04-15/10) >+33326039179 (91m)Des Travailleurs - Carling (57) [<51] >+33387936880 (242m)A la ferme de Porcher Henri - Janville (14) [<51] (01/04-31/10) >+33231233863 (18m)A la ferme Champ de Noyer - Cambremer (14) [<51] (39m)A la ferme de Houssin - Marchesieux (50) [<51] >+33233460948 (17m)De l'Argonne - Minaucourt (51) >+33326604017 (131m)Le Clos de Balleroy - Balleroy (14) [<51] (15/03-15/11) >+33231214148 (121m)Municipal Des Dunes - Creances (50) >+33233463186 (10m)Le Mont Cesar - Gouvieux (60) (01/04-31/10) >+33689492182 (58m)Municipal La Vallee** - Brionne (01/04-30/09) >+33232448035 (50m)Le Bois Joli - Henonville (60) (01/01-31/12) >+33344498792 (138m)A la ferme de la Tournerie - Raids (50) [<51] (01/01-31/12) >+33687828058 (13m)Le Colombier - Moyaux (14) (01/05-15/09) >+33231636308 (147m)Les Bouleaux - Moineville [<51] (01/04-31/10) >+33382466677 (186m)Municipal Sous le Moulin - Charny sur Meuse (55) (01/05-30/09) >+33329842835 (190m)Pre des Moines - Saint Leu d'Esserent (60) (06/01-17/12) >+33344566048 (29m)De Salverte**** - Le Gros Theil (01/01-31/12) >+33232355134 (134m)L'Abbatiale - Saint Leu d'Esserent (60) >+33344279854 (31m)Chateau De Bouafles - Bouafles (27) (15/01-15/12) >+33232540315 (21m)La ferme Le Moulin Foulon - Noron la Poterie (14) [<51] >+33231921468 (55m)Le Bel Air - Louviers (27) (15/03-15/10) >+33232401077 -CCA(124m)La Croix du Bois Sacker - Burtoncourt (57) (01/04-15/10) >+33387357408 -CCA(256m)Le Brevedent**** - Le Brevedent (14) (05/05-15/09) >+33231647288 -CCA(91m)Le Saint-Pierre - Saint Pierre du Vauvray (27) (01/03-31/10) >+33232610155 (14m)A la ferme la Grande Abbaye - Arganchy (14) [<51] (01/01-31/12) >+33231925722 (60m)Campix - St Leu d'Esserent (60) (07/03-30/11) >+33344560848 -CCpg37-BD_FR-B1.002(51m)Le Prieure** - Bavent (01/04-15/10) >+33231782051 (42m)Chateau Gaillard - Bernieres sur Seine (27) (22/02-08/12) >+33232541820 (14m)Municipal Le Paquis - Varennes en Argonne (55) [<51] (21/04-30/09) >+33329807035 (153m)Le Picard Holidays - Tournieres (14) (01/01-31/12) >+33231228244 (58m)Municipal Saint Nicolas** - Le Bec Hellouin (27) (15/03-15/10) >+33232448355 -CCpg43-CCA(134m)Les Trois Rois - Les Andelys (27) (15/03-15/11) >+33232542379 -CCpg42-CCA(12m)Les Grands Espaces - Saint Germain sur Ay (50) (01/05-15/09) >+33233071014 (10m)Les Capucines** - Ranville (01/01-31/12) >+33231786982 (23m)Municipal Les Marronniers** - Pont Authou (01/01-31/12) >+33232427506 (45m)La ferme La Bretonniere - Saint Georges du Vievre (27) [<51] >+33232428267 (149m)Les Pommiers - Saint Sylvestre de Cormeilles (27) [<51] (01/04-31/10) >+33232422969 (160m)Au Manoir de l'Abbaye -�Martragny (14) [<51] (01/01-31/12) >+33231802595 (70m)Le Chateau de Martragny -�Martragny (14) (02/05-12/09) >+33231802140 -CCpg47(63m)Les Hautes Coutures - Benouville (14) (01/04-31/10) >+33231447308 -CCpg45-CCA(10m)Municipal - Briey (54) [<51] >+33382463322 (211m)Roqueforette - Le Petit Saint Germain (50) [<51] (15/04-31/10) >+33233478185 (28m)Le Clos Tranquille*** - Gonneville en Auge (01/04-30/09) >+33231242136 (16m)Municipal - Dangu (27) (28/03-26/10) >+33232554342 (42m)Aire naturelle de Ressencourt - Cormeilles (27) [<51] >+33232578433 (64m)Ferme De Fumichon - Saint Martin De Blagny (14) [<51] (01/06-15/09) >+33231225015 (22m)Les Aubepines - Cires les Mello (60) (01/01-31/12) >+33344564089 (79m)Municipal Le Paquis - Autry (8) [<51] (01/04-31/10) >+33324711057 (113m)Aire naturelle de Legrix - Reux (14) [<51] (01/05-30/09) >+33231648376 (122m)Municipal Les Pommiers - Ouistreham (14) (15/02-15/12) >+33231971266 (3m)Aire naturelle Le Rupalley - Bernesq (14) [<51] (01/06-01/10) >+33231225444 (37m)La Bucaille - Montgardon (50) [<51] >+33233074638 (79m)La ferme Le Creulet - Crouay (14) [<51] (01/01-31/12) >+33231924527 (75m)Du Lac**** - Pont l'Eveque (15/03-31/10) >+33231643131 (13m)La Ferme de Pierrepont - Amblie (14) [<51] (01/04-31/10) >+33231801004 (24m)Le Clos Fleuri - Montmartin en Graignes (50) [<51] (15/06-15/09) >+33233568487 (35m)Du Golf** - Dives s/Mer (03/04-30/09) >+33231247309 (130m)Les Saules - Bosnormand (27) [<51] (15/03-15/11) >+33235876162 (147m)Le Clos Signol - Hacqueville (27) (01/04-15/10) >+33232559251 (119m)Les Naiades - Chatel Chehery (8) (12/04-12/10) >+33324305344 (134m)La Pommeraie*** - Cabourg (01/04-31/10) >+33231915458 (4m)Les Peupliers*** - Merville Franceville Plage (14) (01/04-31/10) >+33231240507 -CCA(3m)Ariane - Merville Franceville Plage (14) (01/04-02/11) >+33231245252 (3m)Municipal Le Point Du Jour**** - Merville Franceville Plage (14) (01/04-31/10) >+33231242334 -CCA(5m)L'Oasis*** - Merville Franceville Plage (29/03-02/11) >+33231242212 (4m)Du Relais - Merville Franceville Plage (14) (01/04-30/10) >+33231242282 (5m)Municipal Des Bords de l'Aure - Bayeux (14) (03/04-01/11) >+33231920843 (35m)La Mer - Merville Franceville Plage (14) (01/04-30/09) >+33231241603 (5m)Aire naturelle Le Rivage - Merville Franceville Plage (14) [<51] >+33231240892 (4m)Municipal Le Stade** - Pont l'Eveque (14) (01/04-30/09) >+33231641503 (9m)Les Ilys Hauts- Consenvoye (55) >+33329858675 (180m)Le Relais de la Vignette - Bayeux (14) >+33231215283 (63m)Parc Naturel de Weekend - Cires les Mello (60) (01/01-31/12) >+33344264225 (38m)Intercommunal Les Trois Rivieres - Creully (14) (01/04-30/09) >+33231809017 (13m)Les Hautes Sentes - Hermanville sur Mer (14) (01/04-30/09) >+33231963912 (6m)Les Salines - Colleville Montgomery (14) (15/03-05/11) >+33231963685 (3m)Les Vattaux - Hermanville sur Mer (14) (01/04-31/10) >+33231970962 (5m)Municipal Des Chevaliers** - Houlgate (01/04-30/09) >+33231243793 (20m)Des Deux Amants - Poses (27) (01/04-31/10) >+33232591186 (13m)La Vallee**** - Houlgate (14) (01/04-15/10) >+33231244069 -CCA(21m)Aire naturelle Du Lieu Joly - Coudray Rabut (14) [<51] (01/05-30/09) >+33231641291 (13m)Les Rives de l'Eure - Criquebeuf sur Seine (27) [<51] >+33235817719 (6m)Hotel de Plein Air*** - Volstroff (15/04-27/10) >+33382569340 (201m)Etang des Haizes -�Saint Symphorien le Valois (50) (01/04-15/10) >+33233460116 (38m)Lieu Castel** - Gonneville s/Mer (01/04-15/10) >+33231911764 (123m)l'Esperance - Montfort sur Risle (27) (01/01-31/12) >+33232561020 (29m)l'Esperance - Denneville (50) (01/04-30/09) >+33233071271 (10m)l'Oasis - Lion sur Mer (14) (30/03-30/09) >+33231972136 (9m)La Ferme Lechevalier - Lion sur Mer (14) [<51] (01/04-30/09) >+33231967437 (11m)La Plage** - Houlgate (01/04-06/11) >+33231287307 (18m)Eure - Pont de l'Arche (27) (01/04-30/10) >+33232989070 (10m)Les Falaises**** - Gonneville s/Mer (01/04-31/10) >+33231248109 (115m)A la ferme du Vallon - Moirey (55) [<51] (01/01-31/12) >+33630788426 (235m)Municipal L'Ile Adeline - Poses (27) (01/04-31/10) >+33232254533 (8m)Municipal - Fismes (51) [<51] (02/05-15/09) >+33326481026 (58m)Bellevue*** - Villers s/Mer (01/04-31/10) >+33231870521 -CCpg44-CCA(122m)Municipal Le Haut Dick - Carentan (50) (01/04-30/09) >+33233421689 -CCA(1m)La Gentilhommiere-Les Pommiers - Banville (14) [<51] >+33231375187 (37m)Municipal Sous les Pommiers - Trevieres (14) (01/04-30/09) >+33231928924 (3m)De la Frette - Pont Sainte Maxence (01/01-31/12) >+33344722007 (31m)Rural de Lahaye Liliane - Fort Moville (27) [<51] >+33232571549 (128m)La Capricieuse - Luc sur Mer (14) (01/04-30/09) >+33231975593 (8m)Le Fanal - Isigny sur Mer (14) (01/04-30/09) >+33231213320 -CCA(3m)La Faloise - Angicourt (60) (01/01-31/12) >+33344731099 (111m)Aire naturelle de Metivier Laurent - Langrune sur Mer (14) [<51] >+33231961039 (10m)Le Brouzel - Sivry sur Meuse (55) [<51] (01/04-01/10) >+33329858645 (180m)La Gabriella - Romagne sous Montfaucon (55) [<51] (01/04-01/11) >+33329851179 (209m)Les Carolins - Saint Lo d'Ourville (50) (15/03-31/10) >+33233048485 (14m)l'Oree de Deauville*** - Vauville (28/03-02/11) >+33231879622 (20m)Les Terrasses - Igoville (27) [<51] (01/01-31/12) >+33235230815 (22m)Aire naturelle de Lecesne - Saint Benoit D'Hebertot (14) [<51] >+33231642432 (141m)La Roseraie d'Omaha - Surrain (14) (01/04-24/09) >+33231211771 -CCA(31m)Le Clos du Moulin - Graye sur Mer (14) (01/04-31/10) >+33231379335 (10m)Cote De Nacre - Saint Aubin sur Mer (14) (03/04-14/09) >+33231971445 -CCA(9m)Le Vieux Fort - Portbail (50) (01/05-30/09) >+33233048199 (6m)La Vallee de Deauville** - St. Arnoult (01/04-31/10) >+33231885817 -CCA(4m)Municipal - Vilosnes Haraumont (55) >+33329858390 (177m)Reine Mathilde - Etreham (14) (01/04-30/09) >+33231217655 -CCpg48-CCA(37m)Le Havre de Bernieres - Bernieres sur Mer (14) (01/04-31/10) >+33231966709 -CCpg46-CCA(3m)Municipal Le Champ de Course - Courseulles sur Mer (14) (01/04-30/09) >+33231379926 (2m)Aire naturelle de Martragny Claude - Saint Come De Fresne (14) [<51] (01/07-31/08) >+33231223501 (10m)Les Bas Carreaux - Tracy sur Mer (14) [<51] (01/04-30/09) >+33231925433 (53m)La Cote des Isles - Portbail (50) >+33233048997 (6m)Aire naturelle de Ozouf Eugene - Saint Lo d'Ourville (50) [<51] (01/06-30/10) >+33233048155 (17m)Les Mielles la Corneviere - Portbail (50) (5m)Municipal - Arromanches Les Bains (14) (01/04-03/11) >+33231223678 (16m)Municipal Canadian Scottish - Graye sur Mer (14) (17/04-13/09) >+33231374523 (1m)Municipal de l'Argonne - Grandpre (8) (01/04-30/09) >+33324305071 (116m)Les Terrasses de Brieulles - Brieulles sur Meuse (55) (01/04-30/09) >+33329809365 (178m)Municipal Quintefeuille - Asnelles (14) (01/04-30/09) >+33231223550 (3m)La Ferme du Lavoir - Formigny (14) [<51] (01/01-31/12) >+33617104542 (30m)La Prairie - Port en Bessin (14) (01/04-30/09) >+33231217006 (19m)Port'land - Port en Bessin (14) (01/04-02/11) >+33231510706 (64m)Les Haras - Touques (14) (01/03-30/11) >+33231884484 (54m)La Hague - Sainte Honorine des Pertes (14) (15/05-15/09) >+33231217724 (67m)Le Robinson - Colleville sur Mer (14) (01/04-30/09) >+33231224519 -CCA(65m)Le Clos Normand**** - Bourg Achard (27) (15/04-30/09) >+33232563484 (129m)Municipal Les Dunes - Saint Georges de la Riviere (50) (01/04-30/10) >+33233520384 (5m)Rural de Levallois Albert - Saint Georges de la Riviere (50) [<51] >+33233047381 (7m)Municipal De Batigny - Pierrefonds (60) (31/03-15/10) >+33344428083 (79m)Les Pommiers - La Cambe (14) [<51] (01/04-01/10) >+33231227492 (29m)La ferme Chez la Fontaine (tentes seulement) - Gefosse Fontenay (14) [<51] (01/06-30/09) >+33231226944 (8m)Municipal** - Thionville [<51] (01/05-30/09) >+33382538375 (154m)Ferme de Benedictines - Grandcamp Maisy (14) [<51] >+33231519312 (16m)Du Golf - Saint Jean de la Riviere (50) (01/04-01/11) >+33233047890 -CCpg55-CCA-BD_FR-A.017b(7m)Les Vikings - Barneville Carteret (50) (03/04-20/09) >+33233538413 -CCA(8m)Le Pre Normand - Saint Jean de la Riviere (50) (01/05-15/09) >+33233538564 (6m)La Baie des Veys - Sainte Marie du Mont (50) [<51] (01/05-15/09) >+33233715690 -CCpg52(3m)Les Bosquets - Barneville Carteret (50) (01/04-15/09) >+33233047362 (6m)Risle Seine Les Etangs - Pont Audemer (27) (01/04-31/10) >+33232424665 -CCA(4m)Municipal De Pont l'Abbe - Picauville (50) [<51] (15/05-30/09) >+33233410018 (2m)Chant Des Oiseaux - Trouville sur Mer (14) >+33231880642 (75m)Omaha Beach - Vierville sur Mer (14) (01/04-30/09) >+33231224173 (40m)Le Bocage - Barneville Carteret (50) (01/04-30/09) >+33233538691 (10m)Municipal les Etangs - Ciry Salsogne (2) (01/01-31/12) >+33323597117 (46m)La Gerfleur - Barneville Carteret (50) (01/04-31/10) >+33233043841 (7m)Lac Vert Plage - Doulcon (55) (01/04-01/10) >+33329809038 (173m)La Bruyere*** - Villerville (01/04-30/09) >+33231982439 -BD_FR-B.097(128m)Municipal Le Vieux Chateau - Saint Sauveur le Vicomte (50) (01/06-15/09) >+33233417204 (9m)Du Joncal - Grandcamp Maisy (14) (01/04-30/09) >+33231226144 -CCA(4m)Aire naturelle De Camping - Grandcamp Maisy (14) [<51] >+33231223713 (2m)La Halte De Mainville - Ressons Le Long (2) (06/01-08/12) >+33323742669 -CCA(50m)Municipal Les Marguerites Du Mail - Soissons (2) (01/01-31/12) >+33323745269 (41m)A la ferme le Pont du Hable - Cricqueville en Bessin (14) [<51] (15/04-15/10) >+33231226231 (0m)Kity Caravan'Inn - Dun sur Meuse (55) (01/04-15/10) >+33680432470 (171m)La Briquerie**** - Equemauville (14) (01/04-30/09) >+33231892832 -CCA(111m)Le Grand Paquis-Mini Golf - Milly sur Bradon (55) [<51] (01/05-30/09) >+33329808489 (170m)La Pointe - Bourg et Comin (2) [<51] (01/01-31/12) >+33323258752 (55m)De la Catiniere*** - Fiquefleur (27) (10/04-15/10) >+33232576351 -CCA(8m)Domaine de la Nature - Presles et Boves (2) (01/01-31/12) >+33323547455 (46m)Les Ronds Duval - Les Moitiers-d'Allonne (50) [<51] (01/05-30/09) >+33608833511 (69m)Municipal Saint Paul - Lyons La Foret (27) (01/04-31/10) >+33232494202 -CCA(89m)De la Trye - Bresles (60) (01/01-31/12) >+33344078095 -CCA(56m)La Croix du Vieux Pont -�Berny Riviere (2) (01/01-31/12) >+33323555002 -CCA(42m)Les Bruyeres - Conteville (27) (04/04-01/11) >+33232560880 (99m)De l'Aigrette - Attichy (60) (01/03-30/11) >+33344421597 (37m)Les Marronniers - Saint Thurien (27) [<51] (01/01-31/12) >+33232566951 (117m)Municipal - Sainte Mere Eglise (50) (15/03-18/10) >+33233413522 (28m)Le Conihout - Jumieges (76) [<51] >+33235379512 (3m)La Belle Etoile - Le Coudray Saint Germer (60) [<51] (01/04-30/09) >+33344818388 (226m)La Base de Plein Air et de Loisirs - Jumieges (76) (01/04-31/10) >+33235379384 (13m)Utah Beach - Sainte Marie du Mont (50) (01/04-18/09) >+33233715369 -CCA(3m)Naturist - Du Bois Mareuil - Lorleau (27) >+33663980045 (152m)Le Phare** - Honfleur (04/04-30/09) >+33231891026 (13m)Municipal - Malling (57) (01/04-30/09) >+33382501297 (147m)La Samaritaine - Buzancy (8) (10/04-18/09) >+33324300888 (172m)Bel Sito - Baubigny (50) (15/04-15/09) >+33675807280 (28m)l'Aubette** - St.Leger Du Bourg Denis (50) (01/01-31/12) >+33235084769 (40m)Municipal Bord de l'Aisne** - Guignicourt (01/04-30/09) >+33323797458 (57m)Rural de James Adolphe - Senoville (50) [<51] >+33233043328 (59m)La Foret -�Jumieges (76) (11/04-25/10) >+33235379343 -CCpg41-CCA(47m)A la ferme de Pepin - Doncourt les Longuyon (54) [<51] >+33382897740 (310m)Municipal - Sierck les Bains (57) [<51] (01/05-30/09) >+33382837239 (147m)Naturist - La Chenaie - Anneville Ambourville (76) (01/05-30/09) >+33235372223 (14m)Le Soleil d'Or - Petiville (76) [<51] (01/01-31/12) >+33235399207 (7m)A la Ferme Aux Ormeaux - Bricquebec (50) [<51] (14/04-15/09) >+33233523513 (45m)Le Syndicat Mixte de l'Othain - Marville (55) (01/02-30/11) >+33329881905 (205m)Municipal Les Mielles - Surtainville (50) (01/01-31/12) >+33233043104 (4m)Le Petit Hameau Des Dunes - Ravenoville (50) [<51] (0m)Le Cormoran -�Ravenoville Plage (50) (05/04-30/09) >+33233413394 -CCpg53-CCA(1m)Le Val d'Ire - Ire le Sec (55) >+33329881307 (247m)Le Lac - Monampteuil (2) (01/04-30/09) >+33323216073 (65m)La Haute Haye - Avesnes en Bray (76) (01/04-30/09) >+33235900371 (155m)Municipal Le Vallage - Attigny (8) [<51] >+33324712306 (155m)Les Iles - Ravenoville (50) >+33233214752 (1m)Le Ranch - Le Rozel (50) (01/04-30/09) >+33233100710 (7m)Municipal Du Parc - La Mailleraye sur Seine (76) [<51] (01/04-30/09) >+33235371204 (17m)Municipal - Saint Germain le Gaillard (50) (01/01-31/12) >+33233525564 (95m)Aire Naturelle l'Oraille - l'Etang Bertrand (50) [<51] (15/04-15/10) >+33233403037 (34m)Rural de Pezet Marie - Le Rozel (50) [<51] (01/01-31/12) >+33233043041 (7m)Du Moulin - Aizelles (2) [<51] (15/04-15/10) >+33323224118 (88m)Le Grand Large -�Les Pieux (50) (11/04-20/09) >+33233524075 -CCpg54-CCA(6m)Municipal Le Clair Ruissel - Nolleval (76) [<51] (15/03-15/10) >+33235908326 (87m)Le Canada - Saint Marcouf (50) (15/04-30/09) >+33233212080 (1m)La Ferme de la Croix-Villiere - Neuville Day (8) [<51] (01/01-31/12) >+30324714419 (143m)Les Nenuphars - Roumare (76) (30/03-20/12) >+33235338075 (134m)Les Araucarias - Carlepont (60) (01/04-31/10) >+33344752739 (66m)Municipal Le Bocage - Valognes (50) [<51] (01/04-15/10) >+33610845933 (33m)Le Pre Fleuri - Carlepont (60) [<51] (01/01-31/12) >+33344752146 (70m)A la ferme de la Rue de Caubriere - Vaudreville (50) [<51] (01/06-31/08) >+33603108974 (46m)La Sinope - Quineville (50) (01/06-30/09) >+33233210738 (2m)A la Ferme de Freneuse - La Frenaye (76) [<51] (01/01-31/12) >+33235317055 (133m)Municipal La Citadelle - Montmedy (55) [<51] (01/05-30/09) >+33329801040 (252m)Barre Y Va - Villequier (76) (03/04-23/10) >+33235962638 -BD_FR-B.093(13m)La Ferme aux 5 Saisons - Flamanville (50) [<51] >+33680663477 (32m)Hameau des Forges - Saint Antoine la Foret (76) [<51] (01/01-31/12) >+33235398028 (125m)Lac de Bairon - Le Chesne (8) (05/04-15/09) >+33324301166 (181m)Les Tourterelles - Flamanville (50) >+33233041824 (63m)La Montagne - Chiry Ourscamp (60) (01/01-31/12) >+33344769829 (66m)Les Bouleaux - Inor (55) (01/01-31/12) >+33329804860 (164m)Les Etangs Du Moulin - Suzy (2) (04/04-30/09) >+33626024079 (102m)Etang du Haut Matz - Ricquebourg (60) [<51] (01/01-31/12) >+33344425159 (59m)La Chenaie** - Laon (01/05-30/09) >+33323202556 (92m)La ferme Le Mellier- Videcosville (50) [<51] >+33233541010 (79m)De Sorel*** -�Orvillers Sorel (60) (01/02-15/12) >+33344850274 -CCpg36(85m)Aire naturelle Les Mesanges - Songeons (60) [<51] (15/04-15/10) >+33344823132 (183m)La Clairefontaine - Siouville Hague (50) [<51] (28/06-31/08) >+33233524273 (6m)La ferme Le vieux Moulin - Roy Boissy (60) [<51] >+33344462946 (117m)Le Rivage - Quettehou (50) (01/04-30/09) >+33233541376 (7m)La Gallouette - Saint Vaast la Hougue (50) (01/04-30/09) >+33233542057 -CCA(1m)l'Etang du Moulin - Salency (60) [<51] (01/01-31/12) >+33344099981 (68m)Le Village Vert - Tollevast (50) >+33233430078 (156m)A la ferme La Neuve Rue - Oursel Maison (60) [<51] (01/01-31/12) >+33344468155 (177m)A la ferme Le Bocage - Trouville (76) [<51] >+33235316017 (149m)Municipal La Tour St. Jerome - Mouzon (8) [<51] >+33324262802 (162m)Municipal La Miniere - Forges les Eaux (76) (15/03-15/10) >+33235905391 (158m)Municipal Le Jonville - Reville (50) (01/04-30/09) >+33233544841 (3m)Aire naturelle La Briqueterie - Crevecoeur le Grand (60) [<51] (01/04-15/11) >+33344469685 (169m)Aire naturelle de Dupuy - Saint Maur (60) [<51] (01/04-30/09) >+33344463473 (182m)D'Ayencourt - Ayencourt (80) (01/01-31/12) >+33322780687 (63m)Le Beau Soleil** - Criquetot l'Esneval (76) (01/04-30/09) >+33235202422 (122m)Le Grand Hameau - Saint Jouin Bruneval (76) (01/04-31/10) >+33235558841 (107m)Ferme La Rue Verte - Flamanville (76) [<51] (01/01-31/12) >+33235968127 (143m)Municipal De la Devise - Vauville (50) >+33233526469 (6m)Les Ombrages - Saint Jouin Bruneval (76) (01/04-30/09) >+33235206796 (122m)Le Pre Fleuri - Montdidier (80) (01/01-31/12) >+33322789322 (77m)Municipal de Collignon - Tourlaville (50) (01/05-30/09) >+33233201688 (4m)Municipal La Saline - Equeurdreville Hainneville (50) (01/01-31/12) >+33233938833 (7m)Municipal Du Fort - Bretteville (50) (01/01-31/12) >+33233222760 (9m)Le Lac - Douzy (8) (15/04-01/10) >+33324263119 (153m)Indiana - Barfleur (50) [<51] (21/06-13/09) >+33233239561 (4m)Municipal Du Marais De La Fontaine** - La Fere (02) [<51] (01/04-30/09) >+33323568294 (49m)L'Anse du Brick -�Maupertus sur Mer (50) (04/04-20/09) >+33233543357 -CCA(28m)Igesa - Querqueville (50) (01/07-31/08) >+33233081692 (5m)Du Banel - Matton et Clemency (8) (01/04-31/10) >+33324271589 -CCA(204m)Le Clos Moisson - Urville Nacqueville (50) (01/01-31/12) >+33233035673 (5m)Municipal La Blanche Nef - Barfleur (50) (15/02-15/11) >+33233231540 (2m)Municipal Les Dunes - Urville Nacqueville (50) (01/04-30/09) >+33233035673 (3m)Les Traverses - Fontaine Bonneleau (60) [<51] >+33344829110 (90m)La Ferme du Bord de Mer - Gatteville le Phare (50) (01/01-31/12) >+33233540177 (1m)Les Tilleuls - Le Tilleul (76) (01/04-30/09) >+33235271161 (99m)Aire naturelle de Laverriere - Laverriere (60) [<51] >+33613216391 (177m)Aire naturelle d' Epivent - Bordeaux Saint Clair (76) [<51] >+33235271260 (117m)La Plage - Fermanville (50) (01/04-15/10) >+33233543884 (16m)l'Aiguille Creuse -�Les Loges (76) (05/04-28/09) >+33235295210 -CCpg40-CCA(95m)Municipal De La Prairie - Sedan (8) (15/04-30/09) >+33324271305 (151m)La Mare Sausseuze - Gerville (76) [<51] >+33235293029 (112m)Le Sablon - Cosqueville (50) [<51] (01/04-31/10) >+33233434172 (6m)Municipal - Etretat (76) (01/01-31/12) >+33235270767 (9m)La Ferme du Manoir - Bordeaux Saint Clair (76) [<51] (01/04-30/09) >+33235297910 (98m)Municipal L'Abbaye - Signy l'Abbaye (8) (01/05-30/09) >+33324528773 (143m)Municipal Du Hable - Omonville la Rogue (50) (01/04-30/09) >+33233528615 (8m)Aire naturelle de Bazin Georges - Bellencombre (76) [<51] (01/04-31/10) >+33235939015 (97m)Les Pommiers - Saint Leonard (76) (15/04-15/10) >+33613552910 (94m)La ferme La Hetraie - Bec de Mortagne (76) (15/03-31/10) >+33235295602 (130m)Les Etangs - Vendeuil (2) [<51] (01/01-31/12) >+33323089491 (54m)Naturist - Du Soleil de la Porte Oceane - Yport (76) (01/05-15/09) >+33235273064 (97m)Municipal La Chenaie - Yport (76) (05/04-28/09) >+33235273356 -CCA(38m)La Ferme du Val de Serre - Marle (02) [<51] (01/01-31/12) >+33323200004 (74m)La Pature - Yport (76) [<51] (15/04-30/09) >+33235273004 (74m)Le Rivage - Yport (76) (01/01-31/12) >+33235273378 (72m)Le Sainte Claire** - Neufchatel en Bray (76) (01/04-15/10) >+33235930393 -CCA(78m)Municipal Du Canada - Toussaint (76) (15/03-19/10) >+33235297834 (94m)Parc de la Saane - Auzouville sur Saane (76) >+33235042025 (72m)Municipal De Reneville - Fecamp (76) (01/04-15/11) >+33235282097 (32m)Municipal Le Grand Mail - Aumale (76) [<51] (20/03-30/09) >+33235934050 (181m)Municipal Les Pres de l'Abbaye - Loeuilly (80) (30/03-29/09) >+33322381388 (52m)La Source - Voyennes (80) [<51] (01/04-30/09) >+33322880111 (58m)Municipal Le Bois des Pecheurs - Poix de Picardie (80) (01/04-30/09) >+33322901171 -CCA(109m)Municipal du Mont Olympe - Charleville-Mezieres (8) (01/04-15/10) >+33324332360 (147m)Le Vivier Aux Carpes*** - Seraucourt le Grand (2) (01/03-31/10) >+33323605010 -CCA(70m)Municipal - Cany Barville (76) (01/04-30/09) >+33235977037 (20m)Le Paquis - La Grandville (8) (12/04-02/11) >+33324376037 (211m)La Valle de l'Avre - Moreuil (80) >+33322097299 (36m)Les 3 Plages - Sassetot le Mauconduit (76) (15/04-15/09) >+33235274011 (91m)l'Orival - Les Grandes Ventes (76) (14/03-26/10) >+33235834590 -CCpg000(162m)Aire naturelle Municipale - Ribemont (2) [<51] (01/05-30/09) >+33323637130 (64m)Ferme des Hetres - Saint Pierre en Port (76) (01/04-15/10) >+33235274247 (92m)Maupassant - Vittefleur (76) (09/03-15/12) >+33235979714 (88m)l'Oiseau Blanc - Sassetot le Mauconduit (76) (15/02-15/11) >+33235274889 (88m)Les Falaises - Saint Pierre en Port (76) (01/04-05/10) >+33235295158 -CCA(84m)Aire naturelle Le Passant - Saint Martin aux Buneaux (76) [<51] (01/04-30/09) >+33235975477 (86m)Municipal Les Grands Pres - Vittefleur (76) (01/04-30/09) >+33235975382 (7m)Municipal Les Mouettes - Saint Martin aux Buneaux (76) (01/01-31/12) >+33235979616 (87m)Atelier de la Charite - Landouzy La Ville (02) [<51] >+33323984544 (231m)Municipal Le Vergne** - Veulettes sur Mer (76) (01/04-30/09) >+33235975344 (9m)La Vallee - Gueures (76) (01/04-15/10) >+33235830894 (22m)Municipal** - Saint Quentin (2) (01/03-30/11) >+33323069405 (80m)Haulme - Haulme (8) >+33324328161 (156m)Aire naturelle Le Bois - Manneville es Plains (76) [<51] (01/05-31/10) >+33235972359 (77m)Municipal d'Etennemare - Saint Valery en Caux (76) (29/03-03/11) >+33235971579 -CCpg39-CCA(49m)Les Garennes de la Mer - Bourg Dun (76) (01/04-15/10) >+33235831044 (41m)Municipal Les Deux Rivieres - Martigny (76) (01/04-09/10) >+33235856082 -CCA(6m)Municipal Le Colombier - Offranville (76) (01/04-15/10) >+33235852114 (85m)Vieilles Forges - Les Mazures (8) (12/04-28/09) >+33324401731 -CCA(258m)Tournavaux - Tournavaux (8) (01/04-30/09) >+33324328259 (146m)Municipal - Bucilly (2) [<51] >+33323582746 (155m)Municipal Les Mouettes - Veules les Roses (76) (01/04-31/10) >+33235976198 -CCA(47m)Municipal Au Port A Diseur - Montherme (8) (12/04-29/09) >+33324530121 (137m)Les Pommiers - Sotteville sur Mer (76) (02/04-31/10) >+33235976212 (45m)Le Faucon - Thilay (8) [<51] >+33324338118 (162m)Municipal Rapides De Phades - Montherme (8) (15/06-15/09) >+33324530673 (158m)Municipal Le Mesnil - Saint Aubin sur Mer (76) (01/04-31/10) >+33235830283 (26m)Les Hortensias** - Vraignes en Vermandos (80) [<51] (01/01-31/12) >+33322856468 (94m)Aire naturelle l'Isolette - Saint Aubin sur Mer (76) [<51] (01/04-01/10) >+33235830003 (24m)A la ferme de Couvron - Macquigny (2) [<51] (01/01-31/12) >+33323610583 (145m)Aire naturelle de Bouclon Jeanne - Longueil (76) [<51] (15/04-15/10) >+33235830465 (41m)Municipal Le Grand Sable - Saint Aubin sur Mer (76) (29/03-29/10) >+33235040355 (5m)De La Vallee De L'Oise - Guise (2) (15/04-15/10) >+33323611486 (96m)La Source -�Hautot sur Mer (76) (15/03-15/10) >+33235842704 -CCpg38-CCA(10m)La Muree - Bourg Fidele (8) [<51] (01/03-31/10) >+33324542445 (345m)Vitamin - Saint Aubin sur Scie (76) (01/04-15/10) >+33235821111 -CCA(93m)La Renardiere - Sailly Laurette (80) (15/03-30/11) >+33322766019 (35m)Municipal De la Plage - Quiberville (76) (01/04-31/10) >+33235851025 (4m)Municipal La Violette** - Proyart (80) (01/04-31/10) >+33322853749 (71m)Le Val D'Oise - Etreaupont (2) [<51] (01/04-31/10) >+33323974804 (126m)Aire naturelle de Lefebvre Robert - Sainte Marguerite sur Mer (76) [<51] (55m)Les Merisiers - Cerisy (80) (01/04-31/10) >+33322766118 (34m)Les Aunes - Marly Gomont (2) [<51] (01/04-30/09) >+33323609049 (111m)Relais Motards - Hautot Sur Mer (76) [<51] (15/04-31/10) >+33235839249 (12m)Municipal Les Poissonniers - Corbie (80) (01/04-31/10) >+33686047385 (34m)Le Pont Rouge et les Vignes - Chipilly (80) (15/03-31/10) >+33674828542 (43m)Le Marqueval - Pourville sur Mer (76) (20/03-15/10) >+33235826646 -CCA(4m)Domaine de la Motte - Signy le Petit (8) (01/01-31/12) >+33324535473 (299m)La ferme Le Bouzencourt - Le Hamel (80) (15/03-15/11) >+33688613300 (33m)Le Port de Plaisance*** - Peronne (80) (01/03-31/10) >+33322841931 -CCA(51m)Du Pavillon - Neuville aux Joutes (8) [<51] (01/04-31/10) >+33324535387 (276m)Les Puits Tournants -�Sailly le Sec (80) (01/04-31/10) >+33322766556 -CCpg35(31m)Parc des Cygnes - Amiens (80) (01/04-15/10) >+33322432928 (23m)Aux Cygnes d'Opale - Blangy s/Bresle (76) (01/04-31/10) >+33235945565 -CCA(50m)Municipal Bovalon - Vadencourt (2) [<51] (01/04-30/09) >+33684888186 (86m)Municipal Les Charmilles** - Cappy (80) (15/04-15/10) >+33322761450 (39m)Le Paradis des Pecheurs - Pont Noyelles (80) (15/03-15/10) >+33322401474 (36m)La Buissonniere* - Cappy (80) [<51] (01/05-01/10) >+33322760910 (43m)Municipal du Brochet* - Peronne [<51] (01/04-01/10) >+33322840235 (54m)Municipal Le Marais - Querrieu (80) (01/04-30/09) >+33322401263 (36m)Les Marais du Levant - Bray sur Somme (80) (01/04-30/10) >+33322760090 (38m)Domaine de Sery - Bouttencourt (80) >+33235935312 (44m)Le Verger - Bray sur Somme (80) [<51] >+33322760077 (60m)La Tortille* - Clery sur Somme (01/04-31/10) >+33322831759 (50m)Le Pre Vert** - Frise (80) [<51] (01/04-30/09) >+33322840290 (48m)De La Cascade - Hirson (2) [<51] >+33323581897 (197m)Municipal - Picquigny (80) (01/04-31/10) >+33322512583 (17m)Municipal Les Bateaux - Revin (8) (01/04-05/11) >+33324401565 (124m)Aire naturelle Horville - Bracquemont (76) [<51] (88m)La Pointe** - Frise (80) [<51] (01/03-15/11) >+33322832481 (44m)Le Chateau et l'Oseraie*** - Feuilleres (80) (01/04-31/10) >+33322831759 (46m)Le Saule en Fer - Frise (80) [<51] (01/04-15/10) >+33322447551 (41m)Sam Suffy - Hem Monacu (80) [<51] (01/04-01/11) >+33322830665 (46m)Les Auges - Hem Monacu (80) [<51] >+33322840171 (46m)Municipal La Foret* - Bazinval (76) [<51] (01/04-31/10) >+33232970401 (66m)Les 4 Derniers - Ribemont sur Ancre (80) [<51] (01/04-31/10) >+33322401937 (39m)Municipal Le Val Boise - Berneval le Grand (76) [<51] (01/04-01/11) >+33235852918 (78m)Les Lauriers** - Curlu (80) (01/01-31/12) >+33322841602 (49m)Les Rosiers* - Curlu (80) (01/04-31/10) >+33322839760 (47m)Les Goelands - Saint Martin en Campagne (76) (15/03-15/10) >+33235838290 -CCA(57m)Le Chateau de Bertangles - Bertangles (80) [<51] (18/04-08/09) >+33322933773 (97m)La Berquerie - Mesnil Reaume (76) (15/03-15/10) >+33235500046 (127m)Le Clos Savoye - Biville sur Mer (76) (01/04-31/10) >+33235836106 (110m)Municipal Bellevue - Fumay (8) (01/04-30/09) >+33324412815 (125m)Les Marguerites** - Gamaches (80) (27/03-15/11) >+33322308951 (23m)Municipal Les Acacias - Touffreville sur Eu (76) [<51] (01/01-31/12) >+33235506633 (33m)Municipal du Lac de Conde - Le Nouvion en Thierache (2) (01/04-30/09) >+33323989858 (190m)Municipal Les Etangs des Moines - Fourmies (59) (01/04-31/10) >+33671017097 (217m)Municipal De Moraypre - Haybes (8) [<51] (01/04-30/09) >+33324411678 (117m)Municipal le Velodrome - Albert (80) (01/04-15/10) >+33322752253 -CCA(67m)De l'Etang - Incheville (76) (01/03-31/10) >+33235503017 (13m)Municipal Le Village - Longpre les Corps Saints (80) [<51] (01/04-30/09) >+33322318444 (54m)Le Marlemperche - Le Nouvion en Thierache (2) (01/01-31/12) >+33323972202 (189m)Municipal - Bouvaincourt sur Bresle (80) (01/04-31/10) >+33322308687 (10m)Municipal Le Mont Joli Bois - Criel sur Mer (76) (01/01-31/12) >+33235508119 (18m)Le Hututu - Ohain (59) [<51] (15/04-15/10) >+33327600733 (254m)Les Mouettes - Criel sur Mer (76) (01/04-04/11) >+33235867073 (16m)Municipal La Peupleraie - Long (80) (15/03-15/11) >+33322318427 (7m)Le Grand Pre - Long (80) (01/01-31/12) >+33323680222 (6m)Bellevue - Authuille (80) (15/03-31/10) >+33322745929 (94m)Parc Val d'Albion - Criel sur Mer (76) [<51] (01/05-15/09) >+33235862142 (34m)Au Bord d'Eau - Authuille (80) >+33322752042 (76m)Municipal Parc du Chateau - Eu (76) (01/04-31/10) >+33235862004 (18m)International Du Golf - Le Treport (76) (01/04-15/09) >+33227280150 (99m)Le Parc des 4 Saisons - Floyon (59) (15/02-20/12) >+33327591414 (166m)Naturist - Eden Avesnois - Boulogne sur Helpe (59) >+33327598148 (182m)Municipal Les Boucaniers - Le Treport (76) (01/01-31/12) >+33235863547 (6m)Municipal du Rompval - Mers les Bains (80) (01/04-01/11) >+33235844321 -CCpg33-CCA-BD_FR-B.072(95m)Municipal Du Chemin du Friset - Prisches (59) [<51] (01/04-30/10) >+33327775900 (184m)Municipal Des Hayettes - Vireux Molhain (8) [<51] >+33324556112 (111m)Municipal Les Portes de la Baie de Somme - Mareuil Caubert (80) (01/04-30/09) >+33322316237 (3m)Le Val de Trie*** - Moyenneville (80) (29/03-15/10) >+33322314888 -CCpg34(27m)Le Clos Cacheleux - Miannay (80) (15/03-15/10) >+33322191747 -CCA(27m)Municipal - Ault (80) (01/01-31/12) >+33322604877 (78m)Municipal Le Chant des Oiseaux - Friaucourt (80) (01/04-15/10) >+33322264954 (96m)La Herelle - Miraumont (80) (01/04-15/10) >+33322748483 (86m)Municipal La Chapelle d'Onival - Ault (80) (15/04-15/11) >+33322604215 (67m)Aire naturelle Le Coureux - Liessies (59) [<51] (01/01-31/12) >+33327618196 (206m)Municipal Le Marais d'Onival - Woignarue (80) (20/04-15/09) >+33322604008 (10m)Le Clos Vert - Grand Fayt (59) [<51] (01/01-31/12) >+33327594550 (141m)De la Foret - Havrincourt (62) [<51] >+33321483822 (100m)Municipal Les Aillots - Saint Blimont (80) (01/04-30/09) >+33322306255 (54m)Municipal de Mars - Avesnes sur Helpe (59) [<51] (15/04-30/09) >+33327579904 (173m)Au Bol d'Air - Semeries (59) (01/04-30/09) >+33327590554 (159m)Les Rocailles - Liessies (59) >+33327618108 (170m)Le Val Joly - Eppe-Sauvage (59) (18/04-28/09) >+33327618376 -CCpg26(197m)Jamonette - Foisches (8) (01/01-31/12) >+33324427237 (195m)Le Sanglier - Rancennes (8) >+33324427261 (99m)La Cle Des Champs - Rancennes (8) [<51] (01/04-31/10) >+33680633272 (100m)Naturist - Les Trois Vallons - Felleries (59) (Easter-30/09) >+3222152351 (225m)Au Bord de l'Authie - Authuille (80) (01/02-01/12) >+33322325613 (66m)Le Chateau Des Tilleuls** - Port Le Grand (80) [<51] (01/03-30/12) >+33322240775 -CCA(11m)Rural de Chevalier Michel - Arrest (80) [<51] (Easter-30/09) >+33322268865 (12m)La Sablonniere - Maroilles (59) [<51] (01/04-01/11) >+33327847452 (154m)Le Moulin des Pres - Maroilles (59) (15/03-15/10) >+33327847551 (131m)Municipal La Boissellerie - Felleries (59) (15/04-30/09) >+33327590650 (177m)Les Haies - Maroilles (59) [<51] (01/03-30/10) >+33327777927 (161m)Les Hirondelles - Noyelles sur Sambre (59) (01/04-15/10) >+33327673954 (140m)La Ferme De la Leu - Lancheres (80) (01/02-30/11) >+33322607187 (8m)Drancourt - Saint Valery sur Somme (80) (19/04-13/09) >+33322269345 -CCA(13m)Le Plein Air - Estreboeuf (80) (01/04-10/10) >+33322608627 (13m)Municipal Le Marais Communal - Pende (80) >+33322608727 (5m)Municipal Les Prairies - Lancheres (80) (01/01-31/12) >+33322607187 (4m)Le Voyeul - Cayeux sur Mer (80) (01/04-15/10) >+33322266084 (3m)Le Picardy - Saint Valery sur Somme (80) (01/04-31/10) >+33322608559 (22m)Les Pres Marcotte - Hem Hardinval (80) (10/04-15/10) >+33322774148 (49m)La Forestiere de Preux - Preux au Bois (59) (01/01-31/12) >+33327773461 (158m)La Vieille Eglise - Cayeux sur Mer (80) (01/01-31/12) >+33322266323 (3m)La Kilienne - Warlincourt les Pas (62) (01/01-31/12) >+33321730303 -CCpg27(123m)Naturist - Natura International - Beaurieux (59) (01/04-31/10) >+33327605177 (219m)Municipal Les Trois Clochers*** - Cambrai [<51] (01/04-15/10) >+33327709164 (45m)La Baie - Pende (80) (27/03-17/10) >+33322607272 (4m)L'Etang Des Peupliers - Solesmes (59) >+33327373208 (72m)Municipal Du Solrezis - Solre le Chateau (59) [<51] (01/04-30/09) >+33327616114 (182m)Le Walric - Saint Valery sur Somme (80) (03/04-01/11) >+33322268197 -CCA(27m)La Croix l'Abbe - Saint Valery sur Somme (80) (01/04-31/10) >+33322608146 (30m)Le Rio* - Noyelles sur Mer (03/04-12/10) >+33322232838 (5m)Aux Haies de Nolette* - Noyelles sur Mer [<51] (01/04-31/10) >+33322232408 (14m)Municipal Le Bois de Pins - Cayeux sur Mer (80) (03/04-01/11) >+33322267104 -CCA(6m)Vert Donjon - Locquignol (59) (01/03-30/10) >+33327342039 (155m)Aerospatiale - Cayeux sur Mer (80) >+33322276898 (6m)Municipal Les Galets de la Molliere - Cayeux sur mer (80) (03/04-01/11) >+33322266185 -CCA(6m)Municipal La Foret - Lucheux (80) (01/04-30/09) >+33322324492 (93m)La Safriere** - Ponthoile (80) (01/04-31/10) >+33322270709 (5m)Au Vert de l'Authie - Beauvoir Wavans (62) (01/03-30/11) >+33321040067 (34m)Le Pre Fleuri* - Le Crotoy (80) [<51] (01/04-30/10) >+33322278726 (6m)Le Roi du Bois - Locquignol (59) (01/04-31/10) >+33327494370 (158m)La Randonniere** - Favieres (80) (01/04-30/09) >+33322270027 (4m)La Prairie** - Le Crotoy (80) (01/04-30/09) >+33322270265 (6m)Municipal l'Epinette** - Sauchy Lestree (62) (01/04-31/10) >+33321595013 (53m)Le Tarteron*** - Le Crotoy (80) (01/04-01/11) >+33322270675 -CCA(3m)Le Pre Vert - Potelle (59) (01/04-30/09) >+33327490947 (140m)Municipal Des Peupliers - Auxi le Chateau (62) (01/04-30/09) >+33321411079 (27m)La Ferme de Mayocq** - Le Crotoy (80) (01/04-31/10) >+33322270999 (5m)Rural Maison Vieille - Noeux les Auxi (62) [<51] (01/04-30/09) >+33321473358 (55m)Le Mormal - Villereau (59) (15/02-15/01) >+33327418868 (143m)Le Ridin *** - Le Crotoy (80) (01/04-30/09) >+33322270322 -CCpg32(5m)Le Lac Vauban - Le Quesnoy (59) (01/04-31/10) >+33327491007 (127m)La Verte Prairie*** - Forest Montiers (80) (01/04-31/10) >+33322283289 (10m)Les Marguerites* - Le Crotoy (80) [<51] (01/04-30/09) >+33322278544 (6m)Les Trois Sablieres*** - Le Crotoy (80) (01/04-08/11) >+33322270133 -CCA(6m)Chateau Gaillard*** - Forest Montiers (80) (01/04-31/10) >+33322239733 (30m)Les Aubepines*** - Le Crotoy (80) (01/04-01/11) >+33322270134 -CCA-BD_FR-B.055(6m)La Blique - Paillencourt (59) >+33327741940 (35m)Les Oiseaux** - Rue (80) (01/02-30/11) >+33322257182 (4m)Municipal Du Becquerel* - Ecourt St.Quentin (62) (01/04-31/10) >+33321735000 (37m)Ferme de la Mottelette - Forest Montiers (80) [<51] (01/04-31/10) >+33322283233 -CCA(10m)Les Colombes* - Aubencheul au Bac (59) (01/04-15/10) >+33327892590 (39m)La Sensee** - Aubigny au Bac (59) (01/04-15/10) >+33327892522 (36m)De l'Abbaye - Oisy le Verger (62) >+33321595154 (43m)Aux Roubaisiens - Oisy le Verger (62) (01/04-15/10) >+33321595154 (37m)La Marliere - Fechain (59) (01/04-15/10) >+33327799808 (34m)Municipal Le Grand Marais* - Ecourt St.Quentin (62) [<51] (01/04-31/10) >+33321735000 (39m)Du Moulin de Frasnoy - Frasnoy (59) (01/04-15/10) >+33327494330 (123m)Municipal La Republique* - Aubigny au Bac (59) (15/03-15/10) >+33327809140 (36m)La Chute d'Eau - Rebreuve sur Canche (62) (01/04-30/10) >+33628565196 (77m)Le Champ Neuf*** - St. Quentin en Tourmont (80) (01/04-15/10) >+33322250794 -CCA(8m)La Hutte - Mecquignies (59) [<51] (01/04-31/10) >+33327630869 (145m)Le Bout des Crocs** - St. Quentin en Tourmont (80) (01/04-31/10) >+33322257333 (7m)Espace Vert - Liencourt (62) (01/04-15/10) >+33321484344 (138m)La Vallee de la Sensee** - Brunemont (01/04-31/10) >+33327809128 (34m)L'Espace Vert des Tremieres - St. Quentin en Tourmont (01/04-31/10) >+33322257427 (6m)Le Val du Ternois - Frevent (62) (01/04-31/10) >+33321037879 (72m)La Paille Haute** - Boiry Notre Dame (62) (01/04-31/10) >+33321481540 -CCA(75m)Municipal Les Biselles*** - Arleux (01/04-31/10) >+33327895236 (35m)La Haie Penee*** - St. Quentin en Tourmont (15/01-15/12) >+33322257344 (4m)La Maye - Rue (80) (01/04-31/10) >+33322250955 -CCA(5m)Municipal De La Sapiniere - Labroye (62) (01/04-30/09) >+33321903627 (23m)L'Oree du Parc le Fleury - Wavrechain sous Faulx (59) (01/01-31/12) >+33327357116 (33m)Le Fromentel - Gommegnies (59) [<51] (01/01-31/12) >+33327498658 (125m)Le Petit Saint Jean - Boubers sur Canche (62) (01/04-15/10) >+33685669228 (64m)La Garenne de Moncourt** - Rue (80) (15/01-15/12) >+33322250693 (7m)Municipal De la Sabliere - Tortequesne (62) (01/04-30/09) >+33321241494 (58m)Les Sorbiers - Bugnicourt (59) [<51] (010/01-31/12) >+33327896441 (68m)Les Peupliers** - Vironchaux (01/04-31/10) >+33322235427 (63m)Municipal Clair de Lune - Maubeuge (59) (01/04-30/09) >+33327622548 (139m)Les Genets** - Rue (80) [<51] (01/07-30/09) >+33322250767 (6m)Municipal** - Plouvain (15/04-15/11) >+33321501683 (46m)Le Coteau - Dompierre sur Authie (80) [<51] >+33322235926 (13m)La Motte - Quend (80) (01/04-27/10) >+33322277535 (4m)Les Etangs - Dompierre sur Authie (80) (01/04-30/09) >+33322235090 (13m)Le Vieux Moulin - Ponches Estruval (80) (21/03-30/09) >+33322235209 (12m)Le Val d'Authie**** - Villers sur Authie (01/04-31/10) >+33322299247 -CCpg31-CCA(8m)Les Trois Tilleuls - Fillievres (62) (01/04-15/10) >+33321479415 (50m)Municipal - Ponches Estruval (80) (01/04-31/10) >+33322235206 (12m)Les Roses - Quend (80) (20/03-01/11) >+33322277617 (8m)Les Nenuphars - Taisnieres sur Hon (59) [<51] >+33620591573 (132m)La Dune Fleurie - Quend (80) (01/01-31/12) >+33608223739 (13m)Les Vertes Feuilles - Quend (80) (04/04-09/11) >+33322235512 -CCA(5m)Les Deux Plages - Quend (80) (01/04-31/10) >+33322234896 -CCA(4m)Les Charmes - Bettrechies (59) (01/04-15/10) >+33327631615 (115m)La Pierre d'Orge - Villers sur Authie (80) (01/01-31/12) >+33322234348 (5m)Municipal du Haut Pont - Douriez (62) [<51] >+33321863355 (11m)Les Genets - Quend (80) (15/04-31/10) >+33322274840 (4m)Les Tilleuls - Blangerval Blangermont (62) [<51] (01/04-31/10) >+33321413439 (129m)Municipal Le Marais - Dominois (80) (15/03-31/10) >+33322299282 (11m)Le Royon - Fort Mahon Plage (80) (20/03-01/11) >+33322234030 -CCA(6m)Le Vert Gazon - Fort Mahon Plage (80) (01/04-05/10) >+33614647139 (7m)La Jonquiere - Hon Hergies (59) (15/03-15/10) >+33327669517 (129m)La Ferme des Aulnes*** - Nampont St. Martin (01/04-31/10) >+33322292269 -CCpg30(10m)Le Manoir - Fort Mahon Plage (80) (28/04-09/09) >+33322234098 (8m)Soleil - Fort Mahon Plage (80) >+33322235879 (7m)Le Colombier - Douriez (62) >+33321903801 (11m)Ech Bosque - Fort Mahon Plage (80) (01/04-31/10) >+33322277422 (5m)Municipal Le Gardon - Saulchoy (62) (01/01-31/12) >+33321860173 (9m)Notre Chaumiere - Sebourg (59) [<51] (01/04-31/10) >+33327257871 (67m)Les Avesnes - Willeman (62) [<51] (15/03-30/09) >+33321479837 (49m)Municipal L'Etang - Violaines (62) [<51] >+33320294125 (48m)La Ferme Saint Ladre - Saint Georges (62) [<51] >+33321048334 (35m)La Route des Villages Fleuris - Saint Georges (62) (01/04-30/09) >+33321031101 (35m)Le St Blaise - Conchil le Temple (62) [<51] >+33321812051 (6m)l'Auberge les Etangs - Roussent (62) (01/02-31/12) >+33321812010 (17m)Les 4 Plages - Conchil le Temple (62) (01/01-31/12) >+33321812294 (10m)La Hulotte - Villers Brulin (62) [<51] (01/04-31/10) >+33321590068 (148m)Le Bec du Perroquet - Groffliers (62) (01/04-31/10) >+33321896853 (6m)Municipal Le Vert Bocage - Grigny (62) [<51] (01/04-30/10) >+33321816922 (25m)Les Jardins de l'Authie** - Waben (62) (01/04-31/10) >+33321812830 (3m)Municipal Les Peupliers - Bouin Plumoison (62) (15/03-15/10) >+33321864480 (22m)Municipal de la Canche - Aubin Saint Vaast (62) >+33321868698 (22m)Le Halloy** - Berck (62) (01/04-30/09) >+33321090054 (7m)Les Carrieres** - Boisjean (62) (01/04-31/10) >+33321811966 (47m)La Guinguette** - Berck (62) (01/04-02/11) >+33321090422 (7m)Verte Vallee-Chateau De Bureuil - Maresquel Ecquemicourt (62) (01/01-31/12) >+33321903723 (22m)La Scierie - Hernicourt (62) [<51] (15/04-30/09) >+33633181880 (77m)Le Valadin - Humeroeuille (62) [<51] (15/04-15/09) >+33321418306 (113m)Le Grand Marais*** - Verton (62) (01/04-01/11) >+33321843609 (4m)Municipal des Etangs - Contes (62) >+33321068610 (18m)La Loge - La Loge (62) (04/04-12/10) >+33321866805 (107m)Municipal Les Evoiches - Marchiennes (59) (01/04-31/10) >+33327904469 (16m)Le Buverlot - Warlaing (59) [<51] >+33327252554 (16m)l'Oree du Bois*** - Rang du Fliers (62) (01/04-31/10) >+33321842851 -CCA(6m)International** - Berck (62) (Easter-30/09) >+33321091333 (8m)Miny-Park - Berck (62) [<51] >+33321090268 (7m)l'Alouette** - Berck (62) (Easter-30/09) >+33321844916 (8m)Le Pre St-Gilles - Blangy sur Ternoise (62) >+33614461315 (40m)Municipal de la Source - Beaurainville (62) (01/01-31/12) >+33680321725 (17m)Le Manoir - Cavron Saint Martin (62) >+33650944962 (38m)La Pointe* - Berck (62) (01/04-31/10) >+33321096878 (6m)Ami-Ami ** - Berck (62) (01/04-30/09) >+33321090555 (8m)La ferme Le Verger - Campigneulles les Grandes (62) [<51] >+33633101677 (49m)Le Clair Vignon - Lespinoy (62) (01/03-31/10) >+33321814226 (11m)Mont Des Bruyeres - Saint Amand les Eaux (59) (15/03-31/10) >+33327485687 (34m)Parc d'Olhain** - Maisnil les Ruitz (62) (01/05-30/09) >+33321279480 (167m)l'Epy** - Merlimont (62) (02/04-18/10) >+33321947415 (10m)Les Jardins de la Mer** - Merlimont (62) (01/04-31/10) >+33321941818 (13m)La Gentilhommiere - Sameon (59) (01/04-30/10) >+33320615403 (19m)Municipal De la Biette - Divion [<51] (01/01-31/12) >+33321621588 (67m)La Fontaine des Clercs*** - Montreuil (01/01-31/12) >+33321060728 (13m)Le Blanc Pignon** - La Calotterie (62) (15/04-31/10) >+33321816026 (10m)Municipal De la Mer** - Cucq (62) (01/06-15/09) >+33321846060 (9m)La Foret** - Cucq (62) (01/04-30/09) >+33321947501 (9m)Le Chateau - Equirre (62) (15/04-11/10) >+33321046123 (102m)Le Bon Air - Sains les Pernes (62) [<51] (10/04-15/10) >+33321047726 (167m)Pomme de Pin*** - Cucq (62) (04/04-02/11) >+33321942855 (5m)Abri Cotier** - Cucq (62) (01/02-20/12) >+33321947104 (13m)Les Etangs Fleuris** - Attin (62) >+33321060101 (5m)Le Petit Clos - Rumegies (59) [<51] (01/04-31/10) >+33327267403 (26m)La ferme Le Chalet - Verchin (62) [<51] (20/04-01/09) >+33321416487 (108m)Les Saules - Aix (59) [<51] (01/04-01/11) >+33320618713 (30m)Des Poteries - Flines les Mortagne (59) (01/01-31/12) >+33327268526 (29m)Municipal Stoneham*** - Le Touquet Paris Pl. (07/02-11/11) >+33321051655 (9m)Le Paradis - Fruges (62) (04/04-12/10) >+33620687908 (119m)Municipal De La Pinede*** - Etaples (62) (15/02-15/12) >+33321943541 (20m)l'Etang des Sources - Matringhem (62) [<51] (01/03-31/10) >+33321415511 (81m)Au Vieux Moulin - Matringhem (62) [<51] >+33321044005 (81m)Municipal l'Etang - Violaines (62) [<51] >+33320294125 (18m)La Dune Blanche* - Camiers (62) (02/05-20/09) >+33321097848 (35m)Municipal** - Lillers (62) [<51] (01/01-31/12) >+33321023306 (22m)Les Dunes* - Camiers (62) (Easter-30/09) >+33321849177 (11m)Du Grand Sart - Sainghin en Melantoi (59) (01/01-31/12) >+33320411054 (30m)Du Baillons - Enquin sur Baillons (62) >+33321053097 (55m)La Carriere - Audincthun (62) (01/04-30/09) >+33321395570 (72m)Les Aulnes - Bezinghem (62) >+33321909388 (62m)Municipal Du Mont Saint Frieux - Dannes (62) (01/04-31/10) >+33321332476 (25m)Les Roses - Aubers (59) (01/04-31/10) >+33608101724 (20m)Des Sablonnieres - Aubers (59) [<51] (01/04-31/10) >+33320502033 (20m)Les Pommiers - Thiembronne (62) (15/03-15/10) >+33321395019 (106m)La Petite Foret - Aire sur la Lys (62) [<51] (01/04-15/10) >+33321936742 (19m)Les Peupliers - Fleurbaix (62) [<51] (15/04-15/10) >+33321656447 (16m)l'Etang - Mametz (62) [<51] (15/03-31/10) >+33603664342 (28m)Le Stade** - Samer (62) (01/04-31/10) >+33321839858 (71m)Le Chateau - Mametz (62) (01/01-31/12) >+33321390526 (25m)Le Tannay - Thiennes (59) [<51] (01/04-31/10) >+33328486414 (18m)Chateau d'Hardelot*** - Condette (01/04-31/10) >+33321875959 (27m)A la Ferme de Gerard Taffin - Merville (59) [<51] >+33328428089 (15m)La Liane - Questrecques (62) [<51] >+33321335196 (21m)Municipal De la Warenne* - St. Etienne au Mont (62) (01/04-30/09) >+33321913138 (69m)Le Paradiso - Steenbecque (59) (01/04-15/10) >+33328421508 (17m)Le Moulin*** - Remilly Wirquin (62) (01/01-31/12) >+33321930599 (53m)Municipal La Falaise*** - Equihen Plage (62) (01/04-03/11) >+33321312261 -CCA(38m)Ferme du Relais - Wittes (62) (01/01-31/12) >+33321392652 (26m)Les Cytises*** - Isques (01/04-15/10) >+33321311110 -CCA(11m)Naturist - Le Pont Charlet - Houplines (59) [<51] (01/04-15/10) >+33320354165 (18m)Du Blequin** - Nielles les Blequin (62) [<51] (01/04-01/11) >+33321396806 (69m)Le Chatelet - Blaringhem (59) [<51] >+33328432461 (19m)Les Alouettes - Houplines (59) (31/03-01/10) >+33320356942 (18m)Les Ramiers - Bondues (59) [<51] (01/05-15/10) >+33320231342 (21m)Les Huit Rues - Morbecque (59) (01/04-15/10) >+33328417160 (55m)La Papelutte - Blaringhem (59) [<51] (01/04-30/09) >+33328432045 (60m)Le Phare** - Le Portel (02/05-20/09) >+33321316920 -CCpg29(14m)Les Genets** - Helfaut (62) (01/04-30/09) >+33321938056 (83m)l'Hermitage** - Blendecques (62) (01/03-31/10) >+33321128778 (87m)La Becquerelle - Lynde (59) (01/03-30/11) >+33328432037 (62m)Municipal Les Sapins - La Capelle les Boulogne (62) [<51] (01/04-31/08) >+33321831661 (87m)A la ferme le Bois Groult - Henneveux (62) [<51] >+33321333216 (73m)A l'Oree du Bois - Ebblinghem (59) [<51] >+33328432325 (34m)Le Middel Straete - Pradelles (59) (15/03-15/10) >+33328486007 (32m)Le Bloemstraete - Renescure (59) [<51] (15/04-15/10) >+33680212846 (31m)Ferme de la Vausserie - Belle et Houllefort (62) [<51] >+33666219254 (46m)Municipal Beausejour - Arques (62) (01/04-31/10) >+33321885366 (4m)Le Napoleon** - Wimereux (62) [<51] (15/04-30/09) >+33321313089 (49m)Manoir de Senlecques - Pernes les Boulogne (62) [<51] >+33321833596 (27m)l'Ete Indien** - Wimereux (62) (01/01-31/12) >+33321302350 -CCA(34m)La Rabaude - Staple (59) [<51] (01/01-31/12) >+33328400328 (41m)Municipal Olympic** - Wimereux (62) (15/03-28/10) >+33321324563 -CCA(18m)A la ferme les Saules - Bailleul (59) [<51] >+33328491375 (57m)Le Relais de la Hem - Herbinghen (62) [<51] (01/04-31/10) >+33625760585 (97m)Le Paradis* - Salperwick (62) [<51] (01/04-31/10) >+33321952169 (6m)Le Clairmarais - Clairmarais (62) (01/02-15/12) >+33321383480 (8m)Mont Noir - Saint Jans Cappel (59) (01/01-01/12) >+33328494634 (143m)Le Canchy** - Licques (15/03-31/10) >+33321826341 (56m)Les Pommiers des Trois Pays*** - Licques (62) (15/03-31/10) >+33321350202 -CCA(68m)Le Fremont** - Serques (62) (01/04-15/10) >+33321398655 (21m)Les Marais - Tilques (62) [<51] (01/05-31/10) >+33321938896 (2m)l'Escale*** - Wacquinghen (01/04-15/10) >+33321320069 -CCA(64m)Aire naturelle Les Houblonnieres - Boeschepe (59) [<51] (15/04-15/10) >+33675006380 (61m)La Lansbergue - Tilques (62) [<51] >+33321932037 (1m)Le Vert Manoir** - Moulle (62) (01/04-31/10) >+33321958361 (8m)Val de Cassel - Zuytpeene (59) [<51] (01/04-31/10) >+33328424405 (27m)Les 5 Chemins Verts - Boeschepe (59) (15/03-31/10) >+33328494237 (91m)A la ferme les Piloteries - Hardinghen (62) [<51] >+33321850185 (65m)Les Bouleaux - Serques (62) [<51] >+33321937386 (2m)Les Ormes - Serques (62) (01/02-01/11) >+33689259913 (7m)La Chaumiere - Buysscheure (59) [<51] (01/04-30/09) >+33328430357 (21m)l'Oree Du Bois** - Landrethun les Ardres (01/04-30/09) >+33321826715 (87m)Bal Parc*** - Tournehem (62) (01/04-31/10) >+33321356590 (36m)l'Eglantier** - Ambleteuse (62) (01/04-31/10) >+33321326048 (24m)A la ferme Houpevent - Ambleteuse (62) [<51] >+33321326030 (60m)A la Ferme de Henri Westel - Buysscheure (59) [<51] (24m)Des Trolls - Marquise (62) (01/04-20/10) >+33321927155 (20m)Le Quenelet - Eperlecques (62) [<51] (01/04-30/09) >+33321939065 (30m)Le Beaucamp*** - Ambleteuse (01/01-31/12) >+33321326210 (66m)A la ferme Les Bles de Ferquent - Ambleteuse (62) [<51] >+33607297543 (62m)Le Chateau du Gandspette*** - Eperlecques (01/04-30/09) >+33321934393 -CCpg28(28m)Municipal Les Ajoncs** - Audresselles (62) (01/04-02/11) >+33321329740 (11m)Le Relax** - Nordausques (01/04-30/09) >+33321356377 (14m)A la ferme de Dutertre Pierre - Audresselles (62) [<51] >+33321329600 (14m)La Cabarette - Wulverdinghe (59) [<51] (01/03-31/10) >+33328484298 (54m)Le Moulin - Volckerinckhove (59) (01/04-31/10) >+33328680323 (33m)Saint Louis*** - Autingues (62) (01/04-18/10) >+33321354683 -CCA(33m)Municipal Du Musee*** - Audinghen (01/04-31/10) >+33321329722 (61m)La Houblonniere - Winnezeele (59) (01/04-31/10) >+33328409306 (25m)Aire naturelle de Allexandre - Audinghen (62) [<51] (01/04-30/10) >+33650413300 (61m)Les Primeveres** - Leubringhen (01/04-31/10) >+33321871333 (97m)La Source** - Balinghem (62) (15/04-31/10) >+33321822829 (5m)La Fregate*** - Ardres (62) (01/04-15/10) >+33321354492 (1m)Le St Antoine - Bollezeele (59) [<51] (01/04-15/10) >+33616945982 (31m)Le Courtil Rose - Bremes (62) (01/04-31/10) >+33321354291 (1m)La Bien Assise*** - Guines (62) (10/04-30/09) >+33321352077 -CCA(13m)La Paillote** - Balinghem (62) (01/04-15/10) >+33321822825 (1m)Le Ritouck* - Ruminghem (62) [<51] (01/04-30/09) >+33321823587 (1m)Les Pins** - Saint Inglevert (62) [<51] (01/04-30/09) >+33321872871 (116m)La Grise Pierre* - Ste. Marie Kerque (62) (01/04-31/10) >+33321857064 (1m)Le Vivier** - Ardres (62) [<51] (01/03-31/10) >+33321354508 (1m)Les Dondaines - Cappelle Brouck (59) [<51] (01/04-30/10) >+33603950568 (0m)Des Chenes - Houtkerque (59) [<51] >+33321930438 (18m)La Vallee*** - Hervelinghen (01/04-31/10) >+33321367396 (49m)Municipal De la Source** - Wissant (62) (15/03-15/11) >+33321359246 (11m)La P'tite Source - Hames Boucres (62) >+33618530269 (1m)La Belle Peche** - Hames Boucres (62) (01/05-31/10) >+33321352107 (1m)La Valle des Fleurs - Eringhem (59) [<51] (01/03-01/12) >+33328689529 (23m)Les Roses - Esquelbecq (59) [<51] (15/04-15/10) >+33328629009 (17m)Le Muchembled - Looberghe (59) [<51] >+33328688337 (0m)Les Epinettes** - Peuplingues (01/04-31/10) >+33321852224 (71m)Aire naturelle Les Erables - Escalles (62) [<51] (01/04-01/11) >+33321852536 (73m)La Colme - Looberghe (59) >+33328298414 (1m)Cap Blanc Nez** - Escalles (62) (15/03-15/11) >+33321852738 (36m)La Hutte - Pitgam (59) [<51] (05/04-30/09) >+33328621330 (1m)Les Prairies de la Colme - Looberghe (59) (01/04-31/10) >+33328220088 (0m)Les Noires Mottes*** - Sangatte (62) (15/03-15/11) >+33321820475 (3m)Fort Lapin*** - Bleriot Plage (62) (01/04-31/10) >+33321976777 (3m)La Gare* - Hondschoote (59) [<51] (01/01-31/12) >+33328683013 (4m)Les Tamaris - Oye Plage (62) [<51] (01/04-15/10) >+33321358330 (2m)Les Palominos - Marck (62) (01/02-21/12) >+33321829280 (4m)Bouscarel** - Oye-Plage (62) [<51] (01/01-31/12) >+33321367637 (4m)Les Argousiers** - Oye-Plage (62) (01/03-31/12) >+33321353278 (3m)Les Oyats**** - Oye-Plage (62) (01/05-30/09) >+33321851540 (5m)Le Casino** - Oye-Plage (62) (01/04-31/10) >+33321858305 (4m)Les Dunes - Oye Plage (62) (01/03-15/11) >+33321358765 (4m)Clairette** - Oye-Plage (62) (15/01-15/12) >+33321851540 (3m)De la Plage*** - Grand Fort Philippe (01/04-31/10) >+33328653195 (3m)Le Bois des Forts**** - Coudekerque (01/01-31/12) >+33328610441 (0m)Des Dunes - Gravelines (01/03-31/10) >+33328230980 (4m)Polder & Vacances - Les Moeres [<51] (10/03-31/10) >+33616996125 (-1m)Municipal La Licorne*** - Malo les Bains (01/04-30/11) >+33328692668 (8m)Les Tilleuls* - Bray Dunes (01/04-30/09) >+33328266154 (1m)Le Perroquet*** - Bray Dunes (01/04-30/09) >+33328583737 (4m)Municipal Les Dunes**** - Bray Dunes (01/03-31/12) >+33328266154 (5m) \ No newline at end of file diff --git a/GeoConverterTests/Files/Sample2.json b/GeoConverterTests/Files/Sample2.json new file mode 100644 index 0000000..9fd6598 --- /dev/null +++ b/GeoConverterTests/Files/Sample2.json @@ -0,0 +1 @@ +{"type":"LineString","coordinates":[[9.21024,41.37824],[9.16559,41.39272],[9.20129,41.3998],[9.17071,41.40625],[9.12695,41.4102],[9.17976,41.41778],[9.17913,41.41943],[9.04365,41.47272],[9.26296,41.47316],[9.04704,41.47606],[8.93818,41.50225],[9.01456,41.50253],[9.16488,41.53137],[8.96312,41.53384],[8.86293,41.5349],[9.29913,41.5477],[9.27609,41.57084],[9.29027,41.57327],[9.20068,41.58657],[9.3349,41.58798],[9.33173,41.58973],[9.35729,41.59377],[9.27437,41.59505],[9.26611,41.60192],[9.21232,41.61779],[8.95427,41.61982],[9.29885,41.62033],[9.29938,41.62165],[9.29965,41.62229],[9.30046,41.62338],[8.81389,41.62598],[8.81641,41.62808],[9.31423,41.62877],[9.3242,41.63103],[9.29329,41.63226],[9.29466,41.63407],[8.97475,41.64021],[9.27919,41.64126],[8.86679,41.6416],[9.32896,41.64466],[9.29422,41.64635],[9.36988,41.65864],[9.38026,41.66663],[9.30163,41.6721],[8.92004,41.68219],[8.92291,41.68373],[8.92519,41.68495],[9.37002,41.68537],[8.89035,41.69239],[9.33547,41.69361],[8.88343,41.69483],[8.88878,41.69553],[8.87775,41.69683],[9.34288,41.69708],[8.84421,41.69783],[8.89641,41.69809],[8.85782,41.70095],[8.83577,41.70293],[9.3509,41.70334],[8.79385,41.70972],[8.80485,41.71126],[8.79931,41.71156],[9.40194,41.71565],[8.8177,41.71598],[9.15084,41.7215],[8.7954,41.72558],[9.19481,41.75008],[9.09555,41.75705],[9.40442,41.76015],[9.17783,41.76864],[8.90375,41.77449],[9.39411,41.80024],[8.76469,41.8088],[8.78401,41.82846],[9.34244,41.844],[8.7973,41.85195],[9.39725,41.86553],[9.39613,41.87665],[8.80791,41.88412],[9.40005,41.89173],[8.82266,41.90717],[8.6854,41.90948],[8.82625,41.91107],[8.72851,41.93725],[9.39906,41.98638],[9.44222,41.99868],[9.43566,41.99905],[9.44722,41.99976],[8.70873,42.00404],[8.92354,42.02749],[9.19474,42.02816],[8.91322,42.02949],[8.75437,42.04133],[8.75446,42.047],[8.74942,42.04705],[8.73084,42.07012],[8.74323,42.07582],[8.7475,42.07937],[9.54953,42.11151],[8.81381,42.11389],[8.7054,42.13049],[9.15148,42.15311],[8.59794,42.16234],[8.78743,42.16505],[9.54401,42.16552],[9.5274,42.17007],[9.55472,42.20229],[9.34547,42.20855],[8.5861,42.21087],[9.31834,42.21151],[9.5553,42.21484],[9.55038,42.22168],[9.19382,42.22376],[9.54837,42.22566],[8.81666,42.25062],[8.72179,42.25364],[8.71021,42.26201],[8.70992,42.26282],[8.70072,42.26358],[9.1077,42.27573],[9.19032,42.28995],[9.14987,42.29974],[9.14788,42.3002],[9.1511,42.30116],[9.147,42.30446],[8.6461,42.30639],[9.54222,42.31518],[9.54472,42.32132],[9.5392,42.32877],[9.00925,42.33258],[9.00985,42.34856],[9.01018,42.34861],[9.5318,42.35485],[9.52983,42.36468],[2.53294,42.37609],[2.60633,42.38854],[9.17613,42.39114],[9.53154,42.39152],[2.49201,42.40297],[2.39808,42.40649],[2.46987,42.40753],[2.56563,42.40952],[9.53293,42.41041],[8.64483,42.41109],[9.53524,42.41145],[1.96675,42.41155],[8.69052,42.41279],[2.6173,42.41282],[8.94592,42.41488],[9.52274,42.42186],[9.20618,42.43099],[1.94478,42.43531],[9.44965,42.43577],[2.0342,42.43773],[1.94385,42.43879],[2.62442,42.43958],[9.52184,42.44008],[2.03195,42.44019],[2.02675,42.44218],[1.94236,42.45586],[3.16328,42.45644],[2.62577,42.45796],[1.91268,42.46019],[2.03521,42.46047],[2.03388,42.46422],[8.68238,42.46516],[9.53389,42.46519],[2.00665,42.46538],[2.65156,42.46664],[1.99884,42.46892],[2.57803,42.469],[9.12119,42.47011],[1.8808,42.47013],[9.12761,42.47261],[9.13467,42.47548],[9.53138,42.47587],[3.11932,42.47713],[2.80388,42.47862],[1.95693,42.47885],[2.67364,42.47912],[2.69479,42.48165],[9.27872,42.48231],[9.52762,42.48388],[2.75871,42.48421],[2.80728,42.48614],[9.52448,42.4872],[2.7023,42.4889],[2.76305,42.48981],[2.79774,42.49138],[2.78153,42.49192],[2.78159,42.49205],[2.79515,42.49235],[1.98509,42.49538],[8.79166,42.50252],[2.66863,42.5033],[2.01631,42.50387],[2.04671,42.50636],[2.82355,42.50658],[2.79488,42.50663],[2.76788,42.50794],[2.82727,42.50998],[2.78309,42.51037],[2.18194,42.51089],[2.63938,42.51466],[2.09712,42.51957],[2.84543,42.52128],[9.05097,42.52134],[2.94641,42.52372],[2.94412,42.52383],[2.93531,42.5254],[2.91405,42.52568],[2.89931,42.52848],[2.98744,42.52966],[3.07166,42.53141],[3.02706,42.53179],[2.86978,42.53214],[3.07657,42.5325],[3.052,42.53311],[2.31121,42.53313],[2.39767,42.53331],[3.06786,42.53353],[2.95594,42.5345],[2.96003,42.5348],[2.35972,42.537],[3.052,42.5388],[2.99517,42.54002],[2.9244,42.5409],[2.83431,42.54157],[2.38477,42.54416],[9.52268,42.54445],[3.04675,42.54657],[1.83468,42.54688],[3.04675,42.54693],[2.58691,42.54779],[3.03609,42.54823],[2.75342,42.54848],[3.04159,42.54972],[3.04181,42.55004],[3.04561,42.55015],[3.04423,42.55027],[3.043,42.5503],[3.03105,42.5506],[3.04622,42.55093],[3.04427,42.5515],[3.04455,42.55158],[3.04285,42.55169],[8.76429,42.55226],[8.75636,42.55229],[3.04343,42.55302],[8.76857,42.55364],[8.78881,42.55424],[2.37756,42.55506],[8.75486,42.55516],[8.75913,42.55541],[3.04227,42.55583],[2.38487,42.55636],[8.75526,42.55657],[8.75529,42.55663],[3.04074,42.55692],[3.02917,42.55709],[8.75613,42.55723],[3.03126,42.55779],[3.02024,42.56057],[2.35978,42.56233],[3.03462,42.56375],[2.3892,42.56454],[2.41967,42.56627],[2.99951,42.56697],[3.04415,42.56769],[3.01092,42.56832],[3.00345,42.56855],[3.03419,42.56987],[3.01254,42.57018],[3.00671,42.5702],[3.02933,42.57091],[2.9995,42.57095],[3.03125,42.57101],[3.04105,42.57243],[3.02172,42.57247],[3.02618,42.57258],[3.01458,42.5727],[3.02076,42.57294],[2.99696,42.57337],[3.04232,42.57552],[2.96467,42.57588],[2.3447,42.57614],[3.03671,42.57991],[3.033,42.5806],[2.10583,42.58199],[8.82209,42.58394],[8.84804,42.59035],[1.80417,42.5917],[2.98055,42.59209],[3.03764,42.59931],[2.39849,42.60316],[8.88457,42.60384],[8.86866,42.60639],[2.91644,42.60643],[2.99098,42.60695],[8.88773,42.60749],[8.87375,42.60863],[2.09106,42.60878],[8.8754,42.60892],[2.9836,42.61236],[2.81355,42.61495],[2.50148,42.61661],[3.01596,42.61864],[2.42284,42.62122],[8.94869,42.62334],[3.02592,42.62462],[3.00267,42.62569],[8.91595,42.62658],[9.01112,42.62738],[9.46737,42.62888],[8.95268,42.63116],[2.89818,42.63764],[9.01974,42.63797],[2.98407,42.63822],[2.53353,42.64273],[1.83095,42.64654],[2.96127,42.6497],[2.38926,42.65091],[9.06677,42.65382],[9.30014,42.66565],[2.70536,42.66822],[2.62901,42.67167],[2.98919,42.67228],[9.44495,42.67341],[9.29702,42.67354],[9.29205,42.67394],[9.28677,42.67403],[3.0312,42.6754],[2.99911,42.68893],[2.65785,42.69067],[9.32661,42.69355],[2.86587,42.69457],[2.0969,42.69518],[3.0339,42.70009],[2.99865,42.70108],[1.88338,42.70227],[3.0305,42.70675],[3.03543,42.70825],[3.03293,42.70909],[2.07612,42.71037],[3.03146,42.71393],[9.32976,42.71786],[9.33568,42.72021],[9.20258,42.72058],[1.89299,42.72425],[3.0331,42.72662],[-0.00744,42.72802],[3.02477,42.72841],[1.82539,42.72846],[2.44098,42.7285],[9.34244,42.72923],[1.81336,42.72988],[2.92227,42.73003],[3.03122,42.73276],[1.8539,42.73297],[2.5748,42.73471],[2.19921,42.7369],[3.03396,42.73926],[3.03363,42.74026],[9.46016,42.74156],[0.08057,42.75349],[1.76431,42.7593],[0.00132,42.75973],[1.48242,42.76342],[3.03159,42.76533],[3.02758,42.76543],[3.0269,42.76571],[2.66557,42.76577],[2.88339,42.76697],[3.03286,42.76757],[3.0282,42.7676],[3.02974,42.76773],[1.49249,42.76858],[1.67158,42.77252],[2.28498,42.7731],[1.70328,42.77444],[3.02098,42.77483],[3.02032,42.77528],[3.02293,42.77577],[3.02854,42.7764],[3.02477,42.77649],[0.60106,42.77666],[3.02759,42.77668],[1.76021,42.77764],[0.60012,42.77776],[3.02995,42.77867],[0.59814,42.78037],[3.0229,42.78117],[0.015,42.78241],[0.01463,42.7829],[3.01919,42.78609],[0.24694,42.78619],[3.02527,42.78624],[1.69162,42.78663],[0.23737,42.78878],[2.38673,42.78885],[1.17769,42.79035],[1.92488,42.79161],[1.69141,42.79213],[0.01726,42.7927],[1.33197,42.79402],[0.60796,42.79464],[0.40652,42.79659],[1.26374,42.7977],[1.58847,42.801],[0.0131,42.80167],[3.02681,42.80521],[2.50235,42.80762],[2.60579,42.80782],[2.25404,42.80795],[0.59768,42.80837],[0.52005,42.8093],[1.89122,42.81081],[1.25571,42.81117],[9.48586,42.81172],[2.37529,42.81175],[2.23876,42.81236],[1.58921,42.81358],[2.73979,42.8144],[0.32297,42.81549],[1.95098,42.81598],[0.59995,42.81651],[1.63449,42.81716],[0.40504,42.81739],[1.99531,42.81945],[0.60627,42.82235],[0.32957,42.82324],[2.02098,42.82357],[0.31884,42.82545],[0.33598,42.82738],[0.00159,42.83168],[2.90424,42.83341],[0.40694,42.83739],[0.33912,42.83803],[9.4735,42.83897],[1.61176,42.83978],[2.92664,42.84357],[0.33857,42.84489],[9.44027,42.84733],[0.34664,42.8481],[3.04042,42.84917],[2.46962,42.8525],[0.60215,42.85362],[1.58803,42.85583],[1.59791,42.85669],[0.34097,42.86384],[0.3607,42.86388],[-0.00254,42.86976],[1.20994,42.87018],[0.73629,42.87122],[1.20556,42.87136],[1.62217,42.87159],[1.22058,42.87216],[-0.01523,42.8724],[-0.00216,42.87334],[0.00305,42.87352],[2.17555,42.87359],[0.00555,42.87452],[0.95767,42.87515],[-0.55656,42.87684],[1.54977,42.87685],[-0.00826,42.87771],[-0.01079,42.87976],[1.89496,42.88068],[-0.02233,42.88221],[-0.01351,42.88275],[2.71613,42.88353],[0.34846,42.88441],[9.47178,42.88637],[1.34446,42.88816],[1.25566,42.88864],[2.7239,42.89005],[1.34939,42.89191],[1.31218,42.89206],[1.21333,42.8926],[2.1046,42.89302],[1.79354,42.89399],[-0.1126,42.89435],[0.05743,42.89458],[-0.11223,42.89637],[-0.02707,42.8965],[-0.11491,42.89733],[-0.02782,42.89771],[1.31432,42.89775],[-0.11243,42.89963],[0.35458,42.90099],[3.05302,42.90116],[-0.1084,42.90217],[-0.10605,42.90254],[3.05162,42.90301],[-0.10713,42.90328],[-0.21208,42.90441],[1.83271,42.90457],[1.93752,42.90841],[0.36617,42.9086],[0.69119,42.91003],[-0.09887,42.9112],[0.69297,42.91231],[2.31839,42.91364],[0.6396,42.91403],[2.99876,42.91428],[2.04419,42.91578],[-0.18907,42.91673],[1.02929,42.92046],[2.21948,42.92051],[1.84487,42.92351],[0.36636,42.92476],[-0.64215,42.92775],[0.20463,42.93056],[1.63875,42.93094],[0.91934,42.93151],[2.22431,42.93255],[3.03081,42.93442],[-0.17857,42.93716],[-0.1775,42.94134],[0.27939,42.94274],[3.03048,42.94364],[0.85413,42.94484],[2.37351,42.94649],[1.95785,42.95201],[1.07838,42.95418],[-0.21204,42.95422],[1.17694,42.95693],[2.99563,42.95794],[-0.2098,42.958],[-0.20523,42.95842],[9.35398,42.95893],[-0.20647,42.95991],[-0.0791,42.96148],[-0.19622,42.96205],[-0.33889,42.96214],[1.51491,42.96419],[9.44817,42.96437],[-0.20072,42.96538],[0.24515,42.96706],[-0.38141,42.96944],[1.57284,42.97077],[0.37679,42.97197],[0.61847,42.97221],[2.9979,42.97252],[-0.18501,42.97344],[-0.18405,42.97349],[1.16653,42.97395],[-0.07528,42.97402],[0.22946,42.97419],[2.00275,42.97433],[-0.16532,42.97459],[0.2282,42.97645],[0.22859,42.97665],[-0.60558,42.97672],[1.66031,42.97893],[1.5511,42.97923],[-0.16544,42.9793],[-0.41395,42.98027],[-0.15965,42.98041],[1.97001,42.98063],[-0.41943,42.98083],[-0.06467,42.9812],[-0.15538,42.98139],[-0.41745,42.98251],[-0.42372,42.9839],[1.93509,42.98411],[-0.10564,42.98555],[-0.10872,42.98635],[1.99194,42.98645],[-0.08864,42.98658],[-0.43091,42.98729],[-0.08942,42.98812],[1.61556,42.98929],[-0.42156,42.99011],[2.07213,42.991],[0.69446,42.99119],[-0.131,42.99129],[-0.12837,42.99189],[-0.07158,42.99195],[-0.09363,42.99233],[1.67852,42.99278],[-0.41893,42.99378],[2.25571,42.99483],[-0.1205,42.99514],[1.30505,42.99629],[1.87191,42.99742],[-0.09174,42.9979],[3.04105,42.99798],[3.04935,42.99808],[-0.60435,42.99817],[0.37892,43.00001],[2.82079,43.0004],[1.44542,43.00181],[-0.42041,43.00332],[1.73,43.00575],[1.63138,43.00689],[1.18415,43.00733],[0.18777,43.00742],[0.79681,43.00955],[-0.07822,43.01127],[1.9251,43.01147],[-0.0972,43.01207],[-0.11255,43.01289],[3.04578,43.01494],[0.71058,43.01544],[1.97429,43.01544],[-0.86129,43.01654],[-0.09671,43.01741],[-0.95161,43.01747],[-0.41691,43.01776],[0.17595,43.018],[-0.092,43.0188],[-0.42043,43.02085],[6.43814,43.02107],[2.97698,43.0246],[0.16976,43.02604],[0.60923,43.02794],[0.57859,43.02827],[-0.10423,43.02962],[6.15592,43.02964],[1.00021,43.02987],[1.93728,43.03129],[-0.07491,43.03142],[-0.07138,43.03504],[-0.07091,43.03553],[0.32051,43.03631],[6.14878,43.03893],[6.1472,43.03956],[6.10333,43.03958],[6.14314,43.04082],[6.12807,43.04144],[6.14612,43.04469],[1.63201,43.04712],[0.81381,43.04723],[2.2228,43.04734],[0.15893,43.05257],[1.34185,43.05445],[0.16517,43.05595],[6.14784,43.05603],[-0.04107,43.05775],[1.62142,43.06253],[-0.42428,43.06321],[2.94088,43.0663],[-0.4159,43.06666],[-0.87667,43.06775],[0.55353,43.069],[5.87584,43.07037],[0.1563,43.07125],[5.85762,43.07164],[0.48031,43.07171],[5.82462,43.07243],[1.37192,43.07398],[0.16869,43.07487],[-0.54314,43.07487],[5.81165,43.07817],[1.47112,43.07859],[0.9498,43.0787],[1.37822,43.07878],[0.16733,43.07944],[0.67622,43.08015],[0.13985,43.08031],[0.15114,43.08168],[-0.42044,43.0829],[0.1557,43.08299],[6.12472,43.0837],[-0.04319,43.08551],[0.28087,43.0859],[0.55418,43.08597],[6.02875,43.08677],[6.02868,43.08706],[0.13227,43.08721],[1.88657,43.08885],[-0.41058,43.08939],[6.12783,43.09014],[0.54094,43.09021],[0.55383,43.09176],[6.05689,43.09254],[-0.37093,43.09265],[6.13963,43.09301],[-0.02164,43.09326],[6.13609,43.09348],[6.16351,43.09354],[0.12292,43.09364],[2.61831,43.09526],[-0.07463,43.09561],[-0.04297,43.09695],[-0.06986,43.09773],[-0.72215,43.09854],[2.37945,43.09921],[6.03111,43.09939],[6.16854,43.09993],[-0.14195,43.10094],[6.16944,43.10096],[-0.12871,43.10153],[-0.0277,43.10236],[-0.05845,43.10257],[3.08478,43.10267],[5.8504,43.10361],[6.01633,43.10365],[-0.13973,43.10371],[-0.03315,43.10443],[-0.06792,43.10454],[6.00812,43.1047],[-0.03447,43.10497],[0.32352,43.10544],[-0.42332,43.10587],[1.5372,43.10714],[6.04309,43.10715],[6.049,43.108],[-0.91113,43.10819],[6.13901,43.10898],[-0.06261,43.10912],[-0.88192,43.10915],[5.85375,43.10943],[0.70811,43.10998],[5.85313,43.11019],[6.17957,43.11091],[-0.86363,43.11158],[0.04928,43.11197],[6.17794,43.112],[5.83045,43.11297],[-0.03663,43.11426],[-0.07531,43.11434],[6.05613,43.11436],[6.09588,43.11487],[6.09461,43.11524],[-0.03152,43.11559],[5.83828,43.11615],[6.23625,43.11721],[2.73609,43.11727],[6.35128,43.11773],[0.31314,43.11844],[-0.37806,43.11846],[-0.05006,43.11848],[-0.61236,43.11848],[6.18628,43.11858],[6.24691,43.11861],[3.06677,43.11865],[1.79411,43.11871],[6.16011,43.1192],[6.18464,43.1205],[-0.73258,43.12124],[6.23543,43.1219],[-0.77433,43.12191],[6.06954,43.12232],[6.18721,43.12284],[6.3506,43.12296],[5.78796,43.12366],[6.33145,43.12395],[6.35106,43.1242],[2.26109,43.12429],[-0.30889,43.12455],[-0.46234,43.12484],[1.60212,43.12489],[6.20544,43.12678],[5.9951,43.12825],[6.24224,43.12843],[1.53003,43.12885],[-0.20668,43.12966],[6.21661,43.13008],[6.34926,43.13015],[5.81494,43.13155],[3.13929,43.13225],[6.32848,43.13346],[6.35324,43.13397],[0.93077,43.13432],[6.35132,43.13514],[6.35435,43.13614],[3.0256,43.13658],[-0.02726,43.13678],[1.44385,43.13791],[2.70272,43.1388],[1.12486,43.13885],[6.34951,43.14128],[-0.91574,43.14259],[3.14421,43.14338],[-0.8883,43.14342],[6.38087,43.14463],[3.14222,43.14507],[3.00403,43.14691],[6.26307,43.15014],[2.72391,43.15086],[-0.44509,43.15163],[5.71511,43.15179],[6.1289,43.15288],[5.74584,43.15313],[-0.68603,43.155],[-0.59478,43.15561],[6.10291,43.15623],[6.44804,43.15633],[6.30821,43.15696],[2.2935,43.15852],[5.72933,43.1596],[3.16238,43.15996],[-0.82699,43.16019],[6.43417,43.16032],[6.1056,43.16058],[-0.68723,43.16112],[-1.23646,43.1613],[6.43544,43.16175],[6.3214,43.16252],[2.68629,43.16293],[2.89167,43.16303],[1.84469,43.16389],[-1.19364,43.1654],[2.03733,43.16582],[-1.24507,43.16613],[3.03815,43.1664],[-1.21561,43.16698],[6.51942,43.167],[-1.23471,43.16739],[1.52311,43.1695],[6.53001,43.16962],[6.52129,43.17052],[0.00165,43.17065],[0.07984,43.17192],[6.52493,43.172],[5.6958,43.1724],[-1.25416,43.17304],[1.41018,43.17305],[-1.216,43.17736],[-1.25971,43.17748],[2.01701,43.17763],[0.97459,43.17847],[-0.62373,43.17867],[2.37035,43.17918],[6.51656,43.18241],[-1.33569,43.1837],[6.0636,43.18493],[5.60733,43.18531],[6.06136,43.18666],[3.19863,43.18702],[5.65811,43.18737],[0.24137,43.18764],[5.64506,43.18925],[5.63699,43.19014],[-1.25364,43.19077],[1.60313,43.19103],[1.01681,43.19144],[1.45689,43.19206],[0.37393,43.19209],[6.63558,43.19283],[1.64732,43.19379],[6.55513,43.19437],[1.40613,43.19668],[1.06731,43.19702],[2.14493,43.19752],[2.35366,43.20021],[5.73814,43.20199],[-0.93935,43.20203],[-0.26094,43.20442],[2.75198,43.20486],[1.26959,43.20489],[6.65104,43.20528],[3.21095,43.20598],[6.63926,43.20646],[2.44179,43.20668],[-0.89722,43.2079],[-1.06947,43.20932],[1.44654,43.20951],[0.59616,43.2115],[6.64406,43.21283],[6.64132,43.21358],[0.89145,43.21376],[2.47027,43.2148],[3.23185,43.21525],[-0.47611,43.21775],[5.75865,43.21831],[6.57781,43.21852],[5.62844,43.22065],[0.62887,43.22409],[5.54149,43.22417],[3.24215,43.22614],[0.78889,43.22625],[3.24371,43.22727],[3.24524,43.22835],[3.24601,43.22869],[-0.50252,43.22919],[3.2487,43.22993],[3.25361,43.23107],[6.00179,43.23121],[6.00717,43.23186],[6.65924,43.23198],[-1.27985,43.232],[3.25746,43.23273],[6.16164,43.23375],[3.26044,43.23378],[6.61324,43.23514],[3.26864,43.2355],[1.41931,43.23562],[3.26833,43.23586],[6.31076,43.23615],[3.26234,43.23708],[3.11063,43.23821],[-1.20599,43.23869],[6.5734,43.24073],[3.07577,43.24128],[6.65661,43.24231],[-0.70336,43.24611],[1.6443,43.24928],[1.68252,43.24976],[3.29087,43.25027],[1.5789,43.25223],[0.52083,43.25224],[3.29164,43.25322],[5.75393,43.2535],[3.28861,43.25416],[5.98378,43.25695],[6.51763,43.2577],[3.28329,43.25792],[2.18759,43.25915],[2.36512,43.25996],[2.95552,43.26009],[3.32179,43.26113],[3.3233,43.26164],[0.52055,43.26265],[3.32042,43.26347],[3.32137,43.26387],[6.53445,43.26416],[3.29496,43.26426],[6.58114,43.26488],[6.53812,43.26533],[-1.33776,43.26614],[3.33032,43.26719],[-0.68446,43.26739],[3.33471,43.26746],[2.16319,43.26818],[3.2305,43.26863],[3.33249,43.26893],[3.33981,43.26916],[3.28515,43.26916],[3.33105,43.26965],[6.57314,43.26996],[1.17962,43.27002],[3.08976,43.27054],[3.32939,43.27115],[6.50377,43.27265],[6.56007,43.27589],[5.9705,43.27661],[3.47844,43.27855],[3.48153,43.27944],[-1.17973,43.27958],[6.56343,43.27965],[3.36339,43.27997],[3.36418,43.28015],[3.46036,43.28056],[6.5826,43.2808],[6.58614,43.28205],[3.37115,43.28219],[-0.24643,43.28248],[2.44146,43.28298],[0.65726,43.28325],[2.82679,43.28368],[6.59156,43.28397],[3.51948,43.2851],[6.57956,43.28522],[3.37408,43.28609],[3.47839,43.28667],[3.44252,43.28671],[2.88818,43.2868],[3.39412,43.28709],[3.39452,43.28722],[3.36218,43.28758],[3.47345,43.28804],[3.47057,43.28806],[3.4627,43.28815],[3.47319,43.28836],[-0.26889,43.28862],[3.46328,43.2897],[-1.57974,43.28997],[3.44778,43.28998],[3.39836,43.29025],[3.40396,43.29082],[3.37291,43.29087],[5.62075,43.291],[3.41887,43.29101],[3.41332,43.29134],[-1.50361,43.29142],[3.41623,43.29185],[6.49228,43.29188],[3.40718,43.29254],[3.39961,43.29257],[3.40066,43.29264],[3.26667,43.2929],[0.51684,43.2931],[0.63958,43.29361],[3.45026,43.29434],[3.45399,43.29468],[-1.22541,43.29497],[3.44982,43.29629],[3.47696,43.2964],[-0.54394,43.29643],[3.39969,43.29671],[3.52778,43.29732],[-0.88672,43.29741],[2.22221,43.29778],[3.42005,43.29779],[3.45639,43.29807],[3.41721,43.29812],[0.74169,43.29826],[5.53642,43.29832],[2.67294,43.29874],[-0.14611,43.30036],[-1.58788,43.30206],[3.42173,43.30217],[1.78642,43.30274],[3.4634,43.30333],[3.53803,43.30583],[3.5393,43.3064],[3.54332,43.30725],[3.50214,43.30748],[3.5406,43.30788],[-1.50178,43.30918],[3.54231,43.30926],[3.546,43.30978],[3.50948,43.3098],[3.54481,43.3103],[3.5432,43.31035],[3.49879,43.31083],[3.54287,43.31134],[3.54481,43.31169],[3.49242,43.31221],[3.36335,43.31241],[3.54678,43.31257],[3.54793,43.31373],[0.3019,43.31381],[3.38281,43.31398],[3.5373,43.31454],[3.54895,43.31492],[1.80176,43.31542],[2.86938,43.3158],[0.36716,43.3162],[3.54548,43.31676],[3.28449,43.31677],[2.01384,43.31742],[3.1434,43.31841],[6.09607,43.31887],[3.55659,43.31911],[-0.56784,43.31988],[3.55019,43.32004],[-0.7616,43.32016],[6.62057,43.32024],[1.93639,43.32055],[-0.45113,43.32062],[3.53583,43.32095],[3.55932,43.32158],[2.52613,43.32372],[0.99077,43.32504],[-1.44265,43.32529],[6.62246,43.32537],[3.4825,43.32676],[2.77453,43.32712],[3.03837,43.32752],[3.54699,43.32794],[-1.02951,43.32969],[5.13515,43.32997],[5.08036,43.33036],[5.07613,43.33052],[6.66737,43.33054],[5.05661,43.33072],[5.07356,43.33191],[0.68134,43.33202],[2.37136,43.33301],[-1.68458,43.33391],[5.06949,43.33433],[5.06744,43.33513],[6.55756,43.33534],[-1.692,43.3359],[6.16658,43.33806],[2.3265,43.33828],[-1.40104,43.33869],[6.1258,43.33909],[2.2521,43.33924],[0.53451,43.33957],[-1.46992,43.33974],[3.58185,43.34032],[2.15029,43.34038],[2.70805,43.3416],[1.48062,43.34219],[-1.70188,43.34229],[-1.55077,43.34391],[0.36977,43.3446],[-1.61698,43.34571],[-0.0136,43.34805],[-0.26262,43.34954],[6.17728,43.35172],[-1.44955,43.35337],[-1.63095,43.35408],[1.64827,43.35557],[-1.41477,43.35576],[2.31861,43.35621],[-1.6358,43.35723],[-1.57474,43.35738],[6.32778,43.35838],[-1.48309,43.35951],[-1.53076,43.35981],[1.77571,43.36041],[5.79226,43.36082],[2.16082,43.36146],[3.31919,43.36252],[-1.5664,43.36289],[6.71172,43.36618],[2.68236,43.36656],[-1.74645,43.36808],[-1.74741,43.36843],[3.43031,43.36909],[1.64299,43.36935],[-1.68612,43.37026],[-1.74627,43.37084],[-1.39778,43.37138],[2.24303,43.37141],[-1.75582,43.37287],[-1.75951,43.37355],[-1.7624,43.37361],[-1.31047,43.37468],[3.00909,43.3755],[-1.73293,43.37665],[-1.73905,43.3767],[2.07452,43.37694],[5.78802,43.37697],[2.30929,43.37956],[-1.69092,43.37967],[-0.85249,43.38043],[-1.31525,43.38149],[-1.69648,43.38252],[3.51808,43.38324],[0.97019,43.38453],[3.42257,43.3878],[0.15552,43.3885],[1.8282,43.38987],[6.72639,43.39162],[-1.45181,43.3923],[-1.69334,43.39348],[-0.94358,43.39526],[3.54818,43.39773],[3.37338,43.39849],[6.67535,43.39866],[5.7261,43.40034],[-1.64113,43.40126],[2.43992,43.40189],[-0.27392,43.40228],[3.53693,43.40499],[-1.64183,43.40556],[6.07834,43.4057],[-1.63727,43.40627],[-1.64158,43.40676],[1.1,43.40683],[6.70909,43.40694],[5.36173,43.40695],[1.10111,43.40785],[2.08669,43.40791],[-1.63622,43.40823],[6.70875,43.40893],[6.72461,43.40907],[6.68696,43.40927],[6.70801,43.41052],[6.69197,43.41092],[-1.62424,43.41259],[6.71053,43.41291],[1.96821,43.41295],[-1.61688,43.4136],[-1.62649,43.41426],[-1.62662,43.415],[-1.61674,43.41539],[6.70538,43.41596],[-1.62384,43.4163],[-1.62519,43.41659],[4.97412,43.41681],[6.70318,43.41736],[6.84816,43.41751],[-1.62398,43.41801],[-1.62097,43.41834],[-1.6232,43.41861],[6.85703,43.42003],[2.93398,43.42093],[6.33695,43.42148],[2.04564,43.4217],[4.9781,43.42256],[3.54004,43.42382],[3.31043,43.42429],[6.22327,43.42565],[5.18381,43.4271],[0.61158,43.42743],[-1.59915,43.42757],[3.75602,43.4276],[5.86492,43.42876],[0.58516,43.42914],[3.75966,43.42948],[6.65999,43.42991],[3.75915,43.42995],[3.75967,43.43],[3.61073,43.43008],[2.01881,43.43077],[2.17179,43.43086],[1.43529,43.4312],[-1.59742,43.43124],[3.36581,43.43129],[6.69063,43.43222],[2.81391,43.4325],[6.86849,43.43298],[3.43294,43.43376],[-1.59074,43.43397],[6.85267,43.43414],[2.01663,43.43437],[-1.58235,43.43523],[-1.56771,43.4366],[6.89158,43.43737],[2.85262,43.43744],[6.88999,43.43753],[-1.5819,43.43821],[-1.5827,43.43837],[6.65645,43.43876],[3.7903,43.43942],[3.79157,43.4399],[3.68311,43.44098],[6.42766,43.44116],[6.85128,43.44138],[6.72319,43.44173],[3.41757,43.44203],[-0.10257,43.44203],[5.62952,43.44221],[3.55169,43.44244],[6.75221,43.44257],[0.75445,43.44323],[3.68065,43.44483],[3.61568,43.44517],[6.65797,43.44541],[3.79839,43.44546],[6.72678,43.44549],[-1.58225,43.4456],[6.80686,43.44643],[6.47362,43.44656],[2.73794,43.44703],[0.31595,43.44853],[6.7284,43.44951],[3.80582,43.4498],[4.40173,43.44999],[3.66564,43.45046],[1.59431,43.45052],[6.74782,43.45075],[6.6337,43.45097],[6.727,43.45161],[3.5153,43.45166],[0.7398,43.45172],[3.04564,43.45185],[3.69241,43.4522],[-0.92029,43.45263],[-1.57346,43.45301],[3.68809,43.45357],[3.4162,43.45391],[6.83275,43.45413],[2.52668,43.45435],[2.06953,43.45446],[2.01526,43.45463],[-1.57611,43.45464],[4.43579,43.4558],[6.71669,43.45704],[6.73767,43.45722],[6.69341,43.45919],[-0.61643,43.45976],[6.59899,43.45992],[5.22988,43.46191],[-1.567,43.46218],[6.54366,43.46231],[6.6576,43.46336],[6.72544,43.46382],[6.72423,43.46402],[-1.53225,43.4641],[6.69578,43.46474],[6.72389,43.46566],[4.99861,43.46625],[3.42406,43.46641],[0.03197,43.4665],[6.54905,43.46711],[5.01925,43.46813],[6.59183,43.4683],[6.54853,43.46841],[3.80553,43.46842],[5.02215,43.46885],[5.22993,43.4691],[-0.14621,43.46962],[6.67876,43.46971],[6.64648,43.47266],[-0.80793,43.47313],[6.18868,43.47368],[3.34345,43.47458],[-0.93824,43.47633],[2.65768,43.47776],[6.63878,43.47789],[5.54508,43.47904],[2.14546,43.48018],[2.48656,43.48051],[2.69882,43.48085],[3.48961,43.48193],[3.77328,43.48203],[6.08057,43.48322],[0.37754,43.4838],[6.72036,43.48384],[6.71678,43.48455],[3.79875,43.48575],[1.53221,43.48669],[-0.75886,43.48741],[3.6919,43.48857],[0.92924,43.48879],[6.53916,43.48957],[2.78485,43.49004],[3.77932,43.49173],[-1.29645,43.49183],[-1.27932,43.4936],[0.57962,43.49416],[2.39081,43.49645],[3.56665,43.49715],[3.0279,43.49744],[3.787,43.5005],[0.68616,43.50213],[4.14445,43.50484],[4.14092,43.50514],[4.12852,43.50637],[1.37635,43.50813],[4.14509,43.50883],[1.21329,43.51009],[4.14604,43.51191],[2.75322,43.51205],[5.47176,43.51277],[0.4091,43.51364],[5.47431,43.51538],[5.54123,43.51736],[6.47862,43.5177],[-0.14748,43.51848],[4.40686,43.52172],[2.82995,43.52193],[4.14941,43.52207],[6.93155,43.52218],[4.14918,43.52287],[4.14895,43.52313],[5.00595,43.52358],[-1.41205,43.52446],[1.74685,43.52547],[6.93334,43.52553],[5.09365,43.52617],[5.68242,43.52741],[6.84,43.5287],[6.92997,43.53092],[-1.06444,43.53126],[0.6504,43.53187],[0.16637,43.53235],[3.9482,43.53346],[1.78602,43.53405],[6.94329,43.53517],[3.95527,43.53597],[3.18594,43.53628],[6.70556,43.53629],[6.14798,43.53681],[3.87038,43.53826],[3.96038,43.53855],[6.94266,43.53916],[3.74749,43.54107],[-1.13135,43.54141],[6.92301,43.54169],[0.7077,43.54273],[-1.10702,43.54299],[3.41742,43.54496],[6.4394,43.54569],[3.3798,43.54744],[3.89497,43.54778],[-1.47251,43.54816],[-1.40419,43.54838],[-0.05633,43.54963],[3.89462,43.54977],[3.99447,43.55073],[0.31382,43.55236],[6.56197,43.55247],[6.29796,43.55342],[3.89389,43.55407],[4.10706,43.5543],[-1.39356,43.55547],[-1.36197,43.55559],[6.28738,43.55565],[6.96068,43.55609],[-1.13832,43.55628],[2.91278,43.55903],[0.17564,43.55971],[2.97359,43.56111],[4.15878,43.56283],[4.07282,43.56311],[6.96587,43.56341],[4.07307,43.56361],[4.07533,43.56453],[6.97765,43.56469],[-1.45246,43.56502],[4.07396,43.56649],[-1.36341,43.56653],[6.22672,43.56655],[4.07595,43.56688],[4.07593,43.56709],[0.32232,43.56768],[3.24626,43.56845],[5.07151,43.56941],[-1.46033,43.5695],[4.21898,43.57261],[6.18827,43.57309],[-1.4705,43.57385],[6.53191,43.57525],[3.92577,43.57621],[3.06899,43.57626],[0.29087,43.57732],[0.25582,43.57969],[-0.92996,43.58233],[6.98895,43.58256],[6.94193,43.58421],[6.68986,43.58431],[6.66627,43.58487],[0.41305,43.58544],[6.69694,43.58566],[2.71412,43.58634],[6.66936,43.58707],[6.71405,43.58756],[6.9385,43.58837],[-0.7427,43.58848],[3.90182,43.5894],[6.92264,43.5902],[6.88044,43.59258],[3.51365,43.59363],[-1.32754,43.59432],[2.72442,43.59465],[-1.45668,43.5951],[-1.45625,43.59553],[-1.45664,43.5956],[-1.46257,43.59593],[-1.46118,43.59625],[2.60767,43.59709],[-1.23055,43.59912],[3.08268,43.60063],[2.68639,43.60126],[2.63602,43.60131],[2.6852,43.60172],[-1.45682,43.60229],[6.77534,43.60282],[-1.1301,43.60332],[6.65199,43.60376],[2.7043,43.60379],[5.75538,43.60425],[2.70126,43.60513],[7.11261,43.60531],[1.37671,43.6058],[2.77927,43.6065],[6.90242,43.60653],[6.74845,43.60661],[6.77125,43.60684],[6.77876,43.60694],[6.89913,43.60775],[0.05363,43.60778],[2.47176,43.60854],[7.12401,43.60903],[-1.31324,43.60925],[-1.25972,43.60976],[6.72076,43.60988],[-0.99172,43.60997],[7.12561,43.61063],[7.11683,43.61096],[7.11687,43.61111],[4.21005,43.61134],[7.1235,43.61155],[7.123,43.61181],[7.11749,43.61198],[7.12561,43.61242],[7.00727,43.61324],[3.49234,43.61437],[2.80041,43.6158],[1.07803,43.6159],[7.12304,43.61615],[7.11355,43.61722],[7.12571,43.61957],[7.11075,43.61984],[2.09392,43.62039],[2.25397,43.62059],[7.1244,43.62068],[4.90027,43.62138],[3.30892,43.62148],[3.29509,43.62157],[-1.44039,43.62198],[2.71529,43.62297],[6.22891,43.62389],[3.56751,43.62395],[6.21741,43.62461],[4.74963,43.62512],[7.12961,43.6256],[2.67919,43.62739],[7.12748,43.62758],[7.12825,43.62951],[-1.43281,43.63058],[2.49274,43.63079],[7.12975,43.63103],[2.41213,43.63229],[2.77221,43.6333],[6.75744,43.63368],[6.94947,43.6348],[7.12888,43.63559],[-0.38193,43.63585],[0.58833,43.636],[6.20766,43.63616],[7.13143,43.63737],[4.80588,43.6377],[4.74048,43.63786],[6.06074,43.63869],[5.27523,43.63974],[3.4952,43.64062],[5.93537,43.64156],[7.13796,43.64189],[5.45845,43.64382],[3.38991,43.64556],[-1.21385,43.64673],[-1.39411,43.6475],[2.77942,43.64763],[3.32244,43.64839],[4.70507,43.64843],[0.63346,43.64922],[6.06063,43.64961],[-0.59175,43.65029],[3.30929,43.65048],[3.89601,43.65134],[4.06645,43.65166],[6.80177,43.65212],[3.54042,43.65393],[1.85177,43.65398],[0.18692,43.65406],[4.29566,43.65444],[2.78889,43.65552],[1.41562,43.65593],[4.14138,43.65671],[7.12197,43.65682],[6.99229,43.65894],[0.73439,43.65929],[4.65441,43.65934],[3.32098,43.6598],[7.10256,43.66004],[3.33509,43.66013],[2.28685,43.66017],[6.15091,43.66031],[4.47369,43.66154],[3.55905,43.66192],[3.02843,43.66258],[1.97129,43.66299],[2.04444,43.66732],[3.21397,43.66761],[4.64463,43.66997],[3.35579,43.67029],[7.13879,43.67112],[4.14774,43.67154],[2.41572,43.67176],[3.17297,43.67339],[5.84715,43.67369],[3.56489,43.67451],[-1.11256,43.67486],[4.42937,43.67556],[7.1703,43.67575],[-1.35561,43.6762],[3.09481,43.67789],[5.06482,43.67826],[7.12596,43.67898],[2.38538,43.67908],[-1.06264,43.67954],[4.91806,43.68047],[4.21377,43.6809],[7.0833,43.68179],[-1.14944,43.68203],[7.09674,43.68211],[7.07302,43.68426],[2.85673,43.68488],[1.18433,43.68534],[1.00238,43.68571],[4.15224,43.68661],[-1.14673,43.68691],[7.15549,43.68729],[-1.03921,43.68838],[7.07172,43.68844],[7.15693,43.68916],[5.52515,43.68995],[-1.23401,43.68995],[7.15652,43.69015],[6.10721,43.69071],[6.86476,43.6912],[3.35069,43.69192],[-0.37346,43.69201],[2.73792,43.69277],[0.07539,43.6928],[3.17002,43.69325],[4.25059,43.69401],[3.99599,43.69419],[-1.42963,43.69481],[5.91902,43.69515],[5.91245,43.69574],[7.14314,43.69587],[-0.13803,43.69699],[6.04049,43.69754],[7.14119,43.69885],[7.00809,43.69902],[-0.42313,43.69966],[4.8577,43.69989],[-1.01429,43.7014],[6.99528,43.70162],[-1.01521,43.70183],[-1.33224,43.70209],[-0.2579,43.70271],[7.05061,43.70516],[-1.07054,43.70615],[5.50724,43.70633],[-1.02153,43.70883],[6.19523,43.71046],[6.0579,43.71061],[-1.01026,43.71186],[-1.07303,43.71202],[7.09001,43.71209],[3.32182,43.71217],[0.56462,43.71276],[6.18642,43.71371],[5.24609,43.71375],[7.17749,43.71463],[6.19266,43.71486],[6.49858,43.71569],[-1.35205,43.71583],[-1.01326,43.71616],[4.16703,43.71689],[2.33931,43.71942],[5.3549,43.71949],[5.19441,43.71991],[-1.09377,43.72056],[5.16033,43.72082],[5.30223,43.72083],[5.20496,43.72097],[4.80934,43.72107],[5.43134,43.72107],[6.18635,43.72146],[6.18198,43.72182],[7.33577,43.72308],[6.17865,43.72312],[6.09402,43.72326],[4.71898,43.7234],[6.62633,43.72343],[6.18294,43.72348],[-1.41365,43.72386],[0.25769,43.72483],[-1.42171,43.72488],[-1.12302,43.7268],[-0.83631,43.72718],[5.55198,43.72737],[5.32022,43.72817],[5.81302,43.72879],[0.09736,43.7301],[6.16423,43.73019],[2.59467,43.73174],[6.07777,43.73422],[5.97052,43.73428],[6.81529,43.73436],[6.02064,43.73515],[3.26438,43.73628],[2.51915,43.73762],[5.7011,43.73785],[5.98092,43.73846],[-1.3128,43.73939],[6.00058,43.74195],[-1.30633,43.74206],[-1.09709,43.74221],[5.99451,43.74305],[7.15883,43.74555],[-0.99523,43.74703],[6.09796,43.74762],[5.41833,43.74804],[5.87831,43.7484],[5.88247,43.74841],[5.95705,43.75064],[1.06125,43.7509],[2.91012,43.7512],[1.31028,43.75159],[5.88216,43.75191],[5.89409,43.752],[7.16118,43.75309],[-1.35199,43.75419],[1.80439,43.7547],[5.95017,43.75502],[3.19155,43.75649],[2.95747,43.75655],[5.44471,43.75657],[5.17313,43.7573],[1.96711,43.75754],[5.50157,43.75796],[5.50467,43.75796],[-1.02672,43.7583],[-0.75366,43.75869],[4.95168,43.76052],[6.15349,43.76074],[2.95264,43.7608],[2.43661,43.76136],[4.12064,43.76138],[-1.28513,43.76164],[3.35704,43.76209],[-0.89596,43.76228],[6.21916,43.76251],[-0.89612,43.76293],[6.22661,43.76429],[4.09729,43.76574],[-0.56268,43.76627],[4.07475,43.76667],[4.69331,43.76744],[5.89687,43.76815],[5.44944,43.76834],[5.37235,43.76836],[6.15827,43.76974],[4.12574,43.7701],[5.9351,43.77063],[6.14594,43.7708],[2.16374,43.77117],[5.94092,43.77134],[7.37282,43.7719],[6.60291,43.77219],[-0.43435,43.77249],[6.16121,43.77346],[6.35129,43.77396],[3.32735,43.77492],[6.29192,43.77522],[6.20719,43.77548],[6.24556,43.77596],[4.93377,43.77601],[6.20912,43.7763],[-0.60474,43.77722],[1.47965,43.77748],[7.49822,43.77954],[-1.10757,43.77959],[0.73327,43.78018],[6.34882,43.78028],[6.23088,43.78045],[2.24596,43.78124],[6.21306,43.78133],[4.82011,43.78203],[6.35002,43.78261],[-1.39578,43.78267],[5.04126,43.78275],[-1.30447,43.78423],[4.11034,43.7843],[-1.22601,43.78609],[4.71777,43.78615],[-1.3092,43.78703],[4.08692,43.78705],[7.44337,43.78781],[4.35181,43.78795],[4.84085,43.78836],[-0.69563,43.78929],[4.84435,43.78985],[6.22273,43.79015],[3.73913,43.79177],[-0.75814,43.79223],[-1.29432,43.79234],[0.64302,43.79274],[7.04217,43.79297],[-1.40628,43.79309],[0.51973,43.79416],[6.43722,43.79578],[0.60175,43.79606],[4.83854,43.79621],[0.82315,43.79628],[6.24306,43.79631],[-1.39507,43.7965],[-1.40127,43.79674],[-1.39516,43.79685],[4.82458,43.7971],[-1.38184,43.79729],[-1.31759,43.79734],[-1.4008,43.7977],[-1.37584,43.79849],[-1.39104,43.80063],[3.10442,43.80314],[4.6557,43.80851],[0.43203,43.80936],[-1.37868,43.81151],[6.09931,43.81306],[6.22605,43.81481],[4.12355,43.81556],[7.34336,43.81605],[3.6081,43.81633],[-1.39081,43.81663],[2.75041,43.8179],[2.34536,43.8181],[5.31132,43.81903],[6.22636,43.81981],[0.25674,43.82064],[5.03713,43.82111],[7.31865,43.82173],[3.14232,43.82216],[6.4314,43.8227],[-1.15078,43.82362],[5.85419,43.82367],[6.56991,43.82424],[5.69728,43.82586],[2.87456,43.82751],[2.43775,43.82785],[6.22438,43.82794],[6.21743,43.82828],[6.42817,43.83012],[5.76368,43.83015],[1.69763,43.83115],[2.33915,43.83205],[4.9459,43.83351],[3.12292,43.83615],[2.91548,43.83625],[3.29023,43.83688],[7.19463,43.83732],[6.49048,43.83785],[6.54189,43.83826],[6.02051,43.83857],[1.85721,43.83865],[7.19593,43.83867],[5.99885,43.83901],[6.49393,43.8391],[1.29975,43.83952],[6.22169,43.83969],[5.13238,43.84026],[5.47146,43.84047],[6.53648,43.8422],[4.90153,43.84285],[6.21502,43.84369],[4.78122,43.84404],[6.73301,43.8449],[6.21555,43.84501],[6.50447,43.84568],[5.56312,43.84588],[6.50986,43.84607],[6.50995,43.84623],[-0.69419,43.84647],[3.7051,43.8466],[0.67206,43.84781],[4.91862,43.85118],[-1.38384,43.85184],[-1.38726,43.85255],[6.50466,43.85309],[4.62536,43.85481],[5.16795,43.85533],[-1.35957,43.85535],[5.48342,43.85539],[6.49488,43.85599],[5.08729,43.85677],[1.24122,43.85802],[6.24454,43.85834],[6.50308,43.85848],[6.49813,43.85885],[7.02434,43.8601],[-1.27421,43.86269],[6.73286,43.86362],[-1.34559,43.86427],[-0.10281,43.86496],[6.46442,43.86559],[3.06698,43.86593],[5.10215,43.86604],[5.4132,43.86638],[6.1316,43.86938],[5.83145,43.86942],[0.25866,43.86965],[3.31464,43.86994],[0.10671,43.87043],[6.37295,43.87079],[5.63594,43.87312],[3.12465,43.87573],[3.71716,43.87591],[0.79684,43.87693],[5.40299,43.87753],[-1.23792,43.87772],[7.44311,43.87843],[4.09612,43.87862],[-1.24868,43.8798],[-1.13762,43.88048],[4.58972,43.88068],[5.10618,43.88078],[4.48889,43.88192],[0.23894,43.882],[-0.30722,43.88263],[3.99986,43.88341],[4.86999,43.88354],[7.42626,43.88387],[0.9978,43.88394],[-1.31428,43.88423],[-1.31478,43.88488],[6.51209,43.88547],[3.56979,43.88638],[6.43448,43.88765],[3.73618,43.88869],[5.27631,43.88985],[0.82838,43.89101],[2.45428,43.89394],[5.40511,43.89396],[1.30054,43.89613],[1.88491,43.89643],[7.4164,43.89686],[6.18064,43.89785],[5.80662,43.89786],[0.81091,43.89813],[-1.27069,43.89967],[-1.31054,43.90287],[-1.2916,43.90322],[0.13507,43.90574],[4.82401,43.9069],[-1.36166,43.90765],[1.98311,43.90929],[3.51555,43.91005],[5.10701,43.91035],[-1.09783,43.91047],[5.78197,43.91105],[0.64536,43.91255],[6.07154,43.91291],[5.46956,43.91385],[5.0719,43.9144],[-1.31851,43.91521],[1.68599,43.9156],[6.54098,43.91602],[0.32002,43.91798],[-1.23925,43.91874],[-1.17473,43.91939],[5.12239,43.91966],[5.34119,43.92077],[-1.22542,43.92156],[-1.30574,43.92186],[3.26704,43.92233],[5.92372,43.92308],[2.47531,43.92436],[2.5465,43.92518],[4.5642,43.92589],[3.7895,43.9265],[3.71499,43.92668],[1.50452,43.92673],[-0.04702,43.92693],[5.20218,43.92704],[4.93336,43.92836],[3.80716,43.92858],[3.59032,43.92897],[4.98316,43.92978],[-0.05567,43.92981],[-1.30846,43.9305],[-1.25746,43.93201],[5.86798,43.93301],[2.16414,43.93454],[7.41223,43.93558],[0.35668,43.93623],[3.57331,43.93651],[3.80227,43.93827],[-0.04479,43.93983],[5.8695,43.94068],[5.22925,43.94069],[2.38441,43.94139],[2.48266,43.9418],[7.51772,43.94219],[7.2826,43.94332],[2.38421,43.9437],[0.19387,43.9439],[2.46898,43.94395],[0.08586,43.9446],[7.01213,43.94523],[1.17034,43.94576],[2.37661,43.94663],[4.54582,43.94798],[2.61277,43.94799],[0.36441,43.94808],[0.07596,43.94954],[2.89263,43.95176],[-1.35195,43.95179],[4.66559,43.95187],[2.62822,43.95245],[4.79938,43.95246],[6.37495,43.95312],[5.80527,43.95312],[3.68265,43.9532],[5.93324,43.95391],[-1.3567,43.95431],[3.96618,43.95518],[4.51532,43.9561],[2.52131,43.95621],[4.80206,43.95649],[2.59067,43.95674],[6.85976,43.95715],[0.68882,43.95736],[-1.26809,43.95771],[4.48716,43.95788],[0.56135,43.95832],[2.54184,43.95836],[6.47672,43.96088],[6.00909,43.96089],[6.50867,43.96093],[0.92309,43.96134],[6.79876,43.96169],[5.78738,43.96224],[5.6048,43.96339],[0.55576,43.96382],[0.185,43.96385],[6.51174,43.96391],[1.24009,43.96587],[-1.1294,43.96657],[4.81942,43.96693],[3.20142,43.96798],[-1.05348,43.968],[1.58933,43.9696],[6.19177,43.97025],[4.79892,43.9706],[1.98672,43.9706],[3.58137,43.97166],[6.65808,43.97176],[5.73702,43.97278],[2.72067,43.97305],[3.58782,43.9736],[0.41978,43.97489],[4.88363,43.9749],[3.84986,43.97539],[6.50905,43.97662],[1.78881,43.97674],[3.68623,43.97708],[1.06136,43.97975],[1.7112,43.97997],[3.88502,43.97998],[0.50183,43.98299],[0.01617,43.98336],[1.91438,43.98393],[2.6605,43.98415],[0.22643,43.98511],[4.82272,43.98558],[2.65753,43.98821],[1.04286,43.98864],[4.91333,43.99059],[3.63748,43.99154],[-1.27604,43.9922],[3.683,43.99227],[1.64811,43.99244],[1.65117,43.99259],[4.81796,43.99382],[2.56037,43.9961],[6.19678,43.99634],[4.38429,43.99837],[-1.26922,43.99891],[5.06584,43.99928],[2.68715,43.99953],[4.00405,44.00048],[3.66139,44.00088],[-0.23471,44.00191],[2.4704,44.00255],[1.86828,44.0026],[0.4683,44.00337],[5.03861,44.00586],[6.55862,44.00674],[7.55528,44.00793],[-0.89239,44.00892],[3.67495,44.00961],[-1.2633,44.01313],[3.32032,44.01319],[5.17085,44.01414],[3.68099,44.01469],[7.31069,44.01688],[3.30126,44.01715],[-1.26993,44.01847],[3.34589,44.01999],[-0.31032,44.02093],[3.29398,44.02098],[4.89148,44.02113],[4.04592,44.02176],[4.02449,44.02285],[2.4001,44.0232],[3.35445,44.02414],[-1.27884,44.02414],[5.63091,44.02651],[-1.22773,44.02698],[4.02768,44.02702],[5.4981,44.0273],[3.2972,44.02778],[4.07383,44.02802],[5.98053,44.02852],[6.11141,44.02898],[5.19995,44.02904],[-1.25803,44.02962],[4.08692,44.02975],[1.0847,44.03064],[5.63057,44.03077],[1.57765,44.03089],[4.45568,44.03209],[0.8398,44.03212],[0.3661,44.03326],[2.4827,44.03442],[-0.94619,44.03514],[4.02419,44.03575],[3.29092,44.03708],[-1.33418,44.03746],[3.99405,44.03853],[3.8618,44.03884],[5.00084,44.03943],[3.96076,44.03993],[4.82475,44.04159],[3.98165,44.04162],[2.01709,44.04163],[-0.54208,44.04265],[3.88132,44.04359],[6.5965,44.044],[-1.20283,44.04418],[5.05421,44.04419],[3.30168,44.04543],[1.67393,44.04634],[4.23017,44.0469],[2.88788,44.04717],[-0.32204,44.04726],[2.76316,44.04929],[1.59183,44.04942],[2.82869,44.05119],[2.89936,44.05253],[1.97228,44.05379],[6.44078,44.05414],[5.81571,44.05482],[5.23699,44.05517],[4.00322,44.05708],[5.22827,44.05715],[5.18223,44.05975],[3.97393,44.06027],[3.44912,44.0613],[1.90752,44.06163],[7.2516,44.06201],[3.98283,44.06229],[5.90131,44.06254],[-1.07238,44.06283],[3.97705,44.06425],[5.98957,44.06469],[7.25704,44.06471],[7.19568,44.06551],[0.64855,44.06556],[1.92439,44.06657],[6.85856,44.0669],[-1.22954,44.0685],[3.97203,44.06854],[3.96922,44.06954],[7.20856,44.06987],[3.46997,44.06994],[3.19074,44.07064],[-1.24587,44.07108],[2.09384,44.07108],[-1.24565,44.07108],[1.51805,44.072],[-1.15637,44.07219],[-1.23226,44.07305],[-1.2389,44.07309],[0.20978,44.0732],[3.04898,44.07479],[2.8294,44.07486],[-1.24671,44.07518],[1.61167,44.07747],[-1.289,44.07761],[0.51734,44.07788],[3.9647,44.07795],[3.9543,44.07853],[3.3861,44.07857],[-1.24906,44.07886],[2.21856,44.07893],[6.49569,44.07911],[4.97849,44.07921],[4.09765,44.07951],[-1.23253,44.07976],[5.11374,44.08048],[4.87717,44.08109],[-1.26164,44.0815],[2.96048,44.0826],[1.62698,44.08423],[5.54432,44.08427],[4.59177,44.08434],[7.24954,44.08474],[1.0277,44.08515],[3.61567,44.08579],[1.76789,44.08605],[6.25086,44.08661],[3.60819,44.08722],[3.2961,44.08732],[-0.71474,44.08848],[-1.31665,44.08886],[3.54734,44.08918],[1.45598,44.08927],[7.59843,44.09185],[1.85163,44.09264],[3.95613,44.09294],[3.63581,44.0938],[2.05671,44.09551],[1.08949,44.09645],[0.88847,44.09682],[4.65965,44.09788],[5.03615,44.09812],[5.2439,44.09913],[2.69243,44.0996],[3.11224,44.09991],[6.98744,44.09998],[6.24939,44.10002],[3.09584,44.10075],[0.31013,44.10094],[3.091,44.1024],[3.08759,44.1027],[5.42485,44.10289],[5.14866,44.10317],[6.01686,44.1048],[3.08826,44.10508],[3.08801,44.10587],[2.68926,44.10658],[6.574,44.10699],[3.48333,44.10801],[2.62165,44.10813],[3.77993,44.10887],[3.08702,44.11032],[3.8541,44.11235],[3.86036,44.11236],[3.77158,44.11269],[3.89062,44.1133],[4.90348,44.1134],[5.18156,44.1138],[-1.22365,44.11389],[3.84451,44.11471],[3.08691,44.11556],[3.93852,44.11583],[6.91138,44.11716],[5.18108,44.12046],[-0.18977,44.12208],[3.73105,44.12236],[5.03437,44.12252],[3.91464,44.12325],[5.10988,44.12386],[3.9196,44.1243],[5.17249,44.12468],[1.24678,44.12547],[2.25656,44.12681],[5.18764,44.13135],[5.17087,44.13171],[3.89037,44.13191],[3.3473,44.13287],[-1.23491,44.1357],[1.47444,44.13577],[3.75761,44.1359],[2.90542,44.13615],[1.86326,44.13806],[6.58989,44.13856],[5.1581,44.13934],[4.98603,44.14279],[-0.74188,44.14415],[-0.9665,44.14521],[-1.24029,44.14542],[4.79549,44.14678],[1.97892,44.1478],[6.7627,44.14926],[3.69112,44.14934],[1.7717,44.1515],[4.04302,44.15189],[3.09919,44.15317],[4.05418,44.1537],[1.84723,44.15503],[0.65795,44.15591],[4.67113,44.15701],[5.97103,44.15741],[3.10133,44.15787],[6.14666,44.15843],[3.41537,44.15875],[1.70174,44.1591],[3.83672,44.15953],[1.75507,44.16034],[6.60596,44.16052],[2.5288,44.16121],[6.75601,44.16126],[4.93544,44.1617],[2.44093,44.16233],[0.95888,44.16263],[3.80037,44.16278],[0.84073,44.16493],[0.74725,44.16496],[1.68804,44.16517],[2.95911,44.16616],[1.54487,44.16649],[4.87604,44.16742],[5.1472,44.16755],[3.12046,44.16767],[2.05927,44.1712],[6.35498,44.17165],[2.21705,44.17286],[4.63685,44.17361],[6.61729,44.17428],[3.2117,44.17535],[4.63543,44.17588],[5.44767,44.17621],[2.17855,44.17731],[6.62152,44.17737],[4.48765,44.17737],[2.99963,44.17747],[3.74942,44.17779],[5.12533,44.17789],[-1.23219,44.17836],[4.4586,44.17899],[-1.22682,44.18044],[2.77406,44.18064],[3.43534,44.18089],[2.07724,44.18124],[4.53538,44.18131],[-1.18206,44.18202],[2.56733,44.18263],[1.60365,44.18267],[4.84985,44.18303],[0.78859,44.18446],[1.38817,44.18472],[5.27515,44.18479],[4.22918,44.18538],[3.13066,44.18553],[3.43808,44.18591],[3.41953,44.18594],[3.13665,44.18673],[1.3659,44.18784],[2.34828,44.18813],[5.99498,44.18849],[4.52499,44.18863],[2.76649,44.18922],[6.75094,44.18931],[7.03725,44.18932],[1.29983,44.18953],[2.65933,44.19016],[3.20341,44.19095],[3.15678,44.19095],[3.20454,44.19116],[2.77431,44.19152],[3.20454,44.19164],[4.50161,44.19232],[1.69577,44.19265],[4.24372,44.19353],[5.45282,44.19381],[3.20901,44.19468],[3.65815,44.19472],[3.45528,44.19519],[3.19972,44.19585],[3.18497,44.19603],[3.19858,44.19649],[2.75637,44.19652],[1.11184,44.19672],[3.18891,44.19708],[3.19708,44.19719],[2.28737,44.19721],[3.19432,44.1979],[3.48343,44.1985],[2.74601,44.19898],[3.17333,44.1996],[2.77565,44.2001],[4.62649,44.20064],[4.4772,44.20066],[5.12483,44.20079],[3.15961,44.20108],[2.77705,44.20167],[2.74872,44.20228],[5.53788,44.20251],[3.15718,44.20252],[-1.29106,44.20354],[3.58727,44.20377],[4.21492,44.20415],[-0.90673,44.20495],[2.4381,44.20579],[2.19335,44.20667],[2.77948,44.20672],[4.25687,44.20953],[4.46825,44.21041],[4.34076,44.21088],[2.017,44.21294],[2.71144,44.21304],[4.74531,44.21389],[4.46888,44.21431],[5.9364,44.21452],[2.77802,44.21502],[2.76484,44.21514],[2.22555,44.21534],[5.72087,44.21548],[2.20749,44.21583],[3.8127,44.21604],[2.31698,44.21609],[-1.28568,44.21647],[1.61317,44.21726],[-1.18488,44.21728],[2.77449,44.2196],[-1.22968,44.21997],[4.47989,44.22001],[0.76976,44.22011],[3.22231,44.22024],[1.96906,44.22027],[6.44641,44.22063],[5.86362,44.22121],[4.4624,44.22195],[-1.20378,44.22272],[-1.19432,44.22328],[5.10482,44.22467],[2.03699,44.22671],[5.12839,44.22681],[6.92482,44.22727],[1.65978,44.22745],[6.92737,44.22776],[0.78476,44.22829],[6.92117,44.22861],[3.99615,44.2288],[0.82252,44.22897],[3.02889,44.22977],[1.32814,44.23021],[3.86306,44.23039],[5.63989,44.23128],[0.39652,44.23212],[-1.11985,44.23319],[1.7764,44.23364],[5.08939,44.23365],[-1.15123,44.23423],[4.17226,44.23435],[4.13629,44.23524],[5.14959,44.23728],[4.20163,44.23748],[4.27434,44.23784],[3.5786,44.24047],[4.44502,44.24114],[5.63781,44.24197],[3.65869,44.24202],[4.2272,44.24207],[5.2106,44.24269],[1.47728,44.24321],[4.72914,44.24349],[0.54281,44.24368],[5.07864,44.24481],[3.29931,44.24564],[4.45081,44.24579],[3.92684,44.24643],[5.26102,44.249],[3.97435,44.25001],[5.37884,44.25087],[5.94452,44.25208],[5.24315,44.25223],[4.54084,44.25306],[-1.18953,44.2533],[4.4422,44.25434],[-0.51053,44.25451],[4.21631,44.25559],[4.08232,44.25575],[6.92256,44.25817],[4.1943,44.25858],[4.27981,44.2595],[4.42048,44.2601],[5.73832,44.26079],[5.12953,44.26234],[4.41836,44.26251],[4.19475,44.26299],[5.37744,44.26325],[4.20963,44.26341],[4.42921,44.26359],[5.05259,44.26452],[4.93179,44.26487],[0.70198,44.26537],[1.13985,44.26599],[4.36895,44.26622],[2.1158,44.26691],[4.35187,44.26699],[5.10511,44.26752],[5.26891,44.26826],[4.36695,44.26994],[0.88822,44.26998],[1.8724,44.2701],[4.37896,44.27029],[3.73063,44.27156],[0.19093,44.27179],[2.00088,44.27259],[3.21512,44.27303],[1.3511,44.27303],[4.5794,44.27315],[6.30544,44.27318],[3.21035,44.27324],[1.04953,44.27334],[4.34869,44.27391],[4.61446,44.27492],[5.27838,44.27572],[5.48609,44.27646],[5.24743,44.27698],[3.22916,44.27773],[4.55521,44.27784],[4.38381,44.27881],[0.27758,44.27972],[4.10115,44.27972],[3.85384,44.27976],[4.61838,44.28124],[4.61473,44.28153],[6.39157,44.28192],[5.93341,44.28203],[4.61419,44.28226],[5.90731,44.28314],[5.2819,44.28415],[-1.1732,44.2863],[3.23405,44.28694],[4.93306,44.28716],[4.58928,44.28943],[4.53342,44.28944],[5.19186,44.28973],[4.06758,44.29101],[4.83974,44.29149],[2.72562,44.29157],[0.53965,44.29197],[5.8948,44.29228],[-1.17943,44.29376],[2.15165,44.29397],[1.78211,44.2972],[4.7871,44.29805],[4.56537,44.29814],[5.65353,44.29891],[5.32972,44.29901],[5.01153,44.29908],[4.15489,44.2997],[4.25077,44.30014],[4.08369,44.30033],[4.57148,44.30036],[3.31835,44.3012],[4.55286,44.3012],[4.85057,44.30207],[1.57714,44.30238],[4.05833,44.30279],[5.27342,44.30285],[4.56607,44.30344],[4.56209,44.30364],[4.01317,44.30378],[4.58443,44.30388],[3.26844,44.30422],[2.73493,44.30463],[0.34494,44.30475],[-0.76926,44.30485],[4.04435,44.3052],[4.55955,44.30578],[3.97164,44.30798],[-1.18099,44.30802],[4.68943,44.30809],[2.74245,44.30815],[3.59833,44.3084],[4.12022,44.30856],[3.96735,44.31022],[4.55666,44.31062],[5.69663,44.31107],[5.07053,44.31107],[4.55609,44.31115],[4.93581,44.31228],[4.43181,44.31294],[5.83265,44.31344],[4.3667,44.31384],[-1.16938,44.31405],[3.2428,44.31432],[0.09151,44.31477],[4.31954,44.31496],[3.5996,44.3175],[3.96379,44.31784],[-1.13904,44.31828],[3.06399,44.31832],[-0.58158,44.32029],[6.08535,44.32271],[4.11932,44.32404],[4.32913,44.32475],[4.62476,44.32519],[4.54223,44.32573],[5.07892,44.32724],[-1.14587,44.32923],[5.06491,44.32969],[-0.97853,44.33081],[5.83879,44.33422],[3.48048,44.33457],[3.95807,44.33525],[5.78267,44.33568],[3.47948,44.3357],[3.49087,44.33575],[3.5899,44.33593],[1.03368,44.33675],[3.49778,44.3369],[3.47658,44.33724],[0.76292,44.33751],[1.54352,44.33759],[1.6656,44.3379],[4.52883,44.33795],[3.904,44.33816],[0.30854,44.33831],[3.58555,44.33832],[2.97303,44.33852],[3.49939,44.33859],[3.46954,44.33912],[4.30014,44.33979],[1.20179,44.3405],[6.03397,44.34068],[4.49949,44.34088],[4.34782,44.34211],[2.02609,44.34237],[6.35994,44.34263],[5.28324,44.34281],[4.60457,44.34359],[3.60556,44.34423],[3.61063,44.34521],[-1.10096,44.34597],[3.39553,44.3462],[-1.0929,44.34622],[6.34342,44.34665],[3.42527,44.34754],[4.37652,44.34855],[3.45848,44.3502],[-1.10789,44.35024],[4.45312,44.35102],[-1.1105,44.35208],[-1.02749,44.35325],[3.40146,44.35339],[3.15463,44.35341],[2.5847,44.35393],[0.92493,44.35581],[0.37462,44.35642],[3.56669,44.35689],[4.38259,44.35721],[3.52057,44.35735],[1.94961,44.35754],[5.76057,44.36001],[3.23056,44.3608],[4.00013,44.36101],[3.74723,44.36182],[3.52241,44.36369],[0.93742,44.36412],[5.1538,44.36486],[3.4252,44.36501],[2.85138,44.36521],[3.43146,44.36547],[4.09432,44.36567],[6.30503,44.36697],[3.52315,44.36899],[1.30811,44.37084],[3.53153,44.37196],[3.53035,44.37232],[5.16252,44.37259],[0.86131,44.37305],[5.13355,44.37305],[2.19736,44.37381],[5.26328,44.37398],[3.52435,44.37591],[2.14629,44.3761],[4.42134,44.37648],[4.26951,44.37652],[4.42096,44.37676],[4.425,44.37681],[4.37216,44.37693],[4.20643,44.37714],[3.54626,44.37718],[4.88123,44.37742],[1.01813,44.37839],[4.2119,44.37865],[0.31745,44.38051],[0.53709,44.38114],[1.04718,44.38114],[4.64858,44.38136],[6.6759,44.38156],[2.29983,44.38208],[5.46118,44.38252],[4.93055,44.38307],[6.6347,44.38323],[6.64271,44.384],[4.41814,44.38405],[0.80935,44.38428],[1.8863,44.38431],[5.4254,44.38523],[6.6598,44.3865],[5.94364,44.38688],[0.44612,44.38728],[2.14804,44.38756],[2.33618,44.38767],[4.404,44.38851],[-1.18164,44.38861],[5.47104,44.38919],[4.23036,44.38981],[4.23276,44.38991],[4.40491,44.3906],[4.51096,44.39126],[4.39691,44.39136],[4.50461,44.39233],[0.25257,44.39233],[4.49228,44.39242],[4.40212,44.39258],[4.99245,44.39264],[6.57264,44.39291],[4.39484,44.39332],[0.68706,44.39492],[4.90067,44.39495],[0.4936,44.39495],[5.46026,44.39509],[0.54743,44.39564],[4.22234,44.39567],[1.76396,44.39571],[4.37958,44.39571],[0.80491,44.39576],[0.78664,44.3959],[4.20152,44.39607],[6.48821,44.39628],[6.54617,44.39647],[4.29142,44.3968],[4.40117,44.39734],[4.38317,44.39737],[5.06093,44.39752],[4.38338,44.39758],[4.38285,44.39764],[4.39999,44.3978],[4.39874,44.39784],[1.11845,44.39784],[5.2505,44.39892],[4.20057,44.39915],[6.53191,44.39927],[4.401,44.39966],[4.37406,44.40049],[4.19711,44.40076],[4.21748,44.40208],[3.74623,44.40353],[4.21628,44.4039],[4.21522,44.40438],[4.21528,44.40461],[-1.14822,44.40473],[4.22011,44.40505],[4.38764,44.40543],[4.37916,44.40547],[4.21983,44.4055],[2.28959,44.40615],[2.3382,44.40644],[4.36425,44.40652],[4.51481,44.40734],[0.54357,44.40778],[5.07959,44.40797],[3.24093,44.40814],[4.29407,44.40833],[4.11033,44.40866],[2.00949,44.40875],[4.35481,44.40885],[4.40079,44.40891],[6.34811,44.40925],[-0.82546,44.40929],[2.20155,44.4093],[4.16768,44.40953],[0.21995,44.41031],[5.35272,44.41036],[4.17118,44.41096],[4.89124,44.41157],[4.35118,44.41191],[4.35061,44.41226],[5.26188,44.41257],[2.1997,44.41279],[4.13917,44.41333],[4.09418,44.4142],[4.2729,44.41423],[4.39848,44.4149],[4.37802,44.4153],[5.19461,44.41551],[4.09728,44.41558],[5.27294,44.4168],[0.42928,44.41759],[-0.49252,44.41833],[4.10149,44.41859],[3.90984,44.41894],[5.71839,44.41939],[3.0885,44.41978],[6.17103,44.42],[6.73685,44.42004],[5.72754,44.42024],[4.09852,44.42034],[4.83898,44.42045],[1.69559,44.42051],[4.23915,44.42054],[3.01897,44.42164],[5.79583,44.42222],[4.34633,44.42269],[4.31393,44.42279],[4.34714,44.42287],[4.32186,44.42313],[6.44149,44.42418],[-1.13296,44.4245],[4.33193,44.42493],[5.21749,44.42501],[6.43661,44.42514],[-0.19904,44.42536],[6.0295,44.42564],[2.16965,44.42636],[-1.13366,44.42669],[-1.15985,44.42673],[4.32861,44.42688],[4.35368,44.42724],[4.33521,44.42744],[4.13239,44.42884],[4.35535,44.42902],[4.35349,44.42903],[6.03172,44.42913],[4.42315,44.42927],[4.3554,44.4293],[-1.16696,44.4294],[4.31763,44.43038],[-1.15581,44.43048],[4.57207,44.43096],[-1.1644,44.43107],[4.32964,44.43139],[4.56811,44.4317],[1.0689,44.4318],[-1.16912,44.43184],[3.93235,44.43241],[4.31456,44.43258],[0.883,44.43343],[-1.13157,44.43401],[4.31495,44.43412],[6.42565,44.43509],[-1.14848,44.43513],[-1.15465,44.43523],[4.42812,44.43531],[5.21198,44.43544],[3.1451,44.4358],[3.20264,44.43593],[4.07865,44.43645],[4.34097,44.43648],[4.57754,44.43681],[-1.13827,44.4384],[-1.14045,44.4391],[5.40453,44.43939],[3.10096,44.4398],[4.63217,44.44097],[2.03732,44.44113],[-1.24557,44.44122],[1.60695,44.44159],[6.30424,44.44232],[3.19646,44.44238],[4.33682,44.44343],[1.17342,44.44409],[3.93222,44.44432],[4.36686,44.44471],[0.44956,44.44488],[5.45918,44.44503],[6.85266,44.44625],[4.32889,44.44667],[4.36686,44.44743],[4.32156,44.4478],[1.67464,44.44839],[4.3336,44.44903],[4.1551,44.44915],[4.33239,44.44915],[4.36351,44.44955],[-0.94486,44.45233],[4.33651,44.4524],[4.4011,44.45262],[1.05676,44.45407],[5.73017,44.45417],[6.04946,44.45577],[2.29787,44.45702],[6.36394,44.4572],[6.29284,44.45727],[4.2778,44.45759],[6.35386,44.45844],[-1.24016,44.45894],[4.34186,44.45896],[-0.3783,44.45933],[6.16951,44.4594],[6.23559,44.45966],[-1.13064,44.46068],[4.3376,44.4614],[-1.19837,44.46166],[3.92807,44.46191],[2.9632,44.46208],[2.1293,44.46309],[6.75188,44.46354],[1.44194,44.46373],[4.27296,44.46442],[2.94972,44.46474],[3.34684,44.46527],[1.4854,44.46602],[0.82321,44.4665],[1.75047,44.46679],[-1.0562,44.46707],[4.41395,44.46732],[2.98232,44.469],[1.68125,44.46915],[1.58625,44.46923],[0.41309,44.4702],[1.5461,44.471],[3.86097,44.47301],[2.9225,44.47302],[1.78365,44.47331],[4.27068,44.47336],[4.35341,44.47389],[-1.08417,44.47395],[-0.25699,44.47443],[3.98535,44.47527],[4.42142,44.47533],[4.26258,44.47543],[5.37291,44.47544],[-1.0686,44.47549],[3.1727,44.4757],[1.19909,44.47626],[4.36206,44.47632],[4.35871,44.4765],[3.49434,44.4765],[6.26857,44.47652],[0.59361,44.4771],[2.45582,44.47741],[1.14213,44.4778],[1.36246,44.47805],[4.26471,44.47822],[5.39514,44.47843],[4.17099,44.47939],[4.3781,44.47948],[4.20842,44.47996],[4.20933,44.48016],[1.05252,44.48025],[-1.09336,44.48128],[5.3791,44.48189],[4.25421,44.48193],[4.20534,44.48209],[1.8446,44.48211],[4.25445,44.48239],[4.23549,44.48369],[1.83915,44.48372],[-1.08987,44.48411],[4.26655,44.48417],[1.55361,44.48421],[4.24187,44.48433],[5.95981,44.48482],[4.3717,44.48497],[5.37781,44.48564],[4.37301,44.48604],[4.36991,44.48618],[4.23989,44.48625],[4.37363,44.48634],[4.71952,44.48738],[4.23964,44.48741],[4.47633,44.4889],[0.99735,44.48918],[1.02039,44.48949],[4.67685,44.48981],[4.36583,44.49094],[3.74355,44.49118],[4.20727,44.49239],[1.93183,44.49275],[4.22335,44.49276],[-0.6287,44.49319],[4.23827,44.49362],[4.2428,44.49511],[4.74166,44.49527],[4.22142,44.49611],[1.08176,44.49636],[4.20883,44.49679],[2.89306,44.49715],[1.0657,44.49744],[6.03158,44.4981],[6.02899,44.49885],[4.27098,44.49901],[4.57652,44.49908],[6.34545,44.49924],[4.23192,44.49926],[4.30619,44.49964],[3.40705,44.50097],[-1.0775,44.5019],[1.69363,44.50191],[4.37937,44.50242],[-1.08074,44.50285],[3.46159,44.50337],[4.29454,44.50365],[1.17292,44.50381],[6.35536,44.50471],[4.2344,44.50476],[5.57538,44.50503],[1.89624,44.50653],[4.37095,44.50658],[4.61951,44.5073],[4.38044,44.5075],[1.66234,44.50771],[4.40347,44.50778],[4.22492,44.50814],[3.66052,44.5083],[4.32059,44.50834],[1.32247,44.50974],[6.55208,44.51106],[3.25466,44.51153],[4.38667,44.5124],[2.81842,44.51389],[6.36435,44.51396],[3.47426,44.51422],[6.36194,44.51455],[6.37234,44.51468],[5.74355,44.51487],[5.21397,44.51497],[6.75666,44.51653],[4.30322,44.51892],[5.79868,44.51902],[6.38747,44.51923],[2.66643,44.51928],[4.23327,44.52029],[-0.89657,44.52032],[5.80399,44.52055],[4.30392,44.52108],[5.73406,44.52116],[5.06146,44.52157],[4.34696,44.52164],[2.7695,44.52213],[5.15188,44.5223],[6.34097,44.52289],[6.00603,44.52294],[2.27447,44.52303],[4.3011,44.52334],[6.40285,44.52345],[0.63987,44.52358],[6.40105,44.52406],[0.03591,44.52418],[3.90785,44.52498],[3.26728,44.52592],[4.32744,44.52598],[6.3183,44.52601],[1.71985,44.52623],[1.46028,44.52635],[6.35866,44.52709],[2.0953,44.52719],[6.32505,44.52779],[1.12548,44.52785],[6.32033,44.52848],[5.02234,44.52951],[4.34008,44.53062],[3.52731,44.53069],[6.50086,44.5309],[5.68452,44.53135],[1.45927,44.53147],[6.43964,44.53164],[-1.16172,44.53171],[3.55595,44.53199],[5.93765,44.53394],[4.40727,44.53411],[2.5647,44.53609],[6.3154,44.53661],[6.30415,44.53692],[6.49125,44.53738],[4.4038,44.53738],[4.41059,44.53764],[6.45771,44.538],[4.41096,44.53817],[4.19165,44.53839],[4.24972,44.53845],[6.49225,44.53845],[6.45439,44.53853],[1.09751,44.53858],[1.37772,44.53866],[5.05693,44.53889],[6.4148,44.539],[6.28032,44.54041],[6.314,44.54152],[6.21922,44.54221],[6.30806,44.54361],[4.04842,44.54372],[4.93041,44.54396],[4.41985,44.54424],[6.49823,44.54468],[6.48914,44.54473],[-1.16009,44.54498],[-0.87375,44.54641],[6.49039,44.5467],[1.08376,44.54769],[6.49649,44.54814],[6.46649,44.54881],[2.41053,44.54903],[3.84186,44.5491],[4.92585,44.54986],[5.95101,44.55002],[3.3044,44.55077],[6.47741,44.55094],[1.17242,44.55154],[6.32603,44.5518],[5.08775,44.55193],[0.88148,44.55254],[4.44904,44.55316],[6.48594,44.55395],[-1.15355,44.55532],[6.50626,44.55544],[1.77085,44.55586],[3.83468,44.55666],[1.11053,44.55703],[6.50764,44.5571],[4.59769,44.55843],[6.48221,44.55853],[6.18012,44.55908],[2.4618,44.55939],[4.23786,44.56046],[4.28616,44.56123],[6.34632,44.56151],[2.67837,44.56222],[6.26753,44.56237],[1.1306,44.56307],[4.46119,44.56401],[4.90788,44.56423],[5.91654,44.5649],[2.66276,44.56492],[5.74731,44.565],[5.477,44.56613],[4.22916,44.5664],[5.56983,44.56712],[4.87497,44.56737],[4.24829,44.56757],[4.3186,44.5682],[4.69547,44.56829],[1.79231,44.56863],[5.2778,44.56935],[5.88362,44.57186],[-1.22095,44.57244],[-1.22043,44.57259],[4.51116,44.5726],[6.53879,44.57263],[2.07287,44.57302],[1.83334,44.5755],[3.8934,44.57598],[1.19283,44.5771],[0.62113,44.57723],[-0.0336,44.57778],[-1.21306,44.57806],[5.12814,44.5783],[4.1519,44.57909],[6.08228,44.57912],[6.08228,44.58002],[5.10822,44.5808],[-1.21249,44.58114],[6.08252,44.58267],[3.63535,44.58275],[5.13585,44.58387],[2.23431,44.58474],[1.16665,44.58478],[-1.20878,44.58519],[1.83753,44.58668],[4.52576,44.58754],[5.84794,44.58767],[2.22183,44.58833],[5.84999,44.58856],[4.40646,44.58995],[1.04792,44.59038],[4.73915,44.59164],[2.92698,44.59173],[5.11744,44.5918],[5.3161,44.5923],[0.69313,44.59404],[0.81649,44.59505],[4.41721,44.59544],[5.16185,44.59568],[5.11153,44.59587],[4.37663,44.59662],[1.55453,44.59697],[6.5421,44.59948],[3.98234,44.59972],[2.39124,44.60007],[0.87109,44.60049],[5.46581,44.60161],[6.5275,44.60173],[2.58323,44.60324],[6.52253,44.60338],[5.28766,44.60412],[2.66833,44.60422],[5.0129,44.60447],[-0.94225,44.60486],[4.47144,44.6051],[4.41796,44.60599],[6.3379,44.60666],[5.13078,44.60738],[0.84283,44.60793],[4.93726,44.60903],[2.23577,44.60922],[0.76387,44.60966],[-0.28542,44.60999],[2.0492,44.61303],[6.5166,44.61339],[0.83504,44.61375],[0.81889,44.61426],[6.52804,44.61436],[5.44618,44.61512],[2.47308,44.61531],[0.51803,44.61579],[6.51746,44.61596],[2.58048,44.61597],[0.584,44.61686],[6.20994,44.61801],[4.43209,44.61922],[1.22427,44.62043],[6.54623,44.62067],[1.96367,44.62182],[2.36211,44.62348],[6.2106,44.62451],[4.27484,44.6251],[4.23286,44.62517],[0.45896,44.62609],[5.5213,44.62711],[1.08242,44.62776],[2.32049,44.62912],[0.22105,44.62923],[5.00559,44.63057],[0.39942,44.6315],[0.30212,44.633],[0.57094,44.63358],[4.5085,44.63359],[6.13086,44.6346],[3.67329,44.63463],[-0.32139,44.6349],[4.77428,44.63689],[5.31783,44.63831],[3.98481,44.63943],[-1.04286,44.6398],[-1.12145,44.63984],[0.68739,44.64013],[6.15184,44.6402],[1.22163,44.642],[3.48614,44.64201],[2.36642,44.64257],[4.37937,44.64272],[6.15087,44.64273],[2.5647,44.64275],[-1.11154,44.64389],[-1.11092,44.6439],[1.56506,44.64405],[4.38755,44.6442],[1.33286,44.64448],[6.20436,44.64551],[6.58456,44.64604],[0.07224,44.64679],[5.05893,44.64715],[4.50362,44.64781],[5.0801,44.64827],[-0.86269,44.64835],[1.08158,44.64837],[4.26669,44.64863],[4.39027,44.6492],[1.43508,44.64954],[4.28695,44.64971],[-0.9792,44.65081],[6.1728,44.65106],[4.32387,44.65116],[-1.17409,44.65126],[2.50045,44.65216],[0.72352,44.65253],[5.41259,44.65258],[3.89154,44.65268],[0.80955,44.65309],[1.9207,44.65324],[6.78891,44.65395],[0.60268,44.65395],[2.70439,44.65565],[0.59128,44.65587],[6.64661,44.65597],[6.65561,44.65631],[4.6933,44.65659],[6.65407,44.65677],[6.63272,44.65686],[0.73144,44.65722],[4.77689,44.65732],[4.89084,44.6576],[6.63839,44.65824],[6.63497,44.65863],[4.31358,44.65897],[6.62653,44.65903],[5.40946,44.65917],[5.40911,44.65919],[1.38608,44.6595],[0.87904,44.65959],[2.1316,44.65984],[3.7537,44.66018],[-0.2414,44.66098],[1.19522,44.66147],[6.64927,44.66173],[-0.29544,44.66212],[6.7808,44.66246],[6.65177,44.66461],[2.16126,44.66499],[6.21977,44.66513],[4.2937,44.66521],[2.68229,44.66675],[4.08951,44.66732],[4.17038,44.66833],[4.28329,44.66846],[6.0858,44.66888],[4.36336,44.66894],[0.39564,44.66925],[4.20302,44.66956],[4.09001,44.66968],[3.04022,44.67016],[6.24085,44.6707],[4.26812,44.6714],[2.10946,44.67189],[5.18118,44.6719],[5.70066,44.67205],[1.47713,44.67253],[4.26074,44.67286],[4.23149,44.67421],[6.60786,44.67676],[4.45879,44.67733],[4.5645,44.67763],[1.87963,44.67766],[2.58287,44.6777],[0.17814,44.6778],[4.80346,44.67878],[6.60311,44.67931],[4.9442,44.67963],[2.78526,44.68023],[6.31898,44.68047],[5.76603,44.68061],[1.30189,44.68081],[5.44721,44.68129],[2.26036,44.68144],[2.8544,44.68158],[5.44795,44.6824],[0.18617,44.68251],[2.66848,44.68284],[5.94874,44.68308],[6.62615,44.68353],[1.26968,44.6837],[-1.00435,44.68408],[4.85452,44.68705],[2.99868,44.68739],[1.09857,44.68799],[2.22554,44.68841],[5.23333,44.68863],[5.22202,44.68975],[0.49008,44.69139],[1.53479,44.69229],[4.71631,44.69256],[6.36885,44.69275],[5.48973,44.69349],[5.12753,44.69363],[4.43307,44.69434],[5.18124,44.69511],[5.30325,44.69538],[5.24145,44.69617],[5.11765,44.69714],[5.2592,44.69898],[0.8836,44.699],[5.25236,44.69915],[2.50682,44.69995],[5.1227,44.70062],[3.38791,44.70149],[4.22256,44.70276],[0.39921,44.7037],[5.1086,44.70387],[2.37793,44.70407],[0.83396,44.7047],[2.20702,44.70476],[0.69357,44.70505],[4.73816,44.70519],[6.6023,44.70564],[3.28275,44.70583],[-1.04548,44.70605],[2.6241,44.7063],[4.22001,44.70726],[5.13175,44.70898],[4.21441,44.70927],[6.59501,44.7107],[2.3596,44.71084],[5.0899,44.71088],[2.56171,44.7114],[3.82992,44.71308],[-1.06027,44.71426],[0.24289,44.71432],[-1.24268,44.71542],[5.26475,44.71633],[4.31875,44.71652],[4.35019,44.72099],[1.37437,44.72342],[6.86547,44.72367],[5.02783,44.72407],[1.16315,44.72412],[1.28563,44.72493],[-0.15084,44.72546],[3.74758,44.72557],[4.00395,44.72573],[-1.08084,44.72614],[4.59819,44.72614],[5.06469,44.72686],[4.92692,44.7269],[6.06402,44.72747],[3.86466,44.72781],[1.597,44.72838],[1.23841,44.73086],[0.60715,44.73207],[4.9933,44.73234],[1.26193,44.73286],[1.91762,44.73312],[3.83587,44.73388],[-1.19603,44.73428],[1.29523,44.73503],[0.54338,44.73518],[5.12143,44.73539],[4.6241,44.73558],[4.25286,44.73577],[2.67875,44.73671],[4.29715,44.73693],[1.27579,44.73809],[3.76921,44.7381],[3.78077,44.73813],[3.95851,44.7385],[4.65967,44.73853],[2.02463,44.7399],[6.56153,44.74148],[1.04503,44.74156],[4.40716,44.74233],[1.26504,44.74262],[5.38449,44.74372],[5.12711,44.74499],[3.87974,44.7455],[6.58069,44.74667],[1.79965,44.74761],[1.04247,44.74805],[1.37535,44.74925],[1.15549,44.74982],[3.72833,44.75044],[5.36631,44.75064],[-1.17927,44.75117],[-1.18753,44.75169],[4.81241,44.75227],[1.18794,44.75263],[5.37778,44.75444],[0.98192,44.75445],[1.23955,44.75455],[5.67898,44.75491],[-0.08711,44.75537],[-0.62786,44.75563],[0.70216,44.75603],[4.09568,44.75668],[5.3585,44.75678],[-1.13092,44.75688],[4.71298,44.75721],[5.35345,44.75733],[-1.11989,44.75763],[-1.07316,44.75766],[-1.07209,44.75767],[6.79948,44.75802],[6.57952,44.75802],[0.90227,44.75807],[0.74708,44.7584],[-1.14017,44.76028],[-1.13694,44.76189],[1.01439,44.76192],[3.88506,44.76227],[5.34674,44.7625],[5.2727,44.76585],[1.17617,44.76789],[4.16571,44.76825],[2.51472,44.76829],[6.97553,44.76948],[4.4717,44.76979],[0.41171,44.77124],[-1.14434,44.77137],[2.87678,44.77232],[-1.14161,44.77285],[1.44095,44.77311],[0.86061,44.77351],[0.67095,44.77455],[3.37203,44.77506],[3.88801,44.77641],[6.55814,44.77774],[1.18184,44.77836],[-1.14302,44.77856],[2.25409,44.77938],[1.17347,44.77965],[3.6332,44.78088],[2.35399,44.781],[1.28889,44.78134],[4.61805,44.78148],[6.02373,44.78179],[6.03589,44.782],[4.51873,44.78201],[-0.12712,44.78253],[-0.3709,44.78382],[1.89576,44.78399],[1.20913,44.78645],[6.88804,44.78786],[5.14789,44.78857],[1.41621,44.78889],[1.47206,44.78938],[6.92913,44.79084],[1.6006,44.79111],[4.12886,44.79146],[1.16205,44.79197],[0.64972,44.79341],[0.83353,44.79523],[1.00798,44.79616],[5.77313,44.79623],[1.13135,44.79766],[-1.22586,44.79801],[2.08597,44.79845],[6.71682,44.79947],[5.9802,44.80019],[3.90104,44.80059],[1.17901,44.80085],[2.75655,44.80163],[3.97044,44.80194],[1.47571,44.80202],[1.29431,44.80204],[3.66257,44.80249],[-1.13358,44.80276],[-1.13279,44.80332],[1.94635,44.80372],[1.67252,44.80439],[1.62755,44.80449],[1.20602,44.80452],[1.1585,44.8051],[1.63223,44.80534],[1.17435,44.8057],[1.47467,44.8059],[1.69546,44.80698],[4.61492,44.80699],[4.63049,44.80768],[2.80658,44.80793],[4.46337,44.8081],[-1.13103,44.80832],[1.1997,44.80863],[4.63595,44.8087],[4.18732,44.80939],[1.61614,44.80953],[1.40666,44.8097],[0.87195,44.81099],[6.96712,44.81185],[6.11269,44.81187],[4.39974,44.81248],[4.48352,44.81312],[1.66504,44.81377],[1.10078,44.81457],[5.74871,44.81492],[4.59972,44.81545],[1.22419,44.81563],[1.22064,44.81574],[1.29128,44.81583],[5.68204,44.81593],[4.06275,44.8161],[1.2142,44.81622],[3.27097,44.81647],[5.92776,44.81666],[3.11562,44.81685],[6.19338,44.81757],[5.01604,44.81773],[1.68626,44.81773],[6.19154,44.8178],[4.05352,44.81805],[6.19596,44.8184],[4.82084,44.81886],[5.94202,44.81899],[1.30893,44.81911],[1.6543,44.81929],[6.5468,44.81938],[5.93943,44.8197],[1.31755,44.81992],[1.21394,44.82103],[1.24468,44.82115],[1.46903,44.82134],[1.22562,44.82184],[1.3447,44.82227],[4.43385,44.82238],[0.07523,44.82253],[5.63979,44.82284],[0.86046,44.82291],[0.80621,44.82298],[1.25108,44.82349],[-0.11014,44.8235],[0.15525,44.82357],[1.23456,44.82371],[6.14729,44.82374],[4.07085,44.82388],[1.17068,44.82401],[4.46143,44.82451],[6.52576,44.82466],[0.06195,44.82471],[4.74659,44.82494],[1.25421,44.82512],[3.90738,44.82516],[1.24244,44.82553],[0.98902,44.8256],[6.4883,44.82573],[1.77826,44.82577],[1.15118,44.82596],[4.76194,44.82616],[4.67927,44.82635],[0.70459,44.82639],[2.05087,44.82682],[0.99093,44.82765],[4.93371,44.82855],[0.03712,44.82868],[4.52285,44.82896],[0.12243,44.82903],[1.15233,44.82915],[1.26664,44.82967],[1.5505,44.83064],[2.68596,44.83096],[1.13005,44.83104],[1.14894,44.83223],[5.28197,44.83286],[1.26839,44.83288],[2.81473,44.83344],[1.80843,44.83367],[2.04082,44.83429],[0.80083,44.83496],[1.46028,44.83518],[1.1587,44.83551],[1.23761,44.83561],[1.06247,44.83595],[1.35778,44.83742],[1.11278,44.83751],[1.14854,44.83812],[2.66359,44.83838],[3.73786,44.83845],[0.33054,44.83865],[2.48311,44.83894],[0.76287,44.83953],[6.48618,44.83991],[0.78559,44.84147],[4.60318,44.8425],[0.2249,44.84415],[6.49009,44.84417],[3.00084,44.84484],[5.58047,44.84516],[4.02679,44.84574],[1.74685,44.84619],[-1.11139,44.84704],[4.53068,44.84737],[4.7234,44.84739],[0.77638,44.84891],[0.47636,44.84898],[1.18305,44.84918],[3.26907,44.85019],[2.23146,44.85019],[4.34743,44.85058],[0.61309,44.8509],[1.51499,44.85092],[5.6248,44.85131],[0.73029,44.85144],[3.33804,44.85153],[1.74553,44.85157],[0.98076,44.85192],[1.71275,44.85249],[-0.03557,44.85337],[1.22093,44.85353],[2.31106,44.85364],[0.91044,44.85365],[3.95468,44.85383],[2.77049,44.85422],[3.32712,44.8545],[1.52279,44.85497],[4.83831,44.85564],[1.03741,44.85584],[5.8437,44.85638],[6.58957,44.85745],[1.23709,44.85753],[1.89788,44.8578],[4.11735,44.85782],[0.96379,44.8604],[6.05295,44.86053],[3.84279,44.86055],[1.55966,44.86154],[0.9813,44.86164],[1.56526,44.86182],[4.55836,44.8619],[1.27207,44.86199],[1.29739,44.86334],[1.37344,44.86338],[0.79638,44.86381],[1.3599,44.86414],[3.66587,44.86531],[1.18815,44.86535],[1.49743,44.86594],[1.41372,44.86679],[1.35717,44.86687],[1.16269,44.8673],[1.27933,44.8674],[2.63558,44.86849],[1.80091,44.86992],[1.28783,44.87035],[6.48456,44.8709],[4.27799,44.87102],[0.86784,44.87306],[1.43367,44.87325],[0.85857,44.87385],[6.68777,44.87466],[5.37902,44.87481],[5.83741,44.87593],[1.57707,44.87604],[1.57285,44.87654],[2.02488,44.87679],[6.61638,44.87731],[4.6413,44.87752],[1.05489,44.87775],[6.60838,44.87788],[0.82492,44.87918],[1.25165,44.87933],[0.88599,44.87976],[1.525,44.88001],[4.60625,44.88081],[1.48274,44.88211],[5.68814,44.88228],[0.34632,44.88323],[-1.08603,44.88339],[5.04149,44.88369],[6.45076,44.88489],[2.9653,44.88491],[1.59928,44.88527],[1.4072,44.88588],[0.60791,44.88619],[0.54571,44.88633],[3.92458,44.8877],[1.08636,44.88839],[2.23779,44.8886],[1.47418,44.88895],[-1.09722,44.88897],[3.20939,44.88971],[0.93376,44.89026],[3.92086,44.89101],[4.58163,44.89217],[5.90416,44.89262],[0.91471,44.89301],[0.87942,44.89324],[-1.20321,44.89342],[1.22748,44.8937],[1.11378,44.89426],[0.64259,44.89433],[-1.10146,44.89464],[3.00127,44.89514],[5.55571,44.89656],[-0.58273,44.89771],[2.46266,44.89858],[5.6736,44.89861],[1.40324,44.89871],[4.63457,44.9],[4.32586,44.9003],[1.29795,44.90062],[1.57141,44.90081],[5.94619,44.90094],[3.08572,44.90157],[5.0116,44.90179],[3.08602,44.90209],[1.33475,44.90249],[4.6497,44.90254],[2.20473,44.90374],[1.2821,44.90404],[3.08413,44.90407],[1.1425,44.90415],[1.7762,44.90497],[2.25393,44.90583],[1.23628,44.90598],[0.97417,44.9065],[1.29165,44.90655],[4.4311,44.90723],[1.11472,44.90862],[1.15021,44.90894],[0.93173,44.90909],[1.1875,44.90939],[5.67051,44.90953],[1.62654,44.90979],[1.74088,44.90994],[1.81858,44.91056],[1.28947,44.91064],[0.91768,44.91136],[2.24907,44.91296],[1.26511,44.9131],[1.01544,44.91361],[4.6967,44.91369],[4.2824,44.91414],[1.79412,44.91444],[6.61365,44.9152],[1.09466,44.91529],[5.62809,44.91534],[0.82129,44.91543],[5.06494,44.91559],[4.41998,44.91575],[4.48055,44.91577],[3.66909,44.91621],[4.57736,44.91625],[1.39099,44.91647],[3.62278,44.91655],[1.83727,44.91667],[-0.14184,44.91669],[5.0276,44.91703],[0.24806,44.91751],[1.24903,44.91761],[6.67381,44.91809],[4.87506,44.9186],[1.27782,44.91906],[1.22969,44.91911],[1.8029,44.91956],[2.84529,44.91962],[4.5292,44.92013],[4.51839,44.92117],[2.26357,44.92136],[2.8041,44.92215],[1.00434,44.92318],[1.02968,44.9241],[2.97909,44.92415],[2.21729,44.92675],[1.26615,44.92678],[1.05696,44.92835],[1.81137,44.929],[6.68263,44.9302],[-0.85567,44.93206],[0.93653,44.93391],[1.12638,44.93397],[1.67948,44.93421],[0.56173,44.93455],[3.04371,44.93457],[6.2815,44.93515],[3.82524,44.93539],[2.45583,44.9359],[1.43751,44.93596],[1.23263,44.93636],[3.98452,44.93652],[1.00639,44.93653],[5.31435,44.93684],[1.08535,44.93688],[0.07101,44.93741],[4.51773,44.93758],[1.76761,44.93835],[1.60738,44.93849],[3.14694,44.93858],[6.68323,44.93905],[4.73211,44.93937],[2.0505,44.93996],[0.21262,44.94162],[1.97836,44.94171],[5.43022,44.94194],[4.36814,44.94235],[1.76437,44.94254],[3.30677,44.94344],[5.15099,44.94448],[0.84872,44.94463],[1.70324,44.94466],[0.96011,44.94492],[5.39471,44.94602],[2.58641,44.94812],[1.43684,44.94939],[0.66868,44.94965],[1.3944,44.95027],[5.68132,44.9511],[0.85063,44.95162],[1.08872,44.95292],[1.21867,44.95512],[4.54687,44.95529],[1.20878,44.95569],[1.04472,44.95584],[3.16107,44.95724],[2.12871,44.95745],[1.27235,44.95767],[3.541,44.95802],[1.06652,44.95938],[-0.30912,44.96006],[0.16536,44.96038],[6.16397,44.96265],[1.32806,44.96343],[1.26417,44.96439],[2.19507,44.96468],[3.8805,44.96474],[1.16508,44.96492],[1.37016,44.96659],[0.02616,44.96753],[5.78028,44.96763],[5.43007,44.96812],[1.04741,44.96857],[3.65034,44.96916],[5.41585,44.96927],[2.63298,44.97124],[1.15863,44.97142],[1.8455,44.9741],[1.18792,44.97464],[1.61457,44.97541],[1.0463,44.97566],[1.84193,44.97733],[-1.14362,44.97808],[1.21781,44.97828],[1.04796,44.97862],[5.16398,44.97944],[1.84084,44.97988],[0.34027,44.98058],[6.49515,44.98063],[1.04482,44.98069],[2.62933,44.98118],[-1.07957,44.98122],[4.22224,44.98374],[6.12031,44.98391],[1.04734,44.9843],[5.78228,44.98462],[2.32724,44.98566],[0.99494,44.98621],[5.75519,44.98644],[6.12027,44.98644],[1.83374,44.98648],[-1.13569,44.98717],[1.67189,44.98804],[1.59298,44.9881],[1.99497,44.98825],[4.4046,44.98895],[1.65203,44.99054],[3.678,44.99135],[4.56512,44.9916],[2.41965,44.99219],[0.5984,44.99302],[3.9034,44.99362],[-0.10737,44.99653],[-0.06325,44.99708],[4.51396,44.99756],[4.89375,44.99772],[1.24549,44.99865],[0.07216,44.99873],[3.21903,44.99906],[0.97658,45.00039],[5.77766,45.00044],[2.0932,45.00086],[1.46385,45.00129],[1.07137,45.00173],[3.28746,45.00178],[-1.09343,45.00192],[5.7724,45.00233],[2.55037,45.00332],[-1.1345,45.00344],[5.44775,45.00393],[4.79323,45.00669],[3.28228,45.00712],[-0.47722,45.00713],[0.93039,45.00765],[-1.11209,45.00809],[-1.16616,45.0082],[0.68978,45.00825],[-1.19249,45.00858],[4.84616,45.00899],[1.85097,45.00991],[4.41984,45.01085],[-1.19478,45.01107],[1.08891,45.01133],[5.2871,45.01138],[3.2747,45.01167],[4.6247,45.01174],[3.27498,45.01245],[0.15828,45.0128],[-0.10832,45.01287],[0.8685,45.01295],[2.50908,45.01299],[2.67046,45.01344],[1.68127,45.01483],[4.11537,45.01597],[6.63183,45.01683],[1.18808,45.01732],[1.24785,45.01766],[0.0213,45.01831],[0.54987,45.01924],[-0.05876,45.01989],[5.77522,45.02055],[5.78278,45.02185],[1.84052,45.02196],[4.32677,45.02387],[4.64931,45.02406],[0.99788,45.02416],[1.90486,45.02468],[5.44383,45.02586],[1.23771,45.02609],[3.59669,45.0268],[0.97135,45.02758],[0.6181,45.02774],[1.84697,45.02874],[0.28225,45.02881],[4.12237,45.02925],[2.67739,45.02967],[0.41111,45.02991],[4.6702,45.03068],[1.04786,45.03142],[2.57679,45.03142],[3.08242,45.03302],[6.54533,45.03396],[6.3539,45.03562],[-0.56112,45.03854],[4.68862,45.03903],[4.06357,45.03913],[4.0501,45.03952],[0.75192,45.04053],[-0.94274,45.04056],[1.11901,45.04096],[6.12619,45.04155],[-0.13317,45.04157],[1.15021,45.04183],[0.25676,45.04234],[6.29701,45.0434],[3.93043,45.04377],[6.31009,45.04518],[0.88822,45.04543],[1.88427,45.04585],[6.05571,45.04637],[3.04841,45.04667],[3.88094,45.05042],[3.10798,45.05043],[4.70007,45.05049],[0.39142,45.05145],[0.99135,45.05149],[2.71341,45.05187],[4.71247,45.0519],[6.03558,45.05252],[4.39536,45.05326],[2.426,45.05327],[1.24177,45.05437],[4.29891,45.05439],[4.25412,45.05442],[0.98708,45.05511],[4.06412,45.05636],[1.91468,45.05722],[4.49871,45.05781],[5.25596,45.0583],[4.34731,45.05858],[5.25359,45.05904],[4.29694,45.0595],[5.27957,45.05956],[1.15882,45.05996],[3.95715,45.06036],[1.66378,45.06142],[5.33313,45.06168],[5.39533,45.06349],[6.03785,45.06401],[6.03903,45.06408],[0.88838,45.06432],[5.39439,45.06455],[4.79249,45.06457],[4.79056,45.06471],[4.79017,45.0648],[6.03965,45.06555],[-1.01936,45.0656],[1.32631,45.06585],[5.39266,45.06591],[4.7947,45.06604],[-1.04812,45.06639],[-1.13907,45.0666],[4.84648,45.06755],[1.27725,45.06768],[6.04498,45.06773],[4.78499,45.0679],[4.78863,45.06795],[1.43057,45.06979],[-1.04092,45.07021],[1.24933,45.07087],[0.9717,45.0711],[4.82762,45.07167],[4.01556,45.07191],[2.25895,45.07212],[1.23503,45.07218],[1.13843,45.07266],[-1.04444,45.07381],[1.92254,45.07399],[-1.07299,45.07458],[2.66388,45.07481],[-1.07346,45.07494],[1.6687,45.07517],[0.01607,45.07521],[1.91714,45.07525],[1.91584,45.07552],[1.9869,45.07574],[-1.074,45.07607],[-1.06779,45.07623],[4.64088,45.07644],[1.93142,45.07686],[5.55632,45.07752],[2.83013,45.07764],[6.18045,45.07864],[2.23081,45.07913],[-0.20641,45.07937],[2.1019,45.07941],[2.22857,45.08114],[1.9295,45.08146],[-1.05704,45.08438],[-1.18531,45.08475],[5.69906,45.08501],[-1.05499,45.08541],[-1.06404,45.08587],[5.77018,45.08668],[5.55501,45.08778],[-1.03347,45.08928],[6.00757,45.09072],[-0.54799,45.09127],[-0.36742,45.09274],[3.62643,45.0931],[4.49879,45.09356],[0.81592,45.09453],[-0.0498,45.0972],[1.38708,45.09871],[1.45115,45.09975],[1.52443,45.10049],[5.80105,45.10069],[-1.14908,45.1011],[2.59587,45.10126],[3.49963,45.1024],[1.94301,45.10249],[2.86544,45.10274],[5.29269,45.10328],[0.97376,45.10341],[-0.99946,45.1043],[2.07328,45.10644],[4.891,45.10722],[0.46991,45.10756],[0.59487,45.10835],[4.67531,45.11032],[3.0284,45.11083],[4.27769,45.11108],[1.95896,45.11154],[0.91905,45.11187],[-1.06732,45.11214],[2.08611,45.11264],[2.50013,45.11327],[6.00801,45.11443],[2.42349,45.11582],[6.00532,45.11583],[5.23998,45.11624],[2.81136,45.11645],[5.58575,45.11802],[5.99844,45.11866],[1.09119,45.11895],[4.99294,45.11927],[3.79357,45.12041],[1.26213,45.12062],[6.0127,45.12068],[5.33233,45.12094],[4.80026,45.12118],[5.33843,45.12159],[2.05534,45.12205],[0.22627,45.12305],[4.53397,45.12369],[4.92435,45.12394],[5.16275,45.12419],[3.92132,45.12506],[0.98053,45.12581],[6.03572,45.12707],[3.62151,45.12736],[1.75429,45.12817],[0.77053,45.12864],[6.041,45.12897],[2.96755,45.12919],[-0.66621,45.12936],[5.53248,45.12959],[0.92866,45.13156],[1.76295,45.13177],[4.12522,45.13251],[4.26022,45.13266],[2.48768,45.13321],[4.25844,45.13358],[5.00527,45.13577],[-1.06366,45.13593],[2.22247,45.13672],[3.97096,45.13926],[-0.48676,45.13966],[0.87164,45.14204],[4.60252,45.14338],[3.58425,45.14362],[5.5154,45.14441],[2.09893,45.14456],[2.03467,45.14557],[1.75898,45.14607],[5.0214,45.14631],[2.49933,45.14697],[0.53314,45.1475],[5.43875,45.14769],[0.7776,45.14798],[-0.00241,45.14884],[4.20422,45.14898],[1.62013,45.15028],[3.40741,45.15227],[2.62205,45.15296],[4.31508,45.15317],[1.87096,45.1534],[3.44329,45.15379],[5.83679,45.15407],[2.93773,45.15458],[3.57825,45.15577],[1.68157,45.15653],[5.8586,45.15679],[2.7086,45.15788],[0.27145,45.159],[5.00979,45.1596],[1.18368,45.16189],[0.58891,45.16231],[1.29095,45.16389],[-0.34095,45.16563],[1.97878,45.1661],[5.6988,45.16692],[-0.61678,45.16705],[6.42937,45.16891],[5.53868,45.17041],[1.39565,45.17074],[5.41503,45.17183],[-1.0531,45.17249],[-1.05326,45.17362],[-0.83939,45.17489],[5.54804,45.1752],[2.3194,45.17527],[3.21668,45.17755],[3.04955,45.17841],[4.73954,45.17893],[-1.07479,45.17931],[0.00199,45.18109],[-1.07584,45.18209],[-1.04467,45.18374],[4.18464,45.18435],[-0.74235,45.18518],[-1.04019,45.18565],[1.70731,45.18617],[3.90646,45.18632],[0.74192,45.18678],[3.75017,45.18681],[0.47916,45.18709],[4.81239,45.18788],[1.8183,45.18839],[0.02631,45.19036],[4.75571,45.19195],[6.66404,45.19414],[4.03618,45.19885],[5.02247,45.19933],[3.52028,45.19986],[2.53031,45.20165],[2.43967,45.20175],[4.956,45.20186],[1.96098,45.20193],[2.14769,45.20199],[0.87219,45.20216],[3.94332,45.20301],[1.63401,45.20437],[3.39817,45.20598],[5.88323,45.20682],[0.13285,45.20797],[6.53747,45.20858],[3.99789,45.20879],[3.71979,45.20883],[2.71838,45.20936],[0.89883,45.20962],[4.04136,45.21008],[2.32356,45.2111],[2.07646,45.21154],[-0.13661,45.21211],[4.89325,45.21272],[6.4783,45.21279],[0.83742,45.21297],[0.75645,45.2133],[0.12854,45.21341],[4.21268,45.21608],[-1.07792,45.21773],[2.31593,45.21867],[1.51847,45.21892],[2.93872,45.21896],[0.86323,45.21984],[5.16794,45.22159],[0.94011,45.2216],[4.15162,45.22286],[-1.16457,45.22288],[2.17277,45.2229],[6.21636,45.22334],[4.95097,45.22405],[6.74599,45.22447],[6.78096,45.22869],[5.38368,45.23039],[0.98472,45.23119],[3.13437,45.23347],[2.46321,45.23622],[0.83098,45.24216],[6.27994,45.24297],[-0.62971,45.24576],[2.69422,45.24666],[5.24808,45.24679],[1.13795,45.24767],[2.53653,45.24839],[3.19224,45.24844],[-0.25126,45.24862],[-1.08483,45.24875],[1.78962,45.24998],[2.07897,45.25048],[0.11698,45.25226],[5.02657,45.25273],[4.1304,45.25316],[2.34713,45.25332],[4.9033,45.25474],[0.49665,45.25648],[0.34234,45.25713],[4.80347,45.25714],[6.2734,45.25763],[4.67426,45.25799],[1.91796,45.25826],[2.80251,45.25863],[5.77615,45.26002],[6.80853,45.26093],[-1.05027,45.26166],[6.79961,45.26309],[1.30016,45.26374],[4.48831,45.26462],[1.30366,45.26555],[1.15373,45.26706],[3.12188,45.26728],[0.33605,45.26772],[-0.40119,45.26785],[-1.16018,45.26807],[-1.06819,45.26828],[1.06929,45.26841],[2.00885,45.26921],[0.17552,45.2694],[4.56794,45.26944],[5.10184,45.27129],[5.28799,45.27141],[6.35109,45.27157],[1.16835,45.27275],[1.59586,45.27329],[3.7112,45.27433],[5.98682,45.27727],[3.10751,45.27738],[1.96566,45.2786],[6.81521,45.27941],[1.0485,45.28044],[1.45776,45.28066],[2.20999,45.28066],[2.787,45.28077],[1.15922,45.28101],[0.54021,45.28127],[3.40467,45.28133],[-1.05149,45.28209],[2.66721,45.28217],[4.97735,45.2826],[6.81442,45.28383],[6.87375,45.28432],[-1.0645,45.28444],[-0.9152,45.28805],[6.22152,45.29028],[0.53047,45.29039],[6.90927,45.29049],[-0.79253,45.2915],[1.58299,45.29472],[4.11974,45.29475],[-1.06647,45.29489],[2.16513,45.29599],[4.92527,45.2981],[5.49845,45.29835],[4.5819,45.29911],[2.3862,45.29914],[5.99546,45.29961],[-0.43557,45.29977],[1.1316,45.29998],[4.80734,45.30006],[4.44887,45.30081],[4.28295,45.3012],[-0.2319,45.3022],[5.87968,45.303],[2.58502,45.30384],[3.21131,45.30634],[4.98817,45.30637],[1.86789,45.30677],[1.97172,45.30746],[4.11838,45.30785],[3.79004,45.30797],[4.74675,45.30862],[6.97319,45.3091],[-1.09263,45.31121],[3.17284,45.31208],[0.26861,45.31209],[-1.08165,45.31268],[4.82455,45.31429],[-0.60296,45.31434],[4.41396,45.31473],[-0.56434,45.31494],[1.32049,45.31519],[-0.24588,45.31637],[6.08387,45.31859],[5.94754,45.32087],[4.54879,45.32188],[4.64687,45.32269],[-0.30569,45.32377],[4.90246,45.3239],[4.51727,45.32456],[0.52328,45.3248],[2.20426,45.3248],[4.83633,45.32488],[-0.62632,45.32556],[5.7972,45.3258],[4.61022,45.32666],[3.68686,45.32681],[3.84823,45.32739],[-0.02387,45.32751],[2.4759,45.32843],[5.26898,45.32846],[1.75483,45.32846],[0.63733,45.32931],[5.66561,45.32986],[4.66199,45.33076],[2.48581,45.33274],[2.75865,45.3339],[3.70416,45.33414],[1.36786,45.33475],[7.02207,45.33516],[4.42295,45.33521],[1.06017,45.33672],[2.47398,45.33676],[5.05998,45.33792],[2.52214,45.33827],[0.11514,45.33908],[2.43943,45.34128],[4.65911,45.34221],[-1.07159,45.34471],[2.69567,45.34499],[1.51537,45.34632],[0.65654,45.34701],[1.21071,45.3476],[1.64513,45.34966],[0.37113,45.35061],[1.10504,45.35234],[-1.05977,45.35278],[-0.66257,45.35399],[-0.6014,45.35468],[3.96134,45.35539],[4.19422,45.36026],[0.66045,45.36087],[6.31339,45.36102],[-0.11693,45.36138],[-1.14602,45.36306],[2.5004,45.3633],[1.87147,45.36459],[-1.09655,45.36475],[2.40682,45.36532],[3.50618,45.36562],[2.58211,45.36635],[4.02144,45.36645],[6.09741,45.36674],[-1.09943,45.36715],[2.73373,45.3685],[1.53801,45.36901],[6.31359,45.36922],[-1.14481,45.37009],[-1.14453,45.3701],[1.5281,45.37011],[5.18276,45.37041],[4.68101,45.37131],[1.88075,45.37242],[-1.07995,45.37407],[1.25306,45.37444],[4.76975,45.37457],[1.94198,45.3746],[-1.08236,45.3759],[6.72236,45.37667],[6.72382,45.37708],[1.3841,45.37716],[5.54936,45.37805],[-0.56874,45.37822],[1.70277,45.37874],[5.641,45.38068],[-1.15821,45.38168],[2.22915,45.38238],[-0.239,45.38287],[-0.72444,45.38294],[5.95177,45.38296],[4.98261,45.38434],[2.29285,45.38442],[4.75274,45.38656],[3.2661,45.38695],[3.89067,45.38724],[3.94465,45.38811],[6.06459,45.3885],[3.94825,45.38981],[2.30499,45.391],[5.7378,45.39115],[2.55064,45.39125],[1.24955,45.39147],[2.39037,45.3916],[1.75903,45.39228],[6.10623,45.39229],[6.27239,45.39246],[5.17412,45.39366],[3.37473,45.39378],[2.60333,45.39435],[0.29363,45.39611],[-1.09495,45.39635],[1.86205,45.3965],[4.78651,45.39723],[2.28661,45.39742],[-1.09513,45.39871],[-1.04828,45.39875],[1.64602,45.39897],[6.08033,45.40098],[2.28137,45.40401],[2.66528,45.40423],[0.7208,45.40562],[1.48589,45.40708],[2.28312,45.40834],[1.47897,45.40837],[0.28109,45.40839],[-1.03228,45.40844],[6.55972,45.40889],[2.2845,45.41038],[3.33599,45.41061],[4.81331,45.41282],[0.93206,45.41326],[3.71854,45.41353],[2.39188,45.41366],[0.57204,45.41375],[4.6914,45.41384],[1.16367,45.41423],[-1.13279,45.41643],[2.48037,45.41674],[-0.95081,45.41699],[4.26151,45.41794],[2.72544,45.41796],[2.06448,45.4182],[4.00847,45.41854],[1.56872,45.41874],[2.33707,45.41916],[5.85839,45.42022],[1.82722,45.42047],[5.47219,45.42088],[4.71406,45.42113],[4.07169,45.4222],[1.71534,45.42358],[4.78242,45.42408],[4.85415,45.42425],[0.53023,45.42459],[4.92878,45.42622],[-0.44854,45.42921],[1.4545,45.4297],[5.70161,45.42977],[6.03724,45.42987],[2.50392,45.43057],[5.51417,45.43118],[3.8822,45.43156],[4.80194,45.43245],[-0.75179,45.43257],[-1.14482,45.43355],[4.22511,45.43377],[-0.24254,45.43428],[-1.03137,45.43436],[5.75595,45.43465],[5.51369,45.43526],[0.88834,45.4355],[-1.09147,45.43659],[0.77644,45.43665],[-0.47554,45.4389],[1.55246,45.44099],[5.51479,45.44187],[6.65996,45.44219],[1.40924,45.44249],[-0.43241,45.4435],[2.48827,45.44358],[3.38118,45.44448],[-1.08658,45.44538],[0.50884,45.44607],[5.53133,45.44611],[6.99248,45.44646],[0.45164,45.44666],[3.4411,45.44699],[2.38598,45.44745],[2.49392,45.44858],[5.54403,45.44911],[6.10298,45.44989],[3.22856,45.44997],[1.65069,45.45178],[1.97498,45.45207],[6.15626,45.4523],[2.51018,45.45238],[5.88319,45.45272],[6.56192,45.45301],[-0.48968,45.4544],[5.63399,45.45506],[5.54545,45.4566],[5.81309,45.4567],[3.54804,45.45681],[4.71843,45.457],[4.74559,45.45815],[5.54921,45.45958],[6.1569,45.45987],[6.73911,45.45991],[4.77722,45.46066],[-0.13858,45.46438],[2.77658,45.46458],[2.76939,45.46545],[5.55891,45.46752],[1.73085,45.46823],[1.61125,45.46881],[2.71884,45.46894],[5.98905,45.46957],[-0.77834,45.46999],[0.80152,45.47006],[5.54685,45.47085],[1.08379,45.47233],[4.32428,45.4724],[3.27203,45.47332],[0.93803,45.47361],[0.53658,45.47414],[3.76029,45.47421],[3.55401,45.47473],[3.43624,45.47587],[6.04009,45.47735],[4.28797,45.4774],[-1.04138,45.47909],[-0.79147,45.47996],[3.73093,45.48006],[-1.14564,45.48032],[1.07285,45.48118],[-1.1509,45.48193],[-1.12716,45.48285],[5.74687,45.48318],[-1.13912,45.48328],[-1.11899,45.48337],[2.53767,45.48453],[-1.11815,45.48562],[-1.12655,45.48745],[1.10274,45.48771],[-0.32088,45.49205],[5.22123,45.49255],[0.44874,45.49502],[-0.74632,45.4954],[5.99385,45.49608],[0.7478,45.49701],[2.63465,45.49759],[-1.13752,45.49908],[0.9064,45.49926],[1.06204,45.49938],[4.21033,45.49989],[6.92193,45.50115],[1.70424,45.50139],[-1.13188,45.50173],[4.72723,45.50178],[1.86907,45.50201],[0.91452,45.50255],[6.0657,45.5028],[3.91226,45.50517],[-0.52301,45.50573],[1.32637,45.50588],[0.69244,45.5067],[6.49098,45.50692],[6.48875,45.50709],[4.21594,45.5075],[5.73905,45.5085],[3.28467,45.50883],[5.20655,45.50896],[6.49042,45.50947],[6.48934,45.51045],[-0.80697,45.51443],[6.60848,45.5153],[4.7726,45.51534],[-1.11159,45.5155],[2.94033,45.51641],[1.32322,45.51693],[0.65799,45.51956],[5.79403,45.52214],[3.91501,45.52298],[-0.30452,45.52322],[5.79189,45.52411],[-0.87343,45.52631],[2.70039,45.52788],[1.20023,45.52806],[5.77768,45.52836],[-0.88024,45.52912],[2.69132,45.52947],[6.77582,45.53109],[2.97669,45.5363],[5.79868,45.53776],[5.79935,45.5382],[3.72878,45.53953],[2.15388,45.53963],[5.77932,45.53982],[5.80229,45.53996],[-1.09395,45.54092],[5.60824,45.54161],[1.63605,45.5424],[2.54275,45.54316],[0.83248,45.54457],[1.54923,45.54472],[0.49687,45.54488],[0.87228,45.54527],[-1.07947,45.54549],[-0.88868,45.54563],[3.36406,45.5457],[3.19897,45.5457],[0.95453,45.54681],[2.28436,45.54758],[-0.83114,45.54985],[5.68122,45.55073],[2.27805,45.55107],[3.27423,45.55113],[0.79554,45.55131],[0.94733,45.5515],[5.98409,45.55153],[1.43611,45.55172],[2.93955,45.55226],[1.1183,45.5547],[5.79134,45.55556],[5.79081,45.55582],[-0.39851,45.55736],[-0.94641,45.5578],[2.88567,45.55817],[6.1693,45.55901],[5.67594,45.55927],[-0.07125,45.55974],[1.81357,45.55977],[0.75914,45.56026],[-0.96051,45.56038],[-0.96223,45.56054],[6.73934,45.56076],[-0.9635,45.56096],[3.10594,45.56116],[2.62532,45.5612],[1.32825,45.56156],[-0.94715,45.56165],[0.7195,45.5621],[5.79446,45.56252],[-0.93737,45.56257],[2.93838,45.56281],[5.74472,45.56342],[6.16365,45.56516],[-0.95903,45.56523],[0.83759,45.56653],[5.79454,45.56655],[-0.94957,45.56768],[2.94014,45.56819],[-0.68164,45.56829],[5.78385,45.56835],[6.67102,45.56839],[1.09669,45.56846],[5.78696,45.56906],[2.9026,45.56955],[-0.97125,45.56966],[6.73999,45.56971],[-0.57811,45.56978],[-0.95689,45.57057],[2.8909,45.57103],[5.79436,45.57108],[2.81793,45.57129],[2.93066,45.57155],[-0.89459,45.57173],[3.01368,45.57174],[-0.9609,45.57239],[2.95728,45.57378],[3.63415,45.57446],[2.91428,45.57516],[2.99981,45.57523],[3.00181,45.5755],[2.93112,45.5758],[-0.98094,45.57656],[6.73402,45.57663],[2.93212,45.57703],[2.80387,45.57711],[3.99462,45.57769],[-0.55514,45.57778],[1.70811,45.57809],[5.09048,45.57896],[2.79251,45.57897],[3.00192,45.57973],[6.67039,45.57984],[-0.98154,45.58327],[-0.98659,45.58354],[-0.97914,45.5836],[-0.77816,45.58425],[1.26986,45.58429],[5.7905,45.5848],[3.09209,45.58482],[2.6521,45.58501],[-0.77571,45.58519],[-0.98551,45.5852],[5.65025,45.58589],[-0.83568,45.58666],[2.80149,45.58672],[2.54895,45.58705],[4.57498,45.58706],[2.75257,45.5898],[-0.00593,45.59082],[3.63978,45.59107],[4.07799,45.5913],[1.11101,45.59185],[4.3358,45.59268],[2.75483,45.59368],[0.67312,45.5937],[2.75611,45.59388],[-0.53881,45.59443],[2.76335,45.59451],[-0.85972,45.5957],[5.63468,45.59589],[2.75115,45.59684],[-0.90371,45.59742],[4.04269,45.59926],[-0.36965,45.59952],[0.70784,45.59991],[0.75738,45.60013],[2.73513,45.60047],[-0.98894,45.60052],[-0.36054,45.60127],[-0.98638,45.60194],[2.68991,45.60272],[2.73758,45.60276],[-0.94762,45.60428],[-0.94392,45.6045],[1.92424,45.60497],[2.69621,45.60543],[-0.96842,45.60584],[-0.93753,45.60596],[4.38001,45.60602],[1.88394,45.60662],[0.0242,45.60736],[0.78444,45.60745],[1.07467,45.60915],[0.88958,45.61028],[6.09683,45.61033],[-0.91967,45.61053],[-0.98313,45.61056],[-0.52159,45.61158],[1.50138,45.61163],[1.03171,45.61368],[-0.99465,45.61505],[1.12331,45.61517],[4.67079,45.61556],[1.1425,45.61611],[2.69324,45.61688],[5.12328,45.61778],[-1.00423,45.61809],[5.52937,45.61878],[1.42862,45.61927],[1.59315,45.62221],[6.78475,45.62248],[6.85472,45.62326],[3.56262,45.62373],[0.68192,45.62554],[6.79363,45.62593],[4.97619,45.62741],[2.08892,45.62833],[6.44927,45.62881],[6.44103,45.62894],[-0.9461,45.62993],[-1.04988,45.63106],[5.572,45.6344],[4.42815,45.63472],[1.16037,45.63505],[5.64905,45.63982],[5.62793,45.64097],[1.82539,45.64175],[1.08893,45.64241],[-1.07679,45.64267],[-1.07191,45.64269],[-1.06338,45.64404],[-1.04205,45.64454],[-0.98637,45.64481],[-0.99589,45.64492],[3.23645,45.6455],[-1.03558,45.64569],[-1.07413,45.64569],[-1.08027,45.6457],[-1.02705,45.64575],[-1.02891,45.64652],[2.55132,45.64662],[-0.95852,45.64786],[4.48506,45.64821],[5.05033,45.64856],[-0.95426,45.64919],[-1.06067,45.64928],[4.56517,45.64942],[-1.11785,45.64952],[-1.11853,45.64981],[-1.12019,45.65092],[1.67854,45.6514],[-1.10902,45.65154],[-1.11927,45.65155],[4.563,45.65199],[-1.11876,45.65202],[5.86317,45.6531],[4.50622,45.6538],[2.4611,45.65424],[0.78963,45.65474],[-1.08484,45.65496],[-1.04501,45.65626],[-1.06729,45.65758],[-1.07029,45.6576],[2.95411,45.65814],[-1.02036,45.65922],[6.57929,45.65933],[0.55839,45.65977],[2.97685,45.66036],[1.65078,45.66191],[2.94864,45.66208],[6.42177,45.66508],[0.5079,45.66681],[3.20512,45.66785],[0.79026,45.66852],[2.98914,45.66922],[3.00054,45.66977],[1.17952,45.67063],[2.18382,45.67142],[-1.05825,45.67221],[-0.22766,45.67259],[-1.09629,45.67442],[4.42401,45.67475],[-0.17304,45.67574],[0.64027,45.67674],[-1.05119,45.67804],[6.39534,45.67807],[1.93825,45.67836],[3.20459,45.67902],[5.46395,45.67914],[5.80235,45.67969],[4.57395,45.68039],[-1.10397,45.68113],[-0.9382,45.68266],[1.6348,45.68285],[5.85551,45.68391],[3.06173,45.68414],[2.82581,45.68545],[-0.93997,45.68631],[4.78606,45.6871],[4.63444,45.68731],[-1.11341,45.6878],[2.74114,45.68786],[6.13095,45.68833],[-1.10827,45.68863],[5.35146,45.68909],[1.37139,45.6893],[3.6332,45.69004],[0.14562,45.69121],[-1.18308,45.69235],[-1.18402,45.69266],[-1.00298,45.69277],[0.44161,45.69314],[5.8248,45.69379],[5.89672,45.69469],[-1.02744,45.69483],[5.88896,45.69659],[-1.22952,45.69705],[-1.06603,45.70007],[3.16902,45.70018],[1.09373,45.70073],[-0.49427,45.7009],[5.88606,45.70107],[-1.16763,45.70134],[2.04071,45.7015],[-1.1574,45.70187],[6.11169,45.70272],[3.72467,45.70312],[5.78862,45.7052],[5.75327,45.70557],[4.58851,45.70619],[4.05503,45.70632],[2.86097,45.7084],[-0.31276,45.70901],[5.95769,45.70999],[-1.1486,45.71044],[-1.1281,45.71255],[6.31583,45.71258],[0.78835,45.71413],[-0.55916,45.71532],[-1.1554,45.71533],[0.91844,45.71625],[6.08254,45.71655],[1.60132,45.71658],[4.45515,45.7173],[6.45475,45.71742],[5.33179,45.71751],[4.08741,45.71774],[3.92774,45.71936],[1.82573,45.71981],[5.12552,45.72026],[-1.17159,45.72112],[6.31318,45.72146],[4.43345,45.7215],[6.56387,45.72158],[5.9751,45.72185],[-1.17445,45.72333],[-1.17429,45.72428],[-1.14633,45.72452],[5.48523,45.72478],[2.89029,45.72573],[-1.17546,45.72625],[-1.17569,45.72772],[3.34573,45.7286],[-1.17904,45.72982],[-1.17597,45.72993],[1.75288,45.73039],[-1.17665,45.73207],[-1.10228,45.73275],[2.81403,45.73366],[0.6807,45.7339],[-1.17679,45.73446],[3.97109,45.73717],[4.01077,45.73731],[2.34104,45.73885],[3.06242,45.73887],[3.22316,45.74059],[0.58627,45.74074],[0.08562,45.7415],[4.40654,45.74277],[5.48141,45.74278],[-1.11372,45.74418],[0.38075,45.74508],[-1.12736,45.74525],[6.5355,45.74717],[5.22559,45.74859],[1.69301,45.74965],[1.9373,45.75035],[4.05671,45.75042],[4.24365,45.75055],[4.64307,45.75088],[4.53649,45.75108],[3.54915,45.75346],[6.13873,45.75378],[4.22599,45.75462],[-0.62872,45.75509],[6.56441,45.75532],[3.57284,45.75555],[3.59254,45.75566],[5.92898,45.75674],[-1.14063,45.75831],[-1.17316,45.75841],[3.0545,45.75854],[-0.94284,45.75948],[-0.94367,45.75973],[5.93041,45.76138],[6.33664,45.76191],[5.90902,45.76236],[-1.15207,45.76363],[6.03024,45.76594],[-0.49587,45.76596],[2.75504,45.76625],[6.30875,45.76675],[4.56689,45.76677],[5.91237,45.76699],[5.90192,45.76782],[5.76978,45.76873],[4.45059,45.77053],[3.97979,45.77157],[-1.16676,45.77306],[-0.96518,45.7743],[6.22611,45.77521],[0.55837,45.7756],[3.24191,45.77565],[5.54781,45.77848],[5.81483,45.77896],[6.20382,45.78181],[0.11871,45.78244],[2.4276,45.78349],[2.70344,45.78432],[5.94244,45.78473],[4.56904,45.78477],[6.23225,45.78533],[4.55861,45.78611],[5.40729,45.78636],[1.86665,45.78644],[-1.15788,45.78749],[4.3455,45.78751],[-1.15861,45.7886],[3.01128,45.7886],[1.89662,45.78962],[6.21772,45.79024],[6.21366,45.79061],[4.99195,45.79075],[-1.16029,45.79076],[6.21635,45.79089],[3.60569,45.79215],[1.90474,45.79296],[1.90761,45.79341],[5.81938,45.79351],[6.20564,45.79514],[5.45782,45.79526],[-1.15121,45.79608],[6.14798,45.79659],[0.06374,45.7977],[1.13946,45.79876],[2.47013,45.79913],[6.20558,45.79962],[3.61639,45.79972],[6.20439,45.80042],[3.94092,45.80134],[6.15151,45.80162],[6.2056,45.8021],[6.20977,45.80256],[6.7217,45.8028],[1.62951,45.80287],[1.84334,45.80307],[3.26192,45.80309],[0.70679,45.80385],[5.30071,45.80388],[5.8456,45.80506],[1.84338,45.80518],[3.76836,45.8081],[5.18589,45.80831],[5.18535,45.80891],[5.12432,45.809],[-0.55294,45.81089],[-1.06109,45.81095],[-0.81831,45.81119],[5.78909,45.81123],[2.43791,45.81174],[5.84937,45.81242],[6.33761,45.81317],[0.8178,45.81325],[6.03024,45.81572],[5.42767,45.81622],[4.62816,45.8163],[2.32483,45.81652],[6.14811,45.81764],[3.86963,45.81783],[1.65245,45.81799],[-1.1343,45.81886],[4.76109,45.81972],[6.53525,45.82226],[1.49177,45.82285],[4.06804,45.824],[6.18581,45.82427],[0.99664,45.82466],[4.16247,45.82507],[0.44421,45.82513],[-1.13744,45.82542],[1.76584,45.82574],[6.22046,45.82602],[6.22135,45.82661],[6.18876,45.82667],[-1.13411,45.82668],[-0.8708,45.82718],[5.42066,45.82748],[-1.13077,45.82942],[-1.21632,45.82947],[4.02344,45.82951],[5.64447,45.82956],[2.84511,45.8297],[6.22051,45.82989],[6.1817,45.83],[6.17854,45.83074],[-1.21342,45.83125],[-1.15092,45.83139],[5.30061,45.83212],[0.5579,45.83277],[-0.64668,45.83294],[6.57679,45.8361],[4.50779,45.83625],[6.56737,45.83633],[6.17864,45.8368],[-0.30852,45.8369],[6.58954,45.83898],[6.58984,45.83962],[2.81326,45.83972],[4.13997,45.84026],[6.5891,45.84038],[6.16477,45.84073],[5.96267,45.84096],[2.75921,45.84161],[0.27287,45.84162],[2.78903,45.84259],[6.14193,45.84286],[4.53925,45.84379],[6.15351,45.84392],[2.8769,45.84441],[6.21335,45.84564],[0.62005,45.84619],[6.15129,45.84806],[5.83456,45.84922],[-0.19932,45.8501],[5.41355,45.85032],[-0.70651,45.85234],[1.96276,45.85269],[5.79289,45.8527],[6.14408,45.85479],[-1.22899,45.85649],[6.19948,45.85708],[0.63739,45.85925],[6.05226,45.86129],[6.04117,45.86156],[-1.24047,45.86216],[6.19698,45.86295],[2.67141,45.86448],[3.47651,45.86801],[1.74997,45.86983],[1.27578,45.87056],[3.48569,45.87167],[3.04674,45.8726],[0.81897,45.87287],[6.72004,45.87378],[6.14135,45.87447],[5.68356,45.87471],[0.7152,45.87667],[-0.68448,45.87796],[0.18184,45.878],[0.86195,45.8783],[6.63586,45.87913],[6.51094,45.87918],[6.64178,45.87924],[6.17611,45.87955],[5.84157,45.88076],[0.96539,45.88078],[-1.24874,45.8812],[2.4928,45.88187],[-1.20648,45.88207],[3.89063,45.88331],[6.65908,45.88599],[5.58758,45.88689],[-1.27557,45.88703],[0.10463,45.88724],[-1.21425,45.88747],[6.30417,45.88747],[1.51218,45.88843],[0.67759,45.88939],[-1.20001,45.88954],[6.22367,45.8899],[6.13224,45.89043],[2.69457,45.89093],[6.78881,45.89135],[6.3352,45.89222],[-1.2142,45.89359],[0.4692,45.89383],[6.6542,45.89404],[3.0539,45.89505],[0.89979,45.89616],[-0.92381,45.89699],[6.82946,45.89819],[2.71384,45.89959],[2.7369,45.90127],[-1.29516,45.90144],[6.83819,45.90154],[3.93055,45.90162],[-1.30266,45.90164],[6.8372,45.902],[6.83672,45.90233],[5.92854,45.90242],[3.59887,45.90299],[-1.30085,45.90327],[-1.30249,45.90386],[-1.21544,45.90424],[6.83583,45.90535],[-1.26903,45.90537],[6.83682,45.9058],[3.06104,45.9059],[5.67928,45.90652],[6.14969,45.90699],[6.15008,45.90709],[6.45203,45.90922],[0.25352,45.90966],[6.00786,45.90974],[6.15375,45.91126],[4.81355,45.91134],[4.06574,45.91171],[5.23397,45.9119],[6.65858,45.91194],[6.86427,45.91227],[-1.22397,45.91281],[2.03911,45.91281],[-1.27901,45.91303],[-1.27883,45.9135],[3.84019,45.91448],[6.8615,45.91472],[3.07773,45.9148],[2.48813,45.91513],[6.60652,45.91537],[2.75637,45.91562],[4.06105,45.91566],[6.64754,45.91608],[-1.25276,45.91644],[6.64897,45.91704],[-1.29822,45.91804],[-1.29203,45.91814],[1.43996,45.91855],[-1.28952,45.91905],[-1.28982,45.92011],[2.16643,45.92096],[3.01231,45.92198],[-1.27161,45.9229],[6.61424,45.92299],[-1.34154,45.92308],[-1.34127,45.92311],[-1.34247,45.92373],[6.65449,45.92394],[6.65087,45.92395],[6.40267,45.92467],[4.55147,45.92596],[6.64623,45.92736],[4.13324,45.92899],[6.7699,45.92993],[-0.95816,45.93024],[4.12834,45.93247],[-1.31441,45.93306],[1.28945,45.93335],[-0.24282,45.93359],[-1.06009,45.93373],[6.64682,45.9364],[6.89257,45.93776],[4.26745,45.9386],[2.80001,45.93982],[4.76887,45.93985],[2.843,45.9399],[6.4282,45.94023],[6.44249,45.94024],[4.7268,45.9405],[1.5147,45.94308],[2.76518,45.94466],[-1.36916,45.946],[2.17608,45.94652],[1.81331,45.94684],[-1.37265,45.94795],[-1.09574,45.94819],[-0.53645,45.94868],[-0.99552,45.94875],[-1.36608,45.94904],[5.82347,45.9496],[6.74023,45.95025],[5.45846,45.9505],[-1.37932,45.95386],[5.53228,45.95395],[-1.37816,45.9573],[-1.11697,45.9592],[-1.38234,45.95954],[-1.36649,45.95981],[0.52882,45.96038],[-1.37032,45.96119],[3.46632,45.96231],[3.73926,45.96264],[5.83654,45.96374],[0.77822,45.96396],[1.75829,45.96464],[0.70939,45.96602],[-1.31758,45.96687],[-1.31869,45.96791],[-1.24475,45.9683],[-1.31831,45.96884],[6.01322,45.96891],[-1.31439,45.97041],[-1.3864,45.97059],[-0.98649,45.9707],[5.59563,45.9708],[-1.31749,45.97119],[1.41351,45.9714],[5.70158,45.9717],[4.75194,45.97247],[5.59562,45.97319],[6.92371,45.97475],[6.03575,45.97822],[-1.24106,45.97843],[-1.0825,45.97843],[6.03363,45.97913],[3.6394,45.98075],[1.89497,45.98266],[6.27137,45.98424],[2.63139,45.98518],[3.74615,45.98703],[5.04339,45.98736],[-1.29347,45.98738],[4.04462,45.98839],[-1.05191,45.99007],[-1.37314,45.99014],[-1.01955,45.99056],[4.81652,45.99087],[4.90385,45.99113],[5.13857,45.99154],[1.04942,45.99174],[-1.37992,45.9924],[-1.0868,45.99264],[6.92981,45.9942],[0.31926,45.99618],[5.03049,45.99728],[1.60322,45.9987],[-1.1182,46.002],[6.19079,46.00238],[-1.38496,46.00351],[5.29848,46.00364],[2.2082,46.00411],[6.06631,46.00444],[6.39429,46.00446],[1.153,46.00471],[-1.38394,46.00476],[1.33529,46.00565],[0.09671,46.00736],[-1.17654,46.00964],[5.97607,46.01036],[2.46523,46.01206],[-1.35534,46.01291],[4.38151,46.01315],[1.27856,46.01404],[0.21285,46.01495],[0.87682,46.01522],[-1.39238,46.01523],[6.24272,46.01645],[-0.79092,46.01667],[5.94327,46.01704],[4.38095,46.01862],[-1.3554,46.01892],[0.67531,46.01905],[-1.35769,46.02022],[4.79351,46.0208],[2.13905,46.02132],[3.6534,46.0223],[1.71751,46.02303],[5.59206,46.02304],[4.31886,46.02359],[6.92427,46.02381],[-1.36069,46.02437],[1.65718,46.02529],[2.89894,46.02741],[-1.38325,46.02766],[2.90173,46.02938],[5.49749,46.03097],[2.95693,46.03206],[1.29575,46.0325],[-1.0227,46.03262],[-1.37337,46.03288],[2.28184,46.03344],[2.81778,46.03693],[-1.38789,46.03813],[-1.37462,46.03825],[-1.38816,46.0391],[4.36884,46.04167],[-1.40456,46.04215],[0.67304,46.04296],[2.49906,46.04321],[-0.27434,46.0448],[5.34443,46.04665],[4.66071,46.047],[4.40499,46.04754],[1.27889,46.04962],[2.8245,46.05004],[4.76371,46.05026],[4.49313,46.051],[3.80144,46.0537],[5.15821,46.05409],[-1.0834,46.0548],[3.8031,46.05499],[-0.9542,46.05519],[4.81806,46.05624],[0.97766,46.05718],[2.76716,46.05719],[2.59823,46.05771],[3.45906,46.06078],[1.39204,46.06088],[3.6685,46.06102],[4.97246,46.0617],[6.57352,46.0694],[-0.86774,46.07059],[2.77631,46.07317],[3.70011,46.07331],[-1.01816,46.07412],[6.83449,46.07458],[4.76289,46.07471],[0.26016,46.07489],[6.7186,46.07706],[2.75072,46.07913],[3.38221,46.07965],[2.04421,46.07981],[1.58516,46.0819],[6.41259,46.08219],[6.41252,46.0827],[3.74323,46.0833],[2.57252,46.0838],[-1.09334,46.08395],[5.15212,46.08641],[-1.09422,46.08664],[-1.09594,46.08762],[6.6782,46.08941],[5.40415,46.08985],[3.8421,46.09018],[0.49889,46.09185],[3.19399,46.09187],[-0.39382,46.0922],[1.47784,46.0936],[2.92922,46.09589],[0.48081,46.09696],[6.08308,46.0984],[1.57949,46.0988],[6.58796,46.09918],[1.35433,46.10015],[-0.7534,46.10135],[1.83532,46.10242],[4.94777,46.10261],[2.16079,46.10346],[-1.13065,46.10411],[3.01471,46.10739],[3.43659,46.10752],[-0.0926,46.10763],[-1.05295,46.10773],[3.04435,46.10827],[3.07361,46.10854],[-0.07866,46.10981],[3.08082,46.11077],[3.01018,46.11118],[3.43227,46.11461],[-0.92658,46.11481],[3.43006,46.11555],[3.67671,46.11574],[2.04543,46.11582],[4.96216,46.11627],[3.42563,46.11644],[-1.11939,46.11659],[3.79438,46.1169],[6.10536,46.12018],[0.37975,46.12208],[0.66061,46.12274],[3.10817,46.12449],[0.09775,46.12566],[1.05088,46.12615],[5.42823,46.12776],[1.27052,46.13179],[6.51869,46.13245],[6.44346,46.13363],[4.9939,46.13732],[5.65874,46.13949],[2.94024,46.14091],[6.47653,46.14245],[-0.21941,46.14408],[2.50835,46.14449],[-1.31509,46.14504],[-0.94571,46.14621],[1.36602,46.14699],[5.33083,46.14728],[-0.11262,46.14796],[4.01337,46.14822],[4.11278,46.14941],[4.45419,46.15028],[-1.15821,46.15056],[6.64287,46.15078],[2.83321,46.15144],[5.60025,46.15147],[1.51073,46.15152],[-1.33357,46.15175],[3.00242,46.15509],[1.70326,46.15724],[-0.63523,46.15773],[-1.27623,46.15815],[0.30169,46.15835],[4.18075,46.15867],[-1.26684,46.15941],[3.05517,46.15983],[3.73535,46.15989],[-1.27682,46.16017],[-1.18436,46.16047],[-1.35269,46.16083],[1.14703,46.16215],[1.85857,46.16247],[6.23088,46.16322],[-0.42956,46.16474],[5.00302,46.16482],[4.33761,46.16502],[4.79207,46.16515],[-1.33437,46.16564],[3.18931,46.16583],[5.57195,46.16684],[-1.36399,46.16853],[-1.3787,46.17434],[1.35346,46.17499],[3.87644,46.17506],[4.81436,46.1752],[-1.38666,46.17742],[-1.11505,46.17784],[-1.0545,46.17807],[-1.38305,46.1783],[2.49009,46.17841],[2.7717,46.17942],[-1.15949,46.17949],[-1.3915,46.18121],[-1.3311,46.18194],[-1.38531,46.18196],[-1.37,46.18209],[-1.30825,46.18381],[4.43043,46.18407],[4.77765,46.18493],[-1.3894,46.1851],[-1.31465,46.1852],[2.43391,46.18597],[-1.40584,46.18676],[-1.34422,46.18748],[4.69893,46.18777],[2.99155,46.1881],[5.81309,46.18887],[-1.39736,46.18905],[2.23847,46.18929],[-1.35053,46.18983],[-1.3562,46.19166],[-1.15868,46.19168],[3.24309,46.19318],[2.81929,46.19326],[-1.43485,46.19335],[1.17361,46.19499],[6.67707,46.19501],[2.8338,46.19565],[-1.18789,46.19568],[6.4596,46.19764],[6.69032,46.19821],[-1.3673,46.19923],[-0.68006,46.19954],[4.33721,46.19968],[0.7791,46.20158],[-1.45075,46.20234],[-1.5273,46.2029],[-1.45511,46.20312],[-0.81619,46.20365],[-1.52035,46.20373],[2.69521,46.20398],[-1.46766,46.20419],[-1.44626,46.20445],[3.79095,46.20457],[3.07786,46.20534],[2.82071,46.20653],[4.98166,46.20782],[5.24088,46.20912],[2.90836,46.21082],[-1.53725,46.2114],[-1.53019,46.21142],[1.08215,46.2116],[5.86389,46.21748],[-1.52833,46.21994],[1.7611,46.22029],[3.10922,46.22031],[2.88336,46.22135],[4.98785,46.22148],[2.53634,46.22155],[2.4708,46.22394],[5.41741,46.22529],[-1.54438,46.22558],[1.25168,46.22595],[2.83211,46.2275],[-1.42608,46.22756],[6.65866,46.22887],[2.9979,46.22915],[4.68727,46.23091],[-0.14488,46.23163],[0.90231,46.23285],[3.14711,46.23346],[2.10189,46.23854],[-1.55974,46.23981],[3.66322,46.24023],[1.68582,46.24052],[4.80596,46.24055],[0.68502,46.24065],[-1.55335,46.2412],[-0.80525,46.24267],[3.6395,46.2431],[1.50665,46.24336],[1.59102,46.24547],[-1.48627,46.24657],[3.26491,46.2466],[-1.49274,46.24835],[1.77918,46.25027],[4.82593,46.25133],[-0.94932,46.2514],[0.5341,46.25158],[5.26642,46.25174],[-1.11962,46.25287],[4.01072,46.25298],[-0.75492,46.2535],[3.11998,46.25369],[5.55693,46.2552],[4.59718,46.25535],[5.07717,46.25631],[0.08847,46.25632],[5.32251,46.25751],[6.82972,46.25772],[-0.21477,46.25893],[1.32361,46.25944],[1.88607,46.26006],[5.42853,46.26467],[3.9577,46.26474],[0.43196,46.26477],[-0.01123,46.26568],[5.53017,46.26903],[2.9948,46.27064],[4.55809,46.27363],[0.36349,46.27657],[0.68286,46.27717],[6.72315,46.27968],[3.5808,46.28174],[5.29096,46.28351],[-0.74314,46.28386],[-0.095,46.284],[2.67749,46.2847],[2.67487,46.28577],[2.65205,46.28667],[3.52743,46.29063],[4.31927,46.29176],[3.57607,46.29235],[6.61551,46.2927],[1.82418,46.29751],[-0.69501,46.29759],[5.89049,46.29863],[-0.80771,46.30088],[-0.20933,46.30132],[2.01879,46.30342],[4.47857,46.30451],[-0.59422,46.30459],[5.35598,46.30554],[3.29247,46.30588],[4.26472,46.30589],[1.77456,46.30886],[1.76784,46.3091],[-0.83601,46.30947],[0.18213,46.31257],[-0.73215,46.31267],[-0.53499,46.31301],[1.36792,46.31362],[-0.60912,46.31496],[-0.99106,46.31688],[1.66528,46.31716],[0.67375,46.32238],[1.84472,46.32389],[3.70996,46.32415],[3.05527,46.32437],[3.5938,46.32444],[-1.31888,46.32516],[6.40221,46.32692],[2.55645,46.3273],[-0.86778,46.32743],[-0.58419,46.32816],[-1.29852,46.32913],[3.58646,46.32987],[-0.67507,46.33052],[6.32519,46.33056],[4.8434,46.33068],[5.1528,46.33164],[1.3111,46.33172],[-1.31785,46.33226],[6.3878,46.33282],[6.06729,46.33416],[-0.943,46.33475],[4.38242,46.33658],[5.62719,46.33675],[4.61447,46.33717],[-1.30843,46.33883],[5.13657,46.33918],[2.16138,46.33938],[6.39251,46.33987],[-0.79626,46.34036],[-1.33859,46.34039],[6.39657,46.34064],[6.39718,46.34094],[5.6306,46.34131],[6.3973,46.34161],[5.64328,46.34283],[-1.31986,46.34335],[1.17973,46.34366],[6.28413,46.34394],[-1.39419,46.34485],[-1.44421,46.34496],[6.3581,46.34562],[-1.3508,46.34585],[-1.43197,46.34631],[6.60856,46.34674],[1.83772,46.34694],[-1.39153,46.34721],[-1.38301,46.34789],[2.18568,46.34824],[-1.38738,46.34836],[-1.43198,46.34854],[-1.24809,46.34901],[-1.40791,46.34915],[-1.25459,46.3493],[-1.37054,46.34962],[-1.3152,46.35014],[-1.42515,46.35098],[0.70913,46.3511],[6.40955,46.35153],[3.51669,46.3521],[-1.08984,46.35249],[3.79188,46.35317],[2.36536,46.35549],[6.45342,46.35687],[-0.66645,46.35691],[-1.2822,46.35692],[-1.44577,46.35717],[6.4725,46.35736],[1.99442,46.35852],[6.34956,46.35905],[0.05045,46.35914],[-0.11929,46.35954],[2.99245,46.3596],[6.34909,46.35985],[-1.45137,46.36106],[4.47459,46.36366],[0.60529,46.36397],[-1.45859,46.36488],[-1.45931,46.36603],[2.95242,46.36708],[6.32973,46.36811],[6.32809,46.36812],[0.6933,46.36912],[-0.74072,46.36926],[6.55057,46.37109],[5.87237,46.37158],[-1.41396,46.37222],[2.2018,46.37225],[1.96177,46.3723],[6.12139,46.375],[6.62054,46.37718],[2.8778,46.37778],[2.46695,46.37795],[3.03765,46.38082],[-0.97282,46.38151],[3.59302,46.38177],[1.68179,46.38215],[-1.12412,46.3822],[2.92823,46.38368],[-1.46744,46.38425],[-0.94245,46.38715],[1.52302,46.38749],[-1.47824,46.38798],[-1.48777,46.38852],[1.61952,46.38891],[5.66063,46.38983],[-1.40192,46.39211],[-1.01991,46.39232],[6.53084,46.39393],[6.52785,46.39416],[-1.48723,46.39525],[-1.20169,46.39531],[-1.37591,46.39597],[0.7058,46.39637],[5.44998,46.39684],[4.79716,46.39688],[6.66486,46.39909],[6.50402,46.39925],[2.03588,46.39972],[6.64676,46.40062],[-1.29754,46.40155],[3.31473,46.40272],[6.67699,46.4028],[-1.50739,46.40365],[3.70234,46.4039],[-1.48778,46.40401],[-1.40526,46.40469],[-1.40487,46.40498],[-1.42231,46.40692],[-0.21695,46.40821],[-1.49575,46.41066],[-1.57269,46.41088],[-1.58092,46.41104],[-1.58971,46.41143],[-1.26549,46.41144],[-1.58356,46.41213],[3.3184,46.41308],[-1.52218,46.41367],[-1.52119,46.41387],[-1.55195,46.41435],[3.06107,46.41528],[-1.47352,46.41753],[-1.52728,46.41829],[5.72395,46.42031],[0.87544,46.42036],[-1.5698,46.42081],[-1.35618,46.42184],[5.09209,46.42223],[1.61303,46.42391],[0.26409,46.42511],[-1.56577,46.42539],[0.33177,46.42646],[0.19039,46.4282],[-0.95707,46.4286],[4.93329,46.42944],[4.66796,46.43078],[1.29546,46.43202],[1.60441,46.43365],[2.25699,46.43421],[-1.54382,46.43454],[3.06611,46.43514],[4.82473,46.43554],[0.12371,46.43675],[-1.634,46.43705],[4.76213,46.43897],[4.28194,46.43963],[-1.66227,46.43989],[-1.46698,46.44172],[-1.67483,46.44233],[1.83074,46.44244],[-1.66463,46.44384],[-1.39818,46.44417],[4.9806,46.44467],[0.56065,46.44566],[1.58223,46.44601],[4.89893,46.44712],[-1.52871,46.44857],[-1.52666,46.44862],[0.66599,46.44885],[6.04676,46.45038],[-1.70212,46.45135],[5.18951,46.4517],[2.9521,46.45462],[2.9679,46.45467],[-1.19604,46.45547],[2.9179,46.45555],[-1.48356,46.45567],[2.5632,46.45719],[4.10483,46.45741],[1.18103,46.45756],[5.25758,46.46004],[-1.34476,46.46286],[-1.65482,46.46488],[-1.65274,46.46583],[1.04404,46.46646],[-1.02832,46.4669],[5.68856,46.46849],[3.0214,46.46891],[-1.48687,46.46999],[-1.6352,46.47024],[1.60295,46.47076],[-0.77108,46.47107],[-1.72578,46.47152],[1.60036,46.47164],[4.15881,46.47238],[-1.721,46.47362],[0.61179,46.47362],[-1.7405,46.47449],[-1.49429,46.47644],[4.80912,46.4771],[-0.59897,46.47932],[-1.74127,46.47937],[3.9677,46.47986],[4.41302,46.48031],[-1.73136,46.48116],[-0.78705,46.48168],[5.46532,46.4837],[5.94855,46.48398],[2.8276,46.48423],[-1.42549,46.48549],[4.91259,46.48762],[2.91166,46.48866],[2.06889,46.48869],[3.02058,46.49145],[-1.76517,46.49167],[-0.08671,46.49325],[-0.01028,46.49412],[5.325,46.49719],[2.48015,46.49867],[2.90803,46.50301],[-1.34643,46.50335],[-1.49538,46.50694],[1.58355,46.50709],[5.22262,46.50787],[2.31785,46.50796],[3.80349,46.50848],[5.79309,46.50932],[5.62021,46.50961],[-1.5634,46.51034],[2.7067,46.51053],[-1.48713,46.51199],[-1.81386,46.51207],[-0.73928,46.51355],[3.68472,46.51589],[4.5986,46.51769],[-1.39317,46.51816],[-0.28431,46.52073],[-0.76906,46.5214],[5.72289,46.52191],[5.67426,46.52316],[4.69811,46.5242],[-0.7694,46.52444],[-1.79197,46.5281],[4.26729,46.52911],[2.61447,46.53019],[2.99508,46.53072],[-1.75803,46.53184],[2.40833,46.53252],[-1.79385,46.53312],[-1.22166,46.53312],[-1.79125,46.53344],[3.74387,46.53535],[-0.7335,46.53555],[-1.60237,46.53907],[-1.73474,46.54053],[2.42675,46.54123],[6.01907,46.54218],[1.40386,46.54238],[-0.49484,46.54513],[-1.34274,46.54569],[-1.80556,46.54626],[0.3352,46.54699],[-1.80518,46.54738],[4.68386,46.54858],[-1.06337,46.54928],[-1.80672,46.54939],[1.15591,46.54951],[2.85074,46.54978],[3.07914,46.55205],[-1.15522,46.55431],[-1.69812,46.55457],[-1.80561,46.55466],[2.34093,46.55477],[-1.23444,46.55518],[3.80938,46.55531],[1.74833,46.55549],[-0.23146,46.55718],[2.86486,46.5579],[4.22507,46.56111],[-1.6261,46.56125],[-1.13736,46.56199],[5.00577,46.5624],[5.25497,46.56322],[5.7563,46.56407],[2.96261,46.56566],[-1.77772,46.56636],[5.75452,46.56758],[-1.52885,46.56778],[3.11722,46.56787],[2.18823,46.56807],[1.99857,46.56823],[5.75491,46.56835],[0.86846,46.56902],[5.35795,46.57051],[2.94751,46.57061],[4.0542,46.57061],[0.65333,46.57086],[4.66245,46.57139],[4.90939,46.57366],[-1.65825,46.57418],[5.96325,46.57597],[5.74218,46.57617],[-1.50683,46.57704],[-1.48583,46.57851],[4.45033,46.57866],[3.04831,46.58058],[1.90845,46.58159],[-0.50352,46.58204],[5.98579,46.58214],[5.69526,46.58693],[5.70071,46.58724],[2.13334,46.58878],[-1.83271,46.59036],[4.77765,46.59191],[5.73164,46.59203],[1.79965,46.59277],[-1.43847,46.59314],[-0.5181,46.59567],[5.87188,46.59574],[1.50619,46.59636],[2.61396,46.5967],[-0.96944,46.59762],[5.86491,46.5993],[5.6882,46.59976],[5.09624,46.60105],[1.97808,46.60131],[-1.84428,46.60141],[0.59901,46.60215],[6.00449,46.60236],[-1.74906,46.60388],[-1.83228,46.60415],[-0.41594,46.60461],[-1.8394,46.60479],[-1.39409,46.6054],[-1.84537,46.60584],[-1.66684,46.6068],[-1.85096,46.60765],[-1.77232,46.60886],[-1.33446,46.60992],[5.84755,46.61443],[5.70161,46.61859],[2.81104,46.61933],[3.75332,46.61967],[3.7647,46.62119],[-0.35024,46.62202],[5.21682,46.62294],[-1.45462,46.62361],[-1.85868,46.62593],[2.58591,46.62679],[1.1724,46.62688],[-1.86452,46.62749],[-0.57667,46.62843],[0.9297,46.62906],[1.47873,46.62954],[-1.85931,46.63004],[3.87252,46.63076],[1.09389,46.63202],[1.42075,46.63253],[-1.86471,46.63267],[-0.13428,46.63294],[1.4093,46.63363],[3.07265,46.63404],[-1.79763,46.63506],[-1.87092,46.63611],[-1.86599,46.63615],[-1.85838,46.63618],[0.16424,46.64017],[-1.80708,46.64021],[-1.17251,46.64053],[5.90369,46.64112],[-0.34854,46.64136],[-0.26744,46.64156],[-1.79958,46.64236],[2.6556,46.64257],[-1.71164,46.64347],[-1.73259,46.64421],[4.69465,46.64631],[4.08736,46.64683],[-1.83334,46.64817],[2.79678,46.64912],[5.77487,46.65177],[5.72122,46.65247],[-1.75062,46.653],[4.94402,46.6545],[1.97542,46.65452],[0.37786,46.65464],[6.06695,46.65598],[0.30211,46.65605],[-0.70584,46.65629],[0.08861,46.65657],[2.68835,46.65674],[1.88201,46.65713],[-0.34814,46.65734],[-1.76851,46.658],[4.10813,46.6582],[-1.06567,46.65969],[3.0945,46.6605],[5.96083,46.66278],[-1.71357,46.66346],[5.81386,46.66421],[0.39469,46.66442],[-1.75524,46.66619],[-1.82579,46.66654],[-1.90228,46.66742],[-0.00294,46.66765],[5.06026,46.67007],[6.1042,46.67007],[-1.90903,46.67093],[-1.90387,46.67094],[-0.84513,46.67141],[2.9038,46.67146],[4.8327,46.67189],[-1.89511,46.67277],[-1.8879,46.67499],[0.5764,46.676],[-1.91226,46.67614],[-1.76906,46.67681],[5.78041,46.67717],[-1.91544,46.67808],[-0.15534,46.68025],[0.35387,46.68121],[-1.89469,46.68161],[2.78657,46.68202],[0.35795,46.68307],[-1.77693,46.68353],[5.56847,46.68439],[0.83907,46.6845],[2.23567,46.68826],[1.91507,46.68867],[-0.95522,46.69],[-1.87795,46.69131],[4.13234,46.69398],[3.10652,46.69484],[-1.46111,46.6964],[-1.83379,46.69664],[0.42615,46.69838],[-1.97269,46.70032],[-1.85755,46.70209],[0.95479,46.70333],[1.21194,46.70635],[6.20877,46.70666],[3.32309,46.70706],[3.9597,46.7076],[3.08953,46.71007],[-1.90687,46.71064],[5.79803,46.71216],[-0.6088,46.71228],[5.63622,46.71256],[2.04968,46.71295],[-1.9084,46.71464],[-1.27554,46.71582],[-1.97247,46.71693],[1.3136,46.71698],[1.9637,46.71797],[2.49134,46.71823],[-2.33021,46.71877],[0.459,46.71903],[0.54427,46.71982],[5.79947,46.72232],[-1.97931,46.72289],[5.7844,46.72375],[2.88264,46.72507],[-1.95938,46.72557],[5.01514,46.72601],[5.7844,46.72622],[-1.95667,46.72696],[3.61616,46.73103],[0.95006,46.73335],[-1.97326,46.73381],[-1.91192,46.73405],[-1.93141,46.73418],[-1.58947,46.73423],[-1.97469,46.73495],[2.79831,46.73506],[-1.98263,46.73939],[-1.94499,46.73978],[-1.92951,46.73979],[-1.98607,46.74023],[-2.00423,46.74046],[-1.98744,46.74059],[-2.00304,46.74102],[-2.00583,46.7413],[1.61983,46.74214],[-1.99491,46.74226],[-1.99055,46.74251],[-1.56364,46.74299],[-2.00524,46.74305],[-1.00433,46.74467],[-2.00446,46.74468],[-2.00862,46.7448],[-1.11719,46.74487],[-2.01006,46.74549],[-1.95381,46.74556],[5.24619,46.74673],[5.89901,46.74678],[-0.69936,46.74764],[-2.00122,46.74769],[-1.90417,46.75007],[-1.88079,46.7502],[-0.94536,46.7517],[-2.01722,46.7521],[-2.01459,46.75268],[-1.68626,46.75289],[0.82647,46.75404],[-2.01331,46.7544],[-1.89888,46.75464],[5.72608,46.75499],[2.17432,46.75543],[-2.00735,46.75573],[-2.00757,46.75661],[-2.01223,46.75662],[-1.72258,46.75702],[-1.97865,46.75714],[3.03328,46.75722],[-2.01224,46.75734],[3.94426,46.75781],[-1.78652,46.75794],[-1.8218,46.76025],[1.163,46.76105],[-2.02311,46.76113],[3.93112,46.76131],[-2.02565,46.76294],[-1.95856,46.76362],[-1.99712,46.76378],[-2.03237,46.76446],[-2.03308,46.76495],[3.77521,46.76666],[-2.04111,46.76797],[-2.02721,46.76969],[2.42892,46.77046],[-2.02791,46.77059],[6.27572,46.77144],[-1.23585,46.77319],[6.36751,46.77425],[-1.05637,46.77536],[4.20608,46.77679],[-0.67375,46.77696],[-1.73408,46.77857],[-2.01284,46.77941],[-2.05552,46.78003],[-2.01739,46.78135],[-0.85332,46.78165],[0.80616,46.78169],[0.8693,46.78266],[4.87225,46.78423],[-2.03587,46.78575],[3.11945,46.78586],[5.28576,46.79012],[-2.04064,46.79167],[6.29377,46.79223],[3.70263,46.79523],[3.9781,46.7963],[-1.73966,46.79722],[0.54396,46.79791],[1.30608,46.7982],[-1.8965,46.79856],[0.80936,46.79904],[-2.07414,46.79934],[4.06906,46.79971],[-2.0781,46.80005],[-2.08406,46.80068],[-2.08038,46.80069],[-1.98078,46.80152],[-1.96878,46.80162],[5.19171,46.80179],[4.09442,46.80203],[-2.09304,46.80328],[-2.09061,46.80377],[-2.09489,46.80402],[4.13496,46.80438],[-2.11338,46.80481],[-2.10078,46.80569],[-2.11358,46.8069],[-2.11348,46.80708],[-1.99955,46.8072],[-2.10474,46.80805],[0.01649,46.80821],[-2.10902,46.80918],[2.73129,46.8095],[-2.11016,46.80971],[-2.10929,46.80985],[-2.1097,46.80999],[-2.12012,46.81012],[4.70062,46.8103],[-2.11626,46.81035],[6.30338,46.81176],[-2.11526,46.81227],[2.30192,46.81445],[-1.77475,46.81513],[-0.14757,46.81647],[4.0563,46.8169],[3.02746,46.8173],[-2.12988,46.81837],[-2.13015,46.81857],[1.22158,46.81892],[-1.8886,46.81893],[-1.99681,46.8194],[-2.13311,46.82038],[-2.12878,46.82095],[-1.64844,46.82121],[4.64412,46.82127],[-2.01271,46.82218],[0.64546,46.82241],[1.69478,46.82367],[4.26817,46.82446],[-1.11786,46.8262],[5.10925,46.82829],[-0.50304,46.82933],[-1.89103,46.83005],[-2.09988,46.83079],[-1.59086,46.83114],[-2.12722,46.83221],[-0.14811,46.83301],[-1.98389,46.83444],[5.69818,46.8345],[3.45552,46.83487],[-2.12726,46.83532],[-2.1262,46.8371],[-2.13886,46.83735],[4.94571,46.84113],[-2.13075,46.84149],[-2.13896,46.842],[-2.12494,46.84232],[-2.12674,46.84451],[-1.49044,46.84527],[-2.12498,46.84662],[-2.12937,46.84791],[-2.12752,46.85032],[1.07306,46.85086],[-2.1213,46.85099],[0.92892,46.85113],[0.873,46.8516],[0.76938,46.85268],[-1.11764,46.85307],[2.31877,46.85538],[-2.11577,46.85913],[5.29382,46.86023],[4.19129,46.86164],[0.75882,46.86286],[-2.12062,46.86634],[3.64328,46.8668],[4.60556,46.86877],[0.2834,46.87057],[-1.94755,46.8736],[-2.00707,46.8742],[4.55877,46.87604],[3.48066,46.87704],[4.95184,46.87959],[-2.13429,46.87969],[2.14602,46.88041],[-2.11143,46.88113],[-2.14918,46.88384],[2.56421,46.88429],[-2.14743,46.88573],[-0.01978,46.88628],[-2.12175,46.88714],[0.5866,46.88784],[-0.89914,46.88991],[4.15421,46.89181],[-2.10289,46.89209],[2.73011,46.89246],[1.41796,46.89297],[-0.24147,46.89741],[-1.9884,46.89984],[-0.97454,46.90036],[6.37482,46.90071],[5.01828,46.90252],[3.99831,46.90271],[0.16549,46.90285],[5.79372,46.90353],[5.78674,46.90363],[3.83914,46.90382],[5.01841,46.90624],[3.82837,46.90685],[4.68544,46.90713],[4.74562,46.91188],[3.22249,46.91324],[3.76473,46.91364],[-1.96115,46.91367],[-0.94958,46.91469],[-1.90271,46.9158],[3.49089,46.9165],[0.806,46.91723],[-1.99014,46.92255],[5.34875,46.92372],[-0.87403,46.92584],[5.17072,46.92622],[-2.16918,46.92939],[5.24515,46.9299],[4.10098,46.93153],[-1.88762,46.93419],[2.27037,46.93636],[-1.21984,46.93778],[1.31186,46.93893],[0.72243,46.94015],[2.95869,46.94029],[-0.48668,46.9409],[4.13157,46.94166],[-2.18541,46.94516],[-0.90189,46.94549],[5.87911,46.94687],[4.62323,46.94702],[4.01171,46.94744],[4.13438,46.94967],[3.95789,46.94985],[4.62189,46.95043],[5.38302,46.95362],[-1.24535,46.95706],[3.74656,46.95723],[-0.90337,46.95797],[6.1328,46.95967],[1.99162,46.96415],[4.2928,46.96463],[-2.21611,46.9663],[-2.21696,46.96649],[-1.99192,46.96699],[0.60362,46.96949],[0.69906,46.96967],[-0.21995,46.98021],[5.81109,46.98057],[3.16075,46.98213],[1.60596,46.98438],[-2.28349,46.98525],[4.76846,46.98563],[4.5061,46.9858],[-0.45178,46.98763],[-1.81603,46.98986],[1.17404,46.99097],[5.67102,46.99345],[-2.22057,46.99697],[-2.22324,46.99783],[-0.75923,46.99891],[5.13702,47.00029],[3.81632,47.00167],[5.82488,47.00275],[5.66413,47.00288],[0.06337,47.00379],[3.90496,47.00635],[5.5988,47.00756],[0.32039,47.00762],[-1.31347,47.00858],[4.19185,47.01144],[3.07794,47.01201],[5.63056,47.01211],[5.85246,47.01228],[4.98286,47.01257],[5.12972,47.01306],[5.12825,47.01409],[-2.2464,47.01488],[-2.23346,47.01598],[5.48149,47.01653],[-2.30374,47.02409],[1.07617,47.02537],[4.88306,47.02677],[2.21834,47.02792],[5.79458,47.02888],[4.83913,47.0328],[-1.35218,47.03456],[-0.84212,47.03664],[-1.98511,47.03681],[6.50313,47.03956],[5.81528,47.04048],[6.26015,47.04123],[-1.64059,47.04199],[0.82195,47.04516],[4.02519,47.046],[6.23824,47.04617],[4.21574,47.04893],[1.04899,47.05155],[-1.47873,47.05168],[-1.966,47.05191],[0.5426,47.05196],[6.59908,47.05304],[3.65426,47.05346],[3.92626,47.05513],[0.84532,47.05516],[-1.96215,47.05672],[3.81565,47.05733],[6.40584,47.05856],[-1.37103,47.06217],[-1.99715,47.06279],[-1.98416,47.06363],[6.21835,47.06375],[1.80043,47.0654],[-1.1792,47.06702],[4.80335,47.06833],[5.16798,47.07003],[-2.02412,47.0703],[1.80608,47.07164],[-2.0084,47.07228],[2.39488,47.07242],[-0.41136,47.0741],[-0.51461,47.0762],[4.24675,47.07668],[-0.54797,47.0777],[4.09193,47.07791],[6.18495,47.08141],[3.59607,47.08209],[1.35264,47.08245],[0.6664,47.08383],[-2.03692,47.0842],[3.09349,47.0843],[2.05067,47.08524],[-2.02877,47.08659],[5.50328,47.08946],[-1.78455,47.09413],[-1.28216,47.09582],[2.18165,47.09648],[3.87385,47.09683],[-2.05191,47.09743],[0.50203,47.09811],[4.1859,47.10014],[6.12782,47.10056],[6.16038,47.10065],[5.27552,47.1022],[4.94144,47.10357],[-1.39747,47.10408],[-1.86666,47.10415],[5.88969,47.10459],[0.62598,47.1046],[0.51113,47.10756],[4.66028,47.1086],[1.40208,47.10966],[-2.15565,47.11596],[3.93271,47.11779],[-2.07095,47.11855],[-2.13006,47.11887],[-2.07289,47.11897],[-2.07585,47.11915],[-2.10019,47.12066],[0.42857,47.12166],[-2.1278,47.12219],[1.00222,47.12291],[-2.19666,47.1247],[-2.20184,47.1249],[5.58808,47.12545],[-0.80101,47.12704],[3.89584,47.12788],[0.42897,47.12875],[-0.15923,47.13196],[-2.23127,47.13274],[4.49814,47.13414],[-1.74414,47.13432],[1.85185,47.1352],[0.28916,47.13535],[4.02032,47.13544],[3.49331,47.13693],[-2.22219,47.13792],[-1.94429,47.13824],[-2.22233,47.13903],[5.85141,47.1395],[0.38764,47.14021],[-2.13093,47.14035],[-2.20351,47.14055],[-2.15306,47.14079],[-2.22822,47.14385],[3.90672,47.14414],[-0.5428,47.14578],[5.6468,47.14671],[0.65292,47.14695],[5.72416,47.148],[2.21842,47.14809],[5.85707,47.14865],[-2.19507,47.15072],[5.75873,47.1509],[-2.20819,47.15262],[-0.13602,47.15273],[0.71288,47.15354],[-2.16497,47.155],[3.87423,47.15592],[0.44552,47.1575],[1.55217,47.15781],[1.1599,47.15794],[4.07427,47.15863],[-2.16276,47.15985],[-2.16878,47.16018],[0.78698,47.16311],[0.23523,47.16399],[3.61453,47.16449],[-2.15091,47.16487],[1.79985,47.16981],[0.61767,47.17055],[4.15253,47.17059],[-2.13525,47.17069],[4.05941,47.17204],[-2.15789,47.1729],[4.07017,47.17315],[-0.34754,47.17418],[-2.15326,47.17618],[3.01018,47.17682],[-1.63128,47.17765],[3.62059,47.17817],[3.33698,47.17832],[-0.43538,47.18028],[4.05288,47.18174],[-2.16156,47.18185],[3.73473,47.18206],[3.94637,47.18554],[4.0718,47.1862],[3.93922,47.18871],[3.67101,47.19025],[4.06002,47.19365],[-0.37064,47.19365],[4.07517,47.19396],[2.39833,47.19714],[5.38251,47.1988],[0.13999,47.2002],[4.08444,47.20233],[-0.73455,47.20234],[5.38275,47.20318],[-2.03688,47.20337],[-0.28131,47.20395],[0.0298,47.20467],[-2.15131,47.20531],[0.08125,47.20712],[2.08127,47.20972],[-2.15409,47.21375],[1.60658,47.21549],[-2.16028,47.21721],[0.05281,47.2182],[-2.14146,47.21911],[-2.15374,47.21982],[-2.13713,47.22035],[0.49707,47.22081],[6.53282,47.22171],[-2.11214,47.22346],[3.58187,47.22894],[0.1128,47.23016],[4.90533,47.2325],[-1.18771,47.23431],[3.59424,47.2348],[-2.16745,47.235],[4.62871,47.23669],[-2.17043,47.23811],[-2.26767,47.24172],[-1.55682,47.24329],[6.66924,47.24613],[6.80053,47.24723],[-0.00086,47.24728],[0.22172,47.24887],[-1.37113,47.24927],[-2.32163,47.24975],[-2.31058,47.25017],[1.92283,47.25133],[-1.45364,47.25157],[-2.31915,47.25282],[-0.03602,47.25296],[0.30215,47.2547],[-2.32131,47.255],[-1.91391,47.2577],[3.64131,47.25862],[0.46982,47.25905],[1.65847,47.25908],[-0.06469,47.2599],[3.92357,47.26209],[1.90823,47.26248],[-1.71715,47.2642],[-2.16925,47.26452],[-0.50727,47.26518],[1.38864,47.26538],[4.54882,47.26543],[6.0713,47.2658],[-2.3348,47.26774],[0.83293,47.26877],[1.86273,47.26898],[-2.45656,47.26934],[0.16873,47.26991],[-2.2929,47.26994],[6.95042,47.27023],[6.27267,47.27107],[-2.4305,47.27124],[1.49128,47.27133],[-2.43952,47.27382],[4.09182,47.27424],[1.40061,47.27509],[0.63247,47.27622],[1.55935,47.27666],[5.56592,47.27698],[-2.30329,47.27765],[-2.49209,47.27842],[-1.77967,47.28002],[3.82267,47.28256],[4.79551,47.28396],[1.76996,47.28612],[2.94564,47.28723],[-1.88203,47.28725],[-2.37262,47.28837],[-2.03999,47.28901],[0.73385,47.28903],[4.22391,47.28938],[5.77731,47.28963],[0.71626,47.29028],[0.35351,47.29118],[2.53794,47.29138],[4.00962,47.29158],[-2.52915,47.2926],[1.32974,47.2936],[-2.37874,47.29367],[-0.14301,47.2937],[-0.59324,47.29375],[-2.53822,47.29404],[-3.09066,47.29407],[4.03194,47.29501],[-2.53515,47.29745],[-2.39991,47.29778],[-2.35763,47.29832],[-0.01217,47.29907],[-0.62995,47.29941],[6.74306,47.29973],[-2.3741,47.30244],[3.91178,47.30255],[2.74583,47.30319],[5.42542,47.30849],[-3.06633,47.30855],[-0.14415,47.30992],[-3.2007,47.31174],[-1.32832,47.31209],[5.45158,47.31226],[2.26334,47.31375],[-3.19143,47.31446],[-3.10614,47.31475],[5.8668,47.31575],[4.09501,47.31827],[1.65743,47.31838],[-2.30728,47.32106],[5.01109,47.32118],[6.82133,47.32266],[1.36816,47.32304],[4.33083,47.32324],[-0.71086,47.32385],[6.36109,47.32481],[5.45562,47.32627],[-0.33536,47.32704],[1.08927,47.32739],[1.04133,47.32744],[-2.08461,47.3278],[0.99698,47.32797],[-0.67134,47.32803],[-2.49926,47.32864],[1.08816,47.32905],[5.97188,47.32906],[0.41848,47.32968],[1.06947,47.33033],[-3.18603,47.33084],[-0.4365,47.33327],[-2.39061,47.33328],[1.18766,47.33384],[0.1145,47.33416],[6.35447,47.33644],[1.17085,47.33846],[-2.4726,47.33993],[-2.41707,47.34189],[-0.22975,47.34206],[2.86585,47.34223],[-2.87694,47.34243],[-2.47159,47.34252],[-1.29065,47.34262],[0.45324,47.34403],[-3.16773,47.34426],[7.01327,47.34431],[-1.20691,47.34435],[1.47411,47.34567],[-2.34602,47.34608],[6.91888,47.34848],[-2.43371,47.34919],[1.29354,47.34929],[0.5501,47.34975],[-0.74896,47.35051],[-2.50572,47.35165],[2.18561,47.3522],[-2.51757,47.35378],[6.37889,47.35403],[-3.16854,47.35463],[1.75562,47.35491],[0.63401,47.3553],[-1.92149,47.35595],[6.08055,47.35773],[0.8149,47.35809],[-0.22564,47.35883],[6.0786,47.35893],[-0.43427,47.35931],[2.44192,47.35978],[-2.51494,47.36016],[-0.6564,47.36022],[-1.18702,47.36201],[6.11439,47.36241],[-0.86114,47.36441],[-1.10052,47.36501],[-1.10893,47.36539],[-3.22583,47.36555],[-1.01275,47.36702],[-3.22448,47.36752],[3.11574,47.36869],[0.72321,47.37062],[-2.55217,47.37077],[3.38349,47.37158],[-0.68472,47.37194],[-2.54891,47.37226],[-0.34557,47.37442],[-2.49225,47.3745],[-2.53557,47.37497],[-2.55034,47.37728],[0.55866,47.38111],[1.45621,47.3818],[1.36192,47.38334],[-2.51012,47.38615],[-2.43901,47.38667],[4.30766,47.38722],[5.99048,47.38755],[-2.52174,47.38805],[2.68081,47.38882],[0.59611,47.38935],[0.06846,47.39136],[-0.87042,47.39186],[-0.27381,47.39231],[0.81151,47.39432],[6.49814,47.39442],[6.13826,47.39467],[4.94331,47.39627],[6.13725,47.39641],[-1.30265,47.39661],[-2.30142,47.39669],[-2.47186,47.39745],[-2.47479,47.39757],[-0.93346,47.39853],[-0.91657,47.39866],[1.95291,47.39985],[4.5306,47.40084],[-2.48323,47.40187],[4.50032,47.4019],[0.7785,47.40208],[-0.55667,47.40224],[-2.48882,47.40501],[1.52997,47.40659],[-2.47601,47.4066],[2.91759,47.40824],[0.79623,47.4087],[-2.46261,47.40936],[-0.31729,47.40986],[-1.66996,47.41255],[-0.8597,47.41273],[0.38993,47.41307],[3.60828,47.4139],[0.98697,47.41683],[-0.54925,47.42311],[-2.44595,47.42344],[-0.52908,47.42462],[6.07482,47.42526],[-2.41819,47.42624],[2.37926,47.42764],[-1.49779,47.42825],[-0.66307,47.42887],[-2.3965,47.42891],[-2.38225,47.42901],[2.05457,47.43025],[0.03915,47.43056],[-2.44599,47.43123],[0.95414,47.43126],[5.28259,47.43206],[7.25475,47.43319],[1.02818,47.43491],[6.34314,47.44057],[-2.32959,47.44061],[4.79236,47.44073],[-2.15996,47.44105],[-0.4087,47.44318],[-2.45055,47.44458],[-2.48387,47.44533],[2.30391,47.44615],[1.04771,47.44662],[-2.45004,47.44741],[-2.31096,47.44875],[-2.4854,47.45135],[3.52785,47.452],[6.58274,47.452],[5.60173,47.45243],[-2.49171,47.45429],[-0.59639,47.45454],[-2.10956,47.45457],[6.80512,47.45559],[3.73832,47.45632],[3.77153,47.45858],[0.21951,47.45864],[1.1411,47.46075],[-0.88869,47.46206],[-2.48394,47.46402],[6.26372,47.46418],[3.25984,47.46529],[-1.76777,47.46778],[4.35601,47.46822],[7.20719,47.46911],[3.14624,47.4704],[-2.46713,47.47147],[-3.10545,47.47433],[-3.10426,47.47617],[-3.09278,47.47623],[-2.45188,47.4769],[-2.17722,47.47796],[1.4508,47.47803],[-2.45499,47.47872],[-3.10089,47.4792],[3.91294,47.47992],[-2.46533,47.48175],[6.30732,47.4828],[3.75896,47.48294],[2.45587,47.4849],[1.19462,47.48491],[7.27049,47.48608],[-2.42087,47.48743],[1.18952,47.48928],[1.2585,47.48984],[-2.80138,47.49005],[-2.37444,47.49042],[-2.80508,47.49059],[-3.13739,47.49204],[-2.7995,47.49535],[2.85046,47.49561],[-2.68261,47.49625],[3.06868,47.49891],[-3.12026,47.49974],[-3.12019,47.50035],[4.11934,47.502],[1.68042,47.5034],[-3.11927,47.50491],[-2.68292,47.50538],[-2.77148,47.50572],[-2.71019,47.50582],[-3.12653,47.50652],[-2.02062,47.50683],[-2.76093,47.50739],[6.35592,47.50767],[-2.70026,47.50835],[-2.79895,47.50867],[-2.8074,47.50973],[1.10482,47.51052],[-2.84215,47.51119],[-2.43453,47.5139],[3.47985,47.51666],[-2.48186,47.51724],[-2.55512,47.51731],[1.24805,47.51775],[-2.59579,47.51873],[-1.75134,47.5188],[-2.55008,47.51883],[-2.57318,47.51908],[-2.64998,47.51914],[-2.30555,47.51918],[-2.56828,47.51988],[-2.59705,47.52016],[-2.56522,47.52025],[-2.65737,47.52045],[-2.59753,47.52187],[-2.60336,47.5219],[-2.59271,47.52192],[5.10892,47.522],[-1.94925,47.52212],[-2.79697,47.52241],[3.53817,47.52269],[-2.85838,47.52443],[-2.14348,47.52446],[-3.14327,47.52449],[1.38664,47.52535],[-2.56782,47.52584],[-2.5247,47.52589],[1.18718,47.5262],[-2.50878,47.52645],[-2.54347,47.52669],[0.45307,47.52698],[2.15725,47.52704],[-2.2898,47.52712],[5.6989,47.52712],[-2.84766,47.52859],[-2.48875,47.52879],[5.18656,47.53078],[-2.52506,47.53177],[-2.48155,47.53177],[-2.54148,47.53183],[7.01719,47.5322],[-2.53747,47.53252],[3.07333,47.53294],[2.03682,47.53299],[-2.53876,47.53324],[-3.14005,47.53476],[3.63321,47.5362],[-2.5443,47.53647],[6.40308,47.53773],[-2.5703,47.53797],[1.81511,47.53822],[-2.57223,47.53857],[-0.61633,47.53871],[-2.5511,47.53877],[7.18051,47.539],[-0.0965,47.53946],[-3.13392,47.53989],[2.66319,47.54129],[7.05759,47.54291],[1.31114,47.54379],[2.82193,47.5439],[-2.91052,47.54393],[2.19183,47.54424],[4.45065,47.5443],[0.31352,47.54595],[-0.29329,47.54817],[1.53775,47.55081],[-2.88305,47.55331],[-3.13252,47.55442],[1.18076,47.55476],[2.48694,47.55518],[-2.565,47.55558],[-2.93984,47.55619],[-2.57377,47.55714],[-2.57463,47.55714],[6.43569,47.55833],[-2.50656,47.5584],[0.66542,47.55898],[-2.56957,47.559],[-2.93774,47.55945],[2.8342,47.55999],[-2.87851,47.56032],[-2.44737,47.56221],[-2.96675,47.56406],[5.43156,47.56694],[2.40832,47.56954],[-3.12638,47.57169],[-2.95774,47.57339],[7.24089,47.57344],[-3.02723,47.57381],[4.7723,47.57394],[-3.068,47.5754],[-3.02884,47.57558],[-2.63607,47.57767],[-3.05434,47.57823],[3.77759,47.57834],[-2.97463,47.5784],[-3.05471,47.57879],[-0.66428,47.57911],[-2.97908,47.57918],[-3.05705,47.57992],[4.00555,47.58073],[-3.05725,47.58121],[5.8758,47.58168],[-2.41573,47.5828],[5.18287,47.58397],[-2.61908,47.58774],[-3.04371,47.58818],[-3.01509,47.58823],[5.3209,47.58826],[3.65332,47.58906],[1.459,47.59138],[-2.90621,47.59258],[0.90687,47.59279],[-2.90582,47.59387],[-2.84494,47.59412],[7.58936,47.59415],[-3.0971,47.59461],[-2.99743,47.59598],[-3.06162,47.59675],[-3.0771,47.59682],[-3.03751,47.59688],[-3.06042,47.5969],[-2.09997,47.59814],[-2.09002,47.59899],[-2.79492,47.60012],[2.76113,47.6002],[-3.08182,47.60112],[-3.12203,47.60139],[-3.03685,47.60203],[-0.83021,47.6022],[-3.07876,47.60224],[-3.07022,47.60227],[5.78222,47.60257],[-2.68819,47.6027],[-1.52777,47.60454],[3.75624,47.60582],[-2.87527,47.60674],[1.37716,47.60689],[-3.09033,47.60785],[-3.06615,47.60831],[3.11953,47.60908],[-3.13151,47.61117],[-3.02914,47.61121],[0.09771,47.61125],[5.96444,47.61278],[7.23268,47.61313],[-3.167,47.61377],[-3.13859,47.61384],[-2.50215,47.61394],[-2.92627,47.61431],[-3.14982,47.61439],[-2.98965,47.61538],[-2.98606,47.61629],[-3.16546,47.6184],[-3.1633,47.62121],[-2.8403,47.62136],[6.4556,47.62174],[-2.56564,47.62193],[-2.80092,47.62214],[6.61088,47.6225],[-0.50221,47.6225],[3.26423,47.62282],[2.48501,47.62317],[-2.82537,47.62449],[5.50426,47.62529],[-1.81844,47.62588],[-3.42151,47.62616],[-2.7413,47.62702],[-3.14603,47.62837],[6.12851,47.63024],[3.1936,47.63052],[-0.71222,47.63079],[4.33293,47.63133],[-3.15831,47.632],[-3.14751,47.63248],[-2.78012,47.63331],[-2.09826,47.63371],[5.757,47.63462],[-1.0413,47.6364],[2.61493,47.64145],[-2.69357,47.64156],[2.72561,47.64156],[3.26556,47.64187],[-3.43734,47.64301],[-2.89878,47.64313],[-2.93751,47.64393],[-3.05356,47.64401],[1.61067,47.64788],[-3.2022,47.65064],[0.16221,47.65094],[6.86453,47.65332],[5.67729,47.65442],[-3.13698,47.65467],[-3.17183,47.65532],[3.73083,47.65862],[5.97525,47.66178],[3.70493,47.66199],[-2.46866,47.66235],[-3.10003,47.66387],[-3.22133,47.66483],[1.5292,47.66612],[-2.96551,47.6662],[0.31129,47.66701],[-2.23184,47.66768],[2.80598,47.6682],[-0.23573,47.6713],[1.52629,47.67213],[5.01806,47.67419],[2.25639,47.67447],[-0.48801,47.67686],[-2.07678,47.68025],[-3.17593,47.68039],[6.03971,47.68153],[2.62329,47.6822],[-3.18869,47.68288],[2.13492,47.68338],[-3.10645,47.68404],[2.3438,47.68555],[1.4871,47.68568],[5.34466,47.68577],[1.55811,47.68673],[6.38516,47.68845],[-3.35865,47.68862],[6.73204,47.68878],[3.99369,47.69388],[0.04676,47.69454],[-0.07948,47.69514],[-2.34878,47.69519],[-3.35146,47.69558],[0.9157,47.6965],[-0.61551,47.69709],[-2.96226,47.69842],[-3.44835,47.6986],[-3.45373,47.69965],[0.06885,47.70131],[0.07319,47.70215],[-1.86477,47.70255],[2.72134,47.70268],[-1.37789,47.70305],[-3.38544,47.70346],[2.94805,47.7048],[6.67456,47.70573],[-3.42181,47.70602],[-3.35635,47.70613],[3.63558,47.70669],[-3.42432,47.70716],[-3.39253,47.70916],[-0.95165,47.71003],[-2.11548,47.71043],[-2.12718,47.71129],[0.49969,47.71188],[5.70627,47.71191],[-0.90977,47.71278],[2.4934,47.71297],[-3.32112,47.71523],[-0.66929,47.71914],[7.22562,47.72224],[1.93351,47.72529],[2.01501,47.72582],[-2.21351,47.72683],[-2.94927,47.72765],[-3.49367,47.72806],[-2.72806,47.73061],[3.29731,47.73155],[0.57128,47.73267],[7.32429,47.73465],[7.01502,47.73548],[-3.46643,47.73605],[5.3063,47.74007],[-3.50095,47.74195],[-2.52981,47.74231],[2.88508,47.74321],[-3.08999,47.74334],[0.61815,47.74434],[-2.25979,47.74446],[-0.41982,47.74623],[-3.50343,47.74631],[7.12444,47.74677],[0.86351,47.7475],[-0.64245,47.74997],[5.77349,47.75012],[-3.01974,47.75085],[0.13275,47.75108],[6.16663,47.75139],[0.19724,47.75177],[6.58683,47.75484],[6.65276,47.75549],[7.09882,47.75581],[0.2878,47.75641],[6.64883,47.75825],[3.09982,47.75827],[-3.08856,47.75883],[3.06821,47.75973],[-0.48598,47.76215],[-1.96676,47.763],[-2.12544,47.76361],[-3.54741,47.76829],[-3.54512,47.76862],[-0.96349,47.76874],[-0.32712,47.7688],[-3.55836,47.76997],[-3.32912,47.77009],[2.36226,47.77154],[-2.31667,47.77164],[-3.54503,47.77175],[-3.5442,47.77265],[2.49577,47.77458],[-3.50622,47.77473],[-3.57001,47.77498],[-0.67316,47.775],[6.58099,47.7755],[1.64302,47.77686],[4.86254,47.77744],[6.99111,47.77821],[6.57214,47.77873],[6.94812,47.77993],[7.39453,47.78267],[-3.5888,47.7828],[-2.59199,47.78292],[-3.54496,47.78397],[5.06488,47.78445],[-3.54664,47.78452],[-3.57091,47.78518],[3.58771,47.78598],[6.01539,47.78646],[-3.55127,47.78668],[-3.70056,47.78806],[1.07634,47.79131],[3.3631,47.79182],[-3.80095,47.79345],[3.04208,47.79394],[-3.79807,47.79466],[5.23223,47.7954],[-3.79914,47.79623],[-3.77502,47.79668],[-4.25487,47.79692],[-4.22857,47.79715],[-3.82706,47.79729],[-4.24768,47.79741],[-4.22908,47.79795],[-4.24895,47.79866],[-4.32678,47.79907],[4.08789,47.79907],[-3.79035,47.7996],[-4.33428,47.80046],[-4.20209,47.8011],[0.95829,47.80206],[-0.52029,47.80237],[-3.71719,47.80251],[-4.3121,47.80361],[-4.20578,47.80424],[7.16999,47.80448],[-3.74525,47.80494],[-4.20622,47.80634],[-3.74757,47.80637],[-3.28296,47.80648],[2.29474,47.80651],[-2.37801,47.80674],[-3.83808,47.80725],[-3.6866,47.80725],[-4.17634,47.8094],[6.73655,47.80962],[1.94325,47.80991],[-4.37088,47.81048],[-3.85094,47.81085],[0.56454,47.81227],[-4.22172,47.81267],[-4.18176,47.81304],[5.32117,47.81326],[3.80625,47.81328],[-2.13925,47.81348],[4.53917,47.81396],[-2.78089,47.81494],[0.33358,47.81564],[2.16384,47.81622],[-3.70942,47.81701],[2.84433,47.8172],[-0.08826,47.81735],[-3.79978,47.81789],[-4.30946,47.81852],[2.40153,47.81947],[-1.82889,47.8195],[6.93496,47.81976],[-3.4065,47.81983],[7.5101,47.82275],[6.38161,47.82311],[-2.14127,47.82338],[0.42627,47.825],[-2.50209,47.82506],[-4.16372,47.82775],[-3.80159,47.82797],[-0.33185,47.83122],[2.37614,47.83135],[0.75243,47.83203],[-4.32637,47.83283],[-1.31636,47.83354],[0.27937,47.83357],[7.16558,47.8336],[-3.89103,47.83368],[-1.67457,47.83628],[-0.69946,47.83851],[-3.881,47.84068],[-2.64076,47.84107],[5.91754,47.84374],[-0.19532,47.84452],[6.19237,47.84611],[-3.01311,47.84632],[-0.94409,47.84819],[-4.03714,47.84875],[-3.41208,47.84938],[7.03063,47.85088],[-4.16093,47.85097],[-4.03531,47.85107],[-4.03603,47.85108],[-4.16184,47.8531],[-4.30738,47.85423],[-4.02695,47.85426],[6.81114,47.8554],[1.92543,47.856],[-3.89999,47.85628],[4.99765,47.85666],[2.22988,47.85668],[-4.02104,47.85687],[-4.02712,47.85882],[-3.98586,47.85923],[4.57963,47.85951],[3.98451,47.86],[-3.98809,47.86012],[5.32985,47.86024],[-4.26766,47.86113],[2.55392,47.86253],[-4.09592,47.86295],[-2.44612,47.86354],[-1.06828,47.86405],[-4.00322,47.86509],[-4.08993,47.86528],[-2.52238,47.86573],[-3.61838,47.86587],[-4.05167,47.86594],[-0.20866,47.86652],[-4.01566,47.8668],[-3.90396,47.86734],[-4.09644,47.86771],[-4.09842,47.86779],[-4.12861,47.86883],[-4.15597,47.8689],[2.11563,47.86894],[4.40496,47.86953],[-3.02673,47.87127],[5.38085,47.87187],[-4.09848,47.87223],[-3.56952,47.8725],[7.17336,47.8726],[2.44473,47.8745],[-3.36383,47.8746],[-2.20892,47.87495],[-4.06885,47.87618],[-3.71391,47.8767],[6.77922,47.87736],[-0.35897,47.87775],[7.01011,47.88],[-4.34798,47.88004],[7.34323,47.88012],[-3.99277,47.88025],[0.80244,47.88047],[7.05889,47.88067],[6.94429,47.88162],[5.77944,47.88197],[-3.92863,47.88215],[-3.10722,47.88274],[-3.99938,47.88508],[2.02803,47.88581],[-4.19653,47.88586],[-4.03777,47.88715],[1.20259,47.88873],[0.03257,47.88884],[6.85758,47.88888],[6.75683,47.88893],[-2.33368,47.88915],[-3.93838,47.89047],[3.09333,47.89061],[-3.9893,47.8912],[-3.99671,47.8917],[-2.64294,47.89255],[6.73816,47.89296],[-4.3289,47.89461],[1.86215,47.89496],[5.39487,47.89509],[-3.6011,47.89514],[3.75288,47.89542],[-3.95488,47.89613],[-3.96698,47.89802],[-3.96804,47.89819],[2.62519,47.89856],[-3.95598,47.89873],[-3.96441,47.89876],[-3.95887,47.89897],[-3.96148,47.8991],[6.05769,47.90016],[6.98228,47.90062],[7.23631,47.90086],[-3.83289,47.90122],[-3.73706,47.90126],[5.30221,47.9024],[1.22832,47.90293],[-4.10229,47.90398],[-3.91947,47.90426],[-3.99485,47.90458],[-3.47491,47.90474],[2.39344,47.90572],[-4.28351,47.90622],[-2.19789,47.90638],[6.78158,47.90712],[-4.14025,47.90896],[-3.9788,47.91129],[-3.36533,47.91223],[-4.23983,47.91272],[-4.29923,47.91637],[-0.16763,47.91681],[6.52565,47.91744],[-0.68209,47.92043],[0.15556,47.92047],[6.47545,47.9247],[-3.68901,47.925],[0.84501,47.92531],[0.74413,47.92686],[-1.75406,47.92746],[3.51818,47.92788],[2.43461,47.92815],[6.17066,47.93368],[2.98729,47.93612],[-3.99938,47.93795],[-2.53104,47.94056],[-4.39553,47.94062],[-4.02613,47.94093],[6.95453,47.94364],[-1.172,47.94373],[-4.29242,47.9463],[-4.38038,47.94732],[-1.36441,47.94759],[6.63296,47.94799],[-2.42265,47.94939],[-4.36963,47.94959],[-3.96357,47.94994],[-3.96741,47.95036],[5.00505,47.95062],[-2.57325,47.95231],[6.752,47.95253],[7.29623,47.9549],[-0.98788,47.9554],[6.21142,47.95643],[3.50948,47.95648],[-2.29009,47.9573],[5.74013,47.95734],[7.02957,47.95813],[2.28143,47.95857],[-2.15264,47.95974],[-3.16071,47.96031],[-0.2277,47.96247],[-0.52991,47.96377],[-3.42285,47.96406],[6.8481,47.96426],[6.41648,47.96538],[-4.3668,47.96591],[-4.36572,47.96592],[-3.8266,47.96622],[6.44655,47.96726],[6.6706,47.96918],[-2.74072,47.96928],[-2.47001,47.96933],[4.65006,47.97272],[1.23325,47.97295],[6.60756,47.97395],[-3.04205,47.97538],[-4.11104,47.97687],[7.59629,47.97858],[-4.43026,47.98044],[7.21903,47.98054],[3.37439,47.98143],[7.01845,47.98278],[-4.39583,47.9833],[2.44113,47.98358],[3.61326,47.98361],[0.89355,47.984],[-2.38083,47.98546],[-0.4086,47.98612],[6.67348,47.98783],[7.55909,47.98972],[-4.35348,47.99173],[-4.12086,47.99186],[-3.87895,47.99225],[-2.82558,47.99306],[3.73514,47.99317],[3.34445,47.99543],[7.0595,47.99705],[2.96559,47.99824],[-2.09664,47.99841],[6.91823,47.99878],[0.93185,47.99884],[5.49582,48.00066],[-4.26963,48.00149],[1.23319,48.00228],[-4.49493,48.00594],[-2.31762,48.00687],[-4.50803,48.00716],[6.26886,48.00752],[2.75098,48.0086],[6.73165,48.01087],[-0.56009,48.01493],[2.3502,48.01589],[7.53554,48.01603],[7.35021,48.01629],[7.29981,48.01698],[7.3011,48.01759],[-4.52475,48.01767],[-3.47162,48.01848],[0.27965,48.0191],[-2.17241,48.02414],[-4.52863,48.02458],[-4.6183,48.02527],[3.30875,48.0256],[-3.12092,48.02683],[7.57257,48.02745],[-3.69469,48.0279],[-4.55675,48.02859],[-2.72774,48.02937],[-1.71645,48.03074],[7.11354,48.03107],[0.91308,48.03262],[-1.04,48.03273],[0.86511,48.03435],[6.96263,48.03479],[0.92401,48.03666],[-4.68169,48.03712],[0.59302,48.03945],[-4.44397,48.03974],[3.91819,48.04093],[2.74231,48.04249],[7.29965,48.04266],[6.03921,48.04296],[-4.31986,48.04303],[7.15154,48.0434],[-2.3307,48.04397],[6.08011,48.04402],[5.48616,48.04469],[-4.63093,48.04498],[7.18066,48.04511],[6.86866,48.0476],[5.22256,48.04851],[7.20778,48.0488],[-1.49606,48.04887],[6.10612,48.04947],[-2.61459,48.05059],[7.20508,48.05158],[0.6505,48.05305],[2.99771,48.05872],[5.56418,48.06033],[-3.83812,48.06076],[-2.20448,48.06085],[6.18935,48.06099],[-3.41401,48.06156],[6.9691,48.06234],[6.96465,48.06243],[6.95668,48.06303],[6.8558,48.06312],[-4.59143,48.06313],[0.48975,48.06332],[6.95869,48.06348],[2.28171,48.06405],[6.96246,48.0641],[-0.83173,48.06435],[6.85375,48.06482],[-3.21287,48.06675],[0.73564,48.06735],[6.94851,48.06759],[6.94804,48.06813],[-4.60073,48.06944],[6.80714,48.06981],[6.9458,48.07055],[-2.7551,48.07066],[-0.59005,48.07153],[0.18934,48.07179],[6.92689,48.07308],[-2.96443,48.07345],[6.94261,48.07826],[7.10787,48.07895],[7.38657,48.07921],[1.33178,48.08016],[3.2882,48.08086],[-4.40697,48.082],[6.94873,48.08413],[1.33445,48.08416],[-4.48207,48.08421],[7.27239,48.08521],[2.48481,48.0872],[7.30657,48.08726],[6.7285,48.0889],[-2.25501,48.09035],[2.78476,48.09181],[0.8768,48.09244],[-4.35246,48.09269],[7.19743,48.09299],[-0.35659,48.09426],[6.04652,48.09436],[-4.34809,48.09641],[-4.19804,48.09662],[5.50802,48.09685],[-4.18282,48.09851],[6.76986,48.09859],[-4.36198,48.09884],[-2.54399,48.10014],[-2.02572,48.10174],[1.11556,48.10189],[-4.35887,48.10305],[2.24142,48.10365],[2.59667,48.10392],[-3.86053,48.10419],[0.34032,48.10461],[4.3808,48.10613],[-0.07896,48.1069],[0.19141,48.10863],[-1.19761,48.10929],[-4.27983,48.11042],[7.12101,48.11519],[-4.26763,48.11597],[-4.27326,48.11599],[1.53851,48.11614],[3.88319,48.11699],[7.12286,48.11765],[1.14138,48.11824],[5.13239,48.11859],[0.51095,48.11869],[7.13172,48.1188],[6.73209,48.119],[6.83118,48.12033],[-3.23358,48.12064],[-0.02065,48.12176],[6.81724,48.12388],[-3.07562,48.12859],[0.96856,48.12907],[7.16257,48.13066],[6.84589,48.13343],[6.7912,48.13364],[6.91273,48.13483],[-1.64563,48.1353],[-2.65591,48.13768],[-1.95293,48.13776],[-0.5517,48.13784],[-3.6168,48.14121],[6.89404,48.14188],[6.78708,48.14217],[0.18428,48.14267],[-4.26889,48.14457],[-4.26732,48.14802],[7.25403,48.14887],[7.59745,48.14934],[-0.41302,48.15078],[6.3644,48.15184],[6.78969,48.15286],[6.35954,48.15621],[0.06268,48.15768],[1.01265,48.15929],[-3.30528,48.16032],[-3.24054,48.16041],[6.96328,48.16102],[6.35199,48.16173],[7.31702,48.16235],[2.25231,48.16347],[-4.29351,48.16613],[6.89366,48.16631],[-4.2888,48.16654],[6.3605,48.16698],[-1.9599,48.16771],[6.89008,48.16821],[-3.7756,48.16827],[6.87999,48.16886],[-4.28938,48.16916],[-3.87728,48.16991],[6.88107,48.17004],[7.11386,48.17035],[1.38628,48.17078],[-4.28308,48.17208],[-3.31255,48.17241],[5.5548,48.17243],[-0.78785,48.17467],[-2.58705,48.17558],[0.64831,48.17589],[6.95416,48.17606],[-3.00954,48.17726],[0.43365,48.17818],[-2.72972,48.17835],[6.74283,48.17852],[0.12448,48.17885],[2.73021,48.1796],[6.46843,48.17972],[5.88522,48.1802],[-2.63859,48.18048],[-4.28939,48.18099],[7.18462,48.18146],[3.28803,48.18312],[-2.18936,48.18335],[-3.81308,48.18341],[6.95792,48.18432],[6.99043,48.18489],[-4.28462,48.18495],[-4.08491,48.18752],[-0.14115,48.18925],[6.77508,48.18987],[-4.09001,48.19003],[-4.30018,48.19065],[-4.30137,48.1925],[-0.99519,48.19301],[-0.12548,48.19358],[-3.98122,48.19358],[1.93263,48.19377],[7.33671,48.19467],[7.30296,48.19804],[-2.41583,48.1981],[0.90793,48.19834],[-3.01282,48.19872],[5.84485,48.19906],[-3.06937,48.20153],[7.36866,48.20211],[4.1666,48.20227],[0.88227,48.20229],[4.62145,48.20327],[-0.12935,48.20346],[-2.04699,48.20349],[7.37229,48.20409],[-4.12415,48.20719],[5.9555,48.2077],[-1.80431,48.20822],[1.14116,48.20848],[-3.05127,48.20869],[7.34474,48.20872],[-0.13471,48.2095],[-4.36891,48.21024],[6.72127,48.21515],[0.90444,48.21731],[-3.38909,48.22066],[-4.52285,48.22148],[-0.75299,48.22302],[-3.71648,48.22339],[-4.37276,48.22372],[-3.1135,48.22513],[-4.37133,48.22526],[0.13444,48.22553],[-3.18313,48.22564],[-2.38241,48.22579],[7.65617,48.22611],[-3.28332,48.22676],[-4.36789,48.22717],[5.96841,48.22745],[-1.1793,48.23099],[4.13739,48.23154],[-3.29849,48.2316],[-4.31135,48.2323],[5.98164,48.23341],[7.16986,48.23524],[-4.51881,48.23721],[-3.70394,48.23763],[-4.54463,48.23853],[2.70389,48.24073],[-4.42924,48.24221],[7.17294,48.25],[-0.37011,48.25147],[5.29901,48.2522],[4.34133,48.25267],[7.08259,48.25391],[7.44775,48.25455],[-2.98824,48.25562],[2.43569,48.25652],[-1.3961,48.25998],[2.04492,48.26043],[4.3465,48.26331],[0.85514,48.26393],[-2.70718,48.26588],[2.72721,48.26601],[-2.55829,48.26602],[5.13643,48.26756],[-2.0541,48.27024],[-1.66377,48.27209],[7.2904,48.2729],[-2.62428,48.27411],[-4.6043,48.27698],[-3.60183,48.27763],[-3.42661,48.27831],[0.92704,48.27928],[-4.5649,48.28075],[-4.50228,48.28084],[0.01516,48.28401],[-4.52862,48.28473],[-2.72143,48.28605],[-4.24163,48.28652],[1.22695,48.28665],[3.55467,48.28704],[7.24001,48.28771],[-4.56452,48.28795],[0.17693,48.28865],[7.41811,48.28906],[-0.11414,48.28914],[4.28279,48.28998],[3.20804,48.29038],[7.48236,48.29144],[-4.46072,48.29176],[-4.26518,48.29264],[5.86855,48.29355],[4.57099,48.29518],[-4.18528,48.2953],[2.43141,48.2957],[2.82953,48.29846],[-3.96477,48.2995],[5.14761,48.30121],[-2.90092,48.30163],[4.33749,48.30275],[7.50273,48.30599],[5.27804,48.30631],[-4.5583,48.30884],[-1.82107,48.30999],[-3.17916,48.31001],[-4.16612,48.31076],[5.86044,48.31103],[-2.25428,48.31109],[4.09691,48.31113],[4.3249,48.31125],[-0.61303,48.31363],[0.74246,48.31506],[2.69654,48.31725],[-3.0593,48.3199],[-0.10928,48.32039],[7.69825,48.32125],[-4.31888,48.32158],[7.44326,48.32282],[-4.31307,48.32362],[0.92527,48.32477],[0.81588,48.32487],[6.42619,48.32579],[7.36092,48.32661],[7.69373,48.32971],[-1.83386,48.33136],[2.04712,48.33232],[2.74975,48.33261],[7.28862,48.33722],[6.63811,48.33867],[-1.6383,48.33898],[3.26485,48.33934],[-4.70288,48.33995],[-2.75659,48.34345],[-4.7417,48.34466],[3.62631,48.3482],[7.10011,48.34834],[4.53256,48.34837],[4.52745,48.34885],[6.98923,48.353],[-2.63722,48.35314],[-0.07657,48.3535],[-1.18189,48.35374],[-4.67098,48.35568],[5.68634,48.35725],[0.37181,48.35778],[3.02701,48.35838],[4.50174,48.35865],[-4.60113,48.35897],[-3.8792,48.35906],[-3.75613,48.36116],[-3.71631,48.36361],[6.83851,48.36364],[-4.54038,48.36535],[-4.7599,48.36748],[-4.24321,48.37051],[7.30814,48.37267],[0.55375,48.37422],[2.9062,48.37471],[4.73823,48.37669],[6.29022,48.37702],[2.96371,48.37741],[-1.46363,48.37774],[5.92462,48.38194],[7.47505,48.3824],[-1.83523,48.3828],[2.80184,48.3831],[-3.91494,48.38416],[-3.85906,48.38625],[7.71244,48.38891],[-0.61702,48.39201],[-3.99896,48.39378],[2.5064,48.39445],[6.86183,48.39451],[3.09329,48.39585],[6.98824,48.39659],[-4.39498,48.39821],[-4.07635,48.40038],[1.48922,48.40095],[-2.90672,48.40128],[-4.35346,48.40141],[-2.31665,48.40171],[-3.43715,48.40178],[-1.74467,48.40464],[7.3234,48.40626],[5.27131,48.40633],[7.44404,48.40664],[7.25773,48.40744],[-4.76908,48.4078],[1.02382,48.40794],[-1.4376,48.40983],[2.14417,48.41024],[7.40059,48.41034],[-1.25664,48.41172],[6.88304,48.41219],[3.42968,48.41224],[7.6709,48.41369],[7.45286,48.41399],[3.24631,48.41418],[5.04001,48.42192],[-4.78474,48.42208],[2.74863,48.42303],[0.07275,48.42577],[0.76889,48.42603],[4.41314,48.42647],[2.3784,48.42667],[-4.78117,48.4291],[5.23077,48.43018],[1.49914,48.43433],[-4.78247,48.43598],[6.18293,48.43619],[0.82861,48.4371],[-0.38825,48.43757],[-1.05241,48.43794],[-4.63016,48.4387],[6.28138,48.43905],[5.67587,48.44308],[2.32122,48.44321],[6.7436,48.4436],[6.55805,48.44529],[1.24155,48.44623],[-2.04615,48.44727],[-4.70903,48.45265],[7.19883,48.45269],[-1.65069,48.45378],[6.94734,48.45494],[-1.28139,48.45873],[-5.09144,48.45917],[-0.20143,48.46123],[-2.35177,48.46144],[2.76927,48.46336],[7.4675,48.46473],[4.12732,48.46604],[-2.02316,48.47165],[4.88404,48.47238],[2.29795,48.47259],[-2.50771,48.47449],[0.6606,48.4746],[-4.52692,48.47544],[-1.31327,48.47891],[-2.29758,48.47932],[-4.75208,48.48003],[6.30573,48.4805],[-3.37469,48.4816],[2.35729,48.48323],[-1.12136,48.48452],[-2.00831,48.48462],[-3.8012,48.48558],[7.3706,48.48722],[4.94945,48.48853],[-0.69693,48.48868],[-2.00858,48.4888],[7.2911,48.4891],[-2.31977,48.48956],[-3.1351,48.48966],[-1.72807,48.49135],[2.41048,48.49304],[7.461,48.49343],[0.06853,48.49574],[-0.62478,48.49811],[-2.75885,48.50032],[2.19094,48.50234],[-2.2333,48.50274],[7.48985,48.5033],[4.72754,48.50348],[3.50889,48.50365],[-1.23717,48.50634],[2.36295,48.50801],[0.36313,48.50818],[3.88502,48.51067],[2.36879,48.5107],[1.01918,48.51298],[-2.06621,48.51456],[-1.3315,48.51462],[0.73961,48.51509],[-2.33395,48.51971],[-2.23231,48.52028],[3.59217,48.52169],[7.38512,48.52428],[-2.65498,48.52431],[-1.96617,48.52466],[2.66916,48.52549],[3.66463,48.52583],[2.02814,48.52643],[-4.75978,48.52691],[0.29202,48.52713],[7.38007,48.5312],[6.27303,48.53128],[-2.67216,48.53294],[-0.40141,48.53738],[0.24634,48.53798],[5.27157,48.53833],[-2.97078,48.53853],[4.14291,48.5389],[7.50003,48.54124],[4.90799,48.54238],[2.13789,48.54334],[0.68719,48.54352],[2.13872,48.54429],[-1.96261,48.5444],[-1.3133,48.54524],[-2.22812,48.54539],[-2.52166,48.54567],[-1.75851,48.54687],[4.02361,48.54763],[-0.41986,48.54775],[-2.73229,48.54813],[-2.59717,48.54832],[-1.68365,48.54936],[-2.25575,48.54939],[6.24319,48.54949],[3.67827,48.54994],[5.58339,48.55014],[4.77198,48.55023],[3.75881,48.55043],[-1.38156,48.55066],[-0.50337,48.55313],[1.04205,48.55336],[0.69024,48.55378],[4.79227,48.55404],[1.03868,48.55581],[-2.76255,48.55666],[-1.51119,48.55691],[4.70601,48.55722],[-1.24111,48.55807],[7.38605,48.55899],[-0.69981,48.55923],[-2.53395,48.55966],[2.20569,48.5598],[-3.42689,48.56503],[7.2981,48.56556],[2.78994,48.56587],[-4.67033,48.56669],[1.93032,48.56743],[-4.65655,48.56871],[-2.5645,48.56883],[1.93339,48.56925],[-0.13901,48.56951],[3.30569,48.57014],[4.84886,48.57199],[-1.20461,48.57299],[-2.01139,48.57348],[-1.97442,48.57378],[-2.33633,48.57424],[-1.76354,48.57482],[2.48425,48.5752],[-1.91985,48.57551],[-4.62746,48.57632],[-1.87981,48.57683],[-0.57656,48.57723],[-4.03014,48.57736],[2.99444,48.57822],[-2.78497,48.57846],[-2.80948,48.57997],[-2.19406,48.58039],[-2.05625,48.58105],[-1.09767,48.58128],[-2.9469,48.58191],[-2.55227,48.58225],[-2.91761,48.5824],[-2.80485,48.58259],[-0.2794,48.5828],[-2.25729,48.58438],[0.81319,48.58598],[2.48794,48.58661],[2.09422,48.5872],[-0.65063,48.58877],[-1.71905,48.58888],[-1.62921,48.58888],[6.85051,48.5889],[-2.55038,48.58979],[-2.22458,48.59076],[-2.29578,48.5912],[-2.8249,48.59176],[-4.60255,48.59324],[-2.1853,48.59324],[-2.22579,48.59403],[-3.14734,48.59413],[-2.48463,48.59413],[-3.3739,48.59436],[-1.59861,48.5946],[-1.5118,48.59639],[6.4989,48.59644],[-4.01369,48.59646],[-1.41239,48.59672],[-1.51289,48.59709],[-2.15693,48.59835],[0.17068,48.59864],[-0.35955,48.59871],[4.79526,48.59917],[-1.712,48.60069],[-4.59585,48.60135],[-4.59882,48.6031],[-2.2418,48.60391],[4.71463,48.60399],[-2.46118,48.60403],[-2.15558,48.60448],[-3.74164,48.60461],[-2.48745,48.60477],[-1.97022,48.6048],[-1.70797,48.60503],[-2.84111,48.60581],[-2.03754,48.60619],[-2.82107,48.6064],[-2.86195,48.60643],[-2.49671,48.60651],[0.88994,48.60762],[-0.31512,48.60866],[-2.33663,48.60872],[3.15864,48.60895],[-1.98701,48.61002],[-4.42793,48.61008],[-2.47859,48.61079],[-3.5775,48.61139],[1.54822,48.61194],[7.07258,48.61324],[-2.25644,48.61367],[-1.50973,48.61409],[-2.99288,48.61433],[-2.12781,48.61487],[-0.60119,48.6149],[2.11848,48.61511],[-1.98689,48.61514],[-3.76801,48.61577],[7.3073,48.61581],[-1.8518,48.61607],[-2.07409,48.61681],[-1.29439,48.61692],[-3.28342,48.61833],[-1.84944,48.6191],[-1.36517,48.62077],[4.70423,48.62446],[1.84403,48.62639],[-2.13058,48.62743],[-1.41522,48.62822],[-1.35286,48.63006],[-4.52386,48.63047],[-2.0843,48.63086],[-4.30858,48.63101],[-4.44958,48.63141],[-2.41359,48.63177],[-2.27874,48.63284],[-2.45164,48.633],[-4.54442,48.63317],[-2.27798,48.63389],[-2.12085,48.63401],[7.42347,48.63414],[-3.92962,48.63476],[-2.07926,48.63484],[-2.83507,48.63549],[7.09341,48.63573],[-2.02792,48.63582],[-4.44582,48.63622],[-2.26908,48.63696],[7.43203,48.63715],[-2.45567,48.63803],[-2.44191,48.63842],[1.27612,48.63899],[-0.21644,48.6391],[-4.27898,48.6401],[-1.87516,48.64085],[-2.45624,48.64088],[-2.2559,48.64203],[-2.42537,48.64273],[-3.64289,48.64347],[7.40012,48.64489],[-3.95662,48.6456],[2.96359,48.64614],[-2.42217,48.64659],[-4.23232,48.64751],[0.75559,48.64771],[7.2532,48.6487],[-0.94588,48.64882],[-3.92082,48.64947],[-2.35388,48.65032],[-2.35647,48.65158],[-0.1433,48.65172],[5.99256,48.65291],[-4.30201,48.65489],[2.30415,48.65517],[6.1399,48.65727],[-4.32875,48.65822],[-3.92883,48.65877],[-4.21746,48.65892],[-3.84819,48.65958],[-0.51697,48.65961],[-4.37664,48.66196],[-2.84471,48.66309],[-2.34153,48.664],[-3.78102,48.66456],[-1.98476,48.66767],[-3.60077,48.66802],[-3.30633,48.6683],[-4.36218,48.6691],[-4.05343,48.67282],[-4.32923,48.67285],[-4.34536,48.6754],[1.9721,48.67611],[-3.65247,48.67654],[2.39083,48.67853],[6.5895,48.67866],[-3.65383,48.68069],[-3.62829,48.68097],[-1.97759,48.68178],[7.87796,48.68304],[-1.8689,48.68313],[-3.62524,48.6832],[-1.37048,48.68463],[-3.78515,48.68539],[5.31686,48.68611],[2.88901,48.68628],[-4.07666,48.68631],[-1.89033,48.68649],[-1.88929,48.68664],[-1.48454,48.68775],[-4.16738,48.68778],[-1.86058,48.68793],[6.58139,48.68817],[-1.921,48.68872],[7.327,48.68889],[-1.86914,48.68898],[-2.90981,48.68977],[4.56988,48.68979],[-4.08357,48.6898],[-1.94144,48.69006],[-4.13962,48.69043],[-3.96761,48.69068],[-1.87395,48.69073],[-1.93322,48.69077],[6.92736,48.69124],[-3.55753,48.69295],[-2.8967,48.69338],[-3.96933,48.69341],[-4.11659,48.69342],[-4.05561,48.69386],[-3.77499,48.69396],[-3.16356,48.69508],[-1.47434,48.69663],[4.63039,48.69673],[-3.83503,48.70268],[3.65406,48.70328],[-1.84795,48.70413],[-4.04865,48.70456],[3.24024,48.70649],[-3.98898,48.70724],[-1.49435,48.70841],[-1.01503,48.71023],[-3.13649,48.71263],[-2.96695,48.71357],[-4.00866,48.71411],[-3.81521,48.71428],[7.22638,48.71929],[-2.95355,48.71949],[3.03766,48.71986],[-3.23665,48.72086],[-1.15181,48.721],[-2.94886,48.72113],[3.70231,48.72132],[-3.4864,48.7216],[-0.91491,48.72283],[-3.44633,48.72295],[-1.52411,48.72359],[-3.57151,48.72402],[3.14805,48.72657],[4.58114,48.7302],[3.04731,48.73086],[7.35544,48.73092],[3.92864,48.73193],[2.75976,48.73208],[-3.00355,48.73513],[-3.0258,48.73668],[-3.54477,48.73827],[1.62429,48.73849],[0.90662,48.7388],[-1.42481,48.73977],[-0.01678,48.73993],[-3.26623,48.74014],[-3.20455,48.74507],[6.05719,48.74733],[-1.55726,48.74966],[2.89706,48.75067],[-3.5063,48.75141],[-3.48995,48.75183],[-0.5442,48.75391],[-2.98506,48.75408],[0.18854,48.75676],[6.95569,48.7568],[6.89975,48.75776],[-1.51437,48.75778],[-2.9624,48.75974],[2.88099,48.76036],[-3.56202,48.76043],[-0.24564,48.76067],[1.29058,48.76089],[-3.56241,48.76112],[-1.339,48.76316],[1.2368,48.76377],[-3.56154,48.76455],[3.30639,48.76687],[-1.54715,48.76958],[-3.02209,48.76966],[-1.55055,48.77059],[-1.54641,48.77247],[5.17407,48.77422],[3.3287,48.77581],[-3.37553,48.77596],[-1.5663,48.77776],[6.53817,48.77809],[-3.1147,48.78002],[-1.56673,48.78138],[3.31206,48.78244],[7.24951,48.78324],[-3.25155,48.78489],[-1.56487,48.78791],[-1.268,48.78869],[0.46628,48.78886],[2.03204,48.78949],[-1.56719,48.78961],[-1.52587,48.79071],[-3.55796,48.79125],[0.84534,48.79376],[-3.48221,48.79418],[2.16087,48.7942],[-1.54625,48.79453],[0.29983,48.79465],[-0.53054,48.7951],[-1.56189,48.79641],[-3.42689,48.79657],[-1.52485,48.79776],[-3.58386,48.79905],[-1.566,48.80011],[-1.54258,48.80154],[-3.56733,48.80158],[7.39658,48.80159],[7.76527,48.80273],[-3.5724,48.80401],[7.53678,48.80572],[2.99305,48.80837],[0.30223,48.80953],[-3.54036,48.81032],[3.59699,48.81103],[-3.54421,48.81289],[-3.386,48.81321],[6.51132,48.81415],[-3.46027,48.81423],[-3.38347,48.8147],[5.93448,48.8157],[-3.01391,48.81647],[-3.36054,48.81674],[-3.30305,48.81789],[-3.01655,48.81886],[-3.35386,48.81943],[-0.45251,48.81944],[-1.57159,48.82169],[-3.4815,48.8231],[-3.4914,48.82536],[4.98291,48.82631],[5.78928,48.82747],[-0.88067,48.82748],[-3.47419,48.82778],[2.48141,48.83018],[1.32972,48.83185],[0.91276,48.83193],[8.01712,48.83227],[0.96434,48.83249],[-3.32847,48.83336],[-1.09252,48.83398],[-1.21704,48.8364],[-3.00783,48.83879],[-3.27899,48.84072],[-0.49573,48.84251],[-0.39841,48.84319],[7.31825,48.84519],[-3.20957,48.84843],[-0.55703,48.85146],[-1.5809,48.85206],[2.92948,48.85357],[2.53935,48.85395],[6.93758,48.85498],[-3.13275,48.85539],[-3.1434,48.85576],[-0.62136,48.85577],[-3.22067,48.85803],[-3.22757,48.86063],[-1.57769,48.86067],[1.44191,48.86185],[1.41564,48.86282],[-3.09211,48.86326],[-0.4815,48.86524],[2.23473,48.86842],[-1.5637,48.86962],[3.55077,48.8709],[-0.41104,48.87142],[3.36136,48.87161],[-1.50522,48.87392],[1.46337,48.88049],[2.7451,48.88128],[8.10001,48.88269],[5.40322,48.88387],[-1.57018,48.8872],[8.13436,48.89064],[2.68213,48.89513],[-0.20477,48.89553],[2.71954,48.89727],[5.53946,48.90229],[0.74484,48.90692],[3.15553,48.90818],[-1.56478,48.90819],[7.28787,48.90964],[2.67055,48.91248],[2.7343,48.9137],[-0.47426,48.91379],[7.36753,48.91617],[-1.54457,48.91701],[8.15491,48.91793],[-1.5059,48.91818],[2.72217,48.92136],[1.47604,48.92463],[1.78873,48.92501],[5.75904,48.92775],[1.66326,48.92916],[7.60417,48.92917],[2.78012,48.93205],[0.19669,48.93254],[4.38329,48.93597],[-0.67894,48.9377],[6.66355,48.93915],[-1.03525,48.9398],[2.14563,48.93994],[7.02985,48.94088],[5.71704,48.94111],[3.02002,48.94495],[0.51102,48.94554],[2.77904,48.94636],[1.97895,48.94719],[4.88557,48.94823],[3.14869,48.94834],[3.07227,48.9532],[3.21084,48.95585],[2.94157,48.9572],[6.63496,48.9574],[-1.55306,48.95753],[2.94537,48.96046],[6.77389,48.96086],[-1.26156,48.96138],[1.99737,48.96187],[7.64522,48.96221],[3.32969,48.96243],[1.9973,48.96261],[5.88542,48.9658],[7.52293,48.96892],[-1.46153,48.97003],[1.96024,48.97003],[-1.55663,48.97032],[8.16545,48.97104],[-1.05561,48.97302],[3.28191,48.97365],[7.05365,48.97692],[-1.55974,48.97908],[7.51434,48.98163],[-1.46714,48.98386],[3.27101,48.98685],[-1.03325,48.98704],[-0.46878,48.98892],[-1.52889,48.99294],[-1.55403,48.99582],[1.9601,48.99643],[3.04236,48.99657],[3.00653,49.00209],[1.03457,49.00242],[2.9414,49.00284],[0.15066,49.00359],[3.01632,49.00453],[3.01708,49.00559],[6.95287,49.0059],[7.5395,49.00851],[-0.85735,49.00951],[-1.5555,49.00979],[7.62362,49.01044],[3.02929,49.01257],[6.95438,49.01283],[6.955,49.01471],[5.67443,49.01658],[5.42048,49.01982],[5.63712,49.02107],[-0.62542,49.02542],[-0.97222,49.02851],[6.92782,49.02874],[0.41031,49.02911],[7.76886,49.03152],[-1.59517,49.0365],[-1.58535,49.03761],[-0.88016,49.03897],[6.05916,49.04037],[6.89262,49.04325],[1.66298,49.04632],[-0.33815,49.04699],[-1.59139,49.05143],[-1.45907,49.05158],[-1.59145,49.05188],[-1.56779,49.05236],[-1.56694,49.05271],[1.53462,49.05641],[1.6131,49.05752],[3.95007,49.05752],[7.62494,49.05943],[7.59349,49.06529],[-0.551,49.0677],[-1.59658,49.0687],[-0.7421,49.0715],[6.95467,49.07621],[5.00259,49.07651],[3.63521,49.07809],[-1.6005,49.07965],[0.5868,49.08017],[-0.40026,49.0824],[7.49249,49.0834],[7.48806,49.08583],[4.90958,49.08936],[5.61461,49.09513],[1.43827,49.09631],[5.47094,49.09711],[2.99981,49.09768],[2.96144,49.09842],[-1.60784,49.10379],[-1.60723,49.10602],[3.73413,49.10663],[-1.46581,49.1067],[-1.19904,49.10691],[6.70837,49.10933],[5.34381,49.11294],[-1.59753,49.12069],[6.16917,49.12389],[2.23552,49.128],[-1.55747,49.13196],[2.05801,49.13246],[2.38858,49.14108],[2.18713,49.1412],[-1.58238,49.14365],[5.53189,49.14922],[5.36559,49.15394],[-0.76032,49.15699],[-1.596,49.15929],[5.06332,49.16136],[0.22054,49.16515],[-1.34909,49.16652],[4.21426,49.16677],[6.71356,49.16749],[-0.16503,49.17013],[0.03901,49.17531],[-1.30723,49.17835],[4.72457,49.17852],[-0.82455,49.18676],[-1.60447,49.1977],[2.4049,49.20062],[0.71524,49.2023],[2.04718,49.2042],[-1.36949,49.20655],[0.39001,49.20979],[5.96152,49.20981],[5.36602,49.21126],[2.42745,49.21167],[0.81533,49.21207],[2.40267,49.21235],[1.38817,49.21304],[-0.78028,49.21361],[1.13283,49.21501],[6.39952,49.22393],[0.30492,49.22483],[1.22421,49.22509],[-0.73363,49.22518],[2.42861,49.22566],[-0.20583,49.22781],[1.33088,49.22821],[5.03319,49.22995],[-0.9323,49.23078],[0.72496,49.23451],[1.40021,49.2356],[-1.64066,49.23655],[-0.25734,49.23801],[0.70238,49.24115],[0.58087,49.24223],[0.44954,49.24623],[-0.59506,49.2486],[-0.6016,49.24912],[-0.27196,49.2496],[5.92983,49.25165],[-1.43741,49.25169],[-0.18907,49.25271],[1.70216,49.25613],[0.37444,49.25614],[-0.94574,49.25781],[2.36192,49.26253],[4.8387,49.26539],[0.141,49.26711],[-0.25496,49.26896],[-0.92413,49.27072],[-1.55906,49.27307],[-0.808,49.27328],[0.20496,49.27488],[-0.50169,49.27563],[-1.16945,49.27849],[-0.06996,49.27921],[0.91,49.27979],[1.55795,49.28143],[4.96271,49.28243],[-0.13812,49.28259],[-0.1702,49.28295],[-0.19067,49.28302],[-0.19129,49.28335],[-0.19048,49.2834],[-0.18957,49.28362],[-0.6976,49.28392],[-0.18692,49.28431],[-0.17979,49.28443],[0.17741,49.28452],[5.2825,49.28459],[-0.79569,49.28538],[2.34721,49.28855],[-0.52939,49.28964],[-0.30251,49.28997],[-0.28187,49.29025],[-0.30317,49.29051],[-0.07445,49.29231],[1.25749,49.2935],[-0.06828,49.29367],[0.17591,49.29753],[1.05748,49.29763],[6.27266,49.29857],[-1.54481,49.3],[-0.03935,49.30265],[0.65323,49.30301],[-1.68837,49.30322],[-0.32083,49.30381],[-0.33042,49.30417],[-0.07083,49.30575],[1.15588,49.30583],[-0.0476,49.3066],[5.40366,49.30702],[1.22557,49.30753],[3.67186,49.30929],[-0.01939,49.30945],[-1.23899,49.30983],[-0.48522,49.31241],[-0.90602,49.31316],[2.60515,49.31325],[0.40464,49.31472],[-0.35822,49.318],[-1.10894,49.31876],[2.48534,49.31879],[-0.38212,49.31932],[5.2653,49.32087],[5.08223,49.32134],[-1.68116,49.32167],[0.06048,49.32216],[1.14639,49.3224],[0.28354,49.3234],[-0.86484,49.32554],[-0.47235,49.32559],[-0.39039,49.32578],[-1.72114,49.32766],[0.086,49.32881],[5.23366,49.32884],[-0.80246,49.33127],[-0.4282,49.33224],[-0.44457,49.33399],[-0.60629,49.33473],[-0.63488,49.33506],[-1.72745,49.33571],[-1.66216,49.33789],[-1.73296,49.33798],[-0.6264,49.33811],[-0.47762,49.33826],[4.87305,49.33851],[5.18379,49.33859],[-0.58247,49.33964],[-0.89586,49.3408],[-0.75648,49.34333],[-0.77079,49.34685],[0.11172,49.34946],[-0.82025,49.34965],[-0.83353,49.35025],[0.8077,49.35358],[-1.74777,49.35358],[-1.7433,49.3537],[2.97581,49.3544],[-1.00987,49.35686],[-1.09672,49.35701],[6.17504,49.3612],[-1.01969,49.36202],[-1.74641,49.36211],[-1.75384,49.364],[-1.75054,49.36417],[-1.17756,49.36558],[-1.76032,49.3662],[0.48746,49.3668],[-1.42412,49.37618],[0.09518,49.37761],[-0.90975,49.37949],[-1.78609,49.38087],[3.47503,49.38234],[-1.76437,49.38333],[5.18032,49.38346],[0.1188,49.38738],[-1.52764,49.38739],[-1.05155,49.38818],[-1.05696,49.38964],[3.15158,49.39286],[3.32704,49.39298],[-1.01972,49.39339],[5.19075,49.39518],[0.2087,49.39776],[5.19424,49.39818],[3.6612,49.39834],[0.30592,49.40088],[3.51288,49.40226],[-1.80634,49.40227],[1.47987,49.40344],[2.25824,49.40507],[3.12882,49.40514],[0.38075,49.40531],[3.05281,49.40675],[0.56007,49.40987],[-1.31042,49.41013],[0.81129,49.41118],[1.83671,49.41145],[0.84624,49.41164],[-1.1819,49.41922],[1.50978,49.41967],[0.22659,49.42463],[6.3001,49.42619],[4.93997,49.42631],[-1.8048,49.42958],[1.15407,49.43113],[3.97031,49.43203],[-1.74674,49.43269],[0.82879,49.4348],[5.71861,49.44021],[6.34896,49.44534],[0.89252,49.4461],[0.59084,49.45938],[-1.6519,49.46252],[5.45859,49.46294],[-1.8288,49.46389],[-1.23453,49.46582],[-1.2354,49.4665],[5.39953,49.46918],[3.55385,49.47098],[1.6688,49.47158],[1.66881,49.47168],[-1.25016,49.4787],[-1.84216,49.48022],[0.77059,49.48432],[-1.79862,49.48716],[-1.56681,49.48729],[-1.84175,49.48793],[3.80857,49.49062],[-1.84235,49.49453],[1.4824,49.49506],[-1.27355,49.50141],[4.68239,49.50243],[0.98451,49.50564],[3.01867,49.50708],[-1.47524,49.51161],[3.04007,49.51294],[-1.36961,49.51492],[-1.29038,49.51717],[0.57355,49.51728],[5.36111,49.52127],[0.70212,49.52163],[-1.85017,49.52935],[0.49777,49.53036],[4.77497,49.53188],[-1.86116,49.53615],[2.94799,49.54265],[5.16023,49.54537],[3.47014,49.54865],[2.75189,49.56156],[3.59534,49.5622],[-1.36977,49.56591],[2.70838,49.56692],[1.87303,49.56902],[-1.83834,49.56983],[1.93899,49.57569],[-1.30612,49.57929],[-1.26871,49.58465],[3.04373,49.58879],[-1.59277,49.58957],[2.16257,49.59121],[0.58402,49.59154],[5.08249,49.60525],[1.54302,49.60603],[-1.23136,49.60702],[2.07104,49.6091],[1.91999,49.61649],[2.55975,49.62205],[0.24923,49.6228],[0.15865,49.62988],[0.84143,49.63226],[-1.84949,49.63312],[0.17111,49.6354],[2.55206,49.64766],[-1.56632,49.65421],[-1.65283,49.65577],[-1.5262,49.65703],[5.0483,49.66269],[-1.25864,49.66545],[3.36286,49.66601],[-1.48754,49.66734],[-1.69691,49.66889],[5.21964,49.66962],[-1.73246,49.67401],[-1.26692,49.67577],[-1.72324,49.67807],[2.15966,49.67876],[-1.2735,49.6802],[0.2135,49.68284],[2.0104,49.6872],[0.24456,49.68877],[-1.43799,49.69157],[0.27576,49.69858],[4.9386,49.69867],[0.31877,49.69934],[-1.41831,49.69996],[0.21546,49.70059],[0.23288,49.70105],[4.41945,49.70154],[-1.84089,49.70441],[1.25522,49.70768],[0.30907,49.70946],[0.45548,49.713],[3.35803,49.7173],[0.30639,49.72697],[0.32067,49.73288],[3.74305,49.73594],[0.30735,49.73608],[0.30754,49.73626],[1.42808,49.73775],[0.41673,49.7402],[0.94142,49.74502],[0.36043,49.75702],[1.74412,49.76601],[2.16801,49.77218],[2.97771,49.77397],[1.97446,49.77626],[4.72078,49.7788],[3.21416,49.78203],[0.6421,49.78319],[4.79102,49.79168],[2.45459,49.79292],[0.51875,49.79349],[1.21804,49.79468],[3.45292,49.79855],[0.49781,49.8039],[0.64902,49.80396],[0.52273,49.80435],[0.49359,49.80961],[0.56398,49.8215],[0.63399,49.82552],[0.54965,49.8277],[4.07161,49.84348],[0.59645,49.84939],[0.95908,49.85217],[3.30929,49.85426],[4.79277,49.85648],[0.7585,49.85777],[0.70438,49.85871],[0.88933,49.86217],[1.14434,49.8707],[1.04286,49.87237],[4.60463,49.87241],[4.78441,49.87402],[4.09064,49.87439],[0.80314,49.87582],[4.74213,49.8776],[0.82946,49.87897],[4.82579,49.88033],[4.77536,49.88336],[0.85204,49.88349],[3.06609,49.88539],[0.87535,49.88756],[3.57976,49.88843],[0.93582,49.8887],[0.87056,49.89368],[3.63372,49.89488],[1.05688,49.89852],[4.53499,49.89982],[1.0745,49.9004],[2.60752,49.9046],[0.92692,49.90483],[2.70235,49.90525],[3.92009,49.90583],[0.94962,49.90611],[2.6376,49.90651],[3.78106,49.90693],[1.04157,49.9073],[2.51686,49.90779],[2.65247,49.90853],[1.04067,49.90881],[4.28686,49.9128],[2.5748,49.91616],[2.93267,49.91755],[4.24984,49.91924],[2.57966,49.91928],[2.25934,49.92073],[1.65683,49.92395],[3.57789,49.92702],[2.74011,49.92839],[2.43707,49.92939],[2.76006,49.93232],[2.94138,49.93431],[2.4343,49.9353],[2.72625,49.93624],[1.61736,49.94169],[2.71565,49.94189],[2.90869,49.94263],[2.82134,49.94268],[4.08821,49.94331],[2.14655,49.9438],[4.63145,49.9441],[1.15043,49.94476],[2.8123,49.94776],[2.84361,49.94824],[2.80798,49.94941],[2.83705,49.95377],[2.83745,49.95387],[1.55104,49.95439],[2.5607,49.95742],[1.19326,49.9615],[2.81535,49.9642],[2.81297,49.96525],[1.20412,49.96636],[2.30127,49.97158],[1.44714,49.97944],[1.25854,49.98192],[4.71161,49.98755],[1.54365,49.99369],[1.33398,49.99496],[3.78258,50.00567],[4.06159,50.00594],[4.72228,50.01116],[2.65553,50.01143],[1.50915,50.01157],[1.98585,50.01402],[3.80771,50.02018],[1.49082,50.02549],[1.3085,50.02558],[4.13502,50.02642],[1.30812,50.03046],[1.98373,50.03468],[1.97802,50.03623],[2.66875,50.04123],[1.33078,50.04344],[2.67087,50.05041],[1.40832,50.05105],[1.36745,50.05172],[3.87894,50.05425],[3.89752,50.05749],[1.38862,50.05795],[1.41446,50.07727],[3.77146,50.07856],[4.72638,50.07908],[1.82314,50.07927],[1.71507,50.08585],[1.71564,50.08641],[1.44799,50.08987],[1.47888,50.08995],[2.73519,50.09135],[1.45803,50.10722],[4.05887,50.10827],[1.45611,50.11025],[3.7976,50.11236],[3.08304,50.11582],[1.57059,50.11818],[3.93467,50.11957],[3.99651,50.12035],[4.08102,50.12131],[4.1148,50.1226],[4.77779,50.12521],[4.80702,50.13085],[4.8099,50.13146],[4.1106,50.13173],[2.36925,50.13769],[1.76336,50.14111],[1.6198,50.14196],[3.76436,50.14226],[3.73719,50.14265],[4.0288,50.14282],[3.77421,50.14412],[3.79165,50.15101],[1.54618,50.15277],[1.63584,50.15344],[1.61896,50.15448],[1.58785,50.16117],[1.55294,50.16167],[1.49345,50.16722],[1.65634,50.16723],[2.28149,50.16858],[3.66759,50.16861],[1.4952,50.16974],[2.50496,50.17169],[4.14474,50.17378],[3.21534,50.17533],[1.58978,50.17618],[3.4923,50.17814],[4.09023,50.17855],[1.6178,50.18325],[1.62263,50.18447],[1.70695,50.18537],[1.72465,50.18961],[1.51675,50.1974],[3.7149,50.19798],[1.52828,50.20061],[1.52624,50.20271],[2.42245,50.20426],[1.69146,50.20924],[2.15999,50.21659],[1.62719,50.21783],[3.70799,50.22015],[1.68353,50.22022],[1.61804,50.22188],[3.10879,50.22297],[1.64017,50.23069],[3.66688,50.23191],[2.10616,50.23426],[1.62763,50.23626],[2.17702,50.23634],[3.70243,50.2382],[1.63184,50.23903],[3.63496,50.24314],[1.73087,50.24488],[1.61941,50.24801],[1.59859,50.24824],[1.74522,50.24849],[1.61212,50.24972],[3.2816,50.2502],[1.66864,50.25269],[3.08315,50.25272],[1.71222,50.25318],[3.16571,50.25587],[3.16207,50.25995],[3.14013,50.26143],[3.13799,50.26412],[3.23043,50.26594],[3.06586,50.26622],[3.67163,50.26747],[3.15424,50.2676],[2.34132,50.26775],[1.6026,50.26799],[3.8088,50.26842],[1.59841,50.27003],[2.45442,50.27029],[3.13805,50.27054],[1.61197,50.27162],[2.29915,50.27294],[2.94852,50.27343],[3.10565,50.27374],[1.61931,50.27407],[1.66176,50.27503],[1.99627,50.27714],[3.29195,50.27833],[3.71876,50.28192],[2.2401,50.28712],[1.68516,50.2876],[3.04935,50.29013],[3.16159,50.2926],[1.81893,50.29285],[3.97658,50.29559],[1.6682,50.30085],[2.92803,50.30384],[1.89789,50.30903],[1.60495,50.30969],[1.896,50.31048],[1.89694,50.31308],[1.69498,50.31358],[2.1589,50.31371],[1.89578,50.31409],[1.59433,50.31444],[3.83977,50.31659],[1.58358,50.31879],[1.60583,50.31935],[1.62452,50.32353],[3.74423,50.32397],[1.66044,50.32407],[1.87683,50.32794],[1.59127,50.32905],[2.21899,50.32967],[1.85901,50.33033],[1.57992,50.3329],[1.5743,50.33438],[3.79695,50.33593],[1.7126,50.33612],[1.57115,50.33997],[1.57326,50.3408],[1.85432,50.34507],[1.5823,50.34536],[1.83995,50.34974],[3.65323,50.35196],[2.14695,50.35774],[2.1466,50.35785],[2.07688,50.35992],[2.06853,50.36027],[1.6556,50.36283],[1.77546,50.37039],[1.66976,50.37322],[2.51612,50.37875],[1.60786,50.3798],[2.05872,50.38172],[1.64947,50.3823],[2.00059,50.38507],[1.97334,50.39448],[1.56663,50.39784],[1.75906,50.39826],[1.56961,50.39895],[1.94889,50.40312],[2.3079,50.40407],[2.20749,50.40458],[1.63359,50.40621],[1.95591,50.40803],[2.03095,50.41005],[3.26762,50.41152],[3.33258,50.41154],[1.61152,50.41698],[1.58685,50.41731],[1.58585,50.41828],[1.56717,50.41837],[2.15918,50.41917],[1.91213,50.41943],[2.01084,50.41993],[1.57459,50.42],[1.56982,50.42748],[1.71346,50.43119],[1.87599,50.43216],[3.4629,50.43535],[2.5743,50.44154],[1.61754,50.4443],[1.60012,50.45854],[3.34455,50.46299],[2.49777,50.46831],[1.76281,50.46837],[1.73881,50.4725],[1.57737,50.4727],[1.59173,50.47364],[2.23294,50.47534],[2.35132,50.47536],[1.61456,50.47639],[1.60661,50.4767],[1.75234,50.48161],[3.35233,50.48558],[2.17792,50.49971],[3.31366,50.50304],[3.47643,50.50406],[1.58911,50.51122],[2.11722,50.51485],[1.6255,50.5324],[2.17063,50.53886],[2.16259,50.54621],[2.76702,50.55032],[1.61831,50.55839],[2.49157,50.56491],[1.58035,50.56664],[3.17432,50.56869],[1.84255,50.56981],[2.14726,50.5775],[1.82614,50.58458],[1.61009,50.58907],[2.81963,50.59646],[2.81125,50.59744],[2.05431,50.62087],[2.43862,50.63312],[2.83275,50.63641],[2.30016,50.63744],[1.73778,50.63927],[2.32406,50.63939],[2.48181,50.64152],[1.62544,50.64662],[2.62184,50.64846],[1.75063,50.66205],[1.58911,50.66206],[2.50131,50.66702],[2.16521,50.66925],[1.57124,50.67093],[2.36914,50.67224],[1.64314,50.67743],[2.93118,50.67785],[2.06178,50.68224],[2.403,50.68302],[2.93343,50.68743],[3.07555,50.70031],[2.49929,50.70129],[2.42214,50.70204],[1.56625,50.70396],[2.26749,50.70469],[2.26195,50.70579],[2.40057,50.71025],[1.71614,50.73105],[1.82438,50.73298],[2.41087,50.7334],[2.59619,50.73482],[2.3751,50.73534],[1.76376,50.74474],[2.30461,50.74557],[1.5982,50.7458],[1.72007,50.75143],[1.60745,50.75264],[2.466,50.75764],[1.6078,50.76125],[2.74956,50.7616],[1.90981,50.76979],[2.22852,50.76987],[2.30246,50.77113],[2.73557,50.77876],[1.95579,50.77929],[1.94769,50.77978],[2.1879,50.7831],[2.21367,50.78334],[1.6697,50.78389],[2.70798,50.78406],[2.21514,50.78522],[2.17439,50.79056],[2.43114,50.7934],[2.67316,50.79412],[1.8123,50.79512],[2.22396,50.79761],[2.20352,50.79866],[2.33924,50.80152],[1.97377,50.80784],[2.05535,50.80846],[1.60466,50.81183],[1.63523,50.81646],[2.32357,50.81723],[1.68459,50.81727],[2.17415,50.81756],[1.63545,50.8177],[1.63105,50.81796],[2.17876,50.81903],[1.59794,50.82006],[2.07596,50.82204],[1.59631,50.82482],[2.26573,50.83128],[2.29069,50.83566],[1.97654,50.83824],[1.59987,50.84356],[2.57122,50.84787],[1.63893,50.8495],[1.72128,50.85887],[1.9454,50.86075],[1.97382,50.86103],[2.32957,50.86171],[1.96605,50.86388],[1.8582,50.86636],[1.95184,50.86636],[2.1648,50.86748],[1.74212,50.87023],[2.14719,50.87143],[1.9735,50.87214],[2.22965,50.87218],[2.59049,50.87371],[1.70915,50.88279],[1.65816,50.8838],[1.87558,50.88466],[1.87599,50.88569],[2.35238,50.88814],[2.4359,50.89528],[2.26437,50.90288],[1.75127,50.9116],[1.72061,50.9122],[2.26737,50.91695],[1.7105,50.91842],[2.31793,50.92163],[2.25739,50.93636],[1.75797,50.94623],[1.81101,50.95677],[2.57818,50.97757],[2.05748,50.98615],[1.97094,50.98621],[2.04199,50.9873],[1.98543,50.98914],[1.99468,50.99263],[2.04678,50.99596],[2.0476,50.99611],[2.04956,50.99653],[2.0971,51.00271],[2.40737,51.0036],[2.118,51.00761],[2.57365,51.02166],[2.42025,51.05171],[2.51841,51.06637],[2.55504,51.07618],[2.52202,51.07945]]} \ No newline at end of file diff --git a/GeoConverterTests/Files/Sample3.gpx b/GeoConverterTests/Files/Sample3.gpx new file mode 100644 index 0000000..dcdd2ca --- /dev/null +++ b/GeoConverterTests/Files/Sample3.gpx @@ -0,0 +1,1545 @@ + + + + 4 Peaks Alta Badia: quattro cime, una sfida + + 4 Peaks Alta Badia - Community + + + + + + + 4 Peaks Alta Badia: quattro cime, una sfida + Dalla primavera 2019 gli appassionati di sport estremi possono cimentarsi in una nuova,emozionante sfida a La Crusc: il “4 Peaks Alta Badia”. Gli scalatori che riescono a conquistare tutte le quattro cime del Sasso Santa Croce in un solo giorno si aggiudicano il titolo di “Alta Badia Mountaineer”. Avventura, adrenalina e panorami mozzafiato attendono tutti coloro che decidono di affrontare lasfida del “4 Peaks Alta Badia”, il cui obiettivo è conquistare le quattro cime di Sasso Santa Croce(Sas dla Crusc 2.907 m), Cima Dieci (Piza dales Diesc 3.026 m), Lavarella (3.055 m) e Conturines(3.064 m). E se per qualcuno è già un’impresa al limite completare il giro in tappe successive, gli alpinisti estremi lo devono fare in un giorno solo (durata complessiva: circa 11,5 ore). + + + 2047.5 + + + 2052.7 + + + 2077.0 + + + 2083.5 + + + 2090.8 + + + 2113.6 + + + 2115.2 + + + 2120.0 + + + 2125.1 + + + 2131.1 + + + 2136.2 + + + 2137.7 + + + 2156.3 + + + 2163.0 + + + 2168.3 + + + 2170.9 + + + 2173.3 + + + 2180.4 + + + 2185.3 + + + 2190.4 + + + 2197.6 + + + 2204.2 + + + 2215.9 + + + 2225.5 + + + 2238.3 + + + 2242.7 + + + 2256.6 + + + 2276.2 + + + 2279.9 + + + 2285.5 + + + 2298.3 + + + 2307.8 + + + 2311.0 + + + 2332.0 + + + 2347.1 + + + 2352.6 + + + 2353.1 + + + 2364.8 + + + 2391.8 + + + 2396.0 + + + 2400.7 + + + 2398.7 + + + 2401.6 + + + 2408.1 + + + 2417.2 + + + 2426.9 + + + 2434.4 + + + 2443.6 + + + 2471.3 + + + 2497.0 + + + 2495.8 + + + 2506.9 + + + 2501.9 + + + 2523.1 + + + 2521.0 + + + 2524.9 + + + 2531.7 + + + 2549.1 + + + 2557.7 + + + 2568.3 + + + 2577.5 + + + 2611.0 + + + 2609.8 + + + 2607.4 + + + 2614.9 + + + 2624.5 + + + 2631.0 + + + 2637.2 + + + 2643.3 + + + 2646.5 + + + 2661.6 + + + 2669.8 + + + 2680.0 + + + 2686.5 + + + 2691.0 + + + 2695.1 + + + 2708.3 + + + 2708.3 + + + 2714.3 + + + 2720.9 + + + 2726.1 + + + 2730.9 + + + 2739.2 + + + 2750.2 + + + 2762.6 + + + 2781.9 + + + 2788.3 + + + 2800.0 + + + 2805.6 + + + 2819.5 + + + 2835.9 + + + 2855.4 + + + 2862.9 + + + 2868.7 + + + 2880.3 + + + 2892.5 + + + 2898.0 + + + 2903.3 + + + 2893.1 + + + 2868.3 + + + 2863.5 + + + 2855.4 + + + 2849.9 + + + 2838.6 + + + 2843.6 + + + 2847.8 + + + 2844.3 + + + 2852.7 + + + 2865.1 + + + 2873.9 + + + 2877.7 + + + 2877.4 + + + 2870.5 + + + 2870.3 + + + 2870.8 + + + 2873.1 + + + 2896.2 + + + 2900.3 + + + 2913.0 + + + 2917.4 + + + 2922.8 + + + 2930.5 + + + 2946.3 + + + 2950.9 + + + 2967.9 + + + 2974.1 + + + 2963.5 + + + 2950.0 + + + 2939.8 + + + 2915.5 + + + 2909.6 + + + 2902.8 + + + 2889.2 + + + 2871.2 + + + 2872.1 + + + 2872.2 + + + 2870.3 + + + 2868.9 + + + 2873.1 + + + 2876.9 + + + 2865.1 + + + 2859.0 + + + 2851.5 + + + 2848.2 + + + 2850.7 + + + 2849.5 + + + 2841.7 + + + 2835.9 + + + 2826.1 + + + 2816.5 + + + 2807.9 + + + 2791.5 + + + 2781.9 + + + 2775.9 + + + 2767.3 + + + 2757.9 + + + 2748.6 + + + 2745.7 + + + 2736.3 + + + 2732.1 + + + 2724.8 + + + 2718.6 + + + 2708.3 + + + 2708.1 + + + 2708.0 + + + 2709.9 + + + 2696.8 + + + 2691.7 + + + 2682.2 + + + 2678.9 + + + 2670.5 + + + 2664.6 + + + 2654.1 + + + 2645.2 + + + 2642.2 + + + 2632.0 + + + 2629.8 + + + 2622.3 + + + 2611.4 + + + 2608.0 + + + 2608.1 + + + 2609.3 + + + 2605.4 + + + 2595.7 + + + 2592.5 + + + 2587.5 + + + 2581.8 + + + 2575.7 + + + 2569.8 + + + 2565.1 + + + 2554.8 + + + 2530.1 + + + 2525.9 + + + 2515.2 + + + 2491.9 + + + 2473.6 + + + 2467.8 + + + 2458.6 + + + 2438.5 + + + 2423.1 + + + 2417.0 + + + 2408.4 + + + 2420.7 + + + 2425.0 + + + 2425.0 + + + 2426.5 + + + 2405.1 + + + 2382.3 + + + 2380.9 + + + 2380.1 + + + 2381.4 + + + 2386.5 + + + 2386.5 + + + 2386.4 + + + 2379.6 + + + 2379.6 + + + 2392.7 + + + 2397.1 + + + 2405.7 + + + 2407.3 + + + 2410.3 + + + 2414.9 + + + 2416.2 + + + 2428.8 + + + 2433.7 + + + 2436.3 + + + 2442.4 + + + 2453.5 + + + 2466.1 + + + 2474.3 + + + 2485.6 + + + 2492.3 + + + 2497.9 + + + 2507.7 + + + 2519.5 + + + 2520.5 + + + 2530.7 + + + 2555.3 + + + 2559.9 + + + 2567.7 + + + 2573.8 + + + 2581.2 + + + 2576.6 + + + 2576.1 + + + 2577.3 + + + 2578.7 + + + 2598.5 + + + 2605.7 + + + 2625.5 + + + 2633.5 + + + 2642.8 + + + 2653.3 + + + 2660.4 + + + 2673.2 + + + 2685.2 + + + 2756.5 + + + 2763.6 + + + 2769.5 + + + 2814.7 + + + 2849.3 + + + 2839.1 + + + 2843.8 + + + 2852.8 + + + 2869.0 + + + 2879.7 + + + 2901.0 + + + 2917.9 + + + 2928.7 + + + 2961.1 + + + 2985.9 + + + 2987.1 + + + 3010.6 + + + 3020.2 + + + 3027.4 + + + 3033.6 + + + 3048.0 + + + 3052.3 + + + 3051.1 + + + 3050.1 + + + 3035.9 + + + 3026.7 + + + 2999.3 + + + 2988.5 + + + 2983.9 + + + 2985.1 + + + 2982.3 + + + 2983.8 + + + 2976.7 + + + 2971.6 + + + 2967.7 + + + 2960.0 + + + 2954.9 + + + 2945.2 + + + 2945.7 + + + 2939.8 + + + 2910.9 + + + 2904.8 + + + 2898.6 + + + 2892.5 + + + 2883.9 + + + 2883.1 + + + 2888.0 + + + 2901.3 + + + 2910.1 + + + 2920.3 + + + 2929.3 + + + 2929.0 + + + 2928.1 + + + 2924.6 + + + 2927.5 + + + 2927.9 + + + 2920.3 + + + 2915.2 + + + 2919.1 + + + 2925.4 + + + 2933.6 + + + 2937.1 + + + 2942.7 + + + 2947.9 + + + 2956.9 + + + 2970.6 + + + 2982.2 + + + 2997.5 + + + 3007.1 + + + 3008.2 + + + 2990.7 + + + 2991.7 + + + 2995.8 + + + 2971.1 + + + 2984.9 + + + 2999.0 + + + 2995.9 + + + 2998.0 + + + 3009.0 + + + 3009.8 + + + 3000.2 + + + 2985.1 + + + 2974.0 + + + 2949.5 + + + 2942.7 + + + 2939.8 + + + 2935.5 + + + 2930.5 + + + 2924.3 + + + 2919.1 + + + 2915.2 + + + 2919.2 + + + 2928.1 + + + 2929.6 + + + 2927.7 + + + 2921.7 + + + 2916.2 + + + 2883.1 + + + 2884.2 + + + 2882.4 + + + 2875.1 + + + 2865.2 + + + 2857.6 + + + 2851.4 + + + 2846.1 + + + 2843.2 + + + 2838.3 + + + 2825.9 + + + 2821.5 + + + 2805.2 + + + 2785.1 + + + 2775.9 + + + 2769.3 + + + 2760.5 + + + 2743.2 + + + 2734.9 + + + 2732.6 + + + 2729.1 + + + 2725.5 + + + 2724.0 + + + 2722.8 + + + 2715.7 + + + 2709.5 + + + 2697.7 + + + 2694.5 + + + 2674.2 + + + 2667.2 + + + 2663.1 + + + 2651.6 + + + 2641.8 + + + 2616.5 + + + 2593.2 + + + 2568.2 + + + 2559.9 + + + 2551.0 + + + 2546.6 + + + 2527.5 + + + 2524.3 + + + 2526.2 + + + 2509.2 + + + 2486.2 + + + 2478.7 + + + 2472.4 + + + 2455.4 + + + 2436.2 + + + 2430.5 + + + 2409.3 + + + 2403.7 + + + 2397.7 + + + 2382.9 + + + 2373.6 + + + 2360.6 + + + 2346.4 + + + 2339.1 + + + 2322.3 + + + 2297.1 + + + 2277.7 + + + 2268.7 + + + 2257.6 + + + 2238.0 + + + 2227.3 + + + 2223.3 + + + 2212.4 + + + 2207.1 + + + 2194.6 + + + 2187.6 + + + 2183.6 + + + 2179.2 + + + 2171.9 + + + 2170.0 + + + 2169.8 + + + 2169.1 + + + 2165.2 + + + 2158.8 + + + 2156.1 + + + 2157.0 + + + 2152.3 + + + 2147.6 + + + 2133.5 + + + 2129.1 + + + 2114.6 + + + 2114.1 + + + 2113.0 + + + 2113.5 + + + 2112.2 + + + 2111.2 + + + 2108.5 + + + 2110.6 + + + 2104.9 + + + 2095.9 + + + 2094.2 + + + 2093.1 + + + 2088.6 + + + 2090.1 + + + 2102.8 + + + 2098.5 + + + 2092.5 + + + 2084.8 + + + 2076.8 + + + 2073.3 + + + 2077.4 + + + 2074.0 + + + 2056.0 + + + 2053.5 + + + 2052.5 + + + 2049.0 + + + 2044.9 + + + 2043.4 + + + 2045.7 + + + 2049.2 + + + 2051.5 + + + 2054.3 + + + 2056.6 + + + 2062.1 + + + 2066.6 + + + 2057.3 + + + 2048.2 + + + 2037.1 + + + 2034.9 + + + 2025.2 + + + 2004.3 + + + 1984.8 + + + 1975.6 + + + 1953.6 + + + 1948.8 + + + 1942.7 + + + 1935.4 + + + 1925.4 + + + 1917.4 + + + 1913.6 + + + 1900.3 + + + 1893.8 + + + 1876.6 + + + 1871.7 + + + 1860.9 + + + 1857.4 + + + 1850.2 + + + 1844.0 + + + 1838.2 + + + 1832.7 + + + 1825.3 + + + 1812.3 + + + 1793.3 + + + 1787.9 + + + 1780.8 + + + 1772.9 + + + 1761.3 + + + 1741.8 + + + 1742.3 + + + 1740.4 + + + 1738.7 + + + 1727.1 + + + 1727.0 + + + 1726.0 + + + + \ No newline at end of file diff --git a/GeoConverterTests/Files/Sample3.json b/GeoConverterTests/Files/Sample3.json new file mode 100644 index 0000000..ba6ae90 --- /dev/null +++ b/GeoConverterTests/Files/Sample3.json @@ -0,0 +1 @@ +{"type":"LineString","coordinates":[[11.938619,46.614436,2047.5],[11.939283,46.614526,2052.7],[11.940865,46.614905,2077],[11.941134,46.614761,2083.5],[11.941379,46.614535,2090.8],[11.943015,46.611794,2113.6],[11.943485,46.611775,2115.2],[11.943948,46.611611,2120],[11.944228,46.611397,2125.1],[11.94501,46.610941,2131.1],[11.945087,46.610757,2136.2],[11.944983,46.610484,2137.7],[11.944911,46.610002,2156.3],[11.944958,46.609613,2163],[11.945101,46.609448,2168.3],[11.94522,46.60928,2170.9],[11.945393,46.609116,2173.3],[11.945517,46.608833,2180.4],[11.945593,46.608739,2185.3],[11.945647,46.608576,2190.4],[11.945674,46.608406,2197.6],[11.945782,46.608353,2204.2],[11.946109,46.608193,2215.9],[11.946225,46.60824,2225.5],[11.946519,46.608434,2238.3],[11.946534,46.608341,2242.7],[11.946648,46.608217,2256.6],[11.946778,46.607966,2276.2],[11.946809,46.607762,2279.9],[11.946916,46.607638,2285.5],[11.946756,46.6073,2298.3],[11.946689,46.60718,2307.8],[11.946729,46.607081,2311],[11.947173,46.606923,2332],[11.94748,46.606696,2347.1],[11.947579,46.606655,2352.6],[11.947782,46.606414,2353.1],[11.947844,46.606169,2364.8],[11.948314,46.605995,2391.8],[11.948424,46.605831,2396],[11.948653,46.605601,2400.7],[11.94893,46.604389,2398.7],[11.949195,46.604237,2401.6],[11.949379,46.603789,2408.1],[11.949347,46.603568,2417.2],[11.949508,46.603613,2426.9],[11.949628,46.60367,2434.4],[11.949869,46.603525,2443.6],[11.950228,46.603447,2471.3],[11.950543,46.603618,2497],[11.950683,46.603501,2495.8],[11.950931,46.603214,2506.9],[11.950718,46.602945,2501.9],[11.950474,46.602358,2523.1],[11.950631,46.602129,2521],[11.951221,46.601829,2524.9],[11.951877,46.60104,2531.7],[11.952228,46.60084,2549.1],[11.952421,46.600767,2557.7],[11.95258,46.600834,2568.3],[11.952797,46.60078,2577.5],[11.95335,46.600817,2611],[11.953232,46.600929,2609.8],[11.952695,46.601637,2607.4],[11.952518,46.601828,2614.9],[11.952136,46.602209,2624.5],[11.951923,46.602667,2631],[11.95188,46.602952,2637.2],[11.951844,46.603347,2643.3],[11.951913,46.603601,2646.5],[11.951999,46.60411,2661.6],[11.951811,46.604375,2669.8],[11.951452,46.605269,2680],[11.951214,46.605584,2686.5],[11.951046,46.605697,2691],[11.950807,46.605987,2695.1],[11.950609,46.606747,2708.3],[11.950954,46.608454,2708.3],[11.950932,46.60865,2714.3],[11.951015,46.608956,2720.9],[11.950877,46.609297,2726.1],[11.95103,46.609701,2730.9],[11.951131,46.610198,2739.2],[11.95127,46.610929,2750.2],[11.95146,46.611541,2762.6],[11.951635,46.612116,2781.9],[11.951477,46.612131,2788.3],[11.951423,46.6124,2800],[11.951621,46.612593,2805.6],[11.952298,46.61313,2819.5],[11.952625,46.613649,2835.9],[11.951901,46.613681,2855.4],[11.951998,46.613867,2862.9],[11.952009,46.61399,2868.7],[11.951443,46.613965,2880.3],[11.951104,46.614091,2892.5],[11.951127,46.614191,2898],[11.951162,46.61432,2903.3],[11.951069,46.614098,2893.1],[11.952044,46.614003,2868.3],[11.952037,46.613892,2863.5],[11.951901,46.613681,2855.4],[11.951993,46.613605,2849.9],[11.952746,46.613794,2838.6],[11.952852,46.61422,2843.6],[11.952339,46.615276,2847.8],[11.95242,46.615605,2844.3],[11.95255,46.616271,2852.7],[11.953005,46.616581,2865.1],[11.952932,46.616684,2873.9],[11.953193,46.616813,2877.7],[11.953473,46.617073,2877.4],[11.954731,46.618073,2870.5],[11.955782,46.618561,2870.3],[11.956315,46.618734,2870.8],[11.956705,46.619053,2873.1],[11.958177,46.619784,2896.2],[11.95838,46.61982,2900.3],[11.959055,46.61999,2913],[11.958919,46.620032,2917.4],[11.958974,46.620177,2922.8],[11.959151,46.620418,2930.5],[11.959391,46.620805,2946.3],[11.959551,46.620907,2950.9],[11.959656,46.621122,2967.9],[11.959742,46.621225,2974.1],[11.959767,46.621097,2963.5],[11.959523,46.62089,2950],[11.959312,46.620668,2939.8],[11.959026,46.620034,2915.5],[11.959016,46.619899,2909.6],[11.958652,46.619843,2902.8],[11.958092,46.61968,2889.2],[11.957405,46.619339,2871.2],[11.957028,46.619224,2872.1],[11.95641,46.618844,2872.2],[11.955969,46.618588,2870.3],[11.955205,46.618334,2868.9],[11.954092,46.617598,2873.1],[11.953598,46.61718,2876.9],[11.953005,46.616581,2865.1],[11.952935,46.616464,2859],[11.952515,46.616238,2851.5],[11.952343,46.615238,2848.2],[11.952469,46.614781,2850.7],[11.952742,46.614364,2849.5],[11.952892,46.614042,2841.7],[11.952625,46.613649,2835.9],[11.952356,46.613298,2826.1],[11.952145,46.613016,2816.5],[11.951882,46.612736,2807.9],[11.951466,46.61222,2791.5],[11.951635,46.612116,2781.9],[11.951689,46.612037,2775.9],[11.951529,46.611696,2767.3],[11.951364,46.611357,2757.9],[11.951257,46.610827,2748.6],[11.951194,46.61055,2745.7],[11.951144,46.610138,2736.3],[11.951068,46.609782,2732.1],[11.950891,46.60925,2724.8],[11.950977,46.608745,2718.6],[11.950954,46.608454,2708.3],[11.951046,46.608205,2708.1],[11.950884,46.607914,2708],[11.950748,46.607131,2709.9],[11.950734,46.606153,2696.8],[11.951003,46.605727,2691.7],[11.951336,46.605365,2682.2],[11.951606,46.605033,2678.9],[11.951801,46.604412,2670.5],[11.951961,46.604208,2664.6],[11.951989,46.603821,2654.1],[11.95189,46.603476,2645.2],[11.951876,46.603264,2642.2],[11.951893,46.602718,2632],[11.951917,46.602492,2629.8],[11.952295,46.601991,2622.3],[11.952692,46.601792,2611.4],[11.952725,46.601494,2608],[11.952934,46.601184,2608.1],[11.953444,46.600956,2609.3],[11.953675,46.6011,2605.4],[11.954399,46.601261,2595.7],[11.95469,46.601341,2592.5],[11.955137,46.601347,2587.5],[11.955511,46.601372,2581.8],[11.955825,46.601679,2575.7],[11.956068,46.601815,2569.8],[11.95657,46.601955,2565.1],[11.957043,46.602135,2554.8],[11.958063,46.602447,2530.1],[11.958274,46.602548,2525.9],[11.959428,46.602908,2515.2],[11.961203,46.603144,2491.9],[11.961974,46.603309,2473.6],[11.962295,46.603282,2467.8],[11.962564,46.603144,2458.6],[11.963618,46.602865,2438.5],[11.964565,46.602629,2423.1],[11.965163,46.602633,2417],[11.966785,46.602591,2408.4],[11.96782,46.602563,2420.7],[11.968974,46.6023,2425],[11.969463,46.602288,2425],[11.969961,46.602255,2426.5],[11.973442,46.60299,2405.1],[11.975,46.602892,2382.3],[11.974898,46.602684,2380.9],[11.974618,46.602493,2380.1],[11.974576,46.602238,2381.4],[11.974715,46.601042,2386.5],[11.974146,46.600444,2386.5],[11.97393,46.6004,2386.4],[11.973607,46.599957,2379.6],[11.973215,46.599818,2379.6],[11.971893,46.599452,2392.7],[11.971576,46.599466,2397.1],[11.970551,46.599379,2405.7],[11.970162,46.59926,2407.3],[11.969637,46.599092,2410.3],[11.969146,46.598871,2414.9],[11.967351,46.597973,2416.2],[11.966519,46.597646,2428.8],[11.966511,46.597363,2433.7],[11.966055,46.597156,2436.3],[11.965833,46.596949,2442.4],[11.965697,46.596662,2453.5],[11.965516,46.596438,2466.1],[11.965239,46.596264,2474.3],[11.96493,46.596057,2485.6],[11.964831,46.595795,2492.3],[11.964816,46.595589,2497.9],[11.964852,46.595274,2507.7],[11.965013,46.594667,2519.5],[11.965067,46.594311,2520.5],[11.965049,46.59342,2530.7],[11.966212,46.594059,2555.3],[11.966306,46.59394,2559.9],[11.966341,46.59379,2567.7],[11.966412,46.593467,2573.8],[11.967134,46.592951,2581.2],[11.96716,46.592781,2576.6],[11.967201,46.592622,2576.1],[11.967183,46.592466,2577.3],[11.967279,46.592142,2578.7],[11.96721,46.591506,2598.5],[11.967181,46.59102,2605.7],[11.967195,46.590679,2625.5],[11.967176,46.590486,2633.5],[11.967158,46.590196,2642.8],[11.967406,46.589895,2653.3],[11.967575,46.589897,2660.4],[11.96774,46.590022,2673.2],[11.967874,46.590054,2685.2],[11.968814,46.589543,2756.5],[11.968906,46.589453,2763.6],[11.969007,46.589365,2769.5],[11.969831,46.58888,2814.7],[11.970325,46.588767,2849.3],[11.970422,46.588573,2839.1],[11.970447,46.58838,2843.8],[11.970428,46.588194,2852.8],[11.970408,46.587871,2869],[11.970393,46.587537,2879.7],[11.970334,46.587095,2901],[11.970263,46.58678,2917.9],[11.970159,46.586591,2928.7],[11.970018,46.586042,2961.1],[11.97036,46.585408,2985.9],[11.970288,46.585271,2987.1],[11.970466,46.585121,3010.6],[11.970393,46.58501,3020.2],[11.970222,46.584927,3027.4],[11.970097,46.584809,3033.6],[11.97032,46.584693,3048],[11.970444,46.584683,3052.3],[11.970994,46.584999,3051.1],[11.970724,46.584805,3050.1],[11.969913,46.584221,3035.9],[11.969672,46.58411,3026.7],[11.969355,46.583727,2999.3],[11.969429,46.583552,2988.5],[11.96944,46.583359,2983.9],[11.969419,46.583033,2985.1],[11.969571,46.582903,2982.3],[11.969557,46.582752,2983.8],[11.969463,46.582464,2976.7],[11.969654,46.582432,2971.6],[11.969763,46.582392,2967.7],[11.96992,46.582246,2960],[11.970014,46.582193,2954.9],[11.97019,46.582103,2945.2],[11.969601,46.582092,2945.7],[11.969572,46.581996,2939.8],[11.969884,46.581653,2910.9],[11.969983,46.581583,2904.8],[11.970007,46.581465,2898.6],[11.970085,46.581357,2892.5],[11.970221,46.580964,2883.9],[11.970401,46.58066,2883.1],[11.970556,46.580407,2888],[11.970868,46.579943,2901.3],[11.971071,46.579655,2910.1],[11.971496,46.579035,2920.3],[11.972528,46.57891,2929.3],[11.973248,46.578973,2929],[11.973911,46.578799,2928.1],[11.97414,46.578505,2924.6],[11.975066,46.577509,2927.5],[11.975268,46.577376,2927.9],[11.975526,46.577297,2920.3],[11.975937,46.577097,2915.2],[11.976001,46.576958,2919.1],[11.976093,46.576838,2925.4],[11.976204,46.576715,2933.6],[11.976304,46.576668,2937.1],[11.976361,46.576576,2942.7],[11.976472,46.576497,2947.9],[11.976668,46.576431,2956.9],[11.976861,46.576255,2970.6],[11.977041,46.576092,2982.2],[11.977123,46.576012,2997.5],[11.977181,46.575895,3007.1],[11.977191,46.575749,3008.2],[11.977358,46.57566,2990.7],[11.977448,46.575693,2991.7],[11.977634,46.575916,2995.8],[11.978207,46.575976,2971.1],[11.977857,46.575951,2984.9],[11.97756,46.575903,2999],[11.97746,46.575733,2995.9],[11.977353,46.575698,2998],[11.977256,46.575818,3009],[11.977054,46.575826,3009.8],[11.977202,46.575991,3000.2],[11.977088,46.576112,2985.1],[11.976997,46.576175,2974],[11.976525,46.576506,2949.5],[11.976361,46.576576,2942.7],[11.976422,46.576662,2939.8],[11.976226,46.576664,2935.5],[11.976192,46.576774,2930.5],[11.976041,46.57684,2924.3],[11.976001,46.576958,2919.1],[11.975937,46.577097,2915.2],[11.974626,46.577869,2919.2],[11.973911,46.578799,2928.1],[11.973438,46.578946,2929.6],[11.972791,46.578951,2927.7],[11.971686,46.578987,2921.7],[11.971173,46.579243,2916.2],[11.970401,46.58066,2883.1],[11.970224,46.581006,2884.2],[11.970338,46.581112,2882.4],[11.970576,46.581051,2875.1],[11.971131,46.581308,2865.2],[11.971405,46.58154,2857.6],[11.971611,46.581583,2851.4],[11.971725,46.581402,2846.1],[11.971871,46.581481,2843.2],[11.972037,46.581561,2838.3],[11.972262,46.581858,2825.9],[11.972302,46.58204,2821.5],[11.972591,46.582421,2805.2],[11.973171,46.582178,2785.1],[11.973454,46.581934,2775.9],[11.973643,46.581826,2769.3],[11.97388,46.581966,2760.5],[11.974274,46.582315,2743.2],[11.974537,46.582457,2734.9],[11.97468,46.582439,2732.6],[11.974983,46.582431,2729.1],[11.97684,46.582895,2725.5],[11.977594,46.582983,2724],[11.977926,46.583052,2722.8],[11.978952,46.583262,2715.7],[11.979555,46.583339,2709.5],[11.980432,46.583727,2697.7],[11.980826,46.584085,2694.5],[11.981609,46.584967,2674.2],[11.98178,46.584916,2667.2],[11.981909,46.584969,2663.1],[11.982303,46.584947,2651.6],[11.983481,46.584829,2641.8],[11.984561,46.584857,2616.5],[11.985944,46.585024,2593.2],[11.987207,46.584996,2568.2],[11.98763,46.584831,2559.9],[11.98795,46.584651,2551],[11.988104,46.584525,2546.6],[11.988173,46.58381,2527.5],[11.988384,46.583614,2524.3],[11.989316,46.583413,2526.2],[11.990093,46.583657,2509.2],[11.991196,46.584132,2486.2],[11.991664,46.584226,2478.7],[11.992036,46.584211,2472.4],[11.992939,46.584136,2455.4],[11.993807,46.584116,2436.2],[11.994082,46.584144,2430.5],[11.994762,46.583759,2409.3],[11.995025,46.583661,2403.7],[11.995279,46.583751,2397.7],[11.995948,46.58381,2382.9],[11.996313,46.584018,2373.6],[11.997068,46.584305,2360.6],[11.997462,46.584627,2346.4],[11.997576,46.58469,2339.1],[11.997839,46.584838,2322.3],[11.998371,46.585219,2297.1],[11.998874,46.585074,2277.7],[11.999028,46.584968,2268.7],[11.999319,46.584901,2257.6],[12.000154,46.584686,2238],[12.000771,46.584909,2227.3],[12.001022,46.58503,2223.3],[12.001653,46.585131,2212.4],[12.002293,46.585176,2207.1],[12.003781,46.585202,2194.6],[12.0043,46.585225,2187.6],[12.004606,46.58544,2183.6],[12.004763,46.585478,2179.2],[12.004884,46.585545,2171.9],[12.005229,46.585466,2170],[12.005889,46.585168,2169.8],[12.00641,46.585085,2169.1],[12.006786,46.585028,2165.2],[12.00741,46.585101,2158.8],[12.007588,46.585029,2156.1],[12.007253,46.584501,2157],[12.00703,46.584143,2152.3],[12.006864,46.583697,2147.6],[12.00674,46.582776,2133.5],[12.006629,46.582384,2129.1],[12.006089,46.579502,2114.6],[12.006011,46.577247,2114.1],[12.006075,46.57656,2113],[12.005434,46.576105,2113.5],[12.004865,46.575808,2112.2],[12.004387,46.575606,2111.2],[12.003781,46.575154,2108.5],[12.003641,46.574921,2110.6],[12.00296,46.574145,2104.9],[12.002463,46.573886,2095.9],[12.002194,46.573643,2094.2],[12.002078,46.573368,2093.1],[12.001767,46.572861,2088.6],[12.001628,46.572413,2090.1],[12.00174,46.571946,2102.8],[12.001826,46.571655,2098.5],[12.001787,46.570984,2092.5],[12.001817,46.570659,2084.8],[12.001793,46.570284,2076.8],[12.001587,46.569903,2073.3],[12.001312,46.569244,2077.4],[12.001413,46.568936,2074],[12.001261,46.568244,2056],[12.001418,46.567995,2053.5],[12.00181,46.567731,2052.5],[12.001888,46.567556,2049],[12.001489,46.567194,2044.9],[12.001132,46.567084,2043.4],[12.000461,46.567078,2045.7],[11.999933,46.56695,2049.2],[11.999592,46.566716,2051.5],[11.999476,46.566458,2054.3],[11.999162,46.566088,2056.6],[11.998793,46.565885,2062.1],[11.998589,46.565496,2066.6],[11.998591,46.565153,2057.3],[11.998788,46.56485,2048.2],[11.998798,46.564697,2037.1],[11.998667,46.564738,2034.9],[11.99869,46.564621,2025.2],[11.998903,46.564158,2004.3],[11.998556,46.563703,1984.8],[11.99837,46.563496,1975.6],[11.997706,46.563388,1953.6],[11.997606,46.563488,1948.8],[11.997451,46.563632,1942.7],[11.997268,46.563813,1935.4],[11.996935,46.563907,1925.4],[11.99665,46.563963,1917.4],[11.996492,46.563964,1913.6],[11.995843,46.56391,1900.3],[11.995276,46.563849,1893.8],[11.993398,46.563342,1876.6],[11.9933,46.563281,1871.7],[11.993062,46.563051,1860.9],[11.992664,46.56283,1857.4],[11.992477,46.56248,1850.2],[11.992434,46.56228,1844],[11.992256,46.562127,1838.2],[11.992222,46.562003,1832.7],[11.992142,46.561835,1825.3],[11.991871,46.561429,1812.3],[11.991547,46.56075,1793.3],[11.991327,46.560609,1787.9],[11.990972,46.560575,1780.8],[11.990534,46.560201,1772.9],[11.990022,46.560131,1761.3],[11.988716,46.55986,1741.8],[11.988258,46.55977,1742.3],[11.988113,46.559577,1740.4],[11.987494,46.559526,1738.7],[11.982729,46.559965,1727.1],[11.982691,46.559954,1727],[11.98229,46.559818,1726]]} \ No newline at end of file diff --git a/GeoConverterTests/GeoConverterTests.csproj b/GeoConverterTests/GeoConverterTests.csproj new file mode 100644 index 0000000..c18b775 --- /dev/null +++ b/GeoConverterTests/GeoConverterTests.csproj @@ -0,0 +1,40 @@ + + + + net8.0 + enable + enable + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/GeoConverterTests/GeoJsonConverterTests.cs b/GeoConverterTests/GeoJsonConverterTests.cs new file mode 100644 index 0000000..62f15dd --- /dev/null +++ b/GeoConverterTests/GeoJsonConverterTests.cs @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using GeoConverter; +using System.Reflection; + +namespace GeoConverterTests +{ + public class GeoJsonConverterTests + { + [Theory] + [InlineData("216051")] + [InlineData("216052")] + [InlineData("216053")] + public void TestKmlConversion(string input) + { + string kml = GetContent(input, "kml"); + var actual = GeoJsonConverter.ConvertFromKml(kml); + string expected = GetContent(input ,"json"); + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData("Sample1")] + [InlineData("Sample2")] + [InlineData("Sample3")] + public void TestGpxConversion(string input) + { + string gpx = GetContent(input, "gpx"); + var actual = GeoJsonConverter.ConvertFromGpx(gpx); + string expected = GetContent(input, "json"); + Assert.Equal(expected, actual); + } + + private static string GetContent(string input, string extension) + { + return File.ReadAllText(Path.Combine("Files", Path.ChangeExtension(input, extension))); + } + } +} \ No newline at end of file diff --git a/GeoConverterTests/Usings.cs b/GeoConverterTests/Usings.cs new file mode 100644 index 0000000..7de589c --- /dev/null +++ b/GeoConverterTests/Usings.cs @@ -0,0 +1,5 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +global using Xunit; \ No newline at end of file diff --git a/Helper/Extensions/DictionaryExtensions.cs b/Helper/Extensions/DictionaryExtensions.cs new file mode 100644 index 0000000..9eac933 --- /dev/null +++ b/Helper/Extensions/DictionaryExtensions.cs @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Helper +{ + public static class DictionaryExtensions + { + //public static Dictionary TryAddOrUpdate(this Dictionary dict, string key, T val) + public static IDictionary TryAddOrUpdate(this IDictionary dict, TKey key, TValue val) + { + if (dict.ContainsKey(key)) + dict[key] = val; + else + dict.Add(key, val); + + return dict; + } + + public static IDictionary ConvertToLowercase(this IDictionary dict, bool keys, bool values) + { + var newdict = new Dictionary(); + + foreach (var kvp in dict) + { + newdict.Add(keys ? kvp.Key.ToLower() : kvp.Key, values ? kvp.Value.ToLower() : kvp.Value); + } + + return newdict; + } + + } +} diff --git a/Helper/Extensions/GpsExtensions.cs b/Helper/Extensions/GpsExtensions.cs new file mode 100644 index 0000000..e67f401 --- /dev/null +++ b/Helper/Extensions/GpsExtensions.cs @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public static class GpsExtensions + { + public static Dictionary ConvertGpsInfoToGpsPoints(this List gpsinfolist) + { + Dictionary gpspoints = new Dictionary(); + foreach (var gpsinfo in gpsinfolist) + { + if (gpsinfo.Gpstype != null) + gpspoints.Add(gpsinfo.Gpstype, gpsinfo); + } + + //TODO LINQ SELECT + + return gpspoints; + } + + public static Dictionary ConvertGpsInfoToGpsPointsLinq(this List gpsinfolist) + { + if (gpsinfolist != null && gpsinfolist.Count > 0) + return gpsinfolist + .Distinct() + .Where(x => x.Gpstype != null) + .ToDictionary(x => x.Gpstype!, x => x); + else + return new Dictionary(); + } + } +} diff --git a/Helper/Extensions/ListExtensions.cs b/Helper/Extensions/ListExtensions.cs new file mode 100644 index 0000000..b539ce9 --- /dev/null +++ b/Helper/Extensions/ListExtensions.cs @@ -0,0 +1,72 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.Extensions +{ + public static class ListExtensions + { + public static List> ChunkBy(this List source, int chunkSize) + { + return source + .Select((x, i) => new { Index = i, Value = x }) + .GroupBy(x => x.Index / chunkSize) + .Select(x => x.Select(v => v.Value).ToList()) + .ToList(); + } + + public static void TryAddOrUpdateOnList(this ICollection smgtags, ICollection tagsToAdd) + { + foreach (var tag in tagsToAdd) + { + smgtags.TryAddOrUpdateOnList(tag); + } + } + + public static void TryRemoveOnList(this ICollection smgtags, string tagToRemove) + { + if (smgtags.Contains(tagToRemove)) + smgtags.Remove(tagToRemove); + } + + public static void TryRemoveOnList(this ICollection smgtags, ICollection tagsToRemove) + { + foreach (var tag in tagsToRemove) + { + smgtags.TryRemoveOnList(tag); + } + } + + public static void TryAddOrUpdateOnList(this ICollection smgtags, string tagToAdd) + { + if (!smgtags.Contains(tagToAdd)) + smgtags.Add(tagToAdd); + } + + public static IEnumerable UnionIfNotNull(this ICollection? sourceunion, ICollection? listtounion) + { + if (sourceunion != null && listtounion != null) + return sourceunion.Union(listtounion); + else if (sourceunion == null && listtounion != null) + return listtounion; + else if (sourceunion != null && listtounion == null) + return sourceunion; + else + return new List(); + } + + public static ICollection? ConverListToLowerCase(this ICollection? smgtags) + { + if (smgtags != null && smgtags.Count > 0) + return smgtags.Select(d => d.ToLower()).ToList(); + else + return smgtags; + } + } +} diff --git a/Helper/Extensions/QueryFactoryExtension.cs b/Helper/Extensions/QueryFactoryExtension.cs new file mode 100644 index 0000000..d6e8ea1 --- /dev/null +++ b/Helper/Extensions/QueryFactoryExtension.cs @@ -0,0 +1,485 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper.Extensions; +using Helper.Generic; +using Helper.Identity; +using Helper.JsonHelpers; +using Microsoft.AspNetCore.Components.Forms; +using Newtonsoft.Json; +using SqlKata; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; + + +namespace Helper +{ + public static class QueryFactoryExtension + { + #region Query Extension Methods Common used + + //Duplicates? + + //public static async Task GetFirstOrDefaultAsObject(this Query query) { + + // var rawdata = await query.FirstOrDefaultAsync(); + // return rawdata != null ? JsonConvert.DeserializeObject(rawdata.Value) : default(T); + //} + + //public static async Task> GetAllAsObject(this Query query) + //{ + // var rawdatalist = await query.GetAsync(); + // List datalist = new List(); + + // foreach (var rawdata in rawdatalist) + // { + // var value = JsonConvert.DeserializeObject(rawdata.Value); + // if (value != null) + // datalist.Add(value); + // } + // return datalist; + //} + + #endregion + + + //Using Newtonsoft + public static async Task GetObjectSingleAsync(this Query query, CancellationToken cancellationToken = default) where T : notnull + { + //using this ContractResolver avoids duplicate Lists + var settings = new JsonSerializerSettings { ContractResolver = new GetOnlyContractResolver() }; + + var result = await query.FirstOrDefaultAsync(); + return result != null ? JsonConvert.DeserializeObject(result.Value, settings) : default!; + //return JsonConvert.DeserializeObject(result.Value, settings) ?? default(T); + } + + //Using System.Text.Json --> producing Exception when single object is not found! + //public static async Task GetObjectSingleAsyncV2(this Query query, CancellationToken cancellationToken = default) where T : notnull + //{ + // var result = await query.FirstOrDefaultAsync(); + // return System.Text.Json.JsonSerializer.Deserialize(result.Value) ?? default!; + //} + + //Using Newtonsoft + public static async Task> GetObjectListAsync(this Query query, CancellationToken cancellationToken = default) where T : notnull + { + //using this ContractResolver avoids duplicate Lists + var settings = new JsonSerializerSettings { ContractResolver = new GetOnlyContractResolver() }; + + var result = await query.GetAsync(); + return result.Select(x => JsonConvert.DeserializeObject(x.Value, settings)!) ?? default!; + } + + #region Using Reflection + public static async Task GetObjectSingleAsync(this Query query, Type type, CancellationToken cancellationToken = default) + { + //using this ContractResolver avoids duplicate Lists + var settings = new JsonSerializerSettings { ContractResolver = new GetOnlyContractResolver() }; + var method = typeof(JsonConvert) + .GetMethods() + .Where(x => x.Name == "DeserializeObject") + .Where(x => x.IsGenericMethod) + .Where(x => x.GetParameters().Any(x => x.Name!.Equals("settings"))); + + var resultraw = await query.FirstOrDefaultAsync(); + + var methodinfo = method.FirstOrDefault()!.MakeGenericMethod(type); + //var parseddata = methodinfo.Invoke(null, new object[] { datar.Value }); + var parseddata = methodinfo.Invoke(null, new object[] { resultraw.Value, settings }); + if (parseddata != null) + return parseddata as IIdentifiable; + else + return null; + } + + //Implementation with refletion not using Generics + public static async Task> GetObjectListAsync(this Query query, Type type, CancellationToken cancellationToken = default) + { + //using this ContractResolver avoids duplicate Lists + //Reflection Json Deserialize + var settings = new JsonSerializerSettings { ContractResolver = new GetOnlyContractResolver() }; + List datalist = new List(); + + var method = typeof(JsonConvert) + .GetMethods() + .Where(x => x.Name == "DeserializeObject") + .Where(x => x.IsGenericMethod) + .Where(x => x.GetParameters().Any(x => x.Name!.Equals("settings"))); + + var dataraw = await query.GetAsync(); + + foreach (var datar in dataraw) + { + var methodinfo = method.FirstOrDefault()!.MakeGenericMethod(type); + //var parseddata = methodinfo.Invoke(null, new object[] { datar.Value }); + var parseddata = methodinfo.Invoke(null, new object[] { datar.Value, settings }); + if(parseddata != null) + datalist.Add(parseddata as IIdentifiable); + } + + //End reflection Json Deserialize + + return datalist; + } + + + + #endregion + + //Using System.Text.Json + //public static async Task> GetObjectListAsyncV2(this Query query, CancellationToken cancellationToken = default) where T : notnull + //{ + // var result = await query.GetAsync(); + // return result.Select(x => System.Text.Json.JsonSerializer.Deserialize(x.Value)!) ?? default!; + //} + + //Insert also data in Raw table + public static async Task InsertInRawtableAndGetIdAsync(this QueryFactory queryfactory, RawDataStore rawData, CancellationToken cancellationToken = default) + { + return await queryfactory.Query("rawdata") + .InsertGetIdAsync(rawData); + } + + #region PG CRUD Helpers + + /// + /// Inserts or Updates the Data + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static async Task UpsertData(this QueryFactory QueryFactory, T data, DataInfo dataconfig, EditInfo editinfo, CRUDConstraints constraints, CompareConfig compareConfig) where T : IIdentifiable, IImportDateassigneable, IMetaData, new() + { + //TOCHECK: What if no id is passed? Generate ID? + //TOCHECK: Id Uppercase or Lowercase depending on table + //TOCHECK: Shortname population? + + List channelstopublish = new List(); + int? objectchangedcount = null; + int? objectimagechangedcount = null; + + + //If no data is passed return error + if (data == null) + return new PGCRUDResult() { id = "", odhtype = "", created = 0, updated = 0, deleted = 0, error = 1, errorreason = "No Data", operation = dataconfig.Operation.ToString(), changes = 0, compareobject = false, objectchanged = 0, objectimagechanged = 0, pushchannels = channelstopublish }; + + + //Check if data exists already + var queryresult = await QueryFactory.Query(dataconfig.Table) + .Select("data") + .Where("id", data.Id) + .When(constraints.AccessRole.Count() > 0, q => q.FilterDataByAccessRoles(constraints.AccessRole)) + //.When(!String.IsNullOrEmpty(constraints.Condition), q => q.FilterAdditionalDataByCondition(constraints.Condition)) + .GetObjectSingleAsync(); + + int createresult = 0; + int updateresult = 0; + int errorresult = 0; + string errorreason = ""; + + + bool imagesequal = false; + EqualityResult equalityresult = new EqualityResult() { isequal = false, patch = null }; + + //Setting LastChange + data.LastChange = DateTime.Now; + //Setting MetaInfo + data._Meta = MetadataHelper.GetMetadataobject(data); + //Setting Editinfo + data._Meta.UpdateInfo = new UpdateInfo() { UpdatedBy = editinfo.Editor, UpdateSource = editinfo.Source }; + //Setting Firstimport + if (data.FirstImport == null) + data.FirstImport = DateTime.Now; + + //Todo setting Shortname + + //Check data condition return not allowed if it fails + if (!CheckCRUDCondition.CRUDOperationAllowed(data, constraints.Condition)) + { + return new PGCRUDResult() { id = data.Id, odhtype = data._Meta.Type, created = 0, updated = 0, deleted = 0, error = 1, errorreason = "Not Allowed", operation = dataconfig.Operation.ToString(), changes = null, compareobject = false, objectchanged = objectchangedcount, objectimagechanged = objectimagechangedcount, pushchannels = channelstopublish }; + } + + if (queryresult == null) + { + if (dataconfig.ErrorWhendataIsNew) + return new PGCRUDResult() { id = data.Id, odhtype = data._Meta.Type, created = 0, updated = 0, deleted = 0, error = 1, errorreason = "Data to update Not Found", operation = dataconfig.Operation.ToString(), changes = null, compareobject = false, objectchanged = objectchangedcount, objectimagechanged = objectimagechangedcount, pushchannels = channelstopublish }; + + createresult = await QueryFactory.Query(dataconfig.Table) + .InsertAsync(new JsonBData() { id = data.Id, data = new JsonRaw(data) }); + + dataconfig.Operation = CRUDOperation.Create; + + if (data is IPublishedOn) + { + if ((data as IPublishedOn).PublishedOn == null) + (data as IPublishedOn).PublishedOn = new List(); + + channelstopublish.AddRange((data as IPublishedOn).PublishedOn); + } + + + //On insert always set the object and image to changed only if compareresult deactivated + if (compareConfig.CompareData) + { + objectchangedcount = 1; + objectimagechangedcount = 1; + } + } + else + { + if (dataconfig.ErrorWhendataExists) + return new PGCRUDResult() { id = data.Id, odhtype = data._Meta.Type, created = 0, updated = 0, deleted = 0, error = 1, errorreason = "Data exists already", operation = dataconfig.Operation.ToString(), changes = null, compareobject = false, objectchanged = objectchangedcount, objectimagechanged = objectimagechangedcount, pushchannels = channelstopublish }; + + //Compare the data + if (compareConfig.CompareData && queryresult != null) + { + equalityresult = EqualityHelper.CompareClassesTest(queryresult, data, new List() { "LastChange", "_Meta", "FirstImport" }, true); + if (equalityresult.isequal) + objectchangedcount = 0; + else + objectchangedcount = 1; + } + + + //Compare Image Gallery Check if this works with a cast to IImageGalleryAware + if (compareConfig.CompareImages && queryresult != null && data is IImageGalleryAware && queryresult is IImageGalleryAware) + { + imagesequal = EqualityHelper.CompareImageGallery((data as IImageGalleryAware).ImageGallery, (queryresult as IImageGalleryAware).ImageGallery, new List() { }); + if (imagesequal) + objectimagechangedcount = 0; + else + objectimagechangedcount = 1; + } + + //Add all Publishedonfields before and after change + if (data is IPublishedOn && queryresult is IPublishedOn) + { + if ((data as IPublishedOn).PublishedOn == null) + (data as IPublishedOn).PublishedOn = new List(); + + channelstopublish.AddRange((data as IPublishedOn).PublishedOn.UnionIfNotNull((queryresult as IPublishedOn).PublishedOn)); + } + + + updateresult = await QueryFactory + .Query(dataconfig.Table) + .Where("id", data.Id) + .UpdateAsync(new JsonBData() { id = data.Id, data = new JsonRaw(data) }); + + dataconfig.Operation = CRUDOperation.Update; + } + + if (createresult == 0 && updateresult == 0) + return new PGCRUDResult() { id = data.Id, odhtype = data._Meta.Type, created = 0, updated = 0, deleted = 0, error = 1, errorreason = "Internal Error", operation = dataconfig.Operation.ToString(), changes = null, compareobject = false, objectchanged = objectchangedcount, objectimagechanged = objectimagechangedcount, pushchannels = channelstopublish }; + + return new PGCRUDResult() { id = data.Id, odhtype = data._Meta.Type, created = createresult, updated = updateresult, deleted = 0, error = errorresult, errorreason = errorreason, operation = dataconfig.Operation.ToString(), compareobject = compareConfig.CompareData, objectchanged = objectchangedcount, objectimagechanged = objectimagechangedcount, pushchannels = channelstopublish, changes = equalityresult.patch }; + } + + + /// + /// Deletes the data + /// + /// + /// + /// + /// + /// + /// + public static async Task DeleteData(this QueryFactory QueryFactory, string id, DataInfo dataconfig, CRUDConstraints constraints) where T : IIdentifiable, IImportDateassigneable, IMetaData + { + List channelstopublish = new List(); + + if (string.IsNullOrEmpty(id)) + return new PGCRUDResult() { id = "", odhtype = "", created = 0, updated = 0, deleted = 0, error = 1, errorreason = "Bad Request", operation = dataconfig.Operation.ToString(), changes = null, compareobject = false, objectchanged = null, objectimagechanged = null, pushchannels = channelstopublish }; + + var idtodelete = Helper.IdGenerator.CheckIdFromType(id); + + //Check if data exists + var queryresult = await QueryFactory.Query(dataconfig.Table) + .Select("data") + .Where("id", idtodelete) + .When(constraints.AccessRole.Count() > 0, q => q.FilterDataByAccessRoles(constraints.AccessRole)) + .GetObjectSingleAsync(); + + var deleteresult = 0; + var errorreason = ""; + + if (queryresult == null) + { + return new PGCRUDResult() { id = idtodelete, odhtype = null, created = 0, updated = 0, deleted = 0, error = 1, errorreason = "Data Not Found", operation = dataconfig.Operation.ToString(), changes = null, compareobject = false, objectchanged = null, objectimagechanged = null, pushchannels = channelstopublish }; + } + else + { + //Check data condition + if (!CheckCRUDCondition.CRUDOperationAllowed(queryresult, constraints.Condition)) + { + return new PGCRUDResult() { id = idtodelete, odhtype = queryresult._Meta.Type, created = 0, updated = 0, deleted = 0, error = 1, errorreason = "Not Allowed", operation = dataconfig.Operation.ToString(), changes = null, compareobject = false, objectchanged = null, objectimagechanged = null, pushchannels = channelstopublish }; + } + + if (queryresult is IPublishedOn && ((IPublishedOn)queryresult).PublishedOn != null) + { + channelstopublish.AddRange(((IPublishedOn)queryresult).PublishedOn); + } + + deleteresult = await QueryFactory.Query(dataconfig.Table).Where("id", idtodelete) + .DeleteAsync(); + } + + if (deleteresult == 0) + return new PGCRUDResult() { id = idtodelete, odhtype = queryresult._Meta.Type, created = 0, updated = 0, deleted = 0, error = 1, errorreason = "Internal Error", operation = dataconfig.Operation.ToString(), changes = null, compareobject = false, objectchanged = null, objectimagechanged = null, pushchannels = channelstopublish }; + + return new PGCRUDResult() { id = idtodelete, odhtype = queryresult._Meta.Type, created = 0, updated = 0, deleted = deleteresult, error = 0, errorreason = errorreason, operation = dataconfig.Operation.ToString(), changes = null, compareobject = false, objectchanged = null, objectimagechanged = null, pushchannels = channelstopublish }; + } + + + //TODO + public static async Task UpsertDataDestinationData(this QueryFactory QueryFactory, T data, V destinationdata, string table, bool errorwhendataexists = false, bool errorwhendataisnew = false, bool comparedata = false, bool compareimagedata = false) + where T : IIdentifiable, IImportDateassigneable, IMetaData, IPublishedOn, IImageGalleryAware, new() + where V : IIdentifiable, IImportDateassigneable, IMetaData + { + + if (data == null) + throw new ArgumentNullException(nameof(data), "no data"); + + //Check if data exists + var query = QueryFactory.Query(table) + .Select("data") + .Where("id", data.Id); + + var queryresult = await query.GetObjectSingleAsync(); + + string operation = ""; + + int createresult = 0; + int updateresult = 0; + int errorresult = 0; + //bool compareresult = false; + EqualityResult equalityresult = new EqualityResult() { isequal = false, patch = null }; + + bool imagecompareresult = false; + List channelstopublish = new List(); + + + data.LastChange = DateTime.Now; + destinationdata.LastChange = DateTime.Now; + //Setting MetaInfo + data._Meta = MetadataHelper.GetMetadataobject(data); + destinationdata._Meta = MetadataHelper.GetMetadataobject(destinationdata); + + if (data.FirstImport == null) + { + data.FirstImport = DateTime.Now; + destinationdata.FirstImport = DateTime.Now; + } + + if (queryresult == null) + { + if (errorwhendataisnew) + throw new ArgumentNullException(nameof(data.Id), "Id does not exist"); + + createresult = await QueryFactory.Query(table) + .InsertAsync(new JsonBDataDestinationData() { id = data.Id, data = new JsonRaw(data), destinationdata = new JsonRaw(destinationdata) }); + operation = "INSERT"; + } + else + { + //Compare the data + if (comparedata && queryresult != null) + equalityresult = EqualityHelper.CompareClassesTest(queryresult, data, new List() { "LastChange", "_Meta", "FirstImport" }, true); + + //Compare Image Gallery + if (compareimagedata && queryresult != null) + imagecompareresult = EqualityHelper.CompareImageGallery(data.ImageGallery, queryresult.ImageGallery, new List() { }); + + //Check if Publishedon List changed and populate channels to publish information + channelstopublish.AddRange(data.PublishedOn.UnionIfNotNull(queryresult.PublishedOn)); + + if (errorwhendataexists) + throw new ArgumentNullException(nameof(data.Id), "Id exists already"); + + updateresult = await QueryFactory.Query(table).Where("id", data.Id) + .UpdateAsync(new JsonBDataDestinationData() { id = data.Id, data = new JsonRaw(data), destinationdata = new JsonRaw(destinationdata) }); + operation = "UPDATE"; + } + + if (createresult == 0 && updateresult == 0) + errorresult = 1; + + return new PGCRUDResult() { id = data.Id, created = createresult, updated = updateresult, deleted = 0, error = errorresult, operation = operation, compareobject = comparedata, objectchanged = equalityresult.isequal ? 0 : 1, objectimagechanged = imagecompareresult ? 0 : 1, pushchannels = channelstopublish, changes = equalityresult.patch }; + } + + + #endregion + + #region RawDataStore + + public static async Task UpsertData(this QueryFactory QueryFactory, T data, string table, int rawdataid, string editor, string editsource, bool errorwhendataexists = false) where T : IIdentifiable, IImportDateassigneable, IMetaData + { + if (data == null) + throw new ArgumentNullException(nameof(data), "no data"); + + //Check if data exists + var query = QueryFactory.Query(table) + .Select("data") + .Where("id", data.Id); + + var queryresult = await query.GetAsync(); + + string operation = ""; + + int createresult = 0; + int updateresult = 0; + int errorresult = 0; + + data.LastChange = DateTime.Now; + //Setting MetaInfo + data._Meta = MetadataHelper.GetMetadataobject(data); + + if (data.FirstImport == null) + data.FirstImport = DateTime.Now; + + //Setting Editinfo + data._Meta.UpdateInfo = new UpdateInfo() { UpdatedBy = editor, UpdateSource = editsource }; + + if (queryresult == null || queryresult.Count() == 0) + { + createresult = await QueryFactory.Query(table) + .InsertAsync(new JsonBDataRaw() { id = data.Id, data = new JsonRaw(data), rawdataid = rawdataid }); + operation = "INSERT"; + } + else + { + if (errorwhendataexists) + throw new ArgumentNullException(nameof(data), "Id exists already"); + + updateresult = await QueryFactory.Query(table).Where("id", data.Id) + .UpdateAsync(new JsonBDataRaw() { id = data.Id, data = new JsonRaw(data), rawdataid = rawdataid }); + operation = "UPDATE"; + } + + if (createresult == 0 && updateresult == 0) + errorresult = 1; + + return new PGCRUDResult() { id = data.Id, created = createresult, updated = updateresult, deleted = 0, error = errorresult, operation = operation }; + } + + #endregion + + } + + +} diff --git a/Helper/Extensions/String2HashExtensions.cs b/Helper/Extensions/String2HashExtensions.cs new file mode 100644 index 0000000..5f7aeea --- /dev/null +++ b/Helper/Extensions/String2HashExtensions.cs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public static class String2HashExtensions + { + public static string ComputeSHA256Hash(this string value) + { + // Create a SHA256 + using (SHA256 sha256Hash = SHA256.Create()) + { + // ComputeHash - returns byte array + byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(value)); + + // Convert byte array to a string + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < bytes.Length; i++) + { + builder.Append(bytes[i].ToString("x2")); + } + return builder.ToString(); + } + } + + public static string ComputeSHA1Hash(this string value) + { + using (SHA1 sha1 = SHA1.Create()) + { + var inputBytes = Encoding.ASCII.GetBytes(value); + var hash = sha1.ComputeHash(inputBytes); + + var sb = new StringBuilder(); + for (var i = 0; i < hash.Length; i++) + { + sb.Append(hash[i].ToString("X2")); + } + return sb.ToString(); + } + } + } +} \ No newline at end of file diff --git a/Helper/Extensions/StringExtensions.cs b/Helper/Extensions/StringExtensions.cs new file mode 100644 index 0000000..c422f7a --- /dev/null +++ b/Helper/Extensions/StringExtensions.cs @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.Extensions +{ + + public static class StringExtensions + { + //TODO EXTEND THIS + + public static string AddHttpsPrefixIfNotPresent(this string value) + { + if (value.StartsWith("http")) + return value; + else + return "https://" + value; + } + } +} diff --git a/Helper/Extensions/XElementExtensions.cs b/Helper/Extensions/XElementExtensions.cs new file mode 100644 index 0000000..af6a59a --- /dev/null +++ b/Helper/Extensions/XElementExtensions.cs @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using System.Xml.Linq; + +namespace Helper +{ + public static class XElementExtensions + { + public static XmlElement ToXmlElement(this XElement el) + { + var doc = new XmlDocument(); + doc.Load(el.CreateReader()); + return doc.DocumentElement!; + } + + public static string InnerXML(this XElement el) + { + var reader = el.CreateReader(); + reader.MoveToContent(); + return reader.ReadInnerXml(); + } + } +} diff --git a/Helper/Factories/PostgresQueryFactory.cs b/Helper/Factories/PostgresQueryFactory.cs new file mode 100644 index 0000000..27c571d --- /dev/null +++ b/Helper/Factories/PostgresQueryFactory.cs @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.Extensions.Logging; +using Npgsql; +using SqlKata; +using SqlKata.Compilers; +using SqlKata.Execution; +using System; + +namespace Helper.Factories +{ + class OdhPostgresCompiler : PostgresCompiler + { + public OdhPostgresCompiler() + { + parameterPlaceholder = "$$"; + } + } + + /// + /// For the time of writing QueryFactory doesn't implement IDisposable + /// so it is a bit dangerous to use with ASP.NET's DI when used directly. + /// This implementation is safe!
+ /// Howewer at the time of writing there exists an issue to fix that: + /// https://github.com/sqlkata/querybuilder/issues/213 + ///
+ public class PostgresQueryFactory : QueryFactory, IDisposable + { + public PostgresQueryFactory(ISettings settings, ILogger logger) + { + Connection = new NpgsqlConnection(settings.PostgresConnectionString); + Compiler = new OdhPostgresCompiler(); + Logger = info => logger.LogDebug("SQL: {sql} {@parameters}", info.RawSql, info.NamedBindings); + } + + public new void Dispose() + { + base.Dispose(); + if (Connection != null) + { + Connection.Dispose(); + Connection = null; + } + } + } +} diff --git a/Helper/Flags/CommonListCreator.cs b/Helper/Flags/CommonListCreator.cs new file mode 100644 index 0000000..8d33eab --- /dev/null +++ b/Helper/Flags/CommonListCreator.cs @@ -0,0 +1,397 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using MongoDB.Driver.Linq; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Helper +{ + public class CommonListCreator + { + public static List CreateIdList(string? activityidstring) + { + List activityIds = new List(); + + if (!String.IsNullOrEmpty(activityidstring)) + { + if (activityidstring.Substring(activityidstring.Length - 1, 1) == ",") + activityidstring = activityidstring.Substring(0, activityidstring.Length - 1); + + var splittedfilter = activityidstring.Split(','); + + foreach (var filter in splittedfilter) + { + activityIds.Add(filter); + } + } + + return activityIds; + } + + public static List CreateNumericIdList(string? idstring) + { + List activityIds = new List(); + + if (!String.IsNullOrEmpty(idstring)) + { + if (idstring.Substring(idstring.Length - 1, 1) == ",") + idstring = idstring.Substring(0, idstring.Length - 1); + + var splittedfilter = idstring.Split(','); + + foreach (var filter in splittedfilter) + { + int filterint; + + if(int.TryParse(filter, out filterint)) + activityIds.Add(filterint); + } + } + + return activityIds; + } + + public static List CreateStringListFromStringParameter(string? inputstring, string separator = ",", IDStyle transformto = IDStyle.mixed) + { + List listToReturn = new List(); + + if (!String.IsNullOrEmpty(inputstring)) + { + //remove last separator if there + if (inputstring.Substring(inputstring.Length - 1, 1) == ",") + inputstring = inputstring.Substring(0, inputstring.Length - 1); + + //Method 1, check if there are quotes inside + //Single Quotes? + //var splittedfilter = Regex.Split(inputstring, ",(?=(?:[^']*'[^']*')*[^']*$)"); + //Double Quotes? + //var splittedfilter = Regex.Split(inputstring, ",(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"); + //TODO Remove brackets + + //Method 2 ChatGPT Regex + Regex splitregx = new Regex("(?:" + separator + "|\\s*(?:\"([^\"]*)\"|'([^']*)'|([^,]*)))"); + var substrings = splitregx.Split(inputstring); + + foreach (var filter in substrings.ToList().Where(x => !String.IsNullOrEmpty(x))) + { + if (transformto == IDStyle.lowercase) + listToReturn.Add(filter.ToLower()); + if (transformto == IDStyle.uppercase) + listToReturn.Add(filter.ToUpper()); + else + listToReturn.Add(filter); + } + } + + return listToReturn; + } + + + public static List CreateSmgPoiSourceList(string? sourcestring) + { + List activityIds = new List(); + + if (!String.IsNullOrEmpty(sourcestring)) + { + if (sourcestring.ToLower() != "null") + { + if (sourcestring.Substring(sourcestring.Length - 1, 1) == ",") + sourcestring = sourcestring.Substring(0, sourcestring.Length - 1); + + var splittedfilter = sourcestring.Split(','); + + foreach (var filter in splittedfilter) + { + activityIds.Add(filter.ToLower()); + } + } + } + + return activityIds; + } + + public static List CreateLowerCaseSmgTagList(string? activityidstring) + { + List activityIds = new List(); + + if (activityidstring != null) + { + if (activityidstring.Substring(activityidstring.Length - 1, 1) == ",") + activityidstring = activityidstring.Substring(0, activityidstring.Length - 1); + + var splittedfilter = activityidstring.Split(','); + + foreach (var filter in splittedfilter) + { + activityIds.Add(filter); + } + } + + return activityIds; + } + + public static List CreateDistrictIdList(string? locfilter, string typ) + { + List locIds = new List(); + + if (locfilter != null) + { + if (locfilter.Substring(locfilter.Length - 1, 1) == ",") + locfilter = locfilter.Substring(0, locfilter.Length - 1); + + var splittedfilter = locfilter.Split(','); + + foreach (var filter in splittedfilter) + { + if (filter.StartsWith(typ)) + locIds.Add(filter.Replace(typ, "")); + } + } + + return locIds; + } + + public static (int min, int max) CreateRangeString(string? rangetoSplit) + { + if (rangetoSplit != null) + { + var splittedfilter = rangetoSplit.Split(','); + + return (Convert.ToInt32(splittedfilter[0]), Convert.ToInt32(splittedfilter[1])); + } + else + return (0, 0); + } + + public static (double, double) CreateRangeStringDouble(string? rangetoSplit) + { + NumberFormatInfo provider = new NumberFormatInfo + { + NumberDecimalSeparator = "." + }; + + if (rangetoSplit != null) + { + var splittedfilter = rangetoSplit.Split(','); + + return (Convert.ToDouble(splittedfilter[0], provider), Convert.ToDouble(splittedfilter[1], provider)); + } + else + return (0.0, 0.0); + } + + public static List CreateDifficultyList(string? difficultyfilter, string? activitypoitype) + { + List difficultyids = new List(); + + if (difficultyfilter != null) + { + if (difficultyfilter.Substring(difficultyfilter.Length - 1, 1) == ",") + difficultyfilter = difficultyfilter.Substring(0, difficultyfilter.Length - 1); + + var splittedfilter = difficultyfilter.Split(','); + + switch (activitypoitype) + { + case "Berg": + case "Radfahren": + case "Wandern": + case "Laufen und Fitness": + + foreach (var filter in splittedfilter) + { + switch (filter) + { + case "1": + difficultyids.Add("1"); + difficultyids.Add("2"); + break; + + case "2": + difficultyids.Add("3"); + difficultyids.Add("4"); + break; + + case "3": + difficultyids.Add("5"); + difficultyids.Add("6"); + break; + } + } + + break; + + case "Rodelbahnen": + //hot koan Schwierigkeit + break; + + case "Aufstiegsanlagen": + //hot koan Schwierigkeit + break; + + case "Piste": + + foreach (var filter in splittedfilter) + { + switch (filter) + { + case "1": + difficultyids.Add("2"); + break; + + case "2": + difficultyids.Add("4"); + break; + + case "3": + difficultyids.Add("6"); + break; + } + } + + break; + + case "Loipen": + + foreach (var filter in splittedfilter) + { + switch (filter) + { + case "1": + difficultyids.Add("2"); + break; + + case "2": + difficultyids.Add("4"); + break; + + case "3": + difficultyids.Add("6"); + break; + } + } + + break; + } + + + } + + return difficultyids; + } + + public static List CreateDifficultyListfromFlag(string? difficultyfilter, string activitypoitype) + { + List difficultyids = new List(); + + if (difficultyfilter != null) + { + if (difficultyfilter.Substring(difficultyfilter.Length - 1, 1) == ",") + difficultyfilter = difficultyfilter.Substring(0, difficultyfilter.Length - 1); + + var splittedfilter = difficultyfilter.Split(','); + + switch (activitypoitype) + { + case "Berg": + case "Radfahren": + case "Wandern": + case "Laufen und Fitness": + + foreach (var filter in splittedfilter) + { + switch (filter) + { + case "one": + difficultyids.Add("leicht"); + break; + + case "two": + difficultyids.Add("wenig schwierig"); + break; + + case "three": + difficultyids.Add("mäßig schwierig"); + break; + + case "four": + difficultyids.Add("schwierig"); + break; + + case "five": + difficultyids.Add("sehr schwierig"); + break; + } + } + + break; + + case "Rodelbahnen": + //hot koan Schwierigkeit + break; + + case "Aufstiegsanlagen": + //hot koan Schwierigkeit + break; + + case "Piste": + + foreach (var filter in splittedfilter) + { + switch (filter) + { + case "one": + difficultyids.Add("blau"); + break; + + case "two": + difficultyids.Add("rot"); + break; + + case "three": + difficultyids.Add("schwarz"); + break; + } + } + + break; + + case "Loipen": + + foreach (var filter in splittedfilter) + { + switch (filter) + { + case "one": + difficultyids.Add("blau"); + break; + + case "two": + difficultyids.Add("gelb"); + break; + + case "three": + difficultyids.Add("rot"); + break; + + case "four": + difficultyids.Add("schwarz"); + break; + } + } + + break; + } + + + } + + return difficultyids; + } + } +} diff --git a/Helper/Flags/ExampleListCreator.cs b/Helper/Flags/ExampleListCreator.cs new file mode 100644 index 0000000..0586c78 --- /dev/null +++ b/Helper/Flags/ExampleListCreator.cs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Helper +{ + public class ExampleListCreator + { + public static List CreateExampleTypefromFlag(string typefilter) + { + List typelist = new List(); + + if (typefilter != "null") + { + int typefilterint = 0; + if (int.TryParse(typefilter, out typefilterint)) + { + ExampleTypeFlag mypoitypeflag = (ExampleTypeFlag)typefilterint; + + var myflags = mypoitypeflag.GetFlags().GetDescriptionList(); + + foreach (var myflag in myflags) + { + typelist.Add(myflag); + } + } + else + return new List(); + } + + return typelist; + } + } +} diff --git a/Helper/Flags/Flags.cs b/Helper/Flags/Flags.cs new file mode 100644 index 0000000..ead85d3 --- /dev/null +++ b/Helper/Flags/Flags.cs @@ -0,0 +1,56 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.ComponentModel; + +namespace Helper +{ + public static class EnumHelper + { + public static IEnumerable GetValues() + { + foreach (object? value in System.Enum.GetValues(typeof(T))) + { + if (value != null) + yield return value; + } + } + } + //Packages Weekday + [Flags] + public enum WeekdayFlag + { + Monday = 1, + Tuesday = 2, + Wednesday = 4, + Thuresday = 8, + Friday = 16, + Saturday = 32, + Sunday = 64 + } + + + #region Articles + + [Flags] + public enum ExampleTypeFlag + { + [Description("examplecategory1")] + examplecategory1 = 1, //1 + [Description("examplecategory2")] + examplecategory2 = 1 << 1, //2 + [Description("examplecategory3")] + examplecategory3 = 1 << 2, //4 + [Description("examplecategory4")] + examplecategory4 = 1 << 3 //8 + } + + + #endregion + +} + + diff --git a/Helper/Flags/FlagsHelper.cs b/Helper/Flags/FlagsHelper.cs new file mode 100644 index 0000000..086472a --- /dev/null +++ b/Helper/Flags/FlagsHelper.cs @@ -0,0 +1,204 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; + +namespace Helper +{ + // The casts to object in the below code are an unfortunate necessity due to + // C#'s restriction against a where T : Enum constraint. (There are ways around + // this, but they're outside the scope of this simple illustration.) + public static class FlagsHelper + { + private static void CheckIsEnum(bool withFlags) + { + if (!typeof(T).IsEnum) + throw new ArgumentException($"Type '{typeof(T).FullName}' is not an enum", nameof(withFlags)); + if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute))) + throw new ArgumentException($"Type '{typeof(T).FullName}' doesn't have the 'Flags' attribute", nameof(withFlags)); + } + + public static bool IsFlagSet(this T value, T flag) where T : struct + { + CheckIsEnum(true); + long lValue = Convert.ToInt64(value); + long lFlag = Convert.ToInt64(flag); + return (lValue & lFlag) != 0; + } + + public static IEnumerable GetFlags(this T value) where T : struct + { + CheckIsEnum(true); + foreach (T flag in Enum.GetValues(typeof(T)).Cast()) + { + if (value.IsFlagSet(flag)) + yield return flag; + } + } + + public static T SetFlags(this T value, T flags, bool on) where T : struct + { + CheckIsEnum(true); + long lValue = Convert.ToInt64(value); + long lFlag = Convert.ToInt64(flags); + if (on) + { + lValue |= lFlag; + } + else + { + lValue &= (~lFlag); + } + return (T)Enum.ToObject(typeof(T), lValue); + } + + public static T SetFlags(this T value, T flags) where T : struct + { + return value.SetFlags(flags, true); + } + + public static T ClearFlags(this T value, T flags) where T : struct + { + return value.SetFlags(flags, false); + } + + public static T CombineFlags(this IEnumerable flags) where T : struct + { + CheckIsEnum(true); + long lValue = 0; + foreach (T flag in flags) + { + long lFlag = Convert.ToInt64(flag); + lValue |= lFlag; + } + return (T)Enum.ToObject(typeof(T), lValue); + } + + public static string? GetDescription(this T value) where T : struct + { + CheckIsEnum(false); + string? name = Enum.GetName(typeof(T), value); + if (name != null) + { + FieldInfo? field = typeof(T).GetField(name); + if (field != null) + { + if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attr) + { + return attr.Description; + } + } + } + return null; + } + + public static string? GetDescription(object value) + { + var mytype = value.GetType(); + //CheckIsEnum(false); + string? name = Enum.GetName(mytype, value); + if (name != null) + { + FieldInfo? field = mytype.GetField(name); + if (field != null) + { + if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attr) + { + return attr.Description; + } + } + } + return null; + } + + public static int GetFlagofType(string? id) + { + foreach (object? smgpoitypeflag in Enum.GetValues(typeof(T))) + { + if (smgpoitypeflag != null) + { + string description = ""; + + string? name = Enum.GetName(typeof(T), smgpoitypeflag); + if (name != null) + { + FieldInfo? field = typeof(T).GetField(name); + if (field != null) + { + if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attr) + { + description = attr.Description; + } + } + } + + if (description == id) + { + return ((int)smgpoitypeflag); + } + } + } + + return -1; + } + + public static long GetFlagofTypeLong(string? id) + { + foreach (object? smgpoitypeflag in Enum.GetValues(typeof(T))) + { + if (smgpoitypeflag != null) + { + string description = ""; + + string? name = Enum.GetName(typeof(T), smgpoitypeflag); + if (name != null) + { + FieldInfo? field = typeof(T).GetField(name); + if (field != null) + { + if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attr) + { + description = attr.Description; + } + } + } + + if (description == id) + { + return ((long)smgpoitypeflag); + } + } + } + + return -1; + } + + //Des gibmer die Liste zrugg! + public static List GetDescriptionList(this IEnumerable enumlist) where T : struct + { + List descriptionList = new List(); + foreach (var value in enumlist) + { + CheckIsEnum(false); + string? name = Enum.GetName(typeof(T), value); + if (name != null) + { + FieldInfo? field = typeof(T).GetField(name); + if (field != null) + { + if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attr) + { + descriptionList.Add(attr.Description); + } + } + } + } + return descriptionList; + } + } +} diff --git a/Helper/Generic/CopyClassHelper.cs b/Helper/Generic/CopyClassHelper.cs new file mode 100644 index 0000000..88e6d84 --- /dev/null +++ b/Helper/Generic/CopyClassHelper.cs @@ -0,0 +1,97 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper.JsonHelpers; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public static class CopyClassHelper + { + /// + /// Performs a Shallow Copy using Reflection + /// + /// The object instance to copy + /// The copied object + public static void CopyPropertyValues(object source, object destination) + { + var destProperties = destination.GetType().GetProperties(); + + foreach (var sourceProperty in source.GetType().GetProperties()) + { + foreach (var destProperty in destProperties) + { + if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType) && destProperty.GetSetMethod() != null) + { + destProperty.SetValue(destination, sourceProperty.GetValue( + source, new object[] { }), new object[] { }); + + break; + } + } + } + } + + ///// + ///// Perform a deep Copy of the object. Class has to be marked as Serializeable + ///// + ///// The type of object being copied. + ///// The object instance to copy. + ///// The copied object. + //public static T Clone(T source) + //{ + // throw new NotImplementedException(); + // // if (!typeof(T).IsSerializable) + // // { + // // throw new ArgumentException("The type must be serializable.", nameof(source)); + // // } + + // // // Don't serialize a null object, simply return the default for that object + // // if (Object.ReferenceEquals(source, null)) + // // { + // // return default(T); + // // } + + // // IFormatter formatter = new BinaryFormatter(); + // // Stream stream = new MemoryStream(); + // // using (stream) + // // { + // // formatter.Serialize(stream, source); + // // stream.Seek(0, SeekOrigin.Begin); + // // return (T)formatter.Deserialize(stream); + // // } + //} + + /// + /// Perform a deep Copy of the object, using Json as a serialisation method. NOTE: Private members are not cloned using this method. + /// + /// The type of object being copied. + /// The object instance to copy. + /// The copied object. + public static T CloneJson(this T source) + { + // Don't serialize a null object, simply return the default for that object + if (Object.ReferenceEquals(source, null)) + { + return default(T); + } + + // initialize inner objects individually + // for example in default constructor some list property initialized with some values, + // but in 'source' these items are cleaned - + // without ObjectCreationHandling.Replace default constructor values will be added to result + var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace, ContractResolver = new GetOnlyContractResolver() }; + + return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source), deserializeSettings); + } + } +} diff --git a/Helper/Generic/CreateSeed.cs b/Helper/Generic/CreateSeed.cs new file mode 100644 index 0000000..59ccc35 --- /dev/null +++ b/Helper/Generic/CreateSeed.cs @@ -0,0 +1,69 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; + +namespace Helper +{ + /// + /// Creates the Seed if there is no Seed defined + /// + public class CreateSeed + { + private static readonly Random random = new Random(); + + public static int GetSeed(int seed) + { + //Kein Seed es wird ein Seed zwischen 0 und 10 erzeugt + if (seed == 0) + { + int randomNumber = random.Next(10); + + return randomNumber; + } + //Wenn der Seed höher 10 ist + else if (seed > 10) + { + while (seed >= 10) + seed /= 10; + + return seed; + } + //Seed passt, wird zurückgebegeben + else + return seed; + } + + public static string? GetSeed(string seedstring) + { + if (seedstring == null) + return null; + + else if (int.TryParse(seedstring, out int seed)) + { + + //Kein Seed es wird ein Seed zwischen 0 und 10 erzeugt + if (seed == 0) + { + int randomNumber = random.Next(1, 50); + + return randomNumber.ToString(); + } + //Wenn der Seed höher 10 ist + else if (seed > 50) + { + while (seed >= 50) + seed /= 10; + + return seed.ToString(); + } + //Seed passt, wird zurückgebegeben + else + return seed.ToString(); + } + else + return null; + } + } +} diff --git a/Helper/Generic/DataOperationClasses.cs b/Helper/Generic/DataOperationClasses.cs new file mode 100644 index 0000000..912406a --- /dev/null +++ b/Helper/Generic/DataOperationClasses.cs @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.Generic +{ + public enum CRUDOperation + { + Create, Update, Delete, Read + } + + public class DataInfo + { + public DataInfo(string table, CRUDOperation operation) + { + Table = table; + Operation = operation; + + if (operation == CRUDOperation.Create) + { + ErrorWhendataExists = true; + ErrorWhendataIsNew = false; + } + else if (operation == CRUDOperation.Update) + { + ErrorWhendataExists = false; + ErrorWhendataIsNew = true; + } + else + { + ErrorWhendataExists = false; + ErrorWhendataIsNew = false; + } + } + + public string Table { get; set; } + public CRUDOperation Operation { get; set; } + public bool ErrorWhendataExists { get; set; } + public bool ErrorWhendataIsNew { get; set; } + } + + public class CompareConfig + { + public CompareConfig(bool comparedata, bool compareimages) + { + CompareData = comparedata; + CompareImages = compareimages; + } + + public bool CompareData { get; set; } + public bool CompareImages { get; set; } + } + + public class EditInfo + { + public EditInfo(string editor, string? source) + { + Editor = editor; + Source = source; + } + public string Editor { get; set; } + public string? Source { get; set; } + } + + public class CRUDConstraints + { + public CRUDConstraints() + { + AccessRole = new List(); + } + + public CRUDConstraints(string? condition, IEnumerable accessRole) + { + Condition = condition; + AccessRole = accessRole; + } + + public string? Condition { get; set; } + public IEnumerable AccessRole { get; set; } + } +} diff --git a/Helper/Generic/DateTimeHelper.cs b/Helper/Generic/DateTimeHelper.cs new file mode 100644 index 0000000..b3e1ac4 --- /dev/null +++ b/Helper/Generic/DateTimeHelper.cs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Text; +using TimeZoneConverter; + +namespace Helper +{ + public class DateTimeHelper + { + public static double DateTimeToUnixTimestamp(DateTime dateTime) + { + var tzinfo = TZConvert.GetTimeZoneInfo("W. Europe Standard Time"); + + return (TimeZoneInfo.ConvertTimeToUtc(dateTime, tzinfo) - + new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc)).TotalSeconds; + } + + public static double DateTimeToUnixTimestampMilliseconds(DateTime dateTime) + { + var tzinfo = TZConvert.GetTimeZoneInfo("W. Europe Standard Time"); + + return (TimeZoneInfo.ConvertTimeToUtc(dateTime, tzinfo) - + new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc)).TotalMilliseconds; + } + + ////TEST without conversion to UTC simply convert to UTC what is passed + //public static double DateTimeToUnixTimestampMillisecondsWithoutUTCConvert(DateTime dateTime) + //{ + // return (dateTime - + // new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc)).TotalMilliseconds; + //} + + //TODO UnixTimeStampToDateTime + + public static DateTime UnixTimeStampToDateTime(double unixTimeStamp) + { + var tzinfo = TZConvert.GetTimeZoneInfo("W. Europe Standard Time"); + + // Unix timestamp is seconds past epoch + System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); + dtDateTime = dtDateTime.AddSeconds(unixTimeStamp).ToUniversalTime(); + + return TimeZoneInfo.ConvertTimeFromUtc(dtDateTime, tzinfo); + } + + public static DateTime UnixTimeStampToDateTimeMilliseconds(double unixTimeStamp) + { + var tzinfo = TZConvert.GetTimeZoneInfo("W. Europe Standard Time"); + + // Unix timestamp is seconds past epoch + System.DateTime dtDateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, System.DateTimeKind.Utc); + dtDateTime = dtDateTime.AddMilliseconds(unixTimeStamp).ToUniversalTime(); + return TimeZoneInfo.ConvertTimeFromUtc(dtDateTime, tzinfo); + } + + + public static bool CompareValidStartEnddate(DateTime start, DateTime end) + { + return end >= start; + } + + } +} diff --git a/Helper/Generic/EqualityHelper.cs b/Helper/Generic/EqualityHelper.cs new file mode 100644 index 0000000..680566a --- /dev/null +++ b/Helper/Generic/EqualityHelper.cs @@ -0,0 +1,237 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using JsonDiffPatchDotNet; +using JsonDiffPatchDotNet.Formatters.JsonPatch; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.Generic +{ + public class EqualityHelper + { + //public static bool CompareClasses(object class1, object class2, List propertiestonotcheck) where T : new() + //{ + // T compareclass1 = new T(); + // T compareclass2 = new T(); + + // CopyClassHelper.CopyPropertyValues(class1, compareclass1); + // CopyClassHelper.CopyPropertyValues(class2, compareclass2); + + // if (propertiestonotcheck != null) + // { + // foreach (string s in propertiestonotcheck) + // { + // //Set the fields null (DateTime sets DateTime min + // var property1 = compareclass1.GetType().GetProperty(s); + // if (property1 != null && property1.GetSetMethod() != null) + // property1.SetValue(compareclass1, null, null); + + // //Set the fields null + // var property2 = compareclass2.GetType().GetProperty(s); + // if (property2 != null && property2.GetSetMethod() != null) + // property2.SetValue(compareclass2, null, null); + // } + // } + + // return (JsonConvert.SerializeObject(compareclass1) == JsonConvert.SerializeObject(compareclass2)); + //} + + public static EqualityResult CompareClassesTest(object class1, object class2, List propertiestonotcheck, bool returndiff) where T : IIdentifiable, new() + { + T compareclass1 = new T(); + T compareclass2 = new T(); + + CopyClassHelper.CopyPropertyValues(class1, compareclass1); + CopyClassHelper.CopyPropertyValues(class2, compareclass2); + + if (propertiestonotcheck != null) + { + foreach (string s in propertiestonotcheck) + { + //Set the fields null (DateTime sets DateTime min + var property1 = compareclass1.GetType().GetProperty(s); + if (property1 != null && property1.GetSetMethod() != null) + property1.SetValue(compareclass1, null, null); + + //Set the fields null + var property2 = compareclass2.GetType().GetProperty(s); + if (property2 != null && property2.GetSetMethod() != null) + property2.SetValue(compareclass2, null, null); + } + } + + //TODO SORT ALL ARRAYS so Deepequals gets not hit..... + + + + //Postgres JsonB does a Dictionary Key sorting automatically. So the retrieved Json has the Dictionary Keys ordered by Keyname alphabetically, therefore a resort is needed to compare + //both Serialized Objects + + //var jsonSerializerSettings = new JsonSerializerSettings(); + //jsonSerializerSettings.Converters.Add(new DictionaryOrderConverter()); + + //To Test for Performance, Deep Equals vs String Comparision? + //var result1 = JsonConvert.SerializeObject(compareclass1, jsonSerializerSettings); + //var result2 = JsonConvert.SerializeObject(compareclass2, jsonSerializerSettings); + //return (result1 == result2); + + + + var equalityresult = new EqualityResult(); + + equalityresult.isequal = JToken.DeepEquals(JToken.FromObject(compareclass1), JToken.FromObject(compareclass2)); + + if(returndiff && !equalityresult.isequal) + { + //TO TEST JSON DIFF + var jdp = new JsonDiffPatch(); + + //new Options() { ArrayDiff = ArrayDiffMode.Simplev } + + JToken patch = jdp.Diff(JToken.FromObject(compareclass1), JToken.FromObject(compareclass2)); + //if (patch != null) + //{ + // var formatter = new JsonDeltaFormatter(); + // var operations = formatter.Format(patch); + //} + + //TEST Array position moves ignore + //var customDiffPatch = jsondiffpatch.create({ + //arrays: + // { + // detectMove: false + //} + //}; + + + + equalityresult.patch = patch; + } + + return equalityresult; + } + + public static bool CompareImageGallery(ICollection? compareclass1, ICollection? compareclass2, List propertiestonotcheck) + { + //If both ImageGalleries are null return equal + if (compareclass1 == null && compareclass2 == null) + return true; + + //If only one ImageGallery is null return not equal + if (compareclass1 == null && compareclass2 != null) + return false; + + //If only one ImageGallery is null return not equal + if (compareclass1 != null && compareclass2 == null) + return false; + + //CopyClassHelper.CopyPropertyValues(class1, compareclass1); + //CopyClassHelper.CopyPropertyValues(class2, compareclass2); + + if (propertiestonotcheck != null) + { + foreach (string s in propertiestonotcheck) + { + //Set the fields null (DateTime sets DateTime min + var property1 = compareclass1.GetType().GetProperty(s); + if (property1 != null) + property1.SetValue(compareclass1, null, null); + + //Set the fields null + var property2 = compareclass2.GetType().GetProperty(s); + if (property2 != null) + property2.SetValue(compareclass2, null, null); + } + } + + //var jsonSerializerSettings = new JsonSerializerSettings(); + //jsonSerializerSettings.Converters.Add(new DictionaryOrderConverter()); + + //var result1 = JsonConvert.SerializeObject(compareclass1, jsonSerializerSettings); + //var result2 = JsonConvert.SerializeObject(compareclass2, jsonSerializerSettings); + + //return (result1 == result2); + + return JToken.DeepEquals(JToken.FromObject(compareclass1), JToken.FromObject(compareclass2)); + } + + public static bool ComparePublishedOn(ICollection compareclass1, ICollection compareclass2) + { + return JToken.DeepEquals(JToken.FromObject(compareclass1), JToken.FromObject(compareclass2)); + } + } + + public class OrderedContractResolver : DefaultContractResolver + { + protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) + { + return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList(); + } + } + + public class DictionaryOrderConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(IDictionary).IsAssignableFrom(objectType); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter."); + } + + public override bool CanRead + { + get { return false; } + } + + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + JObject obj = new JObject(); + + if (typeof(IDictionary).IsAssignableFrom(value.GetType())) + { + var dict = (IDictionary)value; + + if (dict != null && dict.Count() > 0) + { + foreach (var kvp in dict.OrderBy(x => x.Key).ToDictionary(obj => obj.Key, obj => obj.Value)) + { + obj.Add(kvp.Key, kvp.Value); + } + } + } + else if (typeof(IDictionary).IsAssignableFrom(value.GetType())) + { + var dict = (IDictionary)value; + + if (dict != null && dict.Keys.Count > 0) + { + var mykeysordered = ((ICollection)dict.Keys).ToList(); + + foreach (var key in mykeysordered.OrderBy(x => x)) + { + obj.Add(key, JToken.FromObject(dict[key])); + } + } + } + + obj.WriteTo(writer); + } + } + + +} diff --git a/Helper/Generic/GeoSearchHelper.cs b/Helper/Generic/GeoSearchHelper.cs new file mode 100644 index 0000000..d508d85 --- /dev/null +++ b/Helper/Generic/GeoSearchHelper.cs @@ -0,0 +1,431 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Amazon.S3.Model; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Helper +{ + public class GeoSearchHelper + { + readonly double _eQuatorialEarthRadius = 6378.1370D; + readonly double _d2r = (Math.PI / 180D); + + public double HaversineInKM(double lat1, double long1, double lat2, double long2) + { + double dlong = (long2 - long1) * _d2r; + double dlat = (lat2 - lat1) * _d2r; + double a = Math.Pow(Math.Sin(dlat / 2D), 2D) + Math.Cos(lat1 * _d2r) * Math.Cos(lat2 * _d2r) * Math.Pow(Math.Sin(dlong / 2D), 2D); + double c = 2D * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1D - a)); + double d = _eQuatorialEarthRadius * c; + + return d; + } + + public int HaversineInM(double lat1, double long1, double lat2, double long2) + { + return (int)(1000D * HaversineInKM(lat1, long1, lat2, long2)); + } + + public static bool CheckGeoSearch(string latitude, string longitude, string radius) + { + bool geosearch = false; + //Check of Geosearch durchgeführt werden kann + CultureInfo culture = CultureInfo.InvariantCulture; + bool isLatDouble = Double.TryParse(latitude, NumberStyles.Any, culture, out double latitudecheck); + bool isLongDouble = Double.TryParse(longitude, NumberStyles.Any, culture, out double longitudecheck); + bool isRadiusInt = Int32.TryParse(radius, out int radiuscheck); + + if (isLatDouble && isLongDouble && isRadiusInt) + geosearch = true; + + return geosearch; + } + + public static PGGeoSearchResult GetPGGeoSearchResult(string? latitude, string? longitude, string? radius) + { + if (latitude == null && longitude == null) + return new PGGeoSearchResult() { geosearch = false, latitude = 0, longitude = 0, radius = 0 }; + + PGGeoSearchResult pggeosearchresult = new PGGeoSearchResult + { + geosearch = false + }; + //Check of Geosearch durchgeführt werden kann + CultureInfo culture = CultureInfo.InvariantCulture; + bool isLatDouble = Double.TryParse(latitude, NumberStyles.Any, culture, out double latitudecheck); + bool isLongDouble = Double.TryParse(longitude, NumberStyles.Any, culture, out double longitudecheck); + bool isRadiusInt = Int32.TryParse(radius, out int radiuscheck); + + if (isLatDouble && isLongDouble) + { + pggeosearchresult.geosearch = true; + pggeosearchresult.latitude = latitudecheck; + pggeosearchresult.longitude = longitudecheck; + + if (isRadiusInt) + pggeosearchresult.radius = radiuscheck; + else + pggeosearchresult.radius = 150000; + + //Check Distance, DistanceCalculator returns to high number + //var actualdistance = DistanceCalculator.Distance(pggeosearchresult.latitude, pggeosearchresult.longitude, DistanceCalculator.suedtirolMitteLatitude, DistanceCalculator.suedtirolMitteLongitude, 'K'); + //if (actualdistance > 200) + // pggeosearchresult.geosearch = false; + + } + else + { + pggeosearchresult.geosearch = false; + pggeosearchresult.latitude = 0; + pggeosearchresult.longitude = 0; + pggeosearchresult.radius = 0; + } + + return pggeosearchresult; + } + + public static PGGeoSearchResult GetPGGeoSearchResult(double? latitude, double? longitude, int radius) + { + if (latitude == null && longitude == null) + return new PGGeoSearchResult() { geosearch = false, latitude = 0, longitude = 0, radius = 0 }; + + PGGeoSearchResult pggeosearchresult = new PGGeoSearchResult + { + geosearch = false + }; + + + pggeosearchresult.geosearch = true; + pggeosearchresult.latitude = latitude ?? 0; + pggeosearchresult.longitude = longitude ?? 0; + + if (radius > 0) + pggeosearchresult.radius = radius; + else + pggeosearchresult.radius = 150000; + + return pggeosearchresult; + } + + public static RavenGeoSearchResult GetRavenGeoSearchResult(string latitude, string longitude, string radius) + { + if (latitude == null && longitude == null) + return new RavenGeoSearchResult() { geosearch = false, latitude = 0, longitude = 0, radius = 0 }; + + RavenGeoSearchResult pggeosearchresult = new RavenGeoSearchResult + { + geosearch = false + }; + //Check of Geosearch durchgeführt werden kann + CultureInfo culture = CultureInfo.InvariantCulture; + bool isLatDouble = Double.TryParse(latitude, NumberStyles.Any, culture, out double latitudecheck); + bool isLongDouble = Double.TryParse(longitude, NumberStyles.Any, culture, out double longitudecheck); + bool isRadiusInt = Int32.TryParse(radius, out int radiuscheck); + + if (isLatDouble && isLongDouble) + { + pggeosearchresult.geosearch = true; + pggeosearchresult.latitude = latitudecheck; + pggeosearchresult.longitude = longitudecheck; + + if (isRadiusInt) + pggeosearchresult.radius = radiuscheck; + else + pggeosearchresult.radius = 150; + + //Check ob das ganze sinn macht + var actualdistance = DistanceCalculator.Distance(pggeosearchresult.latitude, pggeosearchresult.longitude, DistanceCalculator.suedtirolMitteLatitude, DistanceCalculator.suedtirolMitteLongitude, 'K'); + if (actualdistance > 150) + pggeosearchresult.geosearch = false; + + } + else + { + pggeosearchresult.geosearch = false; + pggeosearchresult.latitude = 0; + pggeosearchresult.longitude = 0; + pggeosearchresult.radius = 0; + } + + return pggeosearchresult; + } + + public static async Task GetPolygon(string? polygon, QueryFactory queryfactory) + { + if(String.IsNullOrEmpty(polygon)) return null; + else + { + GeoPolygonSearchResult result = new GeoPolygonSearchResult(); + //setting standard operation to intersects + result.operation = "intersects"; + + //Check for WKT String + if (CheckWKTSyntax(polygon, queryfactory)) + { + var wktandsrid = GetWKTAndSRIDFromQuerystring(polygon); + + if (wktandsrid != null) + { + result.wktstring = wktandsrid.Value.Item1; + result.srid = wktandsrid.Value.Item2; + return result; + } + else + return null; + } + + else if (polygon.ToLower().StartsWith("bbc(") || polygon.ToLower().StartsWith("bbi(")) + { + result.polygon = new List>(); + + string coordstoprocess = ""; + string polygonwithoutsrid = polygon; + + if (polygon.Split(";").Length > 1) + { + var splitted = polygon.Split(";"); + var sridstr = splitted[1].ToUpper(); + if (sridstr.StartsWith("SRID=")) + result.srid = sridstr.Replace("SRID=", ""); + } + + if (polygon.ToLower().StartsWith("bbc")) + { + result.operation = "contains"; + coordstoprocess = polygon.ToLower().Replace("bbc", ""); + } + else if (polygon.ToLower().StartsWith("bbi")) + { + result.operation = "intersects"; + coordstoprocess = polygon.ToLower().Replace("bbi", ""); + } + else + coordstoprocess = polygon.ToLower(); + + coordstoprocess = Regex.Replace(coordstoprocess, @"\(+|\)+", ""); + CultureInfo culture = CultureInfo.InvariantCulture; + + foreach (var item in coordstoprocess.Split(',')) + { + var coords = item.Trim().Split(" "); + + if (coords.Count() == 2 && Double.TryParse(coords[0], NumberStyles.Any, culture, out double longitude) && Double.TryParse(coords[1], NumberStyles.Any, culture, out double latitude)) + { + result.polygon.Add(Tuple.Create(longitude, latitude)); + } + } + + if (result.polygon.Count == 0) return null; + else return result; + } + else + { + //Format = country.type.id or country.type.name + var inputquery = polygon.Split("."); + if (inputquery.Length != 3) + return null; + + bool idtofilter = int.TryParse(inputquery[2], out int parsedid); + + //Retrieve data from shape table + + var geometry = await queryfactory.Query() + .SelectRaw("ST_AsText(geometry)") + .From("shapes") + .Where("country", inputquery[0].ToUpper()) + .Where("type", inputquery[1].ToLower()) + .When(idtofilter, x => x.Where("id", parsedid)) + .When(!idtofilter, x => x.WhereLike("name", inputquery[2])) + //create a generated column which constructs a name by id,type and name + .FirstOrDefaultAsync(); + + if (!String.IsNullOrEmpty(geometry)) + { + result.wktstring = geometry.ToString(); + + return result; + } + else + return null; + } + } + + } + + public static bool CheckValidWKTString(string? polygon) + { + if (polygon.ToUpper().StartsWith("LINESTRING") || + polygon.ToUpper().StartsWith("POLYGON") || + polygon.ToUpper().StartsWith("MULTIPOINT") || + polygon.ToUpper().StartsWith("MULTILINESTRING") || + polygon.ToUpper().StartsWith("MULTIPOLYGON") || + polygon.ToUpper().StartsWith("GEOMETRYCOLLECTION") || + polygon.ToUpper().StartsWith("POINT ZM") || + polygon.ToUpper().StartsWith("POINT M")) + { + return true; + } + else + return false; + } + + public static bool CheckWKTSyntax(string? polygon, QueryFactory queryFactory) + { + try + { + var wktwithsrid = GetWKTAndSRIDFromQuerystring(polygon); + + if (wktwithsrid != null) + { + var query = queryFactory.Query().SelectRaw($"Count(ST_GeometryFromText('{wktwithsrid.Value.Item1}',{wktwithsrid.Value.Item2}))").Get(); + + if (query != null && query.FirstOrDefault() == 1) + return true; + } + + return false; + } + catch { return false; } + } + + public static (string,string)? GetWKTAndSRIDFromQuerystring(string? polygon) + { + string srid = "4326"; + string wkt = ""; + + //IF S7Rid is added + if (polygon != null && polygon.Split(";").Length > 1) + { + var splitted = polygon.Split(";"); + var sridstr = splitted[1].ToUpper(); + if (sridstr.StartsWith("SRID=")) + { + sridstr = sridstr.Replace("SRID=", ""); + + if (CheckValidWKTString(splitted[0])) + { + wkt = splitted[0]; + return (wkt, sridstr); + } + } + } + //IF only wkt is added + else if (polygon != null && polygon.Split(';').Length == 1) + { + if (CheckValidWKTString(polygon)) + { + wkt = polygon; + + return (wkt, srid); + } + } + + return null; + } + + + } + + + public class DistanceCalculator + { + public const double suedtirolMitteLatitude = 46.655781; + public const double suedtirolMitteLongitude = 11.4296877; + + + //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + //::: ::: + //::: This routine calculates the distance between two points (given the ::: + //::: latitude/longitude of those points). It is being used to calculate ::: + //::: the distance between two locations using GeoDataSource(TM) products ::: + //::: ::: + //::: Definitions: ::: + //::: South latitudes are negative, east longitudes are positive ::: + //::: ::: + //::: Passed to function: ::: + //::: lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees) ::: + //::: lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees) ::: + //::: unit = the unit you desire for results ::: + //::: where: 'M' is statute miles (default) ::: + //::: 'K' is kilometers ::: + //::: 'N' is nautical miles ::: + //::: ::: + //::: Worldwide cities and other features databases with latitude longitude ::: + //::: are available at http://www.geodatasource.com ::: + //::: ::: + //::: For enquiries, please contact sales@geodatasource.com ::: + //::: ::: + //::: Official Web site: http://www.geodatasource.com ::: + //::: ::: + //::: GeoDataSource.com (C) All Rights Reserved 2015 ::: + //::: ::: + //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + + public static double Distance(double lat1, double lon1, double lat2, double lon2, char unit) + { + double theta = lon1 - lon2; + double dist = Math.Sin(Deg2rad(lat1)) * Math.Sin(Deg2rad(lat2)) + Math.Cos(Deg2rad(lat1)) * Math.Cos(Deg2rad(lat2)) * Math.Cos(Deg2rad(theta)); + dist = Math.Acos(dist); + dist = Rad2deg(dist); + dist = dist * 60 * 1.1515; + if (unit == 'K') + { + dist *= 1.609344; + } + else if (unit == 'N') + { + dist *= 0.8684; + } + return (dist); + } + + //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + //:: This function converts decimal degrees to radians ::: + //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + private static double Deg2rad(double deg) + { + return (deg * Math.PI / 180.0); + } + + //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + //:: This function converts radians to decimal degrees ::: + //::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + private static double Rad2deg(double rad) + { + return (rad / Math.PI * 180.0); + } + + } + + public class PGGeoSearchResult + { + public bool geosearch { get; set; } = false; + public double latitude { get; set; } + public double longitude { get; set; } + public int radius { get; set; } + } + + public class GeoPolygonSearchResult + { + public string? operation { get; set; } + public List>? polygon { get; set; } + public string? wktstring { get; set; } = null; + public string srid { get; set; } = "4326"; + } + + public class RavenGeoSearchResult + { + public bool geosearch { get; set; } + public double latitude { get; set; } + public double longitude { get; set; } + public int radius { get; set; } + } +} diff --git a/Helper/Generic/HasLanguageHelper.cs b/Helper/Generic/HasLanguageHelper.cs new file mode 100644 index 0000000..65aa605 --- /dev/null +++ b/Helper/Generic/HasLanguageHelper.cs @@ -0,0 +1,151 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public static class HasLanguageHelper + { + private static void FixDetailBaseAndIntroText(Detail mydetail) + { + if (!String.IsNullOrEmpty(mydetail.BaseText)) + { + mydetail.BaseText = mydetail.BaseText.Trim(); + + if (mydetail.BaseText == " " || mydetail.BaseText == "\n\n") + mydetail.BaseText = ""; + } + if (!String.IsNullOrEmpty(mydetail.IntroText)) + { + mydetail.IntroText = mydetail.IntroText.Trim(); + + if (mydetail.IntroText == " " || mydetail.IntroText == "\n\n") + mydetail.IntroText = ""; + } + } + + private static void FixDetailLanguageField(ILanguage mydetail, string language) + { + if (String.IsNullOrEmpty(mydetail.Language)) + mydetail.Language = language; + } + + //Check Language for Example DataModel + public static void CheckMyInsertedLanguages(this Example example, List availablelanguages) + { + if (example.HasLanguage == null) + example.HasLanguage = new List(); + + //Detail, ImageGallery, ContactInfos, AdditionalArticleInfos, + foreach (string language in availablelanguages) + { + if (example.Detail.ContainsKey(language) || example.ContactInfos.ContainsKey(language)) + { + bool removelang = true; + + if (example.Detail.ContainsKey(language) && example.Detail[language] != null) + { + var detailvalues = example.Detail[language]; + + FixDetailLanguageField(detailvalues, language); + FixDetailBaseAndIntroText(detailvalues); + + if (!String.IsNullOrEmpty(detailvalues.AdditionalText)) + if (!String.IsNullOrEmpty(detailvalues.AdditionalText.Trim())) + removelang = false; + if (!String.IsNullOrEmpty(detailvalues.BaseText)) + if (!String.IsNullOrEmpty(detailvalues.BaseText.Trim())) + removelang = false; + if (!String.IsNullOrEmpty(detailvalues.GetThereText)) + if (!String.IsNullOrEmpty(detailvalues.GetThereText.Trim())) + removelang = false; + if (!String.IsNullOrEmpty(detailvalues.Header)) + if (!String.IsNullOrEmpty(detailvalues.Header.Trim())) + removelang = false; + if (!String.IsNullOrEmpty(detailvalues.IntroText)) + if (!String.IsNullOrEmpty(detailvalues.IntroText.Trim())) + removelang = false; + if (!String.IsNullOrEmpty(detailvalues.SubHeader)) + if (!String.IsNullOrEmpty(detailvalues.SubHeader.Trim())) + removelang = false; + if (!String.IsNullOrEmpty(detailvalues.Title)) + if (!String.IsNullOrEmpty(detailvalues.Title.Trim())) + removelang = false; + + example.Detail[language].Language = language; + } + + if (example.ContactInfos.ContainsKey(language) && example.ContactInfos[language] != null) + { + var contactvalues = example.ContactInfos[language]; + + FixDetailLanguageField(contactvalues, language); + + if (!String.IsNullOrEmpty(contactvalues.Address)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.City)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.CompanyName)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.CountryCode)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.CountryName)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.Email)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.Faxnumber)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.Givenname)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.LogoUrl)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.NamePrefix)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.Phonenumber)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.Surname)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.Tax)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.Url)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.Vat)) + removelang = false; + if (!String.IsNullOrEmpty(contactvalues.ZipCode)) + removelang = false; + + example.ContactInfos[language].Language = language; + } + + //Add Language + if (removelang == false) + { + if (!example.HasLanguage.Contains(language)) + example.HasLanguage.Add(language); + } + //Remove Language + else if (removelang == true) + { + if (example.Detail.ContainsKey(language)) + example.Detail.Remove(language); + + if (example.ContactInfos.ContainsKey(language)) + example.ContactInfos.Remove(language); + + if (example.HasLanguage.Contains(language)) + example.HasLanguage.Remove(language); + } + } + } + } + } +} diff --git a/Helper/Generic/IdGenerator.cs b/Helper/Generic/IdGenerator.cs new file mode 100644 index 0000000..a2aa373 --- /dev/null +++ b/Helper/Generic/IdGenerator.cs @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DataModel; + +namespace Helper +{ + public class IdGenerator + { + /// + /// Translates a ODH Type Object to the Type (Metadata) as String + /// + /// + /// + /// + public static string GenerateIDFromType(T odhtype) + { + return CreateGUID(GetIDStyle(odhtype)); + } + + public static void CheckIdFromType(T odhtype) where T : IIdentifiable + { + var style = GetIDStyle(odhtype); + + if (style == IDStyle.uppercase) + odhtype.Id = odhtype.Id.ToUpper(); + else if (style == IDStyle.lowercase) + odhtype.Id = odhtype.Id.ToLower(); + } + + public static string CheckIdFromType(string id) where T : IIdentifiable + { + var style = GetIDStyle(typeof(T)); + + if (style == IDStyle.uppercase) + return id.ToUpper(); + else if (style == IDStyle.lowercase) + return id.ToLower(); + + return id; + } + + private static string CreateGUID(IDStyle style) + { + var id = System.Guid.NewGuid().ToString(); + + if (style == IDStyle.uppercase) + id = id.ToUpper(); + else if(style == IDStyle.lowercase) + id = id.ToLower(); + + return id; + } + + public static IDStyle GetIDStyle(T odhtype) + { + return odhtype switch + { + Example or ExampleLinked => IDStyle.uppercase, + _ => throw new Exception("not known odh type") + }; + } + + public static IDStyle GetIDStyle(Type odhtype) + { + return odhtype switch + { + Type _ when odhtype == typeof(Example) || odhtype == typeof(ExampleLinked) => IDStyle.uppercase, + _ => throw new Exception("not known odh type") + }; + } + + public static string TransformIDbyIdStyle(string id, IDStyle idstyle) + { + if (idstyle == IDStyle.uppercase) + return id.ToUpper(); + else + return id.ToLower(); + } + } + + public enum IDStyle + { + uppercase, + lowercase, + mixed + } +} diff --git a/Helper/Generic/LicenseHelper.cs b/Helper/Generic/LicenseHelper.cs new file mode 100644 index 0000000..566b617 --- /dev/null +++ b/Helper/Generic/LicenseHelper.cs @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public class LicenseHelper + { + public static LicenseInfo GetLicenseInfoobject(string licensetype, string author, string licenseholder, bool closeddata) + { + return new LicenseInfo() { Author = author, License = licensetype, LicenseHolder = licenseholder, ClosedData = closeddata }; + } + + //TODO Make a HOF and apply all the rules + public static LicenseInfo GetLicenseInfoobject(T myobject, Func licensegenerator) + { + return licensegenerator(myobject); + } + + public static LicenseInfo GetLicenseforExample(Example data) + { + var isopendata = true; + var licensetype = "CC0"; + var licenseholder = @"https://noi.bz.it"; + + return GetLicenseInfoobject(licensetype, "", licenseholder, !isopendata); + } + } +} diff --git a/Helper/Generic/MetaInfoHelper.cs b/Helper/Generic/MetaInfoHelper.cs new file mode 100644 index 0000000..b4745a7 --- /dev/null +++ b/Helper/Generic/MetaInfoHelper.cs @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Microsoft.AspNetCore.Identity; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public class MetadataHelper + { + //Simple Method to reset the Metainfo + public static Metadata GetMetadata(string id, string type, string? source, DateTime? lastupdated = null, bool reduced = false) + { + return new Metadata() { Id = id, Type = type, LastUpdate = lastupdated, Source = source, Reduced = reduced }; + } + + public static Metadata GetMetadata(T data, string source, DateTime? lastupdated = null, bool reduced = false) where T : IIdentifiable, IMetaData + { + string type = ODHTypeHelper.TranslateType2TypeString(data); + + //If source is already set use the old source + //if (data._Meta != null && !string.IsNullOrEmpty(data._Meta.Source)) + // source = data._Meta.Source; + + return new Metadata() { Id = data.Id, Type = type, LastUpdate = lastupdated, Source = source, Reduced = reduced }; + } + + public static Metadata GetMetadataobject(T myobject, Func metadataganerator) + { + return metadataganerator(myobject); + } + + //Discriminator if the function is not passed + public static Metadata GetMetadataobject(T myobject) + { + return myobject switch + { + ExampleLinked al => GetMetadataforExample(al), + PublisherLinked pbl => GetMetadataforPublisher(pbl), + SourceLinked pbl => GetMetadataforSource(pbl), + _ => throw new Exception("not known odh type") + }; + } + + public static Metadata GetMetadataforExample(ExampleLinked data) + { + bool reduced = false; + if (data._Meta != null) + reduced = (bool)data._Meta.Reduced; + + return GetMetadata(data, "noi", data.LastChange, reduced); + } + + public static Metadata GetMetadataforPublisher(PublisherLinked data) + { + string sourcemeta = "noi"; + + return GetMetadata(data, sourcemeta, data.LastChange); + } + + public static Metadata GetMetadataforSource(SourceLinked data) + { + string sourcemeta = "noi"; + + return GetMetadata(data, sourcemeta, data.LastChange); + } + } +} diff --git a/Helper/Generic/ODHTypeHelper.cs b/Helper/Generic/ODHTypeHelper.cs new file mode 100644 index 0000000..031ca0f --- /dev/null +++ b/Helper/Generic/ODHTypeHelper.cs @@ -0,0 +1,305 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public class ODHTypeHelper + { + public static IEnumerable GetAllTypeStrings() + { + return new List() + { + "example", + "publisher", + "source" + }; + } + + #region TypeObject2TypeStringANDPGTable + + /// + /// Translates a ODH Type Object to the Type (Metadata) as String + /// + /// + /// + /// + public static string TranslateType2TypeString(T odhtype) + { + return odhtype switch + { + Example or ExampleLinked => "example", + ExampleType => "exampletype", + Publisher or PublisherLinked => "publisher", + Source or SourceLinked => "source", + _ => throw new Exception("not known odh type") + }; + } + + /// + /// Translates ODH Type Object to PG Table Name + /// + /// + /// + /// + public static string TranslateType2Table(T odhtype) + { + return odhtype switch + { + Example or ExampleLinked => "examples", + ExampleType => "exampletypes", + Publisher or PublisherLinked => "publishers", + Source or SourceLinked => "sources", + _ => throw new Exception("not known odh type") + }; + } + + #endregion + + #region TypeString2TypeObjectANDPGTable + + /// + /// Translates Type (Metadata) as String to PG Table Name + /// + /// + /// + public static string TranslateTypeString2Table(string odhtype) + { + return odhtype switch + { + "example" => "examples", + "exampletype" => "exampletypes", + "publisher" => "publishers", + _ => throw new Exception("not known odh type") + }; + } + + /// + /// Translates Type (Metadata) as String to Type Object + /// + /// + /// + public static Type TranslateTypeString2Type(string odhtype) + { + return odhtype switch + { + "example" => typeof(ExampleLinked), + "exampletype" => typeof(ExampleType), + "publisher" => typeof(PublisherLinked), + "source" => typeof(SourceLinked), + _ => throw new Exception("not known odh type") + }; + } + + #endregion + + #region PGTable2TypeObjectANDString + + /// + /// Translates PG Table Name to Type (Metadata) as String + /// + /// + /// + public static string TranslateTable2TypeString(string odhtype) + { + return odhtype switch + { + "examples" => "example", + "exampletypes" => "exampletype", + "publishers" => "publisher", + "sources" => "source", + _ => throw new Exception("not known odh type") + }; + } + + /// + /// Translates PG Table Name to Type Object + /// + /// + /// + public static Type TranslateTable2Type(string odhtype) + { + return odhtype switch + { + "examples" => typeof(ExampleLinked), + "exampletypes" => typeof(ExampleType), + "publishers" => typeof(PublisherLinked), + "sources" => typeof(SourceLinked), + _ => throw new Exception("not known table name") + }; + } + + #endregion + + #region Type2MetaGeneratorFunction + + //TODO Migrate from Metagenerator + + #endregion + + #region TypeIdConverter + + //TODO insert in IdGenerator + public static string ConvertIdbyTypeString(string odhtype, string id) + { + return odhtype switch + { + "example" => id.ToUpper(), + "exampletype" => id.ToUpper(), + "publisher" => id.ToLower(), + "source" => id.ToLower(), + _ => throw new Exception("not known odh type") + }; + } + + #endregion + + #region JsonRaw2Type + + public static IIdentifiable ConvertJsonRawToObject(string odhtype, JsonRaw raw) + { + return odhtype switch + { + "example" => JsonConvert.DeserializeObject(raw.Value)!, + "exampletype" => JsonConvert.DeserializeObject(raw.Value)!, + "publisher" => JsonConvert.DeserializeObject(raw.Value)!, + "source" => JsonConvert.DeserializeObject(raw.Value)!, + _ => throw new Exception("not known odh type") + }; + } + + #endregion + + #region Search + + /// + /// Gets all ODH Types to search on + /// + /// + /// + public static string[] GetAllSearchableODHTypes(bool getall) + { + var odhtypes = new List(); + + odhtypes.Add("example"); + + if (getall) + { + odhtypes.Add("publisher"); + odhtypes.Add("source"); + odhtypes.Add("exampletype"); + } + + return odhtypes.ToArray(); + } + + public static Func TranslateTypeToSearchField(string odhtype) + { + return odhtype switch + { + "accommodation" => PostgresSQLWhereBuilder.AccoTitleFieldsToSearchFor, + "accommodationroom" => PostgresSQLWhereBuilder.AccoRoomNameFieldsToSearchFor, + "ltsactivity" or "ltspoi" or "ltsgastronomy" or "event" or "odhactivitypoi" or "metaregion" or "region" or "tourismassociation" or "municipality" + or "district" or "skiarea" or "skiregion" or "article" or "experiencearea" or "webcam" or "venue" + => PostgresSQLWhereBuilder.TitleFieldsToSearchFor, + //"measuringpoint" => PostgresSQLWhereBuilder., +// "webcam" => PostgresSQLWhereBuilder.WebcamnameFieldsToSearchFor, + //"venue" => PostgresSQLWhereBuilder.TitleFieldsToSearchFor, + //"eventshort" => "eventeuracnoi", + //"area" => "areas", + //"wineaward" => "wines", + _ => throw new Exception("not known odh type") + }; + } + + public static string TranslateTypeToEndPoint(string odhtype) + { + return odhtype switch + { + "accommodation" => "Accommodation", + "odhactivitypoi" => "ODHActivityPoi", + "event" => "Event", + "region" => "Region", + "skiarea" => "SkiArea", + "tourismassociation" => "TourismAssociation", + "webcam" => "WebcamInfo", + "venue" => "Venue", + "accommodationroom" => "AccommodationRoom", + "package" => "Package", + "ltsactivity" => "Activity", + "ltspoi" => "Poi", + "ltsgastronomy" => "Gastronomy", + "measuringpoint" => "Weather/Measuringpoint", + "article" => "Article", + "municipality" => "Municipality", + "district" => "District", + "skiregion" => "SkiRegion", + "eventshort" => "EventShort", + "experiencearea" => "ExperienceArea", + "metaregion" => "MetaRegion", + "area" => "Area", + "wineaward" => "Wine", + "odhmetadata" => "MetaData", + "odhtag" => "ODHTag", + "tag" => "Tag", + "publisher" => "Publisher", + "source" => "Source", + "weatherhistory" => "WeatherHistory", + "weatherdistrict" => "Weather/District", + "weatherforecast" => "Weather/Forecast", + "weatherrealtime" => "Weather/Realtime", + "snowreport" => "Weather/SnowReport", + "weather" => "Weather", + + _ => throw new Exception("not known odh type") + }; + } + + + #endregion + + public static string TranslateTypeToTitleField(string odhtype, string language) + { + return odhtype switch + { + "example" => $"Detail.{language}.Title", + "accommodation" => $"AccoDetail.{language}.Name", + "accommodationroom" => $"AccoRoomDetail.{language}.Name", + "ltsactivity" or "ltspoi" or "ltsgastronomy" or "event" or "odhactivitypoi" or "metaregion" or "region" or "tourismassociation" or "municipality" + or "district" or "skiarea" or "skiregion" or "article" or "experiencearea" or "venue" + => $"Detail.{language}.Title", + "measuringpoint" => $"Shortname", + "webcam" => $"Webcamname.{language}", + //"eventshort" => "eventeuracnoi", + //"area" => "areas", + //"wineaward" => "wines", + _ => throw new Exception("not known odh type") + }; + } + + public static string TranslateTypeToBaseTextField(string odhtype, string language) + { + return odhtype switch + { + "example" => $"Detail.{language}.BaseText", + "accommodation" => $"AccoDetail.{language}.Longdesc", + "accommodationroom" => $"AccoRoomDetail.{language}.Longdesc", + "ltsactivity" or "ltspoi" or "ltsgastronomy" or "event" or "odhactivitypoi" or "metaregion" or "region" or "tourismassociation" or "municipality" + or "district" or "skiarea" or "skiregion" or "article" or "experiencearea" + => $"Detail.{language}.BaseText", + "measuringpoint" => "notextfield", + "webcam" => "notextfield", + "venue" => "notextfield", + _ => throw new Exception("not known odh type") + }; + } + } +} diff --git a/Helper/Generic/PathStringExtensions.cs b/Helper/Generic/PathStringExtensions.cs new file mode 100644 index 0000000..81a6e32 --- /dev/null +++ b/Helper/Generic/PathStringExtensions.cs @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.Generic +{ + public static class PathStringExtensions + { + public static string GetPathNextTo(this PathString pathString, string splitter, string nextto) + { + if (pathString != null && pathString.HasValue) + { + var splitted = pathString.Value.Split(splitter); + bool next = false; + + foreach(var item in splitted) + { + if (next) + return item; + + if(item == nextto) + next = true; + } + } + + return ""; + } + } +} diff --git a/Helper/Generic/SourceFilterHelper.cs b/Helper/Generic/SourceFilterHelper.cs new file mode 100644 index 0000000..bdd6a61 --- /dev/null +++ b/Helper/Generic/SourceFilterHelper.cs @@ -0,0 +1,100 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.Generic +{ + public static class SourceFilterHelper + { + public static List ExtendSourceFilterODHActivityPois(List sourcelist) + { + List sourcelistnew = new(); + + foreach (var source in sourcelist) + { + sourcelistnew.Add(source); + + if (source == "idm") + { + if (!sourcelistnew.Contains("none")) + sourcelistnew.Add("none"); + if (!sourcelistnew.Contains("magnolia")) + sourcelistnew.Add("magnolia"); + if (!sourcelistnew.Contains("common")) + sourcelistnew.Add("common"); + + } + else if (source == "lts") + { + if (!sourcelistnew.Contains("activitydata")) + sourcelistnew.Add("activitydata"); + if (!sourcelistnew.Contains("poidata")) + sourcelistnew.Add("poidata"); + if (!sourcelistnew.Contains("beacondata")) + sourcelistnew.Add("beacondata"); + if (!sourcelistnew.Contains("gastronomicdata")) + sourcelistnew.Add("gastronomicdata"); + if (!sourcelistnew.Contains("beacondata")) + sourcelistnew.Add("beacondata"); + } + else if (source == "siag") + { + if (!sourcelistnew.Contains("museumdata")) + sourcelistnew.Add("museumdata"); + } + else if (source == "dss") + { + if (!sourcelistnew.Contains("dssliftbase")) + sourcelistnew.Add("dssliftbase"); + if (!sourcelistnew.Contains("dssslopebase")) + sourcelistnew.Add("dssslopebase"); + } + else if (source == "content") + { + if (!sourcelistnew.Contains("none")) + sourcelistnew.Add("none"); + } + else if (source == "a22") + { + if (!sourcelistnew.Contains("tollstation")) + sourcelistnew.Add("tollstation"); + if (!sourcelistnew.Contains("servicearea")) + sourcelistnew.Add("servicearea"); + } + else if (source == "iit") + { + if (!sourcelistnew.Contains("h2 center")) + sourcelistnew.Add("h2 center"); + } + else if (source == "alperia") + { + if (!sourcelistnew.Contains("neogy")) + sourcelistnew.Add("neogy"); + } + else if (source == "echargingspreadsheet") + { + if (!sourcelistnew.Contains("ecogy gmbh")) + sourcelistnew.Add("ecogy gmbh"); + if (!sourcelistnew.Contains("leitner energy")) + sourcelistnew.Add("leitner energy"); + if (!sourcelistnew.Contains("officina elettrica san vigilio di marebbe spa")) + sourcelistnew.Add("officina elettrica san vigilio di marebbe spa"); + if (!sourcelistnew.Contains("ötzi genossenschaft")) + sourcelistnew.Add("ötzi genossenschaft"); + if (!sourcelistnew.Contains("pension erlacher")) + sourcelistnew.Add("pension erlacher"); + if (!sourcelistnew.Contains("vek")) + sourcelistnew.Add("vek"); + } + } + + return sourcelistnew; + } + } +} diff --git a/Helper/GetData/GetData.cs b/Helper/GetData/GetData.cs new file mode 100644 index 0000000..cf06643 --- /dev/null +++ b/Helper/GetData/GetData.cs @@ -0,0 +1,106 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Authentication; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace Helper.GetData +{ + public enum GetDataAuthenticationOptions + { + None, + Basic, + Bearer + } + + public class GetData + { + private string serviceurl; + private string user; + private string pass; + private string bearertoken; + private GetDataAuthenticationOptions authtype; + + public GetData(string _serviceurl, string _user, string _pass, string _bearertoken, GetDataAuthenticationOptions _authtype) + { + serviceurl = _serviceurl; + user = _user; + pass = _pass; + bearertoken = _bearertoken; + authtype = _authtype; + } + + private async Task GetDataFromService() + { + if(authtype == GetDataAuthenticationOptions.Basic) + { + CredentialCache wrCache = new CredentialCache(); + wrCache.Add(new Uri(serviceurl), "Basic", new NetworkCredential(user, pass)); + + using (var handler = new HttpClientHandler { Credentials = wrCache }) + { + using (var client = new HttpClient(handler)) + { + return await client.GetAsync(serviceurl); + } + } + } + if (authtype == GetDataAuthenticationOptions.Bearer) + { + using (var client = new HttpClient()) + { + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearertoken); + + return await client.GetAsync(serviceurl); + } + } + else + { + using (var client = new HttpClient()) + { + return await client.GetAsync(serviceurl); + } + } + } + + public async Task GetDataAsJsonAsync() + { + //Request + HttpResponseMessage response = await GetDataFromService(); + + if (response.StatusCode != HttpStatusCode.OK) + throw new Exception("Error on getting data "+ response.StatusCode.ToString()); + + //Parse JSON Response to + var responsecontent = await response.Content.ReadAsStringAsync(); + dynamic? responseobject = JsonConvert.DeserializeObject(responsecontent); + + return responseobject; + } + + public async Task GetDataAsXmlAsync() + { + //Request + HttpResponseMessage response = await GetDataFromService(); + + if (response.StatusCode != HttpStatusCode.OK) + throw new Exception("Error on getting data " + response.StatusCode.ToString()); + + //Parse JSON Response to + var responsecontent = await response.Content.ReadAsStringAsync(); + XDocument responseobject = XDocument.Parse(responsecontent); + + return responseobject; + } + } +} \ No newline at end of file diff --git a/Helper/Helper.csproj b/Helper/Helper.csproj new file mode 100644 index 0000000..d8c5bfb --- /dev/null +++ b/Helper/Helper.csproj @@ -0,0 +1,31 @@ + + + + net8.0 + enable + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Helper/Identity/AuthorizationMiddleware.cs b/Helper/Identity/AuthorizationMiddleware.cs new file mode 100644 index 0000000..17ea6c9 --- /dev/null +++ b/Helper/Identity/AuthorizationMiddleware.cs @@ -0,0 +1,134 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Caching.Distributed; +using System; +using System.IdentityModel.Tokens.Jwt; +using System.IO; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Linq; +using System.Collections; +using System.Collections.Generic; +using System.Security.Claims; +using Helper; +using System.Net.Http.Headers; +using System.Net.Http; +using Microsoft.Extensions.Configuration; +using Newtonsoft.Json; + +namespace Helper.Identity +{ + public class AuthorizationMiddleware + { + private readonly RequestDelegate _next; + + public AuthorizationMiddleware(RequestDelegate next) + { + _next = next; + } + + public async Task InvokeAsync(HttpContext context, IConfiguration configuration) + { + var endpoint = context.GetEndpoint(); + + //If already a 401 Response is waiting do nothing + if (context.Response.HasStarted) + { + return; + } + + //GET BEARER TOKEN from Authorization Header + var bearertoken = ""; + + if (context.Request.Headers.ContainsKey("Authorization")) + bearertoken = context.Request.Headers["Authorization"].ToString(); + + if (!string.IsNullOrEmpty(bearertoken) && bearertoken.StartsWith("Bearer")) + { + var handler = new JwtSecurityTokenHandler(); + var token = bearertoken.Replace("Bearer", "").Trim(); + + var permissions = await RequestAuthorizationEndpoint(token, configuration.GetSection("OauthServerConfig").GetValue("Authority")); + + //Store the permissions as claims + foreach(var permission in permissions) + { + foreach(var scope in permission.scopes) + { + var resourceendpointsplitted = permission.rsname.Split('?'); + var additionalfilter = resourceendpointsplitted.Length > 1 ? "_" + resourceendpointsplitted[1] : ""; + + if (context.User.Identities.FirstOrDefault() != null) + context.User.Identities.FirstOrDefault().AddClaim(new Claim(ClaimTypes.Role, resourceendpointsplitted[0] + "_" + scope + additionalfilter)); + } + } + + } + + await _next(context); + } + + private static JwtSecurityToken? ReadMyJWTSecurityToken(string token, JwtSecurityTokenHandler handler) + { + try + { + var jwttoken = handler.ReadJwtToken(token); + + return jwttoken; + } + catch + { + return null; + } + } + + private static async Task> RequestAuthorizationEndpoint(string token, string authorizationendpoint) + { + //TODO REQUEST AUTHORIZATION ON KEYCLOAK with grant_type=urn:ietf:params:oauth:grant-type:uma-ticket AND audience=odh-tourism-api + //and pass the bearer token + + var body = new Dictionary(); + body.Add("grant_type", "urn:ietf:params:oauth:grant-type:uma-ticket"); + body.Add("audience", "odh-tourism-api"); + body.Add("response_mode", "permissions"); + + using (var client = new HttpClient()) + { + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + + using var request = new HttpRequestMessage(HttpMethod.Post, authorizationendpoint + "protocol/openid-connect/token") { Content = new FormUrlEncodedContent(body) }; + using var response = await client.SendAsync(request); + + //if (response.StatusCode != HttpStatusCode.OK) + //{ + //Return directly?? Handle Access Denied error when no Role defined in Permissions is found + + //throw new Exception("Error on getting data " + response.StatusCode.ToString()); + //} + + var responseobject = new List(); + + if (response.StatusCode == HttpStatusCode.OK) + { + + //Parse JSON Response to + var responsecontent = await response.Content.ReadAsStringAsync(); + responseobject = JsonConvert.DeserializeObject>(responsecontent); + } + + return responseobject; + } + } + } + + public class KeyCloakPermissions + { + public List scopes { get; set; } + public string rsname { get; set; } + } +} + diff --git a/Helper/Identity/AuthorizeFilter.cs b/Helper/Identity/AuthorizeFilter.cs new file mode 100644 index 0000000..1c42931 --- /dev/null +++ b/Helper/Identity/AuthorizeFilter.cs @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Helper.Generic; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.Identity +{ + public enum PermissionAction + { + Read, + Create, + Update, + Delete + } + + public class AuthorizeODHAttribute : TypeFilterAttribute + { + public AuthorizeODHAttribute(PermissionAction action) + : base(typeof(AuthorizeODHActionFilter)) + { + Arguments = new object[] { action }; + } + } + + public class AuthorizeODHActionFilter : IAuthorizationFilter + { + private readonly PermissionAction _action; + public AuthorizeODHActionFilter(PermissionAction action) + { + _action = action; + } + public void OnAuthorization(AuthorizationFilterContext context) + { + bool isAuthorized = CheckAccess(context.HttpContext.User, _action, context.HttpContext.Request.Path.GetPathNextTo("/","v1")); // :) + + if (!isAuthorized) + { + context.Result = new ForbidResult(); + } + } + + private bool CheckAccess(ClaimsPrincipal User, PermissionAction action, string endpoint) + { + if (!String.IsNullOrEmpty(endpoint)) + return User.Claims.Any(c => c.Type == ClaimTypes.Role && c.Value.StartsWith(endpoint + "_" + action.ToString())); + else + return false; + } + } +} diff --git a/Helper/Identity/CheckCRUDCondition.cs b/Helper/Identity/CheckCRUDCondition.cs new file mode 100644 index 0000000..9f7a674 --- /dev/null +++ b/Helper/Identity/CheckCRUDCondition.cs @@ -0,0 +1,108 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using SqlKata; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.Identity +{ + public class CheckCRUDCondition + { + public static bool CRUDOperationAllowed(T data, string? condition) where T : IIdentifiable, IImportDateassigneable, IMetaData + { + //TODO what if condition has more variables NOT working at the moment because + + bool checkresult = true; + + if (condition == null) + return checkresult; + + List checks = new List(); + + var splittedcondition = condition.Split("&").Select(x => x.Split("=")).Select(x => new ReadCondition() { Column = x[0], Value = x[1] }); + + var itemstoadd = splittedcondition.GroupBy(x => x.Column).Where(g => g.Count() == 1).ToList(); + foreach (var item in itemstoadd) + { + checks.Add(CheckTheFields(data, item.Key, item.Select(x => x.Value).ToList())); + } + + var itemstomerge = splittedcondition.GroupBy(x => x.Column).Where(g => g.Count() > 1).ToList(); + foreach (var item in itemstomerge) + { + checks.Add(CheckTheFields(data, item.Key, item.Select(x => x.Value).ToList())); + } + + return checks.All(x => x == true); + } + + public static bool CheckTheFields(T data, string input, List values) where T : IIdentifiable, IImportDateassigneable, IMetaData + { + var checkresult = true; + + switch (input.ToLower()) + { + //Hardcoded + case "source": + if(!values.Any(x => x == data._Meta.Source)) + checkresult = false; + break; + //Using reflection to get the Type + default: + var property = data.GetType().GetProperty(input); + if (property != null) + { + var propvalue = property.GetValue(data, null); + if (!values.Any(x => x == propvalue.ToString())) + checkresult = false; + } + + break; + } + + return checkresult; + } + + public static bool CRUDOperationAllowedWithoutConstraint(T data, string? condition) + { + bool checkresult = true; + + if (condition == null) + return checkresult; + + var splitmultipleconditions = condition.Split("&"); + + foreach (var singlecondition in splitmultipleconditions) + { + var splittedcondition = condition.Split("="); + + //Add here all allowed conditions + if (splittedcondition.Length > 1) + { + switch (splittedcondition[0].ToLower()) + { + //Using reflection to get the Type + default: + var property = data.GetType().GetProperty(splittedcondition[0]); + if (property != null) + { + var propvalue = property.GetValue(data, null); + if (propvalue.ToString() != splittedcondition[1]) + checkresult = false; + } + + break; + } + } + } + + return checkresult; + } + } +} diff --git a/Helper/Identity/RoleHelper.cs b/Helper/Identity/RoleHelper.cs new file mode 100644 index 0000000..196fa91 --- /dev/null +++ b/Helper/Identity/RoleHelper.cs @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Authorization; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.Identity +{ + public class RoleHelper + { + public static void AddRoleClaims(ClaimsPrincipal? principal, string client) + { + if (principal != null) + { + var claimsIdentity = principal.Identity as ClaimsIdentity; + if (claimsIdentity != null) + { + JObject obj = JObject.Parse(claimsIdentity.Claims.First(c => c.Type == "resource_access").Value); + var roleAccess = obj.GetValue(client)!.ToObject()!.GetValue("roles"); + foreach (JToken role in roleAccess!) + { + //add only if role is not present + if (!principal.IsInRole(role.ToString())) + claimsIdentity.AddClaim(new Claim(ClaimTypes.Role, role.ToString())); + } + + ////Get Roles from resource_access + //if (claimsIdentity.Claims.Where(x => x.Type == "resource_access").FirstOrDefault() != null) + //{ + // var resourceroles = JsonConvert.DeserializeObject>(claimsIdentity.Claims.Where(x => x.Type == "resource_access").FirstOrDefault().Value); + + // if(resourceroles != null && resourceroles.Where(x => x.Key == client).Count() > 0) + // { + // foreach (var resourcerole in resourceroles.Where(x => x.Key == client).FirstOrDefault().Value.roles) + // { + // //add only if role is not present + // if (!principal.IsInRole(resourcerole)) + // claimsIdentity.AddClaim(new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", resourcerole)); + // } + // } + //} + } + } + } + } + public class Resource_Roles + { + public List roles { get; set; } + } + +} diff --git a/Helper/JsonHelpers/ContractResolvers.cs b/Helper/JsonHelpers/ContractResolvers.cs new file mode 100644 index 0000000..547e399 --- /dev/null +++ b/Helper/JsonHelpers/ContractResolvers.cs @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel.Annotations; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Helper.JsonHelpers +{ + public class GetOnlyContractResolver : DefaultContractResolver + { + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var property = base.CreateProperty(member, memberSerialization); + + if (property != null && property.Readable && property.AttributeProvider != null) + { + var attributes = property.AttributeProvider.GetAttributes(typeof(GetOnlyJsonPropertyAttribute), true); + if (attributes != null && attributes.Count > 0) + property.Readable = false; + } + return property; + } + } +} diff --git a/Helper/JsonPathException.cs b/Helper/JsonPathException.cs new file mode 100644 index 0000000..43db4a3 --- /dev/null +++ b/Helper/JsonPathException.cs @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Runtime.Serialization; + +namespace Helper +{ + [Serializable] + public class JsonPathException : Exception + { + public string Path { get; } = ""; + + public JsonPathException() + { + } + + public JsonPathException(string? message, string path) : base(message) + { + Path = path; + } + + public JsonPathException(string? message, string path, Exception? innerException) : base(message, innerException) + { + Path = path; + } + + protected JsonPathException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/Helper/JsonTransformer/JsonTransformer.cs b/Helper/JsonTransformer/JsonTransformer.cs new file mode 100644 index 0000000..12c5f49 --- /dev/null +++ b/Helper/JsonTransformer/JsonTransformer.cs @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Newtonsoft.Json.Linq; +using System; +using System.Linq; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; +using System.Diagnostics.CodeAnalysis; +using DataModel; + +namespace Helper +{ + public static class JsonTransformer + { + public static JsonRaw? TransformRawData( + this JsonRaw raw, string? language, string[] fields, + bool filteroutNullValues, Func urlGenerator, IEnumerable? fieldstohide) + { + JToken? token = JToken.Parse(raw.Value); + //Filter out not desired langugae fields + if (language != null) token = JsonTransformerMethods.FilterByLanguage(token, language); + //Filter by given fields + if (fields != null && fields.Length > 0) token = JsonTransformerMethods.FilterByFields(token, fields, language); + // Filter out all data where the LicenseInfo does not contain `CC0` + // Show all images + //if (checkCC0) token = JsonTransformerMethods.FilterImagesByCC0License(token); + // Filter out all data where the LicenseInfo contains `hgv` as source. + //if (filterClosedData) token = JsonTransformerMethods.FilterAccoRoomInfoByHGVSource(token); + //Filter out all Data + //var rolefilter = FilterOutPropertiesByRole(userroles); + //if (rolefilter.Count > 0) + // if (checkCC0) token = JsonTransformerMethods.FilterOutProperties(token, rolefilter); + + if (fieldstohide != null && fieldstohide.Count() > 0) + token = JsonTransformerMethods.FilterOutProperties(token, fieldstohide.ToList()); + + //if (filterClosedData) token = token.FilterClosedData(); + + //Ensure Self Link is the right url + token = token.TransformSelfLink(urlGenerator); + + if(filteroutNullValues) token = JsonTransformerMethods.FilterOutNullProperties(token); + + //Filter out meta info + //token = token.FilterMetaInformations(); + + return (token == null) ? + null : + new JsonRaw(token.ToString(Formatting.Indented)); + } + + public static List FilterOutPropertiesByRole(IEnumerable userroles) + { + if (userroles.Contains("IDM")) + return new List() { }; + + return new List() { "TVMember", "Beds", "Units", "RepresentationRestriction", "TrustYouID", "TrustYouScore", "TrustYouState", "TrustYouResults", "TrustYouActive" }; + } + } + + sealed class DistinctComparer + : IEqualityComparer<(string name, string path)> + { + public bool Equals([AllowNull] (string name, string path) x, [AllowNull] (string name, string path) y) => + x.name == y.name; + + public int GetHashCode([DisallowNull] (string name, string path) obj) => + obj.name.GetHashCode(); + } + +} diff --git a/Helper/JsonTransformer/JsonTransformerMethods.cs b/Helper/JsonTransformer/JsonTransformerMethods.cs new file mode 100644 index 0000000..d1296f1 --- /dev/null +++ b/Helper/JsonTransformer/JsonTransformerMethods.cs @@ -0,0 +1,374 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public static class JsonTransformerMethods + { + private static readonly HashSet Languages = new HashSet { + "de", "it", "en", "cs", "fr", "nl", "pl", "ru", "ld" + }; + + private static bool IsLanguageKey(string key) => + Languages.Contains(key); + + //Cutting out all not requested Language Dictionary Objects + public static JToken? FilterByLanguage(this JToken? token, string language) + { + if (token == null) + return null; + JToken Walk(JToken token) => + token switch + { + JObject obj => + new JObject( + obj.Properties() + .Where(x => + // Check if property name is a language identifier + // and if it is the same as the provided language argument + !(IsLanguageKey(x.Name) && x.Name != language)) + .Select(Walk)), + JProperty prop => + new JProperty(prop.Name, Walk(prop.Value)), + JArray arr => + new JArray(arr.Select(Walk)), + _ => token + }; + return Walk(token); + } + + //Cutting out all images where the License is not CC0 + public static JToken? FilterImagesByCC0License(this JToken? token) + { + if (token == null) + return null; + static JObject? TransformObj(JObject obj) + { + // Get the License property of an object + var licenseProp = obj.Property("License"); + // If License property exists and it's value isn't CC0 return null, + // which filters away the whole object + return licenseProp != null && (licenseProp.Value == null || (!licenseProp.Value.Equals(new JValue("CC0")) && !licenseProp.Path.StartsWith("LicenseInfo"))) ? + null : + new JObject(obj.Properties().Select(x => Walk(x)).Where(x => x != null)); + }; + static JProperty? TransformProp(JProperty prop) + { + var value = Walk(prop.Value); + return value == null ? null : new JProperty(prop.Name, value); + } + static JToken? Walk(JToken token) => + token switch + { + JObject obj => + TransformObj(obj), + JProperty prop => + TransformProp(prop), + JArray arr => + new JArray( + arr.Select(x => Walk(x)) + // Filter away empty content + .Where(x => x != null)), + _ => token + }; + return Walk(token); + } + + //Cutting out all Rooms where Source is not HGV + public static JToken? FilterAccoRoomInfoByHGVSource(this JToken? token) + { + if (token == null) + return null; + static JObject? TransformObj(JObject obj) + { + // Get the AccoRoomInfo property of an object which has to be an array + var accoRoomInfo = obj.Property("AccoRoomInfo"); + if (accoRoomInfo is not null && accoRoomInfo.Value is JArray) + { + var props = accoRoomInfo.Value.ToArray().Select(prop => + { + // The prop needs to be an object + if (prop is JObject roomInfo) + { + // Get the Source property of an object + var sourceProp = roomInfo.Property("Source"); + // If Source property exists and it's value is hgv return null, + // which filters away the whole object + return sourceProp is not null && (sourceProp.Value is null || sourceProp.Value.Equals(new JValue("hgv"))) ? + null : + new JObject(roomInfo.Properties().Select(x => Walk(x)).Where(x => x != null)); + } + else + { + return prop; + } + }).Where(prop => prop is not null); + obj.TryAddOrUpdate("AccoRoomInfo", new JArray(props)); + return obj; + } + else + { + return obj; + } + }; + static JProperty? TransformProp(JProperty prop) + { + var value = Walk(prop.Value); + return value == null ? null : new JProperty(prop.Name, value); + } + static JToken? Walk(JToken token) => + token switch + { + JObject obj => + TransformObj(obj), + JProperty prop => + TransformProp(prop), + JArray arr => + new JArray( + arr.Select(x => Walk(x)) + // Filter away empty content + .Where(x => x != null)), + _ => token + }; + return Walk(token); + } + + //Cutting out Property passed by List + public static JToken? FilterOutProperties(this JToken? token, List propstocut) + { + if (token == null) + return null; + + static JObject TransformByPropList(JObject obj, List propstocut) + { + // Get the TVMember property of an object which has to be an property + //var accoTVMember = obj.Property("TVMember"); + //if (accoTVMember is not null && accoTVMember is JProperty) + // //Cut out this property + // return new JObject(obj.Properties().Where(x => !propstocut.Contains(x.Name))); + //else + // return obj; + return new JObject(obj.Properties().Where(x => !propstocut.Contains(x.Name))); + } + static JToken Walk(JToken token, List propstocut) => + token switch + { + JObject obj => TransformByPropList(obj, propstocut), + _ => token + }; + + return Walk(token, propstocut); + } + + //Cutting out all properties with null + public static JToken? FilterOutNullProperties(this JToken? token) + { + if (token == null) + return null; + + static JObject RemoveNullProps(JObject obj) + { + return new JObject( + obj.Properties() + .Where(x => !x.Value.IsNullOrEmpty(true, true)) + .Select(x => new JProperty(x.Name, FilterOutNullProperties(x.Value))) + ); + } + static JToken Walk(JToken token) => + token switch + { + JObject obj => RemoveNullProps(obj), + JArray objs => new JArray(objs.Select(FilterOutNullProperties)), + //JProperty prop => new JProperty(prop.Name, Walk(prop.Value)), + _ => token + }; + + return Walk(token); + } + + //Cutting out Property _Meta + public static JToken? FilterMetaInformations(this JToken? token) + { + if (token == null) + return null; + static JObject TransformMetaObj(JObject obj) => + new JObject(obj.Properties().Where(x => x.Name != "_Meta")); + static JToken Walk(JToken token) => + token switch + { + JObject obj => TransformMetaObj(obj), + _ => token + }; + return Walk(token); + } + + //Cutting out all Properties where Meta Contains the information Closeddata is true + public static JToken? FilterClosedData(this JToken? token) + { + if (token == null) + return null; + static JObject? TransformObj(JObject obj) + { + // Get the Metadata property + var metaProp = obj.Property("_Meta"); + if (metaProp != null && metaProp.Value is JObject metaObj) + { + // Get the ClosedData property of an object + var closedDataProp = metaObj.Property("ClosedData"); + // If ClosedData property exists and it's value is true, + // which filters away the whole object + if (closedDataProp != null && closedDataProp.Value.Equals(new JValue(true))) + { + return null; + } + } + return new JObject(obj.Properties().Select(x => Walk(x))); + }; + static JProperty? TransformProp(JProperty prop) + { + var value = Walk(prop.Value); + return value == null ? null : new JProperty(prop.Name, value); + } + static JToken? Walk(JToken token) => + token switch + { + JObject obj => + TransformObj(obj), + JProperty prop => + TransformProp(prop), + JArray arr => + new JArray( + arr.Select(x => Walk(x)) + // Filter away empty content + .Where(x => x != null)), + _ => token + }; + return Walk(token); + } + + //Cuts out all fields that are not requested only Id is active by default + public static JToken? FilterByFields(this JToken? token, string[] fieldsFromQueryString, string? languageParam) + { + if (token == null) + return null; + var language = languageParam ?? "en"; + var fields = new List<(string name, string path)> + { + ("Id", "Id") + }; + fields.AddRange(fieldsFromQueryString.Select(field => (field, field))); + if (token is JObject obj) + { + return new JObject( + fields.Distinct(new DistinctComparer()).Select(x => + { + try + { + try + { + return new JProperty(x.name, token.SelectToken(x.path, errorWhenNoMatch: true)); + } + catch (JsonException) + { + return new JProperty(x.name, token.SelectTokens(x.path, errorWhenNoMatch: true)); + } + } + catch (JsonException) + { + return new JProperty(x.name, (object?)null); + } + }) + ); + } + return token; + } + + //Transforms URL of the self link to the right domain + public static JToken? TransformSelfLink(this JToken? token, Func urlGenerator) + { + if (token == null) + return null; + static JObject? TransformObj(JObject obj, Func urlGenerator) => + new JObject(obj.Properties().Select(x => Walk(x, urlGenerator))); + static string? TransformSelf(string? self, Func urlGenerator) + { + if (self == null) + return null; + // FIXME: Temporary workaround + if (self.StartsWith("https://tourism.opendatahub.bz.it/api/")) + self = self.Substring(38); + if (self.StartsWith("https://tourism.opendatahub.com/api/")) + self = self.Substring(36); + return urlGenerator(self); + } + static JProperty? TransformProp(JProperty prop, Func urlGenerator) + { + if (prop.Name == "Self") + { + string? value = TransformSelf(prop.Value.Value(), urlGenerator); + return new JProperty(prop.Name, value); + } + //Temporary Remove + //if (prop.Name == "ApiUrl") + //{ + // string? value = TransformSelf(prop.Value.Value(), urlGenerator); + // return new JProperty(prop.Name, value); + //} + else + { + var value = Walk(prop.Value, urlGenerator); + return value == null ? null : new JProperty(prop.Name, value); + } + } + static JToken? Walk(JToken token, Func urlGenerator) => + token switch + { + JObject obj => + TransformObj(obj, urlGenerator), + JProperty prop => + TransformProp(prop, urlGenerator), + JArray arr => + new JArray( + arr.Select(x => Walk(x, urlGenerator)) + // Filter away empty content + .Where(x => x != null)), + _ => token + }; + return Walk(token, urlGenerator); + } + + } + + public static class JsonExtensions + { + public static bool IsNullOrEmpty(this JToken token, bool filteremptyarrays, bool filteremptyobjects) + { + bool result = false; + + result = (token == null) || + (token.Type == JTokenType.String && token.ToString() == String.Empty) || + (token.Type == JTokenType.Null); + + if (filteremptyarrays) + result = result || (token == null) || + (token.Type == JTokenType.Array && !token.HasValues); //filter out empty array + + if (filteremptyobjects) + result = result || (token == null) || + (token.Type == JTokenType.Object && !token.HasValues); //filter out empty object + + //(token.Type == JTokenType.Undefined) || //not sure if needed + + return result; + } + } +} diff --git a/Helper/Models/ConfigSettingsModels.cs b/Helper/Models/ConfigSettingsModels.cs new file mode 100644 index 0000000..7d85380 --- /dev/null +++ b/Helper/Models/ConfigSettingsModels.cs @@ -0,0 +1,435 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Policy; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public interface ISettings + { + string PostgresConnectionString { get; } + XmlConfig XmlConfig { get; } + JsonConfig JsonConfig { get; } + S3ImageresizerConfig S3ImageresizerConfig { get; } + PushServerConfig PushServerConfig { get; } + //FCMConfig FCMConfig { get; } + List Field2HideConfig { get; } + List RequestInterceptorConfig { get; } + List RateLimitConfig { get; } + NoRateLimitConfig NoRateLimitConfig { get; } + List FCMConfig { get; } + List NotifierConfig { get; } + } + + //Classes for Settings shared between Projects + + public class XmlConfig + { + public XmlConfig(string xmldir, string xmldirweather) + { + this.Xmldir = xmldir; + this.XmldirWeather = xmldirweather; + } + + public string Xmldir { get; private set; } + public string XmldirWeather { get; private set; } + } + + public class JsonConfig + { + public JsonConfig(string jsondir) + { + this.Jsondir = jsondir; + } + + public string Jsondir { get; private set; } + } + + public class S3ImageresizerConfig + { + public S3ImageresizerConfig(string url, string docurl, string bucketaccesspoint, string accesskey, string secretkey) + { + this.Url = url; + this.DocUrl = docurl; + this.BucketAccessPoint = bucketaccesspoint; + this.AccessKey = accesskey; + this.SecretKey = secretkey; + } + + public string Url { get; private set; } + public string DocUrl { get; private set; } + public string BucketAccessPoint { get; private set; } + public string AccessKey { get; private set; } + public string SecretKey { get; private set; } + } + + public class Field2HideConfig + { + public Field2HideConfig(string entity, string fields, string validforroles) + { + this.Entity = entity; + this.DisplayOnRoles = validforroles != null ? validforroles.Split(',').ToList() : null; + this.Fields = fields != null ? fields.Split(',').ToList() : null; + } + + public string Entity { get; private set; } + public List? Fields { get; private set; } + public List? DisplayOnRoles { get; private set; } + } + + public class RequestInterceptorConfig + { + public RequestInterceptorConfig(string action, string controller, string querystrings, string redirectaction, string redirectcontroller, string redirectquerystrings) + { + this.Action = action; + this.Controller = controller; + this.QueryStrings = querystrings != null ? querystrings.Split('&').ToList() : null; + this.RedirectAction = redirectaction; + this.RedirectController = redirectcontroller; + this.RedirectQueryStrings = redirectquerystrings != null ? redirectquerystrings.Split('&').ToList() : null; + } + + public string Action { get; private set; } + public string Controller { get; private set; } + public List? QueryStrings { get; private set; } + public string RedirectAction { get; private set; } + public string RedirectController { get; private set; } + public List? RedirectQueryStrings { get; private set; } + } + + public class PushServerConfig + { + public PushServerConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class FCMConfig + { + public FCMConfig(string identifier, string serverkey, string senderid, string projectname, string serviceaccount, string serviceaccountjson) + { + this.Identifier = identifier; + this.ServerKey = serverkey; + this.SenderId = senderid; + this.ProjecTName = projectname; + this.ServiceAccount = serviceaccount; + this.ServiceAccountJson = serviceaccountjson; + } + + public string Identifier { get; private set; } + public string ServerKey { get; private set; } + public string SenderId { get; private set; } + public string ProjecTName { get; private set; } + public string ServiceAccount { get; private set; } + public string ServiceAccountJson { get; private set; } + } + + public class RateLimitConfig + { + public RateLimitConfig(string type, int timewindow, int maxrequests) + { + this.Type = type; + this.TimeWindow = timewindow; + this.MaxRequests = maxrequests; + } + + public string Type { get; private set; } + public int TimeWindow { get; private set; } + public int MaxRequests { get; private set; } + } + + public class NoRateLimitConfig + { + public NoRateLimitConfig(List noratelimitroutes, List noratelimitrefers) + { + NoRateLimitRoutes = noratelimitroutes; + NoRateLimitReferer = noratelimitrefers; + } + public List NoRateLimitRoutes { get; private set; } + public List NoRateLimitReferer { get; private set; } + } + + public class NotifierConfig + { + public NotifierConfig(string servicename, string url, string user, string pswd) + { + this.ServiceName = servicename; + this.Url = url; + this.User = user; + this.Password = pswd; + } + + public string ServiceName { get; private set; } + public string Url { get; private set; } + public string User { get; private set; } + public string Password { get; private set; } + } + + #region Data Importer Config + + public class MssConfig + { + public MssConfig(string username, string password, string serviceurl) + { + this.Username = username; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string Username { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class LcsConfig + { + public LcsConfig(string username, string password, string messagepassword, string serviceurl) + { + this.Username = username; + this.Password = password; + this.MessagePassword = messagepassword; + this.ServiceUrl = serviceurl; + } + + public string Username { get; private set; } + public string Password { get; private set; } + public string MessagePassword { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class CDBConfig + { + public CDBConfig(string username, string password, string serviceurl) + { + this.Username = username; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string Username { get; private set; } + public string Password { get; private set; } + + public string ServiceUrl { get; private set; } + } + + public class SiagConfig + { + public SiagConfig(string username, string password, string serviceurl) + { + this.Username = username; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string Username { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class SuedtirolWeinConfig + { + public SuedtirolWeinConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class MusportConfig + { + public MusportConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class EBMSConfig + { + public EBMSConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class RavenConfig + { + public RavenConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class DSSConfig + { + public DSSConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class A22Config + { + public A22Config(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class FeratelConfig + { + public FeratelConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class PanocloudConfig + { + public PanocloudConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class PanomaxConfig + { + public PanomaxConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class NinjaConfig + { + public NinjaConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class LoopTecConfig + { + public LoopTecConfig(string user, string password, string serviceurl) + { + this.User = user; + this.Password = password; + this.ServiceUrl = serviceurl; + } + + public string User { get; private set; } + public string Password { get; private set; } + public string ServiceUrl { get; private set; } + } + + public class S3Config + { + public S3Config(string accesskey, string secretkey, string bucket, string filename) + { + this.AccessKey = accesskey; + this.AccessSecretKey = secretkey; + this.Bucket = bucket; + this.Filename = filename; + } + + public string AccessKey { get; private set; } + public string AccessSecretKey { get; private set; } + public string Bucket { get; private set; } + public string Filename { get; private set; } + } + + #endregion + + + public class NotifyMeta + { + public string Id { get; set; } + public string Url { get; set; } + public string Type { get; set; } + public string NotifyType { get; set; } + public string Mode { get; set; } + public bool HasImagechanged { get; set; } + public bool? Roomschanged { get; set; } + public bool IsDelete { get; set; } + public string Destination { get; set; } + public string UdateMode { get; set; } + public string Origin { get; set; } + public string? Referer { get; set; } + public IDictionary Headers { get; set; } + public IDictionary Parameters { get; set; } + public List ValidTypes { get; set; } + } + + +} diff --git a/Helper/Models/HttpRequestLog.cs b/Helper/Models/HttpRequestLog.cs new file mode 100644 index 0000000..792fa51 --- /dev/null +++ b/Helper/Models/HttpRequestLog.cs @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public struct HttpRequestLog + { + public string username { get; init; } + public string referer { get; init; } + public string origin { get; init; } + public string host { get; init; } + public string path { get; init; } + public string schema { get; init; } + public string method { get; init; } + //public Dictionary? querystring { get; set; } + public string urlparams { get; init; } + public string useragent { get; init; } + public string? ipaddress { get; init; } + public int? statuscode { get; init; } + public long? elapsedtime { get; init; } + public string? appliedquota { get; set; } + + //used for debugging + public string? ratelimitkey { get; set; } + } +} diff --git a/Helper/Models/ImportLog.cs b/Helper/Models/ImportLog.cs new file mode 100644 index 0000000..ba04099 --- /dev/null +++ b/Helper/Models/ImportLog.cs @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public struct ImportLog + { + public string sourceinterface { get; init; } + public bool success { get; init; } + public string sourceid { get; init; } + public string error { get; init; } + } +} diff --git a/Helper/Models/LogOutput.cs b/Helper/Models/LogOutput.cs new file mode 100644 index 0000000..eac0262 --- /dev/null +++ b/Helper/Models/LogOutput.cs @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public struct LogOutput + { + public string log { get; init; } + public string type { get; init; } + public string id { get; init; } + public T output { get; init; } + } +} diff --git a/Helper/Models/WriteLog.cs b/Helper/Models/WriteLog.cs new file mode 100644 index 0000000..72d2484 --- /dev/null +++ b/Helper/Models/WriteLog.cs @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public static class WriteLog + { + /// + /// Writes Log to Console + /// + /// HttpRequestLog / ImportLog ... + /// + /// Type of the Log (HttpRequest, ImportData etc...) + /// Additional Info (apiaccess, dataimport) + /// HttpRequestLog / ImportLog + public static void LogToConsole(string id, string type, string log, T output) + { + LogOutput logoutput = new LogOutput() { id = id, type = type, log = log, output = output }; + Console.WriteLine(JsonConvert.SerializeObject(logoutput)); + } + + + } +} diff --git a/Helper/Postgres/PostGresSQLHelper.cs b/Helper/Postgres/PostGresSQLHelper.cs new file mode 100644 index 0000000..ea19fa8 --- /dev/null +++ b/Helper/Postgres/PostGresSQLHelper.cs @@ -0,0 +1,327 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Npgsql; +using SqlKata; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Globalization; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Helper +{ + public static class PostgresSQLHelper + { + #region Geo Helpers + + //For Activities Pois and Smgpois + + public static string GetGeoWhereSimple(double latitude, double longitude, int radius) + { + return $"earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}),ll_to_earth((data#>>'\\{{Latitude\\}}')::double precision, (data#>>'\\{{Longitude\\}}')::double precision)) < {radius.ToString()}"; + } + + //public static string GetGeoWhereSimple(string latitude, string longitude, string radius) + //{ + // return "earth_distance(ll_to_earth(" + latitude + ", " + longitude + "),ll_to_earth((data->>'Latitude')::double precision, (data->>'Longitude')::double precision)) < " + radius; + //} + + public static string GetGeoOrderBySimple(double latitude, double longitude) + { + return $"earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}),ll_to_earth((data#>>'\\{{Latitude\\}}')::double precision, (data#>>'\\{{Longitude\\}}')::double precision))"; + } + + //public static string GetGeoOrderBySimple(string latitude, string longitude) + //{ + // return "earth_distance(ll_to_earth(" + latitude + ", " + longitude + "),ll_to_earth((data->>'Latitude')::double precision, (data->>'Longitude')::double precision))"; + //} + + public static string GetGeoWhereExtended(double latitude, double longitude, int radius) + { + return $"earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}),ll_to_earth((data#>>'\\{{GpsPoints,position,Latitude\\}}')::double precision, (data#>>'\\{{GpsPoints,position,Longitude\\}}')::double precision)) < {radius.ToString()}"; + } + + public static string GetGeoWhereExtendedGpsInfo(double latitude, double longitude, int radius) + { + return $"earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}),ll_to_earth((data#>>'\\{{GpsInfo,0,Latitude\\}}')::double precision, (data#>>'\\{{GpsInfo,0,Longitude\\}}')::double precision)) < {radius.ToString()}"; + } + + //public static string GetGeoWhereExtended(string latitude, string longitude, string radius) + //{ + // return "earth_distance(ll_to_earth(" + latitude + ", " + longitude + "),ll_to_earth((data->'GpsPoints'->'position'->>'Latitude')::double precision, (data->'GpsPoints'->'position'->>'Longitude')::double precision)) < " + radius; + //} + + public static string GetGeoOrderByExtended(double latitude, double longitude) + { + return $"earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}),ll_to_earth((data#>>'\\{{GpsPoints,position,Latitude\\}}')::double precision, (data#>>'\\{{GpsPoints,position,Longitude\\}}')::double precision))"; + } + + public static string GetGeoOrderByExtended(string latitude, string longitude) + { + return $"earth_distance(ll_to_earth({latitude}, {longitude}),ll_to_earth((data->'GpsPoints'->'position'#>>'\\{{Latitude\\}}')::double precision, (data#>>'\\{{GpsPoints,position,Longitude\\}}')::double precision))"; + } + + public static string GetGeoWhereBoundingBoxes(string latitude, string longitude, string radius) + { + return $"earth_box(ll_to_earth({latitude}, {longitude}), {radius}) @> ll_to_earth((data#>>'\\{{Latitude\\}}')::double precision, (data#>>'\\{{Longitude\\}}')::double precision) and earth_distance(ll_to_earth({latitude}, {longitude}), ll_to_earth((data#>>'\\{{Latitude\\}}')::double precision, (data#>>'\\{{Longitude\\}}')::double precision)) < {radius}"; + } + + public static string GetGeoWhereBoundingBoxes(double latitude, double longitude, int radius) + { + return $"earth_box(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}), {radius.ToString()}) @> ll_to_earth((data#>>'\\{{Latitude\\}}')::double precision, (data#>>'\\{{Longitude\\}}')::double precision) and earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}), ll_to_earth((data#>>'\\{{Latitude\\}}')::double precision, (data#>>'\\{{Longitude\\}}')::double precision)) < {radius.ToString()}"; + } + + public static string GetGeoWhereBoundingBoxesExtended(string latitude, string longitude, string radius) + { + return $"earth_box(ll_to_earth({latitude}, {longitude}), {radius}) @> ll_to_earth((data#>>'\\{{GpsPoints,position,Latitude\\}}')::double precision, (data#>>'\\{{GpsPoints,position,Longitude\\}}')::double precision) and earth_distance(ll_to_earth({latitude}, {longitude}), ll_to_earth((data#>>'\\{{GpsPoints,position,Latitude\\}}')::double precision, (data#>>'\\{{GpsPoints,position,Longitude\\}}')::double precision)) < {radius}"; + } + + public static string GetGeoWhereBoundingBoxesExtended(double latitude, double longitude, int radius) + { + return $"earth_box(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}), {radius.ToString()}) @> ll_to_earth((data#>>'\\{{GpsPoints,position,Latitude\\}}')::double precision, (data#>>'\\{{GpsPoints,position,Longitude\\}}')::double precision) and earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}), ll_to_earth((data#>>'\\{{GpsPoints,position,Latitude\\}}')::double precision, (data#>>'\\{{GpsPoints,position,Longitude\\}}')::double precision)) < {radius.ToString()}"; + } + + //For Accommodations + public static void ApplyGeoSearchWhereOrderbySimple( + ref string where, ref string orderby, PGGeoSearchResult geosearchresult) + { + if (geosearchresult != null) + { + if (geosearchresult.geosearch) + { + if (!String.IsNullOrEmpty(where)) + where += " AND "; + + where += PostgresSQLHelper.GetGeoWhereSimple( + geosearchresult.latitude, + geosearchresult.longitude, + geosearchresult.radius); + orderby = PostgresSQLHelper.GetGeoOrderBySimple( + geosearchresult.latitude, + geosearchresult.longitude); + } + } + } + + public static Query GeoSearchFilterAndOrderby( + this Query query, + PGGeoSearchResult? geosearchresult) + { + if (geosearchresult == null || !geosearchresult.geosearch) + return query; + + return + query.WhereRaw( + GetGeoWhereExtended( + geosearchresult.latitude, + geosearchresult.longitude, + geosearchresult.radius) + ).OrderByRaw( + GetGeoOrderByExtended( + geosearchresult.latitude, + geosearchresult.longitude) + ); + } + + //For Activities Pois and GBActivityPoi + public static void ApplyGeoSearchWhereOrderby( + ref string where, + ref string orderby, + PGGeoSearchResult geosearchresult) + { + if (geosearchresult != null) + { + if (geosearchresult.geosearch) + { + if (!String.IsNullOrEmpty(where)) + where += " AND "; + + where += PostgresSQLHelper.GetGeoWhereExtended( + geosearchresult.latitude, + geosearchresult.longitude, + geosearchresult.radius); + orderby = PostgresSQLHelper.GetGeoOrderByExtended( + geosearchresult.latitude, + geosearchresult.longitude); + } + } + } + + #endregion + + #region Geo Helpers Generated Columns + + //For Activities Pois and Smgpois + + public static string GetGeoWhereSimple_GeneratedColumns(double latitude, double longitude, int radius) + { + return $"earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}),ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision)) < {radius.ToString()}"; + } + + public static string GetGeoWhereInPolygon_GeneratedColumns(string? wkt, List>? polygon, string srid, string? operation = null) + { + if (String.IsNullOrEmpty(wkt)) + return GetGeoWhereInPolygon_GeneratedColumns(polygon, srid, operation); + else + return GetGeoWhereInPolygon_GeneratedColumns(wkt, srid, operation); + } + + public static string GetGeoWhereInPolygon_GeneratedColumns(List> polygon, string srid = "4326", string? operation = "intersects") + { + if(srid != "4326") + return $"{GetPolygonOperator(operation)}(ST_GeometryFromText('POLYGON(({String.Join(",", polygon.Select(t => string.Format("{0} {1}", t.Item1.ToString(CultureInfo.InvariantCulture), t.Item2.ToString(CultureInfo.InvariantCulture))))}))', {srid}), ST_Transform(gen_position,{srid}))"; + else + return $"{GetPolygonOperator(operation)}(ST_GeometryFromText('POLYGON(({String.Join(",", polygon.Select(t => string.Format("{0} {1}", t.Item1.ToString(CultureInfo.InvariantCulture), t.Item2.ToString(CultureInfo.InvariantCulture))))}))', 4326), gen_position)"; + } + + public static string GetGeoWhereInPolygon_GeneratedColumns(string wkt, string srid = "4326", string? operation = "intersects") + { + if(srid != "4326") + return $"{GetPolygonOperator(operation)}(ST_GeometryFromText('{wkt}', {srid}), ST_Transform(gen_position,{srid}))"; + else + return $"{GetPolygonOperator(operation)}(ST_GeometryFromText('{wkt}', 4326), gen_position)"; + } + + public static string GetPolygonOperator(string? operation) => operation switch + { + "contains" => "ST_Contains", + "intersects" => "ST_Intersects", + _ => "ST_Contains" + }; + + + public static string GetGeoOrderBySimple_GeneratedColumns(double latitude, double longitude) + { + return $"earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}),ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision))"; + } + + public static string GetGeoWhereExtended_GeneratedColumns(double latitude, double longitude, int radius) + { + return $"earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}),ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision)) < {radius.ToString()}"; + } + + public static string GetGeoOrderByExtended_GeneratedColumns(double latitude, double longitude) + { + return $"earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}),ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision))"; + } + + public static string GetGeoOrderByExtended_GeneratedColumns(string latitude, string longitude) + { + return $"earth_distance(ll_to_earth({latitude}, {longitude}),ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision))"; + } + + public static string GetGeoWhereBoundingBoxes_GeneratedColumns(string latitude, string longitude, string radius) + { + return $"earth_box(ll_to_earth({latitude}, {longitude}), {radius}) @> ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision) and earth_distance(ll_to_earth({latitude}, {longitude}), ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision)) < {radius}"; + } + + public static string GetGeoWhereBoundingBoxes_GeneratedColumns(double latitude, double longitude, int radius) + { + return $"earth_box(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}), {radius.ToString()}) @> ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision) and earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}), ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision)) < {radius.ToString()}"; + } + + public static string GetGeoWhereBoundingBoxesExtended_GeneratedColumns(string latitude, string longitude, string radius) + { + return $"earth_box(ll_to_earth({latitude}, {longitude}), {radius}) @> ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision) and earth_distance(ll_to_earth({latitude}, {longitude}), ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision)) < {radius}"; + } + + public static string GetGeoWhereBoundingBoxesExtended_GeneratedColumns(double latitude, double longitude, int radius) + { + return $"earth_box(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}), {radius.ToString()}) @> ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision) and earth_distance(ll_to_earth({latitude.ToString(CultureInfo.InvariantCulture)}, {longitude.ToString(CultureInfo.InvariantCulture)}), ll_to_earth((gen_latitude)::double precision, (gen_longitude)::double precision)) < {radius.ToString()}"; + } + + //For Accommodations + public static void ApplyGeoSearchWhereOrderbySimple_GeneratedColumns( + ref string where, ref string orderby, PGGeoSearchResult geosearchresult) + { + if (geosearchresult != null) + { + if (geosearchresult.geosearch) + { + if (!String.IsNullOrEmpty(where)) + where += " AND "; + + where += PostgresSQLHelper.GetGeoWhereSimple_GeneratedColumns( + geosearchresult.latitude, + geosearchresult.longitude, + geosearchresult.radius); + orderby = PostgresSQLHelper.GetGeoOrderBySimple_GeneratedColumns( + geosearchresult.latitude, + geosearchresult.longitude); + } + } + } + + public static Query GeoSearchFilterAndOrderby_GeneratedColumns( + this Query query, + PGGeoSearchResult? geosearchresult) + { + if (geosearchresult == null || !geosearchresult.geosearch) + return query; + + return + query.WhereRaw( + GetGeoWhereExtended_GeneratedColumns( + geosearchresult.latitude, + geosearchresult.longitude, + geosearchresult.radius) + ).OrderByRaw( + GetGeoOrderByExtended_GeneratedColumns( + geosearchresult.latitude, + geosearchresult.longitude) + ); + } + + //For Activities Pois and GBActivityPoi + public static void ApplyGeoSearchWhereOrderby_GeneratedColumns( + ref string where, + ref string orderby, + PGGeoSearchResult geosearchresult) + { + if (geosearchresult != null) + { + if (geosearchresult.geosearch) + { + if (!String.IsNullOrEmpty(where)) + where += " AND "; + + where += PostgresSQLHelper.GetGeoWhereExtended_GeneratedColumns( + geosearchresult.latitude, + geosearchresult.longitude, + geosearchresult.radius); + orderby = PostgresSQLHelper.GetGeoOrderByExtended_GeneratedColumns( + geosearchresult.latitude, + geosearchresult.longitude); + } + } + } + + #endregion + + public static uint PGPagingHelper(uint totalcount, uint pagesize) + { + uint totalpages; + if (totalcount % pagesize == 0) + totalpages = totalcount / pagesize; + else + totalpages = (totalcount / pagesize) + 1; + + return totalpages; + } + + } + + public class PGParameters + { + public string? Name { get; set; } + public NpgsqlTypes.NpgsqlDbType Type { get; set; } + public string? Value { get; set; } + } +} diff --git a/Helper/Postgres/PostGresSQLHelperException.cs b/Helper/Postgres/PostGresSQLHelperException.cs new file mode 100644 index 0000000..48ea68b --- /dev/null +++ b/Helper/Postgres/PostGresSQLHelperException.cs @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Runtime.Serialization; + +namespace Helper +{ + public class PostGresSQLHelperException : Exception + { + public PostGresSQLHelperException() + { + } + + public PostGresSQLHelperException(string message) : base(message) + { + } + + public PostGresSQLHelperException(Exception innerException) : base("Error executing SQL query.", innerException) + { + } + + public PostGresSQLHelperException(string message, Exception innerException) : base(message, innerException) + { + } + + protected PostGresSQLHelperException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/Helper/Postgres/PostgresSQLOrderByBuilder.cs b/Helper/Postgres/PostgresSQLOrderByBuilder.cs new file mode 100644 index 0000000..0aaa495 --- /dev/null +++ b/Helper/Postgres/PostgresSQLOrderByBuilder.cs @@ -0,0 +1,125 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using SqlKata; +using System.Runtime.CompilerServices; + +namespace Helper +{ + public static class PostgresSQLOrderByBuilder + { + /// + /// Build Orderby with Seed, if a seed "null" is passed an orderby query with sortfield and direction will be created + /// + /// + /// + /// + /// + /// + public static void BuildSeedOrderBy(ref string orderby, ref string? seed, string sortifseednull) + { + //string? myseed = seed; + + if (seed != null) + { + seed = Helper.CreateSeed.GetSeed(seed); + orderby = $"md5(id || '{seed}')"; + } + else + { + orderby = sortifseednull; + } + } + + public static Query OrderBySeed(this Query query, ref string? seed, string sortifseednull) + { + string orderby = ""; + BuildSeedOrderBy(ref orderby, ref seed, sortifseednull); + return query.OrderByRaw(orderby); + } + + public static Query OrderByRawIfNotNull(this Query query, string? rawsort) + { + if (!string.IsNullOrEmpty(rawsort)) + { + var splitted = rawsort.Split(","); + + var returnvalue = ""; + + foreach(var split in splitted) + { + string direction = "ASC"; + if (split.StartsWith("-")) + direction = "DESC"; + + returnvalue = returnvalue + "\"" + split.Replace("-", "").Replace("[", "\\[").Replace("]", "\\]") + "\" " + direction + ","; + } + + returnvalue = returnvalue.Substring(0, returnvalue.Length -1); + + return query.OrderByRaw(returnvalue); + } + else + return query; + } + + public static Query OrderOnlyByRawSortIfNotNull(this Query query, string? rawsort) + { + if (!string.IsNullOrEmpty(rawsort)) + return query.OrderByRaw(RawQueryParser.Transformer.TransformSort(rawsort)); + else + return query; + } + + public static Query ApplyOrdering(this Query query, ref string? seed, PGGeoSearchResult geosearchresult, string? rawsort, string? overwritestandardorder = null) => + (geosearchresult, rawsort) switch + { + (PGGeoSearchResult geosr, _) when geosr.geosearch => + query.GeoSearchFilterAndOrderby(geosr), + (_, string raw) => + query.OrderByRaw(RawQueryParser.Transformer.TransformSort(raw)), + _ => + query.OrderBySeed(ref seed, overwritestandardorder != null ? overwritestandardorder : "data#>>'\\{Shortname\\}' ASC") + }; + + public static Query ApplyOrdering_GeneratedColumns(this Query query, ref string? seed, PGGeoSearchResult geosearchresult, string? rawsort, string? overwritestandardorder = null) => + (geosearchresult, rawsort) switch + { + (PGGeoSearchResult geosr, _) when geosr.geosearch => + query.GeoSearchFilterAndOrderby_GeneratedColumns(geosr), + (_, string raw) => + query.OrderByRaw(RawQueryParser.Transformer.TransformSort(raw)), + _ => + query.OrderBySeed(ref seed, overwritestandardorder != null ? overwritestandardorder : "gen_shortname ASC") + }; + + public static Query ApplyOrdering(this Query query, PGGeoSearchResult geosearchresult, string? rawsort, string? overwritestandardorder = null) => + (geosearchresult, rawsort) switch + { + (PGGeoSearchResult geosr, _) when geosr.geosearch => + query.GeoSearchFilterAndOrderby(geosr), + (_, string raw) => + query.OrderByRaw(RawQueryParser.Transformer.TransformSort(raw)), + _ => + query.OrderByRaw(overwritestandardorder != null ? overwritestandardorder : "data#>>'\\{Shortname\\}' ASC") + }; + + public static Query ApplyOrdering_GeneratedColumns(this Query query, PGGeoSearchResult geosearchresult, string? rawsort, string? overwritestandardorder = null) => + (geosearchresult, rawsort) switch + { + (PGGeoSearchResult geosr, _) when geosr.geosearch => + query.GeoSearchFilterAndOrderby_GeneratedColumns(geosr), + (_, string raw) => + query.OrderByRaw(RawQueryParser.Transformer.TransformSort(raw)), + _ => + query.OrderByRaw(overwritestandardorder != null ? overwritestandardorder : "data#>>'\\{Shortname\\}' ASC") + }; + + public static Query ApplyRawFilter(this Query query, string? rawFilter) + { + static string jsonSerializer(object value) => Newtonsoft.Json.JsonConvert.SerializeObject(value); + return rawFilter != null ? query.WhereRaw(RawQueryParser.Transformer.TransformFilter(jsonSerializer, rawFilter)) : query; + } + } +} diff --git a/Helper/Postgres/PostgresSQLQueryExtensions.cs b/Helper/Postgres/PostgresSQLQueryExtensions.cs new file mode 100644 index 0000000..4425995 --- /dev/null +++ b/Helper/Postgres/PostgresSQLQueryExtensions.cs @@ -0,0 +1,1843 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Newtonsoft.Json; +using SqlKata; +using SqlKata.Execution; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; + +namespace Helper +{ + public static class PostgresSQLQueryExtensions + { + /// + /// Convert a (simple) JsonPath path to a Postgres array, + /// which can be used in the #>> operator.
+ /// E.g. Detail.de.Title => Detail,de,Title + ///
+ public static string JsonPathToPostgresArray(string field) => + field.Replace('.', ','); + + public static Query WhereJsonb( + this Query query, + string jsonPath, + string comparisonOperator, + string value) => + query.WhereRaw( + $"data#>>'\\{{{JsonPathToPostgresArray(jsonPath)}\\}}' {comparisonOperator} $$", + value + ); + + public static Query WhereJsonb( + this Query query, + string jsonPath, + string value) => + query.WhereJsonb(jsonPath, "=", value); + + public static Query WhereJsonb( + this Query query, + string jsonPath, + int value) => + query.WhereRaw( + $"data#>>'\\{{{JsonPathToPostgresArray(jsonPath)}\\}}' = $$", + value.ToString() + ); + + public static Query WhereJsonb( + this Query query, + string jsonPath, + bool value) => + query.WhereRaw( + $"data#>>'\\{{{JsonPathToPostgresArray(jsonPath)}\\}}' = $$", + value ? "true" : "false" + ); + + public static Query OrWhereJsonb( + this Query query, + string jsonPath, + string value) => + query.OrWhereRaw( + $"data#>>'\\{{{JsonPathToPostgresArray(jsonPath)}\\}}' = $$", + value + ); + + public static Query OrWhereJsonb( + this Query query, + string jsonPath, + int value) => + query.OrWhereRaw( + $"data#>>'\\{{{JsonPathToPostgresArray(jsonPath)}\\}}' = $$", + value.ToString() + ); + + public static Query OrWhereJsonb( + this Query query, + string jsonPath, + bool value) => + query.OrWhereRaw( + $"data#>>'\\{{{JsonPathToPostgresArray(jsonPath)}\\}}' = $$", + value ? "true" : "false" + ); + + [Obsolete] + public static Query WhereJsonb( + this Query query, + T value, + Func jsonObjectConstructor) => + query.WhereRaw( + "data @> jsonb($$)", + JsonConvert.SerializeObject( + jsonObjectConstructor(value) + ) + ); + + //[Obsolete] + public static Query OrWhereJsonb( + this Query query, + T value, + Func jsonObjectConstructor) => + query.OrWhereRaw( + "data @> jsonb($$)", + JsonConvert.SerializeObject( + jsonObjectConstructor(value) + ) + ); + + //[Obsolete] + //https://github.com/sqlkata/querybuilder/issues/356 + public static Query WhereInJsonb( + this Query query, + IReadOnlyCollection list, + Func jsonObjectConstructor) => + query.Where(q => + { + foreach (var item in list) + { + q = q.OrWhereJsonb( + value: item, + jsonObjectConstructor + ); + } + return q; + }); + + public static Query WhereInJsonb( + this Query query, + IReadOnlyCollection list, + string jsonPath, + Func jsonObjectConstructor) => + query.Where(q => + { + foreach (var item in list) + { + q = q.OrWhereJsonb( + jsonPath, + jsonObjectConstructor(item) + ); + } + return q; + }); + + public static Query WhereInJsonb( + this Query query, + IReadOnlyCollection list, + string jsonPath) + { + if (list.Count == 0) + { + return query; + } + else + { + return query.WhereRaw( + $"data#>>'\\{{{JsonPathToPostgresArray(jsonPath)}\\}}' = ANY($$)", + new[] { new[] { list } } + ); + } + } + + [Obsolete] + public static Query WhereAllInJsonb( + this Query query, + IReadOnlyCollection list, + Func jsonObjectConstructor) => + query.Where(q => + { + foreach (var item in list) + { + q = q.WhereJsonb( + value: item, + jsonObjectConstructor + ); + } + return q; + }); + + public static Query DistrictFilter(this Query query, IReadOnlyCollection districtlist) => + query.WhereInJsonb( + list: districtlist, + "DistrictId", + id => id.ToUpper() + ); + + public static Query IdUpperFilter(this Query query, IReadOnlyCollection idlist) => + query.Where(q => + { + foreach (var id in idlist) + { + q = q.OrWhere("id", "=", id.ToUpper()); + } + return q; + }); + + public static Query IdLowerFilter(this Query query, IReadOnlyCollection idlist) => + query.Where(q => + { + foreach (var id in idlist) + { + q = q.OrWhere("id", "=", id.ToLower()); + } + return q; + }); + + public static Query IdIlikeFilter(this Query query, IReadOnlyCollection idlist) => + query.Where(q => + { + foreach (var id in idlist) + { + q = q.OrWhere("id", "ILIKE", id); + } + return q; + }); + + public static Query LastChangedFilter(this Query query, string? updatefrom) => + query.When( + updatefrom != null, + query => query.WhereRaw( + "to_date(data#>>'\\{LastChange\\}', 'YYYY-MM-DD') > date($$)", + updatefrom + ) + ); + + public static Query LocFilterDistrictFilter(this Query query, IReadOnlyCollection districtlist) => + query.WhereInJsonb( + list: districtlist, + jsonPath: "LocationInfo.DistrictInfo.Id" + ); + + public static Query LocFilterMunicipalityFilter(this Query query, IReadOnlyCollection municipalitylist) => + query.WhereInJsonb( + list: municipalitylist, + jsonPath: "LocationInfo.MunicipalityInfo.Id" + ); + + public static Query LocFilterTvsFilter(this Query query, IReadOnlyCollection tourismvereinlist) => + query.WhereInJsonb( + list: tourismvereinlist, + jsonPath: "LocationInfo.TvInfo.Id" + ); + + public static Query LocFilterRegionFilter(this Query query, IReadOnlyCollection regionlist) => + query.WhereInJsonb( + list: regionlist, + jsonPath: "LocationInfo.RegionInfo.Id" + ); + + public static Query AreaFilter(this Query query, IReadOnlyCollection arealist) => + query.WhereInJsonb( + arealist, + areaid => new { AreaId = new[] { areaid } } + ); + + public static Query AreaFilterMeasuringpoints(this Query query, IReadOnlyCollection arealist) => + query.WhereInJsonb( + arealist, + areaid => new { AreaIds = new[] { areaid } } + ); + + public static Query SkiAreaFilterMeasuringpoints(this Query query, IReadOnlyCollection skiarealist) => + query.WhereInJsonb( + skiarealist, + skiareaid => new { SkiAreaIds = new[] { skiareaid } } + ); + + public static Query HighlightFilter(this Query query, bool? highlight) => + query.When( + highlight != null, + query => query.WhereJsonb( + "Highlight", + highlight ?? false + ) + ); + + public static Query ActiveFilter(this Query query, bool? active) => + query.When( + active != null, + query => query.WhereJsonb( + "Active", + active ?? false + ) + ); + + public static Query SmgActiveFilter(this Query query, bool? smgactive) => + query.When( + smgactive != null, + query => query.WhereJsonb( + "SmgActive", + smgactive ?? false + ) + ); + + public static Query DistanceFilter(this Query query, bool distance, int distancemin, int distancemax) => + query.When( + distance, + query => query.WhereRaw( + "(data#>>'\\{DistanceLength\\}')::numeric > $$ AND (data#>>'\\{DistanceLength\\}')::numeric < $$", + distancemin, + distancemax + ) + ); + + public static Query DurationFilter(this Query query, bool duration, double durationmin, double durationmax) => + query.When( + duration, + query => query.WhereRaw( + "(data#>>'\\{DistanceDuration\\}')::numeric > $$ AND (data#>>'\\{DistanceDuration\\}')::numeric < $$", + durationmin, + durationmax + ) + ); + + public static Query AltitudeFilter(this Query query, bool altitude, int altitudemin, int altitudemax) => + query.When( + altitude, + query => query.WhereRaw( + "(data#>>'\\{AltitudeDifference\\}')::numeric > $$ AND (data#>>'\\{AltitudeDifference\\}')::numeric < $$", + altitudemin, + altitudemax + ) + ); + + public static Query SmgTagFilter(this Query query, IReadOnlyCollection smgtaglist) => + query.WhereInJsonb( + smgtaglist, + tag => new { SmgTags = new[] { tag.ToLower() } } + ); + + //NOT WORKING + //public static Query SmgTagFilter(this Query query, IReadOnlyCollection smgtaglist) => + // query.WhereInJsonb( + // smgtaglist, + // "SmgTags", + // tag => tag.ToLower() + //); + + public static Query SearchFilter(this Query query, string[] fields, string? searchfilter) => + query.When( + searchfilter != null && fields.Length > 0, + query => query.Where(q => + { + foreach (var field in fields) + { + q = q.OrWhereRaw( + $"data#>>'\\{{{JsonPathToPostgresArray(field)}\\}}' ILIKE $$", + $"%{searchfilter}%"); + } + return q; + }) + ); + + public static Query ActivityTypeFilter(this Query query, IReadOnlyCollection activitytypelist) => + query.WhereInJsonb( + list: activitytypelist, + "Type", + type => type + ); + + public static Query ActivityTypeFilterOnTags(this Query query, IReadOnlyCollection activitytypelist) => + query.WhereInJsonb( + list: activitytypelist, + tag => new { SmgTags = new[] { tag.ToLower() } } + ); + + public static Query ActivitySubTypeFilterOnTags(this Query query, IReadOnlyCollection subtypelist) => + query.WhereInJsonb( + list: subtypelist, + tag => new { SmgTags = new[] { tag.ToLower() } } + ); + + public static Query DifficultyFilter(this Query query, IReadOnlyCollection difficultylist) => + query.WhereInJsonb( + list: difficultylist, + jsonPath: "Difficulty" + ); + + public static Query PoiTypeFilterOnTags(this Query query, IReadOnlyCollection poitypelist) => + query.WhereInJsonb( + poitypelist, + poitype => new { SmgTags = new[] { poitype.ToLower() } } + ); + + public static Query PoiSubTypeFilterOnTags(this Query query, IReadOnlyCollection subtypelist) => + query.WhereInJsonb( + subtypelist, + poitype => new { SmgTags = new[] { poitype.ToLower() } } + ); + + public static Query MetaRegionFilter(this Query query, IReadOnlyCollection metaregionlist) => + query.WhereInJsonb( + metaregionlist, + "Id", + id => id.ToUpper() + ); + + // TODO Add correct filters + public static Query CuisineCodeFilter(this Query query, IReadOnlyCollection cuisinecodelist) => + query.WhereInJsonb( + cuisinecodelist, + tag => new { Facilities = new[] { new { Id = tag.ToUpper() } } } + ); + + public static Query CeremonyCodeFilter(this Query query, IReadOnlyCollection ceremonycodelist) => + query.WhereInJsonb( + ceremonycodelist, + tag => new { CapacityCeremony = new[] { new { Id = tag.ToUpper() } } } + ); + + public static Query CategoryCodeFilter(this Query query, IReadOnlyCollection categorycodelist) => + query.WhereInJsonb( + categorycodelist, + tag => new { CategoryCodes = new[] { new { Id = tag.ToUpper() } } } + ); + + public static Query DishCodeFilter(this Query query, IReadOnlyCollection dishcodelist) => + query.WhereInJsonb( + dishcodelist, + tag => new { DishRates = new[] { new { Id = tag.ToUpper() } } } + ); + + public static Query SourceFilter(this Query query, IReadOnlyCollection sourcelist) => + query.WhereInJsonb( + list: sourcelist, + "Source", + id => id.ToUpper() + ); + + //For Alpinebits + public static Query SourceFilterAlpineBits(this Query query, IReadOnlyCollection sourcelist) => + query.WhereInJsonb( + list: sourcelist, + "Source", + id => id.ToLower() + ); + + public static Query SyncSourceInterfaceFilter(this Query query, IReadOnlyCollection sourcelist) => + query.WhereInJsonb( + list: sourcelist, + "SyncSourceInterface", + id => id.ToUpper() + ); + + public static Query SourceFilterMeta(this Query query, IReadOnlyCollection sourcelist) => + query.WhereInJsonb( + list: sourcelist, + "_Meta.Source", + id => id.ToLower() + ); + + //not working + //public static Query HasLanguageFilter(this Query query, IReadOnlyCollection languagelist) => + // query.WhereInJsonb( + // list: languagelist, + // "HasLanguage", + // id => id.ToUpper() + // ); + + public static Query HasLanguageFilter(this Query query, IReadOnlyCollection languagelist) => + query.WhereInJsonb( + languagelist, + lang => new { HasLanguage = new[] { lang.ToLower() } } + ); + + + public static Query ODHActivityPoiTypeFilter(this Query query, IReadOnlyCollection typelist) => + query.WhereInJsonb( + list: typelist, + "Type", + type => type + ); + + public static Query ODHActivityPoiSubTypeFilter(this Query query, IReadOnlyCollection subtypelist) => + query.WhereInJsonb( + list: subtypelist, + "SubType", + type => type + ); + + public static Query ODHActivityPoiPoiTypeFilter(this Query query, IReadOnlyCollection poitypelist) => + query.WhereInJsonb( + list: poitypelist, + "PoiType", + type => type + ); + + //To change, ODH Type Filtering based on + public static Query ODHActivityPoiTypeFilterOnTags(this Query query, IReadOnlyCollection typelist) => + query.WhereInJsonb( + typelist, + type => new { SmgTags = new[] { type.ToLower() } } + ); + + public static Query ODHActivityPoiSubTypeFilterOnTags(this Query query, IReadOnlyCollection subtypelist) => + query.WhereInJsonb( + subtypelist, + subtype => new { SmgTags = new[] { subtype.ToLower() } } + ); + + public static Query ODHActivityPoiPoiTypeFilterOnTags(this Query query, IReadOnlyCollection poitypelist) => + query.WhereInJsonb( + poitypelist, + poitype => new { SmgTags = new[] { poitype.ToLower() } } + ); + + + public static Query EventTopicFilter(this Query query, IReadOnlyCollection eventtopiclist) => + query.WhereInJsonb( + eventtopiclist, + topic => new { TopicRIDs = new[] { topic.ToUpper() } } + ); + + public static Query EventTypeFilter(this Query query, IReadOnlyCollection eventtypelist) => + query.WhereInJsonb( + list: eventtypelist, + "Type", + type => type + ); + + //Obsolete + public static Query EventRancFilter(this Query query, IReadOnlyCollection eventrancfilterlist) => + query.WhereInJsonb( + list: eventrancfilterlist, + "Ranc", + ranc => ranc + ); + + public static Query EventPublisherRancFilter(this Query query, IReadOnlyCollection eventrancfilterlist) => + query.WhereInJsonb( + eventrancfilterlist, + ranc => new { EventPublisher = new[] { new { Ranc = ranc } } } + ); + + public static Query EventOrgFilter(this Query query, IReadOnlyCollection eventorgfilter) => + query.WhereInJsonb( + list: eventorgfilter, + "OrgRID", + org => org + ); + + + //Only Begindate given + public static Query EventDateFilterBegin(this Query query, DateTime? begin, DateTime? end) => + query.When( + begin != DateTime.MinValue && end == DateTime.MaxValue, + query => query.WhereRaw( + "((begindate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND begindate < '" + String.Format("{0:yyyy-MM-dd}", end) + "') OR(enddate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND enddate < '" + String.Format("{0:yyyy-MM-dd}", end) + "'))" + ) + ); + + //Only Enddate given + public static Query EventDateFilterEnd(this Query query, DateTime? begin, DateTime? end) => + query.When( + begin == DateTime.MinValue && end != DateTime.MaxValue, + query => query.WhereRaw( + "((begindate > '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND begindate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "') OR (enddate > '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND enddate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "'))" + ) + ); + + //Both Begin and Enddate given + public static Query EventDateFilterBeginEnd(this Query query, DateTime? begin, DateTime? end) => + query.When( + begin != DateTime.MinValue && end != DateTime.MaxValue, + query => query.WhereRaw( + "((begindate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND begindate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "') OR (enddate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND enddate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "'))" + ) + ); + + public static Query VisibleInSearchFilter(this Query query, bool? visibleinsearch) => + query.When( + visibleinsearch != null, + query => query.WhereJsonb( + "VisibleInSearch", + visibleinsearch ?? false + ) + ); + + public static Query CompanyIdFilter(this Query query, IReadOnlyCollection companyidfilter) => + query.WhereInJsonb( + list: companyidfilter, + "CompanyId", + compid => compid + ); + + public static Query WineIdFilter(this Query query, IReadOnlyCollection wineidfilter) => + query.WhereInJsonb( + list: wineidfilter, + "CustomId", + wineid => wineid + ); + + public static Query AccoAltitudeFilter(this Query query, bool altitude, int altitudemin, int altitudemax) => + query.When( + altitude, + query => query.WhereRaw( + "(data#>>'\\{Altitude\\}')::numeric > $$ AND (data#>>'\\{Altitude\\}')::numeric < $$", + altitudemin, + altitudemax + ) + ); + + public static Query AccoTypeFilter(this Query query, IReadOnlyCollection accotypefilter) => + query.WhereInJsonb( + list: accotypefilter, + "AccoTypeId", + wineid => wineid + ); + + public static Query AccoBoardFilter(this Query query, IReadOnlyCollection boardlist) => + query.WhereInJsonb( + boardlist, + board => new { BoardIds = new[] { board.ToLower() } } + ); + + public static Query AccoBadgeFilter(this Query query, IReadOnlyCollection badgelist) => + query.WhereInJsonb( + badgelist, + badge => new { BadgeIds = new[] { badge.ToLower() } } + ); + + public static Query AccoLTSFeatureFilter(this Query query, IReadOnlyCollection ltsfeaturelist) => + query.WhereInJsonb( + ltsfeaturelist, + feature => new { Features = new[] { new { Id = feature.ToUpper() } } } + ); + + public static Query AccoMarketinggroupFilter(this Query query, IReadOnlyCollection marketinggrouplist) => + query.WhereInJsonb( + marketinggrouplist, + marketinggroup => new { MarketingGroupIds = new[] { marketinggroup } } + ); + + public static Query AccoBookingPortalFeatureFilter(this Query query, IReadOnlyCollection bookingportallist) => + query.WhereInJsonb( + bookingportallist, + bookingportal => new { AccoBookingChannel = new[] { new { Id = bookingportal } } } + ); + + //THEMEFILTER is AND connected + public static Query AccoThemeFilter(this Query query, IReadOnlyCollection themelist) => + query.WhereAllInJsonb( + themelist, + theme => new { ThemeIds = new[] { theme } } + ); + + //TODO THEMEFILTER is AND connected + public static Query AccoFeatureFilter(this Query query, IReadOnlyCollection featurelist) => + query.WhereAllInJsonb( + featurelist, + feature => new { SpecialFeaturesIds = new[] { feature } } + ); + + public static Query AccoCategoryFilter(this Query query, IReadOnlyCollection categorylist) => + query.WhereInJsonb( + list: categorylist, + "AccoCategoryId", + category => category + ); + + public static Query AccoFeatureIdFilter(this Query query, IReadOnlyCollection featureidlist) => + query.WhereInJsonb( + featureidlist, + tag => new { Features = new[] { new { Id = tag.ToUpper() } } } + ); + + + public static Query AccoApartmentFilter(this Query query, bool? apartment) => + query.When( + apartment != null, + query => query.WhereJsonb( + "HasApartment", + apartment ?? false + ) + ); + + public static Query AccoBookableFilter(this Query query, bool? bookable) => + query.When( + bookable != null, + query => query.WhereJsonb( + "IsBookable", + bookable ?? false + ) + ); + + public static Query EventShortLocationFilter(this Query query, IReadOnlyCollection eventlocationlist) => + query.WhereInJsonb( + list: eventlocationlist, + "EventLocation", + id => id.ToUpper() + ); + + public static Query EventShortWebaddressFilter(this Query query, IReadOnlyCollection webaddresslist) => + query.WhereInJsonb( + list: webaddresslist, + "WebAddress", + id => id + ); + + public static Query EventShortTodayActiveFilter(this Query query, string? active) => + query.When( + active != null, + query => query.WhereJsonb( + "Display1", + active ?? "" + ) + ); + + public static Query EventShortWebsiteActiveFilter(this Query query, bool? websiteactive) => + query.When( + websiteactive != null, + query => query.WhereJsonb( + "ActiveWeb", + websiteactive ?? false + ) + ); + + public static Query EventShortCommunityActiveFilter(this Query query, bool? communityactive) => + query.When( + communityactive != null, + query => query.WhereJsonb( + "ActiveCommunityApp", + communityactive ?? false + ) + ); + + ////Only Begindate given + //public static Query EventShortDateFilterBegin(this Query query, DateTime? start, DateTime? end, bool active) => + // query.When( + // start != DateTime.MinValue && end == DateTime.MaxValue && active, + // query => query.WhereRaw( + // "((to_timestamp(data ->> 'EndDate', 'YYYY-MM-DD T HH24:MI:SS') >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "'))" + // ) + // ); + + ////Only Enddate given + //public static Query EventShortDateFilterEnd(this Query query, DateTime? start, DateTime? end, bool active) => + // query.When( + // start == DateTime.MinValue && end != DateTime.MaxValue && active, + // query => query.WhereRaw( + // "((to_timestamp(data->> 'EndDate', 'YYYY-MM-DD T HH24:MI:SS') <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "'))" + // ) + // ); + + //Both Begin and Enddate given + public static Query EventShortDateFilterBeginEnd(this Query query, DateTime? start, DateTime? end, bool active) => + //begin and enddate given + query.When( + start != DateTime.MinValue && end != DateTime.MaxValue && active, + query => query.WhereRaw( + "(((to_timestamp(data ->> 'StartDate', 'YYYY-MM-DD T HH24:MI:SS') >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "') AND (to_timestamp(data->> 'EndDate', 'YYYY-MM-DD T HH24:MI:SS') <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "')))" + ) + ) + //only begindate given + .When( + start != DateTime.MinValue && end == DateTime.MaxValue && active, + query => query.WhereRaw( + "((to_timestamp(data ->> 'EndDate', 'YYYY-MM-DD T HH24:MI:SS') >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "'))" + ) + ) + //only enddate given + .When( + start == DateTime.MinValue && end != DateTime.MaxValue && active, + query => query.WhereRaw( + "((to_timestamp(data->> 'EndDate', 'YYYY-MM-DD T HH24:MI:SS') <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "'))" + ) + ); + + + //Both Begin and Enddate given which allows Today Query (In behaviour) + public static Query EventShortDateFilterBeginEndWithInBehaviour(this Query query, DateTime? start, DateTime? end, bool active) => + query.When( + start != DateTime.MinValue && end != DateTime.MaxValue && active, + query => query.WhereRaw( + "(((to_timestamp(data ->> 'EndDate', 'YYYY-MM-DD T HH24:MI:SS') >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "') AND (to_timestamp(data->> 'StartDate', 'YYYY-MM-DD T HH24:MI:SS') <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "')))" + ) + ); + + ////Only Begindate given + //public static Query EventShortDateFilterBeginByRoom(this Query query, DateTime? start, DateTime? end, bool active) => + // query.When( + // start != DateTime.MinValue && end == DateTime.MaxValue && active, + // query => query.WhereRaw( + // "((to_date(data ->> 'EndDate', 'YYYY-MM-DD') >= '" + String.Format("{0:yyyy-MM-dd}", start) + "'))" + // ) + // ); + + ////Only Enddate given + //public static Query EventShortDateFilterEndByRoom(this Query query, DateTime? start, DateTime? end, bool active) => + // query.When( + // start == DateTime.MinValue && end != DateTime.MaxValue && active, + // query => query.WhereRaw( + // "((to_date(data->> 'EndDate', 'YYYY-MM-DD') <= '" + String.Format("{0:yyyy-MM-dd}", end) + "'))" + // ) + // ); + + //Both Begin and Enddate given + public static Query EventShortDateFilterBeginEndByRoom(this Query query, DateTime? start, DateTime? end, bool active) => + //begindate and enddate given + query.When( + start != DateTime.MinValue && end != DateTime.MaxValue && active, + query => query.WhereRaw( + "(((to_date(data ->> 'EndDate', 'YYYY-MM-DD') >= '" + String.Format("{0:yyyy-MM-dd}", start) + "') AND (to_date(data->> 'StartDate', 'YYYY-MM-DD') <= '" + String.Format("{0:yyyy-MM-dd}", end) + "')))" + ) + ) + //only begindate given + .When( + start != DateTime.MinValue && end == DateTime.MaxValue && active, + query => query.WhereRaw( + "((to_date(data ->> 'EndDate', 'YYYY-MM-DD') >= '" + String.Format("{0:yyyy-MM-dd}", start) + "'))" + ) + ) + //only enddate given + .When( + start == DateTime.MinValue && end != DateTime.MaxValue && active, + query => query.WhereRaw( + "((to_date(data->> 'EndDate', 'YYYY-MM-DD') <= '" + String.Format("{0:yyyy-MM-dd}", end) + "'))" + ) + ); + + public static Query ODHTagMainEntityFilter(this Query query, IReadOnlyCollection mainentitylist) => + query.WhereInJsonb( + list: mainentitylist, + "MainEntity", + id => id.ToLower() + ); + + public static Query ODHTagValidForEntityFilter(this Query query, IReadOnlyCollection validforentitylist) => + query.WhereInJsonb( + validforentitylist, + validforentity => new { ValidForEntity = new[] { validforentity.ToLower() } } + ); + + public static Query ODHTagDisplayAsCategoryFilter(this Query query, bool? displayascategory) => + query.When( + displayascategory != null, + query => query.WhereJsonb( + "DisplayAsCategory", + displayascategory ?? false + ) + ); + + //AlpineBits + public static Query AlpineBitsAccommodationIdFilter(this Query query, IReadOnlyCollection accommodationids) => + query.WhereInJsonb( + list: accommodationids, + "AccommodationId", + id => id + ); + + //AlpineBits + public static Query AlpineBitsMessageFilter(this Query query, IReadOnlyCollection messagetypelist) => + query.WhereInJsonb( + list: messagetypelist, + "MessageType", + id => id + ); + + //Venue Filters (Special case) + + //public static Query VenueLocFilterDistrictFilter(this Query query, IReadOnlyCollection districtlist) => + // query.WhereInJsonb( + // list: districtlist, + // jsonPath: "odhdata.LocationInfo.DistrictInfo.Id" + // ); + + //public static Query VenueLocFilterMunicipalityFilter(this Query query, IReadOnlyCollection municipalitylist) => + // query.WhereInJsonb( + // list: municipalitylist, + // jsonPath: "odhdata.LocationInfo.MunicipalityInfo.Id" + // ); + + //public static Query VenueLocFilterTvsFilter(this Query query, IReadOnlyCollection tourismvereinlist) => + // query.WhereInJsonb( + // list: tourismvereinlist, + // jsonPath: "odhdata.LocationInfo.TvInfo.Id" + // ); + + //public static Query VenueLocFilterRegionFilter(this Query query, IReadOnlyCollection regionlist) => + // query.WhereInJsonb( + // list: regionlist, + // jsonPath: "odhdata.LocationInfo.RegionInfo.Id" + // ); + + //public static Query VenueActiveFilter(this Query query, bool? active) => + // query.When( + // active != null, + // query => query.WhereJsonb( + // "odhdata.Active", + // active ?? false + // ) + // ); + + //public static Query VenueODHActiveFilter(this Query query, bool? odhactive) => + // query.When( + // odhactive != null, + // query => query.WhereJsonb( + // "odhdata.ODHActive", + // odhactive ?? false + // ) + // ); + + public static Query VenueCategoryFilter(this Query query, IReadOnlyCollection categorylist) => + query.WhereInJsonb( + categorylist, + tag => new { VenueCategory = new[] { new { Id = tag.ToUpper() } } } + ); + + public static Query VenueFeatureFilter(this Query query, IReadOnlyCollection featurelist) => + query.WhereInJsonb( + featurelist, + tag => new { RoomDetails = new[] { new { VenueFeatures = new[] { new { Id = tag.ToUpper() } } } } } + ); + + public static Query VenueSetupTypeFilter(this Query query, IReadOnlyCollection setuptypelist) => + query.WhereInJsonb( + setuptypelist, + tag => new { RoomDetails = new[] { new { VenueSetup = new[] { new { Id = tag.ToUpper() } } } } } + ); + + public static Query VenueRoomCountFilter(this Query query, bool roomcount, int roomcountmin, int roomcountmax) => + query.When( + roomcount, + query => query.WhereRaw( + "(data#>>'\\{RoomCount\\}')::numeric > ? AND (data#>>'\\{RoomCount\\}')::numeric < ?", + roomcountmin, + roomcountmax + ) + ); + + //public static Query VenueODHTagFilter(this Query query, IReadOnlyCollection smgtaglist) => + // query.WhereInJsonb( + // smgtaglist, + // tag => new { odhdata = new { ODHTags = new[] { tag.ToLower() } } } + // ); + + //public static Query VenueLastChangedFilter(this Query query, string? updatefrom) => + // query.When( + // updatefrom != null, + // query => query.WhereRaw( + // "to_date(data#>>'\\{meta,lastUpdate\\}', 'YYYY-MM-DD') > date($$)", + // updatefrom + // ) + // ); + + public static Query VenueSourceFilter(this Query query, IReadOnlyCollection sourcelist) => + query.WhereInJsonb( + list: sourcelist, + "SyncSourceInterface", + id => id.ToUpper() + ); + + public static Query SourceTypeFilter(this Query query, IReadOnlyCollection typeslist) => + query.WhereInJsonb( + typeslist, + sourcetype => new { Types = new[] { sourcetype.ToLower() } } + ); + + //public static Query VenueHasLanguageFilter(this Query query, IReadOnlyCollection languagelist) => + // query.WhereInJsonb( + // languagelist, + // lang => new { odhdata = new { HasLanguage = new[] { lang.ToLower() } } } + // ); + + //private static Query VenueCapacityFilterWhere(bool capacity, int capacitymin, int capacitymax) + //{ + // //TODO!!! + // if (capacity) + // { + // //if (!String.IsNullOrEmpty(whereexpression)) + // // whereexpression = whereexpression + " AND "; + + // //whereexpression = whereexpression + "(data ->'odhdata' ->> 'RoomCount')::numeric > @roomcountmin AND (data ->'odhdata' ->> 'RoomCount')::numeric < @roomcountmax"; + // //parameters.Add(new PGParameters() { Name = "roomcountmin", Type = NpgsqlTypes.NpgsqlDbType.Numeric, Value = roomcountmin.ToString() }); + // //parameters.Add(new PGParameters() { Name = "roomcountmax", Type = NpgsqlTypes.NpgsqlDbType.Numeric, Value = roomcountmax.ToString() }); + // } + + //} + + //public static Query PublishedOnFilter(this Query query, IReadOnlyCollection publishedonlist) => + // query.WhereInJsonb( + // publishedonlist, + // publishedon => new { PublishedOn = new[] { publishedon.ToLower() } } + // ); + + + //Standard JSON Filter + //public static Query FilterClosedData(this Query query) => + // query.Where(q => + // q.WhereRaw( + // "data#>>'\\{LicenseInfo,ClosedData\\}' IS NULL" + // ).OrWhereRaw( + // "data#>>'\\{LicenseInfo,ClosedData\\}' = 'false'" + // ) + // ); + + //public static Query FilterClosedDataVenues(this Query query) => + // query.Where(q => + // q.WhereRaw( + // "data#>>'\\{odhdata,LicenseInfo,ClosedData\\}' IS NULL" + // ).OrWhereRaw( + // "data#>>'\\{odhdata,LicenseInfo,ClosedData\\}' = 'false'" + // ) + // ); + + #region Tagging + + public static Query TaggingFilter_OR(this Query query, string tagkey, IReadOnlyCollection taglist) => + query.Where(q => + taglist.Aggregate(q, (q, tag) => + q.OrWhereRaw(@$"(data->>'Tags')::jsonb @? '$.{tagkey}\[*\] ? (@.Id == ""{tag}"")'"))); + + public static Query TaggingFilter_AND(this Query query, string tagkey, IReadOnlyCollection taglist) => + query.Where(q => + taglist.Aggregate(q, (q, tag) => + q.WhereRaw(@$"(data->>'Tags')::jsonb @? '$.{tagkey}\[*\] ? (@.Id == ""{tag}"")'"))); + + public static Query TaggingFilter_OR(this Query query, IDictionary tagdict) => + query.Where(q => + tagdict.Aggregate(q, (q, tag) => + q.OrWhereRaw(@$"(data->>'Tags')::jsonb @? '$.{tag.Value}\[*\] ? (@.Id == ""{tag.Key}"")'"))); + + public static Query TaggingFilter_AND(this Query query, IDictionary tagdict) => + query.Where(q => + tagdict.Aggregate(q, (q, tag) => + q.WhereRaw(@$"(data->>'Tags')::jsonb @? '$.{tag.Value}\[*\] ? (@.Id == ""{tag.Key}"")'"))); + + #endregion + + #region Tagging Generated Column + + public static Query TaggingFilter_GeneratedColumn(this Query query, IDictionary> tags) => + query.Where(q => tags.Aggregate(q, (q, tag) => + q.When(tag.Key == "and", v => q.WhereArrayInListAnd(tag.Value, "gen_tags"), v => q.WhereArrayInListOr(tag.Value, "gen_tags")) + )); + + //? q.WhereArrayInListAnd(tag.Value, "gen_tags") : q.WhereArrayInListOr(tag.Value, "gen_tags")) + + #endregion + + + #region Generated Columns Basic + + //Where Array is in List OR + public static Query WhereArrayInListOr(this Query query, IReadOnlyCollection list, string generatedcolumn) => + query.Where(q => + { + foreach (var item in list) + { + q = q.OrWhereRaw( + generatedcolumn + " @> array\\[$$\\]", item.ToLower() + ); + } + return q; + }); + + //Where Array is in List AND + public static Query WhereArrayInListAnd(this Query query, IReadOnlyCollection list, string generatedcolumn) => + query.Where(q => + q.WhereRaw( + generatedcolumn + " @> array\\[$$\\]", list.Select(x => x.ToLower()) + ) + ); + + //Where Array is in List OR alternative + public static Query WhereStringInListOr(this Query query, IReadOnlyCollection list, string generatedcolumn) => + query.Where(q => + { + foreach (var item in list) + { + q = q.OrWhereRaw( + generatedcolumn + " = $$", item.ToLower() + ); + } + return q; + }); + + #endregion + + #region Generated Columns Where Expressions + + //Filter on Generated Field gen_licenseinfo_closeddata + public static Query FilterClosedData_GeneratedColumn(this Query query) => + query.Where(q => + q.WhereRaw( + "gen_licenseinfo_closeddata IS NULL" + ).OrWhereRaw( + "gen_licenseinfo_closeddata = false" + ) + ); + + //Filter on Generated Field gen_haslanguage AND + public static Query HasLanguageFilterAnd_GeneratedColumn(this Query query, IReadOnlyCollection languagelist) => + query.Where(q => q.WhereRaw( + "gen_haslanguage @> array\\[$$\\]", + languagelist.Select(x => x.ToLower()) + ) + ); + + //Filter on Generated Field gen_haslanguage AND + public static Query HasLanguageFilterOr_GeneratedColumn(this Query query, IReadOnlyCollection languagelist) => + query.Where(q => + { + foreach (var item in languagelist) + { + q = q.OrWhereRaw( + "gen_haslanguage @> array\\[$$\\]", item.ToLower() + ); + } + return q; + }); + + //Filter on Generated Field gen_smgtags AND + public static Query SmgTagFilterAnd_GeneratedColumn(this Query query, IReadOnlyCollection list) => + query.Where(q => q.WhereRaw( + "gen_smgtags @> array\\[$$\\]", + list.Select(x => x.ToLower()) + ) + ); + + //Filter on Generated Field gen_smgtags OR + public static Query SmgTagFilterOr_GeneratedColumn(this Query query, IReadOnlyCollection list) => + query.Where(q => + { + foreach (var item in list) + { + q = q.OrWhereRaw( + "gen_smgtags @> array\\[$$\\]", item.ToLower() + ); + } + return q; + }); + + //Filter on Generated Field gen_articletype OR + public static Query ArticleTypeFilterOr_GeneratedColumn(this Query query, IReadOnlyCollection list) => + query.Where(q => + { + foreach (var item in list) + { + q = q.OrWhereRaw( + "gen_articletype @> array\\[$$\\]", item.ToLower() + ); + } + return q; + }); + + //Filter on Generated Field gen_active + public static Query ActiveFilter_GeneratedColumn(this Query query, bool? active) => + query.When( + active != null, + query => query.WhereRaw( + "gen_active = $$", + active ?? false + ) + ); + + //Filter on Generated Field gen_odhactive + public static Query OdhActiveFilter_GeneratedColumn(this Query query, bool? odhactive) => + query.When( + odhactive != null, + query => query.WhereRaw( + "gen_odhactive = $$", + odhactive ?? false + ) + ); + + //Filter on Generated Field gen_odhactive + public static Query HasImage_GeneratedColumn(this Query query, bool? odhactive) => + query.When( + odhactive != null, + query => query.WhereRaw( + "gen_hasimage = $$", + odhactive ?? false + ) + ); + + //Filter on Generated Field gen_eventtopic OR + public static Query EventTopicFilter_GeneratedColumn(this Query query, IReadOnlyCollection eventtopiclist) => + query.Where(q => + { + foreach (var item in eventtopiclist) + { + q = q.OrWhereRaw( + "gen_eventtopic @> array\\[$$\\]", item.ToUpper() + ); + } + return q; + }); + + //Filter on Generated Field gen_boardids + public static Query AccoBoardIdsFilterOr_GeneratedColumn(this Query query, IReadOnlyCollection boardids) => + query.Where(q => + { + foreach (var item in boardids) + { + q = q.OrWhereRaw( + "gen_boardids @> array\\[$$\\]", item + ); + } + return q; + }); + + //Filter on Generated Field gen_featureids + public static Query AccoFeatureIdsFilterOr_GeneratedColumn(this Query query, IReadOnlyCollection featureids) => + query.Where(q => + { + foreach (var item in featureids) + { + q = q.OrWhereRaw( + "gen_featureids @> array\\[$$\\]", item + ); + } + return q; + }); + + //Filter on Generated Field gen_specialfeatureids + public static Query AccoSpecialFeatureIdsFilterOr_GeneratedColumn(this Query query, IReadOnlyCollection specialfeatureids) => + query.Where(q => + { + foreach (var item in specialfeatureids) + { + q = q.OrWhereRaw( + "gen_specialfeatureids @> array\\[$$\\]", item + ); + } + return q; + }); + + //Filter on Generated Field gen_badgeids + public static Query AccoBadgeIdsFilterOr_GeneratedColumn(this Query query, IReadOnlyCollection boardids) => + query.Where(q => + { + foreach (var item in boardids) + { + q = q.OrWhereRaw( + "gen_badgeids @> array\\[$$\\]", item + ); + } + return q; + }); + + //Filter on Generated Field gen_themeids + public static Query AccoThemeIdsFilterOr_GeneratedColumn(this Query query, IReadOnlyCollection boardids) => + query.Where(q => + { + foreach (var item in boardids) + { + q = q.OrWhereRaw( + "gen_themeids @> array\\[$$\\]", item + ); + } + return q; + }); + + //Filter on Generated Field gen_accotype + public static Query AccoTypeFilter_GeneratedColumn(this Query query, IReadOnlyCollection accotype) => + query.Where(q => + { + foreach (var item in accotype) + { + q = q.OrWhereRaw( + "gen_accotype = $$", item + ); + } + return q; + }); + + //Filter on Generated Field gen_accocategory + public static Query AccoCategoryFilter_GeneratedColumn(this Query query, IReadOnlyCollection accocategory) => + query.Where(q => + { + foreach (var item in accocategory) + { + q = q.OrWhereRaw( + "gen_accocategory = $$", item + ); + } + return q; + }); + + //Filter on Generated Field gen_hasapartment + public static Query AccoApartmentFilter_GeneratedColumn(this Query query, bool? hasapartment) => + query.When( + hasapartment != null, + query => query.WhereRaw( + "gen_hasapartment = $$", + hasapartment ?? false + ) + ); + + //Filter on Generated Field gen_isbookable + public static Query AccoIsBookableFilter_GeneratedColumn(this Query query, bool? isbookable) => + query.When( + isbookable != null, + query => query.WhereRaw( + "gen_isbookable = $$", + isbookable ?? false + ) + ); + + //Filter on Generated Field gen_altitude + public static Query AccoAltitudeFilter_GeneratedColumn(this Query query, bool altitude, int altitudemin, int altitudemax) => + query.When( + altitude, + query => query.WhereRaw( + "(gen_altitude)::numeric > $$ AND (gen_altitude)::numeric < $$", + altitudemin, + altitudemax + ) + ); + + //Filter on Generated Field gen_lastchange + public static Query LastChangedFilter_GeneratedColumn(this Query query, string? updatefrom) => + query.When( + //DISPLAY ERRROR OR IGNORE DATE? + //updatefrom != null && DateTime.TryParseExact(updatefrom, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime updatefromparsed), + //updatefrom != null && DateTime.TryParse(updatefrom, out DateTime updatefromparsed), + updatefrom != null, + query => query.WhereRaw( + //"to_date(gen_lastchange, 'YYYY-MM-DD') > date($$)", + "gen_lastchange > date($$)", + updatefrom + ) + ); + + + //Weatherhistory lastchangedBetween + //Filter on Generated Field gen_lastchange + public static Query LastChangedFilter_GeneratedColumn(this Query query, DateTime? updatefrom, DateTime? updateto) => + query.When( + updatefrom != null && updateto != null, + query => query.WhereRaw( + //"to_date(gen_lastchange, 'YYYY-MM-DD') > date($$)", + "gen_lastchange > date($$) AND gen_lastchange < date($$)", + updatefrom, + updateto + ) + ); + + //Source Filter (SyncSourceInterface) + public static Query SyncSourceInterfaceFilter_GeneratedColumn(this Query query, IReadOnlyCollection sourcelist) => + query.Where(q => + { + foreach (var source in sourcelist) + { + q = q.OrWhere("gen_syncsourceinterface", "ILIKE", source); + } + return q; + }); + + //Source Filter (SyncSourceInterface) + public static Query SourceFilter_GeneratedColumn(this Query query, IReadOnlyCollection sourcelist) => + query.Where(q => + { + foreach (var source in sourcelist) + { + q = q.OrWhere("gen_source", "ILIKE", source); + } + return q; + }); + + //PublishedOn Filter (SyncSourceInterface) + public static Query PublishedOnFilter_GeneratedColumn(this Query query, IReadOnlyCollection publishedonlist) => + query.Where(q => + { + foreach (var item in publishedonlist) + { + q = q.OrWhereRaw( + "gen_publishedon @> array\\[$$\\]", item.ToLower() + ); + } + return q; + }); + + + + //Source Filter for Alpinebits + public static Query SourceFilterAlpineBits_GeneratedColumn(this Query query, IReadOnlyCollection sourcelist) => + query.Where(q => + { + foreach (var source in sourcelist) + { + q = q.OrWhere("gen_source", "ILIKE", source); + } + return q; + }); + + //AlpineBits + public static Query AlpineBitsAccommodationIdFilter_GeneratedColumn(this Query query, IReadOnlyCollection accommodationids) => + query.Where(q => + { + foreach (var item in accommodationids) + { + q = q.OrWhere("gen_accommodation_id", "=", item); + } + return q; + }); + + //AlpineBits + public static Query AlpineBitsMessageFilter_GeneratedColumn(this Query query, IReadOnlyCollection messagetypelist) => + query.Where(q => + { + foreach (var item in messagetypelist) + { + q = q.OrWhereRaw( + "gen_messagetype = $$", item + ); + } + return q; + }); + + + //public static Query TaggingFilter_OR_GeneratedColumn(this Query query, IDictionary tagdict) => + // query.Where(q => + // tagdict.Aggregate(q, (q, tag) => + // q.OrWhereRaw(@$"(data->>'Tags')::jsonb @? '$.{tag.Value}\[*\] ? (@.Id == ""{tag.Key}"")'"))); + + //public static Query TaggingFilter_AND_GeneratedColumn(this Query query, IDictionary tagdict) => + // query.Where(q => + // tagdict.Aggregate(q, (q, tag) => + // q.WhereRaw(@$"(data->>'Tags')::jsonb @? '$.{tag.Value}\[*\] ? (@.Id == ""{tag.Key}"")'"))); + + #endregion + + #region Rawdata Where Experession + + public static Query FilterClosedData_Raw(this Query query) => + query.Where(q => + q.Where("license", "open") + ); + + #endregion + + #region Date_Query_Helpers Event + + //Events + //EVENTS Usecase to check + + //Integrated in Query + //Only Begindate given + //public static Query EventDateFilterBegin_GeneratedColumn(this Query query, DateTime? begin, DateTime? end) => + // query.When( + // begin != DateTime.MinValue && end == DateTime.MaxValue, + // query => query.WhereRaw( + // "((gen_begindate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_begindate < '" + String.Format("{0:yyyy-MM-dd}", end) + "') OR(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "'))" + // ) + // ); + + //Integrated in Query + //Only Enddate given + //public static Query EventDateFilterEnd_GeneratedColumn(this Query query, DateTime? begin, DateTime? end) => + // query.When( + // begin == DateTime.MinValue && end != DateTime.MaxValue, + // query => query.WhereRaw( + // "((gen_begindate > '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_begindate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "') OR (gen_enddate > '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_enddate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "'))" + // ) + // ); + + //Both Begin and Enddate given + public static Query EventDateFilterBeginEnd_GeneratedColumn(this Query query, DateTime? begin, DateTime? end) => + query + //Begin and enddate given + .When( + begin != DateTime.MinValue && end != DateTime.MaxValue, + query => query.WhereRaw( + "((gen_begindate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_begindate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "') OR (gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_enddate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "'))" + ) + ) + //only Begindate given + .When( + begin != DateTime.MinValue && end == DateTime.MaxValue, + query => query.WhereRaw( + "((gen_begindate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_begindate < '" + String.Format("{0:yyyy-MM-dd}", end) + "') OR(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "'))" + ) + ) + //only enddate given + .When( + begin == DateTime.MinValue && end != DateTime.MaxValue, + query => query.WhereRaw( + "((gen_begindate > '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_begindate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "') OR (gen_enddate > '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_enddate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "'))" + ) + ); + + ////EVENT Array of Tuples(begindate, enddate) + ////Both Begin and Enddate given + //public static Query EventDateFilterBeginEndArray_GeneratedColumn(this Query query, DateTime? begin, DateTime? end) => + // query.When( + // begin != DateTime.MinValue && end != DateTime.MaxValue, + // query => + + + + // query.WhereRaw( + // "((gen_begindate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_begindate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "') OR (gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_enddate < '" + String.Format("{0:yyyy-MM-dd}", end?.AddDays(1)) + "'))" + // ) + // ); + + #endregion + + #region Date_Query_Helpers Article + + //Article + //NEWS Usecase: Begindate filter shows all News that ends after requested date, and all News which begin before the requested date + + ////Only Begindate given + //public static Query ArticleDateNewsFilterBeginWithIN_GeneratedColumn(this Query query, DateTime? begin, DateTime? end) => + // query.When( + // begin != DateTime.MinValue && end == DateTime.MaxValue, + // query => query.WhereRaw( + // "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_begindate <= '" + String.Format("{0:yyyy-MM-dd}", begin) + "')" + // ) + // ); + + ////Only Enddate given + //public static Query ArticleDateNewsFilterEndWithIN_GeneratedColumn(this Query query, DateTime? begin, DateTime? end) => + // query.When( + // begin == DateTime.MinValue && end != DateTime.MaxValue, + // query => query.WhereRaw( + // "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", end) + "' AND gen_begindate <= '" + String.Format("{0:yyyy-MM-dd}", end) + "')" + // ) + // ); + + //Both Begindate and Enddate given + public static Query ArticleDateNewsFilterBeginEndWithIN_GeneratedColumn(this Query query, DateTime? begin, DateTime? end) => + query + //begindate and enddate given + .When( + begin != DateTime.MinValue && end != DateTime.MaxValue, + query => query.WhereRaw( + "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_begindate <= '" + String.Format("{0:yyyy-MM-dd}", end) + "')" + ) + ) + //only begindate given + .When( + begin != DateTime.MinValue && end == DateTime.MaxValue, + query => query.WhereRaw( + "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", begin) + "' AND gen_begindate <= '" + String.Format("{0:yyyy-MM-dd}", begin) + "')" + ) + ) + //only enddate given + .When( + begin == DateTime.MinValue && end != DateTime.MaxValue, + query => query.WhereRaw( + "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", end) + "' AND gen_begindate <= '" + String.Format("{0:yyyy-MM-dd}", end) + "')" + ) + ); + + #endregion + + #region Date_Query_Helpers EventShort + + //EventShort + //EVENTSHORT Usecase: all events which ends after the requested date + //REGULAR Behaviour = all events that begins after(=) the startdate and ends before (=) the enddate + //IN Behaviour = all events that ends after the startdate and begins before enddate (All events that are NOW) + + ////Only Begindate given + //public static Query EventShortDateFilterBegin_GeneratedColumn(this Query query, DateTime? start, DateTime? end, bool active) => + // query.When( + // start != DateTime.MinValue && end == DateTime.MaxValue && active, + // query => query.WhereRaw( + // "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "'))" + // ) + // ); + + ////Only Enddate given + //public static Query EventShortDateFilterEnd_GeneratedColumn(this Query query, DateTime? start, DateTime? end, bool active) => + // query.When( + // start == DateTime.MinValue && end != DateTime.MaxValue && active, + // query => query.WhereRaw( + // "(gen_enddate <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "'))" + // ) + // ); + + //Both Begin and Enddate given + public static Query EventShortDateFilterBeginEnd_GeneratedColumn(this Query query, DateTime? start, DateTime? end, bool active) => + query + //begindate and enddate + .When( + start != DateTime.MinValue && end != DateTime.MaxValue && active, + query => query.WhereRaw( + "((gen_begindate >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "') AND (gen_enddate <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "'))" + ) + ) + //only begindate + .When( + start != DateTime.MinValue && end == DateTime.MaxValue && active, + query => query.WhereRaw( + "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "'))" + ) + ) + //only enddate + .When( + start == DateTime.MinValue && end != DateTime.MaxValue && active, + query => query.WhereRaw( + "(gen_enddate <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "'))" + ) + ); + + + + ////Only Begindate given + //public static Query EventShortDateFilterBeginByRoom_GeneratedColumn(this Query query, DateTime? start, DateTime? end, bool active) => + // query.When( + // start != DateTime.MinValue && end == DateTime.MaxValue && active, + // query => query.WhereRaw( + // "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", start) + "'))" + // ) + // ); + + ////Only Enddate given + //public static Query EventShortDateFilterEndByRoom_GeneratedColumn(this Query query, DateTime? start, DateTime? end, bool active) => + // query.When( + // start == DateTime.MinValue && end != DateTime.MaxValue && active, + // query => query.WhereRaw( + // "(gen_enddate <= '" + String.Format("{0:yyyy-MM-dd}", end) + "'))" + // ) + // ); + + //Both Begin and Enddate given which allows Today Query (In behaviour) + public static Query EventShortDateFilter_GeneratedColumn(this Query query, DateTime? start, DateTime? end, bool inbehaviour, bool checktime) => + query + //begindate and enddate given normal behaviour + .When( + start != DateTime.MinValue && end != DateTime.MaxValue && !inbehaviour && checktime, + query => query.WhereRaw( + "((gen_begindate >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "') AND (gen_enddate <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "'))" + ) + ) + //begindate and enddate given IN behaviour + .When( + start != DateTime.MinValue && end != DateTime.MaxValue && inbehaviour && checktime, + query => query.WhereRaw( + "((gen_enddate >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "') AND (gen_begindate <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "'))" + ) + ) + //only begindate given normal + IN behaviour is the same + .When( + start != DateTime.MinValue && end == DateTime.MaxValue && checktime, + query => query.WhereRaw( + "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", start) + "')" + ) + ) + //only enddate given normal + IN behaviour is the same + .When( + start == DateTime.MinValue && end != DateTime.MaxValue && checktime, + query => query.WhereRaw( + "(gen_enddate <= '" + String.Format("{0:yyyy-MM-dd HH:mm:ss}", end) + "')" + ) + ) + //begindate and enddate given normal behaviour without time check + .When( + start != DateTime.MinValue && end != DateTime.MaxValue && !inbehaviour && !checktime, + query => query.WhereRaw( + "((gen_begindate >= '" + String.Format("{0:yyyy-MM-dd}", start) + "') AND (gen_enddate <= '" + String.Format("{0:yyyy-MM-dd}", end) + "'))" + ) + ) + //begindate and enddate given IN behaviour without time check + .When( + start != DateTime.MinValue && end != DateTime.MaxValue && inbehaviour && !checktime, + query => query.WhereRaw( + "((gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", start) + "') AND (gen_begindate <= '" + String.Format("{0:yyyy-MM-dd}", end) + "'))" + ) + ) + //only begindate given + .When( + start != DateTime.MinValue && end == DateTime.MaxValue && !checktime, + query => query.WhereRaw( + "(gen_enddate >= '" + String.Format("{0:yyyy-MM-dd}", start) + "')" + ) + ) + //only enddate given + .When( + start == DateTime.MinValue && end != DateTime.MaxValue && !checktime, + query => query.WhereRaw( + "(gen_enddate <= '" + String.Format("{0:yyyy-MM-dd}", end) + "')" + ) + ); + + #endregion + + #region DateTime_Query_Helpers_tsmultirange + + //Both Begin and Enddate given IN Behaviour + + public static Query DateFilter_GeneratedColumn(this Query query, DateTime? start, DateTime? end, string gen_tsrangecolumn) => + query + .When( + //Both given, Adds a Day to End, if Endday has no time given add a day + start != null && end != null, + query => query.WhereRaw( + String.Format("gen_eventdates && tsrange('\\[{0},{1}\\]')", String.Format("{0:yyyy-MM-dd HH:mm}", start), String.Format("{0:yyyy-MM-dd HH:mm}", end.Value.TimeOfDay == TimeSpan.Zero ? end.Value.AddDays(1) : end)) + )) + .When( + //Only End given setting start to datetime min, if Endday has no time given add a day + start == null && end != null, + query => query.WhereRaw( + String.Format("gen_eventdates && tsrange('\\[{0},{1}\\]')", String.Format("{0:yyyy-MM-dd HH:mm}", DateTime.MinValue), String.Format("{0:yyyy-MM-dd HH:mm}", end.Value.TimeOfDay == TimeSpan.Zero ? end.Value.AddDays(1) : end)) + )) + .When( + //Addds a Day to End + start != null && end == null, + query => query.WhereRaw( + String.Format("gen_eventdates && tsrange('\\[{0},{1}\\]')", String.Format("{0:yyyy-MM-dd HH:mm}", start), String.Format("{0:yyyy-MM-dd HH:mm}", DateTime.MaxValue)) + )); + + + #endregion + + #region Opendata_LTS_Rules + + //anonymous -> where (closeddata = false and source != lts) OR (reduced = true and source = lts and cc0 = true) + //logged -> where (source != lts) OR (reduced = true and source = lts) + //idmuser -> where (source != lts) OR (reduced = false and source = lts) + //public static Query Anonymous_Logged_UserRule_GeneratedColumn(this Query query, bool closeddatafilter, bool idmuser) => + // idmuser ? query.FilterSourceReducedLogged(false) : closeddatafilter ? query.FilterSourceReducedAnonymous() : query.FilterSourceReducedLogged(true); + + //public static Query FilterSourceReducedLogged(this Query query, bool reduced) => + // query.Where(q => + // q.WhereRaw( + // "(gen_source <> 'lts')" + // ).OrWhereRaw( + // "(gen_source = 'lts' AND gen_reduced = $$)", reduced + // ) + // ); + + //public static Query FilterSourceReducedAnonymous(this Query query) => + // query.Where(q => + // q.WhereRaw( + // "(gen_source <> 'lts' AND (gen_licenseinfo_closeddata IS NULL OR gen_licenseinfo_closeddata = $$))", false + // ).OrWhereRaw( + // "(gen_source = 'lts' AND gen_reduced = true AND ((gen_licenseinfo_closeddata IS NULL OR gen_licenseinfo_closeddata = $$)))", false + // ) + // ); + + #endregion + + #region Filter by Roles + + + //TO REVISIT + //public static Query FilterDataByAccessRoles(this Query query, IEnumerable roles) => + // query.When(roles.Contains("ANONYMOUS"), q => q.Where(q => + // { + // foreach (var item in roles) + // { + // q = q.OrWhereRaw( + // "gen_access_role @> array\\[$$\\]", item.ToUpper() + // ); + // } + + // return q; + // })); + + public static Query FilterDataByAccessRoles(this Query query, IEnumerable roles) => + query.Where(q => + { + foreach (var item in roles) + { + q = q.OrWhereRaw( + "gen_access_role @> array\\[$$\\]", item.ToUpper() + ); + } + + return q; + }); + + ////Filter Out Reduced + public static Query FilterReducedDataByRoles(this Query query, IEnumerable roles) => + //Special Rule, if Role IDM is there filter out all reduced data + query.When(roles.Any(x => x == "IDM"), q => q.Where("gen_reduced", false)); + + + #endregion + + #region AdditionalFilter + + public static Query FilterAdditionalDataByCondition(this Query query, string? condition) + { + if (condition != null && condition.Contains("=")) + { + var splittedcondition = condition.Split("&").Select(x => x.Split("=")).Select(x => new ReadCondition() { Column = x[0], Value = x[1] }); + + var itemstoadd = splittedcondition.GroupBy(x => x.Column).Where(g => g.Count() == 1).ToList(); + foreach (var item in itemstoadd) + { + query.GetAdditionalFilterQueryByInput(item.Key, item.Select(x => x.Value).FirstOrDefault()); + } + + var itemstomerge = splittedcondition.GroupBy(x => x.Column).Where(g => g.Count() > 1).ToList(); + foreach (var item in itemstomerge) + { + query.GetAdditionalFilterQueryByInput(item.Key, item.Select(x => x.Value).ToList()); + } + } + + return query; + } + + public static Query GetAdditionalFilterQueryByInput(this Query query, string input, string value) + { + switch (input) + { + case "source": + return query.Where("gen_source", value); + case "accessrole": + return query.WhereRaw("gen_access_role @> array\\[$$\\]", value); + default: + return query.Where("data->>'" + input + "'", value); + } + } + + public static Query GetAdditionalFilterQueryByInput(this Query query, string input, List values) + { + switch (input) + { + case "source": + return query.WhereIn("gen_source", values); + case "accessrole": + return query.FilterDataByAccessRoles(values); + default: + return query.WhereIn("data->>'" + input + "'", values); + } + } + + + + #endregion + } + + public class ReadCondition + { + public string Column { get; set; } + public string Query { get; set; } + public string Value { get; set; } + } + + +} diff --git a/Helper/Postgres/PostgresSQLWhereBuilder.cs b/Helper/Postgres/PostgresSQLWhereBuilder.cs new file mode 100644 index 0000000..e740c04 --- /dev/null +++ b/Helper/Postgres/PostgresSQLWhereBuilder.cs @@ -0,0 +1,296 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using SqlKata; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace Helper +{ + public static class PostgresSQLWhereBuilder + { + private static readonly string[] _languagesToSearchFor = + new[] { "de", "it", "en", "nl", "cs", "pl", "fr", "pl" }; + + + + + /// + /// Provide title fields as JsonPath + /// + /// + /// If provided only the fields with the + /// specified language get returned + /// + public static string[] TitleFieldsToSearchFor(string? language) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true + ).Select(lang => + $"Detail.{lang}.Title" + ).ToArray(); + + public static string[] TitleFieldsToSearchFor(string? language, IReadOnlyCollection? haslanguage) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true && + haslanguage != null ? haslanguage.Contains(lang) : true + ).Select(lang => + $"Detail.{lang}.Title" + ).ToArray(); + + public static string[] AccoTitleFieldsToSearchFor(string? language) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true + ).Select(lang => + $"AccoDetail.{lang}.Name" + ).ToArray(); + + public static string[] AccoTitleFieldsToSearchFor(string? language, IReadOnlyCollection? haslanguage) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true && + haslanguage != null ? haslanguage.Contains(lang) : true + ).Select(lang => + $"AccoDetail.{lang}.Name" + ).ToArray(); + + public static string[] AccoRoomNameFieldsToSearchFor(string? language) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true + ).Select(lang => + $"AccoRoomDetail.{lang}.Name" + ).ToArray(); + + public static string[] AccoRoomNameFieldsToSearchFor(string? language, IReadOnlyCollection? haslanguage) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true && + haslanguage != null ? haslanguage.Contains(lang) : true + ).Select(lang => + $"AccoRoomDetail.{lang}.Name" + ).ToArray(); + + public static string[] EventShortTitleFieldsToSearchFor(string? language) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true + ).Select(lang => + $"EventTitle.{lang}" + ).ToArray(); + + public static string[] EventShortTitleFieldsToSearchFor(string? language, IReadOnlyCollection? haslanguage) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true && + haslanguage != null ? haslanguage.Contains(lang) : true + ).Select(lang => + $"EventTitle.{lang}" + ).ToArray(); + + public static string[] TourismMetaDataTitleFieldsToSearchFor(string? language) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true + ).Select(lang => + $"ApiDescription.{lang}" + ).ToArray(); + + //TODO TRANSFORM LANGUAGE to deu,eng,ita + //public static string[] VenueTitleFieldsToSearchFor(string? language) => + // _languagesToSearchFor.Where(lang => + // language != null ? lang == language : true + // ).Select(lang => + // $"attributes.name.{TransformLanguagetoDDStandard(lang)}" + // ).ToArray(); + + //public static string TransformLanguagetoDDStandard(string language) => language switch + //{ + // "de" => "deu", + // "it" => "ita", + // "en" => "eng", + // _ => language + //}; + + + //TODO search name example + //name: { + // deu: "Akademie deutsch-italienischer Studien", + // ita: "Accademia di studi italo-tedeschi", + // eng: "Academy of German-Italian Studies" + // }, + //private static string[] VenueTitleFieldsToSearchFor(string? language) => + // _languagesToSearchFor.Where(lang => + // language != null ? lang == language : true + // ).Select(lang => + // $"odhdata.Detail.{lang}.Name" + // ).ToArray(); + + //Public for use in Controllers directly + public static string[] TypeDescFieldsToSearchFor(string? language) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true + ).Select(lang => + $"TypeDesc.{lang}" + ).ToArray(); + + public static string[] TagNameFieldsToSearchFor(string? language) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true + ).Select(lang => + $"TagName.{lang}" + ).ToArray(); + + public static string[] NameFieldsToSearchFor(string? language) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true + ).Select(lang => + $"Name.{lang}" + ).ToArray(); + + public static string[] WeatherHistoryFieldsToSearchFor(string? language) => + _languagesToSearchFor.Where(lang => + language != null ? lang == language : true + ).Select(lang => + $"Weather.{lang}.evolutiontitle" + ).ToArray(); + + public static void CheckPassedLanguage(ref string language, IEnumerable availablelanguages) + { + language = language.ToLower(); + + if (!availablelanguages.Contains(language)) + throw new Exception("passed language not available or passed incorrect string"); + } + + //Return where and Parameters + [System.Diagnostics.Conditional("TRACE")] + private static void LogMethodInfo(System.Reflection.MethodBase m, params object?[] parameters) + { + var parameterInfo = + m.GetParameters() + .Zip(parameters) + .Select((x, _) => (x.First.Name, x.Second)); + Serilog.Log.Debug("{method}({@parameters})", m.Name, parameterInfo); + } + + + //Return Where and Parameters for Example + public static Query ExampleWhereExpression( + this Query query, IReadOnlyCollection languagelist, + IReadOnlyCollection idlist, IReadOnlyCollection typelist, bool? activefilter, IReadOnlyCollection sourcelist, + IReadOnlyCollection publishedonlist, string? searchfilter, string? language, string? lastchange, string? additionalfilter, + IEnumerable userroles) + { + LogMethodInfo( + System.Reflection.MethodBase.GetCurrentMethod()!, + "", // not interested in query + idlist, typelist, languagelist, activefilter, sourcelist, publishedonlist, searchfilter, language, lastchange + ); + + return query + .IdUpperFilter(idlist) + .When(typelist.Count > 0, q => q.ArticleTypeFilterOr_GeneratedColumn(typelist)) + .When(languagelist.Count > 0, q => q.HasLanguageFilterAnd_GeneratedColumn(languagelist)) //.HasLanguageFilter(languagelist) + .ActiveFilter_GeneratedColumn(activefilter) //OK GENERATED COLUMNS //.ActiveFilter(activefilter) + .PublishedOnFilter_GeneratedColumn(publishedonlist) //.PublishedOnFilter(publishedonlist) + //.SyncSourceInterfaceFilter_GeneratedColumn(sourcelist) + .SourceFilter_GeneratedColumn(sourcelist) + .LastChangedFilter_GeneratedColumn(lastchange) + .SearchFilter(TitleFieldsToSearchFor(language, languagelist), searchfilter) + .When(!String.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + .FilterDataByAccessRoles(userroles); + } + + + //Return Where and Parameters for OdhTag and Tag + public static Query PublishersWhereExpression( + this Query query, IReadOnlyCollection languagelist, + IReadOnlyCollection idlist, IReadOnlyCollection sourcelist, + string? searchfilter, string? language, + string? additionalfilter, + IEnumerable userroles) + { + LogMethodInfo( + System.Reflection.MethodBase.GetCurrentMethod()!, + "", // not interested in query + searchfilter, language, sourcelist + ); + + return query + .SearchFilter(NameFieldsToSearchFor(language), searchfilter) + .SourceFilter_GeneratedColumn(sourcelist) + .When(idlist != null && idlist.Count > 0, q => query.WhereIn("id", idlist)) + .When(!String.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + .FilterDataByAccessRoles(userroles); + } + + public static Query SourcesWhereExpression( + this Query query, IReadOnlyCollection languagelist, + IReadOnlyCollection idlist, IReadOnlyCollection typeslist, + string? searchfilter, string? language, + string? additionalfilter, + IEnumerable userroles) + { + LogMethodInfo( + System.Reflection.MethodBase.GetCurrentMethod()!, + "", // not interested in query + searchfilter, language, idlist + ); + + return query + .SearchFilter(NameFieldsToSearchFor(language), searchfilter) + .When(idlist != null && idlist.Count > 0, q => query.WhereIn("id", idlist)) + .When(typeslist != null && typeslist.Count > 0, q => query.SourceTypeFilter(typeslist)) + .When(!String.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + .FilterDataByAccessRoles(userroles); + } + + public static Query PushResultWhereExpression( + this Query query, + IReadOnlyCollection idlist, IReadOnlyCollection publisherlist, + DateTime? begin, DateTime? end, + IReadOnlyCollection objectidlist, IReadOnlyCollection objecttypelist, + string? additionalfilter) + { + LogMethodInfo( + System.Reflection.MethodBase.GetCurrentMethod()!, + "", // not interested in query + publisherlist, begin, end, idlist + ); + + return query + .When(idlist != null && idlist.Count > 0, q => query.WhereIn("id", idlist)) + .When(publisherlist != null && publisherlist.Count > 0, q => query.WhereIn("gen_publisher", publisherlist)) + .When(objectidlist != null && objectidlist.Count > 0, q => query.WhereIn("gen_objectid", objectidlist)) + .When(objecttypelist != null && objecttypelist.Count > 0, q => query.WhereIn("gen_objecttype", objecttypelist)) + .LastChangedFilter_GeneratedColumn(begin, end) + .When(!String.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)); + + } + + + //Return Where and Parameters for Rawdata + public static Query RawdataWhereExpression( + this Query query, IReadOnlyCollection idlist, IReadOnlyCollection sourceidlist, + IReadOnlyCollection typelist, IReadOnlyCollection sourcelist, + string? additionalfilter, + IEnumerable userroles) + { + LogMethodInfo( + System.Reflection.MethodBase.GetCurrentMethod()!, + "", // not interested in query + idlist, sourceidlist, typelist, + sourcelist + ); + + return query + .When(typelist != null, q => query.WhereIn("type", typelist)) + .When(sourcelist != null, q => query.WhereIn("datasource", sourcelist)) + .When(idlist != null, q => query.WhereIn("id", idlist)) + //.When(latest, ) + //.When(filterClosedData, q => q.FilterClosedData_Raw()); + .When(!String.IsNullOrEmpty(additionalfilter), q => q.FilterAdditionalDataByCondition(additionalfilter)) + .FilterDataByAccessRoles(userroles); + //TODO future opendata rules on + //.Anonymous_Logged_UserRule_GeneratedColumn(filterClosedData, !reducedData); + } + + } +} diff --git a/Helper/PushServer/PushServerMessageHelper.cs b/Helper/PushServer/PushServerMessageHelper.cs new file mode 100644 index 0000000..ea90b14 --- /dev/null +++ b/Helper/PushServer/PushServerMessageHelper.cs @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public class PushServerMessageHelper + { + public static PushServerMessage GetPuhServerMessage(string title, string text, string language, string group, string? image = null, string? video = null) + { + var message = new PushServerMessage(); + message.text = text; + message.title = title; + message.video = video ?? ""; + message.image = image ?? ""; + var destination = new PushServerDestination(); + destination.group = group; + destination.language = language; + + return message; + } + } +} diff --git a/Helper/Reduced/GpsHelper.cs b/Helper/Reduced/GpsHelper.cs new file mode 100644 index 0000000..0e65799 --- /dev/null +++ b/Helper/Reduced/GpsHelper.cs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using SqlKata.Execution; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public class GpsHelper + { + public static async Task> GetReducedWithGPSInfoList(QueryFactory QueryFactory, string table) + { + try + { + List reducedlist = new List(); + + string select = "data#>>'\\{Id\\}' as Id, (data#>>'\\{Latitude\\}')::double precision as Latitude, (data#>>'\\{Longitude\\}')::double precision as Longitude, data#>>'\\{_Meta,Type\\}' as Type"; + + var query = QueryFactory.Query(table) + .SelectRaw(select); + + var data = + await query + .GetAsync(); + + return data; + } + catch (Exception ex) + { + return new List(); + } + } + } + + public class ReducedWithGPSInfo + { + public double Latitude { get; set; } + public double Longitude { get; set; } + + public string Id { get; set; } + + public string Type { get; set; } + } +} diff --git a/Helper/Requests/RemoteIpHelper.cs b/Helper/Requests/RemoteIpHelper.cs new file mode 100644 index 0000000..a68dac5 --- /dev/null +++ b/Helper/Requests/RemoteIpHelper.cs @@ -0,0 +1,79 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Helper +{ + public static class RemoteIpHelper + { + public static string? GetRequestIP(HttpContext context, bool tryUseXForwardHeader = true) + { + string? ip = null; + + // X-Forwarded-For (csv list): Using the First entry in the list seems to work + // for 99% of cases however it has been suggested that a better (although tedious) + // approach might be to read each IP from right to left and use the first public IP. + // http://stackoverflow.com/a/43554000/538763 + // + if (tryUseXForwardHeader) + ip = GetHeaderValueAs("X-Forwarded-For", context)?.SplitCsv()?.FirstOrDefault(); + + // RemoteIpAddress is always null in DNX RC1 Update1 (bug). + if (ip.IsNullOrWhitespace() && context?.Connection?.RemoteIpAddress != null) + ip = context.Connection.RemoteIpAddress.ToString(); + + if (ip.IsNullOrWhitespace() && context != null) + ip = GetHeaderValueAs("REMOTE_ADDR", context); + + // _httpContextAccessor.HttpContext?.Request?.Host this is the local host. + + //Tests are not running with this exception + //if (ip.IsNullOrWhitespace()) + // throw new Exception("Unable to determine caller's IP."); + + if (ip.IsNullOrWhitespace()) + return ""; + + return ip; + } + + public static T? GetHeaderValueAs(string headerName, HttpContext context) + { + StringValues values = new StringValues(); + + if (context?.Request?.Headers?.TryGetValue(headerName, out values) ?? false) + { + string rawValues = values.ToString(); // writes out as Csv when there are multiple. + + if (!rawValues.IsNullOrWhitespace()) + return (T)Convert.ChangeType(values.ToString(), typeof(T)); + } + return default(T); + } + + private static List? SplitCsv(this string csvList, bool nullOrWhitespaceInputReturnsNull = false) + { + if (string.IsNullOrWhiteSpace(csvList)) + return nullOrWhitespaceInputReturnsNull ? null : new List(); + + return csvList + .TrimEnd(',') + .Split(',') + .AsEnumerable() + .Select(s => s.Trim()) + .ToList(); + } + + private static bool IsNullOrWhitespace(this string? s) + { + return String.IsNullOrWhiteSpace(s); + } + } +} diff --git a/Helper/S3/GetDataFromS3.cs b/Helper/S3/GetDataFromS3.cs new file mode 100644 index 0000000..b715475 --- /dev/null +++ b/Helper/S3/GetDataFromS3.cs @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Amazon.S3; +using Amazon.S3.Transfer; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static Dapper.SqlMapper; + +namespace Helper.S3 +{ + public class GetDataFromS3 + { + public static async Task GetFileFromS3(string bucketname, string accesskey, string secretkey, string filename, string directorytosave) + { + TransferUtility fileTransferUtility = + new TransferUtility( + new AmazonS3Client(accesskey, secretkey, Amazon.RegionEndpoint.EUWest1)); + + var request = new TransferUtilityDownloadRequest() + { + BucketName = bucketname, + Key = filename, + FilePath = directorytosave + filename + }; + + await fileTransferUtility.DownloadAsync(request); + } + } +} diff --git a/Helper/StringHelpers.cs b/Helper/StringHelpers.cs new file mode 100644 index 0000000..ab9215e --- /dev/null +++ b/Helper/StringHelpers.cs @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Helper +{ + public class StringHelpers + { + public static string RemoveSpecialCharacters(string value, char[] specialCharacters) + { + return new String(value.Except(specialCharacters).ToArray()); + } + + public static Dictionary? GenerateDictionaryFromQuerystring(string value) + { + if (String.IsNullOrEmpty(value)) + return null; + else + { + Dictionary? myvaluedict = new Dictionary(); + + string valuenew = value.Replace("?",""); + + var splitted = valuenew.Split('&'); + + if (splitted.Count() > 0) + { + foreach(var splittedfield in splitted) + { + var splittedobj = splittedfield.Split('='); + if (splittedobj.Count() == 2) + myvaluedict.Add(splittedobj[0], splittedobj[1]); + } + + return myvaluedict; + } + else + return null; + } + } + + public static string JoinStringListForPG(string separator, IEnumerable list, string escapechar) + { + var newlist = list.Select(x => (escapechar + x + escapechar)).ToList(); + + return String.Join(separator, newlist); + } + } + + public static class StringExtensions + { + public static bool ConvertStringToBoolean(this string returnValue) + { + if (returnValue == "1") + { + return true; + } + else if (returnValue == "0") + { + return false; + } + else + { + throw new FormatException("The string is not a recognized as a valid boolean value."); + } + } + + public static string[] AddToStringArray(this string[] strarr, string value) + { + var strlist = strarr.ToList(); + strlist.Add(value); + + return strlist.ToArray(); + } + + public static string[] AddToStringArray(this string[] strarr, string[] values) + { + var strlist = strarr.ToList(); + + foreach (var value in values) + { + strlist.Add(value); + } + + return strlist.ToArray(); + } + + public static T TrimStringProperties(this T input) + { + if (input is null) + { + return input; + } + + var props = input.GetType() + .GetProperties(BindingFlags.Instance | BindingFlags.Public) + .Where(prop => prop.GetIndexParameters().Length == 0) + .Where(prop => prop.CanWrite && prop.CanRead); + + foreach (PropertyInfo prop in props) + { + var value = prop.GetValue(input, null); + + if (value is string stringValue && stringValue != null) + { + prop.SetValue(input, stringValue.Trim(), null); + } + else if (value is IEnumerable enumerable) + { + foreach (var item in enumerable) + { + TrimStringProperties(item); + } + } + } + + return input; + } + + } + + +} diff --git a/JsonLDTransformer/JsonLDTransformer.csproj b/JsonLDTransformer/JsonLDTransformer.csproj new file mode 100644 index 0000000..f0e8260 --- /dev/null +++ b/JsonLDTransformer/JsonLDTransformer.csproj @@ -0,0 +1,16 @@ + + + + net8.0 + + + + + + + + + + + + diff --git a/JsonLDTransformer/Objects/LDDataTypes.cs b/JsonLDTransformer/Objects/LDDataTypes.cs new file mode 100644 index 0000000..2fbc5fa --- /dev/null +++ b/JsonLDTransformer/Objects/LDDataTypes.cs @@ -0,0 +1,260 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace JsonLDTransformer.Objects +{ + public class ObjectLD + { + [JsonProperty(PropertyName = "@context", Order = 0)] + public string context { get; set; } + + [JsonProperty(PropertyName = "@type", Order = 1)] + public string type { get; set; } + + [JsonProperty(PropertyName = "@id", Order = 2)] + public string id { get; set; } + } + + + public class RecipeLD : ObjectLD + { + } + + public class EventLD : ObjectLD + { + [JsonProperty(Order = 3)] + public string name { get; set; } + + [JsonProperty(Order = 4)] + public string description { get; set; } + + [JsonProperty(Order = 5)] + public string image { get; set; } + + [JsonProperty(Order = 6)] + public string startDate { get; set; } + + [JsonProperty(Order = 7)] + public string endDate { get; set; } + + [JsonProperty(Order = 8)] + public string url { get; set; } + + [JsonProperty(Order = 9)] + public PlaceLD location { get; set; } + + [JsonProperty(Order = 10)] + public OfferLD offers { get; set; } + + [JsonProperty(Order = 11)] + public OrganizationLD organizer { get; set; } + + } + + public class RestaurantLD : ObjectLD + { + [JsonProperty(Order = 3)] + public string name { get; set; } + + [JsonProperty(Order = 4)] + public string image { get; set; } + + [JsonProperty(Order = 5)] + public string description { get; set; } + + [JsonProperty(Order = 6)] + public string telephone { get; set; } + + [JsonProperty(Order = 7)] + public string email { get; set; } + + [JsonProperty(Order = 8)] + public string url { get; set; } + + [JsonProperty(Order = 9)] + public addressLD address { get; set; } + + [JsonProperty(Order = 10)] + public geoLD geo { get; set; } + + [JsonProperty(Order = 11)] + public List openingHours { get; set; } + + [JsonProperty(Order = 12)] + public List servesCuisine { get; set; } + + [JsonProperty(Order = 8)] + public personLD founder { get; set; } + + + } + + public class TouristAttractionLD : ObjectLD + { + } + + public class ArticleLD : ObjectLD + { + } + + public class SkiResortLD : ObjectLD + { + } + + public class OrganizationLD : ObjectLD + { + [JsonProperty(Order = 3)] + public string name { get; set; } + + [JsonProperty(Order = 4)] + public string telephone { get; set; } + + [JsonProperty(Order = 5)] + public string email { get; set; } + + [JsonProperty(Order = 6)] + public string url { get; set; } + + [JsonProperty(Order = 7)] + public addressLD address { get; set; } + + } + + public class PlaceLD + { + [JsonProperty(PropertyName = "@type", Order = 0)] + public string type { get; set; } + + [JsonProperty(Order = 1)] + public string name { get; set; } + + [JsonProperty(Order = 2)] + public addressLD address { get; set; } + } + + public class OfferLD + { + [JsonProperty(PropertyName = "@type", Order = 0)] + public string type { get; set; } + + [JsonProperty(Order = 1)] + public string name { get; set; } + + [JsonProperty(Order = 2)] + public string description { get; set; } + + [JsonProperty(Order = 3)] + public string url { get; set; } + + [JsonProperty(Order = 4)] + public string validFrom { get; set; } + + [JsonProperty(Order = 5)] + public string validTrough { get; set; } + + [JsonProperty(Order = 6)] + public string price { get; set; } + + [JsonProperty(Order = 7)] + public string priceCurrency { get; set; } + } + + public class LodgingBusinessLD : ObjectLD + { + } + + public class BookLD : ObjectLD + { + } + + public class StoreLD : ObjectLD + { + } + + public class LocalBusinessLD : ObjectLD + { + } + + public class HotelLD : ObjectLD + { + //[JsonProperty(PropertyName = "@context", Order = 0)] + //public string context { get; set; } + + //[JsonProperty(PropertyName = "@type", Order = 1)] + //public string type { get; set; } + + //[JsonProperty(PropertyName = "@id", Order = 2)] + //public string id { get; set; } + + [JsonProperty(Order = 3)] + public string name { get; set; } + + [JsonProperty(Order = 4)] + public string image { get; set; } + + [JsonProperty(Order = 5)] + public string description { get; set; } + + [JsonProperty(Order = 6)] + public string telephone { get; set; } + + [JsonProperty(Order = 7)] + public string email { get; set; } + + [JsonProperty(Order = 8)] + public string url { get; set; } + + [JsonProperty(Order = 9)] + public addressLD address { get; set; } + + [JsonProperty(Order = 10)] + public geoLD geo { get; set; } + } +} + +//Wiederverwendete Propertys +public class addressLD +{ + [JsonProperty(PropertyName = "@type", Order = 0)] + public string type { get; set; } + + [JsonProperty(Order = 1)] + public string streetAddress { get; set; } + [JsonProperty(Order = 2)] + public string postalCode { get; set; } + [JsonProperty(Order = 3)] + public string addressLocality { get; set; } + [JsonProperty(Order = 4)] + public string addressRegion { get; set; } + [JsonProperty(Order = 5)] + public string addressCountry { get; set; } +} + +public class geoLD +{ + [JsonProperty(PropertyName = "@type", Order = 0)] + public string type { get; set; } + + [JsonProperty(Order = 1)] + public double latitude { get; set; } + [JsonProperty(Order = 2)] + public double longitude { get; set; } +} + +public class personLD +{ + [JsonProperty(PropertyName = "@type", Order = 0)] + public string type { get; set; } + + [JsonProperty(Order = 1)] + public string name { get; set; } + +} \ No newline at end of file diff --git a/JsonLDTransformer/TransformToSchemaNet.cs b/JsonLDTransformer/TransformToSchemaNet.cs new file mode 100644 index 0000000..d671e29 --- /dev/null +++ b/JsonLDTransformer/TransformToSchemaNet.cs @@ -0,0 +1,231 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using JsonLDTransformer.Objects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Schema.NET; +using System.Xml; +using HtmlAgilityPack; +using DataModel; +using Newtonsoft.Json; + +namespace JsonLDTransformer +{ + public class TransformToSchemaNet + { + public static List TransformDataToSchemaNet(T data, string currentroute, string type, string language, object parentobject = null, string idtoshow = "", string urltoshow = "", string imageurltoshow = "", bool showid = true) + { + var objectlist = new List(); + + switch (type) + { + case "example": + objectlist.Add(TransformExampleToLD((DataModel.Example)(object)data, currentroute, language, idtoshow, urltoshow, imageurltoshow, showid)); + break; + } + + + return objectlist; + } + + #region Place + + private static Schema.NET.Place TransformExampleToLD(DataModel.Example placetotrasform, string currentroute, string language, string passedid, string passedurl, string passedimage, bool showid) + { + string fallbacklanguage = "en"; + + Schema.NET.Place place = new Schema.NET.Place(); + + if (showid) + { + if (String.IsNullOrEmpty(passedid)) + place.Id = new Uri(currentroute); + else + place.Id = new Uri(passedid); + } + + place.Description = placetotrasform.Detail.ContainsKey(language) ? placetotrasform.Detail[language].BaseText : placetotrasform.Detail.ContainsKey(fallbacklanguage) ? placetotrasform.Detail[fallbacklanguage].BaseText : ""; + place.Name = placetotrasform.Detail.ContainsKey(language) ? placetotrasform.Detail[language].Title : placetotrasform.Detail.ContainsKey(fallbacklanguage) ? placetotrasform.Detail[fallbacklanguage].Title : ""; + + place.FaxNumber = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].Faxnumber : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].Faxnumber : ""; + place.Telephone = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].Phonenumber : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].Phonenumber : ""; + + //Image Overwrite + if (String.IsNullOrEmpty(passedimage)) + { + if (placetotrasform.ImageGallery != null) + if (placetotrasform.ImageGallery.Count > 0) + if (!String.IsNullOrEmpty(placetotrasform.ImageGallery.FirstOrDefault().ImageUrl)) + place.Image = new Uri(placetotrasform.ImageGallery.FirstOrDefault().ImageUrl); + } + else + place.Image = new Uri(passedimage); + + // URL OVERWRITE + if (String.IsNullOrEmpty(passedurl) && String.IsNullOrEmpty(passedid)) + { + string url = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].Url : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].Url : ""; + if (CheckURLValid(url)) + place.Url = new Uri(url); + } + else if (!String.IsNullOrEmpty(passedurl)) + { + if (CheckURLValid(passedurl)) + place.Url = new Uri(passedurl); + } + else if (!String.IsNullOrEmpty(passedid)) + { + if (CheckURLValid(passedid)) + place.Url = new Uri(passedid); + } + + string logo = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].LogoUrl : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].LogoUrl : ""; + if (CheckURLValid(logo)) + place.Logo = new Uri(logo); + + + PostalAddress myaddress = new PostalAddress(); + //myaddress.Type = "http://schema.org/PostalAddress"; + myaddress.StreetAddress = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].Address : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].Address : ""; + myaddress.PostalCode = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].ZipCode : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].ZipCode : ""; + myaddress.AddressLocality = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].City : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].City : ""; + myaddress.AddressRegion = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].Region : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].Region : ""; + myaddress.AddressCountry = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].CountryName : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].CountryName : ""; + myaddress.Telephone = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].Phonenumber : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].Phonenumber : ""; + + string adressurl = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].Url : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].Url : ""; + if (CheckURLValid(adressurl)) + myaddress.Url = new Uri(adressurl); + + myaddress.Email = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].Email : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].Email : ""; + myaddress.FaxNumber = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].Faxnumber : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].Faxnumber : ""; + myaddress.AlternateName = placetotrasform.ContactInfos.ContainsKey(language) ? placetotrasform.ContactInfos[language].CompanyName : placetotrasform.ContactInfos.ContainsKey(fallbacklanguage) ? placetotrasform.ContactInfos[fallbacklanguage].CompanyName : ""; + myaddress.Name = placetotrasform.Detail.ContainsKey(language) ? placetotrasform.Detail[language].Title : placetotrasform.Detail.ContainsKey(fallbacklanguage) ? placetotrasform.Detail[fallbacklanguage].Title : ""; + + + place.Address = myaddress; + + GeoCoordinates mygeo = new GeoCoordinates(); + //mygeo.Type = "http://schema.org/GeoCoordinates"; + mygeo.Latitude = placetotrasform.GpsPoints.ContainsKey("position") ? placetotrasform.GpsPoints["position"].Latitude : 0; + mygeo.Longitude = placetotrasform.GpsPoints.ContainsKey("position") ? placetotrasform.GpsPoints["position"].Longitude : 0; + + place.Geo = mygeo; + + return place; + } + + #endregion + + + public static bool CheckURLValid(string source) + { + Uri uriResult; + return Uri.TryCreate(source, UriKind.Absolute, out uriResult) && uriResult.Scheme == Uri.UriSchemeHttp; + } + } + + public class RecipeDetails + { + public TimeSpan cookTime { get; set; } + public string recipeYield { get; set; } + public List recipeIngredients { get; set; } + public string recipeInstructions { get; set; } + + //NEW + //"kalorien" --> nutrition (Nutritioninformation.... calories) + public NutritionInformation recipeNutritionInfo { get; set; } + //"vorbereitungszeit" --> prepTime (Duration) + public TimeSpan prepTime { get; set; } + //"keywords" --> keywords (TEXT) + public string recipeKeywords { get; set; } + //"kategorie" --> recipecategory (TEXT) + public string recipeCategory { get; set; } + + //"artkueche" --> recipecousine (TEXT) + public string recipeCuisinetype { get; set; } + + + //"author" --> author (Organization or Person) + public Organization author { get; set; } + + //"bewertung" --> aggregaterating (Aggregaterating) + public AggregateRating aggregateRating { get; set; } + + + } + + public class SpecialAnnouncement : Schema.NET.CreativeWork + { + [System.Runtime.Serialization.DataMemberAttribute(Name = "@type", Order = 1)] + public new string Type { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "datePosted")] + [JsonConverter(typeof(DateTimeToIso8601DateValuesJsonConverter))] + public Values DatePosted { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "announcementLocation")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values AnnouncementLocation { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "category")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values Category { get; set; } + + //Webcontent is missing using text + + [System.Runtime.Serialization.DataMemberAttribute(Name = "diseasePreventionInfo")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values DiseasePreventionInfo { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "diseaseSpreadStatistics")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values DiseaseSpreadStatistics { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "gettingTestedInfo")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values GettingTestedInfo { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "governmentBenefitsInfo")] + [JsonConverter(typeof(ValuesJsonConverter))] + public OneOrMany GovernmentBenefitsInfo { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "newsUpdatesAndGuidelines")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values NewsUpdatesAndGuidelines { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "publicTransportClosuresInfo")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values PublicTransportClosuresInfo { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "quarantineGuidelines")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values QuarantineGuidelines { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "schoolClosuresInfo")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values SchoolClosuresInfo { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "travelBans")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values TravelBans { get; set; } + + //Missing props of CreativeWork + [System.Runtime.Serialization.DataMemberAttribute(Name = "abstract")] + [JsonConverter(typeof(ValuesJsonConverter))] + public OneOrMany Abstract { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "copyrightNotice")] + [JsonConverter(typeof(ValuesJsonConverter))] + public OneOrMany CopyrightNotice { get; set; } + + [System.Runtime.Serialization.DataMemberAttribute(Name = "sdPublisher")] + [JsonConverter(typeof(ValuesJsonConverter))] + public Values SdPublisher { get; set; } + } +} diff --git a/LICENSES/AGPL-3.0-or-later.txt b/LICENSES/AGPL-3.0-or-later.txt new file mode 100644 index 0000000..0c97efd --- /dev/null +++ b/LICENSES/AGPL-3.0-or-later.txt @@ -0,0 +1,235 @@ +GNU AFFERO GENERAL PUBLIC LICENSE +Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + + Preamble + +The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. + +Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. + +A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. + +The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. + +An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. + +The precise terms and conditions for copying, distribution and modification follow. + + TERMS AND CONDITIONS + +0. Definitions. + +"This License" refers to version 3 of the GNU Affero General Public License. + +"Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based on the Program. + +To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. + +An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. + +1. Source Code. +The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. + +A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same work. + +2. Basic Permissions. +All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. + +3. Protecting Users' Legal Rights From Anti-Circumvention Law. +No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. + +When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. + +4. Conveying Verbatim Copies. +You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. + +5. Conveying Modified Source Versions. +You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". + + c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. + +A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. + +6. Conveying Non-Source Forms. +You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: + + a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. + + d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. + +"Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. + +If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). + +The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. + +Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. + +7. Additional Terms. +"Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or authors of the material; or + + e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. + +All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. + +8. Termination. + +You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). + +However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. + +Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. + +Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. + +9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. + +10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. + +11. Patents. + +A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. + +If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. + +A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. + +12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. + +13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. + +Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. + +14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. + +Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. + +15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. + +To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + +If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. + +You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/LICENSES/CC0-1.0.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 0000000..2071b23 --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/OdhNotifier/OdhNotifier.csproj b/OdhNotifier/OdhNotifier.csproj new file mode 100644 index 0000000..40f99c3 --- /dev/null +++ b/OdhNotifier/OdhNotifier.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + diff --git a/OdhNotifier/OdhPushNotifierMeta.cs b/OdhNotifier/OdhPushNotifierMeta.cs new file mode 100644 index 0000000..f935c62 --- /dev/null +++ b/OdhNotifier/OdhPushNotifierMeta.cs @@ -0,0 +1,600 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Helper; +using Microsoft.AspNetCore.Components.RenderTree; +using Microsoft.AspNetCore.Server.IIS.Core; +using MongoDB.Driver; +using Newtonsoft.Json.Linq; +using OdhNotifier; +using SqlKata; +using SqlKata.Execution; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.ComponentModel; +using System.Net; +using System.Net.Http.Headers; +using System.Net.Http.Json; +using System.Reflection; +using System.Runtime.Intrinsics.Arm; +using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; + +namespace OdhNotifier +{ + public interface IOdhPushNotifier + { + Task> PushToAllRegisteredServices(string id, string type, string updatemode, IDictionary? additionalpushinfo, bool isdelete, string origin, string? referer = null, List? excludeservices = null); + Task> PushToPublishedOnServices(string id, string type, string updatemode, IDictionary? additionalpushinfo, bool isdelete, string origin, List publishedonlist, string? referer = null); + Task>> PushFailureQueueToPublishedonService(List publishedonlist, int elementstoprocess, string? referer = null); + Task>> PushCustomObjectsToPublishedonService(List publishedonlist, List idlist, string odhtype, IDictionary? additionalpushinfo, string? referer = null); + } + + public class OdhPushNotifier : IOdhPushNotifier, IDisposable + { + private readonly ISettings settings; + protected QueryFactory QueryFactory { get; } + + List notifierconfiglist; + + public OdhPushNotifier(ISettings settings, QueryFactory queryFactory) + { + this.settings = settings; + this.QueryFactory = queryFactory; + + this.notifierconfiglist = settings.NotifierConfig; + } + + /// + /// Pushes to all registered Services in config, a service can be manually excluded by passing and exclude list + /// + /// + /// + /// + /// + /// + /// + /// + public async Task> PushToAllRegisteredServices(string id, string type, string updatemode, IDictionary? additionalpushinfo, bool isdelete, string origin, string? referer = null, List? excludeservices = null) + { + IDictionary notifierresponselist = new Dictionary(); + + foreach (var notifyconfig in notifierconfiglist) + { + if (excludeservices != null && excludeservices.Contains(notifyconfig.ServiceName.ToLower())) + continue; + + NotifyMetaGenerated meta = new NotifyMetaGenerated(notifyconfig, id, type, additionalpushinfo, isdelete, updatemode, origin, referer); + + NotifierResponse notifierresponse = new NotifierResponse(); + + var response = await SendNotify(meta); + notifierresponse.HttpStatusCode = response.Item1; + notifierresponse.Response = response.Item2; + notifierresponse.Service = notifyconfig.ServiceName; + notifierresponse.Success = MapStatusCodeToSuccessProperty(notifierresponse.HttpStatusCode); + + notifierresponselist.TryAddOrUpdate(notifyconfig.ServiceName, notifierresponse); + } + + return notifierresponselist; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public async Task> PushToPublishedOnServices(string id, string type, string updatemode, IDictionary? additionalpushinfo, bool isdelete, string origin, List publishedonlist, string? referer = null) + { + IDictionary notifierresponselist = new Dictionary(); + + //IF + foreach(var pushchannel in publishedonlist) + { + if(notifierconfiglist.Where(x => x.ServiceName.ToLower() == pushchannel.ToLower()).Count() == 0) + notifierresponselist.TryAddOrUpdate(pushchannel, new NotifierResponse() { Success = false, HttpStatusCode = HttpStatusCode.NotFound, Service = pushchannel, Response = "No configuration found for this publisher"}); + } + + foreach (var notifyconfig in notifierconfiglist) + { + if(publishedonlist.Contains(notifyconfig.ServiceName.ToLower())) + { + //Compare and push? + + NotifyMetaGenerated meta = new NotifyMetaGenerated(notifyconfig, id, type, additionalpushinfo, isdelete, updatemode, origin, referer); + + NotifierResponse notifierresponse = new NotifierResponse(); + + var response = await SendNotify(meta); + notifierresponse.HttpStatusCode = response.Item1; + notifierresponse.Response = response.Item2 ; + notifierresponse.Service = notifyconfig.ServiceName; + notifierresponse.Success = MapStatusCodeToSuccessProperty(notifierresponse.HttpStatusCode); + + notifierresponselist.TryAddOrUpdate(notifyconfig.ServiceName, notifierresponse); + } + } + + return notifierresponselist; + } + + private static bool MapStatusCodeToSuccessProperty(HttpStatusCode statusCode) + { + switch (statusCode) + { + case HttpStatusCode.OK: return true; + case HttpStatusCode.Created: return true; + default: return false; + } + } + private async Task> SendNotify(NotifyMeta notify, NotifierFailureQueue? failurequeuedata = null) + { + var requesturl = notify.Url; + + try + { + //If data is from failurequeue proceed directly + if (failurequeuedata != null || CheckValidTypes(notify)) + { + using (var client = new HttpClient()) + { + client.Timeout = TimeSpan.FromSeconds(5); + + //Add all Headers + if (notify.Headers != null) + { + foreach (var header in notify.Headers) + { + client.DefaultRequestHeaders.Add(header.Key, header.Value); + } + } + + //Add Referer Header + if (!String.IsNullOrEmpty(notify.Referer)) + client.DefaultRequestHeaders.Referrer = new Uri(notify.Referer); + + //Add Additional Parameters + if (notify.Parameters != null) + { + requesturl = requesturl + "?"; + foreach (var parameter in notify.Parameters) + { + requesturl = requesturl + parameter.Key + "=" + parameter.Value; + + if (notify.Parameters.Last().Key != parameter.Key) + { + requesturl = requesturl + "&"; + } + } + } + + HttpResponseMessage response = default(HttpResponseMessage); + + //GET or POST the data to the service + if (notify.Mode.ToLower() == "get") + { + response = await client.GetAsync(requesturl); + } + else if (notify.Mode.ToLower() == "post") + { + var data = new StringContent(JsonSerializer.Serialize(new + { + id = notify.Id, + entity = notify.NotifyType, + skipImage = notify.HasImagechanged ? false : true, + isHardDelete = notify.IsDelete + })); + + //If datatype is accommodation add the skiprooms + if(notify.Type == "accommodation") + data = new StringContent(JsonSerializer.Serialize(new + { + id = notify.Id, + entity = notify.NotifyType, + skipImage = notify.HasImagechanged ? false : true, + skipRooms = notify.Roomschanged.HasValue && notify.Roomschanged.Value ? false: true, + isHardDelete = notify.IsDelete + })); + + data.Headers.ContentType = new MediaTypeHeaderValue("application/json"); + + response = await client.PostAsync(requesturl, data); + } + + + if (response != null && (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Created)) + { + //TODO if all ok set the status to ok and update + + if(failurequeuedata != null) + { + failurequeuedata.RetryCount = failurequeuedata.RetryCount + 1; + failurequeuedata.Status = "elaborated"; + failurequeuedata.LastChange = DateTime.Now; + + await QueryFactory.Query("notificationfailures").Where("id", failurequeuedata.Id) + .UpdateAsync(new JsonBData() { id = failurequeuedata.Id, data = new JsonRaw(failurequeuedata) }); + } + + return await ReturnHttpResponse(response, notify, notify.HasImagechanged, notify.Roomschanged.HasValue ? notify.Roomschanged.Value : false, ""); + } + else if (response != null) + { + throw new Exception(response.ReasonPhrase); + } + else + { + throw new Exception("response null"); + } + } + } + else + throw new Exception("invalid_type"); + } + catch (TaskCanceledException ex) + { + if (failurequeuedata == null) + await WriteToFailureQueue(notify, ex.Message); + else + await UpdateFailureQueue(notify, ex.Message, failurequeuedata); + + var response = new HttpResponseMessage(HttpStatusCode.RequestTimeout); + return await ReturnHttpResponse(response, notify, notify.HasImagechanged, notify.Roomschanged.HasValue ? notify.Roomschanged.Value : false, ex.Message); + } + catch (Exception ex) + { + if (failurequeuedata == null) + await WriteToFailureQueue(notify, ex.Message); + else + await UpdateFailureQueue(notify, ex.Message, failurequeuedata); + + var response = new HttpResponseMessage(HttpStatusCode.InternalServerError); + return await ReturnHttpResponse(response, notify, notify.HasImagechanged, notify.Roomschanged.HasValue ? notify.Roomschanged.Value : false, ex.Message); + } + } + + private async Task> ReturnHttpResponse(HttpResponseMessage response, NotifyMeta notify, bool imageupdate, bool roomsupdate, string error) + { + var responsecontent = await ReadResponse(response, notify.Destination); + + if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.Created) + { + GenerateLog(notify.Id, notify.Destination, notify.Type.ToLower() + ".push.trigger", "api", notify.UdateMode, imageupdate, roomsupdate, responsecontent, null, true); + } + else + { + GenerateLog(notify.Id, notify.Destination, notify.Type.ToLower() + ".push.error", "api", notify.UdateMode, imageupdate, roomsupdate, responsecontent, error, false); + } + + //var responseobj = JObject.Parse(responsestring); + + return Tuple.Create(response.StatusCode, responsecontent); + } + + private async Task ReadResponse(HttpResponseMessage response, string service) + { + try + { + //TODO Switch between response service types + + return await response.Content.ReadFromJsonAsync(); + } + catch + { + return await response.Content.ReadAsStringAsync(); + } + } + + + private void GenerateLog(string id, string destination, string message, string origin, string updatemode, bool? imageupdate, bool? roomsupdate, object? response, string? exception, bool success) + { + NotifyLog log = new NotifyLog() { id = id, destination = destination, message = message, origin = origin, imageupdate = imageupdate, roomsupdate = roomsupdate, updatemode = updatemode, response = JsonSerializer.Serialize(response), exception = exception, success = success }; + + Console.WriteLine(JsonSerializer.Serialize(log)); + } + + private void GenerateLog(string id, string destination, string message, string origin, string updatemode, bool? imageupdate, bool? roomsupdate, string? response, string? exception, bool success) + { + NotifyLog log = new NotifyLog() { id = id, destination = destination, message = message, origin = origin, imageupdate = imageupdate, roomsupdate = roomsupdate, updatemode = updatemode, response = response, exception = exception, success = success }; + + Console.WriteLine(JsonSerializer.Serialize(log)); + } + + private async Task WriteToFailureQueue(NotifyMeta notify, string exmessage) + { + NotifierFailureQueue myfailure = new NotifierFailureQueue(); + myfailure.Id = Guid.NewGuid().ToString(); + myfailure.ItemId = notify.Id; + myfailure.Type = notify.Type; + myfailure.NotifyType = notify.NotifyType; + myfailure.Exception = exmessage; + myfailure.LastChange = DateTime.Now; + myfailure.Service = notify.Destination; + myfailure.PushUrl = notify.Url; + myfailure.Status = "open"; + + if (exmessage == "invalid_type" || notify.NotifyType == "NOT SUPPORTED") + myfailure.Status = "not_supported"; + + myfailure.RetryCount = 1; + myfailure.IsDeleteOperation = notify.IsDelete; + myfailure.HasImageChanged = notify.HasImagechanged; + myfailure.Roomschanged = notify.Roomschanged; + + await QueryFactory.Query("notificationfailures") + .InsertAsync(new JsonBData() { id = myfailure.Id, data = new JsonRaw(myfailure) }); + } + + private async Task UpdateFailureQueue(NotifyMeta notify, string exmessage, NotifierFailureQueue myfailure) + { + myfailure.ItemId = notify.Id; + myfailure.Type = notify.Type; + myfailure.NotifyType = notify.NotifyType; + myfailure.Exception = exmessage; + myfailure.LastChange = DateTime.Now; + myfailure.Service = notify.Destination; + myfailure.PushUrl = notify.Url; + myfailure.Status = "open"; + + if (exmessage == "invalid_type" || notify.NotifyType == "NOT SUPPORTED") + myfailure.Status = "not_supported"; + + myfailure.RetryCount = myfailure.RetryCount + 1; //CHECK if this works + myfailure.IsDeleteOperation = notify.IsDelete; + myfailure.HasImageChanged = notify.HasImagechanged; + myfailure.Roomschanged = notify.Roomschanged; + + await QueryFactory.Query("notificationfailures").Where("id", myfailure.Id) + .UpdateAsync(new JsonBData() { id = myfailure.Id, data = new JsonRaw(myfailure) }); + } + + //Valid Types for Push + private static bool CheckValidTypes(NotifyMeta notify) + { + if (notify.ValidTypes.Select(x => x.ToLower()).Contains(notify.NotifyType.ToLower())) + return true; + else + return false; + } + + public void Dispose() + { + // Dispose of unmanaged resources. + //TODO + // Suppress finalization. + GC.SuppressFinalize(this); + } + + private async Task> GetFromFailureQueue(string service, string status, int elementstoprocess) + { + var query = QueryFactory.Query("notificationfailures") + .SelectRaw("data") + .Where("gen_service", service) + .Where("gen_status", status) + .When(elementstoprocess > 0, x => x.Take(elementstoprocess)); + + var data = await query.GetObjectListAsync(); + + return data; + } + + public async Task>> PushFailureQueueToPublishedonService(List publishedonlist, int elementstoprocess = 100, string? referer = null) + { + IDictionary> notifierresponsedict = new Dictionary>(); + + foreach (var notifyconfig in notifierconfiglist) + { + //GET All failed pushes + if (publishedonlist.Contains(notifyconfig.ServiceName.ToLower())) + { + var failedpushes = await GetFromFailureQueue(notifyconfig.ServiceName.ToLower(), "open", elementstoprocess); + + List notifierresponselist = new List(); + + foreach (var failedpush in failedpushes) + { + var additionalpushinfodict = new Dictionary(); + + if (failedpush.HasImageChanged != null && failedpush.HasImageChanged.Value) + additionalpushinfodict.TryAdd("imageschanged", true); + + if (failedpush.Roomschanged != null && failedpush.Roomschanged.Value) + additionalpushinfodict.TryAdd("roomschanged", true); + + NotifyMetaGenerated meta = new NotifyMetaGenerated(notifyconfig, failedpush.ItemId, failedpush.Type, additionalpushinfodict, false, "failurequeue.push", "api", referer); + + NotifierResponse notifierresponse = new NotifierResponse(); + var response = await SendNotify(meta, failedpush); + notifierresponse.HttpStatusCode = response.Item1; + notifierresponse.Service = notifyconfig.ServiceName; + notifierresponse.Response = response.Item2; + notifierresponse.Success = MapStatusCodeToSuccessProperty(notifierresponse.HttpStatusCode); + + //TO CHECK if more Elements are pushed it is overwritten + notifierresponselist.Add(notifierresponse); + } + + notifierresponsedict.TryAddOrUpdate(notifyconfig.ServiceName, notifierresponselist); + } + } + + return notifierresponsedict; + } + + //Not Updating Images and AccommodationRooms + public async Task>> PushCustomObjectsToPublishedonService(List publishedonlist, List idlist, string odhtype, IDictionary? additionalpushinfo, string? referer = null) + { + IDictionary> notifierresponsedict = new Dictionary>(); + + foreach (var notifyconfig in notifierconfiglist) + { + //GET All failed pushes + if (publishedonlist.Contains(notifyconfig.ServiceName.ToLower())) + { + List notifierresponselist = new List(); + + foreach (var id in idlist) + { + NotifyMetaGenerated meta = new NotifyMetaGenerated(notifyconfig, id, odhtype, null, false, "custom.push", "api", referer); + + NotifierResponse notifierresponse = new NotifierResponse(); + var response = await SendNotify(meta, null); + notifierresponse.HttpStatusCode = response.Item1; + notifierresponse.Service = notifyconfig.ServiceName; + notifierresponse.Response = response.Item2; + notifierresponse.Success = MapStatusCodeToSuccessProperty(notifierresponse.HttpStatusCode); + + //TO CHECK if more Elements are pushed it is overwritten + notifierresponselist.Add(notifierresponse); + } + + notifierresponsedict.TryAddOrUpdate(notifyconfig.ServiceName, notifierresponselist); + } + } + + return notifierresponsedict; + } + } + + public class NotifyMetaGenerated : NotifyMeta + { + public NotifyMetaGenerated(NotifierConfig notifyconfig, string id, string type, IDictionary? additionalpushinfo, bool isdelete, string updatemode, string origin, string? referer = null) + { + //Set by parameters + this.Id = id; + this.Type = type; + this.UdateMode = updatemode; + this.Origin = origin; + this.Referer = referer; + this.HasImagechanged = false; + this.Roomschanged = false; + + if(additionalpushinfo != null) + { + if (additionalpushinfo.ContainsKey("imageschanged")) + this.HasImagechanged = additionalpushinfo["imageschanged"]; + if (additionalpushinfo.ContainsKey("roomschanged")) + this.Roomschanged = additionalpushinfo["roomschanged"]; + } + + this.IsDelete = isdelete; + + switch (notifyconfig.ServiceName.ToLower()) + { + case "idm-marketplace": + + //From Config + this.Url = notifyconfig.Url; + this.Headers = new Dictionary() { + { "client_id", notifyconfig.User }, + { "client_secret", notifyconfig.Password } + }; + + //Prefilled + this.Destination = "idm-marketplace"; + this.Mode = "post"; + + this.ValidTypes = new List() + { + "ACCOMMODATION", + "REGION", + "MUNICIPALITY", + "DISTRICT", + "TOURISM_ASSOCIATION", + "ODH_ACTIVITY_POI", + "EVENT", + "ODH_TAG", + "SKI_AREA" + }; + + this.NotifyType = TransformType(this.Type, "idm-marketplace"); + + break; + case "sinfo": + + //From Config + this.Url = notifyconfig.Url; + this.Parameters = new Dictionary() { + { "skipimage", this.HasImagechanged ? "false" : "true" } + }; + + //Prefilled + this.Destination = "sinfo"; + this.Mode = "get"; + + this.ValidTypes = new List() + { + "accommodation", + "activity", + "article", + "event", + "metaregion", + "region", + "experiencearea", + "municipality", + "tvs", + "district", + "skiregion", + "skiarea", + "gastronomy", + "odhactivitypoi", + "smgtags", + "odhtag" + }; + + this.NotifyType = TransformType(this.Type, "sinfo"); + + break; + default: + this.Mode = "get"; + this.Url = notifyconfig.Url; + break; + } + } + + public string TransformType(string type, string servicename) + { + if (servicename == "idm-marketplace") + { + return type.ToLower() switch + { + "accommodation" => "ACCOMMODATION", + "activity" => "NOT SUPPORTED", //deprecated + "article" => "NOT SUPPORTED", //Recipes (only 1 time import in AEM) + "event" => "EVENT", + "metaregion" => "NOT SUPPORTED", //to check + "region" => "REGION", + "experiencearea" => "NOT SUPPORTED", //to check + "municipality" => "MUNICIPALITY", + "tvs" => "TOURISM_ASSOCIATION", + "tv" => "TOURISM_ASSOCIATION", + "district" => "DISTRICT", + "skiregion" => "NOT SUPPORTED", //to check + "skiarea" => "SKI_AREA", + "gastronomy" => "NOT SUPPORTED", //deprecated + "poi" => "NOT SUPPORTED", //deprecated + "odhactivitypoi" => "ODH_ACTIVITY_POI", + "odhtag" => "ODH_TAG", + "ski_area" => "SKI_AREA", + "odh_activity_poi" => "ODH_ACTIVITY_POI", + "webcam" => "NOT SUPPORTED", + "measuringpoint" => "NOT SUPPORTED", + "venue" => "NOT SUPPORTED", + "wine" => "NOT SUPPORTED", + _ => "NOT SUPPORTED" + }; + } + else + return type; + } + + } +} diff --git a/PushServer/FCMMessageConstructor.cs b/PushServer/FCMMessageConstructor.cs new file mode 100644 index 0000000..9dffb01 --- /dev/null +++ b/PushServer/FCMMessageConstructor.cs @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DataModel; + +namespace PushServer +{ + public class FCMMessageConstructor + { + public static FCMModels? ConstructMyMessage(string identifier, string language, IIdentifiable myobject) + { + var message = new FCMModels(); + + //Construct your FCM Message here + + return message; + } + + public static FCMessageV2? ConstructMyMessageV2(string identifier, string language, IIdentifiable myobject) + { + var message = new FCMessageV2(); + + //Construct your FCM Message here + + return message; + } + } +} diff --git a/PushServer/FCMPushNotification.cs b/PushServer/FCMPushNotification.cs new file mode 100644 index 0000000..a1ac6e6 --- /dev/null +++ b/PushServer/FCMPushNotification.cs @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Google.Apis.Auth.OAuth2; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace PushServer +{ + #region Direct Send FCM to Firebase + + public class FCMPushNotification + { + public static async Task SendNotification(FCMModels fcmmessage, string fcmurl, string fcmsenderid, string fcmauthkey) + { + FCMPushNotification result = new FCMPushNotification(); + try + { + HttpClient myclient = new HttpClient(); + + myclient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + fcmauthkey); + myclient.DefaultRequestHeaders.TryAddWithoutValidation("Sender", string.Format("id={0}", fcmsenderid)); + + var myresponse = await myclient.PostAsync(fcmurl, new StringContent(JsonConvert.SerializeObject(fcmmessage), Encoding.UTF8, "application/json")); + + var myresponseparsed = await myresponse.Content.ReadAsStringAsync(); + + return new PushResult() { Error = null, Response = myresponseparsed, Success = true, Messages = 1 }; + } + catch (Exception ex) + { + return new PushResult() { Error = ex.Message, Response = "Error", Success = false, Messages = 1 }; + } + } + + public static async Task SendNotificationV2(FCMessageV2 fcmmessage, string fcmurl, string fcmserviceaccountjsonname) + { + FCMPushNotification result = new FCMPushNotification(); + try + { + + HttpClient myclient = new HttpClient(); + + + //Getting GoogleCredentials from File + var googlecred = await GetGoogleTokenServiceAccount(fcmserviceaccountjsonname); + //GET THE Bearertoken out of the Google Credential + var token = await googlecred.UnderlyingCredential.GetAccessTokenForRequestAsync(); + + myclient.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "Bearer " + token); + + var myresponse = await myclient.PostAsync(fcmurl, new StringContent(JsonConvert.SerializeObject(fcmmessage), Encoding.UTF8, "application/json")); + + var myresponseparsed = await myresponse.Content.ReadAsStringAsync(); + + return new PushResult() { Error = null, Response = myresponseparsed, Success = true, Messages = 1 }; + } + catch (Exception ex) + { + return new PushResult() { Error = ex.Message, Response = "Error", Success = false, Messages = 1 }; + } + } + + public static async Task GetGoogleTokenServiceAccount(string fcmserviceaccountjsonname, bool fromfile = true) + { + //FromJson + GoogleCredential? cred; + + string contents = File.ReadAllText(fcmserviceaccountjsonname); + + if (fromfile) + cred = GoogleCredential.FromFile(fcmserviceaccountjsonname).CreateScoped(new[] { "https://www.googleapis.com/auth/firebase.messaging" }); + else + cred = GoogleCredential.FromJson(fcmserviceaccountjsonname).CreateScoped(new[] { "https://www.googleapis.com/auth/firebase.messaging" }); + + return cred; + } + + public static async Task GetGoogleTokenWebAuthorization(string fcmserviceaccountjsonname) + { + UserCredential credential; + using (var stream = new FileStream(fcmserviceaccountjsonname, FileMode.Open, FileAccess.Read)) + { + credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( + GoogleClientSecrets.Load(stream).Secrets, + new[] { "https://www.googleapis.com/auth/firebase.messaging", "noi-community" }, + "user", CancellationToken.None); + } + + return credential; + } + } + + #endregion +} diff --git a/PushServer/PushServer.csproj b/PushServer/PushServer.csproj new file mode 100644 index 0000000..d84e93e --- /dev/null +++ b/PushServer/PushServer.csproj @@ -0,0 +1,22 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + diff --git a/PushServer/SendToPushServer.cs b/PushServer/SendToPushServer.cs new file mode 100644 index 0000000..c50e5d9 --- /dev/null +++ b/PushServer/SendToPushServer.cs @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +using DataModel; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PushServer +{ + public class SendToPushServer + { + public static async Task SendMessageToPushServer(string serviceurl, PushServerMessage data, string pushserveruser, string pushserverpass, string language) + { + try + { + if (data == null) + throw new Exception("data is null"); + + //HttpClient myclient = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }); + //myclient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip,deflate"); + //HttpClient myclient = new HttpClient(new Cred { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }); + HttpClient myclient = new HttpClient(); + + var byteArray = Encoding.ASCII.GetBytes(pushserveruser + ":" + pushserverpass); + myclient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); + + //myclient.DefaultRequestHeaders.Add("",""); + + //var json = JsonConvert.SerializeObject(data, Formatting.Indented); + + var myresponse = await myclient.PostAsync(serviceurl, new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json")); + + var myresponseparsed = await myresponse.Content.ReadAsStringAsync(); + + //tracesource.TraceEvent(TraceEventType.Information, 0, "Pushed Message:" + json); + //tracesource.TraceEvent(TraceEventType.Information, 0, "PushServer Send Weather success language , info: " + myresponseparsed + " language " + language); + + return myresponseparsed; + } + catch (Exception ex) + { + //tracesource.TraceEvent(TraceEventType.Error, 0, "PushServer Send Weather FAILED, error: " + ex.Message + " language " + language); + + return ex.Message; + } + } + + public static async Task SendCustomMessageToPushServer(string serviceurl, PushServerCustomMessage data, string pushserveruser, string pushserverpass) + { + try + { + if (data == null) + throw new Exception("data is null"); + + //HttpClient myclient = new HttpClient(new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }); + //myclient.DefaultRequestHeaders.Add("Accept-Encoding", "gzip,deflate"); + //HttpClient myclient = new HttpClient(new Cred { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }); + HttpClient myclient = new HttpClient(); + + var byteArray = Encoding.ASCII.GetBytes(pushserveruser + ":" + pushserverpass); + myclient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray)); + + //myclient.DefaultRequestHeaders.Add("",""); + + var json = JsonConvert.SerializeObject(data, Formatting.Indented); + + var myresponse = await myclient.PostAsync(serviceurl, new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json")); + + var myresponseparsed = await myresponse.Content.ReadAsStringAsync(); + + //tracesource.TraceEvent(TraceEventType.Information, 0, "PushServer Send Weather success, info: " + myresponseparsed); + + return myresponseparsed; + } + catch (Exception ex) + { + //tracesource.TraceEvent(TraceEventType.Error, 0, "PushServer Send Weather FAILED, error: " + ex.Message); + + return ex.Message; + } + } + + } + +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..81dc856 --- /dev/null +++ b/README.md @@ -0,0 +1,509 @@ + + +# opendatahub-content-api-core + +Core Components of the Opendatahub Content Api with Examples. + +[![REUSE Compliance](https://github.com/noi-techpark/opendatahub-content-api-core/actions/workflows/reuse.yml/badge.svg)](https://github.com/noi-techpark/opendatahub-content-api-core/wiki/REUSE#badges) +[![CI/CD API](https://github.com/noi-techpark/opendatahub-content-api-core/actions/workflows/main_api.yml/badge.svg)](https://github.com/noi-techpark/opendatahub-content-api-core/actions/workflows/main_api.yml) +[![CI/CD Importer](https://github.com/noi-techpark/opendatahub-content-api-core/actions/workflows/main_importer.yml/badge.svg)](https://github.com/noi-techpark/opendatahub-content-api-core/actions/workflows/main_importer.yml) + +## Project Goals/Requirements: + +* .Net Core 8 +* PostgreSQL Database +* Docker Support +* Swagger Support +* Identity Server Integration (Keycloak) +* Full Async Api +* improved Api Error Handling +* Browseable Api +* Swagger / Openapi Support +* Advanced api operations 1/2 (fields chooser, language selector, search terms) +* Advanced api operation 2/2 (raw sorting, raw filtering) + +## Project Structure + +### DataModel + +Definition of all Models + +### ContentApiCore + +Api to retrieve Content Data + +### Helper + +Class Library with Extension Methods and other Helper Methods + +## Database + +Postgres 15 +Extensions active on DB + +* extension earthdistance; +* extension cube; +* extension pg_trgm; +* extension postgis + +Custom Functions on DB + +* json_array_to_pg_array +* extract_keys_from_jsonb_object_array +* text2ts +* json_array_to_pg_array +* extract_keys_from_jsonb_object_array +* extract_tags +* extract_tagkeys +* is_valid_jsonb +* json_2_tsrange_array +* convert_tsrange_array_to_tsmultirange +* json_2_ts_array +* get_abs_eventdate_single + +These custom functions are used for the generated Columns + +## Getting started: + +Clone the repository +Copy `.env.example` to `.env` +Set the needed environment variables + +### Environment Variables + +* PG_CONNECTION (Connection to Postgres Database) +* XMLDIR; (Directory where xml config file is stored) +* JSONPATH; (Directory where json files are stored) +* S3_BUCKET_ACCESSPOINT; (S3 Bucket for Image Upload accesspoint) +* S3_IMAGEUPLOADER_ACCESSKEY; (S3 Bucket for Image Upload accesskey) +* S3_IMAGEUPLOADER_SECRETKEY; (S3 Bucket for Image Upload secretkey) +* OAUTH_AUTORITY; (Oauth Server Authority URL) +* ELK_URL; (Serilog Elasticsearch Sink Elastic URL) +* ELK_TOKEN; (Serilog Elasticsearch Access Token) + +### using Docker + +go into \ContentApiCore\ folder \ +`docker-compose up` starts the application on http://localhost:8001/ + +### using .Net Core CLI + +Install .Net Core SDK 5\ +go into \ContentApiCore\ folder \ +`dotnet run` +starts the application on +https://localhost:8001; +http://localhost:8000 + +### Postgres + +Activate extensions + +``` +CREATE EXTENSION cube; +``` +``` +CREATE EXTENSION earthdistance; +``` +``` +CREATE EXTENSION pg_trgm; +``` +``` +CREATE EXTENSION postgis; +``` + +Create generated columns on Postgres + +* bool + +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_bool bool GENERATED ALWAYS AS ((data#>'{Active}')::bool)stored; +``` + +*string + +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_string text GENERATED ALWAYS AS ((data#>>'{Source}'))stored; +``` + +*double + +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_double DOUBLE precision GENERATED ALWAYS AS ((data#>'{Latitude}')::DOUBLE precision) stored; +``` + +* array (simple) + +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_array text[] GENERATED ALWAYS AS (json_array_to_pg_array(data#>'{HasLanguage}')) stored; +``` + +* array (object) + +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_array text[] GENERATED ALWAYS AS (extract_keys_from_jsonb_object_array(data#>'{Features}','Id')) stored; +``` + +* date + +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_date timestamp GENERATED ALWAYS AS (text2ts(data#>>'{LastChange}')::timestamp) stored; +``` + +* tsarray +```sql +ALTER TABLE events ADD IF NOT EXISTS gen_tsarray timestamp[] GENERATED ALWAYS AS (json_2_ts_array(data#>'{EventDate}')) stored; +``` + +* tsrangearray +```sql +ALTER TABLE events ADD IF NOT EXISTS gen_tsrangearray tsrange[] GENERATED ALWAYS AS (json_2_tsrange_array(data#>'{EventDate}')) stored; +``` + +* tsmultirange +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_tsmultirange tsmultirange GENERATED ALWAYS AS (convert_tsrange_array_to_tsmultirange(json_2_tsrange_array(data#>'{EventDate}'))) stored; +``` + +* jsonb +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_jsonb jsonb GENERATED ALWAYS AS ((data#>'{SomeJsonB}')::jsonb) stored; +``` + +* geometry (postgis) +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_position public.geometry GENERATED ALWAYS AS (st_setsrid(st_makepoint((data #> '{GpsPoints,position,Longitude}'::text[])::double precision, (data #> '{GpsPoints,position,Latitude}'::text[])::double precision), 4326)) STORED NULL; +``` + +* access_based +```sql +ALTER TABLE tablename ADD IF NOT EXISTS gen_access_role text[] GENERATED ALWAYS AS (calculate_access_array(data#>>'{_Meta,Source}',(data#>'{LicenseInfo,ClosedData}')::bool,(data#>'{_Meta,Reduced}')::bool)) stored; +``` + + +Custom functions for Postgres Generated Columns creation + +* text2ts + +```sql +CREATE OR REPLACE FUNCTION text2ts(text) + RETURNS timestamp without time zone + LANGUAGE sql + IMMUTABLE +AS $function$SELECT CASE WHEN $1 ~'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(?:Z|\+\d{2}:\d{2})?$' THEN CAST($1 AS timestamp without time zone) END; $function$; +``` +* json_array_to_pg_array + +```sql +CREATE OR REPLACE FUNCTION json_array_to_pg_array(jsonarray jsonb) + RETURNS text[] + LANGUAGE plpgsql + IMMUTABLE STRICT +AS $function$ begin if jsonarray <> 'null' then return (select array(select jsonb_array_elements_text(jsonarray))); else return null; end if; end; $function$; +``` + +* extract_keys_from_jsonb_object_array + +```sql +CREATE OR REPLACE FUNCTION extract_keys_from_jsonb_object_array(jsonarray jsonb, key text DEFAULT 'Id'::text) + RETURNS text[] + LANGUAGE plpgsql + IMMUTABLE STRICT +AS $function$ begin if jsonarray <> 'null' then return (select array(select data2::jsonb->> key from (select jsonb_array_elements_text(jsonarray) as data2) as subsel)); else return null; end if; end; $function$; +``` + +* extract_tags + +```sql +CREATE OR REPLACE FUNCTION public.extract_tags(jsonarray jsonb) + RETURNS text[] + LANGUAGE plpgsql + IMMUTABLE strict +AS $function$ begin + return + (select array(select concat(x.tags->>'Source', '.', x.tags->>'Id') from + (select jsonb_path_query(jsonarray, '$.*[*]') tags) x) x); +end; $function$ +``` + +* extract_tagkeys + +```sql +CREATE OR REPLACE FUNCTION public.extract_tagkeys(jsonarray jsonb) + RETURNS text[] + LANGUAGE plpgsql + IMMUTABLE strict +AS $function$ begin + return (array(select distinct unnest(json_array_to_pg_array(jsonb_path_query_array(jsonarray, '$.*[*].Id'))))); +end; $function$ +``` + +* is_valid_jsonb + +```sql +CREATE OR REPLACE FUNCTION is_valid_jsonb(p_json text) +RETURNS JSONB +AS $$ +begin + return p_json::jsonb; +exception + when others then + return null; +end; $$ +LANGUAGE plpgsql IMMUTABLE; +``` + +* json_2_ts_array + +```sql +CREATE OR REPLACE FUNCTION public.json_2_ts_array(jsonarray jsonb) + RETURNS timestamp[] + LANGUAGE plpgsql + IMMUTABLE STRICT +AS $function$ begin if jsonarray <> 'null' then return ( + select + array( + select + (event ->> 'From')::timestamp + (event ->> 'Begin')::time + from + jsonb_array_elements(jsonarray) as event + where + (event ->> 'From')::timestamp + (event ->> 'Begin')::time < (event ->> 'To')::timestamp + (event ->> 'End')::time + ) +); +else return null; +end if; +end; +$function$ +; +``` + +* json_2_tsrange_array + +Used on Events, creates a TSRange Array from EventDate Json + +```sql +CREATE OR REPLACE FUNCTION public.json_2_tsrange_array(jsonarray jsonb) + RETURNS tsrange[] + LANGUAGE plpgsql + IMMUTABLE STRICT +AS $function$ begin if jsonarray <> 'null' then return ( + select + array( + select + tsrange( + ( (event ->> 'From')::timestamp + (event ->> 'Begin')::time), + ( (event ->> 'To')::timestamp + (event ->> 'End')::time) + ) + from + jsonb_array_elements(jsonarray) as event + where + (event ->> 'From')::timestamp + (event ->> 'Begin')::time < (event ->> 'To')::timestamp + (event ->> 'End')::time + ) +); +else return null; +end if; +end; +$function$ +``` + +* convert_tsrange_array_to_tsmultirange + +```sql +CREATE OR REPLACE FUNCTION convert_tsrange_array_to_tsmultirange(tsrange_array tsrange[]) +RETURNS tsmultirange +LANGUAGE plpgsql + IMMUTABLE STRICT +AS $$ +DECLARE + result tsmultirange := tsmultirange(); + tsr tsrange; +BEGIN + IF tsrange_array IS NOT NULL THEN + -- Durchlaufen des tsrange-Arrays + FOREACH tsr IN ARRAY tsrange_array + LOOP + -- Hinzufügen des tsrange-Elements zum tsmultirange + result := result + tsmultirange(tsrange(tsr)); + END LOOP; + END IF; + + RETURN result; +END; +$$; +``` + +* calculate_access_array + +```sql +CREATE OR REPLACE FUNCTION public.calculate_access_array(source text, closeddata boolean) +RETURNS text[] + LANGUAGE plpgsql + IMMUTABLE +AS $function$ + begin + if source = null or closeddata = null then return (array['ANONYMOUS','AUTHORIZED']); + end if; + if closeddata then return (array['AUTHORIZED']); + end if; + --TODO add source BASED RULES + return (array['AUTHORIZED','ANONYMOUS']); +end; +$function$ +; + +//For the rawdata table +CREATE OR REPLACE FUNCTION public.calculate_access_array_rawdata(source text, license text) + RETURNS text[] + LANGUAGE plpgsql + IMMUTABLE +AS $function$ +begin +-- if data is from source lts and not reduced AUTHORIZED only access -- +if license = 'closed' then return (array['AUTHORIZED']); +end if; +-- if data is from source xy do something +return (array['AUTHORIZED','ANONYMOUS']); +end; +$function$ +; +``` + +* get_nearest_tsrange_distance + +Used on Events calculates the difference between a given date and it's next Date Interval + +```sql +--calculates the distance from given date +CREATE OR REPLACE FUNCTION public.get_nearest_tsrange_distance(tsrange_array tsrange[], ts_tocalculate timestamp without time zone, sortorder text, prioritizesingledayevents bool) + RETURNS bigint + LANGUAGE plpgsql + IMMUTABLE STRICT +AS $function$ +DECLARE + result bigint; + intarr bigint[]; + mytsrange tsrange; + tsr timestamp; + singledayadd int; + +BEGIN + IF tsrange_array IS NOT NULL THEN + -- Iterate trough Array + FOREACH mytsrange IN array tsrange_array + loop + singledayadd = 0; + + if(prioritizesingledayevents = true) then + + -- if prioritiyesingledayevents is used, increase all distances for multidayevents with 1 + if(lower(mytsrange)::date = upper(mytsrange)::date) then + singledayadd = 0; + else + singledayadd = 1; + end if; + + end if; + + -- get tsrange which is matching (ongoing event) and add 0 + if mytsrange @> ts_tocalculate then + intarr := array_append(intarr, singledayadd); + else + -- check if period has already ended + if upper(mytsrange)::timestamp > ts_tocalculate then + --if period has not ended calculate distance + intarr := array_append(intarr, extract(epoch from (lower(mytsrange)::timestamp - ts_tocalculate))::bigint + singledayadd); + + end if; + + end if; + + END LOOP; + + --get distance (default minimum distance is returned, desc gets the highest distance) + if sortorder = 'desc' then + result = (select unnest(intarr) as x order by x desc limit 1); + else + result = (select unnest(intarr) as x order by x asc limit 1); + end if; + + END IF; + + RETURN result; +END; +$function$ +; +``` + +* get_nearest_tsrange + +Used on Events, gets the next Date Interval to a passed date as TSRange + +```sql +-- GETS the next tsrange to a given date +CREATE OR REPLACE FUNCTION public.get_nearest_tsrange(tsrange_array tsrange[], ts_tocalculate timestamp without time zone) + RETURNS tsrange + LANGUAGE plpgsql + IMMUTABLE STRICT +AS $function$ +DECLARE + result tsrange; + distance bigint; + distancetemp bigint; + mytsrange tsrange; + tsr timestamp; +BEGIN + IF tsrange_array IS NOT NULL then + + distance = 9999999999; + -- Iterate trough Array + FOREACH mytsrange IN array tsrange_array + loop + -- get tsrange which is matching (ongoing event) + if mytsrange @> ts_tocalculate then + result = mytsrange; + distance = 0; + else + -- check if period has already ended + if upper(mytsrange)::timestamp > ts_tocalculate then + + --if period has not ended calculate distance + distancetemp = extract(epoch from (lower(mytsrange)::timestamp - ts_tocalculate))::bigint; + + if(distance > distancetemp) then + distance = distancetemp; + result = mytsrange; + end if; + + end if; + + end if; + + END LOOP; + + END IF; + + RETURN result; +END; +$function$ +; +``` + +### REUSE + +This project is [REUSE](https://reuse.software) compliant, more information about the usage of REUSE in NOI Techpark repositories can be found [here](https://github.com/noi-techpark/odh-docs/wiki/Guidelines-for-developers-and-licenses#guidelines-for-contributors-and-new-developers). + +Since the CI for this project checks for REUSE compliance you might find it useful to use a pre-commit hook checking for REUSE compliance locally. The [pre-commit-config](.pre-commit-config.yaml) file in the repository root is already configured to check for REUSE compliance with help of the [pre-commit](https://pre-commit.com) tool. + +Install the tool by running: +```bash +pip install pre-commit +``` +Then install the pre-commit hook via the config file by running: +```bash +pre-commit install +``` diff --git a/RawQueryParser/Parser.fs b/RawQueryParser/Parser.fs new file mode 100644 index 0000000..a42d153 --- /dev/null +++ b/RawQueryParser/Parser.fs @@ -0,0 +1,158 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +module RawQueryParser.Parser + +open FParsec + +/// Type alias to simplify the type annotation of a Parser. +type Parser<'a> = Parser<'a, unit> + +let field = + let lettersDigitsAndUnderscore c = isAsciiLetter c || isDigit c || c = '_' || c = '@' + let options = IdentifierOptions(isAsciiIdStart = lettersDigitsAndUnderscore, + isAsciiIdContinue = lettersDigitsAndUnderscore) + let fieldArraySegment = + identifier options .>>? skipString "[*]" + |>> (fun x -> IdentifierArraySegment x) + let arraySegment = skipString "[*]" <|> skipString "[]" >>% ArraySegment + let identifierSegment = identifier options |>> IdentifierSegment + sepBy (fieldArraySegment <|> identifierSegment <|> arraySegment) (skipChar '.') + |>> Field + "field" + +let whitespace = many (skipChar ' ') + +module Sorting = + open Sorting + + /// + /// Parse a sort direction. + /// + /// + /// + /// If omitted the sort is ascending + /// If - the sort is descending + /// + /// + let orderBy: Parser<_> = + opt (skipString "-") + |>> function + | Some _ -> Descending + | None -> Ascending + "order by" + + /// A sortStatement consists of a sort direction and a property. + let sortStatement = + orderBy .>>. field + |>> (fun (order, prop) -> + { Field = prop + Direction = order }) + "sort statement, e.g. Detail.de.Title" + + /// sortStatements consist of multiple statements divided by a comma. + let statements: Parser = + sepBy1 sortStatement (skipChar ',' >>. whitespace) .>> eof + +module Filtering = + open Filtering + + let betweenBrackets p = + between (skipChar '(') (skipChar ')') p + + let betweenQuotes p = + let quotes = skipChar '\"' <|> skipChar '\'' + between quotes quotes p + + let operator: Parser = + choice [ + skipString "eq" >>% Eq + skipString "ne" >>% Ne + skipString "gt" >>% Gt + skipString "ge" >>% Ge + skipString "lt" >>% Lt + skipString "le" >>% Le + skipString "like" >>% Like + ] + + let boolean: Parser = + choice [ + skipString "true" >>% Boolean true + skipString "false" >>% Boolean false + ] + "boolean" + + let number: Parser = + pfloat |>> Number + "number" + + let quotedString = + betweenQuotes ( + manySatisfy (isNoneOf ['\"'; '\'']) + ) + + let string: Parser = + quotedString + |>> String + "string" + + let datetime: Parser = + skipString "dt" >>. quotedString + >>= fun x -> + match System.DateTime.TryParse x with + | true, dateTime -> preturn dateTime + | false, _ -> fail $"Invalid date time value: {x}" + |>> DateTime + "datetime" + + let array: Parser = + pstring "[]" <|> pstring "[*]" + >>% Array + "array" + + let value: Parser = + choice [ + boolean + number + string + datetime + array + ] + + let call: Parser = + betweenBrackets ( + field .>>. (skipChar ',' >>. whitespace >>. value) + ) + + let condition: Parser = + operator .>>. call + |>> (fun (op, (prop, value)) -> + { Field = prop + Operator = op + Value = value }) + "condition, e.g. `eq(field, value)`" + + let inParser = + field .>>. (skipChar ',' >>. whitespace >>. sepBy1 value (skipChar ',' .>> whitespace)) + + let statement', statementRef = createParserForwardedToRef() + + do statementRef := + let innerParser: Parser = + betweenBrackets (sepBy1 statement' (skipChar ',' >>. whitespace)) + let combineWith f (statements: FilterStatement list) = + statements |> List.rev |> List.reduce (fun y x -> f (x, y)) + choice [ + pstring "and" >>. innerParser |>> combineWith And + pstring "or" >>. innerParser |>> combineWith Or + pstring "isnull" >>. betweenBrackets field |>> (IsNull >> Condition) + pstring "isnotnull" >>. betweenBrackets field |>> (IsNotNull >> Condition) + pstring "in" >>. (betweenBrackets inParser |>> (In >> Condition)) + pstring "nin" >>. (betweenBrackets inParser |>> (NotIn >> Condition)) + pstring "likein" >>. (betweenBrackets inParser |>> (LikeIn >> Condition)) + condition |>> (Comparison >> Condition) + ] + + let statement = statement' .>> eof + diff --git a/RawQueryParser/RawQueryParser.fsproj b/RawQueryParser/RawQueryParser.fsproj new file mode 100644 index 0000000..7d834b3 --- /dev/null +++ b/RawQueryParser/RawQueryParser.fsproj @@ -0,0 +1,19 @@ + + + + net6.0 + + + + + + + + + + + + + + + diff --git a/RawQueryParser/Readme.md b/RawQueryParser/Readme.md new file mode 100644 index 0000000..03399d9 --- /dev/null +++ b/RawQueryParser/Readme.md @@ -0,0 +1,160 @@ + + +# Raw Query Parser Project + +This project enables the tourism open data hub to support custom filtering and sorting. + +## What does 'custom' mean? + +With custom filtering and sorting a consumer of the API can filter and sort for things +that aren't supported otherwise. + +> The tourism API has some predefined filters and sorting suited +> especially for the domain and the +> different endpoints of the tourism sector, like points of interest, activities, and +> so on... +> These filters are documented in the OpenAPI specification. + +The custom filtering and sorting is enabled via query strings. + +- `rawfilter` allows the filtering of the data returned by the API endpoint +- `rawsort` allows the sorting of the data returned by the API endpoint + +### `rawfilter` + +Usage: `?rawfilter=` + +```javascript +eq(, ) +eq(Active, true) // all active entries +eq(Type, 'Wandern') // all entries of type 'Wandern' +like(Type, 'ander') // all entries of type like 'ander' +eq(ODHTags, []) // all entries where Array ODHTags is empty +isnotnull(Detail.ru.Title) // all entries with a russian title set +and(ge(GpsInfo.0.Altitude, 200), le(GpsInfo.0.Altitude, 400)) // all entries with an altitude between 200 and 400 meters +in(Features.[*].Id, "a3067617-771a-4b84-b85e-206e5cf4402b") // all entries in an Array with a specific feature ID +in(Features.[].Id, "a3067617-771a-4b84-b85e-206e5cf4402b") // all entries in an Array with a specific feature ID - alternative notation +nin(Features.[].Id, "a3067617-771a-4b84-b85e-206e5cf4402b") // all entries which not have a specific feature ID in an Array +likein(Tags.[].Id, "inter") // all entries in an Array with a Tag Id like the passed value +likein(Tags.[*].Id, "inter") // all entries in an Array with a Tag Id like the passed value - alternative notation +``` + +**Attention**: On the field _ImageGallery _if data is retrieved as anonymous there is a Transformer applied after getting the Result from the DB which cuts out all not CC0 license Images. So there the rawfilter possible can produce false results. + + +> `` is described [here](#Supported-value-types:) +> `` is described [here](#Field-syntax:) + +Keywords/functions: `eq`, `ne`, `gt`, `ge`, `lt`, `le`, `and`, `or`, `isnull`, `isnotnull`, `in`, `nin`, `like`, `likein` + +Precedence is archieved by nesting `and` and `or`. +You can chain multiple conditions inside `and` and `or`: + +``` +and(foo, bar, baz) +``` + +Negation isn't supported altough it might be implemented later if needed. I need to think of a case where negation can't be replaced by the keywords from above. + +No `between`, `startswith` and other special functions. Altough this may change dependeing of the actual use cases. + +> To legitimate the addition of such special functions a production use case has to be satisfied. +> Prefer composition on the value type level over special operators. + +Testing a field if it is NULL or not NULL has special meaning in SQL. You cannot simply query a field for NULL with equality or inequality. You have to use special syntax for that, e.g. `FIELD IS NULL` or `FIELD IS NOT NULL`. +Because of this special meaning of NULL there exist `isnull` and `isnotnull` functions. + +### `rawsort` + +The `rawsort` syntax follows the proposal for sorting on the destination data: https://gitlab.com/alpinebits/destinationdata/standard-specification/-/issues/4 + +Usage: `?rawsort=` + +```javascript +[-] +Detail.de.Title +Geo.0.Altitude +-Geo.0.Altitude, Detail.de.Title +``` +> `` is described [here](#Supported-value-types:) + +Prepending a minus does significate that the field gets sorted descending. + +## Field syntax + +*The `` placeholder in the examples above.* +A field can be a simple flat selection like `Active` or `Type`, which matches a document with the following JSON structure: + +```json +{ "Active": , "Type": , ... } +``` + +But it is possible to traverse throgh the document's hierarchy by separating the names by a dot (.). + +`Detail.ru.Title` matches on a document with the following JSON structure: + +```json +{ "Detail": { "ru": { "Title": , ... }, ... }, ... } +``` + +It is also possible to query arrays: +`Features.[0].Id`: returns the first Element of the Array as single field +`Features.[n].Id`: returns the n-th Element of the Array as single field +`Features.[*].Id`: returns all Elements of the Array (as array) + +This field matches on a document with the following JSON structure: + +```json +{ "Features": [{ "Id": , ... }, { "Id": , ... }, ...], ... } +``` + +## Supported value types: + +*The `` placeholder in the examples above.* + +- Boolean: `true`, `false` +- Number: `1`, `1.12` (exponential notation is not allowed) are always interpreted as a floating point number +- Strings need to be defined in quotes (single or double quotes are both legal, unicode escapes are not allowed) + They are special in that they leverage PostgreSQL special capability to represent different data types (e.g. dates) as strings (`#>>`) which allows to filter them by strings. +- The literal `[]` which denotes an empty JSON array. + +No special or magical conversion happens between the data types. +E.g. `1` applied to a boolean field doesn't get converterted into a boolean type 'automagically'. It is the underlying DB's responsibility to handle such a type missmatch. + +The following error will be thrown by PostreSQL if you try to compare a boolean field with a numeric value (`eq(Active,1)`): + +``` +22023: cannot cast jsonb boolean to type double precision +``` + +## Is it safe? + +As safe as you can expect a feature like that to be! + +Keep in mind that at the end you get a string that gets inserted as a raw string into the SQL statement. So every SQL injection that you are able to get into the query strings are sent to the database engine. + +## Is it performant? + +The query parsing is performant, but the execution time on the DB is nothing that can be easily predicted. +The execution performance totally depends on the JSON capabilities of PostgreSQL, the query planner and the indizes that are defined on the fields. + +> There exist special filters on the endpoints that are optimized for specific production use cases. + +## Why F#? + +This project is written in F# as it allows for a very expressive and concise code and the usage of a parser combinator as an integrated DSL. + +If you are interested in the why's of F# you can view the following [video](https://www.youtube.com/watch?v=_q_7-fEEH10). +If that video has provoked your curiosity you can get in touch with me! ;-) + +## What is a parser combinator? + +A parser combinator library is a collection of larger parsers built from smaller parsers via composition. + +For more information about parser combinators you can read through the [FParsec documentation](https://www.quanttec.com/fparsec/). FParsec is the library that is used in this project. +If you want to get more general information on how parser combinators work and how +the composition of those parsers works i recommend to view this [video](https://www.youtube.com/watch?v=RDalzi7mhdY). diff --git a/RawQueryParser/Transformer.fs b/RawQueryParser/Transformer.fs new file mode 100644 index 0000000..311cfbe --- /dev/null +++ b/RawQueryParser/Transformer.fs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +module RawQueryParser.Transformer + +open FParsec + +/// +/// Transform a sort expression into a +/// PostgreSQL ORDER BY expression. +/// +[] +let transformSort input = + if isNull input then + nullArg (nameof input) + else + match run Parser.Sorting.statements input with + | Success (statements, _, _) -> + Writer.Sorting.writeStatements statements + | Failure (msg, _, _) -> + failwith msg + +/// +/// Transform a filter expression into a +/// PostgreSQL WHERE expression. +/// +[] +let transformFilter(jsonSerializer: System.Func, input) = + if isNull input then + nullArg (nameof input) + else + match run Parser.Filtering.statement input with + | Success (statement, _, _) -> + Writer.Filtering.writeStatement jsonSerializer.Invoke statement + | Failure (msg, _, _) -> + failwith msg + diff --git a/RawQueryParser/Types.fs b/RawQueryParser/Types.fs new file mode 100644 index 0000000..bd74cc2 --- /dev/null +++ b/RawQueryParser/Types.fs @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace RawQueryParser + +/// +/// Differentiate between an identifier segment, e.g. 'Detail' and an array segment: [] +/// +type FieldSegment = + | IdentifierSegment of string + | ArraySegment + | IdentifierArraySegment of string + +/// +/// Defines a field with hierarchical access fields. +/// E.g. Field [IdentifierSegment "Detail"; IdentifierSegment "de"; IdentifierSegment "Title"] +/// or Field [IdentifierSegment "Features"; ArraySegment; IdentifierSegment "Id"] +/// +type Field = Field of fields: FieldSegment list +with member self.ToNestedObject(value) = + let (Field fields) = self + let rec loop m = function + | [] -> + (box value) + | IdentifierSegment h::t + | IdentifierArraySegment h::t -> + box (dict [h, box (loop m t)]) + | ArraySegment::t -> + box [loop m t] + loop value fields + +module Sorting = + /// Defines the sort direction. + type OrderBy = + | Ascending + | Descending + + /// A sort statement is composed of a + /// property and a sort direction. + type SortStatement = + { Field: Field + Direction: OrderBy } + + /// Sort statements are a list of sort statement. + type SortStatements = SortStatement list + +module Filtering = + /// Defines the possible operators. + type Operator = + | Eq + | Ne + | Lt + | Le + | Gt + | Ge + | Like + + /// Defines values of booleans, numbers and strings. + type Value = + | Boolean of bool + | Number of float + | String of string + | DateTime of System.DateTime + | Array + + /// The condition is the combination of a property, an operator and a value. + type Comparison = + { Field: Field + Operator: Operator + Value: Value } + + type Condition = + | Comparison of Comparison + | In of field: Field * values: Value list + | NotIn of field: Field * values: Value list + | LikeIn of Field: Field * value: Value list + | IsNull of Field + | IsNotNull of Field + + /// A filter statement can be a simple condition or a bunch + /// of conditions inside an AND or an OR binary statement. + type FilterStatement = + | And of left: FilterStatement * right: FilterStatement + | Or of left: FilterStatement * right: FilterStatement + | Condition of Condition + diff --git a/RawQueryParser/Writer.fs b/RawQueryParser/Writer.fs new file mode 100644 index 0000000..db80c39 --- /dev/null +++ b/RawQueryParser/Writer.fs @@ -0,0 +1,156 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +/// Generates PostgreSQL commands +module RawQueryParser.Writer + +/// +/// Write a field like +/// Field ["Detail"; "de"; "Title"] +/// as +/// data#>'{Detail,de,Title}' +/// +let writeRawField (Field fields) = + fields + |> List.choose (function + | IdentifierSegment x -> Some x + | IdentifierArraySegment x -> Some x + | ArraySegment -> None) // Filter away array segment + |> String.concat "," + |> sprintf "data#>'\\{%s\\}'" + +let writeFieldEscaped (Field fields) = + fields + |> List.choose (function + | IdentifierSegment x -> Some x + | IdentifierArraySegment x -> Some x + | ArraySegment -> None) // Filter away array segment + |> String.concat "," + |> sprintf "'\\{%s\\}'" + +let writeJsonPathField (Field fields) = + fields + |> List.map (function + | IdentifierSegment x -> $".{x}" + | IdentifierArraySegment x -> $".{x}\[*\]" + | ArraySegment -> "\[*\]") + |> String.concat "" + |> sprintf "$%s" + +/// +/// Write a field like +/// Field ["Detail"; "de"; "Title"] +/// as +/// data#>>'{Detail,de,Title}' +/// +let writeTextField (Field fields) = + fields + |> List.choose (function + | IdentifierSegment x -> Some x + | IdentifierArraySegment x -> Some x + | ArraySegment -> None) // Filter away array segment + |> String.concat "," + |> sprintf "data#>>'\\{%s\\}'" + +module Sorting = + open Sorting + + /// + /// A sort direction gets written + /// as ASC or DESC. + /// + let writeDirection = function + | Ascending -> "ASC" + | Descending -> "DESC" + + /// A statement gets written by concatenating + /// a property with a sort direction. + let writeSortStatement statement = + let direction = writeDirection statement.Direction + let field = writeRawField statement.Field + $"{field} {direction}" + + /// Statements are concatenated "=" + | Ne -> "<>" + | Gt -> ">" + | Ge -> ">=" + | Lt -> "<" + | Le -> "<=" + | Like -> "ILIKE" + + let writeRawValue = function + | Boolean x -> box x + | Number x -> box x + | String x -> box x + | DateTime x -> box x + | Array -> box [||] + + let writeValue = function + | Boolean true -> "TRUE" + | Boolean false -> "FALSE" + | Number value -> $"{value}" + | String value -> $"'%s{value}'" + | DateTime value -> $"""'%s{value.ToString("o")}'::timestamp""" + | Array -> "to_jsonb(array\[\]::varchar\[\])" + + let writeComparison comparison = + let field = + match comparison.Value with + | Boolean _ -> $"({writeRawField comparison.Field})::boolean" + | Number _ -> $"({writeRawField comparison.Field})::float" + | String _ -> writeTextField comparison.Field + | DateTime _ -> $"({writeTextField comparison.Field})::timestamp" + | Array -> $"({writeRawField comparison.Field})::jsonb" + let operator = writeOperator comparison.Operator + let value = + match comparison.Operator, comparison.Value with + | Like, String value -> writeValue (String $"%%{value}%%") + | _, value -> writeValue value + $"{field} {operator} {value}" + + let rec writeStatement (jsonSerializer: obj -> string) = function + | And (left, right) -> $"(%s{writeStatement jsonSerializer left} AND %s{writeStatement jsonSerializer right})" + | Or (left, right) -> $"(%s{writeStatement jsonSerializer left} OR %s{writeStatement jsonSerializer right})" + | Condition (Comparison value) -> writeComparison value + | Condition (In (field, values)) -> + let escapeBrackets (x: string) = + x.Replace("[", "\[") + .Replace("]", "\]") + .Replace("{", "\{") + .Replace("}", "\}") + let writeValue = + writeRawValue + >> field.ToNestedObject + >> jsonSerializer + >> escapeBrackets + >> sprintf "data @> '%s'" + values + |> List.map writeValue + |> String.concat " OR " + |> sprintf "(%s)" + | Condition (NotIn (field, values)) -> + $"NOT {writeStatement jsonSerializer (Condition (In (field, values)))}" + | Condition (LikeIn (field, values)) -> + let field' = writeJsonPathField field + let writeValue (value: Value) = + match value with + | String s -> s + | _ -> failwith "Only strings are supported in a likein filter." + |> fun value -> sprintf $"jsonb_path_exists(data, '%s{field'} ?(@ like_regex \"%s{value}\" flag \"i\")')" + values + |> List.map writeValue + |> String.concat " OR " + |> sprintf "(%s)" + | Condition (IsNull property) -> $"{writeTextField property} IS NULL" + | Condition (IsNotNull property) -> $"{writeTextField property} IS NOT NULL" diff --git a/RawQueryParserTests/ParserTests.fs b/RawQueryParserTests/ParserTests.fs new file mode 100644 index 0000000..ca164df --- /dev/null +++ b/RawQueryParserTests/ParserTests.fs @@ -0,0 +1,224 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +module RawQueryParser.ParserTests + +open Expecto +open Parser + +[] +let parserTests = + testList "Parser" [ + testList "Field" [ + test "Simple field should parse correctly" { + let expected = Ok (Field [ IdentifierSegment "Detail" ]) + let actual = run field "Detail" + Expect.equal actual expected "" + } + test "Hierarchial field should parse correctly" { + let expected = Ok (Field (List.map IdentifierSegment [ "Detail"; "de"; "Title" ])) + let actual = run field "Detail.de.Title" + Expect.equal actual expected "" + } + test "Field with .[] array syntax" { + let expected = Ok (Field [IdentifierSegment "Features"; ArraySegment; IdentifierSegment "Id"]) + let actual = run field "Features.[].Id" + Expect.equal actual expected "" + } + test "Field with .[*] array syntax" { + let expected = Ok (Field [IdentifierSegment "Features"; ArraySegment; IdentifierSegment "Id"]) + let actual = run field "Features.[*].Id" + Expect.equal actual expected "" + } + test "Field with [*] array syntax (JSON path syntax)" { + let expected = Ok (Field [IdentifierArraySegment "Features"; IdentifierSegment "Id"]) + let actual = run field "Features[*].Id" + Expect.equal actual expected "" + } + ] + testList "Sorting" [ + testList "Sort order" [ + test "Order ascending" { + let actual = run Sorting.orderBy "" + Expect.equal actual (Ok Sorting.Ascending) "" + } + test "Order descending" { + let actual = run Sorting.orderBy "-" + Expect.equal actual (Ok Sorting.Descending) "" + } + ] + testList "Sort order and field" [ + test "Sort by single" { + let expected: Result = Ok [ + { Field = Field (List.map IdentifierSegment ["Detail"; "de"; "Title"]); Direction = Sorting.Descending } + ] + let actual = run Sorting.statements "-Detail.de.Title" + Expect.equal actual expected "" + } + test "Sort by multiple" { + let expected: Result = Ok [ + { Field = Field (List.map IdentifierSegment ["Detail"; "de"; "Title"]); Direction = Sorting.Descending } + { Field = Field (List.map IdentifierSegment ["Detail"; "de"; "Body"]); Direction = Sorting.Ascending } + ] + let actual = run Sorting.statements "-Detail.de.Title,Detail.de.Body" + Expect.equal actual expected "" + } + ] + ] + testList "Filtering" [ + test "Simple condition with boolean" { + let expected = + Ok (Comp { Field = Field [IdentifierSegment "Active"] + Operator = Filtering.Operator.Eq + Value = Filtering.Boolean true }) + let actual = run Filtering.statement "eq(Active, true)" + Expect.equal actual expected "" + } + test "Simple condition with number" { + let expected = + Ok (Comp { Field = Field (List.map IdentifierSegment ["Geo"; "Altitude"]) + Operator = Filtering.Operator.Eq + Value = Filtering.Number 200. }) + let actual = run Filtering.statement "eq(Geo.Altitude, 200)" + Expect.equal actual expected "" + } + test "Simple condition with single quote string" { + let expected = + Ok (Comp { Field = Field (List.map IdentifierSegment ["Detail"; "de"; "Title"]) + Operator = Filtering.Operator.Eq + Value = Filtering.String "Foo" }) + let actual = run Filtering.statement "eq(Detail.de.Title, 'Foo')" + Expect.equal actual expected "" + } + test "Simple condition with double quote string" { + let expected = + Ok (Comp { Field = Field (List.map IdentifierSegment ["Detail"; "de"; "Title"]) + Operator = Filtering.Operator.Eq + Value = Filtering.String "Foo" }) + let actual = run Filtering.statement """eq(Detail.de.Title, "Foo")""" + Expect.equal actual expected "" + } + test "Simple condition with date time" { + let expected = + Ok (Comp { Field = Field [ IdentifierSegment "LastChange" ] + Operator = Filtering.Operator.Eq + Value = Filtering.DateTime (System.DateTime(2010,01,01)) }) + let actual = run Filtering.statement """eq(LastChange, dt"2010-01-01")""" + Expect.equal actual expected "" + } + test "Simple condition with array" { + let expected = + Ok (Comp { Field = Field [ IdentifierSegment "ImageGallery" ] + Operator = Filtering.Operator.Eq + Value = Filtering.Array }) + let actual = run Filtering.statement """eq(ImageGallery, [])""" + Expect.equal actual expected "" + } + test "Simple condition with array alternative notation" { + let expected = + Ok (Comp { Field = Field [ IdentifierSegment "ImageGallery" ] + Operator = Filtering.Operator.Eq + Value = Filtering.Array }) + let actual = run Filtering.statement """eq(ImageGallery, [*])""" + Expect.equal actual expected "" + } + test "AND condition" { + let expected = + Ok ( + And ( + Comp { Field = Field (List.map IdentifierSegment ["Geo"; "Altitude"]) + Operator = Filtering.Operator.Ge + Value = Filtering.Number 200. }, + Comp { Field = Field (List.map IdentifierSegment ["Geo"; "Altitude"]) + Operator = Filtering.Operator.Le + Value = Filtering.Number 400. } + ) + ) + let actual = run Filtering.statement "and(ge(Geo.Altitude, 200), le(Geo.Altitude, 400))" + Expect.equal actual expected "" + } + test "AND with multiple conditions" { + let expected = + Ok ( + And ( + Comp { Field = Field (List.map IdentifierSegment ["Active"]) + Operator = Filtering.Operator.Eq + Value = Filtering.Boolean true }, + And ( + Comp { Field = Field (List.map IdentifierSegment ["Geo"; "Altitude"]) + Operator = Filtering.Operator.Ge + Value = Filtering.Number 200. }, + Comp { Field = Field (List.map IdentifierSegment ["Geo"; "Altitude"]) + Operator = Filtering.Operator.Le + Value = Filtering.Number 400. } + ) + ) + ) + let actual = run Filtering.statement "and(eq(Active, true), ge(Geo.Altitude, 200), le(Geo.Altitude, 400))" + Expect.equal actual expected "" + } + test "AND with nested OR" { + let expected = + Ok ( + Or ( + Comp { Field = Field [IdentifierSegment "Active"] + Operator = Filtering.Operator.Eq + Value = Filtering.Boolean true }, + And ( + Comp { Field = Field (List.map IdentifierSegment ["Geo"; "Altitude"]) + Operator = Filtering.Operator.Ge + Value = Filtering.Number 200. }, + Comp { Field = Field (List.map IdentifierSegment ["Geo"; "Altitude"]) + Operator = Filtering.Operator.Le + Value = Filtering.Number 400. } + ) + ) + ) + let actual = run Filtering.statement "or(eq(Active, true), and(ge(Geo.Altitude, 200), le(Geo.Altitude, 400)))" + Expect.equal actual expected "" + } + test "LIKE" { + let expected = Ok <| Comp { + Field = Field [IdentifierSegment "Title"] + Operator = Filtering.Operator.Like + Value = Filtering.String "Ski" + } + let actual = run Filtering.statement "like(Title, 'Ski')" + Expect.equal actual expected "" + } + test "Condition with NULL check" { + let expected = + Ok (Cond (Filtering.IsNull (Field (List.map IdentifierSegment ["Detail"; "ru"; "Title"])))) + let actual = run Filtering.statement "isnull(Detail.ru.Title)" + Expect.equal actual expected "" + } + test "Condition with IN" { + let expected = + Ok ( + In (Field [IdentifierSegment "HasLanguage"], [Filtering.String "de"; Filtering.String "it"]) + ) + let actual = run Filtering.statement "in(HasLanguage,'de','it')" + Expect.equal actual expected "" + } + test "Condition with LIKEIN" { + let expected = + Ok ( + LikeIn (Field [IdentifierSegment "OdhTags"], [Filtering.String "Ski"; Filtering.String "Winter"]) + ) + let actual = run Filtering.statement "likein(OdhTags, 'Ski', 'Winter')" + Expect.equal actual expected "" + } + test "Array syntax" { + let expected = + Ok ( + Comp { Field = Field [IdentifierSegment "Features"; ArraySegment; IdentifierSegment "Id"] + Operator = Filtering.Operator.Eq + Value = Filtering.Number 42. } + ) + let actual = run Filtering.statement "eq(Features.[].Id,42)" + Expect.equal actual expected "" + } + ] + ] + diff --git a/RawQueryParserTests/Prelude.fs b/RawQueryParserTests/Prelude.fs new file mode 100644 index 0000000..15be4aa --- /dev/null +++ b/RawQueryParserTests/Prelude.fs @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +[] +module Prelude + +[] +module TestHelpers = + open FParsec + open RawQueryParser + + let run p input = + match run p input with + | Success (x, _, _) -> Core.Ok x + | Failure (msg, _, _) -> Core.Error msg + + let Cond x = Filtering.Condition x + + let Comp x = Cond (Filtering.Comparison x) + + let In x = Cond (Filtering.In x) + + let LikeIn x = Cond (Filtering.LikeIn x) + + let And x = Filtering.And x + + let Or x = Filtering.Or x + diff --git a/RawQueryParserTests/Program.fs b/RawQueryParserTests/Program.fs new file mode 100644 index 0000000..8375e3c --- /dev/null +++ b/RawQueryParserTests/Program.fs @@ -0,0 +1,5 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +module Program = let [] main _ = 0 diff --git a/RawQueryParserTests/RawQueryParserTests.fsproj b/RawQueryParserTests/RawQueryParserTests.fsproj new file mode 100644 index 0000000..78a9b6e --- /dev/null +++ b/RawQueryParserTests/RawQueryParserTests.fsproj @@ -0,0 +1,28 @@ + + + + net6.0 + + false + false + + + + + + + + + + + + + + + + + + + + + diff --git a/RawQueryParserTests/TransformerTests.fs b/RawQueryParserTests/TransformerTests.fs new file mode 100644 index 0000000..38b3164 --- /dev/null +++ b/RawQueryParserTests/TransformerTests.fs @@ -0,0 +1,120 @@ +// SPDX-FileCopyrightText: NOI Techpark +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +module RawQueryParser.TransformerTests + +open Expecto +open Parser + +[] +let transfomerTests = + testList "Transformer" [ + testList "Sorting" [ + test "Simple sort statement" { + let expected = "data#>'\{Detail,de,Title\}' ASC" + let actual = Transformer.transformSort "Detail.de.Title" + Expect.equal actual expected "" + } + test "Simple sort statement descending" { + let expected = "data#>'\{Detail,de,Title\}' DESC" + let actual = Transformer.transformSort "-Detail.de.Title" + Expect.equal actual expected "" + } + test "Combined sort statements" { + let expected = "data#>'\{Detail,de,Title\}' ASC, data#>'\{Detail,de,Body\}' DESC" + let actual = Transformer.transformSort "Detail.de.Title, -Detail.de.Body" + Expect.equal actual expected "" + } + ] + testList "Filtering" [ + let transformFilter x = + let jsonSerializer = Newtonsoft.Json.JsonConvert.SerializeObject + Transformer.transformFilter (System.Func<_, _> jsonSerializer, x) + test "Simple boolean filter" { + let expected = "(data#>'\{Active\}')::boolean = TRUE" + let actual = transformFilter "eq(Active, true)" + Expect.equal actual expected "" + } + test "Simple number filter" { + let expected = "(data#>'\{Altitude\}')::float = 200" + let actual = transformFilter "eq(Altitude, 200)" + Expect.equal actual expected "" + } + test "Simple string filter" { + let expected = "data#>>'\{Type\}' = 'Wandern'" + let actual = transformFilter "eq(Type, 'Wandern')" + Expect.equal actual expected "" + } + test "Simple like filter" { + let expected = "data#>>'\{Type\}' LIKE '%Wandern%'" + let actual = transformFilter "like(Type, 'Wandern')" + Expect.equal actual expected "" + } + test "Simple datetime filter" { + let expected = "(data#>'\{ImageGallery\}')::jsonb = to_jsonb(array\[\]::varchar\[\])" + let actual = transformFilter "eq(ImageGallery, [])" + Expect.equal actual expected "" + } + test "Simple AND filter" { + let expected = "((data#>'\{Geo,Altitude\}')::float >= 200 AND (data#>'\{Geo,Altitude\}')::float <= 400)" + let actual = transformFilter "and(ge(Geo.Altitude, 200), le(Geo.Altitude, 400))" + Expect.equal actual expected "" + } + test "AND filter with multiple conditions" { + let expected = "((data#>'\{Active\}')::boolean = TRUE AND ((data#>'\{Geo,Altitude\}')::float >= 200 AND (data#>'\{Geo,Altitude\}')::float <= 400))" + let actual = transformFilter "and(eq(Active, true), ge(Geo.Altitude, 200), le(Geo.Altitude, 400))" + Expect.equal actual expected "" + } + test "AND filter with nested OR" { + let expected = "((data#>'\{Active\}')::boolean = TRUE OR ((data#>'\{Geo,Altitude\}')::float >= 200 AND (data#>'\{Geo,Altitude\}')::float <= 400))" + let actual = transformFilter "or(eq(Active, true), and(ge(Geo.Altitude, 200), le(Geo.Altitude, 400)))" + Expect.equal actual expected "" + } + test "NULL" { + let expected = "data#>>'\{Detail,ru,Title\}' IS NULL" + let actual = transformFilter "isnull(Detail.ru.Title)" + Expect.equal actual expected "" + } + test "NOT NULL" { + let expected = "data#>>'\{Detail,ru,Title\}' IS NOT NULL" + let actual = transformFilter "isnotnull(Detail.ru.Title)" + Expect.equal actual expected "" + } + test "IN with simple field" { + let expected = """(data @> '\{"HasLanguage":"de"\}')""" + let actual = transformFilter "in(HasLanguage,'de')" + Expect.equal actual expected "" + } + test "IN with nested fields" { + let expected = """(data @> '\{"Foo":\{"HasLanguage":"de"\}\}')""" + let actual = transformFilter "in(Foo.HasLanguage,'de')" + Expect.equal actual expected "" + } + test "IN with array" { + let expected = """(data @> '\{"Features":\[\{"Id":"a3067617-771a-4b84-b85e-206e5cf4402b"\}\]\}')""" + let actual = transformFilter "in(Features.[].Id,'a3067617-771a-4b84-b85e-206e5cf4402b')" + Expect.equal actual expected "" + } + test "LIKEIN with simple field" { + let expected = """(jsonb_path_exists(data, '$.OdhTags ?(@ like_regex "Ski" flag "q")'))""" + let actual = transformFilter "likein(OdhTags,'Ski')" + Expect.equal actual expected "" + } + test "LIKEIN with array" { + let expected = """(jsonb_path_exists(data, '$.OdhTags\[*\].Id ?(@ like_regex "Ski" flag "q")'))""" + let actual = transformFilter "likein(OdhTags.[*].Id,'Ski')" + Expect.equal actual expected "" + } + test "LIKEIN with nested fields" { + let expected = """(jsonb_path_exists(data, '$.Foo.OdhTags ?(@ like_regex "Ski" flag "q")'))""" + let actual = transformFilter "likein(Foo.OdhTags,'Ski')" + Expect.equal actual expected "" + } + test "LIKEIN with nested field and multiple values" { + let expected = """(jsonb_path_exists(data, '$.Foo.OdhTags ?(@ like_regex "Ski" flag "q")') OR jsonb_path_exists(data, '$.Foo.OdhTags ?(@ like_regex "Winter" flag "q")'))""" + let actual = transformFilter "likein(Foo.OdhTags,'Ski','Winter')" + Expect.equal actual expected "" + } + ] + ] diff --git a/docker-compose.dcproj b/docker-compose.dcproj new file mode 100644 index 0000000..7875c60 --- /dev/null +++ b/docker-compose.dcproj @@ -0,0 +1,14 @@ + + + + 2.1 + Linux + 48bedd14-d366-4553-ad99-c35ddaf28ff2 + LaunchBrowser + {Scheme}://localhost:{ServicePort} + odhapicore + + + + + \ No newline at end of file diff --git a/infrastructure/ansible/ansible.cfg b/infrastructure/ansible/ansible.cfg new file mode 100644 index 0000000..bec5ce0 --- /dev/null +++ b/infrastructure/ansible/ansible.cfg @@ -0,0 +1,4 @@ +[defaults] +inventory = ./hosts +roles_path = ./roles +retry_files_enabled = False diff --git a/infrastructure/ansible/deploy.yml b/infrastructure/ansible/deploy.yml new file mode 100644 index 0000000..905feb9 --- /dev/null +++ b/infrastructure/ansible/deploy.yml @@ -0,0 +1,19 @@ +--- +- hosts: all + vars: + ansible_python_interpreter: /usr/bin/python3 + tasks: + - name: Login to GitHub Container Registry + ansible.builtin.shell: + cmd: echo "{{ docker_password }}" | docker login "{{ docker_host }}" --username "{{ docker_username }}" --password-stdin + - name: Execute Docker deployment + ansible.builtin.include_role: + name: ansible-docker-deployment + vars: + docker_deployment_project_name: '{{ project_name }}' + docker_deployment_release_name: '{{ release_name }}' + docker_deployment_release_files: + - local: ../docker-compose.run.yml + remote: docker-compose.yml + - local: ../../.env + remote: .env \ No newline at end of file diff --git a/infrastructure/ansible/hosts b/infrastructure/ansible/hosts new file mode 100644 index 0000000..f911269 --- /dev/null +++ b/infrastructure/ansible/hosts @@ -0,0 +1,5 @@ +[test] +docker02.testingmachine.eu ansible_user='noi-techpark-bot' ansible_ssh_common_args='-o StrictHostKeyChecking=no' + +[prod] +docker04.opendatahub.com ansible_user='noi-techpark-bot' ansible_ssh_common_args='-o StrictHostKeyChecking=no' diff --git a/infrastructure/ansible/requirements.yml b/infrastructure/ansible/requirements.yml new file mode 100644 index 0000000..003d395 --- /dev/null +++ b/infrastructure/ansible/requirements.yml @@ -0,0 +1,6 @@ +roles: + - src: git+https://github.com/noi-techpark/ansible-docker-deployment.git + version: "2.0" +collections: + - name: community.docker + version: 3.10.4 diff --git a/infrastructure/ansible/roles/.gitignore b/infrastructure/ansible/roles/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/infrastructure/ansible/roles/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/infrastructure/docker-compose.run.yml b/infrastructure/docker-compose.run.yml new file mode 100644 index 0000000..dfa966d --- /dev/null +++ b/infrastructure/docker-compose.run.yml @@ -0,0 +1,22 @@ +services: + api: + image: ${DOCKER_IMAGE}:${DOCKER_TAG} + environment: + ASPNETCORE_URLS: http://+:80 + ASPNETCORE_ENVIRONMENT: ${ASPNETCORE_ENVIRONMENT} + ASPNETCORE_ConnectionStrings__PgConnection: ${PG_CONNECTION} + ASPNETCORE_XmlConfig__Xmldir: ${XMLDIR} + ASPNETCORE_XmlConfig__XmldirWeather: ${XMLDIR} + ASPNETCORE_S3ImageresizerConfig__Url: ${IMG_URL} + ASPNETCORE_S3ImageresizerConfig__DocUrl: ${DOC_URL} + ASPNETCORE_S3ImageresizerConfig__BucketAccessPoint: ${S3_BUCKET_ACCESSPOINT} + ASPNETCORE_S3ImageresizerConfig__AccessKey: ${S3_IMAGEUPLOADER_ACCESSKEY} + ASPNETCORE_S3ImageresizerConfig__SecretKey: ${S3_IMAGEUPLOADER_SECRETKEY} + ASPNETCORE_OauthServerConfig__Authority: ${OAUTH_AUTORITY} + ASPNETCORE_ElasticSearchConfig__ElasticUrl: ${ELK_URL} + ASPNETCORE_ElasticSearchConfig__ElasticAuthtoken: ${ELK_TOKEN} + ASPNETCORE_JsonConfig__Jsondir: ${JSONPATH} + ASPNETCORE_DataBrowserConfig__Url: ${DATABROWSER_URL} + restart: unless-stopped + ports: + - "${SERVER_PORT}:80" \ No newline at end of file diff --git a/opendatahub-content-api-core.sln b/opendatahub-content-api-core.sln new file mode 100644 index 0000000..12a43a1 --- /dev/null +++ b/opendatahub-content-api-core.sln @@ -0,0 +1,90 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31912.275 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Helper", "Helper\Helper.csproj", "{D87BA784-F2A9-4308-AAA9-A94A76922B1C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7698F85B-F8BB-4757-A981-E5763319498B}" + ProjectSection(SolutionItems) = preProject + README.md = README.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataModel", "DataModel\DataModel.csproj", "{B380784A-025B-4983-9FC2-6282759AB38F}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "RawQueryParser", "RawQueryParser\RawQueryParser.fsproj", "{AFEF98C8-8959-4A39-BAC8-936E928D2F01}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "RawQueryParserTests", "RawQueryParserTests\RawQueryParserTests.fsproj", "{997319F9-49A5-4CF7-99BC-EEF54A8F3B45}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonLDTransformer", "JsonLDTransformer\JsonLDTransformer.csproj", "{86048A5A-5F85-4E40-861F-974D2DA2E1D0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PushServer", "PushServer\PushServer.csproj", "{F55BAA43-196C-4699-8E9D-A252F180A7C7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeoConverter", "GeoConverter\GeoConverter.csproj", "{7192CDA4-4C08-4580-8DF8-3055FEF33629}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeoConverterTests", "GeoConverterTests\GeoConverterTests.csproj", "{875F0429-6B54-4734-B3E2-C532EE4899D4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OdhNotifier", "OdhNotifier\OdhNotifier.csproj", "{FFA377A9-71FE-4BA3-A337-90D7EE2463DB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ContentApiCore", "ContentApiCore\ContentApiCore.csproj", "{C88E18B9-FD8A-4D1F-8070-58A47E426C9F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ContentApiCoreTests", "ContentApiCoreTests\ContentApiCoreTests.csproj", "{D2DD4C38-6DFF-4565-9D56-22DC9C3AA0D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D87BA784-F2A9-4308-AAA9-A94A76922B1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D87BA784-F2A9-4308-AAA9-A94A76922B1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D87BA784-F2A9-4308-AAA9-A94A76922B1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D87BA784-F2A9-4308-AAA9-A94A76922B1C}.Release|Any CPU.Build.0 = Release|Any CPU + {B380784A-025B-4983-9FC2-6282759AB38F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B380784A-025B-4983-9FC2-6282759AB38F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B380784A-025B-4983-9FC2-6282759AB38F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B380784A-025B-4983-9FC2-6282759AB38F}.Release|Any CPU.Build.0 = Release|Any CPU + {AFEF98C8-8959-4A39-BAC8-936E928D2F01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AFEF98C8-8959-4A39-BAC8-936E928D2F01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AFEF98C8-8959-4A39-BAC8-936E928D2F01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AFEF98C8-8959-4A39-BAC8-936E928D2F01}.Release|Any CPU.Build.0 = Release|Any CPU + {997319F9-49A5-4CF7-99BC-EEF54A8F3B45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {997319F9-49A5-4CF7-99BC-EEF54A8F3B45}.Debug|Any CPU.Build.0 = Debug|Any CPU + {997319F9-49A5-4CF7-99BC-EEF54A8F3B45}.Release|Any CPU.ActiveCfg = Release|Any CPU + {997319F9-49A5-4CF7-99BC-EEF54A8F3B45}.Release|Any CPU.Build.0 = Release|Any CPU + {86048A5A-5F85-4E40-861F-974D2DA2E1D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86048A5A-5F85-4E40-861F-974D2DA2E1D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86048A5A-5F85-4E40-861F-974D2DA2E1D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86048A5A-5F85-4E40-861F-974D2DA2E1D0}.Release|Any CPU.Build.0 = Release|Any CPU + {F55BAA43-196C-4699-8E9D-A252F180A7C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F55BAA43-196C-4699-8E9D-A252F180A7C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F55BAA43-196C-4699-8E9D-A252F180A7C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F55BAA43-196C-4699-8E9D-A252F180A7C7}.Release|Any CPU.Build.0 = Release|Any CPU + {7192CDA4-4C08-4580-8DF8-3055FEF33629}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7192CDA4-4C08-4580-8DF8-3055FEF33629}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7192CDA4-4C08-4580-8DF8-3055FEF33629}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7192CDA4-4C08-4580-8DF8-3055FEF33629}.Release|Any CPU.Build.0 = Release|Any CPU + {875F0429-6B54-4734-B3E2-C532EE4899D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {875F0429-6B54-4734-B3E2-C532EE4899D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {875F0429-6B54-4734-B3E2-C532EE4899D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {875F0429-6B54-4734-B3E2-C532EE4899D4}.Release|Any CPU.Build.0 = Release|Any CPU + {FFA377A9-71FE-4BA3-A337-90D7EE2463DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FFA377A9-71FE-4BA3-A337-90D7EE2463DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FFA377A9-71FE-4BA3-A337-90D7EE2463DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FFA377A9-71FE-4BA3-A337-90D7EE2463DB}.Release|Any CPU.Build.0 = Release|Any CPU + {C88E18B9-FD8A-4D1F-8070-58A47E426C9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C88E18B9-FD8A-4D1F-8070-58A47E426C9F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C88E18B9-FD8A-4D1F-8070-58A47E426C9F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C88E18B9-FD8A-4D1F-8070-58A47E426C9F}.Release|Any CPU.Build.0 = Release|Any CPU + {D2DD4C38-6DFF-4565-9D56-22DC9C3AA0D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2DD4C38-6DFF-4565-9D56-22DC9C3AA0D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2DD4C38-6DFF-4565-9D56-22DC9C3AA0D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2DD4C38-6DFF-4565-9D56-22DC9C3AA0D8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B5D8E984-4AA8-4EA4-81DB-D18D891A2BDC} + EndGlobalSection +EndGlobal